diff --git a/Debug/PE.js b/Debug/PE.js
new file mode 100644
index 0000000..dd117a2
--- /dev/null
+++ b/Debug/PE.js
@@ -0,0 +1,122 @@
+// JavaScript source code
+
+var fs = require('fs');
+//var buffer = fs.readFileSync('test.bin');
+//var tls = require('tls');
+
+//var pem = tls.loadpkcs7b(buffer);
+//console.log(pem.toString());
+
+
+
+
+var fd = fs.openSync(process.execPath.replace('MeshConsole', 'MC2'), 'rb+');
+var bytesRead;
+var dosHeader = new Buffer(64);
+var ntHeader = new Buffer(24);
+var optHeader;
+
+console.log(process.execPath.replace('MeshConsole', 'MC2'));
+
+bytesRead = fs.readSync(fd, dosHeader, 0, 64, 0);
+if (dosHeader.readUInt16LE(0).toString(16).toUpperCase() != '5A4D')
+{
+ console.log('unrecognized binary format');
+}
+
+bytesRead = fs.readSync(fd, ntHeader, 0, ntHeader.length, dosHeader.readUInt32LE(60));
+
+if (ntHeader.slice(0, 4).toString('hex') != '50450000')
+{
+ console.log('not PE format');
+}
+
+switch (ntHeader.readUInt16LE(4).toString(16))
+{
+ case '14c':
+ console.log('x86 binary');
+ break;
+ case '8664':
+ console.log('x64 binary');
+ break;
+ default:
+ console.log('unknown binary type');
+ break;
+}
+
+console.log('Optional Size = ' + ntHeader.readUInt16LE(20) + 'bytes');
+optHeader = new Buffer(ntHeader.readUInt16LE(20));
+bytesRead = fs.readSync(fd, optHeader, 0, optHeader.length, dosHeader.readUInt32LE(60) + 24);
+var numRVA = undefined;
+var CertificateTableAddress = undefined;
+var CertificateTableSize = undefined;
+
+switch (optHeader.readUInt16LE(0).toString(16).toUpperCase())
+{
+ case '10B':
+ console.log('Found IMAGE_NT_OPTIONAL_HDR32_MAGIC');
+ numRVA = optHeader.readUInt32LE(92);
+ CertificateTableAddress = optHeader.readUInt32LE(128);
+ CertificateTableSize = optHeader.readUInt32LE(132);
+ break;
+ case '20B':
+ console.log('Found IMAGE_NT_OPTIONAL_HDR64_MAGIC');
+ numRVA = optHeader.readUInt32LE(108);
+ CertificateTableAddress = optHeader.readUInt32LE(144);
+ CertificateTableSize = optHeader.readUInt32LE(148);
+ break;
+ default:
+ console.log('Unknown Value found for Optional Magic: ' + ntHeader.readUInt16LE(24).toString(16).toUpperCase());
+ break;
+}
+
+console.log('Number of RVA Entries: ' + numRVA.toString());
+console.log('Certificate Table Address: ' + CertificateTableAddress.toString(16).toUpperCase());
+console.log('Certificate Table Size: ' + CertificateTableSize.toString());
+
+var hdr = new Buffer(8);
+fs.readSync(fd, hdr, 0, hdr.length, CertificateTableAddress);
+console.log('dwLength = ' + hdr.readUInt32LE(0).toString());
+
+console.log('Updating Table Entries: ');
+optHeader.writeUInt32LE(6848, 132);
+hdr.writeUInt32LE(6848, 0);
+
+console.log('written', fs.writeSync(fd, optHeader, 0, optHeader.length, dosHeader.readUInt32LE(60) + 24));
+console.log('written', fs.writeSync(fd, hdr, 0, hdr.length, CertificateTableAddress));
+
+console.log('Done!');
+
+
+fs.closeSync(fd);
+
+//switch (hdr.readUInt16LE(6).toString(16).toUpperCase())
+//{
+// case '1':
+// console.log('Cert Type = X509');
+// break;
+// case '2':
+// console.log('Cert Type = PKCS#7')
+// break;
+// case '3':
+// console.log('Cert Type = RESERVED')
+// break;
+// case '4':
+// console.log('Cert Type = TERMINAL_SERVER')
+// break;
+//}
+
+//var cert = new Buffer(hdr.readUInt32LE(0) - 8);
+//fs.readSync(fd, cert, 0, cert.length, CertificateTableAddress + hdr.length);
+
+//console.log('Cert Length: ' + cert.length);
+//console.log(cert.toString());
+
+//console.log(1);
+//var ws = fs.createWriteStream("test.txt", { flags: "wb" });
+//ws.write(cert);
+//console.log(2);
+//ws.end();
+//console.log(3);
+
+
diff --git a/Debug/PostBuild.js b/Debug/PostBuild.js
new file mode 100644
index 0000000..a188c8c
--- /dev/null
+++ b/Debug/PostBuild.js
@@ -0,0 +1,50 @@
+// JavaScript source code
+
+console.log('Running Post Build Step....');
+
+var fs = require('fs');
+var hash = require('SHA384Stream').create();
+
+var stream1;
+var stream2;
+var pending;
+
+hash.on('hashString', function (h)
+{
+ if (process.platform == 'win32') {
+ pending = 2;
+ var newFileName = process.execPath.substring(0, process.execPath.length - 4) + "_" + h.substring(0, 16) + ".exe";
+ var pdbFileName = process.execPath.substring(0, process.execPath.length - 4) + '.pdb';
+ var newPdbFileName = process.execPath.substring(0, process.execPath.length - 4) + "_" + h.substring(0, 16) + ".pdb";
+
+ console.log(process.execPath + ' => ' + newFileName);
+ console.log(pdbFileName + ' => ' + newPdbFileName);
+
+ stream1 = fs.createReadStream(process.execPath, { flags: "rb" });
+ stream1.output = fs.createWriteStream(newFileName, { flags: "wb+" });
+ stream1.output.on('finish', OnFinish);
+ stream1.pipe(stream1.output);
+
+ stream2 = fs.createReadStream(pdbFileName, { flags: "rb" });
+ stream2.output = fs.createWriteStream(newPdbFileName, { flags: "wb+" });
+ stream2.output.on('finish', OnFinish);
+ stream2.pipe(stream2.output);
+ }
+ else
+ {
+ console.log(process.platform + ' is not supported');
+ process.exit();
+ }
+});
+
+function OnFinish()
+{
+ if (--pending == 0)
+ {
+ console.log('Finished!');
+ process.exit();
+ }
+}
+
+var exeStream = fs.createReadStream(process.execPath, { flags: "rb" });
+exeStream.pipe(hash);
diff --git a/Debug/WebRTC_Test2.html b/Debug/WebRTC_Test2.html
index 0afd78f..f62c2f2 100644
--- a/Debug/WebRTC_Test2.html
+++ b/Debug/WebRTC_Test2.html
@@ -17,7 +17,7 @@
function start()
{
debug("Connecting signaling channel...");
- wsocket = new WebSocket("ws://127.0.0.1:8585/control");
+ wsocket = new WebSocket("ws://192.168.5.128:8585/control");
wsocket.binaryType = "arraybuffer";
wsocket.onopen = function (evt)
{
@@ -33,7 +33,7 @@
debug("Received WebRTC Offer...");
var ax = null;
- if (typeof mozRTCSessionDescription !== 'undefined') { ax = new mozRTCSessionDescription({ type: "answer", sdp: cmd.data }) } else { ax = new RTCSessionDescription({ type: "answer", sdp: cmd.data }) }
+ if (typeof mozRTCSessionDescription !== 'undefined') { ax = new mozRTCSessionDescription({ type: "offer", sdp: cmd.data }) } else { ax = new RTCSessionDescription({ type: "offer", sdp: cmd.data }) }
connection.setRemoteDescription(ax, onSetRemoteDescriptionDone, onError);
}
}
@@ -41,7 +41,7 @@
function onSetRemoteDescriptionDone()
{
- //connection.createAnswer(onAnswerDone, onError);
+ connection.createAnswer(onAnswerDone, onError);
}
function onAnswerDone(answer)
{
@@ -61,13 +61,7 @@
connection.ondatachannel = onDataChannel
connection.onicecandidate = onIceCandidate;
-
- datachannel = connection.createDataChannel("browserDataChannel", {});
- datachannel.onmessage = function (event) { debug("Remote: " + event.data); };
- datachannel.onopen = function () { debug("browserDataChannel Connected."); };
- datachannel.onclose = function (event) { debug("DataChannel was closed by remote"); }
-
- connection.createOffer(onOfferDone, onError, { mandatory: { OfferToReceiveAudio: false, OfferToReceiveVideo: false } });
+ connection.oniceconnectionstatechange = function () { if (connection != null) { if ((connection.iceConnectionState == 'disconnected') || (connection.iceConnectionState == 'failed')) { debug("WTF Happened?"); } } }
}
function onOfferDone(offer)
{
@@ -83,15 +77,15 @@
datachannel.binaryType = "arraybuffer";
datachannel.onmessage = function (msg)
{
- try
- {
- datachannel.send(msg.data.byteLength.toString());
- }
- catch(e)
- {
- debug(e.toString());
- debug(msg.data.toString());
- }
+ //try
+ //{
+ // datachannel.send(msg.data.byteLength.toString() + 'bytes of ' + msg.data[0].toString());
+ //}
+ //catch(e)
+ //{
+ // debug(e.toString());
+ // //debug(msg.data.toString());
+ //}
};
}
diff --git a/Debug/WebRTC_Test2.js b/Debug/WebRTC_Test2.js
index 5927d45..62adf79 100644
--- a/Debug/WebRTC_Test2.js
+++ b/Debug/WebRTC_Test2.js
@@ -1,3 +1,20 @@
+console.enableWebLog(9595);
+var mesh = null;
+var kvmStream = null;
+var Readable = require('stream').Readable;
+var RS = new Readable({
+ read: function (options)
+ {
+ var min = 62000;
+ var max = 65535;
+ var size = Math.floor(Math.random() * (max - min)) + min;
+ var retVal = Buffer.alloc(size).fill(this.val++);
+ retVal.writeUInt32BE(size, 0);
+ if (this.val == 10) { this.val = 0; }
+ return (retVal);
+ }
+});
+RS.val = 0;
var http = require('http');
var rtc = require('ILibWebRTC');
@@ -6,12 +23,30 @@ var signalingChannel;
var dc;
var webServer = http.createServer(OnLocalWebRequest);
-var processMgr = require('ILibProcessPipe');
+
+var childprocess = require('child_process');
var p;
webServer.on('upgrade', OnUpgrade);
webServer.listen(8585);
-//p = processMgr.CreateProcess("c:\\windows\\system32\\cmd.exe", "/c", "start", "http://localhost:8585/start.html");
+
+if (process.platform == 'win32') {
+ p = childprocess.execFile("c:\\windows\\system32\\cmd.exe", ["/c", "start", "http://localhost:8585/start.html"]);
+}
+else {
+ console.log('Manually point your browser to http://localhost:8585/start.html');
+}
+
+
+try
+{
+ mesh = require('MeshAgent');
+}
+catch(e)
+{
+
+}
+
function OnUpgrade(imsg, sck, head)
{
@@ -20,20 +55,102 @@ function OnUpgrade(imsg, sck, head)
signalingChannel.on('data', OnSignalData);
peerConnection = rtc.createConnection();
+ peerConnection.on('disconnected', function () { console.log('SCTP was disconnected'); });
peerConnection.on('connected', OnWebRTC_Connected);
peerConnection.on('dataChannel', OnWebRTC_DataChannel);
- //console.log("Generating WebRTC Offer...");
- //signalingChannel.write({ cmd: "offer", data: peerConnection.generateOffer() });
+ try
+ {
+ // peerConnection.on('_hold', function (val) { console.log('Holding Count: ' + val);});
+ peerConnection.on('_congestionWindowSizeChange', function (val) { console.log('Congestion Window: ' + val); });
+ // peerConnection.on('_receiverCredits', function (val) { console.log('Receiver Credits: ' + val); });
+ peerConnection.on('_t3tx', function (val) { console.log('T3TX: ' + val); });
+ //peerConnection.on('_fastRecovery', function (val) { console.log('Fast Recovery: ' + val);});
+ //peerConnection.on('_rttCalculated', function (val) { console.log('Calculated RTT Value = ' + val); });
+ peerConnection.on('_lastSackTime', function (val) { console.log('Last SACK Time = ' + val); });
+ peerConnection.on('_retransmit', function (val) { console.log('Retransmit: ' + (new Uint32Array([val]))[0]); });
+ //peerConnection.on('_retransmitPacket', function (val) { DebugPacket(val); console.log('RetransmitPacket: ' + val.toString('hex')); });
+ //peerConnection.on('_lastSentTime', function (val) { console.log('Last Sent Time = ' + val); });
+ peerConnection.on('_sackReceived', function (val) { console.log('SACK: ' + (new Uint32Array([val]))[0]); });
+ }
+ catch(e)
+ {
+ }
+
+ console.log("Generating WebRTC Offer...");
+ signalingChannel.write({ cmd: "offer", data: peerConnection.generateOffer() });
}
+
+function FOURBYTEBOUNDARY(a)
+{
+ return ((a) + ((4 - ((a) % 4)) % 4));
+}
+function crc32c(crc, bytes)
+{
+ var POLY = 0x82f63b78;
+ var n;
+
+ crc ^= 0xffffffff;
+ for (n = 0; n < bytes.length; n++) {
+ crc ^= bytes[n];
+ crc = crc & 1 ? (crc >>> 1) ^ POLY : crc >>> 1;
+ crc = crc & 1 ? (crc >>> 1) ^ POLY : crc >>> 1;
+ crc = crc & 1 ? (crc >>> 1) ^ POLY : crc >>> 1;
+ crc = crc & 1 ? (crc >>> 1) ^ POLY : crc >>> 1;
+ crc = crc & 1 ? (crc >>> 1) ^ POLY : crc >>> 1;
+ crc = crc & 1 ? (crc >>> 1) ^ POLY : crc >>> 1;
+ crc = crc & 1 ? (crc >>> 1) ^ POLY : crc >>> 1;
+ crc = crc & 1 ? (crc >>> 1) ^ POLY : crc >>> 1;
+ }
+ return crc ^ 0xffffffff;
+}
+
+function DebugPacket(val)
+{
+ console.log('BufferLen: ' + val.length);
+ console.log('CRC32C: ' + val.readInt32LE(8))
+ val.writeUInt32BE(0, 8);
+ console.log('CRC32C/Calc: ' + crc32c(0, val));
+ console.log('VTAG: ' + val.readUInt32LE(4));
+ var ptr = 12;
+
+ while (ptr + 4 <= val.length)
+ {
+ var hdr = val.slice(ptr);
+
+ var chunkType = hdr[0];
+ var chunkFlags = hdr[1];
+ var chunkSize = hdr.readUInt16BE(2);
+
+ switch (chunkType) {
+ case 0:
+ console.log('DATA Chunk');
+ console.log('...chunkFlags: ' + chunkFlags);
+ console.log('...chunkLength: ' + chunkSize);
+ console.log('...TSN: ' + hdr.readUInt32BE(4));
+ console.log('...StreamID: ' + hdr.readUInt16BE(8));
+ console.log('...Seq: ' + hdr.readUInt16BE(10));
+ console.log('...ProtocolID: ' + hdr.readUInt32BE(12));
+ break;
+ default:
+ console.log('UNKNOWN Chunk');
+ console.log('...chunkFlags: ' + chunkFlags);
+ console.log('...chunkLength: ' + chunkSize);
+ break;
+ }
+
+ ptr += FOURBYTEBOUNDARY(chunkSize);
+ }
+}
function OnSignalData(chunk)
{
var j = JSON.parse(chunk);
if (j.cmd == 'offer')
{
console.log("Received Offer");
- signalingChannel.write({ cmd: "offer", data: peerConnection.setOffer(j.data) });
+ //signalingChannel.write({ cmd: "offer", data: peerConnection.setOffer(j.data) });
+ peerConnection.setOffer(j.data);
}
}
function OnLocalWebRequest(request, response)
@@ -66,24 +183,30 @@ function OnLocalWebRequest(request, response)
function OnWebRTC_Connected()
{
console.log("WebRTC Session Established");
- //this.dc = this.createDataChannel("testChannel", OnTestChannel);
- //if(mesh != null)
- //{
- // // Let create a data channel
- // this.dc = this.createDataChannel("remoteDesktop", OnKVMChannel)
- // this.tempTimeout = setTimeout(function (dc) { console.log("sending: 'test'"); dc.write("test"); }, 10000, this.dc);
- //}
+
+ this.jsdc = this.createDataChannel("testChannel", OnTestChannel);
}
function OnTestChannel()
{
- console.log("Successfully established Data Channel");
+ console.log("Successfully established JavaScript Data Channel");
+
+ if (mesh == null) {
+ RS.pipe(this);
+ }
+ else {
+ kvmStream = mesh.getRemoteDesktopStream();
+ kvmStream.pipe(this);
+ }
}
function OnKVMChannel()
{
console.log("Successfully established Data Channel to test Data throughput");
dc = this;
dc.kvm = mesh.getRemoteDesktopStream();
- dc.on('data', function (buffer) { console.log("Peer Received: " + buffer.toString() + " bytes"); });
+ dc.on('data', function (buffer)
+ {
+ console.log("Peer Received: " + buffer.toString() + " bytes");
+ });
dc.on('end', function () { this.kvm.end(); console.log("Closing KVM Session"); });
dc.kvm.pipe(dc);
}
@@ -91,8 +214,21 @@ function OnWebRTC_DataChannel(dataChannel)
{
console.log("Data Channel (" + dataChannel.name + ") was created");
dc = dataChannel;
- dc.on('data', function (buffer) { console.log("Received: " + buffer.length + " bytes"); dc.write(buffer.length.toString()); });
+ dc.on('data', function (buffer)
+ {
+ //console.log("Received: " + buffer);
+ });
dc.on('end', function () { console.log("Data Channel: " + this.name + " was closed"); });
+
+ //if (mesh == null)
+ //{
+ // RS.pipe(dc);
+ //}
+ //else
+ //{
+ // kvmStream = mesh.getRemoteDesktopStream();
+ // kvmStream.pipe(dc);
+ //}
}
function OnTunnelData(buffer)
{
diff --git a/Debug/httptest.js b/Debug/httptest.js
index 1898603..dd7b73b 100644
--- a/Debug/httptest.js
+++ b/Debug/httptest.js
@@ -2,10 +2,11 @@ var http = require('http');
var https = require('https');
var WS;
console.log("Starting HTTP (Rewrite) Test");
+console.displayStreamPipeMessages = 1;
+console.displayFinalizerMessages = 1;
-var cert = https.generateCertificate('test');
-
-var server = https.createServer();
+var cert = require('tls').generateCertificate('test');
+var server = https.createServer({ pfx: cert, passphrase: 'test' });
server.on('request', function (imsg, rsp)
{
@@ -16,27 +17,28 @@ server.on('upgrade', function (imsg, sck, head)
{
console.log('Server On Upgrade');
WS = sck.upgradeWebSocket();
- WS.on('pong', function () { console.log('Server received PONG'); WS.write('this is test'); WS.write(Buffer.from("This is a good day")); WS.end();});
+ WS.on('pong', function () { console.log('Server received PONG'); WS.write('this is test'); WS.write(Buffer.from("This is a good day.. Bye!")); WS.end();});
WS.on('data', function (chunk) { console.log('Server received: ' + chunk); });
+ WS.on('end', function () { console.log('Server WS ended'); WS = null; });
WS.ping();
});
-server.listen({ port: 9095, pfx: cert, passphrase: 'test' });
+server.listen({ port: 9095 });
//var req = http.get("http://127.0.0.1:9095/test.html");
//var req = http.get("ws://127.0.0.1:9095/test.html");
var req = http.request({ protocol: 'wss:', host: '127.0.0.1', port: 9095, method: 'GET', path: '/test.html', rejectUnauthorized: false})
req.end();
-var req2 = http.request({ protocol: 'https:', host: '127.0.0.1', port: 9095, method: 'GET', path: '/test.html', rejectUnauthorized: false })
-req2.end();
+//var req2 = http.request({ protocol: 'https:', host: '127.0.0.1', port: 9095, method: 'GET', path: '/test.html', rejectUnauthorized: false })
+//req2.end();
req.on('upgrade', function (imsg, sck, head)
{
console.log('client upgraded to WebSocket');
sck.on('ping', function () { console.log('Client received ping'); this.write('Client says hello');});
sck.on('data', function (chunk) { console.log('client received: ' + chunk, typeof (chunk)); });
- sck.on('end', function () { console.log('Client side closed'); });
+ sck.on('end', function () { console.log('Client side closed'); console.logReferenceCount(req); req = null; _debugGC(); });
});
req.on('response', function (imsg)
{
@@ -47,10 +49,10 @@ req.on('response', function (imsg)
})
req.on('error', function (err) { console.log('error received', err); });
-req2.on('response', function (imsg) {
- console.log('received response', imsg.statusCode, imsg.statusMessage);
- imsg.on('end', function () {
- console.log('Done reading IncomingMessageStream');
- });
-})
-req2.on('error', function (err) { console.log('error received', err); });
\ No newline at end of file
+//req2.on('response', function (imsg) {
+// console.log('received response', imsg.statusCode, imsg.statusMessage);
+// imsg.on('end', function () {
+// console.log('Done reading IncomingMessageStream');
+// });
+//})
+//req2.on('error', function (err) { console.log('error received', err); });
\ No newline at end of file
diff --git a/makefile b/makefile
index cf97ca5..960ac3e 100644
--- a/makefile
+++ b/makefile
@@ -32,7 +32,7 @@
SOURCES = microstack/ILibAsyncServerSocket.c microstack/ILibAsyncSocket.c microstack/ILibAsyncUDPSocket.c microstack/ILibParsers.c microstack/ILibMulticastSocket.c
SOURCES += microstack/ILibRemoteLogging.c microstack/ILibWebClient.c microstack/ILibWebRTC.c microstack/ILibWebServer.c microstack/ILibCrypto.c
SOURCES += microstack/ILibWrapperWebRTC.c microstack/md5.c microstack/sha1.c microstack/ILibSimpleDataStore.c microstack/ILibProcessPipe.c microstack/ILibIPAddressMonitor.c
-SOURCES += microscript/duktape.c microscript/ILibAsyncSocket_Duktape.c microscript/ILibDuktape_DuplexStream.c microscript/ILibDuktape_Helpers.c
+SOURCES += microscript/duktape.c microscript/duk_module_duktape.c microscript/ILibAsyncSocket_Duktape.c microscript/ILibDuktape_DuplexStream.c microscript/ILibDuktape_Helpers.c
SOURCES += microscript/ILibDuktape_http.c microscript/ILibDuktape_net.c microscript/ILibDuktape_ReadableStream.c microscript/ILibDuktape_WritableStream.c
SOURCES += microscript/ILibDuktapeModSearch.c microscript/ILibParsers_Duktape.c microscript/ILibWebClient_Duktape.c microscript/ILibDuktape_WebRTC.c
SOURCES += microscript/ILibWebServer_Duktape.c microscript/ILibDuktape_SimpleDataStore.c microscript/ILibDuktape_GenericMarshal.c
@@ -188,6 +188,11 @@ else
CFLAGS += -D_NOHECI
endif
+ifeq ($(WEBRTCDEBUG),1)
+# Adds WebRTC Debug Interfaces
+CFLAGS += -D_WEBRTCDEBUG
+endif
+
ifneq ($(WatchDog),)
CWATCHDOG := -DILibChain_WATCHDOG_TIMEOUT=$(WatchDog)
endif
@@ -264,7 +269,7 @@ $(LIBNAME): $(OBJECTS) $(SOURCES)
# Compile on Raspberry Pi 2/3 with KVM
pi:
- $(MAKE) EXENAME="meshagent_pi" CFLAGS="-std=gnu99 -g -Wall -D_POSIX -DMICROSTACK_PROXY -D_LINKVM $(CWEBLOG) $(CWATCHDOG) -fno-strict-aliasing $(INCDIRS) -DMESH_AGENTID=25 -D_NOFSWATCHER -D_NOHECI" LDFLAGS="-Lopenssl/libstatic/linux/pi $(LDFLAGS) $(LDEXTRA)"
+ $(MAKE) EXENAME="meshagent_pi" CFLAGS="-std=gnu99 -g -Wall -D_POSIX -DMICROSTACK_PROXY -DMICROSTACK_TLS_DETECT -D_LINKVM $(CWEBLOG) $(CWATCHDOG) -fno-strict-aliasing $(INCDIRS) -DMESH_AGENTID=25 -D_NOFSWATCHER -D_NOHECI" LDFLAGS="-Lopenssl/libstatic/linux/pi $(LDFLAGS) $(LDEXTRA)"
strip meshagent_pi
linux:
diff --git a/meshconsole/MeshConsole.vcxproj b/meshconsole/MeshConsole.vcxproj
index e9194ab..7d0ee00 100644
--- a/meshconsole/MeshConsole.vcxproj
+++ b/meshconsole/MeshConsole.vcxproj
@@ -25,9 +25,9 @@
+
-
@@ -48,9 +48,6 @@
-
-
-
@@ -76,9 +73,9 @@
+
-
@@ -97,9 +94,6 @@
-
-
-
@@ -189,7 +183,7 @@
Level3
Disabled
- MESH_AGENTID=1;NOLMSCOMMANDER;_DEBUG;MICROSTACK_PROXY;_LINKVM;DUK_OPT_DEBUGGER_SUPPORT;DUK_OPT_INTERRUPT_COUNTER;WIN32;WINSOCK2;_WINSOCK_DEPRECATED_NO_WARNINGS;_MSC_PLATFORM_TOOLSET_$(PlatformToolset);MICROSTACK_TLS_DETECT;MICROSTACK_NO_STDAFX;_REMOTELOGGING;_REMOTELOGGINGSERVER;ILibChain_WATCHDOG_TIMEOUT=600000;%(PreprocessorDefinitions)
+ MESH_AGENTID=1;NOLMSCOMMANDER;_DEBUG;MICROSTACK_PROXY;_LINKVM;WIN32;WINSOCK2;_WINSOCK_DEPRECATED_NO_WARNINGS;_MSC_PLATFORM_TOOLSET_$(PlatformToolset);MICROSTACK_TLS_DETECT;MICROSTACK_NO_STDAFX;_REMOTELOGGING;_REMOTELOGGINGSERVER;ILibChain_WATCHDOG_TIMEOUT=600000;%(PreprocessorDefinitions)
..\openssl\include;..\;%(AdditionalIncludeDirectories)
MultiThreadedDebug
Async
@@ -214,6 +208,9 @@
/ignore:4099 %(AdditionalOptions)
$(OutDir)$(TargetName)$(TargetExt)
+
+ "$(OutputPath)$(TargetFileName)" ..\modules\PostBuild.js
+
@@ -244,6 +241,9 @@
$(OutDir)$(TargetName)$(TargetExt)
/ignore:4099 %(AdditionalOptions)
+
+ "$(OutputPath)$(TargetFileName)" ..\modules\PostBuild.js
+
diff --git a/meshconsole/MeshConsole.vcxproj.filters b/meshconsole/MeshConsole.vcxproj.filters
index 8aa5def..17ba064 100644
--- a/meshconsole/MeshConsole.vcxproj.filters
+++ b/meshconsole/MeshConsole.vcxproj.filters
@@ -21,9 +21,6 @@
Microscript
-
- Microscript
-
Microscript
@@ -51,15 +48,6 @@
Microscript
-
- Microscript
-
-
- Microscript
-
-
- Microscript
-
Microstack
@@ -154,14 +142,14 @@
Microscript
+
+ Microscript
+
Microscript
-
- Microscript
-
Microscript
@@ -189,15 +177,6 @@
Microscript
-
- Microscript
-
-
- Microscript
-
-
- Microscript
-
Microstack
@@ -295,6 +274,9 @@
Microscript
+
+ Microscript
+
diff --git a/meshconsole/main.c b/meshconsole/main.c
index 47dbf76..2c043d9 100644
--- a/meshconsole/main.c
+++ b/meshconsole/main.c
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@ limitations under the License.
#endif
#include "microscript/ILibDuktape_ScriptContainer.h"
+#include "microstack/ILibCrypto.h"
MeshAgentHostContainer *agentHost = NULL;
diff --git a/meshcore/KVM/Linux/linux_kvm.c b/meshcore/KVM/Linux/linux_kvm.c
index 2fbb4af..74c3292 100644
--- a/meshcore/KVM/Linux/linux_kvm.c
+++ b/meshcore/KVM/Linux/linux_kvm.c
@@ -224,7 +224,7 @@ void getAvailableDisplays(unsigned short **array, int *len) {
if (dir != NULL) {
*len = scandir("/tmp/", &ent, lockfileCheckFn, alphasort);
- if ((*array = (unsigned short *)malloc(*len)) == NULL) ILIBCRITICALEXIT(254);
+ if ((*array = (unsigned short *)malloc((*len)*sizeof(unsigned short))) == NULL) ILIBCRITICALEXIT(254);
for (i = 0; i < *len; i++) {
int dispNo = 0;
diff --git a/meshcore/KVM/Linux/linux_tile.c b/meshcore/KVM/Linux/linux_tile.c
index 4101ff9..8f64559 100644
--- a/meshcore/KVM/Linux/linux_tile.c
+++ b/meshcore/KVM/Linux/linux_tile.c
@@ -390,7 +390,7 @@ int getScreenBuffer(char **desktop, long long *desktopsize, XImage *image)
if (*desktopsize != size) {
if (*desktop != NULL) { free(*desktop); }
*desktopsize = size;
- if ((*desktop = (char *) malloc (*desktopsize)) == NULL) ILIBCRITICALEXIT(254);
+ if ((*desktop = (char *) malloc (*desktopsize + 4)) == NULL) ILIBCRITICALEXIT(254);
}
if (bpp == 16) {
diff --git a/meshcore/KVM/Windows/input.c b/meshcore/KVM/Windows/input.c
index b5d9934..2e9077a 100644
--- a/meshcore/KVM/Windows/input.c
+++ b/meshcore/KVM/Windows/input.c
@@ -1,11 +1,11 @@
-/*
-Copyright 2006 - 2015 Intel Corporation
+/*
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/meshcore/KVM/Windows/input.h b/meshcore/KVM/Windows/input.h
index 4f4c175..89f6131 100644
--- a/meshcore/KVM/Windows/input.h
+++ b/meshcore/KVM/Windows/input.h
@@ -1,11 +1,11 @@
-/*
-Copyright 2006 - 2015 Intel Corporation
+/*
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/meshcore/KVM/Windows/kvm.c b/meshcore/KVM/Windows/kvm.c
index b895770..7ac8d95 100644
--- a/meshcore/KVM/Windows/kvm.c
+++ b/meshcore/KVM/Windows/kvm.c
@@ -1,11 +1,11 @@
/*
-Copyright 2006 - 2015 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
@@ -111,6 +111,7 @@ int kvm_relay_restart(int paused, void *pipeMgr, char *exePath, ILibKVM_WriteHan
HANDLE hStdOut = INVALID_HANDLE_VALUE;
HANDLE hStdIn = INVALID_HANDLE_VALUE;
int ThreadRunning = 0;
+int kvmConsoleMode = 0;
ILibRemoteLogging gKVMRemoteLogging = NULL;
#ifdef _WINSERVICE
@@ -379,7 +380,7 @@ void CheckDesktopSwitch(int checkres, ILibKVM_WriteHandler writeHandler, void *r
if (SCREEN_X != x || SCREEN_Y != y || SCREEN_WIDTH != w || SCREEN_HEIGHT != h || SCALING_FACTOR != SCALING_FACTOR_NEW)
{
- printf("RESOLUTION CHANGED! (supposedly)\n");
+ //printf("RESOLUTION CHANGED! (supposedly)\n");
SCREEN_X = x;
SCREEN_Y = y;
SCREEN_WIDTH = w;
@@ -460,12 +461,13 @@ int kvm_server_inputdata(char* block, int blocklen, ILibKVM_WriteHandler writeHa
{
unsigned short type, size;
+ // Decode the block header
+ if (blocklen < 4) return 0;
+
ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_2, "KVM [SLAVE]: Handle Input [Len = %d]", blocklen);
// KVMDEBUG("kvm_server_inputdata", blocklen);
CheckDesktopSwitch(0, writeHandler, reserved);
- // Decode the block header
- if (blocklen < 4) return 0;
type = ntohs(((unsigned short*)(block))[0]);
size = ntohs(((unsigned short*)(block))[1]);
@@ -649,22 +651,25 @@ typedef struct kvm_data_handler
// This method consumes as many input commands as it can.
int kvm_relay_feeddata(char* buf, int len, ILibKVM_WriteHandler writeHandler, void *reserved)
{
-#ifdef _WINSERVICE
- if (len >= 2 && ntohs(((unsigned short*)buf)[0]) == MNG_CTRLALTDEL)
+ if (gChildProcess != NULL)
{
- HANDLE ht = CreateThread(NULL, 0, kvm_ctrlaltdel, 0, 0, 0);
- if (ht != NULL) CloseHandle(ht);
+ if (len >= 2 && ntohs(((unsigned short*)buf)[0]) == MNG_CTRLALTDEL)
+ {
+ HANDLE ht = CreateThread(NULL, 0, kvm_ctrlaltdel, 0, 0, 0);
+ if (ht != NULL) CloseHandle(ht);
+ }
+ ILibProcessPipe_Process_WriteStdIn(gChildProcess, buf, len, ILibTransport_MemoryOwnership_USER);
+ ILibRemoteLogging_printf(ILibChainGetLogger(gILibChain), ILibRemoteLogging_Modules_Microstack_Generic, ILibRemoteLogging_Flags_VerbosityLevel_2, "KVM [Master]: Write Input [Type = %u]", ntohs(((unsigned short*)buf)[0]));
+ return len;
+ }
+ else
+ {
+ int len2 = 0;
+ int ptr = 0;
+ //while ((len2 = kvm_server_inputdata(buf + ptr, len - ptr, kvm_relay_feeddata_ex, (void*[]) {writeHandler, reserved})) != 0) { ptr += len2; }
+ while ((len2 = kvm_server_inputdata(buf + ptr, len - ptr, writeHandler, reserved)) != 0) { ptr += len2; }
+ return ptr;
}
- ILibProcessPipe_Process_WriteStdIn(gChildProcess, buf, len, ILibTransport_MemoryOwnership_USER);
- ILibRemoteLogging_printf(ILibChainGetLogger(gILibChain), ILibRemoteLogging_Modules_Microstack_Generic, ILibRemoteLogging_Flags_VerbosityLevel_2, "KVM [Master]: Write Input [Type = %u]", ntohs(((unsigned short*)buf)[0]));
- return len;
-#else
- int len2 = 0;
- int ptr = 0;
- //while ((len2 = kvm_server_inputdata(buf + ptr, len - ptr, kvm_relay_feeddata_ex, (void*[]) {writeHandler, reserved})) != 0) { ptr += len2; }
- while ((len2 = kvm_server_inputdata(buf + ptr, len - ptr, writeHandler, reserved)) != 0) { ptr += len2; }
- return ptr;
-#endif
}
// Set the KVM pause state
@@ -781,9 +786,12 @@ DWORD WINAPI kvm_server_mainloop(LPVOID parm)
void *reserved = ((void**)parm)[1];
#ifdef _WINSERVICE
- gKVMRemoteLogging = ILibRemoteLogging_Create(NULL);
- ILibRemoteLogging_SetRawForward(gKVMRemoteLogging, sizeof(KVMDebugLog), kvm_slave_OnRawForwardLog);
- ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM [SLAVE]: Child Processing Running...");
+ if (!kvmConsoleMode)
+ {
+ gKVMRemoteLogging = ILibRemoteLogging_Create(NULL);
+ ILibRemoteLogging_SetRawForward(gKVMRemoteLogging, sizeof(KVMDebugLog), kvm_slave_OnRawForwardLog);
+ ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM [SLAVE]: Child Processing Running...");
+ }
#endif
// This basic lock will prevent 2 thread from running at the same time. Gives time for the first one to fully exit.
@@ -798,27 +806,39 @@ DWORD WINAPI kvm_server_mainloop(LPVOID parm)
KVMDEBUG("kvm_server_mainloop / start1", (int)GetCurrentThreadId());
#ifdef _WINSERVICE
- hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
- hStdIn = GetStdHandle(STD_INPUT_HANDLE);
+ if (!kvmConsoleMode)
+ {
+ hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
+ hStdIn = GetStdHandle(STD_INPUT_HANDLE);
+ }
#endif
KVMDEBUG("kvm_server_mainloop / start2", (int)GetCurrentThreadId());
- if (!initialize_gdiplus())
- {
+ if (!initialize_gdiplus())
+ {
#ifdef _WINSERVICE
- ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM [SLAVE]: initialize_gdiplus() failed");
+ if (!kvmConsoleMode)
+ {
+ ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM [SLAVE]: initialize_gdiplus() failed");
+ }
#endif
- KVMDEBUG("kvm_server_mainloop / initialize_gdiplus failed", (int)GetCurrentThreadId()); return 0;
+ KVMDEBUG("kvm_server_mainloop / initialize_gdiplus failed", (int)GetCurrentThreadId()); return 0;
}
#ifdef _WINSERVICE
- ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM [SLAVE]: initialize_gdiplus() SUCCESS");
+ if (!kvmConsoleMode)
+ {
+ ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM [SLAVE]: initialize_gdiplus() SUCCESS");
+ }
#endif
kvm_server_SetResolution(writeHandler, reserved);
#ifdef _WINSERVICE
- g_shutdown = 0;
- kvmthread = CreateThread(NULL, 0, kvm_mainloopinput, parm, 0, 0);
+ if (!kvmConsoleMode)
+ {
+ g_shutdown = 0;
+ kvmthread = CreateThread(NULL, 0, kvm_mainloopinput, parm, 0, 0);
+ }
#endif
// Set all CRCs to 0xFF
@@ -864,7 +884,10 @@ DWORD WINAPI kvm_server_mainloop(LPVOID parm)
if (get_desktop_buffer(&desktop, &desktopsize) == 1)
{
#ifdef _WINSERVICE
- ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM [SLAVE]: get_desktop_buffer() failed");
+ if (!kvmConsoleMode)
+ {
+ ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM [SLAVE]: get_desktop_buffer() failed");
+ }
#endif
KVMDEBUG("get_desktop_buffer() failed, shutting down", (int)GetCurrentThreadId());
g_shutdown = 1;
@@ -979,32 +1002,22 @@ void kvm_relay_ExitHandler(ILibProcessPipe_Process sender, int exitCode, void* u
void kvm_relay_StdOutHandler(ILibProcessPipe_Process sender, char *buffer, int bufferLen, int* bytesConsumed, void* user)
{
- int ptr = 0;
unsigned short size = 0;
- unsigned short cmd = 0;
UNREFERENCED_PARAMETER(sender);
ILibKVM_WriteHandler writeHandler = (ILibKVM_WriteHandler)((void**)user)[0];
void *reserved = ((void**)user)[1];
- while (bufferLen - ptr > 4)
+ if (bufferLen > 4)
{
- //type = ntohs(((unsigned short*)(pchRequest + ptr))[0]);
- size = ntohs(((unsigned short*)(buffer + ptr))[1]);
- cmd = ntohs(((unsigned short*)(buffer + ptr))[0]);
- if ((ptr + size > bufferLen) || size == 0) break;
- ptr += size;
- }
-
- if (ptr > 0)
- {
- //ILibRemoteLogging_printf(ILibChainGetLogger(gILibChain), ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_2, "KVM Data: CMD: %d, Size = %d", cmd, size);
- writeHandler(buffer, ptr, reserved); // stream object will take care of flow control
- *bytesConsumed = ptr;
- }
- else
- {
- *bytesConsumed = 0;
+ size = ntohs(((unsigned short*)(buffer))[1]);
+ if (size <= bufferLen)
+ {
+ *bytesConsumed = size;
+ writeHandler(buffer, size, reserved);
+ return;
+ }
}
+ *bytesConsumed = 0;
}
void kvm_relay_StdErrHandler(ILibProcessPipe_Process sender, char *buffer, int bufferLen, int* bytesConsumed, void* user)
{
@@ -1055,24 +1068,31 @@ int kvm_relay_restart(int paused, void *pipeMgr, char *exePath, ILibKVM_WriteHan
// Setup the KVM session. Return 1 if ok, 0 if it could not be setup.
int kvm_relay_setup(char *exePath, void *processPipeMgr, ILibKVM_WriteHandler writeHandler, void *reserved)
{
+ if (processPipeMgr != NULL)
+ {
#ifdef _WINSERVICE
- // if (kvmthread != NULL || g_slavekvm != 0) { KVMDEBUG("kvm_relay_setup() session already exists", 0); return 0; }
- if (ThreadRunning == 1 && g_shutdown == 0) { KVMDEBUG("kvm_relay_setup() session already exists", 0); return 0; }
- g_restartcount = 0;
- gProcessSpawnType = ILibProcessPipe_SpawnTypes_USER;
- KVMDEBUG("kvm_relay_setup() session starting", 0);
- return kvm_relay_restart(1, processPipeMgr, exePath, writeHandler, reserved);
+ if (ThreadRunning == 1 && g_shutdown == 0) { KVMDEBUG("kvm_relay_setup() session already exists", 0); return 0; }
+ g_restartcount = 0;
+ gProcessSpawnType = ILibProcessPipe_SpawnTypes_USER;
+ KVMDEBUG("kvm_relay_setup() session starting", 0);
+ return kvm_relay_restart(1, processPipeMgr, exePath, writeHandler, reserved);
#else
- // if (kvmthread != NULL && g_shutdown == 0) return 0;
- void **parms = (void**)ILibMemory_Allocate((2 * sizeof(void*)) + sizeof(int), 0, NULL, NULL);
- parms[0] = writeHandler;
- parms[1] = reserved;
- ((int*)(&parms[2]))[0] = 1;
-
- if (ThreadRunning == 1 && g_shutdown == 0) { KVMDEBUG("kvm_relay_setup() session already exists", 0); free(parms); return 0; }
- kvmthread = CreateThread(NULL, 0, kvm_server_mainloop, (void*)parms, 0, 0);
- return 1;
+ return(0);
#endif
+ }
+ else
+ {
+ // if (kvmthread != NULL && g_shutdown == 0) return 0;
+ void **parms = (void**)ILibMemory_Allocate((2 * sizeof(void*)) + sizeof(int), 0, NULL, NULL);
+ parms[0] = writeHandler;
+ parms[1] = reserved;
+ ((int*)(&parms[2]))[0] = 1;
+ kvmConsoleMode = 1;
+
+ if (ThreadRunning == 1 && g_shutdown == 0) { KVMDEBUG("kvm_relay_setup() session already exists", 0); free(parms); return 0; }
+ kvmthread = CreateThread(NULL, 0, kvm_server_mainloop, (void*)parms, 0, 0);
+ return 1;
+ }
}
// Force a KVM reset & refresh
diff --git a/meshcore/KVM/Windows/kvm.h b/meshcore/KVM/Windows/kvm.h
index 1ed0ea2..5685227 100644
--- a/meshcore/KVM/Windows/kvm.h
+++ b/meshcore/KVM/Windows/kvm.h
@@ -1,11 +1,11 @@
/*
-Copyright 2006 - 2015 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/meshcore/KVM/Windows/tile.cpp b/meshcore/KVM/Windows/tile.cpp
index 749afb1..ce4fce0 100644
--- a/meshcore/KVM/Windows/tile.cpp
+++ b/meshcore/KVM/Windows/tile.cpp
@@ -1,11 +1,11 @@
/*
-Copyright 2006 - 2015 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/meshcore/KVM/Windows/tile.h b/meshcore/KVM/Windows/tile.h
index c491aaa..4eb352d 100644
--- a/meshcore/KVM/Windows/tile.h
+++ b/meshcore/KVM/Windows/tile.h
@@ -1,11 +1,11 @@
/*
-Copyright 2006 - 2015 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/meshcore/agentcore.c b/meshcore/agentcore.c
index 9c3bce6..659117f 100644
--- a/meshcore/agentcore.c
+++ b/meshcore/agentcore.c
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -68,12 +68,12 @@ limitations under the License.
#define MESH_MCASTv4_GROUP "239.255.255.235"
#define MESH_MCASTv6_GROUP "FF02:0:0:0:0:0:0:FE"
+char exeMeshPolicyGuid[] = { 0xB9, 0x96, 0x01, 0x58, 0x80, 0x54, 0x4A, 0x19, 0xB7, 0xF7, 0xE9, 0xBE, 0x44, 0x91, 0x4C, 0x19 };
#define MESH_SCRIPTCONTAINER_ID "\xFF_ScriptContainer_ID"
#define MESH_AGENT_SINGLETON "\xFF_MeshAgentObject_Singleton"
#define SEQ_TABLE_KEY "\xFF_seqTable"
#define CONTAINER_PTR "\xFF_ptr"
#define MESH_AGENT_PTR "\xFFMeshAgentPtr"
-#define MESH_AGENT_DUKPTRS "\xFFptrs"
#define CTX_PTR "\xFF_Heap"
#define CONTEXT_GUID_PTR "_CONTEXT_GUID_PTR"
#define REMOTE_DESKTOP_STREAM "\xFF_RemoteDesktopStream"
@@ -521,85 +521,28 @@ void IPAddressMonitor(void *data)
Begin Mesh Agent Duktape Abstraction
--------------------------------*/
-MeshAgentDuktapePtrs* ILibDuktape_MeshAgent_GetMeshAgentPtrs(duk_context *ctx)
-{
- MeshAgentDuktapePtrs *ptrs = NULL;
- MeshAgentHostContainer *agent = NULL;
-
- duk_push_this(ctx); // [MeshAgent]
- if (duk_has_prop_string(ctx, -1, MESH_AGENT_DUKPTRS))
- {
- // We already created a binding earlier
- duk_get_prop_string(ctx, -1, MESH_AGENT_DUKPTRS); // [MeshAgent][ptrs]
- ptrs = (MeshAgentDuktapePtrs*)Duktape_GetBuffer(ctx, -1, NULL);
- duk_pop(ctx); // [MeshAgent]
- }
- else
- {
- // Create a new binding
- duk_push_fixed_buffer(ctx, sizeof(MeshAgentDuktapePtrs)); // [MeshAgent][buffer]
- ptrs = (MeshAgentDuktapePtrs*)Duktape_GetBuffer(ctx, -1, NULL);
- duk_put_prop_string(ctx, -2, MESH_AGENT_DUKPTRS); // [MeshAgent]
-
- memset(ptrs, 0, sizeof(MeshAgentDuktapePtrs));
- ptrs->ctx = ctx;
- ptrs->MeshAgentObject = duk_get_heapptr(ctx, -1);
-
- duk_get_prop_string(ctx, -1, MESH_AGENT_PTR); // [MeshAgent][Host]
- agent = (MeshAgentHostContainer*)duk_get_pointer(ctx, -1);
- duk_pop(ctx); // [MeshAgent]
- ptrs->Next = agent->DuktapeMeshBindings;
- agent->DuktapeMeshBindings = ptrs;
- }
- duk_pop(ctx); // ...
- return ptrs;
-}
duk_ret_t ILibDuktape_MeshAgent_AddCommandHandler(duk_context *ctx)
{
- MeshAgentDuktapePtrs *ptrs;
- void *OnCommand = duk_require_heapptr(ctx, 0);
-
- ptrs = ILibDuktape_MeshAgent_GetMeshAgentPtrs(ctx);
- ptrs->OnCommand = OnCommand;
+ duk_push_this(ctx); // [agent]
+ duk_get_prop_string(ctx, -1, "on"); // [agent][on]
+ duk_swap_top(ctx, -2); // [on][this]
+ duk_push_string(ctx, "Command"); // [on][this][Command]
+ duk_dup(ctx, 0); // [on][this][Command][listener]
+ duk_call_method(ctx, 2);
return 0;
}
duk_ret_t ILibDuktape_MeshAgent_AddConnectHandler(duk_context *ctx)
{
- MeshAgentDuktapePtrs *ptrs;
- void *OnConnect = duk_require_heapptr(ctx, 0);
-
- ptrs = ILibDuktape_MeshAgent_GetMeshAgentPtrs(ctx);
- ptrs->OnConnect = OnConnect;
+ duk_push_this(ctx); // [agent]
+ duk_get_prop_string(ctx, -1, "on"); // [agent][on]
+ duk_swap_top(ctx, -2); // [on][this]
+ duk_push_string(ctx, "Connected"); // [on][this][connected]
+ duk_dup(ctx, 0); // [on][this][connected][listener]
+ duk_call_method(ctx, 2);
return 0;
}
duk_ret_t ILibDuktape_MeshAgent_Finalizer(duk_context *ctx)
{
- MeshAgentDuktapePtrs *ptrs = NULL, *binding = NULL;
- MeshAgentHostContainer *agent = NULL;
-
- duk_dup(ctx, 0); // [MeshAgent]
- duk_get_prop_string(ctx, -1, MESH_AGENT_PTR); // [MeshAgent][MeshAgentPtr]
- agent = (MeshAgentHostContainer*)duk_get_pointer(ctx, -1);
-
- if (duk_has_prop_string(ctx, -2, MESH_AGENT_DUKPTRS))
- {
- duk_get_prop_string(ctx, -2, MESH_AGENT_DUKPTRS); // [MeshAgent][MeshAgentPtr][ptrs]
- ptrs = (MeshAgentDuktapePtrs*)Duktape_GetBuffer(ctx, -1, NULL);
-
- if (agent->DuktapeMeshBindings == ptrs)
- {
- agent->DuktapeMeshBindings = ptrs->Next;
- }
- else
- {
- binding = agent->DuktapeMeshBindings;
- while (binding->Next != NULL)
- {
- if (binding->Next == ptrs) { binding->Next = ptrs->Next; break; }
- binding = binding->Next;
- }
- }
- }
return 0;
}
@@ -735,7 +678,6 @@ void ILibDuktape_MeshAgent_RemoteDesktop_EndSink(ILibDuktape_DuplexStream *strea
duk_push_heapptr(ptrs->ctx, ptrs->MeshAgentObject); // [MeshAgent]
duk_del_prop_string(ptrs->ctx, -1, REMOTE_DESKTOP_STREAM);
duk_pop(ptrs->ctx); // ...
-
memset(ptrs, 0, sizeof(RemoteDesktop_Ptrs));
}
kvm_cleanup();
@@ -745,7 +687,7 @@ void ILibDuktape_MeshAgent_RemoteDesktop_PauseSink(ILibDuktape_DuplexStream *sen
{
//printf("KVM/PAUSE\n");
#ifdef _POSIX
- ILibProcessPipe_Pipe_Pause(((RemoteDesktop_Ptrs*)user)->kvmPipe);
+ if (((RemoteDesktop_Ptrs*)user)->kvmPipe != NULL) { ILibProcessPipe_Pipe_Pause(((RemoteDesktop_Ptrs*)user)->kvmPipe); }
#else
kvm_pause(1);
#endif
@@ -755,7 +697,7 @@ void ILibDuktape_MeshAgent_RemoteDesktop_ResumeSink(ILibDuktape_DuplexStream *se
//printf("KVM/RESUME\n");
#ifdef _POSIX
- ILibProcessPipe_Pipe_Resume(((RemoteDesktop_Ptrs*)user)->kvmPipe);
+ if (((RemoteDesktop_Ptrs*)user)->kvmPipe != NULL) { ILibProcessPipe_Pipe_Resume(((RemoteDesktop_Ptrs*)user)->kvmPipe); }
#else
kvm_pause(0);
#endif
@@ -838,7 +780,11 @@ duk_ret_t ILibDuktape_MeshAgent_getRemoteDesktop(duk_context *ctx)
// Setup Remote Desktop
#ifdef WIN32
- kvm_relay_setup(agent->exePath, agent->pipeManager, ILibDuktape_MeshAgent_RemoteDesktop_KVM_WriteSink, ptrs);
+ #ifdef _WINSERVICE
+ kvm_relay_setup(agent->exePath, agent->runningAsConsole ? NULL : agent->pipeManager, ILibDuktape_MeshAgent_RemoteDesktop_KVM_WriteSink, ptrs);
+ #else
+ kvm_relay_setup(agent->exePath, NULL, ILibDuktape_MeshAgent_RemoteDesktop_KVM_WriteSink, ptrs);
+ #endif
#else
ptrs->kvmPipe = kvm_relay_setup(agent->pipeManager, ILibDuktape_MeshAgent_RemoteDesktop_KVM_WriteSink, ptrs);
#endif
@@ -933,18 +879,55 @@ duk_ret_t ILibDuktape_MeshAgent_isControlChannelConnected(duk_context *ctx)
duk_ret_t ILibDuktape_MeshAgent_eval(duk_context *ctx)
{
duk_size_t evalStrLen;
- char *evalStr = duk_get_lstring(ctx, 0, &evalStrLen);
+ char *evalStr = (char*)duk_get_lstring(ctx, 0, &evalStrLen);
printf("eval(): %s\n", evalStr);
duk_eval_string(ctx, evalStr);
return(1);
}
+duk_context* ScriptEngine_Stop(MeshAgentHostContainer *agent, char *contextGUID);
+
+void ILibDuktape_MeshAgent_dumpCoreModuleEx(void *chain, void *user)
+{
+ MeshAgentHostContainer* agentHost = (MeshAgentHostContainer*)user;
+ char *CoreModule;
+
+ ScriptEngine_Stop((MeshAgentHostContainer*)user, MeshAgent_JavaCore_ContextGuid);
+ printf("CoreModule was manually dumped, restarting!\n");
+
+ int CoreModuleLen = ILibSimpleDataStore_Get(agentHost->masterDb, "CoreModule", NULL, 0);
+ if (CoreModuleLen > 0)
+ {
+ // There is a core module, launch it now.
+ CoreModule = (char*)ILibMemory_Allocate(CoreModuleLen, 0, NULL, NULL);
+ ILibSimpleDataStore_Get(agentHost->masterDb, "CoreModule", CoreModule, CoreModuleLen);
+
+ if (ILibDuktape_ScriptContainer_CompileJavaScript(agentHost->meshCoreCtx, CoreModule + 4, CoreModuleLen - 4) != 0 ||
+ ILibDuktape_ScriptContainer_ExecuteByteCode(agentHost->meshCoreCtx) != 0)
+ {
+ ILibRemoteLogging_printf(ILibChainGetLogger(agentHost->chain), ILibRemoteLogging_Modules_Microstack_Generic | ILibRemoteLogging_Modules_ConsolePrint,
+ ILibRemoteLogging_Flags_VerbosityLevel_1, "Error Executing MeshCore: %s", duk_safe_to_string(agentHost->meshCoreCtx, -1));
+ duk_pop(agentHost->meshCoreCtx);
+ }
+ free(CoreModule);
+ }
+ agentHost->localScript = 1;
+}
+duk_ret_t ILibDuktape_MeshAgent_dumpCoreModule(duk_context *ctx)
+{
+ duk_push_this(ctx); // [agent]
+ duk_get_prop_string(ctx, -1, MESH_AGENT_PTR); // [agent][ptr]
+ MeshAgentHostContainer *agent = (MeshAgentHostContainer*)duk_get_pointer(ctx, -1);
+
+ agent->localScript = 0;
+ ILibChain_RunOnMicrostackThreadEx(agent->chain, ILibDuktape_MeshAgent_dumpCoreModuleEx, agent);
+ return(0);
+}
void ILibDuktape_MeshAgent_PUSH(duk_context *ctx, void *chain)
{
MeshAgentHostContainer *agent;
ILibDuktape_EventEmitter *emitter;
-
duk_push_heap_stash(ctx); // [stash]
if (duk_has_prop_string(ctx, -1, MESH_AGENT_SINGLETON))
{
@@ -959,6 +942,7 @@ void ILibDuktape_MeshAgent_PUSH(duk_context *ctx, void *chain)
duk_pop_2(ctx); // ...
duk_push_object(ctx); // [MeshAgent]
+ ILibDuktape_WriteID(ctx, "MeshAgent");
duk_push_pointer(ctx, agent); // [MeshAgent][ptr]
duk_put_prop_string(ctx, -2, MESH_AGENT_PTR); // [MeshAgent]
@@ -979,18 +963,10 @@ void ILibDuktape_MeshAgent_PUSH(duk_context *ctx, void *chain)
duk_push_pointer(ctx, &agent->selfcert);
duk_put_prop_string(ctx, -2, ILibDuktape_MeshAgent_Cert_NonLeaf);
#endif
- duk_push_fixed_buffer(ctx, sizeof(MeshAgentDuktapePtrs)); // [MeshAgent][buffer]
- MeshAgentDuktapePtrs *ptrs = (MeshAgentDuktapePtrs*)Duktape_GetBuffer(ctx, -1, NULL);
- duk_put_prop_string(ctx, -2, MESH_AGENT_DUKPTRS); // [MeshAgent]
- memset(ptrs, 0, sizeof(MeshAgentDuktapePtrs));
- ptrs->ctx = ctx;
- ptrs->MeshAgentObject = duk_get_heapptr(ctx, -1);
- ptrs->Next = agent->DuktapeMeshBindings;
- agent->DuktapeMeshBindings = ptrs;
-
- ILibDuktape_EventEmitter_CreateEvent(emitter, "Ready", &(ptrs->OnReady));
- ILibDuktape_EventEmitter_CreateEvent(emitter, "Connected", &(ptrs->OnConnect));
+ ILibDuktape_EventEmitter_CreateEventEx(emitter, "Ready");
+ ILibDuktape_EventEmitter_CreateEventEx(emitter, "Connected");
+ ILibDuktape_EventEmitter_CreateEventEx(emitter, "Command");
ILibDuktape_CreateEventWithGetter(ctx, "isControlChannelConnected", ILibDuktape_MeshAgent_isControlChannelConnected);
ILibDuktape_EventEmitter_AddHook(emitter, "Ready", ILibDuktape_MeshAgent_Ready);
@@ -1002,6 +978,7 @@ void ILibDuktape_MeshAgent_PUSH(duk_context *ctx, void *chain)
ILibDuktape_CreateInstanceMethod(ctx, "SendCommand", ILibDuktape_MeshAgent_SendCommand, 1);
ILibDuktape_CreateFinalizer(ctx, ILibDuktape_MeshAgent_Finalizer);
ILibDuktape_CreateReadonlyProperty_int(ctx, "activeMicroLMS", (agent->microLMS != NULL ? 1 : 0));
+ ILibDuktape_CreateInstanceMethod(ctx, "restartCore", ILibDuktape_MeshAgent_dumpCoreModule, 0);
#ifdef _LINKVM
ILibDuktape_CreateReadonlyProperty_int(ctx, "hasKVM", 1);
ILibDuktape_EventEmitter_CreateEventEx(emitter, "kvmConnected");
@@ -1264,7 +1241,7 @@ duk_context* ScriptEngine_Stop(MeshAgentHostContainer *agent, char *contextGUID)
ILibDuktape_MeshAgent_Init(newCtx, agent->chain, agent);
ILibDuktape_SetNativeUncaughtExceptionHandler(newCtx, settings->nExeptionHandler, settings->nExceptionUserObject);
-
+ if (g_displayFinalizerMessages) { printf("\n\n==> Stopping JavaScript Engine\n"); }
duk_destroy_heap(oldCtx);
agent->meshCoreCtx = newCtx;
if (agent->proxyServer != NULL)
@@ -1314,10 +1291,131 @@ void MeshServer_OnSendOK(ILibWebClient_StateObject sender, void *user1, void *us
// TODO: Inform JavaScript core module that we are in underflow situation
}
+
+int GenerateSHA384FileHash(char *filePath, char *fileHash)
+{
+ FILE *tmpFile = NULL;
+ unsigned int endIndex = 0;
+ unsigned int bytesLeft = 0;
+ size_t bytesRead;
+ unsigned int checkSumIndex = 0;
+ unsigned int tableIndex = 0;
+
+#ifdef WIN32
+ int retVal = 1;
+ fopen_s(&tmpFile, filePath, "rb");
+#else
+ tmpFile = fopen(filePath, "rb");
+#endif
+ if (tmpFile == NULL) { return(1); }
+
+#ifdef WIN32
+ // We need to check if this is a signed binary
+ // Read the PE Headers, to determine where to look for the Embedded JS
+ char *optHeader = NULL;
+ unsigned int NTHeaderIndex = 0;
+ fseek(tmpFile, 0, SEEK_SET);
+ ignore_result(fread(ILibScratchPad, 1, 2, tmpFile));
+ if (ntohs(((unsigned int*)ILibScratchPad)[0]) == 19802) // 5A4D
+ {
+ fseek(tmpFile, 60, SEEK_SET);
+ ignore_result(fread((void*)&NTHeaderIndex, 1, 4, tmpFile));
+ fseek(tmpFile, NTHeaderIndex, SEEK_SET); // NT HEADER
+ checkSumIndex = NTHeaderIndex + 24 + 64;
+
+ ignore_result(fread(ILibScratchPad, 1, 24, tmpFile));
+ if (((unsigned int*)ILibScratchPad)[0] == 17744)
+ {
+ // PE Image
+ optHeader = ILibMemory_AllocateA(((unsigned short*)ILibScratchPad)[10]);
+ ignore_result(fread(optHeader, 1, ILibMemory_AllocateA_Size(optHeader), tmpFile));
+ switch (((unsigned short*)optHeader)[0])
+ {
+ case 0x10B:
+ if (((unsigned int*)(optHeader + 128))[0] != 0)
+ {
+ endIndex = ((unsigned int*)(optHeader + 128))[0];
+ }
+ tableIndex = NTHeaderIndex + 24 + 128;
+ retVal = 0;
+ break;
+ case 0x20B:
+ if (((unsigned int*)(optHeader + 144))[0] != 0)
+ {
+ endIndex = ((unsigned int*)(optHeader + 144))[0];
+ }
+ tableIndex = NTHeaderIndex + 24 + 144;
+ retVal = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ if (retVal != 0)
+ {
+ fclose(tmpFile);
+ return(1);
+ }
+#endif
+
+ if (endIndex == 0)
+ {
+ // We just need to check for Embedded MSH file
+ int mshLen = 0;
+ fseek(tmpFile, -16, SEEK_END);
+ ignore_result(fread(ILibScratchPad, 1, 16, tmpFile));
+ if (memcmp(ILibScratchPad, exeMeshPolicyGuid, 16) == 0)
+ {
+ fseek(tmpFile, -20, SEEK_CUR);
+ ignore_result(fread((void*)&mshLen, 1, 4, tmpFile));
+ mshLen = ntohl(mshLen);
+ endIndex = (unsigned int)ftell(tmpFile) - 4 - mshLen;
+ }
+ else
+ {
+ endIndex = (unsigned int)ftell(tmpFile);
+ }
+ }
+
+ SHA512_CTX ctx;
+ SHA384_Init(&ctx);
+ bytesLeft = endIndex;
+ fseek(tmpFile, 0, SEEK_SET);
+ if (checkSumIndex != 0)
+ {
+ bytesRead = fread(ILibScratchPad, 1, checkSumIndex + 4, tmpFile);
+ ((unsigned int*)(ILibScratchPad + checkSumIndex))[0] = 0;
+ SHA384_Update(&ctx, ILibScratchPad, bytesRead);
+ if (endIndex > 0) { bytesLeft -= (unsigned int)bytesRead; }
+
+ bytesRead = fread(ILibScratchPad, 1, tableIndex + 8 - (checkSumIndex + 4), tmpFile);
+ ((unsigned int*)(ILibScratchPad + bytesRead - 8))[0] = 0;
+ ((unsigned int*)(ILibScratchPad + bytesRead - 8))[1] = 0;
+ SHA384_Update(&ctx, ILibScratchPad, bytesRead);
+ if (endIndex > 0) { bytesLeft -= (unsigned int)bytesRead; }
+ }
+
+ while ((bytesRead = fread(ILibScratchPad, 1, endIndex == 0 ? sizeof(ILibScratchPad) : (bytesLeft > sizeof(ILibScratchPad) ? sizeof(ILibScratchPad) : bytesLeft), tmpFile)) > 0)
+ {
+ SHA384_Update(&ctx, ILibScratchPad, bytesRead);
+ if (endIndex > 0)
+ {
+ bytesLeft -= (unsigned int)bytesRead;
+ if (bytesLeft == 0) { break; }
+ }
+ }
+ SHA384_Final((unsigned char*)fileHash, &ctx);
+ fclose(tmpFile);
+
+ return(0);
+}
+
+
+
// Called when the connection of the mesh server is fully authenticated
void MeshServer_ServerAuthenticated(ILibWebClient_StateObject WebStateObject, MeshAgentHostContainer *agent) {
int len = 0;
- MeshAgentDuktapePtrs *meshBindings;
// Send the mesh agent tag to the server
// We send the tag information independently of the meshcore because we could use this to select what meshcore to use on the server.
@@ -1327,20 +1425,15 @@ void MeshServer_ServerAuthenticated(ILibWebClient_StateObject WebStateObject, Me
// Inform JavaScript core module of the connection
// TODO: Verify with Bryan that only the core module will get this. No other modules should.
- if (agent->serverAuthState == 3) {
- meshBindings = agent->DuktapeMeshBindings;
- while (meshBindings != NULL)
- {
- if (meshBindings->OnConnect != NULL)
- {
- duk_push_heapptr(meshBindings->ctx, meshBindings->OnConnect);
- duk_push_heapptr(meshBindings->ctx, meshBindings->MeshAgentObject);
- duk_push_int(meshBindings->ctx, 1); // Argument 1 here indicates connection
- if (duk_pcall_method(meshBindings->ctx, 1) != 0) { ILibDuktape_Process_UncaughtException(meshBindings->ctx); }
- duk_pop(meshBindings->ctx);
- }
- meshBindings = meshBindings->Next;
- }
+ if (agent->serverAuthState == 3)
+ {
+ ILibDuktape_MeshAgent_PUSH(agent->meshCoreCtx, agent->chain); // [agent]
+ duk_get_prop_string(agent->meshCoreCtx, -1, "emit"); // [agent][emit]
+ duk_swap_top(agent->meshCoreCtx, -2); // [emit][this]
+ duk_push_string(agent->meshCoreCtx, "Connected"); // [emit][this][Connected]
+ duk_push_int(agent->meshCoreCtx, 1); // [emit][this][Connected][1]
+ if (duk_pcall_method(agent->meshCoreCtx, 2) != 0) { ILibDuktape_Process_UncaughtException(agent->meshCoreCtx); }
+ duk_pop(agent->meshCoreCtx); // ...
}
}
@@ -1349,7 +1442,6 @@ void MeshServer_ProcessCommand(ILibWebClient_StateObject WebStateObject, MeshAge
{
unsigned short command = ntohs(((unsigned short*)cmd)[0]);
unsigned short requestid;
- MeshAgentDuktapePtrs *meshBindings;
#ifndef MICROSTACK_NOTLS
// If we are not authenticated with the mesh server, we only support auth commands.
@@ -1501,49 +1593,41 @@ void MeshServer_ProcessCommand(ILibWebClient_StateObject WebStateObject, MeshAge
// TODO: Verify with Bryan that only the core module will get this. No other modules should.
if (cmd[0] == '{' || command >= 1000)
{
- int processed = 0;
+ int popCount = 0;
// if (cmd[0] == '{') { cmd[cmdLen] = 0; printf("%s\r\n", cmd); } // DEBUG: Print JSON command
- meshBindings = agent->DuktapeMeshBindings;
- while (processed == 0 && meshBindings != NULL)
- {
- if (meshBindings->OnCommand != NULL)
- {
- duk_push_heapptr(meshBindings->ctx, meshBindings->OnCommand); // [func]
- duk_push_heapptr(meshBindings->ctx, meshBindings->MeshAgentObject); // [func][this]
- if (cmd[0] == '{')
- {
- // JSON
- duk_push_global_object(meshBindings->ctx); // [g]
- duk_get_prop_string(meshBindings->ctx, -1, "JSON"); // [g][JSON]
- duk_get_prop_string(meshBindings->ctx, -1, "parse"); // [g][JSON][func]
- duk_swap_top(meshBindings->ctx, -3); // [func][JSON][g]
- duk_pop_2(meshBindings->ctx); // [func]
- duk_push_lstring(meshBindings->ctx, cmd, cmdLen); // [func][str]
- if (duk_pcall(meshBindings->ctx, 1) != 0)
- {
- duk_pop(meshBindings->ctx);
- duk_push_lstring(meshBindings->ctx, cmd, cmdLen);
- }
- }
- else
- {
- // BINARY
- duk_push_external_buffer(meshBindings->ctx); // [func][this][buffer]
- duk_config_buffer(meshBindings->ctx, -1, cmd, cmdLen);
- }
- if (duk_pcall_method(meshBindings->ctx, 1) == 0) // [retVal]
- {
- if (duk_is_number(meshBindings->ctx, -1)) { processed = duk_get_int(meshBindings->ctx, -1); } // Get the return value
- }
- else
- {
- ILibDuktape_Process_UncaughtException(meshBindings->ctx);
- }
- duk_pop(meshBindings->ctx); // ...
+ ILibDuktape_MeshAgent_PUSH(agent->meshCoreCtx, agent->chain); // [agent]
+ duk_get_prop_string(agent->meshCoreCtx, -1, "emit"); // [agent][emit]
+ duk_swap_top(agent->meshCoreCtx, -2); // [emit][this]
+ duk_push_string(agent->meshCoreCtx, "Command"); // [emit][this][Command]
+ if (cmd[0] == '{')
+ {
+ // JSON
+ duk_push_global_object(agent->meshCoreCtx); // [emit][this][Command][g]
+ duk_get_prop_string(agent->meshCoreCtx, -1, "JSON"); // [emit][this][Command][g][JSON]
+ duk_get_prop_string(agent->meshCoreCtx, -1, "parse"); // [emit][this][Command][g][JSON][func]
+ duk_swap_top(agent->meshCoreCtx, -3); // [emit][this][Command][func][JSON][g]
+ duk_pop_2(agent->meshCoreCtx); // [emit][this][Command][func]
+ duk_push_lstring(agent->meshCoreCtx, cmd, cmdLen); // [emit][this][Command][func][str]
+ if (duk_pcall(agent->meshCoreCtx, 1) != 0) // [emit][this][Command][JSON]
+ {
+ duk_pop(agent->meshCoreCtx); // [emit][this][Command]
+ duk_push_lstring(agent->meshCoreCtx, cmd, cmdLen); // [emit][this][Command][str]
}
- meshBindings = meshBindings->Next;
+ popCount = 1;
}
+ else
+ {
+ // BINARY
+ duk_push_external_buffer(agent->meshCoreCtx); // [emit][this][Command][extBuffer]
+ duk_insert(agent->meshCoreCtx, -4); // [extBuffer][emit][this][Command]
+ duk_config_buffer(agent->meshCoreCtx, -4, cmd, cmdLen);
+ duk_push_buffer_object(agent->meshCoreCtx, -4, 0, cmdLen, DUK_BUFOBJ_NODEJS_BUFFER);// [extBuffer][emit][this][Command][buffer]
+ popCount = 2;
+ }
+
+ if (duk_pcall_method(agent->meshCoreCtx, 2) != 0) { ILibDuktape_Process_UncaughtException(agent->meshCoreCtx); }
+ duk_pop_n(agent->meshCoreCtx, popCount); // ...
return;
}
@@ -1685,16 +1769,19 @@ void MeshServer_ProcessCommand(ILibWebClient_StateObject WebStateObject, MeshAge
{
// Indicates the end of the agent update transfer
// Check the SHA384 hash of the received file against the file we got.
- if ((util_sha384file(updateFilePath, updateFileHash) == 0) && (memcmp(updateFileHash, cm->coreModuleHash, sizeof(cm->coreModuleHash)) == 0))
+ if ((GenerateSHA384FileHash(updateFilePath, updateFileHash) == 0) && (memcmp(updateFileHash, cm->coreModuleHash, sizeof(cm->coreModuleHash)) == 0))
{
- printf("UPDATE: End OK\r\n");
- // Check the file signature & version number
- //if (signcheck_verifysign(updateFilePath, 1))
- {
- // Everything looks good, lets perform the update
- agent->performSelfUpdate = 1;
- ILibStopChain(agent->chain);
- }
+ //printf("UPDATE: End OK\r\n");
+#ifdef WIN32
+ agent->performSelfUpdate = 1;
+#else
+ // Set performSelfUpdate to the startupType, on Linux is this important: 1 = systemd, 2 = upstart, 3 = sysv-init
+ int len = ILibSimpleDataStore_Get(agent->masterDb, "StartupType", ILibScratchPad, sizeof(ILibScratchPad));
+ if (len > 0) { agent->performSelfUpdate = atoi(ILibScratchPad); }
+ if (agent->performSelfUpdate == 0) { agent->performSelfUpdate = 999; } // Never allow this value to be zero.
+#endif
+ // Everything looks good, lets perform the update
+ ILibStopChain(agent->chain);
} else {
// Hash check failed, delete the file and do nothing. On next server reconnect, we will try again.
util_deletefile(updateFilePath);
@@ -1816,18 +1903,15 @@ void MeshServer_OnResponse(ILibWebClient_StateObject WebStateObject, int Interru
if (agent->serverAuthState == 3)
#endif
{
- MeshAgentDuktapePtrs *meshBindings = agent->DuktapeMeshBindings;
- while (meshBindings != NULL)
+ if (agent->meshCoreCtx != NULL)
{
- if (meshBindings->OnConnect != NULL)
- {
- duk_push_heapptr(meshBindings->ctx, meshBindings->OnConnect);
- duk_push_heapptr(meshBindings->ctx, meshBindings->MeshAgentObject);
- duk_push_int(meshBindings->ctx, 0); // 0 here as second parameter indicates disconnection
- if (duk_pcall_method(meshBindings->ctx, 1) != 0) { ILibDuktape_Process_UncaughtException(meshBindings->ctx); }
- duk_pop(meshBindings->ctx);
- }
- meshBindings = meshBindings->Next;
+ ILibDuktape_MeshAgent_PUSH(agent->meshCoreCtx, agent->chain); // [agent]
+ duk_get_prop_string(agent->meshCoreCtx, -1, "emit"); // [agent][emit]
+ duk_swap_top(agent->meshCoreCtx, -2); // [emit][this]
+ duk_push_string(agent->meshCoreCtx, "Connected"); // [emit][this][Connected]
+ duk_push_int(agent->meshCoreCtx, 0); // [emit][this][Connected][0] (0 means disconnected)
+ if (duk_pcall_method(agent->meshCoreCtx, 2) != 0) { ILibDuktape_Process_UncaughtException(agent->meshCoreCtx); }
+ duk_pop(agent->meshCoreCtx);
}
}
agent->controlChannel = NULL; // Set the agent MeshCentral server control channel
@@ -2094,7 +2178,50 @@ int ValidateMeshServer(ILibWebClient_RequestToken sender, int preverify_ok, STAC
}
#endif
-void importSettings(MeshAgentHostContainer *agent, char* fileName)
+
+void checkForEmbeddedMSH(MeshAgentHostContainer *agent)
+{
+ FILE *tmpFile = NULL;
+ int mshLen;
+
+#ifdef WIN32
+ fopen_s(&tmpFile, agent->exePath, "rb");
+#else
+ tmpFile = fopen(agent->exePath, "rb");
+#endif
+ if (tmpFile == NULL) { return; }
+
+ fseek(tmpFile, -16, SEEK_END);
+ ignore_result(fread(ILibScratchPad, 1, 16, tmpFile));
+ if (memcmp(ILibScratchPad, exeMeshPolicyGuid, 16) == 0)
+ {
+ // Found Embedded MSH File
+ fseek(tmpFile, -20, SEEK_CUR);
+ if (fread((void*)&mshLen, 1, 4, tmpFile) == 4)
+ {
+ mshLen = ntohl(mshLen);
+ fseek(tmpFile, -4 - mshLen, SEEK_CUR);
+ char *eMSH = ILibMemory_AllocateA(mshLen);
+ if (fread(eMSH, 1, mshLen, tmpFile) == mshLen)
+ {
+ FILE *msh = NULL;
+#ifdef WIN32
+ fopen_s(&msh, MeshAgent_MakeAbsolutePath(agent->exePath, ".msh"), "wb");
+#else
+ msh = fopen(MeshAgent_MakeAbsolutePath(agent->exePath, ".msh"), "wb");
+#endif
+ if (msh != NULL)
+ {
+ fwrite(eMSH, 1, mshLen, msh);
+ fclose(msh);
+ }
+ }
+
+ }
+ }
+ fclose(tmpFile);
+}
+int importSettings(MeshAgentHostContainer *agent, char* fileName)
{
int eq;
char* importFile;
@@ -2103,7 +2230,7 @@ void importSettings(MeshAgentHostContainer *agent, char* fileName)
parser_result_field *f;
importFileLen = ILibReadFileFromDiskEx(&importFile, fileName);
- if (importFileLen == 0) { return; }
+ if (importFileLen == 0) { return(0); }
//printf("Importing settings file: %s\n", fileName);
pr = ILibParseString(importFile, 0, importFileLen, "\n", 1);
@@ -2152,6 +2279,8 @@ void importSettings(MeshAgentHostContainer *agent, char* fileName)
}
ILibDestructParserResults(pr);
free(importFile);
+
+ return(importFileLen);
}
void agentDumpKeysSink(ILibSimpleDataStore sender, char* Key, int KeyLen, void *user)
@@ -2207,7 +2336,12 @@ void MeshAgent_Slave(MeshAgentHostContainer *agentHost)
void MeshAgent_ChainEnd(void *chain, void *user)
{
MeshAgentHostContainer *agent = (MeshAgentHostContainer*)user;
- if (agent->meshCoreCtx != NULL) { duk_destroy_heap(agent->meshCoreCtx); }
+ if (agent->meshCoreCtx != NULL)
+ {
+ if (g_displayFinalizerMessages) { printf("\n\n==> Stopping JavaScript Engine\n"); }
+ duk_destroy_heap(agent->meshCoreCtx);
+ }
+ agent->meshCoreCtx = NULL;
}
void MeshAgent_RunScriptOnly_Finalizer(duk_context *ctx, void *user)
@@ -2338,14 +2472,26 @@ int MeshAgent_AgentMode(MeshAgentHostContainer *agentHost, int paramLen, char **
// Read the .proxy file if present and push it into the database
{
- char* str = NULL;
- int len = (int)util_readfile(MeshAgent_MakeAbsolutePath(agentHost->exePath, ".proxy"), &str, 1024);
- if (str != NULL) { ILibSimpleDataStore_PutEx(agentHost->masterDb, "WebProxy", 8, str, len); free(str); } else { ILibSimpleDataStore_DeleteEx(agentHost->masterDb, "WebProxy", 8); }
+ char tmp[255];
+ if (ILibSimpleDataStore_GetEx(agentHost->masterDb, "ignoreProxyFile", 15, tmp, sizeof(tmp)) == 0)
+ {
+ char* str = NULL;
+ int len = (int)util_readfile(MeshAgent_MakeAbsolutePath(agentHost->exePath, ".proxy"), &str, 1024);
+ if (str != NULL) { ILibSimpleDataStore_PutEx(agentHost->masterDb, "WebProxy", 8, str, len); free(str); }
+ else { ILibSimpleDataStore_DeleteEx(agentHost->masterDb, "WebProxy", 8); }
+ }
}
// Check to see if we need to import a settings file
- importSettings(agentHost, MeshAgent_MakeAbsolutePath(agentHost->exePath, ".mshx"));
- importSettings(agentHost, MeshAgent_MakeAbsolutePath(agentHost->exePath, ".msh"));
+ if (importSettings(agentHost, MeshAgent_MakeAbsolutePath(agentHost->exePath, ".mshx")) == 0)
+ {
+ if (importSettings(agentHost, MeshAgent_MakeAbsolutePath(agentHost->exePath, ".msh")) == 0)
+ {
+ // Let's check to see if an .msh was embedded into our binary
+ checkForEmbeddedMSH(agentHost);
+ importSettings(agentHost, MeshAgent_MakeAbsolutePath(agentHost->exePath, ".msh"));
+ }
+ }
#ifdef WIN32
// If running as a Windows service, set basic values to the registry, this allows other applications to know what the mesh agent is doing.
@@ -2495,18 +2641,15 @@ int MeshAgent_AgentMode(MeshAgentHostContainer *agentHost, int paramLen, char **
// Check if there is a CoreModule in the db
char *CoreModule;
int CoreModuleLen = agentHost->localScript == 0 ? ILibSimpleDataStore_Get(agentHost->masterDb, "CoreModule", NULL, 0) : 0;
- MeshAgentDuktapePtrs* ptrs = agentHost->DuktapeMeshBindings;
-
- while (ptrs != NULL)
+
+ if (agentHost->meshCoreCtx != NULL)
{
- if (ptrs->OnReady != NULL)
- {
- duk_push_heapptr(ptrs->ctx, ptrs->OnReady); // [func]
- duk_push_heapptr(ptrs->ctx, ptrs->MeshAgentObject); // [func][this]
- if (duk_pcall_method(ptrs->ctx, 0) != 0) {ILibDuktape_Process_UncaughtException(ptrs->ctx); } // [retVal]
- duk_pop(ptrs->ctx); // ...
- }
- ptrs = ptrs->Next;
+ ILibDuktape_MeshAgent_PUSH(agentHost->meshCoreCtx, agentHost->chain); // [agent]
+ duk_get_prop_string(agentHost->meshCoreCtx, -1, "emit"); // [agent][emit]
+ duk_swap_top(agentHost->meshCoreCtx, -2); // [emit][this]
+ duk_push_string(agentHost->meshCoreCtx, "Ready"); // [emit][this][Ready]
+ if (duk_pcall_method(agentHost->meshCoreCtx, 1) != 0) { ILibDuktape_Process_UncaughtException(agentHost->meshCoreCtx); }
+ duk_pop(agentHost->meshCoreCtx); // ...
}
if (agentHost->localScript == 0)
@@ -2532,6 +2675,7 @@ int MeshAgent_AgentMode(MeshAgentHostContainer *agentHost, int paramLen, char **
}
free(CoreModule);
+ if (ILibSimpleDataStore_Get(agentHost->masterDb, "noUpdateCoreModule", NULL, 0) != 0) { agentHost->localScript = 1; printf("** CoreModule: Update Disabled**\n"); }
}
}
@@ -2757,7 +2901,7 @@ int MeshAgent_Start(MeshAgentHostContainer *agentHost, int paramLen, char **para
#endif
// Perform a self SHA384 Hash
- util_sha384file(agentHost->exePath, agentHost->agentHash);
+ GenerateSHA384FileHash(agentHost->exePath, agentHost->agentHash);
#ifdef _REMOTELOGGINGSERVER
{
@@ -2812,8 +2956,8 @@ int MeshAgent_Start(MeshAgentHostContainer *agentHost, int paramLen, char **para
ILibStartChain(agentHost->chain);
agentHost->chain = NULL; // Mesh agent has exited, set the chain to NULL
- // Check if we need to perform self-update
- if (agentHost->performSelfUpdate == 1)
+ // Check if we need to perform self-update (performSelfUpdate should indicate startup type on Liunx: 1 = systemd, 2 = upstart, 3 = sysv-init)
+ if (agentHost->performSelfUpdate != 0)
{
int i, ptr = 0;
#ifdef WIN32
@@ -2860,7 +3004,19 @@ int MeshAgent_Start(MeshAgentHostContainer *agentHost, int paramLen, char **para
}
#else
// Linux version
- {
+ if (agentHost->performSelfUpdate == 1) {
+ // Systemd is in use, move the update using "mv" and restart the systemd service
+ struct stat results;
+ stat(agentHost->exePath, &results); // This the mode of the current executable
+ chmod(updateFilePath, results.st_mode); // Set the new executable to the same mode as the current one.
+
+ sprintf_s(ILibScratchPad, sizeof(ILibScratchPad), "mv \"%s\" \"%s\"", updateFilePath, agentHost->exePath); // Move the update over our own executable
+ if (system(ILibScratchPad)) {}
+
+ sprintf_s(ILibScratchPad, sizeof(ILibScratchPad), "systemctl restart meshagent"); // Restart the service
+ if (system(ILibScratchPad)) {}
+ } else {
+ // Generic update process, call our own update with arguments.
struct stat results;
stat(agentHost->exePath, &results); // This the mode of the current executable
chmod(updateFilePath, results.st_mode); // Set the new executable to the same mode as the current one.
diff --git a/meshcore/agentcore.h b/meshcore/agentcore.h
index 1c02727..248102b 100644
--- a/meshcore/agentcore.h
+++ b/meshcore/agentcore.h
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -118,16 +118,6 @@ typedef struct MeshAgent_Commands_SCRIPT_ExecuteString
}MeshAgent_Commands_SCRIPT_ExecuteString;
#pragma pack(pop)
-typedef struct MeshAgentDuktapePtrs
-{
- struct MeshAgentDuktapePtrs *Next;
- duk_context *ctx;
- void *MeshAgentObject;
- void *OnCommand;
- void *OnConnect;
- void *OnReady;
-}MeshAgentDuktapePtrs;
-
typedef enum MeshAgentHost_BatteryInfo
{
MeshAgentHost_BatteryInfo_HIGH = 1,
@@ -148,7 +138,6 @@ typedef struct MeshAgentHostContainer
duk_context *meshCoreCtx;
char *meshCoreCtx_embeddedScript;
int meshCoreCtx_embeddedScriptLen;
- MeshAgentDuktapePtrs *DuktapeMeshBindings;
ILibProcessPipe_Manager *pipeManager;
char* exePath;
@@ -192,6 +181,9 @@ typedef struct MeshAgentHostContainer
#ifndef WIN32
int dbRetryCount;
#endif
+#if defined(_WINSERVICE)
+ int runningAsConsole;
+#endif
}MeshAgentHostContainer;
MeshAgentHostContainer* MeshAgent_Create();
diff --git a/meshcore/meshdefines.h b/meshcore/meshdefines.h
index d294782..2d1bf7d 100644
--- a/meshcore/meshdefines.h
+++ b/meshcore/meshdefines.h
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/meshcore/meshinfo.c b/meshcore/meshinfo.c
index 61b0b3b..b662144 100644
--- a/meshcore/meshinfo.c
+++ b/meshcore/meshinfo.c
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/meshcore/meshinfo.h b/meshcore/meshinfo.h
index 73ca7a5..fa671a0 100644
--- a/meshcore/meshinfo.h
+++ b/meshcore/meshinfo.h
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/meshcore/signcheck.c b/meshcore/signcheck.c
index 37ffb09..7abecd6 100644
--- a/meshcore/signcheck.c
+++ b/meshcore/signcheck.c
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/meshcore/signcheck.h b/meshcore/signcheck.h
index 627cba4..0a5d9f0 100644
--- a/meshcore/signcheck.h
+++ b/meshcore/signcheck.h
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/meshservice/MeshService.vcxproj b/meshservice/MeshService.vcxproj
index ae7bfbe..cfa64ad 100644
--- a/meshservice/MeshService.vcxproj
+++ b/meshservice/MeshService.vcxproj
@@ -95,10 +95,10 @@
false
- false
+ true
- false
+ true
$(ProjectName)64
@@ -198,7 +198,8 @@
/ignore:4099 %(AdditionalOptions)
- signtool.exe sign /sha1 fd5940d8fd585545614fea6da455f25d224b00c9 /d "MeshService" /du "http://opentools.homeip.net" /t http://timestamp.comodoca.com/authenticode "$(TargetPath)"
+ REM signtool.exe sign /sha1 fd5940d8fd585545614fea6da455f25d224b00c9 /d "MeshService" /du "http://opentools.homeip.net" /t http://timestamp.comodoca.com/authenticode "$(TargetPath)"
+"$(OutputPath)$(TargetFileName)" ..\modules\PostBuild.js
$(ProjectDir)dpiaware.manifest %(AdditionalManifestFiles)
@@ -233,7 +234,8 @@
$(OutDir)$(TargetName).pdb
- signtool.exe sign /sha1 fd5940d8fd585545614fea6da455f25d224b00c9 /d "MeshService" /du "http://opentools.homeip.net" /t http://timestamp.comodoca.com/authenticode "$(TargetPath)"
+ REM signtool.exe sign /sha1 fd5940d8fd585545614fea6da455f25d224b00c9 /d "MeshService" /du "http://opentools.homeip.net" /t http://timestamp.comodoca.com/authenticode "$(TargetPath)"
+"$(OutputPath)$(TargetFileName)" ..\modules\PostBuild.js
@@ -253,9 +255,9 @@
+
-
@@ -276,9 +278,6 @@
-
-
-
@@ -306,9 +305,9 @@
+
-
@@ -327,9 +326,6 @@
-
-
-
diff --git a/meshservice/MeshService.vcxproj.filters b/meshservice/MeshService.vcxproj.filters
index 303b494..2cf4d2e 100644
--- a/meshservice/MeshService.vcxproj.filters
+++ b/meshservice/MeshService.vcxproj.filters
@@ -34,9 +34,6 @@
Microscript
-
- Microscript
-
Microscript
@@ -64,15 +61,6 @@
Microscript
-
- Microscript
-
-
- Microscript
-
-
- Microscript
-
Microstack
@@ -172,6 +160,9 @@
Microscript
+
+ Microscript
+
@@ -180,9 +171,6 @@
Microscript
-
- Microscript
-
Microscript
@@ -210,15 +198,6 @@
Microscript
-
- Microscript
-
-
- Microscript
-
-
- Microscript
-
Microstack
@@ -316,5 +295,8 @@
Microscript
+
+ Microscript
+
\ No newline at end of file
diff --git a/meshservice/ServiceMain.c b/meshservice/ServiceMain.c
index 3b13fd1..64a57f4 100644
--- a/meshservice/ServiceMain.c
+++ b/meshservice/ServiceMain.c
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -226,11 +226,11 @@ BOOL InstallService()
// Update the faliure action
failactions[0].Type = SC_ACTION_RESTART;
- failactions[0].Delay = 120000; // Wait 2 minutes before faliure restart (milliseconds)
+ failactions[0].Delay = 60000; // Wait 1 minutes before faliure restart (milliseconds)
failactions[1].Type = SC_ACTION_RESTART;
- failactions[1].Delay = 120000; // Wait 2 minutes before faliure restart (milliseconds)
- failactions[2].Type = SC_ACTION_NONE;
- failactions[2].Delay = 120000;
+ failactions[1].Delay = 60000; // Wait 1 minutes before faliure restart (milliseconds)
+ failactions[2].Type = SC_ACTION_RESTART;
+ failactions[2].Delay = 60000;
memset(&fa, 0, sizeof(SERVICE_FAILURE_ACTIONS));
fa.dwResetPeriod = 86400; // After 1 days, reset the faliure counters (seconds)
fa.cActions = 3;
@@ -501,6 +501,14 @@ void fullinstall(int uninstallonly, char* proxy, int proxylen, char* tag, int ta
setup2[setup2len] = 0;
remove(setup2);
+ // Remove "[Executable].mshx" file
+ if ((setup2len = (int)strnlen_s(targetexe, _MAX_PATH + 40)) < 4 || setup2len > 259) return;
+ memcpy_s(setup2, sizeof(setup2), targetexe, setup2len);
+ memcpy_s(setup2 + (setup2len - 3), sizeof(setup2) - setup2len - 3, "mshx", 5);
+ setup2[setup2len + 1] = 0;
+ remove(setup2);
+
+
// Remove "[Executable].proxy" file
if ((setup2len = (int)strnlen_s(targetexe, _MAX_PATH + 40)) < 4 || setup2len > 257) return;
memcpy_s(setup2, sizeof(setup2), targetexe, setup2len);
@@ -778,6 +786,7 @@ int main(int argc, char* argv[])
agent = MeshAgent_Create();
agent->meshCoreCtx_embeddedScript = integratedJavaScript;
agent->meshCoreCtx_embeddedScriptLen = integragedJavaScriptLen;
+ if (integratedJavaScript != NULL || (argc > 1 && strcasecmp(argv[1], "run") == 0)) { agent->runningAsConsole = 1; }
MeshAgent_Start(agent, argc, argv);
retCode = agent->exitCode;
MeshAgent_Destroy(agent);
@@ -1100,7 +1109,7 @@ int main(int argc, char* argv[])
return 0;
}
-char* getMshSettings(char* fileName, char** meshname, char** meshid, char** serverid, char** serverurl)
+char* getMshSettings(char* fileName, char* selfexe, char** meshname, char** meshid, char** serverid, char** serverurl)
{
char* importFile;
int eq, importFileLen;
@@ -1109,18 +1118,43 @@ char* getMshSettings(char* fileName, char** meshname, char** meshid, char** serv
*meshname = *meshid = *serverid = *serverurl = NULL;
importFileLen = ILibReadFileFromDiskEx(&importFile, fileName);
- if (importFile == NULL) return NULL;
+ if (importFile == NULL) {
+ // Could not find the .msh file, see if there is one inside our own executable.
+ FILE *tmpFile = NULL;
+ char exeMeshPolicyGuid[] = { 0xB9, 0x96, 0x01, 0x58, 0x80, 0x54, 0x4A, 0x19, 0xB7, 0xF7, 0xE9, 0xBE, 0x44, 0x91, 0x4C, 0x19 };
+ char tmpHash[16];
+
+ fopen_s(&tmpFile, selfexe, "rb");
+ if (tmpFile == NULL) { return NULL; } // Could not open our own executable
+
+ fseek(tmpFile, -16, SEEK_END);
+ ignore_result(fread(tmpHash, 1, 16, tmpFile)); // Read the GUID
+ if (memcmp(tmpHash, exeMeshPolicyGuid, 16) == 0) { // If this is the Mesh policy file guid, we found a MSH file
+ // Found embedded MSH File
+ fseek(tmpFile, -20, SEEK_CUR);
+ if (fread((void*)&importFileLen, 1, 4, tmpFile) == 4) { // Read the length of the MSH file
+ importFileLen = ntohl(importFileLen);
+ if ((importFileLen >= 20000) || (importFileLen < 1)) { fclose(tmpFile); return NULL; }
+ fseek(tmpFile, -4 - importFileLen, SEEK_CUR);
+ if ((importFile = malloc(importFileLen + 1)) == NULL) { fclose(tmpFile); return NULL; }
+ if (fread(importFile, 1, importFileLen, tmpFile) != importFileLen) { fclose(tmpFile); free(importFile); return NULL; }
+ importFile[importFileLen] = 0;
+ }
+ }
+ else {
+ fclose(tmpFile);
+ return NULL;
+ }
+ fclose(tmpFile);
+ }
pr = ILibParseString(importFile, 0, importFileLen, "\n", 1);
f = pr->FirstResult;
- while (f != NULL)
- {
+ while (f != NULL) {
f->datalength = ILibTrimString(&(f->data), f->datalength);
- if (f->data[0] != 35) // Checking to see if this line is commented out
- {
+ if (f->data[0] != 35) { // Checking to see if this line is commented out
eq = ILibString_IndexOf(f->data, f->datalength, "=", 1);
- if (eq > 0)
- {
+ if (eq > 0) {
char *key, *val;
int keyLen, valLen;
@@ -1145,6 +1179,7 @@ char* getMshSettings(char* fileName, char** meshname, char** meshid, char** serv
return importFile;
}
+
#ifndef _MINCORE
// Message handler for dialog box.
@@ -1229,11 +1264,11 @@ INT_PTR CALLBACK DialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lP
}
}
- if ((mshfile = getMshSettings(fileName, &meshname, &meshid, &serverid, &serverurl)) != NULL)
+ if ((mshfile = getMshSettings(fileName, selfexe, &meshname, &meshid, &serverid, &serverurl)) != NULL)
{
// Set text in the dialog box
- if (strlen(meshid) > 50) { meshid += 2; meshid[42] = 0; }
- if (strlen(serverid) > 50) { serverid[42] = 0; }
+ if (strnlen_s(meshid, 255) > 50) { meshid += 2; meshid[42] = 0; }
+ if (strnlen_s(serverid, 255) > 50) { serverid[42] = 0; }
SetWindowTextA(GetDlgItem(hDlg, IDC_POLICYTEXT), (meshid != NULL) ? meshname : "(None)");
SetWindowTextA(GetDlgItem( hDlg, IDC_HASHTEXT), (meshid != NULL) ? meshid : "(None)");
SetWindowTextA(GetDlgItem(hDlg, IDC_SERVERLOCATION), (serverurl != NULL) ? serverurl : "(None)");
diff --git a/meshservice/firewall.cpp b/meshservice/firewall.cpp
index 982e7f0..b90b392 100644
--- a/meshservice/firewall.cpp
+++ b/meshservice/firewall.cpp
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/microscript/ILibDuktapeModSearch.c b/microscript/ILibDuktapeModSearch.c
index f9fb458..f03cb35 100644
--- a/microscript/ILibDuktapeModSearch.c
+++ b/microscript/ILibDuktapeModSearch.c
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@ limitations under the License.
#include "ILibDuktapeModSearch.h"
#include "microstack/ILibParsers.h"
#include "microscript/ILibDuktape_Helpers.h"
-
+#include "microscript/duk_module_duktape.h"
#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(_MINCORE)
#define _CRTDBG_MAP_ALLOC
@@ -204,6 +204,8 @@ void ILibDuktape_ModSearch_Destroy(duk_context *ctx, void *user)
}
void ILibDuktape_ModSearch_Init(duk_context * ctx, void * chain, ILibSimpleDataStore mDB)
{
+ duk_module_duktape_init(ctx);
+
duk_push_heap_stash(ctx); // [stash]
duk_push_pointer(ctx, chain); // [stash][chain]
duk_put_prop_string(ctx, -2, ILibDuktape_Context_Chain); // [stash]
diff --git a/microscript/ILibDuktapeModSearch.h b/microscript/ILibDuktapeModSearch.h
index 5343e8b..7f86807 100644
--- a/microscript/ILibDuktapeModSearch.h
+++ b/microscript/ILibDuktapeModSearch.h
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/microscript/ILibDuktape_ChildProcess.c b/microscript/ILibDuktape_ChildProcess.c
index 330e189..6aaaf2d 100644
--- a/microscript/ILibDuktape_ChildProcess.c
+++ b/microscript/ILibDuktape_ChildProcess.c
@@ -1,3 +1,19 @@
+/*
+Copyright 2006 - 2018 Intel Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
#include "ILibDuktape_ChildProcess.h"
#include "ILibDuktapeModSearch.h"
@@ -100,6 +116,7 @@ duk_ret_t ILibDuktape_ChildProcess_Kill(duk_context *ctx)
ILibDuktape_ChildProcess_SubProcess* ILibDuktape_ChildProcess_SpawnedProcess_PUSH(duk_context *ctx, ILibProcessPipe_Process mProcess, void *callback)
{
duk_push_object(ctx); // [ChildProcess]
+ ILibDuktape_WriteID(ctx, "childProcess.subProcess");
duk_push_pointer(ctx, mProcess); // [ChildProcess][ptr]
duk_put_prop_string(ctx, -2, ILibDuktape_ChildProcess_Process); // [ChildProcess]
duk_push_fixed_buffer(ctx, sizeof(ILibDuktape_ChildProcess_SubProcess)); // [ChildProcess][buffer]
@@ -121,21 +138,21 @@ ILibDuktape_ChildProcess_SubProcess* ILibDuktape_ChildProcess_SpawnedProcess_PUS
ILibDuktape_CreateInstanceMethod(ctx, "kill", ILibDuktape_ChildProcess_Kill, 0);
duk_push_object(ctx);
- ILibDuktape_WriteID(ctx, "childProcess.stdout");
+ ILibDuktape_WriteID(ctx, "childProcess.subProcess.stdout");
duk_dup(ctx, -2);
ILibDuktape_CreateReadonlyProperty(ctx, "parent");
retVal->stdOut = ILibDuktape_ReadableStream_Init(ctx, ILibDuktape_ChildProcess_SubProcess_StdOut_OnPause, ILibDuktape_ChildProcess_SubProcess_StdOut_OnResume, retVal);
ILibDuktape_CreateReadonlyProperty(ctx, "stdout");
duk_push_object(ctx);
- ILibDuktape_WriteID(ctx, "childProcess.stderr");
+ ILibDuktape_WriteID(ctx, "childProcess.subProcess.stderr");
duk_dup(ctx, -2);
ILibDuktape_CreateReadonlyProperty(ctx, "parent");
retVal->stdErr = ILibDuktape_ReadableStream_Init(ctx, ILibDuktape_ChildProcess_SubProcess_StdErr_OnPause, ILibDuktape_ChildProcess_SubProcess_StdErr_OnResume, retVal);
ILibDuktape_CreateReadonlyProperty(ctx, "stderr");
duk_push_object(ctx);
- ILibDuktape_WriteID(ctx, "childProcess.stdin");
+ ILibDuktape_WriteID(ctx, "childProcess.subProcess.stdin");
duk_dup(ctx, -2);
ILibDuktape_CreateReadonlyProperty(ctx, "parent");
retVal->stdIn = ILibDuktape_WritableStream_Init(ctx, ILibDuktape_ChildProcess_SubProcess_StdIn_WriteHandler, ILibDuktape_ChildProcess_SubProcess_StdIn_EndHandler, retVal);
@@ -231,6 +248,7 @@ duk_ret_t ILibDuktape_ChildProcess_execFile(duk_context *ctx)
void ILibDuktape_ChildProcess_PUSH(duk_context *ctx, void *chain)
{
duk_push_object(ctx);
+ ILibDuktape_WriteID(ctx, "childProcess");
duk_push_pointer(ctx, (void*)ILibProcessPipe_Manager_Create(chain));
duk_put_prop_string(ctx, -2, ILibDuktape_ChildProcess_Manager);
ILibDuktape_CreateFinalizer(ctx, ILibDuktape_ChildProcess_Manager_Finalizer);
diff --git a/microscript/ILibDuktape_ChildProcess.h b/microscript/ILibDuktape_ChildProcess.h
index d7ad69d..9b0282c 100644
--- a/microscript/ILibDuktape_ChildProcess.h
+++ b/microscript/ILibDuktape_ChildProcess.h
@@ -1,3 +1,19 @@
+/*
+Copyright 2006 - 2018 Intel Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
#ifndef __ILIBDUKTAPE_CHILDPROCESS__
#define __ILIBDUKTAPE_CHILDPROCESS__
diff --git a/microscript/ILibDuktape_Dgram.c b/microscript/ILibDuktape_Dgram.c
index 78a532d..55ada6a 100644
--- a/microscript/ILibDuktape_Dgram.c
+++ b/microscript/ILibDuktape_Dgram.c
@@ -1,3 +1,19 @@
+/*
+Copyright 2006 - 2018 Intel Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(_MINCORE)
#define _CRTDBG_MAP_ALLOC
#include
@@ -38,7 +54,6 @@ typedef struct ILibDuktape_DGRAM_DATA
void *socketObject;
void *dgramObject;
void *chain;
- void *OnClose, *OnError, *OnListening, *OnMessage, *OnSendOK;
ILibAsyncUDPSocket_SocketModule *mSocket;
}ILibDuktape_DGRAM_DATA;
typedef enum ILibDuktape_DGRAM_Config
@@ -68,34 +83,39 @@ void ILibDuktape_Dgram_Socket_OnData(ILibAsyncUDPSocket_SocketModule socketModul
ILibDuktape_DGRAM_DATA* ptrs = (ILibDuktape_DGRAM_DATA*)user;
- if (ptrs != NULL && ptrs->ctx != NULL && ptrs->OnMessage != NULL)
+ if (ptrs != NULL && ptrs->ctx != NULL)
{
- duk_push_heapptr(ptrs->ctx, ptrs->OnMessage); // [func]
- duk_push_heapptr(ptrs->ctx, ptrs->socketObject); // [func][this]
+ duk_push_heapptr(ptrs->ctx, ptrs->socketObject); // [this]
+ duk_get_prop_string(ptrs->ctx, -1, "emit"); // [this][emit]
+ duk_swap_top(ptrs->ctx, -2); // [emit][this]
+ duk_push_string(ptrs->ctx, "message"); // [emit][this][message]
duk_push_external_buffer(ptrs->ctx);
- duk_config_buffer(ptrs->ctx, -1, buffer, (duk_size_t)bufferLength); // [func][this][buffer]
- duk_push_object(ptrs->ctx); // [func][this][buffer][rinfo]
- duk_push_string(ptrs->ctx, remoteInterface->sin6_family == AF_INET ? "IPv4" : "IPv6"); // [func][this][buffer][rinfo][family]
- duk_put_prop_string(ptrs->ctx, -2, "family"); // [func][this][buffer][rinfo]
- duk_push_string(ptrs->ctx, ILibRemoteLogging_ConvertAddress((struct sockaddr*)remoteInterface)); // [func][this][buffer][rinfo][address]
- duk_put_prop_string(ptrs->ctx, -2, "address"); // [func][this][buffer][rinfo]
- duk_push_int(ptrs->ctx, (int)ntohs(remoteInterface->sin6_port)); // [func][this][buffer][rinfo][port]
- duk_put_prop_string(ptrs->ctx, -2, "port"); // [func][this][buffer][rinfo]
+ duk_config_buffer(ptrs->ctx, -1, buffer, (duk_size_t)bufferLength); // [emit][this][message][buffer]
+ duk_push_object(ptrs->ctx); // [emit][this][message][buffer][rinfo]
+ duk_push_string(ptrs->ctx, remoteInterface->sin6_family == AF_INET ? "IPv4" : "IPv6"); // [emit][this][message][buffer][rinfo][family]
+ duk_put_prop_string(ptrs->ctx, -2, "family"); // [emit][this][message][buffer][rinfo]
+ duk_push_string(ptrs->ctx, ILibRemoteLogging_ConvertAddress((struct sockaddr*)remoteInterface)); // [emit][this][message][buffer][rinfo][address]
+ duk_put_prop_string(ptrs->ctx, -2, "address"); // [emit][this][message][buffer][rinfo]
+ duk_push_int(ptrs->ctx, (int)ntohs(remoteInterface->sin6_port)); // [emit][this][message][buffer][rinfo][port]
+ duk_put_prop_string(ptrs->ctx, -2, "port"); // [emit][this][message][buffer][rinfo]
duk_push_int(ptrs->ctx, bufferLength);
duk_put_prop_string(ptrs->ctx, -2, "size");
- if (duk_pcall_method(ptrs->ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ptrs->ctx, "dgram.message() dispatch error"); }
+ if (duk_pcall_method(ptrs->ctx, 3) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ptrs->ctx, "dgram.message() dispatch error"); }
duk_pop(ptrs->ctx); // ...
}
}
void ILibDuktape_Dgram_Socket_OnSendOK(ILibAsyncUDPSocket_SocketModule socketModule, void *user1, void *user2)
{
ILibDuktape_DGRAM_DATA* ptrs = (ILibDuktape_DGRAM_DATA*)user1;
- if (ptrs != NULL && ptrs->ctx != NULL && ptrs->OnSendOK != NULL)
+ if (ptrs != NULL && ptrs->ctx != NULL)
{
- duk_push_heapptr(ptrs->ctx, ptrs->OnSendOK); // [func]
- duk_push_heapptr(ptrs->ctx, ptrs->socketObject); // [func][this]
- if (duk_pcall_method(ptrs->ctx, 0) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ptrs->ctx, "net.dgram.socket.onSendOk"); }
+ duk_push_heapptr(ptrs->ctx, ptrs->socketObject); // [this]
+ duk_get_prop_string(ptrs->ctx, -1, "emit"); // [this][emit]
+ duk_swap_top(ptrs->ctx, -2); // [emit][this]
+ duk_push_string(ptrs->ctx, "flushed"); // [emit][this][flushed]
+ if (duk_pcall_method(ptrs->ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ptrs->ctx, "net.dgram.socket.onSendOk"); }
+ duk_pop(ptrs->ctx); // ...
}
}
@@ -201,13 +221,14 @@ duk_ret_t ILibDuktape_DGram_Socket_bind(duk_context *ctx)
#endif
}
- if (ptrs->OnListening != NULL)
- {
- duk_push_heapptr(ctx, ptrs->OnListening); // [func]
- duk_push_heapptr(ctx, ptrs->socketObject); // [func][this]
- if (duk_pcall_method(ctx, 0) != 0) { ILibDuktape_Process_UncaughtException(ctx); }
- duk_pop(ctx); // ...
- }
+
+ duk_push_heapptr(ctx, ptrs->socketObject); // [this]
+ duk_get_prop_string(ctx, -1, "emit"); // [this][emit]
+ duk_swap_top(ctx, -2); // [emit][this]
+ duk_push_string(ctx, "listening"); // [emit][this][listening]
+ if (duk_pcall_method(ctx, 1) != 0) { ILibDuktape_Process_UncaughtException(ctx); }
+ duk_pop(ctx); // ...
+
return 0;
}
@@ -352,12 +373,14 @@ duk_ret_t ILibDuktape_DGram_send(duk_context *ctx)
if (duk_pcall_method(ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "net.dgram.send.callback(): Error "); }
duk_pop(ctx); // ...
}
- else if(ptrs->OnError != NULL)
+ else
{
- duk_push_heapptr(ctx, ptrs->OnError); // [func]
- duk_push_heapptr(ctx, ptrs->socketObject); // [func][this]
+ duk_push_heapptr(ctx, ptrs->socketObject); // [this]
+ duk_get_prop_string(ctx, -1, "emit"); // [this][emit]
+ duk_swap_top(ctx, -2); // [emit][this]
+ duk_push_string(ctx, "error"); // [emit][this][error]
duk_push_error_object(ctx, DUK_ERR_TYPE_ERROR, "net.dgram.send(): Attempted to send on a closed socket");
- if (duk_pcall_method(ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "net.dgram.onError(): Error "); }
+ if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "net.dgram.onError(): Error "); }
duk_pop(ctx); // ...
}
break;
@@ -433,11 +456,11 @@ duk_ret_t ILibDuktape_DGram_createSocket(duk_context *ctx)
ptrs->dgramObject = dgram;
ptrs->emitter = ILibDuktape_EventEmitter_Create(ctx);
- ILibDuktape_EventEmitter_CreateEvent(ptrs->emitter, "close", &(ptrs->OnClose));
- ILibDuktape_EventEmitter_CreateEvent(ptrs->emitter, "error", &(ptrs->OnError));
- ILibDuktape_EventEmitter_CreateEvent(ptrs->emitter, "listening", &(ptrs->OnListening));
- ILibDuktape_EventEmitter_CreateEvent(ptrs->emitter, "message", &(ptrs->OnMessage));
- ILibDuktape_EventEmitter_CreateEvent(ptrs->emitter, "flushed", &(ptrs->OnSendOK));
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "close");
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "error");
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "listening");
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "message");
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "flushed");
ILibDuktape_CreateInstanceMethodWithIntProperty(ctx, "config", config, "bind", ILibDuktape_DGram_Socket_bind, DUK_VARARGS);
@@ -459,6 +482,7 @@ duk_ret_t ILibDuktape_DGram_createSocket(duk_context *ctx)
void ILibDuktape_DGram_PUSH(duk_context *ctx, void *chain)
{
duk_push_object(ctx); // [dgram]
+ ILibDuktape_WriteID(ctx, "dgram");
duk_push_pointer(ctx, chain); // [dgram][chain]
duk_put_prop_string(ctx, -2, ILibDuktape_DGRAM_CHAIN); // [dgram]
ILibDuktape_CreateInstanceMethod(ctx, "createSocket", ILibDuktape_DGram_createSocket, DUK_VARARGS);
diff --git a/microscript/ILibDuktape_Dgram.h b/microscript/ILibDuktape_Dgram.h
index 04b93e0..5bfff1b 100644
--- a/microscript/ILibDuktape_Dgram.h
+++ b/microscript/ILibDuktape_Dgram.h
@@ -1,3 +1,19 @@
+/*
+Copyright 2006 - 2018 Intel Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
#ifndef ___ILibDuktape_Dgram___
#define ___ILibDuktape_Dgram___
diff --git a/microscript/ILibDuktape_DuplexStream.c b/microscript/ILibDuktape_DuplexStream.c
index 60fa68e..41e7300 100644
--- a/microscript/ILibDuktape_DuplexStream.c
+++ b/microscript/ILibDuktape_DuplexStream.c
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/microscript/ILibDuktape_DuplexStream.h b/microscript/ILibDuktape_DuplexStream.h
index cb6b93e..c55206d 100644
--- a/microscript/ILibDuktape_DuplexStream.h
+++ b/microscript/ILibDuktape_DuplexStream.h
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/microscript/ILibDuktape_EncryptionStream.c b/microscript/ILibDuktape_EncryptionStream.c
index 2fd743c..ea1973e 100644
--- a/microscript/ILibDuktape_EncryptionStream.c
+++ b/microscript/ILibDuktape_EncryptionStream.c
@@ -1,3 +1,19 @@
+/*
+Copyright 2006 - 2018 Intel Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
#include "duktape.h"
#include "ILibDuktape_Helpers.h"
#include "ILibParsers_Duktape.h"
diff --git a/microscript/ILibDuktape_EncryptionStream.h b/microscript/ILibDuktape_EncryptionStream.h
index e5d00c8..aa9363a 100644
--- a/microscript/ILibDuktape_EncryptionStream.h
+++ b/microscript/ILibDuktape_EncryptionStream.h
@@ -1,3 +1,19 @@
+/*
+Copyright 2006 - 2018 Intel Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
#ifndef __ILibDuktape_EncryptionStream__
#define __ILibDuktape_EncryptionStream__
diff --git a/microscript/ILibDuktape_EventEmitter.h b/microscript/ILibDuktape_EventEmitter.h
index ba74ad7..ff96c80 100644
--- a/microscript/ILibDuktape_EventEmitter.h
+++ b/microscript/ILibDuktape_EventEmitter.h
@@ -1,3 +1,19 @@
+/*
+Copyright 2006 - 2018 Intel Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
#ifndef __ILibDuktape_EVENT_EMITTER__
#define __ILibDuktape_EVENT_EMITTER__
@@ -22,17 +38,18 @@ ILibDuktape_EventEmitter* ILibDuktape_EventEmitter_GetEmitter_fromThis(duk_conte
ILibDuktape_EventEmitter* ILibDuktape_EventEmitter_GetEmitter_fromObject(duk_context *ctx, void *objHeapptr);
void ILibDuktape_EventEmitter_Init(duk_context *ctx);
-void ILibDuktape_EventEmitter_RemoveAll(ILibDuktape_EventEmitter *emitter); // Removes all event handlers/dispatchers
+int ILibDuktape_EventEmitter_GetEventCount(ILibDuktape_EventEmitter *emitter);
void ILibDuktape_EventEmitter_RemoveAllListeners(ILibDuktape_EventEmitter *emitter, char *eventName); // Invokes JavaScript method EventEmitter.removeAllListeners()
-void ILibDuktape_EventEmitter_CreateEvent(ILibDuktape_EventEmitter *emitter, char *eventName, void **hptr); // Create Event with hybrid dispatcher
void ILibDuktape_EventEmitter_CreateEventEx(ILibDuktape_EventEmitter *emitter, char *eventName); // Create Event with virtual dispatcher
-void ILibDuktape_EventEmitter_RemoveEventHeapptr(ILibDuktape_EventEmitter *emitter, char *eventName, void **heapptr); // Remove native callback pointer
-int ILibDuktape_EventEmitter_AddEventHeapptr(ILibDuktape_EventEmitter *emitter, char *eventName, void **heapptr); // Add Callback after the fact
-int ILibDuktape_EventEmitter_AddSink(ILibDuktape_EventEmitter *emitter, char *eventName, ILibDuktape_EventEmitter_Handler handler); // Add Native Event Handler
int ILibDuktape_EventEmitter_AddOnce(ILibDuktape_EventEmitter *emitter, char *eventName, void *heapptr); // Add native event handler 'once'
int ILibDuktape_EventEmitter_AddOnceEx(ILibDuktape_EventEmitter *emitter, char *eventName, duk_c_function func, duk_idx_t funcArgs);
int ILibDuktape_EventEmitter_AddOnceEx3(duk_context *ctx, duk_idx_t idx, char *eventName, duk_c_function func);
+int ILibDuktape_EventEmitter_PrependOnce(duk_context *ctx, duk_idx_t i, char *eventName, duk_c_function func);
+int ILibDuktape_EventEmitter_HasListeners(ILibDuktape_EventEmitter *emitter, char *eventName);
+#define ILibDuktape_EventEmitter_HasListenersEx(ctx, idx, eventName) ILibDuktape_EventEmitter_HasListeners(ILibDuktape_EventEmitter_GetEmitter(ctx, idx), eventName)
+
#define ILibDuktape_EventEmitter_AddOnceEx2(ctx, idx, eventName, func, argCount) ILibDuktape_EventEmitter_AddOnceEx3(ctx, idx, eventName, func)
+#define ILibDuktape_EventEmitter_SetupEmit(ctx, heapptr, eventName) duk_push_heapptr((ctx), heapptr);duk_get_prop_string((ctx), -1, "emit");duk_swap_top((ctx), -2);duk_push_string((ctx), eventName)
int ILibDuktape_EventEmitter_AddOn(ILibDuktape_EventEmitter *emitter, char *eventName, void *heapptr); // Add native event handler
int ILibDuktape_EventEmitter_AddOnEx(duk_context *ctx, duk_idx_t idx, char *eventName, duk_c_function func);
diff --git a/microscript/ILibDuktape_GenericMarshal.c b/microscript/ILibDuktape_GenericMarshal.c
index 2e90721..ebf8270 100644
--- a/microscript/ILibDuktape_GenericMarshal.c
+++ b/microscript/ILibDuktape_GenericMarshal.c
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/microscript/ILibDuktape_GenericMarshal.h b/microscript/ILibDuktape_GenericMarshal.h
index f312e34..652048d 100644
--- a/microscript/ILibDuktape_GenericMarshal.h
+++ b/microscript/ILibDuktape_GenericMarshal.h
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/microscript/ILibDuktape_HECI.c b/microscript/ILibDuktape_HECI.c
index 3278c42..952ac7d 100644
--- a/microscript/ILibDuktape_HECI.c
+++ b/microscript/ILibDuktape_HECI.c
@@ -1,3 +1,19 @@
+/*
+Copyright 2006 - 2018 Intel Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
#include "ILibDuktape_HECI.h"
#include "ILibDuktapeModSearch.h"
#include "ILibDuktape_Helpers.h"
@@ -220,7 +236,7 @@ duk_ret_t ILibDuktape_HECI_SessionFinalizer(duk_context *ctx)
void ILibDuktape_HECI_Session_EmitErrorEvent(void *chain, void *session)
{
- if (ILibIsRunningOnChainThread(chain) == 0) { ILibChain_RunOnMicrostackThreadEx(chain, ILibDuktape_HECI_Session_EmitErrorEvent, session); }
+ if (ILibIsRunningOnChainThread(chain) == 0) { ILibChain_RunOnMicrostackThreadEx(chain, ILibDuktape_HECI_Session_EmitErrorEvent, session); return; }
ILibDuktape_HECI_Session *s = (ILibDuktape_HECI_Session*)session;
duk_context *ctx = s->stream->readableStream->ctx;
@@ -234,7 +250,7 @@ void ILibDuktape_HECI_Session_EmitErrorEvent(void *chain, void *session)
}
void ILibDuktape_HECI_Session_EmitStreamReady(void *chain, void *session)
{
- if (ILibIsRunningOnChainThread(chain) == 0) { ILibChain_RunOnMicrostackThreadEx(chain, ILibDuktape_HECI_Session_EmitStreamReady, session); }
+ if (ILibIsRunningOnChainThread(chain) == 0) { ILibChain_RunOnMicrostackThreadEx(chain, ILibDuktape_HECI_Session_EmitStreamReady, session); return; }
ILibDuktape_DuplexStream_Ready(((ILibDuktape_HECI_Session*)session)->stream);
}
@@ -278,7 +294,7 @@ ILibTransport_DoneState ILibDuktape_HECI_Session_WriteHandler_Process(ILibDuktap
DWORD bytesWritten;
BOOL result = TRUE;
#else
- size_t bytesWritten;
+ ssize_t bytesWritten;
#endif
while (ILibQueue_GetCount(session->PendingWrites) > 0)
@@ -662,6 +678,7 @@ duk_ret_t ILibDuktape_HECI_Session_connect(duk_context *ctx)
duk_ret_t ILibDuktape_HECI_create(duk_context *ctx)
{
duk_push_object(ctx); // [Session]
+ ILibDuktape_WriteID(ctx, "heci.session");
ILibDuktape_HECI_Push(ctx, NULL); // [Session][HECI]
duk_dup(ctx, -2); // [Session][HECI][Session]
duk_put_prop_string(ctx, -2, ILibDuktape_HECI_Parent); // [Session][HECI]
@@ -939,7 +956,7 @@ void ILibDuktape_HECI_PostSelect(void* object, int slct, fd_set *readset, fd_set
}
if (FD_ISSET(h->descriptor, writeset))
{
- printf("Writeset\n");
+ ILibDuktape_HECI_Session_WriteHandler_Process(h->session);
}
}
void ILibDuktape_HECI_Destroy(void *object)
@@ -957,6 +974,7 @@ void ILibDuktape_HECI_Destroy(void *object)
void ILibDuktape_HECI_Push(duk_context *ctx, void *chain)
{
duk_push_object(ctx); // [HECI]
+ ILibDuktape_WriteID(ctx, "heci");
ILibDuktape_CreateFinalizer(ctx, ILibDuktape_HECI_Finalizer);
#ifdef WIN32
diff --git a/microscript/ILibDuktape_HECI.h b/microscript/ILibDuktape_HECI.h
index fa75ba6..bb0e885 100644
--- a/microscript/ILibDuktape_HECI.h
+++ b/microscript/ILibDuktape_HECI.h
@@ -1,3 +1,19 @@
+/*
+Copyright 2006 - 2018 Intel Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
#ifndef __DUKTAPEHECI__
#define __DUKTAPEHECI__
diff --git a/microscript/ILibDuktape_Helpers.c b/microscript/ILibDuktape_Helpers.c
index 11066ba..5ec2df4 100644
--- a/microscript/ILibDuktape_Helpers.c
+++ b/microscript/ILibDuktape_Helpers.c
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -39,6 +39,14 @@ struct sockaddr_in6 duktape_internalAddress;
#define ILibDuktape_Memory_AllocTable "\xFF_MemoryAllocTable"
#define ILibDuktape_ObjectStashKey "\xFF_ObjectStashKey"
+int ILibDuktape_GetReferenceCount(duk_context *ctx, duk_idx_t i)
+{
+ int retVal = -1;
+ duk_inspect_value(ctx, i);
+ retVal = Duktape_GetIntPropertyValue(ctx, -1, "refc", -1);
+ duk_pop(ctx);
+ return(retVal-1);
+}
void ILibDuktape_Push_ObjectStash(duk_context *ctx)
{
if (duk_has_prop_string(ctx, -1, ILibDuktape_ObjectStashKey))
@@ -299,7 +307,7 @@ void ILibDuktape_CreateEventWithSetterEx(duk_context *ctx, char *propName, duk_c
duk_push_string(ctx, propName); // [obj][prop]
duk_push_c_function(ctx, setterMethod, 1); // [obj][prop][setFunc]
duk_push_string(ctx, propName); // [obj][prop][setFunc][name]
- duk_put_prop_string(ctx, -2, "name"); // [obj][prop][setFunc]
+ duk_put_prop_string(ctx, -2, "propName"); // [obj][prop][setFunc]
duk_def_prop(ctx, -3, DUK_DEFPROP_FORCE | DUK_DEFPROP_HAVE_SETTER); // [obj]
}
void ILibDuktape_CreateEventWithSetter(duk_context *ctx, char *propName, char *propNamePtr, void **hptr)
@@ -333,6 +341,7 @@ void ILibDuktape_Helper_AddHeapFinalizer(duk_context *ctx, ILibDuktape_HelperEve
duk_push_heap_stash(ctx); // [g]
duk_push_object(ctx); // [g][obj]
+ ILibDuktape_WriteID(ctx, "Mesh.ScriptContainer.heapFinalizer");
duk_push_pointer(ctx, user); // [g][obj][user]
duk_put_prop_string(ctx, -2, "user"); // [g][obj]
duk_push_pointer(ctx, handler); // [g][obj][handler]
@@ -362,19 +371,6 @@ int ILibDuktape_Process_GetExitCode(duk_context *ctx)
return(retVal);
}
-ILibDuktape_EventEmitter *ILibDuktape_Process_GetEventEmitter(duk_context *ctx)
-{
- ILibDuktape_EventEmitter *retVal = NULL;
- duk_push_global_object(ctx); // [g]
- if (duk_has_prop_string(ctx, -1, "process"))
- {
- duk_get_prop_string(ctx, -1, "process"); // [g][process]
- retVal = ILibDuktape_EventEmitter_GetEmitter_fromCurrent(ctx);
- duk_pop(ctx); // [g]
- }
- duk_pop(ctx); // ...
- return retVal;
-}
void *ILibDuktape_GetProcessObject(duk_context *ctx)
{
@@ -420,7 +416,7 @@ void ILibDuktape_Process_UncaughtExceptionEx(duk_context *ctx, char *format, ...
void *j = ILibDuktape_GetProcessObject(ctx);
ILibDuktape_EventEmitter *emitter;
- if (strcmp(errmsg, "Process.exit() forced script termination") == 0) { return; }
+ if (ILibString_IndexOf(errmsg, (int)errmsgLen, "Process.exit() forced script termination", 40) >= 0) { return; }
duk_push_heapptr(ctx, j); // [process]
emitter = ILibDuktape_EventEmitter_GetEmitter_fromCurrent(ctx);
@@ -454,7 +450,7 @@ void ILibDuktape_Process_UncaughtExceptionEx(duk_context *ctx, char *format, ...
duk_get_prop_string(emitter->ctx, -1, "emit"); // [process][emit]
duk_swap_top(emitter->ctx, -2); // [emit][this]
duk_push_string(emitter->ctx, "uncaughtException"); // [emit][this][eventName]
- duk_push_error_object(emitter->ctx, DUK_ERR_UNCAUGHT_ERROR, "%s", dest);
+ duk_push_error_object(emitter->ctx, DUK_ERR_ERROR, "%s", dest);
duk_pcall_method(emitter->ctx, 2);
duk_pop(emitter->ctx); // ...
}
@@ -533,18 +529,11 @@ duk_ret_t ILibDuktape_IndependentFinalizer_Dispatch(duk_context *ctx)
handler(ctx, duk_get_heapptr(ctx, -1));
return 0;
}
-void ILibDuktape_CreateIndependentFinalizer(duk_context *ctx, ILibDuktape_IndependentFinalizerHandler handler)
-{
- char tmp[255];
- duk_push_object(ctx); // [obj]
- duk_push_pointer(ctx, handler); // [obj][ptr]
- duk_put_prop_string(ctx, -2, "ptr"); // [obj]
- duk_dup(ctx, -2); // [obj][parent]
- duk_put_prop_string(ctx, -2, "parent"); // [obj]
- ILibDuktape_CreateFinalizer(ctx, ILibDuktape_IndependentFinalizer_Dispatch);
- sprintf_s(tmp, sizeof(tmp), "\xFF_%s", Duktape_GetStashKey(duk_get_heapptr(ctx, -1)));
- duk_put_prop_string(ctx, -2, tmp);
+void ILibDuktape_CreateFinalizer(duk_context *ctx, duk_c_function func)
+{
+ ILibDuktape_EventEmitter_Create(ctx);
+ ILibDuktape_EventEmitter_PrependOnce(ctx, -1, "~", func);
}
duk_ret_t ILibDuktape_CreateProperty_InstanceMethod_Sink(duk_context *ctx)
{
@@ -630,10 +619,14 @@ int ILibDuktape_IsPointerValid(void *chain, void *ptr)
{
return(ILibHashtable_Get(ILibChain_GetBaseHashtable(chain), ptr, NULL, 0) == NULL ? 0 : 1);
}
-void ILibDuktape_PointerValidation_Finalizer(duk_context *ctx, void *obj)
+duk_ret_t ILibDuktape_PointerValidation_Finalizer(duk_context *ctx)
{
+ duk_push_this(ctx);
void *chain = Duktape_GetChain(ctx);
+ void *obj = duk_get_heapptr(ctx, -1);
ILibDuktape_InValidatePointer(chain, obj);
+ duk_pop(ctx);
+ return(0);
}
void ILibDuktape_PointerValidation_Init(duk_context *ctx)
{
@@ -642,7 +635,7 @@ void ILibDuktape_PointerValidation_Init(duk_context *ctx)
{
// Not set up yet, so set it up
ILibDuktape_ValidatePointer(chain, duk_get_heapptr(ctx, -1));
- ILibDuktape_CreateIndependentFinalizer(ctx, ILibDuktape_PointerValidation_Finalizer);
+ ILibDuktape_CreateFinalizer(ctx, ILibDuktape_PointerValidation_Finalizer);
}
}
duk_ret_t ILibDuktape_Immediate_Sink(duk_context *ctx)
@@ -664,14 +657,17 @@ duk_ret_t ILibDuktape_Immediate_Sink(duk_context *ctx)
}
}
- duk_push_heap_stash(ctx); // [immediate][array][stash]
- duk_del_prop_string(ctx, -1, Duktape_GetStashKey(duk_get_heapptr(ctx, -3)));
if (userCallback != NULL) { userCallback(ctx, args, argsLen); }
+
+ duk_push_heap_stash(ctx); // [stash]
+ duk_push_this(ctx); // [stash][immediate]
+ duk_del_prop_string(ctx, -2, Duktape_GetStashKey(duk_get_heapptr(ctx, -1)));
return(0);
}
-void ILibDuktape_Immediate(duk_context *ctx, void ** args, int argsLen, ILibDuktape_ImmediateHandler callback)
+void* ILibDuktape_Immediate(duk_context *ctx, void ** args, int argsLen, ILibDuktape_ImmediateHandler callback)
{
+ void *retval = NULL;
int i = 0;
duk_push_global_object(ctx); // [g]
duk_get_prop_string(ctx, -1, "setImmediate"); // [g][setImmediate]
@@ -690,13 +686,15 @@ void ILibDuktape_Immediate(duk_context *ctx, void ** args, int argsLen, ILibDukt
++i;
}
- if (duk_pcall_method(ctx, 3) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "ILibDuktape_Immediate => immediate(): "); duk_pop(ctx); return; }
+ if (duk_pcall_method(ctx, 3) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "ILibDuktape_Immediate => immediate(): "); duk_pop(ctx); return(NULL); }
- // [immediate]
+
+ retval = duk_get_heapptr(ctx, -1); // [immediate]
duk_push_heap_stash(ctx); // [immediate][stash]
duk_swap_top(ctx, -2); // [stash][immediate]
- duk_put_prop_string(ctx, -2, Duktape_GetStashKey(duk_get_heapptr(ctx, -1)));// [stash]
+ duk_put_prop_string(ctx, -2, Duktape_GetStashKey(retval)); // [stash]
duk_pop(ctx); // ...
+ return(retval);
}
void ILibDuktape_CreateInstanceMethodWithProperties(duk_context *ctx, char *funcName, duk_c_function funcImpl, duk_idx_t numArgs, unsigned int propertyCount, ...)
{
diff --git a/microscript/ILibDuktape_Helpers.h b/microscript/ILibDuktape_Helpers.h
index 28c17ac..71ef00e 100644
--- a/microscript/ILibDuktape_Helpers.h
+++ b/microscript/ILibDuktape_Helpers.h
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -61,7 +61,6 @@ void ILibDuktape_Process_UncaughtExceptionEx(duk_context *ctx, char *format, ...
duk_ret_t ILibDuktape_Error(duk_context *ctx, char *format, ...);
typedef void(*ILibDuktape_IndependentFinalizerHandler)(duk_context *ctx, void *object);
-void ILibDuktape_CreateIndependentFinalizer(duk_context *ctx, ILibDuktape_IndependentFinalizerHandler handler);
int ILibDuktape_Process_GetExitCode(duk_context *ctx);
void ILibDuktape_CreateEventWithGetter(duk_context *ctx, char *propName, duk_c_function getterMethod);
@@ -86,7 +85,7 @@ void ILibDuktape_CreateProperty_InstanceMethod(duk_context *ctx, char *methodNam
void ILibDuktape_CreateProperty_InstanceMethodEx(duk_context *ctx, char *methodName, void *funcHeapPtr);
void ILibDuktape_CreateReadonlyProperty(duk_context *ctx, char *propName);
#define ILibDuktape_CreateReadonlyProperty_int(ctx, propName, propValue) duk_push_int(ctx, propValue);ILibDuktape_CreateReadonlyProperty(ctx, propName)
-#define ILibDuktape_CreateFinalizer(context, funcImpl) duk_push_c_function(context, funcImpl, 1); duk_set_finalizer(context, -2);
+void ILibDuktape_CreateFinalizer(duk_context *ctx, duk_c_function func);
void *ILibDuktape_Memory_Alloc(duk_context *ctx, duk_size_t size);
void *ILibDuktape_Memory_AllocEx(duk_context *ctx, duk_idx_t index, duk_size_t size);
@@ -102,7 +101,8 @@ int ILibDuktape_IsPointerValid(void *chain, void *ptr);
#define ILibDuktape_InValidateHeapPointer(ctx, objIdx) ILibDuktape_InValidatePointer(Duktape_GetChain(ctx), duk_get_heapptr(ctx, objIdx))
typedef void(*ILibDuktape_ImmediateHandler)(duk_context *ctx, void ** args, int argsLen);
-void ILibDuktape_Immediate(duk_context *ctx, void ** args, int argsLen, ILibDuktape_ImmediateHandler callback);
+void* ILibDuktape_Immediate(duk_context *ctx, void ** args, int argsLen, ILibDuktape_ImmediateHandler callback);
+int ILibDuktape_GetReferenceCount(duk_context *ctx, duk_idx_t i);
#define ILibDuktape_WriteID(ctx, id) duk_push_string(ctx, id);duk_put_prop_string(ctx, -2, ILibDuktape_OBJID)
diff --git a/microscript/ILibDuktape_HttpStream.c b/microscript/ILibDuktape_HttpStream.c
index c648bd1..9a41870 100644
--- a/microscript/ILibDuktape_HttpStream.c
+++ b/microscript/ILibDuktape_HttpStream.c
@@ -1,3 +1,19 @@
+/*
+Copyright 2006 - 2018 Intel Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
#ifdef WIN32
#include
#include
@@ -29,7 +45,7 @@ extern void ILibWebClient_ResetWCDO(struct ILibWebClientDataObject *wcdo);
#define ILibDuktape_CR2Agent "\xFF_CR2Agent"
#define ILibDuktape_CR2HTTPStream "\xFF_CR2HTTPStream"
#define ILibDuktape_CR2TLSStream "\xFF_CR2TLSStream"
-#define ILibDuktape_CR2WS "\xFF_ClientRequest2WS"
+#define ILibDuktape_CR2Transform "\xFF_CR2Transform"
#define ILibDuktape_FUNC "\xFF_FUNC"
#define IILibDuktape_HTTP_HoldingQueue "\xFF_HoldingQueue"
#define ILibDuktape_Http_Server_FixedBuffer "\xFF_Http_Server_FixedBuffer"
@@ -41,7 +57,9 @@ extern void ILibWebClient_ResetWCDO(struct ILibWebClientDataObject *wcdo);
#define ILibDuktape_HTTP2PipedWritable "\xFF_HTTP2PipedWritable"
#define ILibDuktape_HTTPStream2Data "\xFF_HTTPStream2Data"
#define ILibDuktape_HTTPStream2HTTP "\xFF_HTTPStream2HTTP"
+#define ILibDuktape_HTTPStream2Socket "\xFF_HTTPStream2Socket"
#define ILibDuktape_IMSG2HttpStream "\xFF_IMSG2HttpStream"
+#define ILibDuktape_IMSG2Ptr "\xFF_IMSG2Ptr"
#define ILibDuktape_IMSG2SR "\xFF_IMSG2ServerResponse"
#define ILibDuktape_NS2HttpServer "\xFF_Http_NetServer2HttpServer"
#define ILibDuktape_Options2ClientRequest "\xFF_Options2ClientRequest"
@@ -52,16 +70,17 @@ extern void ILibWebClient_ResetWCDO(struct ILibWebClientDataObject *wcdo);
#define ILibDuktape_Socket2CR "\xFF_Socket2CR"
#define ILibDuktape_Socket2HttpServer "\xFF_Socket2HttpServer"
#define ILibDuktape_Socket2HttpStream "\xFF_Socket2HttpStream"
+#define ILibDuktape_Socket2DiedListener "\xFF_Socket2DiedListener"
#define ILibDuktape_Socket2TLS "\xFF_Socket2TLS"
#define ILibDuktape_SR2HttpStream "\xFF_ServerResponse2HttpStream"
#define ILibDuktape_SR2ImplicitHeaders "\xFF_ServerResponse2ImplicitHeaders"
#define ILibDuktape_SR2State "\xFF_ServerResponse2State"
#define ILibDuktape_SRUSER "\xFF_SRUSER"
#define ILibDuktape_SR2WS "\xFF_Http_ServerResponse2WS"
-#define ILibDuktape_TLS2CR "\xFF_TLS2CR"
#define ILibDuktape_WebSocket_Client ((void*)0x01)
#define ILibDuktape_WebSocket_Server ((void*)0x02)
#define ILibDuktape_WebSocket_StatePtr "\xFF_WebSocketState"
+#define ILibDuktape_WSENC2WS "\xFF_WSENC2WS"
#define ILibDuktape_WS2CR "\xFF_WS2ClientRequest"
#define ILibDuktape_WSDEC2WS "\xFF_WSDEC2WS"
@@ -73,6 +92,8 @@ typedef struct ILibDuktape_Http_ClientRequest_WriteData
int noMoreWrites;
int headersFinished;
int contentLengthSpecified;
+ int needRetry;
+ int retryCounter;
size_t bufferWriteLen;
size_t bufferLen;
}ILibDuktape_Http_ClientRequest_WriteData;
@@ -90,6 +111,7 @@ typedef struct ILibDuktape_HttpStream_Data
void *WCDO;
void *chain;
int ConnectMethod;
+ int endPropagated;
}ILibDuktape_HttpStream_Data;
typedef struct ILibDuktape_HttpStream_ServerResponse_State
@@ -129,6 +151,9 @@ typedef struct ILibDuktape_WebSocket_State
void *ObjectPtr; // Used to emit Ping/Pong events
duk_context *ctx; // Used to emit Ping/Pong events
+ int noResume;
+ int closed;
+
ILibDuktape_DuplexStream *encodedStream;
ILibDuktape_DuplexStream *decodedStream;
}ILibDuktape_WebSocket_State;
@@ -337,10 +362,10 @@ void ILibDuktape_HttpStream_http_ConvertOptionToSend(duk_context *ctx, void *Obj
while (duk_next(ctx, -1, 1))
{
tmp = (char*)duk_get_lstring(ctx, -2, &len);
- if (buffer != NULL) { memcpy_s(buffer + bufferLen, ILibMemory_AllocateA_Size(buffer) - bufferLen, tmp, len); (buffer + bufferLen)[len] = ':'; }
+ if (buffer != NULL) { memcpy_s(buffer + bufferLen, ILibMemory_AllocateA_Size(buffer) - bufferLen, tmp, len); (buffer + bufferLen)[len] = ':'; (buffer + bufferLen)[len + 1] = ' '; }
if (len == 6 && strncasecmp(tmp, "expect", 6) == 0) { expectSpecified = 1; }
if (len == 14 && strncasecmp(tmp, "content-length", 14) == 0) { data->contentLengthSpecified = 1; }
- bufferLen += (len + 1); // ('key:')
+ bufferLen += (len + 2); // ('key: ')
tmp = (char*)duk_get_lstring(ctx, -1, &len);
if (buffer != NULL) { memcpy_s(buffer + bufferLen, ILibMemory_AllocateA_Size(buffer) - bufferLen, tmp, len); (buffer + bufferLen)[len] = '\r'; (buffer + bufferLen)[len + 1] = '\n'; }
bufferLen += (len + 2); // ('value\r\n')
@@ -382,41 +407,21 @@ void ILibDuktape_HttpStream_http_ConvertOptionToSend(duk_context *ctx, void *Obj
duk_pop_n(ctx, 4); // ...
}
-duk_ret_t ILibDuktape_HttpStream_http_OnTLSConnect(duk_context *ctx)
+
+duk_ret_t ILibDuktape_HttpStream_http_WebSocket_closed(duk_context *ctx)
{
- duk_push_this(ctx); // [TLS]
-
- // ClientRequest Options => DecryptedTransform
- duk_get_prop_string(ctx, -1, ILibDuktape_TLS2CR); // [TLS][ClientRequest]
- duk_get_prop_string(ctx, -2, "clear"); // [TLS][ClientRequest][DecryptedTransform]
- duk_get_prop_string(ctx, -2, ILibDuktape_CR2Options); // [TLS][ClientRequest][DecryptedTransform][Options]
-
- ILibDuktape_HttpStream_http_ConvertOptionToSend(ctx, duk_get_heapptr(ctx, -2), duk_get_heapptr(ctx, -1));
-
- // ClientRequest => DecryptedTransform
- duk_pop(ctx); // [TLS][ClientRequest][DecryptedTransform]
- duk_get_prop_string(ctx, -2, "pipe"); // [TLS][ClientRequest][DecryptedTransform][pipe]
- duk_dup(ctx, -3); // [TLS][ClientRequest][DecryptedTransform][pipe][this]
- duk_dup(ctx, -3); // [TLS][ClientRequest][DecryptedTransform][pipe][this][DecryptedTransform]
- duk_push_object(ctx); // [TLS][ClientRequest][DecryptedTransform][pipe][this][DecryptedTransform][options]
- duk_push_false(ctx); duk_put_prop_string(ctx, -2, "end");
- if (duk_pcall_method(ctx, 2) != 0) { return(ILibDuktape_Error(ctx, "http.onTlsConnect() => Error calling pipe on Transform Stream: %s", duk_safe_to_string(ctx, -1))); }
- duk_pop_2(ctx); // [TLS][ClientRequest]
-
- // TLS EncryptedTransform => HTTP Stream
- duk_get_prop_string(ctx, -2, "encrypted"); // [TLS][ClientRequest][EncryptedTransform]
- duk_get_prop_string(ctx, -1, "pipe"); // [TLS][ClientRequest][EncryptedTransform][pipe]
- duk_swap_top(ctx, -2); // [TLS][ClientRequest][pipe][this]
- duk_get_prop_string(ctx, -3, ILibDuktape_CR2HTTPStream);// [TLS][ClientRequest][pipe][this][http]
- if (duk_pcall_method(ctx, 1) != 0) { return(ILibDuktape_Error(ctx, "http.onTlsConnect() => Error calling pipe: %s", duk_safe_to_string(ctx, -1))); }
- duk_pop(ctx); // [TLS][ClientRequest]
-
- duk_get_prop_string(ctx, -1, ILibDuktape_CR2HTTPStream);// [TLS][ClientRequest][http]
- duk_get_prop_string(ctx, -1, "pipe"); // [TLS][ClientRequest][http][pipe]
- duk_swap_top(ctx, -2); // [TLS][ClientRequest][pipe][this]
- duk_get_prop_string(ctx, -4, "clear"); // [TLS][ClientRequest][http][this][decryptedTransform]
- if (duk_pcall_method(ctx, 1) != 0) { return(ILibDuktape_Error(ctx, "http.onTlsConnect() => Error calling pipe: %s", duk_safe_to_string(ctx, -1))); }
-
+ duk_push_this(ctx); // [socket]
+ if (duk_has_prop_string(ctx, -1, ILibDuktape_Socket2CR))
+ {
+ duk_get_prop_string(ctx, -1, ILibDuktape_Socket2CR); // [socket][CR]
+ duk_push_undefined(ctx); // [socket][CR][undefined]
+ ILibDuktape_CreateReadonlyProperty(ctx, "socket"); // [socket][CR]
+ duk_pop(ctx); // [socket]
+ duk_del_prop_string(ctx, -1, ILibDuktape_Socket2CR);
+ }
+ duk_get_prop_string(ctx, -1, "unpipe"); // [socket][unpipe]
+ duk_swap_top(ctx, -2); // [unpipe][this]
+ duk_call_method(ctx, 0);
return(0);
}
duk_ret_t ILibDuktape_HttpStream_http_onUpgrade(duk_context *ctx)
@@ -436,11 +441,27 @@ duk_ret_t ILibDuktape_HttpStream_http_onUpgrade(duk_context *ctx)
// We were upgraded to WebSocket, so we need to create a WebSocket Stream, detach the HTTPStream, and emit the event
// Upstream Readable => X => HttpStream
duk_push_this(ctx); // [HTTPStream]
+ if (duk_has_prop_string(ctx, -1, ILibDuktape_HTTP2CR))
+ {
+ duk_get_prop_string(ctx, -1, ILibDuktape_HTTP2CR); // [HTTPStream][CR]
+ duk_del_prop_string(ctx, -1, ILibDuktape_CR2HTTPStream);
+ duk_pop(ctx); // [HTTPStream]
+ }
duk_get_prop_string(ctx, -1, ILibDuktape_HTTP2PipedReadable); // [HTTPStream][readable]
+ if (duk_has_prop_string(ctx, -1, ILibDuktape_Socket2HttpStream))
+ {
+ duk_del_prop_string(ctx, -1, ILibDuktape_Socket2HttpStream);
+ }
duk_get_prop_string(ctx, -1, "unpipe"); // [HTTPStream][readable][unpipe]
duk_dup(ctx, -2); // [HTTPStream][readable][unpipe][this]
duk_call_method(ctx, 0); // [HTTPStream][readable][...]
duk_pop(ctx); // [HTTPStream][readable]
+
+ duk_get_prop_string(ctx, -1, "prependOnceListener"); // [HTTPStream][readable][prepend]
+ duk_dup(ctx, -2); // [HTTPStream][readable][prepend][this]
+ duk_push_string(ctx, "close"); // [HTTPStream][readable][prepend][this]['close']
+ duk_push_c_function(ctx, ILibDuktape_HttpStream_http_WebSocket_closed, DUK_VARARGS);
+ duk_call_method(ctx, 2); duk_pop(ctx); // [HTTPStream][readable]
duk_push_external_buffer(ctx); // [HTTPStream][readable][ext]
duk_config_buffer(ctx, -1, decodedKey, decodedKeyLen);
@@ -453,8 +474,8 @@ duk_ret_t ILibDuktape_HttpStream_http_onUpgrade(duk_context *ctx)
duk_remove(ctx, -2); // [HTTPStream][readable][websocket]
duk_get_prop_string(ctx, -3, ILibDuktape_HTTP2CR); // [HTTPStream][readable][websocket][clientRequest]
- duk_dup(ctx, -2); // [HTTPStream][readable][websocket][clientRequest][websocket]
- duk_put_prop_string(ctx, -2, ILibDuktape_CR2WS); // [HTTPStream][readable][websocket][clientRequest]
+ //duk_dup(ctx, -2); // [HTTPStream][readable][websocket][clientRequest][websocket]
+ //duk_put_prop_string(ctx, -2, ILibDuktape_CR2WS); // [HTTPStream][readable][websocket][clientRequest]
duk_put_prop_string(ctx, -2, ILibDuktape_WS2CR); // [HTTPStream][readable][websocket]
// Upstream Readable => WebSocket Encoded
@@ -475,9 +496,10 @@ duk_ret_t ILibDuktape_HttpStream_http_onUpgrade(duk_context *ctx)
duk_call_method(ctx, 1); // [HTTPStream][websocket][...]
duk_pop(ctx); // [HTTPStream][websocket]
}
-
+
duk_get_prop_string(ctx, -1, ILibDuktape_WS2CR); // [HTTPStream][websocket][clientRequest]
duk_get_prop_string(ctx, -1, "emit"); // [HTTPStream][websocket][clientRequest][emit]
+
duk_swap_top(ctx, -2); // [HTTPStream][websocket][emit][this]
duk_push_string(ctx, "upgrade"); // [HTTPStream][websocket][emit][this][upgrade]
duk_dup(ctx, 0); // [HTTPStream][websocket][emit][this][upgrade][imsg]
@@ -486,7 +508,7 @@ duk_ret_t ILibDuktape_HttpStream_http_onUpgrade(duk_context *ctx)
duk_remove(ctx, -2); // [HTTPStream][websocket][emit][this][upgrade][imsg][WS_DEC]
duk_push_null(ctx); // [HTTPStream][websocket][emit][this][upgrade][imsg][WS_DEC][null]
duk_call_method(ctx, 4); duk_pop(ctx); // [HTTPStream][websocket]
-
+
return(0);
}
duk_ret_t ILibDuktape_HttpStream_http_endResponseSink(duk_context *ctx)
@@ -494,21 +516,34 @@ duk_ret_t ILibDuktape_HttpStream_http_endResponseSink(duk_context *ctx)
duk_push_this(ctx); // [imsg]
duk_get_prop_string(ctx, -1, ILibDuktape_IMSG2HttpStream); // [imsg][httpstream]
duk_get_prop_string(ctx, -1, ILibDuktape_HTTP2CR); // [imsg][httpstream][CR]
+
+ duk_del_prop_string(ctx, -3, ILibDuktape_IMSG2HttpStream);
+ duk_del_prop_string(ctx, -2, ILibDuktape_HTTP2CR);
+ duk_del_prop_string(ctx, -1, ILibDuktape_CR2HTTPStream);
+
+ duk_get_prop_string(ctx, -1, "unpipe"); // [imsg][httpstream][CR][unpipe]
+ duk_dup(ctx, -2); // [imsg][httpstream][CR][unpipe][this]
+ duk_call_method(ctx, 0); duk_pop(ctx); // [imsg][httpstream][CR]
+
+ duk_get_prop_string(ctx, -1, "socket"); // [imsg][httpstream][CR][socket]
+ duk_insert(ctx, -4); // [socket][imsg][httpstream][CR]
+ duk_push_undefined(ctx); // [socket][imsg][httpstream][CR][undefined]
+ ILibDuktape_CreateReadonlyProperty(ctx, "socket"); // [socket][imsg][httpstream][CR]
if (Duktape_GetBooleanProperty(ctx, -2, "connectionCloseSpecified", 0) != 0)
{
// We cant persist this connection, so close the socket.
// Agent is already listening for the 'close' event, so it'll cleanup automatically
- duk_get_prop_string(ctx, -1, "socket"); // [imsg][httpstream][CR][socket]
- duk_get_prop_string(ctx, -1, "end"); // [imsg][httpstream][CR][socket][end]
- duk_swap_top(ctx, -2); // [imsg][httpstream][CR][end][this]
+ duk_dup(ctx, -4); // [socket][imsg][httpstream][CR][socket]
+ duk_get_prop_string(ctx, -1, "end"); // [socket][imsg][httpstream][CR][socket][end]
+ duk_swap_top(ctx, -2); // [socket][imsg][httpstream][CR][end][this]
duk_call_method(ctx, 0);
return(0);
}
- duk_get_prop_string(ctx, -1, ILibDuktape_CR2Agent); // [imsg][httpstream][CR][Agent]
- duk_get_prop_string(ctx, -1, "keepSocketAlive"); // [imsg][httpstream][CR][Agent][keepSocketAlive]
- duk_swap_top(ctx, -2); // [imsg][httpstream][CR][keepSocketAlive][this]
- duk_get_prop_string(ctx, -3, "socket"); // [imsg][httpstream][CR][keepSocketAlive][this][socket]
- duk_call_method(ctx, 1); duk_pop(ctx); // [imsg][httpstream][CR]
+ duk_get_prop_string(ctx, -1, ILibDuktape_CR2Agent); // [socket][imsg][httpstream][CR][Agent]
+ duk_get_prop_string(ctx, -1, "keepSocketAlive"); // [socket][imsg][httpstream][CR][Agent][keepSocketAlive]
+ duk_swap_top(ctx, -2); // [socket][imsg][httpstream][CR][keepSocketAlive][this]
+ duk_dup(ctx, -6); // [socket][imsg][httpstream][CR][keepSocketAlive][this][socket]
+ duk_call_method(ctx, 1); duk_pop(ctx); // [socket][imsg][httpstream][CR]
return(0);
}
duk_ret_t ILibDuktape_HttpStream_http_responseSink(duk_context *ctx)
@@ -517,8 +552,92 @@ duk_ret_t ILibDuktape_HttpStream_http_responseSink(duk_context *ctx)
duk_dup(ctx, 0); // [httpstream][imsg]
duk_swap_top(ctx, -2); // [imsg][httpstream]
duk_put_prop_string(ctx, -2, ILibDuktape_IMSG2HttpStream); // [imsg]
-
ILibDuktape_EventEmitter_AddOnceEx3(ctx, 0, "end", ILibDuktape_HttpStream_http_endResponseSink);
+ duk_pop(ctx);
+ return(0);
+}
+duk_ret_t ILibDuktape_HttpStream_http_SocketDiedPrematurely(duk_context *ctx)
+{
+ duk_push_this(ctx); // [socket]
+ duk_get_prop_string(ctx, -1, ILibDuktape_Socket2CR); // [socket][clientRequest]
+ ILibDuktape_Transform *tf = (ILibDuktape_Transform*)Duktape_GetPointerProperty(ctx, -1, ILibDuktape_CR2Transform);
+ if (tf->target->resumeImmediate != NULL)
+ {
+ duk_push_global_object(ctx); // [g]
+ duk_get_prop_string(ctx, -1, "clearImmediate"); // [g][clearImmediate]
+ duk_swap_top(ctx, -2); // [clearImmediate][this]
+ duk_push_heapptr(ctx, tf->target->resumeImmediate); // [clearImmediate][this][immedate]
+ duk_call_method(ctx, 1); duk_pop(ctx); // ...
+ tf->target->resumeImmediate = NULL;
+ }
+
+ duk_get_prop_string(ctx, -1, "unpipe"); // [socket][clientRequest][unpipe]
+ duk_dup(ctx, -2); // [socket][clientRequest][unpipe][this]
+ duk_call_method(ctx, 0); duk_pop(ctx); // [socket][clientRequest]
+
+ ILibDuktape_ReadableStream_DestroyPausedData(tf->target);
+
+
+ // Need to specify some stuff, so the request body will go out again
+ duk_get_prop_string(ctx, -1, ILibDuktape_CR_RequestBuffer); // [socket][clientRequest][buffer]
+ ILibDuktape_Http_ClientRequest_WriteData *wdata = (ILibDuktape_Http_ClientRequest_WriteData*)Duktape_GetBuffer(ctx, -1, NULL);
+ ++wdata->retryCounter;
+ wdata->needRetry = 1;
+ wdata->bufferWriteLen = wdata->bufferLen;
+ wdata->headersFinished = 0;
+ duk_pop(ctx); // [socket][clientRequest]
+
+ if (wdata->retryCounter < 3)
+ {
+ duk_get_prop_string(ctx, -1, ILibDuktape_CR2Agent); // [socket][clientRequest][agent]
+ duk_get_prop_string(ctx, -1, "requests"); // [socket][clientReqeust][agent][requests]
+ duk_get_prop_string(ctx, -4, ILibDuktape_Socket2AgentKey); // [socket][clientRequest][agent][requests][key]
+ duk_get_prop(ctx, -2); // [socket][clientRequest][agent][requests][array]
+ if (!duk_is_undefined(ctx, -1))
+ {
+ // We need to prepend the clientRequest into the request Queue
+ duk_get_prop_string(ctx, -1, "unshift"); // [socket][clientRequest][agent][requests][array][unshift]
+ duk_swap_top(ctx, -2); // [socket][clientRequest][agent][requests][unshift][this]
+ duk_dup(ctx, -5); // [socket][clientRequest][agent][requests][unshift][this][clientRequest]
+ duk_call_method(ctx, 1);
+ }
+ }
+ else
+ {
+ ILibDuktape_EventEmitter_SetupEmit(ctx, duk_get_heapptr(ctx, -1), "error"); // [emit][this][error]
+ duk_push_error_object(ctx, DUK_ERR_ERROR, "Too many failed attempts"); // [emit][this][error][err]
+ duk_call_method(ctx, 2);
+ }
+ return(0);
+}
+duk_ret_t ILibDuktape_HttpStream_http_SocketResponseReceived(duk_context *ctx)
+{
+ duk_push_this(ctx); // [httpStream]
+ duk_get_prop_string(ctx, -1, ILibDuktape_HTTPStream2Socket); // [httpStream][socket]
+ duk_get_prop_string(ctx, -1, ILibDuktape_Socket2CR); // [httpStream][socket][CR]
+ duk_get_prop_string(ctx, -1, ILibDuktape_CR2Options); // [httpStream][socket][CR][Options]
+ duk_del_prop_string(ctx, -1, ILibDuktape_Options2ClientRequest);
+
+ duk_pop_2(ctx); // [httpStream][socket]
+ duk_del_prop_string(ctx, -1, ILibDuktape_Socket2CR);
+
+ duk_get_prop_string(ctx, -1, "removeListener"); // [httpStream][socket][removeListener]
+ duk_swap_top(ctx, -2); // [httpStream][removeListener][this]
+ duk_push_string(ctx, "close"); // [httpStream][removeListener][this][close]
+ duk_get_prop_string(ctx, -2, ILibDuktape_Socket2DiedListener); // [httpStream][removeListener][this][close][listener]
+ duk_call_method(ctx, 2);
+ return(0);
+}
+duk_ret_t ILibDuktape_HttpStream_http_OnSocketClosed(duk_context *ctx)
+{
+ duk_push_this(ctx); // [socket]
+ if (duk_has_prop_string(ctx, -1, ILibDuktape_Socket2HttpStream))
+ {
+ duk_get_prop_string(ctx, -1, ILibDuktape_Socket2HttpStream); // [socket][stream]
+ duk_pop(ctx); // [socket]
+ duk_del_prop_string(ctx, -1, ILibDuktape_Socket2HttpStream);
+ }
+ duk_pop(ctx); // ...
return(0);
}
duk_ret_t ILibDuktape_HttpStream_http_OnSocketReady(duk_context *ctx)
@@ -526,17 +645,54 @@ duk_ret_t ILibDuktape_HttpStream_http_OnSocketReady(duk_context *ctx)
void *httpStream;
duk_dup(ctx, 0); // [socket]
+ duk_push_c_function(ctx, ILibDuktape_HttpStream_http_SocketDiedPrematurely, DUK_VARARGS);
+ duk_put_prop_string(ctx, -2, ILibDuktape_Socket2DiedListener); // [socket]
+
duk_push_this(ctx); // [socket][clientRequest]
+ // Register ourselves for the close event, becuase we'll need to put ourselves back in the Queue if the socket dies before we are done
+ duk_get_prop_string(ctx, -2, "prependOnceListener"); // [socket][clientRequest][prependOnce]
+ duk_dup(ctx, -3); // [socket][clientRequest][prependOnce][this]
+ duk_push_string(ctx, "close"); // [socket][clientRequest][prependOnce][this][close]
+ duk_get_prop_string(ctx, -5, ILibDuktape_Socket2DiedListener); // [socket][clientRequest][prependOnce][this][close][listener]
+ duk_call_method(ctx, 2); duk_pop(ctx); // [socket][clientRequest]
+ duk_put_prop_string(ctx, -2, ILibDuktape_Socket2CR); // [socket]
+ duk_push_this(ctx); // [socket][clientRequest]
+
if (duk_has_prop_string(ctx, -2, ILibDuktape_Socket2HttpStream))
{
// HTTP and/or TLS was already setup previously
duk_get_prop_string(ctx, -2, ILibDuktape_Socket2HttpStream); // [socket][clientRequest][HTTPStream]
+ ILibDuktape_EventEmitter_AddOnceEx3(ctx, -1, "write", ILibDuktape_HttpStream_http_SocketResponseReceived);
+
duk_get_prop_string(ctx, -1, ILibDuktape_HTTPStream2Data); // [socket][clientRequest][HTTPStream][data]
ILibDuktape_HttpStream_Data *data = (ILibDuktape_HttpStream_Data*)Duktape_GetBuffer(ctx, -1, NULL);
ILibWebClient_ResetWCDO(data->WCDO);
if (data->bodyStream != NULL) { ILibDuktape_readableStream_WriteEnd(data->bodyStream); data->bodyStream = NULL; }
duk_pop(ctx); // [socket][clientRequest][HTTPStream]
+
+ // We need to change the events to propagate to the new clientRequest instead of the old one
+ duk_get_prop_string(ctx, -1, "removeAllListeners"); // [socket][clientRequest][HTTPStream][remove]
+ duk_dup(ctx, -2); // [socket][clientRequest][HTTPStream][remove][this]
+ duk_push_string(ctx, "response"); // [socket][clientRequest][HTTPStream][remove][this][response]
+ duk_call_method(ctx, 1); duk_pop(ctx); // [socket][clientRequest][HTTPStream]
+ duk_get_prop_string(ctx, -1, "removeAllListeners"); // [socket][clientRequest][HTTPStream][remove]
+ duk_dup(ctx, -2); // [socket][clientRequest][HTTPStream][remove][this]
+ duk_push_string(ctx, "continue"); // [socket][clientRequest][HTTPStream][remove][this][continue]
+ duk_call_method(ctx, 1); duk_pop(ctx); // [socket][clientRequest][HTTPStream]
+ duk_get_prop_string(ctx, -1, "removeAllListeners"); // [socket][clientRequest][HTTPStream][remove]
+ duk_dup(ctx, -2); // [socket][clientRequest][HTTPStream][remove][this]
+ duk_push_string(ctx, "upgrade"); // [socket][clientRequest][HTTPStream][remove][this][upgrade]
+ duk_call_method(ctx, 1); duk_pop(ctx); // [socket][clientRequest][HTTPStream]
+ duk_push_this(ctx); // [socket][clientRequest][HTTPStream][clientRequest]
+ duk_put_prop_string(ctx, -2, ILibDuktape_HTTP2CR); // [socket][clientRequest][HTTPStream]
+
+ ILibDuktape_EventEmitter_ForwardEvent(ctx, -1, "response", -2, "response");
+ ILibDuktape_EventEmitter_ForwardEvent(ctx, -1, "continue", -2, "continue");
+ ILibDuktape_EventEmitter_AddOnEx(ctx, -1, "upgrade", ILibDuktape_HttpStream_http_onUpgrade);
+ ILibDuktape_EventEmitter_AddOnEx(ctx, -1, "response", ILibDuktape_HttpStream_http_responseSink);
+
+
duk_get_prop_string(ctx, -1, ILibDuktape_HTTP2PipedWritable); // [socket][clientRequest][HTTPStream][destination]
duk_get_prop_string(ctx, -3, ILibDuktape_CR2Options); // [socket][clientRequest][HTTPStream][destination][Options]
ILibDuktape_HttpStream_http_ConvertOptionToSend(ctx, duk_get_heapptr(ctx, -2), duk_get_heapptr(ctx, -1));
@@ -573,13 +729,14 @@ duk_ret_t ILibDuktape_HttpStream_http_OnSocketReady(duk_context *ctx)
ILibDuktape_EventEmitter_ForwardEvent(ctx, -1, "continue", -2, "continue");
ILibDuktape_EventEmitter_AddOnEx(ctx, -1, "upgrade", ILibDuktape_HttpStream_http_onUpgrade);
ILibDuktape_EventEmitter_AddOnEx(ctx, -1, "response", ILibDuktape_HttpStream_http_responseSink);
+ ILibDuktape_EventEmitter_AddOnceEx3(ctx, -1, "write", ILibDuktape_HttpStream_http_SocketResponseReceived);
+ ILibDuktape_EventEmitter_AddOnceEx3(ctx, -3, "close", ILibDuktape_HttpStream_http_OnSocketClosed); // We need to detach HttpStream when socket closes
duk_put_prop_string(ctx, -2, ILibDuktape_CR2HTTPStream); // [socket][clientRequest]
-
duk_get_prop_string(ctx, -1, ILibDuktape_CR2Options); // [socket][clientRequest][options]
ILibDuktape_HttpStream_http_ConvertOptionToSend(ctx, duk_get_heapptr(ctx, -3), duk_get_heapptr(ctx, -1));
duk_pop(ctx); // [socket][clientRequest]
-
+
// ClientRequest => Socket
duk_get_prop_string(ctx, -1, "pipe"); // [socket][clientRequest][pipe]
duk_swap_top(ctx, -2); // [socket][pipe][this]
@@ -589,6 +746,12 @@ duk_ret_t ILibDuktape_HttpStream_http_OnSocketReady(duk_context *ctx)
if (duk_pcall_method(ctx, 2) != 0) { return(ILibDuktape_Error(ctx, "http.onConnect(): Error Piping with socket ")); }
duk_pop(ctx); // [socket]
+ // Save this value, so we can unregister 'close' from socket later
+ duk_push_heapptr(ctx, httpStream); // [socket][httpStream]
+ duk_dup(ctx, -2); // [socket][httpStream][socket]
+ duk_put_prop_string(ctx, -2, ILibDuktape_HTTPStream2Socket); // [socket][httpStream]
+ duk_pop(ctx); // [socket]
+
// Socket => HttpStream
duk_get_prop_string(ctx, -1, "pipe"); // [socket][pipe]
duk_dup(ctx, -2); // [socket][pipe][this]
@@ -601,8 +764,8 @@ duk_ret_t ILibDuktape_HttpStream_http_OnSocketReady(duk_context *ctx)
duk_get_prop_string(ctx, -1, "pipe"); // [socket][http][pipe]
duk_swap_top(ctx, -2); // [socket][pipe][this]
duk_dup(ctx, -3); // [socket][pipe][this][socket]
- if (duk_pcall_method(ctx, 1) != 0) { return(ILibDuktape_Error(ctx, "http.onConnect(): Error calling pipe ")); }
+ if (duk_pcall_method(ctx, 1) != 0) { return(ILibDuktape_Error(ctx, "http.onConnect(): Error calling pipe ")); }
return(0);
}
duk_ret_t ILibDuktape_HttpStream_http_OnConnectError(duk_context *ctx)
@@ -708,37 +871,7 @@ duk_ret_t ILibDuktape_HttpStream_http_OnConnect(duk_context *ctx)
{
duk_ret_t retVal = 0;
duk_push_this(ctx); // [socket]
- duk_get_prop_string(ctx, -1, ILibDuktape_SOCKET2OPTIONS); // [socket][options]
-
- //if (duk_has_prop_string(ctx, -1, "proxy"))
- //{
- // duk_get_prop_string(ctx, -1, "proxy"); // [socket][options][proxy]
- // duk_size_t remoteHostLen;
- // char *remoteHost = (char*)Duktape_GetStringPropertyValueEx(ctx, -1, "remoteHost", NULL, &remoteHostLen);
- // int remotePort = Duktape_GetIntPropertyValue(ctx, -1, "remotePort", 0);
-
- // if (remoteHost != NULL && remotePort != 0)
- // {
- // duk_pop_2(ctx); // [socket]
- // ILibDuktape_EventEmitter_AddOnEx(ctx, -1, "data", ILibDuktape_HttpStream_http_proxyData);
-
- // duk_get_prop_string(ctx, -1, "write"); // [socket][write]
- // duk_swap_top(ctx, -2); // [write][this]
-
- // char *tmp = (char*)ILibMemory_AllocateA((2 * remoteHostLen) + 72);
- // sprintf_s(tmp, ILibMemory_AllocateA_Size(tmp), "CONNECT %s:%u HTTP/1.1\r\nProxy-Connection: keep-alive\r\nHost: %s\r\n\r\n", remoteHost, remotePort, remoteHost);
- // duk_push_string(ctx, tmp); // [write][this][chunk]
- // duk_call_method(ctx, 1);
- // return(0);
- // }
- // else
- // {
- // duk_pop(ctx); // [socket][options]
- // }
- //}
-
- duk_pop(ctx); // [socket]
if (duk_has_prop_string(ctx, -1, ILibDuktape_Socket2CR))
{
// Socket was created with passed in createConnection
@@ -781,7 +914,7 @@ void ILibDuktape_HttpStream_http_request_transformPiped(struct ILibDuktape_Trans
ILibDuktape_readableStream_WriteData(sender->target, tmp, tmpLen);
if (data->bufferWriteLen > 0) { ILibDuktape_readableStream_WriteData(sender->target, data->buffer, (int)data->bufferWriteLen); }
}
- else if(data->bufferWriteLen > 0)
+ else if(data->needRetry != 0)
{
if (data->headersFinished)
{
@@ -790,15 +923,27 @@ void ILibDuktape_HttpStream_http_request_transformPiped(struct ILibDuktape_Trans
else
{
data->headersFinished = 1;
- tmpLen = sprintf_s(tmp, sizeof(tmp), "Transfer-Encoding: chunked\r\n\r\n%X\r\n", (unsigned int)data->bufferWriteLen);
+ if (data->contentLengthSpecified)
+ {
+ tmpLen = sprintf_s(tmp, sizeof(tmp), "Content-Length: %d\r\n\r\n", (int)data->bufferWriteLen);
+ }
+ else
+ {
+ tmpLen = sprintf_s(tmp, sizeof(tmp), "Transfer-Encoding: chunked\r\n\r\n%X\r\n", (unsigned int)data->bufferWriteLen);
+ }
}
ILibDuktape_readableStream_WriteData(sender->target, tmp, tmpLen);
- ILibDuktape_readableStream_WriteData(sender->target, data->buffer, (int)data->bufferWriteLen);
- ILibDuktape_readableStream_WriteData(sender->target, "\r\n", 2);
- free(data->buffer);
- data->buffer = NULL;
+ if (data->bufferWriteLen > 0)
+ {
+ ILibDuktape_readableStream_WriteData(sender->target, data->buffer, (int)data->bufferWriteLen);
+ if (!data->contentLengthSpecified) { ILibDuktape_readableStream_WriteData(sender->target, "\r\n", 2); }
+
+ free(data->buffer);
+ data->buffer = NULL;
+ }
data->bufferLen = data->bufferWriteLen = 0;
+ data->needRetry = 0;
}
}
void ILibDuktape_HttpStream_http_request_transform(struct ILibDuktape_Transform *sender, int Reserved, int flush, char *buffer, int bufferLen, void *user)
@@ -820,6 +965,13 @@ void ILibDuktape_HttpStream_http_request_transform(struct ILibDuktape_Transform
{
ILibDuktape_readableStream_WriteData(sender->target, buffer, bufferLen);
}
+ data->contentLengthSpecified = 1;
+ if (bufferLen > 0)
+ {
+ data->buffer = (char*)ILibMemory_Allocate(bufferLen, 0, NULL, NULL);
+ data->bufferLen = bufferLen;
+ memcpy_s(data->buffer, bufferLen, buffer, bufferLen);
+ }
}
else
{
@@ -844,11 +996,12 @@ void ILibDuktape_HttpStream_http_request_transform(struct ILibDuktape_Transform
}
}
+
duk_ret_t ILibDuktape_HttpStream_http_request(duk_context *ctx)
{
char *proto;
duk_size_t protoLen;
-
+ int isTLS = 0;
int nargs = duk_get_top(ctx);
if (duk_is_string(ctx, 0))
{
@@ -881,7 +1034,8 @@ duk_ret_t ILibDuktape_HttpStream_http_request(duk_context *ctx)
duk_put_prop_string(ctx, -2, "agent"); // [options][protocol][options]
duk_pop(ctx); // [options][protocol]
}
-
+ if ((protoLen == 4 && strncasecmp(proto, "wss:", 4) == 0) || (protoLen == 6 && strncasecmp(proto, "https:", 6) == 0)) { isTLS = 1; }
+
duk_pop(ctx); // [options]
if (!duk_has_prop_string(ctx, -1, "headers"))
{
@@ -912,15 +1066,16 @@ duk_ret_t ILibDuktape_HttpStream_http_request(duk_context *ctx)
duk_put_prop_string(ctx, -2, ILibDuktape_CR2HTTP); // [clientRequest]
duk_push_false(ctx);
- duk_put_prop_string(ctx, -2, ILibDuktape_CR_EndCalled); // [clientRequest]
- duk_push_fixed_buffer(ctx, sizeof(ILibDuktape_Http_ClientRequest_WriteData));
+ duk_put_prop_string(ctx, -2, ILibDuktape_CR_EndCalled); // [clientRequest]
+ duk_push_fixed_buffer(ctx, sizeof(ILibDuktape_Http_ClientRequest_WriteData)); // [clientRequest][buffer]
ILibDuktape_Http_ClientRequest_WriteData *wdata = (ILibDuktape_Http_ClientRequest_WriteData*)Duktape_GetBuffer(ctx, -1, NULL);
- duk_put_prop_string(ctx, -2, ILibDuktape_CR_RequestBuffer);
+ duk_put_prop_string(ctx, -2, ILibDuktape_CR_RequestBuffer); // [clientRequest]
memset(wdata, 0, sizeof(ILibDuktape_Http_ClientRequest_WriteData));
- ILibDuktape_Transform_Init(ctx, ILibDuktape_HttpStream_http_request_transform, ILibDuktape_HttpStream_http_request_transformPiped, wdata);
+ duk_push_pointer(ctx, ILibDuktape_Transform_Init(ctx, ILibDuktape_HttpStream_http_request_transform, ILibDuktape_HttpStream_http_request_transformPiped, wdata));
+ duk_put_prop_string(ctx, -2, ILibDuktape_CR2Transform); // [clientRequest]
- ILibDuktape_WriteID(ctx, "https.clientRequest");
+ ILibDuktape_WriteID(ctx, isTLS ? "https.clientRequest" : "http.clientRequest");
ILibDuktape_EventEmitter *emitter = ILibDuktape_EventEmitter_Create(ctx);
ILibDuktape_EventEmitter_CreateEventEx(emitter, "abort");
ILibDuktape_EventEmitter_CreateEventEx(emitter, "connect");
@@ -930,8 +1085,18 @@ duk_ret_t ILibDuktape_HttpStream_http_request(duk_context *ctx)
ILibDuktape_EventEmitter_CreateEventEx(emitter, "timeout");
ILibDuktape_EventEmitter_CreateEventEx(emitter, "upgrade");
ILibDuktape_EventEmitter_CreateEventEx(emitter, "error");
+ ILibDuktape_EventEmitter_AddOnEx(ctx, -1, "socket", ILibDuktape_HttpStream_http_OnSocketReady);
- ILibDuktape_EventEmitter_AddOnceEx3(ctx, -1, "socket", ILibDuktape_HttpStream_http_OnSocketReady);
+
+
+ if (nargs > 1 && duk_is_function(ctx, 1))
+ {
+ duk_get_prop_string(ctx, -1, "once"); // [clientRequest][once]
+ duk_dup(ctx, -2); // [clientRequest][once][this]
+ duk_push_string(ctx, "response"); // [clientRequest][once][this][response]
+ duk_dup(ctx, 1); // [clientRequest][once][this][response][handler]
+ duk_call_method(ctx, 2); duk_pop(ctx); // [clientRequest]
+ }
duk_dup(ctx, 0); // [clientRequest][options]
duk_put_prop_string(ctx, -2, ILibDuktape_CR2Options); // [clientReqeust]
@@ -1185,7 +1350,6 @@ duk_ret_t ILibDuktape_HttpStream_http_server_upgradeWebsocket(duk_context *ctx)
duk_get_prop_string(ctx, -1, "webSocketStream"); // [http][constructor]
duk_push_lstring(ctx, keyResult, keyResultLen); // [http][constructor][key]
duk_new(ctx, 1); // [http][wss]
-
duk_push_this(ctx); // [http][wss][socket]
duk_get_prop_string(ctx, -1, "pipe"); // [http][wss][socket][pipe]
@@ -1311,7 +1475,8 @@ duk_ret_t ILibDuktape_HttpStream_http_server_onConnection(duk_context *ctx)
//ILibDuktape_EventEmitter_ForwardEvent(ctx, -2, "close", -1, "close");
ILibDuktape_EventEmitter_ForwardEvent(ctx, -2, "connect", -1, "connect");
ILibDuktape_EventEmitter_ForwardEvent(ctx, -2, "request", -1, "request");
- ILibDuktape_EventEmitter_AddOnceEx3(ctx, -2, "upgrade", ILibDuktape_HttpStream_http_server_onUpgrade);
+ if (ILibDuktape_EventEmitter_HasListenersEx(ctx, -1, "upgrade") > 0) { ILibDuktape_EventEmitter_AddOnceEx3(ctx, -2, "upgrade", ILibDuktape_HttpStream_http_server_onUpgrade); }
+
duk_pop(ctx); // [NS][socket][pipe][this][httpStream]
duk_call_method(ctx, 1); duk_pop_2(ctx); // [NS]
@@ -1396,6 +1561,7 @@ duk_ret_t ILibDuktape_HttpStream_http_server_address(duk_context *ctx)
duk_call_method(ctx, 0); // [httpServer][result]
return(1);
}
+
duk_ret_t ILibDuktape_HttpStream_http_createServer(duk_context *ctx)
{
ILibDuktape_Http_Server *server;
@@ -1430,7 +1596,7 @@ duk_ret_t ILibDuktape_HttpStream_http_createServer(duk_context *ctx)
if (nargs > 0 && duk_is_function(ctx, 0))
{
- ILibDuktape_EventEmitter_AddOn(emitter, "request", duk_require_heapptr(ctx, 1));
+ ILibDuktape_EventEmitter_AddOn(emitter, "request", duk_require_heapptr(ctx, 0));
}
ILibDuktape_CreateInstanceMethod(ctx, "close", ILibDuktape_HttpStream_http_server_close, DUK_VARARGS);
@@ -1451,18 +1617,17 @@ duk_ret_t ILibDuktape_HttpStream_http_createServer(duk_context *ctx)
duk_get_prop_string(ctx, -1, "createServer"); // [server][nettls][createServer]
duk_swap_top(ctx, -2); // [server][createServer][this]
- if (nargs > 0 && duk_is_object(ctx, 0))
+ if (nargs > 0 && duk_is_object(ctx, 0) && !duk_is_function(ctx, 0))
{
// Options was specified
duk_dup(ctx, 0); // [server][createServer][this][options]
}
duk_push_c_function(ctx, ILibDuktape_HttpStream_http_server_onConnection, DUK_VARARGS);
- duk_call_method(ctx, (nargs > 0 && duk_is_object(ctx, 0)) ? 2 : 1); // [server][netServer]
+ duk_call_method(ctx, (nargs > 0 && duk_is_object(ctx, 0) && !duk_is_function(ctx, 0)) ? 2 : 1); // [server][netServer]
duk_dup(ctx, -2); // [server][netServer][server]
duk_put_prop_string(ctx, -2, ILibDuktape_NS2HttpServer); // [server][netServer]
duk_put_prop_string(ctx, -2, ILibDuktape_Http_Server2NetServer); // [server]
-
return(1);
}
@@ -1547,6 +1712,13 @@ ILibTransport_DoneState ILibDuktape_HttpStream_WriteSink(ILibDuktape_DuplexStrea
return(ILibTransport_DoneState_INCOMPLETE);
}
+ duk_push_heapptr(DS->readableStream->ctx, DS->ParentObject); // [httpStream]
+ duk_get_prop_string(DS->readableStream->ctx, -1, "emit"); // [httpStream][emit]
+ duk_swap_top(DS->readableStream->ctx, -2); // [emit][this]
+ duk_push_string(DS->readableStream->ctx, "write"); // [emit][this][write]
+ if (duk_pcall_method(DS->readableStream->ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(DS->readableStream->ctx, "httpStream.write(): Error dispatching 'write' event "); }
+ duk_pop(DS->readableStream->ctx); // ...
+
// We're already on Chain Thread, so we can just directly write
int beginPointer = 0;
int PAUSE = 0;
@@ -1571,7 +1743,7 @@ ILibTransport_DoneState ILibDuktape_HttpStream_WriteSink(ILibDuktape_DuplexStrea
duk_swap_top(stream->ctx, -2); // [extBuffer][unshift][this]
duk_push_buffer_object(stream->ctx, -3, 0, (int)bufferLen - beginPointer, DUK_BUFOBJ_NODEJS_BUFFER);// [extBuffer][unshift][this][buffer]
if (duk_pcall_method(stream->ctx, 1) != 0) { MustBuffer = 1; }
- duk_pop(stream->ctx); // ...
+ duk_pop_2(stream->ctx); // ...
}
else
{
@@ -1631,9 +1803,10 @@ void ILibDuktape_HttpStream_EndSink(ILibDuktape_DuplexStream *stream, void *user
{
ILibDuktape_HttpStream_Data *data = (ILibDuktape_HttpStream_Data*)user;
- if (data->bodyStream != NULL)
+ if (data->bodyStream != NULL && data->endPropagated == 0)
{
ILibDuktape_readableStream_WriteEnd(data->bodyStream);
+ data->endPropagated = 1;
}
}
void ILibDuktape_HttpStream_ServerResponse_WriteImplicitHeaders(void *chain, void *user)
@@ -1786,9 +1959,9 @@ ILibTransport_DoneState ILibDuktape_HttpStream_ServerResponse_WriteSink(struct I
tmp->writeStream = state->writeStream;
tmp->endBytes = stream->endBytes;
tmp->chunk = state->chunkSupported;
- if (bufferLen > 0) { memcpy_s(tmp->buffer, bufferLen, buffer, bufferLen); }
+ if (bufferLen > 0) { memcpy_s(tmp->buffer, bufferLen, buffer, bufferLen); tmp->bufferLen = bufferLen; }
- ILibDuktape_HttpStream_ServerResponse_WriteImplicitHeaders(NULL, &tmp);
+ ILibDuktape_HttpStream_ServerResponse_WriteImplicitHeaders(NULL, tmp);
return(ILibTransport_DoneState_COMPLETE);
}
else
@@ -2216,9 +2389,21 @@ void ILibDuktape_HttpStream_ServerResponse_PUSH(duk_context *ctx, void* writeStr
{
ILibDuktape_HttpStream_ServerResponse_State *state;
- duk_push_object(ctx); // [resp]
- duk_push_heapptr(ctx, httpStream); // [resp][httpStream]
- duk_put_prop_string(ctx, -2, ILibDuktape_SR2HttpStream); // [resp]
+ duk_push_object(ctx); // [resp]
+ duk_push_heapptr(ctx, httpStream); // [resp][httpStream]
+ duk_dup(ctx, -1); // [resp][httpStream][dup]
+ duk_put_prop_string(ctx, -3, ILibDuktape_SR2HttpStream); // [resp][httpStream]
+ duk_get_prop_string(ctx, -1, ILibDuktape_HTTPStream2HTTP); // [resp][httpStream][http]
+ duk_get_prop_string(ctx, -1, ILibDuktape_OBJID); // [resp][httpStream][http][id]
+ duk_remove(ctx, -2); // [resp][httpStream][id]
+ duk_get_prop_string(ctx, -1, "concat"); // [resp][httpStream][id][concat]
+ duk_swap_top(ctx, -2); // [resp][httpStream][concat][this]
+ duk_push_string(ctx, ".serverResponse"); // [resp][httpStream][concat][this][serverResponse]
+ if (duk_pcall_method(ctx, 1) != 0) { duk_pop(ctx); duk_push_string(ctx, "http[s].serverResponse"); } // [resp][httpStream][http/s.serverResponse]
+ duk_remove(ctx, -2); // [resp][http/s.serverResponse]
+ duk_put_prop_string(ctx, -2, ILibDuktape_OBJID); // [resp]
+
+
ILibDuktape_PointerValidation_Init(ctx);
ILibDuktape_WriteID(ctx, "http.serverResponse");
duk_push_fixed_buffer(ctx, sizeof(ILibDuktape_HttpStream_ServerResponse_State)); // [resp][state]
@@ -2408,11 +2593,27 @@ duk_ret_t ILibDuktape_HttpStream_IncomingMessage_Digest_ValidatePassword(duk_con
duk_push_int(ctx, retVal);
return(1);
}
+duk_ret_t ILibDuktape_HttpStream_IncomingMessage_finalizer(duk_context *ctx)
+{
+ return(0);
+}
void ILibDuktape_HttpStream_IncomingMessage_PUSH(duk_context *ctx, ILibHTTPPacket *header, void *httpstream)
{
duk_push_object(ctx); // [message]
+ ILibDuktape_CreateFinalizer(ctx, ILibDuktape_HttpStream_IncomingMessage_finalizer);
duk_push_heapptr(ctx, httpstream); // [message][httpStream]
- duk_put_prop_string(ctx, -2, ILibDuktape_IMSG2HttpStream); // [message]
+ duk_dup(ctx, -1); // [message][httpStream][dup]
+ duk_put_prop_string(ctx, -3, ILibDuktape_IMSG2HttpStream); // [message][httpStream]
+ duk_get_prop_string(ctx, -1, ILibDuktape_HTTPStream2HTTP); // [message][httpStream][http]
+ duk_remove(ctx, -2); // [message][http]
+ duk_get_prop_string(ctx, -1, ILibDuktape_OBJID); // [message][http][id]
+ duk_get_prop_string(ctx, -1, "concat"); // [message][http][id][concat]
+ duk_swap_top(ctx, -2); // [message][http][concat][this]
+ duk_push_string(ctx, ".IncomingMessage"); // [message][http][concat][this][.IncomingMessage]
+ if (duk_pcall_method(ctx, 1) != 0) { duk_pop(ctx); duk_push_string(ctx, "http[s].IncomingMessage"); }
+ duk_remove(ctx, -2); // [message][http/s.IncomingMessage]
+ duk_put_prop_string(ctx, -2, ILibDuktape_OBJID); // [message]
+
duk_push_object(ctx); // [message][headers]
packetheader_field_node *node = header->FirstField;
while (node != NULL)
@@ -2479,7 +2680,26 @@ void ILibDuktape_HttpStream_DispatchEnd(void *chain, void *user)
}
free(user);
}
+void ILibDuktape_HttpStream_ForceDisconnect(duk_context *ctx, void ** args, int argsLen)
+{
+ duk_push_heapptr(ctx, args[0]);
+ duk_get_prop_string(ctx, -1, "end");
+ duk_swap_top(ctx, -2);
+ if (duk_pcall_method(ctx, 0) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "httpStream.OnUpgrade(): "); }
+ duk_pop(ctx);
+}
+duk_ret_t ILibDuktape_HttpStream_OnReceive_bodyStreamFinalized(duk_context *ctx)
+{
+ ILibDuktape_HttpStream_Data *data = (ILibDuktape_HttpStream_Data*)Duktape_GetPointerProperty(ctx, 0, ILibDuktape_IMSG2Ptr);
+ if (data != NULL)
+ {
+ if (data->endPropagated == 0) { ILibDuktape_readableStream_WriteEnd(data->bodyStream); }
+ data->endPropagated = 1;
+ data->bodyStream = NULL;
+ }
+ return(0);
+}
void ILibDuktape_HttpStream_OnReceive(ILibWebClient_StateObject WebStateObject, int InterruptFlag, struct packetheader *header, char *bodyBuffer, int *beginPointer, int endPointer, ILibWebClient_ReceiveStatus recvStatus, void *user1, void *user2, int *PAUSE)
{
ILibDuktape_HttpStream_Data *data = (ILibDuktape_HttpStream_Data*)user1;
@@ -2525,7 +2745,22 @@ void ILibDuktape_HttpStream_OnReceive(ILibWebClient_StateObject WebStateObject,
ILibDuktape_HttpStream_IncomingMessage_PUSH(ctx, header, data->DS->ParentObject); // [emit][this][upgrade][imsg]
ILibDuktape_HttpStream_ServerResponse_PUSH(ctx, data->DS->writableStream->pipedReadable, header, data->DS->ParentObject); // [emit][this][request][imsg][rsp]
duk_put_prop_string(ctx, -2, ILibDuktape_IMSG2SR);
- if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "http.httpStream.onReceive->upgrade(): "); }
+ if (duk_pcall_method(ctx, 2) != 0)
+ { ILibDuktape_Process_UncaughtExceptionEx(ctx, "http.httpStream.onReceive->upgrade(): "); }
+ else
+ {
+ if (!duk_get_boolean(ctx, -1))
+ {
+ // No upgrade listener... Close connection
+ printf("\n\nNo Upgrade Listener\n");
+ void *imm = ILibDuktape_Immediate(ctx, (void*[]) { data->DS->writableStream->pipedReadable }, 1, ILibDuktape_HttpStream_ForceDisconnect);
+ duk_push_heapptr(ctx, imm);
+ duk_push_heapptr(ctx, data->DS->writableStream->pipedReadable);
+ duk_put_prop_string(ctx, -2, "r");
+ duk_pop_2(ctx);
+ return;
+ }
+ }
duk_pop(ctx); // ...
}
else
@@ -2604,15 +2839,27 @@ void ILibDuktape_HttpStream_OnReceive(ILibWebClient_StateObject WebStateObject,
case 101:
duk_push_string(ctx, "upgrade"); // [emit][this][upgrade]
ILibDuktape_HttpStream_IncomingMessage_PUSH(ctx, header, data->DS->ParentObject); // [emit][this][upgrade][imsg]
+ duk_del_prop_string(ctx, -1, ILibDuktape_IMSG2HttpStream);
+ duk_insert(ctx, -4); // [imsg][emit][this][upgrade]
+ duk_dup(ctx, -4); // [imsg][emit][this][upgrade][imsg]
if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "http.httpStream.onReceive->upgrade(): "); }
duk_pop(ctx);
+ duk_pop(ctx);
break;
default:
duk_push_string(ctx, "response"); // [emit][this][response]
ILibDuktape_HttpStream_IncomingMessage_PUSH(ctx, header, data->DS->ParentObject); // [emit][this][response][imsg]
data->bodyStream = ILibDuktape_ReadableStream_InitEx(ctx, ILibDuktape_HttpStream_IncomingMessage_PauseSink, ILibDuktape_HttpStream_IncomingMessage_ResumeSink, ILibDuktape_HttpStream_IncomingMessage_UnshiftBytes, data);
+ duk_push_pointer(ctx, data);
+ duk_put_prop_string(ctx, -2, ILibDuktape_IMSG2Ptr);
+ ILibDuktape_EventEmitter_AddOnEx(ctx, -1, "~", ILibDuktape_HttpStream_OnReceive_bodyStreamFinalized);
if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "http.httpStream.onReceive->response(): "); }
duk_pop(ctx);
+
+ if (bodyBuffer != NULL && endPointer > 0)
+ {
+ ILibDuktape_readableStream_WriteData(data->bodyStream, bodyBuffer + *beginPointer, endPointer);
+ }
break;
}
}
@@ -2620,6 +2867,7 @@ void ILibDuktape_HttpStream_OnReceive(ILibWebClient_StateObject WebStateObject,
if (data->bodyStream != NULL && recvStatus == ILibWebClient_ReceiveStatus_Complete)
{
ILibDuktape_readableStream_WriteEnd(data->bodyStream);
+ data->endPropagated = 1;
}
if (recvStatus == ILibWebClient_ReceiveStatus_Complete)
{
@@ -2651,7 +2899,6 @@ duk_ret_t ILibDuktape_HttpStream_Finalizer(duk_context *ctx)
ILibDuktape_InValidateHeapPointer(ctx, 0);
ILibWebClient_DestroyWebClientDataObject(data->WCDO);
-
return(0);
}
@@ -2702,6 +2949,7 @@ duk_ret_t ILibduktape_HttpStream_create(duk_context *ctx)
ILibDuktape_EventEmitter_CreateEventEx(emitter, "clientError");
ILibDuktape_EventEmitter_CreateEventEx(emitter, "request");
ILibDuktape_EventEmitter_CreateEventEx(emitter, "connect");
+ ILibDuktape_EventEmitter_CreateEventEx(emitter, "write");
data->DS = ILibDuktape_DuplexStream_InitEx(ctx, ILibDuktape_HttpStream_WriteSink, ILibDuktape_HttpStream_EndSink,
NULL, NULL, NULL, data);
@@ -2772,7 +3020,7 @@ void ILibDuktape_RemoveObjFromTable(duk_context *ctx, duk_idx_t tableIdx, char *
duk_ret_t ILibDuktape_HttpStream_Agent_socketEndSink(duk_context *ctx)
{
duk_push_this(ctx); // [socket]
- printf("socket has closed: %p\n", duk_get_heapptr(ctx, -1));
+ //printf("socket has closed: %p\n", duk_get_heapptr(ctx, -1));
duk_get_prop_string(ctx, -1, ILibDuktape_Socket2Agent); // [socket][agent]
duk_get_prop_string(ctx, -2, ILibDuktape_Socket2AgentKey); // [socket][agent][key]
char *key = Duktape_GetBuffer(ctx, -1, NULL);
@@ -2806,10 +3054,10 @@ duk_ret_t ILibDuktape_HttpStream_Agent_socketEndSink(duk_context *ctx)
duk_get_prop_string(ctx, -1, "createConnection"); // [socket][agent][agent][createConnection]
duk_swap_top(ctx, -2); // [socket][agent][createConnection][this]
duk_get_prop_string(ctx, -4, "\xFF_NET_SOCKET2OPTIONS"); // [socket][agent][createConnection][this][options]
- duk_call_method(ctx, 1); // [socket][agent][newsocket]
+ duk_push_c_function(ctx, ILibDuktape_HttpStream_http_OnConnect, DUK_VARARGS); // We need to register here, because TLS/NonTLS have different event names
+ duk_call_method(ctx, 2); // [socket][agent][newsocket]
duk_swap_top(ctx, -2); // [socket][newsocket][agent]
duk_put_prop_string(ctx, -2, ILibDuktape_Socket2Agent); // [socket][newsocket]
- ILibDuktape_EventEmitter_AddOnceEx3(ctx, -1, "connect", ILibDuktape_HttpStream_http_OnConnect);
ILibDuktape_EventEmitter_AddOnceEx3(ctx, -1, "error", ILibDuktape_HttpStream_http_OnConnectError);
}
}
@@ -2882,6 +3130,7 @@ duk_ret_t ILibDuktape_HttpStream_Agent_keepSocketAlive(duk_context *ctx)
duk_dup(ctx, -4); // [key][Agent][requests][request][reuseSocket][this][socket][request]
duk_call_method(ctx, 2); // [key][Agent][requests][request][retVal]
retVal = 1;
+ duk_pop(ctx); // [key][Agent][requests][request]
}
}
if (retVal == 0)
@@ -2917,6 +3166,11 @@ duk_ret_t ILibDuktape_HttpStream_Agent_keepSocketAlive(duk_context *ctx)
}
void ILibDuktape_HttpStream_Agent_reuseSocketEx(duk_context *ctx, void ** args, int argsLen)
{
+ duk_push_this(ctx); // [immediate]
+ duk_del_prop_string(ctx, -1, "CR");
+ duk_del_prop_string(ctx, -2, "Socket");
+ duk_pop(ctx); // ...
+
duk_push_heapptr(ctx, args[1]); // [clientRequest]
duk_push_heapptr(ctx, args[0]); // [clientRequest][socket]
@@ -2926,6 +3180,7 @@ void ILibDuktape_HttpStream_Agent_reuseSocketEx(duk_context *ctx, void ** args,
duk_call_method(ctx, 1); duk_pop(ctx); // [clientRequest][socket]
ILibDuktape_CreateReadonlyProperty(ctx, "socket"); // [clientRequest]
+
duk_get_prop_string(ctx, -1, "emit"); // [clientRequest][emit]
duk_swap_top(ctx, -2); // [emit][this]
duk_push_string(ctx, "socket"); // [emit][this][name]
@@ -2936,7 +3191,13 @@ void ILibDuktape_HttpStream_Agent_reuseSocketEx(duk_context *ctx, void ** args,
duk_ret_t ILibDuktape_HttpStream_Agent_reuseSocket(duk_context *ctx)
{
// Yield to the next loop, before we emit a 'socket' event, because emitting this event before anyone has the clientRequest object is pointless
- ILibDuktape_Immediate(ctx, (void*[]) { duk_get_heapptr(ctx, 0), duk_get_heapptr(ctx, 1) }, 2, ILibDuktape_HttpStream_Agent_reuseSocketEx);
+ void *imm = ILibDuktape_Immediate(ctx, (void*[]) { duk_get_heapptr(ctx, 0), duk_get_heapptr(ctx, 1) }, 2, ILibDuktape_HttpStream_Agent_reuseSocketEx);
+ duk_push_heapptr(ctx, imm); // [immediate]
+ duk_dup(ctx, 1); // [immediate][ClientRequest]
+ duk_put_prop_string(ctx, -2, "CR"); // [immediate]
+ duk_dup(ctx, 0); // [immediate][Socket]
+ duk_put_prop_string(ctx, -2, "Socket"); // [immediate]
+ duk_pop(ctx);
return(0);
}
duk_ret_t ILibDuktape_HttpStream_Agent_createConnection_eventSink(duk_context *ctx)
@@ -3144,8 +3405,15 @@ ILibTransport_DoneState ILibDuktape_httpStream_webSocket_WriteWebSocketPacket(IL
if (ILibIsRunningOnChainThread(state->chain) != 0)
{
// We're on the Duktape Thread, so we can just call write multiple times, cuz we won't interleave with JavaScript
- ILibDuktape_DuplexStream_WriteData(state->encodedStream, header, headerLen);
- retVal = ILibDuktape_DuplexStream_WriteData(state->encodedStream, buffer, bufferLen) == 0 ? ILibTransport_DoneState_COMPLETE : ILibTransport_DoneState_INCOMPLETE;
+ if (bufferLen > 0)
+ {
+ ILibDuktape_DuplexStream_WriteData(state->encodedStream, header, headerLen);
+ retVal = ILibDuktape_DuplexStream_WriteData(state->encodedStream, buffer, bufferLen) == 0 ? ILibTransport_DoneState_COMPLETE : ILibTransport_DoneState_INCOMPLETE;
+ }
+ else
+ {
+ retVal = ILibDuktape_DuplexStream_WriteData(state->encodedStream, header, headerLen) == 0 ? ILibTransport_DoneState_COMPLETE : ILibTransport_DoneState_INCOMPLETE;
+ }
}
else
{
@@ -3314,6 +3582,7 @@ ILibTransport_DoneState ILibDuktape_httpStream_webSocket_EncodedWriteSink(ILibDu
switch (OPCODE)
{
case WEBSOCKET_OPCODE_CLOSE:
+ state->closed = 1;
ILibDuktape_DuplexStream_WriteEnd(state->decodedStream);
if (ILibIsRunningOnChainThread(state->chain) != 0 && state->encodedStream->writableStream->pipedReadable != NULL)
{
@@ -3363,7 +3632,7 @@ ILibTransport_DoneState ILibDuktape_httpStream_webSocket_EncodedWriteSink(ILibDu
void ILibDuktape_httpStream_webSocket_EncodedEndSink(ILibDuktape_DuplexStream *stream, void *user)
{
ILibDuktape_WebSocket_State *state = (ILibDuktape_WebSocket_State*)user;
- ILibDuktape_DuplexStream_WriteEnd(state->decodedStream);
+ if (!state->closed) { ILibDuktape_DuplexStream_WriteEnd(state->decodedStream); }
}
void ILibDuktape_httpStream_webSocket_EncodedPauseSink_Chain(void *chain, void *user)
{
@@ -3453,6 +3722,14 @@ void ILibDuktape_httpStream_webSocket_DecodedPauseSink_Chain(void *chain, void *
ILibDuktape_WebSocket_State *state = (ILibDuktape_WebSocket_State*)user;
duk_context *ctx = state->encodedStream->writableStream->ctx;
+ if (state->encodedStream->writableStream->pipedReadable == NULL)
+ {
+ // We're not piped yet, so just set a flag, and we'll make sure we don't resume
+ state->noResume = 1;
+ return;
+ }
+
+
duk_push_heapptr(ctx, state->encodedStream->writableStream->pipedReadable); // [readable]
duk_get_prop_string(ctx, -1, "pause"); // [readable][pause]
duk_swap_top(ctx, -2); // [pause][this]
@@ -3485,6 +3762,12 @@ void ILibDuktape_httpStream_webSocket_DecodedResumeSink_Chain(void *chain, void
ILibDuktape_WebSocket_State *state = (ILibDuktape_WebSocket_State*)user;
duk_context *ctx = state->encodedStream->writableStream->ctx;
+ if (state->encodedStream->writableStream->pipedReadable == NULL)
+ {
+ state->noResume = 0;
+ return;
+ }
+
duk_push_heapptr(ctx, state->encodedStream->writableStream->pipedReadable); // [readable]
duk_get_prop_string(ctx, -1, "resume"); // [readable][resume]
duk_swap_top(ctx, -2); // [resume][this]
@@ -3521,6 +3804,17 @@ duk_ret_t ILibDuktape_httpStream_webSocketStream_finalizer(duk_context *ctx)
{
void *chain = Duktape_GetChain(ctx);
duk_get_prop_string(ctx, 0, ILibDuktape_WebSocket_StatePtr);
+ ILibDuktape_WebSocket_State *state = (ILibDuktape_WebSocket_State*)Duktape_GetBuffer(ctx, -1, NULL);
+
+ if (state->encodedStream->writableStream->pipedReadable != NULL)
+ {
+ duk_push_heapptr(ctx, state->encodedStream->writableStream->pipedReadable); // [readable]
+ duk_get_prop_string(ctx, -1, "unpipe"); // [readable][unpipe]
+ duk_swap_top(ctx, -2); // [unpipe][this]
+ duk_push_heapptr(ctx, state->encodedStream->writableStream->obj); // [unpipe][this][ws]
+ duk_call_method(ctx, 1); duk_pop(ctx); // ...
+ }
+
ILibDuktape_InValidatePointer(chain, Duktape_GetBuffer(ctx, -1, NULL));
return(0);
}
@@ -3544,6 +3838,24 @@ duk_ret_t ILibDuktape_httpStream_webSocketStream_sendPong(duk_context *ctx)
ILibDuktape_httpStream_webSocket_WriteWebSocketPacket(state, WEBSOCKET_OPCODE_PONG, NULL, 0, ILibWebClient_WebSocket_FragmentFlag_Complete);
return(0);
}
+duk_ret_t ILibDuktape_httpStream_webSocketStream_encodedPiped(duk_context *ctx)
+{
+ // Someone Piped to the Encoded Stream
+ duk_push_this(ctx); // [ENC]
+ duk_get_prop_string(ctx, -1, ILibDuktape_WSENC2WS); // [ENC][WS]
+ duk_get_prop_string(ctx, -1, ILibDuktape_WebSocket_StatePtr); // [ENC][WS][state]
+
+ ILibDuktape_WebSocket_State *state = (ILibDuktape_WebSocket_State*)Duktape_GetBuffer(ctx, -1, NULL);
+ if (state->noResume)
+ {
+ state->noResume = 0;
+ duk_push_heapptr(state->ctx, state->encodedStream->writableStream->pipedReadable); // [Readable]
+ duk_get_prop_string(state->ctx, -1, "pause"); // [Readable][pause]
+ duk_swap_top(ctx, -2); // [pause][this]
+ duk_call_method(ctx, 0);
+ }
+ return(0);
+}
duk_ret_t ILibDuktape_httpStream_webSocketStream_new(duk_context *ctx)
{
@@ -3562,6 +3874,10 @@ duk_ret_t ILibDuktape_httpStream_webSocketStream_new(duk_context *ctx)
duk_push_object(ctx); // [WebSocket][Encoded]
ILibDuktape_WriteID(ctx, "http.WebSocketStream.encoded");
state->encodedStream = ILibDuktape_DuplexStream_InitEx(ctx, ILibDuktape_httpStream_webSocket_EncodedWriteSink, ILibDuktape_httpStream_webSocket_EncodedEndSink, ILibDuktape_httpStream_webSocket_EncodedPauseSink, ILibDuktape_httpStream_webSocket_EncodedResumeSink, ILibDuktape_httpStream_webSocket_EncodedUnshiftSink, state);
+ ILibDuktape_EventEmitter_AddOnEx(ctx, -1, "pipe", ILibDuktape_httpStream_webSocketStream_encodedPiped);
+ duk_dup(ctx, -2); // [WebSocket][Encoded][WebSocket]
+ duk_put_prop_string(ctx, -2, ILibDuktape_WSENC2WS); // [WebSocket][Encoded]
+
ILibDuktape_CreateReadonlyProperty(ctx, "encoded"); // [WebSocket]
duk_push_object(ctx); // [WebSocket][Decoded]
ILibDuktape_WriteID(ctx, "http.WebSocketStream.decoded");
diff --git a/microscript/ILibDuktape_MemoryStream.c b/microscript/ILibDuktape_MemoryStream.c
index ca055f7..6b5528b 100644
--- a/microscript/ILibDuktape_MemoryStream.c
+++ b/microscript/ILibDuktape_MemoryStream.c
@@ -1,3 +1,19 @@
+/*
+Copyright 2006 - 2018 Intel Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
#include "duktape.h"
#include "ILibDuktapeModSearch.h"
#include "ILibDuktape_Helpers.h"
diff --git a/microscript/ILibDuktape_NetworkMonitor.c b/microscript/ILibDuktape_NetworkMonitor.c
index de5d43d..204cec2 100644
--- a/microscript/ILibDuktape_NetworkMonitor.c
+++ b/microscript/ILibDuktape_NetworkMonitor.c
@@ -1,3 +1,18 @@
+/*
+Copyright 2006 - 2018 Intel Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
#include "duktape.h"
#include "ILibDuktapeModSearch.h"
@@ -15,9 +30,6 @@ typedef struct ILibDuktape_NetworkMonitor
ILibDuktape_EventEmitter *emitter;
ILibIPAddressMonitor addressMonitor;
ILibHashtable *addressTable;
- void *OnChange;
- void *OnAdded;
- void *OnRemoved;
}ILibDuktape_NetworkMonitor;
@@ -63,45 +75,31 @@ ILibHashtable ILibDuktape_NetworkMonitor_CreateTable(duk_context *ctx)
void ILibDuktape_NetworkMonitor_EventSink_OnEnumerateCurrent(ILibHashtable sender, void *Key1, char* Key2, int Key2Len, void *Data, void *user)
{
duk_context *ctx = (duk_context*)((void**)user)[0];
- void *OnEvent = ((void**)user)[1];
+ char *eventName = (char*)((void**)user)[1];
void *Self = ((void**)user)[2];
ILibHashtable other = (ILibHashtable)((void**)user)[3];
if (ILibHashtable_Get(other, NULL, Key2, Key2Len) == NULL)
{
- if (OnEvent != NULL)
- {
- duk_push_heapptr(ctx, OnEvent); // [func]
- duk_push_heapptr(ctx, Self); // [func][this]
- duk_push_lstring(ctx, Key2, (duk_size_t)Key2Len); // [func][this][address]
- if (duk_pcall_method(ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "NetworkMonitor.OnAdd/Remove(): "); }
- duk_pop(ctx);
- }
+ ILibDuktape_EventEmitter_SetupEmit(ctx, Self, eventName); // [emit][this][eventName]
+ duk_push_lstring(ctx, Key2, (duk_size_t)Key2Len); // [emit][this][eventName][address]
+ if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "NetworkMonitor.OnAdd/Remove(): "); }
+ duk_pop(ctx);
}
}
void ILibDuktape_NetworkMonitor_EventSink(ILibIPAddressMonitor sender, void *user)
{
ILibDuktape_NetworkMonitor *nm = (ILibDuktape_NetworkMonitor*)user;
- if (nm->OnChange != NULL)
- {
- duk_push_heapptr(nm->ctx, nm->OnChange); // [func]
- duk_push_heapptr(nm->ctx, nm->emitter->object); // [func][this]
- if (duk_pcall_method(nm->ctx, 0) != 0) { ILibDuktape_Process_UncaughtExceptionEx(nm->ctx, "NetworkMonitor.change(): "); }
- duk_pop(nm->ctx); // ...
- }
+
+ ILibDuktape_EventEmitter_SetupEmit(nm->ctx, nm->emitter->object, "change"); // [emit][this][change]
+ if (duk_pcall_method(nm->ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(nm->ctx, "NetworkMonitor.change(): "); }
+ duk_pop(nm->ctx); // ...
+
ILibHashtable current = ILibDuktape_NetworkMonitor_CreateTable(nm->ctx);
+ ILibHashtable_Enumerate(current, ILibDuktape_NetworkMonitor_EventSink_OnEnumerateCurrent, (void*[]){ nm->ctx, "add", nm->emitter->object, nm->addressTable });
+ ILibHashtable_Enumerate(nm->addressTable, ILibDuktape_NetworkMonitor_EventSink_OnEnumerateCurrent, (void*[]) { nm->ctx, "remove", nm->emitter->object, current });
- if (nm->OnAdded != NULL)
- {
- void *data[] = { nm->ctx, nm->OnAdded, nm->emitter->object, nm->addressTable };
- ILibHashtable_Enumerate(current, ILibDuktape_NetworkMonitor_EventSink_OnEnumerateCurrent, data);
- }
- if(nm->OnRemoved != NULL)
- {
- void *data[] = { nm->ctx, nm->OnRemoved, nm->emitter->object, current };
- ILibHashtable_Enumerate(nm->addressTable, ILibDuktape_NetworkMonitor_EventSink_OnEnumerateCurrent, data);
- }
ILibHashtable_Destroy(nm->addressTable);
nm->addressTable = current;
@@ -130,9 +128,9 @@ void ILibDuktape_NetworkMonitor_PUSH(duk_context *ctx, void *chain)
nm->emitter = ILibDuktape_EventEmitter_Create(ctx);
nm->addressMonitor = ILibIPAddressMonitor_Create(chain, ILibDuktape_NetworkMonitor_EventSink, nm);
- ILibDuktape_EventEmitter_CreateEvent(nm->emitter, "change", &(nm->OnChange));
- ILibDuktape_EventEmitter_CreateEvent(nm->emitter, "add", &(nm->OnAdded));
- ILibDuktape_EventEmitter_CreateEvent(nm->emitter, "remove", &(nm->OnRemoved));
+ ILibDuktape_EventEmitter_CreateEventEx(nm->emitter, "change");
+ ILibDuktape_EventEmitter_CreateEventEx(nm->emitter, "add");
+ ILibDuktape_EventEmitter_CreateEventEx(nm->emitter, "remove");
ILibDuktape_CreateFinalizer(ctx, ILibDuktape_NetworkMonitor_Finalizer);
//
diff --git a/microscript/ILibDuktape_NetworkMonitor.h b/microscript/ILibDuktape_NetworkMonitor.h
index a94b3d9..fdbf0ed 100644
--- a/microscript/ILibDuktape_NetworkMonitor.h
+++ b/microscript/ILibDuktape_NetworkMonitor.h
@@ -1,3 +1,19 @@
+/*
+Copyright 2006 - 2018 Intel Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
#ifndef __ILIBDUKTAPE_NETWORKMONITOR__
#define __ILIBDUKTAPE_NETWORKMONITOR__
diff --git a/microscript/ILibDuktape_Polyfills.c b/microscript/ILibDuktape_Polyfills.c
index 480fc75..be4ee36 100644
--- a/microscript/ILibDuktape_Polyfills.c
+++ b/microscript/ILibDuktape_Polyfills.c
@@ -1,3 +1,19 @@
+/*
+Copyright 2006 - 2018 Intel Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
#include "duktape.h"
#include "ILibDuktape_Helpers.h"
#include "ILibDuktapeModSearch.h"
@@ -9,7 +25,10 @@
#define ILibDuktape_Timer_Ptrs "\xFF_DuktapeTimer_PTRS"
#define ILibDuktape_Queue_Ptr "\xFF_Queue"
-
+#define ILibDuktape_Stream_Buffer "\xFF_BUFFER"
+#define ILibDuktape_Stream_ReadablePtr "\xFF_ReadablePtr"
+int g_displayStreamPipeMessages = 0;
+int g_displayFinalizerMessages = 0;
duk_ret_t ILibDuktape_Pollyfills_Buffer_slice(duk_context *ctx)
{
@@ -157,23 +176,23 @@ duk_ret_t ILibDuktape_Polyfills_Buffer_alloc(duk_context *ctx)
}
void ILibDuktape_Polyfills_Buffer(duk_context *ctx)
{
- // Polyfill 'Buffer.slice'
- duk_get_prop_string(ctx, -1, "Duktape"); // [g][Duktape]
- duk_get_prop_string(ctx, -1, "Buffer"); // [g][Duktape][Buffer]
- duk_get_prop_string(ctx, -1, "prototype"); // [g][Duktape][Buffer][prototype]
- duk_push_c_function(ctx, ILibDuktape_Pollyfills_Buffer_slice, DUK_VARARGS); // [g][Duktape][Buffer][prototype][func]
- duk_put_prop_string(ctx, -2, "slice"); // [g][Duktape][Buffer][prototype]
- duk_push_c_function(ctx, ILibDuktape_Polyfills_Buffer_readInt32BE, DUK_VARARGS);// [g][Duktape][Buffer][prototype][func]
- duk_put_prop_string(ctx, -2, "readInt32BE"); // [g][Duktape][Buffer][prototype]
- duk_pop_3(ctx); // [g]
+ //// Polyfill 'Buffer.slice'
+ //duk_get_prop_string(ctx, -1, "Duktape"); // [g][Duktape]
+ //duk_get_prop_string(ctx, -1, "Buffer"); // [g][Duktape][Buffer]
+ //duk_get_prop_string(ctx, -1, "prototype"); // [g][Duktape][Buffer][prototype]
+ //duk_push_c_function(ctx, ILibDuktape_Pollyfills_Buffer_slice, DUK_VARARGS); // [g][Duktape][Buffer][prototype][func]
+ //duk_put_prop_string(ctx, -2, "slice"); // [g][Duktape][Buffer][prototype]
+ //duk_push_c_function(ctx, ILibDuktape_Polyfills_Buffer_readInt32BE, DUK_VARARGS);// [g][Duktape][Buffer][prototype][func]
+ //duk_put_prop_string(ctx, -2, "readInt32BE"); // [g][Duktape][Buffer][prototype]
+ //duk_pop_3(ctx); // [g]
- // Polyfill 'Buffer.toString()
- duk_get_prop_string(ctx, -1, "Duktape"); // [g][Duktape]
- duk_get_prop_string(ctx, -1, "Buffer"); // [g][Duktape][Buffer]
- duk_get_prop_string(ctx, -1, "prototype"); // [g][Duktape][Buffer][prototype]
- duk_push_c_function(ctx, ILibDuktape_Polyfills_Buffer_toString, DUK_VARARGS); // [g][Duktape][Buffer][prototype][func]
- duk_put_prop_string(ctx, -2, "toString"); // [g][Duktape][Buffer][prototype]
- duk_pop_3(ctx); // [g]
+ //// Polyfill 'Buffer.toString()
+ //duk_get_prop_string(ctx, -1, "Duktape"); // [g][Duktape]
+ //duk_get_prop_string(ctx, -1, "Buffer"); // [g][Duktape][Buffer]
+ //duk_get_prop_string(ctx, -1, "prototype"); // [g][Duktape][Buffer][prototype]
+ //duk_push_c_function(ctx, ILibDuktape_Polyfills_Buffer_toString, DUK_VARARGS); // [g][Duktape][Buffer][prototype][func]
+ //duk_put_prop_string(ctx, -2, "toString"); // [g][Duktape][Buffer][prototype]
+ //duk_pop_3(ctx); // [g]
// Polyfill Buffer.from()
duk_get_prop_string(ctx, -1, "Buffer"); // [g][Buffer]
@@ -313,6 +332,31 @@ duk_ret_t ILibDuktape_Polyfills_Console_enableWebLog(duk_context *ctx)
#endif
return (0);
}
+duk_ret_t ILibDuktape_Polyfills_Console_displayStreamPipe_getter(duk_context *ctx)
+{
+ duk_push_int(ctx, g_displayStreamPipeMessages);
+ return(1);
+}
+duk_ret_t ILibDuktape_Polyfills_Console_displayStreamPipe_setter(duk_context *ctx)
+{
+ g_displayStreamPipeMessages = duk_require_int(ctx, 0);
+ return(0);
+}
+duk_ret_t ILibDuktape_Polyfills_Console_displayFinalizer_getter(duk_context *ctx)
+{
+ duk_push_int(ctx, g_displayFinalizerMessages);
+ return(1);
+}
+duk_ret_t ILibDuktape_Polyfills_Console_displayFinalizer_setter(duk_context *ctx)
+{
+ g_displayFinalizerMessages = duk_require_int(ctx, 0);
+ return(0);
+}
+duk_ret_t ILibDuktape_Polyfills_Console_logRefCount(duk_context *ctx)
+{
+ printf("Reference Count => %s[%p]:%d\n", Duktape_GetStringPropertyValue(ctx, 0, ILibDuktape_OBJID, "UNKNOWN"), duk_require_heapptr(ctx, 0), ILibDuktape_GetReferenceCount(ctx, 0) - 1);
+ return(0);
+}
void ILibDuktape_Polyfills_Console(duk_context *ctx)
{
// Polyfill console.log()
@@ -326,11 +370,12 @@ void ILibDuktape_Polyfills_Console(duk_context *ctx)
duk_dup(ctx, -1); // [g][console][console]
duk_put_prop_string(ctx, -3, "console"); // [g][console]
}
- duk_push_c_function(ctx, ILibDuktape_Polyfills_Console_log, DUK_VARARGS); // [g][console][log]
- duk_put_prop_string(ctx, -2, "log"); // [g][console]
+ ILibDuktape_CreateInstanceMethod(ctx, "log", ILibDuktape_Polyfills_Console_log, DUK_VARARGS);
ILibDuktape_CreateInstanceMethod(ctx, "enableWebLog", ILibDuktape_Polyfills_Console_enableWebLog, 1);
-
+ ILibDuktape_CreateEventWithGetterAndSetterEx(ctx, "displayStreamPipeMessages", ILibDuktape_Polyfills_Console_displayStreamPipe_getter, ILibDuktape_Polyfills_Console_displayStreamPipe_setter);
+ ILibDuktape_CreateEventWithGetterAndSetterEx(ctx, "displayFinalizerMessages", ILibDuktape_Polyfills_Console_displayFinalizer_getter, ILibDuktape_Polyfills_Console_displayFinalizer_setter);
+ ILibDuktape_CreateInstanceMethod(ctx, "logReferenceCount", ILibDuktape_Polyfills_Console_logRefCount, 1);
duk_pop(ctx); // [g]
}
duk_ret_t ILibDuktape_ntohl(duk_context *ctx)
@@ -404,6 +449,14 @@ duk_ret_t ILibDuktape_Polyfills_timer_finalizer(duk_context *ctx)
// Make sure we remove any timers just in case, so we don't leak resources
ILibDuktape_Timer *ptrs;
duk_get_prop_string(ctx, 0, ILibDuktape_Timer_Ptrs);
+ if (duk_has_prop_string(ctx, 0, "\xFF_callback"))
+ {
+ duk_del_prop_string(ctx, 0, "\xFF_callback");
+ }
+ if (duk_has_prop_string(ctx, 0, "\xFF_argArray"))
+ {
+ duk_del_prop_string(ctx, 0, "\xFF_argArray");
+ }
ptrs = (ILibDuktape_Timer*)Duktape_GetBuffer(ctx, -1, NULL);
ILibLifeTime_Remove(ILibGetBaseTimer(Duktape_GetChain(ctx)), ptrs);
@@ -415,24 +468,29 @@ void ILibDuktape_Polyfills_timer_elapsed(void *obj)
int argCount, i;
duk_context *ctx = ptrs->ctx;
+ duk_push_heapptr(ctx, ptrs->callback); // [func]
+ duk_push_heapptr(ctx, ptrs->object); // [func][this]
+ duk_push_heapptr(ctx, ptrs->args); // [func][this][argArray]
+
if (ptrs->timerType == ILibDuktape_Timer_Type_INTERVAL)
{
- ILibLifeTime_AddEx(ILibGetBaseTimer(Duktape_GetChain(ptrs->ctx)), ptrs, ptrs->timeout, ILibDuktape_Polyfills_timer_elapsed, NULL);
+ ILibLifeTime_AddEx(ILibGetBaseTimer(Duktape_GetChain(ctx)), ptrs, ptrs->timeout, ILibDuktape_Polyfills_timer_elapsed, NULL);
+ }
+ else
+ {
+ duk_del_prop_string(ctx, -2, "\xFF_callback");
+ duk_del_prop_string(ctx, -2, "\xFF_argArray");
}
- duk_push_heapptr(ptrs->ctx, ptrs->callback); // [func]
- duk_push_heapptr(ptrs->ctx, ptrs->object); // [func][this]
-
- duk_push_heapptr(ptrs->ctx, ptrs->args); // [func][this][argArray]
- argCount = (int)duk_get_length(ptrs->ctx, -1);
+ argCount = (int)duk_get_length(ctx, -1);
for (i = 0; i < argCount; ++i)
{
- duk_get_prop_index(ptrs->ctx, -1, i); // [func][this][argArray][arg]
- duk_swap_top(ptrs->ctx, -2); // [func][this][arg][argArray]
+ duk_get_prop_index(ctx, -1, i); // [func][this][argArray][arg]
+ duk_swap_top(ctx, -2); // [func][this][arg][argArray]
}
- duk_pop(ptrs->ctx); // [func][this][...arg...]
- if (duk_pcall_method(ptrs->ctx, argCount) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ptrs->ctx, "timers.onElapsed() callback handler"); }
- duk_pop(ctx); // ...
+ duk_pop(ctx); // [func][this][...arg...]
+ if (duk_pcall_method(ctx, argCount) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "timers.onElapsed() callback handler"); }
+ duk_pop(ctx); // ...
}
duk_ret_t ILibDuktape_Polyfills_timer_set(duk_context *ctx)
{
@@ -447,6 +505,18 @@ duk_ret_t ILibDuktape_Polyfills_timer_set(duk_context *ctx)
timerType = (ILibDuktape_Timer_Type)duk_get_int(ctx, -1);
duk_push_object(ctx); //[retVal]
+ switch (timerType)
+ {
+ case ILibDuktape_Timer_Type_IMMEDIATE:
+ ILibDuktape_WriteID(ctx, "Timers.immediate");
+ break;
+ case ILibDuktape_Timer_Type_INTERVAL:
+ ILibDuktape_WriteID(ctx, "Timers.interval");
+ break;
+ case ILibDuktape_Timer_Type_TIMEOUT:
+ ILibDuktape_WriteID(ctx, "Timers.timeout");
+ break;
+ }
ILibDuktape_CreateFinalizer(ctx, ILibDuktape_Polyfills_timer_finalizer);
duk_push_fixed_buffer(ctx, sizeof(ILibDuktape_Timer)); //[retVal][ptrs]
ptrs = (ILibDuktape_Timer*)Duktape_GetBuffer(ctx, -1, NULL);
@@ -463,13 +533,13 @@ duk_ret_t ILibDuktape_Polyfills_timer_set(duk_context *ctx)
for (argx = ILibDuktape_Timer_Type_IMMEDIATE == timerType ? 1 : 2; argx < nargs; ++argx)
{
duk_dup(ctx, argx); //[retVal][argArray][arg]
- duk_put_prop_index(ctx, -2, argx - (ILibDuktape_Timer_Type_IMMEDIATE == timerType ? 1 : 2)); //[retVal][argArray]
+ duk_put_prop_index(ctx, -2, argx - (ILibDuktape_Timer_Type_IMMEDIATE == timerType ? 1 : 2));//[retVal][argArray]
}
- ptrs->args = duk_get_heapptr(ctx, -1);
+ ptrs->args = duk_get_heapptr(ctx, -1); //[retVal]
duk_put_prop_string(ctx, -2, "\xFF_argArray");
- duk_dup(ctx, 0); //[retVal][callback]
- duk_put_prop_string(ctx, -2, "\xFF_callback"); //[retVal]
+ duk_dup(ctx, 0); //[retVal][callback]
+ duk_put_prop_string(ctx, -2, "\xFF_callback"); //[retVal]
ILibLifeTime_AddEx(ILibGetBaseTimer(chain), ptrs, ptrs->timeout, ILibDuktape_Polyfills_timer_elapsed, NULL);
return 1;
@@ -758,11 +828,179 @@ void ILibDuktape_DynamicBuffer_Push(duk_context *ctx, void *chain)
duk_push_c_function(ctx, ILibDuktape_DynamicBuffer_new, DUK_VARARGS);
}
+duk_ret_t ILibDuktape_Polyfills_debugCrash(duk_context *ctx)
+{
+ void *p = NULL;
+ ((int*)p)[0] = 55;
+ return(0);
+}
+
+void ILibDuktape_Stream_PauseSink(struct ILibDuktape_readableStream *sender, void *user)
+{
+}
+void ILibDuktape_Stream_ResumeSink(struct ILibDuktape_readableStream *sender, void *user)
+{
+ int skip = 0;
+ duk_size_t bufferLen;
+
+ duk_push_heapptr(sender->ctx, sender->object); // [stream]
+ void *func = Duktape_GetHeapptrProperty(sender->ctx, -1, "_read");
+ duk_pop(sender->ctx); // ...
+
+ while (func != NULL && sender->paused == 0)
+ {
+ duk_push_heapptr(sender->ctx, sender->object); // [this]
+ if (!skip && duk_has_prop_string(sender->ctx, -1, ILibDuktape_Stream_Buffer))
+ {
+ duk_get_prop_string(sender->ctx, -1, ILibDuktape_Stream_Buffer); // [this][buffer]
+ if ((bufferLen = duk_get_length(sender->ctx, -1)) > 0)
+ {
+ // Buffer is not empty, so we need to 'PUSH' it
+ duk_get_prop_string(sender->ctx, -2, "push"); // [this][buffer][push]
+ duk_dup(sender->ctx, -3); // [this][buffer][push][this]
+ duk_dup(sender->ctx, -3); // [this][buffer][push][this][buffer]
+ duk_remove(sender->ctx, -4); // [this][push][this][buffer]
+ duk_call_method(sender->ctx, 1); // [this][boolean]
+ sender->paused = !duk_get_boolean(sender->ctx, -1);
+ duk_pop(sender->ctx); // [this]
+
+ if (duk_has_prop_string(sender->ctx, -1, ILibDuktape_Stream_Buffer))
+ {
+ duk_get_prop_string(sender->ctx, -1, ILibDuktape_Stream_Buffer); // [this][buffer]
+ if (duk_get_length(sender->ctx, -1) == bufferLen)
+ {
+ // All the data was unshifted
+ skip = !sender->paused;
+ }
+ duk_pop(sender->ctx); // [this]
+ }
+ duk_pop(sender->ctx); // ...
+ }
+ else
+ {
+ // Buffer is empty
+ duk_pop(sender->ctx); // [this]
+ duk_del_prop_string(sender->ctx, -1, ILibDuktape_Stream_Buffer);
+ duk_pop(sender->ctx); // ...
+ }
+ }
+ else
+ {
+ // We need to 'read' more data
+ duk_push_heapptr(sender->ctx, func); // [this][read]
+ duk_swap_top(sender->ctx, -2); // [read][this]
+ if (duk_pcall_method(sender->ctx, 0) != 0) { ILibDuktape_Process_UncaughtException(sender->ctx); duk_pop(sender->ctx); break; }
+ // // [buffer]
+ duk_push_heapptr(sender->ctx, sender->object); // [buffer][this]
+ duk_swap_top(sender->ctx, -2); // [this][buffer]
+ if (duk_has_prop_string(sender->ctx, -2, ILibDuktape_Stream_Buffer))
+ {
+ duk_push_global_object(sender->ctx); // [this][buffer][g]
+ duk_get_prop_string(sender->ctx, -1, "Buffer"); // [this][buffer][g][Buffer]
+ duk_remove(sender->ctx, -2); // [this][buffer][Buffer]
+ duk_get_prop_string(sender->ctx, -1, "concat"); // [this][buffer][Buffer][concat]
+ duk_swap_top(sender->ctx, -2); // [this][buffer][concat][this]
+ duk_push_array(sender->ctx); // [this][buffer][concat][this][Array]
+ duk_get_prop_string(sender->ctx, -1, "push"); // [this][buffer][concat][this][Array][push]
+ duk_dup(sender->ctx, -2); // [this][buffer][concat][this][Array][push][this]
+ duk_get_prop_string(sender->ctx, -7, ILibDuktape_Stream_Buffer); // [this][buffer][concat][this][Array][push][this][buffer]
+ duk_call_method(sender->ctx, 1); duk_pop(sender->ctx); // [this][buffer][concat][this][Array]
+ duk_get_prop_string(sender->ctx, -1, "push"); // [this][buffer][concat][this][Array][push]
+ duk_dup(sender->ctx, -2); // [this][buffer][concat][this][Array][push][this]
+ duk_dup(sender->ctx, -6); // [this][buffer][concat][this][Array][push][this][buffer]
+ duk_remove(sender->ctx, -7); // [this][concat][this][Array][push][this][buffer]
+ duk_call_method(sender->ctx, 1); duk_pop(sender->ctx); // [this][concat][this][Array]
+ duk_call_method(sender->ctx, 1); // [this][buffer]
+ }
+ duk_put_prop_string(sender->ctx, -2, ILibDuktape_Stream_Buffer); // [this]
+ duk_pop(sender->ctx); // ...
+ skip = 0;
+ }
+ }
+}
+int ILibDuktape_Stream_UnshiftSink(struct ILibDuktape_readableStream *sender, int unshiftBytes, void *user)
+{
+ duk_push_fixed_buffer(sender->ctx, unshiftBytes); // [buffer]
+ memcpy_s(Duktape_GetBuffer(sender->ctx, -1, NULL), unshiftBytes, sender->unshiftReserved, unshiftBytes);
+ duk_push_heapptr(sender->ctx, sender->object); // [buffer][stream]
+ duk_push_buffer_object(sender->ctx, -2, 0, unshiftBytes, DUK_BUFOBJ_NODEJS_BUFFER); // [buffer][stream][buffer]
+ duk_put_prop_string(sender->ctx, -2, ILibDuktape_Stream_Buffer); // [buffer][stream]
+ duk_pop_2(sender->ctx); // ...
+
+ return(unshiftBytes);
+}
+duk_ret_t ILibDuktape_Stream_Push(duk_context *ctx)
+{
+ duk_push_this(ctx); // [stream]
+ ILibDuktape_readableStream *RS = (ILibDuktape_readableStream*)Duktape_GetPointerProperty(ctx, -1, ILibDuktape_Stream_ReadablePtr);
+ duk_get_prop_string(ctx, -1, ILibDuktape_Stream_Buffer); // [stream][buffer]
+ duk_del_prop_string(ctx, -2, ILibDuktape_Stream_Buffer); // (Deleting here, because unshift will save it again, if necessary)
+
+ duk_size_t bufferLen;
+ char *buffer = (char*)Duktape_GetBuffer(ctx, -1, &bufferLen);
+
+ duk_push_boolean(ctx, !ILibDuktape_readableStream_WriteDataEx(RS, 0, buffer, (int)bufferLen)); // [stream][buffer][retVal]
+ return(1);
+}
+duk_ret_t ILibDuktape_Stream_EndSink(duk_context *ctx)
+{
+ duk_push_this(ctx); // [stream]
+ ILibDuktape_readableStream *RS = (ILibDuktape_readableStream*)Duktape_GetPointerProperty(ctx, -1, ILibDuktape_Stream_ReadablePtr);
+ ILibDuktape_readableStream_WriteEnd(RS);
+ return(0);
+}
+duk_idx_t ILibDuktape_Stream_newReadable(duk_context *ctx)
+{
+ ILibDuktape_readableStream *RS;
+ duk_push_object(ctx); // [Readable]
+ ILibDuktape_WriteID(ctx, "stream.readable");
+ RS = ILibDuktape_ReadableStream_InitEx(ctx, ILibDuktape_Stream_PauseSink, ILibDuktape_Stream_ResumeSink, ILibDuktape_Stream_UnshiftSink, NULL);
+ RS->paused = 1;
+
+ duk_push_pointer(ctx, RS);
+ duk_put_prop_string(ctx, -2, ILibDuktape_Stream_ReadablePtr);
+ ILibDuktape_CreateInstanceMethod(ctx, "push", ILibDuktape_Stream_Push, DUK_VARARGS);
+ ILibDuktape_EventEmitter_AddOnceEx3(ctx, -1, "end", ILibDuktape_Stream_EndSink);
+
+ if (duk_is_object(ctx, 0))
+ {
+ void *h = Duktape_GetHeapptrProperty(ctx, 0, "read");
+ if (h != NULL) { duk_push_heapptr(ctx, h); duk_put_prop_string(ctx, -2, "_read"); }
+ }
+ return(1);
+}
+void ILibDuktape_Stream_Init(duk_context *ctx, void *chain)
+{
+ duk_push_object(ctx); // [stream
+ ILibDuktape_WriteID(ctx, "stream");
+ ILibDuktape_CreateInstanceMethod(ctx, "Readable", ILibDuktape_Stream_newReadable, DUK_VARARGS);
+}
+void ILibDuktape_Polyfills_debugGC2(duk_context *ctx, void ** args, int argsLen)
+{
+ if (g_displayFinalizerMessages) { printf("=> GC();\n"); }
+ duk_gc(ctx, 0);
+ duk_gc(ctx, 0);
+}
+duk_ret_t ILibDuktape_Polyfills_debugGC(duk_context *ctx)
+{
+ ILibDuktape_Immediate(ctx, (void*[]) { NULL }, 0, ILibDuktape_Polyfills_debugGC2);
+ return(0);
+}
+duk_ret_t ILibDuktape_Polyfills_debug(duk_context *ctx)
+{
+#ifdef WIN32
+ if (IsDebuggerPresent()) { __debugbreak(); }
+#elif defined(_POSIX)
+ raise(SIGTRAP);
+#endif
+ return(0);
+}
void ILibDuktape_Polyfills_Init(duk_context *ctx)
{
ILibDuktape_ModSearch_AddHandler(ctx, "queue", ILibDuktape_Queue_Push);
ILibDuktape_ModSearch_AddHandler(ctx, "DynamicBuffer", ILibDuktape_DynamicBuffer_Push);
+ ILibDuktape_ModSearch_AddHandler(ctx, "stream", ILibDuktape_Stream_Init);
// Global Polyfills
duk_push_global_object(ctx); // [g]
@@ -774,6 +1012,9 @@ void ILibDuktape_Polyfills_Init(duk_context *ctx)
ILibDuktape_Polyfills_timer(ctx);
ILibDuktape_CreateInstanceMethod(ctx, "addModule", ILibDuktape_Polyfills_addModule, 2);
+ ILibDuktape_CreateInstanceMethod(ctx, "_debugCrash", ILibDuktape_Polyfills_debugCrash, 0);
+ ILibDuktape_CreateInstanceMethod(ctx, "_debugGC", ILibDuktape_Polyfills_debugGC, 0);
+ ILibDuktape_CreateInstanceMethod(ctx, "_debug", ILibDuktape_Polyfills_debug, 0);
duk_pop(ctx); // ...
}
diff --git a/microscript/ILibDuktape_Polyfills.h b/microscript/ILibDuktape_Polyfills.h
index 996474b..33dd1b2 100644
--- a/microscript/ILibDuktape_Polyfills.h
+++ b/microscript/ILibDuktape_Polyfills.h
@@ -1,8 +1,26 @@
+/*
+Copyright 2006 - 2018 Intel Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
#ifndef __ILibDuktape_Polyfills__
#define __ILibDuktape_Polyfills__
#include "duktape.h"
+extern int g_displayStreamPipeMessages;
+extern int g_displayFinalizerMessages;
void ILibDuktape_Polyfills_Init(duk_context *ctx);
#endif
\ No newline at end of file
diff --git a/microscript/ILibDuktape_ReadableStream.c b/microscript/ILibDuktape_ReadableStream.c
index d034337..70542d4 100644
--- a/microscript/ILibDuktape_ReadableStream.c
+++ b/microscript/ILibDuktape_ReadableStream.c
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ limitations under the License.
#include "ILibParsers_Duktape.h"
#include "microstack/ILibParsers.h"
#include "ILibDuktape_EventEmitter.h"
+#include "ILibDuktape_Polyfills.h"
#define ILibDuktape_readableStream_WritePipes "\xFF_WritePipes"
@@ -105,6 +106,19 @@ typedef struct ILibDuktape_readableStream_bufferedData
char buffer[];
}ILibDuktape_readableStream_bufferedData;
+void ILibDuktape_ReadableStream_DestroyPausedData(ILibDuktape_readableStream *stream)
+{
+ ILibDuktape_readableStream_bufferedData *buffered = (ILibDuktape_readableStream_bufferedData*)stream->paused_data;
+ ILibDuktape_readableStream_bufferedData *tmp;
+
+ while (buffered != NULL)
+ {
+ tmp = buffered->Next;
+ free(buffered);
+ buffered = tmp;
+ }
+ stream->paused_data = NULL;
+}
void ILibDuktape_readableStream_WriteData_buffer(ILibDuktape_readableStream *stream, int streamReserved, char *buffer, int bufferLen)
{
ILibDuktape_readableStream_bufferedData *buffered = (ILibDuktape_readableStream_bufferedData*)ILibMemory_Allocate(bufferLen + sizeof(ILibDuktape_readableStream_bufferedData), 0, NULL, NULL);
@@ -137,17 +151,17 @@ void ILibDuktape_readableStream_WriteData_OnData_ChainThread(void *chain, void *
duk_push_external_buffer(stream->ctx); // [ext]
duk_config_buffer(stream->ctx, -1, data->buffer, data->bufferLen);
}
- duk_push_heapptr(stream->ctx, stream->OnData); // [ext][func]
- duk_push_heapptr(stream->ctx, stream->object); // [ext][func][this]
+
+ ILibDuktape_EventEmitter_SetupEmit(stream->ctx, stream->object, "data"); // [ext][emit][this][data]
if (data->Reserved == 0)
{
- duk_push_buffer_object(stream->ctx, -3, 0, data->bufferLen, DUK_BUFOBJ_NODEJS_BUFFER); // [ext][func][this][buffer]
+ duk_push_buffer_object(stream->ctx, -4, 0, data->bufferLen, DUK_BUFOBJ_NODEJS_BUFFER); // [ext][emit][this][data][buffer]
}
else
{
- duk_push_lstring(stream->ctx, data->buffer, data->bufferLen); // [ext][func][this][buffer/string]
+ duk_push_lstring(stream->ctx, data->buffer, data->bufferLen); // [ext][emit][this][data][buffer/string]
}
- if (duk_pcall_method(stream->ctx, 1) != 0) // [...][retVal]
+ if (duk_pcall_method(stream->ctx, 2) != 0) // [...][retVal]
{
ILibDuktape_Process_UncaughtException(stream->ctx);
}
@@ -275,6 +289,7 @@ int ILibDuktape_readableStream_WriteDataEx(ILibDuktape_readableStream *stream, i
{
ILibDuktape_WritableStream *ws = (ILibDuktape_WritableStream*)w->nativeWritable;
ws->Reserved = streamReserved;
+ ws->endBytes = -1;
switch (ws->WriteSink(ws, buffer, bufferLen, ws->WriteSink_User))
{
case ILibTransport_DoneState_INCOMPLETE:
@@ -333,7 +348,7 @@ int ILibDuktape_readableStream_WriteDataEx(ILibDuktape_readableStream *stream, i
stream->pipeInProgress = 0;
sem_post(&(stream->pipeLock));
- if (stream->OnData != NULL)
+ if(ILibDuktape_EventEmitter_HasListeners(stream->emitter, "data"))
{
if (ILibIsRunningOnChainThread(stream->chain))
{
@@ -342,17 +357,16 @@ int ILibDuktape_readableStream_WriteDataEx(ILibDuktape_readableStream *stream, i
duk_push_external_buffer(stream->ctx); // [extBuffer]
duk_config_buffer(stream->ctx, -1, buffer, bufferLen);
}
- duk_push_heapptr(stream->ctx, stream->OnData); // [func]
- duk_push_heapptr(stream->ctx, stream->object); // [func][this]
+ ILibDuktape_EventEmitter_SetupEmit(stream->ctx, stream->object, "data"); // [extBuffer][emit][this][data]
if (streamReserved == 0)
{
- duk_push_buffer_object(stream->ctx, -3, 0, bufferLen, DUK_BUFOBJ_NODEJS_BUFFER); // [extBuffer][func][this][nodeBuffer]
+ duk_push_buffer_object(stream->ctx, -4, 0, bufferLen, DUK_BUFOBJ_NODEJS_BUFFER); // [extBuffer][emit][this][data][nodeBuffer]
}
else
{
- duk_push_lstring(stream->ctx, buffer, bufferLen); // [func][this][string]
+ duk_push_lstring(stream->ctx, buffer, bufferLen); // [extBuffer][emit][this][data][string]
}
- if (duk_pcall_method(stream->ctx, 1) != 0) // [retVal]
+ if (duk_pcall_method(stream->ctx, 2) != 0) // [retVal]
{
ILibDuktape_Process_UncaughtException(stream->ctx);
}
@@ -377,14 +391,14 @@ int ILibDuktape_readableStream_WriteDataEx(ILibDuktape_readableStream *stream, i
ILibChain_RunOnMicrostackThread(stream->chain, ILibDuktape_readableStream_WriteData_OnData_ChainThread, tmp);
}
}
- else if (stream->PauseHandler != NULL && stream->OnEnd == NULL)
+ else if (stream->PauseHandler != NULL && ILibDuktape_EventEmitter_HasListeners(stream->emitter, "end") == 0)
{
// If we get here, it means we are writing data, but nobody is going to be receiving it...
// So we need to buffer the data, so when we are resumed later, we can retry
needPause = 1;
ILibDuktape_readableStream_WriteData_buffer(stream, streamReserved, buffer, bufferLen);
}
- else if (stream->OnEnd != NULL)
+ else if (ILibDuktape_EventEmitter_HasListeners(stream->emitter, "end") != 0)
{
return 0;
}
@@ -429,16 +443,11 @@ int ILibDuktape_readableStream_WriteEnd(ILibDuktape_readableStream *stream)
retVal = 0;
}
}
- else if (stream->OnEnd != NULL)
+ else if (ILibDuktape_EventEmitter_HasListeners(stream->emitter, "end") != 0)
{
- duk_context *x = stream->ctx;
- duk_push_heapptr(stream->ctx, stream->OnEnd); // [func]
- duk_push_heapptr(stream->ctx, stream->object); // [func][this]
- if (duk_pcall_method(stream->ctx, 0) != 0) // [retVal]
- {
- ILibDuktape_Process_UncaughtException(stream->ctx);
- }
- duk_pop(x); // ...
+ ILibDuktape_EventEmitter_SetupEmit(stream->ctx, stream->object, "end"); // [emit][this][end]
+ if (duk_pcall_method(stream->ctx, 1) != 0) { ILibDuktape_Process_UncaughtException(stream->ctx); }
+ duk_pop(stream->ctx); // ...
retVal = 0;
}
}
@@ -447,16 +456,18 @@ int ILibDuktape_readableStream_WriteEnd(ILibDuktape_readableStream *stream)
void ILibDuktape_readableStream_Closed(ILibDuktape_readableStream *stream)
{
ILibDuktape_readableStream_WriteEnd(stream);
- if (stream->OnClose != NULL)
+ if(ILibDuktape_EventEmitter_HasListeners(stream->emitter, "close")!=0)
{
- duk_push_heapptr(stream->ctx, stream->OnClose); // [func]
- duk_push_heapptr(stream->ctx, stream->object); // [func][this]
- if (duk_pcall_method(stream->ctx, 0) != 0) // [retVal]
- {
- ILibDuktape_Process_UncaughtException(stream->ctx);
- }
- duk_pop(stream->ctx); // ...
+ ILibDuktape_EventEmitter_SetupEmit(stream->ctx, stream->object, "close"); // [emit][this][close]
+ if (duk_pcall_method(stream->ctx, 1) != 0) { ILibDuktape_Process_UncaughtException(stream->ctx); }
+ duk_pop(stream->ctx); // ...
}
+
+ duk_push_heapptr(stream->ctx, stream->object); // [stream]
+ duk_get_prop_string(stream->ctx, -1, "unpipe"); // [stream][unpipe]
+ duk_swap_top(stream->ctx, -2); // [unpipe][this]
+ if (duk_pcall_method(stream->ctx, 0) != 0) { ILibDuktape_Process_UncaughtException(stream->ctx); }
+ duk_pop(stream->ctx); // ...
}
duk_ret_t ILibDuktape_readableStream_pause(duk_context *ctx)
@@ -482,7 +493,7 @@ duk_ret_t ILibDuktape_readableStream_pause(duk_context *ctx)
int ILibDuktape_readableStream_resume_flush(ILibDuktape_readableStream *rs)
{
// Sanity check, and make sure there is a listener first, otherwise we're wasting our time
- if (rs->OnData == NULL && rs->nextWriteable == NULL && rs->OnEnd == NULL)
+ if(ILibDuktape_EventEmitter_HasListeners(rs->emitter, "data")==0 && rs->nextWriteable == NULL && ILibDuktape_EventEmitter_HasListeners(rs->emitter, "end")==0)
{
return 1; // No listeners....
}
@@ -528,12 +539,23 @@ duk_ret_t ILibDuktape_readableStream_resume(duk_context *ctx)
void ILibDuktape_ReadableStream_pipe_ResumeLater(duk_context *ctx, void **args, int argsLen)
{
ILibDuktape_readableStream *rs = (ILibDuktape_readableStream*)args[0];
+ rs->resumeImmediate = NULL;
if (ILibDuktape_readableStream_resume_flush(rs) == 0 && rs->ResumeHandler != NULL) { rs->paused = 0; rs->ResumeHandler(rs, rs->user); }
if (rs->PipeHookHandler != NULL) { rs->PipeHookHandler(rs, args[1], rs->user); }
}
void ILibDuktape_readableStream_pipe_later(duk_context *ctx, void **args, int argsLen)
{
duk_push_heapptr(ctx, args[0]); // [readable]
+ duk_get_prop_string(ctx, -1, ILibDuktape_readableStream_RSPTRS);
+ ILibDuktape_readableStream *rs = (ILibDuktape_readableStream*)Duktape_GetBuffer(ctx, -1, NULL);
+ duk_pop(ctx);
+
+ duk_push_heapptr(ctx, rs->pipeImmediate);
+ duk_del_prop_string(ctx, -1, "dest");
+ duk_pop(ctx);
+ rs->pipeImmediate = NULL;
+
+
duk_get_prop_string(ctx, -1, "pipe"); // [readable][pipe]
duk_swap_top(ctx, -2); // [pipe][this]
duk_push_heapptr(ctx, args[1]); // [pipe][this][writable]
@@ -557,8 +579,10 @@ duk_ret_t ILibDuktape_readableStream_pipe(duk_context *ctx)
{
// We must YIELD and try again later, becuase there is an active dispatch going on
duk_push_this(ctx);
- ILibDuktape_Immediate(ctx, (void*[]) { duk_get_heapptr(ctx, -1), duk_get_heapptr(ctx, 0), nargs > 1 ? duk_get_heapptr(ctx, 1) : NULL }, 1 + nargs, ILibDuktape_readableStream_pipe_later);
-
+ rstream->pipeImmediate = ILibDuktape_Immediate(ctx, (void*[]) { duk_get_heapptr(ctx, -1), duk_get_heapptr(ctx, 0), nargs > 1 ? duk_get_heapptr(ctx, 1) : NULL }, 1 + nargs, ILibDuktape_readableStream_pipe_later);
+ duk_push_heapptr(ctx, rstream->pipeImmediate); // [immediate]
+ duk_dup(ctx, 0); // [immediate][ws]
+ duk_put_prop_string(ctx, -2, "dest"); // [immediate]
duk_dup(ctx, 0);
sem_post(&(rstream->pipeLock));
return(1);
@@ -615,12 +639,14 @@ duk_ret_t ILibDuktape_readableStream_pipe(duk_context *ctx)
duk_push_string(ctx, "pipe"); // [emit][this][pipe]
duk_push_this(ctx); // [emit][this][pipe][readable]
duk_call_method(ctx, 2); duk_pop(ctx); // ...
-
-
if (rstream->paused != 0)
{
// We are paused, so we should yield and resume... We yield, so in case the user tries to chain multiple pipes, it will chain first
- ILibDuktape_Immediate(ctx, (void*[]) { rstream, duk_get_heapptr(ctx, 0) }, 1, ILibDuktape_ReadableStream_pipe_ResumeLater);
+ rstream->resumeImmediate = ILibDuktape_Immediate(ctx, (void*[]) { rstream, duk_get_heapptr(ctx, 0) }, 1, ILibDuktape_ReadableStream_pipe_ResumeLater);
+ duk_push_heapptr(ctx, rstream->resumeImmediate); // [immediate]
+ duk_push_this(ctx); // [immediate][this]
+ duk_put_prop_string(ctx, -2, "self"); // [immediate]
+ duk_pop(ctx); // ...
}
else
{
@@ -646,7 +672,12 @@ void ILibDuktape_readableStream_unpipe_later(duk_context *ctx, void ** args, int
if (data->pipeInProgress != 0)
{
// We must yield, and try again, because there's an active dispatch going on
- ILibDuktape_Immediate(ctx, (void*[]) { args[0], args[1] }, argsLen, ILibDuktape_readableStream_unpipe_later);
+ void *imm = ILibDuktape_Immediate(ctx, (void*[]) { args[0], args[1] }, argsLen, ILibDuktape_readableStream_unpipe_later);
+ duk_push_heapptr(ctx, imm); // [immediate]
+ duk_push_heapptr(ctx, args[0]); // [immediate][this]
+ duk_put_prop_string(ctx, -2, "\xFF_Self"); // [immediate]
+ if (args[1] != NULL) { duk_push_heapptr(ctx, args[1]); duk_put_prop_string(ctx, -2, "\xFF_w"); }
+ duk_pop(ctx); // ...
sem_post(&(data->pipeLock));
return;
}
@@ -683,11 +714,11 @@ void ILibDuktape_readableStream_unpipe_later(duk_context *ctx, void ** args, int
for (i = 0; i < (int)arrayLen; ++i)
{
duk_get_prop_index(ctx, -1, i); // [array][ws]
- ILibDuktape_Push_ObjectStash(ctx); // [array][ws][stash]
- if (duk_has_prop_string(ctx, -1, Duktape_GetStashKey(args[1])))
+ if(duk_get_heapptr(ctx, -1) == args[1])
{
+ if (g_displayFinalizerMessages) { printf("*** UNPIPE/Removing Reference to Writeable: %s (RefCount: %d)\n", Duktape_GetStringPropertyValue(ctx, -1, ILibDuktape_OBJID, "UNKNOWN"), ILibDuktape_GetReferenceCount(ctx, -1)); }
// Removing the entry from the Array
- duk_pop_2(ctx); // [array]
+ duk_pop(ctx); // [array]
duk_get_prop_string(ctx, -1, "splice"); // [array][splice]
duk_swap_top(ctx, -2); // [splice][this]
duk_push_int(ctx, i); // [splice][this][i]
@@ -707,10 +738,10 @@ void ILibDuktape_readableStream_unpipe_later(duk_context *ctx, void ** args, int
else
{
// 'unpipe' all pipes
- w = data->nextWriteable;
while (w != NULL)
{
duk_push_heapptr(ctx, w->writableStream); // [ws]
+ if (g_displayFinalizerMessages) { printf("*** UNPIPE/Removing Reference to Writeable: %s (RefCount: %d)\n", Duktape_GetStringPropertyValue(ctx, -1, ILibDuktape_OBJID, "UNKNOWN"), ILibDuktape_GetReferenceCount(ctx, -1)); }
duk_get_prop_string(ctx, -1, "emit"); // [ws][emit]
duk_swap_top(ctx, -2); // [emit][this]
duk_push_string(ctx, "unpipe"); // [emit][this][unpipe]
@@ -752,7 +783,13 @@ duk_ret_t ILibDuktape_readableStream_unpipe(duk_context *ctx)
duk_call_method(ctx, 0); duk_pop(ctx); // [readable]
// We must yield, and do this on the next event loop, because we can't unpipe if we're called from a pipe'ed call
- ILibDuktape_Immediate(ctx, (void*[]) { duk_get_heapptr(ctx, -1), nargs == 1 ? duk_get_heapptr(ctx, 0) : NULL }, nargs + 1, ILibDuktape_readableStream_unpipe_later);
+ void *imm = ILibDuktape_Immediate(ctx, (void*[]) { duk_get_heapptr(ctx, -1), nargs == 1 ? duk_get_heapptr(ctx, 0) : NULL }, nargs + 1, ILibDuktape_readableStream_unpipe_later);
+ duk_push_heapptr(ctx, imm); // [immediate]
+ duk_push_this(ctx); // [immediate][this]
+ duk_put_prop_string(ctx, -2, "\xFF_Self"); // [immediate]
+ if (nargs == 1) { duk_dup(ctx, 0); duk_put_prop_string(ctx, -2, "\xFF_w"); }
+ duk_pop(ctx); // ...
+
return 0;
}
duk_ret_t ILibDuktape_readableStream_isPaused(duk_context *ctx)
@@ -777,13 +814,23 @@ duk_ret_t ILibDuktape_readableStream_pipe_getter(duk_context *ctx)
duk_push_c_function(ctx, ILibDuktape_readableStream_pipe, DUK_VARARGS);
return 1;
}
-void ILibDuktape_ReadableStream_PipeLockFinalizer(duk_context *ctx, void *stream)
+duk_ret_t ILibDuktape_ReadableStream_PipeLockFinalizer(duk_context *ctx)
{
ILibDuktape_readableStream_bufferedData *tmp;
ILibDuktape_readableStream *ptrs;
- duk_push_heapptr(ctx, stream); // [stream]
+
+ duk_push_this(ctx); // [stream]
duk_get_prop_string(ctx, -1, ILibDuktape_readableStream_RSPTRS); // [stream][buffer]
ptrs = (ILibDuktape_readableStream*)Duktape_GetBuffer(ctx, -1, NULL);
+ if (ptrs->pipeImmediate != NULL)
+ {
+ duk_push_global_object(ctx); // [g]
+ duk_get_prop_string(ctx, -1, "clearImmediate"); // [g][clearImmediate]
+ duk_swap_top(ctx, -2); // [clearImmediate][this]
+ duk_push_heapptr(ctx, ptrs->pipeImmediate); // [clearImmediate][this][immedate]
+ duk_call_method(ctx, 1); duk_pop(ctx); // ...
+ ptrs->pipeImmediate = NULL;
+ }
while ((tmp = (ILibDuktape_readableStream_bufferedData*)ptrs->paused_data) != NULL)
{
@@ -794,6 +841,7 @@ void ILibDuktape_ReadableStream_PipeLockFinalizer(duk_context *ctx, void *stream
sem_destroy(&(ptrs->pipeLock));
duk_pop_2(ctx);
+ return(0);
}
duk_ret_t ILibDuktape_ReadableStream_unshift(duk_context *ctx)
{
@@ -809,7 +857,7 @@ duk_ret_t ILibDuktape_ReadableStream_unshift(duk_context *ctx)
else
{
duk_size_t bufferLen;
- Duktape_GetBuffer(ctx, 0, &bufferLen);
+ rs->unshiftReserved = (char*)Duktape_GetBuffer(ctx, 0, &bufferLen);
duk_push_int(ctx, rs->UnshiftHandler(rs, (int)bufferLen, rs->user));
return(1);
}
@@ -831,7 +879,6 @@ ILibDuktape_readableStream* ILibDuktape_ReadableStream_InitEx(duk_context *ctx,
retVal->pipeArray = duk_get_heapptr(ctx, -1);
duk_put_prop_string(ctx, -2, ILibDuktape_readableStream_PipeArray); // [obj]
-
retVal->ctx = ctx;
retVal->chain = Duktape_GetChain(ctx);
retVal->object = duk_get_heapptr(ctx, -1);
@@ -840,12 +887,12 @@ ILibDuktape_readableStream* ILibDuktape_ReadableStream_InitEx(duk_context *ctx,
retVal->ResumeHandler = OnResume;
retVal->UnshiftHandler = OnUnshift;
sem_init(&(retVal->pipeLock), 0, 1);
- ILibDuktape_CreateIndependentFinalizer(ctx, ILibDuktape_ReadableStream_PipeLockFinalizer);
+ ILibDuktape_CreateFinalizer(ctx, ILibDuktape_ReadableStream_PipeLockFinalizer);
- emitter = ILibDuktape_EventEmitter_Create(ctx);
- ILibDuktape_EventEmitter_CreateEvent(emitter, "end", &(retVal->OnEnd));
- ILibDuktape_EventEmitter_CreateEvent(emitter, "data", &(retVal->OnData));
- ILibDuktape_EventEmitter_CreateEvent(emitter, "close", &(retVal->OnClose));
+ retVal->emitter = emitter = ILibDuktape_EventEmitter_Create(ctx);
+ ILibDuktape_EventEmitter_CreateEventEx(emitter, "end");
+ ILibDuktape_EventEmitter_CreateEventEx(emitter, "data");
+ ILibDuktape_EventEmitter_CreateEventEx(emitter, "close");
ILibDuktape_CreateInstanceMethod(ctx, "pause", ILibDuktape_readableStream_pause, 0);
ILibDuktape_CreateInstanceMethod(ctx, "resume", ILibDuktape_readableStream_resume, 0);
diff --git a/microscript/ILibDuktape_ReadableStream.h b/microscript/ILibDuktape_ReadableStream.h
index d515f8d..bd19971 100644
--- a/microscript/ILibDuktape_ReadableStream.h
+++ b/microscript/ILibDuktape_ReadableStream.h
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ limitations under the License.
#include "duktape.h"
#include "microstack/ILibParsers.h"
+#include "ILibDuktape_EventEmitter.h"
#define ILibDuktape_readableStream_RSPTRS "\xFF_ReadableStream_PTRS"
@@ -39,9 +40,6 @@ typedef struct ILibDuktape_readableStream
duk_context *ctx;
void *chain;
void *object;
- void *OnClose;
- void *OnData;
- void *OnEnd;
void *user;
void *pipeArray;
@@ -64,6 +62,10 @@ typedef struct ILibDuktape_readableStream
ILibDuktape_readableStream_PauseResumeHandler ResumeHandler;
ILibDuktape_readableStream_MethodHookHandler PipeHookHandler;
ILibDuktape_readableStream_UnShiftHandler UnshiftHandler;
+ ILibDuktape_EventEmitter *emitter;
+ char *unshiftReserved;
+ void *resumeImmediate;
+ void *pipeImmediate;
}ILibDuktape_readableStream;
ILibDuktape_readableStream* ILibDuktape_ReadableStream_InitEx(duk_context *ctx, ILibDuktape_readableStream_PauseResumeHandler OnPause, ILibDuktape_readableStream_PauseResumeHandler OnResume, ILibDuktape_readableStream_UnShiftHandler OnUnshift, void *user);
@@ -71,6 +73,7 @@ ILibDuktape_readableStream* ILibDuktape_ReadableStream_InitEx(duk_context *ctx,
#define ILibDuktape_ReadableStream_Init(ctx, OnPause, OnResume, user) ILibDuktape_ReadableStream_InitEx(ctx, OnPause, OnResume, NULL, user)
#define ILibDuktape_readableStream_SetPauseResumeHandlers(stream, PauseFunc, ResumeFunc, userObj) ((ILibDuktape_readableStream*)stream)->PauseHandler = PauseFunc; ((ILibDuktape_readableStream*)stream)->ResumeHandler = ResumeFunc; ((ILibDuktape_readableStream*)stream)->user = userObj;
+void ILibDuktape_ReadableStream_DestroyPausedData(ILibDuktape_readableStream *stream);
int ILibDuktape_readableStream_WriteDataEx(ILibDuktape_readableStream *stream, int streamReserved, char* buffer, int bufferLen);
int ILibDuktape_readableStream_WriteEnd(ILibDuktape_readableStream *stream);
#define ILibDuktape_readableStream_WriteData(stream, buffer, bufferLen) ILibDuktape_readableStream_WriteDataEx(stream, 0, buffer, bufferLen)
diff --git a/microscript/ILibDuktape_SHA256.c b/microscript/ILibDuktape_SHA256.c
index 24eb40b..6426294 100644
--- a/microscript/ILibDuktape_SHA256.c
+++ b/microscript/ILibDuktape_SHA256.c
@@ -1,3 +1,19 @@
+/*
+Copyright 2006 - 2018 Intel Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
#include "ILibDuktape_SHA256.h"
#include "duktape.h"
#include "ILibDuktape_Helpers.h"
@@ -21,8 +37,6 @@ typedef struct ILibDuktape_SHA256_Data
duk_context *ctx;
void *object;
- void *OnHash;
- void *OnHashString;
char buffer[33];
SHA256_CTX shctx;
}ILibDuktape_SHA256_Data;
@@ -31,8 +45,6 @@ typedef struct ILibDuktape_SHA512_Data
duk_context *ctx;
void *object;
- void *OnHash;
- void *OnHashString;
char buffer[65];
SHA512_CTX shctx;
}ILibDuktape_SHA512_Data;
@@ -41,8 +53,6 @@ typedef struct ILibDuktape_MD5_Data
duk_context *ctx;
void *object;
- void *OnHash;
- void *OnHashString;
char buffer[33];
MD5_CTX mctx;
}ILibDuktape_MD5_Data;
@@ -82,34 +92,21 @@ ILibTransport_DoneState ILibDuktape_SHA384_Write(struct ILibDuktape_WritableStre
}
void ILibDuktape_SHA256_End(struct ILibDuktape_WritableStream *stream, void *user)
{
-
ILibDuktape_SHA256_Data *data = (ILibDuktape_SHA256_Data*)user;
data->buffer[32] = 0;
SHA256_Final((unsigned char*)data->buffer, &(data->shctx));
- if (data->ctx != NULL && data->OnHash != NULL)
- {
- duk_push_heapptr(data->ctx, data->OnHash); // [func]
- duk_push_heapptr(data->ctx, data->object); // [func][this]
- duk_push_external_buffer(data->ctx); // [func][this][hash]
- duk_config_buffer(data->ctx, -1, data->buffer, 32);
- if (duk_pcall_method(data->ctx, 1) != 0) // [retVal]
- {
- ILibDuktape_Process_UncaughtException(data->ctx);
- }
- duk_pop(data->ctx); // ...
- }
- if (data->ctx != NULL && data->OnHashString != NULL)
- {
- duk_push_heapptr(data->ctx, data->OnHashString); // [func]
- duk_push_heapptr(data->ctx, data->object); // [func][this]
- duk_push_string(data->ctx, util_tohex(data->buffer, 32, ILibScratchPad)); // [func][this][hashString]
- if (duk_pcall_method(data->ctx, 1) != 0) // [retVal]
- {
- ILibDuktape_Process_UncaughtException(data->ctx);
- }
- duk_pop(data->ctx); // ...
- }
+ duk_push_external_buffer(data->ctx); // [extBuffer]
+ duk_config_buffer(data->ctx, -1, data->buffer, 32);
+ ILibDuktape_EventEmitter_SetupEmit(data->ctx, data->object, "hash"); // [extBuffer][emit][this]['hash']
+ duk_push_buffer_object(data->ctx, -4, 0, 32, DUK_BUFOBJ_NODEJS_BUFFER); // [extBuffer][emit][this]['hash'][hash]
+ if (duk_pcall_method(data->ctx, 2) != 0) { ILibDuktape_Process_UncaughtException(data->ctx); }
+ duk_pop_2(data->ctx); // ...
+
+ ILibDuktape_EventEmitter_SetupEmit(data->ctx, data->object, "hashString"); // [emit][this]['hash']
+ duk_push_string(data->ctx, util_tohex(data->buffer, 32, ILibScratchPad)); // [emit][this]['hash'][hashString]
+ if (duk_pcall_method(data->ctx, 1) != 0) { ILibDuktape_Process_UncaughtException(data->ctx); }
+ duk_pop(data->ctx); // ...
}
void ILibDuktape_SHA384_End(struct ILibDuktape_WritableStream *stream, void *user)
{
@@ -117,29 +114,17 @@ void ILibDuktape_SHA384_End(struct ILibDuktape_WritableStream *stream, void *use
data->buffer[48] = 0;
SHA384_Final((unsigned char*)data->buffer, &(data->shctx));
- if (data->ctx != NULL && data->OnHash != NULL)
- {
- duk_push_heapptr(data->ctx, data->OnHash); // [func]
- duk_push_heapptr(data->ctx, data->object); // [func][this]
- duk_push_external_buffer(data->ctx); // [func][this][hash]
- duk_config_buffer(data->ctx, -1, data->buffer, 48);
- if (duk_pcall_method(data->ctx, 1) != 0) // [retVal]
- {
- ILibDuktape_Process_UncaughtException(data->ctx);
- }
- duk_pop(data->ctx); // ...
- }
- if (data->ctx != NULL && data->OnHashString != NULL)
- {
- duk_push_heapptr(data->ctx, data->OnHashString); // [func]
- duk_push_heapptr(data->ctx, data->object); // [func][this]
- duk_push_string(data->ctx, util_tohex(data->buffer, 48, ILibScratchPad)); // [func][this][hashString]
- if (duk_pcall_method(data->ctx, 1) != 0) // [retVal]
- {
- ILibDuktape_Process_UncaughtException(data->ctx);
- }
- duk_pop(data->ctx); // ...
- }
+ duk_push_external_buffer(data->ctx); // [extBuffer]
+ duk_config_buffer(data->ctx, -1, data->buffer, 48);
+ ILibDuktape_EventEmitter_SetupEmit(data->ctx, data->object, "hash"); // [extBuffer][emit][this]['hash']
+ duk_push_buffer_object(data->ctx, -4, 0, 48, DUK_BUFOBJ_NODEJS_BUFFER); // [extBuffer][emit][this]['hash'][hash]
+ if (duk_pcall_method(data->ctx, 2) != 0) { ILibDuktape_Process_UncaughtException(data->ctx); }
+ duk_pop_2(data->ctx); // ...
+
+ ILibDuktape_EventEmitter_SetupEmit(data->ctx, data->object, "hashString"); // [emit][this]['hashString']
+ duk_push_string(data->ctx, util_tohex(data->buffer, 48, ILibScratchPad)); // [emit][this]['hashString'][hashString]
+ if (duk_pcall_method(data->ctx, 2) != 0) { ILibDuktape_Process_UncaughtException(data->ctx); }
+ duk_pop(data->ctx); // ...
}
duk_ret_t ILibDuktape_SHA256_SIGNER_Finalizer(duk_context *ctx)
{
@@ -175,7 +160,7 @@ void ILibDuktape_SHA256_SIGNER_End(struct ILibDuktape_WritableStream *stream, vo
duk_swap_top(data->ctx, -2); // [sigBuffer][signer]
duk_push_heapptr(data->ctx, data->OnSignature); // [sigBuffer][signer][func]
duk_swap_top(data->ctx, -2); // [sigBuffer][func][signer/this]
- duk_push_buffer_object(data->ctx, -3, 0, len, DUK_BUFOBJ_DUKTAPE_BUFFER); // [sigBuffer][func][signer/this][bufView]
+ duk_push_buffer_object(data->ctx, -3, 0, len, DUK_BUFOBJ_NODEJS_BUFFER); // [sigBuffer][func][signer/this][bufView]
if (duk_pcall_method(data->ctx, 1) != 0) { ILibDuktape_Process_UncaughtException(data->ctx); } // ...
}
duk_pop(data->ctx); // ...
@@ -363,29 +348,23 @@ void ILibDuktape_MD5_End(struct ILibDuktape_WritableStream *stream, void *user)
data->buffer[32] = 0;
MD5_Final((unsigned char*)data->buffer, &(data->mctx));
- if (data->ctx != NULL && data->OnHash != NULL)
+ duk_push_external_buffer(data->ctx); // [extBuffer]
+ duk_config_buffer(data->ctx, -1, data->buffer, 32);
+ ILibDuktape_EventEmitter_SetupEmit(data->ctx, data->object, "hash"); // [extBuffer][emit][this]["hash"]
+ duk_push_buffer_object(data->ctx, -4, 0, 32, DUK_BUFOBJ_NODEJS_BUFFER); // [extBuffer][emit][this]["hash"][buffer]
+ if (duk_pcall_method(data->ctx, 2) != 0) // [retVal]
{
- duk_push_heapptr(data->ctx, data->OnHash); // [func]
- duk_push_heapptr(data->ctx, data->object); // [func][this]
- duk_push_external_buffer(data->ctx); // [func][this][hash]
- duk_config_buffer(data->ctx, -1, data->buffer, 32);
- if (duk_pcall_method(data->ctx, 1) != 0) // [retVal]
- {
- ILibDuktape_Process_UncaughtException(data->ctx);
- }
- duk_pop(data->ctx); // ...
+ ILibDuktape_Process_UncaughtException(data->ctx);
}
- if (data->ctx != NULL && data->OnHashString != NULL)
+ duk_pop_2(data->ctx); // ...
+
+ ILibDuktape_EventEmitter_SetupEmit(data->ctx, data->object, "hashString"); // [emit][this]["hashString"]
+ duk_push_string(data->ctx, util_tohex(data->buffer, 32, ILibScratchPad)); // [emit][this]["hashString"][hashString]
+ if (duk_pcall_method(data->ctx, 2) != 0) // [retVal]
{
- duk_push_heapptr(data->ctx, data->OnHashString); // [func]
- duk_push_heapptr(data->ctx, data->object); // [func][this]
- duk_push_string(data->ctx, util_tohex(data->buffer, 32, ILibScratchPad)); // [func][this][hashString]
- if (duk_pcall_method(data->ctx, 1) != 0) // [retVal]
- {
- ILibDuktape_Process_UncaughtException(data->ctx);
- }
- duk_pop(data->ctx); // ...
+ ILibDuktape_Process_UncaughtException(data->ctx);
}
+ duk_pop(data->ctx); // ...
}
duk_ret_t ILibDuktape_MD5_syncHash(duk_context *ctx)
{
@@ -431,8 +410,8 @@ duk_ret_t ILibDuktape_MD5_Create(duk_context *ctx)
ILibDuktape_CreateInstanceMethodWithBooleanProperty(ctx, "strRet", 0, "syncHash", ILibDuktape_MD5_syncHash, 1);
ILibDuktape_CreateInstanceMethodWithBooleanProperty(ctx, "strRet", 1, "syncHashString", ILibDuktape_MD5_syncHash, 1);
- ILibDuktape_EventEmitter_CreateEvent(emitter, "hash", &(data->OnHash));
- ILibDuktape_EventEmitter_CreateEvent(emitter, "hashString", &(data->OnHashString));
+ ILibDuktape_EventEmitter_CreateEventEx(emitter, "hash");
+ ILibDuktape_EventEmitter_CreateEventEx(emitter, "hashString");
data->ctx = ctx;
data->object = duk_get_heapptr(ctx, -1);
@@ -457,8 +436,8 @@ duk_ret_t ILibDuktape_SHA256_Create(duk_context *ctx)
ILibDuktape_CreateInstanceMethodWithBooleanProperty(ctx, "strRet", 0, "syncHash", ILibDuktape_SHA256_syncHash, 1);
ILibDuktape_CreateInstanceMethodWithBooleanProperty(ctx, "strRet", 1, "syncHashString", ILibDuktape_SHA256_syncHash, 1);
- ILibDuktape_EventEmitter_CreateEvent(emitter, "hash", &(data->OnHash));
- ILibDuktape_EventEmitter_CreateEvent(emitter, "hashString", &(data->OnHashString));
+ ILibDuktape_EventEmitter_CreateEventEx(emitter, "hash");
+ ILibDuktape_EventEmitter_CreateEventEx(emitter, "hashString");
data->ctx = ctx;
data->object = duk_get_heapptr(ctx, -1);
@@ -474,6 +453,7 @@ duk_ret_t ILibDuktape_SHA384_Create(duk_context *ctx)
ILibDuktape_EventEmitter *emitter;
duk_push_object(ctx); // [sha]
+ ILibDuktape_WriteID(ctx, "SHA384Stream");
duk_push_fixed_buffer(ctx, sizeof(ILibDuktape_SHA512_Data)); // [sha][buffer]
data = (ILibDuktape_SHA512_Data*)Duktape_GetBuffer(ctx, -1, NULL);
duk_put_prop_string(ctx, -2, ILibDuktape_SHA512_PTR); // [sha]
@@ -484,8 +464,8 @@ duk_ret_t ILibDuktape_SHA384_Create(duk_context *ctx)
ILibDuktape_CreateInstanceMethodWithBooleanProperty(ctx, "strRet", 0, "syncHash", ILibDuktape_SHA384_syncHash, 1);
ILibDuktape_CreateInstanceMethodWithBooleanProperty(ctx, "strRet", 1, "syncHashString", ILibDuktape_SHA384_syncHash, 1);
- ILibDuktape_EventEmitter_CreateEvent(emitter, "hash", &(data->OnHash));
- ILibDuktape_EventEmitter_CreateEvent(emitter, "hashString", &(data->OnHashString));
+ ILibDuktape_EventEmitter_CreateEventEx(emitter, "hash");
+ ILibDuktape_EventEmitter_CreateEventEx(emitter, "hashString");
data->ctx = ctx;
data->object = duk_get_heapptr(ctx, -1);
diff --git a/microscript/ILibDuktape_SHA256.h b/microscript/ILibDuktape_SHA256.h
index 152b75c..d47ec1c 100644
--- a/microscript/ILibDuktape_SHA256.h
+++ b/microscript/ILibDuktape_SHA256.h
@@ -1,3 +1,19 @@
+/*
+Copyright 2006 - 2018 Intel Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
#ifndef ___DUKTAPE_SHA256___
#define ___DUKTAPE_SHA256___
diff --git a/microscript/ILibDuktape_ScriptContainer.c b/microscript/ILibDuktape_ScriptContainer.c
index d1ed4b2..238d02e 100644
--- a/microscript/ILibDuktape_ScriptContainer.c
+++ b/microscript/ILibDuktape_ScriptContainer.c
@@ -1,11 +1,11 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-http://www.apache.org/licenses/LICENSE-2.0
+ http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,7 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-
#ifdef WIN32
#include
#include
@@ -52,6 +51,7 @@ limitations under the License.
#include "ILibDuktape_Polyfills.h"
#include "ILibDuktape_SimpleDataStore.h"
#include "ILibDuktape_NetworkMonitor.h"
+#include "ILibDuktape_ReadableStream.h"
#include "ILibDuktape_SHA256.h"
#include "ILibDuktape_EncryptionStream.h"
@@ -62,13 +62,16 @@ limitations under the License.
extern char **environ;
#endif
#define SCRIPT_ENGINE_PIPE_BUFFER_SIZE 65535
+
+char exeJavaScriptGuid[] = "B996015880544A19B7F7E9BE44914C18";
#define ILibDuktape_ScriptContainer_MasterPtr "\xFF_ScriptContainer_MasterPtr"
#define ILibDuktape_ScriptContainer_SlavePtr "\xFF_ScriptContainer_SlavePtr"
#define ILibDuktape_ScriptContainer_ExePath "\xFF_ScriptContainer_ExePath"
#define ILibDuktape_ScriptContainer_PipeManager "\xFF_ScriptContainer_PipeManager"
#define ILibDuktape_ScriptContainer_PtrTable "\xFF_ScriptContainer_PtrTable"
#define ILibDuktape_ScriptContainer_PtrTable_Idx "\xFF_ScriptContainer_PtrTableIdx"
-
+#define ILibDuktape_ScriptContainer_ProcessIsolated "\xFF_ScriptContainer_ProcessIsolated"
+#define ILibDuktape_ScriptContainer_PeerThread "\xFF_ScriptContainer_PeerThread"
#define ILibDuktape_ScriptContainer_Command_Execute_Status "ScriptContainer_Command_Execute_Status"
#define ILibDuktape_ScriptContainer_Command_Log "ScriptContainer_Command_Log"
@@ -79,6 +82,7 @@ extern char **environ;
#define ILibDuktape_ScriptContainer_Settings_ExitUser "\xFF_ScriptContainerSettings_ExitUser"
#define ILibDuktape_ScriptContainer_Process_ArgArray "\xFF_argArray"
#define ILibDuktape_ScriptContainer_Process_Restart "\xFF_ScriptContainer_Process_Restart"
+#define ILibDuktape_ScriptContainer_Process_stdin "\xFF_stdin"
#define ILibDuktape_ScriptContainer_ExitCode "\xFF_ExitCode"
#define ILibDuktape_ScriptContainer_Exitting "\xFF_Exiting"
@@ -111,6 +115,7 @@ extern char **environ;
extern void ILibDuktape_MemoryStream_Init(duk_context *ctx);
extern void ILibDuktape_NetworkMonitor_Init(duk_context *ctx);
+char g_AgentCrashID[280];
typedef enum SCRIPT_ENGINE_COMMAND
{
@@ -121,6 +126,8 @@ typedef enum SCRIPT_ENGINE_COMMAND
SCRIPT_ENGINE_COMMAND_SEND_JSON = 0x10,
SCRIPT_ENGINE_COMMAND_QUERY = 0x20,
SCRIPT_ENGINE_COMMAND_SET = 0x21,
+ SCRIPT_ENGINE_COMMAND_ERROR = 0x40,
+ SCRIPT_ENGINE_COMMAND_EXIT = 0x80,
SCRIPT_ENGINE_COMMAND_LOG = 0xFF
}SCRIPT_ENGINE_COMMAND;
@@ -132,7 +139,8 @@ typedef struct ILibDuktape_ScriptContainer_Master
ILibProcessPipe_Process child;
void *chain;
- void *OnExit, *OnError, *OnJSON;
+ void *PeerThread, *PeerChain;
+ unsigned int ChildSecurityFlags;
}ILibDuktape_ScriptContainer_Master;
typedef struct ILibDuktape_ScriptContainer_Slave
@@ -140,11 +148,21 @@ typedef struct ILibDuktape_ScriptContainer_Slave
duk_context *ctx;
ILibDuktape_EventEmitter *emitter;
- void *OnData;
void *chain;
int exitCode;
+ int noRespond;
}ILibDuktape_ScriptContainer_Slave;
+
+typedef struct ILibDuktape_ScriptContainer_NonIsolated_Command
+{
+ union { ILibDuktape_ScriptContainer_Master * master; ILibDuktape_ScriptContainer_Slave *slave; }container;
+ char json[];
+}ILibDuktape_ScriptContainer_NonIsolated_Command;
+
+void ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsSlave(void *chain, void *user);
+void ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsMaster(void *chain, void *user);
+
#ifdef _REMOTELOGGING
void ILibDuktape_ScriptContainer_Slave_LogForwarder(ILibRemoteLogging sender, ILibRemoteLogging_Modules module, ILibRemoteLogging_Flags flags, char *buffer, int bufferLen)
{
@@ -190,40 +208,134 @@ void ILibDuktape_ScriptContainer_Slave_OnBrokenPipe(ILibProcessPipe_Pipe sender)
void ILibDuktape_ScriptContainer_CheckEmbedded(char **argv, char **script, int *scriptLen)
{
// Check if .JS file is integrated with executable
+ int i;
FILE *tmpFile;
char *integratedJavaScript = NULL;
int integratedJavaScriptLen = 0;
#ifdef WIN32
if (ILibString_EndsWith(argv[0], -1, ".exe", 4) == 0)
{
+ i = sprintf_s(g_AgentCrashID, sizeof(g_AgentCrashID), "%s_", argv[0]);
sprintf_s(ILibScratchPad, sizeof(ILibScratchPad), "%s.exe", argv[0]);
fopen_s(&tmpFile, ILibScratchPad, "rb");
}
else
{
+ i = ILibString_LastIndexOf(argv[0], -1, "\\", 1);
+ if (i > 0)
+ {
+ i = sprintf_s(g_AgentCrashID, sizeof(g_AgentCrashID), "%s", argv[0] + i + 1);
+ g_AgentCrashID[i-4] = '_';
+ i -= 3;
+ }
+ else
+ {
+ i = sprintf_s(g_AgentCrashID, sizeof(g_AgentCrashID), "%s", argv[0]);
+ g_AgentCrashID[i-4] = '_';
+ i -= 3;
+ }
fopen_s(&tmpFile, argv[0], "rb");
}
#else
+ i = sprintf_s(g_AgentCrashID, sizeof(g_AgentCrashID), "%s_", argv[0]);
tmpFile = fopen(argv[0], "rb");
#endif
if (tmpFile != NULL)
{
- fseek(tmpFile, 0, SEEK_END);
- fseek(tmpFile, ftell(tmpFile) - 4, SEEK_SET);
- ignore_result(fread(ILibScratchPad, 1, 4, tmpFile));
- fseek(tmpFile, 0, SEEK_END);
- if (ftell(tmpFile) == ntohl(((int*)ILibScratchPad)[0]))
+ SHA512_CTX shctx;
+ char hashBuffer[4096];
+ char hashValue[1 + UTIL_SHA384_HASHSIZE];
+ int hashBufferReadLen;
+
+ SHA384_Init(&shctx);
+ while ((hashBufferReadLen = (int)fread(hashBuffer, 1, sizeof(hashBuffer), tmpFile)) > 0)
{
- fseek(tmpFile, ftell(tmpFile) - 8, SEEK_SET);
+ SHA384_Update(&shctx, hashBuffer, hashBufferReadLen);
+ }
+ SHA384_Final((unsigned char*)hashValue, &shctx);
+ util_tohex(hashValue, UTIL_SHA384_HASHSIZE, g_AgentCrashID + i);
+#ifdef WIN32
+ memcpy_s(g_AgentCrashID + i + 16, 5, ".exe", 5);
+#else
+ g_AgentCrashID[i + 16] = 0;
+#endif
+
+ g_ILibCrashID = g_AgentCrashID;
+
+#ifdef WIN32
+ // Read the PE Headers, to determine where to look for the Embedded JS
+ char *optHeader = NULL;
+ fseek(tmpFile, 0, SEEK_SET);
+ ignore_result(fread(ILibScratchPad, 1, 2, tmpFile));
+ if (ntohs(((unsigned int*)ILibScratchPad)[0]) == 19802) // 5A4D
+ {
+ fseek(tmpFile, 60, SEEK_SET);
ignore_result(fread(ILibScratchPad, 1, 4, tmpFile));
- integratedJavaScriptLen = ntohl(((int*)ILibScratchPad)[0]);
- integratedJavaScript = ILibMemory_Allocate(1 + integratedJavaScriptLen, 0, NULL, NULL);
- fseek(tmpFile, 0, SEEK_END);
- fseek(tmpFile, ftell(tmpFile) - 8 - integratedJavaScriptLen, SEEK_SET);
+ fseek(tmpFile, ((unsigned *)ILibScratchPad)[0], SEEK_SET);
+ ignore_result(fread(ILibScratchPad, 1, 24, tmpFile));
+ if (((unsigned int*)ILibScratchPad)[0] == 17744)
+ {
+ // PE Image
+ optHeader = ILibMemory_AllocateA(((unsigned short*)ILibScratchPad)[10]);
+ ignore_result(fread(optHeader, 1, ILibMemory_AllocateA_Size(optHeader), tmpFile));
+ switch (((unsigned short*)optHeader)[0])
+ {
+ case 0x10B:
+ if (((unsigned int*)(optHeader + 128))[0] != 0)
+ {
+ fseek(tmpFile, ((unsigned int*)(optHeader + 128))[0] - 16, SEEK_SET);
+ }
+ else
+ {
+ fseek(tmpFile, -16, SEEK_END);
+ }
+ break;
+ case 0x20B:
+ if (((unsigned int*)(optHeader + 144))[0] != 0)
+ {
+ fseek(tmpFile, ((unsigned int*)(optHeader + 144))[0] - 16, SEEK_SET);
+ }
+ else
+ {
+ fseek(tmpFile, -16, SEEK_END);
+ }
+ break;
+ default:
+ fclose(tmpFile);
+ return;
+ }
+ ignore_result(fread(ILibScratchPad, 1, 16, tmpFile));
+ util_hexToBuf(exeJavaScriptGuid, 32, ILibScratchPad2);
+ if (memcmp(ILibScratchPad, ILibScratchPad2, 16) == 0)
+ {
+ // Found an Embedded JS
+ fseek(tmpFile, -20, SEEK_CUR);
+ ignore_result(fread((void*)&integratedJavaScriptLen, 1, 4, tmpFile));
+ integratedJavaScriptLen = (int)ntohl(integratedJavaScriptLen);
+ fseek(tmpFile, -4 - integratedJavaScriptLen, SEEK_CUR);
+ integratedJavaScript = ILibMemory_Allocate(integratedJavaScriptLen + 1, 0, NULL, NULL);
+ ignore_result(fread(integratedJavaScript, 1, integratedJavaScriptLen, tmpFile));
+ integratedJavaScript[integratedJavaScriptLen] = 0;
+ }
+ }
+ }
+#else
+ fseek(tmpFile, -16, SEEK_END);
+ ignore_result(fread(ILibScratchPad, 1, 16, tmpFile));
+ util_hexToBuf(exeJavaScriptGuid, 32, ILibScratchPad2);
+ if (memcmp(ILibScratchPad, ILibScratchPad2, 16) == 0)
+ {
+ // Found an Embedded JS
+ fseek(tmpFile, -20, SEEK_CUR);
+ ignore_result(fread((void*)&integratedJavaScriptLen, 1, 4, tmpFile));
+ integratedJavaScriptLen = (int)ntohl(integratedJavaScriptLen);
+ fseek(tmpFile, -4 - integratedJavaScriptLen, SEEK_CUR);
+ integratedJavaScript = ILibMemory_Allocate(integratedJavaScriptLen + 1, 0, NULL, NULL);
ignore_result(fread(integratedJavaScript, 1, integratedJavaScriptLen, tmpFile));
integratedJavaScript[integratedJavaScriptLen] = 0;
}
+#endif
fclose(tmpFile);
}
*script = integratedJavaScript;
@@ -353,6 +465,146 @@ duk_ret_t ILibDuktape_ScriptContainer_Process_env(duk_context *ctx)
return(1);
}
+duk_ret_t ILibDuktape_ScriptContainer_Process_Finalizer(duk_context *ctx)
+{
+ // We need to dispatch the 'exit' event
+ int exitCode = 0;
+ duk_push_this(ctx); // [process]
+ if (duk_has_prop_string(ctx, -1, "\xFF_ExitCode"))
+ {
+ duk_get_prop_string(ctx, -1, "\xFF_ExitCode"); // [process][exitCode]
+ exitCode = duk_get_int(ctx, -1);
+ duk_pop(ctx); // [process]
+ }
+ ILibDuktape_EventEmitter_SetupEmit(ctx, duk_get_heapptr(ctx, -1), "exit"); // [emit][this]['exit']
+ duk_push_int(ctx, exitCode); // [emit][this]['exit'][exitCode]
+ duk_call_method(ctx, 2);
+ return(0);
+}
+
+
+typedef struct ILibDuktape_Process_StdIn_Data
+{
+ ILibDuktape_readableStream *rs;
+#ifdef WIN32
+ HANDLE workerThread;
+ HANDLE resumeEvent;
+ int exit;
+#endif
+ int wasUnshifted;
+ int endPointer;
+ int bufferSize;
+ char buffer[];
+}ILibDuktape_Process_StdIn_Data;
+
+#ifdef WIN32
+void __stdcall ILibDuktape_Process_stdin_readSink(ULONG_PTR obj)
+{
+ ILibDuktape_Process_StdIn_Data *data = (ILibDuktape_Process_StdIn_Data*)obj;
+ int endPointer;
+ do
+ {
+ endPointer = data->endPointer;
+ data->wasUnshifted = 0;
+ ILibDuktape_readableStream_WriteData(data->rs, data->buffer, data->endPointer);
+ } while (!data->rs->paused && data->wasUnshifted > 0 && data->wasUnshifted != endPointer);
+
+ data->endPointer = data->wasUnshifted;
+ if (!data->rs->paused) { SetEvent(data->resumeEvent); }
+}
+#endif
+void ILibDuktape_Process_stdin_pauseSink(struct ILibDuktape_readableStream *sender, void *user)
+{
+ UNREFERENCED_PARAMETER(sender);
+ UNREFERENCED_PARAMETER(user);
+
+ // NO-OP, because stream state flag will be paused, which will cause the processing loop to exit
+}
+void ILibDuktape_Process_stdin_resumeSink(struct ILibDuktape_readableStream *sender, void *user)
+{
+ ILibDuktape_Process_StdIn_Data *data = (ILibDuktape_Process_StdIn_Data*)user;
+#ifdef WIN32
+ SetEvent(data->resumeEvent);
+#endif
+}
+int ILibDuktape_Process_stdin_unshiftSink(struct ILibDuktape_readableStream *sender, int unshiftBytes, void *user)
+{
+ ILibDuktape_Process_StdIn_Data *data = (ILibDuktape_Process_StdIn_Data*)user;
+ data->wasUnshifted = unshiftBytes <= data->endPointer ? unshiftBytes : data->endPointer;
+
+ if (unshiftBytes > 0 && unshiftBytes < data->endPointer)
+ {
+ memmove_s(data->buffer, data->bufferSize, data->buffer + (data->endPointer - unshiftBytes), unshiftBytes);
+ data->endPointer = unshiftBytes;
+ }
+ return(data->wasUnshifted);
+}
+#ifdef WIN32
+void ILibDuktape_Process_stdin_WindowsRunLoop(void *arg)
+{
+ ILibDuktape_Process_StdIn_Data *data = (ILibDuktape_Process_StdIn_Data*)arg;
+ HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
+ DWORD bytesRead, waitResult;
+
+ while (((waitResult = WaitForSingleObjectEx(data->resumeEvent, INFINITE, TRUE)) == WAIT_OBJECT_0 || waitResult == WAIT_IO_COMPLETION) && !data->exit)
+ {
+ if (!ReadFile(h, data->buffer + data->endPointer, data->bufferSize - data->endPointer, &bytesRead, NULL))
+ {
+ break;
+ }
+ else
+ {
+ ResetEvent(data->resumeEvent); // Reset, becuase we'll need to pause and context switch to Duktape thread
+ data->endPointer += (int)bytesRead;
+ QueueUserAPC((PAPCFUNC)ILibDuktape_Process_stdin_readSink, ILibChain_GetMicrostackThreadHandle(data->rs->chain), (ULONG_PTR)data);
+ }
+ }
+}
+#endif
+duk_ret_t ILibDuktape_Process_stdin_finalizer(duk_context *ctx)
+{
+ duk_get_prop_string(ctx, 0, ILibDuktape_readableStream_RSPTRS);
+ ILibDuktape_readableStream *rs = (ILibDuktape_readableStream*)Duktape_GetBuffer(ctx, -1, NULL);
+ ILibDuktape_Process_StdIn_Data *data = (ILibDuktape_Process_StdIn_Data*)rs->user;
+
+#ifdef WIN32
+ data->exit = 1;
+ SetEvent(data->resumeEvent);
+ CancelSynchronousIo(data->workerThread);
+ WaitForSingleObject(data->workerThread, 10000);
+
+ CloseHandle(data->resumeEvent);
+#endif
+
+ free(data);
+ return(0);
+}
+duk_ret_t ILibDuktape_Process_stdin_get(duk_context *ctx)
+{
+ duk_push_this(ctx); // [process]
+ if (duk_has_prop_string(ctx, -1, ILibDuktape_ScriptContainer_Process_stdin))
+ {
+ duk_get_prop_string(ctx, -1, ILibDuktape_ScriptContainer_Process_stdin);
+ return(1);
+ }
+
+ duk_push_object(ctx); // [process][stdin]
+ duk_dup(ctx, -1); // [process][stdin][dup]
+ duk_put_prop_string(ctx, -3, ILibDuktape_ScriptContainer_Process_stdin); // [process][stdin]
+ ILibDuktape_WriteID(ctx, "process.stdin");
+ ILibDuktape_readableStream *rs = ILibDuktape_ReadableStream_InitEx(ctx, ILibDuktape_Process_stdin_pauseSink, ILibDuktape_Process_stdin_resumeSink, ILibDuktape_Process_stdin_unshiftSink, NULL);
+ rs->user = ILibMemory_Allocate(sizeof(ILibDuktape_Process_StdIn_Data) + 4096, 0, NULL, NULL);
+ ((ILibDuktape_Process_StdIn_Data*)rs->user)->rs = rs;
+ ((ILibDuktape_Process_StdIn_Data*)rs->user)->bufferSize = 4096;
+
+#ifdef WIN32
+ ((ILibDuktape_Process_StdIn_Data*)rs->user)->resumeEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+ ((ILibDuktape_Process_StdIn_Data*)rs->user)->workerThread = ILibSpawnNormalThread(ILibDuktape_Process_stdin_WindowsRunLoop, rs->user);
+#endif
+
+ ILibDuktape_EventEmitter_AddOnEx(ctx, -1, "~", ILibDuktape_Process_stdin_finalizer);
+ return(1);
+}
void ILibDuktape_ScriptContainer_Process_Init(duk_context *ctx, char **argList)
{
int i = 0;
@@ -360,6 +612,7 @@ void ILibDuktape_ScriptContainer_Process_Init(duk_context *ctx, char **argList)
duk_push_global_object(ctx); // [g]
duk_push_object(ctx); // [g][process]
+ ILibDuktape_WriteID(ctx, "process");
ILibDuktape_CreateEventWithGetter(ctx, "env", ILibDuktape_ScriptContainer_Process_env);
#if defined(WIN32) // [g][process][platform]
@@ -416,8 +669,21 @@ void ILibDuktape_ScriptContainer_Process_Init(duk_context *ctx, char **argList)
duk_push_int(ctx, 0);
ILibDuktape_CreateEventWithGetterAndCustomProperty(ctx, "readOnly", "_argv", ILibDuktape_ScriptContainer_Process_Argv);
+ duk_push_heap_stash(ctx); // [g][process][stash]
+ if (!duk_has_prop_string(ctx, -1, ILibDuktape_ScriptContainer_SlavePtr))
+ {
+ duk_pop(ctx); // [g][process]
+ ILibDuktape_CreateEventWithGetter(ctx, "stdin", ILibDuktape_Process_stdin_get);
+ }
+ else
+ {
+ duk_pop(ctx); // [g][process]
+ }
+
duk_put_prop_string(ctx, -2, "process"); // [g]
duk_pop(ctx); // ...
+
+ ILibDuktape_EventEmitter_AddOnceEx(emitter, "~", ILibDuktape_ScriptContainer_Process_Finalizer, 1);
}
void ILibDuktape_ScriptContainer_ExecTimeout_Finalizer(duk_context *ctx, void *timeoutKey)
{
@@ -510,9 +776,9 @@ void ILibDuktape_ScriptContainer_Engine_free(void *udata, void *ptr)
{
free(ptr);
}
-void ILibDuktape_ScriptContainer_Engine_fatal(duk_context *ctx, duk_errcode_t code, const char *msg)
+void ILibDuktape_ScriptContainer_Engine_fatal(void *udata, const char *msg)
{
- ILIBCRITICALEXITMSG(code, msg);
+ ILIBCRITICALEXITMSG(254, msg);
}
duk_ret_t ILibDuktape_ScriptContainer_OS_arch(duk_context *ctx)
{
@@ -756,6 +1022,7 @@ duk_ret_t ILibDuktape_ScriptContainer_OS_networkInterfaces(duk_context *ctx)
void ILibDuktape_ScriptContainer_OS_Push(duk_context *ctx, void *chain)
{
duk_push_object(ctx); // [os]
+ ILibDuktape_WriteID(ctx, "os");
#ifdef WIN32
duk_push_string(ctx, "\r\n");
@@ -773,10 +1040,13 @@ void ILibDuktape_ScriptContainer_OS_Init(duk_context *ctx)
ILibDuktape_ModSearch_AddHandler(ctx, "os", ILibDuktape_ScriptContainer_OS_Push);
}
extern void ILibDuktape_HttpStream_Init(duk_context *ctx);
-duk_context *ILibDuktape_ScriptContainer_InitializeJavaScriptEngineEx(SCRIPT_ENGINE_SECURITY_FLAGS securityFlags, unsigned int executionTimeout, void *chain, char **argList, ILibSimpleDataStore *db, char *exePath, ILibProcessPipe_Manager pipeManager, ILibDuktape_HelperEvent exitHandler, void *exitUser)
+duk_context *ILibDuktape_ScriptContainer_InitializeJavaScriptEngine_minimal()
{
duk_context *ctx = duk_create_heap(ILibDuktape_ScriptContainer_Engine_malloc, ILibDuktape_ScriptContainer_Engine_realloc, ILibDuktape_ScriptContainer_Engine_free, NULL, ILibDuktape_ScriptContainer_Engine_fatal);
- //duk_context *ctx = duk_create_heap_default();
+ return(ctx);
+}
+duk_context *ILibDuktape_ScriptContainer_InitializeJavaScriptEngineEx3(duk_context *ctx, SCRIPT_ENGINE_SECURITY_FLAGS securityFlags, unsigned int executionTimeout, void *chain, char **argList, ILibSimpleDataStore *db, char *exePath, ILibProcessPipe_Manager pipeManager, ILibDuktape_HelperEvent exitHandler, void *exitUser)
+{
void **timeoutKey = executionTimeout > 0 ? (void**)ILibMemory_Allocate(sizeof(void*), 0, NULL, NULL) : NULL;
duk_push_heap_stash(ctx); // [s]
@@ -897,7 +1167,7 @@ int ILibDuktape_ScriptContainer_CompileJavaScript_FromFile(duk_context *ctx, cha
if (path == NULL || pathLen == 0)
{
- duk_push_error_object(ctx, DUK_ERR_API_ERROR, "Invalid Path specified");
+ duk_push_error_object(ctx, DUK_ERR_ERROR, "Invalid Path specified");
return(1);
}
else
@@ -1153,16 +1423,15 @@ void ILibDuktape_ScriptContainer_Slave_ProcessCommands(ILibDuktape_ScriptContain
break;
case SCRIPT_ENGINE_COMMAND_SEND_JSON:
{
- if (slave->OnData != NULL)
+ if (ILibDuktape_EventEmitter_HasListeners(slave->emitter, "data")!=0)
{
char *json = Duktape_GetStringPropertyValue(slave->ctx, -1, "json", NULL);
if (json != NULL)
{
- duk_push_heapptr(slave->ctx, slave->OnData); // [func]
- duk_push_heapptr(slave->ctx, slave->emitter->object); // [func][this]
- duk_push_string(slave->ctx, json); // [func][this][json]
- duk_json_decode(slave->ctx, -1); // [func][this][object]
- if (duk_pcall_method(slave->ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(slave->ctx, "ScriptContainer.OnData(): "); }
+ ILibDuktape_EventEmitter_SetupEmit(slave->ctx, slave->emitter->object, "data"); // [emit][this][data]
+ duk_push_string(slave->ctx, json); // [emit][this][data][json]
+ duk_json_decode(slave->ctx, -1); // [emit][this][data][object]
+ if (duk_pcall_method(slave->ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(slave->ctx, "ScriptContainer.OnData(): "); }
duk_pop(slave->ctx); // ...
}
}
@@ -1313,6 +1582,15 @@ duk_ret_t ILibDuktape_ScriptContainer_Exit(duk_context *ctx)
duk_push_this(ctx);
duk_get_prop_string(ctx, -1, ILibDuktape_ScriptContainer_MasterPtr);
master = (ILibDuktape_ScriptContainer_Master*)Duktape_GetBuffer(ctx, -1, NULL);
+ if (master->PeerChain != NULL)
+ {
+ char json[] = "{\"command\": \"128\"}";
+ ILibDuktape_ScriptContainer_NonIsolated_Command *cmd = ILibMemory_Allocate(sizeof(json) + sizeof(ILibDuktape_ScriptContainer_NonIsolated_Command), 0, NULL, NULL);
+ cmd->container.slave = ((void**)ILibMemory_GetExtraMemory(master->PeerChain, ILibMemory_CHAIN_CONTAINERSIZE))[1];
+ memcpy_s(cmd->json, sizeof(json), json, sizeof(json));
+ ILibChain_RunOnMicrostackThread(master->PeerChain, ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsSlave, cmd);
+ return(0);
+ }
if (ILibIsChainBeingDestroyed(Duktape_GetChain(ctx)) == 0)
{
@@ -1338,6 +1616,27 @@ duk_ret_t ILibDuktape_ScriptContainer_ExecuteString(duk_context *ctx)
duk_get_prop_string(ctx, -1, ILibDuktape_ScriptContainer_MasterPtr); // [container][buffer]
master = (ILibDuktape_ScriptContainer_Master*)Duktape_GetBuffer(ctx, -1, NULL); // [container][buffer]
+
+ if (master->PeerChain != NULL)
+ {
+ char json[] = "{\"command\": \"2\", \"base64\": \"\"}";
+ char *payload;
+ duk_size_t payloadLen;
+ payload = (char*)duk_get_lstring(ctx, 0, &payloadLen);
+ int encodedPayloadLen = ILibBase64EncodeLength((int)payloadLen);
+ ILibDuktape_ScriptContainer_NonIsolated_Command *cmd = (ILibDuktape_ScriptContainer_NonIsolated_Command*)ILibMemory_Allocate(sizeof(ILibDuktape_ScriptContainer_NonIsolated_Command) + encodedPayloadLen + sizeof(json), 0, NULL, NULL);
+
+ cmd->container.slave = (ILibDuktape_ScriptContainer_Slave*)((void**)ILibMemory_GetExtraMemory(master->PeerChain, ILibMemory_CHAIN_CONTAINERSIZE))[1];
+ int i = sprintf_s(cmd->json, sizeof(json) + encodedPayloadLen, json);
+ char *output = cmd->json + i -2;
+ i += ILibBase64Encode((unsigned char*)payload, (int)payloadLen, (unsigned char**)&output);
+ sprintf_s(cmd->json + i - 2, 3, "\"}");
+
+ ILibChain_RunOnMicrostackThread(master->PeerChain, ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsSlave, cmd);
+ return(0);
+ }
+
+
if (ptr != NULL) { seq = ILibDuktape_ScriptContainer_AddVoidPtr(ctx, duk_get_heapptr(ctx, -2), ptr); }
duk_push_object(ctx); // [container][buffer][obj]
@@ -1364,18 +1663,13 @@ duk_ret_t ILibDuktape_ScriptContainer_ExecuteString(duk_context *ctx)
void ILibDuktape_ScriptContainer_ExitSink(ILibProcessPipe_Process sender, int exitCode, void* user)
{
ILibDuktape_ScriptContainer_Master *master = (ILibDuktape_ScriptContainer_Master*)user;
-
- if (master->OnExit != NULL)
+ ILibDuktape_EventEmitter_SetupEmit(master->ctx, master->emitter->object, "exit"); // [emit][this][exit]
+ duk_push_int(master->ctx, exitCode); // [emit][this][exit][code]
+ if (duk_pcall_method(master->ctx, 2) != 0)
{
- duk_push_heapptr(master->ctx, master->OnExit); // [func]
- duk_push_heapptr(master->ctx, master->emitter->object); // [func][this]
- duk_push_int(master->ctx, exitCode); // [func][this][code]
- if (duk_pcall_method(master->ctx, 1) != 0) // [retVal]
- {
- ILibDuktape_Process_UncaughtException(master->ctx);
- }
- duk_pop(master->ctx); // ...
+ ILibDuktape_Process_UncaughtException(master->ctx);
}
+ duk_pop(master->ctx);
master->child = NULL;
}
@@ -1402,16 +1696,15 @@ void ILibDuktape_ScriptContainer_StdErrSink_MicrostackThread(void *chain, void *
{
case SCRIPT_ENGINE_COMMAND_SEND_JSON:
{
- if (master->OnJSON != NULL)
- {
+ if(ILibDuktape_EventEmitter_HasListeners(master->emitter, "data")!=0)
+ {
char *json = Duktape_GetStringPropertyValue(master->ctx, -1, "json", NULL);
if (json != NULL)
{
- duk_push_heapptr(master->ctx, master->OnJSON);
- duk_push_heapptr(master->ctx, master->emitter->object);
- duk_push_string(master->ctx, json);
- duk_json_decode(master->ctx, -1);
- if (duk_pcall_method(master->ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(master->ctx, "ScriptContainer.OnData(): "); }
+ ILibDuktape_EventEmitter_SetupEmit(master->ctx, master->emitter->object, "data"); // [emit][this][data]
+ duk_push_string(master->ctx, json); // [emit][this][data][str]
+ duk_json_decode(master->ctx, -1); // [emit][this][data][json]
+ if (duk_pcall_method(master->ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(master->ctx, "ScriptContainer.OnData(): "); }
duk_pop(master->ctx);
}
}
@@ -1430,14 +1723,10 @@ void ILibDuktape_ScriptContainer_StdErrSink_MicrostackThread(void *chain, void *
if ((i = Duktape_GetIntPropertyValue(master->ctx, -1, "sequence", -1)) < 0)
{
// No callback was specified
- if (master->OnError != NULL)
- {
- duk_push_heapptr(master->ctx, master->OnError); // [func]
- duk_push_heapptr(master->ctx, master->emitter->object); // [func][this]
- duk_get_prop_string(master->ctx, -3, "error"); // [func][this][error]
- if (duk_pcall_method(master->ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(master->ctx, "ScriptContainer_OnError_Dispatch(): "); }
- duk_pop(master->ctx); // ...
- }
+ ILibDuktape_EventEmitter_SetupEmit(master->ctx, master->emitter->object, "error"); // [emit][this][error]
+ duk_get_prop_string(master->ctx, -4, "error"); // [emit][this][error][errorObj]
+ if (duk_pcall_method(master->ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(master->ctx, "ScriptContainer_OnError_Dispatch(): "); }
+ duk_pop(master->ctx); // ...
}
else
{
@@ -1515,6 +1804,17 @@ duk_ret_t ILibDuktape_ScriptContainer_Finalizer(duk_context *ctx)
{
ILibProcessPipe_Process_KillEx(master->child);
}
+ else if (master->PeerChain != NULL)
+ {
+ char json[] = "{\"command\": \"128\", \"noResponse\": \"1\"}";
+ ILibDuktape_ScriptContainer_NonIsolated_Command *cmd = ILibMemory_Allocate(sizeof(json) + sizeof(ILibDuktape_ScriptContainer_NonIsolated_Command), 0, NULL, NULL);
+ cmd->container.slave = ((void**)ILibMemory_GetExtraMemory(master->PeerChain, ILibMemory_CHAIN_CONTAINERSIZE))[1];
+ memcpy_s(cmd->json, sizeof(json), json, sizeof(json));
+ ILibChain_RunOnMicrostackThread(master->PeerChain, ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsSlave, cmd);
+#ifdef WIN32
+ WaitForSingleObject(master->PeerThread, INFINITE);
+#endif
+ }
return(0);
}
@@ -1535,10 +1835,23 @@ duk_ret_t ILibDuktape_ScriptContainer_SendToSlave(duk_context *ctx)
duk_put_prop_string(ctx, -2, "json"); // [container][master][obj]
duk_json_encode(ctx, -1); // [container][master][json]
- len = sprintf_s(ILibScratchPad2 + 4, sizeof(ILibScratchPad2) - 4, "%s", duk_get_string(ctx, -1));
- ((int*)ILibScratchPad2)[0] = len + 4;
- ILibProcessPipe_Process_WriteStdIn(master->child, ILibScratchPad2, len + 4, ILibTransport_MemoryOwnership_USER);
+ if (master->child != NULL)
+ {
+ len = sprintf_s(ILibScratchPad2 + 4, sizeof(ILibScratchPad2) - 4, "%s", duk_get_string(ctx, -1));
+ ((int*)ILibScratchPad2)[0] = len + 4;
+
+ ILibProcessPipe_Process_WriteStdIn(master->child, ILibScratchPad2, len + 4, ILibTransport_MemoryOwnership_USER);
+ }
+ else if(master->PeerChain != NULL)
+ {
+ duk_size_t payloadLen;
+ char *payload = (char*)duk_get_lstring(ctx, -1, &payloadLen);
+ ILibDuktape_ScriptContainer_NonIsolated_Command *cmd = ILibMemory_Allocate(sizeof(ILibDuktape_ScriptContainer_NonIsolated_Command) + (int)payloadLen + 1, 0, NULL, NULL);
+ cmd->container.slave = (ILibDuktape_ScriptContainer_Slave*)((void**)ILibMemory_GetExtraMemory(master->PeerChain, ILibMemory_CHAIN_CONTAINERSIZE))[1];
+ memcpy_s(cmd->json, payloadLen + 1, payload, payloadLen + 1);
+ ILibChain_RunOnMicrostackThread(master->PeerChain, ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsSlave, cmd);
+ }
return(0);
}
duk_ret_t ILibDuktape_ScriptContainer_Master_AddModule(duk_context *ctx)
@@ -1565,6 +1878,181 @@ duk_ret_t ILibDuktape_ScriptContainer_Master_AddModule(duk_context *ctx)
ILibProcessPipe_Process_WriteStdIn(master->child, ILibScratchPad2, len+4, ILibTransport_MemoryOwnership_USER);
return(0);
}
+
+
+void ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsMaster(void *chain, void *user)
+{
+ ILibDuktape_ScriptContainer_NonIsolated_Command *cmd = (ILibDuktape_ScriptContainer_NonIsolated_Command*)user;
+ ILibDuktape_ScriptContainer_Master *master = cmd->container.master;
+ ILibDuktape_ScriptContainer_Slave *slave = master->PeerChain == NULL ? NULL : (ILibDuktape_ScriptContainer_Slave*)((void**)ILibMemory_GetExtraMemory(master->PeerChain, ILibMemory_CHAIN_CONTAINERSIZE))[1];
+
+ int id;
+ duk_push_string(master->ctx, cmd->json); // [string]
+ duk_json_decode(master->ctx, -1); // [json]
+ free(cmd);
+
+ switch ((id = Duktape_GetIntPropertyValue(master->ctx, -1, "command", -1)))
+ {
+ case 0: // Ready
+ {
+ // Call INIT first
+ char json[] = "{\"command\": \"1\"}";
+ ILibDuktape_ScriptContainer_NonIsolated_Command* initCmd = (ILibDuktape_ScriptContainer_NonIsolated_Command*)ILibMemory_Allocate(sizeof(json) + sizeof(ILibDuktape_ScriptContainer_NonIsolated_Command), 0, NULL, NULL);
+ initCmd->container.slave = slave;
+ memcpy_s(initCmd->json, sizeof(json), json, sizeof(json));
+ ILibChain_RunOnMicrostackThread(master->PeerChain, ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsSlave, initCmd);
+
+ // Emit Ready Event
+ duk_push_heapptr(master->ctx, master->emitter->object); // [json][container]
+ duk_get_prop_string(master->ctx, -1, "emit"); // [json][container][emit]
+ duk_swap_top(master->ctx, -2); // [json][emit][this]
+ duk_push_string(master->ctx, "ready"); // [json][emit][this][ready]
+ if (duk_pcall_method(master->ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(master->ctx, "Error Dispatching 'ready' event to Master Script Container"); }
+ duk_pop(master->ctx); // [json]
+ }
+ break;
+ case SCRIPT_ENGINE_COMMAND_ERROR:
+ duk_push_heapptr(master->ctx, master->emitter->object); // [json][container]
+ duk_get_prop_string(master->ctx, -1, "emit"); // [json][container][emit]
+ duk_swap_top(master->ctx, -2); // [json][emit][this]
+ duk_push_string(master->ctx, "error"); // [json][emit][this][error]
+ duk_get_prop_string(master->ctx, -4, "message"); // [json][emit][this][error][msg]
+ if (duk_pcall_method(master->ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(master->ctx, "Error Emitting ScriptContainer Error Message: "); }
+ duk_pop(master->ctx); // [json]
+ break;
+ case SCRIPT_ENGINE_COMMAND_EXIT:
+ duk_push_heapptr(master->ctx, master->emitter->object); // [json][container]
+ duk_get_prop_string(master->ctx, -1, "emit"); // [json][container][emit]
+ duk_swap_top(master->ctx, -2); // [json][emit][this]
+ duk_push_string(master->ctx, "exit"); // [json][emit][this][exit]
+ duk_get_prop_string(master->ctx, -4, "exitCode"); // [json][emit][this][exit][msg]
+ if (duk_pcall_method(master->ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(master->ctx, "Error Emitting ScriptContainer Exit: "); }
+ duk_pop(master->ctx); // [json]
+ master->PeerChain = NULL;
+ break;
+ default:
+ ILibDuktape_Process_UncaughtExceptionEx(master->ctx, "Unknown Command [%d] Received from Slave Container ", id);
+ break;
+ }
+
+ duk_pop(master->ctx); // ...
+
+}
+
+void ILibDuktape_ScriptContainer_NonIsolatedWorker_ExceptionSink(duk_context *ctx, char *msg, void *user)
+{
+ duk_push_object(ctx); // [obj]
+ duk_push_int(ctx, (int)SCRIPT_ENGINE_COMMAND_ERROR);
+ duk_put_prop_string(ctx, -2, "command");
+ duk_push_string(ctx, msg);
+ duk_put_prop_string(ctx, -2, "message");
+ duk_json_encode(ctx, -1); // [json]
+
+ duk_size_t payloadLen;
+ char *payload = (char*)duk_get_lstring(ctx, -1, &payloadLen);
+
+ ILibDuktape_ScriptContainer_NonIsolated_Command *cmd = (ILibDuktape_ScriptContainer_NonIsolated_Command*)ILibMemory_Allocate((int)(sizeof(ILibDuktape_ScriptContainer_NonIsolated_Command) + payloadLen + 1), 0, NULL, NULL);
+ cmd->container.master = ((void**)ILibMemory_GetExtraMemory(Duktape_GetChain(ctx), ILibMemory_CHAIN_CONTAINERSIZE))[0];
+ memcpy_s(cmd->json, payloadLen + 1, payload, payloadLen + 1);
+
+ duk_pop(ctx); // ...
+
+ ILibChain_RunOnMicrostackThread(cmd->container.master->chain, ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsMaster, cmd);
+}
+void ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsSlave(void *chain, void *user)
+{
+ ILibDuktape_ScriptContainer_NonIsolated_Command *cmd = (ILibDuktape_ScriptContainer_NonIsolated_Command*)user;
+ ILibDuktape_ScriptContainer_Slave *slave = cmd->container.slave;
+ ILibDuktape_ScriptContainer_Master *master = (ILibDuktape_ScriptContainer_Master*)((void**)ILibMemory_GetExtraMemory(slave->chain, ILibMemory_CHAIN_CONTAINERSIZE))[0];
+
+ int id;
+ duk_push_string(slave->ctx, cmd->json); // [string]
+ duk_json_decode(slave->ctx, -1); // [json]
+ free(cmd);
+
+ switch ((id = Duktape_GetIntPropertyValue(slave->ctx, -1, "command", -1)))
+ {
+ case SCRIPT_ENGINE_COMMAND_INIT:
+ ILibDuktape_ScriptContainer_InitializeJavaScriptEngineEx3(slave->ctx, (SCRIPT_ENGINE_SECURITY_FLAGS)master->ChildSecurityFlags, 0, slave->chain, NULL, NULL, NULL, NULL, ILibDuktape_ScriptContainer_Slave_HeapDestroyed, slave);
+ ILibDuktape_SetNativeUncaughtExceptionHandler(slave->ctx, ILibDuktape_ScriptContainer_NonIsolatedWorker_ExceptionSink, master);
+ break;
+ case SCRIPT_ENGINE_COMMAND_EXEC:
+ {
+ char *payload;
+ duk_size_t payloadLen;
+
+ payload = (char*)Duktape_GetStringPropertyValueEx(slave->ctx, -1, "base64", NULL, &payloadLen);
+ payloadLen = ILibBase64Decode((unsigned char*)payload, (int)payloadLen, (unsigned char**)&payload);
+
+ if (ILibDuktape_ScriptContainer_CompileJavaScript(slave->ctx, payload, (int)payloadLen) == 0 && ILibDuktape_ScriptContainer_ExecuteByteCode(slave->ctx) == 0)
+ {
+ // SUCCESS
+ duk_pop(slave->ctx);
+ }
+ else
+ {
+ // ERROR
+ ILibDuktape_Process_UncaughtExceptionEx(slave->ctx, "ScriptContainer Error: ");
+ duk_pop(slave->ctx);
+ }
+ }
+ break;
+ case SCRIPT_ENGINE_COMMAND_SEND_JSON:
+ {
+ if (slave->emitter != NULL)
+ {
+ duk_get_prop_string(slave->ctx, -1, "json"); // [cmd][string]
+ duk_json_decode(slave->ctx, -1); // [cmd][obj]
+ duk_push_heapptr(slave->ctx, slave->emitter->object); // [cmd][obj][container]
+ duk_get_prop_string(slave->ctx, -1, "emit"); // [cmd][obj][container][emit]
+ duk_swap_top(slave->ctx, -2); // [cmd][obj][emit][this]
+ duk_push_string(slave->ctx, "data"); // [cmd][obj][emit][this][data]
+ duk_dup(slave->ctx, -4); // [cmd][obj][emit][this][data][obj]
+ if (duk_pcall_method(slave->ctx, 2) != 0) { ILibDuktape_Process_UncaughtException(slave->ctx); }
+ duk_pop_2(slave->ctx); // [cmd]
+ }
+ }
+ break;
+ case SCRIPT_ENGINE_COMMAND_EXIT:
+ slave->noRespond = Duktape_GetIntPropertyValue(slave->ctx, -1, "noResponse", 0);
+ duk_pop(slave->ctx);
+ duk_destroy_heap(slave->ctx);
+ return;
+ }
+ duk_pop(slave->ctx); // ...
+}
+
+void ILibDuktape_ScriptContainer_NonIsolatedWorker(void *arg)
+{
+ ILibDuktape_ScriptContainer_Master *master = (ILibDuktape_ScriptContainer_Master*)arg;
+ ILibDuktape_ScriptContainer_Slave *slave = ILibMemory_AllocateA(sizeof(ILibDuktape_ScriptContainer_Slave));
+ char json[] = "{\"command\": \"0\"}";
+
+ slave->chain = ILibCreateChainEx(2 * sizeof(void*));
+ ((void**)ILibMemory_GetExtraMemory(slave->chain, ILibMemory_CHAIN_CONTAINERSIZE))[0] = master;
+ ((void**)ILibMemory_GetExtraMemory(slave->chain, ILibMemory_CHAIN_CONTAINERSIZE))[1] = slave;
+ master->PeerChain = slave->chain;
+ slave->ctx = ILibDuktape_ScriptContainer_InitializeJavaScriptEngine_minimal();
+
+ duk_push_heap_stash(slave->ctx);
+ duk_push_pointer(slave->ctx, slave);
+ duk_put_prop_string(slave->ctx, -2, ILibDuktape_ScriptContainer_SlavePtr);
+ duk_pop(slave->ctx);
+
+ ILibDuktape_ScriptContainer_NonIsolated_Command* cmd = (ILibDuktape_ScriptContainer_NonIsolated_Command*)ILibMemory_Allocate(sizeof(json) + sizeof(ILibDuktape_ScriptContainer_NonIsolated_Command), 0, NULL, NULL);
+ cmd->container.master = master;
+ memcpy_s(cmd->json, sizeof(json), json, sizeof(json));
+ ILibChain_RunOnMicrostackThread(master->chain, ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsMaster, cmd);
+ ILibStartChain(slave->chain);
+
+ if (slave->noRespond == 0)
+ {
+ cmd = (ILibDuktape_ScriptContainer_NonIsolated_Command*)ILibMemory_Allocate(64 + sizeof(ILibDuktape_ScriptContainer_NonIsolated_Command), 0, NULL, NULL);
+ cmd->container.master = master;
+ sprintf_s(cmd->json, 64, "{\"command\": \"128\", \"exitCode\": \"%d\"}", slave->exitCode);
+ ILibChain_RunOnMicrostackThread(master->chain, ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsMaster, cmd);
+ }
+}
duk_ret_t ILibDuktape_ScriptContainer_Create(duk_context *ctx)
{
char *exePath;
@@ -1575,6 +2063,12 @@ duk_ret_t ILibDuktape_ScriptContainer_Create(duk_context *ctx)
char *buffer;
char header[4];
ILibProcessPipe_SpawnTypes spawnType = (duk_get_top(ctx) > 2 && duk_is_number(ctx, 2)) ? (ILibProcessPipe_SpawnTypes)duk_require_int(ctx, 2) : ILibProcessPipe_SpawnTypes_DEFAULT;
+ int processIsolation = 1;
+
+ if (duk_get_top(ctx) > 0 && duk_is_object(ctx, 0))
+ {
+ processIsolation = Duktape_GetIntPropertyValue(ctx, 0, "processIsolation", 1);
+ }
duk_push_heap_stash(ctx);
duk_get_prop_string(ctx, -1, ILibDuktape_ScriptContainer_ExePath);
@@ -1584,6 +2078,7 @@ duk_ret_t ILibDuktape_ScriptContainer_Create(duk_context *ctx)
manager = (ILibProcessPipe_Manager)duk_get_pointer(ctx, -1);
duk_push_object(ctx); // [container]
+ ILibDuktape_WriteID(ctx, "ScriptContainer.master");
duk_push_fixed_buffer(ctx, sizeof(ILibDuktape_ScriptContainer_Master)); // [container][buffer]
master = (ILibDuktape_ScriptContainer_Master*)Duktape_GetBuffer(ctx, -1, NULL);
duk_put_prop_string(ctx, -2, ILibDuktape_ScriptContainer_MasterPtr); // [container]
@@ -1592,9 +2087,9 @@ duk_ret_t ILibDuktape_ScriptContainer_Create(duk_context *ctx)
master->ctx = ctx;
master->emitter = ILibDuktape_EventEmitter_Create(ctx);
master->chain = Duktape_GetChain(ctx);
- ILibDuktape_EventEmitter_CreateEvent(master->emitter, "exit", &(master->OnExit));
- ILibDuktape_EventEmitter_CreateEvent(master->emitter, "error", &(master->OnError));
- ILibDuktape_EventEmitter_CreateEvent(master->emitter, "data", &(master->OnJSON));
+ ILibDuktape_EventEmitter_CreateEventEx(master->emitter, "exit");
+ ILibDuktape_EventEmitter_CreateEventEx(master->emitter, "error");
+ ILibDuktape_EventEmitter_CreateEventEx(master->emitter, "data");
ILibDuktape_CreateProperty_InstanceMethod(ctx, "exit", ILibDuktape_ScriptContainer_Exit, DUK_VARARGS);
ILibDuktape_CreateInstanceMethod(master->ctx, "ExecuteScript", ILibDuktape_ScriptContainer_ExecuteScript, DUK_VARARGS);
ILibDuktape_CreateInstanceMethod(master->ctx, "ExecuteString", ILibDuktape_ScriptContainer_ExecuteString, DUK_VARARGS);
@@ -1602,28 +2097,43 @@ duk_ret_t ILibDuktape_ScriptContainer_Create(duk_context *ctx)
ILibDuktape_CreateInstanceMethod(master->ctx, "addModule", ILibDuktape_ScriptContainer_Master_AddModule, 2);
ILibDuktape_CreateFinalizer(master->ctx, ILibDuktape_ScriptContainer_Finalizer);
- unsigned int executionTimeout = (unsigned int)duk_require_int(ctx, 0);
- unsigned int securityFlags = (unsigned int)duk_require_int(ctx, 1) | SCRIPT_ENGINE_NO_MESH_AGENT_ACCESS;
+ if (processIsolation)
+ {
+ // We're going to spawn a child process to run this ScriptContainer
+ unsigned int executionTimeout = (unsigned int)duk_require_int(ctx, 0);
+ master->ChildSecurityFlags = (unsigned int)duk_require_int(ctx, 1) | SCRIPT_ENGINE_NO_MESH_AGENT_ACCESS;
- master->child = ILibProcessPipe_Manager_SpawnProcessEx2(manager, exePath, (char * const*)param, spawnType, 2 * sizeof(void*));
- if (master->child == NULL) { return(ILibDuktape_Error(ctx, "ScriptContainer.Create(): Error spawning child process, using [%s]", exePath)); }
+ master->child = ILibProcessPipe_Manager_SpawnProcessEx2(manager, exePath, (char * const*)param, spawnType, 2 * sizeof(void*));
+ if (master->child == NULL) { return(ILibDuktape_Error(ctx, "ScriptContainer.Create(): Error spawning child process, using [%s]", exePath)); }
+
+ duk_push_true(ctx);
+ duk_put_prop_string(ctx, -2, ILibDuktape_ScriptContainer_ProcessIsolated);
+ duk_push_object(ctx); // [container][obj]
+ duk_push_int(ctx, (int)SCRIPT_ENGINE_COMMAND_INIT);
+ duk_put_prop_string(ctx, -2, "command");
+ duk_push_int(ctx, (int)executionTimeout);
+ duk_put_prop_string(ctx, -2, "executionTimeout");
+ duk_push_int(ctx, (int)master->ChildSecurityFlags);
+ duk_put_prop_string(ctx, -2, "securityFlags");
+ duk_json_encode(ctx, -1);
+ buffer = (char*)Duktape_GetBuffer(ctx, -1, &bufferLen);
- duk_push_object(ctx); // [container][obj]
- duk_push_int(ctx, (int)SCRIPT_ENGINE_COMMAND_INIT);
- duk_put_prop_string(ctx, -2, "command");
- duk_push_int(ctx, (int)executionTimeout);
- duk_put_prop_string(ctx, -2, "executionTimeout");
- duk_push_int(ctx, (int)securityFlags);
- duk_put_prop_string(ctx, -2, "securityFlags");
- duk_json_encode(ctx, -1);
- buffer = (char*)Duktape_GetBuffer(ctx, -1, &bufferLen);
+ duk_swap_top(ctx, -2); // [json][container]
- duk_swap_top(ctx, -2); // [json][container]
-
- ((int*)header)[0] = (int)bufferLen + 4;
- ILibProcessPipe_Process_AddHandlers(master->child, SCRIPT_ENGINE_PIPE_BUFFER_SIZE, ILibDuktape_ScriptContainer_ExitSink, ILibDuktape_ScriptContainer_StdOutSink, ILibDuktape_ScriptContainer_StdErrSink, ILibDuktape_ScriptContainer_SendOkSink, master);
- ILibProcessPipe_Process_WriteStdIn(master->child, header, sizeof(header), ILibTransport_MemoryOwnership_USER);
- ILibProcessPipe_Process_WriteStdIn(master->child, buffer, (int)bufferLen, ILibTransport_MemoryOwnership_USER);
+ ((int*)header)[0] = (int)bufferLen + 4;
+ ILibProcessPipe_Process_AddHandlers(master->child, SCRIPT_ENGINE_PIPE_BUFFER_SIZE, ILibDuktape_ScriptContainer_ExitSink, ILibDuktape_ScriptContainer_StdOutSink, ILibDuktape_ScriptContainer_StdErrSink, ILibDuktape_ScriptContainer_SendOkSink, master);
+ ILibProcessPipe_Process_WriteStdIn(master->child, header, sizeof(header), ILibTransport_MemoryOwnership_USER);
+ ILibProcessPipe_Process_WriteStdIn(master->child, buffer, (int)bufferLen, ILibTransport_MemoryOwnership_USER);
+ }
+ else
+ {
+ // We're going to spawn a thread to host this Script Container
+ duk_push_false(ctx);
+ duk_put_prop_string(ctx, -2, ILibDuktape_ScriptContainer_ProcessIsolated);
+ ILibDuktape_EventEmitter_CreateEventEx(master->emitter, "ready");
+ master->PeerThread = ILibSpawnNormalThread(ILibDuktape_ScriptContainer_NonIsolatedWorker, master);
+ master->ChildSecurityFlags = Duktape_GetIntPropertyValue(ctx, 0, "permissions", 0);
+ }
return 1;
}
void ILibDuktape_ScriptContainer_PUSH_MASTER(duk_context *ctx, void *chain)
@@ -1653,8 +2163,9 @@ void ILibDuktape_ScriptContainer_PUSH_SLAVE(duk_context *ctx, void *chain)
duk_pop(ctx); // ...
duk_push_object(ctx);
+ ILibDuktape_WriteID(ctx, "ScriptContainer.slave");
slave->emitter = ILibDuktape_EventEmitter_Create(ctx);
- ILibDuktape_EventEmitter_CreateEvent(slave->emitter, "data", &(slave->OnData));
+ ILibDuktape_EventEmitter_CreateEventEx(slave->emitter, "data");
ILibDuktape_CreateInstanceMethod(ctx, "send", ILibDuktape_ScriptContainer_Slave_SendToMaster, 1);
}
diff --git a/microscript/ILibDuktape_ScriptContainer.h b/microscript/ILibDuktape_ScriptContainer.h
index 534cd90..9dc3289 100644
--- a/microscript/ILibDuktape_ScriptContainer.h
+++ b/microscript/ILibDuktape_ScriptContainer.h
@@ -1,11 +1,11 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-http://www.apache.org/licenses/LICENSE-2.0
+ http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
@@ -144,9 +144,10 @@ void ILibDuktape_ScriptContainer_CheckEmbedded(char **argv, char **script, int *
void ILibDuktape_ScriptContainer_InitMaster(void *chain, char *exePath, ILibProcessPipe_Manager manager);
int ILibDuktape_ScriptContainer_StartSlave(void *chain, ILibProcessPipe_Manager manager);
-
+duk_context *ILibDuktape_ScriptContainer_InitializeJavaScriptEngine_minimal();
+duk_context *ILibDuktape_ScriptContainer_InitializeJavaScriptEngineEx3(duk_context *ctx, SCRIPT_ENGINE_SECURITY_FLAGS securityFlags, unsigned int executionTimeout, void *chain, char **argList, ILibSimpleDataStore *db, char *exePath, ILibProcessPipe_Manager pipeManager, ILibDuktape_HelperEvent exitHandler, void *exitUser);
duk_context *ILibDuktape_ScriptContainer_InitializeJavaScriptEngineEx2(SCRIPT_ENGINE_SETTINGS *settings);
-duk_context *ILibDuktape_ScriptContainer_InitializeJavaScriptEngineEx(SCRIPT_ENGINE_SECURITY_FLAGS securityFlags, unsigned int executionTimeout, void *chain, char **argList, ILibSimpleDataStore *db, char *exePath, ILibProcessPipe_Manager pipeManager, ILibDuktape_HelperEvent exitHandler, void *exitUser);
+#define ILibDuktape_ScriptContainer_InitializeJavaScriptEngineEx(securityFlags, executionTimeout, chain, argList, db, exePath, pipeManager, exitHandler, exitUser) ILibDuktape_ScriptContainer_InitializeJavaScriptEngineEx3(ILibDuktape_ScriptContainer_InitializeJavaScriptEngine_minimal(), (securityFlags), (executionTimeout), (chain), (argList), (db), (exePath), (pipeManager), (exitHandler), (exitUser))
#define ILibDuktape_ScriptContainer_InitializeJavaScriptEngine(securityFlags, executionTimeout, chain, pp_argList, db, exitHandler, exitUser) ILibDuktape_ScriptContainer_InitializeJavaScriptEngineEx((securityFlags), (executionTimeout), (chain), (pp_argList), (db), NULL, NULL, (exitHandler), (exitUser))
SCRIPT_ENGINE_SETTINGS *ILibDuktape_ScriptContainer_GetSettings(duk_context *ctx);
diff --git a/microscript/ILibDuktape_SimpleDataStore.c b/microscript/ILibDuktape_SimpleDataStore.c
index 91fc9d9..1a4badf 100644
--- a/microscript/ILibDuktape_SimpleDataStore.c
+++ b/microscript/ILibDuktape_SimpleDataStore.c
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -179,6 +179,17 @@ duk_ret_t ILibDuktape_SimpleDataStore_Keys(duk_context *ctx)
ILibSimpleDataStore_EnumerateKeys(ds, ILibDuktape_SimpleDataStore_Keys_EnumerationSink, &enumerator);
return 1;
}
+duk_ret_t ILibDuktape_SimpleDataStore_Delete(duk_context *ctx)
+{
+ duk_push_this(ctx); // [DataStore]
+ duk_get_prop_string(ctx, -1, ILibDuktape_DataStore_PTR); // [DataStore][ptr]
+ ILibSimpleDataStore ds = (ILibSimpleDataStore)duk_get_pointer(ctx, -1);
+ duk_size_t keyLen;
+ char *key = (char*)duk_get_lstring(ctx, 0, &keyLen);
+
+ ILibSimpleDataStore_DeleteEx(ds, key, (int)keyLen);
+ return(0);
+}
duk_ret_t ILibDuktape_SimpleDataStore_Create(duk_context *ctx)
{
ILibSimpleDataStore dataStore;
@@ -214,6 +225,7 @@ duk_ret_t ILibDuktape_SimpleDataStore_Create(duk_context *ctx)
duk_push_pointer(ctx, dataStore); // [DataStore][RetVal][ds]
duk_put_prop_string(ctx, -2, ILibDuktape_DataStore_PTR);// [DataStore][RetVal]
+ ILibDuktape_CreateInstanceMethod(ctx, "Delete", ILibDuktape_SimpleDataStore_Delete, 1);
ILibDuktape_CreateInstanceMethod(ctx, "Put", ILibDuktape_SimpleDataStore_Put, 2);
ILibDuktape_CreateInstanceMethod(ctx, "Get", ILibDuktape_SimpleDataStore_Get, DUK_VARARGS);
ILibDuktape_CreateInstanceMethod(ctx, "Compact", ILibDuktape_SimpleDataStore_Compact, 0);
diff --git a/microscript/ILibDuktape_SimpleDataStore.h b/microscript/ILibDuktape_SimpleDataStore.h
index f427f03..2cfe04e 100644
--- a/microscript/ILibDuktape_SimpleDataStore.h
+++ b/microscript/ILibDuktape_SimpleDataStore.h
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/microscript/ILibDuktape_WebRTC.c b/microscript/ILibDuktape_WebRTC.c
index aa29ae5..6ef7e0c 100644
--- a/microscript/ILibDuktape_WebRTC.c
+++ b/microscript/ILibDuktape_WebRTC.c
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -44,11 +44,7 @@ typedef struct ILibWebRTC_Duktape_Handlers
void *ConnectionObject;
ILibDuktape_EventEmitter *emitter;
- void *OnConnect;
- void *OnDataChannel;
void *OnConnectionSendOK;
- void *OnCandidate;
- void *OnDisconnect;
}ILibWebRTC_Duktape_Handlers;
typedef struct ILibDuktape_WebRTC_DataChannel
{
@@ -56,7 +52,6 @@ typedef struct ILibDuktape_WebRTC_DataChannel
duk_context *ctx;
ILibDuktape_EventEmitter *emitter;
ILibDuktape_DuplexStream *stream;
- void *OnAck;
}ILibDuktape_WebRTC_DataChannel;
extern void* ILibWrapper_WebRTC_Connection_GetStunModule(ILibWrapper_WebRTC_Connection connection);
@@ -170,7 +165,8 @@ void ILibDuktape_WebRTC_DataChannel_OnClose(struct ILibWrapper_WebRTC_DataChanne
void ILibDuktape_WebRTC_DataChannel_OnData(struct ILibWrapper_WebRTC_DataChannel* dataChannel, char* data, int dataLen, int dataType)
{
ILibDuktape_WebRTC_DataChannel *ptrs = (ILibDuktape_WebRTC_DataChannel*)dataChannel->userData;
- if (ptrs != NULL) { ILibDuktape_DuplexStream_WriteData(ptrs->stream, data, dataLen); }
+
+ if (ptrs != NULL) { ILibDuktape_DuplexStream_WriteDataEx(ptrs->stream, dataType == 51 ? 1 : 0, data, dataLen); }
}
duk_ret_t ILibDuktape_WebRTC_DataChannel_Finalizer(duk_context *ctx)
{
@@ -178,12 +174,14 @@ duk_ret_t ILibDuktape_WebRTC_DataChannel_Finalizer(duk_context *ctx)
ILibDuktape_WebRTC_DataChannel *ptrs = (ILibDuktape_WebRTC_DataChannel*)Duktape_GetBuffer(ctx, -1, NULL);
if (ptrs->dataChannel != NULL)
{
+ printf("WebRTC Data Channel Finalizer on Connection: %p\n", ptrs->dataChannel->parent);
ptrs->dataChannel->userData = NULL;
ILibWrapper_WebRTC_DataChannel_Close(ptrs->dataChannel);
}
return 0;
}
+
void ILibDuktape_WebRTC_DataChannel_PUSH(duk_context *ctx, ILibWrapper_WebRTC_DataChannel *dataChannel)
{
if (dataChannel == NULL) { duk_push_null(ctx); return; }
@@ -195,6 +193,7 @@ void ILibDuktape_WebRTC_DataChannel_PUSH(duk_context *ctx, ILibWrapper_WebRTC_Da
dataChannel->OnRawData = ILibDuktape_WebRTC_DataChannel_OnData;
duk_push_object(ctx); // [dataChannel]
+ ILibDuktape_WriteID(ctx, "webRTC.dataChannel");
duk_push_fixed_buffer(ctx, sizeof(ILibDuktape_WebRTC_DataChannel)); // [dataChannel][buffer]
ptrs = (ILibDuktape_WebRTC_DataChannel*)Duktape_GetBuffer(ctx, -1, NULL);
dataChannel->userData = ptrs;
@@ -209,7 +208,8 @@ void ILibDuktape_WebRTC_DataChannel_PUSH(duk_context *ctx, ILibWrapper_WebRTC_Da
duk_push_int(ctx, dataChannel->streamId);
duk_put_prop_string(ctx, -2, "id");
- ILibDuktape_EventEmitter_CreateEvent(ptrs->emitter, "ack", &(ptrs->OnAck));
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "ack");
+
ptrs->stream = ILibDuktape_DuplexStream_Init(ctx, ILibDuktape_WebRTC_DataChannel_Stream_WriteSink, ILibDuktape_WebRTC_DataChannel_Stream_EndSink,
ILibDuktape_WebRTC_DataChannel_Stream_PauseSink, ILibDuktape_WebRTC_DataChannel_Stream_ResumeSink, ptrs);
}
@@ -221,6 +221,8 @@ duk_ret_t ILibDuktape_WebRTC_ConnectionFactory_Finalizer(duk_context *ctx)
duk_get_prop_string(ctx, 0, ILibDuktape_WebRTC_ConnectionFactoryPtr);
factory = (ILibWrapper_WebRTC_ConnectionFactory)duk_get_pointer(ctx, -1);
+ printf("WebRTC Factory Finalizer: %p\n", factory);
+
if (factory != NULL && ILibIsChainBeingDestroyed(chain) == 0)
{
ILibWrapper_WebRTC_ConnectionFactory_RemoveFromChain(factory);
@@ -228,48 +230,140 @@ duk_ret_t ILibDuktape_WebRTC_ConnectionFactory_Finalizer(duk_context *ctx)
return 0;
}
+#ifdef _WEBRTCDEBUG
+void ILibDuktape_WebRTC_Connection_Debug(void* dtlsSession, char* debugField, int data)
+{
+ ILibHashtable *t = ILibChain_GetBaseHashtable(((ILibTransport*)dtlsSession)->ChainLink.ParentChain);
+ ILibWebRTC_Duktape_Handlers *ptrs = (ILibWebRTC_Duktape_Handlers*)ILibHashtable_Get(t, dtlsSession, NULL, 0);
+ if (ptrs != NULL)
+ {
+ if (strcmp(debugField, "OnHold") == 0)
+ {
+ ILibDuktape_EventEmitter_SetupEmit(ptrs->ctx, ptrs->ConnectionObject, "_hold"); // [emit][this][name]
+ }
+ else if (strcmp(debugField, "OnCongestionWindowSizeChanged") == 0)
+ {
+ ILibDuktape_EventEmitter_SetupEmit(ptrs->ctx, ptrs->ConnectionObject, "_congestionWindowSizeChange"); // [emit][this][name]
+ }
+ else if (strcmp(debugField, "OnRTTCalculated") == 0)
+ {
+ ILibDuktape_EventEmitter_SetupEmit(ptrs->ctx, ptrs->ConnectionObject, "_rttCalculated"); // [emit][this][name]
+ }
+ else if (strcmp(debugField, "OnFastRecovery") == 0)
+ {
+ ILibDuktape_EventEmitter_SetupEmit(ptrs->ctx, ptrs->ConnectionObject, "_fastRecovery"); // [emit][this][name]
+ }
+ else if (strcmp(debugField, "OnLastSackTime") == 0)
+ {
+ ILibDuktape_EventEmitter_SetupEmit(ptrs->ctx, ptrs->ConnectionObject, "_lastSackTime"); // [emit][this][name]
+ }
+ else if (strcmp(debugField, "OnLastSentTime") == 0)
+ {
+ ILibDuktape_EventEmitter_SetupEmit(ptrs->ctx, ptrs->ConnectionObject, "_lastSentTime"); // [emit][this][name]
+ }
+ else if (strcmp(debugField, "OnReceiverCredits") == 0)
+ {
+ ILibDuktape_EventEmitter_SetupEmit(ptrs->ctx, ptrs->ConnectionObject, "_receiverCredits"); // [emit][this][name]
+ }
+ else if (strcmp(debugField, "OnT3RTX") == 0)
+ {
+ ILibDuktape_EventEmitter_SetupEmit(ptrs->ctx, ptrs->ConnectionObject, "_t3tx"); // [emit][this][name]
+ }
+ else if (strcmp(debugField, "OnSendRetry") == 0)
+ {
+ ILibDuktape_EventEmitter_SetupEmit(ptrs->ctx, ptrs->ConnectionObject, "_retransmit"); // [emit][this][name]
+ }
+ else if (strcmp(debugField, "OnSACKReceived") == 0)
+ {
+ ILibDuktape_EventEmitter_SetupEmit(ptrs->ctx, ptrs->ConnectionObject, "_sackReceived"); // [emit][this][name]
+ }
+ else if (strcmp(debugField, "OnRetryPacket") == 0)
+ {
+ duk_push_external_buffer(ptrs->ctx); // [extBuffer]
+ ILibDuktape_EventEmitter_SetupEmit(ptrs->ctx, ptrs->ConnectionObject, "_retransmitPacket"); // [extBuffer][emit][this][name]
+ duk_config_buffer(ptrs->ctx, -4, debugField + 14, data);
+ duk_push_buffer_object(ptrs->ctx, -4, 0, data, DUK_BUFOBJ_NODEJS_BUFFER);
+ if (duk_pcall_method(ptrs->ctx, 2) != 0) { ILibDuktape_Process_UncaughtException(ptrs->ctx); }
+ duk_pop_2(ptrs->ctx); // ...
+ return;
+ }
+ else
+ {
+ return;
+ }
+ duk_push_int(ptrs->ctx, data); // [emit][this][name][val]
+ if (duk_pcall_method(ptrs->ctx, 2) != 0) { ILibDuktape_Process_UncaughtException(ptrs->ctx); }
+ duk_pop(ptrs->ctx); // ...
+ }
+}
+#endif
void ILibDuktape_WebRTC_OnConnection(ILibWrapper_WebRTC_Connection connection, int connected)
{
ILibWebRTC_Duktape_Handlers *ptrs = (ILibWebRTC_Duktape_Handlers*)ILibMemory_GetExtraMemory(connection, ILibMemory_WebRTC_Connection_CONTAINERSIZE);
- if (ptrs->OnConnect != NULL && connected != 0)
+ if (connected == 0)
{
- duk_push_heapptr(ptrs->ctx, ptrs->OnConnect); // [func]
- duk_push_heapptr(ptrs->ctx, ptrs->ConnectionObject); // [func][this]
- if (duk_pcall_method(ptrs->ctx, 0) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ptrs->ctx, "webrtc.connection.onConnect(): "); }
- duk_pop(ptrs->ctx); // ...
+ ILibDuktape_EventEmitter_SetupEmit(ptrs->ctx, ptrs->ConnectionObject, "disconnected"); // [emit][this][disconnected]
+ duk_del_prop_string(ptrs->ctx, -2, ILibDuktape_WebRTC_ConnectionPtr);
}
- else if (ptrs->OnDisconnect != NULL && connected == 0)
+ else
{
- duk_push_heapptr(ptrs->ctx, ptrs->OnDisconnect); // [func]
- duk_push_heapptr(ptrs->ctx, ptrs->ConnectionObject); // [func][this]
- if (duk_pcall_method(ptrs->ctx, 0) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ptrs->ctx, "webrtc.connection.onConnect(): "); }
- duk_pop(ptrs->ctx); // ...
+ ILibDuktape_EventEmitter_SetupEmit(ptrs->ctx, ptrs->ConnectionObject, "connected"); // [emit][this][connected]
}
+ if (duk_pcall_method(ptrs->ctx, 1) != 0) { ILibDuktape_Process_UncaughtException(ptrs->ctx); }
+ duk_pop(ptrs->ctx); // ...
+#ifdef _WEBRTCDEBUG
+ ILibHashtable *t = ILibChain_GetBaseHashtable(Duktape_GetChain(ptrs->ctx));
+
+ if (connected != 0)
+ {
+ ILibSCTP_Debug_SetDebugCallback(ILibWrapper_WebRTC_Connection2DtlsSession(connection), "OnHold", ILibDuktape_WebRTC_Connection_Debug);
+ ILibSCTP_Debug_SetDebugCallback(ILibWrapper_WebRTC_Connection2DtlsSession(connection), "OnCongestionWindowSizeChanged", ILibDuktape_WebRTC_Connection_Debug);
+ ILibSCTP_Debug_SetDebugCallback(ILibWrapper_WebRTC_Connection2DtlsSession(connection), "OnRTTCalculated", ILibDuktape_WebRTC_Connection_Debug);
+ ILibSCTP_Debug_SetDebugCallback(ILibWrapper_WebRTC_Connection2DtlsSession(connection), "OnFastRecovery", ILibDuktape_WebRTC_Connection_Debug);
+ ILibSCTP_Debug_SetDebugCallback(ILibWrapper_WebRTC_Connection2DtlsSession(connection), "OnReceiverCredits", ILibDuktape_WebRTC_Connection_Debug);
+ ILibSCTP_Debug_SetDebugCallback(ILibWrapper_WebRTC_Connection2DtlsSession(connection), "OnT3RTX", ILibDuktape_WebRTC_Connection_Debug);
+ ILibSCTP_Debug_SetDebugCallback(ILibWrapper_WebRTC_Connection2DtlsSession(connection), "OnSendRetry", ILibDuktape_WebRTC_Connection_Debug);
+ ILibSCTP_Debug_SetDebugCallback(ILibWrapper_WebRTC_Connection2DtlsSession(connection), "OnSendFastRetry", ILibDuktape_WebRTC_Connection_Debug);
+ ILibSCTP_Debug_SetDebugCallback(ILibWrapper_WebRTC_Connection2DtlsSession(connection), "OnRetryPacket", ILibDuktape_WebRTC_Connection_Debug);
+ ILibSCTP_Debug_SetDebugCallback(ILibWrapper_WebRTC_Connection2DtlsSession(connection), "OnSACKReceived", ILibDuktape_WebRTC_Connection_Debug);
+ ILibHashtable_Put(t, ILibWrapper_WebRTC_Connection2DtlsSession(connection), NULL, 0, ptrs);
+ }
+ else
+ {
+ ILibSCTP_Debug_SetDebugCallback(ILibWrapper_WebRTC_Connection2DtlsSession(connection), "OnHold", NULL);
+ ILibSCTP_Debug_SetDebugCallback(ILibWrapper_WebRTC_Connection2DtlsSession(connection), "OnCongestionWindowSizeChanged", NULL);
+ ILibSCTP_Debug_SetDebugCallback(ILibWrapper_WebRTC_Connection2DtlsSession(connection), "OnRTTCalculated", NULL);
+ ILibSCTP_Debug_SetDebugCallback(ILibWrapper_WebRTC_Connection2DtlsSession(connection), "OnFastRecovery", NULL);
+ ILibSCTP_Debug_SetDebugCallback(ILibWrapper_WebRTC_Connection2DtlsSession(connection), "OnReceiverCredits", NULL);
+ ILibSCTP_Debug_SetDebugCallback(ILibWrapper_WebRTC_Connection2DtlsSession(connection), "OnT3RTX", NULL);
+ ILibSCTP_Debug_SetDebugCallback(ILibWrapper_WebRTC_Connection2DtlsSession(connection), "OnSendRetry", NULL);
+ ILibSCTP_Debug_SetDebugCallback(ILibWrapper_WebRTC_Connection2DtlsSession(connection), "OnSendFastRetry", NULL);
+ ILibSCTP_Debug_SetDebugCallback(ILibWrapper_WebRTC_Connection2DtlsSession(connection), "OnRetryPacket", NULL);
+ ILibSCTP_Debug_SetDebugCallback(ILibWrapper_WebRTC_Connection2DtlsSession(connection), "OnSACKReceived", NULL);
+ ILibHashtable_Remove(t, ILibWrapper_WebRTC_Connection2DtlsSession(connection), NULL, 0);
+ }
+#endif
+
}
void ILibDuktape_WebRTC_OnDataChannel(ILibWrapper_WebRTC_Connection connection, ILibWrapper_WebRTC_DataChannel *dataChannel)
{
ILibWebRTC_Duktape_Handlers *ptrs = (ILibWebRTC_Duktape_Handlers*)ILibMemory_GetExtraMemory(connection, ILibMemory_WebRTC_Connection_CONTAINERSIZE);
- if (ptrs->OnDataChannel != NULL)
- {
- duk_push_heapptr(ptrs->ctx, ptrs->OnDataChannel); // [func]
- duk_push_heapptr(ptrs->ctx, ptrs->ConnectionObject); // [func][this]
- ILibDuktape_WebRTC_DataChannel_PUSH(ptrs->ctx, dataChannel);// [func][this][dataChannel]
- if (duk_pcall_method(ptrs->ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ptrs->ctx, "webrtc.connection.onDataChannel(): "); }
- duk_pop(ptrs->ctx); // ...
- }
+ ILibDuktape_EventEmitter_SetupEmit(ptrs->ctx, ptrs->ConnectionObject, "dataChannel"); // [emit][this][dataChannel]
+ ILibDuktape_WebRTC_DataChannel_PUSH(ptrs->ctx, dataChannel); // [emit][this][dataChannel][dc]
+ if (duk_pcall_method(ptrs->ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ptrs->ctx, "webrtc.connection.onDataChannel(): "); }
+ duk_pop(ptrs->ctx); // ...
}
void ILibDuktape_WebRTC_offer_onCandidate(ILibWrapper_WebRTC_Connection connection, struct sockaddr_in6* candidate)
{
- ILibWebRTC_Duktape_Handlers *ptrs = (ILibWebRTC_Duktape_Handlers*)ILibMemory_GetExtraMemory(connection, ILibMemory_WebRTC_Connection_CONTAINERSIZE);
- if (ptrs->OnCandidate != NULL)
+ if (candidate != NULL)
{
- duk_push_heapptr(ptrs->ctx, ptrs->OnCandidate); // [func]
- duk_push_heapptr(ptrs->ctx, ptrs->ConnectionObject); // [func][this]
- ILibDuktape_SockAddrToOptions(ptrs->ctx, candidate); // [func][this][options]
- if (duk_pcall_method(ptrs->ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ptrs->ctx, "webrtc.connection.onCandidate(): "); }
+ ILibWebRTC_Duktape_Handlers *ptrs = (ILibWebRTC_Duktape_Handlers*)ILibMemory_GetExtraMemory(connection, ILibMemory_WebRTC_Connection_CONTAINERSIZE);
+ ILibDuktape_EventEmitter_SetupEmit(ptrs->ctx, ptrs->ConnectionObject, "candidate"); // [emit][this][candidate]
+ ILibDuktape_SockAddrToOptions(ptrs->ctx, candidate); // [emit][this][candidate][options]
+ if (duk_pcall_method(ptrs->ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ptrs->ctx, "webrtc.connection.onCandidate(): "); }
duk_pop(ptrs->ctx); // ...
}
}
@@ -307,20 +401,16 @@ duk_ret_t ILibDuktape_WebRTC_setOffer(duk_context *ctx)
}
else
{
- duk_push_null(ctx);
+ return(ILibDuktape_Error(ctx, "WebRTC: Error setting offer. Most likely too many outstanding offers"));
}
return 1;
}
void ILibDuktape_WebRTC_DataChannel_OnAck(struct ILibWrapper_WebRTC_DataChannel* dataChannel)
{
ILibDuktape_WebRTC_DataChannel *ptrs = (ILibDuktape_WebRTC_DataChannel*)dataChannel->userData;
- if (ptrs->OnAck != NULL)
- {
- duk_push_heapptr(ptrs->ctx, ptrs->OnAck); // [func]
- duk_push_heapptr(ptrs->ctx, ptrs->emitter->object); // [func][this]
- if (duk_pcall_method(ptrs->ctx, 0) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ptrs->ctx, "webrtc.dataChannel.onAck(): "); };
- duk_pop(ptrs->ctx); // ...
- }
+ ILibDuktape_EventEmitter_SetupEmit(ptrs->ctx, ptrs->emitter->object, "ack"); // [emit][this][ack]
+ if (duk_pcall_method(ptrs->ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ptrs->ctx, "webrtc.dataChannel.onAck(): "); };
+ duk_pop(ptrs->ctx); // ...
}
duk_ret_t ILibDuktape_WebRTC_createDataChannel(duk_context *ctx)
{
@@ -378,8 +468,13 @@ duk_ret_t ILibDuktape_WebRTC_Connection_Finalizer(duk_context *ctx)
ILibWrapper_WebRTC_Connection connection;
duk_get_prop_string(ctx, 0, ILibDuktape_WebRTC_ConnectionPtr);
connection = (ILibWrapper_WebRTC_Connection)duk_get_pointer(ctx, -1);
+ printf("WebRTCConnection Finalizer on %p\n", (void*)connection);
if (connection == NULL) { return 0; }
+#ifdef _WEBRTCDEBUG
+ ILibHashtable_Remove(ILibChain_GetBaseHashtable(Duktape_GetChain(ctx)), ILibWrapper_WebRTC_Connection2DtlsSession(connection), NULL, 0);
+#endif
+
if (ILibWrapper_WebRTC_Connection_IsConnected(connection) != 0)
{
ILibWrapper_WebRTC_Connection_CloseAllDataChannels(connection);
@@ -398,17 +493,31 @@ duk_ret_t ILibDuktape_WebRTC_CreateConnection(duk_context *ctx)
factory = (ILibWrapper_WebRTC_ConnectionFactory)duk_get_pointer(ctx, -1);
duk_push_object(ctx); // [factory][connection]
+ ILibDuktape_WriteID(ctx, "webRTC.peerConnection");
connection = ILibWrapper_WebRTC_ConnectionFactory_CreateConnection2(factory, ILibDuktape_WebRTC_OnConnection, ILibDuktape_WebRTC_OnDataChannel, NULL, sizeof(ILibWebRTC_Duktape_Handlers));
ptrs = (ILibWebRTC_Duktape_Handlers*)ILibMemory_GetExtraMemory(connection, ILibMemory_WebRTC_Connection_CONTAINERSIZE);
ptrs->ctx = ctx;
ptrs->ConnectionObject = duk_get_heapptr(ctx, -1);
ptrs->emitter = ILibDuktape_EventEmitter_Create(ctx);
- ILibDuktape_EventEmitter_CreateEvent(ptrs->emitter, "candidate", &(ptrs->OnCandidate));
- ILibDuktape_EventEmitter_CreateEvent(ptrs->emitter, "dataChannel", &(ptrs->OnDataChannel));
- ILibDuktape_EventEmitter_CreateEvent(ptrs->emitter, "connected", &(ptrs->OnConnect));
- ILibDuktape_EventEmitter_CreateEvent(ptrs->emitter, "disconnected", &(ptrs->OnDisconnect));
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "candidate");
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "dataChannel");
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "connected");
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "disconnected");
+#ifdef _WEBRTCDEBUG
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "_hold");
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "_lastSackTime");
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "_lastSentTime");
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "_congestionWindowSizeChange");
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "_fastRecovery");
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "_rttCalculated");
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "_receiverCredits");
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "_t3tx");
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "_retransmit");
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "_retransmitPacket");
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "_sackReceived");
+#endif
duk_push_pointer(ctx, connection); // [factory][connection][ptr]
duk_put_prop_string(ctx, -2, ILibDuktape_WebRTC_ConnectionPtr); // [factory][connection]
@@ -429,6 +538,7 @@ void ILibDuktape_WebRTC_Push(duk_context *ctx, void *chain)
ILibWrapper_WebRTC_ConnectionFactory factory;
duk_push_object(ctx); // [factory]
+ ILibDuktape_WriteID(ctx, "webRTC");
factory = ILibWrapper_WebRTC_ConnectionFactory_CreateConnectionFactory(chain, 0);
duk_push_pointer(ctx, factory); // [factory][ptr]
duk_put_prop_string(ctx, -2, ILibDuktape_WebRTC_ConnectionFactoryPtr); // [factory]
diff --git a/microscript/ILibDuktape_WebRTC.h b/microscript/ILibDuktape_WebRTC.h
index 6bee0bf..d2f96a6 100644
--- a/microscript/ILibDuktape_WebRTC.h
+++ b/microscript/ILibDuktape_WebRTC.h
@@ -1,3 +1,19 @@
+/*
+Copyright 2006 - 2018 Intel Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
#ifndef ___ILibDuktape_WebRTC___
#define ___ILibDuktape_WebRTC___
diff --git a/microscript/ILibDuktape_WritableStream.c b/microscript/ILibDuktape_WritableStream.c
index 11a8003..d4a646b 100644
--- a/microscript/ILibDuktape_WritableStream.c
+++ b/microscript/ILibDuktape_WritableStream.c
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ limitations under the License.
#include "ILibDuktape_Helpers.h"
#include "ILibDuktape_WritableStream.h"
#include "ILibDuktape_EventEmitter.h"
+#include "ILibDuktape_Polyfills.h"
#ifdef __DOXY__
/*!
@@ -118,11 +119,13 @@ void ILibDuktape_WritableStream_Ready(ILibDuktape_WritableStream *stream)
}
duk_pop(stream->ctx); // ...
}
- else if (stream->OnDrain != NULL)
+ else
{
- duk_push_heapptr(stream->ctx, stream->OnDrain); // [func]
- duk_push_heapptr(stream->ctx, stream->obj); // [func][this]
- if (duk_pcall_method(stream->ctx, 0) != 0) // [retVal]
+ duk_push_heapptr(stream->ctx, stream->obj); // [this]
+ duk_get_prop_string(stream->ctx, -1, "emit"); // [this][emit]
+ duk_swap_top(stream->ctx, -2); // [emit][this]
+ duk_push_string(stream->ctx, "drain"); // [emit][this][drain]
+ if (duk_pcall_method(stream->ctx, 1) != 0) // [retVal]
{
ILibDuktape_Process_UncaughtException(stream->ctx);
}
@@ -132,20 +135,17 @@ void ILibDuktape_WritableStream_Ready(ILibDuktape_WritableStream *stream)
else
{
// End of Stream
- if (stream->OnFinish != NULL)
- {
- duk_push_heapptr(stream->ctx, stream->OnFinish); // [func]
- duk_push_heapptr(stream->ctx, stream->obj); // [func][this]
- if (duk_pcall_method(stream->ctx, 0) != 0) // [retVal]
- {
- ILibDuktape_Process_UncaughtException(stream->ctx);
- }
- duk_pop(stream->ctx); // ...
- }
if (stream->EndSink != NULL)
{
stream->EndSink(stream, stream->WriteSink_User);
}
+
+ duk_push_heapptr(stream->ctx, stream->obj); // [stream]
+ duk_get_prop_string(stream->ctx, -1, "emit"); // [stream][emit]
+ duk_swap_top(stream->ctx, -2); // [emit][this]
+ duk_push_string(stream->ctx, "finish"); // [emit][this][finish]
+ if (duk_pcall_method(stream->ctx, 1) != 0) { ILibDuktape_Process_UncaughtException(stream->ctx); }
+ duk_pop(stream->ctx); // ...
}
}
@@ -167,6 +167,7 @@ duk_ret_t ILibDuktape_WritableStream_Write(duk_context *ctx)
if (stream->WriteSink != NULL)
{
+ stream->endBytes = -1;
switch (stream->WriteSink(stream, buffer, (int)bufferLen, stream->WriteSink_User))
{
case ILibTransport_DoneState_COMPLETE:
@@ -192,19 +193,18 @@ duk_ret_t ILibDuktape_WritableStream_Write(duk_context *ctx)
duk_push_false(ctx);
break;
default:
- if (stream->OnError != NULL)
+ duk_push_heapptr(ctx, stream->obj); // [this]
+ duk_get_prop_string(ctx, -1, "emit"); // [this][emit]
+ duk_swap_top(ctx, -2); // [emit][this]
+ duk_push_string(ctx, "error"); // [emit][this][error]
+ duk_push_object(ctx); // [emit][this][error][errorObj]
+ duk_push_string(ctx, "ILibDuktape_WritableStream_Write");
+ duk_put_prop_string(ctx, -2, "stack");
+ duk_push_string(ctx, "ILibDuktape_WriteableStream_Write/Handler returned Error");
+ duk_put_prop_string(ctx, -2, "message");
+ if (duk_pcall_method(ctx, 2) != 0) // [retVal]
{
- duk_push_heapptr(ctx, stream->OnError); // [func]
- duk_push_heapptr(ctx, stream->obj); // [func][this]
- duk_push_object(ctx); // [func][this][error]
- duk_push_string(ctx, "ILibDuktape_WritableStream_Write");
- duk_put_prop_string(ctx, -2, "stack");
- duk_push_string(ctx, "ILibDuktape_WriteableStream_Write/Handler returned Error");
- duk_put_prop_string(ctx, -2, "message");
- if (duk_pcall_method(ctx, 1) != 0) // [retVal]
- {
- ILibDuktape_Process_UncaughtException(ctx);
- }
+ ILibDuktape_Process_UncaughtException(ctx);
}
duk_push_false(ctx);
break;
@@ -230,10 +230,7 @@ duk_ret_t ILibDuktape_WritableStream_End(duk_context *ctx)
{
if (nargs > 2 && !duk_is_null_or_undefined(ctx, 2))
{
- stream->OnFinish = duk_require_heapptr(ctx, 2);
- duk_push_this(ctx); // [stream]
- duk_dup(ctx, 2); // [stream][flush]
- duk_put_prop_string(ctx, -2, "_Finish"); // [stream]
+ ILibDuktape_EventEmitter_AddOnce(ILibDuktape_EventEmitter_GetEmitter_fromThis(ctx), "finish", duk_require_heapptr(ctx, 2));
}
stream->endBytes = (int)bufferLen;
if (stream->WriteSink(stream, buffer, (int)bufferLen, stream->WriteSink_User) == ILibTransport_DoneState_INCOMPLETE)
@@ -247,16 +244,14 @@ duk_ret_t ILibDuktape_WritableStream_End(duk_context *ctx)
if (stream->WaitForEnd == 0)
{
// Continue with closing stream
- if (stream->OnFinish != NULL)
- {
- duk_push_heapptr(ctx, stream->OnFinish); // [func]
- duk_push_heapptr(ctx, stream->obj); // [func][this]
- if (duk_pcall_method(ctx, 0) != 0) // [retVal]
- {
- ILibDuktape_Process_UncaughtException(ctx);
- }
- }
if (stream->EndSink != NULL) { stream->EndSink(stream, stream->WriteSink_User); }
+
+ duk_push_heapptr(stream->ctx, stream->obj); // [stream]
+ duk_get_prop_string(stream->ctx, -1, "emit"); // [stream][emit]
+ duk_swap_top(stream->ctx, -2); // [emit][this]
+ duk_push_string(stream->ctx, "finish"); // [emit][this][finish]
+ if (duk_pcall_method(stream->ctx, 1) != 0) { ILibDuktape_Process_UncaughtException(stream->ctx); }
+ duk_pop(stream->ctx); // ...
}
return 0;
@@ -268,9 +263,20 @@ duk_ret_t ILibDuktape_WritableStream_End_Getter(duk_context *ctx)
}
duk_ret_t ILibDuktape_WritableStream_UnPipeSink(duk_context *ctx)
{
- duk_dup(ctx, 0);
- duk_push_this(ctx);
- //printf("UNPIPE: [%s] => X => [%s]\n", Duktape_GetStringPropertyValue(ctx, -2, ILibDuktape_OBJID, "unknown"), Duktape_GetStringPropertyValue(ctx, -1, ILibDuktape_OBJID, "unknown"));
+ ILibDuktape_WritableStream *ws;
+
+ duk_dup(ctx, 0); // [readable]
+ duk_push_this(ctx); // [readable][writable]
+ if (duk_has_prop_string(ctx, -1, ILibDuktape_WritableStream_WSPTRS))
+ {
+ duk_get_prop_string(ctx, -1, ILibDuktape_WritableStream_WSPTRS); // [readable][writable][ptr]
+ ws = (ILibDuktape_WritableStream*)Duktape_GetBuffer(ctx, -1, NULL);
+ ws->pipedReadable = NULL;
+ ws->pipedReadable_native = NULL;
+ duk_pop(ctx); // [readable][writable]
+ if (g_displayStreamPipeMessages) { printf("UNPIPE: [%s] => X => [%s:%d]\n", Duktape_GetStringPropertyValue(ctx, -2, ILibDuktape_OBJID, "unknown"), Duktape_GetStringPropertyValue(ctx, -1, ILibDuktape_OBJID, "unknown"), ILibDuktape_GetReferenceCount(ctx, -1) - 1); if (g_displayFinalizerMessages) { duk_eval_string(ctx, "_debugGC();"); duk_pop(ctx); } }
+ }
+ duk_pop_2(ctx);
return(0);
}
duk_ret_t ILibDuktape_WritableStream_PipeSink(duk_context *ctx)
@@ -289,8 +295,7 @@ duk_ret_t ILibDuktape_WritableStream_PipeSink(duk_context *ctx)
duk_dup(ctx, 0);
duk_push_this(ctx);
- //printf("PIPE: [%s] => [%s]\n", Duktape_GetStringPropertyValue(ctx, -2, ILibDuktape_OBJID, "unknown"), Duktape_GetStringPropertyValue(ctx, -1, ILibDuktape_OBJID, "unknown"));
-
+ if (g_displayStreamPipeMessages) { printf("PIPE: [%s] => [%s:%d]\n", Duktape_GetStringPropertyValue(ctx, -2, ILibDuktape_OBJID, "unknown"), Duktape_GetStringPropertyValue(ctx, -1, ILibDuktape_OBJID, "unknown"), ILibDuktape_GetReferenceCount(ctx, -1)); }
return(0);
}
@@ -315,11 +320,11 @@ ILibDuktape_WritableStream* ILibDuktape_WritableStream_Init(duk_context *ctx, IL
emitter = ILibDuktape_EventEmitter_Create(ctx);
ILibDuktape_EventEmitter_CreateEventEx(emitter, "pipe");
ILibDuktape_EventEmitter_CreateEventEx(emitter, "unpipe");
- ILibDuktape_EventEmitter_CreateEvent(emitter, "drain", &(retVal->OnDrain));
- ILibDuktape_EventEmitter_CreateEvent(emitter, "finish", &(retVal->OnFinish));
- ILibDuktape_EventEmitter_CreateEvent(emitter, "error", &(retVal->OnError));
+ ILibDuktape_EventEmitter_CreateEventEx(emitter, "drain");
+ ILibDuktape_EventEmitter_CreateEventEx(emitter, "finish");
+ ILibDuktape_EventEmitter_CreateEventEx(emitter, "error");
- ILibDuktape_CreateInstanceMethod(ctx, "write", ILibDuktape_WritableStream_Write, DUK_VARARGS);
+ ILibDuktape_CreateProperty_InstanceMethod(ctx, "write", ILibDuktape_WritableStream_Write, DUK_VARARGS);
ILibDuktape_CreateEventWithGetter(ctx, "end", ILibDuktape_WritableStream_End_Getter);
ILibDuktape_EventEmitter_AddOnEx(ctx, -1, "pipe", ILibDuktape_WritableStream_PipeSink);
diff --git a/microscript/ILibDuktape_WritableStream.h b/microscript/ILibDuktape_WritableStream.h
index 27863ec..cbe0b73 100644
--- a/microscript/ILibDuktape_WritableStream.h
+++ b/microscript/ILibDuktape_WritableStream.h
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -33,14 +33,10 @@ typedef struct ILibDuktape_WritableStream
int JSCreated;
duk_context *ctx;
void *obj;
- void *OnDrain;
void *OnWriteFlush;
ILibDuktape_WriteableStream_WriteFlushNative OnWriteFlushEx;
void *OnWriteFlushEx_User;
-
- void *OnError;
- void *OnFinish;
char WaitForEnd;
ILibDuktape_WritableStream_WriteHandler WriteSink;
diff --git a/microscript/ILibDuktape_fs.c b/microscript/ILibDuktape_fs.c
index 8b2b94f..32ae3ce 100644
--- a/microscript/ILibDuktape_fs.c
+++ b/microscript/ILibDuktape_fs.c
@@ -1,11 +1,11 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-http://www.apache.org/licenses/LICENSE-2.0
+ http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
@@ -69,7 +69,6 @@ typedef struct ILibDuktape_fs_writeStreamData
ILibDuktape_EventEmitter *emitter;
void *fsObject;
void *WriteStreamObject;
- void *onClose;
FILE *fPtr;
int fd;
int autoClose;
@@ -82,7 +81,6 @@ typedef struct ILibDuktape_fs_readStreamData
void *ReadStreamObject;
void *fsObject;
ILibDuktape_EventEmitter *emitter;
- void *onClose;
FILE *fPtr;
int fd;
int autoClose;
@@ -99,7 +97,6 @@ typedef struct ILibDuktape_fs_watcherData
duk_context *ctx;
void *object;
void *parent;
- void *OnChange;
ILibDuktape_EventEmitter *emitter;
#if defined(WIN32)
int recursive;
@@ -240,9 +237,7 @@ duk_ret_t ILibDuktape_fs_openSync(duk_context *ctx)
}
else
{
- duk_push_string(ctx, "fs.openSync ERROR");
- duk_throw(ctx);
- return(DUK_RET_ERROR);
+ return(ILibDuktape_Error(ctx, "fs.openSync(): Error opening '%s'", path));
}
}
duk_ret_t ILibDuktape_fs_readSync(duk_context *ctx)
@@ -260,7 +255,7 @@ duk_ret_t ILibDuktape_fs_readSync(duk_context *ctx)
{
if (duk_is_number(ctx, 4))
{
- fseek(f, duk_require_int(ctx, 4), SEEK_CUR);
+ fseek(f, duk_require_int(ctx, 4), SEEK_SET);
}
bytesRead = (int)fread(buffer + offset, 1, length, f);
duk_push_int(ctx, bytesRead);
@@ -285,7 +280,7 @@ duk_ret_t ILibDuktape_fs_writeSync(duk_context *ctx)
f = ILibDuktape_fs_getFilePtr(ctx, duk_require_int(ctx, 0));
if (f != NULL)
{
- if (nargs > 4) { fseek(f, duk_require_int(ctx, 4), SEEK_CUR); }
+ if (nargs > 4) { fseek(f, duk_require_int(ctx, 4), SEEK_SET); printf("Write: Seeking to %d\n", duk_require_int(ctx, 4)); }
bytesWritten = (int)fwrite(buffer, 1, length, f);
duk_push_int(ctx, bytesWritten);
return 1;
@@ -339,17 +334,14 @@ void ILibDuktape_fs_writeStream_endHandler(struct ILibDuktape_WritableStream *st
data->fPtr = NULL;
}
- if (data->ctx != NULL && data->onClose != NULL)
- {
- // Call the 'close' event on the WriteStream
- duk_push_heapptr(data->ctx, data->onClose); // [func]
- duk_push_heapptr(data->ctx, data->WriteStreamObject); // [func][this]
- if (duk_pcall_method(data->ctx, 0) != 0) // [retVal]
- {
- ILibDuktape_Process_UncaughtException(data->ctx);
- }
- duk_pop(data->ctx);
- }
+
+ // Call the 'close' event on the WriteStream
+ duk_push_heapptr(data->ctx, data->WriteStreamObject); // [this]
+ duk_get_prop_string(data->ctx, -1, "emit"); // [this][emit]
+ duk_swap_top(data->ctx, -2); // [emit][this]
+ duk_push_string(data->ctx, "close"); // [emit][this][close]
+ if (duk_pcall_method(data->ctx, 1) != 0) { ILibDuktape_Process_UncaughtException(data->ctx); }
+ duk_pop(data->ctx); // ...
}
duk_ret_t ILibDuktape_fs_writeStream_finalizer(duk_context *ctx)
{
@@ -413,6 +405,7 @@ duk_ret_t ILibDuktape_fs_createWriteStream(duk_context *ctx)
if (f != NULL)
{
duk_push_object(ctx); // [writeStream]
+ ILibDuktape_WriteID(ctx, "fs.writeStream");
duk_push_fixed_buffer(ctx, sizeof(ILibDuktape_fs_writeStreamData)); // [writeStream][buffer]
data = (ILibDuktape_fs_writeStreamData*)Duktape_GetBuffer(ctx, -1, NULL);
memset(data, 0, sizeof(ILibDuktape_fs_writeStreamData));
@@ -428,7 +421,7 @@ duk_ret_t ILibDuktape_fs_createWriteStream(duk_context *ctx)
data->emitter = ILibDuktape_EventEmitter_Create(ctx);
data->stream = ILibDuktape_WritableStream_Init(ctx, ILibDuktape_fs_writeStream_writeHandler, ILibDuktape_fs_writeStream_endHandler, data);
- ILibDuktape_EventEmitter_CreateEvent(data->emitter, "close", &(data->onClose));
+ ILibDuktape_EventEmitter_CreateEventEx(data->emitter, "close");
ILibDuktape_CreateFinalizer(ctx, ILibDuktape_fs_writeStream_finalizer);
return 1;
}
@@ -454,14 +447,15 @@ void ILibDuktape_fs_readStream_Resume(struct ILibDuktape_readableStream *sender,
sender->paused = 0;
if (data->bytesRead == -1) { data->bytesRead = 1; }
- while (sender->paused == 0 && data->bytesRead > 0 && data->bytesLeft < 0)
+ while (sender->paused == 0 && data->bytesRead > 0 && (data->bytesLeft < 0 || data->bytesLeft > 0))
{
- bytesToRead = data->bytesLeft < 0 ? sizeof(data->buffer) : data->bytesLeft;
+ bytesToRead = data->bytesLeft < 0 ? sizeof(data->buffer) : (data->bytesLeft > sizeof(data->buffer) ? sizeof(data->buffer) : data->bytesLeft);
data->bytesRead = (int)fread(data->buffer, 1, bytesToRead, data->fPtr);
if (data->bytesRead > 0)
{
if (data->bytesLeft > 0) { data->bytesLeft -= data->bytesRead; }
ILibDuktape_readableStream_WriteData(sender, data->buffer, data->bytesRead);
+ if (data->bytesLeft == 0) { data->bytesRead = 0; }
}
}
if (sender->paused == 0 && data->bytesRead == 0)
@@ -477,14 +471,13 @@ void ILibDuktape_fs_readStream_Resume(struct ILibDuktape_readableStream *sender,
data->fd = 0;
data->fPtr = NULL;
- if (data->onClose != NULL && data->ctx != NULL)
+ if (data->ctx != NULL && data->ReadStreamObject != NULL)
{
- duk_push_heapptr(data->ctx, data->onClose); // [func]
- duk_push_heapptr(data->ctx, data->ReadStreamObject); // [func][this]
- if (duk_pcall_method(data->ctx, 0) != 0) // [retVal]
- {
- ILibDuktape_Process_UncaughtException(data->ctx);
- }
+ duk_push_heapptr(data->ctx, data->ReadStreamObject); // [this]
+ duk_get_prop_string(data->ctx, -1, "emit"); // [this][emit]
+ duk_swap_top(data->ctx, -2); // [emit][this]
+ duk_push_string(data->ctx, "close"); // [emit][this][close]
+ if (duk_pcall_method(data->ctx, 1) != 0) { ILibDuktape_Process_UncaughtException(data->ctx); }
duk_pop(data->ctx); // ...
}
}
@@ -551,6 +544,7 @@ duk_ret_t ILibDuktape_fs_createReadStream(duk_context *ctx)
}
duk_push_object(ctx); // [readStream]
+ ILibDuktape_WriteID(ctx, "fs.readStream");
duk_push_fixed_buffer(ctx, sizeof(ILibDuktape_fs_readStreamData)); // [readStream][buffer]
data = (ILibDuktape_fs_readStreamData*)Duktape_GetBuffer(ctx, -1, NULL);
memset(data, 0, sizeof(ILibDuktape_fs_readStreamData));
@@ -564,17 +558,19 @@ duk_ret_t ILibDuktape_fs_createReadStream(duk_context *ctx)
data->fPtr = f;
data->autoClose = autoClose;
data->ReadStreamObject = duk_get_heapptr(ctx, -1);
- data->bytesLeft = end;
+ data->bytesLeft = end < 0 ? end : (end - start + 1);
data->bytesRead = -1;
data->stream = ILibDuktape_ReadableStream_Init(ctx, ILibDuktape_fs_readStream_Pause, ILibDuktape_fs_readStream_Resume, data);
data->stream->paused = 1;
- ILibDuktape_EventEmitter_CreateEvent(data->emitter, "close", &(data->onClose));
+ //printf("readStream [start: %d, end: %d\n", start, end);
+
+ ILibDuktape_EventEmitter_CreateEventEx(data->emitter, "close");
ILibDuktape_CreateFinalizer(ctx, ILibDuktape_fs_readStream_finalizer);
if (start != 0)
{
- fseek(f, start, SEEK_CUR);
+ fseek(f, start, SEEK_SET);
}
return 1;
@@ -904,24 +900,23 @@ void ILibDuktape_fs_watch_iocompletionEx(void *chain, void *user)
n = (n->NextEntryOffset != 0) ? ((FILE_NOTIFY_INFORMATION*)((char*)n + n->NextEntryOffset)) : NULL;
}
- if (data->OnChange != NULL)
+
+ duk_push_heapptr(data->ctx, data->object); // [detail][fsWatcher]
+ duk_get_prop_string(data->ctx, -1, "emit"); // [detail][fsWatcher][emit]
+ duk_swap_top(data->ctx, -2); // [detail][emit][this]
+ duk_push_string(data->ctx, "change"); // [detail][emit][this][change]
+ duk_push_string(data->ctx, changed == 0 ? "rename" : "change"); // [detail][emit][this][change][type]
+ if (changed == 0)
{
- duk_push_heapptr(data->ctx, data->OnChange); // [detail][change]
- duk_push_heapptr(data->ctx, data->object); // [detail][change][fsWatcher]
- duk_push_string(data->ctx, changed == 0 ? "rename" : "change"); // [detail][change][fsWatcher][type]
- if (changed == 0)
- {
- duk_get_prop_string(data->ctx, -4, "oldname"); // [detail][listener][fsWatcher][type][fileName]
- }
- else
- {
- duk_get_prop_string(data->ctx, -4, "\xFF_FileName"); // [detail][listener][fsWatcher][type][fileName]
- }
- duk_dup(data->ctx, -5); // [detail][change][fsWatcher][type][fileName][detail]
- if (duk_pcall_method(data->ctx, 3) != 0) { ILibDuktape_Process_UncaughtException(data->ctx); }
- duk_pop(data->ctx); // [detail]
+ duk_get_prop_string(data->ctx, -4, "oldname"); // [detail][emit][this][change][type][fileName]
}
- duk_pop(data->ctx); // ...
+ else
+ {
+ duk_get_prop_string(data->ctx, -4, "\xFF_FileName"); // [detail][emit][this][change][type][fileName]
+ }
+ duk_dup(data->ctx, -5); // [detail][emit][this][change][type][fileName][detail]
+ if (duk_pcall_method(data->ctx, 4) != 0) { ILibDuktape_Process_UncaughtException(data->ctx); }
+ duk_pop_2(data->ctx); // ...
memset(data->results, 0, sizeof(data->results));
if (data->h != NULL)
@@ -1001,7 +996,7 @@ void ILibDuktape_fs_notifyDispatcher_PostSelect(void* object, int slct, fd_set *
wd.p = NULL;
wd.i = evt->wd;
watcher = (ILibDuktape_fs_watcherData*)ILibHashtable_Get(data->watchTable, wd.p, NULL, 0);
- if (watcher == NULL || watcher->OnChange == NULL) { continue; }
+ if (watcher == NULL || ILibDuktape_EventEmitter_HasListeners(watcher->emitter, "change") == 0) { continue; }
duk_push_object(watcher->ctx); // [detail]
@@ -1021,21 +1016,19 @@ void ILibDuktape_fs_notifyDispatcher_PostSelect(void* object, int slct, fd_set *
duk_push_string(watcher->ctx, evt->name);
duk_put_prop_string(watcher->ctx, -2, "\xFF_FileName");
}
-
- duk_push_heapptr(watcher->ctx, watcher->OnChange); // [detail][change]
- duk_push_heapptr(watcher->ctx, watcher->object); // [detail][change][fsWatcher]
- duk_push_string(watcher->ctx, changed == 0 ? "rename" : "change"); // [detail][change][fsWatcher][type]
+ ILibDuktape_EventEmitter_SetupEmit(watcher->ctx, watcher->object, "change");// [detail][emit][this][change]
+ duk_push_string(watcher->ctx, changed == 0 ? "rename" : "change"); // [detail][emit][this][change][type]
if (changed == 0)
{
- duk_get_prop_string(watcher->ctx, -4, "oldname"); // [detail][listener][fsWatcher][type][fileName]
+ duk_get_prop_string(watcher->ctx, -5, "oldname"); // [detail][emit][this][change][type][fileName]
}
else
{
- duk_get_prop_string(watcher->ctx, -4, "\xFF_FileName"); // [detail][listener][fsWatcher][type][fileName]
+ duk_get_prop_string(watcher->ctx, -5, "\xFF_FileName"); // [detail][emit][this][change][type][fileName]
}
- duk_dup(watcher->ctx, -5); // [detail][change][fsWatcher][type][fileName][detail]
- if (duk_pcall_method(watcher->ctx, 3) != 0) { ILibDuktape_Process_UncaughtException(watcher->ctx); }
- duk_pop_2(watcher->ctx); // ...
+ duk_dup(watcher->ctx, -6); // [detail][emit][this][change][type][fileName][detail]
+ if (duk_pcall_method(watcher->ctx, 4) != 0) { ILibDuktape_Process_UncaughtException(watcher->ctx); }
+ duk_pop_2(watcher->ctx); // ...
}
}
}
@@ -1099,6 +1092,7 @@ duk_ret_t ILibDuktape_fs_watch(duk_context *ctx)
#endif
duk_push_object(ctx); // [FSWatcher]
+ ILibDuktape_WriteID(ctx, "fs.fsWatcher");
duk_push_fixed_buffer(ctx, sizeof(ILibDuktape_fs_watcherData)); // [FSWatcher][data]
data = (ILibDuktape_fs_watcherData*)Duktape_GetBuffer(ctx, -1, NULL);
duk_put_prop_string(ctx, -2, FS_WATCHER_DATA_PTR); // [FSWatcher]
@@ -1117,7 +1111,7 @@ duk_ret_t ILibDuktape_fs_watch(duk_context *ctx)
ILibDuktape_CreateInstanceMethod(ctx, "close", ILibDuktape_fs_watcher_close, 0);
- ILibDuktape_EventEmitter_CreateEvent(data->emitter, "change", &(data->OnChange));
+ ILibDuktape_EventEmitter_CreateEventEx(data->emitter, "change");
ILibDuktape_CreateFinalizer(ctx, ILibDuktape_fs_watcher_finalizer);
for (i = 1; i < nargs; ++i)
@@ -1233,10 +1227,26 @@ duk_ret_t ILibDuktape_fs_readFileSync(duk_context *ctx)
return(1);
}
+duk_ret_t ILibDuktape_fs_existsSync(duk_context *ctx)
+{
+ duk_push_this(ctx); // [fs]
+ duk_get_prop_string(ctx, -1, "statSync"); // [fs][statSync]
+ duk_swap_top(ctx, -2); // [statSync][this]
+ duk_dup(ctx, 0); // [statSync][this][path]
+ if (duk_pcall_method(ctx, 1) != 0)
+ {
+ duk_push_false(ctx);
+ }
+ else
+ {
+ duk_push_true(ctx);
+ }
+ return(1);
+}
void ILibDuktape_fs_PUSH(duk_context *ctx, void *chain)
{
duk_push_object(ctx); // [fs]
-
+ ILibDuktape_WriteID(ctx, "fs");
duk_push_pointer(ctx, chain); // [fs][chain]
duk_put_prop_string(ctx, -2, FS_CHAIN_PTR); // [fs]
@@ -1256,6 +1266,7 @@ void ILibDuktape_fs_PUSH(duk_context *ctx, void *chain)
ILibDuktape_CreateInstanceMethod(ctx, "statSync", ILibDuktape_fs_statSync, 1);
ILibDuktape_CreateInstanceMethod(ctx, "readDrivesSync", ILibDuktape_fs_readDrivesSync, 0);
ILibDuktape_CreateInstanceMethod(ctx, "readFileSync", ILibDuktape_fs_readFileSync, DUK_VARARGS);
+ ILibDuktape_CreateInstanceMethod(ctx, "existsSync", ILibDuktape_fs_existsSync, 1);
#ifndef _NOFSWATCHER
ILibDuktape_CreateInstanceMethod(ctx, "watch", ILibDuktape_fs_watch, DUK_VARARGS);
#endif
diff --git a/microscript/ILibDuktape_fs.h b/microscript/ILibDuktape_fs.h
index 4ac8c92..bc34d0c 100644
--- a/microscript/ILibDuktape_fs.h
+++ b/microscript/ILibDuktape_fs.h
@@ -1,3 +1,19 @@
+/*
+Copyright 2006 - 2018 Intel Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
#ifndef ___DUKTAPE_FS___
#define ___DUKTAPE_FS___
diff --git a/microscript/ILibDuktape_http.c b/microscript/ILibDuktape_http.c
index 728ee0f..f62338b 100644
--- a/microscript/ILibDuktape_http.c
+++ b/microscript/ILibDuktape_http.c
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -41,14 +41,12 @@ limitations under the License.
duk_ret_t ILibDuktape_httpDigest_clientRequest_response2(duk_context *ctx)
{
- ILibHTTPPacket *packet;
- duk_get_prop_string(ctx, 0, "PacketPtr");
- packet = (ILibHTTPPacket*)duk_get_pointer(ctx, -1);
-
duk_push_current_function(ctx);
duk_get_prop_string(ctx, -1, "digestClientRequest");// [digestClientRequest]
- if (packet->StatusCode == 200)
+ int statusCode = Duktape_GetIntPropertyValue(ctx, 0, "statusCode", 0);
+
+ if (statusCode == 200)
{
duk_get_prop_string(ctx, -1, "emit"); // [digestClientRequest][emit]
duk_swap_top(ctx, -2); // [emit][this]
@@ -60,8 +58,8 @@ duk_ret_t ILibDuktape_httpDigest_clientRequest_response2(duk_context *ctx)
{
duk_get_prop_string(ctx, -1, "emit"); // [digestClientRequest][emit]
duk_swap_top(ctx, -2); // [emit][this]
- duk_push_string(ctx, "error"); // [emit][this][response]
- duk_dup(ctx, 0); // [emit][this][response][imsg]
+ duk_push_string(ctx, "error"); // [emit][this][error]
+ duk_dup(ctx, 0); // [emit][this][error][imsg]
if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "http-digest: Error dispatching response event"); }
}
@@ -143,8 +141,8 @@ extern void ILibWebServer_Digest_ParseAuthenticationHeader(void* table, char* va
char *ILibDuktape_httpDigest_generateAuthenticationHeader(duk_context *ctx, void *digestObj, void *optionsObj)
{
int top = duk_get_top(ctx);
- int NC;
- char *CNONCE;
+ int NC = 0;
+ char *CNONCE = NULL;
char *wwwauth, *username, *password;
char *method, *path;
@@ -188,7 +186,9 @@ char *ILibDuktape_httpDigest_generateAuthenticationHeader(duk_context *ctx, void
}
else
{
+ duk_get_prop_string(ctx, -1, DIGEST2CNONCE); // [digest][buffer]
CNONCE = (char*)Duktape_GetBuffer(ctx, -1, NULL);
+ duk_pop(ctx); // [digest]
NC = Duktape_GetIntPropertyValue(ctx, -1, DIGEST2NC, 0) + 1;
duk_push_int(ctx, NC); // [digest][NC]
duk_put_prop_string(ctx, -2, DIGEST2NC); // [digest]
@@ -198,14 +198,10 @@ char *ILibDuktape_httpDigest_generateAuthenticationHeader(duk_context *ctx, void
util_md5hex(ILibScratchPad2, tmpLen, result3);
duk_pop(ctx); // ...
- tmpLen = sprintf_s(ILibScratchPad2, sizeof(ILibScratchPad2), "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\"", username, realm, nonce, path);
- if (opaque != NULL) { tmpLen += sprintf_s(ILibScratchPad2 + tmpLen, sizeof(ILibScratchPad2) - tmpLen, ", opaque=\"%s\"", opaque); }
- if (qop != NULL)
- {
- tmpLen += sprintf_s(ILibScratchPad2 + tmpLen, sizeof(ILibScratchPad2) - tmpLen, ", qop=\"%s\", nc=%08x, cnonce=\"%s\"", qop, NC, CNONCE);
- }
-
- tmpLen += sprintf_s(ILibScratchPad2 + tmpLen, sizeof(ILibScratchPad2) - tmpLen, ", response=\"%s\"", result3);
+ tmpLen = sprintf_s(ILibScratchPad2, sizeof(ILibScratchPad2), "Digest username=\"%s\",realm=\"%s\",nonce=\"%s\",uri=\"%s\"", username, realm, nonce, path);
+ if (opaque != NULL) { tmpLen += sprintf_s(ILibScratchPad2 + tmpLen, sizeof(ILibScratchPad2) - tmpLen, ",opaque=\"%s\"", opaque); }
+ tmpLen += sprintf_s(ILibScratchPad2 + tmpLen, sizeof(ILibScratchPad2) - tmpLen, ",response=\"%s\"", result3);
+ if (qop != NULL) { tmpLen += sprintf_s(ILibScratchPad2 + tmpLen, sizeof(ILibScratchPad2) - tmpLen, ",qop=\"%s\",nc=\"%08x\",cnonce=\"%s\"", qop, NC, CNONCE); }
if (realmLen > 0) { realm[realmLen] = '"'; }
if (nonceLen > 0) { nonce[nonceLen] = '"'; }
@@ -305,8 +301,8 @@ duk_ret_t ILibDuktape_httpDigest_clientRequest_response(duk_context *ctx)
duk_dup(ctx, -2); // [clientRequest][buffer][clientRequest]
duk_get_prop_string(ctx, -1, "write"); // [clientRequest][buffer][clientRequest][write]
duk_swap_top(ctx, -2); // [clientRequest][buffer][write][this]
- duk_swap(ctx, -3, -2); // [clientRequest][write][buffer][this]
- duk_swap_top(ctx, -2); // [clientReqeust][write][this][buffer]
+ duk_dup(ctx, -3); // [clientRequest][buffer][write][this][buffer]
+ duk_remove(ctx, -4); // [clientRequest][write][this][buffer]
if (duk_pcall_method(ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "httpDigest.clientRequest.onResponse(): Error calling clientRequest.write(): "); }
duk_pop(ctx); // [clientRequest]
}
@@ -410,6 +406,12 @@ ILibTransport_DoneState ILibDuktape_httpDigest_http_request_WriteHandler(struct
duk_put_prop_string(ctx, -2, DIGESTCLIENTREQUEST_TmpBuffer); // [digestClientRequest]
memcpy_s(tmpBuffer, bufLen, buffer, (size_t)bufferLen);
}
+
+ if (stream->endBytes > 0)
+ {
+ duk_push_true(ctx);
+ duk_put_prop_string(ctx, -2, DIGESTCLIENTREQUEST_END_CALLED);
+ }
}
if (duk_has_prop_string(ctx, -1, DIGEST_CLIENT_REQUEST))
@@ -477,6 +479,7 @@ duk_ret_t ILibDuktape_httpDigest_http_request(duk_context *ctx)
void *clientRequest = NULL;
ILibDuktape_EventEmitter *emitter;
char *auth = NULL;
+ int needCallEnd = 0;
duk_push_this(ctx); // [digest]
duk_get_prop_string(ctx, -1, HTTP_DIGEST); // [digest][http]
@@ -489,6 +492,7 @@ duk_ret_t ILibDuktape_httpDigest_http_request(duk_context *ctx)
duk_dup(ctx, -2); // [digest][request][this][parseUri][this]
duk_dup(ctx, 0); // [digest][request][this][parseUri][this][uri]
duk_call_method(ctx, 1); // [digest][request][this][options]
+ needCallEnd = 1;
}
else
{
@@ -522,6 +526,13 @@ duk_ret_t ILibDuktape_httpDigest_http_request(duk_context *ctx)
duk_push_c_function(ctx, ILibDuktape_httpDigest_clientRequest_response, DUK_VARARGS); // [once][this][response][method]
duk_push_object(ctx); // [once][this][response][method][digest-clientRequest]
+ ILibDuktape_WriteID(ctx, "httpDigest.clientRequest");
+ if (needCallEnd)
+ {
+ duk_push_true(ctx);
+ duk_put_prop_string(ctx, -2, DIGESTCLIENTREQUEST_END_CALLED);
+ }
+
duk_push_this(ctx); // [once][this][response][method][digest-clientRequest][digest]
duk_put_prop_string(ctx, -2, DIGESTCLIENTREQUEST_DIGEST); // [once][this][response][method][digest-clientRequest]
duk_push_heapptr(ctx, clientRequest); // [once][this][response][method][digest-clientRequest][clientRequest]
@@ -557,6 +568,13 @@ duk_ret_t ILibDuktape_httpDigest_http_request(duk_context *ctx)
ILibDuktape_EventEmitter_ForwardEvent(ctx, -2, "timeout", -1, "timeout");
ILibDuktape_EventEmitter_ForwardEvent(ctx, -2, "drain", -1, "drain");
+ if (needCallEnd)
+ {
+ duk_get_prop_string(ctx, -2, "end"); // [clientRequest][digestClientRequest][end]
+ duk_dup(ctx, -3); // [clientRequest][digestClientRequest][end][this]
+ duk_call_method(ctx, 0); duk_pop(ctx); // [clientRequest][digestClientRequest]
+ }
+
return(1);
}
duk_ret_t ILibduktape_httpDigest_create(duk_context *ctx)
@@ -566,6 +584,7 @@ duk_ret_t ILibduktape_httpDigest_create(duk_context *ctx)
ILibDuktape_EventEmitter *emitter;
duk_push_object(ctx); // [obj]
+ ILibDuktape_WriteID(ctx, "httpDigest");
ILibDuktape_CreateEventWithSetterEx(ctx, "clientRequest", ILibDuktape_httpDigest_clientRequest_setter);
ILibDuktape_CreateEventWithSetterEx(ctx, "http", ILibDuktape_httpDigest_http_setter);
emitter = ILibDuktape_EventEmitter_Create(ctx);
@@ -580,6 +599,7 @@ duk_ret_t ILibduktape_httpDigest_create(duk_context *ctx)
duk_put_prop_string(ctx, -2, DIGEST_PASSWORD);
duk_push_fixed_buffer(ctx, 16);
util_randomtext(16, (char*)Duktape_GetBuffer(ctx, -1, NULL));
+ ((char*)Duktape_GetBuffer(ctx, -1, NULL))[15] = 0;
duk_put_prop_string(ctx, -2, DIGEST2CNONCE);
duk_push_int(ctx, 0);
duk_put_prop_string(ctx, -2, DIGEST2NC);
diff --git a/microscript/ILibDuktape_http.h b/microscript/ILibDuktape_http.h
index dae8760..34ecee8 100644
--- a/microscript/ILibDuktape_http.h
+++ b/microscript/ILibDuktape_http.h
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/microscript/ILibDuktape_net.c b/microscript/ILibDuktape_net.c
index aa02323..0782d80 100644
--- a/microscript/ILibDuktape_net.c
+++ b/microscript/ILibDuktape_net.c
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -34,10 +34,6 @@ typedef struct ILibDuktape_net_socket
void *net;
void *duplexStream;
void *chain;
- void *OnConnect;
- void *OnClose;
- void *OnError;
- void *OnTimeout;
void *OnSetTimeout;
int unshiftBytes;
ILibDuktape_EventEmitter *emitter;
@@ -53,9 +49,7 @@ typedef struct ILibDuktape_net_server
void *self;
ILibAsyncServerSocket_ServerModule server;
ILibDuktape_EventEmitter *emitter;
- void *OnClose;
- void *OnListening;
- void *OnError;
+ int isTLS;
}ILibDuktape_net_server;
typedef struct ILibDuktape_net_server_session
{
@@ -66,8 +60,6 @@ typedef struct ILibDuktape_net_server_session
ILibDuktape_DuplexStream *stream;
int unshiftBytes;
-
- void *OnTimeout;
}ILibDuktape_net_server_session;
int ILibDuktape_TLS_ctx2socket = -1;
@@ -83,6 +75,7 @@ int ILibDuktape_TLS_ctx2server = -1;
#define ILibDuktape_SERVER2ContextTable "\xFF_Server2ContextTable"
#define ILibDuktape_SERVER2OPTIONS "\xFF_ServerToOptions"
#define ILibDuktape_SERVER2LISTENOPTIONS "\xFF_ServerToListenOptions"
+#define ILibDuktape_TLSSocket2SecureContext "\xFF_TLSSocket2SecureContext"
extern void ILibAsyncServerSocket_RemoveFromChain(ILibAsyncServerSocket_ServerModule serverModule);
@@ -143,28 +136,34 @@ void ILibDuktape_net_socket_OnConnect(ILibAsyncSocket_SocketModule socketModule,
return;
}
#endif
- if (ptrs->OnConnect != NULL)
- {
- duk_push_heapptr(ptrs->ctx, ptrs->OnConnect); // [func]
- duk_push_heapptr(ptrs->ctx, ptrs->object); // [func][this]
- if (duk_pcall_method(ptrs->ctx, 0) != 0) // [retVal]
- {
- ILibDuktape_Process_UncaughtException(ptrs->ctx);
- }
- duk_pop(ptrs->ctx); // ...
- }
+ duk_push_heapptr(ptrs->ctx, ptrs->object); // [this]
+ duk_get_prop_string(ptrs->ctx, -1, "emit"); // [this][emit]
+ duk_swap_top(ptrs->ctx, -2); // [emit][this]
+ duk_push_string(ptrs->ctx, "connect"); // [emit][this][connect]
+ if (duk_pcall_method(ptrs->ctx, 1) != 0) { ILibDuktape_Process_UncaughtException(ptrs->ctx); }
+ duk_pop(ptrs->ctx); // ...
}
- else if(ptrs->OnError != NULL)
+ else
{
- duk_push_heapptr(ptrs->ctx, ptrs->OnError); // [func]
- ILibDuktape_net_socket_PUSH(ptrs->ctx, socketModule); // [func][this]
- duk_push_object(ptrs->ctx); // [func][this][error]
- duk_push_string(ptrs->ctx, "Connection Failed"); // [func][this][error][msg]
- duk_put_prop_string(ptrs->ctx, -2, "message"); // [func][this][error]
- if (duk_pcall_method(ptrs->ctx, 1) != 0) // [retVal]
+ duk_push_heapptr(ptrs->ctx, ptrs->object); // [this]
+ duk_get_prop_string(ptrs->ctx, -1, "emit"); // [this][emit]
+ duk_swap_top(ptrs->ctx, -2); // [emit][this]
+ duk_push_string(ptrs->ctx, "error"); // [emit][this][error]
+ duk_push_object(ptrs->ctx); // [emit][this][error][errorObj]
+#ifndef MICROSTACK_NOTLS
+ if (ptrs->ssl != NULL && ILibAsyncSocket_TLS_WasHandshakeError(socketModule))
{
- ILibDuktape_Process_UncaughtException(ptrs->ctx);
+ duk_push_string(ptrs->ctx, "TLS Handshake Error"); // [emit][this][error][errorObj][msg]
}
+ else
+ {
+ duk_push_string(ptrs->ctx, "Connection Failed"); // [emit][this][error][errorObj][msg]
+ }
+#else
+ duk_push_string(ptrs->ctx, "Connection Failed"); // [emit][this][error][errorObj][msg]
+#endif
+ duk_put_prop_string(ptrs->ctx, -2, "message"); // [emit][this][error][errorObj]
+ if (duk_pcall_method(ptrs->ctx, 2) != 0) { ILibDuktape_Process_UncaughtException(ptrs->ctx); }
duk_pop(ptrs->ctx); // ...
}
}
@@ -338,13 +337,13 @@ duk_ret_t ILibDuktape_net_socket_address(duk_context *ctx)
void ILibDuktape_net_socket_timeoutSink(ILibAsyncSocket_SocketModule socketModule, void *user)
{
ILibDuktape_net_socket *ptrs = (ILibDuktape_net_socket*)((ILibChain_Link*)socketModule)->ExtraMemoryPtr;
- if (ptrs->OnTimeout != NULL)
- {
- duk_push_heapptr(ptrs->ctx, ptrs->OnTimeout); // [func]
- duk_push_heapptr(ptrs->ctx, ptrs->object); // [func][this]
- if (duk_pcall_method(ptrs->ctx, 0) != 0) { ILibDuktape_Process_UncaughtException(ptrs->ctx); }
- duk_pop(ptrs->ctx); // ...
- }
+
+ duk_push_heapptr(ptrs->ctx, ptrs->object); // [this]
+ duk_get_prop_string(ptrs->ctx, -1, "emit"); // [this][emit]
+ duk_swap_top(ptrs->ctx, -2); // [emit][this]
+ duk_push_string(ptrs->ctx, "timeout"); // [emit][this][timeout]
+ if (duk_pcall_method(ptrs->ctx, 1) != 0) { ILibDuktape_Process_UncaughtException(ptrs->ctx); }
+ duk_pop(ptrs->ctx); // ...
}
duk_ret_t ILibDuktape_net_socket_setTimeout(duk_context *ctx)
{
@@ -378,9 +377,6 @@ duk_ret_t ILibDuktape_net_socket_finalizer(duk_context *ctx)
if (ptrs->socketModule != NULL)
{
if (ILibAsyncSocket_IsConnected(ptrs->socketModule) != 0) { ILibAsyncSocket_Disconnect(ptrs->socketModule); }
-#ifndef MICROSTACK_NOTLS
- if (ptrs->ssl_ctx != NULL) { SSL_CTX_free(ptrs->ssl_ctx); ptrs->ssl_ctx = NULL; }
-#endif
ILibChain_SafeRemove(chain, ptrs->socketModule);
}
@@ -423,10 +419,10 @@ void ILibDuktape_net_socket_PUSH(duk_context *ctx, ILibAsyncSocket_SocketModule
ptrs->emitter = ILibDuktape_EventEmitter_Create(ctx);
ptrs->duplexStream = ILibDuktape_DuplexStream_InitEx(ctx, ILibDuktape_net_socket_WriteHandler, ILibDuktape_net_socket_EndHandler, ILibDuktape_net_socket_PauseHandler, ILibDuktape_net_socket_ResumeHandler, ILibDuktape_net_socket_unshift, ptrs);
- ILibDuktape_EventEmitter_CreateEvent(ptrs->emitter, "close", &(ptrs->OnClose));
- ILibDuktape_EventEmitter_CreateEvent(ptrs->emitter, "connect", &(ptrs->OnConnect));
- ILibDuktape_EventEmitter_CreateEvent(ptrs->emitter, "error", &(ptrs->OnError));
- ILibDuktape_EventEmitter_CreateEvent(ptrs->emitter, "timeout", &(ptrs->OnTimeout));
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "close");
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "connect");
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "error");
+ ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "timeout");
ILibDuktape_CreateProperty_InstanceMethod(ctx, "connect", ILibDuktape_net_socket_connect, DUK_VARARGS);
@@ -576,7 +572,7 @@ void ILibDuktape_net_server_OnConnect(ILibAsyncServerSocket_ServerModule AsyncSe
session->emitter = ILibDuktape_EventEmitter_Create(ptr->ctx);
- ILibDuktape_EventEmitter_CreateEvent(session->emitter, "timeout", &(session->OnTimeout));
+ ILibDuktape_EventEmitter_CreateEventEx(session->emitter, "timeout");
session->stream = ILibDuktape_DuplexStream_InitEx(ptr->ctx, ILibDuktape_net_server_WriteSink, ILibDuktape_net_server_EndSink,
ILibDuktape_net_server_PauseSink, ILibDuktape_net_server_ResumeSink, ILibDuktape_net_server_unshiftSink, session);
@@ -587,7 +583,7 @@ void ILibDuktape_net_server_OnConnect(ILibAsyncServerSocket_ServerModule AsyncSe
void ILibDuktape_net_server_OnDisconnect(ILibAsyncServerSocket_ServerModule AsyncServerSocketModule, ILibAsyncServerSocket_ConnectionToken ConnectionToken, void *user)
{
ILibDuktape_net_server_session *session = (ILibDuktape_net_server_session*)user;
- ILibDuktape_DuplexStream_WriteEnd(session->stream);
+ ILibDuktape_DuplexStream_Closed(session->stream);
}
void ILibDuktape_net_server_OnReceive(ILibAsyncServerSocket_ServerModule AsyncServerSocketModule, ILibAsyncServerSocket_ConnectionToken ConnectionToken, char* buffer, int *p_beginPointer, int endPointer, ILibAsyncServerSocket_OnInterrupt *OnInterrupt, void **user, int *PAUSE)
{
@@ -689,34 +685,37 @@ duk_ret_t ILibDuktape_net_server_listen(duk_context *ctx)
ILibAsyncServerSocket_SetTag(server->server, server);
#ifndef MICROSTACK_NOTLS
{
- duk_push_this(ctx); // [server]
- if (duk_has_prop_string(ctx, -1, "addContext"))
+ if (server->isTLS)
{
- duk_get_prop_string(ctx, -1, "addContext"); // [server][addContext]
- duk_swap_top(ctx, -2); // [addContext][this]
- duk_push_string(ctx, "*"); // [addContext][this][*]
- duk_eval_string(ctx, "require('tls');"); // [addContext][this][*][tls]
- duk_get_prop_string(ctx, -1, "createSecureContext"); // [addContext][this][*][tls][createSecureContext]
- duk_swap_top(ctx, -2); // [addContext][this][*][createSecureContext][this]
- duk_get_prop_string(ctx, -4, ILibDuktape_SERVER2OPTIONS); // [addContext][this][*][createSecureContext][this][options]
- duk_call_method(ctx, 1); // [addContext][this][*][secureContext]
- duk_call_method(ctx, 2); duk_pop(ctx); // ...
- }
- else
- {
- duk_pop(ctx); // ...
+ duk_push_this(ctx); // [server]
+ if (duk_has_prop_string(ctx, -1, "addContext"))
+ {
+ duk_get_prop_string(ctx, -1, "addContext"); // [server][addContext]
+ duk_swap_top(ctx, -2); // [addContext][this]
+ duk_push_string(ctx, "*"); // [addContext][this][*]
+ duk_eval_string(ctx, "require('tls');"); // [addContext][this][*][tls]
+ duk_get_prop_string(ctx, -1, "createSecureContext"); // [addContext][this][*][tls][createSecureContext]
+ duk_swap_top(ctx, -2); // [addContext][this][*][createSecureContext][this]
+ duk_get_prop_string(ctx, -4, ILibDuktape_SERVER2OPTIONS); // [addContext][this][*][createSecureContext][this][options]
+ duk_call_method(ctx, 1); // [addContext][this][*][secureContext]
+ duk_call_method(ctx, 2); duk_pop(ctx); // ...
+ }
+ else
+ {
+ duk_pop(ctx); // ...
+ }
}
}
#endif
- if (server->OnListening != NULL)
- {
- duk_push_heapptr(server->ctx, server->OnListening); // [func]
- duk_push_heapptr(server->ctx, server->self); // [func][this]
- if (duk_pcall_method(server->ctx, 0) != 0) { ILibDuktape_Process_UncaughtExceptionEx(server->ctx, "net.server.listen(): Error "); }
- duk_pop(server->ctx); // ...
- }
+ duk_push_heapptr(server->ctx, server->self); // [this]
+ duk_get_prop_string(server->ctx, -1, "emit"); // [this][emit]
+ duk_swap_top(server->ctx, -2); // [emit][this]
+ duk_push_string(server->ctx, "listening"); // [emit][this][listenting]
+ if (duk_pcall_method(server->ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(server->ctx, "net.server.listen(): Error "); }
+ duk_pop(server->ctx); // ...
+
#ifndef WIN32
ignore_result(backlog);
#endif
@@ -783,11 +782,12 @@ duk_ret_t ILibDuktape_net_createServer(duk_context *ctx)
server = (ILibDuktape_net_server*)Duktape_GetBuffer(ctx, -1, NULL);
memset(server, 0, sizeof(ILibDuktape_net_server));
duk_put_prop_string(ctx, -2, ILibDuktape_net_Server_buffer); // [server]
-
+
+ server->isTLS = isTLS;
server->self = duk_get_heapptr(ctx, -1);
server->ctx = ctx;
server->emitter = ILibDuktape_EventEmitter_Create(ctx);
- ILibDuktape_EventEmitter_CreateEvent(server->emitter, "close", &(server->OnClose));
+ ILibDuktape_EventEmitter_CreateEventEx(server->emitter, "close");
ILibDuktape_EventEmitter_CreateEventEx(server->emitter, "connection");
#ifndef MICROSTACK_NOTLS
if (isTLS)
@@ -799,8 +799,8 @@ duk_ret_t ILibDuktape_net_createServer(duk_context *ctx)
if (ILibDuktape_TLS_ctx2server < 0) { ILibDuktape_TLS_ctx2server = SSL_get_ex_new_index(0, "ILibDuktape_TLS_Server index", NULL, NULL, NULL); }
}
#endif
- ILibDuktape_EventEmitter_CreateEvent(server->emitter, "error", &(server->OnError));
- ILibDuktape_EventEmitter_CreateEvent(server->emitter, "listening", &(server->OnListening));
+ ILibDuktape_EventEmitter_CreateEventEx(server->emitter, "error");
+ ILibDuktape_EventEmitter_CreateEventEx(server->emitter, "listening");
ILibDuktape_CreateInstanceMethod(ctx, "listen", ILibDuktape_net_server_listen, DUK_VARARGS);
ILibDuktape_CreateInstanceMethod(ctx, "address", ILibDuktape_net_server_address, 0);
@@ -816,6 +816,13 @@ duk_ret_t ILibDuktape_net_createServer(duk_context *ctx)
if (duk_is_object(ctx, i))
{
// Options
+ if (isTLS && !duk_has_prop_string(ctx, i, "secureProtocol"))
+ {
+ duk_dup(ctx, i); // [options]
+ duk_push_string(ctx, "SSLv23_server_method"); // [options][secureProtocol]
+ duk_put_prop_string(ctx, -2, "secureProtocol"); // [options]
+ duk_pop(ctx); // ...
+ }
}
}
@@ -974,7 +981,7 @@ int ILibDuktape_TLS_verify(int preverify_ok, X509_STORE_CTX *storectx)
if (Duktape_GetBooleanProperty(data->ctx, -1, "rejectUnauthorized", 1)) { duk_pop_2(data->ctx); return(preverify_ok); }
void *OnVerify = Duktape_GetHeapptrProperty(data->ctx, -1, "checkServerIdentity");
- if (OnVerify == NULL) { return(1); }
+ if (OnVerify == NULL) { duk_pop_2(data->ctx); return(1); }
duk_push_heapptr(data->ctx, OnVerify); // [func]
duk_push_heapptr(data->ctx, data->object); // [func][this]
@@ -1141,10 +1148,6 @@ duk_ret_t ILibDuktape_TLS_connect(duk_context *ctx)
ILibAsyncSocket_SocketModule module = ILibCreateAsyncSocketModuleWithMemory(Duktape_GetChain(ctx), 4096, ILibDuktape_net_socket_OnData, ILibDuktape_net_socket_OnConnect, ILibDuktape_net_socket_OnDisconnect, ILibDuktape_net_socket_OnSendOK, sizeof(ILibDuktape_net_socket));
ILibDuktape_net_socket *data = (ILibDuktape_net_socket*)((ILibChain_Link*)module)->ExtraMemoryPtr;
- data->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
- SSL_CTX_set_options(data->ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1);
- SSL_CTX_set_verify(data->ssl_ctx, SSL_VERIFY_PEER, ILibDuktape_TLS_verify); /* Ask for authentication */
-
if (ILibDuktape_TLS_ctx2socket < 0)
{
ILibDuktape_TLS_ctx2socket = SSL_get_ex_new_index(0, "ILibDuktape_TLS index", NULL, NULL, NULL);
@@ -1152,6 +1155,28 @@ duk_ret_t ILibDuktape_TLS_connect(duk_context *ctx)
ILibDuktape_net_socket_PUSH(ctx, module); // [socket]
ILibDuktape_WriteID(ctx, "tls.socket");
+ duk_dup(ctx, 0); // [socket][options]
+ if (duk_has_prop_string(ctx, -1, "secureContext"))
+ {
+ duk_get_prop_string(ctx, -1, "secureContext"); // [socket][options][secureContext]
+ }
+ else
+ {
+ duk_push_this(ctx); // [socket][options][tls]
+ duk_get_prop_string(ctx, -1, "createSecureContext"); // [socket][options][tls][createSecureContext]
+ duk_swap_top(ctx, -2); // [socket][options][createSecureContext][this]
+ duk_dup(ctx, -3); // [socket][options][createSecureContext][this][options]
+ duk_call_method(ctx, 1); // [socket][options][secureContext]
+ }
+ if ((data->ssl_ctx = (SSL_CTX*)Duktape_GetPointerProperty(ctx, -1, ILibDuktape_SecureContext2SSLCTXPTR)) == NULL)
+ {
+ return(ILibDuktape_Error(ctx, "Invalid SecureContext Object"));
+ }
+ SSL_CTX_set_verify(data->ssl_ctx, SSL_VERIFY_PEER, ILibDuktape_TLS_verify); /* Ask for authentication */
+
+ duk_remove(ctx, -2); // [socket][secureContext]
+ duk_put_prop_string(ctx, -2, ILibDuktape_TLSSocket2SecureContext);
+
duk_dup(ctx, 0); // [socket][options]
duk_put_prop_string(ctx, -2, ILibDuktape_SOCKET2OPTIONS); // [socket]
ILibDuktape_EventEmitter_CreateEventEx(data->emitter, "secureConnect");
@@ -1197,6 +1222,7 @@ duk_ret_t ILibDuktape_TLS_connect(duk_context *ctx)
SSL_set_ex_data(data->ssl, ILibDuktape_TLS_ctx2socket, data);
SSL_set_tlsext_host_name(data->ssl, host);
}
+
return(1);
}
duk_ret_t ILibDuktape_TLS_secureContext_Finalizer(duk_context *ctx)
@@ -1211,6 +1237,7 @@ duk_ret_t ILibDuktape_TLS_secureContext_Finalizer(duk_context *ctx)
duk_ret_t ILibDuktape_TLS_createSecureContext(duk_context *ctx)
{
duk_push_object(ctx); // [secureContext]
+ ILibDuktape_WriteID(ctx, "tls.secureContext");
duk_push_fixed_buffer(ctx, sizeof(struct util_cert)); // [secureContext][cert]
struct util_cert *cert = (struct util_cert*)Duktape_GetBuffer(ctx, -1, NULL);
duk_put_prop_string(ctx, -2, ILibDuktape_SecureContext2CertBuffer); // [secureContext]
@@ -1218,14 +1245,69 @@ duk_ret_t ILibDuktape_TLS_createSecureContext(duk_context *ctx)
ILibDuktape_CreateFinalizer(ctx, ILibDuktape_TLS_secureContext_Finalizer);
duk_size_t secureProtocolLen;
- char *secureProtocol = (char*)Duktape_GetStringPropertyValueEx(ctx, 0, "secureProtocol", "SSLv23_server_method", &secureProtocolLen);
+ char *secureProtocol = (char*)Duktape_GetStringPropertyValueEx(ctx, 0, "secureProtocol", "SSLv23_method", &secureProtocolLen);
SSL_CTX *ssl_ctx = NULL;
- if (secureProtocolLen == 20 && strncmp(secureProtocol, "SSLv23_server_method", 20) == 0)
+ if (secureProtocolLen == 13 && strncmp(secureProtocol, "SSLv23_method", 13) == 0)
{
- ssl_ctx = SSL_CTX_new(SSLv23_server_method());
+ ssl_ctx = SSL_CTX_new(TLS_method());
SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1);
}
+ else if (secureProtocolLen == 20 && strncmp(secureProtocol, "SSLv23_client_method", 20) == 0)
+ {
+ ssl_ctx = SSL_CTX_new(TLS_method());
+ SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1);
+ }
+ else if (secureProtocolLen == 20 && strncmp(secureProtocol, "SSLv23_server_method", 20) == 0)
+ {
+ ssl_ctx = SSL_CTX_new(TLS_method());
+ SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1);
+ }
+ else if (secureProtocolLen == 12 && strncmp(secureProtocol, "TLSv1_method", 12) == 0)
+ {
+ ssl_ctx = SSL_CTX_new(TLS_method());
+ SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2);
+ }
+ else if (secureProtocolLen == 19 && strncmp(secureProtocol, "TLSv1_client_method", 19) == 0)
+ {
+ ssl_ctx = SSL_CTX_new(TLS_method());
+ SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2);
+ }
+ else if (secureProtocolLen == 19 && strncmp(secureProtocol, "TLSv1_server_method", 19) == 0)
+ {
+ ssl_ctx = SSL_CTX_new(TLS_method());
+ SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2);
+ }
+ else if (secureProtocolLen == 14 && strncmp(secureProtocol, "TLSv1_1_method", 14) == 0)
+ {
+ ssl_ctx = SSL_CTX_new(TLS_method());
+ SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_2);
+ }
+ else if (secureProtocolLen == 21 && strncmp(secureProtocol, "TLSv1_1_client_method", 21) == 0)
+ {
+ ssl_ctx = SSL_CTX_new(TLS_method());
+ SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_2);
+ }
+ else if (secureProtocolLen == 21 && strncmp(secureProtocol, "TLSv1_1_server_method", 21) == 0)
+ {
+ ssl_ctx = SSL_CTX_new(TLS_method());
+ SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_2);
+ }
+ else if (secureProtocolLen == 14 && strncmp(secureProtocol, "TLSv1_2_method", 14) == 0)
+ {
+ ssl_ctx = SSL_CTX_new(TLS_method());
+ SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
+ }
+ else if (secureProtocolLen == 21 && strncmp(secureProtocol, "TLSv1_2_client_method", 21) == 0)
+ {
+ ssl_ctx = SSL_CTX_new(TLS_method());
+ SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
+ }
+ else if (secureProtocolLen == 21 && strncmp(secureProtocol, "TLSv1_2_server_method", 21) == 0)
+ {
+ ssl_ctx = SSL_CTX_new(TLS_method());
+ SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
+ }
else if (secureProtocolLen == 11 && strncmp(secureProtocol, "DTLS_method", 11) == 0)
{
ssl_ctx = SSL_CTX_new(DTLS_method());
@@ -1266,11 +1348,31 @@ duk_ret_t ILibDuktape_TLS_generateCertificate(duk_context *ctx)
duk_push_fixed_buffer(ctx, len);
memcpy_s((void*)Duktape_GetBuffer(ctx, -1, NULL), len, data, len);
duk_push_buffer_object(ctx, -1, 0, len, DUK_BUFOBJ_NODEJS_BUFFER);
-
+ ILibDuktape_WriteID(ctx, "tls.pfxCertificate");
util_free(data);
util_freecert(&cert);
return 1;
}
+duk_ret_t ILibDuktape_TLS_loadpkcs7b(duk_context *ctx)
+{
+ duk_size_t len;
+ char *buffer = (char*)Duktape_GetBuffer(ctx, 0, &len);
+ int val = util_from_pkcs7b_string(buffer, (int)len, NULL, 0);
+ char *out;
+
+ if (val > 0)
+ {
+ duk_push_fixed_buffer(ctx, val);
+ out = Duktape_GetBuffer(ctx, -1, NULL);
+ duk_push_buffer_object(ctx, -1, 0, val, DUK_BUFOBJ_NODEJS_BUFFER);
+ util_from_pkcs7b_string(buffer, (int)len, out, val);
+ return(1);
+ }
+ else
+ {
+ return(ILibDuktape_Error(ctx, "Error reading pkcs7b data"));
+ }
+}
void ILibDuktape_tls_PUSH(duk_context *ctx, void *chain)
{
duk_push_object(ctx); // [TLS]
@@ -1278,6 +1380,7 @@ void ILibDuktape_tls_PUSH(duk_context *ctx, void *chain)
ILibDuktape_CreateInstanceMethod(ctx, "connect", ILibDuktape_TLS_connect, DUK_VARARGS);
ILibDuktape_CreateInstanceMethod(ctx, "createSecureContext", ILibDuktape_TLS_createSecureContext, 1);
ILibDuktape_CreateInstanceMethod(ctx, "generateCertificate", ILibDuktape_TLS_generateCertificate, 1);
+ ILibDuktape_CreateInstanceMethod(ctx, "loadpkcs7b", ILibDuktape_TLS_loadpkcs7b, 1);
}
#endif
diff --git a/microscript/ILibDuktape_net.h b/microscript/ILibDuktape_net.h
index 4049076..3a9e7bd 100644
--- a/microscript/ILibDuktape_net.h
+++ b/microscript/ILibDuktape_net.h
@@ -1,5 +1,5 @@
/*
-Copyright 2006 - 2017 Intel Corporation
+Copyright 2006 - 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/microscript/ILibduktape_EventEmitter.c b/microscript/ILibduktape_EventEmitter.c
index 6cc1b76..3bc65cb 100644
--- a/microscript/ILibduktape_EventEmitter.c
+++ b/microscript/ILibduktape_EventEmitter.c
@@ -1,3 +1,19 @@
+/*
+Copyright 2006 - 2018 Intel Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(_MINCORE)
#define _CRTDBG_MAP_ALLOC
#include
@@ -7,6 +23,7 @@
#include "ILibDuktape_EventEmitter.h"
#include "ILibDuktapeModSearch.h"
#include "ILibDuktape_Helpers.h"
+#include "ILibDuktape_Polyfills.h"
#define ILibDuktape_EventEmitter_MaxEventNameLen 255
#define ILibDuktape_EventEmitter_Data "\xFF_EventEmitter_Data"
@@ -127,39 +144,19 @@ void ILibDuktape_EventEmitter_FinalizerEx(ILibHashtable sender, void *Key1, char
duk_pop_2(data->ctx); // ...
}
}
-duk_ret_t ILibDuktape_EventEmitter_Finalizer(duk_context *ctx)
+
+int ILibDuktape_EventEmitter_HasListeners(ILibDuktape_EventEmitter *emitter, char *eventName)
{
- ILibDuktape_EventEmitter *data;
- duk_get_prop_string(ctx, 0, ILibDuktape_EventEmitter_Data);
- data = (ILibDuktape_EventEmitter*)Duktape_GetBuffer(ctx, -1, NULL);
-
- // Check to see if this is the process object going away
- if (ILibDuktape_GetProcessObject(ctx) == data->object)
+ int retVal = 0;
+ if (emitter->eventTable != NULL)
{
- // We need to dispatch the 'exit' event
- int exitCode = 0;
- duk_push_heapptr(data->ctx, data->object); // [process]
- if (duk_has_prop_string(data->ctx, -1, "\xFF_ExitCode"))
+ ILibLinkedList eventList = ILibHashtable_Get(emitter->eventTable, NULL, eventName, (int)strnlen_s(eventName, 255));
+ if (eventList != NULL)
{
- duk_get_prop_string(data->ctx, -1, "\xFF_ExitCode"); // [process][exitCode]
- exitCode = duk_get_int(data->ctx, -1);
- duk_pop(data->ctx); // [process]
+ retVal = ILibLinkedList_GetCount(eventList);
}
- duk_get_prop_string(data->ctx, -1, "emit"); // [process][emit]
- duk_swap_top(data->ctx, -2); // [emit][this]
- duk_push_string(data->ctx, "exit"); // [emit][this][eventName/exit]
- duk_push_int(data->ctx, exitCode); // [emit][this][eventName/exit][exitCode]
- duk_pcall_method(data->ctx, 2);
- duk_pop(data->ctx);
}
-
-
- // We need to clear the Native Dispatcher, while destroying the Hashtable
- ILibHashtable_DestroyEx(data->eventTable, ILibDuktape_EventEmitter_FinalizerEx, data);
-
- memset(data, 0, sizeof(ILibDuktape_EventEmitter));
-
- return 0;
+ return(retVal);
}
duk_ret_t ILibDuktape_EventEmitter_emit(duk_context *ctx)
{
@@ -170,25 +167,24 @@ duk_ret_t ILibDuktape_EventEmitter_emit(duk_context *ctx)
void *self;
int nargs = duk_get_top(ctx);
ILibDuktape_EventEmitter *data;
- void *node, *nextNode, *func, *dispatcher;
- int i, j, count;
- void **hptr;
+ void *node, *nextNode, *func;
+ int i, j;
void **emitList;
+ char *objid;
- duk_push_this(ctx);
+ duk_push_this(ctx); // [this]
+ objid = Duktape_GetStringPropertyValue(ctx, -1, ILibDuktape_OBJID, "unknown");
duk_get_prop_string(ctx, -1, ILibDuktape_EventEmitter_TempObject); // [this][tmp]
duk_get_prop_string(ctx, -1, ILibDuktape_EventEmitter_Data); // [this][tmp][data]
data = (ILibDuktape_EventEmitter*)Duktape_GetBuffer(ctx, -1, NULL);
duk_pop_2(ctx); // [this]
self = duk_get_heapptr(ctx, -1);
+ duk_pop(ctx); // ...
if (data->eventTable == NULL) { duk_push_false(ctx); return(1); } // This probably means the finalizer was already run on the eventEmitter
eventList = ILibHashtable_Get(data->eventTable, NULL, name, (int)nameLen);
- if (eventList == NULL) { return ILibDuktape_Error(ctx, "EventEmitter.emit(): Event '%s' not found", name); }
- dispatcher = ILibHashtable_Get(data->eventTable, ILibDuktape_EventEmitter_SetterFunc, name, (int)nameLen);
- if (dispatcher == NULL) { return ILibDuktape_Error(ctx, "EventEmitter.emit(): Internal Error with event '%s'", name); }
-
+ if (eventList == NULL) { return ILibDuktape_Error(ctx, "EventEmitter.emit(): Event '%s' not found on object '%s'", name, objid); }
// Copy the list, so we can enumerate with local memory, so the list can be manipulated while we are dispatching
#ifdef WIN32
@@ -213,22 +209,6 @@ duk_ret_t ILibDuktape_EventEmitter_emit(duk_context *ctx)
}
emitList[i] = NULL;
- // If no more listeners, we can set the hptr to NULL
- if (ILibLinkedList_GetCount(eventList) == 0)
- {
- duk_push_heapptr(ctx, dispatcher); // [dispatcher]
- duk_get_prop_string(ctx, -1, ILibDuktape_EventEmitter_HPTR_LIST); // [dispatcher][hptrList]
- count = (int)duk_get_length(ctx, -1);
- for (i = 0; i < count; ++i)
- {
- duk_get_prop_index(ctx, -1, i); // [dispatcher][hptrList][hptr]
- hptr = (void**)duk_get_pointer(ctx, -1);
- *hptr = NULL;
- duk_pop(ctx); // [dispatcher][hptrList]
- }
- duk_pop_2(ctx); // ...
- }
-
// Now that we have all the housekeeping stuff out of the way, we can actually dispatch our events
i = 0;
while ((func = emitList[i++]) != NULL)
@@ -241,13 +221,27 @@ duk_ret_t ILibDuktape_EventEmitter_emit(duk_context *ctx)
}
if (duk_pcall_method(ctx, nargs - 1) != 0)
{
- return(ILibDuktape_Error(ctx, "EventEmitter.emit(): Event dispatch for '%s' threw an exception: %s", name, duk_safe_to_string(ctx, -1)));
+ return(ILibDuktape_Error(ctx, "EventEmitter.emit(): Event dispatch for '%s' on '%s' threw an exception: %s", name, objid, duk_safe_to_string(ctx, -1)));
}
duk_pop(ctx); // ...
}
duk_push_boolean(ctx, i > 1 ? 1 : 0);
return(1);
}
+int ILibDuktape_EventEmitter_PrependOnce(duk_context *ctx, duk_idx_t i, char *eventName, duk_c_function func)
+{
+ int retVal = 1;
+
+ duk_dup(ctx, i); // [this]
+ duk_get_prop_string(ctx, -1, "prependOnceListener"); // [this][prependOnce]
+ duk_swap_top(ctx, -2); // [prependOnce][this]
+ duk_push_string(ctx, eventName); // [prependOnce][this][eventName]
+ duk_push_c_function(ctx, func, DUK_VARARGS); // [prependOnce][this][eventName][func]
+ if (duk_pcall_method(ctx, 2) != 0) { retVal = 0; }
+ duk_pop(ctx); // ...
+ return(retVal);
+}
+
int ILibDuktape_EventEmitter_AddOnce(ILibDuktape_EventEmitter *emitter, char *eventName, void *heapptr)
{
int retVal = 1;
@@ -315,8 +309,9 @@ duk_ret_t ILibDuktape_EventEmitter_on(duk_context *ctx)
void *callback = duk_require_heapptr(ctx, 1);
ILibDuktape_EventEmitter *data;
int once;
- void *eventList, *node, *dispatcher, **hptr;
- int i, count, prepend;
+ void *eventList, *node;
+ int prepend;
+ ILibDuktape_EventEmitter_HookHandler hookHandler = NULL;
duk_push_current_function(ctx);
once = Duktape_GetIntPropertyValue(ctx, -1, "once", 0);
@@ -333,8 +328,7 @@ duk_ret_t ILibDuktape_EventEmitter_on(duk_context *ctx)
{
return(ILibDuktape_Error(ctx, "EventEmitter.on(): Event '%s' not found", propName));
}
- dispatcher = ILibHashtable_Get(data->eventTable, ILibDuktape_EventEmitter_SetterFunc, propName, (int)propNameLen);
- if (dispatcher == NULL) { return(ILibDuktape_Error(ctx, "EventEmitter.on(): Internal error with Event '%s'", propName)); }
+ hookHandler = ILibHashtable_Get(data->eventTable, ILibDuktape_EventEmitter_Hook, propName, (int)propNameLen);
node = prepend ? ILibLinkedList_AddHead(eventList, callback) : ILibLinkedList_AddTail(eventList, callback);
((int*)ILibLinkedList_GetExtendedMemory(node))[0] = once;
@@ -344,17 +338,7 @@ duk_ret_t ILibDuktape_EventEmitter_on(duk_context *ctx)
duk_push_heapptr(ctx, callback);
duk_put_prop_string(ctx, -2, Duktape_GetStashKey(callback)); // Save the callback to the tmp object, so it won't get GC'ed
- duk_push_heapptr(ctx, dispatcher); // [dispatcher]
- duk_get_prop_string(ctx, -1, ILibDuktape_EventEmitter_HPTR_LIST); // [dispatcher][hptrList]
- count = (int)duk_get_length(ctx, -1);
- for (i = 0; i < count; ++i)
- {
- duk_get_prop_index(ctx, -1, i); // [dispatcher][hptrList][hptr]
- hptr = (void**)duk_get_pointer(ctx, -1);
- *hptr = dispatcher;
- duk_pop(ctx); // [dispatcher][hptrList]
- }
-
+ if (hookHandler != NULL) { hookHandler(data, propName, callback); }
return 0;
}
ILibDuktape_EventEmitter* ILibDuktape_EventEmitter_GetEmitter_fromThis(duk_context *ctx)
@@ -406,36 +390,69 @@ duk_ret_t ILibDuktape_EventEmitter_removeAllListeners(duk_context *ctx)
duk_size_t eventNameLen;
char *eventName = Duktape_GetBuffer(ctx, 0, &eventNameLen);
ILibDuktape_EventEmitter *emitter = ILibDuktape_EventEmitter_GetEmitter_fromThis(ctx);
- void *eventList, *dispatcher;
- int count, i;
- void **hptr;
+ void *eventList;
if (emitter != NULL)
{
eventList = ILibHashtable_Get(emitter->eventTable, NULL, eventName, (int)eventNameLen);
if (eventList == NULL) { return(ILibDuktape_Error(ctx, "EventEmitter.removeAllListeners(): Event '%s' not found", eventName)); }
- dispatcher = ILibHashtable_Get(emitter->eventTable, ILibDuktape_EventEmitter_SetterFunc, eventName, (int)eventNameLen);
- if (dispatcher == NULL) { return(ILibDuktape_Error(ctx, "EventEmitter.removeAllListeners(): Internal error with Event '%s'", eventName)); }
-
-
- // NULL was passed, we'll need to clear all listeners.
- // Start by setting the Native Dispatcher to NULL, so it appears there are no subscribers
- duk_push_heapptr(ctx, dispatcher); // [dispatcher]
- duk_get_prop_string(ctx, -1, ILibDuktape_EventEmitter_HPTR_LIST); // [dispatcher][hptrList]
- count = (int)duk_get_length(ctx, -1);
- for (i = 0; i < count; ++i)
- {
- duk_get_prop_index(ctx, -1, i); // [dispatcher][hptrList][hptr]
- hptr = (void**)duk_get_pointer(ctx, -1);
- *hptr = NULL;
- duk_pop(ctx); // [dispatcher][hptrList]
- }
ILibLinkedList_Clear(eventList);
emitter->totalListeners[0] = 0;
}
return(0);
}
+
+void ILibDuktape_EventEmitter_EmbeddedFinalizer2(ILibHashtable sender, void *Key1, char* Key2, int Key2Len, void *Data, void *user)
+{
+ if (Key1 == NULL)
+ {
+ char *name = (char*)ILibMemory_AllocateA(Key2Len + 1);
+ name[Key2Len] = 0;
+ memcpy_s(name, Key2Len + 1, Key2, Key2Len);
+ printf("%s ", name);
+ }
+}
+duk_ret_t ILibDuktape_EventEmitter_EmbeddedFinalizer(duk_context *ctx)
+{
+ ILibDuktape_EventEmitter_SetupEmit(ctx, duk_get_heapptr(ctx, 0), "~"); // [emit][this][~]
+ duk_dup(ctx, 0); // [emit][this][~][self]
+ if (g_displayFinalizerMessages)
+ {
+ printf("+-+- Finalizer Event for: %s [%p] -+-+\n", Duktape_GetStringPropertyValue(ctx, -1, ILibDuktape_OBJID, "UNKNOWN"), duk_get_heapptr(ctx, -1));
+ if (strcmp(Duktape_GetStringPropertyValue(ctx, -1, ILibDuktape_OBJID, "UNKNOWN"), "UNKNOWN") == 0)
+ {
+ ILibDuktape_EventEmitter *emitter = ILibDuktape_EventEmitter_GetEmitter(ctx, -1);
+ if (emitter != NULL)
+ {
+ printf("UNKNOWN: Listeners=%d\n", ILibDuktape_EventEmitter_HasListeners(emitter, "~"));
+
+ duk_enum(ctx, -1, DUK_ENUM_OWN_PROPERTIES_ONLY); // [enumerator]
+ while (duk_next(ctx, -1, 1))
+ {
+ printf("Key: %s, Val: %s\n", duk_get_string(ctx, -2), duk_get_string(ctx, -1));// [enumerator][key][val]
+ duk_pop_2(ctx); // [enumerator]
+ }
+ duk_pop(ctx); // ...
+ printf("Event Names: ");
+ if (emitter->eventTable != NULL) { ILibHashtable_Enumerate(emitter->eventTable, ILibDuktape_EventEmitter_EmbeddedFinalizer2, NULL); }
+ printf("\n");
+ }
+ }
+ }
+ if (duk_pcall_method(ctx, 2) != 0)
+ {
+ ILibDuktape_Process_UncaughtExceptionEx(ctx, "Error in Finalizer: [Invalid C function means you forgot to return 0] ");
+ }
+
+ ILibDuktape_EventEmitter *data = ILibDuktape_EventEmitter_GetEmitter(ctx, 0);
+ if (data == NULL) { return(ILibDuktape_Error(ctx, "Internal Error")); } // This is deadcode, will never occur, but is here because Klockwork thinks this could happen
+
+ // We need to clear the Native Dispatcher, while destroying the Hashtable
+ ILibHashtable_DestroyEx(data->eventTable, ILibDuktape_EventEmitter_FinalizerEx, data);
+ memset(data, 0, sizeof(ILibDuktape_EventEmitter));
+ return(0);
+}
ILibDuktape_EventEmitter* ILibDuktape_EventEmitter_Create(duk_context *ctx)
{
ILibDuktape_EventEmitter *retVal;
@@ -456,10 +473,8 @@ ILibDuktape_EventEmitter* ILibDuktape_EventEmitter_Create(duk_context *ctx)
retVal->tmpObject = duk_get_heapptr(ctx, -2);
duk_put_prop_string(ctx, -2, ILibDuktape_EventEmitter_Data); // [emitterTmp]
- ILibDuktape_CreateFinalizer(ctx, ILibDuktape_EventEmitter_Finalizer);
duk_put_prop_string(ctx, -2, ILibDuktape_EventEmitter_TempObject); // [...parent...]
-
retVal->ctx = ctx;
retVal->object = duk_get_heapptr(ctx, -1);
retVal->eventTable = ILibHashtable_Create();
@@ -489,6 +504,10 @@ ILibDuktape_EventEmitter* ILibDuktape_EventEmitter_Create(duk_context *ctx)
}
duk_pop(ctx);
+ ILibDuktape_EventEmitter_CreateEventEx(retVal, "~");
+ duk_push_c_function(ctx, ILibDuktape_EventEmitter_EmbeddedFinalizer, 1);
+ duk_set_finalizer(ctx, -2);
+
return retVal;
}
@@ -505,15 +524,10 @@ duk_ret_t ILibDuktape_EventEmitter_SetEvent(duk_context *ctx)
duk_size_t propNameLen;
ILibDuktape_EventEmitter *data;
ILibLinkedList eventList = NULL;
- void **hptr;
- void *dispatcher;
- int i, count;
duk_push_current_function(ctx); // [func]
- duk_get_prop_string(ctx, -1, "name"); // [func][name]
+ duk_get_prop_string(ctx, -1, "eventName"); // [func][name]
propName = (char*)duk_get_lstring(ctx, -1, &propNameLen);
- duk_get_prop_string(ctx, -2, ILibDuktape_EventEmitter_DispatcherFunc); // [func][name][dispatcher]
- dispatcher = duk_get_heapptr(ctx, -1);
duk_push_this(ctx); // [obj]
duk_get_prop_string(ctx, -1, ILibDuktape_EventEmitter_TempObject); // [this][tmp]
@@ -526,142 +540,20 @@ duk_ret_t ILibDuktape_EventEmitter_SetEvent(duk_context *ctx)
if (duk_is_null_or_undefined(ctx, 0))
{
// NULL was passed, we'll need to clear all listeners.
- // Start by setting the Native Dispatcher to NULL, so it appears there are no subscribers
- duk_push_heapptr(ctx, dispatcher); // [dispatcher]
- duk_get_prop_string(ctx, -1, ILibDuktape_EventEmitter_HPTR_LIST); // [dispatcher][hptrList]
- count = (int)duk_get_length(ctx, -1);
- for (i = 0; i < count; ++i)
- {
- duk_get_prop_index(ctx, -1, i); // [dispatcher][hptrList][hptr]
- hptr = (void**)duk_get_pointer(ctx, -1);
- *hptr = NULL;
- duk_pop(ctx); // [dispatcher][hptrList]
- }
-
- ILibLinkedList_Clear(eventList);
+ duk_push_this(ctx); // [obj]
+ duk_get_prop_string(ctx, -1, "removeAllListeners"); // [obj][removeAll]
+ duk_swap_top(ctx, -2); // [removeAll][this]
+ duk_push_string(ctx, propName); // [removeAll][this][name]
+ duk_call_method(ctx, 1); duk_pop(ctx);
}
else
{
- void *callback = duk_require_heapptr(ctx, 0);
- ILibDuktape_EventEmitter_HookHandler hookHandler = ILibHashtable_Get(data->eventTable, ILibDuktape_EventEmitter_Hook, propName, (int)propNameLen);
-
- ILibLinkedList_AddTail(eventList, callback);
- duk_push_heapptr(ctx, data->tmpObject);
- duk_push_heapptr(ctx, callback);
- duk_put_prop_string(ctx, -2, Duktape_GetStashKey(callback)); // Save callback to tmpObject so it won't get GC'ed
-
- duk_push_heapptr(ctx, dispatcher); // [dispatcher]
- duk_get_prop_string(ctx, -1, ILibDuktape_EventEmitter_HPTR_LIST); // [dispatcher][hptrList]
- count = (int)duk_get_length(ctx, -1);
- for (i = 0; i < count; ++i)
- {
- duk_get_prop_index(ctx, -1, i); // [dispatcher][hptrList][hptr]
- hptr = (void**)duk_get_pointer(ctx, -1);
- *hptr = dispatcher; // Set this, so from Native, it looks like there is a subscriber.
- duk_pop(ctx); // [dispatcher][hptrList]
- }
-
- if (hookHandler != NULL)
- {
- hookHandler(data, propName, callback);
- }
+ ILibDuktape_EventEmitter_AddOn(data, propName, duk_get_heapptr(ctx, 0));
}
return 0;
}
-duk_ret_t ILibDuktape_EventEmitter_Dispatcher(duk_context *ctx)
-{
- int nargs = duk_get_top(ctx);
- void *self;
- int i;
- char *name;
- duk_push_current_function(ctx); // [func]
- duk_get_prop_string(ctx, -1, "name"); // [func][name]
- name = (char*)duk_get_string(ctx, -1);
- duk_get_prop_string(ctx, -2, "this"); // [func][name][this]
- self = duk_get_heapptr(ctx, -1);
- duk_get_prop_string(ctx, -1, "emit"); // [func][name][this][emitter]
-
- //-------------------------------------------------------------------------------------------------
-
- duk_push_heapptr(ctx, self); // [emitter][this]
- duk_push_string(ctx, name); // [emitter][this][name]
- for (i = 0; i < nargs; ++i)
- {
- duk_dup(ctx, i); // [emitter][this][name][...args...]
- }
- duk_call_method(ctx, nargs + 1); // Exception will bubble up.
-
- return 0;
-}
-duk_ret_t ILibDuktape_EventEmitter_NativeDispatch(duk_context *ctx)
-{
- int nargs = duk_get_top(ctx);
- char *name;
- ILibDuktape_EventEmitter_Handler handler;
- void *args;
- int i = 0;
-
- duk_push_current_function(ctx); // [func]
- duk_get_prop_string(ctx, -1, "name"); // [func][name]
- name = (char*)duk_get_string(ctx, -1);
- duk_get_prop_string(ctx, -2, "handler"); // [func][name][handler]
- handler = (ILibDuktape_EventEmitter_Handler)duk_get_pointer(ctx, -1);
-
- duk_push_array(ctx); // [func][name][handler][args]
- args = duk_get_heapptr(ctx, -1);
-
- for (i = 0; i < nargs; ++i)
- {
- duk_dup(ctx, i); // [func][name][handler][args][...arg...]
- duk_put_prop_index(ctx, -2, i); // [func][name][handler][args]
- }
-
- duk_push_this(ctx);
- handler(ctx, duk_get_heapptr(ctx, -1), name, args);
-
- return 0;
-}
-int ILibDuktape_EventEmitter_AddSink(ILibDuktape_EventEmitter *emitter, char *eventName, ILibDuktape_EventEmitter_Handler handler)
-{
- ILibLinkedList eventList;
- void *func;
-
- duk_push_heapptr(emitter->ctx, emitter->tmpObject); // [tmp]
- duk_push_c_function(emitter->ctx, ILibDuktape_EventEmitter_NativeDispatch, DUK_VARARGS); // [tmp][dispatch]
- duk_push_string(emitter->ctx, eventName); // [tmp][dispatch][name]
- duk_put_prop_string(emitter->ctx, -2, "name"); // [tmp][dispatch]
- duk_push_pointer(emitter->ctx, handler); // [tmp][dispatch][nativePtr]
- duk_put_prop_string(emitter->ctx, -2, "handler"); // [tmp][dispatch]
- func = duk_get_heapptr(emitter->ctx, -1);
- eventList = ILibHashtable_Get(emitter->eventTable, NULL, eventName, (int)strnlen_s(eventName, ILibDuktape_EventEmitter_MaxEventNameLen));
- if (eventList == NULL) { return 1; }
-
- ((int*)ILibLinkedList_GetExtendedMemory(ILibLinkedList_AddTail(eventList, func)))[0] = 2;
- emitter->totalListeners[0]++;
-
- duk_put_prop_string(emitter->ctx, -2, Duktape_GetStashKey(func)); // [tmp]
- duk_pop(emitter->ctx); // ...
-
- return 0;
-}
-void ILibDuktape_EventEmitter_RemoveAllEx(ILibHashtable sender, void *Key1, char* Key2, int Key2Len, void *Data, void *user)
-{
- ILibDuktape_EventEmitter *data = (ILibDuktape_EventEmitter*)user;
- if (Key1 == ILibDuktape_EventEmitter_SetterFunc)
- {
- // If this is not NULL, this is the JavaScript Setter Func
- memcpy_s(ILibScratchPad, sizeof(ILibScratchPad), Key2, Key2Len);
- ILibScratchPad[Key2Len] = 0;
- duk_push_heapptr(data->ctx, Data); // [Setter]
- duk_del_prop_string(data->ctx, -1, ILibDuktape_EventEmitter_HPTR_LIST);
- duk_push_array(data->ctx); // [Setter][list]
- duk_put_prop_string(data->ctx, -2, ILibDuktape_EventEmitter_HPTR_LIST); // [Setter]
-
- duk_pop(data->ctx); // ...
- }
-}
void ILibDuktape_EventEmitter_RemoveAllListeners(ILibDuktape_EventEmitter *emitter, char *eventName)
{
duk_push_heapptr(emitter->ctx, emitter->object); // [this]
@@ -671,125 +563,45 @@ void ILibDuktape_EventEmitter_RemoveAllListeners(ILibDuktape_EventEmitter *emitt
if (duk_pcall_method(emitter->ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(emitter->ctx, "EventEmitter.removeAllListeners(): "); }
duk_pop(emitter->ctx); // ...
}
-void ILibDuktape_EventEmitter_RemoveAll(ILibDuktape_EventEmitter *emitter)
+void ILibDuktape_EventEmitter_GetEventCountSink(ILibHashtable sender, void *Key1, char* Key2, int Key2Len, void *Data, void *user)
{
- if (emitter->eventTable != NULL) { ILibHashtable_Enumerate(emitter->eventTable, ILibDuktape_EventEmitter_RemoveAllEx, emitter); }
-}
-void ILibDuktape_EventEmitter_RemoveEventHeapptr(ILibDuktape_EventEmitter *emitter, char *eventName, void **heapptr)
-{
- int i, count;
- void *dispatcher = NULL;
- int eventNameLen = (int)strnlen_s(eventName, ILibDuktape_EventEmitter_MaxEventNameLen);
- if ((dispatcher = ILibHashtable_Get(emitter->eventTable, ILibDuktape_EventEmitter_SetterFunc, eventName, eventNameLen)) != NULL)
+ int *count = (int*)user;
+ if (Key1 == NULL)
{
- // This event already exists... Let's hook up the hptr to the existing dispatcher
- duk_push_heapptr(emitter->ctx, dispatcher); // [dispatcher]
- if (heapptr != NULL)
- {
- duk_get_prop_string(emitter->ctx, -1, ILibDuktape_EventEmitter_HPTR_LIST); // [dispatcher][hptrList]
- count = (int)duk_get_length(emitter->ctx, -1);
- for (i = 0; i < count; ++i)
- {
- duk_get_prop_index(emitter->ctx, -1, i); // [dispatcher][hptrList][hptr]
- if (duk_get_pointer(emitter->ctx, -1) == heapptr)
- {
- duk_pop(emitter->ctx); // [dispatcher][hptrList]
- duk_del_prop_index(emitter->ctx, -1, i);
- break;
- }
- duk_pop(emitter->ctx); // [dispatcher][hptrList]
- }
- duk_pop(emitter->ctx); // [dispatcher]
- }
- else
- {
- duk_del_prop_string(emitter->ctx, -1, ILibDuktape_EventEmitter_HPTR_LIST); // [dispatcher]
- duk_push_array(emitter->ctx); // [dispatcher][hptrList]
- duk_put_prop_string(emitter->ctx, -2, ILibDuktape_EventEmitter_HPTR_LIST); // [dispatcher]
- }
- duk_pop(emitter->ctx); // ...
+ ++(*count);
}
}
-int ILibDuktape_EventEmitter_AddEventHeapptr(ILibDuktape_EventEmitter *emitter, char *eventName, void **heapptr)
+int ILibDuktape_EventEmitter_GetEventCount(ILibDuktape_EventEmitter *emitter)
{
- ILibLinkedList eventList = NULL;
- void *dispatcher = NULL;
- int eventNameLen = (int)strnlen_s(eventName, ILibDuktape_EventEmitter_MaxEventNameLen);
- if ((dispatcher = ILibHashtable_Get(emitter->eventTable, ILibDuktape_EventEmitter_SetterFunc, eventName, eventNameLen)) != NULL)
- {
- // This event already exists... Let's hook up the hptr to the existing dispatcher
- duk_push_heapptr(emitter->ctx, dispatcher); // [dispatcher]
- duk_get_prop_string(emitter->ctx, -1, ILibDuktape_EventEmitter_HPTR_LIST); // [dispatcher][hptrList]
- duk_push_pointer(emitter->ctx, heapptr); // [dispatcher][hptrList][hptr]
- duk_put_prop_index(emitter->ctx, -2, (duk_uarridx_t)duk_get_length(emitter->ctx, -2)); // [dispatcher][hptrList]
- duk_pop_2(emitter->ctx); // ...
+ int retVal = 0;
+ if (emitter->eventTable != NULL) { ILibHashtable_Enumerate(emitter->eventTable, ILibDuktape_EventEmitter_GetEventCountSink, &retVal); }
+ return(retVal);
+}
- // Now lets check if there was already a subscriber
- if ((eventList = ILibHashtable_Get(emitter->eventTable, NULL, eventName, eventNameLen)) != NULL && ILibLinkedList_GetCount(eventList) > 0)
- {
- *heapptr = dispatcher;
- }
- return 0;
- }
- return 1;
-}
void ILibDuktape_EventEmitter_CreateEventEx(ILibDuktape_EventEmitter *emitter, char *eventName)
{
- void **heapptr;
- duk_push_heapptr(emitter->ctx, emitter->tmpObject); // [emitter]
- duk_push_object(emitter->ctx); // [emitter][tmp]
- duk_push_fixed_buffer(emitter->ctx, sizeof(void*)); // [emitter][tmp][buffer]
- heapptr = (void**)Duktape_GetBuffer(emitter->ctx, -1, NULL);
- memset((void*)heapptr, 0, sizeof(void*));
- duk_put_prop_string(emitter->ctx, -2, "\xFF_buffer"); // [emitter][tmp]
- duk_put_prop_string(emitter->ctx, -2, Duktape_GetStashKey(duk_get_heapptr(emitter->ctx, -1))); // [emitter]
- duk_pop(emitter->ctx); // ...
-
- ILibDuktape_EventEmitter_CreateEvent(emitter, eventName, heapptr);
-}
-void ILibDuktape_EventEmitter_CreateEvent(ILibDuktape_EventEmitter *emitter, char *eventName, void **hptr)
-{
- void *dispatcher = NULL;
int eventNameLen = (int)strnlen_s(eventName, ILibDuktape_EventEmitter_MaxEventNameLen);
- if ((dispatcher = ILibHashtable_Get(emitter->eventTable, ILibDuktape_EventEmitter_SetterFunc, eventName, eventNameLen)) != NULL)
+
+ if (ILibHashtable_Get(emitter->eventTable, NULL, eventName, eventNameLen) != NULL)
{
- // This event already exists... Let's hook up the hptr to the existing dispatcher
- duk_push_heapptr(emitter->ctx, dispatcher); // [dispatcher]
- duk_get_prop_string(emitter->ctx, -1, ILibDuktape_EventEmitter_HPTR_LIST); // [dispatcher][hptrList]
- duk_push_pointer(emitter->ctx, hptr); // [dispatcher][hptrList][hptr]
- duk_put_prop_index(emitter->ctx, -2, (duk_uarridx_t)duk_get_length(emitter->ctx, -2)); // [dispatcher][hptrList]
- duk_pop_2(emitter->ctx); // ...
+ // This event already exists...
return;
}
-
duk_push_heapptr(emitter->ctx, emitter->object); // [obj]
// Create the Property Setter
duk_push_string(emitter->ctx, eventName); // [obj][prop]
duk_push_c_function(emitter->ctx, ILibDuktape_EventEmitter_SetEvent, 1); // [obj][prop][setFunc]
duk_push_string(emitter->ctx, eventName); // [obj][prop][setFunc][name]
- duk_put_prop_string(emitter->ctx, -2, "name"); // [obj][prop][setFunc]
-
- // Set some custom properties into the setter func, so we can access it later
- duk_push_c_function(emitter->ctx, ILibDuktape_EventEmitter_Dispatcher, DUK_VARARGS); // [obj][prop][setFunc][dispatcher]
- dispatcher = duk_get_heapptr(emitter->ctx, -1);
- duk_push_heapptr(emitter->ctx, emitter->object); // [obj][prop][setFunc][dispatcher][this]
- duk_put_prop_string(emitter->ctx, -2, "this"); // [obj][prop][setFunc][dispatcher]
- duk_push_string(emitter->ctx, eventName); // [obj][prop][setFunc][dispatcher][name]
- duk_put_prop_string(emitter->ctx, -2, "name"); // [obj][prop][setFunc][dispatcher]
- duk_push_array(emitter->ctx); // [obj][prop][setFunc][dispatcher][hptrList]
- duk_push_pointer(emitter->ctx, hptr); // [obj][prop][setFunc][dispatcher][hptrList][hptr]
- duk_put_prop_index(emitter->ctx, -2, 0); // [obj][prop][setFunc][dispatcher][hptrList]
- duk_put_prop_string(emitter->ctx, -2, ILibDuktape_EventEmitter_HPTR_LIST); // [obj][prop][setFunc][dispatcher]
- duk_put_prop_string(emitter->ctx, -2, ILibDuktape_EventEmitter_DispatcherFunc); // [obj][prop][setFunc]
+ duk_put_prop_string(emitter->ctx, -2, "eventName"); // [obj][prop][setFunc]
duk_def_prop(emitter->ctx, -3, DUK_DEFPROP_FORCE | DUK_DEFPROP_HAVE_SETTER); // [obj]
duk_pop(emitter->ctx); // ...
ILibHashtable_Put(emitter->eventTable, NULL, eventName, eventNameLen, ILibLinkedList_CreateEx(sizeof(int)));
- ILibHashtable_Put(emitter->eventTable, ILibDuktape_EventEmitter_SetterFunc, eventName, eventNameLen, dispatcher);
}
+
void *ILibDuktape_EventEmitter_GetDispatcher(ILibDuktape_EventEmitter *emitter, char *eventName)
{
return ILibHashtable_Get(emitter->eventTable, ILibDuktape_EventEmitter_SetterFunc, eventName, (int)strnlen_s(eventName, ILibDuktape_EventEmitter_MaxEventNameLen));
@@ -798,16 +610,13 @@ duk_ret_t ILibDuktape_EventEmitter_Inherits_createEvent(duk_context *ctx)
{
char *name = (char*)duk_require_string(ctx, 0);
ILibDuktape_EventEmitter *emitter;
- void **hptr;
+
duk_push_this(ctx); // [emitterUtils]
duk_get_prop_string(ctx, -1, "emitter"); // [emitterUtils][ptr]
emitter = (ILibDuktape_EventEmitter*)duk_get_pointer(ctx, -1);
duk_pop(ctx); // [emitterUtils]
- duk_push_fixed_buffer(ctx, sizeof(void*)); // [emitterUtils][buffer]
- hptr = (void**)Duktape_GetBuffer(ctx, -1, NULL);
- duk_put_prop_string(ctx, -2, name); // [emitterUtils]
- ILibDuktape_EventEmitter_CreateEvent(emitter, name, hptr);
+ ILibDuktape_EventEmitter_CreateEventEx(emitter, name);
return 0;
}
duk_ret_t ILibDuktape_EventEmitter_Inherits_addMethod(duk_context *ctx)
@@ -878,8 +687,22 @@ duk_ret_t ILibDuktape_EventEmitter_ForwardEvent_Sink(duk_context *ctx)
if (duk_pcall_method(ctx, 1 + nargs) != 0) { return(ILibDuktape_Error(ctx, "EventEmitter.ForwardEvent() [%s]: %s", name, duk_safe_to_string(ctx, -1))); }
return(0);
}
+
+duk_ret_t ILibDuktape_EventEmitter_ForwardEvent_Finalizer(duk_context *ctx)
+{
+ duk_push_current_function(ctx); // [func]
+ duk_get_prop_string(ctx, -1, "fptr"); // [func][fptr]
+ duk_get_prop_string(ctx, -1, "targetObject"); // [func][fptr][target]
+ duk_del_prop_string(ctx, -2, "targetObject");
+ if (g_displayFinalizerMessages) { printf("EventEmitter.Forwarder[%s]: Deleted reference to [%s] RC=%d\n", Duktape_GetStringPropertyValue(ctx, -3, "targetName", "UNKNOWN"), Duktape_GetStringPropertyValue(ctx, -1, ILibDuktape_OBJID, "UNKNOWN"), ILibDuktape_GetReferenceCount(ctx, -1) - 1); }
+ duk_pop_n(ctx, 3);
+
+ if (g_displayFinalizerMessages) { duk_eval_string(ctx, "_debugGC();"); duk_pop(ctx); }
+ return(0);
+}
void ILibDuktape_EventEmitter_ForwardEvent(duk_context *ctx, duk_idx_t eventSourceIndex, char *sourceEventName, duk_idx_t eventTargetIndex, char *targetEventName)
{
+ void *fptr;
void *target;
duk_dup(ctx, eventTargetIndex); // [targetObject]
target = duk_get_heapptr(ctx, -1);
@@ -889,12 +712,26 @@ void ILibDuktape_EventEmitter_ForwardEvent(duk_context *ctx, duk_idx_t eventSour
duk_swap_top(ctx, -2); // [on][this]
duk_push_string(ctx, sourceEventName); // [on][this][name]
duk_push_c_function(ctx, ILibDuktape_EventEmitter_ForwardEvent_Sink, DUK_VARARGS); // [on][this][name][sink]
+ fptr = duk_get_heapptr(ctx, -1);
duk_push_heapptr(ctx, target); // [on][this][name][sink][targetObject]
duk_put_prop_string(ctx, -2, "targetObject"); // [on][this][name][sink]
duk_push_string(ctx, targetEventName); // [on][this][name][sink][targetName]
duk_put_prop_string(ctx, -2, "targetName"); // [on][this][name][sink]
if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "EventEmitter_ForwardEvent(): "); }
duk_pop(ctx); // ...
+
+ duk_dup(ctx, eventSourceIndex); // [sourceObject]
+ duk_get_prop_string(ctx, -1, "prependOnceListener"); // [sourceObject][prependOnce]
+ duk_swap_top(ctx, -2); // [prependOnce][this]
+ duk_push_string(ctx, "~"); // [prependOnce][this]['~']
+ duk_push_c_function(ctx, ILibDuktape_EventEmitter_ForwardEvent_Finalizer, DUK_VARARGS); // [prependOnce][this]['~'][func]
+ duk_push_heapptr(ctx, fptr); // [prependOnce][this]['~'][func][fptr]
+ duk_put_prop_string(ctx, -2, "fptr"); // [prependOnce][this]['~'][func]
+ duk_push_string(ctx, targetEventName); // [prependOnce][this]['~'][func][name]
+ duk_put_prop_string(ctx, -2, "targetName"); // [prependOnce][this]['~'][func]
+
+ if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "EventEmitter_ForwardEvent_SetFinalizer(): "); }
+ duk_pop(ctx); // ...
}
int ILibDuktape_EventEmitter_AddOnEx(duk_context *ctx, duk_idx_t idx, char *eventName, duk_c_function func)
{
diff --git a/microscript/duk_config.h b/microscript/duk_config.h
index c809fdd..3f217ef 100644
--- a/microscript/duk_config.h
+++ b/microscript/duk_config.h
@@ -1,16 +1,18 @@
/*
* duk_config.h configuration header generated by genconfig.py.
*
- * Git commit: 0a70d7e4c5227c84e3fed5209828973117d02849
- * Git describe: v1.8.0
- * Git branch: v1.8-maintenance
+ * Git commit: a459cf3c9bd1779fc01b435d69302b742675a08f
+ * Git describe: v2.2.0
+ * Git branch: master
*
* Supported platforms:
* - Mac OSX, iPhone, Darwin
+ * - Orbis
* - OpenBSD
* - Generic BSD
* - Atari ST TOS
* - AmigaOS
+ * - Durango (XboxOne)
* - Windows
* - Flashplayer (Crossbridge)
* - QNX
@@ -18,6 +20,8 @@
* - Emscripten
* - Linux
* - Solaris
+ * - AIX
+ * - HPUX
* - Generic POSIX
* - Cygwin
* - Generic UNIX
@@ -60,20 +64,24 @@
*/
/* DLL build detection */
-#if defined(DUK_OPT_DLL_BUILD)
-#define DUK_F_DLL_BUILD
-#elif defined(DUK_OPT_NO_DLL_BUILD)
-#undef DUK_F_DLL_BUILD
-#else
/* not configured for DLL build */
#undef DUK_F_DLL_BUILD
-#endif
/* Apple OSX, iOS */
#if defined(__APPLE__)
#define DUK_F_APPLE
#endif
+/* FreeBSD */
+#if defined(__FreeBSD__) || defined(__FreeBSD)
+#define DUK_F_FREEBSD
+#endif
+
+/* Orbis (PS4) variant */
+#if defined(DUK_F_FREEBSD) && defined(__ORBIS__)
+#define DUK_F_ORBIS
+#endif
+
/* OpenBSD */
#if defined(__OpenBSD__) || defined(__OpenBSD)
#define DUK_F_OPENBSD
@@ -84,11 +92,6 @@
#define DUK_F_NETBSD
#endif
-/* FreeBSD */
-#if defined(__FreeBSD__) || defined(__FreeBSD)
-#define DUK_F_FREEBSD
-#endif
-
/* BSD variant */
#if defined(DUK_F_FREEBSD) || defined(DUK_F_NETBSD) || defined(DUK_F_OPENBSD) || \
defined(__bsdi__) || defined(__DragonFly__)
@@ -126,6 +129,11 @@
#endif
#endif
+/* Durango (Xbox One) */
+#if defined(_DURANGO) || defined(_XBOX_ONE)
+#define DUK_F_DURANGO
+#endif
+
/* Windows, both 32-bit and 64-bit */
#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || \
defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__)
@@ -170,6 +178,28 @@
/* illumos / Solaris */
#if defined(__sun) && defined(__SVR4)
#define DUK_F_SUN
+#if defined(__SUNPRO_C) && (__SUNPRO_C < 0x550)
+#define DUK_F_OLD_SOLARIS
+/* Defines _ILP32 / _LP64 required by DUK_F_X86/DUK_F_X64. Platforms
+ * are processed before architectures, so this happens before the
+ * DUK_F_X86/DUK_F_X64 detection is emitted.
+ */
+#include
+#endif
+#endif
+
+/* AIX */
+#if defined(_AIX)
+/* defined(__xlc__) || defined(__IBMC__): works but too wide */
+#define DUK_F_AIX
+#endif
+
+/* HPUX */
+#if defined(__hpux)
+#define DUK_F_HPUX
+#if defined(__ia64)
+#define DUK_F_HPUX_ITANIUM
+#endif
#endif
/* POSIX */
@@ -188,17 +218,6 @@
#define DUK_F_UNIX
#endif
-/* stdint.h not available */
-#if defined(DUK_F_WINDOWS) && defined(_MSC_VER)
-#if (_MSC_VER < 1700)
-/* VS2012+ has stdint.h, < VS2012 does not (but it's available for download). */
-#define DUK_F_NO_STDINT_H
-#endif
-#endif
-#if !defined(DUK_F_NO_STDINT_H) && (defined(DUK_F_TOS) || defined(DUK_F_BCC))
-#define DUK_F_NO_STDINT_H
-#endif
-
/* C++ */
#undef DUK_F_CPP
#if defined(__cplusplus)
@@ -208,6 +227,9 @@
/* Intel x86 (32-bit), x64 (64-bit) or x32 (64-bit but 32-bit pointers),
* define only one of DUK_F_X86, DUK_F_X64, DUK_F_X32.
* https://sites.google.com/site/x32abi/
+ *
+ * With DUK_F_OLD_SOLARIS the header must be included
+ * before this.
*/
#if defined(__amd64__) || defined(__amd64) || \
defined(__x86_64__) || defined(__x86_64) || \
@@ -230,9 +252,9 @@
#endif
/* ARM */
-#if defined(__arm__) || defined(__thumb__) || defined(_ARM) || defined(_M_ARM)
+#if defined(__arm__) || defined(__thumb__) || defined(_ARM) || defined(_M_ARM) || defined(__aarch64__)
#define DUK_F_ARM
-#if defined(__LP64__) || defined(_LP64) || defined(__arm64) || defined(__arm64__)
+#if defined(__LP64__) || defined(_LP64) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__)
#define DUK_F_ARM64
#else
#define DUK_F_ARM32
@@ -334,6 +356,10 @@
#define DUK_F_VBCC
#endif
+#if defined(ANDROID) || defined(__ANDROID__)
+#define DUK_F_ANDROID
+#endif
+
/* Atari Mint */
#if defined(__MINT__)
#define DUK_F_MINT
@@ -380,6 +406,20 @@
#define DUK_JMPBUF_TYPE jmp_buf
#define DUK_SETJMP(jb) _setjmp((jb))
#define DUK_LONGJMP(jb) _longjmp((jb), 1)
+#elif defined(DUK_F_ORBIS)
+/* --- Orbis --- */
+/* Orbis = PS4 */
+#define DUK_USE_DATE_NOW_GETTIMEOFDAY
+#define DUK_USE_DATE_TZO_GMTIME_S
+/* no parsing (not an error) */
+#define DUK_USE_DATE_FMT_STRFTIME
+#include
+#include
+#include
+#include
+#include
+
+#define DUK_USE_OS_STRING "orbis"
#elif defined(DUK_F_OPENBSD)
/* --- OpenBSD --- */
/* http://www.monkey.org/openbsd/archive/ports/0401/msg00089.html */
@@ -436,7 +476,7 @@
#define DUK_USE_DATE_PRS_STRPTIME
#define DUK_USE_DATE_FMT_STRFTIME
#include
-#ifndef UINTPTR_MAX
+#if !defined(UINTPTR_MAX)
#define UINTPTR_MAX UINT_MAX
#endif
#else
@@ -449,8 +489,47 @@
#if !defined(DUK_USE_BYTEORDER) && (defined(DUK_F_M68K) || defined(DUK_F_PPC))
#define DUK_USE_BYTEORDER 3
#endif
+#elif defined(DUK_F_DURANGO)
+/* --- Durango (XboxOne) --- */
+/* Durango = XboxOne
+ * Configuration is nearly identical to Windows, except for
+ * DUK_USE_DATE_TZO_WINDOWS.
+ */
+
+/* Initial fix: disable secure CRT related warnings when compiling Duktape
+ * itself (must be defined before including Windows headers). Don't define
+ * for user code including duktape.h.
+ */
+#if defined(DUK_COMPILING_DUKTAPE) && !defined(_CRT_SECURE_NO_WARNINGS)
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+/* MSVC does not have sys/param.h */
+#define DUK_USE_DATE_NOW_WINDOWS
+#define DUK_USE_DATE_TZO_WINDOWS_NO_DST
+/* Note: PRS and FMT are intentionally left undefined for now. This means
+ * there is no platform specific date parsing/formatting but there is still
+ * the ISO 8601 standard format.
+ */
+#if defined(DUK_COMPILING_DUKTAPE)
+/* Only include when compiling Duktape to avoid polluting application build
+ * with a lot of unnecessary defines.
+ */
+#include
+#endif
+
+#define DUK_USE_OS_STRING "durango"
+
+#if !defined(DUK_USE_BYTEORDER)
+#define DUK_USE_BYTEORDER 1
+#endif
#elif defined(DUK_F_WINDOWS)
/* --- Windows --- */
+/* Windows version can't obviously be determined at compile time,
+ * but _WIN32_WINNT indicates the minimum version targeted:
+ * - https://msdn.microsoft.com/en-us/library/6sehtctf.aspx
+ */
+
/* Initial fix: disable secure CRT related warnings when compiling Duktape
* itself (must be defined before including Windows headers). Don't define
* for user code including duktape.h.
@@ -461,12 +540,7 @@
/* Windows 32-bit and 64-bit are currently the same. */
/* MSVC does not have sys/param.h */
-#define DUK_USE_DATE_NOW_WINDOWS
-#define DUK_USE_DATE_TZO_WINDOWS
-/* Note: PRS and FMT are intentionally left undefined for now. This means
- * there is no platform specific date parsing/formatting but there is still
- * the ISO 8601 standard format.
- */
+
#if defined(DUK_COMPILING_DUKTAPE)
/* Only include when compiling Duktape to avoid polluting application build
* with a lot of unnecessary defines.
@@ -474,6 +548,34 @@
#include
#endif
+/* GetSystemTimePreciseAsFileTime() available from Windows 8:
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/hh706895(v=vs.85).aspx
+ */
+#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS) || defined(DUK_USE_DATE_NOW_WINDOWS)
+/* User forced provider. */
+#else
+#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602)
+#define DUK_USE_DATE_NOW_WINDOWS_SUBMS
+#else
+#define DUK_USE_DATE_NOW_WINDOWS
+#endif
+#endif
+
+#define DUK_USE_DATE_TZO_WINDOWS
+
+/* Note: PRS and FMT are intentionally left undefined for now. This means
+ * there is no platform specific date parsing/formatting but there is still
+ * the ISO 8601 standard format.
+ */
+
+/* QueryPerformanceCounter() may go backwards in Windows XP, so enable for
+ * Vista and later: https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx#qpc_support_in_windows_versions
+ */
+#if !defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC) && \
+ defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
+#define DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC
+#endif
+
#define DUK_USE_OS_STRING "windows"
/* On Windows, assume we're little endian. Even Itanium which has a
@@ -518,6 +620,10 @@
#define DUK_USE_OS_STRING "qnx"
#elif defined(DUK_F_TINSPIRE)
/* --- TI-Nspire --- */
+#if defined(DUK_COMPILING_DUKTAPE) && !defined(_XOPEN_SOURCE)
+#define _XOPEN_SOURCE /* e.g. strptime */
+#endif
+
#define DUK_USE_DATE_NOW_GETTIMEOFDAY
#define DUK_USE_DATE_TZO_GMTIME_R
#define DUK_USE_DATE_PRS_STRPTIME
@@ -531,13 +637,13 @@
#elif defined(DUK_F_EMSCRIPTEN)
/* --- Emscripten --- */
#if defined(DUK_COMPILING_DUKTAPE)
-#ifndef _POSIX_C_SOURCE
+#if !defined(_POSIX_C_SOURCE)
#define _POSIX_C_SOURCE 200809L
#endif
-#ifndef _GNU_SOURCE
+#if !defined(_GNU_SOURCE)
#define _GNU_SOURCE /* e.g. getdate_r */
#endif
-#ifndef _XOPEN_SOURCE
+#if !defined(_XOPEN_SOURCE)
#define _XOPEN_SOURCE /* e.g. strptime */
#endif
#endif /* DUK_COMPILING_DUKTAPE */
@@ -562,13 +668,13 @@
#elif defined(DUK_F_LINUX)
/* --- Linux --- */
#if defined(DUK_COMPILING_DUKTAPE)
-#ifndef _POSIX_C_SOURCE
+#if !defined(_POSIX_C_SOURCE)
#define _POSIX_C_SOURCE 200809L
#endif
-#ifndef _GNU_SOURCE
+#if !defined(_GNU_SOURCE)
#define _GNU_SOURCE /* e.g. getdate_r */
#endif
-#ifndef _XOPEN_SOURCE
+#if !defined(_XOPEN_SOURCE)
#define _XOPEN_SOURCE /* e.g. strptime */
#endif
#endif /* DUK_COMPILING_DUKTAPE */
@@ -589,6 +695,10 @@
#define DUK_USE_DATE_PRS_STRPTIME
#define DUK_USE_DATE_FMT_STRFTIME
+#if 0 /* XXX: safe condition? */
+#define DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME
+#endif
+
#define DUK_USE_OS_STRING "linux"
#elif defined(DUK_F_SUN)
/* --- Solaris --- */
@@ -598,12 +708,50 @@
#define DUK_USE_DATE_FMT_STRFTIME
#include
+#if defined(DUK_F_OLD_SOLARIS)
+/* Old Solaris with no endian.h, stdint.h */
+#define DUK_F_NO_STDINT_H
+#if !defined(DUK_USE_BYTEORDER)
+#define DUK_USE_BYTEORDER 3
+#endif
+#else /* DUK_F_OLD_SOLARIS */
#include
+#endif /* DUK_F_OLD_SOLARIS */
+
#include
#include
#include
#define DUK_USE_OS_STRING "solaris"
+#elif defined(DUK_F_AIX)
+/* --- AIX --- */
+#if !defined(DUK_USE_BYTEORDER)
+#define DUK_USE_BYTEORDER 3
+#endif
+#define DUK_USE_DATE_NOW_GETTIMEOFDAY
+#define DUK_USE_DATE_TZO_GMTIME_R
+#define DUK_USE_DATE_PRS_STRPTIME
+#define DUK_USE_DATE_FMT_STRFTIME
+#include
+#include
+#include
+
+#define DUK_USE_OS_STRING "aix"
+#elif defined(DUK_F_HPUX)
+/* --- HPUX --- */
+#define DUK_F_NO_STDINT_H
+#if !defined(DUK_USE_BYTEORDER)
+#define DUK_USE_BYTEORDER 3
+#endif
+#define DUK_USE_DATE_NOW_GETTIMEOFDAY
+#define DUK_USE_DATE_TZO_GMTIME_R
+#define DUK_USE_DATE_PRS_STRPTIME
+#define DUK_USE_DATE_FMT_STRFTIME
+#include
+#include
+#include
+
+#define DUK_USE_OS_STRING "hpux"
#elif defined(DUK_F_POSIX)
/* --- Generic POSIX --- */
#define DUK_USE_DATE_NOW_GETTIMEOFDAY
@@ -760,12 +908,8 @@
/* --- MIPS 32-bit --- */
#define DUK_USE_ARCH_STRING "mips32"
/* MIPS byte order varies so rely on autodetection. */
-/* Based on 'make checkalign' there are no alignment requirements on
- * Linux MIPS except for doubles, which need align by 4. Alignment
- * requirements vary based on target though.
- */
#if !defined(DUK_USE_ALIGN_BY)
-#define DUK_USE_ALIGN_BY 4
+#define DUK_USE_ALIGN_BY 8
#endif
#define DUK_USE_PACKED_TVAL
#define DUK_F_PACKED_TVAL_PROVIDED
@@ -773,9 +917,6 @@
/* --- MIPS 64-bit --- */
#define DUK_USE_ARCH_STRING "mips64"
/* MIPS byte order varies so rely on autodetection. */
-/* Good default is a bit arbitrary because alignment requirements
- * depend on target. See https://github.com/svaarala/duktape/issues/102.
- */
#if !defined(DUK_USE_ALIGN_BY)
#define DUK_USE_ALIGN_BY 8
#endif
@@ -887,6 +1028,11 @@
#define DUK_USE_BRANCH_HINTS
#define DUK_LIKELY(x) __builtin_expect((x), 1)
#define DUK_UNLIKELY(x) __builtin_expect((x), 0)
+#if defined(__clang__) && defined(__has_builtin)
+#if __has_builtin(__builtin_unpredictable)
+#define DUK_UNPREDICTABLE(x) __builtin_unpredictable((x))
+#endif
+#endif
#if defined(DUK_F_C99) || defined(DUK_F_CPP11)
#define DUK_NOINLINE __attribute__((noinline))
@@ -894,6 +1040,9 @@
#define DUK_ALWAYS_INLINE inline __attribute__((always_inline))
#endif
+/* DUK_HOT */
+/* DUK_COLD */
+
#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS)
/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're
* compiling Duktape or the application.
@@ -995,6 +1144,7 @@
#define DUK_LIKELY(x) __builtin_expect((x), 1)
#define DUK_UNLIKELY(x) __builtin_expect((x), 0)
#endif
+/* XXX: equivalent of clang __builtin_unpredictable? */
#if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && \
defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 30101)
@@ -1003,6 +1153,12 @@
#define DUK_ALWAYS_INLINE inline __attribute__((always_inline))
#endif
+#if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && \
+ defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40300)
+#define DUK_HOT __attribute__((hot))
+#define DUK_COLD __attribute__((cold))
+#endif
+
#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS)
/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're
* compiling Duktape or the application.
@@ -1181,6 +1337,18 @@
#define DUK_SNPRINTF _snprintf
#define DUK_VSNPRINTF _vsnprintf
#endif
+
+/* Avoid warning when doing DUK_UNREF(some_function). */
+#if defined(_MSC_VER) && (_MSC_VER < 1500)
+#pragma warning(disable: 4100 4101 4550 4551)
+#define DUK_UNREF(x)
+#else
+#define DUK_UNREF(x) do { __pragma(warning(suppress:4100 4101 4550 4551)) (x); } while (0)
+#endif
+
+/* Older versions of MSVC don't support the LL/ULL suffix. */
+#define DUK_U64_CONSTANT(x) x##ui64
+#define DUK_I64_CONSTANT(x) x##i64
#elif defined(DUK_F_EMSCRIPTEN)
/* --- Emscripten --- */
#define DUK_NORETURN(decl) decl __attribute__((noreturn))
@@ -1194,6 +1362,11 @@
#define DUK_USE_BRANCH_HINTS
#define DUK_LIKELY(x) __builtin_expect((x), 1)
#define DUK_UNLIKELY(x) __builtin_expect((x), 0)
+#if defined(__clang__) && defined(__has_builtin)
+#if __has_builtin(__builtin_unpredictable)
+#define DUK_UNPREDICTABLE(x) __builtin_unpredictable((x))
+#endif
+#endif
#if defined(DUK_F_C99) || defined(DUK_F_CPP11)
#define DUK_NOINLINE __attribute__((noinline))
@@ -1401,10 +1574,16 @@
#if defined(DUK_F_X86) || defined(DUK_F_X32) || \
defined(DUK_F_M68K) || defined(DUK_F_PPC32) || \
defined(DUK_F_BCC) || \
- (defined(__WORDSIZE) && (__WORDSIZE == 32))
+ (defined(__WORDSIZE) && (__WORDSIZE == 32)) || \
+ ((defined(DUK_F_OLD_SOLARIS) || defined(DUK_F_AIX) || \
+ defined(DUK_F_HPUX)) && defined(_ILP32)) || \
+ defined(DUK_F_ARM32)
#define DUK_F_32BIT_PTRS
#elif defined(DUK_F_X64) || \
- (defined(__WORDSIZE) && (__WORDSIZE == 64))
+ (defined(__WORDSIZE) && (__WORDSIZE == 64)) || \
+ ((defined(DUK_F_OLD_SOLARIS) || defined(DUK_F_AIX) || \
+ defined(DUK_F_HPUX)) && defined(_LP64)) || \
+ defined(DUK_F_ARM64)
#define DUK_F_64BIT_PTRS
#else
/* not sure, not needed with C99 anyway */
@@ -1607,13 +1786,16 @@ typedef unsigned long long duk_uint64_t;
typedef signed long long duk_int64_t;
#endif
#endif
-#if !defined(DUK_F_HAVE_64BIT) && \
- (defined(DUK_F_MINGW) || defined(DUK_F_MSVC))
-/* Both MinGW and MSVC have a 64-bit type. */
+#if !defined(DUK_F_HAVE_64BIT) && defined(DUK_F_MINGW)
#define DUK_F_HAVE_64BIT
typedef unsigned long duk_uint64_t;
typedef signed long duk_int64_t;
#endif
+#if !defined(DUK_F_HAVE_64BIT) && defined(DUK_F_MSVC)
+#define DUK_F_HAVE_64BIT
+typedef unsigned __int64 duk_uint64_t;
+typedef signed __int64 duk_int64_t;
+#endif
#if !defined(DUK_F_HAVE_64BIT)
/* cannot detect 64-bit type, not always needed so don't error */
#endif
@@ -1821,8 +2003,8 @@ typedef duk_uint_fast16_t duk_small_uint_fast_t;
#define DUK_SMALL_UINT_FAST_MIN DUK_UINT_FAST16_MIN
#define DUK_SMALL_UINT_FAST_MAX DUK_UINT_FAST16_MAX
-/* Boolean values are represented with the platform 'int'. */
-typedef duk_small_int_t duk_bool_t;
+/* Boolean values are represented with the platform 'unsigned int'. */
+typedef duk_small_uint_t duk_bool_t;
#define DUK_BOOL_MIN DUK_SMALL_INT_MIN
#define DUK_BOOL_MAX DUK_SMALL_INT_MAX
@@ -1893,7 +2075,10 @@ typedef double duk_double_t;
#endif
#endif
-/* Type for public API calls. */
+/* Type used in public API declarations and user code. Typedef maps to
+ * 'struct duk_hthread' like the 'duk_hthread' typedef which is used
+ * exclusively in internals.
+ */
typedef struct duk_hthread duk_context;
/* Check whether we should use 64-bit integers or not.
@@ -1912,6 +2097,11 @@ typedef struct duk_hthread duk_context;
* Fill-ins for platform, architecture, and compiler
*/
+/* An abort()-like primitive is needed by the default fatal error handler. */
+#if !defined(DUK_ABORT)
+#define DUK_ABORT abort
+#endif
+
#if !defined(DUK_SETJMP)
#define DUK_JMPBUF_TYPE jmp_buf
#define DUK_SETJMP(jb) setjmp((jb))
@@ -1925,17 +2115,6 @@ typedef struct duk_hthread duk_context;
#define DUK_LONGJMP(jb) siglongjmp((jb), 1)
#endif
-typedef FILE duk_file;
-#if !defined(DUK_STDIN)
-#define DUK_STDIN stdin
-#endif
-#if !defined(DUK_STDOUT)
-#define DUK_STDOUT stdout
-#endif
-#if !defined(DUK_STDERR)
-#define DUK_STDERR stderr
-#endif
-
/* Special naming to avoid conflict with e.g. DUK_FREE() in duk_heap.h
* (which is unfortunately named). May sometimes need replacement, e.g.
* some compilers don't handle zero length or NULL correctly in realloc().
@@ -2002,12 +2181,6 @@ typedef FILE duk_file;
#if !defined(DUK_STRNCMP)
#define DUK_STRNCMP strncmp
#endif
-#if !defined(DUK_PRINTF)
-#define DUK_PRINTF printf
-#endif
-#if !defined(DUK_FPRINTF)
-#define DUK_FPRINTF fprintf
-#endif
#if !defined(DUK_SPRINTF)
#define DUK_SPRINTF sprintf
#endif
@@ -2028,46 +2201,9 @@ typedef FILE duk_file;
#if !defined(DUK_VSSCANF)
#define DUK_VSSCANF vsscanf
#endif
-#if !defined(DUK_FOPEN)
-#define DUK_FOPEN fopen
-#endif
-#if !defined(DUK_FCLOSE)
-#define DUK_FCLOSE fclose
-#endif
-#if !defined(DUK_FREAD)
-#define DUK_FREAD fread
-#endif
-#if !defined(DUK_FWRITE)
-#define DUK_FWRITE fwrite
-#endif
-#if !defined(DUK_FSEEK)
-#define DUK_FSEEK fseek
-#endif
-#if !defined(DUK_FTELL)
-#define DUK_FTELL ftell
-#endif
-#if !defined(DUK_FFLUSH)
-#define DUK_FFLUSH fflush
-#endif
-#if !defined(DUK_FPUTC)
-#define DUK_FPUTC fputc
-#endif
#if !defined(DUK_MEMZERO)
#define DUK_MEMZERO(p,n) DUK_MEMSET((p), 0, (n))
#endif
-#if !defined(DUK_ABORT)
-#define DUK_ABORT abort
-#endif
-#if !defined(DUK_EXIT)
-#define DUK_EXIT exit
-#endif
-
-#if !defined(DUK_DOUBLE_2TO32)
-#define DUK_DOUBLE_2TO32 4294967296.0
-#endif
-#if !defined(DUK_DOUBLE_2TO31)
-#define DUK_DOUBLE_2TO31 2147483648.0
-#endif
#if !defined(DUK_DOUBLE_INFINITY)
#undef DUK_USE_COMPUTED_INFINITY
@@ -2076,7 +2212,8 @@ typedef FILE duk_file;
#define DUK_DOUBLE_INFINITY (__builtin_inf())
#elif defined(INFINITY)
#define DUK_DOUBLE_INFINITY ((double) INFINITY)
-#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC)
+#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) && \
+ !defined(DUK_F_OLD_SOLARIS) && !defined(DUK_F_AIX)
#define DUK_DOUBLE_INFINITY (1.0 / 0.0)
#else
/* In VBCC (1.0 / 0.0) results in a warning and 0.0 instead of infinity.
@@ -2092,7 +2229,8 @@ typedef FILE duk_file;
#undef DUK_USE_COMPUTED_NAN
#if defined(NAN)
#define DUK_DOUBLE_NAN NAN
-#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC)
+#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) && \
+ !defined(DUK_F_OLD_SOLARIS) && !defined(DUK_F_AIX)
#define DUK_DOUBLE_NAN (0.0 / 0.0)
#else
/* In VBCC (0.0 / 0.0) results in a warning and 0.0 instead of NaN.
@@ -2141,6 +2279,9 @@ typedef FILE duk_file;
* To be safe, use replacements.
*/
#define DUK_F_USE_REPL_ALL
+#elif defined(DUK_F_AIX)
+/* Older versions may be missing isnan(), etc. */
+#define DUK_F_USE_REPL_ALL
#endif
#if defined(DUK_F_USE_REPL_ALL)
@@ -2176,29 +2317,6 @@ typedef FILE duk_file;
#undef DUK_F_USE_REPL_ALL
#endif
-/* Some math functions are C99 only. This is also an issue with some
- * embedded environments using uclibc where uclibc has been configured
- * not to provide some functions. For now, use replacements whenever
- * using uclibc.
- */
-#undef DUK_USE_MATH_FMIN
-#undef DUK_USE_MATH_FMAX
-#undef DUK_USE_MATH_ROUND
-#if defined(DUK_F_UCLIBC)
-/* uclibc may be missing these */
-#elif defined(DUK_F_AMIGAOS) && defined(DUK_F_VBCC)
-/* vbcc + AmigaOS may be missing these */
-#elif defined(DUK_F_MINT)
-/* mint clib is missing these */
-#elif !defined(DUK_F_C99) && !defined(DUK_F_CPP11)
-/* build is not C99 or C++11, play it safe */
-#else
-/* C99 or C++11, no known issues */
-#define DUK_USE_MATH_FMIN
-#define DUK_USE_MATH_FMAX
-#define DUK_USE_MATH_ROUND
-#endif
-
/* These functions don't currently need replacement but are wrapped for
* completeness. Because these are used as function pointers, they need
* to be defined as concrete C functions (not macros).
@@ -2206,12 +2324,6 @@ typedef FILE duk_file;
#if !defined(DUK_FABS)
#define DUK_FABS fabs
#endif
-#if !defined(DUK_FMIN)
-#define DUK_FMIN fmin
-#endif
-#if !defined(DUK_FMAX)
-#define DUK_FMAX fmax
-#endif
#if !defined(DUK_FLOOR)
#define DUK_FLOOR floor
#endif
@@ -2255,13 +2367,43 @@ typedef FILE duk_file;
#define DUK_SQRT sqrt
#endif
-/* NetBSD 6.0 x86 (at least) has a few problems with pow() semantics,
- * see test-bug-netbsd-math-pow.js. Use NetBSD specific workaround.
- * (This might be a wider problem; if so, generalize the define name.)
+/* The functions below exist only in C99/C++11 or later and need a workaround
+ * for platforms that don't include them. MSVC isn't detected as C99, but
+ * these functions also exist in MSVC 2013 and later so include a clause for
+ * that too. Android doesn't have log2; disable all of these for Android.
*/
-#undef DUK_USE_POW_NETBSD_WORKAROUND
-#if defined(DUK_F_NETBSD)
-#define DUK_USE_POW_NETBSD_WORKAROUND
+#if (defined(DUK_F_C99) || defined(DUK_F_CPP11) || (defined(_MSC_VER) && (_MSC_VER >= 1800))) && \
+ !defined(DUK_F_ANDROID) && !defined(DUK_F_MINT)
+#if !defined(DUK_CBRT)
+#define DUK_CBRT cbrt
+#endif
+#if !defined(DUK_LOG2)
+#define DUK_LOG2 log2
+#endif
+#if !defined(DUK_LOG10)
+#define DUK_LOG10 log10
+#endif
+#if !defined(DUK_TRUNC)
+#define DUK_TRUNC trunc
+#endif
+#endif /* DUK_F_C99 etc */
+
+/* NetBSD 6.0 x86 (at least) has a few problems with pow() semantics,
+ * see test-bug-netbsd-math-pow.js. MinGW has similar (but different)
+ * issues, see test-bug-mingw-math-issues.js. Enable pow() workarounds
+ * for these targets.
+ */
+#undef DUK_USE_POW_WORKAROUNDS
+#if defined(DUK_F_NETBSD) || defined(DUK_F_MINGW)
+#define DUK_USE_POW_WORKAROUNDS
+#endif
+
+/* Similar workarounds for atan2() semantics issues. MinGW issues are
+ * documented in test-bug-mingw-math-issues.js.
+ */
+#undef DUK_USE_ATAN2_WORKAROUNDS
+#if defined(DUK_F_MINGW)
+#define DUK_USE_ATAN2_WORKAROUNDS
#endif
/* Rely as little as possible on compiler behavior for NaN comparison,
@@ -2304,25 +2446,6 @@ typedef FILE duk_file;
* byte order for doubles is referred to as "mixed endian".
*/
-/* For custom platforms allow user to define byteorder explicitly.
- * Since endianness headers are not standardized, this is a useful
- * workaround for custom platforms for which endianness detection
- * is not directly supported. Perhaps custom hardware is used and
- * user cannot submit upstream patches.
- */
-#if defined(DUK_OPT_FORCE_BYTEORDER)
-#undef DUK_USE_BYTEORDER
-#if (DUK_OPT_FORCE_BYTEORDER == 1)
-#define DUK_USE_BYTEORDER 1
-#elif (DUK_OPT_FORCE_BYTEORDER == 2)
-#define DUK_USE_BYTEORDER 2
-#elif (DUK_OPT_FORCE_BYTEORDER == 3)
-#define DUK_USE_BYTEORDER 3
-#else
-#error invalid DUK_OPT_FORCE_BYTEORDER value
-#endif
-#endif /* DUK_OPT_FORCE_BYTEORDER */
-
/* GCC and Clang provide endianness defines as built-in predefines, with
* leading and trailing double underscores (e.g. __BYTE_ORDER__). See
* output of "make gccpredefs" and "make clangpredefs". Clang doesn't
@@ -2425,18 +2548,6 @@ typedef FILE duk_file;
#define DUK_USE_ALIGN_BY 8
#endif
-/* User forced alignment to 4 or 8. */
-#if defined(DUK_OPT_FORCE_ALIGN)
-#undef DUK_USE_ALIGN_BY
-#if (DUK_OPT_FORCE_ALIGN == 4)
-#define DUK_USE_ALIGN_BY 4
-#elif (DUK_OPT_FORCE_ALIGN == 8)
-#define DUK_USE_ALIGN_BY 8
-#else
-#error invalid DUK_OPT_FORCE_ALIGN value
-#endif
-#endif
-
/* Compiler specific hackery needed to force struct size to match aligment,
* see e.g. duk_hbuffer.h.
*
@@ -2479,9 +2590,8 @@ typedef FILE duk_file;
#endif
#if !defined(DUK_CAUSE_SEGFAULT)
-/* This is optionally used by panic handling to cause the program to segfault
- * (instead of e.g. abort()) on panic. Valgrind will then indicate the C
- * call stack leading to the panic.
+/* This can be used for testing; valgrind will then indicate the C call stack
+ * leading to the call site.
*/
#define DUK_CAUSE_SEGFAULT() do { *((volatile duk_uint32_t *) NULL) = (duk_uint32_t) 0xdeadbeefUL; } while (0)
#endif
@@ -2489,7 +2599,8 @@ typedef FILE duk_file;
/* Macro for suppressing warnings for potentially unreferenced variables.
* The variables can be actually unreferenced or unreferenced in some
* specific cases only; for instance, if a variable is only debug printed,
- * it is unreferenced when debug printing is disabled.
+ * it is unreferenced when debug printing is disabled. May cause warnings
+ * for volatile arguments.
*/
#define DUK_UNREF(x) do { (void) (x); } while (0)
#endif
@@ -2517,6 +2628,9 @@ typedef FILE duk_file;
#if !defined(DUK_UNLIKELY)
#define DUK_UNLIKELY(x) (x)
#endif
+#if !defined(DUK_UNPREDICTABLE)
+#define DUK_UNPREDICTABLE(x) (x)
+#endif
#if !defined(DUK_NOINLINE)
#define DUK_NOINLINE /*nop*/
@@ -2528,6 +2642,13 @@ typedef FILE duk_file;
#define DUK_ALWAYS_INLINE /*nop*/
#endif
+#if !defined(DUK_HOT)
+#define DUK_HOT /*nop*/
+#endif
+#if !defined(DUK_COLD)
+#define DUK_COLD /*nop*/
+#endif
+
#if !defined(DUK_EXTERNAL_DECL)
#define DUK_EXTERNAL_DECL extern
#endif
@@ -2604,6 +2725,13 @@ typedef FILE duk_file;
#undef DUK_USE_GCC_PRAGMAS
#endif
+#if !defined(DUK_U64_CONSTANT)
+#define DUK_U64_CONSTANT(x) x##ULL
+#endif
+#if !defined(DUK_I64_CONSTANT)
+#define DUK_I64_CONSTANT(x) x##LL
+#endif
+
/* Workaround for GH-323: avoid inlining control when compiling from
* multiple sources, as it causes compiler portability trouble.
*/
@@ -2656,14 +2784,6 @@ typedef FILE duk_file;
#undef DUK_F_PACKED_TVAL_POSSIBLE
#endif /* DUK_F_PACKED_TVAL_PROVIDED */
-
-/* Feature option forcing. */
-#if defined(DUK_OPT_NO_PACKED_TVAL)
-#undef DUK_USE_PACKED_TVAL
-#elif defined(DUK_OPT_PACKED_TVAL)
-#undef DUK_USE_PACKED_TVAL
-#define DUK_USE_PACKED_TVAL
-#endif
/* Object property allocation layout has implications for memory and code
* footprint and generated code size/speed. The best layout also depends
* on whether the platform has alignment requirements or benefits from
@@ -2693,853 +2813,195 @@ typedef FILE duk_file;
#error __FAST_MATH__ defined, refusing to compile
#endif
-/*
- * Feature option handling
- */
-
-#if !defined(DUK_USE_ALIGN_BY)
-#if defined(DUK_OPT_FORCE_ALIGN)
-#define DUK_USE_ALIGN_BY DUK_OPT_FORCE_ALIGN
-#else
-#define DUK_USE_ALIGN_BY 8
-#endif
-#endif
-
-#if defined(DUK_OPT_ASSERTIONS)
-#define DUK_USE_ASSERTIONS
-#elif defined(DUK_OPT_NO_ASSERTIONS)
-#undef DUK_USE_ASSERTIONS
-#else
-#undef DUK_USE_ASSERTIONS
-#endif
-
-#if defined(DUK_OPT_AUGMENT_ERRORS)
-#define DUK_USE_AUGMENT_ERROR_CREATE
-#elif defined(DUK_OPT_NO_AUGMENT_ERRORS)
-#undef DUK_USE_AUGMENT_ERROR_CREATE
-#else
-#define DUK_USE_AUGMENT_ERROR_CREATE
-#endif
-
-#if defined(DUK_OPT_AUGMENT_ERRORS)
-#define DUK_USE_AUGMENT_ERROR_THROW
-#elif defined(DUK_OPT_NO_AUGMENT_ERRORS)
-#undef DUK_USE_AUGMENT_ERROR_THROW
-#else
-#define DUK_USE_AUGMENT_ERROR_THROW
-#endif
-
-#if defined(DUK_OPT_BROWSER_LIKE)
-#define DUK_USE_BROWSER_LIKE
-#elif defined(DUK_OPT_NO_BROWSER_LIKE)
-#undef DUK_USE_BROWSER_LIKE
-#else
-#define DUK_USE_BROWSER_LIKE
-#endif
-
-#if defined(DUK_OPT_BUFFEROBJECT_SUPPORT)
-#define DUK_USE_BUFFEROBJECT_SUPPORT
-#elif defined(DUK_OPT_NO_BUFFEROBJECT_SUPPORT)
-#undef DUK_USE_BUFFEROBJECT_SUPPORT
-#else
-#define DUK_USE_BUFFEROBJECT_SUPPORT
-#endif
-
-#if defined(DUK_OPT_BUFLEN16)
-#define DUK_USE_BUFLEN16
-#elif defined(DUK_OPT_NO_BUFLEN16)
-#undef DUK_USE_BUFLEN16
-#else
-#undef DUK_USE_BUFLEN16
-#endif
-
-#if defined(DUK_OPT_BYTECODE_DUMP_SUPPORT)
-#define DUK_USE_BYTECODE_DUMP_SUPPORT
-#elif defined(DUK_OPT_NO_BYTECODE_DUMP_SUPPORT)
-#undef DUK_USE_BYTECODE_DUMP_SUPPORT
-#else
-#define DUK_USE_BYTECODE_DUMP_SUPPORT
-#endif
-
-#if defined(DUK_OPT_COMMONJS_MODULES)
-#define DUK_USE_COMMONJS_MODULES
-#elif defined(DUK_OPT_NO_COMMONJS_MODULES)
-#undef DUK_USE_COMMONJS_MODULES
-#else
-#define DUK_USE_COMMONJS_MODULES
-#endif
-
-#if defined(DUK_OPT_CPP_EXCEPTIONS)
-#define DUK_USE_CPP_EXCEPTIONS
-#elif defined(DUK_OPT_NO_CPP_EXCEPTIONS)
-#undef DUK_USE_CPP_EXCEPTIONS
-#else
-#undef DUK_USE_CPP_EXCEPTIONS
-#endif
-
-#if defined(DUK_OPT_DATAPTR16)
-#define DUK_USE_DATAPTR16
-#elif defined(DUK_OPT_NO_DATAPTR16)
-#undef DUK_USE_DATAPTR16
-#else
-#undef DUK_USE_DATAPTR16
-#endif
-
-#if defined(DUK_OPT_DATAPTR_DEC16)
-#define DUK_USE_DATAPTR_DEC16(udata,ptr) DUK_OPT_DATAPTR_DEC16((udata),(ptr))
-#else
-#undef DUK_USE_DATAPTR_DEC16
-#endif
-
-#if defined(DUK_OPT_DATAPTR_ENC16)
-#define DUK_USE_DATAPTR_ENC16(udata,ptr) DUK_OPT_DATAPTR_ENC16((udata),(ptr))
-#else
-#undef DUK_USE_DATAPTR_ENC16
-#endif
-
-#if defined(DUK_OPT_DDDPRINT)
-#define DUK_USE_DDDPRINT
-#elif defined(DUK_OPT_NO_DDDPRINT)
-#undef DUK_USE_DDDPRINT
-#else
-#undef DUK_USE_DDDPRINT
-#endif
-
-#if defined(DUK_OPT_DDPRINT)
-#define DUK_USE_DDPRINT
-#elif defined(DUK_OPT_NO_DDPRINT)
-#undef DUK_USE_DDPRINT
-#else
-#undef DUK_USE_DDPRINT
-#endif
-
-#if defined(DUK_OPT_DEBUG)
-#define DUK_USE_DEBUG
-#elif defined(DUK_OPT_NO_DEBUG)
-#undef DUK_USE_DEBUG
-#else
-#undef DUK_USE_DEBUG
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_DUMPHEAP)
-#define DUK_USE_DEBUGGER_DUMPHEAP
-#elif defined(DUK_OPT_NO_DEBUGGER_DUMPHEAP)
-#undef DUK_USE_DEBUGGER_DUMPHEAP
-#else
-#undef DUK_USE_DEBUGGER_DUMPHEAP
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_FWD_LOGGING)
-#define DUK_USE_DEBUGGER_FWD_LOGGING
-#elif defined(DUK_OPT_NO_DEBUGGER_FWD_LOGGING)
-#undef DUK_USE_DEBUGGER_FWD_LOGGING
-#else
-#undef DUK_USE_DEBUGGER_FWD_LOGGING
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_FWD_PRINTALERT)
-#define DUK_USE_DEBUGGER_FWD_PRINTALERT
-#elif defined(DUK_OPT_NO_DEBUGGER_FWD_PRINTALERT)
-#undef DUK_USE_DEBUGGER_FWD_PRINTALERT
-#else
-#undef DUK_USE_DEBUGGER_FWD_PRINTALERT
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_INSPECT)
-#define DUK_USE_DEBUGGER_INSPECT
-#elif defined(DUK_OPT_NO_DEBUGGER_INSPECT)
-#undef DUK_USE_DEBUGGER_INSPECT
-#else
-#undef DUK_USE_DEBUGGER_INSPECT
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_PAUSE_UNCAUGHT)
-#define DUK_USE_DEBUGGER_PAUSE_UNCAUGHT
-#elif defined(DUK_OPT_NO_DEBUGGER_PAUSE_UNCAUGHT)
-#undef DUK_USE_DEBUGGER_PAUSE_UNCAUGHT
-#else
-#undef DUK_USE_DEBUGGER_PAUSE_UNCAUGHT
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_SUPPORT)
-#define DUK_USE_DEBUGGER_SUPPORT
-#elif defined(DUK_OPT_NO_DEBUGGER_SUPPORT)
-#undef DUK_USE_DEBUGGER_SUPPORT
-#else
-#undef DUK_USE_DEBUGGER_SUPPORT
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_THROW_NOTIFY)
-#define DUK_USE_DEBUGGER_THROW_NOTIFY
-#elif defined(DUK_OPT_NO_DEBUGGER_THROW_NOTIFY)
-#undef DUK_USE_DEBUGGER_THROW_NOTIFY
-#else
-#define DUK_USE_DEBUGGER_THROW_NOTIFY
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_TRANSPORT_TORTURE)
-#define DUK_USE_DEBUGGER_TRANSPORT_TORTURE
-#elif defined(DUK_OPT_NO_DEBUGGER_TRANSPORT_TORTURE)
-#undef DUK_USE_DEBUGGER_TRANSPORT_TORTURE
-#else
-#undef DUK_USE_DEBUGGER_TRANSPORT_TORTURE
-#endif
-
-#if defined(DUK_OPT_DEBUG_BUFSIZE)
-#define DUK_USE_DEBUG_BUFSIZE DUK_OPT_DEBUG_BUFSIZE
-#else
-#define DUK_USE_DEBUG_BUFSIZE 65536L
-#endif
-
-#if defined(DUK_OPT_REFERENCE_COUNTING)
-#define DUK_USE_DOUBLE_LINKED_HEAP
-#elif defined(DUK_OPT_NO_REFERENCE_COUNTING)
-#undef DUK_USE_DOUBLE_LINKED_HEAP
-#else
-#define DUK_USE_DOUBLE_LINKED_HEAP
-#endif
-
-#if defined(DUK_OPT_DPRINT)
-#define DUK_USE_DPRINT
-#elif defined(DUK_OPT_NO_DPRINT)
-#undef DUK_USE_DPRINT
-#else
-#undef DUK_USE_DPRINT
-#endif
-
-#if defined(DUK_OPT_DPRINT_COLORS)
-#define DUK_USE_DPRINT_COLORS
-#elif defined(DUK_OPT_NO_DPRINT_COLORS)
-#undef DUK_USE_DPRINT_COLORS
-#else
-#undef DUK_USE_DPRINT_COLORS
-#endif
-
-#if defined(DUK_OPT_DPRINT_RDTSC)
-#define DUK_USE_DPRINT_RDTSC
-#elif defined(DUK_OPT_NO_DPRINT_RDTSC)
-#undef DUK_USE_DPRINT_RDTSC
-#else
-#undef DUK_USE_DPRINT_RDTSC
-#endif
-
-#if defined(DUK_OPT_AUGMENT_ERRORS)
-#define DUK_USE_ERRCREATE
-#elif defined(DUK_OPT_NO_AUGMENT_ERRORS)
-#undef DUK_USE_ERRCREATE
-#else
-#define DUK_USE_ERRCREATE
-#endif
-
-#if defined(DUK_OPT_AUGMENT_ERRORS)
-#define DUK_USE_ERRTHROW
-#elif defined(DUK_OPT_NO_AUGMENT_ERRORS)
-#undef DUK_USE_ERRTHROW
-#else
-#define DUK_USE_ERRTHROW
-#endif
-
-#if defined(DUK_OPT_ES6_OBJECT_PROTO_PROPERTY)
-#define DUK_USE_ES6_OBJECT_PROTO_PROPERTY
-#elif defined(DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY)
-#undef DUK_USE_ES6_OBJECT_PROTO_PROPERTY
-#else
-#define DUK_USE_ES6_OBJECT_PROTO_PROPERTY
-#endif
-
-#if defined(DUK_OPT_ES6_OBJECT_SETPROTOTYPEOF)
-#define DUK_USE_ES6_OBJECT_SETPROTOTYPEOF
-#elif defined(DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF)
-#undef DUK_USE_ES6_OBJECT_SETPROTOTYPEOF
-#else
-#define DUK_USE_ES6_OBJECT_SETPROTOTYPEOF
-#endif
-
-#if defined(DUK_OPT_ES6_PROXY)
-#define DUK_USE_ES6_PROXY
-#elif defined(DUK_OPT_NO_ES6_PROXY)
-#undef DUK_USE_ES6_PROXY
-#else
-#define DUK_USE_ES6_PROXY
-#endif
-
-#if defined(DUK_OPT_ES6_REGEXP_BRACES)
-#define DUK_USE_ES6_REGEXP_BRACES
-#elif defined(DUK_OPT_NO_ES6_REGEXP_BRACES)
-#undef DUK_USE_ES6_REGEXP_BRACES
-#else
-#define DUK_USE_ES6_REGEXP_BRACES
-#endif
-
-#undef DUK_USE_EXEC_INDIRECT_BOUND_CHECK
-#if defined(DUK_OPT_DEBUG) || defined(DUK_OPT_ASSERTIONS)
-/* Enabled with debug/assertions just so that any issues can be caught. */
-#define DUK_USE_EXEC_INDIRECT_BOUND_CHECK
-#endif
-
-#undef DUK_USE_EXEC_TIMEOUT_CHECK
-#if defined(DUK_OPT_EXEC_TIMEOUT_CHECK)
-#define DUK_USE_EXEC_TIMEOUT_CHECK(udata) DUK_OPT_EXEC_TIMEOUT_CHECK((udata))
-#endif
-
-#undef DUK_USE_EXTSTR_FREE
-#if defined(DUK_OPT_EXTERNAL_STRINGS) && defined(DUK_OPT_EXTSTR_FREE)
-#define DUK_USE_EXTSTR_FREE(udata,ptr) DUK_OPT_EXTSTR_FREE((udata), (ptr))
-#endif
-
-#undef DUK_USE_EXTSTR_INTERN_CHECK
-#if defined(DUK_OPT_EXTERNAL_STRINGS) && defined(DUK_OPT_EXTSTR_INTERN_CHECK)
-#define DUK_USE_EXTSTR_INTERN_CHECK(udata,ptr,len) DUK_OPT_EXTSTR_INTERN_CHECK((udata), (ptr), (len))
-#endif
-
-/* Support for 48-bit signed integer duk_tval with transparent semantics. */
-#undef DUK_USE_FASTINT
-#if defined(DUK_OPT_FASTINT)
-#if !defined(DUK_F_HAVE_64BIT)
-#error DUK_OPT_FASTINT requires 64-bit integer type support at the moment
-#endif
-#define DUK_USE_FASTINT
-#endif
-
-#if defined(DUK_OPT_FILE_IO)
-#define DUK_USE_FILE_IO
-#elif defined(DUK_OPT_NO_FILE_IO)
-#undef DUK_USE_FILE_IO
-#else
-#define DUK_USE_FILE_IO
-#endif
-
-#if defined(DUK_OPT_FUNCPTR16)
-#define DUK_USE_FUNCPTR16
-#elif defined(DUK_OPT_NO_FUNCPTR16)
-#undef DUK_USE_FUNCPTR16
-#else
-#undef DUK_USE_FUNCPTR16
-#endif
-
-#if defined(DUK_OPT_FUNCPTR_DEC16)
-#define DUK_USE_FUNCPTR_DEC16(udata,ptr) DUK_OPT_FUNCPTR_DEC16((udata),(ptr))
-#else
-#undef DUK_USE_FUNCPTR_DEC16
-#endif
-
-#if defined(DUK_OPT_FUNCPTR_ENC16)
-#define DUK_USE_FUNCPTR_ENC16(udata,ptr) DUK_OPT_FUNCPTR_ENC16((udata),(ptr))
-#else
-#undef DUK_USE_FUNCPTR_ENC16
-#endif
-
-#if defined(DUK_OPT_GC_TORTURE)
-#define DUK_USE_GC_TORTURE
-#elif defined(DUK_OPT_NO_GC_TORTURE)
-#undef DUK_USE_GC_TORTURE
-#else
-#undef DUK_USE_GC_TORTURE
-#endif
-
-#if defined(DUK_OPT_HEAPPTR16)
-#define DUK_USE_HEAPPTR16
-#elif defined(DUK_OPT_NO_HEAPPTR16)
-#undef DUK_USE_HEAPPTR16
-#else
-#undef DUK_USE_HEAPPTR16
-#endif
-
-#if defined(DUK_OPT_HEAPPTR_DEC16)
-#define DUK_USE_HEAPPTR_DEC16(udata,ptr) DUK_OPT_HEAPPTR_DEC16((udata),(ptr))
-#else
-#undef DUK_USE_HEAPPTR_DEC16
-#endif
-
-#if defined(DUK_OPT_HEAPPTR_ENC16)
-#define DUK_USE_HEAPPTR_ENC16(udata,ptr) DUK_OPT_HEAPPTR_ENC16((udata),(ptr))
-#else
-#undef DUK_USE_HEAPPTR_ENC16
-#endif
-
-/* For now, hash part is dropped if and only if 16-bit object fields are used. */
-#define DUK_USE_HOBJECT_HASH_PART
-#if defined(DUK_OPT_OBJSIZES16)
-#undef DUK_USE_HOBJECT_HASH_PART
-#endif
-
-#if defined(DUK_OPT_HSTRING_CLEN)
-#define DUK_USE_HSTRING_CLEN
-#elif defined(DUK_OPT_NO_HSTRING_CLEN)
-#undef DUK_USE_HSTRING_CLEN
-#else
-#define DUK_USE_HSTRING_CLEN
-#endif
-
-#if defined(DUK_OPT_EXTERNAL_STRINGS)
-#define DUK_USE_HSTRING_EXTDATA
-#elif defined(DUK_OPT_NO_EXTERNAL_STRINGS)
-#undef DUK_USE_HSTRING_EXTDATA
-#else
-#undef DUK_USE_HSTRING_EXTDATA
-#endif
-
-#if defined(DUK_OPT_INTERRUPT_COUNTER)
-#define DUK_USE_INTERRUPT_COUNTER
-#elif defined(DUK_OPT_NO_INTERRUPT_COUNTER)
-#undef DUK_USE_INTERRUPT_COUNTER
-#else
-#undef DUK_USE_INTERRUPT_COUNTER
-#endif
-
-#if defined(DUK_OPT_JC)
-#define DUK_USE_JC
-#elif defined(DUK_OPT_NO_JC)
-#undef DUK_USE_JC
-#else
-#define DUK_USE_JC
-#endif
-
-#if defined(DUK_OPT_JSON_STRINGIFY_FASTPATH)
-#define DUK_USE_JSON_STRINGIFY_FASTPATH
-#elif defined(DUK_OPT_NO_JSON_STRINGIFY_FASTPATH)
-#undef DUK_USE_JSON_STRINGIFY_FASTPATH
-#else
-#undef DUK_USE_JSON_STRINGIFY_FASTPATH
-#endif
-
-#if defined(DUK_OPT_JX)
-#define DUK_USE_JX
-#elif defined(DUK_OPT_NO_JX)
-#undef DUK_USE_JX
-#else
-#define DUK_USE_JX
-#endif
-
-#if defined(DUK_OPT_LIGHTFUNC_BUILTINS)
-#define DUK_USE_LIGHTFUNC_BUILTINS
-#elif defined(DUK_OPT_NO_LIGHTFUNC_BUILTINS)
-#undef DUK_USE_LIGHTFUNC_BUILTINS
-#else
-#undef DUK_USE_LIGHTFUNC_BUILTINS
-#endif
-
-#if defined(DUK_OPT_MARK_AND_SWEEP)
-#define DUK_USE_MARK_AND_SWEEP
-#elif defined(DUK_OPT_NO_MARK_AND_SWEEP)
-#undef DUK_USE_MARK_AND_SWEEP
-#else
-#define DUK_USE_MARK_AND_SWEEP
-#endif
-
-#if defined(DUK_OPT_MS_STRINGTABLE_RESIZE)
-#define DUK_USE_MS_STRINGTABLE_RESIZE
-#elif defined(DUK_OPT_NO_MS_STRINGTABLE_RESIZE)
-#undef DUK_USE_MS_STRINGTABLE_RESIZE
-#else
-#define DUK_USE_MS_STRINGTABLE_RESIZE
-#endif
-
-#if defined(DUK_OPT_NONSTD_ARRAY_CONCAT_TRAILER)
-#define DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER
-#elif defined(DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER)
-#undef DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER
-#else
-#define DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER
-#endif
-
-#if defined(DUK_OPT_NONSTD_ARRAY_MAP_TRAILER)
-#define DUK_USE_NONSTD_ARRAY_MAP_TRAILER
-#elif defined(DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER)
-#undef DUK_USE_NONSTD_ARRAY_MAP_TRAILER
-#else
-#define DUK_USE_NONSTD_ARRAY_MAP_TRAILER
-#endif
-
-#if defined(DUK_OPT_NONSTD_ARRAY_SPLICE_DELCOUNT)
-#define DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
-#elif defined(DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT)
-#undef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
-#else
-#define DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
-#endif
-
-#if defined(DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY)
-#define DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
-#elif defined(DUK_OPT_NO_NONSTD_FUNC_CALLER_PROPERTY)
-#undef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
-#else
-#undef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
-#endif
-
-#if defined(DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY)
-#define DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY
-#elif defined(DUK_OPT_NO_NONSTD_FUNC_SOURCE_PROPERTY)
-#undef DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY
-#else
-#undef DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY
-#endif
-
-#if defined(DUK_OPT_NONSTD_FUNC_STMT)
-#define DUK_USE_NONSTD_FUNC_STMT
-#elif defined(DUK_OPT_NO_NONSTD_FUNC_STMT)
-#undef DUK_USE_NONSTD_FUNC_STMT
-#else
-#define DUK_USE_NONSTD_FUNC_STMT
-#endif
-
-#if defined(DUK_OPT_NONSTD_ACCESSOR_KEY_ARGUMENT)
-#define DUK_USE_NONSTD_GETTER_KEY_ARGUMENT
-#elif defined(DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT)
-#undef DUK_USE_NONSTD_GETTER_KEY_ARGUMENT
-#else
-#define DUK_USE_NONSTD_GETTER_KEY_ARGUMENT
-#endif
-
-#if defined(DUK_OPT_NONSTD_JSON_ESC_U2028_U2029)
-#define DUK_USE_NONSTD_JSON_ESC_U2028_U2029
-#elif defined(DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029)
-#undef DUK_USE_NONSTD_JSON_ESC_U2028_U2029
-#else
-#define DUK_USE_NONSTD_JSON_ESC_U2028_U2029
-#endif
-
-#if defined(DUK_OPT_NONSTD_REGEXP_DOLLAR_ESCAPE)
-#define DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE
-#elif defined(DUK_OPT_NO_NONSTD_REGEXP_DOLLAR_ESCAPE)
-#undef DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE
-#else
-#define DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE
-#endif
-
-#if defined(DUK_OPT_NONSTD_ACCESSOR_KEY_ARGUMENT)
-#define DUK_USE_NONSTD_SETTER_KEY_ARGUMENT
-#elif defined(DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT)
-#undef DUK_USE_NONSTD_SETTER_KEY_ARGUMENT
-#else
-#define DUK_USE_NONSTD_SETTER_KEY_ARGUMENT
-#endif
-
-#if defined(DUK_OPT_NONSTD_STRING_FROMCHARCODE_32BIT)
-#define DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT
-#elif defined(DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT)
-#undef DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT
-#else
-#define DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT
-#endif
-
-#if defined(DUK_OPT_OBJSIZES16)
-#define DUK_USE_OBJSIZES16
-#elif defined(DUK_OPT_NO_OBJSIZES16)
-#undef DUK_USE_OBJSIZES16
-#else
-#undef DUK_USE_OBJSIZES16
-#endif
-
-#if defined(DUK_OPT_OCTAL_SUPPORT)
-#define DUK_USE_OCTAL_SUPPORT
-#elif defined(DUK_OPT_NO_OCTAL_SUPPORT)
-#undef DUK_USE_OCTAL_SUPPORT
-#else
-#define DUK_USE_OCTAL_SUPPORT
-#endif
-
-#if defined(DUK_OPT_PACKED_TVAL)
-#define DUK_USE_PACKED_TVAL
-#elif defined(DUK_OPT_NO_PACKED_TVAL)
-#undef DUK_USE_PACKED_TVAL
-#else
-/* Already provided above */
-#endif
-
-#undef DUK_USE_PANIC_ABORT
-#if !defined(DUK_OPT_SEGFAULT_ON_PANIC)
-#define DUK_USE_PANIC_ABORT
-#endif
-
-#undef DUK_USE_PANIC_HANDLER
-#if defined(DUK_OPT_PANIC_HANDLER)
-#define DUK_USE_PANIC_HANDLER(code,msg) DUK_OPT_PANIC_HANDLER((code),(msg))
-#endif
-
-#undef DUK_USE_PANIC_SEGFAULT
-#if defined(DUK_OPT_SEGFAULT_ON_PANIC)
-#define DUK_USE_PANIC_SEGFAULT
-#endif
-
-#if defined(DUK_OPT_PARANOID_ERRORS)
-#define DUK_USE_PARANOID_ERRORS
-#elif defined(DUK_OPT_NO_PARANOID_ERRORS)
-#undef DUK_USE_PARANOID_ERRORS
-#else
-#undef DUK_USE_PARANOID_ERRORS
-#endif
-
-#if defined(DUK_OPT_PC2LINE)
-#define DUK_USE_PC2LINE
-#elif defined(DUK_OPT_NO_PC2LINE)
-#undef DUK_USE_PC2LINE
-#else
-#define DUK_USE_PC2LINE
-#endif
-
-#if defined(DUK_OPT_REFCOUNT16)
-#define DUK_USE_REFCOUNT16
-#elif defined(DUK_OPT_NO_REFCOUNT16)
-#undef DUK_USE_REFCOUNT16
-#else
-#undef DUK_USE_REFCOUNT16
-#endif
-
-#if defined(DUK_OPT_REFERENCE_COUNTING)
-#define DUK_USE_REFERENCE_COUNTING
-#elif defined(DUK_OPT_NO_REFERENCE_COUNTING)
-#undef DUK_USE_REFERENCE_COUNTING
-#else
-#define DUK_USE_REFERENCE_COUNTING
-#endif
-
-#if defined(DUK_OPT_REGEXP_CANON_WORKAROUND)
-#define DUK_USE_REGEXP_CANON_WORKAROUND
-#elif defined(DUK_OPT_NO_REGEXP_CANON_WORKAROUND)
-#undef DUK_USE_REGEXP_CANON_WORKAROUND
-#else
-#undef DUK_USE_REGEXP_CANON_WORKAROUND
-#endif
-
-#if defined(DUK_OPT_REGEXP_SUPPORT)
-#define DUK_USE_REGEXP_SUPPORT
-#elif defined(DUK_OPT_NO_REGEXP_SUPPORT)
-#undef DUK_USE_REGEXP_SUPPORT
-#else
-#define DUK_USE_REGEXP_SUPPORT
-#endif
-
-#if defined(DUK_OPT_ROM_GLOBAL_CLONE)
-#define DUK_USE_ROM_GLOBAL_CLONE
-#elif defined(DUK_OPT_NO_ROM_GLOBAL_CLONE)
-#undef DUK_USE_ROM_GLOBAL_CLONE
-#else
-#undef DUK_USE_ROM_GLOBAL_CLONE
-#endif
-
-#if defined(DUK_OPT_ROM_GLOBAL_INHERIT)
-#define DUK_USE_ROM_GLOBAL_INHERIT
-#elif defined(DUK_OPT_NO_ROM_GLOBAL_INHERIT)
-#undef DUK_USE_ROM_GLOBAL_INHERIT
-#else
-#undef DUK_USE_ROM_GLOBAL_INHERIT
-#endif
-
-#if defined(DUK_OPT_ROM_OBJECTS)
-#define DUK_USE_ROM_OBJECTS
-#elif defined(DUK_OPT_NO_ROM_OBJECTS)
-#undef DUK_USE_ROM_OBJECTS
-#else
-#undef DUK_USE_ROM_OBJECTS
-#endif
-
-#if defined(DUK_OPT_ROM_STRINGS)
-#define DUK_USE_ROM_STRINGS
-#elif defined(DUK_OPT_NO_ROM_STRINGS)
-#undef DUK_USE_ROM_STRINGS
-#else
-#undef DUK_USE_ROM_STRINGS
-#endif
-
-#if defined(DUK_OPT_SECTION_B)
-#define DUK_USE_SECTION_B
-#elif defined(DUK_OPT_NO_SECTION_B)
-#undef DUK_USE_SECTION_B
-#else
-#define DUK_USE_SECTION_B
-#endif
-
-#if defined(DUK_OPT_SELF_TESTS)
-#define DUK_USE_SELF_TESTS
-#elif defined(DUK_OPT_NO_SELF_TESTS)
-#undef DUK_USE_SELF_TESTS
-#else
-#undef DUK_USE_SELF_TESTS
-#endif
-
-#if defined(DUK_OPT_SHUFFLE_TORTURE)
-#define DUK_USE_SHUFFLE_TORTURE
-#elif defined(DUK_OPT_NO_SHUFFLE_TORTURE)
-#undef DUK_USE_SHUFFLE_TORTURE
-#else
-#undef DUK_USE_SHUFFLE_TORTURE
-#endif
-
-#if defined(DUK_OPT_SOURCE_NONBMP)
-#define DUK_USE_SOURCE_NONBMP
-#elif defined(DUK_OPT_NO_SOURCE_NONBMP)
-#undef DUK_USE_SOURCE_NONBMP
-#else
-#define DUK_USE_SOURCE_NONBMP
-#endif
-
-#if defined(DUK_OPT_STRHASH16)
-#define DUK_USE_STRHASH16
-#elif defined(DUK_OPT_NO_STRHASH16)
-#undef DUK_USE_STRHASH16
-#else
-#undef DUK_USE_STRHASH16
-#endif
-
-#if defined(DUK_OPT_STRICT_DECL)
-#define DUK_USE_STRICT_DECL
-#elif defined(DUK_OPT_NO_STRICT_DECL)
-#undef DUK_USE_STRICT_DECL
-#else
-#define DUK_USE_STRICT_DECL
-#endif
-
-#if defined(DUK_OPT_STRICT_UTF8_SOURCE)
-#define DUK_USE_STRICT_UTF8_SOURCE
-#elif defined(DUK_OPT_NO_STRICT_UTF8_SOURCE)
-#undef DUK_USE_STRICT_UTF8_SOURCE
-#else
-#undef DUK_USE_STRICT_UTF8_SOURCE
-#endif
-
-#if defined(DUK_OPT_STRLEN16)
-#define DUK_USE_STRLEN16
-#elif defined(DUK_OPT_NO_STRLEN16)
-#undef DUK_USE_STRLEN16
-#else
-#undef DUK_USE_STRLEN16
-#endif
-
-#undef DUK_USE_STRTAB_CHAIN
-#if defined(DUK_OPT_STRTAB_CHAIN) && defined(DUK_OPT_STRTAB_CHAIN_SIZE)
-#define DUK_USE_STRTAB_CHAIN
-#endif
-
-#undef DUK_USE_STRTAB_CHAIN_SIZE
-#if defined(DUK_OPT_STRTAB_CHAIN) && defined(DUK_OPT_STRTAB_CHAIN_SIZE)
-/* Low memory algorithm: separate chaining using arrays, fixed size hash */
-#define DUK_USE_STRTAB_CHAIN_SIZE DUK_OPT_STRTAB_CHAIN_SIZE
-#endif
-
-#undef DUK_USE_STRTAB_PROBE
-#if !(defined(DUK_OPT_STRTAB_CHAIN) && defined(DUK_OPT_STRTAB_CHAIN_SIZE))
-#define DUK_USE_STRTAB_PROBE
-#endif
-
-#if defined(DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY)
-#undef DUK_USE_TAILCALL
-#else
-#define DUK_USE_TAILCALL
-#endif
-
-#if defined(DUK_OPT_TARGET_INFO)
-#define DUK_USE_TARGET_INFO DUK_OPT_TARGET_INFO
-#else
-#define DUK_USE_TARGET_INFO "unknown"
-#endif
-
-#if defined(DUK_OPT_NO_AUGMENT_ERRORS)
-#undef DUK_USE_TRACEBACKS
-#elif defined(DUK_OPT_NO_TRACEBACKS)
-#undef DUK_USE_TRACEBACKS
-#else
-#define DUK_USE_TRACEBACKS
-#endif
-
-#if defined(DUK_OPT_TRACEBACK_DEPTH)
-#define DUK_USE_TRACEBACK_DEPTH DUK_OPT_TRACEBACK_DEPTH
-#else
-#define DUK_USE_TRACEBACK_DEPTH 10
-#endif
-
-#if defined(DUK_OPT_DECLARE)
-#define DUK_USE_USER_DECLARE() DUK_OPT_DECLARE
-#else
-#define DUK_USE_USER_DECLARE() /* no user declarations */
-#endif
-
-/* User provided InitJS. */
-#undef DUK_USE_USER_INITJS
-#if defined(DUK_OPT_USER_INITJS)
-#define DUK_USE_USER_INITJS (DUK_OPT_USER_INITJS)
-#endif
-
-#if defined(DUK_OPT_VERBOSE_ERRORS)
-#define DUK_USE_VERBOSE_ERRORS
-#elif defined(DUK_OPT_NO_VERBOSE_ERRORS)
-#undef DUK_USE_VERBOSE_ERRORS
-#else
-#define DUK_USE_VERBOSE_ERRORS
-#endif
-
-#if defined(DUK_OPT_VOLUNTARY_GC)
-#define DUK_USE_VOLUNTARY_GC
-#elif defined(DUK_OPT_NO_VOLUNTARY_GC)
-#undef DUK_USE_VOLUNTARY_GC
-#else
-#define DUK_USE_VOLUNTARY_GC
-#endif
-
-#if defined(DUK_OPT_ZERO_BUFFER_DATA)
-#define DUK_USE_ZERO_BUFFER_DATA
-#elif defined(DUK_OPT_NO_ZERO_BUFFER_DATA)
-#undef DUK_USE_ZERO_BUFFER_DATA
-#else
-#define DUK_USE_ZERO_BUFFER_DATA
-#endif
-
/*
* Autogenerated defaults
*/
+#define DUK_USE_ARRAY_BUILTIN
+#define DUK_USE_ARRAY_FASTPATH
+#define DUK_USE_ARRAY_PROP_FASTPATH
+#undef DUK_USE_ASSERTIONS
+#define DUK_USE_AUGMENT_ERROR_CREATE
+#define DUK_USE_AUGMENT_ERROR_THROW
#define DUK_USE_AVOID_PLATFORM_FUNCPTRS
#define DUK_USE_BASE64_FASTPATH
-#define DUK_USE_BUILTIN_INITJS
+#define DUK_USE_BOOLEAN_BUILTIN
+#define DUK_USE_BUFFEROBJECT_SUPPORT
+#undef DUK_USE_BUFLEN16
+#define DUK_USE_BYTECODE_DUMP_SUPPORT
+#define DUK_USE_CACHE_ACTIVATION
+#define DUK_USE_CACHE_CATCHER
+#define DUK_USE_CALLSTACK_LIMIT 10000
+#define DUK_USE_COMMONJS_MODULES
#define DUK_USE_COMPILER_RECLIMIT 2500
+#define DUK_USE_COROUTINE_SUPPORT
+#undef DUK_USE_CPP_EXCEPTIONS
+#undef DUK_USE_DATAPTR16
+#undef DUK_USE_DATAPTR_DEC16
+#undef DUK_USE_DATAPTR_ENC16
+#define DUK_USE_DATE_BUILTIN
#undef DUK_USE_DATE_FORMAT_STRING
#undef DUK_USE_DATE_GET_LOCAL_TZOFFSET
#undef DUK_USE_DATE_GET_NOW
#undef DUK_USE_DATE_PARSE_STRING
#undef DUK_USE_DATE_PRS_GETDATE
+#undef DUK_USE_DEBUG
+#undef DUK_USE_DEBUGGER_DUMPHEAP
+#undef DUK_USE_DEBUGGER_INSPECT
+#undef DUK_USE_DEBUGGER_PAUSE_UNCAUGHT
+#undef DUK_USE_DEBUGGER_SUPPORT
+#define DUK_USE_DEBUGGER_THROW_NOTIFY
+#undef DUK_USE_DEBUGGER_TRANSPORT_TORTURE
+#define DUK_USE_DEBUG_BUFSIZE 65536L
+#define DUK_USE_DEBUG_LEVEL 0
+#undef DUK_USE_DEBUG_WRITE
+#define DUK_USE_DOUBLE_LINKED_HEAP
+#define DUK_USE_DUKTAPE_BUILTIN
+#define DUK_USE_ENCODING_BUILTINS
+#define DUK_USE_ERRCREATE
+#define DUK_USE_ERRTHROW
+#define DUK_USE_ES6
+#define DUK_USE_ES6_OBJECT_PROTO_PROPERTY
+#define DUK_USE_ES6_OBJECT_SETPROTOTYPEOF
+#define DUK_USE_ES6_PROXY
+#define DUK_USE_ES6_REGEXP_SYNTAX
+#define DUK_USE_ES6_UNICODE_ESCAPE
+#define DUK_USE_ES7
+#define DUK_USE_ES7_EXP_OPERATOR
+#define DUK_USE_ES8
+#define DUK_USE_ES9
#define DUK_USE_ESBC_LIMITS
#define DUK_USE_ESBC_MAX_BYTES 2147418112L
#define DUK_USE_ESBC_MAX_LINENUMBER 2147418112L
#undef DUK_USE_EXEC_FUN_LOCAL
+#undef DUK_USE_EXEC_INDIRECT_BOUND_CHECK
+#undef DUK_USE_EXEC_PREFER_SIZE
+#define DUK_USE_EXEC_REGCONST_OPTIMIZE
+#undef DUK_USE_EXEC_TIMEOUT_CHECK
#undef DUK_USE_EXPLICIT_NULL_INIT
+#undef DUK_USE_EXTSTR_FREE
+#undef DUK_USE_EXTSTR_INTERN_CHECK
+#undef DUK_USE_FASTINT
#define DUK_USE_FAST_REFCOUNT_DEFAULT
+#undef DUK_USE_FATAL_HANDLER
+#define DUK_USE_FATAL_MAXLEN 128
+#define DUK_USE_FINALIZER_SUPPORT
+#undef DUK_USE_FINALIZER_TORTURE
+#undef DUK_USE_FUNCPTR16
+#undef DUK_USE_FUNCPTR_DEC16
+#undef DUK_USE_FUNCPTR_ENC16
+#define DUK_USE_FUNCTION_BUILTIN
+#define DUK_USE_FUNC_FILENAME_PROPERTY
+#define DUK_USE_FUNC_NAME_PROPERTY
+#undef DUK_USE_GC_TORTURE
+#undef DUK_USE_GET_MONOTONIC_TIME
+#undef DUK_USE_GET_RANDOM_DOUBLE
+#undef DUK_USE_GLOBAL_BINDING
+#define DUK_USE_GLOBAL_BUILTIN
+#undef DUK_USE_HEAPPTR16
+#undef DUK_USE_HEAPPTR_DEC16
+#undef DUK_USE_HEAPPTR_ENC16
#define DUK_USE_HEX_FASTPATH
+#define DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT 2
+#define DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT 9
+#define DUK_USE_HOBJECT_ARRAY_MINGROW_ADD 16
+#define DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR 8
+#define DUK_USE_HOBJECT_ENTRY_MINGROW_ADD 16
+#define DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR 8
+#define DUK_USE_HOBJECT_HASH_PART
+#define DUK_USE_HOBJECT_HASH_PROP_LIMIT 8
+#define DUK_USE_HSTRING_ARRIDX
+#define DUK_USE_HSTRING_CLEN
+#undef DUK_USE_HSTRING_EXTDATA
+#define DUK_USE_HSTRING_LAZY_CLEN
+#define DUK_USE_HTML_COMMENTS
#define DUK_USE_IDCHAR_FASTPATH
+#undef DUK_USE_INJECT_HEAP_ALLOC_ERROR
+#undef DUK_USE_INTERRUPT_COUNTER
#undef DUK_USE_INTERRUPT_DEBUG_FIXUP
+#define DUK_USE_JC
+#define DUK_USE_JSON_BUILTIN
#define DUK_USE_JSON_DECNUMBER_FASTPATH
#define DUK_USE_JSON_DECSTRING_FASTPATH
#define DUK_USE_JSON_DEC_RECLIMIT 1000
#define DUK_USE_JSON_EATWHITE_FASTPATH
#define DUK_USE_JSON_ENC_RECLIMIT 1000
#define DUK_USE_JSON_QUOTESTRING_FASTPATH
+#undef DUK_USE_JSON_STRINGIFY_FASTPATH
+#define DUK_USE_JSON_SUPPORT
+#define DUK_USE_JX
#define DUK_USE_LEXER_SLIDING_WINDOW
-#undef DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE
+#undef DUK_USE_LIGHTFUNC_BUILTINS
#define DUK_USE_MARK_AND_SWEEP_RECLIMIT 256
#define DUK_USE_MATH_BUILTIN
#define DUK_USE_NATIVE_CALL_RECLIMIT 1000
-#undef DUK_USE_PANIC_EXIT
+#define DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER
+#define DUK_USE_NONSTD_ARRAY_MAP_TRAILER
+#define DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
+#undef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+#undef DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY
+#define DUK_USE_NONSTD_FUNC_STMT
+#define DUK_USE_NONSTD_GETTER_KEY_ARGUMENT
+#define DUK_USE_NONSTD_JSON_ESC_U2028_U2029
+#define DUK_USE_NONSTD_SETTER_KEY_ARGUMENT
+#define DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT
+#define DUK_USE_NUMBER_BUILTIN
+#define DUK_USE_OBJECT_BUILTIN
+#undef DUK_USE_OBJSIZES16
+#undef DUK_USE_PARANOID_ERRORS
+#define DUK_USE_PC2LINE
+#define DUK_USE_PERFORMANCE_BUILTIN
#undef DUK_USE_PREFER_SIZE
+#undef DUK_USE_PROMISE_BUILTIN
#define DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS
-#undef DUK_USE_REFZERO_FINALIZER_TORTURE
+#undef DUK_USE_REFCOUNT16
+#define DUK_USE_REFCOUNT32
+#define DUK_USE_REFERENCE_COUNTING
+#define DUK_USE_REFLECT_BUILTIN
+#define DUK_USE_REGEXP_CANON_BITMAP
+#undef DUK_USE_REGEXP_CANON_WORKAROUND
#define DUK_USE_REGEXP_COMPILER_RECLIMIT 10000
#define DUK_USE_REGEXP_EXECUTOR_RECLIMIT 10000
+#define DUK_USE_REGEXP_SUPPORT
+#undef DUK_USE_ROM_GLOBAL_CLONE
+#undef DUK_USE_ROM_GLOBAL_INHERIT
+#undef DUK_USE_ROM_OBJECTS
#define DUK_USE_ROM_PTRCOMP_FIRST 63488L
+#undef DUK_USE_ROM_STRINGS
+#define DUK_USE_SECTION_B
+#undef DUK_USE_SELF_TESTS
+#define DUK_USE_SHEBANG_COMMENTS
+#undef DUK_USE_SHUFFLE_TORTURE
+#define DUK_USE_SOURCE_NONBMP
+#undef DUK_USE_STRHASH16
#undef DUK_USE_STRHASH_DENSE
#define DUK_USE_STRHASH_SKIP_SHIFT 5
+#define DUK_USE_STRICT_DECL
+#undef DUK_USE_STRICT_UTF8_SOURCE
+#define DUK_USE_STRING_BUILTIN
+#undef DUK_USE_STRLEN16
+#define DUK_USE_STRTAB_GROW_LIMIT 17
+#define DUK_USE_STRTAB_MAXSIZE 268435456L
+#define DUK_USE_STRTAB_MINSIZE 1024
+#undef DUK_USE_STRTAB_PTRCOMP
+#define DUK_USE_STRTAB_RESIZE_CHECK_MASK 255
+#define DUK_USE_STRTAB_SHRINK_LIMIT 6
+#undef DUK_USE_STRTAB_TORTURE
+#undef DUK_USE_SYMBOL_BUILTIN
+#define DUK_USE_TAILCALL
+#define DUK_USE_TARGET_INFO "unknown"
+#define DUK_USE_TRACEBACKS
+#define DUK_USE_TRACEBACK_DEPTH 10
+#define DUK_USE_USER_DECLARE() /* no user declarations */
+#define DUK_USE_VALSTACK_GROW_SHIFT 2
+#define DUK_USE_VALSTACK_LIMIT 1000000L
+#define DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT 2
+#define DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT 4
#undef DUK_USE_VALSTACK_UNSAFE
+#define DUK_USE_VERBOSE_ERRORS
#define DUK_USE_VERBOSE_EXECUTOR_ERRORS
-
-/*
- * Alternative customization header
- *
- * If you want to modify the final DUK_USE_xxx flags directly (without
- * using the available DUK_OPT_xxx flags), define DUK_OPT_HAVE_CUSTOM_H
- * and tweak the final flags there.
- */
-
-#if defined(DUK_OPT_HAVE_CUSTOM_H)
-#include "duk_custom.h"
-#endif
+#define DUK_USE_VOLUNTARY_GC
+#define DUK_USE_ZERO_BUFFER_DATA
/*
* You may add overriding #define/#undef directives below for
@@ -3562,21 +3024,25 @@ typedef FILE duk_file;
#if defined(DUK_USE_DATE_GET_NOW)
/* External provider already defined. */
#elif defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
-#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_gettimeofday((ctx))
+#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_gettimeofday()
#elif defined(DUK_USE_DATE_NOW_TIME)
-#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_time((ctx))
+#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_time()
#elif defined(DUK_USE_DATE_NOW_WINDOWS)
-#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_windows((ctx))
+#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_windows()
+#elif defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS)
+#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_windows_subms()
#else
#error no provider for DUK_USE_DATE_GET_NOW()
#endif
#if defined(DUK_USE_DATE_GET_LOCAL_TZOFFSET)
/* External provider already defined. */
-#elif defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME)
+#elif defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S) || defined(DUK_USE_DATE_TZO_GMTIME)
#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_gmtime((d))
#elif defined(DUK_USE_DATE_TZO_WINDOWS)
#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows((d))
+#elif defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST)
+#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows_no_dst((d))
#else
#error no provider for DUK_USE_DATE_GET_LOCAL_TZOFFSET()
#endif
@@ -3600,8 +3066,317 @@ typedef FILE duk_file;
/* No provider for DUK_USE_DATE_FORMAT_STRING(), fall back to ISO 8601 only. */
#endif
+#if defined(DUK_USE_GET_MONOTONIC_TIME)
+/* External provider already defined. */
+#elif defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME)
+#define DUK_USE_GET_MONOTONIC_TIME(ctx) duk_bi_date_get_monotonic_time_clock_gettime()
+#elif defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC)
+#define DUK_USE_GET_MONOTONIC_TIME(ctx) duk_bi_date_get_monotonic_time_windows_qpc()
+#else
+/* No provider for DUK_USE_GET_MONOTONIC_TIME(), fall back to DUK_USE_DATE_GET_NOW(). */
+#endif
+
#endif /* DUK_COMPILING_DUKTAPE */
+/*
+ * Checks for legacy feature options (DUK_OPT_xxx)
+ */
+
+#if defined(DUK_OPT_ASSERTIONS)
+#error unsupported legacy feature option DUK_OPT_ASSERTIONS used
+#endif
+#if defined(DUK_OPT_BUFFEROBJECT_SUPPORT)
+#error unsupported legacy feature option DUK_OPT_BUFFEROBJECT_SUPPORT used
+#endif
+#if defined(DUK_OPT_BUFLEN16)
+#error unsupported legacy feature option DUK_OPT_BUFLEN16 used
+#endif
+#if defined(DUK_OPT_DATAPTR16)
+#error unsupported legacy feature option DUK_OPT_DATAPTR16 used
+#endif
+#if defined(DUK_OPT_DATAPTR_DEC16)
+#error unsupported legacy feature option DUK_OPT_DATAPTR_DEC16 used
+#endif
+#if defined(DUK_OPT_DATAPTR_ENC16)
+#error unsupported legacy feature option DUK_OPT_DATAPTR_ENC16 used
+#endif
+#if defined(DUK_OPT_DDDPRINT)
+#error unsupported legacy feature option DUK_OPT_DDDPRINT used
+#endif
+#if defined(DUK_OPT_DDPRINT)
+#error unsupported legacy feature option DUK_OPT_DDPRINT used
+#endif
+#if defined(DUK_OPT_DEBUG)
+#error unsupported legacy feature option DUK_OPT_DEBUG used
+#endif
+#if defined(DUK_OPT_DEBUGGER_DUMPHEAP)
+#error unsupported legacy feature option DUK_OPT_DEBUGGER_DUMPHEAP used
+#endif
+#if defined(DUK_OPT_DEBUGGER_FWD_LOGGING)
+#error unsupported legacy feature option DUK_OPT_DEBUGGER_FWD_LOGGING used
+#endif
+#if defined(DUK_OPT_DEBUGGER_FWD_PRINTALERT)
+#error unsupported legacy feature option DUK_OPT_DEBUGGER_FWD_PRINTALERT used
+#endif
+#if defined(DUK_OPT_DEBUGGER_SUPPORT)
+#error unsupported legacy feature option DUK_OPT_DEBUGGER_SUPPORT used
+#endif
+#if defined(DUK_OPT_DEBUGGER_TRANSPORT_TORTURE)
+#error unsupported legacy feature option DUK_OPT_DEBUGGER_TRANSPORT_TORTURE used
+#endif
+#if defined(DUK_OPT_DEBUG_BUFSIZE)
+#error unsupported legacy feature option DUK_OPT_DEBUG_BUFSIZE used
+#endif
+#if defined(DUK_OPT_DECLARE)
+#error unsupported legacy feature option DUK_OPT_DECLARE used
+#endif
+#if defined(DUK_OPT_DEEP_C_STACK)
+#error unsupported legacy feature option DUK_OPT_DEEP_C_STACK used
+#endif
+#if defined(DUK_OPT_DLL_BUILD)
+#error unsupported legacy feature option DUK_OPT_DLL_BUILD used
+#endif
+#if defined(DUK_OPT_DPRINT)
+#error unsupported legacy feature option DUK_OPT_DPRINT used
+#endif
+#if defined(DUK_OPT_DPRINT_COLORS)
+#error unsupported legacy feature option DUK_OPT_DPRINT_COLORS used
+#endif
+#if defined(DUK_OPT_DPRINT_RDTSC)
+#error unsupported legacy feature option DUK_OPT_DPRINT_RDTSC used
+#endif
+#if defined(DUK_OPT_EXEC_TIMEOUT_CHECK)
+#error unsupported legacy feature option DUK_OPT_EXEC_TIMEOUT_CHECK used
+#endif
+#if defined(DUK_OPT_EXTERNAL_STRINGS)
+#error unsupported legacy feature option DUK_OPT_EXTERNAL_STRINGS used
+#endif
+#if defined(DUK_OPT_EXTSTR_FREE)
+#error unsupported legacy feature option DUK_OPT_EXTSTR_FREE used
+#endif
+#if defined(DUK_OPT_EXTSTR_INTERN_CHECK)
+#error unsupported legacy feature option DUK_OPT_EXTSTR_INTERN_CHECK used
+#endif
+#if defined(DUK_OPT_FASTINT)
+#error unsupported legacy feature option DUK_OPT_FASTINT used
+#endif
+#if defined(DUK_OPT_FORCE_ALIGN)
+#error unsupported legacy feature option DUK_OPT_FORCE_ALIGN used
+#endif
+#if defined(DUK_OPT_FORCE_BYTEORDER)
+#error unsupported legacy feature option DUK_OPT_FORCE_BYTEORDER used
+#endif
+#if defined(DUK_OPT_FUNCPTR16)
+#error unsupported legacy feature option DUK_OPT_FUNCPTR16 used
+#endif
+#if defined(DUK_OPT_FUNCPTR_DEC16)
+#error unsupported legacy feature option DUK_OPT_FUNCPTR_DEC16 used
+#endif
+#if defined(DUK_OPT_FUNCPTR_ENC16)
+#error unsupported legacy feature option DUK_OPT_FUNCPTR_ENC16 used
+#endif
+#if defined(DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY)
+#error unsupported legacy feature option DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY used
+#endif
+#if defined(DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY)
+#error unsupported legacy feature option DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY used
+#endif
+#if defined(DUK_OPT_GC_TORTURE)
+#error unsupported legacy feature option DUK_OPT_GC_TORTURE used
+#endif
+#if defined(DUK_OPT_HAVE_CUSTOM_H)
+#error unsupported legacy feature option DUK_OPT_HAVE_CUSTOM_H used
+#endif
+#if defined(DUK_OPT_HEAPPTR16)
+#error unsupported legacy feature option DUK_OPT_HEAPPTR16 used
+#endif
+#if defined(DUK_OPT_HEAPPTR_DEC16)
+#error unsupported legacy feature option DUK_OPT_HEAPPTR_DEC16 used
+#endif
+#if defined(DUK_OPT_HEAPPTR_ENC16)
+#error unsupported legacy feature option DUK_OPT_HEAPPTR_ENC16 used
+#endif
+#if defined(DUK_OPT_INTERRUPT_COUNTER)
+#error unsupported legacy feature option DUK_OPT_INTERRUPT_COUNTER used
+#endif
+#if defined(DUK_OPT_JSON_STRINGIFY_FASTPATH)
+#error unsupported legacy feature option DUK_OPT_JSON_STRINGIFY_FASTPATH used
+#endif
+#if defined(DUK_OPT_LIGHTFUNC_BUILTINS)
+#error unsupported legacy feature option DUK_OPT_LIGHTFUNC_BUILTINS used
+#endif
+#if defined(DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY)
+#error unsupported legacy feature option DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY used
+#endif
+#if defined(DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY)
+#error unsupported legacy feature option DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY used
+#endif
+#if defined(DUK_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT)
+#error unsupported legacy feature option DUK_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT used
+#endif
+#if defined(DUK_OPT_NO_AUGMENT_ERRORS)
+#error unsupported legacy feature option DUK_OPT_NO_AUGMENT_ERRORS used
+#endif
+#if defined(DUK_OPT_NO_BROWSER_LIKE)
+#error unsupported legacy feature option DUK_OPT_NO_BROWSER_LIKE used
+#endif
+#if defined(DUK_OPT_NO_BUFFEROBJECT_SUPPORT)
+#error unsupported legacy feature option DUK_OPT_NO_BUFFEROBJECT_SUPPORT used
+#endif
+#if defined(DUK_OPT_NO_BYTECODE_DUMP_SUPPORT)
+#error unsupported legacy feature option DUK_OPT_NO_BYTECODE_DUMP_SUPPORT used
+#endif
+#if defined(DUK_OPT_NO_COMMONJS_MODULES)
+#error unsupported legacy feature option DUK_OPT_NO_COMMONJS_MODULES used
+#endif
+#if defined(DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY)
+#error unsupported legacy feature option DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY used
+#endif
+#if defined(DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF)
+#error unsupported legacy feature option DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF used
+#endif
+#if defined(DUK_OPT_NO_ES6_PROXY)
+#error unsupported legacy feature option DUK_OPT_NO_ES6_PROXY used
+#endif
+#if defined(DUK_OPT_NO_FILE_IO)
+#error unsupported legacy feature option DUK_OPT_NO_FILE_IO used
+#endif
+#if defined(DUK_OPT_NO_FUNC_STMT)
+#error unsupported legacy feature option DUK_OPT_NO_FUNC_STMT used
+#endif
+#if defined(DUK_OPT_NO_JC)
+#error unsupported legacy feature option DUK_OPT_NO_JC used
+#endif
+#if defined(DUK_OPT_NO_JSONC)
+#error unsupported legacy feature option DUK_OPT_NO_JSONC used
+#endif
+#if defined(DUK_OPT_NO_JSONX)
+#error unsupported legacy feature option DUK_OPT_NO_JSONX used
+#endif
+#if defined(DUK_OPT_NO_JX)
+#error unsupported legacy feature option DUK_OPT_NO_JX used
+#endif
+#if defined(DUK_OPT_NO_MARK_AND_SWEEP)
+#error unsupported legacy feature option DUK_OPT_NO_MARK_AND_SWEEP used
+#endif
+#if defined(DUK_OPT_NO_MS_STRINGTABLE_RESIZE)
+#error unsupported legacy feature option DUK_OPT_NO_MS_STRINGTABLE_RESIZE used
+#endif
+#if defined(DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT)
+#error unsupported legacy feature option DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT used
+#endif
+#if defined(DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER)
+#error unsupported legacy feature option DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER used
+#endif
+#if defined(DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER)
+#error unsupported legacy feature option DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER used
+#endif
+#if defined(DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT)
+#error unsupported legacy feature option DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT used
+#endif
+#if defined(DUK_OPT_NO_NONSTD_FUNC_STMT)
+#error unsupported legacy feature option DUK_OPT_NO_NONSTD_FUNC_STMT used
+#endif
+#if defined(DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029)
+#error unsupported legacy feature option DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029 used
+#endif
+#if defined(DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT)
+#error unsupported legacy feature option DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT used
+#endif
+#if defined(DUK_OPT_NO_OBJECT_ES6_PROTO_PROPERTY)
+#error unsupported legacy feature option DUK_OPT_NO_OBJECT_ES6_PROTO_PROPERTY used
+#endif
+#if defined(DUK_OPT_NO_OBJECT_ES6_SETPROTOTYPEOF)
+#error unsupported legacy feature option DUK_OPT_NO_OBJECT_ES6_SETPROTOTYPEOF used
+#endif
+#if defined(DUK_OPT_NO_OCTAL_SUPPORT)
+#error unsupported legacy feature option DUK_OPT_NO_OCTAL_SUPPORT used
+#endif
+#if defined(DUK_OPT_NO_PACKED_TVAL)
+#error unsupported legacy feature option DUK_OPT_NO_PACKED_TVAL used
+#endif
+#if defined(DUK_OPT_NO_PC2LINE)
+#error unsupported legacy feature option DUK_OPT_NO_PC2LINE used
+#endif
+#if defined(DUK_OPT_NO_REFERENCE_COUNTING)
+#error unsupported legacy feature option DUK_OPT_NO_REFERENCE_COUNTING used
+#endif
+#if defined(DUK_OPT_NO_REGEXP_SUPPORT)
+#error unsupported legacy feature option DUK_OPT_NO_REGEXP_SUPPORT used
+#endif
+#if defined(DUK_OPT_NO_SECTION_B)
+#error unsupported legacy feature option DUK_OPT_NO_SECTION_B used
+#endif
+#if defined(DUK_OPT_NO_SOURCE_NONBMP)
+#error unsupported legacy feature option DUK_OPT_NO_SOURCE_NONBMP used
+#endif
+#if defined(DUK_OPT_NO_STRICT_DECL)
+#error unsupported legacy feature option DUK_OPT_NO_STRICT_DECL used
+#endif
+#if defined(DUK_OPT_NO_TRACEBACKS)
+#error unsupported legacy feature option DUK_OPT_NO_TRACEBACKS used
+#endif
+#if defined(DUK_OPT_NO_VERBOSE_ERRORS)
+#error unsupported legacy feature option DUK_OPT_NO_VERBOSE_ERRORS used
+#endif
+#if defined(DUK_OPT_NO_VOLUNTARY_GC)
+#error unsupported legacy feature option DUK_OPT_NO_VOLUNTARY_GC used
+#endif
+#if defined(DUK_OPT_NO_ZERO_BUFFER_DATA)
+#error unsupported legacy feature option DUK_OPT_NO_ZERO_BUFFER_DATA used
+#endif
+#if defined(DUK_OPT_OBJSIZES16)
+#error unsupported legacy feature option DUK_OPT_OBJSIZES16 used
+#endif
+#if defined(DUK_OPT_PANIC_HANDLER)
+#error unsupported legacy feature option DUK_OPT_PANIC_HANDLER used
+#endif
+#if defined(DUK_OPT_REFCOUNT16)
+#error unsupported legacy feature option DUK_OPT_REFCOUNT16 used
+#endif
+#if defined(DUK_OPT_SEGFAULT_ON_PANIC)
+#error unsupported legacy feature option DUK_OPT_SEGFAULT_ON_PANIC used
+#endif
+#if defined(DUK_OPT_SELF_TESTS)
+#error unsupported legacy feature option DUK_OPT_SELF_TESTS used
+#endif
+#if defined(DUK_OPT_SETJMP)
+#error unsupported legacy feature option DUK_OPT_SETJMP used
+#endif
+#if defined(DUK_OPT_SHUFFLE_TORTURE)
+#error unsupported legacy feature option DUK_OPT_SHUFFLE_TORTURE used
+#endif
+#if defined(DUK_OPT_SIGSETJMP)
+#error unsupported legacy feature option DUK_OPT_SIGSETJMP used
+#endif
+#if defined(DUK_OPT_STRHASH16)
+#error unsupported legacy feature option DUK_OPT_STRHASH16 used
+#endif
+#if defined(DUK_OPT_STRICT_UTF8_SOURCE)
+#error unsupported legacy feature option DUK_OPT_STRICT_UTF8_SOURCE used
+#endif
+#if defined(DUK_OPT_STRLEN16)
+#error unsupported legacy feature option DUK_OPT_STRLEN16 used
+#endif
+#if defined(DUK_OPT_STRTAB_CHAIN)
+#error unsupported legacy feature option DUK_OPT_STRTAB_CHAIN used
+#endif
+#if defined(DUK_OPT_STRTAB_CHAIN_SIZE)
+#error unsupported legacy feature option DUK_OPT_STRTAB_CHAIN_SIZE used
+#endif
+#if defined(DUK_OPT_TARGET_INFO)
+#error unsupported legacy feature option DUK_OPT_TARGET_INFO used
+#endif
+#if defined(DUK_OPT_TRACEBACK_DEPTH)
+#error unsupported legacy feature option DUK_OPT_TRACEBACK_DEPTH used
+#endif
+#if defined(DUK_OPT_UNDERSCORE_SETJMP)
+#error unsupported legacy feature option DUK_OPT_UNDERSCORE_SETJMP used
+#endif
+#if defined(DUK_OPT_USER_INITJS)
+#error unsupported legacy feature option DUK_OPT_USER_INITJS used
+#endif
+
/*
* Checks for config option consistency (DUK_USE_xxx)
*/
@@ -3615,6 +3390,12 @@ typedef FILE duk_file;
#if defined(DUK_USE_ALIGN_8)
#error unsupported config option used (option has been removed): DUK_USE_ALIGN_8
#endif
+#if defined(DUK_USE_BROWSER_LIKE)
+#error unsupported config option used (option has been removed): DUK_USE_BROWSER_LIKE
+#endif
+#if defined(DUK_USE_BUILTIN_INITJS)
+#error unsupported config option used (option has been removed): DUK_USE_BUILTIN_INITJS
+#endif
#if defined(DUK_USE_BYTEORDER_FORCED)
#error unsupported config option used (option has been removed): DUK_USE_BYTEORDER_FORCED
#endif
@@ -3624,6 +3405,18 @@ typedef FILE duk_file;
#if defined(DUK_USE_DATAPTR_ENC16) && !defined(DUK_USE_DATAPTR16)
#error config option DUK_USE_DATAPTR_ENC16 requires option DUK_USE_DATAPTR16 (which is missing)
#endif
+#if defined(DUK_USE_DDDPRINT)
+#error unsupported config option used (option has been removed): DUK_USE_DDDPRINT
+#endif
+#if defined(DUK_USE_DDPRINT)
+#error unsupported config option used (option has been removed): DUK_USE_DDPRINT
+#endif
+#if defined(DUK_USE_DEBUGGER_FWD_LOGGING)
+#error unsupported config option used (option has been removed): DUK_USE_DEBUGGER_FWD_LOGGING
+#endif
+#if defined(DUK_USE_DEBUGGER_FWD_PRINTALERT)
+#error unsupported config option used (option has been removed): DUK_USE_DEBUGGER_FWD_PRINTALERT
+#endif
#if defined(DUK_USE_DEBUGGER_SUPPORT) && !defined(DUK_USE_INTERRUPT_COUNTER)
#error config option DUK_USE_DEBUGGER_SUPPORT requires option DUK_USE_INTERRUPT_COUNTER (which is missing)
#endif
@@ -3657,9 +3450,21 @@ typedef FILE duk_file;
#if defined(DUK_USE_DOUBLE_ME) && defined(DUK_USE_DOUBLE_BE)
#error config option DUK_USE_DOUBLE_ME conflicts with option DUK_USE_DOUBLE_BE (which is also defined)
#endif
+#if defined(DUK_USE_DPRINT)
+#error unsupported config option used (option has been removed): DUK_USE_DPRINT
+#endif
#if defined(DUK_USE_DPRINT) && !defined(DUK_USE_DEBUG)
#error config option DUK_USE_DPRINT requires option DUK_USE_DEBUG (which is missing)
#endif
+#if defined(DUK_USE_DPRINT_COLORS)
+#error unsupported config option used (option has been removed): DUK_USE_DPRINT_COLORS
+#endif
+#if defined(DUK_USE_DPRINT_RDTSC)
+#error unsupported config option used (option has been removed): DUK_USE_DPRINT_RDTSC
+#endif
+#if defined(DUK_USE_ES6_REGEXP_BRACES)
+#error unsupported config option used (option has been removed): DUK_USE_ES6_REGEXP_BRACES
+#endif
#if defined(DUK_USE_ESBC_MAX_BYTES) && !defined(DUK_USE_ESBC_LIMITS)
#error config option DUK_USE_ESBC_MAX_BYTES requires option DUK_USE_ESBC_LIMITS (which is missing)
#endif
@@ -3675,6 +3480,12 @@ typedef FILE duk_file;
#if defined(DUK_USE_EXTSTR_INTERN_CHECK) && !defined(DUK_USE_HSTRING_EXTDATA)
#error config option DUK_USE_EXTSTR_INTERN_CHECK requires option DUK_USE_HSTRING_EXTDATA (which is missing)
#endif
+#if defined(DUK_USE_FASTINT) && !defined(DUK_USE_64BIT_OPS)
+#error config option DUK_USE_FASTINT requires option DUK_USE_64BIT_OPS (which is missing)
+#endif
+#if defined(DUK_USE_FILE_IO)
+#error unsupported config option used (option has been removed): DUK_USE_FILE_IO
+#endif
#if defined(DUK_USE_FULL_TVAL)
#error unsupported config option used (option has been removed): DUK_USE_FULL_TVAL
#endif
@@ -3723,15 +3534,57 @@ typedef FILE duk_file;
#if defined(DUK_USE_INTEGER_ME) && defined(DUK_USE_INTEGER_BE)
#error config option DUK_USE_INTEGER_ME conflicts with option DUK_USE_INTEGER_BE (which is also defined)
#endif
+#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE)
+#error unsupported config option used (option has been removed): DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE
+#endif
+#if defined(DUK_USE_MARK_AND_SWEEP)
+#error unsupported config option used (option has been removed): DUK_USE_MARK_AND_SWEEP
+#endif
+#if defined(DUK_USE_MATH_FMAX)
+#error unsupported config option used (option has been removed): DUK_USE_MATH_FMAX
+#endif
+#if defined(DUK_USE_MATH_FMIN)
+#error unsupported config option used (option has been removed): DUK_USE_MATH_FMIN
+#endif
+#if defined(DUK_USE_MATH_ROUND)
+#error unsupported config option used (option has been removed): DUK_USE_MATH_ROUND
+#endif
+#if defined(DUK_USE_MS_STRINGTABLE_RESIZE)
+#error unsupported config option used (option has been removed): DUK_USE_MS_STRINGTABLE_RESIZE
+#endif
+#if defined(DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE)
+#error unsupported config option used (option has been removed): DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE
+#endif
#if defined(DUK_USE_NO_DOUBLE_ALIASING_SELFTEST)
#error unsupported config option used (option has been removed): DUK_USE_NO_DOUBLE_ALIASING_SELFTEST
#endif
+#if defined(DUK_USE_OCTAL_SUPPORT)
+#error unsupported config option used (option has been removed): DUK_USE_OCTAL_SUPPORT
+#endif
#if defined(DUK_USE_PACKED_TVAL_POSSIBLE)
#error unsupported config option used (option has been removed): DUK_USE_PACKED_TVAL_POSSIBLE
#endif
+#if defined(DUK_USE_PANIC_ABORT)
+#error unsupported config option used (option has been removed): DUK_USE_PANIC_ABORT
+#endif
+#if defined(DUK_USE_PANIC_EXIT)
+#error unsupported config option used (option has been removed): DUK_USE_PANIC_EXIT
+#endif
+#if defined(DUK_USE_PANIC_HANDLER)
+#error unsupported config option used (option has been removed): DUK_USE_PANIC_HANDLER
+#endif
+#if defined(DUK_USE_PANIC_SEGFAULT)
+#error unsupported config option used (option has been removed): DUK_USE_PANIC_SEGFAULT
+#endif
+#if defined(DUK_USE_POW_NETBSD_WORKAROUND)
+#error unsupported config option used (option has been removed): DUK_USE_POW_NETBSD_WORKAROUND
+#endif
#if defined(DUK_USE_RDTSC)
#error unsupported config option used (option has been removed): DUK_USE_RDTSC
#endif
+#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE)
+#error unsupported config option used (option has been removed): DUK_USE_REFZERO_FINALIZER_TORTURE
+#endif
#if defined(DUK_USE_ROM_GLOBAL_CLONE) && !defined(DUK_USE_ROM_STRINGS)
#error config option DUK_USE_ROM_GLOBAL_CLONE requires option DUK_USE_ROM_STRINGS (which is missing)
#endif
@@ -3762,9 +3615,21 @@ typedef FILE duk_file;
#if defined(DUK_USE_SIGSETJMP)
#error unsupported config option used (option has been removed): DUK_USE_SIGSETJMP
#endif
+#if defined(DUK_USE_STRTAB_CHAIN)
+#error unsupported config option used (option has been removed): DUK_USE_STRTAB_CHAIN
+#endif
+#if defined(DUK_USE_STRTAB_CHAIN_SIZE)
+#error unsupported config option used (option has been removed): DUK_USE_STRTAB_CHAIN_SIZE
+#endif
#if defined(DUK_USE_STRTAB_CHAIN_SIZE) && !defined(DUK_USE_STRTAB_CHAIN)
#error config option DUK_USE_STRTAB_CHAIN_SIZE requires option DUK_USE_STRTAB_CHAIN (which is missing)
#endif
+#if defined(DUK_USE_STRTAB_PROBE)
+#error unsupported config option used (option has been removed): DUK_USE_STRTAB_PROBE
+#endif
+#if defined(DUK_USE_STRTAB_PTRCOMP) && !defined(DUK_USE_HEAPPTR16)
+#error config option DUK_USE_STRTAB_PTRCOMP requires option DUK_USE_HEAPPTR16 (which is missing)
+#endif
#if defined(DUK_USE_TAILCALL) && defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
#error config option DUK_USE_TAILCALL conflicts with option DUK_USE_NONSTD_FUNC_CALLER_PROPERTY (which is also defined)
#endif
@@ -3774,6 +3639,9 @@ typedef FILE duk_file;
#if defined(DUK_USE_UNDERSCORE_SETJMP)
#error unsupported config option used (option has been removed): DUK_USE_UNDERSCORE_SETJMP
#endif
+#if defined(DUK_USE_USER_INITJS)
+#error unsupported config option used (option has been removed): DUK_USE_USER_INITJS
+#endif
#if defined(DUK_USE_CPP_EXCEPTIONS) && !defined(__cplusplus)
#error DUK_USE_CPP_EXCEPTIONS enabled but not compiling with a C++ compiler
diff --git a/microscript/duk_module_duktape.c b/microscript/duk_module_duktape.c
new file mode 100644
index 0000000..e2616ba
--- /dev/null
+++ b/microscript/duk_module_duktape.c
@@ -0,0 +1,471 @@
+/*
+ * Duktape 1.x compatible module loading framework
+ */
+
+#include "duktape.h"
+#include "duk_module_duktape.h"
+
+/* (v)snprintf() is missing before MSVC 2015. Note that _(v)snprintf() does
+ * NOT NUL terminate on truncation, but that's OK here.
+ * http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
+ */
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+#define snprintf _snprintf
+#endif
+
+#if 0 /* Enable manually */
+#define DUK__ASSERT(x) do { \
+ if (!(x)) { \
+ fprintf(stderr, "ASSERTION FAILED at %s:%d: " #x "\n", __FILE__, __LINE__); \
+ fflush(stderr); \
+ } \
+ } while (0)
+#define DUK__ASSERT_TOP(ctx,val) do { \
+ DUK__ASSERT(duk_get_top((ctx)) == (val)); \
+ } while (0)
+#else
+#define DUK__ASSERT(x) do { (void) (x); } while (0)
+#define DUK__ASSERT_TOP(ctx,val) do { (void) ctx; (void) (val); } while (0)
+#endif
+
+static void duk__resolve_module_id(duk_context *ctx, const char *req_id, const char *mod_id) {
+ duk_uint8_t buf[DUK_COMMONJS_MODULE_ID_LIMIT];
+ duk_uint8_t *p;
+ duk_uint8_t *q;
+ duk_uint8_t *q_last; /* last component */
+ duk_int_t int_rc;
+
+ DUK__ASSERT(req_id != NULL);
+ /* mod_id may be NULL */
+
+ /*
+ * A few notes on the algorithm:
+ *
+ * - Terms are not allowed to begin with a period unless the term
+ * is either '.' or '..'. This simplifies implementation (and
+ * is within CommonJS modules specification).
+ *
+ * - There are few output bound checks here. This is on purpose:
+ * the resolution input is length checked and the output is never
+ * longer than the input. The resolved output is written directly
+ * over the input because it's never longer than the input at any
+ * point in the algorithm.
+ *
+ * - Non-ASCII characters are processed as individual bytes and
+ * need no special treatment. However, U+0000 terminates the
+ * algorithm; this is not an issue because U+0000 is not a
+ * desirable term character anyway.
+ */
+
+ /*
+ * Set up the resolution input which is the requested ID directly
+ * (if absolute or no current module path) or with current module
+ * ID prepended (if relative and current module path exists).
+ *
+ * Suppose current module is 'foo/bar' and relative path is './quux'.
+ * The 'bar' component must be replaced so the initial input here is
+ * 'foo/bar/.././quux'.
+ */
+
+ if (mod_id != NULL && req_id[0] == '.') {
+ int_rc = snprintf((char *) buf, sizeof(buf), "%s/../%s", mod_id, req_id);
+ } else {
+ int_rc = snprintf((char *) buf, sizeof(buf), "%s", req_id);
+ }
+ if (int_rc >= (duk_int_t) sizeof(buf) || int_rc < 0) {
+ /* Potentially truncated, NUL not guaranteed in any case.
+ * The (int_rc < 0) case should not occur in practice.
+ */
+ goto resolve_error;
+ }
+ DUK__ASSERT(strlen((const char *) buf) < sizeof(buf)); /* at most sizeof(buf) - 1 */
+
+ /*
+ * Resolution loop. At the top of the loop we're expecting a valid
+ * term: '.', '..', or a non-empty identifier not starting with a period.
+ */
+
+ p = buf;
+ q = buf;
+ for (;;) {
+ duk_uint_fast8_t c;
+
+ /* Here 'p' always points to the start of a term.
+ *
+ * We can also unconditionally reset q_last here: if this is
+ * the last (non-empty) term q_last will have the right value
+ * on loop exit.
+ */
+
+ DUK__ASSERT(p >= q); /* output is never longer than input during resolution */
+
+ q_last = q;
+
+ c = *p++;
+ if (c == 0) {
+ goto resolve_error;
+ } else if (c == '.') {
+ c = *p++;
+ if (c == '/') {
+ /* Term was '.' and is eaten entirely (including dup slashes). */
+ goto eat_dup_slashes;
+ }
+ if (c == '.' && *p == '/') {
+ /* Term was '..', backtrack resolved name by one component.
+ * q[-1] = previous slash (or beyond start of buffer)
+ * q[-2] = last char of previous component (or beyond start of buffer)
+ */
+ p++; /* eat (first) input slash */
+ DUK__ASSERT(q >= buf);
+ if (q == buf) {
+ goto resolve_error;
+ }
+ DUK__ASSERT(*(q - 1) == '/');
+ q--; /* Backtrack to last output slash (dups already eliminated). */
+ for (;;) {
+ /* Backtrack to previous slash or start of buffer. */
+ DUK__ASSERT(q >= buf);
+ if (q == buf) {
+ break;
+ }
+ if (*(q - 1) == '/') {
+ break;
+ }
+ q--;
+ }
+ goto eat_dup_slashes;
+ }
+ goto resolve_error;
+ } else if (c == '/') {
+ /* e.g. require('/foo'), empty terms not allowed */
+ goto resolve_error;
+ } else {
+ for (;;) {
+ /* Copy term name until end or '/'. */
+ *q++ = c;
+ c = *p++;
+ if (c == 0) {
+ /* This was the last term, and q_last was
+ * updated to match this term at loop top.
+ */
+ goto loop_done;
+ } else if (c == '/') {
+ *q++ = '/';
+ break;
+ } else {
+ /* write on next loop */
+ }
+ }
+ }
+
+ eat_dup_slashes:
+ for (;;) {
+ /* eat dup slashes */
+ c = *p;
+ if (c != '/') {
+ break;
+ }
+ p++;
+ }
+ }
+ loop_done:
+ /* Output #1: resolved absolute name. */
+ DUK__ASSERT(q >= buf);
+ duk_push_lstring(ctx, (const char *) buf, (size_t) (q - buf));
+
+ /* Output #2: last component name. */
+ DUK__ASSERT(q >= q_last);
+ DUK__ASSERT(q_last >= buf);
+ duk_push_lstring(ctx, (const char *) q_last, (size_t) (q - q_last));
+ return;
+
+ resolve_error:
+ (void) duk_type_error(ctx, "cannot resolve module id: %s", (const char *) req_id);
+}
+
+/* Stack indices for better readability. */
+#define DUK__IDX_REQUESTED_ID 0 /* module id requested */
+#define DUK__IDX_REQUIRE 1 /* current require() function */
+#define DUK__IDX_REQUIRE_ID 2 /* the base ID of the current require() function, resolution base */
+#define DUK__IDX_RESOLVED_ID 3 /* resolved, normalized absolute module ID */
+#define DUK__IDX_LASTCOMP 4 /* last component name in resolved path */
+#define DUK__IDX_DUKTAPE 5 /* Duktape object */
+#define DUK__IDX_MODLOADED 6 /* Duktape.modLoaded[] module cache */
+#define DUK__IDX_UNDEFINED 7 /* 'undefined', artifact of lookup */
+#define DUK__IDX_FRESH_REQUIRE 8 /* new require() function for module, updated resolution base */
+#define DUK__IDX_EXPORTS 9 /* default exports table */
+#define DUK__IDX_MODULE 10 /* module object containing module.exports, etc */
+
+static duk_ret_t duk__require(duk_context *ctx) {
+ const char *str_req_id; /* requested identifier */
+ const char *str_mod_id; /* require.id of current module */
+ duk_int_t pcall_rc;
+
+ /* NOTE: we try to minimize code size by avoiding unnecessary pops,
+ * so the stack looks a bit cluttered in this function. DUK__ASSERT_TOP()
+ * assertions are used to ensure stack configuration is correct at each
+ * step.
+ */
+
+ /*
+ * Resolve module identifier into canonical absolute form.
+ */
+
+ str_req_id = duk_require_string(ctx, DUK__IDX_REQUESTED_ID);
+ duk_push_current_function(ctx);
+ duk_get_prop_string(ctx, -1, "id");
+ str_mod_id = duk_get_string(ctx, DUK__IDX_REQUIRE_ID); /* ignore non-strings */
+ duk__resolve_module_id(ctx, str_req_id, str_mod_id);
+ str_req_id = NULL;
+ str_mod_id = NULL;
+
+ /* [ requested_id require require.id resolved_id last_comp ] */
+ DUK__ASSERT_TOP(ctx, DUK__IDX_LASTCOMP + 1);
+
+ /*
+ * Cached module check.
+ *
+ * If module has been loaded or its loading has already begun without
+ * finishing, return the same cached value (module.exports). The
+ * value is registered when module load starts so that circular
+ * references can be supported to some extent.
+ */
+
+ duk_push_global_stash(ctx);
+ duk_get_prop_string(ctx, -1, "\xff" "module:Duktape");
+ duk_remove(ctx, -2); /* Lookup stashed, original 'Duktape' object. */
+ duk_get_prop_string(ctx, DUK__IDX_DUKTAPE, "modLoaded"); /* Duktape.modLoaded */
+ duk_require_type_mask(ctx, DUK__IDX_MODLOADED, DUK_TYPE_MASK_OBJECT);
+ DUK__ASSERT_TOP(ctx, DUK__IDX_MODLOADED + 1);
+
+ duk_dup(ctx, DUK__IDX_RESOLVED_ID);
+ if (duk_get_prop(ctx, DUK__IDX_MODLOADED)) {
+ /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded Duktape.modLoaded[id] ] */
+ duk_get_prop_string(ctx, -1, "exports"); /* return module.exports */
+ return 1;
+ }
+ DUK__ASSERT_TOP(ctx, DUK__IDX_UNDEFINED + 1);
+
+ /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined ] */
+
+ /*
+ * Module not loaded (and loading not started previously).
+ *
+ * Create a new require() function with 'id' set to resolved ID
+ * of module being loaded. Also create 'exports' and 'module'
+ * tables but don't register exports to the loaded table yet.
+ * We don't want to do that unless the user module search callbacks
+ * succeeds in finding the module.
+ */
+
+ /* Fresh require: require.id is left configurable (but not writable)
+ * so that is not easy to accidentally tweak it, but it can still be
+ * done with Object.defineProperty().
+ *
+ * XXX: require.id could also be just made non-configurable, as there
+ * is no practical reason to touch it (at least from Ecmascript code).
+ */
+ duk_push_c_function(ctx, duk__require, 1 /*nargs*/);
+ duk_push_string(ctx, "name");
+ duk_push_string(ctx, "require");
+ duk_def_prop(ctx, DUK__IDX_FRESH_REQUIRE, DUK_DEFPROP_HAVE_VALUE); /* not writable, not enumerable, not configurable */
+ duk_push_string(ctx, "id");
+ duk_dup(ctx, DUK__IDX_RESOLVED_ID);
+ duk_def_prop(ctx, DUK__IDX_FRESH_REQUIRE, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_SET_CONFIGURABLE); /* a fresh require() with require.id = resolved target module id */
+
+ /* Module table:
+ * - module.exports: initial exports table (may be replaced by user)
+ * - module.id is non-writable and non-configurable, as the CommonJS
+ * spec suggests this if possible
+ * - module.filename: not set, defaults to resolved ID if not explicitly
+ * set by modSearch() (note capitalization, not .fileName, matches Node.js)
+ * - module.name: not set, defaults to last component of resolved ID if
+ * not explicitly set by modSearch()
+ */
+ duk_push_object(ctx); /* exports */
+ duk_push_object(ctx); /* module */
+ duk_push_string(ctx, "exports");
+ duk_dup(ctx, DUK__IDX_EXPORTS);
+ duk_def_prop(ctx, DUK__IDX_MODULE, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_SET_WRITABLE | DUK_DEFPROP_SET_CONFIGURABLE); /* module.exports = exports */
+ duk_push_string(ctx, "id");
+ duk_dup(ctx, DUK__IDX_RESOLVED_ID); /* resolved id: require(id) must return this same module */
+ duk_def_prop(ctx, DUK__IDX_MODULE, DUK_DEFPROP_HAVE_VALUE); /* module.id = resolved_id; not writable, not enumerable, not configurable */
+ duk_compact(ctx, DUK__IDX_MODULE); /* module table remains registered to modLoaded, minimize its size */
+ DUK__ASSERT_TOP(ctx, DUK__IDX_MODULE + 1);
+
+ /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module ] */
+
+ /* Register the module table early to modLoaded[] so that we can
+ * support circular references even in modSearch(). If an error
+ * is thrown, we'll delete the reference.
+ */
+ duk_dup(ctx, DUK__IDX_RESOLVED_ID);
+ duk_dup(ctx, DUK__IDX_MODULE);
+ duk_put_prop(ctx, DUK__IDX_MODLOADED); /* Duktape.modLoaded[resolved_id] = module */
+
+ /*
+ * Call user provided module search function and build the wrapped
+ * module source code (if necessary). The module search function
+ * can be used to implement pure Ecmacsript, pure C, and mixed
+ * Ecmascript/C modules.
+ *
+ * The module search function can operate on the exports table directly
+ * (e.g. DLL code can register values to it). It can also return a
+ * string which is interpreted as module source code (if a non-string
+ * is returned the module is assumed to be a pure C one). If a module
+ * cannot be found, an error must be thrown by the user callback.
+ *
+ * Because Duktape.modLoaded[] already contains the module being
+ * loaded, circular references for C modules should also work
+ * (although expected to be quite rare).
+ */
+
+ duk_push_string(ctx, "(function(require,exports,module){");
+
+ /* Duktape.modSearch(resolved_id, fresh_require, exports, module). */
+ duk_get_prop_string(ctx, DUK__IDX_DUKTAPE, "modSearch"); /* Duktape.modSearch */
+ duk_dup(ctx, DUK__IDX_RESOLVED_ID);
+ duk_dup(ctx, DUK__IDX_FRESH_REQUIRE);
+ duk_dup(ctx, DUK__IDX_EXPORTS);
+ duk_dup(ctx, DUK__IDX_MODULE); /* [ ... Duktape.modSearch resolved_id last_comp fresh_require exports module ] */
+ pcall_rc = duk_pcall(ctx, 4 /*nargs*/); /* -> [ ... source ] */
+ DUK__ASSERT_TOP(ctx, DUK__IDX_MODULE + 3);
+
+ if (pcall_rc != DUK_EXEC_SUCCESS) {
+ /* Delete entry in Duktape.modLoaded[] and rethrow. */
+ goto delete_rethrow;
+ }
+
+ /* If user callback did not return source code, module loading
+ * is finished (user callback initialized exports table directly).
+ */
+ if (!duk_is_string(ctx, -1)) {
+ /* User callback did not return source code, so module loading
+ * is finished: just update modLoaded with final module.exports
+ * and we're done.
+ */
+ goto return_exports;
+ }
+
+ /* Finish the wrapped module source. Force module.filename as the
+ * function .fileName so it gets set for functions defined within a
+ * module. This also ensures loggers created within the module get
+ * the module ID (or overridden filename) as their default logger name.
+ * (Note capitalization: .filename matches Node.js while .fileName is
+ * used elsewhere in Duktape.)
+ */
+ duk_push_string(ctx, "\n})"); /* Newline allows module last line to contain a // comment. */
+ duk_concat(ctx, 3);
+ if (!duk_get_prop_string(ctx, DUK__IDX_MODULE, "filename")) {
+ /* module.filename for .fileName, default to resolved ID if
+ * not present.
+ */
+ duk_pop(ctx);
+ duk_dup(ctx, DUK__IDX_RESOLVED_ID);
+ }
+ pcall_rc = duk_pcompile(ctx, DUK_COMPILE_EVAL);
+ if (pcall_rc != DUK_EXEC_SUCCESS) {
+ goto delete_rethrow;
+ }
+ pcall_rc = duk_pcall(ctx, 0); /* -> eval'd function wrapper (not called yet) */
+ if (pcall_rc != DUK_EXEC_SUCCESS) {
+ goto delete_rethrow;
+ }
+
+ /* Module has now evaluated to a wrapped module function. Force its
+ * .name to match module.name (defaults to last component of resolved
+ * ID) so that it is shown in stack traces too. Note that we must not
+ * introduce an actual name binding into the function scope (which is
+ * usually the case with a named function) because it would affect the
+ * scope seen by the module and shadow accesses to globals of the same name.
+ * This is now done by compiling the function as anonymous and then forcing
+ * its .name without setting a "has name binding" flag.
+ */
+
+ duk_push_string(ctx, "name");
+ if (!duk_get_prop_string(ctx, DUK__IDX_MODULE, "name")) {
+ /* module.name for .name, default to last component if
+ * not present.
+ */
+ duk_pop(ctx);
+ duk_dup(ctx, DUK__IDX_LASTCOMP);
+ }
+ duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_FORCE);
+
+ /*
+ * Call the wrapped module function.
+ *
+ * Use a protected call so that we can update Duktape.modLoaded[resolved_id]
+ * even if the module throws an error.
+ */
+
+ /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module mod_func ] */
+ DUK__ASSERT_TOP(ctx, DUK__IDX_MODULE + 2);
+
+ duk_dup(ctx, DUK__IDX_EXPORTS); /* exports (this binding) */
+ duk_dup(ctx, DUK__IDX_FRESH_REQUIRE); /* fresh require (argument) */
+ duk_get_prop_string(ctx, DUK__IDX_MODULE, "exports"); /* relookup exports from module.exports in case it was changed by modSearch */
+ duk_dup(ctx, DUK__IDX_MODULE); /* module (argument) */
+ DUK__ASSERT_TOP(ctx, DUK__IDX_MODULE + 6);
+
+ /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module mod_func exports fresh_require exports module ] */
+
+ pcall_rc = duk_pcall_method(ctx, 3 /*nargs*/);
+ if (pcall_rc != DUK_EXEC_SUCCESS) {
+ /* Module loading failed. Node.js will forget the module
+ * registration so that another require() will try to load
+ * the module again. Mimic that behavior.
+ */
+ goto delete_rethrow;
+ }
+
+ /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module result(ignored) ] */
+ DUK__ASSERT_TOP(ctx, DUK__IDX_MODULE + 2);
+
+ /* fall through */
+
+ return_exports:
+ duk_get_prop_string(ctx, DUK__IDX_MODULE, "exports");
+ duk_compact(ctx, -1); /* compact the exports table */
+ return 1; /* return module.exports */
+
+ delete_rethrow:
+ duk_dup(ctx, DUK__IDX_RESOLVED_ID);
+ duk_del_prop(ctx, DUK__IDX_MODLOADED); /* delete Duktape.modLoaded[resolved_id] */
+ (void) duk_throw(ctx); /* rethrow original error */
+ return 0; /* not reachable */
+}
+
+void duk_module_duktape_init(duk_context *ctx) {
+ /* Stash 'Duktape' in case it's modified. */
+ duk_push_global_stash(ctx);
+ duk_get_global_string(ctx, "Duktape");
+ duk_put_prop_string(ctx, -2, "\xff" "module:Duktape");
+ duk_pop(ctx);
+
+ /* Register `require` as a global function. */
+ duk_eval_string(ctx,
+ "(function(req){"
+ "var D=Object.defineProperty;"
+ "D(req,'name',{value:'require'});"
+ "D(this,'require',{value:req,writable:true,configurable:true});"
+ "D(Duktape,'modLoaded',{value:Object.create(null),writable:true,configurable:true});"
+ "})");
+ duk_push_c_function(ctx, duk__require, 1 /*nargs*/);
+ duk_call(ctx, 1);
+ duk_pop(ctx);
+}
+
+#undef DUK__ASSERT
+#undef DUK__ASSERT_TOP
+#undef DUK__IDX_REQUESTED_ID
+#undef DUK__IDX_REQUIRE
+#undef DUK__IDX_REQUIRE_ID
+#undef DUK__IDX_RESOLVED_ID
+#undef DUK__IDX_LASTCOMP
+#undef DUK__IDX_DUKTAPE
+#undef DUK__IDX_MODLOADED
+#undef DUK__IDX_UNDEFINED
+#undef DUK__IDX_FRESH_REQUIRE
+#undef DUK__IDX_EXPORTS
+#undef DUK__IDX_MODULE
diff --git a/microscript/duk_module_duktape.h b/microscript/duk_module_duktape.h
new file mode 100644
index 0000000..8c88081
--- /dev/null
+++ b/microscript/duk_module_duktape.h
@@ -0,0 +1,14 @@
+#if !defined(DUK_MODULE_DUKTAPE_H_INCLUDED)
+#define DUK_MODULE_DUKTAPE_H_INCLUDED
+
+#include "duktape.h"
+
+/* Maximum length of CommonJS module identifier to resolve. Length includes
+ * both current module ID, requested (possibly relative) module ID, and a
+ * slash in between.
+ */
+#define DUK_COMMONJS_MODULE_ID_LIMIT 256
+
+extern void duk_module_duktape_init(duk_context *ctx);
+
+#endif /* DUK_MODULE_DUKTAPE_H_INCLUDED */
diff --git a/microscript/duktape.c b/microscript/duktape.c
index 4816c09..05e4b1d 100644
--- a/microscript/duktape.c
+++ b/microscript/duktape.c
@@ -1,8 +1,8 @@
/*
- * Single source autogenerated distributable for Duktape 1.8.0.
+ * Single source autogenerated distributable for Duktape 2.2.0.
*
- * Git commit 0a70d7e4c5227c84e3fed5209828973117d02849 (v1.8.0).
- * Git branch v1.8-maintenance.
+ * Git commit a459cf3c9bd1779fc01b435d69302b742675a08f (v2.2.0).
+ * Git branch master.
*
* See Duktape AUTHORS.rst and LICENSE.txt for copyright and
* licensing information.
@@ -36,6 +36,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+
/* AUTHORS.rst */
/*
* ===============
@@ -69,6 +70,23 @@
* * Ren\u00e9 Hollander
* * Julien Hamaide (https://github.com/crazyjul)
* * Sebastian G\u00f6tte (https://github.com/jaseg)
+* * Tomasz Magulski (https://github.com/magul)
+* * \D. Bohdan (https://github.com/dbohdan)
+* * Ond\u0159ej Jirman (https://github.com/megous)
+* * Sa\u00fal Ibarra Corretg\u00e9
+* * Jeremy HU
+* * Ole Andr\u00e9 Vadla Ravn\u00e5s (https://github.com/oleavr)
+* * Harold Brenes (https://github.com/harold-b)
+* * Oliver Crow (https://github.com/ocrow)
+* * Jakub Ch\u0142api\u0144ski (https://github.com/jchlapinski)
+* * Brett Vickers (https://github.com/beevik)
+* * Dominik Okwieka (https://github.com/okitec)
+* * Remko Tron\u00e7on (https://el-tramo.be)
+* * Romero Malaquias (rbsm@ic.ufal.br)
+* * Michael Drake
+* * Steven Don (https://github.com/shdon)
+* * Simon Stone (https://github.com/sstone1)
+* * \J. McC. (https://github.com/jmhmccr)
*
* Other contributions
* ===================
@@ -106,11 +124,22 @@
* * Michael Drake (https://github.com/tlsa)
* * https://github.com/chris-y
* * Laurent Zubiaur (https://github.com/lzubiaur)
-* * Ole Andr\u00e9 Vadla Ravn\u00e5s (https://github.com/oleavr)
+* * Neil Kolban (https://github.com/nkolban)
*
* If you are accidentally missing from this list, send me an e-mail
* (``sami.vaarala@iki.fi``) and I'll fix the omission.
*/
+
+#line 1 "duk_replacements.c"
+/*
+ * Replacements for missing platform functions.
+ *
+ * Unlike the originals, fpclassify() and signbit() replacements don't
+ * work on any floating point types, only doubles. The C typing here
+ * mimics the standard prototypes.
+ */
+
+/* #include duk_internal.h */
#line 1 "duk_internal.h"
/*
* Top-level include file to be used for all (internal) source files.
@@ -119,7 +148,7 @@
* have not been designed to be individually included.
*/
-#ifndef DUK_INTERNAL_H_INCLUDED
+#if !defined(DUK_INTERNAL_H_INCLUDED)
#define DUK_INTERNAL_H_INCLUDED
/*
@@ -141,9 +170,7 @@
/*
* User declarations, e.g. prototypes for user functions used by Duktape
- * macros. Concretely, if DUK_USE_PANIC_HANDLER is used and the macro
- * value calls a user function, it needs to be declared for Duktape
- * compilation to avoid warnings.
+ * macros.
*/
DUK_USE_USER_DECLARE()
@@ -157,8 +184,434 @@ DUK_USE_USER_DECLARE()
* dependencies.
*/
+/* #include duk_dblunion.h */
+#line 1 "duk_dblunion.h"
+/*
+ * Union to access IEEE double memory representation, indexes for double
+ * memory representation, and some macros for double manipulation.
+ *
+ * Also used by packed duk_tval. Use a union for bit manipulation to
+ * minimize aliasing issues in practice. The C99 standard does not
+ * guarantee that this should work, but it's a very widely supported
+ * practice for low level manipulation.
+ *
+ * IEEE double format summary:
+ *
+ * seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
+ * A B C D E F G H
+ *
+ * s sign bit
+ * eee... exponent field
+ * fff... fraction
+ *
+ * See http://en.wikipedia.org/wiki/Double_precision_floating-point_format.
+ *
+ * NaNs are represented as exponent 0x7ff and mantissa != 0. The NaN is a
+ * signaling NaN when the highest bit of the mantissa is zero, and a quiet
+ * NaN when the highest bit is set.
+ *
+ * At least three memory layouts are relevant here:
+ *
+ * A B C D E F G H Big endian (e.g. 68k) DUK_USE_DOUBLE_BE
+ * H G F E D C B A Little endian (e.g. x86) DUK_USE_DOUBLE_LE
+ * D C B A H G F E Mixed/cross endian (e.g. ARM) DUK_USE_DOUBLE_ME
+ *
+ * ARM is a special case: ARM double values are in mixed/cross endian
+ * format while ARM duk_uint64_t values are in standard little endian
+ * format (H G F E D C B A). When a double is read as a duk_uint64_t
+ * from memory, the register will contain the (logical) value
+ * E F G H A B C D. This requires some special handling below.
+ *
+ * Indexes of various types (8-bit, 16-bit, 32-bit) in memory relative to
+ * the logical (big endian) order:
+ *
+ * byte order duk_uint8_t duk_uint16_t duk_uint32_t
+ * BE 01234567 0123 01
+ * LE 76543210 3210 10
+ * ME (ARM) 32107654 1032 01
+ *
+ * Some processors may alter NaN values in a floating point load+store.
+ * For instance, on X86 a FLD + FSTP may convert a signaling NaN to a
+ * quiet one. This is catastrophic when NaN space is used in packed
+ * duk_tval values. See: misc/clang_aliasing.c.
+ */
+
+#if !defined(DUK_DBLUNION_H_INCLUDED)
+#define DUK_DBLUNION_H_INCLUDED
+
+/*
+ * Union for accessing double parts, also serves as packed duk_tval
+ */
+
+union duk_double_union {
+ double d;
+ float f[2];
+#if defined(DUK_USE_64BIT_OPS)
+ duk_uint64_t ull[1];
+#endif
+ duk_uint32_t ui[2];
+ duk_uint16_t us[4];
+ duk_uint8_t uc[8];
+#if defined(DUK_USE_PACKED_TVAL)
+ void *vp[2]; /* used by packed duk_tval, assumes sizeof(void *) == 4 */
+#endif
+};
+
+typedef union duk_double_union duk_double_union;
+
+/*
+ * Indexes of various types with respect to big endian (logical) layout
+ */
+
+#if defined(DUK_USE_DOUBLE_LE)
+#if defined(DUK_USE_64BIT_OPS)
+#define DUK_DBL_IDX_ULL0 0
+#endif
+#define DUK_DBL_IDX_UI0 1
+#define DUK_DBL_IDX_UI1 0
+#define DUK_DBL_IDX_US0 3
+#define DUK_DBL_IDX_US1 2
+#define DUK_DBL_IDX_US2 1
+#define DUK_DBL_IDX_US3 0
+#define DUK_DBL_IDX_UC0 7
+#define DUK_DBL_IDX_UC1 6
+#define DUK_DBL_IDX_UC2 5
+#define DUK_DBL_IDX_UC3 4
+#define DUK_DBL_IDX_UC4 3
+#define DUK_DBL_IDX_UC5 2
+#define DUK_DBL_IDX_UC6 1
+#define DUK_DBL_IDX_UC7 0
+#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */
+#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */
+#elif defined(DUK_USE_DOUBLE_BE)
+#if defined(DUK_USE_64BIT_OPS)
+#define DUK_DBL_IDX_ULL0 0
+#endif
+#define DUK_DBL_IDX_UI0 0
+#define DUK_DBL_IDX_UI1 1
+#define DUK_DBL_IDX_US0 0
+#define DUK_DBL_IDX_US1 1
+#define DUK_DBL_IDX_US2 2
+#define DUK_DBL_IDX_US3 3
+#define DUK_DBL_IDX_UC0 0
+#define DUK_DBL_IDX_UC1 1
+#define DUK_DBL_IDX_UC2 2
+#define DUK_DBL_IDX_UC3 3
+#define DUK_DBL_IDX_UC4 4
+#define DUK_DBL_IDX_UC5 5
+#define DUK_DBL_IDX_UC6 6
+#define DUK_DBL_IDX_UC7 7
+#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */
+#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */
+#elif defined(DUK_USE_DOUBLE_ME)
+#if defined(DUK_USE_64BIT_OPS)
+#define DUK_DBL_IDX_ULL0 0 /* not directly applicable, byte order differs from a double */
+#endif
+#define DUK_DBL_IDX_UI0 0
+#define DUK_DBL_IDX_UI1 1
+#define DUK_DBL_IDX_US0 1
+#define DUK_DBL_IDX_US1 0
+#define DUK_DBL_IDX_US2 3
+#define DUK_DBL_IDX_US3 2
+#define DUK_DBL_IDX_UC0 3
+#define DUK_DBL_IDX_UC1 2
+#define DUK_DBL_IDX_UC2 1
+#define DUK_DBL_IDX_UC3 0
+#define DUK_DBL_IDX_UC4 7
+#define DUK_DBL_IDX_UC5 6
+#define DUK_DBL_IDX_UC6 5
+#define DUK_DBL_IDX_UC7 4
+#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */
+#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */
+#else
+#error internal error
+#endif
+
+/*
+ * Helper macros for reading/writing memory representation parts, used
+ * by duk_numconv.c and duk_tval.h.
+ */
+
+#define DUK_DBLUNION_SET_DOUBLE(u,v) do { \
+ (u)->d = (v); \
+ } while (0)
+
+#define DUK_DBLUNION_SET_HIGH32(u,v) do { \
+ (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \
+ } while (0)
+
+#if defined(DUK_USE_64BIT_OPS)
+#if defined(DUK_USE_DOUBLE_ME)
+#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \
+ (u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \
+ } while (0)
+#else
+#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \
+ (u)->ull[DUK_DBL_IDX_ULL0] = ((duk_uint64_t) (v)) << 32; \
+ } while (0)
+#endif
+#else /* DUK_USE_64BIT_OPS */
+#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \
+ (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \
+ (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0; \
+ } while (0)
+#endif /* DUK_USE_64BIT_OPS */
+
+#define DUK_DBLUNION_SET_LOW32(u,v) do { \
+ (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \
+ } while (0)
+
+#define DUK_DBLUNION_GET_DOUBLE(u) ((u)->d)
+#define DUK_DBLUNION_GET_HIGH32(u) ((u)->ui[DUK_DBL_IDX_UI0])
+#define DUK_DBLUNION_GET_LOW32(u) ((u)->ui[DUK_DBL_IDX_UI1])
+
+#if defined(DUK_USE_64BIT_OPS)
+#if defined(DUK_USE_DOUBLE_ME)
+#define DUK_DBLUNION_SET_UINT64(u,v) do { \
+ (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) ((v) >> 32); \
+ (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \
+ } while (0)
+#define DUK_DBLUNION_GET_UINT64(u) \
+ ((((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI0]) << 32) | \
+ ((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI1]))
+#else
+#define DUK_DBLUNION_SET_UINT64(u,v) do { \
+ (u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \
+ } while (0)
+#define DUK_DBLUNION_GET_UINT64(u) ((u)->ull[DUK_DBL_IDX_ULL0])
+#endif
+#define DUK_DBLUNION_SET_INT64(u,v) DUK_DBLUNION_SET_UINT64((u), (duk_uint64_t) (v))
+#define DUK_DBLUNION_GET_INT64(u) ((duk_int64_t) DUK_DBLUNION_GET_UINT64((u)))
+#endif /* DUK_USE_64BIT_OPS */
+
+/*
+ * Double NaN manipulation macros related to NaN normalization needed when
+ * using the packed duk_tval representation. NaN normalization is necessary
+ * to keep double values compatible with the duk_tval format.
+ *
+ * When packed duk_tval is used, the NaN space is used to store pointers
+ * and other tagged values in addition to NaNs. Actual NaNs are normalized
+ * to a specific quiet NaN. The macros below are used by the implementation
+ * to check and normalize NaN values when they might be created. The macros
+ * are essentially NOPs when the non-packed duk_tval representation is used.
+ *
+ * A FULL check is exact and checks all bits. A NOTFULL check is used by
+ * the packed duk_tval and works correctly for all NaNs except those that
+ * begin with 0x7ff0. Since the 'normalized NaN' values used with packed
+ * duk_tval begin with 0x7ff8, the partial check is reliable when packed
+ * duk_tval is used. The 0x7ff8 prefix means the normalized NaN will be a
+ * quiet NaN regardless of its remaining lower bits.
+ *
+ * The ME variant below is specifically for ARM byte order, which has the
+ * feature that while doubles have a mixed byte order (32107654), unsigned
+ * long long values has a little endian byte order (76543210). When writing
+ * a logical double value through a ULL pointer, the 32-bit words need to be
+ * swapped; hence the #if defined()s below for ULL writes with DUK_USE_DOUBLE_ME.
+ * This is not full ARM support but suffices for some environments.
+ */
+
+#if defined(DUK_USE_64BIT_OPS)
+#if defined(DUK_USE_DOUBLE_ME)
+/* Macros for 64-bit ops + mixed endian doubles. */
+#define DUK__DBLUNION_SET_NAN_FULL(u) do { \
+ (u)->ull[DUK_DBL_IDX_ULL0] = DUK_U64_CONSTANT(0x000000007ff80000); \
+ } while (0)
+#define DUK__DBLUNION_IS_NAN_FULL(u) \
+ ((((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000)) == DUK_U64_CONSTANT(0x000000007ff00000)) && \
+ ((((u)->ull[DUK_DBL_IDX_ULL0]) & DUK_U64_CONSTANT(0xffffffff000fffff)) != 0))
+#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x000000007ff80000))
+#define DUK__DBLUNION_IS_ANYINF(u) \
+ (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0xffffffff7fffffff)) == DUK_U64_CONSTANT(0x000000007ff00000))
+#define DUK__DBLUNION_IS_POSINF(u) \
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x000000007ff00000))
+#define DUK__DBLUNION_IS_NEGINF(u) \
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x00000000fff00000))
+#define DUK__DBLUNION_IS_ANYZERO(u) \
+ (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0xffffffff7fffffff)) == DUK_U64_CONSTANT(0x0000000000000000))
+#define DUK__DBLUNION_IS_POSZERO(u) \
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000000000000))
+#define DUK__DBLUNION_IS_NEGZERO(u) \
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000080000000))
+#else
+/* Macros for 64-bit ops + big/little endian doubles. */
+#define DUK__DBLUNION_SET_NAN_FULL(u) do { \
+ (u)->ull[DUK_DBL_IDX_ULL0] = DUK_U64_CONSTANT(0x7ff8000000000000); \
+ } while (0)
+#define DUK__DBLUNION_IS_NAN_FULL(u) \
+ ((((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000)) == DUK_U64_CONSTANT(0x7ff0000000000000)) && \
+ ((((u)->ull[DUK_DBL_IDX_ULL0]) & DUK_U64_CONSTANT(0x000fffffffffffff)) != 0))
+#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x7ff8000000000000))
+#define DUK__DBLUNION_IS_ANYINF(u) \
+ (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7fffffffffffffff)) == DUK_U64_CONSTANT(0x7ff0000000000000))
+#define DUK__DBLUNION_IS_POSINF(u) \
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x7ff0000000000000))
+#define DUK__DBLUNION_IS_NEGINF(u) \
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0xfff0000000000000))
+#define DUK__DBLUNION_IS_ANYZERO(u) \
+ (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7fffffffffffffff)) == DUK_U64_CONSTANT(0x0000000000000000))
+#define DUK__DBLUNION_IS_POSZERO(u) \
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000000000000))
+#define DUK__DBLUNION_IS_NEGZERO(u) \
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x8000000000000000))
+#endif
+#else /* DUK_USE_64BIT_OPS */
+/* Macros for no 64-bit ops, any endianness. */
+#define DUK__DBLUNION_SET_NAN_FULL(u) do { \
+ (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) 0x7ff80000UL; \
+ (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0x00000000UL; \
+ } while (0)
+#define DUK__DBLUNION_IS_NAN_FULL(u) \
+ ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL) && \
+ (((u)->ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) != 0 || \
+ (u)->ui[DUK_DBL_IDX_UI1] != 0))
+#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
+ (((u)->ui[DUK_DBL_IDX_UI0] == 0x7ff80000UL) && \
+ ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
+#define DUK__DBLUNION_IS_ANYINF(u) \
+ ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7fffffffUL) == 0x7ff00000UL) && \
+ ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
+#define DUK__DBLUNION_IS_POSINF(u) \
+ (((u)->ui[DUK_DBL_IDX_UI0] == 0x7ff00000UL) && \
+ ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
+#define DUK__DBLUNION_IS_NEGINF(u) \
+ (((u)->ui[DUK_DBL_IDX_UI0] == 0xfff00000UL) && \
+ ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
+#define DUK__DBLUNION_IS_ANYZERO(u) \
+ ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7fffffffUL) == 0x00000000UL) && \
+ ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
+#define DUK__DBLUNION_IS_POSZERO(u) \
+ (((u)->ui[DUK_DBL_IDX_UI0] == 0x00000000UL) && \
+ ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
+#define DUK__DBLUNION_IS_NEGZERO(u) \
+ (((u)->ui[DUK_DBL_IDX_UI0] == 0x80000000UL) && \
+ ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
+#endif /* DUK_USE_64BIT_OPS */
+
+#define DUK__DBLUNION_SET_NAN_NOTFULL(u) do { \
+ (u)->us[DUK_DBL_IDX_US0] = 0x7ff8UL; \
+ } while (0)
+
+#define DUK__DBLUNION_IS_NAN_NOTFULL(u) \
+ /* E == 0x7ff, topmost four bits of F != 0 => assume NaN */ \
+ ((((u)->us[DUK_DBL_IDX_US0] & 0x7ff0UL) == 0x7ff0UL) && \
+ (((u)->us[DUK_DBL_IDX_US0] & 0x000fUL) != 0x0000UL))
+
+#define DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL(u) \
+ /* E == 0x7ff, F == 8 => normalized NaN */ \
+ ((u)->us[DUK_DBL_IDX_US0] == 0x7ff8UL)
+
+#define DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL(u) do { \
+ if (DUK__DBLUNION_IS_NAN_FULL((u))) { \
+ DUK__DBLUNION_SET_NAN_FULL((u)); \
+ } \
+ } while (0)
+
+#define DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL(u) do { \
+ if (DUK__DBLUNION_IS_NAN_NOTFULL((u))) { \
+ DUK__DBLUNION_SET_NAN_NOTFULL((u)); \
+ } \
+ } while (0)
+
+/* Concrete macros for NaN handling used by the implementation internals.
+ * Chosen so that they match the duk_tval representation: with a packed
+ * duk_tval, ensure NaNs are properly normalized; with a non-packed duk_tval
+ * these are essentially NOPs.
+ */
+
+#if defined(DUK_USE_PACKED_TVAL)
+#if defined(DUK_USE_FULL_TVAL)
+#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL((u))
+#define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u))
+#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NORMALIZED_NAN_FULL((u))
+#define DUK_DBLUNION_SET_NAN(d) DUK__DBLUNION_SET_NAN_FULL((d))
+#else
+#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL((u))
+#define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_NOTFULL((u))
+#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL((u))
+#define DUK_DBLUNION_SET_NAN(d) DUK__DBLUNION_SET_NAN_NOTFULL((d))
+#endif
+#define DUK_DBLUNION_IS_NORMALIZED(u) \
+ (!DUK_DBLUNION_IS_NAN((u)) || /* either not a NaN */ \
+ DUK_DBLUNION_IS_NORMALIZED_NAN((u))) /* or is a normalized NaN */
+#else /* DUK_USE_PACKED_TVAL */
+#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) /* nop: no need to normalize */
+#define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u)) /* (DUK_ISNAN((u)->d)) */
+#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u)) /* (DUK_ISNAN((u)->d)) */
+#define DUK_DBLUNION_IS_NORMALIZED(u) 1 /* all doubles are considered normalized */
+#define DUK_DBLUNION_SET_NAN(u) do { \
+ /* in non-packed representation we don't care about which NaN is used */ \
+ (u)->d = DUK_DOUBLE_NAN; \
+ } while (0)
+#endif /* DUK_USE_PACKED_TVAL */
+
+#define DUK_DBLUNION_IS_ANYINF(u) DUK__DBLUNION_IS_ANYINF((u))
+#define DUK_DBLUNION_IS_POSINF(u) DUK__DBLUNION_IS_POSINF((u))
+#define DUK_DBLUNION_IS_NEGINF(u) DUK__DBLUNION_IS_NEGINF((u))
+
+#define DUK_DBLUNION_IS_ANYZERO(u) DUK__DBLUNION_IS_ANYZERO((u))
+#define DUK_DBLUNION_IS_POSZERO(u) DUK__DBLUNION_IS_POSZERO((u))
+#define DUK_DBLUNION_IS_NEGZERO(u) DUK__DBLUNION_IS_NEGZERO((u))
+
+/* XXX: native 64-bit byteswaps when available */
+
+/* 64-bit byteswap, same operation independent of target endianness. */
+#define DUK_DBLUNION_BSWAP64(u) do { \
+ duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
+ duk__bswaptmp1 = (u)->ui[0]; \
+ duk__bswaptmp2 = (u)->ui[1]; \
+ duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
+ duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
+ (u)->ui[0] = duk__bswaptmp2; \
+ (u)->ui[1] = duk__bswaptmp1; \
+ } while (0)
+
+/* Byteswap an IEEE double in the duk_double_union from host to network
+ * order. For a big endian target this is a no-op.
+ */
+#if defined(DUK_USE_DOUBLE_LE)
+#define DUK_DBLUNION_DOUBLE_HTON(u) do { \
+ duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
+ duk__bswaptmp1 = (u)->ui[0]; \
+ duk__bswaptmp2 = (u)->ui[1]; \
+ duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
+ duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
+ (u)->ui[0] = duk__bswaptmp2; \
+ (u)->ui[1] = duk__bswaptmp1; \
+ } while (0)
+#elif defined(DUK_USE_DOUBLE_ME)
+#define DUK_DBLUNION_DOUBLE_HTON(u) do { \
+ duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
+ duk__bswaptmp1 = (u)->ui[0]; \
+ duk__bswaptmp2 = (u)->ui[1]; \
+ duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
+ duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
+ (u)->ui[0] = duk__bswaptmp1; \
+ (u)->ui[1] = duk__bswaptmp2; \
+ } while (0)
+#elif defined(DUK_USE_DOUBLE_BE)
+#define DUK_DBLUNION_DOUBLE_HTON(u) do { } while (0)
+#else
+#error internal error, double endianness insane
+#endif
+
+/* Reverse operation is the same. */
+#define DUK_DBLUNION_DOUBLE_NTOH(u) DUK_DBLUNION_DOUBLE_HTON((u))
+
+/* Some sign bit helpers. */
+#if defined(DUK_USE_64BIT_OPS)
+#define DUK_DBLUNION_HAS_SIGNBIT(u) (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x8000000000000000)) != 0)
+#define DUK_DBLUNION_GET_SIGNBIT(u) (((u)->ull[DUK_DBL_IDX_ULL0] >> 63U))
+#else
+#define DUK_DBLUNION_HAS_SIGNBIT(u) (((u)->ui[DUK_DBL_IDX_UI0] & 0x80000000UL) != 0)
+#define DUK_DBLUNION_GET_SIGNBIT(u) (((u)->ui[DUK_DBL_IDX_UI0] >> 31U))
+#endif
+
+#endif /* DUK_DBLUNION_H_INCLUDED */
+/* #include duk_replacements.h */
#line 1 "duk_replacements.h"
-#ifndef DUK_REPLACEMENTS_H_INCLUDED
+#if !defined(DUK_REPLACEMENTS_H_INCLUDED)
#define DUK_REPLACEMENTS_H_INCLUDED
#if !defined(DUK_SINGLE_FILE)
@@ -168,6 +621,8 @@ DUK_INTERNAL_DECL double duk_computed_infinity;
#if defined(DUK_USE_COMPUTED_NAN)
DUK_INTERNAL_DECL double duk_computed_nan;
#endif
+#endif /* !DUK_SINGLE_FILE */
+
#if defined(DUK_USE_REPL_FPCLASSIFY)
DUK_INTERNAL_DECL int duk_repl_fpclassify(double x);
#endif
@@ -183,9 +638,9 @@ DUK_INTERNAL_DECL int duk_repl_isnan(double x);
#if defined(DUK_USE_REPL_ISINF)
DUK_INTERNAL_DECL int duk_repl_isinf(double x);
#endif
-#endif /* !DUK_SINGLE_FILE */
#endif /* DUK_REPLACEMENTS_H_INCLUDED */
+/* #include duk_jmpbuf.h */
#line 1 "duk_jmpbuf.h"
/*
* Wrapper for jmp_buf.
@@ -197,7 +652,7 @@ DUK_INTERNAL_DECL int duk_repl_isinf(double x);
* http://en.wikipedia.org/wiki/Setjmp.h#Member_types
*/
-#ifndef DUK_JMPBUF_H_INCLUDED
+#if !defined(DUK_JMPBUF_H_INCLUDED)
#define DUK_JMPBUF_H_INCLUDED
#if defined(DUK_USE_CPP_EXCEPTIONS)
@@ -211,6 +666,7 @@ struct duk_jmpbuf {
#endif
#endif /* DUK_JMPBUF_H_INCLUDED */
+/* #include duk_exception.h */
#line 1 "duk_exception.h"
/*
* Exception for Duktape internal throws when C++ exceptions are used
@@ -220,7 +676,7 @@ struct duk_jmpbuf {
* that user code would accidentally catch this exception.
*/
-#ifndef DUK_EXCEPTION_H_INCLUDED
+#if !defined(DUK_EXCEPTION_H_INCLUDED)
#define DUK_EXCEPTION_H_INCLUDED
#if defined(DUK_USE_CPP_EXCEPTIONS)
@@ -230,12 +686,13 @@ class duk_internal_exception {
#endif
#endif /* DUK_EXCEPTION_H_INCLUDED */
+/* #include duk_forwdecl.h */
#line 1 "duk_forwdecl.h"
/*
* Forward declarations for all Duktape structures.
*/
-#ifndef DUK_FORWDECL_H_INCLUDED
+#if !defined(DUK_FORWDECL_H_INCLUDED)
#define DUK_FORWDECL_H_INCLUDED
/*
@@ -251,13 +708,18 @@ struct duk_jmpbuf;
/* duk_tval intentionally skipped */
struct duk_heaphdr;
struct duk_heaphdr_string;
+struct duk_harray;
struct duk_hstring;
struct duk_hstring_external;
struct duk_hobject;
-struct duk_hcompiledfunction;
-struct duk_hnativefunction;
+struct duk_hcompfunc;
+struct duk_hnatfunc;
+struct duk_hboundfunc;
struct duk_hthread;
-struct duk_hbufferobject;
+struct duk_hbufobj;
+struct duk_hdecenv;
+struct duk_hobjenv;
+struct duk_hproxy;
struct duk_hbuffer;
struct duk_hbuffer_fixed;
struct duk_hbuffer_dynamic;
@@ -276,7 +738,7 @@ struct duk_strcache;
struct duk_ljstate;
struct duk_strtab_entry;
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
struct duk_fixedbuffer;
#endif
@@ -306,13 +768,18 @@ typedef struct duk_jmpbuf duk_jmpbuf;
/* duk_tval intentionally skipped */
typedef struct duk_heaphdr duk_heaphdr;
typedef struct duk_heaphdr_string duk_heaphdr_string;
+typedef struct duk_harray duk_harray;
typedef struct duk_hstring duk_hstring;
typedef struct duk_hstring_external duk_hstring_external;
typedef struct duk_hobject duk_hobject;
-typedef struct duk_hcompiledfunction duk_hcompiledfunction;
-typedef struct duk_hnativefunction duk_hnativefunction;
-typedef struct duk_hbufferobject duk_hbufferobject;
+typedef struct duk_hcompfunc duk_hcompfunc;
+typedef struct duk_hnatfunc duk_hnatfunc;
+typedef struct duk_hboundfunc duk_hboundfunc;
typedef struct duk_hthread duk_hthread;
+typedef struct duk_hbufobj duk_hbufobj;
+typedef struct duk_hdecenv duk_hdecenv;
+typedef struct duk_hobjenv duk_hobjenv;
+typedef struct duk_hproxy duk_hproxy;
typedef struct duk_hbuffer duk_hbuffer;
typedef struct duk_hbuffer_fixed duk_hbuffer_fixed;
typedef struct duk_hbuffer_dynamic duk_hbuffer_dynamic;
@@ -331,7 +798,7 @@ typedef struct duk_strcache duk_strcache;
typedef struct duk_ljstate duk_ljstate;
typedef struct duk_strtab_entry duk_strtab_entry;
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
typedef struct duk_fixedbuffer duk_fixedbuffer;
#endif
@@ -353,6 +820,7 @@ typedef struct duk_re_matcher_ctx duk_re_matcher_ctx;
typedef struct duk_re_compiler_ctx duk_re_compiler_ctx;
#endif /* DUK_FORWDECL_H_INCLUDED */
+/* #include duk_tval.h */
#line 1 "duk_tval.h"
/*
* Tagged type definition (duk_tval) and accessor macros.
@@ -366,15 +834,13 @@ typedef struct duk_re_compiler_ctx duk_re_compiler_ctx;
* 64-bit environments (it usually pads to 16 bytes per value).
*
* Selecting the tagged type format involves many trade-offs (memory
- * use, size and performance of generated code, portability, etc),
- * see doc/types.rst for a detailed discussion (especially of how the
- * IEEE double format is used to pack tagged values).
+ * use, size and performance of generated code, portability, etc).
*
* NB: because macro arguments are often expressions, macros should
* avoid evaluating their argument more than once.
*/
-#ifndef DUK_TVAL_H_INCLUDED
+#if !defined(DUK_TVAL_H_INCLUDED)
#define DUK_TVAL_H_INCLUDED
/* sanity */
@@ -391,10 +857,17 @@ typedef struct duk_re_compiler_ctx duk_re_compiler_ctx;
/* use duk_double_union as duk_tval directly */
typedef union duk_double_union duk_tval;
+typedef struct {
+ duk_uint16_t a;
+ duk_uint16_t b;
+ duk_uint16_t c;
+ duk_uint16_t d;
+} duk_tval_unused;
/* tags */
#define DUK_TAG_NORMALIZED_NAN 0x7ff8UL /* the NaN variant we use */
/* avoid tag 0xfff0, no risk of confusion with negative infinity */
+#define DUK_TAG_MIN 0xfff1UL
#if defined(DUK_USE_FASTINT)
#define DUK_TAG_FASTINT 0xfff1UL /* embed: integer value */
#endif
@@ -408,195 +881,226 @@ typedef union duk_double_union duk_tval;
#define DUK_TAG_STRING 0xfff8UL /* embed: duk_hstring ptr */
#define DUK_TAG_OBJECT 0xfff9UL /* embed: duk_hobject ptr */
#define DUK_TAG_BUFFER 0xfffaUL /* embed: duk_hbuffer ptr */
+#define DUK_TAG_MAX 0xfffaUL
/* for convenience */
#define DUK_XTAG_BOOLEAN_FALSE 0xfff50000UL
#define DUK_XTAG_BOOLEAN_TRUE 0xfff50001UL
+#define DUK_TVAL_IS_VALID_TAG(tv) \
+ (DUK_TVAL_GET_TAG((tv)) - DUK_TAG_MIN <= DUK_TAG_MAX - DUK_TAG_MIN)
+
+/* DUK_TVAL_UNUSED initializer for duk_tval_unused, works for any endianness. */
+#define DUK_TVAL_UNUSED_INITIALIZER() \
+ { DUK_TAG_UNUSED, DUK_TAG_UNUSED, DUK_TAG_UNUSED, DUK_TAG_UNUSED }
+
/* two casts to avoid gcc warning: "warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]" */
#if defined(DUK_USE_64BIT_OPS)
#if defined(DUK_USE_DOUBLE_ME)
-#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \
- (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 16) | (((duk_uint64_t) (duk_uint32_t) (h)) << 32); \
+#define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \
+ (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 16) | (((duk_uint64_t) (duk_uint32_t) (h)) << 32); \
} while (0)
#else
-#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \
- (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 48) | ((duk_uint64_t) (duk_uint32_t) (h)); \
+#define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \
+ (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 48) | ((duk_uint64_t) (duk_uint32_t) (h)); \
} while (0)
#endif
#else /* DUK_USE_64BIT_OPS */
-#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \
- (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) (tag)) << 16; \
- (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (h); \
+#define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) (tag)) << 16; \
+ duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (h); \
} while (0)
#endif /* DUK_USE_64BIT_OPS */
#if defined(DUK_USE_64BIT_OPS)
/* Double casting for pointer to avoid gcc warning (cast from pointer to integer of different size) */
#if defined(DUK_USE_DOUBLE_ME)
-#define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \
- (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 16) | \
- ((duk_uint64_t) (flags)) | \
- (((duk_uint64_t) (duk_uint32_t) (fp)) << 32); \
+#define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \
+ (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 16) | \
+ ((duk_uint64_t) (flags)) | \
+ (((duk_uint64_t) (duk_uint32_t) (fp)) << 32); \
} while (0)
#else
-#define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \
- (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 48) | \
- (((duk_uint64_t) (flags)) << 32) | \
- ((duk_uint64_t) (duk_uint32_t) (fp)); \
+#define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \
+ (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 48) | \
+ (((duk_uint64_t) (flags)) << 32) | \
+ ((duk_uint64_t) (duk_uint32_t) (fp)); \
} while (0)
#endif
#else /* DUK_USE_64BIT_OPS */
-#define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \
- (v)->ui[DUK_DBL_IDX_UI0] = (((duk_uint32_t) DUK_TAG_LIGHTFUNC) << 16) | ((duk_uint32_t) (flags)); \
- (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (fp); \
+#define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->ui[DUK_DBL_IDX_UI0] = (((duk_uint32_t) DUK_TAG_LIGHTFUNC) << 16) | ((duk_uint32_t) (flags)); \
+ duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (fp); \
} while (0)
#endif /* DUK_USE_64BIT_OPS */
#if defined(DUK_USE_FASTINT)
/* Note: masking is done for 'i' to deal with negative numbers correctly */
#if defined(DUK_USE_DOUBLE_ME)
-#define DUK__TVAL_SET_FASTINT(v,i) do { \
- (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16 | (((duk_uint32_t) ((i) >> 32)) & 0x0000ffffUL); \
- (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \
+#define DUK__TVAL_SET_I48(tv,i) do { \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16 | (((duk_uint32_t) ((i) >> 32)) & 0x0000ffffUL); \
+ duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \
} while (0)
-#define DUK__TVAL_SET_FASTINT_U32(v,i) do { \
- (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16; \
- (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \
+#define DUK__TVAL_SET_U32(tv,i) do { \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16; \
+ duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \
} while (0)
#else
-#define DUK__TVAL_SET_FASTINT(v,i) do { \
- (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (((duk_uint64_t) (i)) & 0x0000ffffffffffffULL); \
+#define DUK__TVAL_SET_I48(tv,i) do { \
+ (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (((duk_uint64_t) (i)) & DUK_U64_CONSTANT(0x0000ffffffffffff)); \
} while (0)
-#define DUK__TVAL_SET_FASTINT_U32(v,i) do { \
- (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (duk_uint64_t) (i); \
+#define DUK__TVAL_SET_U32(tv,i) do { \
+ (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (duk_uint64_t) (i); \
} while (0)
#endif
-#define DUK__TVAL_SET_FASTINT_I32(v,i) do { \
+/* This needs to go through a cast because sign extension is needed. */
+#define DUK__TVAL_SET_I32(tv,i) do { \
duk_int64_t duk__tmp = (duk_int64_t) (i); \
- DUK_TVAL_SET_FASTINT((v), duk__tmp); \
+ DUK_TVAL_SET_I48((tv), duk__tmp); \
} while (0)
-/* XXX: clumsy sign extend and masking of 16 topmost bits */
+/* XXX: Clumsy sign extend and masking of 16 topmost bits. */
#if defined(DUK_USE_DOUBLE_ME)
-#define DUK__TVAL_GET_FASTINT(v) (((duk_int64_t) ((((duk_uint64_t) (v)->ui[DUK_DBL_IDX_UI0]) << 32) | ((duk_uint64_t) (v)->ui[DUK_DBL_IDX_UI1]))) << 16 >> 16)
+#define DUK__TVAL_GET_FASTINT(tv) (((duk_int64_t) ((((duk_uint64_t) (tv)->ui[DUK_DBL_IDX_UI0]) << 32) | ((duk_uint64_t) (tv)->ui[DUK_DBL_IDX_UI1]))) << 16 >> 16)
#else
-#define DUK__TVAL_GET_FASTINT(v) ((((duk_int64_t) (v)->ull[DUK_DBL_IDX_ULL0]) << 16) >> 16)
+#define DUK__TVAL_GET_FASTINT(tv) ((((duk_int64_t) (tv)->ull[DUK_DBL_IDX_ULL0]) << 16) >> 16)
#endif
-#define DUK__TVAL_GET_FASTINT_U32(v) ((v)->ui[DUK_DBL_IDX_UI1])
-#define DUK__TVAL_GET_FASTINT_I32(v) ((duk_int32_t) (v)->ui[DUK_DBL_IDX_UI1])
+#define DUK__TVAL_GET_FASTINT_U32(tv) ((tv)->ui[DUK_DBL_IDX_UI1])
+#define DUK__TVAL_GET_FASTINT_I32(tv) ((duk_int32_t) (tv)->ui[DUK_DBL_IDX_UI1])
#endif /* DUK_USE_FASTINT */
-#define DUK_TVAL_SET_UNDEFINED(v) do { \
- (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNDEFINED; \
+#define DUK_TVAL_SET_UNDEFINED(tv) do { \
+ (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNDEFINED; \
} while (0)
-#define DUK_TVAL_SET_UNUSED(v) do { \
- (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNUSED; \
+#define DUK_TVAL_SET_UNUSED(tv) do { \
+ (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNUSED; \
} while (0)
-#define DUK_TVAL_SET_NULL(v) do { \
- (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_NULL; \
+#define DUK_TVAL_SET_NULL(tv) do { \
+ (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_NULL; \
} while (0)
-#define DUK_TVAL_SET_BOOLEAN(v,val) DUK_DBLUNION_SET_HIGH32((v), (((duk_uint32_t) DUK_TAG_BOOLEAN) << 16) | ((duk_uint32_t) (val)))
+#define DUK_TVAL_SET_BOOLEAN(tv,val) DUK_DBLUNION_SET_HIGH32((tv), (((duk_uint32_t) DUK_TAG_BOOLEAN) << 16) | ((duk_uint32_t) (val)))
-#define DUK_TVAL_SET_NAN(v) DUK_DBLUNION_SET_NAN_FULL((v))
+#define DUK_TVAL_SET_NAN(tv) DUK_DBLUNION_SET_NAN_FULL((tv))
/* Assumes that caller has normalized NaNs, otherwise trouble ahead. */
#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_SET_DOUBLE(v,d) do { \
+#define DUK_TVAL_SET_DOUBLE(tv,d) do { \
duk_double_t duk__dblval; \
duk__dblval = (d); \
DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \
- DUK_DBLUNION_SET_DOUBLE((v), duk__dblval); \
+ DUK_DBLUNION_SET_DOUBLE((tv), duk__dblval); \
} while (0)
-#define DUK_TVAL_SET_FASTINT(v,i) DUK__TVAL_SET_FASTINT((v), (i))
-#define DUK_TVAL_SET_FASTINT_I32(v,i) DUK__TVAL_SET_FASTINT_I32((v), (i))
-#define DUK_TVAL_SET_FASTINT_U32(v,i) DUK__TVAL_SET_FASTINT_U32((v), (i))
-#define DUK_TVAL_SET_NUMBER_CHKFAST(v,d) duk_tval_set_number_chkfast((v), (d))
-#define DUK_TVAL_SET_NUMBER(v,d) DUK_TVAL_SET_DOUBLE((v), (d))
-#define DUK_TVAL_CHKFAST_INPLACE(v) do { \
+#define DUK_TVAL_SET_I48(tv,i) DUK__TVAL_SET_I48((tv), (i))
+#define DUK_TVAL_SET_I32(tv,i) DUK__TVAL_SET_I32((tv), (i))
+#define DUK_TVAL_SET_U32(tv,i) DUK__TVAL_SET_U32((tv), (i))
+#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) duk_tval_set_number_chkfast_fast((tv), (d))
+#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) duk_tval_set_number_chkfast_slow((tv), (d))
+#define DUK_TVAL_SET_NUMBER(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d))
+#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { \
duk_tval *duk__tv; \
duk_double_t duk__d; \
- duk__tv = (v); \
+ duk__tv = (tv); \
if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
- DUK_TVAL_SET_NUMBER_CHKFAST(duk__tv, duk__d); \
+ DUK_TVAL_SET_NUMBER_CHKFAST_FAST(duk__tv, duk__d); \
} \
} while (0)
-#else
-#define DUK_TVAL_SET_DOUBLE(v,d) do { \
+#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { \
+ duk_tval *duk__tv; \
+ duk_double_t duk__d; \
+ duk__tv = (tv); \
+ if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
+ duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
+ DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(duk__tv, duk__d); \
+ } \
+ } while (0)
+#else /* DUK_USE_FASTINT */
+#define DUK_TVAL_SET_DOUBLE(tv,d) do { \
duk_double_t duk__dblval; \
duk__dblval = (d); \
DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \
- DUK_DBLUNION_SET_DOUBLE((v), duk__dblval); \
+ DUK_DBLUNION_SET_DOUBLE((tv), duk__dblval); \
} while (0)
-#define DUK_TVAL_SET_FASTINT(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i)) /* XXX: fast int-to-double */
-#define DUK_TVAL_SET_FASTINT_I32(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i))
-#define DUK_TVAL_SET_FASTINT_U32(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i))
-#define DUK_TVAL_SET_NUMBER_CHKFAST(v,d) DUK_TVAL_SET_DOUBLE((v), (d))
-#define DUK_TVAL_SET_NUMBER(v,d) DUK_TVAL_SET_DOUBLE((v), (d))
-#define DUK_TVAL_CHKFAST_INPLACE(v) do { } while (0)
-#endif
+#define DUK_TVAL_SET_I48(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i)) /* XXX: fast int-to-double */
+#define DUK_TVAL_SET_I32(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i))
+#define DUK_TVAL_SET_U32(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i))
+#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d))
+#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d))
+#define DUK_TVAL_SET_NUMBER(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d))
+#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { } while (0)
+#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { } while (0)
+#endif /* DUK_USE_FASTINT */
-#define DUK_TVAL_SET_LIGHTFUNC(v,fp,flags) DUK__TVAL_SET_LIGHTFUNC((v), (fp), (flags))
-#define DUK_TVAL_SET_STRING(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_STRING)
-#define DUK_TVAL_SET_OBJECT(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_OBJECT)
-#define DUK_TVAL_SET_BUFFER(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_BUFFER)
-#define DUK_TVAL_SET_POINTER(v,p) DUK__TVAL_SET_TAGGEDPOINTER((v), (p), DUK_TAG_POINTER)
+#define DUK_TVAL_SET_FASTINT(tv,i) DUK_TVAL_SET_I48((tv), (i)) /* alias */
-#define DUK_TVAL_SET_TVAL(v,x) do { *(v) = *(x); } while (0)
+#define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) DUK__TVAL_SET_LIGHTFUNC((tv), (fp), (flags))
+#define DUK_TVAL_SET_STRING(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_STRING)
+#define DUK_TVAL_SET_OBJECT(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_OBJECT)
+#define DUK_TVAL_SET_BUFFER(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_BUFFER)
+#define DUK_TVAL_SET_POINTER(tv,p) DUK__TVAL_SET_TAGGEDPOINTER((tv), (p), DUK_TAG_POINTER)
+
+#define DUK_TVAL_SET_TVAL(tv,x) do { *(tv) = *(x); } while (0)
/* getters */
-#define DUK_TVAL_GET_BOOLEAN(v) ((int) (v)->us[DUK_DBL_IDX_US1])
+#define DUK_TVAL_GET_BOOLEAN(tv) ((duk_small_uint_t) (tv)->us[DUK_DBL_IDX_US1])
#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_GET_DOUBLE(v) ((v)->d)
-#define DUK_TVAL_GET_FASTINT(v) DUK__TVAL_GET_FASTINT((v))
-#define DUK_TVAL_GET_FASTINT_U32(v) DUK__TVAL_GET_FASTINT_U32((v))
-#define DUK_TVAL_GET_FASTINT_I32(v) DUK__TVAL_GET_FASTINT_I32((v))
-#define DUK_TVAL_GET_NUMBER(v) duk_tval_get_number_packed((v))
+#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->d)
+#define DUK_TVAL_GET_FASTINT(tv) DUK__TVAL_GET_FASTINT((tv))
+#define DUK_TVAL_GET_FASTINT_U32(tv) DUK__TVAL_GET_FASTINT_U32((tv))
+#define DUK_TVAL_GET_FASTINT_I32(tv) DUK__TVAL_GET_FASTINT_I32((tv))
+#define DUK_TVAL_GET_NUMBER(tv) duk_tval_get_number_packed((tv))
#else
-#define DUK_TVAL_GET_NUMBER(v) ((v)->d)
-#define DUK_TVAL_GET_DOUBLE(v) ((v)->d)
+#define DUK_TVAL_GET_NUMBER(tv) ((tv)->d)
+#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->d)
#endif
-#define DUK_TVAL_GET_LIGHTFUNC(v,out_fp,out_flags) do { \
- (out_flags) = (v)->ui[DUK_DBL_IDX_UI0] & 0xffffUL; \
- (out_fp) = (duk_c_function) (v)->ui[DUK_DBL_IDX_UI1]; \
+#define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags) do { \
+ (out_flags) = (tv)->ui[DUK_DBL_IDX_UI0] & 0xffffUL; \
+ (out_fp) = (duk_c_function) (tv)->ui[DUK_DBL_IDX_UI1]; \
} while (0)
-#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(v) ((duk_c_function) ((v)->ui[DUK_DBL_IDX_UI1]))
-#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(v) (((int) (v)->ui[DUK_DBL_IDX_UI0]) & 0xffffUL)
-#define DUK_TVAL_GET_STRING(v) ((duk_hstring *) (v)->vp[DUK_DBL_IDX_VP1])
-#define DUK_TVAL_GET_OBJECT(v) ((duk_hobject *) (v)->vp[DUK_DBL_IDX_VP1])
-#define DUK_TVAL_GET_BUFFER(v) ((duk_hbuffer *) (v)->vp[DUK_DBL_IDX_VP1])
-#define DUK_TVAL_GET_POINTER(v) ((void *) (v)->vp[DUK_DBL_IDX_VP1])
-#define DUK_TVAL_GET_HEAPHDR(v) ((duk_heaphdr *) (v)->vp[DUK_DBL_IDX_VP1])
+#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((duk_c_function) ((tv)->ui[DUK_DBL_IDX_UI1]))
+#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) (((duk_small_uint_t) (tv)->ui[DUK_DBL_IDX_UI0]) & 0xffffUL)
+#define DUK_TVAL_GET_STRING(tv) ((duk_hstring *) (tv)->vp[DUK_DBL_IDX_VP1])
+#define DUK_TVAL_GET_OBJECT(tv) ((duk_hobject *) (tv)->vp[DUK_DBL_IDX_VP1])
+#define DUK_TVAL_GET_BUFFER(tv) ((duk_hbuffer *) (tv)->vp[DUK_DBL_IDX_VP1])
+#define DUK_TVAL_GET_POINTER(tv) ((void *) (tv)->vp[DUK_DBL_IDX_VP1])
+#define DUK_TVAL_GET_HEAPHDR(tv) ((duk_heaphdr *) (tv)->vp[DUK_DBL_IDX_VP1])
/* decoding */
-#define DUK_TVAL_GET_TAG(v) ((duk_small_uint_t) (v)->us[DUK_DBL_IDX_US0])
+#define DUK_TVAL_GET_TAG(tv) ((duk_small_uint_t) (tv)->us[DUK_DBL_IDX_US0])
-#define DUK_TVAL_IS_UNDEFINED(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_UNDEFINED)
-#define DUK_TVAL_IS_UNUSED(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_UNUSED)
-#define DUK_TVAL_IS_NULL(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_NULL)
-#define DUK_TVAL_IS_BOOLEAN(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_BOOLEAN)
-#define DUK_TVAL_IS_BOOLEAN_TRUE(v) ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_TRUE)
-#define DUK_TVAL_IS_BOOLEAN_FALSE(v) ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_FALSE)
-#define DUK_TVAL_IS_LIGHTFUNC(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_LIGHTFUNC)
-#define DUK_TVAL_IS_STRING(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_STRING)
-#define DUK_TVAL_IS_OBJECT(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_OBJECT)
-#define DUK_TVAL_IS_BUFFER(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_BUFFER)
-#define DUK_TVAL_IS_POINTER(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_POINTER)
+#define DUK_TVAL_IS_UNDEFINED(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_UNDEFINED)
+#define DUK_TVAL_IS_UNUSED(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_UNUSED)
+#define DUK_TVAL_IS_NULL(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_NULL)
+#define DUK_TVAL_IS_BOOLEAN(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_BOOLEAN)
+#define DUK_TVAL_IS_BOOLEAN_TRUE(tv) ((tv)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_TRUE)
+#define DUK_TVAL_IS_BOOLEAN_FALSE(tv) ((tv)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_FALSE)
+#define DUK_TVAL_IS_LIGHTFUNC(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_LIGHTFUNC)
+#define DUK_TVAL_IS_STRING(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_STRING)
+#define DUK_TVAL_IS_OBJECT(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_OBJECT)
+#define DUK_TVAL_IS_BUFFER(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_BUFFER)
+#define DUK_TVAL_IS_POINTER(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_POINTER)
#if defined(DUK_USE_FASTINT)
/* 0xfff0 is -Infinity */
-#define DUK_TVAL_IS_DOUBLE(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff0UL)
-#define DUK_TVAL_IS_FASTINT(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_FASTINT)
-#define DUK_TVAL_IS_NUMBER(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff1UL)
+#define DUK_TVAL_IS_DOUBLE(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff0UL)
+#define DUK_TVAL_IS_FASTINT(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_FASTINT)
+#define DUK_TVAL_IS_NUMBER(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff1UL)
#else
-#define DUK_TVAL_IS_NUMBER(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff0UL)
-#define DUK_TVAL_IS_DOUBLE(v) DUK_TVAL_IS_NUMBER((v))
+#define DUK_TVAL_IS_NUMBER(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff0UL)
+#define DUK_TVAL_IS_DOUBLE(tv) DUK_TVAL_IS_NUMBER((tv))
#endif
/* This is performance critical because it appears in every DECREF. */
-#define DUK_TVAL_IS_HEAP_ALLOCATED(v) (DUK_TVAL_GET_TAG((v)) >= DUK_TAG_STRING)
+#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) (DUK_TVAL_GET_TAG((tv)) >= DUK_TAG_STRING)
#if defined(DUK_USE_FASTINT)
DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_packed(duk_tval *tv);
@@ -631,8 +1135,8 @@ struct duk_tval_struct {
void *voidptr;
duk_hstring *hstring;
duk_hobject *hobject;
- duk_hcompiledfunction *hcompiledfunction;
- duk_hnativefunction *hnativefunction;
+ duk_hcompfunc *hcompfunc;
+ duk_hnatfunc *hnatfunc;
duk_hthread *hthread;
duk_hbuffer *hbuffer;
duk_heaphdr *heaphdr;
@@ -640,7 +1144,22 @@ struct duk_tval_struct {
} v;
};
-#define DUK__TAG_NUMBER 0 /* not exposed */
+typedef struct {
+ duk_small_uint_t t;
+ duk_small_uint_t v_extra;
+ /* The rest of the fields don't matter except for debug dumps and such
+ * for which a partial initializer may trigger out-ot-bounds memory
+ * reads. Include a double field which is usually as large or larger
+ * than pointers (not always however).
+ */
+ duk_double_t d;
+} duk_tval_unused;
+
+#define DUK_TVAL_UNUSED_INITIALIZER() \
+ { DUK_TAG_UNUSED, 0, 0.0 }
+
+#define DUK_TAG_MIN 0
+#define DUK_TAG_NUMBER 0 /* DUK_TAG_NUMBER only defined for non-packed duk_tval */
#if defined(DUK_USE_FASTINT)
#define DUK_TAG_FASTINT 1
#endif
@@ -653,8 +1172,12 @@ struct duk_tval_struct {
#define DUK_TAG_STRING 8 /* first heap allocated, match bit boundary */
#define DUK_TAG_OBJECT 9
#define DUK_TAG_BUFFER 10
+#define DUK_TAG_MAX 10
-/* DUK__TAG_NUMBER is intentionally first, as it is the default clause in code
+#define DUK_TVAL_IS_VALID_TAG(tv) \
+ (DUK_TVAL_GET_TAG((tv)) - DUK_TAG_MIN <= DUK_TAG_MAX - DUK_TAG_MIN)
+
+/* DUK_TAG_NUMBER is intentionally first, as it is the default clause in code
* to support the 8-byte representation. Further, it is a non-heap-allocated
* type so it should come before DUK_TAG_STRING. Finally, it should not break
* the tag value ranges covered by case-clauses in a switch-case.
@@ -662,106 +1185,159 @@ struct duk_tval_struct {
/* setters */
#define DUK_TVAL_SET_UNDEFINED(tv) do { \
- (tv)->t = DUK_TAG_UNDEFINED; \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_UNDEFINED; \
} while (0)
#define DUK_TVAL_SET_UNUSED(tv) do { \
- (tv)->t = DUK_TAG_UNUSED; \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_UNUSED; \
} while (0)
#define DUK_TVAL_SET_NULL(tv) do { \
- (tv)->t = DUK_TAG_NULL; \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_NULL; \
} while (0)
#define DUK_TVAL_SET_BOOLEAN(tv,val) do { \
- (tv)->t = DUK_TAG_BOOLEAN; \
- (tv)->v.i = (val); \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_BOOLEAN; \
+ duk__tv->v.i = (duk_small_int_t) (val); \
} while (0)
#if defined(DUK_USE_FASTINT)
#define DUK_TVAL_SET_DOUBLE(tv,val) do { \
- (tv)->t = DUK__TAG_NUMBER; \
- (tv)->v.d = (val); \
+ duk_tval *duk__tv; \
+ duk_double_t duk__dblval; \
+ duk__dblval = (val); \
+ DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); /* nop for unpacked duk_tval */ \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_NUMBER; \
+ duk__tv->v.d = duk__dblval; \
} while (0)
-#define DUK_TVAL_SET_FASTINT(tv,val) do { \
- (tv)->t = DUK_TAG_FASTINT; \
- (tv)->v.fi = (val); \
+#define DUK_TVAL_SET_I48(tv,val) do { \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_FASTINT; \
+ duk__tv->v.fi = (val); \
} while (0)
-#define DUK_TVAL_SET_FASTINT_U32(tv,val) do { \
- (tv)->t = DUK_TAG_FASTINT; \
- (tv)->v.fi = (duk_int64_t) (val); \
+#define DUK_TVAL_SET_U32(tv,val) do { \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_FASTINT; \
+ duk__tv->v.fi = (duk_int64_t) (val); \
} while (0)
-#define DUK_TVAL_SET_FASTINT_I32(tv,val) do { \
- (tv)->t = DUK_TAG_FASTINT; \
- (tv)->v.fi = (duk_int64_t) (val); \
+#define DUK_TVAL_SET_I32(tv,val) do { \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_FASTINT; \
+ duk__tv->v.fi = (duk_int64_t) (val); \
} while (0)
-#define DUK_TVAL_SET_NUMBER_CHKFAST(tv,d) \
- duk_tval_set_number_chkfast((tv), (d))
+#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) \
+ duk_tval_set_number_chkfast_fast((tv), (d))
+#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) \
+ duk_tval_set_number_chkfast_slow((tv), (d))
#define DUK_TVAL_SET_NUMBER(tv,val) \
DUK_TVAL_SET_DOUBLE((tv), (val))
-#define DUK_TVAL_CHKFAST_INPLACE(v) do { \
+#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { \
duk_tval *duk__tv; \
duk_double_t duk__d; \
- duk__tv = (v); \
+ duk__tv = (tv); \
if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
- DUK_TVAL_SET_NUMBER_CHKFAST(duk__tv, duk__d); \
+ DUK_TVAL_SET_NUMBER_CHKFAST_FAST(duk__tv, duk__d); \
} \
} while (0)
-#else
+#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { \
+ duk_tval *duk__tv; \
+ duk_double_t duk__d; \
+ duk__tv = (tv); \
+ if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
+ duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
+ DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(duk__tv, duk__d); \
+ } \
+ } while (0)
+#else /* DUK_USE_FASTINT */
#define DUK_TVAL_SET_DOUBLE(tv,d) \
DUK_TVAL_SET_NUMBER((tv), (d))
-#define DUK_TVAL_SET_FASTINT(tv,val) \
+#define DUK_TVAL_SET_I48(tv,val) \
DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) /* XXX: fast int-to-double */
-#define DUK_TVAL_SET_FASTINT_U32(tv,val) \
+#define DUK_TVAL_SET_U32(tv,val) \
DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val))
-#define DUK_TVAL_SET_FASTINT_I32(tv,val) \
+#define DUK_TVAL_SET_I32(tv,val) \
DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val))
#define DUK_TVAL_SET_NUMBER(tv,val) do { \
- (tv)->t = DUK__TAG_NUMBER; \
- (tv)->v.d = (val); \
+ duk_tval *duk__tv; \
+ duk_double_t duk__dblval; \
+ duk__dblval = (val); \
+ DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); /* nop for unpacked duk_tval */ \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_NUMBER; \
+ duk__tv->v.d = duk__dblval; \
} while (0)
-#define DUK_TVAL_SET_NUMBER_CHKFAST(tv,d) \
+#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) \
DUK_TVAL_SET_NUMBER((tv), (d))
-#define DUK_TVAL_CHKFAST_INPLACE(v) do { } while (0)
+#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) \
+ DUK_TVAL_SET_NUMBER((tv), (d))
+#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { } while (0)
+#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { } while (0)
#endif /* DUK_USE_FASTINT */
+#define DUK_TVAL_SET_FASTINT(tv,i) \
+ DUK_TVAL_SET_I48((tv), (i)) /* alias */
+
#define DUK_TVAL_SET_POINTER(tv,hptr) do { \
- (tv)->t = DUK_TAG_POINTER; \
- (tv)->v.voidptr = (hptr); \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_POINTER; \
+ duk__tv->v.voidptr = (hptr); \
} while (0)
#define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \
- (tv)->t = DUK_TAG_LIGHTFUNC; \
- (tv)->v_extra = (flags); \
- (tv)->v.lightfunc = (duk_c_function) (fp); \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_LIGHTFUNC; \
+ duk__tv->v_extra = (flags); \
+ duk__tv->v.lightfunc = (duk_c_function) (fp); \
} while (0)
#define DUK_TVAL_SET_STRING(tv,hptr) do { \
- (tv)->t = DUK_TAG_STRING; \
- (tv)->v.hstring = (hptr); \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_STRING; \
+ duk__tv->v.hstring = (hptr); \
} while (0)
#define DUK_TVAL_SET_OBJECT(tv,hptr) do { \
- (tv)->t = DUK_TAG_OBJECT; \
- (tv)->v.hobject = (hptr); \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_OBJECT; \
+ duk__tv->v.hobject = (hptr); \
} while (0)
#define DUK_TVAL_SET_BUFFER(tv,hptr) do { \
- (tv)->t = DUK_TAG_BUFFER; \
- (tv)->v.hbuffer = (hptr); \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_BUFFER; \
+ duk__tv->v.hbuffer = (hptr); \
} while (0)
#define DUK_TVAL_SET_NAN(tv) do { \
/* in non-packed representation we don't care about which NaN is used */ \
- (tv)->t = DUK__TAG_NUMBER; \
- (tv)->v.d = DUK_DOUBLE_NAN; \
+ duk_tval *duk__tv; \
+ duk__tv = (tv); \
+ duk__tv->t = DUK_TAG_NUMBER; \
+ duk__tv->v.d = DUK_DOUBLE_NAN; \
} while (0)
-#define DUK_TVAL_SET_TVAL(v,x) do { *(v) = *(x); } while (0)
+#define DUK_TVAL_SET_TVAL(tv,x) do { *(tv) = *(x); } while (0)
/* getters */
-#define DUK_TVAL_GET_BOOLEAN(tv) ((tv)->v.i)
+#define DUK_TVAL_GET_BOOLEAN(tv) ((duk_small_uint_t) (tv)->v.i)
#if defined(DUK_USE_FASTINT)
#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d)
#define DUK_TVAL_GET_FASTINT(tv) ((tv)->v.fi)
@@ -788,7 +1364,7 @@ struct duk_tval_struct {
(out_fp) = (tv)->v.lightfunc; \
} while (0)
#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((tv)->v.lightfunc)
-#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) ((duk_uint32_t) ((tv)->v_extra))
+#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) ((duk_small_uint_t) ((tv)->v_extra))
#define DUK_TVAL_GET_STRING(tv) ((tv)->v.hstring)
#define DUK_TVAL_GET_OBJECT(tv) ((tv)->v.hobject)
#define DUK_TVAL_GET_BUFFER(tv) ((tv)->v.hbuffer)
@@ -803,13 +1379,13 @@ struct duk_tval_struct {
#define DUK_TVAL_IS_BOOLEAN_TRUE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i != 0))
#define DUK_TVAL_IS_BOOLEAN_FALSE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i == 0))
#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_IS_DOUBLE(tv) ((tv)->t == DUK__TAG_NUMBER)
+#define DUK_TVAL_IS_DOUBLE(tv) ((tv)->t == DUK_TAG_NUMBER)
#define DUK_TVAL_IS_FASTINT(tv) ((tv)->t == DUK_TAG_FASTINT)
-#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK__TAG_NUMBER || \
+#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK_TAG_NUMBER || \
(tv)->t == DUK_TAG_FASTINT)
#else
-#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK__TAG_NUMBER)
-#define DUK_TVAL_IS_DOUBLE(v) DUK_TVAL_IS_NUMBER((v))
+#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK_TAG_NUMBER)
+#define DUK_TVAL_IS_DOUBLE(tv) DUK_TVAL_IS_NUMBER((tv))
#endif /* DUK_USE_FASTINT */
#define DUK_TVAL_IS_POINTER(tv) ((tv)->t == DUK_TAG_POINTER)
#define DUK_TVAL_IS_LIGHTFUNC(tv) ((tv)->t == DUK_TAG_LIGHTFUNC)
@@ -840,19 +1416,24 @@ DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv
* Convenience (independent of representation)
*/
-#define DUK_TVAL_SET_BOOLEAN_TRUE(v) DUK_TVAL_SET_BOOLEAN(v, 1)
-#define DUK_TVAL_SET_BOOLEAN_FALSE(v) DUK_TVAL_SET_BOOLEAN(v, 0)
+#define DUK_TVAL_SET_BOOLEAN_TRUE(tv) DUK_TVAL_SET_BOOLEAN((tv), 1)
+#define DUK_TVAL_SET_BOOLEAN_FALSE(tv) DUK_TVAL_SET_BOOLEAN((tv), 0)
+
+#define DUK_TVAL_STRING_IS_SYMBOL(tv) \
+ DUK_HSTRING_HAS_SYMBOL(DUK_TVAL_GET_STRING((tv)))
/* Lightfunc flags packing and unpacking. */
-/* Sign extend: 0x0000##00 -> 0x##000000 -> sign extend to 0xssssss## */
+/* Sign extend: 0x0000##00 -> 0x##000000 -> sign extend to 0xssssss##.
+ * Avoid signed shifts due to portability limitations.
+ */
#define DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags) \
- ((((duk_int32_t) (lf_flags)) << 16) >> 24)
+ ((duk_int32_t) (duk_int8_t) (((duk_uint16_t) (lf_flags)) >> 8))
#define DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags) \
- (((lf_flags) >> 4) & 0x0f)
+ (((lf_flags) >> 4) & 0x0fU)
#define DUK_LFUNC_FLAGS_GET_NARGS(lf_flags) \
- ((lf_flags) & 0x0f)
+ ((lf_flags) & 0x0fU)
#define DUK_LFUNC_FLAGS_PACK(magic,length,nargs) \
- (((magic) & 0xff) << 8) | ((length) << 4) | (nargs)
+ ((((duk_small_uint_t) (magic)) & 0xffU) << 8) | ((length) << 4) | (nargs)
#define DUK_LFUNC_NARGS_VARARGS 0x0f /* varargs marker */
#define DUK_LFUNC_NARGS_MIN 0x00
@@ -864,24 +1445,26 @@ DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv
/* fastint constants etc */
#if defined(DUK_USE_FASTINT)
-#define DUK_FASTINT_MIN (-0x800000000000LL)
-#define DUK_FASTINT_MAX 0x7fffffffffffLL
+#define DUK_FASTINT_MIN (DUK_I64_CONSTANT(-0x800000000000))
+#define DUK_FASTINT_MAX (DUK_I64_CONSTANT(0x7fffffffffff))
#define DUK_FASTINT_BITS 48
-DUK_INTERNAL_DECL void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x);
+DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_fast(duk_tval *tv, duk_double_t x);
+DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double_t x);
#endif
#endif /* DUK_TVAL_H_INCLUDED */
+/* #include duk_builtins.h */
#line 1 "duk_builtins.h"
/*
* Automatically generated by genbuiltins.py, do not edit!
*/
-#ifndef DUK_BUILTINS_H_INCLUDED
+#if !defined(DUK_BUILTINS_H_INCLUDED)
#define DUK_BUILTINS_H_INCLUDED
#if defined(DUK_USE_ROM_STRINGS)
-#error ROM support not enabled, rerun make_dist.py with --rom-support
+#error ROM support not enabled, rerun configure.py with --rom-support
#else /* DUK_USE_ROM_STRINGS */
#define DUK_STRIDX_UC_UNDEFINED 0 /* 'Undefined' */
#define DUK_HEAP_STRING_UC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_UNDEFINED)
@@ -889,102 +1472,102 @@ DUK_INTERNAL_DECL void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x)
#define DUK_STRIDX_UC_NULL 1 /* 'Null' */
#define DUK_HEAP_STRING_UC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NULL)
#define DUK_HTHREAD_STRING_UC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NULL)
-#define DUK_STRIDX_UC_ARGUMENTS 2 /* 'Arguments' */
+#define DUK_STRIDX_UC_SYMBOL 2 /* 'Symbol' */
+#define DUK_HEAP_STRING_UC_SYMBOL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_SYMBOL)
+#define DUK_HTHREAD_STRING_UC_SYMBOL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_SYMBOL)
+#define DUK_STRIDX_UC_ARGUMENTS 3 /* 'Arguments' */
#define DUK_HEAP_STRING_UC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ARGUMENTS)
#define DUK_HTHREAD_STRING_UC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ARGUMENTS)
-#define DUK_STRIDX_UC_OBJECT 3 /* 'Object' */
+#define DUK_STRIDX_UC_OBJECT 4 /* 'Object' */
#define DUK_HEAP_STRING_UC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_OBJECT)
#define DUK_HTHREAD_STRING_UC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_OBJECT)
-#define DUK_STRIDX_UC_FUNCTION 4 /* 'Function' */
+#define DUK_STRIDX_UC_FUNCTION 5 /* 'Function' */
#define DUK_HEAP_STRING_UC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_FUNCTION)
#define DUK_HTHREAD_STRING_UC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_FUNCTION)
-#define DUK_STRIDX_ARRAY 5 /* 'Array' */
+#define DUK_STRIDX_ARRAY 6 /* 'Array' */
#define DUK_HEAP_STRING_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY)
#define DUK_HTHREAD_STRING_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY)
-#define DUK_STRIDX_UC_STRING 6 /* 'String' */
+#define DUK_STRIDX_UC_STRING 7 /* 'String' */
#define DUK_HEAP_STRING_UC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_STRING)
#define DUK_HTHREAD_STRING_UC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_STRING)
-#define DUK_STRIDX_UC_BOOLEAN 7 /* 'Boolean' */
+#define DUK_STRIDX_UC_BOOLEAN 8 /* 'Boolean' */
#define DUK_HEAP_STRING_UC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BOOLEAN)
#define DUK_HTHREAD_STRING_UC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BOOLEAN)
-#define DUK_STRIDX_UC_NUMBER 8 /* 'Number' */
+#define DUK_STRIDX_UC_NUMBER 9 /* 'Number' */
#define DUK_HEAP_STRING_UC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NUMBER)
#define DUK_HTHREAD_STRING_UC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NUMBER)
-#define DUK_STRIDX_DATE 9 /* 'Date' */
+#define DUK_STRIDX_DATE 10 /* 'Date' */
#define DUK_HEAP_STRING_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATE)
#define DUK_HTHREAD_STRING_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATE)
-#define DUK_STRIDX_REG_EXP 10 /* 'RegExp' */
+#define DUK_STRIDX_REG_EXP 11 /* 'RegExp' */
#define DUK_HEAP_STRING_REG_EXP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REG_EXP)
#define DUK_HTHREAD_STRING_REG_EXP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REG_EXP)
-#define DUK_STRIDX_UC_ERROR 11 /* 'Error' */
+#define DUK_STRIDX_UC_ERROR 12 /* 'Error' */
#define DUK_HEAP_STRING_UC_ERROR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ERROR)
#define DUK_HTHREAD_STRING_UC_ERROR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ERROR)
-#define DUK_STRIDX_MATH 12 /* 'Math' */
+#define DUK_STRIDX_MATH 13 /* 'Math' */
#define DUK_HEAP_STRING_MATH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MATH)
#define DUK_HTHREAD_STRING_MATH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MATH)
-#define DUK_STRIDX_JSON 13 /* 'JSON' */
+#define DUK_STRIDX_JSON 14 /* 'JSON' */
#define DUK_HEAP_STRING_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON)
#define DUK_HTHREAD_STRING_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON)
-#define DUK_STRIDX_EMPTY_STRING 14 /* '' */
+#define DUK_STRIDX_EMPTY_STRING 15 /* '' */
#define DUK_HEAP_STRING_EMPTY_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EMPTY_STRING)
#define DUK_HTHREAD_STRING_EMPTY_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EMPTY_STRING)
-#define DUK_STRIDX_ARRAY_BUFFER 15 /* 'ArrayBuffer' */
+#define DUK_STRIDX_ARRAY_BUFFER 16 /* 'ArrayBuffer' */
#define DUK_HEAP_STRING_ARRAY_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY_BUFFER)
#define DUK_HTHREAD_STRING_ARRAY_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY_BUFFER)
-#define DUK_STRIDX_DATA_VIEW 16 /* 'DataView' */
+#define DUK_STRIDX_DATA_VIEW 17 /* 'DataView' */
#define DUK_HEAP_STRING_DATA_VIEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA_VIEW)
#define DUK_HTHREAD_STRING_DATA_VIEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA_VIEW)
-#define DUK_STRIDX_INT8_ARRAY 17 /* 'Int8Array' */
+#define DUK_STRIDX_INT8_ARRAY 18 /* 'Int8Array' */
#define DUK_HEAP_STRING_INT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT8_ARRAY)
#define DUK_HTHREAD_STRING_INT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT8_ARRAY)
-#define DUK_STRIDX_UINT8_ARRAY 18 /* 'Uint8Array' */
+#define DUK_STRIDX_UINT8_ARRAY 19 /* 'Uint8Array' */
#define DUK_HEAP_STRING_UINT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_ARRAY)
#define DUK_HTHREAD_STRING_UINT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_ARRAY)
-#define DUK_STRIDX_UINT8_CLAMPED_ARRAY 19 /* 'Uint8ClampedArray' */
+#define DUK_STRIDX_UINT8_CLAMPED_ARRAY 20 /* 'Uint8ClampedArray' */
#define DUK_HEAP_STRING_UINT8_CLAMPED_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_CLAMPED_ARRAY)
#define DUK_HTHREAD_STRING_UINT8_CLAMPED_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_CLAMPED_ARRAY)
-#define DUK_STRIDX_INT16_ARRAY 20 /* 'Int16Array' */
+#define DUK_STRIDX_INT16_ARRAY 21 /* 'Int16Array' */
#define DUK_HEAP_STRING_INT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT16_ARRAY)
#define DUK_HTHREAD_STRING_INT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT16_ARRAY)
-#define DUK_STRIDX_UINT16_ARRAY 21 /* 'Uint16Array' */
+#define DUK_STRIDX_UINT16_ARRAY 22 /* 'Uint16Array' */
#define DUK_HEAP_STRING_UINT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT16_ARRAY)
#define DUK_HTHREAD_STRING_UINT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT16_ARRAY)
-#define DUK_STRIDX_INT32_ARRAY 22 /* 'Int32Array' */
+#define DUK_STRIDX_INT32_ARRAY 23 /* 'Int32Array' */
#define DUK_HEAP_STRING_INT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT32_ARRAY)
#define DUK_HTHREAD_STRING_INT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT32_ARRAY)
-#define DUK_STRIDX_UINT32_ARRAY 23 /* 'Uint32Array' */
+#define DUK_STRIDX_UINT32_ARRAY 24 /* 'Uint32Array' */
#define DUK_HEAP_STRING_UINT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT32_ARRAY)
#define DUK_HTHREAD_STRING_UINT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT32_ARRAY)
-#define DUK_STRIDX_FLOAT32_ARRAY 24 /* 'Float32Array' */
+#define DUK_STRIDX_FLOAT32_ARRAY 25 /* 'Float32Array' */
#define DUK_HEAP_STRING_FLOAT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT32_ARRAY)
#define DUK_HTHREAD_STRING_FLOAT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT32_ARRAY)
-#define DUK_STRIDX_FLOAT64_ARRAY 25 /* 'Float64Array' */
+#define DUK_STRIDX_FLOAT64_ARRAY 26 /* 'Float64Array' */
#define DUK_HEAP_STRING_FLOAT64_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT64_ARRAY)
#define DUK_HTHREAD_STRING_FLOAT64_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT64_ARRAY)
-#define DUK_STRIDX_GLOBAL 26 /* 'global' */
+#define DUK_STRIDX_GLOBAL 27 /* 'global' */
#define DUK_HEAP_STRING_GLOBAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GLOBAL)
#define DUK_HTHREAD_STRING_GLOBAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GLOBAL)
-#define DUK_STRIDX_OBJ_ENV 27 /* 'ObjEnv' */
+#define DUK_STRIDX_OBJ_ENV 28 /* 'ObjEnv' */
#define DUK_HEAP_STRING_OBJ_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OBJ_ENV)
#define DUK_HTHREAD_STRING_OBJ_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OBJ_ENV)
-#define DUK_STRIDX_DEC_ENV 28 /* 'DecEnv' */
+#define DUK_STRIDX_DEC_ENV 29 /* 'DecEnv' */
#define DUK_HEAP_STRING_DEC_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEC_ENV)
#define DUK_HTHREAD_STRING_DEC_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEC_ENV)
-#define DUK_STRIDX_UC_BUFFER 29 /* 'Buffer' */
+#define DUK_STRIDX_UC_BUFFER 30 /* 'Buffer' */
#define DUK_HEAP_STRING_UC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BUFFER)
#define DUK_HTHREAD_STRING_UC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BUFFER)
-#define DUK_STRIDX_UC_POINTER 30 /* 'Pointer' */
+#define DUK_STRIDX_UC_POINTER 31 /* 'Pointer' */
#define DUK_HEAP_STRING_UC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_POINTER)
#define DUK_HTHREAD_STRING_UC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_POINTER)
-#define DUK_STRIDX_UC_THREAD 31 /* 'Thread' */
+#define DUK_STRIDX_UC_THREAD 32 /* 'Thread' */
#define DUK_HEAP_STRING_UC_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_THREAD)
#define DUK_HTHREAD_STRING_UC_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_THREAD)
-#define DUK_STRIDX_EVAL 32 /* 'eval' */
+#define DUK_STRIDX_EVAL 33 /* 'eval' */
#define DUK_HEAP_STRING_EVAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVAL)
#define DUK_HTHREAD_STRING_EVAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVAL)
-#define DUK_STRIDX_DEFINE_PROPERTY 33 /* 'defineProperty' */
-#define DUK_HEAP_STRING_DEFINE_PROPERTY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFINE_PROPERTY)
-#define DUK_HTHREAD_STRING_DEFINE_PROPERTY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFINE_PROPERTY)
#define DUK_STRIDX_VALUE 34 /* 'value' */
#define DUK_HEAP_STRING_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE)
#define DUK_HTHREAD_STRING_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE)
@@ -1027,9 +1610,9 @@ DUK_INTERNAL_DECL void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x)
#define DUK_STRIDX_LAST_INDEX 47 /* 'lastIndex' */
#define DUK_HEAP_STRING_LAST_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LAST_INDEX)
#define DUK_HTHREAD_STRING_LAST_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LAST_INDEX)
-#define DUK_STRIDX_ESCAPED_EMPTY_REGEXP 48 /* '(?:)' */
-#define DUK_HEAP_STRING_ESCAPED_EMPTY_REGEXP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ESCAPED_EMPTY_REGEXP)
-#define DUK_HTHREAD_STRING_ESCAPED_EMPTY_REGEXP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ESCAPED_EMPTY_REGEXP)
+#define DUK_STRIDX_FLAGS 48 /* 'flags' */
+#define DUK_HEAP_STRING_FLAGS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLAGS)
+#define DUK_HTHREAD_STRING_FLAGS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLAGS)
#define DUK_STRIDX_INDEX 49 /* 'index' */
#define DUK_HEAP_STRING_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INDEX)
#define DUK_HTHREAD_STRING_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INDEX)
@@ -1051,30 +1634,30 @@ DUK_INTERNAL_DECL void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x)
#define DUK_STRIDX_LC_STRING 55 /* 'string' */
#define DUK_HEAP_STRING_LC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_STRING)
#define DUK_HTHREAD_STRING_LC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_STRING)
-#define DUK_STRIDX_LC_OBJECT 56 /* 'object' */
+#define DUK_STRIDX_LC_SYMBOL 56 /* 'symbol' */
+#define DUK_HEAP_STRING_LC_SYMBOL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_SYMBOL)
+#define DUK_HTHREAD_STRING_LC_SYMBOL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_SYMBOL)
+#define DUK_STRIDX_LC_OBJECT 57 /* 'object' */
#define DUK_HEAP_STRING_LC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_OBJECT)
#define DUK_HTHREAD_STRING_LC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_OBJECT)
-#define DUK_STRIDX_LC_UNDEFINED 57 /* 'undefined' */
+#define DUK_STRIDX_LC_UNDEFINED 58 /* 'undefined' */
#define DUK_HEAP_STRING_LC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_UNDEFINED)
#define DUK_HTHREAD_STRING_LC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_UNDEFINED)
-#define DUK_STRIDX_NAN 58 /* 'NaN' */
+#define DUK_STRIDX_NAN 59 /* 'NaN' */
#define DUK_HEAP_STRING_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAN)
#define DUK_HTHREAD_STRING_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAN)
-#define DUK_STRIDX_INFINITY 59 /* 'Infinity' */
+#define DUK_STRIDX_INFINITY 60 /* 'Infinity' */
#define DUK_HEAP_STRING_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INFINITY)
#define DUK_HTHREAD_STRING_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INFINITY)
-#define DUK_STRIDX_MINUS_INFINITY 60 /* '-Infinity' */
+#define DUK_STRIDX_MINUS_INFINITY 61 /* '-Infinity' */
#define DUK_HEAP_STRING_MINUS_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_INFINITY)
#define DUK_HTHREAD_STRING_MINUS_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_INFINITY)
-#define DUK_STRIDX_MINUS_ZERO 61 /* '-0' */
+#define DUK_STRIDX_MINUS_ZERO 62 /* '-0' */
#define DUK_HEAP_STRING_MINUS_ZERO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_ZERO)
#define DUK_HTHREAD_STRING_MINUS_ZERO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_ZERO)
-#define DUK_STRIDX_COMMA 62 /* ',' */
+#define DUK_STRIDX_COMMA 63 /* ',' */
#define DUK_HEAP_STRING_COMMA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMMA)
#define DUK_HTHREAD_STRING_COMMA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMMA)
-#define DUK_STRIDX_SPACE 63 /* ' ' */
-#define DUK_HEAP_STRING_SPACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SPACE)
-#define DUK_HTHREAD_STRING_SPACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SPACE)
#define DUK_STRIDX_NEWLINE_4SPACE 64 /* '\n ' */
#define DUK_HEAP_STRING_NEWLINE_4SPACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEWLINE_4SPACE)
#define DUK_HTHREAD_STRING_NEWLINE_4SPACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEWLINE_4SPACE)
@@ -1093,388 +1676,301 @@ DUK_INTERNAL_DECL void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x)
#define DUK_STRIDX_CALLER 69 /* 'caller' */
#define DUK_HEAP_STRING_CALLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLER)
#define DUK_HTHREAD_STRING_CALLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLER)
-#define DUK_STRIDX_HAS 70 /* 'has' */
-#define DUK_HEAP_STRING_HAS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HAS)
-#define DUK_HTHREAD_STRING_HAS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HAS)
-#define DUK_STRIDX_GET 71 /* 'get' */
-#define DUK_HEAP_STRING_GET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET)
-#define DUK_HTHREAD_STRING_GET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET)
+#define DUK_STRIDX_APPLY 70 /* 'apply' */
+#define DUK_HEAP_STRING_APPLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_APPLY)
+#define DUK_HTHREAD_STRING_APPLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_APPLY)
+#define DUK_STRIDX_CONSTRUCT 71 /* 'construct' */
+#define DUK_HEAP_STRING_CONSTRUCT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCT)
+#define DUK_HTHREAD_STRING_CONSTRUCT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCT)
#define DUK_STRIDX_DELETE_PROPERTY 72 /* 'deleteProperty' */
#define DUK_HEAP_STRING_DELETE_PROPERTY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE_PROPERTY)
#define DUK_HTHREAD_STRING_DELETE_PROPERTY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE_PROPERTY)
-#define DUK_STRIDX_ENUMERATE 73 /* 'enumerate' */
-#define DUK_HEAP_STRING_ENUMERATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUMERATE)
-#define DUK_HTHREAD_STRING_ENUMERATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUMERATE)
-#define DUK_STRIDX_OWN_KEYS 74 /* 'ownKeys' */
+#define DUK_STRIDX_GET 73 /* 'get' */
+#define DUK_HEAP_STRING_GET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET)
+#define DUK_HTHREAD_STRING_GET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET)
+#define DUK_STRIDX_HAS 74 /* 'has' */
+#define DUK_HEAP_STRING_HAS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HAS)
+#define DUK_HTHREAD_STRING_HAS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HAS)
+#define DUK_STRIDX_OWN_KEYS 75 /* 'ownKeys' */
#define DUK_HEAP_STRING_OWN_KEYS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OWN_KEYS)
#define DUK_HTHREAD_STRING_OWN_KEYS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OWN_KEYS)
-#define DUK_STRIDX_SET_PROTOTYPE_OF 75 /* 'setPrototypeOf' */
+#define DUK_STRIDX_SET_PROTOTYPE_OF 76 /* 'setPrototypeOf' */
#define DUK_HEAP_STRING_SET_PROTOTYPE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_PROTOTYPE_OF)
#define DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_PROTOTYPE_OF)
-#define DUK_STRIDX___PROTO__ 76 /* '__proto__' */
+#define DUK_STRIDX___PROTO__ 77 /* '__proto__' */
#define DUK_HEAP_STRING___PROTO__(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX___PROTO__)
#define DUK_HTHREAD_STRING___PROTO__(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX___PROTO__)
-#define DUK_STRIDX_REQUIRE 77 /* 'require' */
-#define DUK_HEAP_STRING_REQUIRE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REQUIRE)
-#define DUK_HTHREAD_STRING_REQUIRE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REQUIRE)
-#define DUK_STRIDX_ID 78 /* 'id' */
-#define DUK_HEAP_STRING_ID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ID)
-#define DUK_HTHREAD_STRING_ID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ID)
-#define DUK_STRIDX_EXPORTS 79 /* 'exports' */
-#define DUK_HEAP_STRING_EXPORTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORTS)
-#define DUK_HTHREAD_STRING_EXPORTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORTS)
-#define DUK_STRIDX_FILENAME 80 /* 'filename' */
-#define DUK_HEAP_STRING_FILENAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILENAME)
-#define DUK_HTHREAD_STRING_FILENAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILENAME)
-#define DUK_STRIDX_TO_STRING 81 /* 'toString' */
+#define DUK_STRIDX_TO_STRING 78 /* 'toString' */
#define DUK_HEAP_STRING_TO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_STRING)
#define DUK_HTHREAD_STRING_TO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_STRING)
-#define DUK_STRIDX_TO_JSON 82 /* 'toJSON' */
+#define DUK_STRIDX_TO_JSON 79 /* 'toJSON' */
#define DUK_HEAP_STRING_TO_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_JSON)
#define DUK_HTHREAD_STRING_TO_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_JSON)
-#define DUK_STRIDX_TYPE 83 /* 'type' */
+#define DUK_STRIDX_TYPE 80 /* 'type' */
#define DUK_HEAP_STRING_TYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPE)
#define DUK_HTHREAD_STRING_TYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPE)
-#define DUK_STRIDX_DATA 84 /* 'data' */
+#define DUK_STRIDX_DATA 81 /* 'data' */
#define DUK_HEAP_STRING_DATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA)
#define DUK_HTHREAD_STRING_DATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA)
-#define DUK_STRIDX_LENGTH 85 /* 'length' */
+#define DUK_STRIDX_LENGTH 82 /* 'length' */
#define DUK_HEAP_STRING_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LENGTH)
#define DUK_HTHREAD_STRING_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LENGTH)
-#define DUK_STRIDX_BYTE_LENGTH 86 /* 'byteLength' */
-#define DUK_HEAP_STRING_BYTE_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BYTE_LENGTH)
-#define DUK_HTHREAD_STRING_BYTE_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BYTE_LENGTH)
-#define DUK_STRIDX_BYTE_OFFSET 87 /* 'byteOffset' */
-#define DUK_HEAP_STRING_BYTE_OFFSET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BYTE_OFFSET)
-#define DUK_HTHREAD_STRING_BYTE_OFFSET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BYTE_OFFSET)
-#define DUK_STRIDX_BYTES_PER_ELEMENT 88 /* 'BYTES_PER_ELEMENT' */
-#define DUK_HEAP_STRING_BYTES_PER_ELEMENT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BYTES_PER_ELEMENT)
-#define DUK_HTHREAD_STRING_BYTES_PER_ELEMENT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BYTES_PER_ELEMENT)
-#define DUK_STRIDX_SET 89 /* 'set' */
+#define DUK_STRIDX_SET 83 /* 'set' */
#define DUK_HEAP_STRING_SET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET)
#define DUK_HTHREAD_STRING_SET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET)
-#define DUK_STRIDX_STACK 90 /* 'stack' */
+#define DUK_STRIDX_STACK 84 /* 'stack' */
#define DUK_HEAP_STRING_STACK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STACK)
#define DUK_HTHREAD_STRING_STACK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STACK)
-#define DUK_STRIDX_PC 91 /* 'pc' */
+#define DUK_STRIDX_PC 85 /* 'pc' */
#define DUK_HEAP_STRING_PC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PC)
#define DUK_HTHREAD_STRING_PC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PC)
-#define DUK_STRIDX_LINE_NUMBER 92 /* 'lineNumber' */
+#define DUK_STRIDX_LINE_NUMBER 86 /* 'lineNumber' */
#define DUK_HEAP_STRING_LINE_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE_NUMBER)
#define DUK_HTHREAD_STRING_LINE_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE_NUMBER)
-#define DUK_STRIDX_INT_TRACEDATA 93 /* '\xffTracedata' */
+#define DUK_STRIDX_INT_TRACEDATA 87 /* '\x82Tracedata' */
#define DUK_HEAP_STRING_INT_TRACEDATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TRACEDATA)
#define DUK_HTHREAD_STRING_INT_TRACEDATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TRACEDATA)
-#define DUK_STRIDX_NAME 94 /* 'name' */
+#define DUK_STRIDX_NAME 88 /* 'name' */
#define DUK_HEAP_STRING_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAME)
#define DUK_HTHREAD_STRING_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAME)
-#define DUK_STRIDX_FILE_NAME 95 /* 'fileName' */
+#define DUK_STRIDX_FILE_NAME 89 /* 'fileName' */
#define DUK_HEAP_STRING_FILE_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILE_NAME)
#define DUK_HTHREAD_STRING_FILE_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILE_NAME)
-#define DUK_STRIDX_LC_BUFFER 96 /* 'buffer' */
-#define DUK_HEAP_STRING_LC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BUFFER)
-#define DUK_HTHREAD_STRING_LC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BUFFER)
-#define DUK_STRIDX_LC_POINTER 97 /* 'pointer' */
+#define DUK_STRIDX_LC_POINTER 90 /* 'pointer' */
#define DUK_HEAP_STRING_LC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_POINTER)
#define DUK_HTHREAD_STRING_LC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_POINTER)
-#define DUK_STRIDX_INT_VALUE 98 /* '\xffValue' */
-#define DUK_HEAP_STRING_INT_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE)
-#define DUK_HTHREAD_STRING_INT_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE)
-#define DUK_STRIDX_INT_NEXT 99 /* '\xffNext' */
-#define DUK_HEAP_STRING_INT_NEXT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_NEXT)
-#define DUK_HTHREAD_STRING_INT_NEXT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_NEXT)
-#define DUK_STRIDX_INT_BYTECODE 100 /* '\xffBytecode' */
-#define DUK_HEAP_STRING_INT_BYTECODE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_BYTECODE)
-#define DUK_HTHREAD_STRING_INT_BYTECODE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_BYTECODE)
-#define DUK_STRIDX_INT_FORMALS 101 /* '\xffFormals' */
-#define DUK_HEAP_STRING_INT_FORMALS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FORMALS)
-#define DUK_HTHREAD_STRING_INT_FORMALS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FORMALS)
-#define DUK_STRIDX_INT_VARMAP 102 /* '\xffVarmap' */
-#define DUK_HEAP_STRING_INT_VARMAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARMAP)
-#define DUK_HTHREAD_STRING_INT_VARMAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARMAP)
-#define DUK_STRIDX_INT_LEXENV 103 /* '\xffLexenv' */
-#define DUK_HEAP_STRING_INT_LEXENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_LEXENV)
-#define DUK_HTHREAD_STRING_INT_LEXENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_LEXENV)
-#define DUK_STRIDX_INT_VARENV 104 /* '\xffVarenv' */
-#define DUK_HEAP_STRING_INT_VARENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV)
-#define DUK_HTHREAD_STRING_INT_VARENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV)
-#define DUK_STRIDX_INT_SOURCE 105 /* '\xffSource' */
-#define DUK_HEAP_STRING_INT_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_SOURCE)
-#define DUK_HTHREAD_STRING_INT_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_SOURCE)
-#define DUK_STRIDX_INT_PC2LINE 106 /* '\xffPc2line' */
-#define DUK_HEAP_STRING_INT_PC2LINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_PC2LINE)
-#define DUK_HTHREAD_STRING_INT_PC2LINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_PC2LINE)
-#define DUK_STRIDX_INT_ARGS 107 /* '\xffArgs' */
-#define DUK_HEAP_STRING_INT_ARGS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_ARGS)
-#define DUK_HTHREAD_STRING_INT_ARGS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_ARGS)
-#define DUK_STRIDX_INT_MAP 108 /* '\xffMap' */
-#define DUK_HEAP_STRING_INT_MAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_MAP)
-#define DUK_HTHREAD_STRING_INT_MAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_MAP)
-#define DUK_STRIDX_INT_FINALIZER 109 /* '\xffFinalizer' */
-#define DUK_HEAP_STRING_INT_FINALIZER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FINALIZER)
-#define DUK_HTHREAD_STRING_INT_FINALIZER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FINALIZER)
-#define DUK_STRIDX_INT_HANDLER 110 /* '\xffHandler' */
-#define DUK_HEAP_STRING_INT_HANDLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_HANDLER)
-#define DUK_HTHREAD_STRING_INT_HANDLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_HANDLER)
-#define DUK_STRIDX_INT_CALLEE 111 /* '\xffCallee' */
-#define DUK_HEAP_STRING_INT_CALLEE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_CALLEE)
-#define DUK_HTHREAD_STRING_INT_CALLEE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_CALLEE)
-#define DUK_STRIDX_INT_THREAD 112 /* '\xffThread' */
-#define DUK_HEAP_STRING_INT_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THREAD)
-#define DUK_HTHREAD_STRING_INT_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THREAD)
-#define DUK_STRIDX_INT_REGBASE 113 /* '\xffRegbase' */
-#define DUK_HEAP_STRING_INT_REGBASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_REGBASE)
-#define DUK_HTHREAD_STRING_INT_REGBASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_REGBASE)
-#define DUK_STRIDX_INT_TARGET 114 /* '\xffTarget' */
+#define DUK_STRIDX_INT_TARGET 91 /* '\x82Target' */
#define DUK_HEAP_STRING_INT_TARGET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TARGET)
#define DUK_HTHREAD_STRING_INT_TARGET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TARGET)
-#define DUK_STRIDX_INT_THIS 115 /* '\xffThis' */
-#define DUK_HEAP_STRING_INT_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THIS)
-#define DUK_HTHREAD_STRING_INT_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THIS)
-#define DUK_STRIDX_COMPILE 116 /* 'compile' */
+#define DUK_STRIDX_INT_NEXT 92 /* '\x82Next' */
+#define DUK_HEAP_STRING_INT_NEXT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_NEXT)
+#define DUK_HTHREAD_STRING_INT_NEXT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_NEXT)
+#define DUK_STRIDX_INT_BYTECODE 93 /* '\x82Bytecode' */
+#define DUK_HEAP_STRING_INT_BYTECODE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_BYTECODE)
+#define DUK_HTHREAD_STRING_INT_BYTECODE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_BYTECODE)
+#define DUK_STRIDX_INT_FORMALS 94 /* '\x82Formals' */
+#define DUK_HEAP_STRING_INT_FORMALS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FORMALS)
+#define DUK_HTHREAD_STRING_INT_FORMALS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FORMALS)
+#define DUK_STRIDX_INT_VARMAP 95 /* '\x82Varmap' */
+#define DUK_HEAP_STRING_INT_VARMAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARMAP)
+#define DUK_HTHREAD_STRING_INT_VARMAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARMAP)
+#define DUK_STRIDX_INT_SOURCE 96 /* '\x82Source' */
+#define DUK_HEAP_STRING_INT_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_SOURCE)
+#define DUK_HTHREAD_STRING_INT_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_SOURCE)
+#define DUK_STRIDX_INT_PC2LINE 97 /* '\x82Pc2line' */
+#define DUK_HEAP_STRING_INT_PC2LINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_PC2LINE)
+#define DUK_HTHREAD_STRING_INT_PC2LINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_PC2LINE)
+#define DUK_STRIDX_INT_MAP 98 /* '\x82Map' */
+#define DUK_HEAP_STRING_INT_MAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_MAP)
+#define DUK_HTHREAD_STRING_INT_MAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_MAP)
+#define DUK_STRIDX_INT_VARENV 99 /* '\x82Varenv' */
+#define DUK_HEAP_STRING_INT_VARENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV)
+#define DUK_HTHREAD_STRING_INT_VARENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV)
+#define DUK_STRIDX_INT_FINALIZER 100 /* '\x82Finalizer' */
+#define DUK_HEAP_STRING_INT_FINALIZER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FINALIZER)
+#define DUK_HTHREAD_STRING_INT_FINALIZER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FINALIZER)
+#define DUK_STRIDX_INT_VALUE 101 /* '\x82Value' */
+#define DUK_HEAP_STRING_INT_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE)
+#define DUK_HTHREAD_STRING_INT_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE)
+#define DUK_STRIDX_COMPILE 102 /* 'compile' */
#define DUK_HEAP_STRING_COMPILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPILE)
#define DUK_HTHREAD_STRING_COMPILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPILE)
-#define DUK_STRIDX_INPUT 117 /* 'input' */
+#define DUK_STRIDX_INPUT 103 /* 'input' */
#define DUK_HEAP_STRING_INPUT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INPUT)
#define DUK_HTHREAD_STRING_INPUT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INPUT)
-#define DUK_STRIDX_ERR_CREATE 118 /* 'errCreate' */
+#define DUK_STRIDX_ERR_CREATE 104 /* 'errCreate' */
#define DUK_HEAP_STRING_ERR_CREATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_CREATE)
#define DUK_HTHREAD_STRING_ERR_CREATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_CREATE)
-#define DUK_STRIDX_ERR_THROW 119 /* 'errThrow' */
+#define DUK_STRIDX_ERR_THROW 105 /* 'errThrow' */
#define DUK_HEAP_STRING_ERR_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_THROW)
#define DUK_HTHREAD_STRING_ERR_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_THROW)
-#define DUK_STRIDX_MOD_SEARCH 120 /* 'modSearch' */
-#define DUK_HEAP_STRING_MOD_SEARCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MOD_SEARCH)
-#define DUK_HTHREAD_STRING_MOD_SEARCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MOD_SEARCH)
-#define DUK_STRIDX_MOD_LOADED 121 /* 'modLoaded' */
-#define DUK_HEAP_STRING_MOD_LOADED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MOD_LOADED)
-#define DUK_HTHREAD_STRING_MOD_LOADED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MOD_LOADED)
-#define DUK_STRIDX_ENV 122 /* 'env' */
+#define DUK_STRIDX_ENV 106 /* 'env' */
#define DUK_HEAP_STRING_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENV)
#define DUK_HTHREAD_STRING_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENV)
-#define DUK_STRIDX_HEX 123 /* 'hex' */
+#define DUK_STRIDX_HEX 107 /* 'hex' */
#define DUK_HEAP_STRING_HEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HEX)
#define DUK_HTHREAD_STRING_HEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HEX)
-#define DUK_STRIDX_BASE64 124 /* 'base64' */
+#define DUK_STRIDX_BASE64 108 /* 'base64' */
#define DUK_HEAP_STRING_BASE64(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BASE64)
#define DUK_HTHREAD_STRING_BASE64(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BASE64)
-#define DUK_STRIDX_JX 125 /* 'jx' */
+#define DUK_STRIDX_JX 109 /* 'jx' */
#define DUK_HEAP_STRING_JX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JX)
#define DUK_HTHREAD_STRING_JX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JX)
-#define DUK_STRIDX_JC 126 /* 'jc' */
+#define DUK_STRIDX_JC 110 /* 'jc' */
#define DUK_HEAP_STRING_JC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JC)
#define DUK_HTHREAD_STRING_JC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JC)
-#define DUK_STRIDX_RESUME 127 /* 'resume' */
-#define DUK_HEAP_STRING_RESUME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RESUME)
-#define DUK_HTHREAD_STRING_RESUME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RESUME)
-#define DUK_STRIDX_FMT 128 /* 'fmt' */
-#define DUK_HEAP_STRING_FMT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FMT)
-#define DUK_HTHREAD_STRING_FMT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FMT)
-#define DUK_STRIDX_RAW 129 /* 'raw' */
-#define DUK_HEAP_STRING_RAW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RAW)
-#define DUK_HTHREAD_STRING_RAW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RAW)
-#define DUK_STRIDX_LC_TRACE 130 /* 'trace' */
-#define DUK_HEAP_STRING_LC_TRACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_TRACE)
-#define DUK_HTHREAD_STRING_LC_TRACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_TRACE)
-#define DUK_STRIDX_LC_DEBUG 131 /* 'debug' */
-#define DUK_HEAP_STRING_LC_DEBUG(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_DEBUG)
-#define DUK_HTHREAD_STRING_LC_DEBUG(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_DEBUG)
-#define DUK_STRIDX_LC_INFO 132 /* 'info' */
-#define DUK_HEAP_STRING_LC_INFO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_INFO)
-#define DUK_HTHREAD_STRING_LC_INFO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_INFO)
-#define DUK_STRIDX_LC_WARN 133 /* 'warn' */
-#define DUK_HEAP_STRING_LC_WARN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_WARN)
-#define DUK_HTHREAD_STRING_LC_WARN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_WARN)
-#define DUK_STRIDX_LC_ERROR 134 /* 'error' */
-#define DUK_HEAP_STRING_LC_ERROR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ERROR)
-#define DUK_HTHREAD_STRING_LC_ERROR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ERROR)
-#define DUK_STRIDX_LC_FATAL 135 /* 'fatal' */
-#define DUK_HEAP_STRING_LC_FATAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FATAL)
-#define DUK_HTHREAD_STRING_LC_FATAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FATAL)
-#define DUK_STRIDX_LC_N 136 /* 'n' */
-#define DUK_HEAP_STRING_LC_N(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_N)
-#define DUK_HTHREAD_STRING_LC_N(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_N)
-#define DUK_STRIDX_LC_L 137 /* 'l' */
-#define DUK_HEAP_STRING_LC_L(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_L)
-#define DUK_HTHREAD_STRING_LC_L(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_L)
-#define DUK_STRIDX_CLOG 138 /* 'clog' */
-#define DUK_HEAP_STRING_CLOG(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLOG)
-#define DUK_HTHREAD_STRING_CLOG(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLOG)
-#define DUK_STRIDX_TO_LOG_STRING 139 /* 'toLogString' */
-#define DUK_HEAP_STRING_TO_LOG_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOG_STRING)
-#define DUK_HTHREAD_STRING_TO_LOG_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOG_STRING)
-#define DUK_STRIDX_JSON_EXT_UNDEFINED 140 /* '{"_undef":true}' */
+#define DUK_STRIDX_JSON_EXT_UNDEFINED 111 /* '{"_undef":true}' */
#define DUK_HEAP_STRING_JSON_EXT_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_UNDEFINED)
#define DUK_HTHREAD_STRING_JSON_EXT_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_UNDEFINED)
-#define DUK_STRIDX_JSON_EXT_NAN 141 /* '{"_nan":true}' */
+#define DUK_STRIDX_JSON_EXT_NAN 112 /* '{"_nan":true}' */
#define DUK_HEAP_STRING_JSON_EXT_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NAN)
#define DUK_HTHREAD_STRING_JSON_EXT_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NAN)
-#define DUK_STRIDX_JSON_EXT_POSINF 142 /* '{"_inf":true}' */
+#define DUK_STRIDX_JSON_EXT_POSINF 113 /* '{"_inf":true}' */
#define DUK_HEAP_STRING_JSON_EXT_POSINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_POSINF)
#define DUK_HTHREAD_STRING_JSON_EXT_POSINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_POSINF)
-#define DUK_STRIDX_JSON_EXT_NEGINF 143 /* '{"_ninf":true}' */
+#define DUK_STRIDX_JSON_EXT_NEGINF 114 /* '{"_ninf":true}' */
#define DUK_HEAP_STRING_JSON_EXT_NEGINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NEGINF)
#define DUK_HTHREAD_STRING_JSON_EXT_NEGINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NEGINF)
-#define DUK_STRIDX_JSON_EXT_FUNCTION1 144 /* '{"_func":true}' */
+#define DUK_STRIDX_JSON_EXT_FUNCTION1 115 /* '{"_func":true}' */
#define DUK_HEAP_STRING_JSON_EXT_FUNCTION1(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION1)
#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION1(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION1)
-#define DUK_STRIDX_JSON_EXT_FUNCTION2 145 /* '{_func:true}' */
+#define DUK_STRIDX_JSON_EXT_FUNCTION2 116 /* '{_func:true}' */
#define DUK_HEAP_STRING_JSON_EXT_FUNCTION2(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION2)
#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION2(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION2)
-#define DUK_STRIDX_BREAK 146 /* 'break' */
+#define DUK_STRIDX_BREAK 117 /* 'break' */
#define DUK_HEAP_STRING_BREAK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BREAK)
#define DUK_HTHREAD_STRING_BREAK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BREAK)
-#define DUK_STRIDX_CASE 147 /* 'case' */
+#define DUK_STRIDX_CASE 118 /* 'case' */
#define DUK_HEAP_STRING_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CASE)
#define DUK_HTHREAD_STRING_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CASE)
-#define DUK_STRIDX_CATCH 148 /* 'catch' */
+#define DUK_STRIDX_CATCH 119 /* 'catch' */
#define DUK_HEAP_STRING_CATCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CATCH)
#define DUK_HTHREAD_STRING_CATCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CATCH)
-#define DUK_STRIDX_CONTINUE 149 /* 'continue' */
+#define DUK_STRIDX_CONTINUE 120 /* 'continue' */
#define DUK_HEAP_STRING_CONTINUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONTINUE)
#define DUK_HTHREAD_STRING_CONTINUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONTINUE)
-#define DUK_STRIDX_DEBUGGER 150 /* 'debugger' */
+#define DUK_STRIDX_DEBUGGER 121 /* 'debugger' */
#define DUK_HEAP_STRING_DEBUGGER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEBUGGER)
#define DUK_HTHREAD_STRING_DEBUGGER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEBUGGER)
-#define DUK_STRIDX_DEFAULT 151 /* 'default' */
+#define DUK_STRIDX_DEFAULT 122 /* 'default' */
#define DUK_HEAP_STRING_DEFAULT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFAULT)
#define DUK_HTHREAD_STRING_DEFAULT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFAULT)
-#define DUK_STRIDX_DELETE 152 /* 'delete' */
+#define DUK_STRIDX_DELETE 123 /* 'delete' */
#define DUK_HEAP_STRING_DELETE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE)
#define DUK_HTHREAD_STRING_DELETE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE)
-#define DUK_STRIDX_DO 153 /* 'do' */
+#define DUK_STRIDX_DO 124 /* 'do' */
#define DUK_HEAP_STRING_DO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DO)
#define DUK_HTHREAD_STRING_DO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DO)
-#define DUK_STRIDX_ELSE 154 /* 'else' */
+#define DUK_STRIDX_ELSE 125 /* 'else' */
#define DUK_HEAP_STRING_ELSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ELSE)
#define DUK_HTHREAD_STRING_ELSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ELSE)
-#define DUK_STRIDX_FINALLY 155 /* 'finally' */
+#define DUK_STRIDX_FINALLY 126 /* 'finally' */
#define DUK_HEAP_STRING_FINALLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FINALLY)
#define DUK_HTHREAD_STRING_FINALLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FINALLY)
-#define DUK_STRIDX_FOR 156 /* 'for' */
+#define DUK_STRIDX_FOR 127 /* 'for' */
#define DUK_HEAP_STRING_FOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FOR)
#define DUK_HTHREAD_STRING_FOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FOR)
-#define DUK_STRIDX_LC_FUNCTION 157 /* 'function' */
+#define DUK_STRIDX_LC_FUNCTION 128 /* 'function' */
#define DUK_HEAP_STRING_LC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FUNCTION)
#define DUK_HTHREAD_STRING_LC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FUNCTION)
-#define DUK_STRIDX_IF 158 /* 'if' */
+#define DUK_STRIDX_IF 129 /* 'if' */
#define DUK_HEAP_STRING_IF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IF)
#define DUK_HTHREAD_STRING_IF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IF)
-#define DUK_STRIDX_IN 159 /* 'in' */
+#define DUK_STRIDX_IN 130 /* 'in' */
#define DUK_HEAP_STRING_IN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IN)
#define DUK_HTHREAD_STRING_IN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IN)
-#define DUK_STRIDX_INSTANCEOF 160 /* 'instanceof' */
+#define DUK_STRIDX_INSTANCEOF 131 /* 'instanceof' */
#define DUK_HEAP_STRING_INSTANCEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INSTANCEOF)
#define DUK_HTHREAD_STRING_INSTANCEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INSTANCEOF)
-#define DUK_STRIDX_NEW 161 /* 'new' */
+#define DUK_STRIDX_NEW 132 /* 'new' */
#define DUK_HEAP_STRING_NEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEW)
#define DUK_HTHREAD_STRING_NEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEW)
-#define DUK_STRIDX_RETURN 162 /* 'return' */
+#define DUK_STRIDX_RETURN 133 /* 'return' */
#define DUK_HEAP_STRING_RETURN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RETURN)
#define DUK_HTHREAD_STRING_RETURN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RETURN)
-#define DUK_STRIDX_SWITCH 163 /* 'switch' */
+#define DUK_STRIDX_SWITCH 134 /* 'switch' */
#define DUK_HEAP_STRING_SWITCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SWITCH)
#define DUK_HTHREAD_STRING_SWITCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SWITCH)
-#define DUK_STRIDX_THIS 164 /* 'this' */
+#define DUK_STRIDX_THIS 135 /* 'this' */
#define DUK_HEAP_STRING_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THIS)
#define DUK_HTHREAD_STRING_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THIS)
-#define DUK_STRIDX_THROW 165 /* 'throw' */
+#define DUK_STRIDX_THROW 136 /* 'throw' */
#define DUK_HEAP_STRING_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THROW)
#define DUK_HTHREAD_STRING_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THROW)
-#define DUK_STRIDX_TRY 166 /* 'try' */
+#define DUK_STRIDX_TRY 137 /* 'try' */
#define DUK_HEAP_STRING_TRY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRY)
#define DUK_HTHREAD_STRING_TRY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRY)
-#define DUK_STRIDX_TYPEOF 167 /* 'typeof' */
+#define DUK_STRIDX_TYPEOF 138 /* 'typeof' */
#define DUK_HEAP_STRING_TYPEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPEOF)
#define DUK_HTHREAD_STRING_TYPEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF)
-#define DUK_STRIDX_VAR 168 /* 'var' */
+#define DUK_STRIDX_VAR 139 /* 'var' */
#define DUK_HEAP_STRING_VAR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR)
#define DUK_HTHREAD_STRING_VAR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR)
-#define DUK_STRIDX_CONST 169 /* 'const' */
+#define DUK_STRIDX_CONST 140 /* 'const' */
#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST)
#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST)
-#define DUK_STRIDX_VOID 170 /* 'void' */
+#define DUK_STRIDX_VOID 141 /* 'void' */
#define DUK_HEAP_STRING_VOID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID)
#define DUK_HTHREAD_STRING_VOID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID)
-#define DUK_STRIDX_WHILE 171 /* 'while' */
+#define DUK_STRIDX_WHILE 142 /* 'while' */
#define DUK_HEAP_STRING_WHILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE)
#define DUK_HTHREAD_STRING_WHILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WHILE)
-#define DUK_STRIDX_WITH 172 /* 'with' */
+#define DUK_STRIDX_WITH 143 /* 'with' */
#define DUK_HEAP_STRING_WITH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WITH)
#define DUK_HTHREAD_STRING_WITH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH)
-#define DUK_STRIDX_CLASS 173 /* 'class' */
+#define DUK_STRIDX_CLASS 144 /* 'class' */
#define DUK_HEAP_STRING_CLASS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS)
#define DUK_HTHREAD_STRING_CLASS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS)
-#define DUK_STRIDX_ENUM 174 /* 'enum' */
+#define DUK_STRIDX_ENUM 145 /* 'enum' */
#define DUK_HEAP_STRING_ENUM(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM)
#define DUK_HTHREAD_STRING_ENUM(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM)
-#define DUK_STRIDX_EXPORT 175 /* 'export' */
+#define DUK_STRIDX_EXPORT 146 /* 'export' */
#define DUK_HEAP_STRING_EXPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT)
#define DUK_HTHREAD_STRING_EXPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORT)
-#define DUK_STRIDX_EXTENDS 176 /* 'extends' */
+#define DUK_STRIDX_EXTENDS 147 /* 'extends' */
#define DUK_HEAP_STRING_EXTENDS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXTENDS)
#define DUK_HTHREAD_STRING_EXTENDS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXTENDS)
-#define DUK_STRIDX_IMPORT 177 /* 'import' */
+#define DUK_STRIDX_IMPORT 148 /* 'import' */
#define DUK_HEAP_STRING_IMPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPORT)
#define DUK_HTHREAD_STRING_IMPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPORT)
-#define DUK_STRIDX_SUPER 178 /* 'super' */
+#define DUK_STRIDX_SUPER 149 /* 'super' */
#define DUK_HEAP_STRING_SUPER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUPER)
#define DUK_HTHREAD_STRING_SUPER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUPER)
-#define DUK_STRIDX_LC_NULL 179 /* 'null' */
+#define DUK_STRIDX_LC_NULL 150 /* 'null' */
#define DUK_HEAP_STRING_LC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NULL)
#define DUK_HTHREAD_STRING_LC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NULL)
-#define DUK_STRIDX_TRUE 180 /* 'true' */
+#define DUK_STRIDX_TRUE 151 /* 'true' */
#define DUK_HEAP_STRING_TRUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRUE)
#define DUK_HTHREAD_STRING_TRUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRUE)
-#define DUK_STRIDX_FALSE 181 /* 'false' */
+#define DUK_STRIDX_FALSE 152 /* 'false' */
#define DUK_HEAP_STRING_FALSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FALSE)
#define DUK_HTHREAD_STRING_FALSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FALSE)
-#define DUK_STRIDX_IMPLEMENTS 182 /* 'implements' */
+#define DUK_STRIDX_IMPLEMENTS 153 /* 'implements' */
#define DUK_HEAP_STRING_IMPLEMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPLEMENTS)
#define DUK_HTHREAD_STRING_IMPLEMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPLEMENTS)
-#define DUK_STRIDX_INTERFACE 183 /* 'interface' */
+#define DUK_STRIDX_INTERFACE 154 /* 'interface' */
#define DUK_HEAP_STRING_INTERFACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INTERFACE)
#define DUK_HTHREAD_STRING_INTERFACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INTERFACE)
-#define DUK_STRIDX_LET 184 /* 'let' */
+#define DUK_STRIDX_LET 155 /* 'let' */
#define DUK_HEAP_STRING_LET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LET)
#define DUK_HTHREAD_STRING_LET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LET)
-#define DUK_STRIDX_PACKAGE 185 /* 'package' */
+#define DUK_STRIDX_PACKAGE 156 /* 'package' */
#define DUK_HEAP_STRING_PACKAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PACKAGE)
#define DUK_HTHREAD_STRING_PACKAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PACKAGE)
-#define DUK_STRIDX_PRIVATE 186 /* 'private' */
+#define DUK_STRIDX_PRIVATE 157 /* 'private' */
#define DUK_HEAP_STRING_PRIVATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PRIVATE)
#define DUK_HTHREAD_STRING_PRIVATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PRIVATE)
-#define DUK_STRIDX_PROTECTED 187 /* 'protected' */
+#define DUK_STRIDX_PROTECTED 158 /* 'protected' */
#define DUK_HEAP_STRING_PROTECTED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTECTED)
#define DUK_HTHREAD_STRING_PROTECTED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTECTED)
-#define DUK_STRIDX_PUBLIC 188 /* 'public' */
+#define DUK_STRIDX_PUBLIC 159 /* 'public' */
#define DUK_HEAP_STRING_PUBLIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PUBLIC)
#define DUK_HTHREAD_STRING_PUBLIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PUBLIC)
-#define DUK_STRIDX_STATIC 189 /* 'static' */
+#define DUK_STRIDX_STATIC 160 /* 'static' */
#define DUK_HEAP_STRING_STATIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STATIC)
#define DUK_HTHREAD_STRING_STATIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STATIC)
-#define DUK_STRIDX_YIELD 190 /* 'yield' */
+#define DUK_STRIDX_YIELD 161 /* 'yield' */
#define DUK_HEAP_STRING_YIELD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_YIELD)
#define DUK_HTHREAD_STRING_YIELD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_YIELD)
-#define DUK_HEAP_NUM_STRINGS 191
-#define DUK_STRIDX_START_RESERVED 146
-#define DUK_STRIDX_START_STRICT_RESERVED 182
-#define DUK_STRIDX_END_RESERVED 191 /* exclusive endpoint */
+#define DUK_HEAP_NUM_STRINGS 162
+#define DUK_STRIDX_START_RESERVED 117
+#define DUK_STRIDX_START_STRICT_RESERVED 153
+#define DUK_STRIDX_END_RESERVED 162 /* exclusive endpoint */
/* To convert a heap stridx to a token number, subtract
* DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED.
*/
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[1049];
+DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[892];
#endif /* !DUK_SINGLE_FILE */
#define DUK_STRDATA_MAX_STRLEN 17
-#define DUK_STRDATA_DATA_LENGTH 1049
+#define DUK_STRDATA_DATA_LENGTH 892
#endif /* DUK_USE_ROM_STRINGS */
#if defined(DUK_USE_ROM_OBJECTS)
-#error ROM support not enabled, rerun make_dist.py with --rom-support
-#else
+#error RAM support not enabled, rerun configure.py with --ram-support
+#else /* DUK_USE_ROM_OBJECTS */
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_context *ctx);
@@ -1486,15 +1982,15 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_constructor(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_constructor(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_constructor(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_eval(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx);
@@ -1506,12 +2002,11 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_escape(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_require(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_assign(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx);
@@ -1519,16 +2014,21 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_con
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_has_own_property(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_defineaccessor(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_lookupaccessor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_native_function_length(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_native_function_name(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx);
@@ -1545,6 +2045,7 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *c
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor_from_code_point(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_at(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx);
@@ -1559,6 +2060,9 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_trim(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_repeat(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_includes(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx);
@@ -1579,7 +2083,9 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_to_string(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_tostring(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_flags(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx);
@@ -1589,9 +2095,13 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_clz32(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_hypot(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_imul(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_max(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_min(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_random(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_sign(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_parse(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx);
@@ -1604,16 +2114,23 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_yield(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_resume(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_current(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_prototype_fmt(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_prototype_raw(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_prototype_log_shared(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_apply(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_construct(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_delete_property(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_get(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_has(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_set(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_buffer_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_set(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_uint8array_allocplain(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_uint8array_plainof(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx);
@@ -1624,122 +2141,113 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_prototype_encode(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_performance_now(duk_context *ctx);
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149];
+DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[176];
#endif /* !DUK_SINGLE_FILE */
-#if defined(DUK_USE_BUILTIN_INITJS)
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[204];
-#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTIN_INITJS_DATA_LENGTH 204
-#endif /* DUK_USE_BUILTIN_INITJS */
#define DUK_BIDX_GLOBAL 0
#define DUK_BIDX_GLOBAL_ENV 1
#define DUK_BIDX_OBJECT_CONSTRUCTOR 2
#define DUK_BIDX_OBJECT_PROTOTYPE 3
#define DUK_BIDX_FUNCTION_CONSTRUCTOR 4
#define DUK_BIDX_FUNCTION_PROTOTYPE 5
-#define DUK_BIDX_ARRAY_CONSTRUCTOR 6
-#define DUK_BIDX_ARRAY_PROTOTYPE 7
-#define DUK_BIDX_STRING_CONSTRUCTOR 8
-#define DUK_BIDX_STRING_PROTOTYPE 9
-#define DUK_BIDX_BOOLEAN_CONSTRUCTOR 10
-#define DUK_BIDX_BOOLEAN_PROTOTYPE 11
-#define DUK_BIDX_NUMBER_CONSTRUCTOR 12
-#define DUK_BIDX_NUMBER_PROTOTYPE 13
-#define DUK_BIDX_DATE_CONSTRUCTOR 14
-#define DUK_BIDX_DATE_PROTOTYPE 15
-#define DUK_BIDX_REGEXP_CONSTRUCTOR 16
-#define DUK_BIDX_REGEXP_PROTOTYPE 17
-#define DUK_BIDX_ERROR_CONSTRUCTOR 18
-#define DUK_BIDX_ERROR_PROTOTYPE 19
-#define DUK_BIDX_EVAL_ERROR_CONSTRUCTOR 20
-#define DUK_BIDX_EVAL_ERROR_PROTOTYPE 21
-#define DUK_BIDX_RANGE_ERROR_CONSTRUCTOR 22
-#define DUK_BIDX_RANGE_ERROR_PROTOTYPE 23
-#define DUK_BIDX_REFERENCE_ERROR_CONSTRUCTOR 24
-#define DUK_BIDX_REFERENCE_ERROR_PROTOTYPE 25
-#define DUK_BIDX_SYNTAX_ERROR_CONSTRUCTOR 26
-#define DUK_BIDX_SYNTAX_ERROR_PROTOTYPE 27
-#define DUK_BIDX_TYPE_ERROR_CONSTRUCTOR 28
-#define DUK_BIDX_TYPE_ERROR_PROTOTYPE 29
-#define DUK_BIDX_URI_ERROR_CONSTRUCTOR 30
-#define DUK_BIDX_URI_ERROR_PROTOTYPE 31
-#define DUK_BIDX_MATH 32
-#define DUK_BIDX_JSON 33
-#define DUK_BIDX_TYPE_ERROR_THROWER 34
-#define DUK_BIDX_PROXY_CONSTRUCTOR 35
-#define DUK_BIDX_DUKTAPE 36
-#define DUK_BIDX_THREAD_CONSTRUCTOR 37
-#define DUK_BIDX_THREAD_PROTOTYPE 38
-#define DUK_BIDX_BUFFER_CONSTRUCTOR 39
-#define DUK_BIDX_BUFFER_PROTOTYPE 40
-#define DUK_BIDX_POINTER_CONSTRUCTOR 41
-#define DUK_BIDX_POINTER_PROTOTYPE 42
-#define DUK_BIDX_LOGGER_CONSTRUCTOR 43
-#define DUK_BIDX_LOGGER_PROTOTYPE 44
-#define DUK_BIDX_DOUBLE_ERROR 45
-#define DUK_BIDX_ARRAYBUFFER_CONSTRUCTOR 46
-#define DUK_BIDX_ARRAYBUFFER_PROTOTYPE 47
-#define DUK_BIDX_DATAVIEW_CONSTRUCTOR 48
-#define DUK_BIDX_DATAVIEW_PROTOTYPE 49
-#define DUK_BIDX_TYPEDARRAY_PROTOTYPE 50
-#define DUK_BIDX_INT8ARRAY_CONSTRUCTOR 51
-#define DUK_BIDX_INT8ARRAY_PROTOTYPE 52
-#define DUK_BIDX_UINT8ARRAY_CONSTRUCTOR 53
-#define DUK_BIDX_UINT8ARRAY_PROTOTYPE 54
-#define DUK_BIDX_UINT8CLAMPEDARRAY_CONSTRUCTOR 55
-#define DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE 56
-#define DUK_BIDX_INT16ARRAY_CONSTRUCTOR 57
-#define DUK_BIDX_INT16ARRAY_PROTOTYPE 58
-#define DUK_BIDX_UINT16ARRAY_CONSTRUCTOR 59
-#define DUK_BIDX_UINT16ARRAY_PROTOTYPE 60
-#define DUK_BIDX_INT32ARRAY_CONSTRUCTOR 61
-#define DUK_BIDX_INT32ARRAY_PROTOTYPE 62
-#define DUK_BIDX_UINT32ARRAY_CONSTRUCTOR 63
-#define DUK_BIDX_UINT32ARRAY_PROTOTYPE 64
-#define DUK_BIDX_FLOAT32ARRAY_CONSTRUCTOR 65
-#define DUK_BIDX_FLOAT32ARRAY_PROTOTYPE 66
-#define DUK_BIDX_FLOAT64ARRAY_CONSTRUCTOR 67
-#define DUK_BIDX_FLOAT64ARRAY_PROTOTYPE 68
-#define DUK_BIDX_NODEJS_BUFFER_CONSTRUCTOR 69
-#define DUK_BIDX_NODEJS_BUFFER_PROTOTYPE 70
-#define DUK_NUM_BUILTINS 71
-#define DUK_NUM_BIDX_BUILTINS 71
-#define DUK_NUM_ALL_BUILTINS 71
+#define DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE 6
+#define DUK_BIDX_ARRAY_CONSTRUCTOR 7
+#define DUK_BIDX_ARRAY_PROTOTYPE 8
+#define DUK_BIDX_STRING_CONSTRUCTOR 9
+#define DUK_BIDX_STRING_PROTOTYPE 10
+#define DUK_BIDX_BOOLEAN_CONSTRUCTOR 11
+#define DUK_BIDX_BOOLEAN_PROTOTYPE 12
+#define DUK_BIDX_NUMBER_CONSTRUCTOR 13
+#define DUK_BIDX_NUMBER_PROTOTYPE 14
+#define DUK_BIDX_DATE_CONSTRUCTOR 15
+#define DUK_BIDX_DATE_PROTOTYPE 16
+#define DUK_BIDX_REGEXP_CONSTRUCTOR 17
+#define DUK_BIDX_REGEXP_PROTOTYPE 18
+#define DUK_BIDX_ERROR_CONSTRUCTOR 19
+#define DUK_BIDX_ERROR_PROTOTYPE 20
+#define DUK_BIDX_EVAL_ERROR_CONSTRUCTOR 21
+#define DUK_BIDX_EVAL_ERROR_PROTOTYPE 22
+#define DUK_BIDX_RANGE_ERROR_CONSTRUCTOR 23
+#define DUK_BIDX_RANGE_ERROR_PROTOTYPE 24
+#define DUK_BIDX_REFERENCE_ERROR_CONSTRUCTOR 25
+#define DUK_BIDX_REFERENCE_ERROR_PROTOTYPE 26
+#define DUK_BIDX_SYNTAX_ERROR_CONSTRUCTOR 27
+#define DUK_BIDX_SYNTAX_ERROR_PROTOTYPE 28
+#define DUK_BIDX_TYPE_ERROR_CONSTRUCTOR 29
+#define DUK_BIDX_TYPE_ERROR_PROTOTYPE 30
+#define DUK_BIDX_URI_ERROR_CONSTRUCTOR 31
+#define DUK_BIDX_URI_ERROR_PROTOTYPE 32
+#define DUK_BIDX_TYPE_ERROR_THROWER 33
+#define DUK_BIDX_DUKTAPE 34
+#define DUK_BIDX_THREAD_PROTOTYPE 35
+#define DUK_BIDX_POINTER_PROTOTYPE 36
+#define DUK_BIDX_DOUBLE_ERROR 37
+#define DUK_BIDX_SYMBOL_PROTOTYPE 38
+#define DUK_BIDX_ARRAYBUFFER_PROTOTYPE 39
+#define DUK_BIDX_DATAVIEW_PROTOTYPE 40
+#define DUK_BIDX_INT8ARRAY_PROTOTYPE 41
+#define DUK_BIDX_UINT8ARRAY_PROTOTYPE 42
+#define DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE 43
+#define DUK_BIDX_INT16ARRAY_PROTOTYPE 44
+#define DUK_BIDX_UINT16ARRAY_PROTOTYPE 45
+#define DUK_BIDX_INT32ARRAY_PROTOTYPE 46
+#define DUK_BIDX_UINT32ARRAY_PROTOTYPE 47
+#define DUK_BIDX_FLOAT32ARRAY_PROTOTYPE 48
+#define DUK_BIDX_FLOAT64ARRAY_PROTOTYPE 49
+#define DUK_BIDX_NODEJS_BUFFER_PROTOTYPE 50
+#define DUK_NUM_BUILTINS 51
+#define DUK_NUM_BIDX_BUILTINS 51
+#define DUK_NUM_ALL_BUILTINS 76
#if defined(DUK_USE_DOUBLE_LE)
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3833];
+DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3972];
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 3833
+#define DUK_BUILTINS_DATA_LENGTH 3972
#elif defined(DUK_USE_DOUBLE_BE)
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3833];
+DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3972];
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 3833
+#define DUK_BUILTINS_DATA_LENGTH 3972
#elif defined(DUK_USE_DOUBLE_ME)
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3833];
+DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3972];
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 3833
+#define DUK_BUILTINS_DATA_LENGTH 3972
#else
#error invalid endianness defines
#endif
#endif /* DUK_USE_ROM_OBJECTS */
#endif /* DUK_BUILTINS_H_INCLUDED */
-#line 52 "duk_internal.h"
+#line 51 "duk_internal.h"
+/* #include duk_util.h */
#line 1 "duk_util.h"
/*
* Utilities
*/
-#ifndef DUK_UTIL_H_INCLUDED
+#if !defined(DUK_UTIL_H_INCLUDED)
#define DUK_UTIL_H_INCLUDED
-#define DUK_UTIL_MIN_HASH_PRIME 17 /* must match genhashsizes.py */
+#if defined(DUK_USE_GET_RANDOM_DOUBLE)
+#define DUK_UTIL_GET_RANDOM_DOUBLE(thr) DUK_USE_GET_RANDOM_DOUBLE((thr)->heap_udata)
+#else
+#define DUK_UTIL_GET_RANDOM_DOUBLE(thr) duk_util_tinyrandom_get_double(thr)
+#endif
-#define DUK_UTIL_GET_HASH_PROBE_STEP(hash) (duk_util_probe_steps[(hash) & 0x1f])
+/*
+ * Some useful constants
+ */
+
+#define DUK_DOUBLE_2TO32 4294967296.0
+#define DUK_DOUBLE_2TO31 2147483648.0
+#define DUK_DOUBLE_LOG2E 1.4426950408889634
+#define DUK_DOUBLE_LOG10E 0.4342944819032518
/*
* Endian conversion
@@ -1771,6 +2279,8 @@ struct duk_bitdecoder_ctx {
duk_small_int_t currbits;
};
+#define DUK_BD_BITPACKED_STRING_MAXLEN 256
+
/*
* Bitstream encoder
*/
@@ -1824,10 +2334,10 @@ struct duk_bitencoder_ctx {
/*
* Buffer writer (dynamic buffer only)
*
- * Helper for writing to a dynamic buffer with a concept of a "spare" area
+ * Helper for writing to a dynamic buffer with a concept of a "slack" area
* to reduce resizes. You can ensure there is enough space beforehand and
* then write for a while without further checks, relying on a stable data
- * pointer. Spare handling is automatic so call sites only indicate how
+ * pointer. Slack handling is automatic so call sites only indicate how
* much data they need right now.
*
* There are several ways to write using bufwriter. The best approach
@@ -1853,8 +2363,13 @@ struct duk_bufwriter_ctx {
duk_hbuffer_dynamic *buf;
};
-#define DUK_BW_SPARE_ADD 64
-#define DUK_BW_SPARE_SHIFT 4 /* 2^4 -> 1/16 = 6.25% spare */
+#if defined(DUK_USE_PREFER_SIZE)
+#define DUK_BW_SLACK_ADD 64
+#define DUK_BW_SLACK_SHIFT 4 /* 2^4 -> 1/16 = 6.25% slack */
+#else
+#define DUK_BW_SLACK_ADD 64
+#define DUK_BW_SLACK_SHIFT 2 /* 2^2 -> 1/4 = 25% slack */
+#endif
/* Initialization and finalization (compaction), converting to other types. */
@@ -1869,7 +2384,7 @@ struct duk_bufwriter_ctx {
duk_bw_compact((thr), (bw_ctx)); \
} while (0)
#define DUK_BW_PUSH_AS_STRING(thr,bw_ctx) do { \
- duk_push_lstring((duk_context *) (thr), \
+ duk_push_lstring((thr), \
(const char *) (bw_ctx)->p_base, \
(duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \
} while (0)
@@ -1952,7 +2467,7 @@ struct duk_bufwriter_ctx {
duk_bw_compact((thr), (bw_ctx)); \
} while (0)
-/* Fast write calls which assume you control the spare beforehand.
+/* Fast write calls which assume you control the slack beforehand.
* Multibyte write variants exist and use a temporary write pointer
* because byte writes alias with anything: with a stored pointer
* explicit pointer load/stores get generated (e.g. gcc -Os).
@@ -2015,7 +2530,7 @@ struct duk_bufwriter_ctx {
#define DUK_BW_WRITE_RAW_XUTF8(thr,bw_ctx,cp) do { \
duk_ucodepoint_t duk__cp; \
duk_small_int_t duk__enc_len; \
- duk__cp = (cp); \
+ duk__cp = (duk_ucodepoint_t) (cp); \
DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_xutf8_length(duk__cp)); \
duk__enc_len = duk_unicode_encode_xutf8(duk__cp, (bw_ctx)->p); \
(bw_ctx)->p += duk__enc_len; \
@@ -2209,7 +2724,7 @@ DUK_INTERNAL_DECL const duk_int8_t duk_base64_dectab[256];
#endif /* !DUK_SINGLE_FILE */
/* Note: assumes that duk_util_probe_steps size is 32 */
-#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE)
+#if defined(DUK_USE_HOBJECT_HASH_PART)
#if !defined(DUK_SINGLE_FILE)
DUK_INTERNAL_DECL duk_uint8_t duk_util_probe_steps[32];
#endif /* !DUK_SINGLE_FILE */
@@ -2219,19 +2734,20 @@ DUK_INTERNAL_DECL duk_uint8_t duk_util_probe_steps[32];
DUK_INTERNAL_DECL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed);
#endif
-#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE)
-DUK_INTERNAL_DECL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size);
-#endif
-
-DUK_INTERNAL_DECL duk_int32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits);
-DUK_INTERNAL_DECL duk_small_int_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx);
-DUK_INTERNAL_DECL duk_int32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value);
+DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits);
+DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx);
+DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value);
+DUK_INTERNAL_DECL duk_int32_t duk_bd_decode_flagged_signed(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value);
+DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx);
+DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_bitpacked_string(duk_bitdecoder_ctx *bd, duk_uint8_t *out);
DUK_INTERNAL_DECL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits);
DUK_INTERNAL_DECL void duk_be_finish(duk_bitencoder_ctx *ctx);
-DUK_INTERNAL_DECL duk_uint32_t duk_util_tinyrandom_get_bits(duk_hthread *thr, duk_small_int_t n);
+#if !defined(DUK_USE_GET_RANDOM_DOUBLE)
DUK_INTERNAL_DECL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_util_tinyrandom_prepare_seed(duk_hthread *thr);
+#endif
DUK_INTERNAL_DECL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf);
DUK_INTERNAL_DECL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size);
@@ -2256,475 +2772,685 @@ DUK_INTERNAL_DECL void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint32_t val);
DUK_INTERNAL_DECL void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val);
#if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger. */
-DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len);
+DUK_INTERNAL_DECL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len);
#endif
+DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival);
+DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival);
+DUK_INTERNAL_DECL duk_bool_t duk_double_is_anyinf(duk_double_t x);
+DUK_INTERNAL_DECL duk_bool_t duk_double_is_posinf(duk_double_t x);
+DUK_INTERNAL_DECL duk_bool_t duk_double_is_neginf(duk_double_t x);
+DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan(duk_double_t x);
+DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_or_zero(duk_double_t x);
+DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_or_inf(duk_double_t x);
+DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_zero_inf(duk_double_t x);
+DUK_INTERNAL_DECL duk_small_uint_t duk_double_signbit(duk_double_t x);
+DUK_INTERNAL_DECL duk_double_t duk_double_trunc_towards_zero(duk_double_t x);
+DUK_INTERNAL_DECL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y);
+DUK_INTERNAL_DECL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y);
+DUK_INTERNAL_DECL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y);
+
#endif /* DUK_UTIL_H_INCLUDED */
+/* #include duk_strings.h */
#line 1 "duk_strings.h"
/*
- * Shared error messages: declarations and macros
+ * Shared string macros.
*
- * Error messages are accessed through macros with fine-grained, explicit
- * error message distinctions. Concrete error messages are selected by the
- * macros and multiple macros can map to the same concrete string to save
- * on code footprint. This allows flexible footprint/verbosity tuning with
- * minimal code impact. There are a few limitations to this approach:
- * (1) switching between plain messages and format strings doesn't work
- * conveniently, and (2) conditional strings are a bit awkward to handle.
+ * Using shared macros helps minimize strings data size because it's easy
+ * to check if an existing string could be used. String constants don't
+ * need to be all defined here; defining a string here makes sense if there's
+ * a high chance the string could be reused. Also, using macros allows
+ * a call site express the exact string needed, but the macro may map to an
+ * approximate string to reduce unique string count. Macros can also be
+ * more easily tuned for low memory targets than #if defined()s throughout
+ * the code base.
*
* Because format strings behave differently in the call site (they need to
- * be followed by format arguments), they have a special prefix (DUK_STR_FMT_
- * and duk_str_fmt_).
+ * be followed by format arguments), they use a special prefix DUK_STR_FMT_.
*
* On some compilers using explicit shared strings is preferable; on others
* it may be better to use straight literals because the compiler will combine
* them anyway, and such strings won't end up unnecessarily in a symbol table.
*/
-#ifndef DUK_ERRMSG_H_INCLUDED
+#if !defined(DUK_ERRMSG_H_INCLUDED)
#define DUK_ERRMSG_H_INCLUDED
-#define DUK_STR_INTERNAL_ERROR duk_str_internal_error
-#define DUK_STR_INVALID_COUNT duk_str_invalid_count
-#define DUK_STR_INVALID_CALL_ARGS duk_str_invalid_call_args
-#define DUK_STR_NOT_CONSTRUCTABLE duk_str_not_constructable
-#define DUK_STR_NOT_CALLABLE duk_str_not_callable
-#define DUK_STR_NOT_EXTENSIBLE duk_str_not_extensible
-#define DUK_STR_NOT_WRITABLE duk_str_not_writable
-#define DUK_STR_NOT_CONFIGURABLE duk_str_not_configurable
+/* Mostly API and built-in method related */
+#define DUK_STR_INTERNAL_ERROR "internal error"
+#define DUK_STR_UNSUPPORTED "unsupported"
+#define DUK_STR_INVALID_COUNT "invalid count"
+#define DUK_STR_INVALID_ARGS "invalid args"
+#define DUK_STR_INVALID_STATE "invalid state"
+#define DUK_STR_INVALID_INPUT "invalid input"
+#define DUK_STR_INVALID_LENGTH "invalid length"
+#define DUK_STR_NOT_CONSTRUCTABLE "not constructable"
+#define DUK_STR_CONSTRUCT_ONLY "constructor requires 'new'"
+#define DUK_STR_NOT_CALLABLE "not callable"
+#define DUK_STR_NOT_EXTENSIBLE "not extensible"
+#define DUK_STR_NOT_WRITABLE "not writable"
+#define DUK_STR_NOT_CONFIGURABLE "not configurable"
+#define DUK_STR_INVALID_CONTEXT "invalid context"
+#define DUK_STR_INVALID_INDEX "invalid args"
+#define DUK_STR_PUSH_BEYOND_ALLOC_STACK "cannot push beyond allocated stack"
+#define DUK_STR_NOT_UNDEFINED "unexpected type"
+#define DUK_STR_NOT_NULL "unexpected type"
+#define DUK_STR_NOT_BOOLEAN "unexpected type"
+#define DUK_STR_NOT_NUMBER "unexpected type"
+#define DUK_STR_NOT_STRING "unexpected type"
+#define DUK_STR_NOT_OBJECT "unexpected type"
+#define DUK_STR_NOT_POINTER "unexpected type"
+#define DUK_STR_NOT_BUFFER "not buffer" /* still in use with verbose messages */
+#define DUK_STR_UNEXPECTED_TYPE "unexpected type"
+#define DUK_STR_NOT_THREAD "unexpected type"
+#define DUK_STR_NOT_COMPFUNC "unexpected type"
+#define DUK_STR_NOT_NATFUNC "unexpected type"
+#define DUK_STR_NOT_C_FUNCTION "unexpected type"
+#define DUK_STR_NOT_FUNCTION "unexpected type"
+#define DUK_STR_NOT_REGEXP "unexpected type"
+#define DUK_STR_TOPRIMITIVE_FAILED "coercion to primitive failed"
+#define DUK_STR_NUMBER_OUTSIDE_RANGE "number outside range"
+#define DUK_STR_NOT_OBJECT_COERCIBLE "not object coercible"
+#define DUK_STR_CANNOT_NUMBER_COERCE_SYMBOL "cannot number coerce Symbol"
+#define DUK_STR_CANNOT_STRING_COERCE_SYMBOL "cannot string coerce Symbol"
+#define DUK_STR_STRING_TOO_LONG "string too long"
+#define DUK_STR_BUFFER_TOO_LONG "buffer too long"
+#define DUK_STR_ALLOC_FAILED "alloc failed"
+#define DUK_STR_WRONG_BUFFER_TYPE "wrong buffer type"
+#define DUK_STR_BASE64_ENCODE_FAILED "base64 encode failed"
+#define DUK_STR_SOURCE_DECODE_FAILED "source decode failed"
+#define DUK_STR_UTF8_DECODE_FAILED "utf-8 decode failed"
+#define DUK_STR_BASE64_DECODE_FAILED "base64 decode failed"
+#define DUK_STR_HEX_DECODE_FAILED "hex decode failed"
+#define DUK_STR_INVALID_BYTECODE "invalid bytecode"
+#define DUK_STR_NO_SOURCECODE "no sourcecode"
+#define DUK_STR_RESULT_TOO_LONG "result too long"
+#define DUK_STR_INVALID_CFUNC_RC "invalid C function rc"
+#define DUK_STR_INVALID_INSTANCEOF_RVAL "invalid instanceof rval"
+#define DUK_STR_INVALID_INSTANCEOF_RVAL_NOPROTO "instanceof rval has no .prototype"
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_internal_error;
-DUK_INTERNAL_DECL const char *duk_str_invalid_count;
-DUK_INTERNAL_DECL const char *duk_str_invalid_call_args;
-DUK_INTERNAL_DECL const char *duk_str_not_constructable;
-DUK_INTERNAL_DECL const char *duk_str_not_callable;
-DUK_INTERNAL_DECL const char *duk_str_not_extensible;
-DUK_INTERNAL_DECL const char *duk_str_not_writable;
-DUK_INTERNAL_DECL const char *duk_str_not_configurable;
-#endif /* !DUK_SINGLE_FILE */
+/* JSON */
+#define DUK_STR_FMT_PTR "%p"
+#define DUK_STR_FMT_INVALID_JSON "invalid json (at offset %ld)"
+#define DUK_STR_JSONDEC_RECLIMIT "json decode recursion limit"
+#define DUK_STR_JSONENC_RECLIMIT "json encode recursion limit"
+#define DUK_STR_CYCLIC_INPUT "cyclic input"
-#define DUK_STR_INVALID_CONTEXT duk_str_invalid_context
-#define DUK_STR_INVALID_INDEX duk_str_invalid_call_args
-#define DUK_STR_PUSH_BEYOND_ALLOC_STACK duk_str_push_beyond_alloc_stack
-#define DUK_STR_NOT_UNDEFINED duk_str_unexpected_type
-#define DUK_STR_NOT_NULL duk_str_unexpected_type
-#define DUK_STR_NOT_BOOLEAN duk_str_unexpected_type
-#define DUK_STR_NOT_NUMBER duk_str_unexpected_type
-#define DUK_STR_NOT_STRING duk_str_unexpected_type
-#define DUK_STR_NOT_OBJECT duk_str_unexpected_type
-#define DUK_STR_NOT_POINTER duk_str_unexpected_type
-#define DUK_STR_NOT_BUFFER duk_str_not_buffer /* still in use with verbose messages */
-#define DUK_STR_UNEXPECTED_TYPE duk_str_unexpected_type
-#define DUK_STR_NOT_THREAD duk_str_unexpected_type
-#define DUK_STR_NOT_COMPILEDFUNCTION duk_str_unexpected_type
-#define DUK_STR_NOT_NATIVEFUNCTION duk_str_unexpected_type
-#define DUK_STR_NOT_C_FUNCTION duk_str_unexpected_type
-#define DUK_STR_NOT_FUNCTION duk_str_unexpected_type
-#define DUK_STR_NOT_REGEXP duk_str_unexpected_type
-#define DUK_STR_DEFAULTVALUE_COERCE_FAILED duk_str_defaultvalue_coerce_failed
-#define DUK_STR_NUMBER_OUTSIDE_RANGE duk_str_number_outside_range
-#define DUK_STR_NOT_OBJECT_COERCIBLE duk_str_not_object_coercible
-#define DUK_STR_STRING_TOO_LONG duk_str_string_too_long
-#define DUK_STR_BUFFER_TOO_LONG duk_str_buffer_too_long
-#define DUK_STR_SPRINTF_TOO_LONG duk_str_sprintf_too_long
-#define DUK_STR_ALLOC_FAILED duk_str_alloc_failed
-#define DUK_STR_POP_TOO_MANY duk_str_pop_too_many
-#define DUK_STR_WRONG_BUFFER_TYPE duk_str_wrong_buffer_type
-#define DUK_STR_ENCODE_FAILED duk_str_encode_failed
-#define DUK_STR_DECODE_FAILED duk_str_decode_failed
-#define DUK_STR_NO_SOURCECODE duk_str_no_sourcecode
-#define DUK_STR_CONCAT_RESULT_TOO_LONG duk_str_concat_result_too_long
-#define DUK_STR_UNIMPLEMENTED duk_str_unimplemented
-#define DUK_STR_UNSUPPORTED duk_str_unsupported
-#define DUK_STR_ARRAY_LENGTH_OVER_2G duk_str_array_length_over_2g
+/* Object property access */
+#define DUK_STR_INVALID_BASE "invalid base value"
+#define DUK_STR_STRICT_CALLER_READ "cannot read strict 'caller'"
+#define DUK_STR_PROXY_REJECTED "proxy rejected"
+#define DUK_STR_INVALID_ARRAY_LENGTH "invalid array length"
+#define DUK_STR_SETTER_UNDEFINED "setter undefined"
+#define DUK_STR_INVALID_DESCRIPTOR "invalid descriptor"
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_invalid_context;
-DUK_INTERNAL_DECL const char *duk_str_push_beyond_alloc_stack;
-DUK_INTERNAL_DECL const char *duk_str_not_buffer;
-DUK_INTERNAL_DECL const char *duk_str_unexpected_type;
-DUK_INTERNAL_DECL const char *duk_str_defaultvalue_coerce_failed;
-DUK_INTERNAL_DECL const char *duk_str_number_outside_range;
-DUK_INTERNAL_DECL const char *duk_str_not_object_coercible;
-DUK_INTERNAL_DECL const char *duk_str_string_too_long;
-DUK_INTERNAL_DECL const char *duk_str_buffer_too_long;
-DUK_INTERNAL_DECL const char *duk_str_sprintf_too_long;
-DUK_INTERNAL_DECL const char *duk_str_alloc_failed;
-DUK_INTERNAL_DECL const char *duk_str_pop_too_many;
-DUK_INTERNAL_DECL const char *duk_str_wrong_buffer_type;
-DUK_INTERNAL_DECL const char *duk_str_encode_failed;
-DUK_INTERNAL_DECL const char *duk_str_decode_failed;
-DUK_INTERNAL_DECL const char *duk_str_no_sourcecode;
-DUK_INTERNAL_DECL const char *duk_str_concat_result_too_long;
-DUK_INTERNAL_DECL const char *duk_str_unimplemented;
-DUK_INTERNAL_DECL const char *duk_str_unsupported;
-DUK_INTERNAL_DECL const char *duk_str_array_length_over_2g;
-#endif /* !DUK_SINGLE_FILE */
+/* Proxy */
+#define DUK_STR_PROXY_REVOKED "proxy revoked"
+#define DUK_STR_INVALID_TRAP_RESULT "invalid trap result"
-#define DUK_STR_FMT_PTR duk_str_fmt_ptr
-#define DUK_STR_FMT_INVALID_JSON duk_str_fmt_invalid_json
-#define DUK_STR_JSONDEC_RECLIMIT duk_str_jsondec_reclimit
-#define DUK_STR_JSONENC_RECLIMIT duk_str_jsonenc_reclimit
-#define DUK_STR_CYCLIC_INPUT duk_str_cyclic_input
+/* Variables */
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_fmt_ptr;
-DUK_INTERNAL_DECL const char *duk_str_fmt_invalid_json;
-DUK_INTERNAL_DECL const char *duk_str_jsondec_reclimit;
-DUK_INTERNAL_DECL const char *duk_str_jsonenc_reclimit;
-DUK_INTERNAL_DECL const char *duk_str_cyclic_input;
-#endif /* !DUK_SINGLE_FILE */
+/* Lexer */
+#define DUK_STR_INVALID_ESCAPE "invalid escape"
+#define DUK_STR_UNTERMINATED_STRING "unterminated string"
+#define DUK_STR_UNTERMINATED_COMMENT "unterminated comment"
+#define DUK_STR_UNTERMINATED_REGEXP "unterminated regexp"
+#define DUK_STR_TOKEN_LIMIT "token limit"
+#define DUK_STR_REGEXP_SUPPORT_DISABLED "regexp support disabled"
+#define DUK_STR_INVALID_NUMBER_LITERAL "invalid number literal"
+#define DUK_STR_INVALID_TOKEN "invalid token"
-#define DUK_STR_PROXY_REVOKED duk_str_proxy_revoked
-#define DUK_STR_INVALID_BASE duk_str_invalid_base
-#define DUK_STR_STRICT_CALLER_READ duk_str_strict_caller_read
-#define DUK_STR_PROXY_REJECTED duk_str_proxy_rejected
-#define DUK_STR_INVALID_ARRAY_LENGTH duk_str_invalid_array_length
-#define DUK_STR_ARRAY_LENGTH_WRITE_FAILED duk_str_array_length_write_failed
-#define DUK_STR_ARRAY_LENGTH_NOT_WRITABLE duk_str_array_length_not_writable
-#define DUK_STR_SETTER_UNDEFINED duk_str_setter_undefined
-#define DUK_STR_REDEFINE_VIRT_PROP duk_str_redefine_virt_prop
-#define DUK_STR_INVALID_DESCRIPTOR duk_str_invalid_descriptor
-#define DUK_STR_PROPERTY_IS_VIRTUAL duk_str_property_is_virtual
+/* Compiler */
+#define DUK_STR_PARSE_ERROR "parse error"
+#define DUK_STR_DUPLICATE_LABEL "duplicate label"
+#define DUK_STR_INVALID_LABEL "invalid label"
+#define DUK_STR_INVALID_ARRAY_LITERAL "invalid array literal"
+#define DUK_STR_INVALID_OBJECT_LITERAL "invalid object literal"
+#define DUK_STR_INVALID_VAR_DECLARATION "invalid variable declaration"
+#define DUK_STR_CANNOT_DELETE_IDENTIFIER "cannot delete identifier"
+#define DUK_STR_INVALID_EXPRESSION "invalid expression"
+#define DUK_STR_INVALID_LVALUE "invalid lvalue"
+#define DUK_STR_INVALID_NEWTARGET "invalid new.target"
+#define DUK_STR_EXPECTED_IDENTIFIER "expected identifier"
+#define DUK_STR_EMPTY_EXPR_NOT_ALLOWED "empty expression not allowed"
+#define DUK_STR_INVALID_FOR "invalid for statement"
+#define DUK_STR_INVALID_SWITCH "invalid switch statement"
+#define DUK_STR_INVALID_BREAK_CONT_LABEL "invalid break/continue label"
+#define DUK_STR_INVALID_RETURN "invalid return"
+#define DUK_STR_INVALID_TRY "invalid try"
+#define DUK_STR_INVALID_THROW "invalid throw"
+#define DUK_STR_WITH_IN_STRICT_MODE "with in strict mode"
+#define DUK_STR_FUNC_STMT_NOT_ALLOWED "function statement not allowed"
+#define DUK_STR_UNTERMINATED_STMT "unterminated statement"
+#define DUK_STR_INVALID_ARG_NAME "invalid argument name"
+#define DUK_STR_INVALID_FUNC_NAME "invalid function name"
+#define DUK_STR_INVALID_GETSET_NAME "invalid getter/setter name"
+#define DUK_STR_FUNC_NAME_REQUIRED "function name required"
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_proxy_revoked;
-DUK_INTERNAL_DECL const char *duk_str_invalid_base;
-DUK_INTERNAL_DECL const char *duk_str_strict_caller_read;
-DUK_INTERNAL_DECL const char *duk_str_proxy_rejected;
-DUK_INTERNAL_DECL const char *duk_str_invalid_array_length;
-DUK_INTERNAL_DECL const char *duk_str_array_length_write_failed;
-DUK_INTERNAL_DECL const char *duk_str_array_length_not_writable;
-DUK_INTERNAL_DECL const char *duk_str_setter_undefined;
-DUK_INTERNAL_DECL const char *duk_str_redefine_virt_prop;
-DUK_INTERNAL_DECL const char *duk_str_invalid_descriptor;
-DUK_INTERNAL_DECL const char *duk_str_property_is_virtual;
-#endif /* !DUK_SINGLE_FILE */
+/* RegExp */
+#define DUK_STR_INVALID_QUANTIFIER "invalid regexp quantifier"
+#define DUK_STR_INVALID_QUANTIFIER_NO_ATOM "quantifier without preceding atom"
+#define DUK_STR_INVALID_QUANTIFIER_VALUES "quantifier values invalid (qmin > qmax)"
+#define DUK_STR_QUANTIFIER_TOO_MANY_COPIES "quantifier requires too many atom copies"
+#define DUK_STR_UNEXPECTED_CLOSING_PAREN "unexpected closing parenthesis"
+#define DUK_STR_UNEXPECTED_END_OF_PATTERN "unexpected end of pattern"
+#define DUK_STR_UNEXPECTED_REGEXP_TOKEN "unexpected token in regexp"
+#define DUK_STR_INVALID_REGEXP_FLAGS "invalid regexp flags"
+#define DUK_STR_INVALID_REGEXP_ESCAPE "invalid regexp escape"
+#define DUK_STR_INVALID_BACKREFS "invalid backreference(s)"
+#define DUK_STR_INVALID_REGEXP_CHARACTER "invalid regexp character"
+#define DUK_STR_INVALID_REGEXP_GROUP "invalid regexp group"
+#define DUK_STR_UNTERMINATED_CHARCLASS "unterminated character class"
+#define DUK_STR_INVALID_RANGE "invalid range"
-#define DUK_STR_PARSE_ERROR duk_str_parse_error
-#define DUK_STR_DUPLICATE_LABEL duk_str_duplicate_label
-#define DUK_STR_INVALID_LABEL duk_str_invalid_label
-#define DUK_STR_INVALID_ARRAY_LITERAL duk_str_invalid_array_literal
-#define DUK_STR_INVALID_OBJECT_LITERAL duk_str_invalid_object_literal
-#define DUK_STR_INVALID_VAR_DECLARATION duk_str_invalid_var_declaration
-#define DUK_STR_CANNOT_DELETE_IDENTIFIER duk_str_cannot_delete_identifier
-#define DUK_STR_INVALID_EXPRESSION duk_str_invalid_expression
-#define DUK_STR_INVALID_LVALUE duk_str_invalid_lvalue
-#define DUK_STR_EXPECTED_IDENTIFIER duk_str_expected_identifier
-#define DUK_STR_EMPTY_EXPR_NOT_ALLOWED duk_str_empty_expr_not_allowed
-#define DUK_STR_INVALID_FOR duk_str_invalid_for
-#define DUK_STR_INVALID_SWITCH duk_str_invalid_switch
-#define DUK_STR_INVALID_BREAK_CONT_LABEL duk_str_invalid_break_cont_label
-#define DUK_STR_INVALID_RETURN duk_str_invalid_return
-#define DUK_STR_INVALID_TRY duk_str_invalid_try
-#define DUK_STR_INVALID_THROW duk_str_invalid_throw
-#define DUK_STR_WITH_IN_STRICT_MODE duk_str_with_in_strict_mode
-#define DUK_STR_FUNC_STMT_NOT_ALLOWED duk_str_func_stmt_not_allowed
-#define DUK_STR_UNTERMINATED_STMT duk_str_unterminated_stmt
-#define DUK_STR_INVALID_ARG_NAME duk_str_invalid_arg_name
-#define DUK_STR_INVALID_FUNC_NAME duk_str_invalid_func_name
-#define DUK_STR_INVALID_GETSET_NAME duk_str_invalid_getset_name
-#define DUK_STR_FUNC_NAME_REQUIRED duk_str_func_name_required
-
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_parse_error;
-DUK_INTERNAL_DECL const char *duk_str_duplicate_label;
-DUK_INTERNAL_DECL const char *duk_str_invalid_label;
-DUK_INTERNAL_DECL const char *duk_str_invalid_array_literal;
-DUK_INTERNAL_DECL const char *duk_str_invalid_object_literal;
-DUK_INTERNAL_DECL const char *duk_str_invalid_var_declaration;
-DUK_INTERNAL_DECL const char *duk_str_cannot_delete_identifier;
-DUK_INTERNAL_DECL const char *duk_str_invalid_expression;
-DUK_INTERNAL_DECL const char *duk_str_invalid_lvalue;
-DUK_INTERNAL_DECL const char *duk_str_expected_identifier;
-DUK_INTERNAL_DECL const char *duk_str_empty_expr_not_allowed;
-DUK_INTERNAL_DECL const char *duk_str_invalid_for;
-DUK_INTERNAL_DECL const char *duk_str_invalid_switch;
-DUK_INTERNAL_DECL const char *duk_str_invalid_break_cont_label;
-DUK_INTERNAL_DECL const char *duk_str_invalid_return;
-DUK_INTERNAL_DECL const char *duk_str_invalid_try;
-DUK_INTERNAL_DECL const char *duk_str_invalid_throw;
-DUK_INTERNAL_DECL const char *duk_str_with_in_strict_mode;
-DUK_INTERNAL_DECL const char *duk_str_func_stmt_not_allowed;
-DUK_INTERNAL_DECL const char *duk_str_unterminated_stmt;
-DUK_INTERNAL_DECL const char *duk_str_invalid_arg_name;
-DUK_INTERNAL_DECL const char *duk_str_invalid_func_name;
-DUK_INTERNAL_DECL const char *duk_str_invalid_getset_name;
-DUK_INTERNAL_DECL const char *duk_str_func_name_required;
-#endif /* !DUK_SINGLE_FILE */
-
-#define DUK_STR_INVALID_QUANTIFIER_NO_ATOM duk_str_invalid_quantifier_no_atom
-#define DUK_STR_INVALID_QUANTIFIER_VALUES duk_str_invalid_quantifier_values
-#define DUK_STR_QUANTIFIER_TOO_MANY_COPIES duk_str_quantifier_too_many_copies
-#define DUK_STR_UNEXPECTED_CLOSING_PAREN duk_str_unexpected_closing_paren
-#define DUK_STR_UNEXPECTED_END_OF_PATTERN duk_str_unexpected_end_of_pattern
-#define DUK_STR_UNEXPECTED_REGEXP_TOKEN duk_str_unexpected_regexp_token
-#define DUK_STR_INVALID_REGEXP_FLAGS duk_str_invalid_regexp_flags
-#define DUK_STR_INVALID_BACKREFS duk_str_invalid_backrefs
-
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_invalid_quantifier_no_atom;
-DUK_INTERNAL_DECL const char *duk_str_invalid_quantifier_values;
-DUK_INTERNAL_DECL const char *duk_str_quantifier_too_many_copies;
-DUK_INTERNAL_DECL const char *duk_str_unexpected_closing_paren;
-DUK_INTERNAL_DECL const char *duk_str_unexpected_end_of_pattern;
-DUK_INTERNAL_DECL const char *duk_str_unexpected_regexp_token;
-DUK_INTERNAL_DECL const char *duk_str_invalid_regexp_flags;
-DUK_INTERNAL_DECL const char *duk_str_invalid_backrefs;
-#endif /* !DUK_SINGLE_FILE */
-
-#define DUK_STR_VALSTACK_LIMIT duk_str_valstack_limit
-#define DUK_STR_CALLSTACK_LIMIT duk_str_callstack_limit
-#define DUK_STR_CATCHSTACK_LIMIT duk_str_catchstack_limit
-#define DUK_STR_PROTOTYPE_CHAIN_LIMIT duk_str_prototype_chain_limit
-#define DUK_STR_BOUND_CHAIN_LIMIT duk_str_bound_chain_limit
-#define DUK_STR_C_CALLSTACK_LIMIT duk_str_c_callstack_limit
-#define DUK_STR_COMPILER_RECURSION_LIMIT duk_str_compiler_recursion_limit
-#define DUK_STR_BYTECODE_LIMIT duk_str_bytecode_limit
-#define DUK_STR_REG_LIMIT duk_str_reg_limit
-#define DUK_STR_TEMP_LIMIT duk_str_temp_limit
-#define DUK_STR_CONST_LIMIT duk_str_const_limit
-#define DUK_STR_FUNC_LIMIT duk_str_func_limit
-#define DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT duk_str_regexp_compiler_recursion_limit
-#define DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT duk_str_regexp_executor_recursion_limit
-#define DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT duk_str_regexp_executor_step_limit
-
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_valstack_limit;
-DUK_INTERNAL_DECL const char *duk_str_callstack_limit;
-DUK_INTERNAL_DECL const char *duk_str_catchstack_limit;
-DUK_INTERNAL_DECL const char *duk_str_prototype_chain_limit;
-DUK_INTERNAL_DECL const char *duk_str_bound_chain_limit;
-DUK_INTERNAL_DECL const char *duk_str_c_callstack_limit;
-DUK_INTERNAL_DECL const char *duk_str_compiler_recursion_limit;
-DUK_INTERNAL_DECL const char *duk_str_bytecode_limit;
-DUK_INTERNAL_DECL const char *duk_str_reg_limit;
-DUK_INTERNAL_DECL const char *duk_str_temp_limit;
-DUK_INTERNAL_DECL const char *duk_str_const_limit;
-DUK_INTERNAL_DECL const char *duk_str_func_limit;
-DUK_INTERNAL_DECL const char *duk_str_regexp_compiler_recursion_limit;
-DUK_INTERNAL_DECL const char *duk_str_regexp_executor_recursion_limit;
-DUK_INTERNAL_DECL const char *duk_str_regexp_executor_step_limit;
-#endif /* !DUK_SINGLE_FILE */
-
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_anon;
-#endif /* !DUK_SINGLE_FILE */
+/* Limits */
+#define DUK_STR_VALSTACK_LIMIT "valstack limit"
+#define DUK_STR_CALLSTACK_LIMIT "callstack limit"
+#define DUK_STR_PROTOTYPE_CHAIN_LIMIT "prototype chain limit"
+#define DUK_STR_BOUND_CHAIN_LIMIT "function call bound chain limit"
+#define DUK_STR_C_CALLSTACK_LIMIT "C call stack depth limit"
+#define DUK_STR_COMPILER_RECURSION_LIMIT "compiler recursion limit"
+#define DUK_STR_BYTECODE_LIMIT "bytecode limit"
+#define DUK_STR_REG_LIMIT "register limit"
+#define DUK_STR_TEMP_LIMIT "temp limit"
+#define DUK_STR_CONST_LIMIT "const limit"
+#define DUK_STR_FUNC_LIMIT "function limit"
+#define DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT "regexp compiler recursion limit"
+#define DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT "regexp executor recursion limit"
+#define DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT "regexp step limit"
#endif /* DUK_ERRMSG_H_INCLUDED */
+/* #include duk_js_bytecode.h */
#line 1 "duk_js_bytecode.h"
/*
* Ecmascript bytecode
*/
-#ifndef DUK_JS_BYTECODE_H_INCLUDED
+#if !defined(DUK_JS_BYTECODE_H_INCLUDED)
#define DUK_JS_BYTECODE_H_INCLUDED
/*
- * Logical instruction layout
- * ==========================
+ * Bytecode instruction layout
+ * ===========================
+ *
+ * Instructions are unsigned 32-bit integers divided as follows:
*
* !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! !
* !1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!
- * +---------------------------------------------------+-----------+
- * ! C ! B ! A ! OP !
- * +---------------------------------------------------+-----------+
+ * +-----------------------------------------------+---------------+
+ * ! C ! B ! A ! OP !
+ * +-----------------------------------------------+---------------+
*
- * OP (6 bits): opcode (DUK_OP_*), access should be fastest
- * A (8 bits): typically a target register number
- * B (9 bits): typically first source register/constant number
- * C (9 bits): typically second source register/constant number
+ * OP (8 bits): opcode (DUK_OP_*), access should be fastest
+ * consecutive opcodes allocated when opcode needs flags
+ * A (8 bits): typically a target register number
+ * B (8 bits): typically first source register/constant number
+ * C (8 bits): typically second source register/constant number
*
* Some instructions combine BC or ABC together for larger parameter values.
- * Signed integers (e.g. jump offsets) are encoded as unsigned, with an opcode
- * specific bias. B and C may denote a register or a constant, see
- * DUK_BC_ISREG() and DUK_BC_ISCONST().
+ * Signed integers (e.g. jump offsets) are encoded as unsigned, with an
+ * opcode specific bias.
*
- * Note: macro naming is a bit misleading, e.g. "ABC" in macro name but
- * the field layout is logically "CBA".
+ * Some opcodes have flags which are handled by allocating consecutive
+ * opcodes to make space for 1-N flags. Flags can also be e.g. in the 'A'
+ * field when there's room for the specific opcode.
+ *
+ * For example, if three flags were needed, they could be allocated from
+ * the opcode field as follows:
+ *
+ * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! !
+ * !1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!
+ * +-----------------------------------------------+---------------+
+ * ! C ! B ! A ! OP !Z!Y!X!
+ * +-----------------------------------------------+---------------+
+ *
+ * Some opcodes accept a reg/const argument which is handled by allocating
+ * flags in the OP field, see DUK_BC_ISREG() and DUK_BC_ISCONST(). The
+ * following convention is shared by most opcodes, so that the compiler
+ * can handle reg/const flagging without opcode specific code paths:
+ *
+ * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! !
+ * !1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!
+ * +-----------------------------------------------+---------------+
+ * ! C ! B ! A ! OP !Y!X!
+ * +-----------------------------------------------+---------------+
+ *
+ * X 1=B is const, 0=B is reg
+ * Y 1=C is const, 0=C is reg
+ *
+ * In effect OP, OP + 1, OP + 2, and OP + 3 are allocated from the
+ * 8-bit opcode space for a single logical opcode. The base opcode
+ * number should be divisible by 4. If the opcode is called 'FOO'
+ * the following opcode constants would be defined:
+ *
+ * DUK_OP_FOO 100 // base opcode number
+ * DUK_OP_FOO_RR 100 // FOO, B=reg, C=reg
+ * DUK_OP_FOO_CR 101 // FOO, B=const, C=reg
+ * DUK_OP_FOO_RC 102 // FOO, B=reg, C=const
+ * DUK_OP_FOO_CC 103 // FOO, B=const, C=const
+ *
+ * If only B or C is a reg/const, the unused opcode combinations can be
+ * used for other opcodes (which take no reg/const argument). However,
+ * such opcode values are initially reserved, at least while opcode space
+ * is available. For example, if 'BAR' uses B for a register field and
+ * C is a reg/const:
+ *
+ * DUK_OP_BAR 116 // base opcode number
+ * DUK_OP_BAR_RR 116 // BAR, B=reg, C=reg
+ * DUK_OP_BAR_CR_UNUSED 117 // unused, could be repurposed
+ * DUK_OP_BAR_RC 118 // BAR, B=reg, C=const
+ * DUK_OP_BAR_CC_UNUSED 119 // unused, could be repurposed
+ *
+ * Macro naming is a bit misleading, e.g. "ABC" in macro name but the
+ * field layout is concretely "CBA" in the register.
*/
typedef duk_uint32_t duk_instr_t;
-#define DUK_DEC_OP(x) ((x) & 0x3fUL)
-#define DUK_DEC_A(x) (((x) >> 6) & 0xffUL)
-#define DUK_DEC_B(x) (((x) >> 14) & 0x1ffUL)
-#define DUK_DEC_C(x) (((x) >> 23) & 0x1ffUL)
-#define DUK_DEC_BC(x) (((x) >> 14) & 0x3ffffUL)
-#define DUK_DEC_ABC(x) (((x) >> 6) & 0x3ffffffUL)
+#define DUK_BC_SHIFT_OP 0
+#define DUK_BC_SHIFT_A 8
+#define DUK_BC_SHIFT_B 16
+#define DUK_BC_SHIFT_C 24
+#define DUK_BC_SHIFT_BC DUK_BC_SHIFT_B
+#define DUK_BC_SHIFT_ABC DUK_BC_SHIFT_A
+
+#define DUK_BC_UNSHIFTED_MASK_OP 0xffUL
+#define DUK_BC_UNSHIFTED_MASK_A 0xffUL
+#define DUK_BC_UNSHIFTED_MASK_B 0xffUL
+#define DUK_BC_UNSHIFTED_MASK_C 0xffUL
+#define DUK_BC_UNSHIFTED_MASK_BC 0xffffUL
+#define DUK_BC_UNSHIFTED_MASK_ABC 0xffffffUL
+
+#define DUK_BC_SHIFTED_MASK_OP (DUK_BC_UNSHIFTED_MASK_OP << DUK_BC_SHIFT_OP)
+#define DUK_BC_SHIFTED_MASK_A (DUK_BC_UNSHIFTED_MASK_A << DUK_BC_SHIFT_A)
+#define DUK_BC_SHIFTED_MASK_B (DUK_BC_UNSHIFTED_MASK_B << DUK_BC_SHIFT_B)
+#define DUK_BC_SHIFTED_MASK_C (DUK_BC_UNSHIFTED_MASK_C << DUK_BC_SHIFT_C)
+#define DUK_BC_SHIFTED_MASK_BC (DUK_BC_UNSHIFTED_MASK_BC << DUK_BC_SHIFT_BC)
+#define DUK_BC_SHIFTED_MASK_ABC (DUK_BC_UNSHIFTED_MASK_ABC << DUK_BC_SHIFT_ABC)
+
+#define DUK_DEC_OP(x) ((x) & 0xffUL)
+#define DUK_DEC_A(x) (((x) >> 8) & 0xffUL)
+#define DUK_DEC_B(x) (((x) >> 16) & 0xffUL)
+#define DUK_DEC_C(x) (((x) >> 24) & 0xffUL)
+#define DUK_DEC_BC(x) (((x) >> 16) & 0xffffUL)
+#define DUK_DEC_ABC(x) (((x) >> 8) & 0xffffffUL)
#define DUK_ENC_OP(op) ((duk_instr_t) (op))
#define DUK_ENC_OP_ABC(op,abc) ((duk_instr_t) ( \
- (((duk_instr_t) (abc)) << 6) | \
+ (((duk_instr_t) (abc)) << 8) | \
((duk_instr_t) (op)) \
))
#define DUK_ENC_OP_A_BC(op,a,bc) ((duk_instr_t) ( \
- (((duk_instr_t) (bc)) << 14) | \
- (((duk_instr_t) (a)) << 6) | \
+ (((duk_instr_t) (bc)) << 16) | \
+ (((duk_instr_t) (a)) << 8) | \
((duk_instr_t) (op)) \
))
#define DUK_ENC_OP_A_B_C(op,a,b,c) ((duk_instr_t) ( \
- (((duk_instr_t) (c)) << 23) | \
- (((duk_instr_t) (b)) << 14) | \
- (((duk_instr_t) (a)) << 6) | \
+ (((duk_instr_t) (c)) << 24) | \
+ (((duk_instr_t) (b)) << 16) | \
+ (((duk_instr_t) (a)) << 8) | \
((duk_instr_t) (op)) \
))
-#define DUK_ENC_OP_A_B(op,a,b) DUK_ENC_OP_A_B_C(op,a,b,0)
-#define DUK_ENC_OP_A(op,a) DUK_ENC_OP_A_B_C(op,a,0,0)
+#define DUK_ENC_OP_A_B(op,a,b) DUK_ENC_OP_A_B_C((op),(a),(b),0)
+#define DUK_ENC_OP_A(op,a) DUK_ENC_OP_A_B_C((op),(a),0,0)
+#define DUK_ENC_OP_BC(op,bc) DUK_ENC_OP_A_BC((op),0,(bc))
+
+/* Get opcode base value with B/C reg/const flags cleared. */
+#define DUK_BC_NOREGCONST_OP(op) ((op) & 0xfc)
/* Constants should be signed so that signed arithmetic involving them
* won't cause values to be coerced accidentally to unsigned.
*/
#define DUK_BC_OP_MIN 0
-#define DUK_BC_OP_MAX 0x3fL
+#define DUK_BC_OP_MAX 0xffL
#define DUK_BC_A_MIN 0
#define DUK_BC_A_MAX 0xffL
#define DUK_BC_B_MIN 0
-#define DUK_BC_B_MAX 0x1ffL
+#define DUK_BC_B_MAX 0xffL
#define DUK_BC_C_MIN 0
-#define DUK_BC_C_MAX 0x1ffL
+#define DUK_BC_C_MAX 0xffL
#define DUK_BC_BC_MIN 0
-#define DUK_BC_BC_MAX 0x3ffffL
+#define DUK_BC_BC_MAX 0xffffL
#define DUK_BC_ABC_MIN 0
-#define DUK_BC_ABC_MAX 0x3ffffffL
-#define DUK_BC_EXTRAOP_MIN DUK_BC_A_MIN
-#define DUK_BC_EXTRAOP_MAX DUK_BC_A_MAX
+#define DUK_BC_ABC_MAX 0xffffffL
+/* Masks for B/C reg/const indicator in opcode field. */
+#define DUK_BC_REGCONST_B (0x01UL)
+#define DUK_BC_REGCONST_C (0x02UL)
+
+/* Misc. masks for opcode field. */
+#define DUK_BC_INCDECP_FLAG_DEC (0x04UL)
+#define DUK_BC_INCDECP_FLAG_POST (0x08UL)
+
+/* Opcodes. */
#define DUK_OP_LDREG 0
#define DUK_OP_STREG 1
-#define DUK_OP_LDCONST 2
-#define DUK_OP_LDINT 3
-#define DUK_OP_LDINTX 4
-#define DUK_OP_MPUTOBJ 5
-#define DUK_OP_MPUTOBJI 6
-#define DUK_OP_MPUTARR 7
-#define DUK_OP_MPUTARRI 8
-#define DUK_OP_NEW 9
-#define DUK_OP_NEWI 10
-#define DUK_OP_REGEXP 11
-#define DUK_OP_CSREG 12
-#define DUK_OP_CSREGI 13
-#define DUK_OP_GETVAR 14
-#define DUK_OP_PUTVAR 15
-#define DUK_OP_DECLVAR 16
-#define DUK_OP_DELVAR 17
-#define DUK_OP_CSVAR 18
-#define DUK_OP_CSVARI 19
-#define DUK_OP_CLOSURE 20
-#define DUK_OP_GETPROP 21
-#define DUK_OP_PUTPROP 22
-#define DUK_OP_DELPROP 23
-#define DUK_OP_CSPROP 24
-#define DUK_OP_CSPROPI 25
-#define DUK_OP_ADD 26
-#define DUK_OP_SUB 27
-#define DUK_OP_MUL 28
-#define DUK_OP_DIV 29
-#define DUK_OP_MOD 30
-#define DUK_OP_BAND 31
-#define DUK_OP_BOR 32
-#define DUK_OP_BXOR 33
-#define DUK_OP_BASL 34
-#define DUK_OP_BLSR 35
-#define DUK_OP_BASR 36
-#define DUK_OP_EQ 37
-#define DUK_OP_NEQ 38
-#define DUK_OP_SEQ 39
-#define DUK_OP_SNEQ 40
-#define DUK_OP_GT 41
-#define DUK_OP_GE 42
-#define DUK_OP_LT 43
+#define DUK_OP_JUMP 2
+#define DUK_OP_LDCONST 3
+#define DUK_OP_LDINT 4
+#define DUK_OP_LDINTX 5
+#define DUK_OP_LDTHIS 6
+#define DUK_OP_LDUNDEF 7
+#define DUK_OP_LDNULL 8
+#define DUK_OP_LDTRUE 9
+#define DUK_OP_LDFALSE 10
+#define DUK_OP_GETVAR 11
+#define DUK_OP_BNOT 12
+#define DUK_OP_LNOT 13
+#define DUK_OP_UNM 14
+#define DUK_OP_UNP 15
+#define DUK_OP_EQ 16
+#define DUK_OP_EQ_RR 16
+#define DUK_OP_EQ_CR 17
+#define DUK_OP_EQ_RC 18
+#define DUK_OP_EQ_CC 19
+#define DUK_OP_NEQ 20
+#define DUK_OP_NEQ_RR 20
+#define DUK_OP_NEQ_CR 21
+#define DUK_OP_NEQ_RC 22
+#define DUK_OP_NEQ_CC 23
+#define DUK_OP_SEQ 24
+#define DUK_OP_SEQ_RR 24
+#define DUK_OP_SEQ_CR 25
+#define DUK_OP_SEQ_RC 26
+#define DUK_OP_SEQ_CC 27
+#define DUK_OP_SNEQ 28
+#define DUK_OP_SNEQ_RR 28
+#define DUK_OP_SNEQ_CR 29
+#define DUK_OP_SNEQ_RC 30
+#define DUK_OP_SNEQ_CC 31
+#define DUK_OP_GT 32
+#define DUK_OP_GT_RR 32
+#define DUK_OP_GT_CR 33
+#define DUK_OP_GT_RC 34
+#define DUK_OP_GT_CC 35
+#define DUK_OP_GE 36
+#define DUK_OP_GE_RR 36
+#define DUK_OP_GE_CR 37
+#define DUK_OP_GE_RC 38
+#define DUK_OP_GE_CC 39
+#define DUK_OP_LT 40
+#define DUK_OP_LT_RR 40
+#define DUK_OP_LT_CR 41
+#define DUK_OP_LT_RC 42
+#define DUK_OP_LT_CC 43
#define DUK_OP_LE 44
-#define DUK_OP_IF 45
-#define DUK_OP_JUMP 46
-#define DUK_OP_RETURN 47
-#define DUK_OP_CALL 48
-#define DUK_OP_CALLI 49
-#define DUK_OP_TRYCATCH 50
-#define DUK_OP_EXTRA 51
-#define DUK_OP_PREINCR 52 /* pre/post opcode values have constraints, */
-#define DUK_OP_PREDECR 53 /* see duk_js_executor.c */
-#define DUK_OP_POSTINCR 54
-#define DUK_OP_POSTDECR 55
-#define DUK_OP_PREINCV 56
-#define DUK_OP_PREDECV 57
-#define DUK_OP_POSTINCV 58
-#define DUK_OP_POSTDECV 59
-#define DUK_OP_PREINCP 60
-#define DUK_OP_PREDECP 61
-#define DUK_OP_POSTINCP 62
-#define DUK_OP_POSTDECP 63
-#define DUK_OP_NONE 64 /* dummy value used as marker */
+#define DUK_OP_LE_RR 44
+#define DUK_OP_LE_CR 45
+#define DUK_OP_LE_RC 46
+#define DUK_OP_LE_CC 47
+#define DUK_OP_IFTRUE 48
+#define DUK_OP_IFTRUE_R 48
+#define DUK_OP_IFTRUE_C 49
+#define DUK_OP_IFFALSE 50
+#define DUK_OP_IFFALSE_R 50
+#define DUK_OP_IFFALSE_C 51
+#define DUK_OP_ADD 52
+#define DUK_OP_ADD_RR 52
+#define DUK_OP_ADD_CR 53
+#define DUK_OP_ADD_RC 54
+#define DUK_OP_ADD_CC 55
+#define DUK_OP_SUB 56
+#define DUK_OP_SUB_RR 56
+#define DUK_OP_SUB_CR 57
+#define DUK_OP_SUB_RC 58
+#define DUK_OP_SUB_CC 59
+#define DUK_OP_MUL 60
+#define DUK_OP_MUL_RR 60
+#define DUK_OP_MUL_CR 61
+#define DUK_OP_MUL_RC 62
+#define DUK_OP_MUL_CC 63
+#define DUK_OP_DIV 64
+#define DUK_OP_DIV_RR 64
+#define DUK_OP_DIV_CR 65
+#define DUK_OP_DIV_RC 66
+#define DUK_OP_DIV_CC 67
+#define DUK_OP_MOD 68
+#define DUK_OP_MOD_RR 68
+#define DUK_OP_MOD_CR 69
+#define DUK_OP_MOD_RC 70
+#define DUK_OP_MOD_CC 71
+#define DUK_OP_EXP 72
+#define DUK_OP_EXP_RR 72
+#define DUK_OP_EXP_CR 73
+#define DUK_OP_EXP_RC 74
+#define DUK_OP_EXP_CC 75
+#define DUK_OP_BAND 76
+#define DUK_OP_BAND_RR 76
+#define DUK_OP_BAND_CR 77
+#define DUK_OP_BAND_RC 78
+#define DUK_OP_BAND_CC 79
+#define DUK_OP_BOR 80
+#define DUK_OP_BOR_RR 80
+#define DUK_OP_BOR_CR 81
+#define DUK_OP_BOR_RC 82
+#define DUK_OP_BOR_CC 83
+#define DUK_OP_BXOR 84
+#define DUK_OP_BXOR_RR 84
+#define DUK_OP_BXOR_CR 85
+#define DUK_OP_BXOR_RC 86
+#define DUK_OP_BXOR_CC 87
+#define DUK_OP_BASL 88
+#define DUK_OP_BASL_RR 88
+#define DUK_OP_BASL_CR 89
+#define DUK_OP_BASL_RC 90
+#define DUK_OP_BASL_CC 91
+#define DUK_OP_BLSR 92
+#define DUK_OP_BLSR_RR 92
+#define DUK_OP_BLSR_CR 93
+#define DUK_OP_BLSR_RC 94
+#define DUK_OP_BLSR_CC 95
+#define DUK_OP_BASR 96
+#define DUK_OP_BASR_RR 96
+#define DUK_OP_BASR_CR 97
+#define DUK_OP_BASR_RC 98
+#define DUK_OP_BASR_CC 99
+#define DUK_OP_INSTOF 100
+#define DUK_OP_INSTOF_RR 100
+#define DUK_OP_INSTOF_CR 101
+#define DUK_OP_INSTOF_RC 102
+#define DUK_OP_INSTOF_CC 103
+#define DUK_OP_IN 104
+#define DUK_OP_IN_RR 104
+#define DUK_OP_IN_CR 105
+#define DUK_OP_IN_RC 106
+#define DUK_OP_IN_CC 107
+#define DUK_OP_GETPROP 108
+#define DUK_OP_GETPROP_RR 108
+#define DUK_OP_GETPROP_CR 109
+#define DUK_OP_GETPROP_RC 110
+#define DUK_OP_GETPROP_CC 111
+#define DUK_OP_PUTPROP 112
+#define DUK_OP_PUTPROP_RR 112
+#define DUK_OP_PUTPROP_CR 113
+#define DUK_OP_PUTPROP_RC 114
+#define DUK_OP_PUTPROP_CC 115
+#define DUK_OP_DELPROP 116
+#define DUK_OP_DELPROP_RR 116
+#define DUK_OP_DELPROP_CR_UNUSED 117 /* unused now */
+#define DUK_OP_DELPROP_RC 118
+#define DUK_OP_DELPROP_CC_UNUSED 119 /* unused now */
+#define DUK_OP_PREINCR 120 /* pre/post opcode values have constraints, */
+#define DUK_OP_PREDECR 121 /* see duk_js_executor.c and duk_js_compiler.c. */
+#define DUK_OP_POSTINCR 122
+#define DUK_OP_POSTDECR 123
+#define DUK_OP_PREINCV 124
+#define DUK_OP_PREDECV 125
+#define DUK_OP_POSTINCV 126
+#define DUK_OP_POSTDECV 127
+#define DUK_OP_PREINCP 128 /* pre/post inc/dec prop opcodes have constraints */
+#define DUK_OP_PREINCP_RR 128
+#define DUK_OP_PREINCP_CR 129
+#define DUK_OP_PREINCP_RC 130
+#define DUK_OP_PREINCP_CC 131
+#define DUK_OP_PREDECP 132
+#define DUK_OP_PREDECP_RR 132
+#define DUK_OP_PREDECP_CR 133
+#define DUK_OP_PREDECP_RC 134
+#define DUK_OP_PREDECP_CC 135
+#define DUK_OP_POSTINCP 136
+#define DUK_OP_POSTINCP_RR 136
+#define DUK_OP_POSTINCP_CR 137
+#define DUK_OP_POSTINCP_RC 138
+#define DUK_OP_POSTINCP_CC 139
+#define DUK_OP_POSTDECP 140
+#define DUK_OP_POSTDECP_RR 140
+#define DUK_OP_POSTDECP_CR 141
+#define DUK_OP_POSTDECP_RC 142
+#define DUK_OP_POSTDECP_CC 143
+#define DUK_OP_DECLVAR 144
+#define DUK_OP_DECLVAR_RR 144
+#define DUK_OP_DECLVAR_CR 145
+#define DUK_OP_DECLVAR_RC 146
+#define DUK_OP_DECLVAR_CC 147
+#define DUK_OP_REGEXP 148
+#define DUK_OP_REGEXP_RR 148
+#define DUK_OP_REGEXP_CR 149
+#define DUK_OP_REGEXP_RC 150
+#define DUK_OP_REGEXP_CC 151
+#define DUK_OP_CLOSURE 152
+#define DUK_OP_TYPEOF 153
+#define DUK_OP_TYPEOFID 154
+#define DUK_OP_PUTVAR 155
+#define DUK_OP_DELVAR 156
+#define DUK_OP_RETREG 157
+#define DUK_OP_RETUNDEF 158
+#define DUK_OP_RETCONST 159
+#define DUK_OP_RETCONSTN 160 /* return const without incref (e.g. number) */
+#define DUK_OP_LABEL 161
+#define DUK_OP_ENDLABEL 162
+#define DUK_OP_BREAK 163
+#define DUK_OP_CONTINUE 164
+#define DUK_OP_TRYCATCH 165
+#define DUK_OP_ENDTRY 166
+#define DUK_OP_ENDCATCH 167
+#define DUK_OP_ENDFIN 168
+#define DUK_OP_THROW 169
+#define DUK_OP_INVLHS 170
+#define DUK_OP_CSREG 171
+#define DUK_OP_CSVAR 172
+#define DUK_OP_CSVAR_RR 172
+#define DUK_OP_CSVAR_CR 173
+#define DUK_OP_CSVAR_RC 174
+#define DUK_OP_CSVAR_CC 175
+#define DUK_OP_CALL0 176 /* DUK_OP_CALL0 & 0x0F must be zero. */
+#define DUK_OP_CALL1 177
+#define DUK_OP_CALL2 178
+#define DUK_OP_CALL3 179
+#define DUK_OP_CALL4 180
+#define DUK_OP_CALL5 181
+#define DUK_OP_CALL6 182
+#define DUK_OP_CALL7 183
+#define DUK_OP_CALL8 184
+#define DUK_OP_CALL9 185
+#define DUK_OP_CALL10 186
+#define DUK_OP_CALL11 187
+#define DUK_OP_CALL12 188
+#define DUK_OP_CALL13 189
+#define DUK_OP_CALL14 190
+#define DUK_OP_CALL15 191
+#define DUK_OP_NEWOBJ 192
+#define DUK_OP_NEWARR 193
+#define DUK_OP_MPUTOBJ 194
+#define DUK_OP_MPUTOBJI 195
+#define DUK_OP_INITSET 196
+#define DUK_OP_INITGET 197
+#define DUK_OP_MPUTARR 198
+#define DUK_OP_MPUTARRI 199
+#define DUK_OP_SETALEN 200
+#define DUK_OP_INITENUM 201
+#define DUK_OP_NEXTENUM 202
+#define DUK_OP_NEWTARGET 203
+#define DUK_OP_DEBUGGER 204
+#define DUK_OP_NOP 205
+#define DUK_OP_INVALID 206
+#define DUK_OP_UNUSED207 207
+#define DUK_OP_GETPROPC 208
+#define DUK_OP_GETPROPC_RR 208
+#define DUK_OP_GETPROPC_CR 209
+#define DUK_OP_GETPROPC_RC 210
+#define DUK_OP_GETPROPC_CC 211
+#define DUK_OP_UNUSED212 212
+#define DUK_OP_UNUSED213 213
+#define DUK_OP_UNUSED214 214
+#define DUK_OP_UNUSED215 215
+#define DUK_OP_UNUSED216 216
+#define DUK_OP_UNUSED217 217
+#define DUK_OP_UNUSED218 218
+#define DUK_OP_UNUSED219 219
+#define DUK_OP_UNUSED220 220
+#define DUK_OP_UNUSED221 221
+#define DUK_OP_UNUSED222 222
+#define DUK_OP_UNUSED223 223
+#define DUK_OP_UNUSED224 224
+#define DUK_OP_UNUSED225 225
+#define DUK_OP_UNUSED226 226
+#define DUK_OP_UNUSED227 227
+#define DUK_OP_UNUSED228 228
+#define DUK_OP_UNUSED229 229
+#define DUK_OP_UNUSED230 230
+#define DUK_OP_UNUSED231 231
+#define DUK_OP_UNUSED232 232
+#define DUK_OP_UNUSED233 233
+#define DUK_OP_UNUSED234 234
+#define DUK_OP_UNUSED235 235
+#define DUK_OP_UNUSED236 236
+#define DUK_OP_UNUSED237 237
+#define DUK_OP_UNUSED238 238
+#define DUK_OP_UNUSED239 239
+#define DUK_OP_UNUSED240 240
+#define DUK_OP_UNUSED241 241
+#define DUK_OP_UNUSED242 242
+#define DUK_OP_UNUSED243 243
+#define DUK_OP_UNUSED244 244
+#define DUK_OP_UNUSED245 245
+#define DUK_OP_UNUSED246 246
+#define DUK_OP_UNUSED247 247
+#define DUK_OP_UNUSED248 248
+#define DUK_OP_UNUSED249 249
+#define DUK_OP_UNUSED250 250
+#define DUK_OP_UNUSED251 251
+#define DUK_OP_UNUSED252 252
+#define DUK_OP_UNUSED253 253
+#define DUK_OP_UNUSED254 254
+#define DUK_OP_UNUSED255 255
+#define DUK_OP_NONE 256 /* dummy value used as marker (doesn't fit in 8-bit field) */
-/* DUK_OP_EXTRA, sub-operation in A */
-#define DUK_EXTRAOP_NOP 0
-#define DUK_EXTRAOP_INVALID 1
-#define DUK_EXTRAOP_LDTHIS 2
-#define DUK_EXTRAOP_LDUNDEF 3
-#define DUK_EXTRAOP_LDNULL 4
-#define DUK_EXTRAOP_LDTRUE 5
-#define DUK_EXTRAOP_LDFALSE 6
-#define DUK_EXTRAOP_NEWOBJ 7
-#define DUK_EXTRAOP_NEWARR 8
-#define DUK_EXTRAOP_SETALEN 9
-#define DUK_EXTRAOP_TYPEOF 10
-#define DUK_EXTRAOP_TYPEOFID 11
-#define DUK_EXTRAOP_INITENUM 12
-#define DUK_EXTRAOP_NEXTENUM 13
-#define DUK_EXTRAOP_INITSET 14
-#define DUK_EXTRAOP_INITSETI 15
-#define DUK_EXTRAOP_INITGET 16
-#define DUK_EXTRAOP_INITGETI 17
-#define DUK_EXTRAOP_ENDTRY 18
-#define DUK_EXTRAOP_ENDCATCH 19
-#define DUK_EXTRAOP_ENDFIN 20
-#define DUK_EXTRAOP_THROW 21
-#define DUK_EXTRAOP_INVLHS 22
-#define DUK_EXTRAOP_UNM 23
-#define DUK_EXTRAOP_UNP 24
-#define DUK_EXTRAOP_DEBUGGER 25
-#define DUK_EXTRAOP_BREAK 26
-#define DUK_EXTRAOP_CONTINUE 27
-#define DUK_EXTRAOP_BNOT 28
-#define DUK_EXTRAOP_LNOT 29
-#define DUK_EXTRAOP_INSTOF 30
-#define DUK_EXTRAOP_IN 31
-#define DUK_EXTRAOP_LABEL 32
-#define DUK_EXTRAOP_ENDLABEL 33
+/* XXX: Allocate flags from opcode field? Would take 16 opcode slots
+ * but avoids shuffling in more cases. Maybe not worth it.
+ */
+/* DUK_OP_TRYCATCH flags in A. */
+#define DUK_BC_TRYCATCH_FLAG_HAVE_CATCH (1U << 0)
+#define DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY (1U << 1)
+#define DUK_BC_TRYCATCH_FLAG_CATCH_BINDING (1U << 2)
+#define DUK_BC_TRYCATCH_FLAG_WITH_BINDING (1U << 3)
-/* DUK_OP_CALL flags in A */
-#define DUK_BC_CALL_FLAG_TAILCALL (1 << 0)
-#define DUK_BC_CALL_FLAG_EVALCALL (1 << 1)
+/* DUK_OP_DECLVAR flags in A; bottom bits are reserved for propdesc flags
+ * (DUK_PROPDESC_FLAG_XXX).
+ */
+#define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1U << 4) /* function declaration */
-/* DUK_OP_TRYCATCH flags in A */
-#define DUK_BC_TRYCATCH_FLAG_HAVE_CATCH (1 << 0)
-#define DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY (1 << 1)
-#define DUK_BC_TRYCATCH_FLAG_CATCH_BINDING (1 << 2)
-#define DUK_BC_TRYCATCH_FLAG_WITH_BINDING (1 << 3)
+/* DUK_OP_CALLn flags, part of opcode field. Three lowest bits must match
+ * DUK_CALL_FLAG_xxx directly.
+ */
+#define DUK_BC_CALL_FLAG_TAILCALL (1U << 0)
+#define DUK_BC_CALL_FLAG_CONSTRUCT (1U << 1)
+#define DUK_BC_CALL_FLAG_CALLED_AS_EVAL (1U << 2)
+#define DUK_BC_CALL_FLAG_INDIRECT (1U << 3)
-/* DUK_OP_RETURN flags in A */
-#define DUK_BC_RETURN_FLAG_HAVE_RETVAL (1 << 0)
-
-/* DUK_OP_DECLVAR flags in A; bottom bits are reserved for propdesc flags (DUK_PROPDESC_FLAG_XXX) */
-#define DUK_BC_DECLVAR_FLAG_UNDEF_VALUE (1 << 4) /* use 'undefined' for value automatically */
-#define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1 << 5) /* function declaration */
-
-/* misc constants and helper macros */
-#define DUK_BC_REGLIMIT 256 /* if B/C is >= this value, refers to a const */
-#define DUK_BC_ISREG(x) ((x) < DUK_BC_REGLIMIT)
-#define DUK_BC_ISCONST(x) ((x) >= DUK_BC_REGLIMIT)
-#define DUK_BC_LDINT_BIAS (1L << 17)
-#define DUK_BC_LDINTX_SHIFT 18
-#define DUK_BC_JUMP_BIAS (1L << 25)
+/* Misc constants and helper macros. */
+#define DUK_BC_LDINT_BIAS (1L << 15)
+#define DUK_BC_LDINTX_SHIFT 16
+#define DUK_BC_JUMP_BIAS (1L << 23)
#endif /* DUK_JS_BYTECODE_H_INCLUDED */
+/* #include duk_lexer.h */
#line 1 "duk_lexer.h"
/*
* Lexer defines.
*/
-#ifndef DUK_LEXER_H_INCLUDED
+#if !defined(DUK_LEXER_H_INCLUDED)
#define DUK_LEXER_H_INCLUDED
typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct);
@@ -2752,10 +3478,9 @@ typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepo
#define DUK_LEXER_SETPOINT(ctx,pt) duk_lexer_setpoint((ctx), (pt))
-#define DUK_LEXER_GETPOINT(ctx,pt) do { (pt)->offset = (ctx)->window[0].offset; \
- (pt)->line = (ctx)->window[0].line; } while (0)
+#define DUK_LEXER_GETPOINT(ctx,pt) duk_lexer_getpoint((ctx), (pt))
-/* currently 6 characters of lookup are actually needed (duk_lexer.c) */
+/* Currently 6 characters of lookup are actually needed (duk_lexer.c). */
#define DUK_LEXER_WINDOW_SIZE 6
#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
#define DUK_LEXER_BUFFER_SIZE 64
@@ -2857,41 +3582,45 @@ typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepo
#define DUK_TOK_MUL 68
#define DUK_TOK_DIV 69
#define DUK_TOK_MOD 70
-#define DUK_TOK_INCREMENT 71
-#define DUK_TOK_DECREMENT 72
-#define DUK_TOK_ALSHIFT 73 /* named "arithmetic" because result is signed */
-#define DUK_TOK_ARSHIFT 74
-#define DUK_TOK_RSHIFT 75
-#define DUK_TOK_BAND 76
-#define DUK_TOK_BOR 77
-#define DUK_TOK_BXOR 78
-#define DUK_TOK_LNOT 79
-#define DUK_TOK_BNOT 80
-#define DUK_TOK_LAND 81
-#define DUK_TOK_LOR 82
-#define DUK_TOK_QUESTION 83
-#define DUK_TOK_COLON 84
-#define DUK_TOK_EQUALSIGN 85
-#define DUK_TOK_ADD_EQ 86
-#define DUK_TOK_SUB_EQ 87
-#define DUK_TOK_MUL_EQ 88
-#define DUK_TOK_DIV_EQ 89
-#define DUK_TOK_MOD_EQ 90
-#define DUK_TOK_ALSHIFT_EQ 91
-#define DUK_TOK_ARSHIFT_EQ 92
-#define DUK_TOK_RSHIFT_EQ 93
-#define DUK_TOK_BAND_EQ 94
-#define DUK_TOK_BOR_EQ 95
-#define DUK_TOK_BXOR_EQ 96
+#define DUK_TOK_EXP 71
+#define DUK_TOK_INCREMENT 72
+#define DUK_TOK_DECREMENT 73
+#define DUK_TOK_ALSHIFT 74 /* named "arithmetic" because result is signed */
+#define DUK_TOK_ARSHIFT 75
+#define DUK_TOK_RSHIFT 76
+#define DUK_TOK_BAND 77
+#define DUK_TOK_BOR 78
+#define DUK_TOK_BXOR 79
+#define DUK_TOK_LNOT 80
+#define DUK_TOK_BNOT 81
+#define DUK_TOK_LAND 82
+#define DUK_TOK_LOR 83
+#define DUK_TOK_QUESTION 84
+#define DUK_TOK_COLON 85
+#define DUK_TOK_EQUALSIGN 86
+#define DUK_TOK_ADD_EQ 87
+#define DUK_TOK_SUB_EQ 88
+#define DUK_TOK_MUL_EQ 89
+#define DUK_TOK_DIV_EQ 90
+#define DUK_TOK_MOD_EQ 91
+#define DUK_TOK_EXP_EQ 92
+#define DUK_TOK_ALSHIFT_EQ 93
+#define DUK_TOK_ARSHIFT_EQ 94
+#define DUK_TOK_RSHIFT_EQ 95
+#define DUK_TOK_BAND_EQ 96
+#define DUK_TOK_BOR_EQ 97
+#define DUK_TOK_BXOR_EQ 98
/* literals (E5 Section 7.8), except null, true, false, which are treated
* like reserved words (above).
*/
-#define DUK_TOK_NUMBER 97
-#define DUK_TOK_STRING 98
-#define DUK_TOK_REGEXP 99
+#define DUK_TOK_NUMBER 99
+#define DUK_TOK_STRING 100
+#define DUK_TOK_REGEXP 101
-#define DUK_TOK_MAXVAL 99 /* inclusive */
+#define DUK_TOK_MAXVAL 101 /* inclusive */
+
+#define DUK_TOK_INVALID DUK_SMALL_UINT_MAX
/* Convert heap string index to a token (reserved words) */
#define DUK_STRIDX_TO_TOK(x) ((x) - DUK_STRIDX_START_RESERVED + DUK_TOK_START_RESERVED)
@@ -3050,12 +3779,12 @@ typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepo
#define DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD 8
#define DUK_RETOK_ATOM_PERIOD 9
#define DUK_RETOK_ATOM_CHAR 10
-#define DUK_RETOK_ATOM_DIGIT 11
-#define DUK_RETOK_ATOM_NOT_DIGIT 12
-#define DUK_RETOK_ATOM_WHITE 13
-#define DUK_RETOK_ATOM_NOT_WHITE 14
-#define DUK_RETOK_ATOM_WORD_CHAR 15
-#define DUK_RETOK_ATOM_NOT_WORD_CHAR 16
+#define DUK_RETOK_ATOM_DIGIT 11 /* assumptions in regexp compiler */
+#define DUK_RETOK_ATOM_NOT_DIGIT 12 /* -""- */
+#define DUK_RETOK_ATOM_WHITE 13 /* -""- */
+#define DUK_RETOK_ATOM_NOT_WHITE 14 /* -""- */
+#define DUK_RETOK_ATOM_WORD_CHAR 15 /* -""- */
+#define DUK_RETOK_ATOM_NOT_WORD_CHAR 16 /* -""- */
#define DUK_RETOK_ATOM_BACKREFERENCE 17
#define DUK_RETOK_ATOM_START_CAPTURE_GROUP 18
#define DUK_RETOK_ATOM_START_NONCAPTURE_GROUP 19
@@ -3071,8 +3800,8 @@ typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepo
* stale values otherwise.
*/
struct duk_token {
- duk_small_int_t t; /* token type (with reserved word identification) */
- duk_small_int_t t_nores; /* token type (with reserved words as DUK_TOK_IDENTIFER) */
+ duk_small_uint_t t; /* token type (with reserved word identification) */
+ duk_small_uint_t t_nores; /* token type (with reserved words as DUK_TOK_IDENTIFER) */
duk_double_t num; /* numeric value of token */
duk_hstring *str1; /* string 1 of token (borrowed, stored to ctx->slot1_idx) */
duk_hstring *str2; /* string 2 of token (borrowed, stored to ctx->slot2_idx) */
@@ -3087,11 +3816,11 @@ struct duk_token {
/* A regexp token value. */
struct duk_re_token {
- duk_small_int_t t; /* token type */
- duk_small_int_t greedy;
- duk_uint_fast32_t num; /* numeric value (character, count) */
- duk_uint_fast32_t qmin;
- duk_uint_fast32_t qmax;
+ duk_small_uint_t t; /* token type */
+ duk_small_uint_t greedy;
+ duk_uint32_t num; /* numeric value (character, count) */
+ duk_uint32_t qmin;
+ duk_uint32_t qmax;
};
/* A structure for 'snapshotting' a point for rewinding */
@@ -3131,6 +3860,8 @@ struct duk_lexer_ctx {
duk_int_t token_count; /* number of tokens parsed */
duk_int_t token_limit; /* maximum token count before error (sanity backstop) */
+
+ duk_small_uint_t flags; /* lexer flags, use compiler flag defines for now */
};
/*
@@ -3139,6 +3870,7 @@ struct duk_lexer_ctx {
DUK_INTERNAL_DECL void duk_lexer_initctx(duk_lexer_ctx *lex_ctx);
+DUK_INTERNAL_DECL void duk_lexer_getpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt);
DUK_INTERNAL_DECL void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt);
DUK_INTERNAL_DECL
@@ -3146,18 +3878,19 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
duk_token *out_token,
duk_bool_t strict_mode,
duk_bool_t regexp_mode);
-#ifdef DUK_USE_REGEXP_SUPPORT
+#if defined(DUK_USE_REGEXP_SUPPORT)
DUK_INTERNAL_DECL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token);
DUK_INTERNAL_DECL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range_callback gen_range, void *userdata);
#endif /* DUK_USE_REGEXP_SUPPORT */
#endif /* DUK_LEXER_H_INCLUDED */
+/* #include duk_js_compiler.h */
#line 1 "duk_js_compiler.h"
/*
* Ecmascript compiler.
*/
-#ifndef DUK_JS_COMPILER_H_INCLUDED
+#if !defined(DUK_JS_COMPILER_H_INCLUDED)
#define DUK_JS_COMPILER_H_INCLUDED
/* ecmascript compiler limits */
@@ -3180,22 +3913,23 @@ DUK_INTERNAL_DECL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_
#define DUK_IVAL_NONE 0 /* no value */
#define DUK_IVAL_PLAIN 1 /* register, constant, or value */
#define DUK_IVAL_ARITH 2 /* binary arithmetic; DUK_OP_ADD, DUK_OP_EQ, other binary ops */
-#define DUK_IVAL_ARITH_EXTRAOP 3 /* binary arithmetic using extraops; DUK_EXTRAOP_INSTOF etc */
-#define DUK_IVAL_PROP 4 /* property access */
-#define DUK_IVAL_VAR 5 /* variable access */
+#define DUK_IVAL_PROP 3 /* property access */
+#define DUK_IVAL_VAR 4 /* variable access */
#define DUK_ISPEC_NONE 0 /* no value */
#define DUK_ISPEC_VALUE 1 /* value resides in 'valstack_idx' */
#define DUK_ISPEC_REGCONST 2 /* value resides in a register or constant */
-/* bit mask which indicates that a regconst is a constant instead of a register */
-#define DUK_JS_CONST_MARKER 0x80000000UL
+/* Bit mask which indicates that a regconst is a constant instead of a register.
+ * Chosen so that when a regconst is cast to duk_int32_t, all consts are
+ * negative values.
+ */
+#define DUK_REGCONST_CONST_MARKER DUK_INT32_MIN /* = -0x80000000 */
-/* type to represent a reg/const reference during compilation */
-typedef duk_uint32_t duk_regconst_t;
-
-/* type to represent a straight register reference, with <0 indicating none */
-typedef duk_int32_t duk_reg_t;
+/* Type to represent a reg/const reference during compilation, with <0
+ * indicating a constant. Some call sites also use -1 to indicate 'none'.
+ */
+typedef duk_int32_t duk_regconst_t;
typedef struct {
duk_small_uint_t t; /* DUK_ISPEC_XXX */
@@ -3213,7 +3947,7 @@ typedef struct {
/* XXX: can be optimized for smaller footprint esp. on 32-bit environments */
duk_small_uint_t t; /* DUK_IVAL_XXX */
- duk_small_uint_t op; /* bytecode opcode (or extraop) for binary ops */
+ duk_small_uint_t op; /* bytecode opcode for binary ops */
duk_ispec x1;
duk_ispec x2;
} duk_ivalue;
@@ -3235,8 +3969,8 @@ struct duk_compiler_instr {
* Compiler state
*/
-#define DUK_LABEL_FLAG_ALLOW_BREAK (1 << 0)
-#define DUK_LABEL_FLAG_ALLOW_CONTINUE (1 << 1)
+#define DUK_LABEL_FLAG_ALLOW_BREAK (1U << 0)
+#define DUK_LABEL_FLAG_ALLOW_CONTINUE (1U << 1)
#define DUK_DECL_TYPE_VAR 0
#define DUK_DECL_TYPE_FUNC 1
@@ -3259,7 +3993,7 @@ typedef struct {
*/
} duk_labelinfo;
-/* Compiling state of one function, eventually converted to duk_hcompiledfunction */
+/* Compiling state of one function, eventually converted to duk_hcompfunc */
struct duk_compiler_func {
/* These pointers are at the start of the struct so that they pack
* nicely. Mixing pointers and integer values is bad on some
@@ -3283,7 +4017,7 @@ struct duk_compiler_func {
duk_hobject *h_argnames; /* array of formal argument names (-> _Formals) */
duk_hobject *h_varmap; /* variable map for pass 2 (identifier -> register number or null (unmapped)) */
- /* value stack indices for tracking objects */
+ /* Value stack indices for tracking objects. */
/* code_idx: not needed */
duk_idx_t consts_idx;
duk_idx_t funcs_idx;
@@ -3293,52 +4027,54 @@ struct duk_compiler_func {
duk_idx_t argnames_idx;
duk_idx_t varmap_idx;
- /* temp reg handling */
- duk_reg_t temp_first; /* first register that is a temporary (below: variables) */
- duk_reg_t temp_next; /* next temporary register to allocate */
- duk_reg_t temp_max; /* highest value of temp_reg (temp_max - 1 is highest used reg) */
+ /* Temp reg handling. */
+ duk_regconst_t temp_first; /* first register that is a temporary (below: variables) */
+ duk_regconst_t temp_next; /* next temporary register to allocate */
+ duk_regconst_t temp_max; /* highest value of temp_reg (temp_max - 1 is highest used reg) */
- /* shuffle registers if large number of regs/consts */
- duk_reg_t shuffle1;
- duk_reg_t shuffle2;
- duk_reg_t shuffle3;
+ /* Shuffle registers if large number of regs/consts. */
+ duk_regconst_t shuffle1;
+ duk_regconst_t shuffle2;
+ duk_regconst_t shuffle3;
- /* stats for current expression being parsed */
+ /* Stats for current expression being parsed. */
duk_int_t nud_count;
duk_int_t led_count;
duk_int_t paren_level; /* parenthesis count, 0 = top level */
duk_bool_t expr_lhs; /* expression is left-hand-side compatible */
duk_bool_t allow_in; /* current paren level allows 'in' token */
- /* misc */
+ /* Misc. */
duk_int_t stmt_next; /* statement id allocation (running counter) */
duk_int_t label_next; /* label id allocation (running counter) */
duk_int_t catch_depth; /* catch stack depth */
duk_int_t with_depth; /* with stack depth (affects identifier lookups) */
duk_int_t fnum_next; /* inner function numbering */
duk_int_t num_formals; /* number of formal arguments */
- duk_reg_t reg_stmt_value; /* register for writing value of 'non-empty' statements (global or eval code), -1 is marker */
+ duk_regconst_t reg_stmt_value; /* register for writing value of 'non-empty' statements (global or eval code), -1 is marker */
#if defined(DUK_USE_DEBUGGER_SUPPORT)
- duk_int_t min_line; /* XXX: typing (duk_hcompiledfunction has duk_uint32_t) */
+ duk_int_t min_line; /* XXX: typing (duk_hcompfunc has duk_uint32_t) */
duk_int_t max_line;
#endif
- /* status booleans */
- duk_bool_t is_function; /* is an actual function (not global/eval code) */
- duk_bool_t is_eval; /* is eval code */
- duk_bool_t is_global; /* is global code */
- duk_bool_t is_setget; /* is a setter/getter */
- duk_bool_t is_decl; /* is a function declaration (as opposed to function expression) */
- duk_bool_t is_strict; /* function is strict */
- duk_bool_t is_notail; /* function must not be tail called */
- duk_bool_t in_directive_prologue; /* parsing in "directive prologue", recognize directives */
- duk_bool_t in_scanning; /* parsing in "scanning" phase (first pass) */
- duk_bool_t may_direct_eval; /* function may call direct eval */
- duk_bool_t id_access_arguments; /* function refers to 'arguments' identifier */
- duk_bool_t id_access_slow; /* function makes one or more slow path accesses */
- duk_bool_t is_arguments_shadowed; /* argument/function declaration shadows 'arguments' */
- duk_bool_t needs_shuffle; /* function needs shuffle registers */
- duk_bool_t reject_regexp_in_adv; /* reject RegExp literal on next advance() call; needed for handling IdentifierName productions */
+ /* Status booleans. */
+ duk_uint8_t is_function; /* is an actual function (not global/eval code) */
+ duk_uint8_t is_eval; /* is eval code */
+ duk_uint8_t is_global; /* is global code */
+ duk_uint8_t is_namebinding; /* needs a name binding */
+ duk_uint8_t is_constructable; /* result is constructable */
+ duk_uint8_t is_setget; /* is a setter/getter */
+ duk_uint8_t is_strict; /* function is strict */
+ duk_uint8_t is_notail; /* function must not be tail called */
+ duk_uint8_t in_directive_prologue; /* parsing in "directive prologue", recognize directives */
+ duk_uint8_t in_scanning; /* parsing in "scanning" phase (first pass) */
+ duk_uint8_t may_direct_eval; /* function may call direct eval */
+ duk_uint8_t id_access_arguments; /* function refers to 'arguments' identifier */
+ duk_uint8_t id_access_slow; /* function makes one or more slow path accesses that won't match own static variables */
+ duk_uint8_t id_access_slow_own; /* function makes one or more slow path accesses that may match own static variables */
+ duk_uint8_t is_arguments_shadowed; /* argument/function declaration shadows 'arguments' */
+ duk_uint8_t needs_shuffle; /* function needs shuffle registers */
+ duk_uint8_t reject_regexp_in_adv; /* reject RegExp literal on next advance() call; needed for handling IdentifierName productions */
};
struct duk_compiler_ctx {
@@ -3373,19 +4109,16 @@ struct duk_compiler_ctx {
* Prototypes
*/
-#define DUK_JS_COMPILE_FLAG_EVAL (1 << 0) /* source is eval code (not global) */
-#define DUK_JS_COMPILE_FLAG_STRICT (1 << 1) /* strict outer context */
-#define DUK_JS_COMPILE_FLAG_FUNCEXPR (1 << 2) /* source is a function expression (used for Function constructor) */
-
DUK_INTERNAL_DECL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer, duk_size_t src_length, duk_small_uint_t flags);
#endif /* DUK_JS_COMPILER_H_INCLUDED */
+/* #include duk_regexp.h */
#line 1 "duk_regexp.h"
/*
* Regular expression structs, constants, and bytecode defines.
*/
-#ifndef DUK_REGEXP_H_INCLUDED
+#if !defined(DUK_REGEXP_H_INCLUDED)
#define DUK_REGEXP_H_INCLUDED
/* maximum bytecode copies for {n,m} quantifiers */
@@ -3419,9 +4152,9 @@ DUK_INTERNAL_DECL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_b
#define DUK_REOP_ASSERT_NOT_WORD_BOUNDARY 19
/* flags */
-#define DUK_RE_FLAG_GLOBAL (1 << 0)
-#define DUK_RE_FLAG_IGNORE_CASE (1 << 1)
-#define DUK_RE_FLAG_MULTILINE (1 << 2)
+#define DUK_RE_FLAG_GLOBAL (1U << 0)
+#define DUK_RE_FLAG_IGNORE_CASE (1U << 1)
+#define DUK_RE_FLAG_MULTILINE (1U << 2)
struct duk_re_matcher_ctx {
duk_hthread *thr;
@@ -3457,19 +4190,22 @@ struct duk_re_compiler_ctx {
* Prototypes
*/
+#if defined(DUK_USE_REGEXP_SUPPORT)
DUK_INTERNAL_DECL void duk_regexp_compile(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_regexp_create_instance(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_regexp_match(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_regexp_match_force_global(duk_hthread *thr); /* hacky helper for String.prototype.split() */
+#endif
#endif /* DUK_REGEXP_H_INCLUDED */
+/* #include duk_heaphdr.h */
#line 1 "duk_heaphdr.h"
/*
* Heap header definition and assorted macros, including ref counting.
* Access all fields through the accessor macros.
*/
-#ifndef DUK_HEAPHDR_H_INCLUDED
+#if !defined(DUK_HEAPHDR_H_INCLUDED)
#define DUK_HEAPHDR_H_INCLUDED
/*
@@ -3477,30 +4213,45 @@ DUK_INTERNAL_DECL void duk_regexp_match_force_global(duk_hthread *thr); /* hack
*
* All heap objects share the same flags and refcount fields. Objects other
* than strings also need to have a single or double linked list pointers
- * for insertion into the "heap allocated" list. Strings are held in the
- * heap-wide string table so they don't need link pointers.
+ * for insertion into the "heap allocated" list. Strings have single linked
+ * list pointers for string table chaining.
*
* Technically, 'h_refcount' must be wide enough to guarantee that it cannot
- * wrap (otherwise objects might be freed incorrectly after wrapping). This
- * means essentially that the refcount field must be as wide as data pointers.
- * On 64-bit platforms this means that the refcount needs to be 64 bits even
- * if an 'int' is 32 bits. This is a bit unfortunate, and compromising on
- * this might be reasonable in the future.
+ * wrap; otherwise objects might be freed incorrectly after wrapping. The
+ * default refcount field is 32 bits even on 64-bit systems: while that's in
+ * theory incorrect, the Duktape heap needs to be larger than 64GB for the
+ * count to actually wrap (assuming 16-byte duk_tvals). This is very unlikely
+ * to ever be an issue, but if it is, disabling DUK_USE_REFCOUNT32 causes
+ * Duktape to use size_t for refcounts which should always be safe.
*
* Heap header size on 32-bit platforms: 8 bytes without reference counting,
* 16 bytes with reference counting.
+ *
+ * Note that 'raw' macros such as DUK_HEAPHDR_GET_REFCOUNT() are not
+ * defined without DUK_USE_REFERENCE_COUNTING, so caller must #if defined()
+ * around them.
*/
+/* XXX: macro for shared header fields (avoids some padding issues) */
+
struct duk_heaphdr {
duk_uint32_t h_flags;
#if defined(DUK_USE_REFERENCE_COUNTING)
+#if defined(DUK_USE_ASSERTIONS)
+ /* When assertions enabled, used by mark-and-sweep for refcount
+ * validation. Largest reasonable type; also detects overflows.
+ */
+ duk_size_t h_assert_refcount;
+#endif
#if defined(DUK_USE_REFCOUNT16)
- duk_uint16_t h_refcount16;
+ duk_uint16_t h_refcount;
+#elif defined(DUK_USE_REFCOUNT32)
+ duk_uint32_t h_refcount;
#else
duk_size_t h_refcount;
#endif
-#endif
+#endif /* DUK_USE_REFERENCE_COUNTING */
#if defined(DUK_USE_HEAPPTR16)
duk_uint16_t h_next16;
@@ -3540,15 +4291,26 @@ struct duk_heaphdr_string {
duk_uint32_t h_flags;
#if defined(DUK_USE_REFERENCE_COUNTING)
+#if defined(DUK_USE_ASSERTIONS)
+ /* When assertions enabled, used by mark-and-sweep for refcount
+ * validation. Largest reasonable type; also detects overflows.
+ */
+ duk_size_t h_assert_refcount;
+#endif
#if defined(DUK_USE_REFCOUNT16)
- duk_uint16_t h_refcount16;
+ duk_uint16_t h_refcount;
duk_uint16_t h_strextra16; /* round out to 8 bytes */
+#elif defined(DUK_USE_REFCOUNT32)
+ duk_uint32_t h_refcount;
#else
duk_size_t h_refcount;
#endif
#else
duk_uint16_t h_strextra16;
-#endif
+#endif /* DUK_USE_REFERENCE_COUNTING */
+
+ duk_hstring *h_next;
+ /* No 'h_prev' pointer for strings. */
};
#define DUK_HEAPHDR_FLAGS_TYPE_MASK 0x00000003UL
@@ -3569,11 +4331,11 @@ struct duk_heaphdr_string {
#define DUK_HEAPHDR_FLAG_FINALIZED DUK_HEAPHDR_HEAP_FLAG(3) /* mark-and-sweep: finalized (on previous pass) */
#define DUK_HEAPHDR_FLAG_READONLY DUK_HEAPHDR_HEAP_FLAG(4) /* read-only object, in code section */
-#define DUK_HTYPE_MIN 1
-#define DUK_HTYPE_STRING 1
-#define DUK_HTYPE_OBJECT 2
-#define DUK_HTYPE_BUFFER 3
-#define DUK_HTYPE_MAX 3
+#define DUK_HTYPE_MIN 0
+#define DUK_HTYPE_STRING 0
+#define DUK_HTYPE_OBJECT 1
+#define DUK_HTYPE_BUFFER 2
+#define DUK_HTYPE_MAX 2
#if defined(DUK_USE_HEAPPTR16)
#define DUK_HEAPHDR_GET_NEXT(heap,h) \
@@ -3604,23 +4366,15 @@ struct duk_heaphdr_string {
#endif
#if defined(DUK_USE_REFERENCE_COUNTING)
-#if defined(DUK_USE_REFCOUNT16)
-#define DUK_HEAPHDR_GET_REFCOUNT(h) ((h)->h_refcount16)
-#define DUK_HEAPHDR_SET_REFCOUNT(h,val) do { \
- (h)->h_refcount16 = (val); \
- } while (0)
-#define DUK_HEAPHDR_PREINC_REFCOUNT(h) (++(h)->h_refcount16) /* result: updated refcount */
-#define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount16) /* result: updated refcount */
-#else
#define DUK_HEAPHDR_GET_REFCOUNT(h) ((h)->h_refcount)
#define DUK_HEAPHDR_SET_REFCOUNT(h,val) do { \
(h)->h_refcount = (val); \
+ DUK_ASSERT((h)->h_refcount == (val)); /* No truncation. */ \
} while (0)
#define DUK_HEAPHDR_PREINC_REFCOUNT(h) (++(h)->h_refcount) /* result: updated refcount */
#define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount) /* result: updated refcount */
-#endif
#else
-/* refcount macros not defined without refcounting, caller must #ifdef now */
+/* refcount macros not defined without refcounting, caller must #if defined() now */
#endif /* DUK_USE_REFERENCE_COUNTING */
/*
@@ -3629,19 +4383,22 @@ struct duk_heaphdr_string {
*/
#define DUK_HEAPHDR_GET_FLAGS_RAW(h) ((h)->h_flags)
-
+#define DUK_HEAPHDR_SET_FLAGS_RAW(h,val) do { \
+ (h)->h_flags = (val); } \
+ }
#define DUK_HEAPHDR_GET_FLAGS(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK)
#define DUK_HEAPHDR_SET_FLAGS(h,val) do { \
(h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) | (val); \
} while (0)
-
#define DUK_HEAPHDR_GET_TYPE(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_TYPE_MASK)
#define DUK_HEAPHDR_SET_TYPE(h,val) do { \
(h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_TYPE_MASK)) | (val); \
} while (0)
+/* Comparison for type >= DUK_HTYPE_MIN skipped; because DUK_HTYPE_MIN is zero
+ * and the comparison is unsigned, it's always true and generates warnings.
+ */
#define DUK_HEAPHDR_HTYPE_VALID(h) ( \
- DUK_HEAPHDR_GET_TYPE((h)) >= DUK_HTYPE_MIN && \
DUK_HEAPHDR_GET_TYPE((h)) <= DUK_HTYPE_MAX \
)
@@ -3703,7 +4460,23 @@ struct duk_heaphdr_string {
} while (0)
#endif
-#define DUK_HEAPHDR_STRING_INIT_NULLS(h) /* currently nop */
+#define DUK_HEAPHDR_STRING_INIT_NULLS(h) do { \
+ (h)->h_next = NULL; \
+ } while (0)
+
+/*
+ * Type tests
+ */
+
+/* Take advantage of the fact that for DUK_HTYPE_xxx numbers the lowest bit
+ * is only set for DUK_HTYPE_OBJECT (= 1).
+ */
+#if 0
+#define DUK_HEAPHDR_IS_OBJECT(h) (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_OBJECT)
+#endif
+#define DUK_HEAPHDR_IS_OBJECT(h) ((h)->h_flags & 0x01UL)
+#define DUK_HEAPHDR_IS_STRING(h) (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_STRING)
+#define DUK_HEAPHDR_IS_BUFFER(h) (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_BUFFER)
/*
* Assert helpers
@@ -3726,17 +4499,24 @@ struct duk_heaphdr_string {
#define DUK_ASSERT_HEAPHDR_LINKS(heap,h) do {} while (0)
#endif
+#define DUK_ASSERT_HEAPHDR_VALID(h) do { \
+ DUK_ASSERT((h) != NULL); \
+ DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID((h))); \
+ } while (0)
+
+#endif /* DUK_HEAPHDR_H_INCLUDED */
+/* #include duk_refcount.h */
+#line 1 "duk_refcount.h"
/*
* Reference counting helper macros. The macros take a thread argument
* and must thus always be executed in a specific thread context. The
- * thread argument is needed for features like finalization. Currently
- * it is not required for INCREF, but it is included just in case.
- *
- * Note that 'raw' macros such as DUK_HEAPHDR_GET_REFCOUNT() are not
- * defined without DUK_USE_REFERENCE_COUNTING, so caller must #ifdef
- * around them.
+ * thread argument is not really needed anymore: DECREF can operate with
+ * a heap pointer only, and INCREF needs neither.
*/
+#if !defined(DUK_REFCOUNT_H_INCLUDED)
+#define DUK_REFCOUNT_H_INCLUDED
+
#if defined(DUK_USE_REFERENCE_COUNTING)
#if defined(DUK_USE_ROM_OBJECTS)
@@ -3766,6 +4546,7 @@ struct duk_heaphdr_string {
DUK_ASSERT(duk__h != NULL); \
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \
+ DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) != 0); /* No wrapping. */ \
} \
} while (0)
#define DUK_TVAL_DECREF_FAST(thr,tv) do { \
@@ -3781,87 +4562,208 @@ struct duk_heaphdr_string {
} \
} \
} while (0)
+#define DUK_TVAL_DECREF_NORZ_FAST(thr,tv) do { \
+ duk_tval *duk__tv = (tv); \
+ DUK_ASSERT(duk__tv != NULL); \
+ if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \
+ duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \
+ DUK_ASSERT(duk__h != NULL); \
+ DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
+ DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
+ if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
+ duk_heaphdr_refzero_norz((thr), duk__h); \
+ } \
+ } \
+ } while (0)
#define DUK_HEAPHDR_INCREF_FAST(thr,h) do { \
duk_heaphdr *duk__h = (duk_heaphdr *) (h); \
DUK_ASSERT(duk__h != NULL); \
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \
DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \
+ DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) != 0); /* No wrapping. */ \
} \
} while (0)
-#define DUK_HEAPHDR_DECREF_FAST(thr,h) do { \
+#define DUK_HEAPHDR_DECREF_FAST_RAW(thr,h,rzcall,rzcast) do { \
duk_heaphdr *duk__h = (duk_heaphdr *) (h); \
DUK_ASSERT(duk__h != NULL); \
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \
if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
- duk_heaphdr_refzero((thr), duk__h); \
+ (rzcall)((thr), (rzcast) duk__h); \
} \
} \
} while (0)
+#define DUK_HEAPHDR_DECREF_FAST(thr,h) \
+ DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *)
+#define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) \
+ DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *)
/* Slow variants, call to a helper to reduce code size.
* Can be used explicitly when size is always more important than speed.
*/
-#define DUK_TVAL_INCREF_SLOW(thr,tv) do { \
- duk_tval_incref((tv)); \
- } while (0)
-#define DUK_TVAL_DECREF_SLOW(thr,tv) do { \
- duk_tval_decref((thr), (tv)); \
- } while (0)
-#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do { \
- duk_heaphdr_incref((duk_heaphdr *) (h)); \
- } while (0)
-#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do { \
- duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); \
- } while (0)
+#define DUK_TVAL_INCREF_SLOW(thr,tv) do { duk_tval_incref((tv)); } while (0)
+#define DUK_TVAL_DECREF_SLOW(thr,tv) do { duk_tval_decref((thr), (tv)); } while (0)
+#define DUK_TVAL_DECREF_NORZ_SLOW(thr,tv) do { duk_tval_decref_norz((thr), (tv)); } while (0)
+#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0)
+#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0)
+#define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0)
+#define DUK_HSTRING_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0)
+#define DUK_HSTRING_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0)
+#define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0)
+#define DUK_HBUFFER_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0)
+#define DUK_HBUFFER_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0)
+#define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0)
+#define DUK_HOBJECT_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0)
+#define DUK_HOBJECT_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0)
+#define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0)
/* Default variants. Selection depends on speed/size preference.
* Concretely: with gcc 4.8.1 -Os x64 the difference in final binary
* is about +1kB for _FAST variants.
*/
#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
+/* XXX: It would be nice to specialize for specific duk_hobject subtypes
+ * but current refzero queue handling prevents that.
+ */
#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_FAST((thr),(tv))
#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_FAST((thr),(tv))
+#define DUK_TVAL_DECREF_NORZ(thr,tv) DUK_TVAL_DECREF_NORZ_FAST((thr),(tv))
#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_FAST((thr),(h))
-#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST((thr),(h))
+#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *)
+#define DUK_HEAPHDR_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *)
+#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
+#define DUK_HSTRING_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *)
+#define DUK_HSTRING_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *) /* no 'norz' variant */
+#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
+#define DUK_HOBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
+#define DUK_HOBJECT_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
+#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
+#define DUK_HBUFFER_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *)
+#define DUK_HBUFFER_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *) /* no 'norz' variant */
+#define DUK_HCOMPFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
+#define DUK_HCOMPFUNC_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
+#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
+#define DUK_HNATFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
+#define DUK_HNATFUNC_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
+#define DUK_HNATFUNC_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
+#define DUK_HBUFOBJ_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
+#define DUK_HBUFOBJ_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
+#define DUK_HBUFOBJ_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
+#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
+#define DUK_HTHREAD_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
+#define DUK_HTHREAD_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
#else
#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_SLOW((thr),(tv))
#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_SLOW((thr),(tv))
+#define DUK_TVAL_DECREF_NORZ(thr,tv) DUK_TVAL_DECREF_NORZ_SLOW((thr),(tv))
#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_SLOW((thr),(h))
#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_SLOW((thr),(h))
+#define DUK_HEAPHDR_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_NORZ_SLOW((thr),(h))
+#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
+#define DUK_HSTRING_DECREF(thr,h) DUK_HSTRING_DECREF_SLOW((thr),(h))
+#define DUK_HSTRING_DECREF_NORZ(thr,h) DUK_HSTRING_DECREF_NORZ_SLOW((thr),(h))
+#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
+#define DUK_HOBJECT_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(h))
+#define DUK_HOBJECT_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(h))
+#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
+#define DUK_HBUFFER_DECREF(thr,h) DUK_HBUFFER_DECREF_SLOW((thr),(h))
+#define DUK_HBUFFER_DECREF_NORZ(thr,h) DUK_HBUFFER_DECREF_NORZ_SLOW((thr),(h))
+#define DUK_HCOMPFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
+#define DUK_HCOMPFUNC_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj)
+#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj)
+#define DUK_HNATFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
+#define DUK_HNATFUNC_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj)
+#define DUK_HNATFUNC_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj)
+#define DUK_HBUFOBJ_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
+#define DUK_HBUFOBJ_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj)
+#define DUK_HBUFOB_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj)
+#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
+#define DUK_HTHREAD_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj)
+#define DUK_HTHREAD_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj)
#endif
-/* Casting convenience. */
-#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
-#define DUK_HSTRING_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
-#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
-#define DUK_HOBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
-#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
-#define DUK_HBUFFER_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
-#define DUK_HCOMPILEDFUNCTION_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
-#define DUK_HCOMPILEDFUNCTION_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
-#define DUK_HNATIVEFUNCTION_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
-#define DUK_HNATIVEFUNCTION_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
-#define DUK_HBUFFEROBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
-#define DUK_HBUFFEROBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
-#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
-#define DUK_HTHREAD_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
-
/* Convenience for some situations; the above macros don't allow NULLs
- * for performance reasons.
+ * for performance reasons. Macros cover only actually needed cases.
*/
-#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do { \
+#define DUK_HEAPHDR_INCREF_ALLOWNULL(thr,h) do { \
if ((h) != NULL) { \
DUK_HEAPHDR_INCREF((thr), (duk_heaphdr *) (h)); \
} \
} while (0)
-#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do { \
+#define DUK_HEAPHDR_DECREF_ALLOWNULL(thr,h) do { \
if ((h) != NULL) { \
DUK_HEAPHDR_DECREF((thr), (duk_heaphdr *) (h)); \
} \
} while (0)
+#define DUK_HEAPHDR_DECREF_NORZ_ALLOWNULL(thr,h) do { \
+ if ((h) != NULL) { \
+ DUK_HEAPHDR_DECREF_NORZ((thr), (duk_heaphdr *) (h)); \
+ } \
+ } while (0)
+#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do { \
+ if ((h) != NULL) { \
+ DUK_HOBJECT_INCREF((thr), (h)); \
+ } \
+ } while (0)
+#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do { \
+ if ((h) != NULL) { \
+ DUK_HOBJECT_DECREF((thr), (h)); \
+ } \
+ } while (0)
+#define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do { \
+ if ((h) != NULL) { \
+ DUK_HOBJECT_DECREF_NORZ((thr), (h)); \
+ } \
+ } while (0)
+#define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do { \
+ if ((h) != NULL) { \
+ DUK_HBUFFER_INCREF((thr), (h)); \
+ } \
+ } while (0)
+#define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do { \
+ if ((h) != NULL) { \
+ DUK_HBUFFER_DECREF((thr), (h)); \
+ } \
+ } while (0)
+#define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do { \
+ if ((h) != NULL) { \
+ DUK_HBUFFER_DECREF_NORZ((thr), (h)); \
+ } \
+ } while (0)
+#define DUK_HTHREAD_INCREF_ALLOWNULL(thr,h) do { \
+ if ((h) != NULL) { \
+ DUK_HTHREAD_INCREF((thr), (h)); \
+ } \
+ } while (0)
+#define DUK_HTHREAD_DECREF_ALLOWNULL(thr,h) do { \
+ if ((h) != NULL) { \
+ DUK_HTHREAD_DECREF((thr), (h)); \
+ } \
+ } while (0)
+#define DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr,h) do { \
+ if ((h) != NULL) { \
+ DUK_HTHREAD_DECREF_NORZ((thr), (h)); \
+ } \
+ } while (0)
+
+/* Called after one or more DECREF NORZ calls to handle pending side effects.
+ * At present DECREF NORZ does freeing inline but doesn't execute finalizers,
+ * so these macros check for pending finalizers and execute them. The FAST
+ * variant is performance critical.
+ */
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+#define DUK_REFZERO_CHECK_FAST(thr) do { \
+ duk_refzero_check_fast((thr)); \
+ } while (0)
+#define DUK_REFZERO_CHECK_SLOW(thr) do { \
+ duk_refzero_check_slow((thr)); \
+ } while (0)
+#else /* DUK_USE_FINALIZER_SUPPORT */
+#define DUK_REFZERO_CHECK_FAST(thr) do { } while (0)
+#define DUK_REFZERO_CHECK_SLOW(thr) do { } while (0)
+#endif /* DUK_USE_FINALIZER_SUPPORT */
/*
* Macros to set a duk_tval and update refcount of the target (decref the
@@ -3876,6 +4778,13 @@ struct duk_heaphdr_string {
DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
} while (0)
+#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0(thr,tvptr_dst) do { \
+ duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
+ DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
+ DUK_TVAL_SET_UNDEFINED(tv__dst); \
+ DUK_TVAL_DECREF_NORZ((thr), &tv__tmp); \
+ } while (0)
+
#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \
duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
@@ -3906,7 +4815,7 @@ struct duk_heaphdr_string {
#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_NUMBER_CHKFAST(tv__dst, (newval)); \
+ DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \
DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
} while (0)
#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
@@ -3922,22 +4831,22 @@ struct duk_heaphdr_string {
DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
} while (0)
#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_SET_FASTINT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
+#define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_FASTINT(tv__dst, (newval)); \
+ DUK_TVAL_SET_I48(tv__dst, (newval)); \
DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
} while (0)
-#define DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
+#define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_FASTINT_I32(tv__dst, (newval)); \
+ DUK_TVAL_SET_I32(tv__dst, (newval)); \
DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
} while (0)
-#define DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
+#define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_FASTINT_U32(tv__dst, (newval)); \
+ DUK_TVAL_SET_U32(tv__dst, (newval)); \
DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
} while (0)
#else
@@ -4019,6 +4928,7 @@ struct duk_heaphdr_string {
/* XXX: no optimized variants yet */
#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
+#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0
#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0
#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0
#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0
@@ -4027,14 +4937,15 @@ struct duk_heaphdr_string {
#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0
#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0
#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_FASTINT_UPDREF_ALT0
-#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0
-#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0
+#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_I48_UPDREF_ALT0
+#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_I32_UPDREF_ALT0
+#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_U32_UPDREF_ALT0
#else
-#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast int-to-double */
-#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
-#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
+#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast int-to-double */
+#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
+#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
#endif /* DUK_USE_FASTINT */
+#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_I48_UPDREF /* convenience */
#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0
#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0
#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0
@@ -4060,32 +4971,71 @@ struct duk_heaphdr_string {
#define DUK_TVAL_INCREF_FAST(thr,v) do {} while (0) /* nop */
#define DUK_TVAL_DECREF_FAST(thr,v) do {} while (0) /* nop */
+#define DUK_TVAL_DECREF_NORZ_FAST(thr,v) do {} while (0) /* nop */
#define DUK_TVAL_INCREF_SLOW(thr,v) do {} while (0) /* nop */
#define DUK_TVAL_DECREF_SLOW(thr,v) do {} while (0) /* nop */
+#define DUK_TVAL_DECREF_NORZ_SLOW(thr,v) do {} while (0) /* nop */
#define DUK_TVAL_INCREF(thr,v) do {} while (0) /* nop */
#define DUK_TVAL_DECREF(thr,v) do {} while (0) /* nop */
+#define DUK_TVAL_DECREF_NORZ(thr,v) do {} while (0) /* nop */
#define DUK_HEAPHDR_INCREF_FAST(thr,h) do {} while (0) /* nop */
#define DUK_HEAPHDR_DECREF_FAST(thr,h) do {} while (0) /* nop */
+#define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */
#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do {} while (0) /* nop */
#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do {} while (0) /* nop */
+#define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */
#define DUK_HEAPHDR_INCREF(thr,h) do {} while (0) /* nop */
#define DUK_HEAPHDR_DECREF(thr,h) do {} while (0) /* nop */
+#define DUK_HEAPHDR_DECREF_NORZ(thr,h) do {} while (0) /* nop */
+#define DUK_HSTRING_INCREF_FAST(thr,h) do {} while (0) /* nop */
+#define DUK_HSTRING_DECREF_FAST(thr,h) do {} while (0) /* nop */
+#define DUK_HSTRING_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */
+#define DUK_HSTRING_INCREF_SLOW(thr,h) do {} while (0) /* nop */
+#define DUK_HSTRING_DECREF_SLOW(thr,h) do {} while (0) /* nop */
+#define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */
#define DUK_HSTRING_INCREF(thr,h) do {} while (0) /* nop */
#define DUK_HSTRING_DECREF(thr,h) do {} while (0) /* nop */
+#define DUK_HSTRING_DECREF_NORZ(thr,h) do {} while (0) /* nop */
+#define DUK_HOBJECT_INCREF_FAST(thr,h) do {} while (0) /* nop */
+#define DUK_HOBJECT_DECREF_FAST(thr,h) do {} while (0) /* nop */
+#define DUK_HOBJECT_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */
+#define DUK_HOBJECT_INCREF_SLOW(thr,h) do {} while (0) /* nop */
+#define DUK_HOBJECT_DECREF_SLOW(thr,h) do {} while (0) /* nop */
+#define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */
#define DUK_HOBJECT_INCREF(thr,h) do {} while (0) /* nop */
#define DUK_HOBJECT_DECREF(thr,h) do {} while (0) /* nop */
+#define DUK_HOBJECT_DECREF_NORZ(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFFER_INCREF_FAST(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFFER_DECREF_FAST(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFFER_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFFER_INCREF_SLOW(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFFER_DECREF_SLOW(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */
#define DUK_HBUFFER_INCREF(thr,h) do {} while (0) /* nop */
#define DUK_HBUFFER_DECREF(thr,h) do {} while (0) /* nop */
-#define DUK_HCOMPILEDFUNCTION_INCREF(thr,h) do {} while (0) /* nop */
-#define DUK_HCOMPILEDFUNCTION_DECREF(thr,h) do {} while (0) /* nop */
-#define DUK_HNATIVEFUNCTION_INCREF(thr,h) do {} while (0) /* nop */
-#define DUK_HNATIVEFUNCTION_DECREF(thr,h) do {} while (0) /* nop */
-#define DUK_HBUFFEROBJECT_INCREF(thr,h) do {} while (0) /* nop */
-#define DUK_HBUFFEROBJECT_DECREF(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFFER_DECREF_NORZ(thr,h) do {} while (0) /* nop */
+
+#define DUK_HCOMPFUNC_INCREF(thr,h) do {} while (0) /* nop */
+#define DUK_HCOMPFUNC_DECREF(thr,h) do {} while (0) /* nop */
+#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) do {} while (0) /* nop */
+#define DUK_HNATFUNC_INCREF(thr,h) do {} while (0) /* nop */
+#define DUK_HNATFUNC_DECREF(thr,h) do {} while (0) /* nop */
+#define DUK_HNATFUNC_DECREF_NORZ(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFOBJ_INCREF(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFOBJ_DECREF(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFOBJ_DECREF_NORZ(thr,h) do {} while (0) /* nop */
#define DUK_HTHREAD_INCREF(thr,h) do {} while (0) /* nop */
#define DUK_HTHREAD_DECREF(thr,h) do {} while (0) /* nop */
+#define DUK_HTHREAD_DECREF_NORZ(thr,h) do {} while (0) /* nop */
#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
+#define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
+#define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do {} while (0) /* nop */
+
+#define DUK_REFZERO_CHECK_FAST(thr) do {} while (0) /* nop */
+#define DUK_REFZERO_CHECK_SLOW(thr) do {} while (0) /* nop */
#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \
duk_tval *tv__dst; tv__dst = (tvptr_dst); \
@@ -4118,7 +5068,7 @@ struct duk_heaphdr_string {
} while (0)
#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_NUMBER_CHKFAST(tv__dst, (newval)); \
+ DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \
DUK_UNREF((thr)); \
} while (0)
#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
@@ -4132,19 +5082,19 @@ struct duk_heaphdr_string {
DUK_UNREF((thr)); \
} while (0)
#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_SET_FASTINT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
+#define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_FASTINT(tv__dst, (newval)); \
+ DUK_TVAL_SET_I48(tv__dst, (newval)); \
DUK_UNREF((thr)); \
} while (0)
-#define DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
+#define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_FASTINT_I32(tv__dst, (newval)); \
+ DUK_TVAL_SET_I32(tv__dst, (newval)); \
DUK_UNREF((thr)); \
} while (0)
-#define DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
+#define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_FASTINT_U32(tv__dst, (newval)); \
+ DUK_TVAL_SET_U32(tv__dst, (newval)); \
DUK_UNREF((thr)); \
} while (0)
#else
@@ -4190,6 +5140,7 @@ struct duk_heaphdr_string {
} while (0)
#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
+#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0
#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0
#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0
@@ -4198,14 +5149,15 @@ struct duk_heaphdr_string {
#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0
#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0
#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_FASTINT_UPDREF_ALT0
-#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0
-#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0
+#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_I48_UPDREF_ALT0
+#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_I32_UPDREF_ALT0
+#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_U32_UPDREF_ALT0
#else
-#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast-int-to-double */
-#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
-#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
+#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast-int-to-double */
+#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
+#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
#endif /* DUK_USE_FASTINT */
+#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_I48_UPDREF /* convenience */
#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0
#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0
#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0
@@ -4218,16 +5170,80 @@ struct duk_heaphdr_string {
#endif /* DUK_USE_REFERENCE_COUNTING */
-#endif /* DUK_HEAPHDR_H_INCLUDED */
+/*
+ * Some convenience macros that don't have optimized implementations now.
+ */
+
+#define DUK_TVAL_SET_TVAL_UPDREF_NORZ(thr,tv_dst,tv_src) do { \
+ duk_hthread *duk__thr = (thr); \
+ duk_tval *duk__dst = (tv_dst); \
+ duk_tval *duk__src = (tv_src); \
+ DUK_UNREF(duk__thr); \
+ DUK_TVAL_DECREF_NORZ(thr, duk__dst); \
+ DUK_TVAL_SET_TVAL(duk__dst, duk__src); \
+ DUK_TVAL_INCREF(thr, duk__dst); \
+ } while (0)
+
+#define DUK_TVAL_SET_U32_UPDREF_NORZ(thr,tv_dst,val) do { \
+ duk_hthread *duk__thr = (thr); \
+ duk_tval *duk__dst = (tv_dst); \
+ duk_uint32_t duk__val = (duk_uint32_t) (val); \
+ DUK_UNREF(duk__thr); \
+ DUK_TVAL_DECREF_NORZ(thr, duk__dst); \
+ DUK_TVAL_SET_U32(duk__dst, duk__val); \
+ } while (0)
+
+/*
+ * Prototypes
+ */
+
+#if defined(DUK_USE_REFERENCE_COUNTING)
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+DUK_INTERNAL_DECL void duk_refzero_check_slow(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_refzero_check_fast(duk_hthread *thr);
+#endif
+DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize_norz(duk_heap *heap, duk_heaphdr *hdr);
+DUK_INTERNAL_DECL void duk_hobject_refcount_finalize_norz(duk_heap *heap, duk_hobject *h);
+#if 0 /* Not needed: fast path handles inline; slow path uses duk_heaphdr_decref() which is needed anyway. */
+DUK_INTERNAL_DECL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h);
+DUK_INTERNAL_DECL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h);
+DUK_INTERNAL_DECL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h);
+DUK_INTERNAL_DECL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h);
+DUK_INTERNAL_DECL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h);
+DUK_INTERNAL_DECL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h);
+#endif
+DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h);
+DUK_INTERNAL_DECL void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h);
+#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
+DUK_INTERNAL_DECL void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h); /* no 'norz' variant */
+DUK_INTERNAL_DECL void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h); /* no 'norz' variant */
+DUK_INTERNAL_DECL void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h);
+DUK_INTERNAL_DECL void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h);
+#else
+DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv);
+DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv);
+DUK_INTERNAL_DECL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv);
+DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h);
+DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h);
+DUK_INTERNAL_DECL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h);
+#endif
+#else /* DUK_USE_REFERENCE_COUNTING */
+/* no refcounting */
+#endif /* DUK_USE_REFERENCE_COUNTING */
+
+#endif /* DUK_REFCOUNT_H_INCLUDED */
+/* #include duk_api_internal.h */
#line 1 "duk_api_internal.h"
/*
* Internal API calls which have (stack and other) semantics similar
* to the public API.
*/
-#ifndef DUK_API_INTERNAL_H_INCLUDED
+#if !defined(DUK_API_INTERNAL_H_INCLUDED)
#define DUK_API_INTERNAL_H_INCLUDED
+#define DUK_INTERNAL_SYMBOL(x) ("\x82" x)
+
/* duk_push_sprintf constants */
#define DUK_PUSH_SPRINTF_INITIAL_SIZE 256L
#define DUK_PUSH_SPRINTF_SANITY_LIMIT (1L * 1024L * 1024L * 1024L)
@@ -4237,183 +5253,336 @@ struct duk_heaphdr_string {
*/
#define DUK_ERRCODE_FLAG_NOBLAME_FILELINE (1L << 24)
-/* Valstack resize flags */
-#define DUK_VSRESIZE_FLAG_SHRINK (1 << 0)
-#define DUK_VSRESIZE_FLAG_COMPACT (1 << 1)
-#define DUK_VSRESIZE_FLAG_THROW (1 << 2)
-
/* Current convention is to use duk_size_t for value stack sizes and global indices,
* and duk_idx_t for local frame indices.
*/
-DUK_INTERNAL_DECL
-duk_bool_t duk_valstack_resize_raw(duk_context *ctx,
- duk_size_t min_new_size,
- duk_small_uint_t flags);
+DUK_INTERNAL_DECL void duk_valstack_grow_check_throw(duk_hthread *thr, duk_size_t min_bytes);
+DUK_INTERNAL_DECL duk_bool_t duk_valstack_grow_check_nothrow(duk_hthread *thr, duk_size_t min_bytes);
+DUK_INTERNAL_DECL void duk_valstack_shrink_check_nothrow(duk_hthread *thr, duk_bool_t snug);
+
+DUK_INTERNAL_DECL void duk_copy_tvals_incref(duk_hthread *thr, duk_tval *tv_dst, duk_tval *tv_src, duk_size_t count);
+
+DUK_INTERNAL_DECL duk_tval *duk_reserve_gap(duk_hthread *thr, duk_idx_t idx_base, duk_idx_t count);
+
+DUK_INTERNAL_DECL void duk_set_top_unsafe(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL void duk_set_top_and_wipe(duk_hthread *thr, duk_idx_t top, duk_idx_t idx_wipe_start);
+
+DUK_INTERNAL_DECL void duk_dup_0(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_dup_1(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_dup_2(duk_hthread *thr);
+/* duk_dup_m1() would be same as duk_dup_top() */
+DUK_INTERNAL_DECL void duk_dup_m2(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_dup_m3(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_dup_m4(duk_hthread *thr);
+
+DUK_INTERNAL_DECL void duk_remove_unsafe(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL void duk_remove_m2(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_remove_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count);
+DUK_INTERNAL_DECL void duk_remove_n_unsafe(duk_hthread *thr, duk_idx_t idx, duk_idx_t count);
+
+DUK_INTERNAL_DECL duk_int_t duk_get_type_tval(duk_tval *tv);
+DUK_INTERNAL_DECL duk_uint_t duk_get_type_mask_tval(duk_tval *tv);
#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS)
-DUK_INTERNAL_DECL const char *duk_get_type_name(duk_context *ctx, duk_idx_t index);
+DUK_INTERNAL_DECL const char *duk_get_type_name(duk_hthread *thr, duk_idx_t idx);
#endif
+DUK_INTERNAL_DECL duk_small_uint_t duk_get_class_number(duk_hthread *thr, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL void duk_push_tval(duk_context *ctx, duk_tval *tv);
+DUK_INTERNAL_DECL duk_tval *duk_get_tval(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_tval *duk_get_tval_or_unused(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_tval *duk_require_tval(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL void duk_push_tval(duk_hthread *thr, duk_tval *tv);
/* Push the current 'this' binding; throw TypeError if binding is not object
* coercible (CheckObjectCoercible).
*/
-DUK_INTERNAL_DECL void duk_push_this_check_object_coercible(duk_context *ctx);
+DUK_INTERNAL_DECL void duk_push_this_check_object_coercible(duk_hthread *thr);
/* duk_push_this() + CheckObjectCoercible() + duk_to_object() */
-DUK_INTERNAL_DECL duk_hobject *duk_push_this_coercible_to_object(duk_context *ctx);
+DUK_INTERNAL_DECL duk_hobject *duk_push_this_coercible_to_object(duk_hthread *thr);
/* duk_push_this() + CheckObjectCoercible() + duk_to_string() */
-DUK_INTERNAL_DECL duk_hstring *duk_push_this_coercible_to_string(duk_context *ctx);
+DUK_INTERNAL_DECL duk_hstring *duk_push_this_coercible_to_string(duk_hthread *thr);
+
+DUK_INTERNAL_DECL duk_hstring *duk_push_uint_to_hstring(duk_hthread *thr, duk_uint_t i);
/* Get a borrowed duk_tval pointer to the current 'this' binding. Caller must
* make sure there's an active callstack entry. Note that the returned pointer
* is unstable with regards to side effects.
*/
-DUK_INTERNAL_DECL duk_tval *duk_get_borrowed_this_tval(duk_context *ctx);
+DUK_INTERNAL_DECL duk_tval *duk_get_borrowed_this_tval(duk_hthread *thr);
/* XXX: add fastint support? */
-#define duk_push_u64(ctx,val) \
- duk_push_number((ctx), (duk_double_t) (val))
-#define duk_push_i64(ctx,val) \
- duk_push_number((ctx), (duk_double_t) (val))
+#define duk_push_u64(thr,val) \
+ duk_push_number((thr), (duk_double_t) (val))
+#define duk_push_i64(thr,val) \
+ duk_push_number((thr), (duk_double_t) (val))
/* duk_push_(u)int() is guaranteed to support at least (un)signed 32-bit range */
-#define duk_push_u32(ctx,val) \
- duk_push_uint((ctx), (duk_uint_t) (val))
-#define duk_push_i32(ctx,val) \
- duk_push_int((ctx), (duk_int_t) (val))
+#define duk_push_u32(thr,val) \
+ duk_push_uint((thr), (duk_uint_t) (val))
+#define duk_push_i32(thr,val) \
+ duk_push_int((thr), (duk_int_t) (val))
/* sometimes stack and array indices need to go on the stack */
-#define duk_push_idx(ctx,val) \
- duk_push_int((ctx), (duk_int_t) (val))
-#define duk_push_uarridx(ctx,val) \
- duk_push_uint((ctx), (duk_uint_t) (val))
-#define duk_push_size_t(ctx,val) \
- duk_push_uint((ctx), (duk_uint_t) (val)) /* XXX: assumed to fit for now */
+#define duk_push_idx(thr,val) \
+ duk_push_int((thr), (duk_int_t) (val))
+#define duk_push_uarridx(thr,val) \
+ duk_push_uint((thr), (duk_uint_t) (val))
+#define duk_push_size_t(thr,val) \
+ duk_push_uint((thr), (duk_uint_t) (val)) /* XXX: assumed to fit for now */
-DUK_INTERNAL_DECL duk_hstring *duk_get_hstring(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hobject *duk_get_hobject(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hbuffer *duk_get_hbuffer(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hcompiledfunction *duk_get_hcompiledfunction(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hnativefunction *duk_get_hnativefunction(duk_context *ctx, duk_idx_t index);
+DUK_INTERNAL_DECL duk_bool_t duk_is_string_notsymbol(duk_hthread *thr, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum);
+DUK_INTERNAL_DECL duk_bool_t duk_is_callable_tval(duk_hthread *thr, duk_tval *tv);
-#if 0 /* This would be pointless: unexpected type and lightfunc would both return NULL */
-DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_or_lfunc(duk_context *ctx, duk_idx_t index);
-#endif
-DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index);
+DUK_INTERNAL_DECL duk_hstring *duk_get_hstring(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hstring *duk_get_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL const char *duk_get_string_notsymbol(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hobject *duk_get_hobject(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hbuffer *duk_get_hbuffer(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hthread *duk_get_hthread(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hcompfunc *duk_get_hcompfunc(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hnatfunc *duk_get_hnatfunc(duk_hthread *thr, duk_idx_t idx);
+
+DUK_INTERNAL_DECL void *duk_get_buffer_data_raw(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len, duk_bool_t throw_flag, duk_bool_t *out_isbuffer);
+
+DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum);
+
+DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask);
+DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask);
+DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_accept_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask);
+#define duk_require_hobject_promote_lfunc(thr,idx) \
+ duk_require_hobject_promote_mask((thr), (idx), DUK_TYPE_MASK_LIGHTFUNC)
+#define duk_get_hobject_promote_lfunc(thr,idx) \
+ duk_get_hobject_promote_mask((thr), (idx), DUK_TYPE_MASK_LIGHTFUNC)
#if 0 /*unused*/
-DUK_INTERNAL_DECL void *duk_get_voidptr(duk_context *ctx, duk_idx_t index);
+DUK_INTERNAL_DECL void *duk_get_voidptr(duk_hthread *thr, duk_idx_t idx);
#endif
-DUK_INTERNAL_DECL duk_hstring *duk_to_hstring(duk_context *ctx, duk_idx_t index);
+DUK_INTERNAL_DECL duk_hstring *duk_known_hstring(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hobject *duk_known_hobject(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hbuffer *duk_known_hbuffer(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hcompfunc *duk_known_hcompfunc(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hnatfunc *duk_known_hnatfunc(duk_hthread *thr, duk_idx_t idx);
+
+DUK_INTERNAL_DECL duk_double_t duk_to_number_tval(duk_hthread *thr, duk_tval *tv);
+
+DUK_INTERNAL_DECL duk_hstring *duk_to_hstring(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hstring *duk_to_hstring_m1(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_hstring *duk_to_hstring_acceptsymbol(duk_hthread *thr, duk_idx_t idx);
+
+DUK_INTERNAL_DECL duk_hobject *duk_to_hobject(duk_hthread *thr, duk_idx_t idx);
+
+DUK_INTERNAL_DECL duk_double_t duk_to_number_m1(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_double_t duk_to_number_m2(duk_hthread *thr);
+
#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */
-DUK_INTERNAL_DECL duk_hstring *duk_safe_to_hstring(duk_context *ctx, duk_idx_t index);
-#endif
-DUK_INTERNAL_DECL void duk_to_object_class_string_top(duk_context *ctx);
-#if !defined(DUK_USE_PARANOID_ERRORS)
-DUK_INTERNAL_DECL void duk_push_hobject_class_string(duk_context *ctx, duk_hobject *h);
+DUK_INTERNAL_DECL duk_hstring *duk_safe_to_hstring(duk_hthread *thr, duk_idx_t idx);
#endif
+DUK_INTERNAL_DECL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv);
-DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped); /* out_clamped=NULL, RangeError if outside range */
-DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval);
-DUK_INTERNAL_DECL duk_int_t duk_to_int_check_range(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval);
+DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped_raw(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped); /* out_clamped=NULL, RangeError if outside range */
+DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval);
+DUK_INTERNAL_DECL duk_int_t duk_to_int_check_range(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval);
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL_DECL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t index);
+DUK_INTERNAL_DECL duk_uint8_t duk_to_uint8clamped(duk_hthread *thr, duk_idx_t idx);
#endif
+DUK_INTERNAL_DECL duk_hstring *duk_to_property_key_hstring(duk_hthread *thr, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hcompiledfunction *duk_require_hcompiledfunction(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hnativefunction *duk_require_hnativefunction(duk_context *ctx, duk_idx_t index);
+DUK_INTERNAL_DECL duk_hstring *duk_require_hstring(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hstring *duk_require_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL const char *duk_require_lstring_notsymbol(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len);
+DUK_INTERNAL_DECL const char *duk_require_string_notsymbol(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hobject *duk_require_hobject(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hbuffer *duk_require_hbuffer(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hthread *duk_require_hthread(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hcompfunc *duk_require_hcompfunc(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hnatfunc *duk_require_hnatfunc(duk_hthread *thr, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum);
+DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum);
-DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_or_lfunc(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index);
+DUK_INTERNAL_DECL void duk_push_hstring(duk_hthread *thr, duk_hstring *h);
+DUK_INTERNAL_DECL void duk_push_hstring_stridx(duk_hthread *thr, duk_small_uint_t stridx);
+DUK_INTERNAL_DECL void duk_push_hstring_empty(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_push_hobject(duk_hthread *thr, duk_hobject *h);
+DUK_INTERNAL_DECL void duk_push_hbuffer(duk_hthread *thr, duk_hbuffer *h);
+#define duk_push_hthread(thr,h) \
+ duk_push_hobject((thr), (duk_hobject *) (h))
+#define duk_push_hnatfunc(thr,h) \
+ duk_push_hobject((thr), (duk_hobject *) (h))
+DUK_INTERNAL_DECL void duk_push_hobject_bidx(duk_hthread *thr, duk_small_int_t builtin_idx);
+DUK_INTERNAL_DECL duk_hobject *duk_push_object_helper(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
+DUK_INTERNAL_DECL duk_hobject *duk_push_object_helper_proto(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_hobject *proto);
+DUK_INTERNAL_DECL duk_hcompfunc *duk_push_hcompfunc(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_hboundfunc *duk_push_hboundfunc(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_push_c_function_builtin(duk_hthread *thr, duk_c_function func, duk_int_t nargs);
+DUK_INTERNAL_DECL void duk_push_c_function_builtin_noconstruct(duk_hthread *thr, duk_c_function func, duk_int_t nargs);
-DUK_INTERNAL_DECL void duk_push_hstring(duk_context *ctx, duk_hstring *h);
-DUK_INTERNAL_DECL void duk_push_hstring_stridx(duk_context *ctx, duk_small_int_t stridx);
-DUK_INTERNAL_DECL void duk_push_hobject(duk_context *ctx, duk_hobject *h);
-DUK_INTERNAL_DECL void duk_push_hbuffer(duk_context *ctx, duk_hbuffer *h);
-#define duk_push_hthread(ctx,h) \
- duk_push_hobject((ctx), (duk_hobject *) (h))
-#define duk_push_hcompiledfunction(ctx,h) \
- duk_push_hobject((ctx), (duk_hobject *) (h))
-#define duk_push_hnativefunction(ctx,h) \
- duk_push_hobject((ctx), (duk_hobject *) (h))
-DUK_INTERNAL_DECL void duk_push_hobject_bidx(duk_context *ctx, duk_small_int_t builtin_idx);
-DUK_INTERNAL_DECL duk_idx_t duk_push_object_helper(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
-DUK_INTERNAL_DECL duk_idx_t duk_push_object_helper_proto(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_hobject *proto);
-DUK_INTERNAL_DECL duk_idx_t duk_push_object_internal(duk_context *ctx);
-DUK_INTERNAL_DECL duk_idx_t duk_push_compiledfunction(duk_context *ctx);
-DUK_INTERNAL_DECL void duk_push_c_function_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs);
-DUK_INTERNAL_DECL void duk_push_c_function_noconstruct_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs);
-
-DUK_INTERNAL_DECL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, duk_size_t sz);
-DUK_INTERNAL_DECL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv);
-DUK_INTERNAL_DECL void duk_push_lightfunc_tostring(duk_context *ctx, duk_tval *tv);
-DUK_INTERNAL_DECL duk_hbufferobject *duk_push_bufferobject_raw(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
-
-#if !defined(DUK_USE_PARANOID_ERRORS)
-DUK_INTERNAL_DECL const char *duk_push_string_readable(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tval *tv);
-#endif
-
-DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [val] */
-DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [val] -> [] */
-DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [] */
-DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [] */
-
-DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_boolean(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_bool_t *out_has_prop); /* [] -> [] */
-
-DUK_INTERNAL_DECL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_index, duk_small_uint_t desc_flags); /* [key val] -> [] */
-DUK_INTERNAL_DECL void duk_xdef_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index, duk_small_uint_t desc_flags); /* [val] -> [] */
-DUK_INTERNAL_DECL void duk_xdef_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags); /* [val] -> [] */
-DUK_INTERNAL_DECL void duk_xdef_prop_stridx_builtin(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags); /* [] -> [] */
-DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags); /* [] -> [] */
-
-/* These are macros for now, but could be separate functions to reduce code
- * footprint (check call site count before refactoring).
+/* XXX: duk_push_harray() and duk_push_hcompfunc() are inconsistent with
+ * duk_push_hobject() etc which don't create a new value.
*/
-#define duk_xdef_prop_wec(ctx,obj_index) \
- duk_xdef_prop((ctx), (obj_index), DUK_PROPDESC_FLAGS_WEC)
-#define duk_xdef_prop_index_wec(ctx,obj_index,arr_index) \
- duk_xdef_prop_index((ctx), (obj_index), (arr_index), DUK_PROPDESC_FLAGS_WEC)
-#define duk_xdef_prop_stridx_wec(ctx,obj_index,stridx) \
- duk_xdef_prop_stridx((ctx), (obj_index), (stridx), DUK_PROPDESC_FLAGS_WEC)
+DUK_INTERNAL_DECL duk_harray *duk_push_harray(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_harray *duk_push_harray_with_size(duk_hthread *thr, duk_uint32_t size);
+DUK_INTERNAL_DECL duk_tval *duk_push_harray_with_size_outptr(duk_hthread *thr, duk_uint32_t size);
-/* Set object 'length'. */
-DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_size_t length);
+DUK_INTERNAL_DECL void duk_push_string_funcptr(duk_hthread *thr, duk_uint8_t *ptr, duk_size_t sz);
+DUK_INTERNAL_DECL void duk_push_lightfunc_name_raw(duk_hthread *thr, duk_c_function func, duk_small_uint_t lf_flags);
+DUK_INTERNAL_DECL void duk_push_lightfunc_name(duk_hthread *thr, duk_tval *tv);
+DUK_INTERNAL_DECL void duk_push_lightfunc_tostring(duk_hthread *thr, duk_tval *tv);
+#if 0 /* not used yet */
+DUK_INTERNAL_DECL void duk_push_hnatfunc_name(duk_hthread *thr, duk_hnatfunc *h);
+#endif
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+DUK_INTERNAL_DECL duk_hbufobj *duk_push_bufobj_raw(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
+#endif
+
+DUK_INTERNAL_DECL void *duk_push_fixed_buffer_nozero(duk_hthread *thr, duk_size_t len);
+DUK_INTERNAL_DECL void *duk_push_fixed_buffer_zero(duk_hthread *thr, duk_size_t len);
+
+DUK_INTERNAL_DECL const char *duk_push_string_readable(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL const char *duk_push_string_tval_readable(duk_hthread *thr, duk_tval *tv);
+DUK_INTERNAL_DECL const char *duk_push_string_tval_readable_error(duk_hthread *thr, duk_tval *tv);
+
+/* The duk_xxx_prop_stridx_short() variants expect their arguments to be short
+ * enough to be packed into a single 32-bit integer argument. Argument limits
+ * vary per call; typically 16 bits are assigned to the signed value stack index
+ * and the stridx. In practice these work well for footprint with constant
+ * arguments and such call sites are also easiest to verify to be correct.
+ */
+
+DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [val] */
+DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
+#define duk_get_prop_stridx_short(thr,obj_idx,stridx) \
+ (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \
+ DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
+ duk_get_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
+DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_boolean(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_bool_t *out_has_prop); /* [] -> [] */
+
+DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [val] -> [] */
+DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
+#define duk_put_prop_stridx_short(thr,obj_idx,stridx) \
+ (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \
+ DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
+ duk_put_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
+
+DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
+#if 0 /* Too few call sites to be useful. */
+DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
+#define duk_del_prop_stridx_short(thr,obj_idx,stridx) \
+ (DUK_ASSERT_EXPR((obj_idx) >= -0x8000L && (obj_idx) <= 0x7fffL), \
+ DUK_ASSERT_EXPR((stridx) >= 0 && (stridx) <= 0xffffL), \
+ duk_del_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
+#endif
+#define duk_del_prop_stridx_short(thr,obj_idx,stridx) \
+ duk_del_prop_stridx((thr), (obj_idx), (stridx))
+
+DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
+#if 0 /* Too few call sites to be useful. */
+DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
+#define duk_has_prop_stridx_short(thr,obj_idx,stridx) \
+ (DUK_ASSERT_EXPR((obj_idx) >= -0x8000L && (obj_idx) <= 0x7fffL), \
+ DUK_ASSERT_EXPR((stridx) >= 0 && (stridx) <= 0xffffL), \
+ duk_has_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
+#endif
+#define duk_has_prop_stridx_short(thr,obj_idx,stridx) \
+ duk_has_prop_stridx((thr), (obj_idx), (stridx))
+
+DUK_INTERNAL_DECL void duk_xdef_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t desc_flags); /* [key val] -> [] */
+
+DUK_INTERNAL_DECL void duk_xdef_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx, duk_small_uint_t desc_flags); /* [val] -> [] */
+
+/* XXX: Because stridx and desc_flags have a limited range, this call could
+ * always pack stridx and desc_flags into a single argument.
+ */
+DUK_INTERNAL_DECL void duk_xdef_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_uint_t desc_flags); /* [val] -> [] */
+DUK_INTERNAL_DECL void duk_xdef_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
+#define duk_xdef_prop_stridx_short(thr,obj_idx,stridx,desc_flags) \
+ (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x80L && (duk_int_t) (obj_idx) <= 0x7fL), \
+ DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
+ DUK_ASSERT_EXPR((duk_int_t) (desc_flags) >= 0 && (duk_int_t) (desc_flags) <= 0xffL), \
+ duk_xdef_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 24) + (((duk_uint_t) (stridx)) << 8) + (duk_uint_t) (desc_flags)))
+
+#define duk_xdef_prop_wec(thr,obj_idx) \
+ duk_xdef_prop((thr), (obj_idx), DUK_PROPDESC_FLAGS_WEC)
+#define duk_xdef_prop_index_wec(thr,obj_idx,arr_idx) \
+ duk_xdef_prop_index((thr), (obj_idx), (arr_idx), DUK_PROPDESC_FLAGS_WEC)
+#define duk_xdef_prop_stridx_wec(thr,obj_idx,stridx) \
+ duk_xdef_prop_stridx((thr), (obj_idx), (stridx), DUK_PROPDESC_FLAGS_WEC)
+#define duk_xdef_prop_stridx_short_wec(thr,obj_idx,stridx) \
+ duk_xdef_prop_stridx_short((thr), (obj_idx), (stridx), DUK_PROPDESC_FLAGS_WEC)
+
+#if 0 /*unused*/
+DUK_INTERNAL_DECL void duk_xdef_prop_stridx_builtin(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags); /* [] -> [] */
+#endif
+
+DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
+
+DUK_INTERNAL_DECL void duk_pack(duk_hthread *thr, duk_idx_t count);
+DUK_INTERNAL_DECL duk_idx_t duk_unpack_array_like(duk_hthread *thr, duk_idx_t idx);
+#if 0
+DUK_INTERNAL_DECL void duk_unpack(duk_hthread *thr);
+#endif
+
+DUK_INTERNAL_DECL void duk_require_constructor_call(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_require_constructable(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL void duk_push_symbol_descriptive_string(duk_hthread *thr, duk_hstring *h);
+
+DUK_INTERNAL_DECL void duk_resolve_nonbound_function(duk_hthread *thr);
+
+DUK_INTERNAL_DECL duk_idx_t duk_get_top_require_min(duk_hthread *thr, duk_idx_t min_top);
+DUK_INTERNAL_DECL duk_idx_t duk_get_top_index_unsafe(duk_hthread *thr);
+
+DUK_INTERNAL_DECL void duk_pop_n_unsafe(duk_hthread *thr, duk_idx_t count);
+DUK_INTERNAL_DECL void duk_pop_unsafe(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_pop_2_unsafe(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_pop_3_unsafe(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_pop_n_nodecref_unsafe(duk_hthread *thr, duk_idx_t count);
+DUK_INTERNAL_DECL void duk_pop_nodecref_unsafe(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_pop_2_nodecref_unsafe(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_pop_3_nodecref_unsafe(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_pop_undefined(duk_hthread *thr);
+
+DUK_INTERNAL_DECL void duk_compact_m1(duk_hthread *thr);
+
+DUK_INTERNAL_DECL void duk_seal_freeze_raw(duk_hthread *thr, duk_idx_t obj_idx, duk_bool_t is_freeze);
+
+DUK_INTERNAL_DECL void duk_insert_undefined(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL void duk_insert_undefined_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count);
+
+DUK_INTERNAL_DECL void duk_concat_2(duk_hthread *thr);
+
+DUK_INTERNAL_DECL duk_int_t duk_pcall_method_flags(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags);
/* Raw internal valstack access macros: access is unsafe so call site
* must have a guarantee that the index is valid. When that is the case,
* using these macro results in faster and smaller code than duk_get_tval().
* Both 'ctx' and 'idx' are evaluted multiple times, but only for asserts.
*/
-#define DUK_ASSERT_VALID_NEGIDX(ctx,idx) \
- (DUK_ASSERT_EXPR((idx) < 0), DUK_ASSERT_EXPR(duk_is_valid_index((ctx), (idx))))
-#define DUK_ASSERT_VALID_POSIDX(ctx,idx) \
- (DUK_ASSERT_EXPR((idx) >= 0), DUK_ASSERT_EXPR(duk_is_valid_index((ctx), (idx))))
-#define DUK_GET_TVAL_NEGIDX(ctx,idx) \
- (DUK_ASSERT_VALID_NEGIDX((ctx),(idx)), ((duk_hthread *) (ctx))->valstack_top + (idx))
-#define DUK_GET_TVAL_POSIDX(ctx,idx) \
- (DUK_ASSERT_VALID_POSIDX((ctx),(idx)), ((duk_hthread *) (ctx))->valstack_bottom + (idx))
-#define DUK_GET_HOBJECT_NEGIDX(ctx,idx) \
- (DUK_ASSERT_VALID_NEGIDX((ctx),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (ctx))->valstack_top + (idx)))
-#define DUK_GET_HOBJECT_POSIDX(ctx,idx) \
- (DUK_ASSERT_VALID_POSIDX((ctx),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (ctx))->valstack_bottom + (idx)))
+#define DUK_ASSERT_VALID_NEGIDX(thr,idx) \
+ (DUK_ASSERT_EXPR((duk_int_t) (idx) < 0), DUK_ASSERT_EXPR(duk_is_valid_index((thr), (idx))))
+#define DUK_ASSERT_VALID_POSIDX(thr,idx) \
+ (DUK_ASSERT_EXPR((duk_int_t) (idx) >= 0), DUK_ASSERT_EXPR(duk_is_valid_index((thr), (idx))))
+#define DUK_GET_TVAL_NEGIDX(thr,idx) \
+ (DUK_ASSERT_VALID_NEGIDX((thr),(idx)), ((duk_hthread *) (thr))->valstack_top + (idx))
+#define DUK_GET_TVAL_POSIDX(thr,idx) \
+ (DUK_ASSERT_VALID_POSIDX((thr),(idx)), ((duk_hthread *) (thr))->valstack_bottom + (idx))
+#define DUK_GET_HOBJECT_NEGIDX(thr,idx) \
+ (DUK_ASSERT_VALID_NEGIDX((thr),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (thr))->valstack_top + (idx)))
+#define DUK_GET_HOBJECT_POSIDX(thr,idx) \
+ (DUK_ASSERT_VALID_POSIDX((thr),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (thr))->valstack_bottom + (idx)))
+
+#define DUK_GET_THIS_TVAL_PTR(thr) \
+ (DUK_ASSERT_EXPR((thr)->valstack_bottom > (thr)->valstack), \
+ (thr)->valstack_bottom - 1)
+
+DUK_INTERNAL_DECL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_double_t duk_time_get_ecmascript_time_nofrac(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr);
#endif /* DUK_API_INTERNAL_H_INCLUDED */
+/* #include duk_hstring.h */
#line 1 "duk_hstring.h"
/*
* Heap string representation.
@@ -4431,7 +5600,7 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz
* really a practical issue.
*/
-#ifndef DUK_HSTRING_H_INCLUDED
+#if !defined(DUK_HSTRING_H_INCLUDED)
#define DUK_HSTRING_H_INCLUDED
/* Impose a maximum string length for now. Restricted artificially to
@@ -4457,15 +5626,17 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz
#define DUK_HSTRING_FLAG_ASCII DUK_HEAPHDR_USER_FLAG(0) /* string is ASCII, clen == blen */
#define DUK_HSTRING_FLAG_ARRIDX DUK_HEAPHDR_USER_FLAG(1) /* string is a valid array index */
-#define DUK_HSTRING_FLAG_INTERNAL DUK_HEAPHDR_USER_FLAG(2) /* string is internal */
-#define DUK_HSTRING_FLAG_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(3) /* string is a reserved word (non-strict) */
-#define DUK_HSTRING_FLAG_STRICT_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(4) /* string is a reserved word (strict) */
-#define DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS DUK_HEAPHDR_USER_FLAG(5) /* string is 'eval' or 'arguments' */
-#define DUK_HSTRING_FLAG_EXTDATA DUK_HEAPHDR_USER_FLAG(6) /* string data is external (duk_hstring_external) */
+#define DUK_HSTRING_FLAG_SYMBOL DUK_HEAPHDR_USER_FLAG(2) /* string is a symbol (invalid utf-8) */
+#define DUK_HSTRING_FLAG_HIDDEN DUK_HEAPHDR_USER_FLAG(3) /* string is a hidden symbol (implies symbol, Duktape 1.x internal string) */
+#define DUK_HSTRING_FLAG_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(4) /* string is a reserved word (non-strict) */
+#define DUK_HSTRING_FLAG_STRICT_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(5) /* string is a reserved word (strict) */
+#define DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS DUK_HEAPHDR_USER_FLAG(6) /* string is 'eval' or 'arguments' */
+#define DUK_HSTRING_FLAG_EXTDATA DUK_HEAPHDR_USER_FLAG(7) /* string data is external (duk_hstring_external) */
#define DUK_HSTRING_HAS_ASCII(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
#define DUK_HSTRING_HAS_ARRIDX(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
-#define DUK_HSTRING_HAS_INTERNAL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL)
+#define DUK_HSTRING_HAS_SYMBOL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL)
+#define DUK_HSTRING_HAS_HIDDEN(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN)
#define DUK_HSTRING_HAS_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
#define DUK_HSTRING_HAS_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
#define DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
@@ -4473,7 +5644,8 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz
#define DUK_HSTRING_SET_ASCII(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
#define DUK_HSTRING_SET_ARRIDX(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
-#define DUK_HSTRING_SET_INTERNAL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL)
+#define DUK_HSTRING_SET_SYMBOL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL)
+#define DUK_HSTRING_SET_HIDDEN(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN)
#define DUK_HSTRING_SET_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
#define DUK_HSTRING_SET_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
#define DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
@@ -4481,7 +5653,8 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz
#define DUK_HSTRING_CLEAR_ASCII(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
#define DUK_HSTRING_CLEAR_ARRIDX(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
-#define DUK_HSTRING_CLEAR_INTERNAL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL)
+#define DUK_HSTRING_CLEAR_SYMBOL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL)
+#define DUK_HSTRING_CLEAR_HIDDEN(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN)
#define DUK_HSTRING_CLEAR_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
#define DUK_HSTRING_CLEAR_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
#define DUK_HSTRING_CLEAR_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
@@ -4492,7 +5665,7 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz
*/
#define DUK_HSTRING_IS_ASCII(x) (DUK_HSTRING_GET_BYTELEN((x)) == DUK_HSTRING_GET_CHARLEN((x)))
#endif
-#define DUK_HSTRING_IS_ASCII(x) DUK_HSTRING_HAS_ASCII((x))
+#define DUK_HSTRING_IS_ASCII(x) DUK_HSTRING_HAS_ASCII((x)) /* lazily set! */
#define DUK_HSTRING_IS_EMPTY(x) (DUK_HSTRING_GET_BYTELEN((x)) == 0)
#if defined(DUK_USE_STRHASH16)
@@ -4513,7 +5686,7 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz
(x)->hdr.h_strextra16 = (v); \
} while (0)
#if defined(DUK_USE_HSTRING_CLEN)
-#define DUK_HSTRING_GET_CHARLEN(x) ((x)->clen16)
+#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x))
#define DUK_HSTRING_SET_CHARLEN(x,v) do { \
(x)->clen16 = (v); \
} while (0)
@@ -4528,7 +5701,7 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz
#define DUK_HSTRING_SET_BYTELEN(x,v) do { \
(x)->blen = (v); \
} while (0)
-#define DUK_HSTRING_GET_CHARLEN(x) ((x)->clen)
+#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x))
#define DUK_HSTRING_SET_CHARLEN(x,v) do { \
(x)->clen = (v); \
} while (0)
@@ -4548,18 +5721,31 @@ DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_siz
#define DUK_HSTRING_GET_DATA_END(x) \
(DUK_HSTRING_GET_DATA((x)) + (x)->blen)
-/* marker value; in E5 2^32-1 is not a valid array index (2^32-2 is highest valid) */
+/* Marker value; in E5 2^32-1 is not a valid array index (2^32-2 is highest
+ * valid).
+ */
#define DUK_HSTRING_NO_ARRAY_INDEX (0xffffffffUL)
-/* get array index related to string (or return DUK_HSTRING_NO_ARRAY_INDEX);
+#if defined(DUK_USE_HSTRING_ARRIDX)
+#define DUK_HSTRING_GET_ARRIDX_FAST(h) ((h)->arridx)
+#define DUK_HSTRING_GET_ARRIDX_SLOW(h) ((h)->arridx)
+#else
+/* Get array index related to string (or return DUK_HSTRING_NO_ARRAY_INDEX);
* avoids helper call if string has no array index value.
*/
#define DUK_HSTRING_GET_ARRIDX_FAST(h) \
- (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_string_helper((h)) : DUK_HSTRING_NO_ARRAY_INDEX)
+ (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_hstring_fast_known((h)) : DUK_HSTRING_NO_ARRAY_INDEX)
-/* slower but more compact variant */
+/* Slower but more compact variant. */
#define DUK_HSTRING_GET_ARRIDX_SLOW(h) \
- (duk_js_to_arrayindex_string_helper((h)))
+ (duk_js_to_arrayindex_hstring_fast((h)))
+#endif
+
+/* XXX: these actually fit into duk_hstring */
+#define DUK_SYMBOL_TYPE_HIDDEN 0
+#define DUK_SYMBOL_TYPE_GLOBAL 1
+#define DUK_SYMBOL_TYPE_LOCAL 2
+#define DUK_SYMBOL_TYPE_WELLKNOWN 3
/*
* Misc
@@ -4573,25 +5759,26 @@ struct duk_hstring {
*/
duk_heaphdr_string hdr;
- /* Note: we could try to stuff a partial hash (e.g. 16 bits) into the
- * shared heap header. Good hashing needs more hash bits though.
- */
-
- /* string hash */
+ /* String hash. */
#if defined(DUK_USE_STRHASH16)
/* If 16-bit hash is in use, stuff it into duk_heaphdr_string flags. */
#else
duk_uint32_t hash;
#endif
- /* length in bytes (not counting NUL term) */
+ /* Precomputed array index (or DUK_HSTRING_NO_ARRAY_INDEX). */
+#if defined(DUK_USE_HSTRING_ARRIDX)
+ duk_uarridx_t arridx;
+#endif
+
+ /* Length in bytes (not counting NUL term). */
#if defined(DUK_USE_STRLEN16)
/* placed in duk_heaphdr_string */
#else
duk_uint32_t blen;
#endif
- /* length in codepoints (must be E5 compatible) */
+ /* Length in codepoints (must be E5 compatible). */
#if defined(DUK_USE_STRLEN16)
#if defined(DUK_USE_HSTRING_CLEN)
duk_uint16_t clen16;
@@ -4603,7 +5790,7 @@ struct duk_hstring {
#endif
/*
- * String value of 'blen+1' bytes follows (+1 for NUL termination
+ * String data of 'blen+1' bytes follows (+1 for NUL termination
* convenience for C API). No alignment needs to be guaranteed
* for strings, but fields above should guarantee alignment-by-4
* (but not alignment-by-8).
@@ -4627,13 +5814,15 @@ struct duk_hstring_external {
* Prototypes
*/
-DUK_INTERNAL_DECL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos);
-
-#if !defined(DUK_USE_HSTRING_CLEN)
+DUK_INTERNAL_DECL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos, duk_bool_t surrogate_aware);
+DUK_INTERNAL_DECL duk_bool_t duk_hstring_equals_ascii_cstring(duk_hstring *h, const char *cstr);
DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
+#if !defined(DUK_USE_HSTRING_LAZY_CLEN)
+DUK_INTERNAL_DECL void duk_hstring_init_charlen(duk_hstring *h);
#endif
#endif /* DUK_HSTRING_H_INCLUDED */
+/* #include duk_hobject.h */
#line 1 "duk_hobject.h"
/*
* Heap object representation.
@@ -4666,31 +5855,36 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
* parts are resized together, and makes property access a bit complicated.
*/
-#ifndef DUK_HOBJECT_H_INCLUDED
+#if !defined(DUK_HOBJECT_H_INCLUDED)
#define DUK_HOBJECT_H_INCLUDED
-/* Object flag. There are currently 26 flag bits available. Make sure
- * this stays in sync with debugger object inspection code.
+/* Object flags. Make sure this stays in sync with debugger object
+ * inspection code.
+ */
+
+/* XXX: some flags are object subtype specific (e.g. common to all function
+ * subtypes, duk_harray, etc) and could be reused for different subtypes.
*/
#define DUK_HOBJECT_FLAG_EXTENSIBLE DUK_HEAPHDR_USER_FLAG(0) /* object is extensible */
#define DUK_HOBJECT_FLAG_CONSTRUCTABLE DUK_HEAPHDR_USER_FLAG(1) /* object is constructable */
-#define DUK_HOBJECT_FLAG_BOUND DUK_HEAPHDR_USER_FLAG(2) /* object established using Function.prototype.bind() */
-#define DUK_HOBJECT_FLAG_COMPILEDFUNCTION DUK_HEAPHDR_USER_FLAG(4) /* object is a compiled function (duk_hcompiledfunction) */
-#define DUK_HOBJECT_FLAG_NATIVEFUNCTION DUK_HEAPHDR_USER_FLAG(5) /* object is a native function (duk_hnativefunction) */
-#define DUK_HOBJECT_FLAG_BUFFEROBJECT DUK_HEAPHDR_USER_FLAG(6) /* object is a buffer object (duk_hbufferobject) (always exotic) */
-#define DUK_HOBJECT_FLAG_THREAD DUK_HEAPHDR_USER_FLAG(7) /* object is a thread (duk_hthread) */
+#define DUK_HOBJECT_FLAG_CALLABLE DUK_HEAPHDR_USER_FLAG(2) /* object is callable */
+#define DUK_HOBJECT_FLAG_BOUNDFUNC DUK_HEAPHDR_USER_FLAG(3) /* object established using Function.prototype.bind() */
+#define DUK_HOBJECT_FLAG_COMPFUNC DUK_HEAPHDR_USER_FLAG(4) /* object is a compiled function (duk_hcompfunc) */
+#define DUK_HOBJECT_FLAG_NATFUNC DUK_HEAPHDR_USER_FLAG(5) /* object is a native function (duk_hnatfunc) */
+#define DUK_HOBJECT_FLAG_BUFOBJ DUK_HEAPHDR_USER_FLAG(6) /* object is a buffer object (duk_hbufobj) (always exotic) */
+#define DUK_HOBJECT_FLAG_FASTREFS DUK_HEAPHDR_USER_FLAG(7) /* object has no fields needing DECREF/marking beyond base duk_hobject header */
#define DUK_HOBJECT_FLAG_ARRAY_PART DUK_HEAPHDR_USER_FLAG(8) /* object has an array part (a_size may still be 0) */
#define DUK_HOBJECT_FLAG_STRICT DUK_HEAPHDR_USER_FLAG(9) /* function: function object is strict */
#define DUK_HOBJECT_FLAG_NOTAIL DUK_HEAPHDR_USER_FLAG(10) /* function: function must not be tail called */
-#define DUK_HOBJECT_FLAG_NEWENV DUK_HEAPHDR_USER_FLAG(11) /* function: create new environment when called (see duk_hcompiledfunction) */
+#define DUK_HOBJECT_FLAG_NEWENV DUK_HEAPHDR_USER_FLAG(11) /* function: create new environment when called (see duk_hcompfunc) */
#define DUK_HOBJECT_FLAG_NAMEBINDING DUK_HEAPHDR_USER_FLAG(12) /* function: create binding for func name (function templates only, used for named function expressions) */
#define DUK_HOBJECT_FLAG_CREATEARGS DUK_HEAPHDR_USER_FLAG(13) /* function: create an arguments object on function call */
-#define DUK_HOBJECT_FLAG_ENVRECCLOSED DUK_HEAPHDR_USER_FLAG(14) /* envrec: (declarative) record is closed */
+#define DUK_HOBJECT_FLAG_HAVE_FINALIZER DUK_HEAPHDR_USER_FLAG(14) /* object has a callable (own) finalizer property */
#define DUK_HOBJECT_FLAG_EXOTIC_ARRAY DUK_HEAPHDR_USER_FLAG(15) /* 'Array' object, array length and index exotic behavior */
#define DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ DUK_HEAPHDR_USER_FLAG(16) /* 'String' object, array index exotic behavior */
#define DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS DUK_HEAPHDR_USER_FLAG(17) /* 'Arguments' object and has arguments exotic behavior (non-strict callee) */
-#define DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC DUK_HEAPHDR_USER_FLAG(18) /* Duktape/C (nativefunction) object, exotic 'length' */
-#define DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ DUK_HEAPHDR_USER_FLAG(19) /* 'Proxy' object */
+#define DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ DUK_HEAPHDR_USER_FLAG(18) /* 'Proxy' object */
+#define DUK_HOBJECT_FLAG_SPECIAL_CALL DUK_HEAPHDR_USER_FLAG(19) /* special casing in call behavior, for .call(), .apply(), etc. */
#define DUK_HOBJECT_FLAG_CLASS_BASE DUK_HEAPHDR_USER_FLAG_NUMBER(20)
#define DUK_HOBJECT_FLAG_CLASS_BITS 5
@@ -4711,26 +5905,27 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
#define DUK_HOBJECT_CLASS_AS_FLAGS(v) (((duk_uint_t) (v)) << DUK_HOBJECT_FLAG_CLASS_BASE)
/* E5 Section 8.6.2 + custom classes */
-#define DUK_HOBJECT_CLASS_UNUSED 0
-#define DUK_HOBJECT_CLASS_ARGUMENTS 1
+#define DUK_HOBJECT_CLASS_NONE 0
+#define DUK_HOBJECT_CLASS_OBJECT 1
#define DUK_HOBJECT_CLASS_ARRAY 2
-#define DUK_HOBJECT_CLASS_BOOLEAN 3
-#define DUK_HOBJECT_CLASS_DATE 4
-#define DUK_HOBJECT_CLASS_ERROR 5
-#define DUK_HOBJECT_CLASS_FUNCTION 6
-#define DUK_HOBJECT_CLASS_JSON 7
-#define DUK_HOBJECT_CLASS_MATH 8
-#define DUK_HOBJECT_CLASS_NUMBER 9
-#define DUK_HOBJECT_CLASS_OBJECT 10
+#define DUK_HOBJECT_CLASS_FUNCTION 3
+#define DUK_HOBJECT_CLASS_ARGUMENTS 4
+#define DUK_HOBJECT_CLASS_BOOLEAN 5
+#define DUK_HOBJECT_CLASS_DATE 6
+#define DUK_HOBJECT_CLASS_ERROR 7
+#define DUK_HOBJECT_CLASS_JSON 8
+#define DUK_HOBJECT_CLASS_MATH 9
+#define DUK_HOBJECT_CLASS_NUMBER 10
#define DUK_HOBJECT_CLASS_REGEXP 11
#define DUK_HOBJECT_CLASS_STRING 12
#define DUK_HOBJECT_CLASS_GLOBAL 13
-#define DUK_HOBJECT_CLASS_OBJENV 14 /* custom */
-#define DUK_HOBJECT_CLASS_DECENV 15 /* custom */
-#define DUK_HOBJECT_CLASS_BUFFER 16 /* custom; implies DUK_HOBJECT_IS_BUFFEROBJECT */
+#define DUK_HOBJECT_CLASS_SYMBOL 14
+#define DUK_HOBJECT_CLASS_OBJENV 15 /* custom */
+#define DUK_HOBJECT_CLASS_DECENV 16 /* custom */
#define DUK_HOBJECT_CLASS_POINTER 17 /* custom */
#define DUK_HOBJECT_CLASS_THREAD 18 /* custom; implies DUK_HOBJECT_IS_THREAD */
-#define DUK_HOBJECT_CLASS_ARRAYBUFFER 19 /* implies DUK_HOBJECT_IS_BUFFEROBJECT */
+#define DUK_HOBJECT_CLASS_BUFOBJ_MIN 19
+#define DUK_HOBJECT_CLASS_ARRAYBUFFER 19 /* implies DUK_HOBJECT_IS_BUFOBJ */
#define DUK_HOBJECT_CLASS_DATAVIEW 20
#define DUK_HOBJECT_CLASS_INT8ARRAY 21
#define DUK_HOBJECT_CLASS_UINT8ARRAY 22
@@ -4741,11 +5936,12 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
#define DUK_HOBJECT_CLASS_UINT32ARRAY 27
#define DUK_HOBJECT_CLASS_FLOAT32ARRAY 28
#define DUK_HOBJECT_CLASS_FLOAT64ARRAY 29
+#define DUK_HOBJECT_CLASS_BUFOBJ_MAX 29
#define DUK_HOBJECT_CLASS_MAX 29
-/* class masks */
+/* Class masks. */
#define DUK_HOBJECT_CMASK_ALL ((1UL << (DUK_HOBJECT_CLASS_MAX + 1)) - 1UL)
-#define DUK_HOBJECT_CMASK_UNUSED (1UL << DUK_HOBJECT_CLASS_UNUSED)
+#define DUK_HOBJECT_CMASK_NONE (1UL << DUK_HOBJECT_CLASS_NONE)
#define DUK_HOBJECT_CMASK_ARGUMENTS (1UL << DUK_HOBJECT_CLASS_ARGUMENTS)
#define DUK_HOBJECT_CMASK_ARRAY (1UL << DUK_HOBJECT_CLASS_ARRAY)
#define DUK_HOBJECT_CMASK_BOOLEAN (1UL << DUK_HOBJECT_CLASS_BOOLEAN)
@@ -4759,11 +5955,10 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
#define DUK_HOBJECT_CMASK_REGEXP (1UL << DUK_HOBJECT_CLASS_REGEXP)
#define DUK_HOBJECT_CMASK_STRING (1UL << DUK_HOBJECT_CLASS_STRING)
#define DUK_HOBJECT_CMASK_GLOBAL (1UL << DUK_HOBJECT_CLASS_GLOBAL)
+#define DUK_HOBJECT_CMASK_SYMBOL (1UL << DUK_HOBJECT_CLASS_SYMBOL)
#define DUK_HOBJECT_CMASK_OBJENV (1UL << DUK_HOBJECT_CLASS_OBJENV)
#define DUK_HOBJECT_CMASK_DECENV (1UL << DUK_HOBJECT_CLASS_DECENV)
-#define DUK_HOBJECT_CMASK_BUFFER (1UL << DUK_HOBJECT_CLASS_BUFFER)
#define DUK_HOBJECT_CMASK_POINTER (1UL << DUK_HOBJECT_CLASS_POINTER)
-#define DUK_HOBJECT_CMASK_THREAD (1UL << DUK_HOBJECT_CLASS_THREAD)
#define DUK_HOBJECT_CMASK_ARRAYBUFFER (1UL << DUK_HOBJECT_CLASS_ARRAYBUFFER)
#define DUK_HOBJECT_CMASK_DATAVIEW (1UL << DUK_HOBJECT_CLASS_DATAVIEW)
#define DUK_HOBJECT_CMASK_INT8ARRAY (1UL << DUK_HOBJECT_CLASS_INT8ARRAY)
@@ -4776,9 +5971,8 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
#define DUK_HOBJECT_CMASK_FLOAT32ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT32ARRAY)
#define DUK_HOBJECT_CMASK_FLOAT64ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT64ARRAY)
-#define DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS \
- (DUK_HOBJECT_CMASK_BUFFER | \
- DUK_HOBJECT_CMASK_ARRAYBUFFER | \
+#define DUK_HOBJECT_CMASK_ALL_BUFOBJS \
+ (DUK_HOBJECT_CMASK_ARRAYBUFFER | \
DUK_HOBJECT_CMASK_DATAVIEW | \
DUK_HOBJECT_CMASK_INT8ARRAY | \
DUK_HOBJECT_CMASK_UINT8ARRAY | \
@@ -4793,102 +5987,144 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
#define DUK_HOBJECT_IS_OBJENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_OBJENV)
#define DUK_HOBJECT_IS_DECENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DECENV)
#define DUK_HOBJECT_IS_ENV(h) (DUK_HOBJECT_IS_OBJENV((h)) || DUK_HOBJECT_IS_DECENV((h)))
-#define DUK_HOBJECT_IS_ARRAY(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAY)
-#define DUK_HOBJECT_IS_COMPILEDFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
-#define DUK_HOBJECT_IS_NATIVEFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
-#define DUK_HOBJECT_IS_BUFFEROBJECT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT)
-#define DUK_HOBJECT_IS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
+#define DUK_HOBJECT_IS_ARRAY(h) DUK_HOBJECT_HAS_EXOTIC_ARRAY((h)) /* Rely on class Array <=> exotic Array */
+#define DUK_HOBJECT_IS_BOUNDFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
+#define DUK_HOBJECT_IS_COMPFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
+#define DUK_HOBJECT_IS_NATFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+#define DUK_HOBJECT_IS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
+#else
+#define DUK_HOBJECT_IS_BUFOBJ(h) 0
+#endif
+#define DUK_HOBJECT_IS_THREAD(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_THREAD)
+#if defined(DUK_USE_ES6_PROXY)
+#define DUK_HOBJECT_IS_PROXY(h) DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ((h))
+#else
+#define DUK_HOBJECT_IS_PROXY(h) 0
+#endif
#define DUK_HOBJECT_IS_NONBOUND_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
- DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \
- DUK_HOBJECT_FLAG_NATIVEFUNCTION)
+ DUK_HOBJECT_FLAG_COMPFUNC | \
+ DUK_HOBJECT_FLAG_NATFUNC)
#define DUK_HOBJECT_IS_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
- DUK_HOBJECT_FLAG_BOUND | \
- DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \
- DUK_HOBJECT_FLAG_NATIVEFUNCTION)
+ DUK_HOBJECT_FLAG_BOUNDFUNC | \
+ DUK_HOBJECT_FLAG_COMPFUNC | \
+ DUK_HOBJECT_FLAG_NATFUNC)
-#define DUK_HOBJECT_IS_CALLABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
- DUK_HOBJECT_FLAG_BOUND | \
- DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \
- DUK_HOBJECT_FLAG_NATIVEFUNCTION)
+#define DUK_HOBJECT_IS_CALLABLE(h) DUK_HOBJECT_HAS_CALLABLE((h))
-/* object has any exotic behavior(s) */
+/* Object has any exotic behavior(s). */
#define DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \
DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS | \
DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \
- DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC | \
- DUK_HOBJECT_FLAG_BUFFEROBJECT | \
+ DUK_HOBJECT_FLAG_BUFOBJ | \
DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
-
#define DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS)
+/* Object has any virtual properties (not counting Proxy behavior). */
+#define DUK_HOBJECT_VIRTUAL_PROPERTY_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \
+ DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \
+ DUK_HOBJECT_FLAG_BUFOBJ)
+#define DUK_HOBJECT_HAS_VIRTUAL_PROPERTIES(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_VIRTUAL_PROPERTY_FLAGS)
+
#define DUK_HOBJECT_HAS_EXTENSIBLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
#define DUK_HOBJECT_HAS_CONSTRUCTABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
-#define DUK_HOBJECT_HAS_BOUND(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND)
-#define DUK_HOBJECT_HAS_COMPILEDFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
-#define DUK_HOBJECT_HAS_NATIVEFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
-#define DUK_HOBJECT_HAS_BUFFEROBJECT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT)
-#define DUK_HOBJECT_HAS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
+#define DUK_HOBJECT_HAS_CALLABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE)
+#define DUK_HOBJECT_HAS_BOUNDFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
+#define DUK_HOBJECT_HAS_COMPFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
+#define DUK_HOBJECT_HAS_NATFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+#define DUK_HOBJECT_HAS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
+#else
+#define DUK_HOBJECT_HAS_BUFOBJ(h) 0
+#endif
+#define DUK_HOBJECT_HAS_FASTREFS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS)
#define DUK_HOBJECT_HAS_ARRAY_PART(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
#define DUK_HOBJECT_HAS_STRICT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
#define DUK_HOBJECT_HAS_NOTAIL(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
#define DUK_HOBJECT_HAS_NEWENV(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
#define DUK_HOBJECT_HAS_NAMEBINDING(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
#define DUK_HOBJECT_HAS_CREATEARGS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
-#define DUK_HOBJECT_HAS_ENVRECCLOSED(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED)
+#define DUK_HOBJECT_HAS_HAVE_FINALIZER(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_HAVE_FINALIZER)
#define DUK_HOBJECT_HAS_EXOTIC_ARRAY(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
#define DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
#define DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
-#define DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC)
+#if defined(DUK_USE_ES6_PROXY)
#define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
+#else
+#define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h) 0
+#endif
+#define DUK_HOBJECT_HAS_SPECIAL_CALL(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL)
#define DUK_HOBJECT_SET_EXTENSIBLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
#define DUK_HOBJECT_SET_CONSTRUCTABLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
-#define DUK_HOBJECT_SET_BOUND(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND)
-#define DUK_HOBJECT_SET_COMPILEDFUNCTION(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
-#define DUK_HOBJECT_SET_NATIVEFUNCTION(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
-#define DUK_HOBJECT_SET_BUFFEROBJECT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT)
-#define DUK_HOBJECT_SET_THREAD(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
+#define DUK_HOBJECT_SET_CALLABLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE)
+#define DUK_HOBJECT_SET_BOUNDFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
+#define DUK_HOBJECT_SET_COMPFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
+#define DUK_HOBJECT_SET_NATFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+#define DUK_HOBJECT_SET_BUFOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
+#endif
+#define DUK_HOBJECT_SET_FASTREFS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS)
#define DUK_HOBJECT_SET_ARRAY_PART(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
#define DUK_HOBJECT_SET_STRICT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
#define DUK_HOBJECT_SET_NOTAIL(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
#define DUK_HOBJECT_SET_NEWENV(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
#define DUK_HOBJECT_SET_NAMEBINDING(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
#define DUK_HOBJECT_SET_CREATEARGS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
-#define DUK_HOBJECT_SET_ENVRECCLOSED(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED)
+#define DUK_HOBJECT_SET_HAVE_FINALIZER(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_HAVE_FINALIZER)
#define DUK_HOBJECT_SET_EXOTIC_ARRAY(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
#define DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
#define DUK_HOBJECT_SET_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
-#define DUK_HOBJECT_SET_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC)
+#if defined(DUK_USE_ES6_PROXY)
#define DUK_HOBJECT_SET_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
+#endif
+#define DUK_HOBJECT_SET_SPECIAL_CALL(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL)
#define DUK_HOBJECT_CLEAR_EXTENSIBLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
#define DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
-#define DUK_HOBJECT_CLEAR_BOUND(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND)
-#define DUK_HOBJECT_CLEAR_COMPILEDFUNCTION(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
-#define DUK_HOBJECT_CLEAR_NATIVEFUNCTION(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
-#define DUK_HOBJECT_CLEAR_BUFFEROBJECT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT)
-#define DUK_HOBJECT_CLEAR_THREAD(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
+#define DUK_HOBJECT_CLEAR_CALLABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE)
+#define DUK_HOBJECT_CLEAR_BOUNDFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
+#define DUK_HOBJECT_CLEAR_COMPFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
+#define DUK_HOBJECT_CLEAR_NATFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+#define DUK_HOBJECT_CLEAR_BUFOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
+#endif
+#define DUK_HOBJECT_CLEAR_FASTREFS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS)
#define DUK_HOBJECT_CLEAR_ARRAY_PART(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
#define DUK_HOBJECT_CLEAR_STRICT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
#define DUK_HOBJECT_CLEAR_NOTAIL(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
#define DUK_HOBJECT_CLEAR_NEWENV(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
#define DUK_HOBJECT_CLEAR_NAMEBINDING(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
#define DUK_HOBJECT_CLEAR_CREATEARGS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
-#define DUK_HOBJECT_CLEAR_ENVRECCLOSED(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED)
+#define DUK_HOBJECT_CLEAR_HAVE_FINALIZER(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_HAVE_FINALIZER)
#define DUK_HOBJECT_CLEAR_EXOTIC_ARRAY(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
#define DUK_HOBJECT_CLEAR_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
#define DUK_HOBJECT_CLEAR_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
-#define DUK_HOBJECT_CLEAR_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC)
+#if defined(DUK_USE_ES6_PROXY)
#define DUK_HOBJECT_CLEAR_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
+#endif
+#define DUK_HOBJECT_CLEAR_SPECIAL_CALL(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL)
-/* flags used for property attributes in duk_propdesc and packed flags */
-#define DUK_PROPDESC_FLAG_WRITABLE (1 << 0) /* E5 Section 8.6.1 */
-#define DUK_PROPDESC_FLAG_ENUMERABLE (1 << 1) /* E5 Section 8.6.1 */
-#define DUK_PROPDESC_FLAG_CONFIGURABLE (1 << 2) /* E5 Section 8.6.1 */
-#define DUK_PROPDESC_FLAG_ACCESSOR (1 << 3) /* accessor */
-#define DUK_PROPDESC_FLAG_VIRTUAL (1 << 4) /* property is virtual: used in duk_propdesc, never stored
+/* Object can/cannot use FASTREFS, i.e. has no strong reference fields beyond
+ * duk_hobject base header. This is used just for asserts so doesn't need to
+ * be optimized.
+ */
+#define DUK_HOBJECT_PROHIBITS_FASTREFS(h) \
+ (DUK_HOBJECT_IS_COMPFUNC((h)) || DUK_HOBJECT_IS_DECENV((h)) || DUK_HOBJECT_IS_OBJENV((h)) || \
+ DUK_HOBJECT_IS_BUFOBJ((h)) || DUK_HOBJECT_IS_THREAD((h)) || DUK_HOBJECT_IS_PROXY((h)) || \
+ DUK_HOBJECT_IS_BOUNDFUNC((h)))
+#define DUK_HOBJECT_ALLOWS_FASTREFS(h) (!DUK_HOBJECT_PROHIBITS_FASTREFS((h)))
+
+/* Flags used for property attributes in duk_propdesc and packed flags.
+ * Must fit into 8 bits.
+ */
+#define DUK_PROPDESC_FLAG_WRITABLE (1U << 0) /* E5 Section 8.6.1 */
+#define DUK_PROPDESC_FLAG_ENUMERABLE (1U << 1) /* E5 Section 8.6.1 */
+#define DUK_PROPDESC_FLAG_CONFIGURABLE (1U << 2) /* E5 Section 8.6.1 */
+#define DUK_PROPDESC_FLAG_ACCESSOR (1U << 3) /* accessor */
+#define DUK_PROPDESC_FLAG_VIRTUAL (1U << 4) /* property is virtual: used in duk_propdesc, never stored
* (used by e.g. buffer virtual properties)
*/
#define DUK_PROPDESC_FLAGS_MASK (DUK_PROPDESC_FLAG_WRITABLE | \
@@ -4896,12 +6132,12 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
DUK_PROPDESC_FLAG_CONFIGURABLE | \
DUK_PROPDESC_FLAG_ACCESSOR)
-/* additional flags which are passed in the same flags argument as property
+/* Additional flags which are passed in the same flags argument as property
* flags but are not stored in object properties.
*/
-#define DUK_PROPDESC_FLAG_NO_OVERWRITE (1 << 4) /* internal define property: skip write silently if exists */
+#define DUK_PROPDESC_FLAG_NO_OVERWRITE (1U << 4) /* internal define property: skip write silently if exists */
-/* convenience */
+/* Convenience defines for property attributes. */
#define DUK_PROPDESC_FLAGS_NONE 0
#define DUK_PROPDESC_FLAGS_W (DUK_PROPDESC_FLAG_WRITABLE)
#define DUK_PROPDESC_FLAGS_E (DUK_PROPDESC_FLAG_ENUMERABLE)
@@ -4913,9 +6149,9 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
DUK_PROPDESC_FLAG_ENUMERABLE | \
DUK_PROPDESC_FLAG_CONFIGURABLE)
-/* flags for duk_hobject_get_own_propdesc() and variants */
-#define DUK_GETDESC_FLAG_PUSH_VALUE (1 << 0) /* push value to stack */
-#define DUK_GETDESC_FLAG_IGNORE_PROTOLOOP (1 << 1) /* don't throw for prototype loop */
+/* Flags for duk_hobject_get_own_propdesc() and variants. */
+#define DUK_GETDESC_FLAG_PUSH_VALUE (1U << 0) /* push value to stack */
+#define DUK_GETDESC_FLAG_IGNORE_PROTOLOOP (1U << 1) /* don't throw for prototype loop */
/*
* Macro for object validity check
@@ -4927,9 +6163,8 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
DUK_ASSERT((h) != NULL); \
DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE((h)) || \
DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FUNCTION); \
- DUK_ASSERT(!DUK_HOBJECT_IS_BUFFEROBJECT((h)) || \
- (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_BUFFER || \
- DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAYBUFFER || \
+ DUK_ASSERT(!DUK_HOBJECT_IS_BUFOBJ((h)) || \
+ (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAYBUFFER || \
DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DATAVIEW || \
DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT8ARRAY || \
DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT8ARRAY || \
@@ -4940,6 +6175,9 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT32ARRAY || \
DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FLOAT32ARRAY || \
DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FLOAT64ARRAY)); \
+ /* Object is an Array <=> object has exotic array behavior */ \
+ DUK_ASSERT((DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAY && DUK_HOBJECT_HAS_EXOTIC_ARRAY((h))) || \
+ (DUK_HOBJECT_GET_CLASS_NUMBER((h)) != DUK_HOBJECT_CLASS_ARRAY && !DUK_HOBJECT_HAS_EXOTIC_ARRAY((h)))); \
} while (0)
/*
@@ -5222,9 +6460,6 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
*/
#define DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY 10000L
-/* Maximum traversal depth for "bound function" chains. */
-#define DUK_HOBJECT_BOUND_CHAIN_SANITY 10000L
-
/*
* Ecmascript [[Class]]
*/
@@ -5256,9 +6491,32 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
} while (0)
#endif
-/* note: this updates refcounts */
+/* Set prototype, DECREF earlier value, INCREF new value (tolerating NULLs). */
#define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr,h,p) duk_hobject_set_prototype_updref((thr), (h), (p))
+/* Set initial prototype, assume NULL previous prototype, INCREF new value,
+ * tolerate NULL.
+ */
+#define DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr,h,proto) do { \
+ duk_hthread *duk__thr = (thr); \
+ duk_hobject *duk__obj = (h); \
+ duk_hobject *duk__proto = (proto); \
+ DUK_UNREF(duk__thr); \
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(duk__thr->heap, duk__obj) == NULL); \
+ DUK_HOBJECT_SET_PROTOTYPE(duk__thr->heap, duk__obj, duk__proto); \
+ DUK_HOBJECT_INCREF_ALLOWNULL(duk__thr, duk__proto); \
+ } while (0)
+
+/*
+ * Finalizer check
+ */
+
+#if defined(DUK_USE_HEAPPTR16)
+#define DUK_HOBJECT_HAS_FINALIZER_FAST(heap,h) duk_hobject_has_finalizer_fast_raw((heap), (h))
+#else
+#define DUK_HOBJECT_HAS_FINALIZER_FAST(heap,h) duk_hobject_has_finalizer_fast_raw((h))
+#endif
+
/*
* Resizing and hash behavior
*/
@@ -5272,22 +6530,9 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
#if defined(DUK_USE_OBJSIZES16)
#define DUK_HOBJECT_MAX_PROPERTIES 0x0000ffffUL
#else
-#define DUK_HOBJECT_MAX_PROPERTIES 0x7fffffffUL /* 2**31-1 ~= 2G properties */
+#define DUK_HOBJECT_MAX_PROPERTIES 0x3fffffffUL /* 2**30-1 ~= 1G properties */
#endif
-/* higher value conserves memory; also note that linear scan is cache friendly */
-#define DUK_HOBJECT_E_USE_HASH_LIMIT 32
-
-/* hash size relative to entries size: for value X, approx. hash_prime(e_size + e_size / X) */
-#define DUK_HOBJECT_H_SIZE_DIVISOR 4 /* hash size approx. 1.25 times entries size */
-
-/* if new_size < L * old_size, resize without abandon check; L = 3-bit fixed point, e.g. 9 -> 9/8 = 112.5% */
-#define DUK_HOBJECT_A_FAST_RESIZE_LIMIT 9 /* 112.5%, i.e. new size less than 12.5% higher -> fast resize */
-
-/* if density < L, abandon array part, L = 3-bit fixed point, e.g. 2 -> 2/8 = 25% */
-/* limit is quite low: one array entry is 8 bytes, one normal entry is 4+1+8+4 = 17 bytes (with hash entry) */
-#define DUK_HOBJECT_A_ABANDON_LIMIT 2 /* 25%, i.e. less than 25% used -> abandon */
-
/* internal align target for props allocation, must be 2*n for some n */
#if (DUK_USE_ALIGN_BY == 4)
#define DUK_HOBJECT_ALIGN_TARGET 4
@@ -5299,18 +6544,6 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
#error invalid DUK_USE_ALIGN_BY
#endif
-/* controls for minimum entry part growth */
-#define DUK_HOBJECT_E_MIN_GROW_ADD 16
-#define DUK_HOBJECT_E_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */
-
-/* controls for minimum array part growth */
-#define DUK_HOBJECT_A_MIN_GROW_ADD 16
-#define DUK_HOBJECT_A_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */
-
-/* probe sequence */
-#define DUK_HOBJECT_HASH_INITIAL(hash,h_size) ((hash) % (h_size))
-#define DUK_HOBJECT_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash))
-
/*
* PC-to-line constants
*/
@@ -5340,7 +6573,7 @@ union duk_propvalue {
struct duk_propdesc {
/* read-only values 'lifted' for ease of use */
- duk_small_int_t flags;
+ duk_small_uint_t flags;
duk_hobject *get;
duk_hobject *set;
@@ -5421,7 +6654,7 @@ struct duk_hobject {
#if defined(DUK_USE_HEAPPTR16)
/* Located in duk_heaphdr h_extra16. Subclasses of duk_hobject (like
- * duk_hcompiledfunction) are not free to use h_extra16 for this reason.
+ * duk_hcompfunc) are not free to use h_extra16 for this reason.
*/
#else
duk_uint8_t *props;
@@ -5464,19 +6697,41 @@ DUK_INTERNAL_DECL duk_uint8_t duk_class_number_to_stridx[32];
*/
/* alloc and init */
-DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags);
-#if 0 /* unused */
-DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags);
+DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags);
+DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
+DUK_INTERNAL_DECL duk_harray *duk_harray_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
+DUK_INTERNAL_DECL duk_hcompfunc *duk_hcompfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
+DUK_INTERNAL_DECL duk_hnatfunc *duk_hnatfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
+DUK_INTERNAL_DECL duk_hboundfunc *duk_hboundfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags);
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+DUK_INTERNAL_DECL duk_hbufobj *duk_hbufobj_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
+#endif
+DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags);
+DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
+DUK_INTERNAL_DECL duk_hdecenv *duk_hdecenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
+DUK_INTERNAL_DECL duk_hobjenv *duk_hobjenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
+DUK_INTERNAL_DECL duk_hproxy *duk_hproxy_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
+
+/* resize */
+DUK_INTERNAL_DECL void duk_hobject_realloc_props(duk_hthread *thr,
+ duk_hobject *obj,
+ duk_uint32_t new_e_size,
+ duk_uint32_t new_a_size,
+ duk_uint32_t new_h_size,
+ duk_bool_t abandon_array);
+DUK_INTERNAL_DECL void duk_hobject_resize_entrypart(duk_hthread *thr,
+ duk_hobject *obj,
+ duk_uint32_t new_e_size);
+#if 0 /*unused*/
+DUK_INTERNAL_DECL void duk_hobject_resize_arraypart(duk_hthread *thr,
+ duk_hobject *obj,
+ duk_uint32_t new_a_size);
#endif
-DUK_INTERNAL_DECL duk_hcompiledfunction *duk_hcompiledfunction_alloc(duk_heap *heap, duk_uint_t hobject_flags);
-DUK_INTERNAL_DECL duk_hnativefunction *duk_hnativefunction_alloc(duk_heap *heap, duk_uint_t hobject_flags);
-DUK_INTERNAL duk_hbufferobject *duk_hbufferobject_alloc(duk_heap *heap, duk_uint_t hobject_flags);
-DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc(duk_heap *heap, duk_uint_t hobject_flags);
/* low-level property functions */
-DUK_INTERNAL_DECL void duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx);
+DUK_INTERNAL_DECL duk_bool_t duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx);
DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key);
-DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *out_attrs);
+DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_uint_t *out_attrs);
DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_array_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_uarridx_t i);
DUK_INTERNAL_DECL duk_bool_t duk_hobject_get_own_propdesc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, duk_small_uint_t flags);
@@ -5493,39 +6748,40 @@ DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_
DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key);
/* internal property functions */
-#define DUK_DELPROP_FLAG_THROW (1 << 0)
-#define DUK_DELPROP_FLAG_FORCE (1 << 1)
+#define DUK_DELPROP_FLAG_THROW (1U << 0)
+#define DUK_DELPROP_FLAG_FORCE (1U << 1)
DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags);
DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key);
DUK_INTERNAL_DECL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags);
DUK_INTERNAL_DECL void duk_hobject_define_property_internal_arridx(duk_hthread *thr, duk_hobject *obj, duk_uarridx_t arr_idx, duk_small_uint_t flags);
-DUK_INTERNAL_DECL void duk_hobject_define_accessor_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_hobject *getter, duk_hobject *setter, duk_small_uint_t propflags);
-DUK_INTERNAL_DECL void duk_hobject_set_length(duk_hthread *thr, duk_hobject *obj, duk_uint32_t length); /* XXX: duk_uarridx_t? */
-DUK_INTERNAL_DECL void duk_hobject_set_length_zero(duk_hthread *thr, duk_hobject *obj);
-DUK_INTERNAL_DECL duk_uint32_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj); /* XXX: duk_uarridx_t? */
+DUK_INTERNAL_DECL duk_size_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj);
+#if defined(DUK_USE_HEAPPTR16)
+DUK_INTERNAL_DECL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_heap *heap, duk_hobject *obj);
+#else
+DUK_INTERNAL_DECL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_hobject *obj);
+#endif
/* helpers for defineProperty() and defineProperties() */
-DUK_INTERNAL_DECL
-void duk_hobject_prepare_property_descriptor(duk_context *ctx,
- duk_idx_t idx_in,
- duk_uint_t *out_defprop_flags,
- duk_idx_t *out_idx_value,
- duk_hobject **out_getter,
- duk_hobject **out_setter);
-DUK_INTERNAL_DECL
-void duk_hobject_define_property_helper(duk_context *ctx,
- duk_uint_t defprop_flags,
- duk_hobject *obj,
- duk_hstring *key,
- duk_idx_t idx_value,
- duk_hobject *get,
- duk_hobject *set);
+DUK_INTERNAL_DECL void duk_hobject_prepare_property_descriptor(duk_hthread *thr,
+ duk_idx_t idx_in,
+ duk_uint_t *out_defprop_flags,
+ duk_idx_t *out_idx_value,
+ duk_hobject **out_getter,
+ duk_hobject **out_setter);
+DUK_INTERNAL_DECL duk_bool_t duk_hobject_define_property_helper(duk_hthread *thr,
+ duk_uint_t defprop_flags,
+ duk_hobject *obj,
+ duk_hstring *key,
+ duk_idx_t idx_value,
+ duk_hobject *get,
+ duk_hobject *set,
+ duk_bool_t throw_flag);
/* Object built-in methods */
-DUK_INTERNAL_DECL duk_ret_t duk_hobject_object_get_own_property_descriptor(duk_context *ctx);
+DUK_INTERNAL_DECL void duk_hobject_object_get_own_property_descriptor(duk_hthread *thr, duk_idx_t obj_idx);
DUK_INTERNAL_DECL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze);
DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen);
-DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_ownprop_helper(duk_context *ctx, duk_small_uint_t required_desc_flags);
+DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_ownprop_helper(duk_hthread *thr, duk_small_uint_t required_desc_flags);
/* internal properties */
DUK_INTERNAL_DECL duk_bool_t duk_hobject_get_internal_value(duk_heap *heap, duk_hobject *obj, duk_tval *tv);
@@ -5534,34 +6790,40 @@ DUK_INTERNAL_DECL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *h
/* hobject management functions */
DUK_INTERNAL_DECL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj);
-/* ES6 proxy */
+/* ES2015 proxy */
#if defined(DUK_USE_ES6_PROXY)
-DUK_INTERNAL_DECL duk_bool_t duk_hobject_proxy_check(duk_hthread *thr, duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler);
-DUK_INTERNAL_DECL duk_hobject *duk_hobject_resolve_proxy_target(duk_hthread *thr, duk_hobject *obj);
+DUK_INTERNAL_DECL duk_bool_t duk_hobject_proxy_check(duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler);
+DUK_INTERNAL_DECL duk_hobject *duk_hobject_resolve_proxy_target(duk_hobject *obj);
#endif
/* enumeration */
-DUK_INTERNAL_DECL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint_t enum_flags);
-DUK_INTERNAL_DECL duk_ret_t duk_hobject_get_enumerated_keys(duk_context *ctx, duk_small_uint_t enum_flags);
-DUK_INTERNAL_DECL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_bool_t get_value);
+DUK_INTERNAL_DECL void duk_hobject_enumerator_create(duk_hthread *thr, duk_small_uint_t enum_flags);
+DUK_INTERNAL_DECL duk_ret_t duk_hobject_get_enumerated_keys(duk_hthread *thr, duk_small_uint_t enum_flags);
+DUK_INTERNAL_DECL duk_bool_t duk_hobject_enumerator_next(duk_hthread *thr, duk_bool_t get_value);
/* macros */
DUK_INTERNAL_DECL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p);
-/* finalization */
-DUK_INTERNAL_DECL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj);
-
/* pc2line */
#if defined(DUK_USE_PC2LINE)
DUK_INTERNAL_DECL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length);
-DUK_INTERNAL_DECL duk_uint_fast32_t duk_hobject_pc2line_query(duk_context *ctx, duk_idx_t idx_func, duk_uint_fast32_t pc);
+DUK_INTERNAL_DECL duk_uint_fast32_t duk_hobject_pc2line_query(duk_hthread *thr, duk_idx_t idx_func, duk_uint_fast32_t pc);
#endif
/* misc */
DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop);
+#if !defined(DUK_USE_OBJECT_BUILTIN)
+/* These declarations are needed when related built-in is disabled and
+ * genbuiltins.py won't automatically emit the declerations.
+ */
+DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_hthread *thr);
+#endif
+
#endif /* DUK_HOBJECT_H_INCLUDED */
-#line 1 "duk_hcompiledfunction.h"
+/* #include duk_hcompfunc.h */
+#line 1 "duk_hcompfunc.h"
/*
* Heap compiled function (Ecmascript function) representation.
*
@@ -5569,8 +6831,8 @@ DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *t
* bytecode, constants, and inner functions.
*/
-#ifndef DUK_HCOMPILEDFUNCTION_H_INCLUDED
-#define DUK_HCOMPILEDFUNCTION_H_INCLUDED
+#if !defined(DUK_HCOMPFUNC_H_INCLUDED)
+#define DUK_HCOMPFUNC_H_INCLUDED
/*
* Field accessor macros
@@ -5579,37 +6841,52 @@ DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *t
/* XXX: casts could be improved, especially for GET/SET DATA */
#if defined(DUK_USE_HEAPPTR16)
-#define DUK_HCOMPILEDFUNCTION_GET_DATA(heap,h) \
+#define DUK_HCOMPFUNC_GET_DATA(heap,h) \
((duk_hbuffer_fixed *) (void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->data16))
-#define DUK_HCOMPILEDFUNCTION_SET_DATA(heap,h,v) do { \
+#define DUK_HCOMPFUNC_SET_DATA(heap,h,v) do { \
(h)->data16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
} while (0)
-#define DUK_HCOMPILEDFUNCTION_GET_FUNCS(heap,h) \
+#define DUK_HCOMPFUNC_GET_FUNCS(heap,h) \
((duk_hobject **) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->funcs16)))
-#define DUK_HCOMPILEDFUNCTION_SET_FUNCS(heap,h,v) do { \
+#define DUK_HCOMPFUNC_SET_FUNCS(heap,h,v) do { \
(h)->funcs16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
} while (0)
-#define DUK_HCOMPILEDFUNCTION_GET_BYTECODE(heap,h) \
+#define DUK_HCOMPFUNC_GET_BYTECODE(heap,h) \
((duk_instr_t *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->bytecode16)))
-#define DUK_HCOMPILEDFUNCTION_SET_BYTECODE(heap,h,v) do { \
+#define DUK_HCOMPFUNC_SET_BYTECODE(heap,h,v) do { \
(h)->bytecode16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
} while (0)
+#define DUK_HCOMPFUNC_GET_LEXENV(heap,h) \
+ ((duk_hobject *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->lex_env16)))
+#define DUK_HCOMPFUNC_SET_LEXENV(heap,h,v) do { \
+ (h)->lex_env16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
+ } while (0)
+#define DUK_HCOMPFUNC_GET_VARENV(heap,h) \
+ ((duk_hobject *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->var_env16)))
+#define DUK_HCOMPFUNC_SET_VARENV(heap,h,v) do { \
+ (h)->var_env16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
+ } while (0)
#else
-#define DUK_HCOMPILEDFUNCTION_GET_DATA(heap,h) \
- ((duk_hbuffer_fixed *) (void *) (h)->data)
-#define DUK_HCOMPILEDFUNCTION_SET_DATA(heap,h,v) do { \
+#define DUK_HCOMPFUNC_GET_DATA(heap,h) ((duk_hbuffer_fixed *) (void *) (h)->data)
+#define DUK_HCOMPFUNC_SET_DATA(heap,h,v) do { \
(h)->data = (duk_hbuffer *) (v); \
} while (0)
-#define DUK_HCOMPILEDFUNCTION_GET_FUNCS(heap,h) \
- ((h)->funcs)
-#define DUK_HCOMPILEDFUNCTION_SET_FUNCS(heap,h,v) do { \
+#define DUK_HCOMPFUNC_GET_FUNCS(heap,h) ((h)->funcs)
+#define DUK_HCOMPFUNC_SET_FUNCS(heap,h,v) do { \
(h)->funcs = (v); \
} while (0)
-#define DUK_HCOMPILEDFUNCTION_GET_BYTECODE(heap,h) \
- ((h)->bytecode)
-#define DUK_HCOMPILEDFUNCTION_SET_BYTECODE(heap,h,v) do { \
+#define DUK_HCOMPFUNC_GET_BYTECODE(heap,h) ((h)->bytecode)
+#define DUK_HCOMPFUNC_SET_BYTECODE(heap,h,v) do { \
(h)->bytecode = (v); \
} while (0)
+#define DUK_HCOMPFUNC_GET_LEXENV(heap,h) ((h)->lex_env)
+#define DUK_HCOMPFUNC_SET_LEXENV(heap,h,v) do { \
+ (h)->lex_env = (v); \
+ } while (0)
+#define DUK_HCOMPFUNC_GET_VARENV(heap,h) ((h)->var_env)
+#define DUK_HCOMPFUNC_SET_VARENV(heap,h,v) do { \
+ (h)->var_env = (v); \
+ } while (0)
#endif
/*
@@ -5617,71 +6894,78 @@ DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *t
*/
/* Note: assumes 'data' is always a fixed buffer */
-#define DUK_HCOMPILEDFUNCTION_GET_BUFFER_BASE(heap,h) \
- DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPILEDFUNCTION_GET_DATA((heap), (h)))
+#define DUK_HCOMPFUNC_GET_BUFFER_BASE(heap,h) \
+ DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPFUNC_GET_DATA((heap), (h)))
-#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap,h) \
- ((duk_tval *) (void *) DUK_HCOMPILEDFUNCTION_GET_BUFFER_BASE((heap), (h)))
+#define DUK_HCOMPFUNC_GET_CONSTS_BASE(heap,h) \
+ ((duk_tval *) (void *) DUK_HCOMPFUNC_GET_BUFFER_BASE((heap), (h)))
-#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap,h) \
- DUK_HCOMPILEDFUNCTION_GET_FUNCS((heap), (h))
+#define DUK_HCOMPFUNC_GET_FUNCS_BASE(heap,h) \
+ DUK_HCOMPFUNC_GET_FUNCS((heap), (h))
-#define DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(heap,h) \
- DUK_HCOMPILEDFUNCTION_GET_BYTECODE((heap), (h))
+#define DUK_HCOMPFUNC_GET_CODE_BASE(heap,h) \
+ DUK_HCOMPFUNC_GET_BYTECODE((heap), (h))
-#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(heap,h) \
- ((duk_tval *) (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS((heap), (h)))
+#define DUK_HCOMPFUNC_GET_CONSTS_END(heap,h) \
+ ((duk_tval *) (void *) DUK_HCOMPFUNC_GET_FUNCS((heap), (h)))
-#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(heap,h) \
- ((duk_hobject **) (void *) DUK_HCOMPILEDFUNCTION_GET_BYTECODE((heap), (h)))
+#define DUK_HCOMPFUNC_GET_FUNCS_END(heap,h) \
+ ((duk_hobject **) (void *) DUK_HCOMPFUNC_GET_BYTECODE((heap), (h)))
-/* XXX: double evaluation of DUK_HCOMPILEDFUNCTION_GET_DATA() */
-#define DUK_HCOMPILEDFUNCTION_GET_CODE_END(heap,h) \
- ((duk_instr_t *) (void *) (DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPILEDFUNCTION_GET_DATA((heap), (h))) + \
- DUK_HBUFFER_GET_SIZE((duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA((heap), h))))
+/* XXX: double evaluation of DUK_HCOMPFUNC_GET_DATA() */
+#define DUK_HCOMPFUNC_GET_CODE_END(heap,h) \
+ ((duk_instr_t *) (void *) (DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPFUNC_GET_DATA((heap), (h))) + \
+ DUK_HBUFFER_GET_SIZE((duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA((heap), h))))
-#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE(heap,h) \
+#define DUK_HCOMPFUNC_GET_CONSTS_SIZE(heap,h) \
( \
(duk_size_t) \
( \
- ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_END((heap), (h))) - \
- ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE((heap), (h))) \
+ ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CONSTS_END((heap), (h))) - \
+ ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CONSTS_BASE((heap), (h))) \
) \
)
-#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE(heap,h) \
+#define DUK_HCOMPFUNC_GET_FUNCS_SIZE(heap,h) \
( \
(duk_size_t) \
( \
- ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END((heap), (h))) - \
- ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE((heap), (h))) \
+ ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_FUNCS_END((heap), (h))) - \
+ ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_FUNCS_BASE((heap), (h))) \
) \
)
-#define DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(heap,h) \
+#define DUK_HCOMPFUNC_GET_CODE_SIZE(heap,h) \
( \
(duk_size_t) \
( \
- ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_END((heap),(h))) - \
- ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE((heap),(h))) \
+ ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CODE_END((heap),(h))) - \
+ ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CODE_BASE((heap),(h))) \
) \
)
-#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(heap,h) \
- ((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE((heap), (h)) / sizeof(duk_tval)))
+#define DUK_HCOMPFUNC_GET_CONSTS_COUNT(heap,h) \
+ ((duk_size_t) (DUK_HCOMPFUNC_GET_CONSTS_SIZE((heap), (h)) / sizeof(duk_tval)))
-#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(heap,h) \
- ((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE((heap), (h)) / sizeof(duk_hobject *)))
+#define DUK_HCOMPFUNC_GET_FUNCS_COUNT(heap,h) \
+ ((duk_size_t) (DUK_HCOMPFUNC_GET_FUNCS_SIZE((heap), (h)) / sizeof(duk_hobject *)))
-#define DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(heap,h) \
- ((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE((heap), (h)) / sizeof(duk_instr_t)))
+#define DUK_HCOMPFUNC_GET_CODE_COUNT(heap,h) \
+ ((duk_size_t) (DUK_HCOMPFUNC_GET_CODE_SIZE((heap), (h)) / sizeof(duk_instr_t)))
+/*
+ * Validity assert
+ */
+
+#define DUK_ASSERT_HCOMPFUNC_VALID(h) do { \
+ DUK_ASSERT((h) != NULL); \
+ } while (0)
/*
* Main struct
*/
-struct duk_hcompiledfunction {
+struct duk_hcompfunc {
/* shared object part */
duk_hobject obj;
@@ -5728,6 +7012,17 @@ struct duk_hcompiledfunction {
duk_instr_t *bytecode;
#endif
+ /* Lexenv: lexical environment of closure, NULL for templates.
+ * Varenv: variable environment of closure, NULL for templates.
+ */
+#if defined(DUK_USE_HEAPPTR16)
+ duk_uint16_t lex_env16;
+ duk_uint16_t var_env16;
+#else
+ duk_hobject *lex_env;
+ duk_hobject *var_env;
+#endif
+
/*
* 'nregs' registers are allocated on function entry, at most 'nargs'
* are initialized to arguments, and the rest to undefined. Arguments
@@ -5783,8 +7078,6 @@ struct duk_hcompiledfunction {
* _Formals: [ "arg1", "arg2" ],
* _Source: "function func(arg1, arg2) { ... }",
* _Pc2line: ,
- * _Varenv: ,
- * _Lexenv:
* }
*
* More detailed description of these properties can be found
@@ -5800,19 +7093,20 @@ struct duk_hcompiledfunction {
#endif
};
-#endif /* DUK_HCOMPILEDFUNCTION_H_INCLUDED */
-#line 1 "duk_hnativefunction.h"
+#endif /* DUK_HCOMPFUNC_H_INCLUDED */
+/* #include duk_hnatfunc.h */
+#line 1 "duk_hnatfunc.h"
/*
* Heap native function representation.
*/
-#ifndef DUK_HNATIVEFUNCTION_H_INCLUDED
-#define DUK_HNATIVEFUNCTION_H_INCLUDED
+#if !defined(DUK_HNATFUNC_H_INCLUDED)
+#define DUK_HNATFUNC_H_INCLUDED
-#define DUK_HNATIVEFUNCTION_NARGS_VARARGS ((duk_int16_t) -1)
-#define DUK_HNATIVEFUNCTION_NARGS_MAX ((duk_int16_t) 0x7fff)
+#define DUK_HNATFUNC_NARGS_VARARGS ((duk_int16_t) -1)
+#define DUK_HNATFUNC_NARGS_MAX ((duk_int16_t) 0x7fff)
-struct duk_hnativefunction {
+struct duk_hnatfunc {
/* shared object part */
duk_hobject obj;
@@ -5829,46 +7123,91 @@ struct duk_hnativefunction {
* versa.
*
* Note: cannot place nargs/magic into the heaphdr flags, because
- * duk_hobject takes almost all flags already (and needs the spare).
+ * duk_hobject takes almost all flags already.
*/
};
-#endif /* DUK_HNATIVEFUNCTION_H_INCLUDED */
-#line 1 "duk_hbufferobject.h"
+#endif /* DUK_HNATFUNC_H_INCLUDED */
+/* #include duk_hboundfunc.h */
+#line 1 "duk_hboundfunc.h"
+/*
+ * Bound function representation.
+ */
+
+#if !defined(DUK_HBOUNDFUNC_H_INCLUDED)
+#define DUK_HBOUNDFUNC_H_INCLUDED
+
+/* Artificial limit for args length. Ensures arithmetic won't overflow
+ * 32 bits when combining bound functions.
+ */
+#define DUK_HBOUNDFUNC_MAX_ARGS 0x20000000UL
+
+#define DUK_ASSERT_HBOUNDFUNC_VALID(h) do { \
+ DUK_ASSERT((h) != NULL); \
+ DUK_ASSERT(DUK_HOBJECT_IS_BOUNDFUNC((duk_hobject *) (h))); \
+ DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(&(h)->target) || \
+ (DUK_TVAL_IS_OBJECT(&(h)->target) && \
+ DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(&(h)->target)))); \
+ DUK_ASSERT(!DUK_TVAL_IS_UNUSED(&(h)->this_binding)); \
+ DUK_ASSERT((h)->nargs == 0 || (h)->args != NULL); \
+ } while (0)
+
+struct duk_hboundfunc {
+ /* Shared object part. */
+ duk_hobject obj;
+
+ /* Final target function, stored as duk_tval so that lightfunc can be
+ * represented too.
+ */
+ duk_tval target;
+
+ /* This binding. */
+ duk_tval this_binding;
+
+ /* Arguments to prepend. */
+ duk_tval *args; /* Separate allocation. */
+ duk_idx_t nargs;
+};
+
+#endif /* DUK_HBOUNDFUNC_H_INCLUDED */
+/* #include duk_hbufobj.h */
+#line 1 "duk_hbufobj.h"
/*
* Heap Buffer object representation. Used for all Buffer variants.
*/
-#ifndef DUK_HBUFFEROBJECT_H_INCLUDED
-#define DUK_HBUFFEROBJECT_H_INCLUDED
+#if !defined(DUK_HBUFOBJ_H_INCLUDED)
+#define DUK_HBUFOBJ_H_INCLUDED
+
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
/* All element accessors are host endian now (driven by TypedArray spec). */
-#define DUK_HBUFFEROBJECT_ELEM_UINT8 0
-#define DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED 1
-#define DUK_HBUFFEROBJECT_ELEM_INT8 2
-#define DUK_HBUFFEROBJECT_ELEM_UINT16 3
-#define DUK_HBUFFEROBJECT_ELEM_INT16 4
-#define DUK_HBUFFEROBJECT_ELEM_UINT32 5
-#define DUK_HBUFFEROBJECT_ELEM_INT32 6
-#define DUK_HBUFFEROBJECT_ELEM_FLOAT32 7
-#define DUK_HBUFFEROBJECT_ELEM_FLOAT64 8
-#define DUK_HBUFFEROBJECT_ELEM_MAX 8
+#define DUK_HBUFOBJ_ELEM_UINT8 0
+#define DUK_HBUFOBJ_ELEM_UINT8CLAMPED 1
+#define DUK_HBUFOBJ_ELEM_INT8 2
+#define DUK_HBUFOBJ_ELEM_UINT16 3
+#define DUK_HBUFOBJ_ELEM_INT16 4
+#define DUK_HBUFOBJ_ELEM_UINT32 5
+#define DUK_HBUFOBJ_ELEM_INT32 6
+#define DUK_HBUFOBJ_ELEM_FLOAT32 7
+#define DUK_HBUFOBJ_ELEM_FLOAT64 8
+#define DUK_HBUFOBJ_ELEM_MAX 8
-#define DUK_ASSERT_HBUFFEROBJECT_VALID(h) do { \
+#define DUK_ASSERT_HBUFOBJ_VALID(h) do { \
DUK_ASSERT((h) != NULL); \
DUK_ASSERT((h)->shift <= 3); \
- DUK_ASSERT((h)->elem_type <= DUK_HBUFFEROBJECT_ELEM_MAX); \
- DUK_ASSERT(((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8) || \
- ((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED) || \
- ((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT8) || \
- ((h)->shift == 1 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT16) || \
- ((h)->shift == 1 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT16) || \
- ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT32) || \
- ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT32) || \
- ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_FLOAT32) || \
- ((h)->shift == 3 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_FLOAT64)); \
- DUK_ASSERT((h)->is_view == 0 || (h)->is_view == 1); \
- DUK_ASSERT(DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) (h))); \
+ DUK_ASSERT((h)->elem_type <= DUK_HBUFOBJ_ELEM_MAX); \
+ DUK_ASSERT(((h)->shift == 0 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT8) || \
+ ((h)->shift == 0 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT8CLAMPED) || \
+ ((h)->shift == 0 && (h)->elem_type == DUK_HBUFOBJ_ELEM_INT8) || \
+ ((h)->shift == 1 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT16) || \
+ ((h)->shift == 1 && (h)->elem_type == DUK_HBUFOBJ_ELEM_INT16) || \
+ ((h)->shift == 2 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT32) || \
+ ((h)->shift == 2 && (h)->elem_type == DUK_HBUFOBJ_ELEM_INT32) || \
+ ((h)->shift == 2 && (h)->elem_type == DUK_HBUFOBJ_ELEM_FLOAT32) || \
+ ((h)->shift == 3 && (h)->elem_type == DUK_HBUFOBJ_ELEM_FLOAT64)); \
+ DUK_ASSERT((h)->is_typedarray == 0 || (h)->is_typedarray == 1); \
+ DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) (h))); \
if ((h)->buf == NULL) { \
DUK_ASSERT((h)->offset == 0); \
DUK_ASSERT((h)->length == 0); \
@@ -5884,58 +7223,64 @@ struct duk_hnativefunction {
/* Get the current data pointer (caller must ensure buf != NULL) as a
* duk_uint8_t ptr.
*/
-#define DUK_HBUFFEROBJECT_GET_SLICE_BASE(heap,h) \
+#define DUK_HBUFOBJ_GET_SLICE_BASE(heap,h) \
(DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
(((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR((heap), (h)->buf)) + (h)->offset))
/* True if slice is full, i.e. offset is zero and length covers the entire
- * buffer. This status may change independently of the duk_hbufferobject if
- * the underlying buffer is dynamic and changes without the hbufferobject
+ * buffer. This status may change independently of the duk_hbufobj if
+ * the underlying buffer is dynamic and changes without the hbufobj
* being changed.
*/
-#define DUK_HBUFFEROBJECT_FULL_SLICE(h) \
+#define DUK_HBUFOBJ_FULL_SLICE(h) \
(DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
((h)->offset == 0 && (h)->length == DUK_HBUFFER_GET_SIZE((h)->buf)))
/* Validate that the whole slice [0,length[ is contained in the underlying
* buffer. Caller must ensure 'buf' != NULL.
*/
-#define DUK_HBUFFEROBJECT_VALID_SLICE(h) \
+#define DUK_HBUFOBJ_VALID_SLICE(h) \
(DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
((h)->offset + (h)->length <= DUK_HBUFFER_GET_SIZE((h)->buf)))
/* Validate byte read/write for virtual 'offset', i.e. check that the
* offset, taking into account h->offset, is within the underlying
* buffer size. This is a safety check which is needed to ensure
- * that even a misconfigured duk_hbufferobject never causes memory
- * unsafe behavior (e.g. if an underlying dynamic buffer changes
- * after being setup). Caller must ensure 'buf' != NULL.
+ * that even a misconfigured duk_hbufobj never causes memory unsafe
+ * behavior (e.g. if an underlying dynamic buffer changes after being
+ * setup). Caller must ensure 'buf' != NULL.
*/
-#define DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_INCL(h,off) \
+#define DUK_HBUFOBJ_VALID_BYTEOFFSET_INCL(h,off) \
(DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
((h)->offset + (off) < DUK_HBUFFER_GET_SIZE((h)->buf)))
-#define DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h,off) \
+#define DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h,off) \
(DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
((h)->offset + (off) <= DUK_HBUFFER_GET_SIZE((h)->buf)))
/* Clamp an input byte length (already assumed to be within the nominal
- * duk_hbufferobject 'length') to the current dynamic buffer limits to
- * yield a byte length limit that's safe for memory accesses. This value
- * can be invalidated by any side effect because it may trigger a user
+ * duk_hbufobj 'length') to the current dynamic buffer limits to yield
+ * a byte length limit that's safe for memory accesses. This value can
+ * be invalidated by any side effect because it may trigger a user
* callback that resizes the underlying buffer.
*/
-#define DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h,len) \
+#define DUK_HBUFOBJ_CLAMP_BYTELENGTH(h,len) \
(DUK_ASSERT_EXPR((h) != NULL), \
- duk_hbufferobject_clamp_bytelength((h), (len)))
+ duk_hbufobj_clamp_bytelength((h), (len)))
-struct duk_hbufferobject {
+/* Typed arrays have virtual indices, ArrayBuffer and DataView do not. */
+#define DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h) ((h)->is_typedarray)
+
+struct duk_hbufobj {
/* Shared object part. */
duk_hobject obj;
/* Underlying buffer (refcounted), may be NULL. */
duk_hbuffer *buf;
+ /* .buffer reference to an ArrayBuffer, may be NULL. */
+ duk_hobject *buf_prop;
+
/* Slice and accessor information.
*
* Because the underlying buffer may be dynamic, these may be
@@ -5958,86 +7303,74 @@ struct duk_hbufferobject {
* 3 = double
*/
duk_uint8_t elem_type; /* element type */
- duk_uint8_t is_view;
+ duk_uint8_t is_typedarray;
};
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL_DECL duk_uint_t duk_hbufferobject_clamp_bytelength(duk_hbufferobject *h_bufobj, duk_uint_t len);
-#endif
-DUK_INTERNAL_DECL void duk_hbufferobject_push_validated_read(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size);
-DUK_INTERNAL_DECL void duk_hbufferobject_validated_write(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size);
+DUK_INTERNAL_DECL duk_uint_t duk_hbufobj_clamp_bytelength(duk_hbufobj *h_bufobj, duk_uint_t len);
+DUK_INTERNAL_DECL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_hbuffer *h_buf);
+DUK_INTERNAL_DECL void duk_hbufobj_push_validated_read(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size);
+DUK_INTERNAL_DECL void duk_hbufobj_validated_write(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size);
+DUK_INTERNAL_DECL void duk_hbufobj_promote_plain(duk_hthread *thr, duk_idx_t idx);
-#endif /* DUK_HBUFFEROBJECT_H_INCLUDED */
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
+#endif /* DUK_HBUFOBJ_H_INCLUDED */
+/* #include duk_hthread.h */
#line 1 "duk_hthread.h"
/*
* Heap thread object representation.
*
- * duk_hthread is also the 'context' (duk_context) for exposed APIs
- * which mostly operate on the topmost frame of the value stack.
+ * duk_hthread is also the 'context' for public API functions via a
+ * different typedef. Most API calls operate on the topmost frame
+ * of the value stack only.
*/
-#ifndef DUK_HTHREAD_H_INCLUDED
+#if !defined(DUK_HTHREAD_H_INCLUDED)
#define DUK_HTHREAD_H_INCLUDED
/*
* Stack constants
*/
-#define DUK_VALSTACK_GROW_STEP 128 /* roughly 1 kiB */
-#define DUK_VALSTACK_SHRINK_THRESHOLD 256 /* roughly 2 kiB */
-#define DUK_VALSTACK_SHRINK_SPARE 64 /* roughly 0.5 kiB */
-#define DUK_VALSTACK_INITIAL_SIZE 128 /* roughly 1.0 kiB -> but rounds up to DUK_VALSTACK_GROW_STEP in practice */
-#define DUK_VALSTACK_INTERNAL_EXTRA 64 /* internal extra elements assumed on function entry,
- * always added to user-defined 'extra' for e.g. the
- * duk_check_stack() call.
- */
-#define DUK_VALSTACK_API_ENTRY_MINIMUM DUK_API_ENTRY_STACK
- /* number of elements guaranteed to be user accessible
- * (in addition to call arguments) on Duktape/C function entry.
- */
+/* Initial valstack size, roughly 0.7kiB. */
+#define DUK_VALSTACK_INITIAL_SIZE 96U
-/* Note: DUK_VALSTACK_INITIAL_SIZE must be >= DUK_VALSTACK_API_ENTRY_MINIMUM
- * + DUK_VALSTACK_INTERNAL_EXTRA so that the initial stack conforms to spare
- * requirements.
+/* Internal extra elements assumed on function entry, always added to
+ * user-defined 'extra' for e.g. the duk_check_stack() call.
*/
+#define DUK_VALSTACK_INTERNAL_EXTRA 32U
-#define DUK_VALSTACK_DEFAULT_MAX 1000000L
-
-#define DUK_CALLSTACK_GROW_STEP 8 /* roughly 256 bytes */
-#define DUK_CALLSTACK_SHRINK_THRESHOLD 16 /* roughly 512 bytes */
-#define DUK_CALLSTACK_SHRINK_SPARE 8 /* roughly 256 bytes */
-#define DUK_CALLSTACK_INITIAL_SIZE 8
-#define DUK_CALLSTACK_DEFAULT_MAX 10000L
-
-#define DUK_CATCHSTACK_GROW_STEP 4 /* roughly 64 bytes */
-#define DUK_CATCHSTACK_SHRINK_THRESHOLD 8 /* roughly 128 bytes */
-#define DUK_CATCHSTACK_SHRINK_SPARE 4 /* roughly 64 bytes */
-#define DUK_CATCHSTACK_INITIAL_SIZE 4
-#define DUK_CATCHSTACK_DEFAULT_MAX 10000L
+/* Number of elements guaranteed to be user accessible (in addition to call
+ * arguments) on Duktape/C function entry. This is the major public API
+ * commitment.
+ */
+#define DUK_VALSTACK_API_ENTRY_MINIMUM DUK_API_ENTRY_STACK
/*
* Activation defines
*/
-#define DUK_ACT_FLAG_STRICT (1 << 0) /* function executes in strict mode */
-#define DUK_ACT_FLAG_TAILCALLED (1 << 1) /* activation has tail called one or more times */
-#define DUK_ACT_FLAG_CONSTRUCT (1 << 2) /* function executes as a constructor (called via "new") */
-#define DUK_ACT_FLAG_PREVENT_YIELD (1 << 3) /* activation prevents yield (native call or "new") */
-#define DUK_ACT_FLAG_DIRECT_EVAL (1 << 4) /* activation is a direct eval call */
-#define DUK_ACT_FLAG_BREAKPOINT_ACTIVE (1 << 5) /* activation has active breakpoint(s) */
+#define DUK_ACT_FLAG_STRICT (1U << 0) /* function executes in strict mode */
+#define DUK_ACT_FLAG_TAILCALLED (1U << 1) /* activation has tail called one or more times */
+#define DUK_ACT_FLAG_CONSTRUCT (1U << 2) /* function executes as a constructor (called via "new") */
+#define DUK_ACT_FLAG_PREVENT_YIELD (1U << 3) /* activation prevents yield (native call or "new") */
+#define DUK_ACT_FLAG_DIRECT_EVAL (1U << 4) /* activation is a direct eval call */
+#define DUK_ACT_FLAG_CONSTRUCT_PROXY (1U << 5) /* activation is for Proxy 'construct' call, special return value handling */
+#define DUK_ACT_FLAG_BREAKPOINT_ACTIVE (1U << 6) /* activation has active breakpoint(s) */
-#define DUK_ACT_GET_FUNC(act) ((act)->func)
+#define DUK_ACT_GET_FUNC(act) ((act)->func)
/*
* Flags for __FILE__ / __LINE__ registered into tracedata
*/
-#define DUK_TB_FLAG_NOBLAME_FILELINE (1 << 0) /* don't report __FILE__ / __LINE__ as fileName/lineNumber */
+#define DUK_TB_FLAG_NOBLAME_FILELINE (1U << 0) /* don't report __FILE__ / __LINE__ as fileName/lineNumber */
/*
* Catcher defines
*/
+/* XXX: remove catcher type entirely */
+
/* flags field: LLLLLLFT, L = label (24 bits), F = flags (4 bits), T = type (4 bits) */
#define DUK_CAT_TYPE_MASK 0x0000000fUL
#define DUK_CAT_TYPE_BITS 4
@@ -6045,10 +7378,10 @@ DUK_INTERNAL_DECL void duk_hbufferobject_validated_write(duk_context *ctx, duk_h
#define DUK_CAT_LABEL_BITS 24
#define DUK_CAT_LABEL_SHIFT 8
-#define DUK_CAT_FLAG_CATCH_ENABLED (1 << 4) /* catch part will catch */
-#define DUK_CAT_FLAG_FINALLY_ENABLED (1 << 5) /* finally part will catch */
-#define DUK_CAT_FLAG_CATCH_BINDING_ENABLED (1 << 6) /* request to create catch binding */
-#define DUK_CAT_FLAG_LEXENV_ACTIVE (1 << 7) /* catch or with binding is currently active */
+#define DUK_CAT_FLAG_CATCH_ENABLED (1U << 4) /* catch part will catch */
+#define DUK_CAT_FLAG_FINALLY_ENABLED (1U << 5) /* finally part will catch */
+#define DUK_CAT_FLAG_CATCH_BINDING_ENABLED (1U << 6) /* request to create catch binding */
+#define DUK_CAT_FLAG_LEXENV_ACTIVE (1U << 7) /* catch or with binding is currently active */
#define DUK_CAT_TYPE_UNKNOWN 0
#define DUK_CAT_TYPE_TCF 1
@@ -6105,8 +7438,6 @@ DUK_INTERNAL_DECL void duk_hbufferobject_validated_write(duk_context *ctx, duk_h
#endif
#endif /* DUK_USE_ROM_STRINGS */
-#define DUK_HTHREAD_GET_CURRENT_ACTIVATION(thr) (&(thr)->callstack[(thr)->callstack_top - 1])
-
/* values for the state field */
#define DUK_HTHREAD_STATE_INACTIVE 1 /* thread not currently running */
#define DUK_HTHREAD_STATE_RUNNING 2 /* thread currently running (only one at a time) */
@@ -6131,42 +7462,75 @@ DUK_INTERNAL_DECL void duk_hbufferobject_validated_write(duk_context *ctx, duk_h
* diagnose behavior so it's worth checking even when the check is not 100%.
*/
-#if defined(DUK_USE_PREFER_SIZE)
-#define DUK_ASSERT_CTX_VSSIZE(ctx) /*nop*/
-#else
-#define DUK_ASSERT_CTX_VSSIZE(ctx) \
- DUK_ASSERT((duk_size_t) (((duk_hthread *) (ctx))->valstack_end - ((duk_hthread *) (ctx))->valstack) == \
- ((duk_hthread *) (ctx))->valstack_size)
-#endif
-#define DUK_ASSERT_CTX_VALID(ctx) do { \
- DUK_ASSERT((ctx) != NULL); \
- DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) (ctx)) == DUK_HTYPE_OBJECT); \
- DUK_ASSERT(DUK_HOBJECT_IS_THREAD((duk_hobject *) (ctx))); \
- DUK_ASSERT(((duk_hthread *) (ctx))->unused1 == 0); \
- DUK_ASSERT(((duk_hthread *) (ctx))->unused2 == 0); \
- DUK_ASSERT(((duk_hthread *) (ctx))->valstack != NULL); \
- DUK_ASSERT(((duk_hthread *) (ctx))->valstack_end >= ((duk_hthread *) (ctx))->valstack); \
- DUK_ASSERT(((duk_hthread *) (ctx))->valstack_top >= ((duk_hthread *) (ctx))->valstack); \
- DUK_ASSERT(((duk_hthread *) (ctx))->valstack_top >= ((duk_hthread *) (ctx))->valstack_bottom); \
- DUK_ASSERT(((duk_hthread *) (ctx))->valstack_end >= ((duk_hthread *) (ctx))->valstack_top); \
- DUK_ASSERT_CTX_VSSIZE((ctx)); \
+/* Assertions for internals. */
+#define DUK_ASSERT_HTHREAD_VALID(thr) do { \
+ DUK_ASSERT((thr) != NULL); \
+ DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) (thr)) == DUK_HTYPE_OBJECT); \
+ DUK_ASSERT(DUK_HOBJECT_IS_THREAD((duk_hobject *) (thr))); \
+ DUK_ASSERT((thr)->unused1 == 0); \
+ DUK_ASSERT((thr)->unused2 == 0); \
} while (0)
+/* Assertions for public API calls; a bit stronger. */
+#define DUK_ASSERT_CTX_VALID(thr) do { \
+ DUK_ASSERT((thr) != NULL); \
+ DUK_ASSERT_HTHREAD_VALID((thr)); \
+ DUK_ASSERT((thr)->valstack != NULL); \
+ DUK_ASSERT((thr)->valstack_bottom != NULL); \
+ DUK_ASSERT((thr)->valstack_top != NULL); \
+ DUK_ASSERT((thr)->valstack_end != NULL); \
+ DUK_ASSERT((thr)->valstack_alloc_end != NULL); \
+ DUK_ASSERT((thr)->valstack_alloc_end >= (thr)->valstack); \
+ DUK_ASSERT((thr)->valstack_end >= (thr)->valstack); \
+ DUK_ASSERT((thr)->valstack_top >= (thr)->valstack); \
+ DUK_ASSERT((thr)->valstack_top >= (thr)->valstack_bottom); \
+ DUK_ASSERT((thr)->valstack_end >= (thr)->valstack_top); \
+ DUK_ASSERT((thr)->valstack_alloc_end >= (thr)->valstack_end); \
+ } while (0)
+
+/* Assertions for API call entry specifically. Checks 'ctx' but also may
+ * check internal state (e.g. not in a debugger transport callback).
+ */
+#define DUK_ASSERT_API_ENTRY(thr) do { \
+ DUK_ASSERT_CTX_VALID((thr)); \
+ DUK_ASSERT((thr)->heap != NULL); \
+ DUK_ASSERT((thr)->heap->dbg_calling_transport == 0); \
+ } while (0)
+
+/*
+ * Assertion helpers.
+ */
+
+#define DUK_ASSERT_STRIDX_VALID(val) \
+ DUK_ASSERT((duk_uint_t) (val) < DUK_HEAP_NUM_STRINGS)
+
+#define DUK_ASSERT_BIDX_VALID(val) \
+ DUK_ASSERT((duk_uint_t) (val) < DUK_NUM_BUILTINS)
+
+/*
+ * Misc
+ */
+
+/* Fast access to 'this' binding. Assumes there's a call in progress. */
+#define DUK_HTHREAD_THIS_PTR(thr) \
+ (DUK_ASSERT_EXPR((thr) != NULL), \
+ DUK_ASSERT_EXPR((thr)->valstack_bottom > (thr)->valstack), \
+ (thr)->valstack_bottom - 1)
+
/*
* Struct defines
*/
-/* XXX: for a memory-code tradeoff, remove 'func' and make it's access either a function
- * or a macro. This would make the activation 32 bytes long on 32-bit platforms again.
- */
-
-/* Note: it's nice if size is 2^N (at least for 32-bit platforms). */
+/* Fields are ordered for alignment/packing. */
struct duk_activation {
duk_tval tv_func; /* borrowed: full duk_tval for function being executed; for lightfuncs */
duk_hobject *func; /* borrowed: function being executed; for bound function calls, this is the final, real function, NULL for lightfuncs */
+ duk_activation *parent; /* previous (parent) activation (or NULL if none) */
duk_hobject *var_env; /* current variable environment (may be NULL if delayed) */
duk_hobject *lex_env; /* current lexical environment (may be NULL if delayed) */
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+ duk_catcher *cat; /* current catcher (or NULL) */
+
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
/* Previous value of 'func' caller, restored when unwound. Only in use
* when 'func' is non-strict.
*/
@@ -6174,52 +7538,61 @@ struct duk_activation {
#endif
duk_instr_t *curr_pc; /* next instruction to execute (points to 'func' bytecode, stable pointer), NULL for native calls */
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- duk_uint32_t prev_line; /* needed for stepping */
-#endif
- duk_small_uint_t flags;
- /* idx_bottom and idx_retval are only used for book-keeping of
- * Ecmascript-initiated calls, to allow returning to an Ecmascript
- * function properly. They are duk_size_t to match the convention
- * that value stack sizes are duk_size_t and local frame indices
- * are duk_idx_t.
+ /* bottom_byteoff and retval_byteoff are only used for book-keeping
+ * of Ecmascript-initiated calls, to allow returning to an Ecmascript
+ * function properly.
*/
/* Bottom of valstack for this activation, used to reset
- * valstack_bottom on return; index is absolute. Note:
- * idx_top not needed because top is set to 'nregs' always
- * when returning to an Ecmascript activation.
+ * valstack_bottom on return; offset is absolute. There's
+ * no need to track 'top' because native call handling deals
+ * with that using locals, and for Ecmascript returns 'nregs'
+ * indicates the necessary top.
*/
- duk_size_t idx_bottom;
+ duk_size_t bottom_byteoff;
/* Return value when returning to this activation (points to caller
- * reg, not callee reg); index is absolute (only set if activation is
+ * reg, not callee reg); offset is absolute (only set if activation is
* not topmost).
*
- * Note: idx_bottom is always set, while idx_retval is only applicable
- * for activations below the topmost one. Currently idx_retval for
- * the topmost activation is considered garbage (and it not initialized
- * on entry or cleared on return; may contain previous or garbage
- * values).
+ * Note: bottom_byteoff is always set, while retval_byteoff is only
+ * applicable for activations below the topmost one. Currently
+ * retval_byteoff for the topmost activation is considered garbage
+ * (and it not initialized on entry or cleared on return; may contain
+ * previous or garbage values).
*/
- duk_size_t idx_retval;
+ duk_size_t retval_byteoff;
- /* Current 'this' binding is the value just below idx_bottom.
+ /* Current 'this' binding is the value just below bottom.
* Previously, 'this' binding was handled with an index to the
* (calling) valstack. This works for everything except tail
- * calls, which must not "cumulate" valstack temps.
+ * calls, which must not "accumulate" valstack temps.
*/
+
+ /* Value stack reserve (valstack_end) byte offset to be restored
+ * when returning to this activation. Only used by the bytecode
+ * executor.
+ */
+ duk_size_t reserve_byteoff;
+
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ duk_uint32_t prev_line; /* needed for stepping */
+#endif
+
+ duk_small_uint_t flags;
};
-/* Note: it's nice if size is 2^N (not 4x4 = 16 bytes on 32 bit) */
struct duk_catcher {
+ duk_catcher *parent; /* previous (parent) catcher (or NULL if none) */
duk_hstring *h_varname; /* borrowed reference to catch variable name (or NULL if none) */
/* (reference is valid as long activation exists) */
duk_instr_t *pc_base; /* resume execution from pc_base or pc_base+1 (points to 'func' bytecode, stable pointer) */
- duk_size_t callstack_index; /* callstack index of related activation */
duk_size_t idx_base; /* idx_base and idx_base+1 get completion value and type */
duk_uint32_t flags; /* type and control flags, label number */
+ /* XXX: could pack 'flags' and 'idx_base' to same value in practice,
+ * on 32-bit targets this would make duk_catcher 16 bytes.
+ */
};
struct duk_hthread {
@@ -6244,39 +7617,49 @@ struct duk_hthread {
duk_uint8_t unused1;
duk_uint8_t unused2;
- /* Sanity limits for stack sizes. */
- duk_size_t valstack_max;
- duk_size_t callstack_max;
- duk_size_t catchstack_max;
-
- /* XXX: Valstack, callstack, and catchstack are currently assumed
- * to have non-NULL pointers. Relaxing this would not lead to big
- * benefits (except perhaps for terminated threads).
+ /* XXX: Valstack and callstack are currently assumed to have non-NULL
+ * pointers. Relaxing this would not lead to big benefits (except
+ * perhaps for terminated threads).
*/
- /* Value stack: these are expressed as pointers for faster stack manipulation.
- * [valstack,valstack_top[ is GC-reachable, [valstack_top,valstack_end[ is
- * not GC-reachable but kept initialized as 'undefined'.
+ /* Value stack: these are expressed as pointers for faster stack
+ * manipulation. [valstack,valstack_top[ is GC-reachable,
+ * [valstack_top,valstack_alloc_end[ is not GC-reachable but kept
+ * initialized as 'undefined'. [valstack,valstack_end[ is the
+ * guaranteed/reserved space and the valstack cannot be resized to
+ * a smaller size. [valstack_end,valstack_alloc_end[ is currently
+ * allocated slack that can be used to grow the current guaranteed
+ * space but may be shrunk away without notice.
+ *
+ *
+ * <----------------------- guaranteed --->
+ * <---- slack --->
+ * <--- frame --->
+ * .-------------+=============+----------+--------------.
+ * |xxxxxxxxxxxxx|yyyyyyyyyyyyy|uuuuuuuuuu|uuuuuuuuuuuuuu|
+ * `-------------+=============+----------+--------------'
+ *
+ * ^ ^ ^ ^ ^
+ * | | | | |
+ * valstack bottom top end alloc_end
+ *
+ * xxx = arbitrary values, below current frame
+ * yyy = arbitrary values, inside current frame
+ * uuu = outside active value stack, initialized to 'undefined'
*/
duk_tval *valstack; /* start of valstack allocation */
- duk_tval *valstack_end; /* end of valstack allocation (exclusive) */
+ duk_tval *valstack_end; /* end of valstack reservation/guarantee (exclusive) */
+ duk_tval *valstack_alloc_end; /* end of valstack allocation */
duk_tval *valstack_bottom; /* bottom of current frame */
duk_tval *valstack_top; /* top of current frame (exclusive) */
-#if !defined(DUK_USE_PREFER_SIZE)
- duk_size_t valstack_size; /* cached: valstack_end - valstack (in entries, not bytes) */
-#endif
- /* Call stack. [0,callstack_top[ is GC reachable. */
- duk_activation *callstack;
- duk_size_t callstack_size; /* allocation size */
- duk_size_t callstack_top; /* next to use, highest used is top - 1 */
+ /* Call stack, represented as a linked list starting from the current
+ * activation (or NULL if nothing is active).
+ */
+ duk_activation *callstack_curr; /* current activation (or NULL if none) */
+ duk_size_t callstack_top; /* number of activation records in callstack (0 if none) */
duk_size_t callstack_preventcount; /* number of activation records in callstack preventing a yield */
- /* Catch stack. [0,catchstack_top[ is GC reachable. */
- duk_catcher *catchstack;
- duk_size_t catchstack_size; /* allocation size */
- duk_size_t catchstack_top; /* next to use, highest used is top - 1 */
-
/* Yield/resume book-keeping. */
duk_hthread *resumer; /* who resumed us (if any) */
@@ -6329,17 +7712,22 @@ DUK_INTERNAL_DECL void duk_hthread_create_builtin_objects(duk_hthread *thr);
DUK_INTERNAL_DECL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr);
DUK_INTERNAL_DECL void duk_hthread_terminate(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_callstack_grow(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_callstack_shrink_check(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top);
-DUK_INTERNAL_DECL void duk_hthread_catchstack_grow(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_catchstack_shrink_check(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top);
+DUK_INTERNAL_DECL duk_activation *duk_hthread_activation_alloc(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_hthread_activation_free(duk_hthread *thr, duk_activation *act);
+DUK_INTERNAL_DECL void duk_hthread_activation_unwind_norz(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_hthread_activation_unwind_reuse_norz(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_activation *duk_hthread_get_activation_for_level(duk_hthread *thr, duk_int_t level);
+
+DUK_INTERNAL_DECL duk_catcher *duk_hthread_catcher_alloc(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_hthread_catcher_free(duk_hthread *thr, duk_catcher *cat);
+DUK_INTERNAL_DECL void duk_hthread_catcher_unwind_norz(duk_hthread *thr, duk_activation *act);
+DUK_INTERNAL_DECL void duk_hthread_catcher_unwind_nolexenv_norz(duk_hthread *thr, duk_activation *act);
+
+#if defined(DUK_USE_FINALIZER_TORTURE)
+DUK_INTERNAL_DECL void duk_hthread_valstack_torture_realloc(duk_hthread *thr);
+#endif
-DUK_INTERNAL_DECL duk_activation *duk_hthread_get_current_activation(duk_hthread *thr);
DUK_INTERNAL_DECL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */
-DUK_INTERNAL_DECL void *duk_hthread_get_callstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */
-DUK_INTERNAL_DECL void *duk_hthread_get_catchstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */
#if defined(DUK_USE_DEBUGGER_SUPPORT)
DUK_INTERNAL_DECL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act);
@@ -6349,6 +7737,106 @@ DUK_INTERNAL_DECL void duk_hthread_sync_currpc(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_hthread_sync_and_null_currpc(duk_hthread *thr);
#endif /* DUK_HTHREAD_H_INCLUDED */
+/* #include duk_harray.h */
+#line 1 "duk_harray.h"
+/*
+ * Array object representation, used for actual Array instances.
+ *
+ * All objects with the exotic array behavior (which must coincide with having
+ * internal class array) MUST be duk_harrays. No other object can be a
+ * duk_harray. However, duk_harrays may not always have an array part.
+ */
+
+#if !defined(DUK_HARRAY_H_INCLUDED)
+#define DUK_HARRAY_H_INCLUDED
+
+#define DUK_ASSERT_HARRAY_VALID(h) do { \
+ DUK_ASSERT((h) != NULL); \
+ DUK_ASSERT(DUK_HOBJECT_IS_ARRAY((duk_hobject *) (h))); \
+ DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY((duk_hobject *) (h))); \
+ } while (0)
+
+#define DUK_HARRAY_LENGTH_WRITABLE(h) (!(h)->length_nonwritable)
+#define DUK_HARRAY_LENGTH_NONWRITABLE(h) ((h)->length_nonwritable)
+#define DUK_HARRAY_SET_LENGTH_WRITABLE(h) do { (h)->length_nonwritable = 0; } while (0)
+#define DUK_HARRAY_SET_LENGTH_NONWRITABLE(h) do { (h)->length_nonwritable = 1; } while (0)
+
+struct duk_harray {
+ /* Shared object part. */
+ duk_hobject obj;
+
+ /* Array .length.
+ *
+ * At present Array .length may be smaller, equal, or even larger
+ * than the allocated underlying array part. Fast path code must
+ * always take this into account carefully.
+ */
+ duk_uint32_t length;
+
+ /* Array .length property attributes. The property is always
+ * non-enumerable and non-configurable. It's initially writable
+ * but per Object.defineProperty() rules it can be made non-writable
+ * even if it is non-configurable. Thus we need to track the
+ * writability explicitly.
+ *
+ * XXX: this field to be eliminated and moved into duk_hobject
+ * flags field to save space.
+ */
+ duk_bool_t length_nonwritable;
+};
+
+#endif /* DUK_HARRAY_H_INCLUDED */
+/* #include duk_henv.h */
+#line 1 "duk_henv.h"
+/*
+ * Environment object representation.
+ */
+
+#if !defined(DUK_HENV_H_INCLUDED)
+#define DUK_HENV_H_INCLUDED
+
+#define DUK_ASSERT_HDECENV_VALID(h) do { \
+ DUK_ASSERT((h) != NULL); \
+ DUK_ASSERT(DUK_HOBJECT_IS_DECENV((duk_hobject *) (h))); \
+ DUK_ASSERT((h)->thread == NULL || (h)->varmap != NULL); \
+ } while (0)
+
+#define DUK_ASSERT_HOBJENV_VALID(h) do { \
+ DUK_ASSERT((h) != NULL); \
+ DUK_ASSERT(DUK_HOBJECT_IS_OBJENV((duk_hobject *) (h))); \
+ DUK_ASSERT((h)->target != NULL); \
+ DUK_ASSERT((h)->has_this == 0 || (h)->has_this == 1); \
+ } while (0)
+
+struct duk_hdecenv {
+ /* Shared object part. */
+ duk_hobject obj;
+
+ /* These control variables provide enough information to access live
+ * variables for a closure that is still open. If thread == NULL,
+ * the record is closed and the identifiers are in the property table.
+ */
+ duk_hthread *thread;
+ duk_hobject *varmap;
+ duk_size_t regbase_byteoff;
+};
+
+struct duk_hobjenv {
+ /* Shared object part. */
+ duk_hobject obj;
+
+ /* Target object and 'this' binding for object binding. */
+ duk_hobject *target;
+
+ /* The 'target' object is used as a this binding in only some object
+ * environments. For example, the global environment does not provide
+ * a this binding, but a with statement does.
+ */
+ duk_bool_t has_this;
+};
+
+#endif /* DUK_HENV_H_INCLUDED */
+/* #include duk_hbuffer.h */
#line 1 "duk_hbuffer.h"
/*
* Heap buffer representation.
@@ -6361,7 +7849,7 @@ DUK_INTERNAL_DECL void duk_hthread_sync_and_null_currpc(duk_hthread *thr);
* The data pointer for a variable size buffer of zero size may be NULL.
*/
-#ifndef DUK_HBUFFER_H_INCLUDED
+#if !defined(DUK_HBUFFER_H_INCLUDED)
#define DUK_HBUFFER_H_INCLUDED
/*
@@ -6407,9 +7895,6 @@ DUK_INTERNAL_DECL void duk_hthread_sync_and_null_currpc(duk_hthread *thr);
* Field access
*/
-/* Get/set the current user visible size, without accounting for a dynamic
- * buffer's "spare" (= usable size).
- */
#if defined(DUK_USE_BUFLEN16)
/* size stored in duk_heaphdr unused flag bits */
#define DUK_HBUFFER_GET_SIZE(x) ((x)->hdr.h_flags >> 16)
@@ -6529,7 +8014,7 @@ struct duk_hbuffer {
* it is useful for writing robust native code.
*/
- /* Current size (not counting a dynamic buffer's "spare"). */
+ /* Current size. */
#if defined(DUK_USE_BUFLEN16)
/* Stored in duk_heaphdr unused flags. */
#else
@@ -6678,6 +8163,35 @@ DUK_INTERNAL_DECL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic
DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf);
#endif /* DUK_HBUFFER_H_INCLUDED */
+/* #include duk_hproxy.h */
+#line 1 "duk_hproxy.h"
+/*
+ * Proxy object representation.
+ */
+
+#if !defined(DUK_HPROXY_H_INCLUDED)
+#define DUK_HPROXY_H_INCLUDED
+
+#define DUK_ASSERT_HPROXY_VALID(h) do { \
+ DUK_ASSERT((h) != NULL); \
+ DUK_ASSERT((h)->target != NULL); \
+ DUK_ASSERT((h)->handler != NULL); \
+ DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ((duk_hobject *) (h))); \
+ } while (0)
+
+struct duk_hproxy {
+ /* Shared object part. */
+ duk_hobject obj;
+
+ /* Proxy target object. */
+ duk_hobject *target;
+
+ /* Proxy handlers (traps). */
+ duk_hobject *handler;
+};
+
+#endif /* DUK_HPROXY_H_INCLUDED */
+/* #include duk_heap.h */
#line 1 "duk_heap.h"
/*
* Heap structure.
@@ -6686,7 +8200,7 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
* strings for one or more threads.
*/
-#ifndef DUK_HEAP_H_INCLUDED
+#if !defined(DUK_HEAP_H_INCLUDED)
#define DUK_HEAP_H_INCLUDED
/* alloc function typedefs in duktape.h */
@@ -6695,12 +8209,10 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
* Heap flags
*/
-#define DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING (1 << 0) /* mark-and-sweep is currently running */
-#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1 << 1) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */
-#define DUK_HEAP_FLAG_REFZERO_FREE_RUNNING (1 << 2) /* refcount code is processing refzero list */
-#define DUK_HEAP_FLAG_ERRHANDLER_RUNNING (1 << 3) /* an error handler (user callback to augment/replace error) is running */
-#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1 << 4) /* executor interrupt running (used to avoid nested interrupts) */
-#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1 << 5) /* heap destruction ongoing, finalizer rescue no longer possible */
+#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1U << 0) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */
+#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1U << 1) /* executor interrupt running (used to avoid nested interrupts) */
+#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1U << 2) /* heap destruction ongoing, finalizer rescue no longer possible */
+#define DUK_HEAP_FLAG_DEBUGGER_PAUSED (1U << 3) /* debugger is paused: talk with debug client until step/resume */
#define DUK__HEAP_HAS_FLAGS(heap,bits) ((heap)->flags & (bits))
#define DUK__HEAP_SET_FLAGS(heap,bits) do { \
@@ -6710,26 +8222,20 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
(heap)->flags &= ~(bits); \
} while (0)
-#define DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
#define DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
-#define DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
-#define DUK_HEAP_HAS_ERRHANDLER_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
#define DUK_HEAP_HAS_INTERRUPT_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
#define DUK_HEAP_HAS_FINALIZER_NORESCUE(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
+#define DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED)
-#define DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
#define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
-#define DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
-#define DUK_HEAP_SET_ERRHANDLER_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
#define DUK_HEAP_SET_INTERRUPT_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
#define DUK_HEAP_SET_FINALIZER_NORESCUE(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
+#define DUK_HEAP_SET_DEBUGGER_PAUSED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED)
-#define DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
#define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
-#define DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
-#define DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
#define DUK_HEAP_CLEAR_INTERRUPT_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
#define DUK_HEAP_CLEAR_FINALIZER_NORESCUE(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
+#define DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED)
/*
* Longjmp types, also double as identifying continuation type for a rethrow (in 'finally')
@@ -6752,11 +8258,25 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
* field and the GC caller can impose further flags.
*/
-#define DUK_MS_FLAG_EMERGENCY (1 << 0) /* emergency mode: try extra hard */
-#define DUK_MS_FLAG_NO_STRINGTABLE_RESIZE (1 << 1) /* don't resize stringtable (but may sweep it); needed during stringtable resize */
-#define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1 << 2) /* don't compact objects; needed during object property allocation resize */
-#define DUK_MS_FLAG_NO_FINALIZERS (1 << 3) /* don't run finalizers; leave finalizable objects in finalize_list for next round */
-#define DUK_MS_FLAG_SKIP_FINALIZERS (1 << 4) /* don't run finalizers; queue finalizable objects back to heap_allocated */
+/* Emergency mark-and-sweep: try extra hard, even at the cost of
+ * performance.
+ */
+#define DUK_MS_FLAG_EMERGENCY (1U << 0)
+
+/* Voluntary mark-and-sweep: triggered periodically. */
+#define DUK_MS_FLAG_VOLUNTARY (1U << 1)
+
+/* Postpone rescue decisions for reachable objects with FINALIZED set.
+ * Used during finalize_list processing to avoid incorrect rescue
+ * decisions due to finalize_list being a reachability root.
+ */
+#define DUK_MS_FLAG_POSTPONE_RESCUE (1U << 2)
+
+/* Don't compact objects; needed during object property table resize
+ * to prevent a recursive resize. It would suffice to protect only the
+ * current object being resized, but this is not yet implemented.
+ */
+#define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1U << 3)
/*
* Thread switching
@@ -6774,6 +8294,18 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
} while (0)
#endif
+/*
+ * Stats
+ */
+
+#if defined(DUK_USE_DEBUG)
+#define DUK_STATS_INC(heap,fieldname) do { \
+ (heap)->fieldname += 1; \
+ } while (0)
+#else
+#define DUK_STATS_INC(heap,fieldname) do {} while (0)
+#endif
+
/*
* Other heap related defines
*/
@@ -6788,7 +8320,6 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
* GC is skipped because there is no thread do it with yet (happens
* only during init phases).
*/
-#if defined(DUK_USE_MARK_AND_SWEEP)
#if defined(DUK_USE_REFERENCE_COUNTING)
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 12800L /* 50x heap size */
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L
@@ -6798,6 +8329,12 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L
#endif
+
+/* GC torture. */
+#if defined(DUK_USE_GC_TORTURE)
+#define DUK_GC_TORTURE(heap) do { duk_heap_mark_and_sweep((heap), 0); } while (0)
+#else
+#define DUK_GC_TORTURE(heap) do { } while (0)
#endif
/* Stringcache is used for speeding up char-offset-to-byte-offset
@@ -6806,33 +8343,15 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
#define DUK_HEAP_STRCACHE_SIZE 4
#define DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT 16 /* strings up to the this length are not cached */
-/* helper to insert a (non-string) heap object into heap allocated list */
-#define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap,hdr) duk_heap_insert_into_heap_allocated((heap),(hdr))
-
-/*
- * Stringtable
- */
-
-/* initial stringtable size, must be prime and higher than DUK_UTIL_MIN_HASH_PRIME */
-#define DUK_STRTAB_INITIAL_SIZE 17
-
-/* indicates a deleted string; any fixed non-NULL, non-hstring pointer works */
-#define DUK_STRTAB_DELETED_MARKER(heap) ((duk_hstring *) heap)
-
-/* resizing parameters */
-#define DUK_STRTAB_MIN_FREE_DIVISOR 4 /* load factor max 75% */
-#define DUK_STRTAB_MIN_USED_DIVISOR 4 /* load factor min 25% */
-#define DUK_STRTAB_GROW_ST_SIZE(n) ((n) + (n)) /* used entries + approx 100% -> reset load to 50% */
-
-#define DUK_STRTAB_U32_MAX_STRLEN 10 /* 4'294'967'295 */
-#define DUK_STRTAB_HIGHEST_32BIT_PRIME 0xfffffffbUL
-
-/* probe sequence (open addressing) */
-#define DUK_STRTAB_HASH_INITIAL(hash,h_size) ((hash) % (h_size))
-#define DUK_STRTAB_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash))
-
-/* fixed top level hashtable size (separate chaining) */
-#define DUK_STRTAB_CHAIN_SIZE DUK_USE_STRTAB_CHAIN_SIZE
+/* Some list management macros. */
+#define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap,hdr) duk_heap_insert_into_heap_allocated((heap), (hdr))
+#if defined(DUK_USE_REFERENCE_COUNTING)
+#define DUK_HEAP_REMOVE_FROM_HEAP_ALLOCATED(heap,hdr) duk_heap_remove_from_heap_allocated((heap), (hdr))
+#endif
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+#define DUK_HEAP_INSERT_INTO_FINALIZE_LIST(heap,hdr) duk_heap_insert_into_finalize_list((heap), (hdr))
+#define DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(heap,hdr) duk_heap_remove_from_finalize_list((heap), (hdr))
+#endif
/*
* Built-in strings
@@ -6902,11 +8421,22 @@ typedef void *(*duk_mem_getptr)(duk_heap *heap, void *ud);
#define DUK_REALLOC_INDIRECT(heap,cb,ud,newsize) duk_heap_mem_realloc_indirect((heap), (cb), (ud), (newsize))
#define DUK_FREE(heap,ptr) duk_heap_mem_free((heap), (ptr))
+/*
+ * Checked allocation, relative to a thread
+ *
+ * DUK_FREE_CHECKED() doesn't actually throw, but accepts a 'thr' argument
+ * for convenience.
+ */
+
+#define DUK_ALLOC_CHECKED(thr,size) duk_heap_mem_alloc_checked((thr), (size))
+#define DUK_ALLOC_CHECKED_ZEROED(thr,size) duk_heap_mem_alloc_checked_zeroed((thr), (size))
+#define DUK_FREE_CHECKED(thr,ptr) duk_heap_mem_free((thr)->heap, (ptr))
+
/*
* Memory constants
*/
-#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT 5 /* Retry allocation after mark-and-sweep for this
+#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT 10 /* Retry allocation after mark-and-sweep for this
* many times. A single mark-and-sweep round is
* not guaranteed to free all unreferenced memory
* because of finalization (in fact, ANY number of
@@ -6936,38 +8466,20 @@ typedef void *(*duk_mem_getptr)(duk_heap *heap, void *ud);
/* Milliseconds between status notify and transport peeks. */
#define DUK_HEAP_DBG_RATELIMIT_MILLISECS 200
-/* Step types */
-#define DUK_STEP_TYPE_NONE 0
-#define DUK_STEP_TYPE_INTO 1
-#define DUK_STEP_TYPE_OVER 2
-#define DUK_STEP_TYPE_OUT 3
+/* Debugger pause flags. */
+#define DUK_PAUSE_FLAG_ONE_OPCODE (1U << 0) /* pause when a single opcode has been executed */
+#define DUK_PAUSE_FLAG_ONE_OPCODE_ACTIVE (1U << 1) /* one opcode pause actually active; artifact of current implementation */
+#define DUK_PAUSE_FLAG_LINE_CHANGE (1U << 2) /* pause when current line number changes */
+#define DUK_PAUSE_FLAG_FUNC_ENTRY (1U << 3) /* pause when entering a function */
+#define DUK_PAUSE_FLAG_FUNC_EXIT (1U << 4) /* pause when exiting current function */
+#define DUK_PAUSE_FLAG_CAUGHT_ERROR (1U << 5) /* pause when about to throw an error that is caught */
+#define DUK_PAUSE_FLAG_UNCAUGHT_ERROR (1U << 6) /* pause when about to throw an error that won't be caught */
struct duk_breakpoint {
duk_hstring *filename;
duk_uint32_t line;
};
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
-#define DUK_HEAP_IS_DEBUGGER_ATTACHED(heap) ((heap)->dbg_read_cb != NULL)
-#define DUK_HEAP_CLEAR_STEP_STATE(heap) do { \
- (heap)->dbg_step_type = DUK_STEP_TYPE_NONE; \
- (heap)->dbg_step_thread = NULL; \
- (heap)->dbg_step_csindex = 0; \
- (heap)->dbg_step_startline = 0; \
- } while (0)
-#define DUK_HEAP_SET_PAUSED(heap) do { \
- (heap)->dbg_paused = 1; \
- (heap)->dbg_state_dirty = 1; \
- DUK_HEAP_CLEAR_STEP_STATE((heap)); \
- } while (0)
-#define DUK_HEAP_CLEAR_PAUSED(heap) do { \
- (heap)->dbg_paused = 0; \
- (heap)->dbg_state_dirty = 1; \
- DUK_HEAP_CLEAR_STEP_STATE((heap)); \
- } while (0)
-#define DUK_HEAP_IS_PAUSED(heap) ((heap)->dbg_paused)
-#endif /* DUK_USE_DEBUGGER_SUPPORT */
-
/*
* String cache should ideally be at duk_hthread level, but that would
* cause string finalization to slow down relative to the number of
@@ -6996,28 +8508,17 @@ struct duk_ljstate {
duk_tval value2; /* 2nd related value (type specific) */
};
-/*
- * Stringtable entry for fixed size stringtable
- */
-
-struct duk_strtab_entry {
-#if defined(DUK_USE_HEAPPTR16)
- /* A 16-bit listlen makes sense with 16-bit heap pointers: there
- * won't be space for 64k strings anyway.
- */
- duk_uint16_t listlen; /* if 0, 'str16' used, if > 0, 'strlist16' used */
- union {
- duk_uint16_t strlist16;
- duk_uint16_t str16;
- } u;
-#else
- duk_size_t listlen; /* if 0, 'str' used, if > 0, 'strlist' used */
- union {
- duk_hstring **strlist;
- duk_hstring *str;
- } u;
-#endif
-};
+#define DUK_ASSERT_LJSTATE_UNSET(heap) do { \
+ DUK_ASSERT(heap != NULL); \
+ DUK_ASSERT(heap->lj.type == DUK_LJ_TYPE_UNKNOWN); \
+ DUK_ASSERT(heap->lj.iserror == 0); \
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&heap->lj.value1)); \
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&heap->lj.value2)); \
+ } while (0)
+#define DUK_ASSERT_LJSTATE_SET(heap) do { \
+ DUK_ASSERT(heap != NULL); \
+ DUK_ASSERT(heap->lj.type != DUK_LJ_TYPE_UNKNOWN); \
+ } while (0)
/*
* Main heap structure
@@ -7032,16 +8533,10 @@ struct duk_heap {
duk_free_function free_func;
/* Heap udata, used for allocator functions but also for other heap
- * level callbacks like pointer compression, etc.
+ * level callbacks like fatal function, pointer compression, etc.
*/
void *heap_udata;
- /* Precomputed pointers when using 16-bit heap pointer packing. */
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t heapptr_null16;
- duk_uint16_t heapptr_deleted16;
-#endif
-
/* Fatal error handling, called e.g. when a longjmp() is needed but
* lj.jmpbuf_ptr is NULL. fatal_func must never return; it's not
* declared as "noreturn" because doing that for typedefs is a bit
@@ -7049,56 +8544,144 @@ struct duk_heap {
*/
duk_fatal_function fatal_func;
- /* allocated heap objects */
+ /* Main list of allocated heap objects. Objects are either here,
+ * in finalize_list waiting for processing, or in refzero_list
+ * temporarily while a DECREF refzero cascade finishes.
+ */
duk_heaphdr *heap_allocated;
- /* work list for objects whose refcounts are zero but which have not been
- * "finalized"; avoids recursive C calls when refcounts go to zero in a
- * chain of objects.
+ /* Temporary work list for freeing a cascade of objects when a DECREF
+ * (or DECREF_NORZ) encounters a zero refcount. Using a work list
+ * allows fixed C stack size when refcounts go to zero for a chain of
+ * objects. Outside of DECREF this is always a NULL because DECREF is
+ * processed without side effects (only memory free calls).
*/
#if defined(DUK_USE_REFERENCE_COUNTING)
duk_heaphdr *refzero_list;
- duk_heaphdr *refzero_list_tail;
#endif
-#if defined(DUK_USE_MARK_AND_SWEEP)
- /* mark-and-sweep control */
-#if defined(DUK_USE_VOLUNTARY_GC)
- duk_int_t mark_and_sweep_trigger_counter;
-#endif
- duk_int_t mark_and_sweep_recursion_depth;
-
- /* mark-and-sweep flags automatically active (used for critical sections) */
- duk_small_uint_t mark_and_sweep_base_flags;
-
- /* work list for objects to be finalized (by mark-and-sweep) */
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+ /* Work list for objects to be finalized. */
duk_heaphdr *finalize_list;
+#if defined(DUK_USE_ASSERTIONS)
+ /* Object whose finalizer is executing right now (no nesting). */
+ duk_heaphdr *currently_finalizing;
+#endif
#endif
- /* longjmp state */
+ /* Freelist for duk_activations and duk_catchers. */
+#if defined(DUK_USE_CACHE_ACTIVATION)
+ duk_activation *activation_free;
+#endif
+#if defined(DUK_USE_CACHE_CATCHER)
+ duk_catcher *catcher_free;
+#endif
+
+ /* Voluntary mark-and-sweep trigger counter. Intentionally signed
+ * because we continue decreasing the value when voluntary GC cannot
+ * run.
+ */
+#if defined(DUK_USE_VOLUNTARY_GC)
+ duk_int_t ms_trigger_counter;
+#endif
+
+ /* Mark-and-sweep recursion control: too deep recursion causes
+ * multi-pass processing to avoid growing C stack without bound.
+ */
+ duk_uint_t ms_recursion_depth;
+
+ /* Mark-and-sweep flags automatically active (used for critical sections). */
+ duk_small_uint_t ms_base_flags;
+
+ /* Mark-and-sweep running flag. Prevents re-entry, and also causes
+ * refzero events to be ignored (= objects won't be queued to refzero_list).
+ */
+ duk_uint_t ms_running;
+
+ /* Mark-and-sweep prevent count, stacking. Used to avoid M&S side
+ * effects (besides finalizers which are controlled separately) such
+ * as compacting the string table or object property tables. This
+ * is also bumped when ms_running is set to prevent recursive re-entry.
+ * Can also be bumped when mark-and-sweep is not running.
+ */
+ duk_uint_t ms_prevent_count;
+
+ /* Finalizer processing prevent count, stacking. Bumped when finalizers
+ * are processed to prevent recursive finalizer processing (first call site
+ * processing finalizers handles all finalizers until the list is empty).
+ * Can also be bumped explicitly to prevent finalizer execution.
+ */
+ duk_uint_t pf_prevent_count;
+
+ /* When processing finalize_list, don't actually run finalizers but
+ * queue finalizable objects back to heap_allocated as is. This is
+ * used during heap destruction to deal with finalizers that keep
+ * on creating more finalizable garbage.
+ */
+ duk_uint_t pf_skip_finalizers;
+
+#if defined(DUK_USE_ASSERTIONS)
+ /* Set when we're in a critical path where an error throw would cause
+ * e.g. sandboxing/protected call violations or state corruption. This
+ * is just used for asserts.
+ */
+ duk_bool_t error_not_allowed;
+#endif
+
+#if defined(DUK_USE_ASSERTIONS)
+ /* Set when heap is still being initialized, helps with writing
+ * some assertions.
+ */
+ duk_bool_t heap_initializing;
+#endif
+
+ /* Marker for detecting internal "double faults", errors thrown when
+ * we're trying to create an error object, see duk_error_throw.c.
+ */
+ duk_bool_t creating_error;
+
+ /* Marker for indicating we're calling a user error augmentation
+ * (errCreate/errThrow) function. Errors created/thrown during
+ * such a call are not augmented.
+ */
+#if defined(DUK_USE_AUGMENT_ERROR_THROW) || defined(DUK_USE_AUGMENT_ERROR_CREATE)
+ duk_bool_t augmenting_error;
+#endif
+
+ /* Longjmp state. */
duk_ljstate lj;
- /* marker for detecting internal "double faults", see duk_error_throw.c */
- duk_bool_t handling_error;
-
- /* heap thread, used internally and for finalization */
+ /* Heap thread, used internally and for finalization. */
duk_hthread *heap_thread;
- /* current thread */
- duk_hthread *curr_thread; /* currently running thread */
+ /* Current running thread. */
+ duk_hthread *curr_thread;
- /* heap level "stash" object (e.g., various reachability roots) */
+ /* Heap level "stash" object (e.g., various reachability roots). */
duk_hobject *heap_object;
/* duk_handle_call / duk_handle_safe_call recursion depth limiting */
duk_int_t call_recursion_depth;
duk_int_t call_recursion_limit;
- /* mix-in value for computing string hashes; should be reasonably unpredictable */
+ /* Mix-in value for computing string hashes; should be reasonably unpredictable. */
duk_uint32_t hash_seed;
- /* rnd_state for duk_util_tinyrandom.c */
- duk_uint32_t rnd_state;
+ /* Random number state for duk_util_tinyrandom.c. */
+#if !defined(DUK_USE_GET_RANDOM_DOUBLE)
+#if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS)
+ duk_uint32_t rnd_state; /* State for Shamir's three-op algorithm */
+#else
+ duk_uint64_t rnd_state[2]; /* State for xoroshiro128+ */
+#endif
+#endif
+
+ /* Counter for unique local symbol creation. */
+ /* XXX: When 64-bit types are available, it would be more efficient to
+ * use a duk_uint64_t at least for incrementing but maybe also for
+ * string formatting in the Symbol constructor.
+ */
+ duk_uint32_t sym_counter[2];
/* For manual debugging: instruction count based on executor and
* interrupt counter book-keeping. Inspect debug logs to see how
@@ -7109,10 +8692,9 @@ struct duk_heap {
duk_int_t inst_count_interrupt;
#endif
- /* debugger */
-
+ /* Debugger state. */
#if defined(DUK_USE_DEBUGGER_SUPPORT)
- /* callbacks and udata; dbg_read_cb != NULL is used to indicate attached state */
+ /* Callbacks and udata; dbg_read_cb != NULL is used to indicate attached state. */
duk_debug_read_function dbg_read_cb; /* required, NULL implies detached */
duk_debug_write_function dbg_write_cb; /* required */
duk_debug_peek_function dbg_peek_cb;
@@ -7122,55 +8704,51 @@ struct duk_heap {
duk_debug_detached_function dbg_detached_cb;
void *dbg_udata;
- /* debugger state, only relevant when attached */
+ /* The following are only relevant when debugger is attached. */
duk_bool_t dbg_processing; /* currently processing messages or breakpoints: don't enter message processing recursively (e.g. no breakpoints when processing debugger eval) */
- duk_bool_t dbg_paused; /* currently paused: talk with debug client until step/resume */
duk_bool_t dbg_state_dirty; /* resend state next time executor is about to run */
duk_bool_t dbg_force_restart; /* force executor restart to recheck breakpoints; used to handle function returns (see GH-303) */
duk_bool_t dbg_detaching; /* debugger detaching; used to avoid calling detach handler recursively */
- duk_small_uint_t dbg_step_type; /* step type: none, step into, step over, step out */
- duk_hthread *dbg_step_thread; /* borrowed; NULL if no step state (NULLed in unwind) */
- duk_size_t dbg_step_csindex; /* callstack index */
- duk_uint32_t dbg_step_startline; /* starting line number */
+ duk_small_uint_t dbg_pause_flags; /* flags for automatic pause behavior */
+ duk_activation *dbg_pause_act; /* activation related to pause behavior (pause on line change, function entry/exit) */
+ duk_uint32_t dbg_pause_startline; /* starting line number for line change related pause behavior */
duk_breakpoint dbg_breakpoints[DUK_HEAP_MAX_BREAKPOINTS]; /* breakpoints: [0,breakpoint_count[ gc reachable */
duk_small_uint_t dbg_breakpoint_count;
duk_breakpoint *dbg_breakpoints_active[DUK_HEAP_MAX_BREAKPOINTS + 1]; /* currently active breakpoints: NULL term, borrowed pointers */
/* XXX: make active breakpoints actual copies instead of pointers? */
/* These are for rate limiting Status notifications and transport peeking. */
- duk_uint32_t dbg_exec_counter; /* cumulative opcode execution count (overflows are OK) */
- duk_uint32_t dbg_last_counter; /* value of dbg_exec_counter when we last did a Date-based check */
+ duk_uint_t dbg_exec_counter; /* cumulative opcode execution count (overflows are OK) */
+ duk_uint_t dbg_last_counter; /* value of dbg_exec_counter when we last did a Date-based check */
duk_double_t dbg_last_time; /* time when status/peek was last done (Date-based rate limit) */
/* Used to support single-byte stream lookahead. */
duk_bool_t dbg_have_next_byte;
duk_uint8_t dbg_next_byte;
+#endif /* DUK_USE_DEBUGGER_SUPPORT */
+#if defined(DUK_USE_ASSERTIONS)
+ duk_bool_t dbg_calling_transport; /* transport call in progress, calling into Duktape forbidden */
#endif
- /* string intern table (weak refs) */
-#if defined(DUK_USE_STRTAB_PROBE)
-#if defined(DUK_USE_HEAPPTR16)
+ /* String intern table (weak refs). */
+#if defined(DUK_USE_STRTAB_PTRCOMP)
duk_uint16_t *strtable16;
#else
duk_hstring **strtable;
#endif
- duk_uint32_t st_size; /* alloc size in elements */
- duk_uint32_t st_used; /* used elements (includes DELETED) */
+ duk_uint32_t st_mask; /* mask for lookup, st_size - 1 */
+ duk_uint32_t st_size; /* stringtable size */
+#if (DUK_USE_STRTAB_MINSIZE != DUK_USE_STRTAB_MAXSIZE)
+ duk_uint32_t st_count; /* string count for resize load factor checks */
#endif
+ duk_bool_t st_resizing; /* string table is being resized; avoid recursive resize */
- /* XXX: static alloc is OK until separate chaining stringtable
- * resizing is implemented.
- */
-#if defined(DUK_USE_STRTAB_CHAIN)
- duk_strtab_entry strtable[DUK_STRTAB_CHAIN_SIZE];
-#endif
-
- /* string access cache (codepoint offset -> byte offset) for fast string
+ /* String access cache (codepoint offset -> byte offset) for fast string
* character looping; 'weak' reference which needs special handling in GC.
*/
duk_strcache strcache[DUK_HEAP_STRCACHE_SIZE];
- /* built-in strings */
+ /* Built-in strings. */
#if defined(DUK_USE_ROM_STRINGS)
/* No field needed when strings are in ROM. */
#else
@@ -7179,6 +8757,51 @@ struct duk_heap {
#else
duk_hstring *strs[DUK_HEAP_NUM_STRINGS];
#endif
+#endif
+
+ /* Stats. */
+#if defined(DUK_USE_DEBUG)
+ duk_int_t stats_exec_opcodes;
+ duk_int_t stats_exec_interrupt;
+ duk_int_t stats_exec_throw;
+ duk_int_t stats_call_all;
+ duk_int_t stats_call_tailcall;
+ duk_int_t stats_call_ecmatoecma;
+ duk_int_t stats_safecall_all;
+ duk_int_t stats_safecall_nothrow;
+ duk_int_t stats_safecall_throw;
+ duk_int_t stats_ms_try_count;
+ duk_int_t stats_ms_skip_count;
+ duk_int_t stats_ms_emergency_count;
+ duk_int_t stats_strtab_intern_hit;
+ duk_int_t stats_strtab_intern_miss;
+ duk_int_t stats_strtab_resize_check;
+ duk_int_t stats_strtab_resize_grow;
+ duk_int_t stats_strtab_resize_shrink;
+ duk_int_t stats_object_realloc_props;
+ duk_int_t stats_object_abandon_array;
+ duk_int_t stats_getownpropdesc_count;
+ duk_int_t stats_getownpropdesc_hit;
+ duk_int_t stats_getownpropdesc_miss;
+ duk_int_t stats_getpropdesc_count;
+ duk_int_t stats_getpropdesc_hit;
+ duk_int_t stats_getpropdesc_miss;
+ duk_int_t stats_getprop_all;
+ duk_int_t stats_getprop_arrayidx;
+ duk_int_t stats_getprop_bufobjidx;
+ duk_int_t stats_getprop_bufferidx;
+ duk_int_t stats_getprop_bufferlen;
+ duk_int_t stats_getprop_stringidx;
+ duk_int_t stats_getprop_stringlen;
+ duk_int_t stats_getprop_proxy;
+ duk_int_t stats_getprop_arguments;
+ duk_int_t stats_putprop_all;
+ duk_int_t stats_putprop_arrayidx;
+ duk_int_t stats_putprop_bufobjidx;
+ duk_int_t stats_putprop_bufferidx;
+ duk_int_t stats_putprop_proxy;
+ duk_int_t stats_getvar_all;
+ duk_int_t stats_putvar_all;
#endif
};
@@ -7193,41 +8816,40 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
void *heap_udata,
duk_fatal_function fatal_func);
DUK_INTERNAL_DECL void duk_heap_free(duk_heap *heap);
-DUK_INTERNAL_DECL void duk_free_hobject_inner(duk_heap *heap, duk_hobject *h);
-DUK_INTERNAL_DECL void duk_free_hbuffer_inner(duk_heap *heap, duk_hbuffer *h);
-DUK_INTERNAL_DECL void duk_free_hstring_inner(duk_heap *heap, duk_hstring *h);
+DUK_INTERNAL_DECL void duk_free_hobject(duk_heap *heap, duk_hobject *h);
+DUK_INTERNAL_DECL void duk_free_hbuffer(duk_heap *heap, duk_hbuffer *h);
+DUK_INTERNAL_DECL void duk_free_hstring(duk_heap *heap, duk_hstring *h);
DUK_INTERNAL_DECL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr);
DUK_INTERNAL_DECL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr);
-#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING)
-DUK_INTERNAL_DECL void duk_heap_remove_any_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr);
+#if defined(DUK_USE_REFERENCE_COUNTING)
+DUK_INTERNAL_DECL void duk_heap_remove_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr);
+#endif
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+DUK_INTERNAL_DECL void duk_heap_insert_into_finalize_list(duk_heap *heap, duk_heaphdr *hdr);
+DUK_INTERNAL_DECL void duk_heap_remove_from_finalize_list(duk_heap *heap, duk_heaphdr *hdr);
+#endif
+#if defined(DUK_USE_ASSERTIONS)
+DUK_INTERNAL_DECL duk_bool_t duk_heap_in_heap_allocated(duk_heap *heap, duk_heaphdr *ptr);
#endif
#if defined(DUK_USE_INTERRUPT_COUNTER)
DUK_INTERNAL_DECL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr);
#endif
-#if 0 /*unused*/
-DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen);
-#endif
-DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen);
-DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t len);
-#if 0 /*unused*/
-DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val);
-#endif
-DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val);
-DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val);
+DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen);
+DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t len);
+DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_u32(duk_heap *heap, duk_uint32_t val);
+DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_u32_checked(duk_hthread *thr, duk_uint32_t val);
#if defined(DUK_USE_REFERENCE_COUNTING)
-DUK_INTERNAL_DECL void duk_heap_string_remove(duk_heap *heap, duk_hstring *h);
+DUK_INTERNAL_DECL void duk_heap_strtable_unlink(duk_heap *heap, duk_hstring *h);
#endif
-#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_MS_STRINGTABLE_RESIZE)
-DUK_INTERNAL_DECL void duk_heap_force_strtab_resize(duk_heap *heap);
-#endif
-DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap);
+DUK_INTERNAL_DECL void duk_heap_strtable_unlink_prev(duk_heap *heap, duk_hstring *h, duk_hstring *prev);
+DUK_INTERNAL_DECL void duk_heap_strtable_force_resize(duk_heap *heap);
+DUK_INTERNAL void duk_heap_strtable_free(duk_heap *heap);
#if defined(DUK_USE_DEBUG)
-DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap);
+DUK_INTERNAL void duk_heap_strtable_dump(duk_heap *heap);
#endif
-
DUK_INTERNAL_DECL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h);
DUK_INTERNAL_DECL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset);
@@ -7239,44 +8861,27 @@ DUK_INTERNAL_DECL void duk_default_free_function(void *udata, void *ptr);
DUK_INTERNAL_DECL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size);
DUK_INTERNAL_DECL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size);
+DUK_INTERNAL_DECL void *duk_heap_mem_alloc_checked(duk_hthread *thr, duk_size_t size);
+DUK_INTERNAL_DECL void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, duk_size_t size);
DUK_INTERNAL_DECL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize);
DUK_INTERNAL_DECL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize);
DUK_INTERNAL_DECL void duk_heap_mem_free(duk_heap *heap, void *ptr);
-#ifdef DUK_USE_REFERENCE_COUNTING
-#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
-DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv);
-#endif
-#if 0 /* unused */
-DUK_INTERNAL_DECL void duk_tval_incref_allownull(duk_tval *tv);
-#endif
-DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv);
-#if 0 /* unused */
-DUK_INTERNAL_DECL void duk_tval_decref_allownull(duk_hthread *thr, duk_tval *tv);
-#endif
-#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
-DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h);
-#endif
-#if 0 /* unused */
-DUK_INTERNAL_DECL void duk_heaphdr_incref_allownull(duk_heaphdr *h);
-#endif
-DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h);
-DUK_INTERNAL_DECL void duk_heaphdr_decref_allownull(duk_hthread *thr, duk_heaphdr *h);
-DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h);
-DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr);
-#else
-/* no refcounting */
-#endif
+DUK_INTERNAL_DECL void duk_heap_free_freelists(duk_heap *heap);
-#if defined(DUK_USE_MARK_AND_SWEEP)
-DUK_INTERNAL_DECL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags);
-#endif
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+DUK_INTERNAL_DECL void duk_heap_run_finalizer(duk_heap *heap, duk_hobject *obj);
+DUK_INTERNAL_DECL void duk_heap_process_finalize_list(duk_heap *heap);
+#endif /* DUK_USE_FINALIZER_SUPPORT */
+
+DUK_INTERNAL_DECL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags);
DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len);
#endif /* DUK_HEAP_H_INCLUDED */
+/* #include duk_debugger.h */
#line 1 "duk_debugger.h"
-#ifndef DUK_DEBUGGER_H_INCLUDED
+#if !defined(DUK_DEBUGGER_H_INCLUDED)
#define DUK_DEBUGGER_H_INCLUDED
/* Debugger protocol version is defined in the public API header. */
@@ -7317,9 +8922,9 @@ DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uin
/* Commands and notifys initiated by Duktape. */
#define DUK_DBG_CMD_STATUS 0x01
-#define DUK_DBG_CMD_PRINT 0x02
-#define DUK_DBG_CMD_ALERT 0x03
-#define DUK_DBG_CMD_LOG 0x04
+#define DUK_DBG_CMD_UNUSED_2 0x02 /* Duktape 1.x: print notify */
+#define DUK_DBG_CMD_UNUSED_3 0x03 /* Duktape 1.x: alert notify */
+#define DUK_DBG_CMD_UNUSED_4 0x04 /* Duktape 1.x: log notify */
#define DUK_DBG_CMD_THROW 0x05
#define DUK_DBG_CMD_DETACHING 0x06
#define DUK_DBG_CMD_APPNOTIFY 0x07
@@ -7351,7 +8956,8 @@ DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uin
/* The low 8 bits map directly to duk_hobject.h DUK_PROPDESC_FLAG_xxx.
* The remaining flags are specific to the debugger.
*/
-#define DUK_DBG_PROPFLAG_INTERNAL (1 << 8)
+#define DUK_DBG_PROPFLAG_SYMBOL (1U << 8)
+#define DUK_DBG_PROPFLAG_HIDDEN (1U << 9)
#if defined(DUK_USE_DEBUGGER_SUPPORT)
DUK_INTERNAL_DECL void duk_debug_do_detach(duk_heap *heap);
@@ -7417,9 +9023,16 @@ DUK_INTERNAL_DECL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bo
DUK_INTERNAL_DECL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstring *filename, duk_uint32_t line);
DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index);
-#endif
+
+DUK_INTERNAL_DECL duk_bool_t duk_debug_is_attached(duk_heap *heap);
+DUK_INTERNAL_DECL duk_bool_t duk_debug_is_paused(duk_heap *heap);
+DUK_INTERNAL_DECL void duk_debug_set_paused(duk_heap *heap);
+DUK_INTERNAL_DECL void duk_debug_clear_paused(duk_heap *heap);
+DUK_INTERNAL_DECL void duk_debug_clear_pause_state(duk_heap *heap);
+#endif /* DUK_USE_DEBUGGER_SUPPORT */
#endif /* DUK_DEBUGGER_H_INCLUDED */
+/* #include duk_debug.h */
#line 1 "duk_debug.h"
/*
* Debugging macros, DUK_DPRINT() and its variants in particular.
@@ -7443,24 +9056,24 @@ DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_s
* works poorly with threading.
*/
-#ifndef DUK_DEBUG_H_INCLUDED
+#if !defined(DUK_DEBUG_H_INCLUDED)
#define DUK_DEBUG_H_INCLUDED
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
-#if defined(DUK_USE_DPRINT)
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0)
#define DUK_D(x) x
#else
#define DUK_D(x) do { } while (0) /* omit */
#endif
-#if defined(DUK_USE_DDPRINT)
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
#define DUK_DD(x) x
#else
#define DUK_DD(x) do { } while (0) /* omit */
#endif
-#if defined(DUK_USE_DDDPRINT)
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
#define DUK_DDD(x) x
#else
#define DUK_DDD(x) do { } while (0) /* omit */
@@ -7470,26 +9083,26 @@ DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_s
* Exposed debug macros: debugging enabled
*/
-#define DUK_LEVEL_DEBUG 1
-#define DUK_LEVEL_DDEBUG 2
-#define DUK_LEVEL_DDDEBUG 3
-
-#ifdef DUK_USE_VARIADIC_MACROS
+#if defined(DUK_USE_VARIADIC_MACROS)
/* Note: combining __FILE__, __LINE__, and __func__ into fmt would be
* possible compile time, but waste some space with shared function names.
*/
-#define DUK__DEBUG_LOG(lev,...) duk_debug_log((duk_small_int_t) (lev), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, DUK_FUNC_MACRO, __VA_ARGS__);
+#define DUK__DEBUG_LOG(lev,...) duk_debug_log((duk_int_t) (lev), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, DUK_FUNC_MACRO, __VA_ARGS__);
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0)
#define DUK_DPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DEBUG, __VA_ARGS__)
+#else
+#define DUK_DPRINT(...)
+#endif
-#ifdef DUK_USE_DDPRINT
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
#define DUK_DDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDEBUG, __VA_ARGS__)
#else
#define DUK_DDPRINT(...)
#endif
-#ifdef DUK_USE_DDDPRINT
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
#define DUK_DDDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDDEBUG, __VA_ARGS__)
#else
#define DUK_DDDPRINT(...)
@@ -7499,11 +9112,10 @@ DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_s
#define DUK__DEBUG_STASH(lev) \
(void) DUK_SNPRINTF(duk_debug_file_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FILE_MACRO), \
- duk_debug_file_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \
- (void) DUK_SNPRINTF(duk_debug_line_stash, DUK_DEBUG_STASH_SIZE, "%ld", (long) DUK_LINE_MACRO), \
- duk_debug_line_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \
+ (void) (duk_debug_file_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0), \
+ (void) (duk_debug_line_stash = (duk_int_t) DUK_LINE_MACRO), \
(void) DUK_SNPRINTF(duk_debug_func_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FUNC_MACRO), \
- duk_debug_func_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \
+ (void) (duk_debug_func_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0), \
(void) (duk_debug_level_stash = (lev))
/* Without variadic macros resort to comma expression trickery to handle debug
@@ -7512,19 +9124,19 @@ DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_s
* statement from the compiler.
*/
-#ifdef DUK_USE_DPRINT
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0)
#define DUK_DPRINT DUK__DEBUG_STASH(DUK_LEVEL_DEBUG), (void) duk_debug_log /* args go here in parens */
#else
#define DUK_DPRINT 0 && /* args go here as a comma expression in parens */
#endif
-#ifdef DUK_USE_DDPRINT
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
#define DUK_DDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDEBUG), (void) duk_debug_log /* args go here in parens */
#else
#define DUK_DDPRINT 0 && /* args */
#endif
-#ifdef DUK_USE_DDDPRINT
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
#define DUK_DDDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDDEBUG), (void) duk_debug_log /* args go here in parens */
#else
#define DUK_DDDPRINT 0 && /* args */
@@ -7542,7 +9154,7 @@ DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_s
#define DUK_DD(x) do { } while (0) /* omit */
#define DUK_DDD(x) do { } while (0) /* omit */
-#ifdef DUK_USE_VARIADIC_MACROS
+#if defined(DUK_USE_VARIADIC_MACROS)
#define DUK_DPRINT(...)
#define DUK_DDPRINT(...)
@@ -7562,7 +9174,7 @@ DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_s
* Structs
*/
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
struct duk_fixedbuffer {
duk_uint8_t *buffer;
duk_size_t length;
@@ -7575,23 +9187,23 @@ struct duk_fixedbuffer {
* Prototypes
*/
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
DUK_INTERNAL_DECL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap);
#if 0 /*unused*/
DUK_INTERNAL_DECL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...);
#endif
DUK_INTERNAL_DECL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size);
-#ifdef DUK_USE_VARIADIC_MACROS
-DUK_INTERNAL_DECL void duk_debug_log(duk_small_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...);
+#if defined(DUK_USE_VARIADIC_MACROS)
+DUK_INTERNAL_DECL void duk_debug_log(duk_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...);
#else /* DUK_USE_VARIADIC_MACROS */
/* parameter passing, not thread safe */
#define DUK_DEBUG_STASH_SIZE 128
#if !defined(DUK_SINGLE_FILE)
DUK_INTERNAL_DECL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE];
-DUK_INTERNAL_DECL char duk_debug_line_stash[DUK_DEBUG_STASH_SIZE];
+DUK_INTERNAL_DECL duk_int_t duk_debug_line_stash;
DUK_INTERNAL_DECL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE];
-DUK_INTERNAL_DECL duk_small_int_t duk_debug_level_stash;
+DUK_INTERNAL_DECL duk_int_t duk_debug_level_stash;
#endif
DUK_INTERNAL_DECL void duk_debug_log(const char *fmt, ...);
#endif /* DUK_USE_VARIADIC_MACROS */
@@ -7606,22 +9218,24 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
#endif /* DUK_USE_DEBUG */
#endif /* DUK_DEBUG_H_INCLUDED */
+/* #include duk_error.h */
#line 1 "duk_error.h"
/*
* Error handling macros, assertion macro, error codes.
*
- * There are three level of 'errors':
+ * There are three types of 'errors':
*
- * 1. Ordinary errors, relative to a thread, cause a longjmp, catchable.
- * 2. Fatal errors, relative to a heap, cause fatal handler to be called.
- * 3. Panic errors, unrelated to a heap and cause a process exit.
+ * 1. Ordinary errors relative to a thread, cause a longjmp, catchable.
+ * 2. Fatal errors relative to a heap, cause fatal handler to be called.
+ * 3. Fatal errors without context, cause the default (not heap specific)
+ * fatal handler to be called.
*
- * Panics are used by the default fatal error handler and by debug code
- * such as assertions. By providing a proper fatal error handler, user
- * code can avoid panics in non-debug builds.
+ * Fatal errors without context are used by debug code such as assertions.
+ * By providing a fatal error handler for a Duktape heap, user code can
+ * avoid fatal errors without context in non-debug builds.
*/
-#ifndef DUK_ERROR_H_INCLUDED
+#if !defined(DUK_ERROR_H_INCLUDED)
#define DUK_ERROR_H_INCLUDED
/*
@@ -7736,66 +9350,247 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
#endif /* DUK_USE_VERBOSE_ERRORS */
/*
- * Fatal error
+ * Fatal error without context
*
- * There are no fatal error macros at the moment. There are so few call
- * sites that the fatal error handler is called directly.
+ * The macro is an expression to make it compatible with DUK_ASSERT_EXPR().
*/
+#define DUK_FATAL_WITHOUT_CONTEXT(msg) \
+ duk_default_fatal_handler(NULL, (msg))
+
/*
- * Panic error
+ * Error throwing helpers
*
- * Panic errors are not relative to either a heap or a thread, and cause
- * DUK_PANIC() macro to be invoked. Unless a user provides DUK_USE_PANIC_HANDLER,
- * DUK_PANIC() calls a helper which prints out the error and causes a process
- * exit.
+ * The goal is to provide verbose and configurable error messages. Call
+ * sites should be clean in source code and compile to a small footprint.
+ * Small footprint is also useful for performance because small cold paths
+ * reduce code cache pressure. Adding macros here only makes sense if there
+ * are enough call sites to get concrete benefits.
*
- * The user can override the macro to provide custom handling. A macro is
- * used to allow the user to have inline panic handling if desired (without
- * causing a potentially risky function call).
+ * DUK_ERROR_xxx() macros are generic and can be used anywhere.
*
- * Panics are only used in debug code such as assertions, and by the default
- * fatal error handler.
+ * DUK_DCERROR_xxx() macros can only be used in Duktape/C functions where
+ * the "return DUK_RET_xxx;" shorthand is available for low memory targets.
+ * The DUK_DCERROR_xxx() macros always either throw or perform a
+ * 'return DUK_RET_xxx' from the calling function.
*/
-#if defined(DUK_USE_PANIC_HANDLER)
-/* already defined, good */
-#define DUK_PANIC(code,msg) DUK_USE_PANIC_HANDLER((code),(msg))
-#else
-#define DUK_PANIC(code,msg) duk_default_panic_handler((code),(msg))
-#endif /* DUK_USE_PANIC_HANDLER */
+#if defined(DUK_USE_VERBOSE_ERRORS)
+/* Verbose errors with key/value summaries (non-paranoid) or without key/value
+ * summaries (paranoid, for some security sensitive environments), the paranoid
+ * vs. non-paranoid distinction affects only a few specific errors.
+ */
+#if defined(DUK_USE_PARANOID_ERRORS)
+#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \
+ duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx), (expectname)); \
+ } while (0)
+#else /* DUK_USE_PARANOID_ERRORS */
+#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \
+ duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx), (expectname)); \
+ } while (0)
+#endif /* DUK_USE_PARANOID_ERRORS */
+
+#define DUK_ERROR_INTERNAL(thr) do { \
+ duk_err_error_internal((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
+ } while (0)
+#define DUK_DCERROR_INTERNAL(thr) do { \
+ DUK_ERROR_INTERNAL((thr)); \
+ return 0; \
+ } while (0)
+#define DUK_ERROR_ALLOC_FAILED(thr) do { \
+ duk_err_error_alloc_failed((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
+ } while (0)
+#define DUK_ERROR_UNSUPPORTED(thr) do { \
+ DUK_ERROR((thr), DUK_ERR_ERROR, DUK_STR_UNSUPPORTED); \
+ } while (0)
+#define DUK_ERROR_ERROR(thr,msg) do { \
+ duk_err_error((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
+ } while (0)
+#define DUK_ERROR_RANGE_INDEX(thr,idx) do { \
+ duk_err_range_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx)); \
+ } while (0)
+#define DUK_ERROR_RANGE_PUSH_BEYOND(thr) do { \
+ duk_err_range_push_beyond((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
+ } while (0)
+#define DUK_ERROR_RANGE_INVALID_ARGS(thr) do { \
+ DUK_ERROR_RANGE((thr), DUK_STR_INVALID_ARGS); \
+ } while (0)
+#define DUK_DCERROR_RANGE_INVALID_ARGS(thr) do { \
+ DUK_ERROR_RANGE_INVALID_ARGS((thr)); \
+ return 0; \
+ } while (0)
+#define DUK_ERROR_RANGE_INVALID_COUNT(thr) do { \
+ DUK_ERROR_RANGE((thr), DUK_STR_INVALID_COUNT); \
+ } while (0)
+#define DUK_DCERROR_RANGE_INVALID_COUNT(thr) do { \
+ DUK_ERROR_RANGE_INVALID_COUNT((thr)); \
+ return 0; \
+ } while (0)
+#define DUK_ERROR_RANGE_INVALID_LENGTH(thr) do { \
+ DUK_ERROR_RANGE((thr), DUK_STR_INVALID_LENGTH); \
+ } while (0)
+#define DUK_DCERROR_RANGE_INVALID_LENGTH(thr) do { \
+ DUK_ERROR_RANGE_INVALID_LENGTH((thr)); \
+ return 0; \
+ } while (0)
+#define DUK_ERROR_RANGE(thr,msg) do { \
+ duk_err_range((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
+ } while (0)
+#define DUK_ERROR_EVAL(thr,msg) do { \
+ DUK_ERROR((thr), DUK_ERR_EVAL_ERROR, (msg)); \
+ } while (0)
+#define DUK_ERROR_REFERENCE(thr,msg) do { \
+ DUK_ERROR((thr), DUK_ERR_REFERENCE_ERROR, (msg)); \
+ } while (0)
+#define DUK_ERROR_SYNTAX(thr,msg) do { \
+ DUK_ERROR((thr), DUK_ERR_SYNTAX_ERROR, (msg)); \
+ } while (0)
+#define DUK_ERROR_TYPE_INVALID_ARGS(thr) do { \
+ duk_err_type_invalid_args((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
+ } while (0)
+#define DUK_DCERROR_TYPE_INVALID_ARGS(thr) do { \
+ DUK_ERROR_TYPE_INVALID_ARGS((thr)); \
+ return 0; \
+ } while (0)
+#define DUK_ERROR_TYPE_INVALID_STATE(thr) do { \
+ duk_err_type_invalid_state((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
+ } while (0)
+#define DUK_DCERROR_TYPE_INVALID_STATE(thr) do { \
+ DUK_ERROR_TYPE_INVALID_STATE((thr)); \
+ return 0; \
+ } while (0)
+#define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
+ duk_err_type_invalid_trap_result((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
+ } while (0)
+#define DUK_DCERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
+ DUK_ERROR_TYPE((thr), DUK_STR_INVALID_TRAP_RESULT); \
+ } while (0)
+#define DUK_ERROR_TYPE(thr,msg) do { \
+ DUK_ERROR((thr), DUK_ERR_TYPE_ERROR, (msg)); \
+ } while (0)
+#define DUK_ERROR_URI(thr,msg) do { \
+ DUK_ERROR((thr), DUK_ERR_URI_ERROR, (msg)); \
+ } while (0)
+#else /* DUK_USE_VERBOSE_ERRORS */
+/* Non-verbose errors for low memory targets: no file, line, or message. */
+
+#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \
+ duk_err_type((thr)); \
+ } while (0)
+
+#define DUK_ERROR_INTERNAL(thr) do { \
+ duk_err_error((thr)); \
+ } while (0)
+#define DUK_DCERROR_INTERNAL(thr) do { \
+ DUK_UNREF((thr)); \
+ return DUK_RET_ERROR; \
+ } while (0)
+#define DUK_ERROR_ALLOC_FAILED(thr) do { \
+ duk_err_error((thr)); \
+ } while (0)
+#define DUK_ERROR_UNSUPPORTED(thr) do { \
+ duk_err_error((thr)); \
+ } while (0)
+#define DUK_ERROR_ERROR(thr,msg) do { \
+ duk_err_error((thr)); \
+ } while (0)
+#define DUK_ERROR_RANGE_INDEX(thr,idx) do { \
+ duk_err_range((thr)); \
+ } while (0)
+#define DUK_ERROR_RANGE_PUSH_BEYOND(thr) do { \
+ duk_err_range((thr)); \
+ } while (0)
+#define DUK_ERROR_RANGE_INVALID_ARGS(thr) do { \
+ duk_err_range((thr)); \
+ } while (0)
+#define DUK_DCERROR_RANGE_INVALID_ARGS(thr) do { \
+ DUK_UNREF((thr)); \
+ return DUK_RET_RANGE_ERROR; \
+ } while (0)
+#define DUK_ERROR_RANGE_INVALID_COUNT(thr) do { \
+ duk_err_range((thr)); \
+ } while (0)
+#define DUK_DCERROR_RANGE_INVALID_COUNT(thr) do { \
+ DUK_UNREF((thr)); \
+ return DUK_RET_RANGE_ERROR; \
+ } while (0)
+#define DUK_ERROR_RANGE_INVALID_LENGTH(thr) do { \
+ duk_err_range((thr)); \
+ } while (0)
+#define DUK_DCERROR_RANGE_INVALID_LENGTH(thr) do { \
+ DUK_UNREF((thr)); \
+ return DUK_RET_RANGE_ERROR; \
+ } while (0)
+#define DUK_ERROR_RANGE(thr,msg) do { \
+ duk_err_range((thr)); \
+ } while (0)
+#define DUK_ERROR_EVAL(thr,msg) do { \
+ duk_err_eval((thr)); \
+ } while (0)
+#define DUK_ERROR_REFERENCE(thr,msg) do { \
+ duk_err_reference((thr)); \
+ } while (0)
+#define DUK_ERROR_SYNTAX(thr,msg) do { \
+ duk_err_syntax((thr)); \
+ } while (0)
+#define DUK_ERROR_TYPE_INVALID_ARGS(thr) do { \
+ duk_err_type((thr)); \
+ } while (0)
+#define DUK_DCERROR_TYPE_INVALID_ARGS(thr) do { \
+ DUK_UNREF((thr)); \
+ return DUK_RET_TYPE_ERROR; \
+ } while (0)
+#define DUK_ERROR_TYPE_INVALID_STATE(thr) do { \
+ duk_err_type((thr)); \
+ } while (0)
+#define DUK_DCERROR_TYPE_INVALID_STATE(thr) do { \
+ duk_err_type((thr)); \
+ } while (0)
+#define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
+ duk_err_type((thr)); \
+ } while (0)
+#define DUK_DCERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
+ DUK_UNREF((thr)); \
+ return DUK_RET_TYPE_ERROR; \
+ } while (0)
+#define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
+ duk_err_type((thr)); \
+ } while (0)
+#define DUK_ERROR_TYPE(thr,msg) do { \
+ duk_err_type((thr)); \
+ } while (0)
+#define DUK_ERROR_URI(thr,msg) do { \
+ duk_err_uri((thr)); \
+ } while (0)
+#endif /* DUK_USE_VERBOSE_ERRORS */
/*
- * Assert macro: failure causes panic.
+ * Assert macro: failure causes a fatal error.
+ *
+ * NOTE: since the assert macro doesn't take a heap/context argument, there's
+ * no way to look up a heap/context specific fatal error handler which may have
+ * been given by the application. Instead, assertion failures always use the
+ * internal default fatal error handler; it can be replaced via duk_config.h
+ * and then applies to all Duktape heaps.
*/
#if defined(DUK_USE_ASSERTIONS)
-/* the message should be a compile time constant without formatting (less risk);
+/* The message should be a compile time constant without formatting (less risk);
* we don't care about assertion text size because they're not used in production
* builds.
*/
#define DUK_ASSERT(x) do { \
if (!(x)) { \
- DUK_PANIC(DUK_ERR_ASSERTION_ERROR, \
- "assertion failed: " #x \
+ DUK_FATAL_WITHOUT_CONTEXT("assertion failed: " #x \
" (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"); \
} \
} while (0)
-/* Assertion compatible inside a comma expression, evaluates to void.
- * Currently not compatible with DUK_USE_PANIC_HANDLER() which may have
- * a statement block.
- */
-#if defined(DUK_USE_PANIC_HANDLER)
-/* XXX: resolve macro definition issue or call through a helper function? */
-#define DUK_ASSERT_EXPR(x) ((void) 0)
-#else
+/* Assertion compatible inside a comma expression, evaluates to void. */
#define DUK_ASSERT_EXPR(x) \
- ((void) ((x) ? 0 : (DUK_PANIC(DUK_ERR_ASSERTION_ERROR, \
- "assertion failed: " #x \
+ ((void) ((x) ? 0 : (DUK_FATAL_WITHOUT_CONTEXT("assertion failed: " #x \
" (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"), 0)))
-#endif
#else /* DUK_USE_ASSERTIONS */
@@ -7840,6 +9635,22 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
#define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval) /* nop */
#endif
+#define DUK_ASSERT_VS_SPACE(thr) \
+ DUK_ASSERT(thr->valstack_top < thr->valstack_end)
+
+/*
+ * Helper to initialize a memory area (e.g. struct) with garbage when
+ * assertions enabled.
+ */
+
+#if defined(DUK_USE_ASSERTIONS)
+#define DUK_ASSERT_SET_GARBAGE(ptr,size) do { \
+ DUK_MEMSET((void *) (ptr), 0x5a, size); \
+ } while (0)
+#else
+#define DUK_ASSERT_SET_GARBAGE(ptr,size) do {} while (0)
+#endif
+
/*
* Helper for valstack space
*
@@ -7860,126 +9671,6 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
#define DUK_ASSERT_VALSTACK_SPACE(thr,n) /* no valstack space check */
#endif
-/*
- * Error throwing helpers
- *
- * The goal is to provide verbose and configurable error messages. Call
- * sites should be clean in source code and compile to a small footprint.
- * Small footprint is also useful for performance because small cold paths
- * reduce code cache pressure. Adding macros here only makes sense if there
- * are enough call sites to get concrete benefits.
- */
-
-#if defined(DUK_USE_VERBOSE_ERRORS)
-/* Verbose errors with key/value summaries (non-paranoid) or without key/value
- * summaries (paranoid, for some security sensitive environments), the paranoid
- * vs. non-paranoid distinction affects only a few specific errors.
- */
-#if defined(DUK_USE_PARANOID_ERRORS)
-#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \
- duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (index), (expectname)); \
- } while (0)
-#else /* DUK_USE_PARANOID_ERRORS */
-#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \
- duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (index), (expectname)); \
- } while (0)
-#endif /* DUK_USE_PARANOID_ERRORS */
-
-#define DUK_ERROR_UNIMPLEMENTED(thr,msg) do { \
- DUK_ERROR((thr), DUK_ERR_UNIMPLEMENTED_ERROR, (msg)); \
- } while (0)
-#define DUK_ERROR_UNIMPLEMENTED_DEFMSG(thr) do { \
- duk_err_unimplemented_defmsg((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
- } while (0)
-#define DUK_ERROR_UNSUPPORTED(thr,msg) do { \
- DUK_ERROR((thr), DUK_ERR_UNSUPPORTED_ERROR, (msg)); \
- } while (0)
-#if !defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
-#define DUK_ERROR_UNSUPPORTED_DEFMSG(thr) do { \
- duk_err_unsupported_defmsg((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
- } while (0)
-#endif
-#define DUK_ERROR_INTERNAL(thr,msg) do { \
- duk_err_internal((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
- } while (0)
-#define DUK_ERROR_INTERNAL_DEFMSG(thr) do { \
- duk_err_internal_defmsg((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
- } while (0)
-#define DUK_ERROR_ALLOC(thr,msg) do { \
- duk_err_alloc((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
- } while (0)
-#define DUK_ERROR_ALLOC_DEFMSG(thr) do { \
- DUK_ERROR_ALLOC((thr), DUK_STR_ALLOC_FAILED); \
- } while (0)
-/* DUK_ERR_ASSERTION_ERROR: no macros needed */
-#define DUK_ERROR_API_INDEX(thr,index) do { \
- duk_err_api_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (index)); \
- } while (0)
-#define DUK_ERROR_API(thr,msg) do { \
- duk_err_api((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
- } while (0)
-/* DUK_ERR_UNCAUGHT_ERROR: no macros needed */
-/* DUK_ERR_ERROR: no macros needed */
-/* DUK_ERR_EVAL: no macros needed */
-#define DUK_ERROR_RANGE(thr,msg) do { \
- duk_err_range((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
- } while (0)
-/* DUK_ERR_REFERENCE_ERROR: no macros needed */
-#define DUK_ERROR_SYNTAX(thr,msg) do { \
- DUK_ERROR((thr), DUK_ERR_SYNTAX_ERROR, (msg)); \
- } while (0)
-#define DUK_ERROR_TYPE(thr,msg) do { \
- DUK_ERROR((thr), DUK_ERR_TYPE_ERROR, (msg)); \
- } while (0)
-/* DUK_ERR_URI_ERROR: no macros needed */
-#else /* DUK_USE_VERBOSE_ERRORS */
-/* Non-verbose errors for low memory targets: no file, line, or message. */
-
-#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \
- duk_err_type((thr)); \
- } while (0)
-
-#define DUK_ERROR_UNIMPLEMENTED(thr,msg) do { \
- duk_err_unimplemented((thr)); \
- } while (0)
-#define DUK_ERROR_UNIMPLEMENTED_DEFMSG(thr) do { \
- duk_err_unimplemented((thr)); \
- } while (0)
-#define DUK_ERROR_UNSUPPORTED(thr,msg) do { \
- duk_err_unsupported((thr)); \
- } while (0)
-#define DUK_ERROR_UNSUPPORTED_DEFMSG(thr) do { \
- duk_err_unsupported((thr)); \
- } while (0)
-#define DUK_ERROR_INTERNAL(thr,msg) do { \
- duk_err_internal((thr)); \
- } while (0)
-#define DUK_ERROR_INTERNAL_DEFMSG(thr) do { \
- duk_err_internal((thr)); \
- } while (0)
-#define DUK_ERROR_ALLOC(thr,msg) do { \
- duk_err_alloc((thr)); \
- } while (0)
-#define DUK_ERROR_ALLOC_DEFMSG(thr) do { \
- duk_err_alloc((thr)); \
- } while (0)
-#define DUK_ERROR_API_INDEX(thr,index) do { \
- duk_err_api((thr)); \
- } while (0)
-#define DUK_ERROR_API(thr,msg) do { \
- duk_err_api((thr)); \
- } while (0)
-#define DUK_ERROR_RANGE(thr,msg) do { \
- duk_err_range((thr)); \
- } while (0)
-#define DUK_ERROR_SYNTAX(thr,msg) do { \
- duk_err_syntax((thr)); \
- } while (0)
-#define DUK_ERROR_TYPE(thr,msg) do { \
- duk_err_type((thr)); \
- } while (0)
-#endif /* DUK_USE_VERBOSE_ERRORS */
-
/*
* Prototypes
*/
@@ -7999,8 +9690,11 @@ DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_create_and_throw(duk_hthread *thr, d
DUK_NORETURN(DUK_INTERNAL_DECL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc));
+#define DUK_AUGMENT_FLAG_NOBLAME_FILELINE (1U << 0) /* if set, don't blame C file/line for .fileName and .lineNumber */
+#define DUK_AUGMENT_FLAG_SKIP_ONE (1U << 1) /* if set, skip topmost activation in traceback construction */
+
#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
-DUK_INTERNAL_DECL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *filename, duk_int_t line, duk_bool_t noblame_fileline);
+DUK_INTERNAL_DECL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *filename, duk_int_t line, duk_small_uint_t flags);
#endif
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
DUK_INTERNAL_DECL void duk_err_augment_error_throw(duk_hthread *thr);
@@ -8008,50 +9702,48 @@ DUK_INTERNAL_DECL void duk_err_augment_error_throw(duk_hthread *thr);
#if defined(DUK_USE_VERBOSE_ERRORS)
#if defined(DUK_USE_PARANOID_ERRORS)
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name));
#else
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name));
#endif
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error_alloc_failed(duk_hthread *thr, const char *filename, duk_int_t linenumber));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range_push_beyond(duk_hthread *thr, const char *filename, duk_int_t linenumber));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unimplemented_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber));
-#if !defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unsupported_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber));
-#endif
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_internal_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_alloc(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_args(duk_hthread *thr, const char *filename, duk_int_t linenumber));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_state(duk_hthread *thr, const char *filename, duk_int_t linenumber));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_trap_result(duk_hthread *thr, const char *filename, duk_int_t linenumber));
#else /* DUK_VERBOSE_ERRORS */
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error(duk_hthread *thr));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_eval(duk_hthread *thr));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_reference(duk_hthread *thr));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_syntax(duk_hthread *thr));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type(duk_hthread *thr));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api(duk_hthread *thr));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unimplemented(duk_hthread *thr));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unsupported(duk_hthread *thr));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_internal(duk_hthread *thr));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_alloc(duk_hthread *thr));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_uri(duk_hthread *thr));
#endif /* DUK_VERBOSE_ERRORS */
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_longjmp(duk_hthread *thr));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg));
+DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_fatal_handler(void *udata, const char *msg));
-#if !defined(DUK_USE_PANIC_HANDLER)
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_panic_handler(duk_errcode_t code, const char *msg));
+DUK_INTERNAL_DECL void duk_err_setup_ljstate1(duk_hthread *thr, duk_small_uint_t lj_type, duk_tval *tv_val);
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+DUK_INTERNAL_DECL void duk_err_check_debugger_integration(duk_hthread *thr);
#endif
-DUK_INTERNAL_DECL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t lj_type);
-
DUK_INTERNAL_DECL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_errcode_t err_code);
#endif /* DUK_ERROR_H_INCLUDED */
+/* #include duk_unicode.h */
#line 1 "duk_unicode.h"
/*
* Unicode helpers
*/
-#ifndef DUK_UNICODE_H_INCLUDED
+#if !defined(DUK_UNICODE_H_INCLUDED)
#define DUK_UNICODE_H_INCLUDED
/*
@@ -8214,25 +9906,34 @@ DUK_INTERNAL_DECL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, d
#define DUK_ASC_TILDE 0x7e
#define DUK_ASC_DEL 0x7f
+/*
+ * Miscellaneous
+ */
+
+/* Uppercase A is 0x41, lowercase a is 0x61; OR 0x20 to convert uppercase
+ * to lowercase.
+ */
+#define DUK_LOWERCASE_CHAR_ASCII(x) ((x) | 0x20)
+
/*
* Unicode tables
*/
-#ifdef DUK_USE_SOURCE_NONBMP
+#if defined(DUK_USE_SOURCE_NONBMP)
/*
* Automatically generated by extract_chars.py, do not edit!
*/
-extern const duk_uint8_t duk_unicode_ids_noa[791];
+extern const duk_uint8_t duk_unicode_ids_noa[1036];
#else
/*
* Automatically generated by extract_chars.py, do not edit!
*/
-extern const duk_uint8_t duk_unicode_ids_noabmp[611];
+extern const duk_uint8_t duk_unicode_ids_noabmp[625];
#endif
-#ifdef DUK_USE_SOURCE_NONBMP
+#if defined(DUK_USE_SOURCE_NONBMP)
/*
* Automatically generated by extract_chars.py, do not edit!
*/
@@ -8246,26 +9947,26 @@ extern const duk_uint8_t duk_unicode_ids_m_let_noa[42];
extern const duk_uint8_t duk_unicode_ids_m_let_noabmp[24];
#endif
-#ifdef DUK_USE_SOURCE_NONBMP
+#if defined(DUK_USE_SOURCE_NONBMP)
/*
* Automatically generated by extract_chars.py, do not edit!
*/
-extern const duk_uint8_t duk_unicode_idp_m_ids_noa[397];
+extern const duk_uint8_t duk_unicode_idp_m_ids_noa[530];
#else
/*
* Automatically generated by extract_chars.py, do not edit!
*/
-extern const duk_uint8_t duk_unicode_idp_m_ids_noabmp[348];
+extern const duk_uint8_t duk_unicode_idp_m_ids_noabmp[357];
#endif
/*
* Automatically generated by extract_caseconv.py, do not edit!
*/
-extern const duk_uint8_t duk_unicode_caseconv_uc[1288];
-extern const duk_uint8_t duk_unicode_caseconv_lc[616];
+extern const duk_uint8_t duk_unicode_caseconv_uc[1386];
+extern const duk_uint8_t duk_unicode_caseconv_lc[680];
#if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
/*
@@ -8275,6 +9976,17 @@ extern const duk_uint8_t duk_unicode_caseconv_lc[616];
extern const duk_uint16_t duk_unicode_re_canon_lookup[65536];
#endif
+#if defined(DUK_USE_REGEXP_CANON_BITMAP)
+/*
+ * Automatically generated by extract_caseconv.py, do not edit!
+ */
+
+#define DUK_CANON_BITMAP_BLKSIZE 32
+#define DUK_CANON_BITMAP_BLKSHIFT 5
+#define DUK_CANON_BITMAP_BLKMASK 31
+extern const duk_uint8_t duk_unicode_re_canon_bitmap[256];
+#endif
+
/*
* Extern
*/
@@ -8310,23 +10022,26 @@ DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_
DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp);
DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp);
DUK_INTERNAL_DECL void duk_unicode_case_convert_string(duk_hthread *thr, duk_bool_t uppercase);
+#if defined(DUK_USE_REGEXP_SUPPORT)
DUK_INTERNAL_DECL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp);
DUK_INTERNAL_DECL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t cp);
+#endif
#endif /* DUK_UNICODE_H_INCLUDED */
+/* #include duk_json.h */
#line 1 "duk_json.h"
/*
* Defines for JSON, especially duk_bi_json.c.
*/
-#ifndef DUK_JSON_H_INCLUDED
+#if !defined(DUK_JSON_H_INCLUDED)
#define DUK_JSON_H_INCLUDED
/* Encoding/decoding flags */
-#define DUK_JSON_FLAG_ASCII_ONLY (1 << 0) /* escape any non-ASCII characters */
-#define DUK_JSON_FLAG_AVOID_KEY_QUOTES (1 << 1) /* avoid key quotes when key is an ASCII Identifier */
-#define DUK_JSON_FLAG_EXT_CUSTOM (1 << 2) /* extended types: custom encoding */
-#define DUK_JSON_FLAG_EXT_COMPATIBLE (1 << 3) /* extended types: compatible encoding */
+#define DUK_JSON_FLAG_ASCII_ONLY (1U << 0) /* escape any non-ASCII characters */
+#define DUK_JSON_FLAG_AVOID_KEY_QUOTES (1U << 1) /* avoid key quotes when key is an ASCII Identifier */
+#define DUK_JSON_FLAG_EXT_CUSTOM (1U << 2) /* extended types: custom encoding */
+#define DUK_JSON_FLAG_EXT_COMPATIBLE (1U << 3) /* extended types: compatible encoding */
/* How much stack to require on entry to object/array encode */
#define DUK_JSON_ENC_REQSTACK 32
@@ -8353,8 +10068,8 @@ typedef struct {
duk_small_uint_t flag_ext_compatible;
duk_small_uint_t flag_ext_custom_or_compatible;
#endif
- duk_int_t recursion_depth;
- duk_int_t recursion_limit;
+ duk_uint_t recursion_depth;
+ duk_uint_t recursion_limit;
duk_uint_t mask_for_undefined; /* type bit mask: types which certainly produce 'undefined' */
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
duk_small_uint_t stridx_custom_undefined;
@@ -8383,28 +10098,31 @@ typedef struct {
} duk_json_dec_ctx;
#endif /* DUK_JSON_H_INCLUDED */
+/* #include duk_js.h */
#line 1 "duk_js.h"
/*
* Ecmascript execution, support primitives.
*/
-#ifndef DUK_JS_H_INCLUDED
+#if !defined(DUK_JS_H_INCLUDED)
#define DUK_JS_H_INCLUDED
-/* Flags for call handling. */
-#define DUK_CALL_FLAG_IGNORE_RECLIMIT (1 << 0) /* duk_handle_call_xxx: call ignores C recursion limit (for errhandler calls) */
-#define DUK_CALL_FLAG_CONSTRUCTOR_CALL (1 << 1) /* duk_handle_call_xxx: constructor call (i.e. called as 'new Foo()') */
-#define DUK_CALL_FLAG_IS_RESUME (1 << 2) /* duk_handle_ecma_call_setup: setup for a resume() */
-#define DUK_CALL_FLAG_IS_TAILCALL (1 << 3) /* duk_handle_ecma_call_setup: setup for a tail call */
-#define DUK_CALL_FLAG_DIRECT_EVAL (1 << 4) /* call is a direct eval call */
+/* Flags for call handling. Lowest flags must match bytecode DUK_BC_CALL_FLAG_xxx 1:1. */
+#define DUK_CALL_FLAG_TAILCALL (1U << 0) /* setup for a tail call */
+#define DUK_CALL_FLAG_CONSTRUCT (1U << 1) /* constructor call (i.e. called as 'new Foo()') */
+#define DUK_CALL_FLAG_CALLED_AS_EVAL (1U << 2) /* call was made using the identifier 'eval' */
+#define DUK_CALL_FLAG_ALLOW_ECMATOECMA (1U << 3) /* ecma-to-ecma call with executor reuse is possible */
+#define DUK_CALL_FLAG_DIRECT_EVAL (1U << 4) /* call is a direct eval call */
+#define DUK_CALL_FLAG_CONSTRUCT_PROXY (1U << 5) /* handled via 'construct' proxy trap, check return value invariant(s) */
+#define DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED (1U << 6) /* prototype of 'default instance' updated, temporary flag in call handling */
/* Flags for duk_js_equals_helper(). */
-#define DUK_EQUALS_FLAG_SAMEVALUE (1 << 0) /* use SameValue instead of non-strict equality */
-#define DUK_EQUALS_FLAG_STRICT (1 << 1) /* use strict equality instead of non-strict equality */
+#define DUK_EQUALS_FLAG_SAMEVALUE (1U << 0) /* use SameValue instead of non-strict equality */
+#define DUK_EQUALS_FLAG_STRICT (1U << 1) /* use strict equality instead of non-strict equality */
/* Flags for duk_js_compare_helper(). */
-#define DUK_COMPARE_FLAG_EVAL_LEFT_FIRST (1 << 0) /* eval left argument first */
-#define DUK_COMPARE_FLAG_NEGATE (1 << 1) /* negate result */
+#define DUK_COMPARE_FLAG_NEGATE (1U << 0) /* negate result */
+#define DUK_COMPARE_FLAG_EVAL_LEFT_FIRST (1U << 1) /* eval left argument first */
/* conversions, coercions, comparison, etc */
DUK_INTERNAL_DECL duk_bool_t duk_js_toboolean(duk_tval *tv);
@@ -8414,18 +10132,25 @@ DUK_INTERNAL_DECL duk_double_t duk_js_tointeger(duk_hthread *thr, duk_tval *tv);
DUK_INTERNAL_DECL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv);
DUK_INTERNAL_DECL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv);
DUK_INTERNAL_DECL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv);
-DUK_INTERNAL_DECL duk_small_int_t duk_js_to_arrayindex_raw_string(const duk_uint8_t *str, duk_uint32_t blen, duk_uarridx_t *out_idx);
-DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h);
-DUK_INTERNAL_DECL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags);
+DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string(const duk_uint8_t *str, duk_uint32_t blen);
+#if !defined(DUK_USE_HSTRING_ARRIDX)
+DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_hstring_fast_known(duk_hstring *h);
+DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_hstring_fast(duk_hstring *h);
+#endif
+DUK_INTERNAL_DECL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags);
DUK_INTERNAL_DECL duk_small_int_t duk_js_data_compare(const duk_uint8_t *buf1, const duk_uint8_t *buf2, duk_size_t len1, duk_size_t len2);
DUK_INTERNAL_DECL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2);
#if 0 /* unused */
DUK_INTERNAL_DECL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *h1, duk_hbuffer *h2);
#endif
-DUK_INTERNAL_DECL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags);
+DUK_INTERNAL_DECL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags);
DUK_INTERNAL_DECL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
DUK_INTERNAL_DECL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
-DUK_INTERNAL_DECL duk_hstring *duk_js_typeof(duk_hthread *thr, duk_tval *tv_x);
+DUK_INTERNAL_DECL duk_small_uint_t duk_js_typeof_stridx(duk_tval *tv_x);
+
+/* arithmetic */
+DUK_INTERNAL_DECL double duk_js_arith_pow(double x, double y);
+DUK_INTERNAL_DECL double duk_js_arith_mod(double x, double y);
#define duk_js_equals(thr,tv_x,tv_y) \
duk_js_equals_helper((thr), (tv_x), (tv_y), 0)
@@ -8462,56 +10187,59 @@ DUK_INTERNAL_DECL void duk_js_putvar_activation(duk_hthread *thr, duk_activation
DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name);
#endif
DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name);
-DUK_INTERNAL_DECL duk_bool_t duk_js_declvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_small_int_t prop_flags, duk_bool_t is_func_decl);
+DUK_INTERNAL_DECL duk_bool_t duk_js_declvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_small_uint_t prop_flags, duk_bool_t is_func_decl);
DUK_INTERNAL_DECL void duk_js_init_activation_environment_records_delayed(duk_hthread *thr, duk_activation *act);
-DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env, duk_hobject *func, duk_size_t regbase);
-DUK_INTERNAL_DECL duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_size_t idx_bottom);
-DUK_INTERNAL_DECL
-void duk_js_push_closure(duk_hthread *thr,
- duk_hcompiledfunction *fun_temp,
- duk_hobject *outer_var_env,
- duk_hobject *outer_lex_env,
- duk_bool_t add_auto_proto);
+DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env);
+DUK_INTERNAL_DECL duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_size_t bottom_byteoff);
+DUK_INTERNAL_DECL void duk_js_push_closure(duk_hthread *thr,
+ duk_hcompfunc *fun_temp,
+ duk_hobject *outer_var_env,
+ duk_hobject *outer_lex_env,
+ duk_bool_t add_auto_proto);
/* call handling */
-DUK_INTERNAL_DECL duk_int_t duk_handle_call_protected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
-DUK_INTERNAL_DECL void duk_handle_call_unprotected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
-DUK_INTERNAL_DECL duk_int_t duk_handle_safe_call(duk_hthread *thr, duk_safe_call_function func, duk_idx_t num_stack_args, duk_idx_t num_stack_res);
-DUK_INTERNAL_DECL duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
+DUK_INTERNAL_DECL duk_int_t duk_handle_call_unprotected(duk_hthread *thr, duk_idx_t idx_func, duk_small_uint_t call_flags);
+DUK_INTERNAL_DECL duk_int_t duk_handle_call_unprotected_nargs(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags);
+DUK_INTERNAL_DECL duk_int_t duk_handle_safe_call(duk_hthread *thr, duk_safe_call_function func, void *udata, duk_idx_t num_stack_args, duk_idx_t num_stack_res);
+DUK_INTERNAL_DECL void duk_call_construct_postprocess(duk_hthread *thr, duk_small_uint_t proxy_invariant);
+#if defined(DUK_USE_VERBOSE_ERRORS)
+DUK_INTERNAL_DECL void duk_call_setup_propcall_error(duk_hthread *thr, duk_tval *tv_targ, duk_tval *tv_base, duk_tval *tv_key);
+#endif
/* bytecode execution */
DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr);
#endif /* DUK_JS_H_INCLUDED */
+/* #include duk_numconv.h */
#line 1 "duk_numconv.h"
-#ifndef DUK_NUMCONV_H_INCLUDED
-#define DUK_NUMCONV_H_INCLUDED
-
/*
* Number-to-string conversion. The semantics of these is very tightly
* bound with the Ecmascript semantics required for call sites.
*/
+#if !defined(DUK_NUMCONV_H_INCLUDED)
+#define DUK_NUMCONV_H_INCLUDED
+
/* Output a specified number of digits instead of using the shortest
* form. Used for toPrecision() and toFixed().
*/
-#define DUK_N2S_FLAG_FIXED_FORMAT (1 << 0)
+#define DUK_N2S_FLAG_FIXED_FORMAT (1U << 0)
/* Force exponential format. Used for toExponential(). */
-#define DUK_N2S_FLAG_FORCE_EXP (1 << 1)
+#define DUK_N2S_FLAG_FORCE_EXP (1U << 1)
/* If number would need zero padding (for whole number part), use
* exponential format instead. E.g. if input number is 12300, 3
* digits are generated ("123"), output "1.23e+4" instead of "12300".
* Used for toPrecision().
*/
-#define DUK_N2S_FLAG_NO_ZERO_PAD (1 << 2)
+#define DUK_N2S_FLAG_NO_ZERO_PAD (1U << 2)
/* Digit count indicates number of fractions (i.e. an absolute
* digit index instead of a relative one). Used together with
* DUK_N2S_FLAG_FIXED_FORMAT for toFixed().
*/
-#define DUK_N2S_FLAG_FRACTION_DIGITS (1 << 3)
+#define DUK_N2S_FLAG_FRACTION_DIGITS (1U << 3)
/*
* String-to-number conversion
@@ -8524,152 +10252,170 @@ DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr);
#define DUK_S2N_MAX_EXPONENT 1000000000
/* Trim white space (= allow leading and trailing whitespace) */
-#define DUK_S2N_FLAG_TRIM_WHITE (1 << 0)
+#define DUK_S2N_FLAG_TRIM_WHITE (1U << 0)
/* Allow exponent */
-#define DUK_S2N_FLAG_ALLOW_EXP (1 << 1)
+#define DUK_S2N_FLAG_ALLOW_EXP (1U << 1)
/* Allow trailing garbage (e.g. treat "123foo" as "123) */
-#define DUK_S2N_FLAG_ALLOW_GARBAGE (1 << 2)
+#define DUK_S2N_FLAG_ALLOW_GARBAGE (1U << 2)
/* Allow leading plus sign */
-#define DUK_S2N_FLAG_ALLOW_PLUS (1 << 3)
+#define DUK_S2N_FLAG_ALLOW_PLUS (1U << 3)
/* Allow leading minus sign */
-#define DUK_S2N_FLAG_ALLOW_MINUS (1 << 4)
+#define DUK_S2N_FLAG_ALLOW_MINUS (1U << 4)
/* Allow 'Infinity' */
-#define DUK_S2N_FLAG_ALLOW_INF (1 << 5)
+#define DUK_S2N_FLAG_ALLOW_INF (1U << 5)
/* Allow fraction part */
-#define DUK_S2N_FLAG_ALLOW_FRAC (1 << 6)
+#define DUK_S2N_FLAG_ALLOW_FRAC (1U << 6)
/* Allow naked fraction (e.g. ".123") */
-#define DUK_S2N_FLAG_ALLOW_NAKED_FRAC (1 << 7)
+#define DUK_S2N_FLAG_ALLOW_NAKED_FRAC (1U << 7)
/* Allow empty fraction (e.g. "123.") */
-#define DUK_S2N_FLAG_ALLOW_EMPTY_FRAC (1 << 8)
+#define DUK_S2N_FLAG_ALLOW_EMPTY_FRAC (1U << 8)
/* Allow empty string to be interpreted as 0 */
-#define DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO (1 << 9)
+#define DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO (1U << 9)
/* Allow leading zeroes (e.g. "0123" -> "123") */
-#define DUK_S2N_FLAG_ALLOW_LEADING_ZERO (1 << 10)
+#define DUK_S2N_FLAG_ALLOW_LEADING_ZERO (1U << 10)
/* Allow automatic detection of hex base ("0x" or "0X" prefix),
* overrides radix argument and forces integer mode.
*/
-#define DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT (1 << 11)
+#define DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT (1U << 11)
-/* Allow automatic detection of octal base, overrides radix
- * argument and forces integer mode.
+/* Allow automatic detection of legacy octal base ("0n"),
+ * overrides radix argument and forces integer mode.
*/
-#define DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT (1 << 12)
+#define DUK_S2N_FLAG_ALLOW_AUTO_LEGACY_OCT_INT (1U << 12)
+
+/* Allow automatic detection of ES2015 octal base ("0o123"),
+ * overrides radix argument and forces integer mode.
+ */
+#define DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT (1U << 13)
+
+/* Allow automatic detection of ES2015 binary base ("0b10001"),
+ * overrides radix argument and forces integer mode.
+ */
+#define DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT (1U << 14)
/*
* Prototypes
*/
-DUK_INTERNAL_DECL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags);
-DUK_INTERNAL_DECL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk_small_uint_t flags);
+DUK_INTERNAL_DECL void duk_numconv_stringify(duk_hthread *thr, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags);
+DUK_INTERNAL_DECL void duk_numconv_parse(duk_hthread *thr, duk_small_int_t radix, duk_small_uint_t flags);
#endif /* DUK_NUMCONV_H_INCLUDED */
+/* #include duk_bi_protos.h */
#line 1 "duk_bi_protos.h"
/*
* Prototypes for built-in functions not automatically covered by the
* header declarations emitted by genbuiltins.py.
*/
-#ifndef DUK_BUILTIN_PROTOS_H_INCLUDED
+#if !defined(DUK_BUILTIN_PROTOS_H_INCLUDED)
#define DUK_BUILTIN_PROTOS_H_INCLUDED
-/* Buffer size needed for duk_bi_date_format_timeval().
+/* Buffer size needed for ISO 8601 formatting.
* Accurate value is 32 + 1 for NUL termination:
* >>> len('+123456-01-23T12:34:56.123+12:34')
* 32
* Include additional space to be safe.
*/
-#define DUK_BI_DATE_ISO8601_BUFSIZE 48
-
-/* Maximum length of CommonJS module identifier to resolve. Length includes
- * both current module ID, requested (possibly relative) module ID, and a
- * slash in between.
- */
-#define DUK_BI_COMMONJS_MODULE_ID_LIMIT 256
+#define DUK_BI_DATE_ISO8601_BUFSIZE 40
/* Helpers exposed for internal use */
DUK_INTERNAL_DECL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts, duk_double_t *dparts, duk_small_uint_t flags);
DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dparts, duk_small_uint_t flags);
-DUK_INTERNAL_DECL void duk_bi_date_format_timeval(duk_double_t timeval, duk_uint8_t *out_buf);
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year);
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x);
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t year);
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x);
/* Built-in providers */
#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
-DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx);
+DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_gettimeofday(void);
#endif
#if defined(DUK_USE_DATE_NOW_TIME)
-DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_time(duk_context *ctx);
+DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_time(void);
#endif
#if defined(DUK_USE_DATE_NOW_WINDOWS)
-DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx);
+DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows(void);
#endif
-#if defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME)
+#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS)
+DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows_subms(void);
+#endif
+#if defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S) || defined(DUK_USE_DATE_TZO_GMTIME)
DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d);
#endif
#if defined(DUK_USE_DATE_TZO_WINDOWS)
DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d);
#endif
+#if defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST)
+DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_double_t d);
+#endif
#if defined(DUK_USE_DATE_PRS_STRPTIME)
-DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, const char *str);
+DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_strptime(duk_hthread *thr, const char *str);
#endif
#if defined(DUK_USE_DATE_PRS_GETDATE)
-DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const char *str);
+DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_getdate(duk_hthread *thr, const char *str);
#endif
#if defined(DUK_USE_DATE_FMT_STRFTIME)
-DUK_INTERNAL_DECL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags);
+DUK_INTERNAL_DECL duk_bool_t duk_bi_date_format_parts_strftime(duk_hthread *thr, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags);
+#endif
+
+#if defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME)
+DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_monotonic_time_clock_gettime(void);
+#endif
+#if defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC)
+DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_monotonic_time_windows_qpc(void);
#endif
DUK_INTERNAL_DECL
-void duk_bi_json_parse_helper(duk_context *ctx,
+void duk_bi_json_parse_helper(duk_hthread *thr,
duk_idx_t idx_value,
duk_idx_t idx_reviver,
duk_small_uint_t flags);
DUK_INTERNAL_DECL
-void duk_bi_json_stringify_helper(duk_context *ctx,
+void duk_bi_json_stringify_helper(duk_hthread *thr,
duk_idx_t idx_value,
duk_idx_t idx_replacer,
duk_idx_t idx_space,
duk_small_uint_t flags);
+DUK_INTERNAL_DECL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_hthread *thr);
+
+#if defined(DUK_USE_ES6_PROXY)
+DUK_INTERNAL_DECL void duk_proxy_ownkeys_postprocess(duk_hthread *thr, duk_hobject *h_proxy_target, duk_uint_t flags);
+#endif
+
#endif /* DUK_BUILTIN_PROTOS_H_INCLUDED */
+/* #include duk_selftest.h */
#line 1 "duk_selftest.h"
/*
* Selftest code
*/
-#ifndef DUK_SELFTEST_H_INCLUDED
+#if !defined(DUK_SELFTEST_H_INCLUDED)
#define DUK_SELFTEST_H_INCLUDED
#if defined(DUK_USE_SELF_TESTS)
-DUK_INTERNAL_DECL void duk_selftest_run_tests(void);
+DUK_INTERNAL_DECL duk_uint_t duk_selftest_run_tests(duk_alloc_function alloc_func,
+ duk_realloc_function realloc_func,
+ duk_free_function free_func,
+ void *udata);
#endif
#endif /* DUK_SELFTEST_H_INCLUDED */
-#line 78 "duk_internal.h"
+#line 82 "duk_internal.h"
#endif /* DUK_INTERNAL_H_INCLUDED */
-#line 1 "duk_replacements.c"
-/*
- * Replacements for missing platform functions.
- *
- * Unlike the originals, fpclassify() and signbit() replacements don't
- * work on any floating point types, only doubles. The C typing here
- * mimics the standard prototypes.
- */
-
-/* include removed: duk_internal.h */
+#line 10 "duk_replacements.c"
#if defined(DUK_USE_COMPUTED_NAN)
DUK_INTERNAL double duk_computed_nan;
@@ -8743,130 +10489,14 @@ DUK_INTERNAL int duk_repl_isinf(double x) {
return (c == DUK_FP_INFINITE);
}
#endif
-#line 1 "duk_strings.c"
-/*
- * Shared error message strings
- *
- * To minimize code footprint, try to share error messages inside Duktape
- * code. Modern compilers will do this automatically anyway, this is mostly
- * for older compilers.
- */
-
-/* include removed: duk_internal.h */
-
-/* Mostly API and built-in method related */
-DUK_INTERNAL const char *duk_str_internal_error = "internal error";
-DUK_INTERNAL const char *duk_str_invalid_count = "invalid count";
-DUK_INTERNAL const char *duk_str_invalid_call_args = "invalid call args";
-DUK_INTERNAL const char *duk_str_not_constructable = "not constructable";
-DUK_INTERNAL const char *duk_str_not_callable = "not callable";
-DUK_INTERNAL const char *duk_str_not_extensible = "not extensible";
-DUK_INTERNAL const char *duk_str_not_writable = "not writable";
-DUK_INTERNAL const char *duk_str_not_configurable = "not configurable";
-
-DUK_INTERNAL const char *duk_str_invalid_context = "invalid context";
-DUK_INTERNAL const char *duk_str_push_beyond_alloc_stack = "attempt to push beyond currently allocated stack";
-DUK_INTERNAL const char *duk_str_not_buffer = "not buffer"; /* still in use with verbose messages */
-DUK_INTERNAL const char *duk_str_unexpected_type = "unexpected type";
-DUK_INTERNAL const char *duk_str_defaultvalue_coerce_failed = "[[DefaultValue]] coerce failed";
-DUK_INTERNAL const char *duk_str_number_outside_range = "number outside range";
-DUK_INTERNAL const char *duk_str_not_object_coercible = "not object coercible";
-DUK_INTERNAL const char *duk_str_string_too_long = "string too long";
-DUK_INTERNAL const char *duk_str_buffer_too_long = "buffer too long";
-DUK_INTERNAL const char *duk_str_sprintf_too_long = "sprintf message too long";
-DUK_INTERNAL const char *duk_str_alloc_failed = "alloc failed";
-DUK_INTERNAL const char *duk_str_pop_too_many = "attempt to pop too many entries";
-DUK_INTERNAL const char *duk_str_wrong_buffer_type = "wrong buffer type";
-DUK_INTERNAL const char *duk_str_encode_failed = "encode failed";
-DUK_INTERNAL const char *duk_str_decode_failed = "decode failed";
-DUK_INTERNAL const char *duk_str_no_sourcecode = "no sourcecode";
-DUK_INTERNAL const char *duk_str_concat_result_too_long = "concat result too long";
-DUK_INTERNAL const char *duk_str_unimplemented = "unimplemented";
-DUK_INTERNAL const char *duk_str_unsupported = "unsupported";
-DUK_INTERNAL const char *duk_str_array_length_over_2g = "array length over 2G";
-
-/* JSON */
-DUK_INTERNAL const char *duk_str_fmt_ptr = "%p";
-DUK_INTERNAL const char *duk_str_fmt_invalid_json = "invalid json (at offset %ld)";
-DUK_INTERNAL const char *duk_str_jsondec_reclimit = "json decode recursion limit";
-DUK_INTERNAL const char *duk_str_jsonenc_reclimit = "json encode recursion limit";
-DUK_INTERNAL const char *duk_str_cyclic_input = "cyclic input";
-
-/* Object property access */
-DUK_INTERNAL const char *duk_str_proxy_revoked = "proxy revoked";
-DUK_INTERNAL const char *duk_str_invalid_base = "invalid base value";
-DUK_INTERNAL const char *duk_str_strict_caller_read = "attempt to read strict 'caller'";
-DUK_INTERNAL const char *duk_str_proxy_rejected = "proxy rejected";
-DUK_INTERNAL const char *duk_str_invalid_array_length = "invalid array length";
-DUK_INTERNAL const char *duk_str_array_length_write_failed = "array length write failed";
-DUK_INTERNAL const char *duk_str_array_length_not_writable = "array length non-writable";
-DUK_INTERNAL const char *duk_str_setter_undefined = "setter undefined";
-DUK_INTERNAL const char *duk_str_redefine_virt_prop = "attempt to redefine virtual property";
-DUK_INTERNAL const char *duk_str_invalid_descriptor = "invalid descriptor";
-DUK_INTERNAL const char *duk_str_property_is_virtual = "property is virtual";
-
-/* Compiler */
-DUK_INTERNAL const char *duk_str_parse_error = "parse error";
-DUK_INTERNAL const char *duk_str_duplicate_label = "duplicate label";
-DUK_INTERNAL const char *duk_str_invalid_label = "invalid label";
-DUK_INTERNAL const char *duk_str_invalid_array_literal = "invalid array literal";
-DUK_INTERNAL const char *duk_str_invalid_object_literal = "invalid object literal";
-DUK_INTERNAL const char *duk_str_invalid_var_declaration = "invalid variable declaration";
-DUK_INTERNAL const char *duk_str_cannot_delete_identifier = "cannot delete identifier";
-DUK_INTERNAL const char *duk_str_invalid_expression = "invalid expression";
-DUK_INTERNAL const char *duk_str_invalid_lvalue = "invalid lvalue";
-DUK_INTERNAL const char *duk_str_expected_identifier = "expected identifier";
-DUK_INTERNAL const char *duk_str_empty_expr_not_allowed = "empty expression not allowed";
-DUK_INTERNAL const char *duk_str_invalid_for = "invalid for statement";
-DUK_INTERNAL const char *duk_str_invalid_switch = "invalid switch statement";
-DUK_INTERNAL const char *duk_str_invalid_break_cont_label = "invalid break/continue label";
-DUK_INTERNAL const char *duk_str_invalid_return = "invalid return";
-DUK_INTERNAL const char *duk_str_invalid_try = "invalid try";
-DUK_INTERNAL const char *duk_str_invalid_throw = "invalid throw";
-DUK_INTERNAL const char *duk_str_with_in_strict_mode = "with in strict mode";
-DUK_INTERNAL const char *duk_str_func_stmt_not_allowed = "function statement not allowed";
-DUK_INTERNAL const char *duk_str_unterminated_stmt = "unterminated statement";
-DUK_INTERNAL const char *duk_str_invalid_arg_name = "invalid argument name";
-DUK_INTERNAL const char *duk_str_invalid_func_name = "invalid function name";
-DUK_INTERNAL const char *duk_str_invalid_getset_name = "invalid getter/setter name";
-DUK_INTERNAL const char *duk_str_func_name_required = "function name required";
-
-/* Regexp */
-DUK_INTERNAL const char *duk_str_invalid_quantifier_no_atom = "quantifier without preceding atom";
-DUK_INTERNAL const char *duk_str_invalid_quantifier_values = "quantifier values invalid (qmin > qmax)";
-DUK_INTERNAL const char *duk_str_quantifier_too_many_copies = "quantifier expansion requires too many atom copies";
-DUK_INTERNAL const char *duk_str_unexpected_closing_paren = "unexpected closing parenthesis";
-DUK_INTERNAL const char *duk_str_unexpected_end_of_pattern = "unexpected end of pattern";
-DUK_INTERNAL const char *duk_str_unexpected_regexp_token = "unexpected token in regexp";
-DUK_INTERNAL const char *duk_str_invalid_regexp_flags = "invalid regexp flags";
-DUK_INTERNAL const char *duk_str_invalid_backrefs = "invalid backreference(s)";
-
-/* Limits */
-DUK_INTERNAL const char *duk_str_valstack_limit = "valstack limit";
-DUK_INTERNAL const char *duk_str_callstack_limit = "callstack limit";
-DUK_INTERNAL const char *duk_str_catchstack_limit = "catchstack limit";
-DUK_INTERNAL const char *duk_str_prototype_chain_limit = "prototype chain limit";
-DUK_INTERNAL const char *duk_str_bound_chain_limit = "function call bound chain limit";
-DUK_INTERNAL const char *duk_str_c_callstack_limit = "C call stack depth limit";
-DUK_INTERNAL const char *duk_str_compiler_recursion_limit = "compiler recursion limit";
-DUK_INTERNAL const char *duk_str_bytecode_limit = "bytecode limit";
-DUK_INTERNAL const char *duk_str_reg_limit = "register limit";
-DUK_INTERNAL const char *duk_str_temp_limit = "temp limit";
-DUK_INTERNAL const char *duk_str_const_limit = "const limit";
-DUK_INTERNAL const char *duk_str_func_limit = "function limit";
-DUK_INTERNAL const char *duk_str_regexp_compiler_recursion_limit = "regexp compiler recursion limit";
-DUK_INTERNAL const char *duk_str_regexp_executor_recursion_limit = "regexp executor recursion limit";
-DUK_INTERNAL const char *duk_str_regexp_executor_step_limit = "regexp step limit";
-
-/* Misc */
#line 1 "duk_debug_macros.c"
/*
* Debugging macro calls.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-#ifdef DUK_USE_DEBUG
+#if defined(DUK_USE_DEBUG)
/*
* Debugging enabled
@@ -8876,91 +10506,34 @@ DUK_INTERNAL const char *duk_str_regexp_executor_step_limit = "regexp step limit
#include
#include
+#if !defined(DUK_USE_DEBUG_WRITE)
+#error debugging enabled (DUK_USE_DEBUG) but DUK_USE_DEBUG_WRITE not defined
+#endif
+
#define DUK__DEBUG_BUFSIZE DUK_USE_DEBUG_BUFSIZE
-DUK_LOCAL char duk__debug_buf[DUK__DEBUG_BUFSIZE];
-DUK_LOCAL const char *duk__get_level_string(duk_small_int_t level) {
- switch ((int) level) {
- case DUK_LEVEL_DEBUG:
- return "D";
- case DUK_LEVEL_DDEBUG:
- return "DD";
- case DUK_LEVEL_DDDEBUG:
- return "DDD";
- }
- return "???";
-}
+#if defined(DUK_USE_VARIADIC_MACROS)
-#ifdef DUK_USE_DPRINT_COLORS
-
-/* http://en.wikipedia.org/wiki/ANSI_escape_code */
-#define DUK__TERM_REVERSE "\x1b[7m"
-#define DUK__TERM_BRIGHT "\x1b[1m"
-#define DUK__TERM_RESET "\x1b[0m"
-#define DUK__TERM_BLUE "\x1b[34m"
-#define DUK__TERM_RED "\x1b[31m"
-
-DUK_LOCAL const char *duk__get_term_1(duk_small_int_t level) {
- DUK_UNREF(level);
- return (const char *) DUK__TERM_RED;
-}
-
-DUK_LOCAL const char *duk__get_term_2(duk_small_int_t level) {
- switch ((int) level) {
- case DUK_LEVEL_DEBUG:
- return (const char *) (DUK__TERM_RESET DUK__TERM_BRIGHT);
- case DUK_LEVEL_DDEBUG:
- return (const char *) (DUK__TERM_RESET);
- case DUK_LEVEL_DDDEBUG:
- return (const char *) (DUK__TERM_RESET DUK__TERM_BLUE);
- }
- return (const char *) DUK__TERM_RESET;
-}
-
-DUK_LOCAL const char *duk__get_term_3(duk_small_int_t level) {
- DUK_UNREF(level);
- return (const char *) DUK__TERM_RESET;
-}
-
-#else
-
-DUK_LOCAL const char *duk__get_term_1(duk_small_int_t level) {
- DUK_UNREF(level);
- return (const char *) "";
-}
-
-DUK_LOCAL const char *duk__get_term_2(duk_small_int_t level) {
- DUK_UNREF(level);
- return (const char *) "";
-}
-
-DUK_LOCAL const char *duk__get_term_3(duk_small_int_t level) {
- DUK_UNREF(level);
- return (const char *) "";
-}
-
-#endif /* DUK_USE_DPRINT_COLORS */
-
-#ifdef DUK_USE_VARIADIC_MACROS
-
-DUK_INTERNAL void duk_debug_log(duk_small_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...) {
+DUK_INTERNAL void duk_debug_log(duk_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...) {
va_list ap;
+ long arg_level;
+ const char *arg_file;
+ long arg_line;
+ const char *arg_func;
+ const char *arg_msg;
+ char buf[DUK__DEBUG_BUFSIZE];
va_start(ap, fmt);
- DUK_MEMZERO((void *) duk__debug_buf, (size_t) DUK__DEBUG_BUFSIZE);
- duk_debug_vsnprintf(duk__debug_buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
+ DUK_MEMZERO((void *) buf, (size_t) DUK__DEBUG_BUFSIZE);
+ duk_debug_vsnprintf(buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
- DUK_FPRINTF(DUK_STDERR, "%s[%s] %s:%ld (%s):%s %s%s\n",
- (const char *) duk__get_term_1(level),
- (const char *) duk__get_level_string(level),
- (const char *) file,
- (long) line,
- (const char *) func,
- (const char *) duk__get_term_2(level),
- (const char *) duk__debug_buf,
- (const char *) duk__get_term_3(level));
- DUK_FFLUSH(DUK_STDERR);
+ arg_level = (long) level;
+ arg_file = (const char *) file;
+ arg_line = (long) line;
+ arg_func = (const char *) func;
+ arg_msg = (const char *) buf;
+ DUK_USE_DEBUG_WRITE(arg_level, arg_file, arg_line, arg_func, arg_msg);
va_end(ap);
}
@@ -8968,29 +10541,30 @@ DUK_INTERNAL void duk_debug_log(duk_small_int_t level, const char *file, duk_int
#else /* DUK_USE_VARIADIC_MACROS */
DUK_INTERNAL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE];
-DUK_INTERNAL char duk_debug_line_stash[DUK_DEBUG_STASH_SIZE];
+DUK_INTERNAL duk_int_t duk_debug_line_stash;
DUK_INTERNAL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE];
-DUK_INTERNAL duk_small_int_t duk_debug_level_stash;
+DUK_INTERNAL duk_int_t duk_debug_level_stash;
DUK_INTERNAL void duk_debug_log(const char *fmt, ...) {
va_list ap;
- duk_small_int_t level = duk_debug_level_stash;
+ long arg_level;
+ const char *arg_file;
+ long arg_line;
+ const char *arg_func;
+ const char *arg_msg;
+ char buf[DUK__DEBUG_BUFSIZE];
va_start(ap, fmt);
- DUK_MEMZERO((void *) duk__debug_buf, (size_t) DUK__DEBUG_BUFSIZE);
- duk_debug_vsnprintf(duk__debug_buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
+ DUK_MEMZERO((void *) buf, (size_t) DUK__DEBUG_BUFSIZE);
+ duk_debug_vsnprintf(buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
- DUK_FPRINTF(DUK_STDERR, "%s[%s] %s:%s (%s):%s %s%s\n",
- (const char *) duk__get_term_1(level),
- (const char *) duk__get_level_string(duk_debug_level_stash),
- (const char *) duk_debug_file_stash,
- (const char *) duk_debug_line_stash,
- (const char *) duk_debug_func_stash,
- (const char *) duk__get_term_2(level),
- (const char *) duk__debug_buf,
- (const char *) duk__get_term_3(level));
- DUK_FFLUSH(DUK_STDERR);
+ arg_level = (long) duk_debug_level_stash;
+ arg_file = (const char *) duk_debug_file_stash;
+ arg_line = (long) duk_debug_line_stash;
+ arg_func = (const char *) duk_debug_func_stash;
+ arg_msg = (const char *) buf;
+ DUK_USE_DEBUG_WRITE(arg_level, arg_file, arg_line, arg_func, arg_msg);
va_end(ap);
}
@@ -9004,75 +10578,78 @@ DUK_INTERNAL void duk_debug_log(const char *fmt, ...) {
*/
#endif /* DUK_USE_DEBUG */
+
+/* automatic undefs */
+#undef DUK__DEBUG_BUFSIZE
#line 1 "duk_builtins.c"
/*
* Automatically generated by genbuiltins.py, do not edit!
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
+
+#if defined(DUK_USE_ASSERTIONS)
+#define DUK__REFCINIT(refc) 0 /*h_assert_refcount*/, (refc) /*actual*/
+#else
+#define DUK__REFCINIT(refc) (refc) /*actual*/
+#endif
#if defined(DUK_USE_ROM_STRINGS)
-#error ROM support not enabled, rerun make_dist.py with --rom-support
+#error ROM support not enabled, rerun configure.py with --rom-support
#else /* DUK_USE_ROM_STRINGS */
-DUK_INTERNAL const duk_uint8_t duk_strings_data[1049] = {
-79,104,209,144,168,105,6,78,182,139,90,122,8,154,140,35,103,35,117,193,73,
-5,52,116,180,104,166,135,52,189,4,98,12,27,178,156,80,211,31,161,115,150,
-64,52,221,109,24,18,68,157,24,38,67,118,36,55,73,119,151,164,140,93,18,117,
-128,153,201,228,201,205,2,250,8,196,24,232,104,82,146,40,232,193,48,118,
-168,37,147,212,54,127,113,208,70,32,194,187,68,54,127,113,208,70,32,196,
-123,68,54,127,113,209,44,12,121,7,208,70,32,194,186,134,207,236,126,219,
-160,140,65,133,246,136,108,254,199,237,186,8,196,24,87,80,217,253,159,217,
-116,17,136,48,190,209,13,159,217,253,151,65,24,131,12,233,86,224,79,236,
-254,203,160,140,65,134,116,171,112,39,246,223,105,208,70,32,193,140,183,4,
-11,55,92,20,244,141,169,186,50,11,164,109,77,208,208,165,36,79,215,185,13,
-153,34,110,204,241,32,6,66,84,11,112,200,84,52,157,124,92,242,70,120,45,64,
-186,17,22,138,38,0,172,140,19,154,84,26,145,0,86,69,17,180,97,34,0,172,132,
-75,144,215,77,221,91,132,5,147,178,156,80,211,30,160,93,9,215,21,115,119,
-169,49,75,211,138,26,101,205,222,68,157,47,78,40,105,151,55,120,204,156,
-189,56,161,166,52,157,72,136,138,65,154,232,147,162,4,136,150,81,115,66,
-208,210,37,96,148,250,134,140,151,39,212,125,255,221,125,73,80,209,146,233,
-124,93,55,79,15,34,196,230,202,113,160,166,232,157,132,148,128,98,28,46,
-114,200,6,153,180,96,73,19,74,113,67,76,103,5,36,20,211,70,140,133,67,72,
-49,245,160,235,81,212,52,168,106,39,132,253,111,80,210,161,168,158,5,245,
-191,96,31,172,15,208,23,226,190,131,232,62,131,232,11,251,127,93,245,223,
-93,251,172,234,27,80,45,3,250,14,140,19,34,65,19,81,132,108,228,97,1,107,
-33,12,32,45,100,136,206,9,12,196,155,134,69,146,100,235,226,231,146,51,194,
-72,218,48,145,4,200,119,89,189,81,49,39,72,147,235,226,233,186,120,121,58,
-226,167,90,124,93,55,107,71,137,33,68,68,130,64,206,75,189,209,156,144,84,
-44,141,3,8,137,187,178,156,80,211,26,110,242,100,230,146,120,121,8,48,76,6,
-89,26,105,157,65,196,201,213,145,166,153,212,28,76,157,113,75,34,78,62,14,
-38,73,105,228,142,136,178,48,141,152,228,73,150,83,0,148,39,137,75,67,73,
-214,209,129,36,85,190,206,32,17,6,9,128,141,3,8,130,161,100,235,64,194,24,
-52,41,73,19,189,200,108,201,19,111,181,2,232,66,239,173,37,230,157,244,56,
-153,4,225,145,27,233,93,22,1,114,62,251,80,69,128,121,247,213,146,228,109,
-79,190,212,17,35,106,125,246,78,164,68,68,111,175,23,217,45,13,33,119,208,
-68,210,38,250,192,61,91,233,80,208,45,25,36,81,190,156,13,26,201,19,239,
-162,2,214,66,31,125,153,226,64,13,27,236,72,96,130,68,62,251,48,68,196,153,
-119,217,157,18,56,156,199,161,100,42,26,250,77,36,140,122,40,144,19,34,9,
-24,246,103,139,172,150,56,125,145,1,17,29,44,112,250,183,0,100,24,200,218,
-140,228,185,130,9,19,237,190,208,73,184,146,35,68,146,163,8,50,178,99,136,
-44,89,196,2,33,70,64,208,196,67,74,226,88,17,105,73,24,186,37,40,38,5,133,
-161,89,4,183,25,115,119,86,227,118,83,138,26,103,255,223,209,106,141,25,11,
-244,95,117,56,208,159,250,223,251,250,45,52,13,250,47,186,156,104,79,253,
-111,253,253,22,144,210,253,23,221,78,52,39,254,187,254,254,139,77,67,75,
-244,95,117,56,208,159,250,239,251,250,45,22,141,23,209,125,212,227,66,127,
-235,63,239,69,163,69,247,83,141,9,255,165,12,72,5,16,64,145,10,32,76,71,64,
-156,217,161,180,34,6,64,208,198,36,78,50,20,20,92,204,50,44,147,32,134,226,
-17,114,33,202,134,129,107,192,202,232,160,180,104,166,135,52,72,40,144,213,
-33,178,152,26,34,56,163,105,44,104,146,116,139,77,43,34,98,57,38,116,72,
-179,60,93,97,206,56,52,240,242,56,163,168,34,81,57,178,153,42,228,12,182,
-58,22,66,89,19,57,68,176,74,68,35,104,195,18,239,116,102,114,94,100,104,
-228,100,49,238,140,203,42,60,145,35,104,181,146,113,161,10,80,46,68,82,24,
-245,145,132,108,228,148,54,100,137,64,34,13,100,153,222,1,40,6,33,223,20,
-84,19,34,95,23,76,130,153,6,103,208,43,64,141,41,130,104,17,112,130,44,96,
+DUK_INTERNAL const duk_uint8_t duk_strings_data[892] = {
+79,40,209,144,168,105,6,78,54,139,89,185,44,48,46,90,120,8,154,140,35,103,
+35,113,193,73,5,52,112,180,104,166,135,52,188,4,98,12,27,146,156,80,211,31,
+129,115,150,64,52,220,109,24,18,68,156,24,38,67,114,36,55,9,119,151,132,
+140,93,18,113,128,153,201,212,201,205,2,248,8,196,24,224,104,82,146,40,224,
+193,48,114,168,37,147,196,54,123,28,4,98,12,43,148,67,103,177,192,70,32,
+196,121,68,54,123,28,18,192,199,144,124,4,98,12,43,136,108,244,117,184,8,
+196,24,95,40,134,207,71,91,128,140,65,133,113,13,158,158,151,1,24,131,11,
+229,16,217,233,233,112,17,136,48,206,21,110,4,244,244,184,8,196,24,103,10,
+183,2,122,218,156,4,98,12,24,203,112,64,179,113,193,79,8,218,155,131,32,
+184,70,212,220,13,10,82,68,252,123,144,217,146,38,228,207,18,0,100,37,64,
+178,212,11,161,17,104,162,96,10,200,193,57,165,65,169,16,5,100,81,27,70,18,
+32,10,200,68,185,13,116,221,197,184,64,89,57,41,197,13,49,234,5,208,156,
+113,87,55,118,147,20,187,56,161,166,92,221,212,73,210,236,226,134,153,115,
+119,76,201,203,179,138,26,99,73,212,136,136,164,25,174,137,56,32,72,137,
+101,23,52,45,13,34,86,9,79,136,104,201,114,149,96,52,138,134,140,151,75,
+226,233,186,120,121,22,39,54,83,141,5,55,68,236,36,164,3,16,225,115,150,64,
+52,205,163,2,72,154,83,138,26,99,75,12,11,150,103,5,36,20,211,70,140,133,
+67,72,49,241,160,227,81,196,52,168,106,39,132,252,183,136,105,80,212,79,2,
+249,110,128,126,88,95,133,109,237,237,237,151,235,127,46,249,119,203,190,
+186,206,33,181,2,208,61,190,12,19,34,65,19,81,132,108,228,97,1,107,33,12,
+32,45,100,137,64,247,175,9,19,155,41,198,130,155,134,69,146,100,227,226,
+231,146,51,192,204,73,140,224,145,221,102,241,68,196,157,34,79,143,139,166,
+233,225,228,227,138,157,173,167,197,211,118,214,210,38,238,74,113,67,76,
+105,187,169,147,154,73,225,228,32,193,48,25,100,105,166,113,200,147,44,166,
+1,40,79,18,150,134,147,141,163,2,72,171,115,147,136,4,65,130,96,35,64,194,
+32,168,89,56,208,48,135,123,144,217,146,39,220,228,193,19,18,101,220,227,
+73,121,167,115,129,196,200,39,12,136,220,225,93,22,1,114,62,231,42,8,176,
+15,62,231,36,234,68,68,70,231,30,45,37,161,164,38,231,24,7,159,115,149,4,
+72,218,171,115,133,67,64,180,100,145,54,231,42,5,208,135,19,152,244,44,133,
+67,95,73,164,145,143,5,18,2,100,65,35,30,76,241,117,134,70,212,103,37,204,
+16,72,154,218,130,77,196,145,63,127,123,106,141,25,11,189,243,169,198,132,
+251,235,119,247,182,154,6,239,124,234,113,161,62,250,221,253,237,164,52,
+187,223,58,156,104,79,190,187,127,123,105,168,105,119,190,117,56,208,159,
+125,118,254,246,209,104,209,111,124,234,113,161,62,250,205,253,162,209,162,
+249,212,227,66,125,244,161,137,0,162,8,18,33,68,9,136,232,19,155,52,54,132,
+64,200,26,24,196,137,198,66,130,139,153,134,69,146,100,16,220,66,46,68,57,
+80,208,45,120,25,93,20,22,141,20,208,230,137,5,18,26,164,54,83,3,68,71,20,
+109,37,141,18,78,145,105,165,100,76,71,36,206,137,22,103,139,172,57,199,6,
+158,30,71,20,117,4,74,39,54,83,37,92,129,150,199,66,200,75,34,103,40,150,9,
+72,132,109,24,98,93,238,140,206,75,204,141,28,140,134,61,209,153,101,71,
+146,36,109,22,178,78,52,33,74,5,200,138,67,30,178,48,141,156,146,134,204,
+145,40,4,65,172,147,59,192,37,0,196,59,226,138,130,100,75,226,233,144,83,
+32,204,250,5,104,17,165,48,77,2,46,16,69,140,
};
#endif /* DUK_USE_ROM_STRINGS */
#if defined(DUK_USE_ROM_OBJECTS)
-#error ROM support not enabled, rerun make_dist.py with --rom-support
+#error ROM support not enabled, rerun configure.py with --rom-support
#else /* DUK_USE_ROM_OBJECTS */
-/* native functions: 149 */
-DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
+/* native functions: 176 */
+DUK_INTERNAL const duk_c_function duk_bi_native_functions[176] = {
+ NULL,
duk_bi_array_constructor,
duk_bi_array_constructor_is_array,
duk_bi_array_prototype_concat,
@@ -9094,8 +10671,6 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
duk_bi_boolean_constructor,
duk_bi_boolean_prototype_tostring_shared,
duk_bi_buffer_compare_shared,
- duk_bi_buffer_constructor,
- duk_bi_buffer_prototype_tostring_shared,
duk_bi_buffer_readfield,
duk_bi_buffer_slice_shared,
duk_bi_buffer_writefield,
@@ -9142,20 +10717,20 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
duk_bi_global_object_is_nan,
duk_bi_global_object_parse_float,
duk_bi_global_object_parse_int,
- duk_bi_global_object_print_helper,
- duk_bi_global_object_require,
duk_bi_global_object_unescape,
duk_bi_json_object_parse,
duk_bi_json_object_stringify,
- duk_bi_logger_constructor,
- duk_bi_logger_prototype_fmt,
- duk_bi_logger_prototype_log_shared,
- duk_bi_logger_prototype_raw,
+ duk_bi_math_object_clz32,
+ duk_bi_math_object_hypot,
+ duk_bi_math_object_imul,
duk_bi_math_object_max,
duk_bi_math_object_min,
duk_bi_math_object_onearg_shared,
duk_bi_math_object_random,
+ duk_bi_math_object_sign,
duk_bi_math_object_twoarg_shared,
+ duk_bi_native_function_length,
+ duk_bi_native_function_name,
duk_bi_nodejs_buffer_byte_length,
duk_bi_nodejs_buffer_concat,
duk_bi_nodejs_buffer_constructor,
@@ -9174,625 +10749,654 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
duk_bi_number_prototype_to_string,
duk_bi_number_prototype_value_of,
duk_bi_object_constructor,
+ duk_bi_object_constructor_assign,
duk_bi_object_constructor_create,
duk_bi_object_constructor_define_properties,
duk_bi_object_constructor_define_property,
duk_bi_object_constructor_get_own_property_descriptor,
+ duk_bi_object_constructor_is,
duk_bi_object_constructor_is_extensible,
duk_bi_object_constructor_is_sealed_frozen_shared,
duk_bi_object_constructor_keys_shared,
duk_bi_object_constructor_prevent_extensions,
duk_bi_object_constructor_seal_freeze_shared,
duk_bi_object_getprototype_shared,
+ duk_bi_object_prototype_defineaccessor,
duk_bi_object_prototype_has_own_property,
duk_bi_object_prototype_is_prototype_of,
+ duk_bi_object_prototype_lookupaccessor,
duk_bi_object_prototype_property_is_enumerable,
duk_bi_object_prototype_to_locale_string,
duk_bi_object_prototype_to_string,
duk_bi_object_prototype_value_of,
duk_bi_object_setprototype_shared,
+ duk_bi_performance_now,
duk_bi_pointer_constructor,
duk_bi_pointer_prototype_tostring_shared,
duk_bi_proxy_constructor,
+ duk_bi_reflect_apply,
+ duk_bi_reflect_construct,
+ duk_bi_reflect_object_delete_property,
+ duk_bi_reflect_object_get,
+ duk_bi_reflect_object_has,
+ duk_bi_reflect_object_set,
duk_bi_regexp_constructor,
duk_bi_regexp_prototype_exec,
+ duk_bi_regexp_prototype_flags,
+ duk_bi_regexp_prototype_shared_getter,
duk_bi_regexp_prototype_test,
- duk_bi_regexp_prototype_to_string,
+ duk_bi_regexp_prototype_tostring,
duk_bi_string_constructor,
duk_bi_string_constructor_from_char_code,
+ duk_bi_string_constructor_from_code_point,
duk_bi_string_prototype_caseconv_shared,
duk_bi_string_prototype_char_at,
duk_bi_string_prototype_char_code_at,
duk_bi_string_prototype_concat,
+ duk_bi_string_prototype_includes,
duk_bi_string_prototype_indexof_shared,
duk_bi_string_prototype_locale_compare,
duk_bi_string_prototype_match,
+ duk_bi_string_prototype_repeat,
duk_bi_string_prototype_replace,
duk_bi_string_prototype_search,
duk_bi_string_prototype_slice,
duk_bi_string_prototype_split,
+ duk_bi_string_prototype_startswith_endswith,
duk_bi_string_prototype_substr,
duk_bi_string_prototype_substring,
duk_bi_string_prototype_to_string,
duk_bi_string_prototype_trim,
+ duk_bi_textdecoder_constructor,
+ duk_bi_textdecoder_prototype_decode,
+ duk_bi_textdecoder_prototype_shared_getter,
+ duk_bi_textencoder_constructor,
+ duk_bi_textencoder_prototype_encode,
+ duk_bi_textencoder_prototype_encoding_getter,
duk_bi_thread_constructor,
duk_bi_thread_current,
duk_bi_thread_resume,
duk_bi_thread_yield,
duk_bi_type_error_thrower,
+ duk_bi_typedarray_buffer_getter,
+ duk_bi_typedarray_bytelength_getter,
+ duk_bi_typedarray_byteoffset_getter,
duk_bi_typedarray_constructor,
duk_bi_typedarray_set,
+ duk_bi_uint8array_allocplain,
+ duk_bi_uint8array_plainof,
};
-#if defined(DUK_USE_BUILTIN_INITJS)
-DUK_INTERNAL const duk_uint8_t duk_initjs_data[204] = {
-40,102,117,110,99,116,105,111,110,40,100,44,97,41,123,102,117,110,99,116,
-105,111,110,32,98,40,97,44,98,44,99,41,123,79,98,106,101,99,116,46,100,101,
-102,105,110,101,80,114,111,112,101,114,116,121,40,97,44,98,44,123,118,97,
-108,117,101,58,99,44,119,114,105,116,97,98,108,101,58,33,48,44,101,110,117,
-109,101,114,97,98,108,101,58,33,49,44,99,111,110,102,105,103,117,114,97,98,
-108,101,58,33,48,125,41,125,98,40,97,46,76,111,103,103,101,114,44,34,99,
-108,111,103,34,44,110,101,119,32,97,46,76,111,103,103,101,114,40,34,67,34,
-41,41,59,98,40,97,44,34,109,111,100,76,111,97,100,101,100,34,44,79,98,106,
-101,99,116,46,99,114,101,97,116,101,40,110,117,108,108,41,41,125,41,40,116,
-104,105,115,44,68,117,107,116,97,112,101,41,59,10,0,
-};
-#endif /* DUK_USE_BUILTIN_INITJS */
#if defined(DUK_USE_DOUBLE_LE)
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = {
-105,195,75,32,3,148,52,154,248,9,26,13,128,112,105,0,240,22,20,26,95,124,6,
-152,52,137,0,120,99,74,239,129,18,70,241,191,2,98,13,79,32,42,88,210,90,2,
-240,1,50,141,37,168,76,94,216,118,69,229,203,127,44,0,84,163,73,106,21,75,
-14,236,249,98,242,229,191,150,0,46,81,164,181,14,165,151,54,94,89,119,99,
-203,23,151,45,252,176,1,146,141,37,168,93,63,59,186,97,241,23,151,45,252,
-176,1,178,141,37,168,77,79,60,50,197,229,203,127,44,0,116,163,73,106,17,86,
-148,152,188,185,111,229,128,15,148,129,198,137,36,58,166,142,91,251,212,
-243,195,44,94,92,183,242,13,79,8,45,14,91,252,121,148,52,199,120,63,72,105,
-21,240,118,128,210,237,224,245,17,165,43,224,211,55,231,207,151,148,161,70,
-145,0,31,40,107,26,2,18,138,26,228,192,142,0,16,161,174,76,9,74,26,228,192,
-158,0,8,161,174,76,10,96,2,42,26,228,192,174,0,26,161,174,76,11,96,3,74,26,
-228,192,190,0,44,161,174,76,12,96,3,202,26,228,192,206,0,70,161,169,84,14,
-202,3,255,254,32,234,0,0,0,0,0,0,7,195,248,119,0,0,0,0,0,0,3,193,252,57,
-136,1,152,32,16,194,0,166,24,6,49,0,57,138,2,12,96,18,99,128,163,32,5,153,
-40,76,94,216,118,69,229,203,127,35,41,10,165,135,118,124,177,121,114,223,
-200,203,67,169,101,205,151,150,93,216,242,197,229,203,127,35,49,11,167,231,
-119,76,62,34,242,229,191,145,154,132,212,243,195,44,94,92,183,242,51,144,
-138,180,164,197,229,203,127,35,60,6,26,0,52,208,193,226,117,215,211,15,12,
-166,146,11,67,150,255,30,77,24,58,113,64,243,92,8,27,0,68,217,130,70,212,
-19,54,224,161,185,5,77,216,44,111,65,115,126,12,28,16,100,225,156,16,32,18,
-17,195,15,46,121,100,238,232,136,136,87,12,60,185,229,141,179,126,30,136,
-100,130,233,231,59,12,228,34,66,52,243,141,167,118,158,153,80,73,9,201,151,
-30,252,153,106,210,146,118,72,150,76,184,247,228,203,86,148,152,123,246,
-240,223,187,46,238,135,132,132,229,221,143,126,76,181,105,73,61,36,75,46,
-236,123,242,101,171,74,76,61,251,120,111,221,151,119,67,226,65,178,243,199,
-135,134,83,242,66,58,238,203,207,30,30,25,81,201,5,225,203,78,238,136,163,
-208,92,59,50,242,232,138,62,0,2,38,163,19,255,255,224,142,80,192,0,20,31,
-240,14,135,103,203,210,135,45,253,55,244,243,195,44,252,205,197,0,1,18,221,
-82,0,3,24,207,151,164,254,251,168,114,223,195,47,46,158,98,101,231,143,150,
-158,29,55,242,104,68,79,62,94,147,251,238,161,203,127,12,188,186,121,157,
-135,110,94,109,100,131,99,229,151,15,76,172,168,8,89,217,16,201,151,54,157,
-217,104,114,223,195,47,46,154,114,243,102,68,19,158,92,59,27,73,6,205,203,
-46,95,89,91,74,0,3,17,225,203,47,108,187,186,69,241,211,46,238,122,119,238,
-230,216,72,70,158,116,242,225,217,151,35,81,33,26,121,198,229,191,214,93,
-205,69,0,1,134,105,231,23,199,76,187,185,233,197,179,43,73,32,154,242,249,
-230,214,80,0,31,255,193,2,38,103,110,117,24,81,115,0,78,228,0,161,208,16,
-237,24,121,207,239,186,135,45,252,50,242,233,229,188,144,221,60,232,114,
-223,211,127,79,60,50,207,204,224,72,167,14,91,248,101,229,211,204,158,113,
-119,117,219,151,150,28,91,50,184,144,40,95,224,0,15,248,64,4,20,78,129,5,
-195,195,134,207,38,232,130,99,195,179,97,201,244,19,22,157,217,14,15,130,
-135,254,0,48,125,60,224,242,229,135,200,9,1,255,12,2,162,136,112,2,112,80,
-128,0,193,177,239,221,143,15,64,35,224,152,20,144,62,27,248,3,2,9,195,175,
-61,0,231,208,126,89,123,101,229,207,40,72,32,188,244,105,205,208,40,16,94,
-123,52,227,202,22,136,39,61,252,186,6,18,13,207,134,205,56,242,134,175,65,
-250,238,231,163,78,110,129,231,208,125,59,178,101,241,63,48,25,248,0,12,47,
-102,30,125,36,238,201,151,196,252,192,103,255,255,240,92,189,178,242,242,8,
-105,4,231,191,110,80,67,80,0,24,62,109,252,162,225,199,160,16,212,0,10,7,
-183,15,0,67,80,0,56,54,109,59,58,101,228,8,106,0,9,6,229,151,39,92,121,66,
-15,192,0,97,124,178,228,235,143,45,45,57,244,116,8,63,255,255,10,39,248,0,
-195,51,114,223,182,30,140,60,161,239,201,149,248,248,31,241,0,140,80,129,
-202,10,49,128,10,35,1,6,199,163,15,40,61,32,9,10,199,163,15,40,123,242,101,
-131,210,4,144,108,123,247,99,195,210,8,250,15,167,118,76,190,39,230,131,52,
-133,236,195,207,164,157,217,50,248,159,154,12,212,0,6,27,179,126,60,59,50,
-195,223,183,134,30,89,97,9,5,219,135,166,61,16,164,131,242,203,195,102,28,
-121,97,145,6,231,151,15,44,122,33,201,5,231,179,78,60,177,8,130,243,225,
-179,79,72,148,66,121,245,197,207,167,45,59,179,197,162,23,211,124,205,253,
-242,242,135,135,158,87,240,68,122,111,153,191,30,29,153,102,111,239,151,
-148,60,60,242,191,130,23,211,125,94,28,50,242,135,135,158,87,240,128,0,196,
-122,111,153,191,30,29,153,106,240,225,151,148,60,60,242,191,132,0,6,9,211,
-150,157,177,160,131,115,235,139,159,78,81,72,10,47,248,0,3,254,40,17,138,
-48,66,136,152,64,0,66,129,48,5,27,252,88,76,216,54,47,214,131,50,172,88,31,
-255,255,255,255,255,253,239,240,153,178,103,95,173,6,101,88,176,0,64,0,0,0,
-0,0,0,3,168,0,0,0,0,0,0,31,15,241,26,19,233,201,169,38,180,91,242,103,70,
-147,58,77,75,48,0,0,0,0,0,0,60,31,226,51,162,199,131,82,77,104,183,228,206,
-141,38,116,154,150,96,0,0,0,0,0,0,120,127,128,15,248,192,70,40,0,0,0,0,0,0,
-0,0,3,10,44,68,9,216,8,20,49,130,15,211,124,109,62,50,228,95,36,55,166,248,
-190,56,111,221,151,119,77,56,118,47,18,23,211,125,14,89,113,233,231,167,
-126,230,18,5,31,252,0,224,188,48,242,231,148,116,144,58,181,33,143,127,64,
-247,111,238,56,0,127,199,2,49,72,0,0,0,0,0,0,248,127,180,81,36,4,51,166,
-248,152,122,101,167,211,150,157,217,201,2,0,3,12,233,190,166,157,185,105,
-244,229,167,118,114,64,128,1,4,228,129,0,3,137,116,223,51,126,60,59,50,196,
-195,211,45,62,156,180,238,206,72,16,0,72,151,77,243,55,227,195,179,45,77,
-59,114,211,233,203,78,236,228,129,0,5,10,73,2,0,12,21,18,4,0,28,82,35,32,
-80,74,8,62,124,189,42,105,219,148,148,16,188,249,122,70,235,179,101,156,
-184,121,15,132,0,34,29,159,47,74,181,33,198,235,179,101,156,184,121,15,132,
-0,38,17,159,47,73,187,247,116,208,62,16,0,168,94,124,189,42,212,135,55,126,
-238,154,7,194,0,23,7,207,151,164,76,61,50,143,132,0,50,21,159,47,74,181,33,
-196,195,211,40,248,64,3,96,217,242,244,137,135,200,248,64,3,161,57,242,244,
-171,82,28,76,62,71,194,0,31,8,207,151,164,141,253,121,115,31,8,0,132,47,62,
-94,149,106,67,145,191,175,46,99,225,0,17,133,103,203,210,110,157,221,122,
-101,230,62,16,1,40,110,124,189,42,212,135,55,78,238,189,50,243,31,8,0,156,
-43,62,94,148,242,227,223,187,39,49,240,128,10,67,115,229,233,86,164,58,121,
-113,239,221,147,152,248,64,5,97,249,242,244,155,167,102,205,60,242,227,223,
-187,39,49,240,128,11,68,179,229,233,86,164,57,186,118,108,211,207,46,61,
-251,178,115,31,8,0,188,71,62,94,149,52,237,203,235,126,236,179,243,102,231,
-151,161,0,32,252,242,244,169,167,110,82,34,67,249,229,233,55,78,205,154,
-121,229,199,191,118,78,100,37,0,24,137,115,203,210,173,72,115,116,236,217,
-167,158,92,123,247,100,230,66,80,1,152,87,60,189,41,229,199,191,118,78,100,
-43,224,3,80,222,121,122,85,169,14,158,92,123,247,100,230,66,190,0,55,10,
-231,151,164,221,59,186,244,203,204,133,252,0,114,27,207,47,74,181,33,205,
-211,187,175,76,188,200,95,192,7,97,28,242,244,145,191,175,46,100,51,224,3,
-208,190,121,122,85,169,14,70,254,188,185,144,207,128,15,193,249,229,233,19,
-15,76,164,37,0,32,133,115,203,210,173,72,113,48,244,202,66,80,2,24,71,60,
-189,38,239,221,211,65,10,248,1,20,47,158,94,149,106,67,155,191,119,77,4,43,
-224,4,112,190,121,122,70,235,179,101,156,184,121,16,191,128,18,67,185,229,
-233,86,164,56,221,118,108,179,151,15,34,23,240,2,88,62,124,189,44,229,195,
-200,124,32,4,208,126,121,122,89,203,135,145,9,64,9,194,145,254,0,0,255,144,
-24,100,130,14,0,16,176,2,192,129,11,33,12,1,168,193,108,96,186,48,95,32,0,
-0,0,0,0,0,0,0,56,38,95,25,113,189,18,9,211,47,62,143,100,20,95,0,20,159,
-240,0,7,252,144,162,241,2,195,66,7,11,89,204,140,197,252,229,197,226,230,
-115,3,16,69,19,64,5,43,252,0,9,255,40,16,188,33,49,123,97,217,23,151,45,
-252,131,66,7,0,20,191,240,0,39,252,176,66,240,133,82,195,187,62,88,188,185,
-111,228,26,16,56,0,166,127,128,1,63,230,2,23,132,58,150,92,217,121,101,221,
-143,44,94,92,183,242,13,8,28,0,83,127,192,0,159,243,65,11,194,23,79,206,
-238,152,124,69,229,203,127,32,208,129,192,5,59,252,0,9,255,56,16,188,33,53,
-60,240,203,23,151,45,252,131,66,7,0,20,255,240,0,39,252,240,66,240,132,85,
-165,38,47,46,91,249,6,132,14,0,31,255,228,64,98,192,105,87,20,139,10,191,5,
-64,130,76,156,197,132,1,101,91,91,187,22,176,36,8,28,201,204,160,119,156,
-253,127,33,23,115,31,193,102,79,142,202,44,15,232,34,182,84,113,95,115,248,
-52,201,241,216,176,139,0,59,148,152,85,239,47,108,254,5,66,76,1,130,212,69,
-79,178,16,148,8,61,58,52,170,49,190,202,6,105,219,251,52,245,7,49,252,22,
-157,26,85,25,64,205,59,127,102,158,160,246,63,74,7,135,23,53,2,65,48,227,
-223,205,64,160,0,48,76,60,244,238,80,40,0,20,19,15,76,59,148,10,0,7,5,195,
-211,14,230,74,72,130,99,203,167,98,129,64,1,32,120,247,243,80,40,0,44,15,
-47,142,10,5,0,6,130,230,217,191,127,37,2,128,3,192,246,111,206,160,80,0,
-136,30,220,62,19,151,160,123,116,238,79,94,129,240,223,221,73,32,0,48,110,
-88,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0,
-21,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23,
-134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0,
-191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,0,0,0,0,0,12,98,
-160,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144,
-60,56,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7,
-147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3,
-252,131,32,248,250,242,229,151,119,72,240,3,254,148,0,2,168,254,0,0,255,
-167,0,33,68,88,32,0,33,64,176,2,170,254,0,0,255,169,0,33,69,220,32,0,33,67,
-184,2,172,254,0,0,255,171,8,137,144,0,0,0,0,0,0,0,128,68,73,4,195,187,126,
-226,8,4,178,16,41,164,32,147,7,136,52,193,240,0,18,17,48,124,0,8,133,76,31,
-0,3,33,147,7,192,1,8,116,193,240,0,82,127,255,132,47,65,11,137,191,174,45,
-153,98,242,229,191,144,105,4,95,47,46,91,249,32,211,185,6,94,92,183,242,65,
-163,14,236,155,52,238,206,0,85,255,192,6,13,167,157,109,57,123,136,144,31,
-245,192,3,5,231,179,78,60,163,9,0,2,10,199,248,0,3,254,192,4,32,249,242,
-244,147,187,163,129,116,128,24,66,51,229,233,87,78,238,142,5,210,0,65,8,
-207,151,164,157,221,24,182,23,72,1,140,39,62,94,149,116,238,232,197,176,
-186,64,8,97,25,242,244,147,187,163,54,66,233,0,50,132,231,203,210,174,157,
-221,25,178,23,72,1,20,43,62,94,145,182,111,195,209,155,33,116,128,17,194,
-179,229,233,27,102,252,61,27,52,23,72,1,36,31,158,94,146,119,116,112,50,
-208,3,8,71,60,189,42,233,221,209,192,203,64,8,33,28,242,244,147,187,163,22,
-195,45,0,49,132,243,203,210,174,157,221,24,182,25,104,1,12,35,158,94,146,
-119,116,102,200,101,160,6,80,158,121,122,85,211,187,163,54,67,45,0,34,133,
-115,203,210,54,205,248,122,51,100,50,208,2,56,87,60,189,35,108,223,135,163,
-102,131,45,0,36,7,255,248,1,11,50,136,132,115,235,139,15,46,88,124,140,36,
-0,4,43,79,224,139,16,0,0,0,0,0,0,60,15,192,101,253,152,0,5,109,252,17,98,0,
-0,0,0,0,0,7,129,248,12,191,181,0,0,174,63,130,44,64,0,0,0,0,0,0,240,63,1,
-151,246,224,0,21,215,240,69,136,0,0,0,0,0,0,0,8,0,50,254,228,0,2,188,254,8,
-177,0,0,0,0,0,0,0,1,0,6,95,221,128,0,87,223,193,22,32,0,0,0,0,0,0,8,32,0,
-203,251,208,0,11,3,248,34,196,0,0,0,0,0,0,1,4,0,25,127,126,0,1,97,127,4,88,
-128,0,0,0,0,0,0,32,128,3,47,240,64,0,44,79,224,139,16,0,0,0,0,0,0,8,16,0,
-101,254,24,0,5,141,252,1,96,216,247,238,199,135,162,162,33,90,121,197,221,
-143,126,77,59,179,172,146,17,167,156,46,185,179,101,228,176,65,89,77,16,
-124,123,246,240,195,203,40,162,64,0,193,255,138,5,144,158,89,112,228,171,
-39,119,71,2,232,132,114,203,135,36,157,221,28,11,164,0,66,25,203,46,28,149,
-100,238,232,197,180,200,162,233,0,1,134,114,203,135,37,89,59,186,49,109,10,
-40,186,64,2,97,124,178,225,201,39,119,70,45,166,69,23,72,0,140,47,150,92,
-57,36,238,232,197,180,40,162,233,0,25,134,114,203,135,37,89,59,186,51,101,
-50,40,186,64,0,161,156,178,225,201,86,78,238,140,217,66,138,46,144,0,168,
-95,44,184,114,73,221,209,155,41,145,69,210,0,37,11,229,151,14,73,59,186,51,
-101,10,40,186,64,6,161,124,178,225,201,27,102,252,61,38,69,23,72,0,28,47,
-150,92,57,35,108,223,135,164,40,162,233,0,11,134,114,203,135,36,77,253,113,
-108,203,50,40,186,64,1,33,156,178,225,201,19,127,92,91,50,194,138,46,144,0,
-200,87,44,184,114,85,147,187,164,200,162,237,0,5,133,114,203,135,37,89,59,
-186,66,138,46,208,0,216,79,44,184,114,73,221,210,100,81,118,128,10,194,121,
-101,195,146,78,238,144,162,139,180,0,118,21,223,150,158,153,106,201,221,
-209,192,203,33,61,249,105,233,150,78,238,142,6,90,0,33,13,239,203,79,76,
-181,100,238,232,197,180,200,163,45,0,1,134,247,229,167,166,90,178,119,116,
-98,218,20,81,150,128,4,195,59,242,211,211,44,157,221,24,182,153,20,101,160,
-2,48,206,252,180,244,203,39,119,70,45,161,69,25,104,0,204,55,191,45,61,50,
-213,147,187,163,54,83,34,140,180,0,10,27,223,150,158,153,106,201,221,209,
-155,40,81,70,90,0,21,12,239,203,79,76,178,119,116,102,202,100,81,150,128,9,
-67,59,242,211,211,44,157,221,25,178,133,20,101,160,3,80,206,252,180,244,
-203,27,102,252,61,38,69,25,104,0,28,51,191,45,61,50,198,217,191,15,72,81,
-70,90,0,23,13,239,203,79,76,177,55,245,197,179,44,200,163,45,0,4,134,247,
-229,167,166,88,155,250,226,217,150,20,81,150,128,6,66,251,242,211,211,45,
-89,59,186,76,138,51,16,0,88,95,126,90,122,101,171,39,119,72,81,70,98,0,27,
-10,239,203,79,76,178,119,116,153,20,102,32,2,176,174,252,180,244,203,39,
-119,72,81,70,98,0,58,40,173,176,82,90,4,19,54,157,155,21,217,6,203,199,174,
-29,156,197,9,7,199,191,111,12,60,178,138,20,0,6,9,143,127,15,42,208,130,
-243,217,167,30,81,132,65,123,242,211,211,42,228,0,
+DUK_INTERNAL const duk_uint8_t duk_builtins_data[3972] = {
+144,148,105,223,160,68,52,228,62,12,104,200,165,132,52,167,194,138,105,242,
+252,57,28,211,57,18,64,52,238,62,44,138,111,171,241,164,19,87,125,30,33,
+167,16,145,159,8,211,136,9,225,42,5,240,145,139,163,163,8,211,136,10,228,
+64,211,19,132,140,93,29,56,70,156,64,119,34,66,146,36,104,137,194,70,46,
+142,172,35,78,32,47,146,195,102,11,240,145,139,163,175,8,211,136,9,228,240,
+242,112,145,139,163,179,8,211,136,8,237,34,130,118,49,116,118,225,26,48,0,
+1,80,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
+33,8,66,34,33,154,112,0,1,73,247,35,79,91,237,198,174,192,47,31,23,95,17,
+13,51,19,35,93,68,216,209,128,0,10,192,174,79,15,32,248,8,196,24,8,107,192,
+0,5,98,118,27,94,0,0,43,19,227,94,0,0,43,20,46,215,128,0,10,197,28,198,188,
+0,0,86,41,100,53,224,0,2,177,79,85,175,0,0,21,138,154,45,120,0,0,172,85,
+217,107,192,0,5,98,182,243,86,193,106,52,127,66,249,50,94,124,35,68,225,
+146,49,13,31,170,23,201,146,243,224,200,39,12,145,136,67,134,11,49,0,0,0,0,
+0,0,3,225,255,51,0,0,0,0,0,0,3,193,255,47,18,1,172,19,120,71,10,25,196,136,
+113,162,156,136,199,42,57,204,144,115,132,240,149,2,248,72,197,209,58,2,
+185,16,52,196,225,35,23,68,233,14,228,72,82,68,141,17,56,72,197,209,58,130,
+249,44,54,96,191,9,24,186,39,88,79,39,135,147,132,140,93,19,176,35,180,138,
+9,216,197,209,59,82,79,31,40,242,1,248,58,42,96,121,14,232,94,62,46,190,15,
+38,31,145,33,86,65,76,242,150,143,69,48,242,179,79,45,56,243,51,207,53,64,
+243,116,79,57,72,243,180,207,61,80,243,245,79,65,88,244,34,249,50,94,124,
+35,68,225,146,39,163,23,201,146,243,224,200,39,12,145,61,40,183,146,37,116,
+88,6,136,158,244,241,174,230,202,80,135,130,50,39,16,217,231,208,20,240,70,
+68,225,86,224,79,60,64,84,75,141,7,27,157,32,66,37,194,161,168,153,51,132,
+9,25,4,225,147,180,138,50,196,18,25,4,225,147,180,138,5,215,49,238,105,27,
+60,185,2,72,209,56,100,237,34,140,193,4,136,209,56,100,237,34,129,117,204,
+123,154,70,207,50,64,98,72,64,121,51,68,8,163,73,33,1,228,208,16,0,65,112,
+152,56,196,159,31,23,77,211,195,201,199,23,150,73,169,234,34,24,49,39,199,
+89,188,124,92,242,70,120,224,201,33,69,15,155,163,196,64,153,137,62,58,205,
+227,226,231,146,51,199,26,6,18,92,130,64,192,148,144,102,240,23,129,133,18,
+2,100,224,160,56,100,42,26,78,62,46,121,35,60,112,216,32,50,21,13,39,31,23,
+60,145,154,9,46,18,1,36,64,47,148,64,98,196,132,201,57,68,132,95,18,84,141,
+159,9,121,145,178,67,155,46,73,2,17,46,72,128,89,7,199,32,66,37,194,197,
+217,35,120,228,131,17,46,18,243,35,100,128,172,156,98,2,40,152,151,32,130,
+166,36,248,235,55,143,139,158,72,207,28,150,24,23,46,92,130,80,72,151,21,0,
+100,213,103,229,245,8,186,190,144,24,78,136,24,94,152,3,142,9,113,214,111,
+31,23,60,145,158,57,164,13,68,184,248,186,110,158,30,78,56,188,226,10,62,
+46,121,35,60,113,18,225,27,70,18,32,10,201,208,32,134,214,208,200,84,52,
+156,49,39,50,71,107,107,152,129,13,173,161,144,168,105,57,34,78,100,142,
+214,215,49,16,134,214,210,220,229,81,252,49,39,50,71,107,107,158,65,13,173,
+165,185,202,163,249,34,78,100,142,214,215,60,146,12,16,28,128,62,175,42,6,
+143,36,136,16,64,90,242,135,192,129,67,71,147,62,65,5,215,231,214,6,215,62,
+180,8,49,1,3,162,92,4,98,12,41,14,67,40,106,229,1,132,130,8,24,78,104,129,
+54,62,96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,
+178,58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,
+129,232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,
+201,126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,
+132,0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,
+46,36,29,4,78,69,6,60,226,31,192,7,255,252,24,192,163,11,23,51,130,56,35,
+193,56,100,243,31,6,150,46,103,4,225,147,143,114,27,63,57,241,200,169,194,
+133,42,166,175,240,6,23,240,0,97,28,17,224,39,233,32,80,142,8,240,78,25,56,
+9,250,136,22,39,12,156,123,144,217,240,19,245,18,6,19,154,32,79,214,124,14,
+134,140,151,227,139,237,52,11,88,37,62,33,163,37,248,226,251,77,32,213,184,
+64,89,56,39,49,224,137,61,196,5,96,38,35,251,200,15,18,61,96,17,62,40,6,
+145,1,17,31,228,64,89,45,2,39,205,0,178,122,209,63,162,2,101,64,202,113,67,
+77,247,64,92,221,197,186,196,143,4,9,19,208,1,25,187,139,112,128,178,113,
+110,177,35,193,2,68,244,0,46,110,229,30,242,71,130,4,137,232,4,35,55,113,
+110,16,22,78,81,239,36,120,32,72,158,128,64,147,138,25,249,0,52,72,242,2,
+127,2,5,74,96,140,229,203,34,103,250,154,4,17,163,151,44,137,159,234,105,4,
+33,162,93,6,73,123,13,1,165,64,202,113,251,33,6,64,14,71,78,20,101,213,207,
+4,194,207,2,12,162,0,158,176,23,218,168,23,66,64,255,255,255,255,255,255,
+239,127,19,214,33,187,85,2,232,72,0,32,0,0,0,0,0,0,25,136,0,0,0,0,0,0,31,
+15,228,122,247,73,19,69,73,180,134,149,13,68,241,0,0,0,0,0,0,3,193,252,143,
+90,67,2,104,169,54,144,210,161,168,158,32,0,0,0,0,0,0,120,127,142,73,78,20,
+0,0,0,0,0,0,0,0,8,58,189,233,24,77,217,24,93,240,1,230,238,21,23,32,247,68,
+13,155,184,75,189,205,35,102,128,47,114,64,185,187,143,137,4,137,33,205,
+222,17,6,96,48,87,130,50,37,114,1,246,147,21,143,224,54,186,213,128,114,90,
+112,164,0,0,0,0,0,0,124,63,226,117,119,128,25,55,112,96,153,57,41,197,13,
+53,224,65,147,119,38,134,19,146,156,80,211,94,5,194,94,6,37,55,113,110,16,
+22,78,12,19,39,37,56,161,166,188,14,74,110,226,220,32,44,156,154,24,78,74,
+113,67,77,120,32,97,175,4,28,61,224,133,172,186,70,22,248,1,204,73,242,104,
+97,47,128,44,196,159,11,69,175,152,32,35,100,33,142,49,39,218,76,69,237,22,
+190,96,128,141,144,136,32,196,159,24,230,204,246,66,40,179,18,125,164,196,
+206,185,179,61,144,140,28,196,159,6,9,146,200,71,20,98,79,180,152,135,208,
+76,150,66,64,99,18,124,24,49,100,36,137,49,39,218,76,67,232,49,100,37,8,49,
+39,195,186,145,149,144,150,44,196,159,105,49,31,174,164,101,100,38,10,49,
+39,198,33,180,153,37,100,38,141,49,39,218,76,76,234,27,73,146,86,66,112,
+163,18,124,145,4,230,142,86,66,120,211,18,125,164,197,46,144,78,104,229,
+100,40,15,49,39,198,33,107,68,136,39,52,114,178,20,73,24,147,237,38,38,117,
+11,90,36,65,57,163,149,144,164,68,196,159,38,134,19,46,105,56,226,150,68,
+157,160,3,200,147,228,208,194,92,32,124,137,62,49,11,90,36,65,57,163,149,
+178,166,74,68,159,105,49,51,168,90,209,34,9,205,28,173,149,65,82,36,249,34,
+9,205,28,173,175,170,54,68,159,105,49,75,164,19,154,57,91,95,88,84,137,62,
+49,13,164,201,43,111,235,141,145,39,218,76,76,234,27,73,146,86,223,216,17,
+34,79,135,117,35,43,115,236,139,145,39,218,76,71,235,169,25,91,159,104,60,
+137,62,12,19,37,178,182,42,68,159,105,49,15,160,153,45,149,193,18,36,248,
+199,54,103,182,190,232,185,18,125,164,196,206,185,179,61,181,247,133,200,
+147,225,104,181,243,4,4,109,191,190,58,68,159,105,49,23,180,90,249,130,2,
+54,223,224,67,152,147,230,8,8,217,12,16,121,18,124,193,1,27,101,131,131,56,
+7,38,193,198,72,0,0,0,0,0,0,0,0,198,231,240,134,39,63,136,151,95,63,136,49,
+89,252,66,98,243,248,133,96,132,185,5,224,32,36,201,41,248,200,213,249,0,
+131,64,7,39,192,218,148,124,137,74,216,231,198,227,141,182,124,78,40,217,
+231,197,227,4,213,227,192,159,72,10,5,21,218,138,120,74,129,124,36,98,232,
+228,74,81,62,160,20,10,107,181,21,114,32,105,137,194,70,46,142,68,165,19,
+235,1,64,170,187,81,119,34,66,146,36,104,137,194,70,46,142,68,165,19,236,1,
+64,174,187,81,95,37,134,204,23,225,35,23,71,34,82,137,246,128,160,89,93,
+168,167,147,195,201,194,70,46,142,68,165,19,238,1,64,182,187,81,71,105,20,
+19,177,139,163,145,41,68,16,7,6,15,82,70,72,115,96,0,0,0,0,0,93,105,160,91,
+60,149,195,200,194,8,134,149,216,114,1,128,83,192,144,8,194,195,16,12,168,
+110,20,120,12,141,22,16,120,12,100,22,12,120,28,78,99,192,41,224,136,115,
+36,14,100,197,213,245,193,48,189,112,40,2,237,96,175,131,117,2,178,112,145,
+139,163,145,131,114,70,46,142,218,27,182,72,197,209,219,56,26,53,161,166,
+28,1,204,178,10,14,38,78,44,141,52,207,31,0,0,21,64,129,100,180,8,148,145,
+92,203,176,160,226,100,226,200,211,76,241,240,0,1,84,2,131,137,147,142,41,
+100,73,199,192,0,5,88,6,13,10,82,70,62,0,0,42,66,88,115,18,124,67,103,177,
+69,49,130,12,73,242,136,108,246,40,165,177,6,36,248,134,207,71,90,138,99,
+68,152,147,229,16,217,232,235,81,75,130,12,73,241,13,158,158,149,20,199,9,
+49,39,202,33,179,211,210,162,151,69,24,147,225,86,224,79,79,74,138,94,20,
+98,79,133,91,129,61,109,74,41,124,60,137,62,33,179,216,166,216,193,18,36,
+249,68,54,123,20,218,216,137,18,124,67,103,163,173,77,177,162,100,73,242,
+136,108,244,117,169,181,193,18,36,248,134,207,79,74,155,99,132,200,147,229,
+16,217,233,233,83,107,162,164,73,240,171,112,39,167,165,77,175,10,145,39,
+194,173,192,158,182,165,54,191,153,51,72,71,161,196,201,45,167,146,59,68,
+89,24,70,206,0,0,0,0,0,0,7,129,249,153,51,104,71,161,196,201,45,167,146,59,
+68,89,24,70,206,0,0,0,0,0,0,7,129,249,153,51,136,71,161,196,201,45,167,146,
+59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,153,51,168,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,0,0,0,0,2,1,153,51,200,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,0,0,0,0,2,1,153,51,232,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,153,52,8,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,153,52,40,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,153,52,72,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,0,0,0,1,2,1,135,52,102,32,76,72,1,246,136,235,
+103,177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,
+171,37,20,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,
+158,142,183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,
+246,136,235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,
+37,20,138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,
+75,161,37,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,
+39,208,146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,
+129,89,58,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,
+17,214,207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,
+207,161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,
+207,98,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,
+78,209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,
+146,155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,
+104,142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,
+146,155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,
+217,233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,
+162,137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,
+77,156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,
+117,179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,
+162,100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,123,
+102,53,155,80,2,21,11,94,201,128,196,133,0,185,80,32,56,156,199,130,36,160,
+72,16,78,126,54,48,5,146,208,34,82,72,1,109,20,76,155,120,28,34,1,225,32,
+52,171,138,69,133,95,130,160,4,234,219,163,161,0,89,86,214,238,197,172,9,0,
+31,86,221,40,29,231,63,95,200,69,220,199,225,122,183,27,72,144,63,160,138,
+217,81,197,125,207,195,117,110,54,142,129,32,7,114,147,10,189,229,237,159,
+130,235,209,0,96,181,17,83,236,132,37,0,63,101,8,207,71,107,74,6,105,219,
+251,52,245,7,49,248,94,202,17,158,148,12,211,183,246,105,234,15,99,242,159,
+129,228,176,192,185,127,46,155,185,41,197,13,55,38,3,127,255,20,138,160,
+192,25,106,8,8,1,58,90,130,64,128,146,27,168,37,8,9,129,186,130,96,160,152,
+27,165,171,64,32,131,25,234,10,64,65,17,11,212,19,133,18,243,167,165,163,
+32,24,157,45,65,64,6,75,191,80,80,66,149,110,116,117,5,8,41,240,247,79,72,
+188,8,134,81,122,84,1,173,198,212,20,48,139,113,180,181,5,36,42,220,109,29,
+13,65,74,6,192,95,76,188,6,196,55,78,188,6,247,91,86,136,26,32,104,220,205,
+72,1,98,234,52,122,130,136,18,72,51,117,68,3,146,27,168,40,161,37,8,207,80,
+81,129,204,13,212,20,112,179,141,26,45,65,75,112,20,43,193,25,19,66,128,
+153,78,40,105,144,92,104,152,131,124,27,253,128,0,10,116,3,68,146,163,9,
+128,0,10,102,3,138,145,137,27,60,0,0,82,129,7,2,4,16,7,2,70,143,178,203,
+164,237,35,14,25,10,134,147,143,139,158,72,207,28,54,77,47,109,13,55,113,
+120,96,196,159,29,102,241,241,115,201,25,227,131,36,133,20,62,110,143,17,
+16,113,137,62,62,46,155,167,135,147,142,47,44,151,79,221,64,98,37,194,94,
+100,108,144,21,147,140,73,168,228,19,17,124,73,82,54,124,37,230,70,201,14,
+108,185,36,155,14,243,243,83,212,69,131,132,4,12,137,114,168,37,166,145,7,
+10,4,28,200,14,12,40,56,153,56,178,52,211,60,124,0,0,85,0,160,226,100,227,
+138,89,18,113,240,0,1,86,1,131,66,148,145,143,128,0,10,144,93,134,0,0,43,
+80,17,42,4,17,136,49,73,19,49,134,16,143,67,137,146,91,79,36,118,136,178,
+48,141,156,0,0,0,0,0,0,15,3,243,49,135,16,143,67,137,146,91,79,36,118,136,
+178,48,141,156,0,0,0,0,0,0,15,3,245,20,5,173,194,227,214,4,55,0,0,21,196,7,
+122,192,134,241,197,192,0,5,121,25,140,64,132,122,28,76,146,218,121,35,180,
+69,145,132,108,224,0,0,0,0,0,0,120,31,153,140,72,132,122,28,76,146,218,121,
+35,180,69,145,132,108,224,0,0,0,0,0,0,0,32,25,140,80,132,122,28,76,146,218,
+121,35,180,69,145,132,108,224,0,0,0,0,0,0,0,32,25,140,88,132,122,28,76,146,
+218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,8,32,25,140,96,132,122,28,76,
+146,218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,8,32,25,140,104,132,122,
+28,76,146,218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,8,32,25,140,112,
+132,122,28,76,146,218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,16,32,16,
+113,225,0,48,156,209,2,122,244,5,34,92,35,68,225,161,166,218,16,33,18,224,
+104,82,146,59,50,5,7,19,39,22,70,154,103,215,32,28,78,99,193,18,80,70,131,
+165,1,205,34,8,35,68,225,161,166,239,255,4,12,70,137,195,39,248,73,7,78,3,
+154,102,16,70,137,195,67,77,223,248,1,74,9,129,125,255,130,9,65,154,232,
+147,161,115,59,255,5,64,195,32,156,50,126,197,14,2,3,107,173,213,0,
};
#elif defined(DUK_USE_DOUBLE_BE)
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = {
-105,195,75,32,3,148,52,154,248,9,26,13,128,112,105,0,240,22,20,26,95,124,6,
-152,52,137,0,120,99,74,239,129,18,70,241,191,2,98,13,79,32,42,88,210,90,2,
-240,1,50,141,37,168,76,94,216,118,69,229,203,127,44,0,84,163,73,106,21,75,
-14,236,249,98,242,229,191,150,0,46,81,164,181,14,165,151,54,94,89,119,99,
-203,23,151,45,252,176,1,146,141,37,168,93,63,59,186,97,241,23,151,45,252,
-176,1,178,141,37,168,77,79,60,50,197,229,203,127,44,0,116,163,73,106,17,86,
-148,152,188,185,111,229,128,15,148,129,198,137,36,58,166,142,91,251,212,
-243,195,44,94,92,183,242,13,79,8,45,14,91,252,121,148,52,199,120,63,72,105,
-21,240,118,128,210,237,224,245,17,165,43,224,211,55,231,207,151,148,161,70,
-145,0,31,40,107,26,2,18,138,26,228,192,142,0,16,161,174,76,9,74,26,228,192,
-158,0,8,161,174,76,10,96,2,42,26,228,192,174,0,26,161,174,76,11,96,3,74,26,
-228,192,190,0,44,161,174,76,12,96,3,202,26,228,192,206,0,70,161,169,84,14,
-202,3,255,254,32,234,3,255,192,0,0,0,0,0,0,119,1,255,192,0,0,0,0,0,0,57,
-136,1,152,32,16,194,0,166,24,6,49,0,57,138,2,12,96,18,99,128,163,32,5,153,
-40,76,94,216,118,69,229,203,127,35,41,10,165,135,118,124,177,121,114,223,
-200,203,67,169,101,205,151,150,93,216,242,197,229,203,127,35,49,11,167,231,
-119,76,62,34,242,229,191,145,154,132,212,243,195,44,94,92,183,242,51,144,
-138,180,164,197,229,203,127,35,60,6,26,0,52,208,193,226,117,215,211,15,12,
-166,146,11,67,150,255,30,77,24,58,113,64,243,92,8,27,0,68,217,130,70,212,
-19,54,224,161,185,5,77,216,44,111,65,115,126,12,28,16,100,225,156,16,32,18,
-17,195,15,46,121,100,238,232,136,136,87,12,60,185,229,141,179,126,30,136,
-100,130,233,231,59,12,228,34,66,52,243,141,167,118,158,153,80,73,9,201,151,
-30,252,153,106,210,146,118,72,150,76,184,247,228,203,86,148,152,123,246,
-240,223,187,46,238,135,132,132,229,221,143,126,76,181,105,73,61,36,75,46,
-236,123,242,101,171,74,76,61,251,120,111,221,151,119,67,226,65,178,243,199,
-135,134,83,242,66,58,238,203,207,30,30,25,81,201,5,225,203,78,238,136,163,
-208,92,59,50,242,232,138,62,0,2,38,163,19,255,255,224,142,80,192,0,20,31,
-240,14,135,103,203,210,135,45,253,55,244,243,195,44,252,205,197,0,1,18,221,
-82,0,3,24,207,151,164,254,251,168,114,223,195,47,46,158,98,101,231,143,150,
-158,29,55,242,104,68,79,62,94,147,251,238,161,203,127,12,188,186,121,157,
-135,110,94,109,100,131,99,229,151,15,76,172,168,8,89,217,16,201,151,54,157,
-217,104,114,223,195,47,46,154,114,243,102,68,19,158,92,59,27,73,6,205,203,
-46,95,89,91,74,0,3,17,225,203,47,108,187,186,69,241,211,46,238,122,119,238,
-230,216,72,70,158,116,242,225,217,151,35,81,33,26,121,198,229,191,214,93,
-205,69,0,1,134,105,231,23,199,76,187,185,233,197,179,43,73,32,154,242,249,
-230,214,80,0,31,255,193,2,38,103,110,117,24,81,115,0,78,228,0,161,208,16,
-237,24,121,207,239,186,135,45,252,50,242,233,229,188,144,221,60,232,114,
-223,211,127,79,60,50,207,204,224,72,167,14,91,248,101,229,211,204,158,113,
-119,117,219,151,150,28,91,50,184,144,40,95,224,0,15,248,64,4,20,78,129,5,
-195,195,134,207,38,232,130,99,195,179,97,201,244,19,22,157,217,14,15,130,
-135,254,0,48,125,60,224,242,229,135,200,9,1,255,12,2,162,136,112,2,112,80,
-128,0,193,177,239,221,143,15,64,35,224,152,20,144,62,27,248,3,2,9,195,175,
-61,0,231,208,126,89,123,101,229,207,40,72,32,188,244,105,205,208,40,16,94,
-123,52,227,202,22,136,39,61,252,186,6,18,13,207,134,205,56,242,134,175,65,
-250,238,231,163,78,110,129,231,208,125,59,178,101,241,63,48,25,248,0,12,47,
-102,30,125,36,238,201,151,196,252,192,103,255,255,240,92,189,178,242,242,8,
-105,4,231,191,110,80,67,80,0,24,62,109,252,162,225,199,160,16,212,0,10,7,
-183,15,0,67,80,0,56,54,109,59,58,101,228,8,106,0,9,6,229,151,39,92,121,66,
-15,192,0,97,124,178,228,235,143,45,45,57,244,116,8,63,255,255,10,39,248,0,
-195,51,114,223,182,30,140,60,161,239,201,149,248,248,31,241,0,140,80,129,
-202,10,49,128,10,35,1,6,199,163,15,40,61,32,9,10,199,163,15,40,123,242,101,
-131,210,4,144,108,123,247,99,195,210,8,250,15,167,118,76,190,39,230,131,52,
-133,236,195,207,164,157,217,50,248,159,154,12,212,0,6,27,179,126,60,59,50,
-195,223,183,134,30,89,97,9,5,219,135,166,61,16,164,131,242,203,195,102,28,
-121,97,145,6,231,151,15,44,122,33,201,5,231,179,78,60,177,8,130,243,225,
-179,79,72,148,66,121,245,197,207,167,45,59,179,197,162,23,211,124,205,253,
-242,242,135,135,158,87,240,68,122,111,153,191,30,29,153,102,111,239,151,
-148,60,60,242,191,130,23,211,125,94,28,50,242,135,135,158,87,240,128,0,196,
-122,111,153,191,30,29,153,106,240,225,151,148,60,60,242,191,132,0,6,9,211,
-150,157,177,160,131,115,235,139,159,78,81,72,10,47,248,0,3,254,40,17,138,
-48,66,136,152,64,0,66,129,48,5,27,252,88,76,216,54,47,214,131,50,172,88,15,
-253,255,255,255,255,255,255,240,153,178,103,95,173,6,101,88,176,0,0,0,0,0,
-0,0,0,67,168,15,255,0,0,0,0,0,0,17,26,19,233,201,169,38,180,91,242,103,70,
-147,58,77,75,48,31,252,0,0,0,0,0,0,34,51,162,199,131,82,77,104,183,228,206,
-141,38,116,154,150,96,127,248,0,0,0,0,0,0,0,15,248,192,70,40,0,0,0,0,0,0,0,
-0,3,10,44,68,9,216,8,20,49,130,15,211,124,109,62,50,228,95,36,55,166,248,
-190,56,111,221,151,119,77,56,118,47,18,23,211,125,14,89,113,233,231,167,
-126,230,18,5,31,252,0,224,188,48,242,231,148,116,144,58,181,33,143,127,64,
-247,111,238,56,0,127,199,2,49,72,127,248,0,0,0,0,0,0,180,81,36,4,51,166,
-248,152,122,101,167,211,150,157,217,201,2,0,3,12,233,190,166,157,185,105,
-244,229,167,118,114,64,128,1,4,228,129,0,3,137,116,223,51,126,60,59,50,196,
-195,211,45,62,156,180,238,206,72,16,0,72,151,77,243,55,227,195,179,45,77,
-59,114,211,233,203,78,236,228,129,0,5,10,73,2,0,12,21,18,4,0,28,82,35,32,
-80,74,8,62,124,189,42,105,219,148,148,16,188,249,122,70,235,179,101,156,
-184,121,15,132,0,34,29,159,47,74,181,33,198,235,179,101,156,184,121,15,132,
-0,38,17,159,47,73,187,247,116,208,62,16,0,168,94,124,189,42,212,135,55,126,
-238,154,7,194,0,23,7,207,151,164,76,61,50,143,132,0,50,21,159,47,74,181,33,
-196,195,211,40,248,64,3,96,217,242,244,137,135,200,248,64,3,161,57,242,244,
-171,82,28,76,62,71,194,0,31,8,207,151,164,141,253,121,115,31,8,0,132,47,62,
-94,149,106,67,145,191,175,46,99,225,0,17,133,103,203,210,110,157,221,122,
-101,230,62,16,1,40,110,124,189,42,212,135,55,78,238,189,50,243,31,8,0,156,
-43,62,94,148,242,227,223,187,39,49,240,128,10,67,115,229,233,86,164,58,121,
-113,239,221,147,152,248,64,5,97,249,242,244,155,167,102,205,60,242,227,223,
-187,39,49,240,128,11,68,179,229,233,86,164,57,186,118,108,211,207,46,61,
-251,178,115,31,8,0,188,71,62,94,149,52,237,203,235,126,236,179,243,102,231,
-151,161,0,32,252,242,244,169,167,110,82,34,67,249,229,233,55,78,205,154,
-121,229,199,191,118,78,100,37,0,24,137,115,203,210,173,72,115,116,236,217,
-167,158,92,123,247,100,230,66,80,1,152,87,60,189,41,229,199,191,118,78,100,
-43,224,3,80,222,121,122,85,169,14,158,92,123,247,100,230,66,190,0,55,10,
-231,151,164,221,59,186,244,203,204,133,252,0,114,27,207,47,74,181,33,205,
-211,187,175,76,188,200,95,192,7,97,28,242,244,145,191,175,46,100,51,224,3,
-208,190,121,122,85,169,14,70,254,188,185,144,207,128,15,193,249,229,233,19,
-15,76,164,37,0,32,133,115,203,210,173,72,113,48,244,202,66,80,2,24,71,60,
-189,38,239,221,211,65,10,248,1,20,47,158,94,149,106,67,155,191,119,77,4,43,
-224,4,112,190,121,122,70,235,179,101,156,184,121,16,191,128,18,67,185,229,
-233,86,164,56,221,118,108,179,151,15,34,23,240,2,88,62,124,189,44,229,195,
-200,124,32,4,208,126,121,122,89,203,135,145,9,64,9,194,145,254,0,0,255,144,
-24,100,130,14,0,16,176,2,192,129,11,33,12,1,168,193,108,96,186,48,95,32,0,
-0,0,0,0,0,0,0,56,38,95,25,113,189,18,9,211,47,62,143,100,20,95,0,20,159,
-240,0,7,252,144,162,241,2,195,66,7,11,89,204,140,197,252,229,197,226,230,
-115,3,16,69,19,64,5,43,252,0,9,255,40,16,188,33,49,123,97,217,23,151,45,
-252,131,66,7,0,20,191,240,0,39,252,176,66,240,133,82,195,187,62,88,188,185,
-111,228,26,16,56,0,166,127,128,1,63,230,2,23,132,58,150,92,217,121,101,221,
-143,44,94,92,183,242,13,8,28,0,83,127,192,0,159,243,65,11,194,23,79,206,
-238,152,124,69,229,203,127,32,208,129,192,5,59,252,0,9,255,56,16,188,33,53,
-60,240,203,23,151,45,252,131,66,7,0,20,255,240,0,39,252,240,66,240,132,85,
-165,38,47,46,91,249,6,132,14,0,31,255,228,64,98,192,64,5,191,10,139,20,87,
-105,130,76,156,197,132,4,0,38,187,27,187,85,81,104,28,201,204,160,31,243,
-23,33,127,125,28,247,193,102,79,142,202,44,3,255,113,84,118,82,184,47,232,
-52,201,241,216,176,139,0,255,111,45,236,84,155,148,58,5,66,76,4,0,146,31,
-181,68,66,209,136,61,58,52,170,49,190,202,1,255,53,4,243,51,249,222,108,22,
-157,26,85,25,64,63,246,160,158,102,127,59,205,74,7,135,23,53,2,65,48,227,
-223,205,64,160,0,48,76,60,244,238,80,40,0,20,19,15,76,59,148,10,0,7,5,195,
-211,14,230,74,72,130,99,203,167,98,129,64,1,32,120,247,243,80,40,0,44,15,
-47,142,10,5,0,6,130,230,217,191,127,37,2,128,3,192,246,111,206,160,80,0,
-136,30,220,62,19,151,160,123,116,238,79,94,129,240,223,221,73,32,0,48,110,
-88,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0,
-21,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23,
-134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0,
-191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,32,98,140,0,0,0,0,
-0,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144,60,
-56,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7,
-147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3,
-252,131,32,248,250,242,229,151,119,72,240,3,254,148,0,2,168,254,0,0,255,
-167,0,33,68,88,32,0,33,64,176,2,170,254,0,0,255,169,0,33,69,220,32,0,33,67,
-184,2,172,254,0,0,255,171,8,137,144,128,0,0,0,0,0,0,0,68,73,4,195,187,126,
-226,8,4,178,16,41,164,32,147,7,136,52,193,240,0,18,17,48,124,0,8,133,76,31,
-0,3,33,147,7,192,1,8,116,193,240,0,82,127,255,132,47,65,11,137,191,174,45,
-153,98,242,229,191,144,105,4,95,47,46,91,249,32,211,185,6,94,92,183,242,65,
-163,14,236,155,52,238,206,0,85,255,192,6,13,167,157,109,57,123,136,144,31,
-245,192,3,5,231,179,78,60,163,9,0,2,10,199,248,0,3,254,192,4,32,249,242,
-244,147,187,163,129,116,128,24,66,51,229,233,87,78,238,142,5,210,0,65,8,
-207,151,164,157,221,24,182,23,72,1,140,39,62,94,149,116,238,232,197,176,
-186,64,8,97,25,242,244,147,187,163,54,66,233,0,50,132,231,203,210,174,157,
-221,25,178,23,72,1,20,43,62,94,145,182,111,195,209,155,33,116,128,17,194,
-179,229,233,27,102,252,61,27,52,23,72,1,36,31,158,94,146,119,116,112,50,
-208,3,8,71,60,189,42,233,221,209,192,203,64,8,33,28,242,244,147,187,163,22,
-195,45,0,49,132,243,203,210,174,157,221,24,182,25,104,1,12,35,158,94,146,
-119,116,102,200,101,160,6,80,158,121,122,85,211,187,163,54,67,45,0,34,133,
-115,203,210,54,205,248,122,51,100,50,208,2,56,87,60,189,35,108,223,135,163,
-102,131,45,0,36,7,255,248,1,11,50,136,132,115,235,139,15,46,88,124,140,36,
-0,4,43,79,224,139,16,15,252,0,0,0,0,0,0,0,101,253,152,0,5,109,252,17,98,1,
-255,128,0,0,0,0,0,0,12,191,181,0,0,174,63,130,44,64,63,240,0,0,0,0,0,0,1,
-151,246,224,0,21,215,240,69,136,8,0,0,0,0,0,0,0,0,50,254,228,0,2,188,254,8,
-177,1,0,0,0,0,0,0,0,0,6,95,221,128,0,87,223,193,22,32,32,8,0,0,0,0,0,0,0,
-203,251,208,0,11,3,248,34,196,4,1,0,0,0,0,0,0,0,25,127,126,0,1,97,127,4,88,
-128,128,32,0,0,0,0,0,0,3,47,240,64,0,44,79,224,139,16,16,8,0,0,0,0,0,0,0,
-101,254,24,0,5,141,252,1,96,216,247,238,199,135,162,162,33,90,121,197,221,
-143,126,77,59,179,172,146,17,167,156,46,185,179,101,228,176,65,89,77,16,
-124,123,246,240,195,203,40,162,64,0,193,255,138,5,144,158,89,112,228,171,
-39,119,71,2,232,132,114,203,135,36,157,221,28,11,164,0,66,25,203,46,28,149,
-100,238,232,197,180,200,162,233,0,1,134,114,203,135,37,89,59,186,49,109,10,
-40,186,64,2,97,124,178,225,201,39,119,70,45,166,69,23,72,0,140,47,150,92,
-57,36,238,232,197,180,40,162,233,0,25,134,114,203,135,37,89,59,186,51,101,
-50,40,186,64,0,161,156,178,225,201,86,78,238,140,217,66,138,46,144,0,168,
-95,44,184,114,73,221,209,155,41,145,69,210,0,37,11,229,151,14,73,59,186,51,
-101,10,40,186,64,6,161,124,178,225,201,27,102,252,61,38,69,23,72,0,28,47,
-150,92,57,35,108,223,135,164,40,162,233,0,11,134,114,203,135,36,77,253,113,
-108,203,50,40,186,64,1,33,156,178,225,201,19,127,92,91,50,194,138,46,144,0,
-200,87,44,184,114,85,147,187,164,200,162,237,0,5,133,114,203,135,37,89,59,
-186,66,138,46,208,0,216,79,44,184,114,73,221,210,100,81,118,128,10,194,121,
-101,195,146,78,238,144,162,139,180,0,118,21,223,150,158,153,106,201,221,
-209,192,203,33,61,249,105,233,150,78,238,142,6,90,0,33,13,239,203,79,76,
-181,100,238,232,197,180,200,163,45,0,1,134,247,229,167,166,90,178,119,116,
-98,218,20,81,150,128,4,195,59,242,211,211,44,157,221,24,182,153,20,101,160,
-2,48,206,252,180,244,203,39,119,70,45,161,69,25,104,0,204,55,191,45,61,50,
-213,147,187,163,54,83,34,140,180,0,10,27,223,150,158,153,106,201,221,209,
-155,40,81,70,90,0,21,12,239,203,79,76,178,119,116,102,202,100,81,150,128,9,
-67,59,242,211,211,44,157,221,25,178,133,20,101,160,3,80,206,252,180,244,
-203,27,102,252,61,38,69,25,104,0,28,51,191,45,61,50,198,217,191,15,72,81,
-70,90,0,23,13,239,203,79,76,177,55,245,197,179,44,200,163,45,0,4,134,247,
-229,167,166,88,155,250,226,217,150,20,81,150,128,6,66,251,242,211,211,45,
-89,59,186,76,138,51,16,0,88,95,126,90,122,101,171,39,119,72,81,70,98,0,27,
-10,239,203,79,76,178,119,116,153,20,102,32,2,176,174,252,180,244,203,39,
-119,72,81,70,98,0,58,40,173,176,82,90,4,19,54,157,155,21,217,6,203,199,174,
-29,156,197,9,7,199,191,111,12,60,178,138,20,0,6,9,143,127,15,42,208,130,
-243,217,167,30,81,132,65,123,242,211,211,42,228,0,
+DUK_INTERNAL const duk_uint8_t duk_builtins_data[3972] = {
+144,148,105,223,160,68,52,228,62,12,104,200,165,132,52,167,194,138,105,242,
+252,57,28,211,57,18,64,52,238,62,44,138,111,171,241,164,19,87,125,30,33,
+167,16,145,159,8,211,136,9,225,42,5,240,145,139,163,163,8,211,136,10,228,
+64,211,19,132,140,93,29,56,70,156,64,119,34,66,146,36,104,137,194,70,46,
+142,172,35,78,32,47,146,195,102,11,240,145,139,163,175,8,211,136,9,228,240,
+242,112,145,139,163,179,8,211,136,8,237,34,130,118,49,116,118,225,26,48,0,
+1,80,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
+33,8,66,34,33,154,112,0,1,73,247,35,79,91,237,198,174,192,47,31,23,95,17,
+13,51,19,35,93,68,216,209,128,0,10,192,174,79,15,32,248,8,196,24,8,107,192,
+0,5,98,118,27,94,0,0,43,19,227,94,0,0,43,20,46,215,128,0,10,197,28,198,188,
+0,0,86,41,100,53,224,0,2,177,79,85,175,0,0,21,138,154,45,120,0,0,172,85,
+217,107,192,0,5,98,182,243,86,193,106,52,127,66,249,50,94,124,35,68,225,
+146,49,13,31,170,23,201,146,243,224,200,39,12,145,136,67,134,11,49,1,255,
+224,0,0,0,0,0,3,51,1,255,192,0,0,0,0,0,3,47,18,1,172,19,120,71,10,25,196,
+136,113,162,156,136,199,42,57,204,144,115,132,240,149,2,248,72,197,209,58,
+2,185,16,52,196,225,35,23,68,233,14,228,72,82,68,141,17,56,72,197,209,58,
+130,249,44,54,96,191,9,24,186,39,88,79,39,135,147,132,140,93,19,176,35,180,
+138,9,216,197,209,59,82,79,31,40,242,1,248,58,42,96,121,14,232,94,62,46,
+190,15,38,31,145,33,86,65,76,242,150,143,69,48,242,179,79,45,56,243,51,207,
+53,64,243,116,79,57,72,243,180,207,61,80,243,245,79,65,88,244,34,249,50,94,
+124,35,68,225,146,39,163,23,201,146,243,224,200,39,12,145,61,40,183,146,37,
+116,88,6,136,158,244,241,174,230,202,80,135,130,50,39,16,217,231,208,20,
+240,70,68,225,86,224,79,60,64,84,75,141,7,27,157,32,66,37,194,161,168,153,
+51,132,9,25,4,225,147,180,138,50,196,18,25,4,225,147,180,138,5,215,49,238,
+105,27,60,185,2,72,209,56,100,237,34,140,193,4,136,209,56,100,237,34,129,
+117,204,123,154,70,207,50,64,98,72,64,121,51,68,8,163,73,33,1,228,208,16,0,
+65,112,152,56,196,159,31,23,77,211,195,201,199,23,150,73,169,234,34,24,49,
+39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,163,196,64,153,137,62,
+58,205,227,226,231,146,51,199,26,6,18,92,130,64,192,148,144,102,240,23,129,
+133,18,2,100,224,160,56,100,42,26,78,62,46,121,35,60,112,216,32,50,21,13,
+39,31,23,60,145,154,9,46,18,1,36,64,47,148,64,98,196,132,201,57,68,132,95,
+18,84,141,159,9,121,145,178,67,155,46,73,2,17,46,72,128,89,7,199,32,66,37,
+194,197,217,35,120,228,131,17,46,18,243,35,100,128,172,156,98,2,40,152,151,
+32,130,166,36,248,235,55,143,139,158,72,207,28,150,24,23,46,92,130,80,72,
+151,21,0,100,213,103,229,245,8,186,190,144,24,78,136,24,94,152,3,142,9,113,
+214,111,31,23,60,145,158,57,164,13,68,184,248,186,110,158,30,78,56,188,226,
+10,62,46,121,35,60,113,18,225,27,70,18,32,10,201,208,32,134,214,208,200,84,
+52,156,49,39,50,71,107,107,152,129,13,173,161,144,168,105,57,34,78,100,142,
+214,215,49,16,134,214,210,220,229,81,252,49,39,50,71,107,107,158,65,13,173,
+165,185,202,163,249,34,78,100,142,214,215,60,146,12,16,28,128,62,175,42,6,
+143,36,136,16,64,90,242,135,192,129,67,71,147,62,65,5,215,231,214,6,215,62,
+180,8,49,1,3,162,92,4,98,12,41,14,67,40,106,229,1,132,130,8,24,78,104,129,
+54,62,96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,
+178,58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,
+129,232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,
+201,126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,
+132,0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,
+46,36,29,4,78,69,6,60,226,31,192,7,255,252,24,192,163,11,23,51,130,56,35,
+193,56,100,243,31,6,150,46,103,4,225,147,143,114,27,63,57,241,200,169,194,
+133,42,166,175,240,6,23,240,0,97,28,17,224,39,233,32,80,142,8,240,78,25,56,
+9,250,136,22,39,12,156,123,144,217,240,19,245,18,6,19,154,32,79,214,124,14,
+134,140,151,227,139,237,52,11,88,37,62,33,163,37,248,226,251,77,32,213,184,
+64,89,56,39,49,224,137,61,196,5,96,38,35,251,200,15,18,61,96,17,62,40,6,
+145,1,17,31,228,64,89,45,2,39,205,0,178,122,209,63,162,2,101,64,202,113,67,
+77,247,64,92,221,197,186,196,143,4,9,19,208,1,25,187,139,112,128,178,113,
+110,177,35,193,2,68,244,0,46,110,229,30,242,71,130,4,137,232,4,35,55,113,
+110,16,22,78,81,239,36,120,32,72,158,128,64,147,138,25,249,0,52,72,242,2,
+127,2,5,74,96,140,229,203,34,103,250,154,4,17,163,151,44,137,159,234,105,4,
+33,162,93,6,73,123,13,1,165,64,202,113,251,33,6,64,14,71,78,20,101,213,207,
+4,194,207,2,12,162,0,158,176,23,218,168,23,66,64,127,239,255,255,255,255,
+255,255,19,214,33,187,85,2,232,72,0,0,0,0,0,0,0,0,57,136,15,255,0,0,0,0,0,
+0,4,122,247,73,19,69,73,180,134,149,13,68,241,1,255,192,0,0,0,0,0,0,143,90,
+67,2,104,169,54,144,210,161,168,158,32,127,248,0,0,0,0,0,0,14,73,78,20,0,0,
+0,0,0,0,0,0,8,58,189,233,24,77,217,24,93,240,1,230,238,21,23,32,247,68,13,
+155,184,75,189,205,35,102,128,47,114,64,185,187,143,137,4,137,33,205,222,
+17,6,96,48,87,130,50,37,114,1,246,147,21,143,224,54,186,213,128,114,90,112,
+164,63,252,0,0,0,0,0,0,98,117,119,128,25,55,112,96,153,57,41,197,13,53,224,
+65,147,119,38,134,19,146,156,80,211,94,5,194,94,6,37,55,113,110,16,22,78,
+12,19,39,37,56,161,166,188,14,74,110,226,220,32,44,156,154,24,78,74,113,67,
+77,120,32,97,175,4,28,61,224,133,172,186,70,22,248,1,204,73,242,104,97,47,
+128,44,196,159,11,69,175,152,32,35,100,33,142,49,39,218,76,69,237,22,190,
+96,128,141,144,136,32,196,159,24,230,204,246,66,40,179,18,125,164,196,206,
+185,179,61,144,140,28,196,159,6,9,146,200,71,20,98,79,180,152,135,208,76,
+150,66,64,99,18,124,24,49,100,36,137,49,39,218,76,67,232,49,100,37,8,49,39,
+195,186,145,149,144,150,44,196,159,105,49,31,174,164,101,100,38,10,49,39,
+198,33,180,153,37,100,38,141,49,39,218,76,76,234,27,73,146,86,66,112,163,
+18,124,145,4,230,142,86,66,120,211,18,125,164,197,46,144,78,104,229,100,40,
+15,49,39,198,33,107,68,136,39,52,114,178,20,73,24,147,237,38,38,117,11,90,
+36,65,57,163,149,144,164,68,196,159,38,134,19,46,105,56,226,150,68,157,160,
+3,200,147,228,208,194,92,32,124,137,62,49,11,90,36,65,57,163,149,178,166,
+74,68,159,105,49,51,168,90,209,34,9,205,28,173,149,65,82,36,249,34,9,205,
+28,173,175,170,54,68,159,105,49,75,164,19,154,57,91,95,88,84,137,62,49,13,
+164,201,43,111,235,141,145,39,218,76,76,234,27,73,146,86,223,216,17,34,79,
+135,117,35,43,115,236,139,145,39,218,76,71,235,169,25,91,159,104,60,137,62,
+12,19,37,178,182,42,68,159,105,49,15,160,153,45,149,193,18,36,248,199,54,
+103,182,190,232,185,18,125,164,196,206,185,179,61,181,247,133,200,147,225,
+104,181,243,4,4,109,191,190,58,68,159,105,49,23,180,90,249,130,2,54,223,
+224,67,152,147,230,8,8,217,12,16,121,18,124,193,1,27,101,131,131,56,7,38,
+193,198,72,0,0,0,0,0,0,0,0,198,231,240,134,39,63,136,151,95,63,136,49,89,
+252,66,98,243,248,133,96,132,185,5,224,32,36,201,41,248,200,213,249,0,131,
+64,7,39,192,218,148,124,137,74,216,231,198,227,141,182,124,78,40,217,231,
+197,227,4,213,227,192,159,72,10,5,21,218,138,120,74,129,124,36,98,232,228,
+74,81,62,160,20,10,107,181,21,114,32,105,137,194,70,46,142,68,165,19,235,1,
+64,170,187,81,119,34,66,146,36,104,137,194,70,46,142,68,165,19,236,1,64,
+174,187,81,95,37,134,204,23,225,35,23,71,34,82,137,246,128,160,89,93,168,
+167,147,195,201,194,70,46,142,68,165,19,238,1,64,182,187,81,71,105,20,19,
+177,139,163,145,41,68,16,7,6,15,82,70,72,115,96,32,105,221,0,0,0,0,0,91,60,
+149,195,200,194,8,134,149,216,114,1,128,83,192,144,8,194,195,16,12,168,110,
+20,120,12,141,22,16,120,12,100,22,12,120,28,78,99,192,41,224,136,115,36,14,
+100,197,213,245,193,48,189,112,40,2,237,96,175,131,117,2,178,112,145,139,
+163,145,131,114,70,46,142,218,27,182,72,197,209,219,56,26,53,161,166,28,1,
+204,178,10,14,38,78,44,141,52,207,31,0,0,21,64,129,100,180,8,148,145,92,
+203,176,160,226,100,226,200,211,76,241,240,0,1,84,2,131,137,147,142,41,100,
+73,199,192,0,5,88,6,13,10,82,70,62,0,0,42,66,88,115,18,124,67,103,177,69,
+49,130,12,73,242,136,108,246,40,165,177,6,36,248,134,207,71,90,138,99,68,
+152,147,229,16,217,232,235,81,75,130,12,73,241,13,158,158,149,20,199,9,49,
+39,202,33,179,211,210,162,151,69,24,147,225,86,224,79,79,74,138,94,20,98,
+79,133,91,129,61,109,74,41,124,60,137,62,33,179,216,166,216,193,18,36,249,
+68,54,123,20,218,216,137,18,124,67,103,163,173,77,177,162,100,73,242,136,
+108,244,117,169,181,193,18,36,248,134,207,79,74,155,99,132,200,147,229,16,
+217,233,233,83,107,162,164,73,240,171,112,39,167,165,77,175,10,145,39,194,
+173,192,158,182,165,54,191,153,51,72,71,161,196,201,45,167,146,59,68,89,24,
+70,206,1,255,128,0,0,0,0,0,1,153,51,104,71,161,196,201,45,167,146,59,68,89,
+24,70,206,1,255,128,0,0,0,0,0,1,153,51,136,71,161,196,201,45,167,146,59,68,
+89,24,70,206,1,255,128,0,0,0,0,0,1,153,51,168,71,161,196,201,45,167,146,59,
+68,89,24,70,206,2,0,0,0,0,0,0,0,1,153,51,200,71,161,196,201,45,167,146,59,
+68,89,24,70,206,2,0,0,0,0,0,0,0,1,153,51,232,71,161,196,201,45,167,146,59,
+68,89,24,70,206,2,0,128,0,0,0,0,0,1,153,52,8,71,161,196,201,45,167,146,59,
+68,89,24,70,206,2,0,128,0,0,0,0,0,1,153,52,40,71,161,196,201,45,167,146,59,
+68,89,24,70,206,2,0,128,0,0,0,0,0,1,153,52,72,71,161,196,201,45,167,146,59,
+68,89,24,70,206,2,1,0,0,0,0,0,0,1,135,52,102,32,76,72,1,246,136,235,103,
+177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,171,37,
+20,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,158,142,
+183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,246,136,
+235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,37,20,
+138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,75,161,
+37,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,39,208,
+146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,129,89,
+58,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,17,214,
+207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,207,
+161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,207,
+98,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,78,
+209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,146,
+155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,104,
+142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,146,
+155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,217,
+233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,162,
+137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,77,
+156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,117,
+179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,162,
+100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,123,102,
+53,155,80,2,21,11,94,201,128,196,133,0,185,80,32,56,156,199,130,36,160,72,
+16,78,126,54,48,5,146,208,34,82,72,1,109,20,76,155,120,28,34,1,225,32,32,2,
+223,133,69,138,43,180,132,234,219,163,161,1,0,9,174,198,238,213,84,88,31,
+86,221,40,7,252,197,200,95,223,71,61,225,122,183,27,72,144,15,253,197,81,
+217,74,224,191,131,117,110,54,142,129,32,31,237,229,189,138,147,114,135,2,
+235,209,1,0,36,135,237,81,16,180,96,63,101,8,207,71,107,74,1,255,53,4,243,
+51,249,222,104,94,202,17,158,148,3,255,106,9,230,103,243,188,210,159,129,
+228,176,192,185,127,46,155,185,41,197,13,55,38,3,127,255,20,138,160,192,25,
+106,8,8,1,58,90,130,64,128,146,27,168,37,8,9,129,186,130,96,160,152,27,165,
+171,64,32,131,25,234,10,64,65,17,11,212,19,133,18,243,167,165,163,32,24,
+157,45,65,64,6,75,191,80,80,66,149,110,116,117,5,8,41,240,247,79,72,188,8,
+134,81,122,84,1,173,198,212,20,48,139,113,180,181,5,36,42,220,109,29,13,65,
+74,6,192,95,76,188,6,196,55,78,188,6,247,91,86,136,26,32,104,220,205,72,1,
+98,234,52,122,130,136,18,72,51,117,68,3,146,27,168,40,161,37,8,207,80,81,
+129,204,13,212,20,112,179,141,26,45,65,75,112,20,43,193,25,19,66,128,153,
+78,40,105,144,92,104,152,131,124,27,253,128,0,10,116,3,68,146,163,9,128,0,
+10,102,3,138,145,137,27,60,0,0,82,129,7,2,4,16,7,2,70,143,178,203,164,237,
+35,14,25,10,134,147,143,139,158,72,207,28,54,77,47,109,13,55,113,120,96,
+196,159,29,102,241,241,115,201,25,227,131,36,133,20,62,110,143,17,16,113,
+137,62,62,46,155,167,135,147,142,47,44,151,79,221,64,98,37,194,94,100,108,
+144,21,147,140,73,168,228,19,17,124,73,82,54,124,37,230,70,201,14,108,185,
+36,155,14,243,243,83,212,69,131,132,4,12,137,114,168,37,166,145,7,10,4,28,
+200,14,12,40,56,153,56,178,52,211,60,124,0,0,85,0,160,226,100,227,138,89,
+18,113,240,0,1,86,1,131,66,148,145,143,128,0,10,144,93,134,0,0,43,80,17,42,
+4,17,136,49,73,19,49,134,16,143,67,137,146,91,79,36,118,136,178,48,141,156,
+3,255,0,0,0,0,0,0,3,49,135,16,143,67,137,146,91,79,36,118,136,178,48,141,
+156,3,255,0,0,0,0,0,0,5,20,5,173,194,227,214,4,55,0,0,21,196,7,122,192,134,
+241,197,192,0,5,121,25,140,64,132,122,28,76,146,218,121,35,180,69,145,132,
+108,224,31,248,0,0,0,0,0,0,25,140,72,132,122,28,76,146,218,121,35,180,69,
+145,132,108,224,32,0,0,0,0,0,0,0,25,140,80,132,122,28,76,146,218,121,35,
+180,69,145,132,108,224,32,0,0,0,0,0,0,0,25,140,88,132,122,28,76,146,218,
+121,35,180,69,145,132,108,224,32,8,0,0,0,0,0,0,25,140,96,132,122,28,76,146,
+218,121,35,180,69,145,132,108,224,32,8,0,0,0,0,0,0,25,140,104,132,122,28,
+76,146,218,121,35,180,69,145,132,108,224,32,8,0,0,0,0,0,0,25,140,112,132,
+122,28,76,146,218,121,35,180,69,145,132,108,224,32,16,0,0,0,0,0,0,16,113,
+225,0,48,156,209,2,122,244,5,34,92,35,68,225,161,166,218,16,33,18,224,104,
+82,146,59,50,5,7,19,39,22,70,154,103,215,32,28,78,99,193,18,80,70,131,165,
+1,205,34,8,35,68,225,161,166,239,255,4,12,70,137,195,39,248,73,7,78,3,154,
+102,16,70,137,195,67,77,223,248,1,74,9,129,125,255,130,9,65,154,232,147,
+161,115,59,255,5,64,195,32,156,50,126,197,14,2,3,107,173,213,0,
};
#elif defined(DUK_USE_DOUBLE_ME)
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = {
-105,195,75,32,3,148,52,154,248,9,26,13,128,112,105,0,240,22,20,26,95,124,6,
-152,52,137,0,120,99,74,239,129,18,70,241,191,2,98,13,79,32,42,88,210,90,2,
-240,1,50,141,37,168,76,94,216,118,69,229,203,127,44,0,84,163,73,106,21,75,
-14,236,249,98,242,229,191,150,0,46,81,164,181,14,165,151,54,94,89,119,99,
-203,23,151,45,252,176,1,146,141,37,168,93,63,59,186,97,241,23,151,45,252,
-176,1,178,141,37,168,77,79,60,50,197,229,203,127,44,0,116,163,73,106,17,86,
-148,152,188,185,111,229,128,15,148,129,198,137,36,58,166,142,91,251,212,
-243,195,44,94,92,183,242,13,79,8,45,14,91,252,121,148,52,199,120,63,72,105,
-21,240,118,128,210,237,224,245,17,165,43,224,211,55,231,207,151,148,161,70,
-145,0,31,40,107,26,2,18,138,26,228,192,142,0,16,161,174,76,9,74,26,228,192,
-158,0,8,161,174,76,10,96,2,42,26,228,192,174,0,26,161,174,76,11,96,3,74,26,
-228,192,190,0,44,161,174,76,12,96,3,202,26,228,192,206,0,70,161,169,84,14,
-202,3,255,254,32,234,0,0,7,195,248,0,0,0,0,119,0,0,3,193,252,0,0,0,0,57,
-136,1,152,32,16,194,0,166,24,6,49,0,57,138,2,12,96,18,99,128,163,32,5,153,
-40,76,94,216,118,69,229,203,127,35,41,10,165,135,118,124,177,121,114,223,
-200,203,67,169,101,205,151,150,93,216,242,197,229,203,127,35,49,11,167,231,
-119,76,62,34,242,229,191,145,154,132,212,243,195,44,94,92,183,242,51,144,
-138,180,164,197,229,203,127,35,60,6,26,0,52,208,193,226,117,215,211,15,12,
-166,146,11,67,150,255,30,77,24,58,113,64,243,92,8,27,0,68,217,130,70,212,
-19,54,224,161,185,5,77,216,44,111,65,115,126,12,28,16,100,225,156,16,32,18,
-17,195,15,46,121,100,238,232,136,136,87,12,60,185,229,141,179,126,30,136,
-100,130,233,231,59,12,228,34,66,52,243,141,167,118,158,153,80,73,9,201,151,
-30,252,153,106,210,146,118,72,150,76,184,247,228,203,86,148,152,123,246,
-240,223,187,46,238,135,132,132,229,221,143,126,76,181,105,73,61,36,75,46,
-236,123,242,101,171,74,76,61,251,120,111,221,151,119,67,226,65,178,243,199,
-135,134,83,242,66,58,238,203,207,30,30,25,81,201,5,225,203,78,238,136,163,
-208,92,59,50,242,232,138,62,0,2,38,163,19,255,255,224,142,80,192,0,20,31,
-240,14,135,103,203,210,135,45,253,55,244,243,195,44,252,205,197,0,1,18,221,
-82,0,3,24,207,151,164,254,251,168,114,223,195,47,46,158,98,101,231,143,150,
-158,29,55,242,104,68,79,62,94,147,251,238,161,203,127,12,188,186,121,157,
-135,110,94,109,100,131,99,229,151,15,76,172,168,8,89,217,16,201,151,54,157,
-217,104,114,223,195,47,46,154,114,243,102,68,19,158,92,59,27,73,6,205,203,
-46,95,89,91,74,0,3,17,225,203,47,108,187,186,69,241,211,46,238,122,119,238,
-230,216,72,70,158,116,242,225,217,151,35,81,33,26,121,198,229,191,214,93,
-205,69,0,1,134,105,231,23,199,76,187,185,233,197,179,43,73,32,154,242,249,
-230,214,80,0,31,255,193,2,38,103,110,117,24,81,115,0,78,228,0,161,208,16,
-237,24,121,207,239,186,135,45,252,50,242,233,229,188,144,221,60,232,114,
-223,211,127,79,60,50,207,204,224,72,167,14,91,248,101,229,211,204,158,113,
-119,117,219,151,150,28,91,50,184,144,40,95,224,0,15,248,64,4,20,78,129,5,
-195,195,134,207,38,232,130,99,195,179,97,201,244,19,22,157,217,14,15,130,
-135,254,0,48,125,60,224,242,229,135,200,9,1,255,12,2,162,136,112,2,112,80,
-128,0,193,177,239,221,143,15,64,35,224,152,20,144,62,27,248,3,2,9,195,175,
-61,0,231,208,126,89,123,101,229,207,40,72,32,188,244,105,205,208,40,16,94,
-123,52,227,202,22,136,39,61,252,186,6,18,13,207,134,205,56,242,134,175,65,
-250,238,231,163,78,110,129,231,208,125,59,178,101,241,63,48,25,248,0,12,47,
-102,30,125,36,238,201,151,196,252,192,103,255,255,240,92,189,178,242,242,8,
-105,4,231,191,110,80,67,80,0,24,62,109,252,162,225,199,160,16,212,0,10,7,
-183,15,0,67,80,0,56,54,109,59,58,101,228,8,106,0,9,6,229,151,39,92,121,66,
-15,192,0,97,124,178,228,235,143,45,45,57,244,116,8,63,255,255,10,39,248,0,
-195,51,114,223,182,30,140,60,161,239,201,149,248,248,31,241,0,140,80,129,
-202,10,49,128,10,35,1,6,199,163,15,40,61,32,9,10,199,163,15,40,123,242,101,
-131,210,4,144,108,123,247,99,195,210,8,250,15,167,118,76,190,39,230,131,52,
-133,236,195,207,164,157,217,50,248,159,154,12,212,0,6,27,179,126,60,59,50,
-195,223,183,134,30,89,97,9,5,219,135,166,61,16,164,131,242,203,195,102,28,
-121,97,145,6,231,151,15,44,122,33,201,5,231,179,78,60,177,8,130,243,225,
-179,79,72,148,66,121,245,197,207,167,45,59,179,197,162,23,211,124,205,253,
-242,242,135,135,158,87,240,68,122,111,153,191,30,29,153,102,111,239,151,
-148,60,60,242,191,130,23,211,125,94,28,50,242,135,135,158,87,240,128,0,196,
-122,111,153,191,30,29,153,106,240,225,151,148,60,60,242,191,132,0,6,9,211,
-150,157,177,160,131,115,235,139,159,78,81,72,10,47,248,0,3,254,40,17,138,
-48,66,136,152,64,0,66,129,48,5,27,252,88,76,216,54,47,214,131,50,172,88,31,
-255,253,239,255,255,255,255,240,153,178,103,95,173,6,101,88,176,0,0,0,0,0,
-64,0,0,3,168,0,0,31,15,224,0,0,0,17,26,19,233,201,169,38,180,91,242,103,70,
-147,58,77,75,48,0,0,60,31,192,0,0,0,34,51,162,199,131,82,77,104,183,228,
-206,141,38,116,154,150,96,0,0,120,127,128,0,0,0,0,15,248,192,70,40,0,0,0,0,
-0,0,0,0,3,10,44,68,9,216,8,20,49,130,15,211,124,109,62,50,228,95,36,55,166,
-248,190,56,111,221,151,119,77,56,118,47,18,23,211,125,14,89,113,233,231,
-167,126,230,18,5,31,252,0,224,188,48,242,231,148,116,144,58,181,33,143,127,
-64,247,111,238,56,0,127,199,2,49,72,0,0,248,127,0,0,0,0,180,81,36,4,51,166,
-248,152,122,101,167,211,150,157,217,201,2,0,3,12,233,190,166,157,185,105,
-244,229,167,118,114,64,128,1,4,228,129,0,3,137,116,223,51,126,60,59,50,196,
-195,211,45,62,156,180,238,206,72,16,0,72,151,77,243,55,227,195,179,45,77,
-59,114,211,233,203,78,236,228,129,0,5,10,73,2,0,12,21,18,4,0,28,82,35,32,
-80,74,8,62,124,189,42,105,219,148,148,16,188,249,122,70,235,179,101,156,
-184,121,15,132,0,34,29,159,47,74,181,33,198,235,179,101,156,184,121,15,132,
-0,38,17,159,47,73,187,247,116,208,62,16,0,168,94,124,189,42,212,135,55,126,
-238,154,7,194,0,23,7,207,151,164,76,61,50,143,132,0,50,21,159,47,74,181,33,
-196,195,211,40,248,64,3,96,217,242,244,137,135,200,248,64,3,161,57,242,244,
-171,82,28,76,62,71,194,0,31,8,207,151,164,141,253,121,115,31,8,0,132,47,62,
-94,149,106,67,145,191,175,46,99,225,0,17,133,103,203,210,110,157,221,122,
-101,230,62,16,1,40,110,124,189,42,212,135,55,78,238,189,50,243,31,8,0,156,
-43,62,94,148,242,227,223,187,39,49,240,128,10,67,115,229,233,86,164,58,121,
-113,239,221,147,152,248,64,5,97,249,242,244,155,167,102,205,60,242,227,223,
-187,39,49,240,128,11,68,179,229,233,86,164,57,186,118,108,211,207,46,61,
-251,178,115,31,8,0,188,71,62,94,149,52,237,203,235,126,236,179,243,102,231,
-151,161,0,32,252,242,244,169,167,110,82,34,67,249,229,233,55,78,205,154,
-121,229,199,191,118,78,100,37,0,24,137,115,203,210,173,72,115,116,236,217,
-167,158,92,123,247,100,230,66,80,1,152,87,60,189,41,229,199,191,118,78,100,
-43,224,3,80,222,121,122,85,169,14,158,92,123,247,100,230,66,190,0,55,10,
-231,151,164,221,59,186,244,203,204,133,252,0,114,27,207,47,74,181,33,205,
-211,187,175,76,188,200,95,192,7,97,28,242,244,145,191,175,46,100,51,224,3,
-208,190,121,122,85,169,14,70,254,188,185,144,207,128,15,193,249,229,233,19,
-15,76,164,37,0,32,133,115,203,210,173,72,113,48,244,202,66,80,2,24,71,60,
-189,38,239,221,211,65,10,248,1,20,47,158,94,149,106,67,155,191,119,77,4,43,
-224,4,112,190,121,122,70,235,179,101,156,184,121,16,191,128,18,67,185,229,
-233,86,164,56,221,118,108,179,151,15,34,23,240,2,88,62,124,189,44,229,195,
-200,124,32,4,208,126,121,122,89,203,135,145,9,64,9,194,145,254,0,0,255,144,
-24,100,130,14,0,16,176,2,192,129,11,33,12,1,168,193,108,96,186,48,95,32,0,
-0,0,0,0,0,0,0,56,38,95,25,113,189,18,9,211,47,62,143,100,20,95,0,20,159,
-240,0,7,252,144,162,241,2,195,66,7,11,89,204,140,197,252,229,197,226,230,
-115,3,16,69,19,64,5,43,252,0,9,255,40,16,188,33,49,123,97,217,23,151,45,
-252,131,66,7,0,20,191,240,0,39,252,176,66,240,133,82,195,187,62,88,188,185,
-111,228,26,16,56,0,166,127,128,1,63,230,2,23,132,58,150,92,217,121,101,221,
-143,44,94,92,183,242,13,8,28,0,83,127,192,0,159,243,65,11,194,23,79,206,
-238,152,124,69,229,203,127,32,208,129,192,5,59,252,0,9,255,56,16,188,33,53,
-60,240,203,23,151,45,252,131,66,7,0,20,255,240,0,39,252,240,66,240,132,85,
-165,38,47,46,91,249,6,132,14,0,31,255,228,64,98,192,10,191,5,64,105,87,20,
-139,130,76,156,197,132,11,22,176,36,1,101,91,91,184,28,201,204,160,33,23,
-115,31,247,156,253,127,65,102,79,142,202,44,4,113,95,115,255,232,34,182,88,
-52,201,241,216,176,139,1,239,47,108,252,59,148,152,86,5,66,76,15,178,16,
-148,1,130,212,69,72,61,58,52,170,49,190,202,4,245,7,49,254,105,219,251,52,
-22,157,26,85,25,64,158,160,246,63,205,59,127,102,74,7,135,23,53,2,65,48,
-227,223,205,64,160,0,48,76,60,244,238,80,40,0,20,19,15,76,59,148,10,0,7,5,
-195,211,14,230,74,72,130,99,203,167,98,129,64,1,32,120,247,243,80,40,0,44,
-15,47,142,10,5,0,6,130,230,217,191,127,37,2,128,3,192,246,111,206,160,80,0,
-136,30,220,62,19,151,160,123,116,238,79,94,129,240,223,221,73,32,0,48,110,
-88,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0,
-21,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23,
-134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0,
-191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,0,12,98,160,0,0,0,
-0,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144,60,
-56,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7,
-147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3,
-252,131,32,248,250,242,229,151,119,72,240,3,254,148,0,2,168,254,0,0,255,
-167,0,33,68,88,32,0,33,64,176,2,170,254,0,0,255,169,0,33,69,220,32,0,33,67,
-184,2,172,254,0,0,255,171,8,137,144,0,0,0,128,0,0,0,0,68,73,4,195,187,126,
-226,8,4,178,16,41,164,32,147,7,136,52,193,240,0,18,17,48,124,0,8,133,76,31,
-0,3,33,147,7,192,1,8,116,193,240,0,82,127,255,132,47,65,11,137,191,174,45,
-153,98,242,229,191,144,105,4,95,47,46,91,249,32,211,185,6,94,92,183,242,65,
-163,14,236,155,52,238,206,0,85,255,192,6,13,167,157,109,57,123,136,144,31,
-245,192,3,5,231,179,78,60,163,9,0,2,10,199,248,0,3,254,192,4,32,249,242,
-244,147,187,163,129,116,128,24,66,51,229,233,87,78,238,142,5,210,0,65,8,
-207,151,164,157,221,24,182,23,72,1,140,39,62,94,149,116,238,232,197,176,
-186,64,8,97,25,242,244,147,187,163,54,66,233,0,50,132,231,203,210,174,157,
-221,25,178,23,72,1,20,43,62,94,145,182,111,195,209,155,33,116,128,17,194,
-179,229,233,27,102,252,61,27,52,23,72,1,36,31,158,94,146,119,116,112,50,
-208,3,8,71,60,189,42,233,221,209,192,203,64,8,33,28,242,244,147,187,163,22,
-195,45,0,49,132,243,203,210,174,157,221,24,182,25,104,1,12,35,158,94,146,
-119,116,102,200,101,160,6,80,158,121,122,85,211,187,163,54,67,45,0,34,133,
-115,203,210,54,205,248,122,51,100,50,208,2,56,87,60,189,35,108,223,135,163,
-102,131,45,0,36,7,255,248,1,11,50,136,132,115,235,139,15,46,88,124,140,36,
-0,4,43,79,224,139,16,0,0,60,15,192,0,0,0,0,101,253,152,0,5,109,252,17,98,0,
-0,7,129,248,0,0,0,0,12,191,181,0,0,174,63,130,44,64,0,0,240,63,0,0,0,0,1,
-151,246,224,0,21,215,240,69,136,0,0,0,8,0,0,0,0,0,50,254,228,0,2,188,254,8,
-177,0,0,0,1,0,0,0,0,0,6,95,221,128,0,87,223,193,22,32,0,0,8,32,0,0,0,0,0,
-203,251,208,0,11,3,248,34,196,0,0,1,4,0,0,0,0,0,25,127,126,0,1,97,127,4,88,
-128,0,0,32,128,0,0,0,0,3,47,240,64,0,44,79,224,139,16,0,0,8,16,0,0,0,0,0,
-101,254,24,0,5,141,252,1,96,216,247,238,199,135,162,162,33,90,121,197,221,
-143,126,77,59,179,172,146,17,167,156,46,185,179,101,228,176,65,89,77,16,
-124,123,246,240,195,203,40,162,64,0,193,255,138,5,144,158,89,112,228,171,
-39,119,71,2,232,132,114,203,135,36,157,221,28,11,164,0,66,25,203,46,28,149,
-100,238,232,197,180,200,162,233,0,1,134,114,203,135,37,89,59,186,49,109,10,
-40,186,64,2,97,124,178,225,201,39,119,70,45,166,69,23,72,0,140,47,150,92,
-57,36,238,232,197,180,40,162,233,0,25,134,114,203,135,37,89,59,186,51,101,
-50,40,186,64,0,161,156,178,225,201,86,78,238,140,217,66,138,46,144,0,168,
-95,44,184,114,73,221,209,155,41,145,69,210,0,37,11,229,151,14,73,59,186,51,
-101,10,40,186,64,6,161,124,178,225,201,27,102,252,61,38,69,23,72,0,28,47,
-150,92,57,35,108,223,135,164,40,162,233,0,11,134,114,203,135,36,77,253,113,
-108,203,50,40,186,64,1,33,156,178,225,201,19,127,92,91,50,194,138,46,144,0,
-200,87,44,184,114,85,147,187,164,200,162,237,0,5,133,114,203,135,37,89,59,
-186,66,138,46,208,0,216,79,44,184,114,73,221,210,100,81,118,128,10,194,121,
-101,195,146,78,238,144,162,139,180,0,118,21,223,150,158,153,106,201,221,
-209,192,203,33,61,249,105,233,150,78,238,142,6,90,0,33,13,239,203,79,76,
-181,100,238,232,197,180,200,163,45,0,1,134,247,229,167,166,90,178,119,116,
-98,218,20,81,150,128,4,195,59,242,211,211,44,157,221,24,182,153,20,101,160,
-2,48,206,252,180,244,203,39,119,70,45,161,69,25,104,0,204,55,191,45,61,50,
-213,147,187,163,54,83,34,140,180,0,10,27,223,150,158,153,106,201,221,209,
-155,40,81,70,90,0,21,12,239,203,79,76,178,119,116,102,202,100,81,150,128,9,
-67,59,242,211,211,44,157,221,25,178,133,20,101,160,3,80,206,252,180,244,
-203,27,102,252,61,38,69,25,104,0,28,51,191,45,61,50,198,217,191,15,72,81,
-70,90,0,23,13,239,203,79,76,177,55,245,197,179,44,200,163,45,0,4,134,247,
-229,167,166,88,155,250,226,217,150,20,81,150,128,6,66,251,242,211,211,45,
-89,59,186,76,138,51,16,0,88,95,126,90,122,101,171,39,119,72,81,70,98,0,27,
-10,239,203,79,76,178,119,116,153,20,102,32,2,176,174,252,180,244,203,39,
-119,72,81,70,98,0,58,40,173,176,82,90,4,19,54,157,155,21,217,6,203,199,174,
-29,156,197,9,7,199,191,111,12,60,178,138,20,0,6,9,143,127,15,42,208,130,
-243,217,167,30,81,132,65,123,242,211,211,42,228,0,
+DUK_INTERNAL const duk_uint8_t duk_builtins_data[3972] = {
+144,148,105,223,160,68,52,228,62,12,104,200,165,132,52,167,194,138,105,242,
+252,57,28,211,57,18,64,52,238,62,44,138,111,171,241,164,19,87,125,30,33,
+167,16,145,159,8,211,136,9,225,42,5,240,145,139,163,163,8,211,136,10,228,
+64,211,19,132,140,93,29,56,70,156,64,119,34,66,146,36,104,137,194,70,46,
+142,172,35,78,32,47,146,195,102,11,240,145,139,163,175,8,211,136,9,228,240,
+242,112,145,139,163,179,8,211,136,8,237,34,130,118,49,116,118,225,26,48,0,
+1,80,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
+33,8,66,34,33,154,112,0,1,73,247,35,79,91,237,198,174,192,47,31,23,95,17,
+13,51,19,35,93,68,216,209,128,0,10,192,174,79,15,32,248,8,196,24,8,107,192,
+0,5,98,118,27,94,0,0,43,19,227,94,0,0,43,20,46,215,128,0,10,197,28,198,188,
+0,0,86,41,100,53,224,0,2,177,79,85,175,0,0,21,138,154,45,120,0,0,172,85,
+217,107,192,0,5,98,182,243,86,193,106,52,127,66,249,50,94,124,35,68,225,
+146,49,13,31,170,23,201,146,243,224,200,39,12,145,136,67,134,11,49,0,0,3,
+225,252,0,0,0,3,51,0,0,3,193,252,0,0,0,3,47,18,1,172,19,120,71,10,25,196,
+136,113,162,156,136,199,42,57,204,144,115,132,240,149,2,248,72,197,209,58,
+2,185,16,52,196,225,35,23,68,233,14,228,72,82,68,141,17,56,72,197,209,58,
+130,249,44,54,96,191,9,24,186,39,88,79,39,135,147,132,140,93,19,176,35,180,
+138,9,216,197,209,59,82,79,31,40,242,1,248,58,42,96,121,14,232,94,62,46,
+190,15,38,31,145,33,86,65,76,242,150,143,69,48,242,179,79,45,56,243,51,207,
+53,64,243,116,79,57,72,243,180,207,61,80,243,245,79,65,88,244,34,249,50,94,
+124,35,68,225,146,39,163,23,201,146,243,224,200,39,12,145,61,40,183,146,37,
+116,88,6,136,158,244,241,174,230,202,80,135,130,50,39,16,217,231,208,20,
+240,70,68,225,86,224,79,60,64,84,75,141,7,27,157,32,66,37,194,161,168,153,
+51,132,9,25,4,225,147,180,138,50,196,18,25,4,225,147,180,138,5,215,49,238,
+105,27,60,185,2,72,209,56,100,237,34,140,193,4,136,209,56,100,237,34,129,
+117,204,123,154,70,207,50,64,98,72,64,121,51,68,8,163,73,33,1,228,208,16,0,
+65,112,152,56,196,159,31,23,77,211,195,201,199,23,150,73,169,234,34,24,49,
+39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,163,196,64,153,137,62,
+58,205,227,226,231,146,51,199,26,6,18,92,130,64,192,148,144,102,240,23,129,
+133,18,2,100,224,160,56,100,42,26,78,62,46,121,35,60,112,216,32,50,21,13,
+39,31,23,60,145,154,9,46,18,1,36,64,47,148,64,98,196,132,201,57,68,132,95,
+18,84,141,159,9,121,145,178,67,155,46,73,2,17,46,72,128,89,7,199,32,66,37,
+194,197,217,35,120,228,131,17,46,18,243,35,100,128,172,156,98,2,40,152,151,
+32,130,166,36,248,235,55,143,139,158,72,207,28,150,24,23,46,92,130,80,72,
+151,21,0,100,213,103,229,245,8,186,190,144,24,78,136,24,94,152,3,142,9,113,
+214,111,31,23,60,145,158,57,164,13,68,184,248,186,110,158,30,78,56,188,226,
+10,62,46,121,35,60,113,18,225,27,70,18,32,10,201,208,32,134,214,208,200,84,
+52,156,49,39,50,71,107,107,152,129,13,173,161,144,168,105,57,34,78,100,142,
+214,215,49,16,134,214,210,220,229,81,252,49,39,50,71,107,107,158,65,13,173,
+165,185,202,163,249,34,78,100,142,214,215,60,146,12,16,28,128,62,175,42,6,
+143,36,136,16,64,90,242,135,192,129,67,71,147,62,65,5,215,231,214,6,215,62,
+180,8,49,1,3,162,92,4,98,12,41,14,67,40,106,229,1,132,130,8,24,78,104,129,
+54,62,96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,
+178,58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,
+129,232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,
+201,126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,
+132,0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,
+46,36,29,4,78,69,6,60,226,31,192,7,255,252,24,192,163,11,23,51,130,56,35,
+193,56,100,243,31,6,150,46,103,4,225,147,143,114,27,63,57,241,200,169,194,
+133,42,166,175,240,6,23,240,0,97,28,17,224,39,233,32,80,142,8,240,78,25,56,
+9,250,136,22,39,12,156,123,144,217,240,19,245,18,6,19,154,32,79,214,124,14,
+134,140,151,227,139,237,52,11,88,37,62,33,163,37,248,226,251,77,32,213,184,
+64,89,56,39,49,224,137,61,196,5,96,38,35,251,200,15,18,61,96,17,62,40,6,
+145,1,17,31,228,64,89,45,2,39,205,0,178,122,209,63,162,2,101,64,202,113,67,
+77,247,64,92,221,197,186,196,143,4,9,19,208,1,25,187,139,112,128,178,113,
+110,177,35,193,2,68,244,0,46,110,229,30,242,71,130,4,137,232,4,35,55,113,
+110,16,22,78,81,239,36,120,32,72,158,128,64,147,138,25,249,0,52,72,242,2,
+127,2,5,74,96,140,229,203,34,103,250,154,4,17,163,151,44,137,159,234,105,4,
+33,162,93,6,73,123,13,1,165,64,202,113,251,33,6,64,14,71,78,20,101,213,207,
+4,194,207,2,12,162,0,158,176,23,218,168,23,66,64,255,255,239,127,255,255,
+255,255,19,214,33,187,85,2,232,72,0,0,0,0,0,32,0,0,25,136,0,0,31,15,224,0,
+0,0,4,122,247,73,19,69,73,180,134,149,13,68,241,0,0,3,193,252,0,0,0,0,143,
+90,67,2,104,169,54,144,210,161,168,158,32,0,0,120,127,128,0,0,0,14,73,78,
+20,0,0,0,0,0,0,0,0,8,58,189,233,24,77,217,24,93,240,1,230,238,21,23,32,247,
+68,13,155,184,75,189,205,35,102,128,47,114,64,185,187,143,137,4,137,33,205,
+222,17,6,96,48,87,130,50,37,114,1,246,147,21,143,224,54,186,213,128,114,90,
+112,164,0,0,124,63,128,0,0,0,98,117,119,128,25,55,112,96,153,57,41,197,13,
+53,224,65,147,119,38,134,19,146,156,80,211,94,5,194,94,6,37,55,113,110,16,
+22,78,12,19,39,37,56,161,166,188,14,74,110,226,220,32,44,156,154,24,78,74,
+113,67,77,120,32,97,175,4,28,61,224,133,172,186,70,22,248,1,204,73,242,104,
+97,47,128,44,196,159,11,69,175,152,32,35,100,33,142,49,39,218,76,69,237,22,
+190,96,128,141,144,136,32,196,159,24,230,204,246,66,40,179,18,125,164,196,
+206,185,179,61,144,140,28,196,159,6,9,146,200,71,20,98,79,180,152,135,208,
+76,150,66,64,99,18,124,24,49,100,36,137,49,39,218,76,67,232,49,100,37,8,49,
+39,195,186,145,149,144,150,44,196,159,105,49,31,174,164,101,100,38,10,49,
+39,198,33,180,153,37,100,38,141,49,39,218,76,76,234,27,73,146,86,66,112,
+163,18,124,145,4,230,142,86,66,120,211,18,125,164,197,46,144,78,104,229,
+100,40,15,49,39,198,33,107,68,136,39,52,114,178,20,73,24,147,237,38,38,117,
+11,90,36,65,57,163,149,144,164,68,196,159,38,134,19,46,105,56,226,150,68,
+157,160,3,200,147,228,208,194,92,32,124,137,62,49,11,90,36,65,57,163,149,
+178,166,74,68,159,105,49,51,168,90,209,34,9,205,28,173,149,65,82,36,249,34,
+9,205,28,173,175,170,54,68,159,105,49,75,164,19,154,57,91,95,88,84,137,62,
+49,13,164,201,43,111,235,141,145,39,218,76,76,234,27,73,146,86,223,216,17,
+34,79,135,117,35,43,115,236,139,145,39,218,76,71,235,169,25,91,159,104,60,
+137,62,12,19,37,178,182,42,68,159,105,49,15,160,153,45,149,193,18,36,248,
+199,54,103,182,190,232,185,18,125,164,196,206,185,179,61,181,247,133,200,
+147,225,104,181,243,4,4,109,191,190,58,68,159,105,49,23,180,90,249,130,2,
+54,223,224,67,152,147,230,8,8,217,12,16,121,18,124,193,1,27,101,131,131,56,
+7,38,193,198,72,0,0,0,0,0,0,0,0,198,231,240,134,39,63,136,151,95,63,136,49,
+89,252,66,98,243,248,133,96,132,185,5,224,32,36,201,41,248,200,213,249,0,
+131,64,7,39,192,218,148,124,137,74,216,231,198,227,141,182,124,78,40,217,
+231,197,227,4,213,227,192,159,72,10,5,21,218,138,120,74,129,124,36,98,232,
+228,74,81,62,160,20,10,107,181,21,114,32,105,137,194,70,46,142,68,165,19,
+235,1,64,170,187,81,119,34,66,146,36,104,137,194,70,46,142,68,165,19,236,1,
+64,174,187,81,95,37,134,204,23,225,35,23,71,34,82,137,246,128,160,89,93,
+168,167,147,195,201,194,70,46,142,68,165,19,238,1,64,182,187,81,71,105,20,
+19,177,139,163,145,41,68,16,7,6,15,82,70,72,115,96,0,93,105,160,0,0,0,0,91,
+60,149,195,200,194,8,134,149,216,114,1,128,83,192,144,8,194,195,16,12,168,
+110,20,120,12,141,22,16,120,12,100,22,12,120,28,78,99,192,41,224,136,115,
+36,14,100,197,213,245,193,48,189,112,40,2,237,96,175,131,117,2,178,112,145,
+139,163,145,131,114,70,46,142,218,27,182,72,197,209,219,56,26,53,161,166,
+28,1,204,178,10,14,38,78,44,141,52,207,31,0,0,21,64,129,100,180,8,148,145,
+92,203,176,160,226,100,226,200,211,76,241,240,0,1,84,2,131,137,147,142,41,
+100,73,199,192,0,5,88,6,13,10,82,70,62,0,0,42,66,88,115,18,124,67,103,177,
+69,49,130,12,73,242,136,108,246,40,165,177,6,36,248,134,207,71,90,138,99,
+68,152,147,229,16,217,232,235,81,75,130,12,73,241,13,158,158,149,20,199,9,
+49,39,202,33,179,211,210,162,151,69,24,147,225,86,224,79,79,74,138,94,20,
+98,79,133,91,129,61,109,74,41,124,60,137,62,33,179,216,166,216,193,18,36,
+249,68,54,123,20,218,216,137,18,124,67,103,163,173,77,177,162,100,73,242,
+136,108,244,117,169,181,193,18,36,248,134,207,79,74,155,99,132,200,147,229,
+16,217,233,233,83,107,162,164,73,240,171,112,39,167,165,77,175,10,145,39,
+194,173,192,158,182,165,54,191,153,51,72,71,161,196,201,45,167,146,59,68,
+89,24,70,206,0,0,7,129,248,0,0,0,1,153,51,104,71,161,196,201,45,167,146,59,
+68,89,24,70,206,0,0,7,129,248,0,0,0,1,153,51,136,71,161,196,201,45,167,146,
+59,68,89,24,70,206,0,0,7,129,248,0,0,0,1,153,51,168,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,2,0,0,0,0,1,153,51,200,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,2,0,0,0,0,1,153,51,232,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,153,52,8,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,153,52,40,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,153,52,72,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,1,2,0,0,0,0,1,135,52,102,32,76,72,1,246,136,235,
+103,177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,
+171,37,20,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,
+158,142,183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,
+246,136,235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,
+37,20,138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,
+75,161,37,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,
+39,208,146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,
+129,89,58,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,
+17,214,207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,
+207,161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,
+207,98,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,
+78,209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,
+146,155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,
+104,142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,
+146,155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,
+217,233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,
+162,137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,
+77,156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,
+117,179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,
+162,100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,123,
+102,53,155,80,2,21,11,94,201,128,196,133,0,185,80,32,56,156,199,130,36,160,
+72,16,78,126,54,48,5,146,208,34,82,72,1,109,20,76,155,120,28,34,1,225,32,5,
+95,130,160,52,171,138,69,132,234,219,163,161,2,197,172,9,0,89,86,214,236,
+31,86,221,40,8,69,220,199,253,231,63,95,193,122,183,27,72,144,17,197,125,
+207,255,160,138,217,67,117,110,54,142,129,32,61,229,237,159,135,114,147,10,
+130,235,209,3,236,132,37,0,96,181,17,80,63,101,8,207,71,107,74,4,245,7,49,
+254,105,219,251,48,94,202,17,158,148,9,234,15,99,252,211,183,246,98,159,
+129,228,176,192,185,127,46,155,185,41,197,13,55,38,3,127,255,20,138,160,
+192,25,106,8,8,1,58,90,130,64,128,146,27,168,37,8,9,129,186,130,96,160,152,
+27,165,171,64,32,131,25,234,10,64,65,17,11,212,19,133,18,243,167,165,163,
+32,24,157,45,65,64,6,75,191,80,80,66,149,110,116,117,5,8,41,240,247,79,72,
+188,8,134,81,122,84,1,173,198,212,20,48,139,113,180,181,5,36,42,220,109,29,
+13,65,74,6,192,95,76,188,6,196,55,78,188,6,247,91,86,136,26,32,104,220,205,
+72,1,98,234,52,122,130,136,18,72,51,117,68,3,146,27,168,40,161,37,8,207,80,
+81,129,204,13,212,20,112,179,141,26,45,65,75,112,20,43,193,25,19,66,128,
+153,78,40,105,144,92,104,152,131,124,27,253,128,0,10,116,3,68,146,163,9,
+128,0,10,102,3,138,145,137,27,60,0,0,82,129,7,2,4,16,7,2,70,143,178,203,
+164,237,35,14,25,10,134,147,143,139,158,72,207,28,54,77,47,109,13,55,113,
+120,96,196,159,29,102,241,241,115,201,25,227,131,36,133,20,62,110,143,17,
+16,113,137,62,62,46,155,167,135,147,142,47,44,151,79,221,64,98,37,194,94,
+100,108,144,21,147,140,73,168,228,19,17,124,73,82,54,124,37,230,70,201,14,
+108,185,36,155,14,243,243,83,212,69,131,132,4,12,137,114,168,37,166,145,7,
+10,4,28,200,14,12,40,56,153,56,178,52,211,60,124,0,0,85,0,160,226,100,227,
+138,89,18,113,240,0,1,86,1,131,66,148,145,143,128,0,10,144,93,134,0,0,43,
+80,17,42,4,17,136,49,73,19,49,134,16,143,67,137,146,91,79,36,118,136,178,
+48,141,156,0,0,15,3,240,0,0,0,3,49,135,16,143,67,137,146,91,79,36,118,136,
+178,48,141,156,0,0,15,3,240,0,0,0,5,20,5,173,194,227,214,4,55,0,0,21,196,7,
+122,192,134,241,197,192,0,5,121,25,140,64,132,122,28,76,146,218,121,35,180,
+69,145,132,108,224,0,0,120,31,128,0,0,0,25,140,72,132,122,28,76,146,218,
+121,35,180,69,145,132,108,224,0,0,0,32,0,0,0,0,25,140,80,132,122,28,76,146,
+218,121,35,180,69,145,132,108,224,0,0,0,32,0,0,0,0,25,140,88,132,122,28,76,
+146,218,121,35,180,69,145,132,108,224,0,0,8,32,0,0,0,0,25,140,96,132,122,
+28,76,146,218,121,35,180,69,145,132,108,224,0,0,8,32,0,0,0,0,25,140,104,
+132,122,28,76,146,218,121,35,180,69,145,132,108,224,0,0,8,32,0,0,0,0,25,
+140,112,132,122,28,76,146,218,121,35,180,69,145,132,108,224,0,0,16,32,0,0,
+0,0,16,113,225,0,48,156,209,2,122,244,5,34,92,35,68,225,161,166,218,16,33,
+18,224,104,82,146,59,50,5,7,19,39,22,70,154,103,215,32,28,78,99,193,18,80,
+70,131,165,1,205,34,8,35,68,225,161,166,239,255,4,12,70,137,195,39,248,73,
+7,78,3,154,102,16,70,137,195,67,77,223,248,1,74,9,129,125,255,130,9,65,154,
+232,147,161,115,59,255,5,64,195,32,156,50,126,197,14,2,3,107,173,213,0,
};
#else
#error invalid endianness defines
#endif
#endif /* DUK_USE_ROM_OBJECTS */
+
+/* automatic undefs */
+#undef DUK__REFCINIT
#line 1 "duk_error_macros.c"
/*
- * Error, fatal, and panic handling.
+ * Error and fatal handling.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
#define DUK__ERRFMT_BUFSIZE 256 /* size for formatting buffers */
#if defined(DUK_USE_VERBOSE_ERRORS)
-DUK_INTERNAL void duk_err_handle_error_fmt(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *fmt, ...) {
+DUK_INTERNAL DUK_COLD void duk_err_handle_error_fmt(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *fmt, ...) {
va_list ap;
char msg[DUK__ERRFMT_BUFSIZE];
va_start(ap, fmt);
@@ -9802,13 +11406,13 @@ DUK_INTERNAL void duk_err_handle_error_fmt(duk_hthread *thr, const char *filenam
va_end(ap); /* dead code, but ensures portability (see Linux man page notes) */
}
-DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg) {
+DUK_INTERNAL DUK_COLD void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg) {
duk_err_create_and_throw(thr, (duk_errcode_t) (line_and_code >> 24), msg, filename, (duk_int_t) (line_and_code & 0x00ffffffL));
}
#else /* DUK_USE_VERBOSE_ERRORS */
-DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) {
+DUK_INTERNAL DUK_COLD void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) {
duk_err_create_and_throw(thr, code);
}
@@ -9820,69 +11424,72 @@ DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) {
#if defined(DUK_USE_VERBOSE_ERRORS)
#if defined(DUK_USE_PARANOID_ERRORS)
-DUK_INTERNAL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name) {
+DUK_INTERNAL DUK_COLD void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name) {
DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)",
- expect_name, duk_get_type_name((duk_context *) thr, index), (long) index);
+ expect_name, duk_get_type_name(thr, idx), (long) idx);
}
#else
-DUK_INTERNAL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name) {
+DUK_INTERNAL DUK_COLD void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name) {
DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)",
- expect_name, duk_push_string_readable((duk_context *) thr, index), (long) index);
+ expect_name, duk_push_string_readable(thr, idx), (long) idx);
}
#endif
-DUK_INTERNAL void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
+DUK_INTERNAL DUK_COLD void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
+ DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, DUK_STR_INTERNAL_ERROR);
+}
+DUK_INTERNAL DUK_COLD void duk_err_error_alloc_failed(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
+ DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, DUK_STR_ALLOC_FAILED);
+}
+DUK_INTERNAL DUK_COLD void duk_err_error(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
+ DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, message);
+}
+DUK_INTERNAL DUK_COLD void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, message);
}
-DUK_INTERNAL void duk_err_api_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index) {
- DUK_ERROR_RAW_FMT1(thr, filename, linenumber, DUK_ERR_API_ERROR, "invalid stack index %ld", (long) (index));
+DUK_INTERNAL DUK_COLD void duk_err_range_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx) {
+ DUK_ERROR_RAW_FMT1(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, "invalid stack index %ld", (long) (idx));
}
-DUK_INTERNAL void duk_err_api(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
- DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_API_ERROR, message);
+DUK_INTERNAL DUK_COLD void duk_err_range_push_beyond(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
+ DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
}
-DUK_INTERNAL void duk_err_unimplemented_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
- DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_UNIMPLEMENTED_ERROR, DUK_STR_UNIMPLEMENTED);
+DUK_INTERNAL DUK_COLD void duk_err_type_invalid_args(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
+ DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_ARGS);
}
-#if !defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
-DUK_INTERNAL void duk_err_unsupported_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
- DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_UNSUPPORTED_ERROR, DUK_STR_UNSUPPORTED);
+DUK_INTERNAL DUK_COLD void duk_err_type_invalid_state(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
+ DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_STATE);
}
-#endif
-DUK_INTERNAL void duk_err_internal_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
- DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_INTERNAL_ERROR, DUK_STR_INTERNAL_ERROR);
-}
-DUK_INTERNAL void duk_err_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
- DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_INTERNAL_ERROR, message);
-}
-DUK_INTERNAL void duk_err_alloc(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
- DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ALLOC_ERROR, message);
+DUK_INTERNAL DUK_COLD void duk_err_type_invalid_trap_result(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
+ DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_TRAP_RESULT);
}
#else
/* The file/line arguments are NULL and 0, they're ignored by DUK_ERROR_RAW()
* when non-verbose errors are used.
*/
-DUK_INTERNAL void duk_err_type(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_TYPE_ERROR, NULL);
+
+DUK_NORETURN(DUK_LOCAL_DECL void duk__err_shared(duk_hthread *thr, duk_errcode_t code));
+DUK_LOCAL void duk__err_shared(duk_hthread *thr, duk_errcode_t code) {
+ DUK_ERROR_RAW(thr, NULL, 0, code, NULL);
}
-DUK_INTERNAL void duk_err_api(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_API_ERROR, NULL);
+DUK_INTERNAL DUK_COLD void duk_err_error(duk_hthread *thr) {
+ duk__err_shared(thr, DUK_ERR_ERROR);
}
-DUK_INTERNAL void duk_err_range(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_RANGE_ERROR, NULL);
+DUK_INTERNAL DUK_COLD void duk_err_range(duk_hthread *thr) {
+ duk__err_shared(thr, DUK_ERR_RANGE_ERROR);
}
-DUK_INTERNAL void duk_err_syntax(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_SYNTAX_ERROR, NULL);
+DUK_INTERNAL DUK_COLD void duk_err_eval(duk_hthread *thr) {
+ duk__err_shared(thr, DUK_ERR_EVAL_ERROR);
}
-DUK_INTERNAL void duk_err_unimplemented(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_UNIMPLEMENTED_ERROR, NULL);
+DUK_INTERNAL DUK_COLD void duk_err_reference(duk_hthread *thr) {
+ duk__err_shared(thr, DUK_ERR_REFERENCE_ERROR);
}
-DUK_INTERNAL void duk_err_unsupported(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_UNSUPPORTED_ERROR, NULL);
+DUK_INTERNAL DUK_COLD void duk_err_syntax(duk_hthread *thr) {
+ duk__err_shared(thr, DUK_ERR_SYNTAX_ERROR);
}
-DUK_INTERNAL void duk_err_internal(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_INTERNAL_ERROR, NULL);
+DUK_INTERNAL DUK_COLD void duk_err_type(duk_hthread *thr) {
+ duk__err_shared(thr, DUK_ERR_TYPE_ERROR);
}
-DUK_INTERNAL void duk_err_alloc(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, thr, DUK_ERR_ALLOC_ERROR, NULL);
+DUK_INTERNAL DUK_COLD void duk_err_uri(duk_hthread *thr) {
+ duk__err_shared(thr, DUK_ERR_URI_ERROR);
}
#endif
@@ -9890,60 +11497,41 @@ DUK_INTERNAL void duk_err_alloc(duk_hthread *thr) {
* Default fatal error handler
*/
-DUK_INTERNAL void duk_default_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg) {
- DUK_UNREF(ctx);
-#if defined(DUK_USE_FILE_IO)
- DUK_FPRINTF(DUK_STDERR, "FATAL %ld: %s\n", (long) code, (const char *) (msg ? msg : "null"));
- DUK_FFLUSH(DUK_STDERR);
-#else
- /* omit print */
-#endif
- DUK_D(DUK_DPRINT("default fatal handler called, code %ld -> calling DUK_PANIC()", (long) code));
- DUK_PANIC(code, msg);
- DUK_UNREACHABLE();
-}
-
-/*
- * Default panic handler
- */
-
-#if !defined(DUK_USE_PANIC_HANDLER)
-DUK_INTERNAL void duk_default_panic_handler(duk_errcode_t code, const char *msg) {
-#if defined(DUK_USE_FILE_IO)
- DUK_FPRINTF(DUK_STDERR, "PANIC %ld: %s ("
-#if defined(DUK_USE_PANIC_ABORT)
- "calling abort"
-#elif defined(DUK_USE_PANIC_EXIT)
- "calling exit"
-#elif defined(DUK_USE_PANIC_SEGFAULT)
- "segfaulting on purpose"
-#else
-#error no DUK_USE_PANIC_xxx macro defined
-#endif
- ")\n", (long) code, (const char *) (msg ? msg : "null"));
- DUK_FFLUSH(DUK_STDERR);
-#else
- /* omit print */
- DUK_UNREF(code);
+DUK_INTERNAL DUK_COLD void duk_default_fatal_handler(void *udata, const char *msg) {
+ DUK_UNREF(udata);
DUK_UNREF(msg);
-#endif
-#if defined(DUK_USE_PANIC_ABORT)
- DUK_ABORT();
-#elif defined(DUK_USE_PANIC_EXIT)
- DUK_EXIT(-1);
-#elif defined(DUK_USE_PANIC_SEGFAULT)
- /* exit() afterwards to satisfy "noreturn" */
- DUK_CAUSE_SEGFAULT(); /* SCANBUILD: "Dereference of null pointer", normal */
- DUK_EXIT(-1);
+#if defined(DUK_USE_FATAL_HANDLER)
+ /* duk_config.h provided a custom default fatal handler. */
+ DUK_D(DUK_DPRINT("custom default fatal error handler called: %s", msg ? msg : "NULL"));
+ DUK_USE_FATAL_HANDLER(udata, msg);
#else
-#error no DUK_USE_PANIC_xxx macro defined
+ /* Default behavior is to abort() on error. There's no printout
+ * which makes this awkward, so it's always recommended to use an
+ * explicit fatal error handler.
+ *
+ * ====================================================================
+ * NOTE: If you are seeing this, you are most likely dealing with an
+ * uncaught error. You should provide a fatal error handler in Duktape
+ * heap creation, and should consider using a protected call as your
+ * first call into an empty Duktape context to properly handle errors.
+ * See:
+ * - http://duktape.org/guide.html#error-handling
+ * - http://wiki.duktape.org/HowtoFatalErrors.html
+ * - http://duktape.org/api.html#taglist-protected
+ * ====================================================================
+ */
+ DUK_D(DUK_DPRINT("built-in default fatal error handler called: %s", msg ? msg : "NULL"));
+ DUK_ABORT();
#endif
- DUK_UNREACHABLE();
+ DUK_D(DUK_DPRINT("fatal error handler returned, enter forever loop"));
+ for (;;) {
+ /* Loop forever to ensure we don't return. */
+ }
}
-#endif /* !DUK_USE_PANIC_HANDLER */
+/* automatic undefs */
#undef DUK__ERRFMT_BUFSIZE
#line 1 "duk_unicode_support.c"
/*
@@ -9951,7 +11539,7 @@ DUK_INTERNAL void duk_default_panic_handler(duk_errcode_t code, const char *msg)
* case conversion, decoding, etc.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Fast path tables
@@ -10198,8 +11786,17 @@ DUK_INTERNAL duk_small_int_t duk_unicode_decode_xutf8(duk_hthread *thr, const du
while (n > 0) {
DUK_ASSERT(p >= ptr_start && p < ptr_end);
- res = res << 6;
- res += (duk_uint32_t) ((*p++) & 0x3f);
+ ch = (duk_uint_fast8_t) (*p++);
+#if 0
+ if (ch & 0xc0 != 0x80) {
+ /* not a continuation byte */
+ p--;
+ *ptr = p;
+ *out_cp = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
+ return 1;
+ }
+#endif
+ res = (res << 6) + (duk_uint32_t) (ch & 0x3f);
n--;
}
@@ -10218,7 +11815,7 @@ DUK_INTERNAL duk_ucodepoint_t duk_unicode_decode_xutf8_checked(duk_hthread *thr,
if (duk_unicode_decode_xutf8(thr, ptr, ptr_start, ptr_end, &cp)) {
return cp;
}
- DUK_ERROR_INTERNAL(thr, "utf-8 decode failed"); /* XXX: 'internal error' is a bit of a misnomer */
+ DUK_ERROR_INTERNAL(thr);
DUK_UNREACHABLE();
return 0;
}
@@ -10233,7 +11830,7 @@ DUK_INTERNAL duk_ucodepoint_t duk_unicode_decode_xutf8_checked(duk_hthread *thr,
* chosen from several variants, based on x64 gcc -O2 testing. See:
* https://github.com/svaarala/duktape/pull/422
*
- * NOTE: must match src/dukutil.py:duk_unicode_unvalidated_utf8_length().
+ * NOTE: must match tools/dukutil.py:duk_unicode_unvalidated_utf8_length().
*/
#if defined(DUK_USE_PREFER_SIZE)
@@ -10344,7 +11941,7 @@ DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *d
* Used for slow path Unicode matching.
*/
-/* Must match src/extract_chars.py, generate_match_table3(). */
+/* Must match tools/extract_chars.py, generate_match_table3(). */
DUK_LOCAL duk_uint32_t duk__uni_decode_value(duk_bitdecoder_ctx *bd_ctx) {
duk_uint32_t t;
@@ -10415,7 +12012,7 @@ DUK_INTERNAL duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp) {
* FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;;
*
* It also specifies any Unicode category 'Zs' characters as white
- * space. These can be extracted with the "src/extract_chars.py" script.
+ * space. These can be extracted with the "tools/extract_chars.py" script.
* Current result:
*
* RAW OUTPUT:
@@ -10522,7 +12119,7 @@ DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp)
*
* The "UnicodeLetter" alternative of the production allows letters
* from various Unicode categories. These can be extracted with the
- * "src/extract_chars.py" script.
+ * "tools/extract_chars.py" script.
*
* Because the result has hundreds of Unicode codepoint ranges, matching
* for any values >= 0x80 are done using a very slow range-by-range scan
@@ -10553,7 +12150,7 @@ DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp)
/* Non-ASCII slow path (range-by-range linear comparison), very slow */
-#ifdef DUK_USE_SOURCE_NONBMP
+#if defined(DUK_USE_SOURCE_NONBMP)
if (duk__uni_range_match(duk_unicode_ids_noa,
(duk_size_t) sizeof(duk_unicode_ids_noa),
(duk_codepoint_t) cp)) {
@@ -10619,7 +12216,7 @@ DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp)
* The matching code reuses the "identifier start" tables, and then
* consults a separate range set for characters in "identifier part"
* but not in "identifier start". These can be extracted with the
- * "src/extract_chars.py" script.
+ * "tools/extract_chars.py" script.
*
* UnicodeCombiningMark -> categories Mn, Mc
* UnicodeDigit -> categories Nd
@@ -10643,7 +12240,7 @@ DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp)
/* Non-ASCII slow path (range-by-range linear comparison), very slow */
-#ifdef DUK_USE_SOURCE_NONBMP
+#if defined(DUK_USE_SOURCE_NONBMP)
if (duk__uni_range_match(duk_unicode_ids_noa,
sizeof(duk_unicode_ids_noa),
(duk_codepoint_t) cp) ||
@@ -10702,7 +12299,7 @@ DUK_INTERNAL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp) {
/* Non-ASCII slow path (range-by-range linear comparison), very slow */
-#ifdef DUK_USE_SOURCE_NONBMP
+#if defined(DUK_USE_SOURCE_NONBMP)
if (duk__uni_range_match(duk_unicode_ids_noa,
sizeof(duk_unicode_ids_noa),
(duk_codepoint_t) cp) &&
@@ -10734,14 +12331,14 @@ DUK_INTERNAL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp) {
/*
* Complex case conversion helper which decodes a bit-packed conversion
- * control stream generated by unicode/extract_caseconv.py. The conversion
+ * control stream generated by tools/extract_caseconv.py. The conversion
* is very slow because it runs through the conversion data in a linear
* fashion to save space (which is why ASCII characters have a special
* fast path before arriving here).
*
* The particular bit counts etc have been determined experimentally to
* be small but still sufficient, and must match the Python script
- * (src/extract_caseconv.py).
+ * (tools/extract_caseconv.py).
*
* The return value is the case converted codepoint or -1 if the conversion
* results in multiple characters (this is useful for regexp Canonicalization
@@ -10765,8 +12362,8 @@ duk_codepoint_t duk__slow_case_conversion(duk_hthread *thr,
duk_codepoint_t start_i;
duk_codepoint_t start_o;
- DUK_UNREF(thr);
DUK_ASSERT(bd_ctx != NULL);
+ DUK_UNREF(thr);
DUK_DDD(DUK_DDDPRINT("slow case conversion for codepoint: %ld", (long) cp));
@@ -10801,7 +12398,7 @@ duk_codepoint_t duk__slow_case_conversion(duk_hthread *thr,
}
/* 1:1 conversion */
- n = (duk_small_int_t) duk_bd_decode(bd_ctx, 6);
+ n = (duk_small_int_t) duk_bd_decode(bd_ctx, 7);
DUK_DDD(DUK_DDDPRINT("checking 1:1 conversions (count %ld)", (long) n));
while (n--) {
start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
@@ -10948,15 +12545,14 @@ duk_codepoint_t duk__case_transform_helper(duk_hthread *thr,
* Replace valstack top with case converted version.
*/
-DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_small_int_t uppercase) {
- duk_context *ctx = (duk_context *) thr;
+DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_bool_t uppercase) {
duk_hstring *h_input;
duk_bufwriter_ctx bw_alloc;
duk_bufwriter_ctx *bw;
const duk_uint8_t *p, *p_start, *p_end;
duk_codepoint_t prev, curr, next;
- h_input = duk_require_hstring(ctx, -1);
+ h_input = duk_require_hstring(thr, -1); /* Accept symbols. */
DUK_ASSERT(h_input != NULL);
bw = &bw_alloc;
@@ -10976,7 +12572,7 @@ DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_small_in
curr = next;
next = -1;
if (p < p_end) {
- next = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
+ next = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
} else {
/* end of input and last char has been processed */
if (curr < 0) {
@@ -11003,11 +12599,12 @@ DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_small_in
}
DUK_BW_COMPACT(thr, bw);
- duk_to_string(ctx, -1); /* invalidates h_buf pointer */
- duk_remove(ctx, -2);
+ (void) duk_buffer_to_string(thr, -1); /* Safe, output is encoded. */
+ /* invalidates h_buf pointer */
+ duk_remove_m2(thr);
}
-#ifdef DUK_USE_REGEXP_SUPPORT
+#if defined(DUK_USE_REGEXP_SUPPORT)
/*
* Canonicalize() abstract operation needed for canonicalization of individual
@@ -11124,7 +12721,7 @@ DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10] = {
* Misc util stuff
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Lowercase digits for radix values 2 to 36. Also doubles as lowercase
@@ -11342,90 +12939,195 @@ DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len) {
}
}
#endif
-#line 1 "duk_util_hashprime.c"
+
/*
- * Round a number upwards to a prime (not usually the nearest one).
- *
- * Uses a table of successive 32-bit primes whose ratio is roughly
- * constant. This keeps the relative upwards 'rounding error' bounded
- * and the data size small. A simple 'predict-correct' compression is
- * used to compress primes to one byte per prime. See genhashsizes.py
- * for details.
- *
- * The minimum prime returned here must be coordinated with the possible
- * probe sequence steps in duk_hobject and duk_heap stringtable.
+ * Miscellaneous coercion / clamping helpers.
*/
-/* include removed: duk_internal.h */
-
-/* Awkward inclusion condition: drop out of compilation if not needed by any
- * call site: object hash part or probing stringtable.
+/* Check whether a duk_double_t is a whole number in the 32-bit range (reject
+ * negative zero), and if so, return a duk_int32_t.
+ * For compiler use: don't allow negative zero as it will cause trouble with
+ * LDINT+LDINTX, positive zero is OK.
*/
-#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE)
+DUK_INTERNAL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival) {
+ duk_int32_t t;
-/* hash size ratio goal, must match genhashsizes.py */
-#define DUK__HASH_SIZE_RATIO 1177 /* floor(1.15 * (1 << 10)) */
-
-/* prediction corrections for prime list (see genhashsizes.py) */
-DUK_LOCAL const duk_int8_t duk__hash_size_corrections[] = {
- 17, /* minimum prime */
- 4, 3, 4, 1, 4, 1, 1, 2, 2, 2, 2, 1, 6, 6, 9, 5, 1, 2, 2, 5, 1, 3, 3, 3,
- 5, 4, 4, 2, 4, 8, 3, 4, 23, 2, 4, 7, 8, 11, 2, 12, 15, 10, 1, 1, 5, 1, 5,
- 8, 9, 17, 14, 10, 7, 5, 2, 46, 21, 1, 9, 9, 4, 4, 10, 23, 36, 6, 20, 29,
- 18, 6, 19, 21, 16, 11, 5, 5, 48, 9, 1, 39, 14, 8, 4, 29, 9, 1, 15, 48, 12,
- 22, 6, 15, 27, 4, 2, 17, 28, 8, 9, 4, 5, 8, 3, 3, 8, 37, 11, 15, 8, 30,
- 43, 6, 33, 41, 5, 20, 32, 41, 38, 24, 77, 14, 19, 11, 4, 35, 18, 19, 41,
- 10, 23, 16, 9, 2,
- -1
-};
-
-/* probe steps (see genhashsizes.py), currently assumed to be 32 entries long
- * (DUK_UTIL_GET_HASH_PROBE_STEP macro).
- */
-DUK_INTERNAL duk_uint8_t duk_util_probe_steps[32] = {
- 2, 3, 5, 7, 11, 13, 19, 31, 41, 47, 59, 67, 73, 79, 89, 101, 103, 107,
- 109, 127, 137, 139, 149, 157, 163, 167, 173, 181, 191, 193, 197, 199
-};
-
-DUK_INTERNAL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size) {
- const duk_int8_t *p = duk__hash_size_corrections;
- duk_uint32_t curr;
-
- curr = (duk_uint32_t) *p++;
- for (;;) {
- duk_small_int_t t = (duk_small_int_t) *p++;
- if (t < 0) {
- /* may happen if size is very close to 2^32-1 */
- break;
- }
-
- /* prediction: portable variant using doubles if 64-bit values not available */
-#ifdef DUK_USE_64BIT_OPS
- curr = (duk_uint32_t) ((((duk_uint64_t) curr) * ((duk_uint64_t) DUK__HASH_SIZE_RATIO)) >> 10);
-#else
- /* 32-bit x 11-bit = 43-bit, fits accurately into a double */
- curr = (duk_uint32_t) DUK_FLOOR(((double) curr) * ((double) DUK__HASH_SIZE_RATIO) / 1024.0);
-#endif
-
- /* correction */
- curr += t;
-
- DUK_DDD(DUK_DDDPRINT("size=%ld, curr=%ld", (long) size, (long) curr));
-
- if (curr >= size) {
- return curr;
+ t = (duk_int32_t) x;
+ if (!((duk_double_t) t == x)) {
+ return 0;
+ }
+ if (t == 0) {
+ duk_double_union du;
+ du.d = x;
+ if (DUK_DBLUNION_HAS_SIGNBIT(&du)) {
+ return 0;
}
}
+ *ival = t;
+ return 1;
+}
+
+/* Check whether a duk_double_t is a whole number in the 32-bit range, and if
+ * so, return a duk_int32_t.
+ */
+DUK_INTERNAL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival) {
+ duk_int32_t t;
+
+ t = (duk_int32_t) x;
+ if (!((duk_double_t) t == x)) {
+ return 0;
+ }
+ *ival = t;
+ return 1;
+}
+
+/*
+ * IEEE double checks
+ */
+
+DUK_INTERNAL duk_bool_t duk_double_is_anyinf(duk_double_t x) {
+ duk_double_union du;
+ du.d = x;
+ return DUK_DBLUNION_IS_ANYINF(&du);
+}
+
+DUK_INTERNAL duk_bool_t duk_double_is_posinf(duk_double_t x) {
+ duk_double_union du;
+ du.d = x;
+ return DUK_DBLUNION_IS_POSINF(&du);
+}
+
+DUK_INTERNAL duk_bool_t duk_double_is_neginf(duk_double_t x) {
+ duk_double_union du;
+ du.d = x;
+ return DUK_DBLUNION_IS_NEGINF(&du);
+}
+
+DUK_INTERNAL duk_bool_t duk_double_is_nan(duk_double_t x) {
+ duk_double_union du;
+ du.d = x;
+ /* Assumes we're dealing with a Duktape internal NaN which is
+ * NaN normalized if duk_tval requires it.
+ */
+ DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
+ return DUK_DBLUNION_IS_NAN(&du);
+}
+
+DUK_INTERNAL duk_bool_t duk_double_is_nan_or_zero(duk_double_t x) {
+ duk_double_union du;
+ du.d = x;
+ /* Assumes we're dealing with a Duktape internal NaN which is
+ * NaN normalized if duk_tval requires it.
+ */
+ DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
+ return DUK_DBLUNION_IS_NAN(&du) || DUK_DBLUNION_IS_ANYZERO(&du);
+}
+
+DUK_INTERNAL duk_bool_t duk_double_is_nan_or_inf(duk_double_t x) {
+ duk_double_union du;
+ du.d = x;
+ /* If exponent is 0x7FF the argument is either a NaN or an
+ * infinity. We don't need to check any other fields.
+ */
+#if defined(DUK_USE_64BIT_OPS)
+#if defined(DUK_USE_DOUBLE_ME)
+ return (du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000)) == DUK_U64_CONSTANT(0x000000007ff00000);
+#else
+ return (du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000)) == DUK_U64_CONSTANT(0x7ff0000000000000);
+#endif
+#else
+ return (du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL;
+#endif
+}
+
+DUK_INTERNAL duk_bool_t duk_double_is_nan_zero_inf(duk_double_t x) {
+ duk_double_union du;
+#if defined(DUK_USE_64BIT_OPS)
+ duk_uint64_t t;
+#else
+ duk_uint32_t t;
+#endif
+ du.d = x;
+#if defined(DUK_USE_64BIT_OPS)
+#if defined(DUK_USE_DOUBLE_ME)
+ t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000);
+ if (t == DUK_U64_CONSTANT(0x0000000000000000)) {
+ t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x0000000080000000);
+ return t == 0;
+ }
+ if (t == DUK_U64_CONSTANT(0x000000007ff00000)) {
+ return 1;
+ }
+#else
+ t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000);
+ if (t == DUK_U64_CONSTANT(0x0000000000000000)) {
+ t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x8000000000000000);
+ return t == 0;
+ }
+ if (t == DUK_U64_CONSTANT(0x7ff0000000000000)) {
+ return 1;
+ }
+#endif
+#else
+ t = du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL;
+ if (t == 0x00000000UL) {
+ return DUK_DBLUNION_IS_ANYZERO(&du);
+ }
+ if (t == 0x7ff00000UL) {
+ return 1;
+ }
+#endif
return 0;
}
-#endif /* DUK_USE_HOBJECT_HASH_PART || DUK_USE_STRTAB_PROBE */
+DUK_INTERNAL duk_small_uint_t duk_double_signbit(duk_double_t x) {
+ duk_double_union du;
+ du.d = x;
+ return (duk_small_uint_t) DUK_DBLUNION_GET_SIGNBIT(&du);
+}
+
+DUK_INTERNAL duk_double_t duk_double_trunc_towards_zero(duk_double_t x) {
+ /* XXX: optimize */
+ duk_small_uint_t s = duk_double_signbit(x);
+ x = DUK_FLOOR(DUK_FABS(x)); /* truncate towards zero */
+ if (s) {
+ x = -x;
+ }
+ return x;
+}
+
+DUK_INTERNAL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y) {
+ duk_double_union du1;
+ duk_double_union du2;
+ du1.d = x;
+ du2.d = y;
+
+ return (((du1.ui[DUK_DBL_IDX_UI0] ^ du2.ui[DUK_DBL_IDX_UI0]) & 0x80000000UL) == 0);
+}
+
+DUK_INTERNAL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y) {
+ /* Doesn't replicate fmin() behavior exactly: for fmin() if one
+ * argument is a NaN, the other argument should be returned.
+ * Duktape doesn't rely on this behavior so the replacement can
+ * be simplified.
+ */
+ return (x < y ? x : y);
+}
+
+DUK_INTERNAL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y) {
+ /* Doesn't replicate fmax() behavior exactly: for fmax() if one
+ * argument is a NaN, the other argument should be returned.
+ * Duktape doesn't rely on this behavior so the replacement can
+ * be simplified.
+ */
+ return (x > y ? x : y);
+}
#line 1 "duk_hobject_class.c"
/*
* Hobject Ecmascript [[Class]].
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
#if (DUK_STRIDX_UC_ARGUMENTS > 255)
#error constant too large
@@ -11472,9 +13174,6 @@ DUK_INTERNAL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size) {
#if (DUK_STRIDX_DEC_ENV > 255)
#error constant too large
#endif
-#if (DUK_STRIDX_UC_BUFFER > 255)
-#error constant too large
-#endif
#if (DUK_STRIDX_UC_POINTER > 255)
#error constant too large
#endif
@@ -11520,23 +13219,23 @@ DUK_INTERNAL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size) {
/* Note: assumes that these string indexes are 8-bit, genstrings.py must ensure that */
DUK_INTERNAL duk_uint8_t duk_class_number_to_stridx[32] = {
- DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */
- DUK_STRIDX_UC_ARGUMENTS,
+ DUK_STRIDX_EMPTY_STRING, /* NONE, intentionally empty */
+ DUK_STRIDX_UC_OBJECT,
DUK_STRIDX_ARRAY,
+ DUK_STRIDX_UC_FUNCTION,
+ DUK_STRIDX_UC_ARGUMENTS,
DUK_STRIDX_UC_BOOLEAN,
DUK_STRIDX_DATE,
DUK_STRIDX_UC_ERROR,
- DUK_STRIDX_UC_FUNCTION,
DUK_STRIDX_JSON,
DUK_STRIDX_MATH,
DUK_STRIDX_UC_NUMBER,
- DUK_STRIDX_UC_OBJECT,
DUK_STRIDX_REG_EXP,
DUK_STRIDX_UC_STRING,
DUK_STRIDX_GLOBAL,
+ DUK_STRIDX_UC_SYMBOL,
DUK_STRIDX_OBJ_ENV,
DUK_STRIDX_DEC_ENV,
- DUK_STRIDX_UC_BUFFER,
DUK_STRIDX_UC_POINTER,
DUK_STRIDX_UC_THREAD,
DUK_STRIDX_ARRAY_BUFFER,
@@ -11561,7 +13260,7 @@ DUK_INTERNAL duk_uint8_t duk_class_number_to_stridx[32] = {
* a NULL or a unique pointer which is a no-op for free.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
DUK_INTERNAL void *duk_default_alloc_function(void *udata, duk_size_t size) {
@@ -11593,15 +13292,14 @@ DUK_INTERNAL void duk_default_free_function(void *udata, void *ptr) {
* Buffer
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-DUK_EXTERNAL void *duk_resize_buffer(duk_context *ctx, duk_idx_t index, duk_size_t new_size) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void *duk_resize_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t new_size) {
duk_hbuffer_dynamic *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, index);
+ h = (duk_hbuffer_dynamic *) duk_require_hbuffer(thr, idx);
DUK_ASSERT(h != NULL);
if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) {
@@ -11614,15 +13312,14 @@ DUK_EXTERNAL void *duk_resize_buffer(duk_context *ctx, duk_idx_t index, duk_size
return DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h);
}
-DUK_EXTERNAL void *duk_steal_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void *duk_steal_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
duk_hbuffer_dynamic *h;
void *ptr;
duk_size_t sz;
- DUK_ASSERT(ctx != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
- h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, index);
+ h = (duk_hbuffer_dynamic *) duk_require_hbuffer(thr, idx);
DUK_ASSERT(h != NULL);
if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) {
@@ -11645,13 +13342,12 @@ DUK_EXTERNAL void *duk_steal_buffer(duk_context *ctx, duk_idx_t index, duk_size_
return ptr;
}
-DUK_EXTERNAL void duk_config_buffer(duk_context *ctx, duk_idx_t index, void *ptr, duk_size_t len) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_config_buffer(duk_hthread *thr, duk_idx_t idx, void *ptr, duk_size_t len) {
duk_hbuffer_external *h;
- DUK_ASSERT(ctx != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
- h = (duk_hbuffer_external *) duk_require_hbuffer(ctx, index);
+ h = (duk_hbuffer_external *) duk_require_hbuffer(thr, idx);
DUK_ASSERT(h != NULL);
if (!DUK_HBUFFER_HAS_EXTERNAL(h)) {
@@ -11675,35 +13371,35 @@ DUK_EXTERNAL void duk_config_buffer(duk_context *ctx, duk_idx_t index, void *ptr
* validated which is not easy to do with indirect register references etc.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
#if defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
-#define DUK__SER_MARKER 0xff
-#define DUK__SER_VERSION 0x00
+#define DUK__SER_MARKER 0xbf
#define DUK__SER_STRING 0x00
#define DUK__SER_NUMBER 0x01
#define DUK__BYTECODE_INITIAL_ALLOC 256
+#define DUK__NO_FORMALS 0xffffffffUL
/*
* Dump/load helpers, xxx_raw() helpers do no buffer checks
*/
-DUK_LOCAL duk_uint8_t *duk__load_string_raw(duk_context *ctx, duk_uint8_t *p) {
+DUK_LOCAL duk_uint8_t *duk__load_string_raw(duk_hthread *thr, duk_uint8_t *p) {
duk_uint32_t len;
len = DUK_RAW_READ_U32_BE(p);
- duk_push_lstring(ctx, (const char *) p, len);
+ duk_push_lstring(thr, (const char *) p, len);
p += len;
return p;
}
-DUK_LOCAL duk_uint8_t *duk__load_buffer_raw(duk_context *ctx, duk_uint8_t *p) {
+DUK_LOCAL duk_uint8_t *duk__load_buffer_raw(duk_hthread *thr, duk_uint8_t *p) {
duk_uint32_t len;
duk_uint8_t *buf;
len = DUK_RAW_READ_U32_BE(p);
- buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len);
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) len);
DUK_ASSERT(buf != NULL);
DUK_MEMCPY((void *) buf, (const void *) p, (size_t) len);
p += len;
@@ -11759,7 +13455,7 @@ DUK_LOCAL duk_uint8_t *duk__dump_string_prop(duk_hthread *thr, duk_uint8_t *p, d
DUK_ASSERT(h_str != NULL);
}
DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(h_str), p);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(h_str), p);
p = duk__dump_hstring_raw(p, h_str);
return p;
}
@@ -11773,10 +13469,10 @@ DUK_LOCAL duk_uint8_t *duk__dump_buffer_prop(duk_hthread *thr, duk_uint8_t *p, d
h_buf = DUK_TVAL_GET_BUFFER(tv);
DUK_ASSERT(h_buf != NULL);
DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HBUFFER_GET_SIZE(h_buf), p);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HBUFFER_GET_SIZE(h_buf), p);
p = duk__dump_hbuffer_raw(thr, p, h_buf);
} else {
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
DUK_RAW_WRITE_U32_BE(p, 0);
}
return p;
@@ -11792,7 +13488,7 @@ DUK_LOCAL duk_uint8_t *duk__dump_uint32_prop(duk_hthread *thr, duk_uint8_t *p, d
} else {
val = def_value;
}
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
DUK_RAW_WRITE_U32_BE(p, val);
return p;
}
@@ -11833,12 +13529,12 @@ DUK_LOCAL duk_uint8_t *duk__dump_varmap(duk_hthread *thr, duk_uint8_t *p, duk_bu
#endif
DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(key) + 4, p);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(key) + 4U, p);
p = duk__dump_hstring_raw(p, key);
DUK_RAW_WRITE_U32_BE(p, val);
}
}
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Varmap */
return p;
}
@@ -11848,42 +13544,48 @@ DUK_LOCAL duk_uint8_t *duk__dump_formals(duk_hthread *thr, duk_uint8_t *p, duk_b
tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_FORMALS(thr));
if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) {
- duk_hobject *h;
- duk_uint_fast32_t i;
+ duk_harray *h;
+ duk_uint32_t i;
- h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
-
- /* We know _Formals is dense and all entries will be in the
- * array part. GC and finalizers shouldn't affect _Formals
- * so side effects should be fine.
+ /* Here we rely on _Formals being a dense array containing
+ * strings. This should be the case unless _Formals has been
+ * tweaked by the application (which we don't support right
+ * now).
*/
- for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
+ h = (duk_harray *) DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_ARRAY((duk_hobject *) h));
+ DUK_ASSERT(h->length <= DUK_HOBJECT_GET_ASIZE((duk_hobject *) h));
+
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
+ DUK_ASSERT(h->length != DUK__NO_FORMALS); /* limits */
+ DUK_RAW_WRITE_U32_BE(p, h->length);
+
+ for (i = 0; i < h->length; i++) {
duk_tval *tv_val;
duk_hstring *varname;
- tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, h, i);
+ tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, (duk_hobject *) h, i);
DUK_ASSERT(tv_val != NULL);
- if (DUK_TVAL_IS_STRING(tv_val)) {
- /* Array is dense and contains only strings, but ASIZE may
- * be larger than used part and there are UNUSED entries.
- */
- varname = DUK_TVAL_GET_STRING(tv_val);
- DUK_ASSERT(varname != NULL);
+ DUK_ASSERT(DUK_TVAL_IS_STRING(tv_val));
- DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(varname), p);
- p = duk__dump_hstring_raw(p, varname);
- }
+ varname = DUK_TVAL_GET_STRING(tv_val);
+ DUK_ASSERT(varname != NULL);
+ DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(varname) >= 1);
+
+ DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(varname), p);
+ p = duk__dump_hstring_raw(p, varname);
}
+ } else {
+ DUK_DD(DUK_DDPRINT("dumping function without _Formals, emit marker to indicate missing _Formals"));
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
+ DUK_RAW_WRITE_U32_BE(p, DUK__NO_FORMALS); /* marker: no formals */
}
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
- DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Formals */
return p;
}
-static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func, duk_bufwriter_ctx *bw_ctx, duk_uint8_t *p) {
- duk_hthread *thr;
+static duk_uint8_t *duk__dump_func(duk_hthread *thr, duk_hcompfunc *func, duk_bufwriter_ctx *bw_ctx, duk_uint8_t *p) {
duk_tval *tv, *tv_end;
duk_instr_t *ins, *ins_end;
duk_hobject **fn, **fn_end;
@@ -11893,39 +13595,35 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func
duk_uint16_t tmp16;
duk_double_t d;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(ctx);
- DUK_UNREF(thr);
-
DUK_DD(DUK_DDPRINT("dumping function %p to %p: "
"consts=[%p,%p[ (%ld bytes, %ld items), "
"funcs=[%p,%p[ (%ld bytes, %ld items), "
"code=[%p,%p[ (%ld bytes, %ld items)",
(void *) func,
(void *) p,
- (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, func),
- (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, func),
- (long) DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE(thr->heap, func),
- (long) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(thr->heap, func),
- (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, func),
- (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, func),
- (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE(thr->heap, func),
- (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, func),
- (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, func),
- (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, func),
- (long) DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(thr->heap, func),
- (long) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(thr->heap, func)));
+ (void *) DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, func),
+ (void *) DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, func),
+ (long) DUK_HCOMPFUNC_GET_CONSTS_SIZE(thr->heap, func),
+ (long) DUK_HCOMPFUNC_GET_CONSTS_COUNT(thr->heap, func),
+ (void *) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, func),
+ (void *) DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, func),
+ (long) DUK_HCOMPFUNC_GET_FUNCS_SIZE(thr->heap, func),
+ (long) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, func),
+ (void *) DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, func),
+ (void *) DUK_HCOMPFUNC_GET_CODE_END(thr->heap, func),
+ (long) DUK_HCOMPFUNC_GET_CODE_SIZE(thr->heap, func),
+ (long) DUK_HCOMPFUNC_GET_CODE_COUNT(thr->heap, func)));
DUK_ASSERT(DUK_USE_ESBC_MAX_BYTES <= 0x7fffffffUL); /* ensures no overflow */
- count_instr = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(thr->heap, func);
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 3 * 4 + 2 * 2 + 3 * 4 + count_instr * 4, p);
+ count_instr = (duk_uint32_t) DUK_HCOMPFUNC_GET_CODE_COUNT(thr->heap, func);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 3U * 4U + 2U * 2U + 3U * 4U + count_instr * 4U, p);
/* Fixed header info. */
tmp32 = count_instr;
DUK_RAW_WRITE_U32_BE(p, tmp32);
- tmp32 = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(thr->heap, func);
+ tmp32 = (duk_uint32_t) DUK_HCOMPFUNC_GET_CONSTS_COUNT(thr->heap, func);
DUK_RAW_WRITE_U32_BE(p, tmp32);
- tmp32 = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, func);
+ tmp32 = (duk_uint32_t) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, func);
DUK_RAW_WRITE_U32_BE(p, tmp32);
tmp16 = func->nregs;
DUK_RAW_WRITE_U16_BE(p, tmp16);
@@ -11940,14 +13638,15 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func
DUK_RAW_WRITE_U32_BE(p, 0);
DUK_RAW_WRITE_U32_BE(p, 0);
#endif
- tmp32 = ((duk_heaphdr *) func)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK;
+ tmp32 = DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) func); /* masks flags, only duk_hobject flags */
+ tmp32 &= ~(DUK_HOBJECT_FLAG_HAVE_FINALIZER); /* finalizer flag is lost */
DUK_RAW_WRITE_U32_BE(p, tmp32);
/* Bytecode instructions: endian conversion needed unless
* platform is big endian.
*/
- ins = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, func);
- ins_end = DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, func);
+ ins = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, func);
+ ins_end = DUK_HCOMPFUNC_GET_CODE_END(thr->heap, func);
DUK_ASSERT((duk_size_t) (ins_end - ins) == (duk_size_t) count_instr);
#if defined(DUK_USE_INTEGER_BE)
DUK_MEMCPY((void *) p, (const void *) ins, (size_t) (ins_end - ins));
@@ -11961,8 +13660,8 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func
#endif
/* Constants: variable size encoding. */
- tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, func);
- tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, func);
+ tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, func);
+ tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, func);
while (tv != tv_end) {
/* constants are strings or numbers now */
DUK_ASSERT(DUK_TVAL_IS_STRING(tv) ||
@@ -11972,12 +13671,12 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func
h_str = DUK_TVAL_GET_STRING(tv);
DUK_ASSERT(h_str != NULL);
DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1 + 4 + DUK_HSTRING_GET_BYTELEN(h_str), p),
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1U + 4U + DUK_HSTRING_GET_BYTELEN(h_str), p),
*p++ = DUK__SER_STRING;
p = duk__dump_hstring_raw(p, h_str);
} else {
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1 + 8, p);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1U + 8U, p);
*p++ = DUK__SER_NUMBER;
d = DUK_TVAL_GET_NUMBER(tv);
DUK_RAW_WRITE_DOUBLE_BE(p, d);
@@ -11986,8 +13685,8 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func
}
/* Inner functions recursively. */
- fn = (duk_hobject **) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, func);
- fn_end = (duk_hobject **) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, func);
+ fn = (duk_hobject **) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, func);
+ fn_end = (duk_hobject **) DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, func);
while (fn != fn_end) {
/* XXX: This causes recursion up to inner function depth
* which is normally not an issue, e.g. mark-and-sweep uses
@@ -11995,11 +13694,13 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func
* this would mean some sort of a work list or just refusing
* to serialize deep functions.
*/
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(*fn));
- p = duk__dump_func(ctx, (duk_hcompiledfunction *) *fn, bw_ctx, p);
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(*fn));
+ p = duk__dump_func(thr, (duk_hcompfunc *) *fn, bw_ctx, p);
fn++;
}
+ /* Lexenv and varenv are not dumped. */
+
/* Object extra properties.
*
* There are some difference between function templates and functions.
@@ -12008,9 +13709,15 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func
*/
p = duk__dump_uint32_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_LENGTH, (duk_uint32_t) func->nargs);
+#if defined(DUK_USE_FUNC_NAME_PROPERTY)
p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_NAME);
+#endif
+#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_FILE_NAME);
+#endif
+#if defined(DUK_USE_PC2LINE)
p = duk__dump_buffer_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_INT_PC2LINE);
+#endif
p = duk__dump_varmap(thr, p, bw_ctx, (duk_hobject *) func);
p = duk__dump_formals(thr, p, bw_ctx, (duk_hobject *) func);
@@ -12033,9 +13740,8 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func
DUK_ASSERT((duk_size_t) (p_end - p) >= (duk_size_t) (n)); \
} while (0)
-static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t *p_end) {
- duk_hthread *thr;
- duk_hcompiledfunction *h_fun;
+static duk_uint8_t *duk__load_func(duk_hthread *thr, duk_uint8_t *p, duk_uint8_t *p_end) {
+ duk_hcompfunc *h_fun;
duk_hbuffer *h_data;
duk_size_t data_size;
duk_uint32_t count_instr, count_const, count_funcs;
@@ -12047,14 +13753,16 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
duk_idx_t idx_base;
duk_tval *tv1;
duk_uarridx_t arr_idx;
+ duk_uarridx_t arr_limit;
+ duk_hobject *func_env;
+ duk_bool_t need_pop;
/* XXX: There's some overlap with duk_js_closure() here, but
* seems difficult to share code. Ensure that the final function
* looks the same as created by duk_js_closure().
*/
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT(thr != NULL);
DUK_DD(DUK_DDPRINT("loading function, p=%p, p_end=%p", (void *) p, (void *) p_end));
@@ -12075,19 +13783,19 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
* inner functions being loaded. Require enough space to handle
* large functions correctly.
*/
- duk_require_stack(ctx, 2 + count_const + count_funcs);
- idx_base = duk_get_top(ctx);
+ duk_require_stack(thr, (duk_idx_t) (2 + count_const + count_funcs));
+ idx_base = duk_get_top(thr);
/* Push function object, init flags etc. This must match
* duk_js_push_closure() quite carefully.
*/
- duk_push_compiledfunction(ctx);
- h_fun = duk_get_hcompiledfunction(ctx, -1);
+ h_fun = duk_push_hcompfunc(thr);
DUK_ASSERT(h_fun != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) h_fun));
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, h_fun) == NULL);
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, h_fun) == NULL);
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, h_fun) == NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) h_fun));
+ DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, h_fun) == NULL);
+ DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, h_fun) == NULL);
+ DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, h_fun) == NULL);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_fun) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
h_fun->nregs = DUK_RAW_READ_U16_BE(p);
h_fun->nargs = DUK_RAW_READ_U16_BE(p);
@@ -12098,25 +13806,28 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
p += 8; /* skip line info */
#endif
- /* duk_hcompiledfunction flags; quite version specific */
+ /* duk_hcompfunc flags; quite version specific */
tmp32 = DUK_RAW_READ_U32_BE(p);
- DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) h_fun, tmp32);
+ DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) h_fun, tmp32); /* masks flags to only change duk_hobject flags */
- /* standard prototype */
+ /* standard prototype (no need to set here, already set) */
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_fun) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
+#if 0
DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &h_fun->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
+#endif
/* assert just a few critical flags */
DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h_fun) == DUK_HTYPE_OBJECT);
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&h_fun->obj));
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(&h_fun->obj));
- DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(&h_fun->obj));
- DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(&h_fun->obj));
+ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&h_fun->obj));
+ DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(&h_fun->obj));
+ DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(&h_fun->obj));
+ DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(&h_fun->obj));
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&h_fun->obj));
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&h_fun->obj));
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&h_fun->obj));
/* Create function 'data' buffer but don't attach it yet. */
- fun_data = (duk_uint8_t *) duk_push_fixed_buffer(ctx, data_size);
+ fun_data = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, data_size);
DUK_ASSERT(fun_data != NULL);
/* Load bytecode instructions. */
@@ -12142,7 +13853,7 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
const_type = DUK_RAW_READ_U8(p);
switch (const_type) {
case DUK__SER_STRING: {
- p = duk__load_string_raw(ctx, p);
+ p = duk__load_string_raw(thr, p);
break;
}
case DUK__SER_NUMBER: {
@@ -12153,8 +13864,8 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
duk_double_t val;
DUK__ASSERT_LEFT(8);
val = DUK_RAW_READ_DOUBLE_BE(p);
- DUK_TVAL_SET_NUMBER_CHKFAST(&tv_tmp, val);
- duk_push_tval(ctx, &tv_tmp);
+ DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(&tv_tmp, val);
+ duk_push_tval(thr, &tv_tmp);
break;
}
default: {
@@ -12165,7 +13876,7 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
/* Load inner functions to value stack, but don't yet copy to buffer. */
for (n = count_funcs; n > 0; n--) {
- p = duk__load_func(ctx, p, p_end);
+ p = duk__load_func(thr, p, p_end);
if (p == NULL) {
goto format_error;
}
@@ -12180,13 +13891,12 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
* them afterwards.
*/
- h_data = (duk_hbuffer *) duk_get_hbuffer(ctx, idx_base + 1);
- DUK_ASSERT(h_data != NULL);
+ h_data = (duk_hbuffer *) duk_known_hbuffer(thr, idx_base + 1);
DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC(h_data));
- DUK_HCOMPILEDFUNCTION_SET_DATA(thr->heap, h_fun, h_data);
+ DUK_HCOMPFUNC_SET_DATA(thr->heap, h_fun, h_data);
DUK_HBUFFER_INCREF(thr, h_data);
- tv1 = duk_get_tval(ctx, idx_base + 2); /* may be NULL if no constants or inner funcs */
+ tv1 = duk_get_tval(thr, idx_base + 2); /* may be NULL if no constants or inner funcs */
DUK_ASSERT((count_const == 0 && count_funcs == 0) || tv1 != NULL);
q = fun_data;
@@ -12200,7 +13910,7 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
tv1 += count_const;
}
- DUK_HCOMPILEDFUNCTION_SET_FUNCS(thr->heap, h_fun, (duk_hobject **) (void *) q);
+ DUK_HCOMPFUNC_SET_FUNCS(thr->heap, h_fun, (duk_hobject **) (void *) q);
for (n = count_funcs; n > 0; n--) {
duk_hobject *h_obj;
@@ -12214,108 +13924,140 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
q += sizeof(duk_hobject *);
}
- DUK_HCOMPILEDFUNCTION_SET_BYTECODE(thr->heap, h_fun, (duk_instr_t *) (void *) q);
+ DUK_HCOMPFUNC_SET_BYTECODE(thr->heap, h_fun, (duk_instr_t *) (void *) q);
/* The function object is now reachable and refcounts are fine,
* so we can pop off all the temporaries.
*/
- DUK_DDD(DUK_DDDPRINT("function is reachable, reset top; func: %!iT", duk_get_tval(ctx, idx_base)));
- duk_set_top(ctx, idx_base + 1);
+ DUK_DDD(DUK_DDDPRINT("function is reachable, reset top; func: %!iT", duk_get_tval(thr, idx_base)));
+ duk_set_top(thr, idx_base + 1);
/* Setup function properties. */
tmp32 = DUK_RAW_READ_U32_BE(p);
- duk_push_u32(ctx, tmp32);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
+ duk_push_u32(thr, tmp32);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);
- p = duk__load_string_raw(ctx, p);
+#if defined(DUK_USE_FUNC_NAME_PROPERTY)
+ p = duk__load_string_raw(thr, p); /* -> [ func funcname ] */
+ func_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
+ DUK_ASSERT(func_env != NULL);
+ need_pop = 0;
if (DUK_HOBJECT_HAS_NAMEBINDING((duk_hobject *) h_fun)) {
/* Original function instance/template had NAMEBINDING.
* Must create a lexical environment on loading to allow
* recursive functions like 'function foo() { foo(); }'.
*/
- duk_hobject *proto;
+ duk_hdecenv *new_env;
- proto = thr->builtins[DUK_BIDX_GLOBAL_ENV];
- (void) duk_push_object_helper_proto(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
- proto);
- duk_dup(ctx, -2); /* -> [ func funcname env funcname ] */
- duk_dup(ctx, idx_base); /* -> [ func funcname env funcname func ] */
- duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ func funcname env ] */
- duk_xdef_prop_stridx(ctx, idx_base, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC);
- /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it
- * will be ignored anyway
- */
+ new_env = duk_hdecenv_alloc(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
+ DUK_ASSERT(new_env != NULL);
+ DUK_ASSERT(new_env->thread == NULL); /* Closed. */
+ DUK_ASSERT(new_env->varmap == NULL);
+ DUK_ASSERT(new_env->regbase_byteoff == 0);
+ DUK_ASSERT_HDECENV_VALID(new_env);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL);
+ DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, func_env);
+ DUK_HOBJECT_INCREF(thr, func_env);
+
+ func_env = (duk_hobject *) new_env;
+
+ duk_push_hobject(thr, (duk_hobject *) new_env);
+
+ duk_dup_m2(thr); /* -> [ func funcname env funcname ] */
+ duk_dup(thr, idx_base); /* -> [ func funcname env funcname func ] */
+ duk_xdef_prop(thr, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ func funcname env ] */
+
+ need_pop = 1; /* Need to pop env, but -after- updating h_fun and increfs. */
}
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
+ DUK_ASSERT(func_env != NULL);
+ DUK_HCOMPFUNC_SET_LEXENV(thr->heap, h_fun, func_env);
+ DUK_HCOMPFUNC_SET_VARENV(thr->heap, h_fun, func_env);
+ DUK_HOBJECT_INCREF(thr, func_env);
+ DUK_HOBJECT_INCREF(thr, func_env);
+ if (need_pop) {
+ duk_pop(thr);
+ }
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
+#endif /* DUK_USE_FUNC_NAME_PROPERTY */
- p = duk__load_string_raw(ctx, p);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC);
+#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
+ p = duk__load_string_raw(thr, p);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C);
+#endif /* DUK_USE_FUNC_FILENAME_PROPERTY */
- duk_push_object(ctx);
- duk_dup(ctx, -2);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* func.prototype.constructor = func */
- duk_compact(ctx, -1);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W);
+ if (DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_fun)) {
+ /* Restore empty external .prototype only for constructable
+ * functions.
+ */
+ duk_push_object(thr);
+ duk_dup_m2(thr);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* func.prototype.constructor = func */
+ duk_compact_m1(thr);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W);
+ }
- p = duk__load_buffer_raw(ctx, p);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_WC);
+#if defined(DUK_USE_PC2LINE)
+ p = duk__load_buffer_raw(thr, p);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_WC);
+#endif /* DUK_USE_PC2LINE */
- duk_push_object(ctx); /* _Varmap */
+ duk_push_object(thr); /* _Varmap */
for (;;) {
/* XXX: awkward */
- p = duk__load_string_raw(ctx, p);
- if (duk_get_length(ctx, -1) == 0) {
- duk_pop(ctx);
+ p = duk__load_string_raw(thr, p);
+ if (duk_get_length(thr, -1) == 0) {
+ duk_pop(thr);
break;
}
tmp32 = DUK_RAW_READ_U32_BE(p);
- duk_push_u32(ctx, tmp32);
- duk_put_prop(ctx, -3);
+ duk_push_u32(thr, tmp32);
+ duk_put_prop(thr, -3);
}
- duk_compact(ctx, -1);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
+ duk_compact_m1(thr);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
- duk_push_array(ctx); /* _Formals */
- for (arr_idx = 0; ; arr_idx++) {
- /* XXX: awkward */
- p = duk__load_string_raw(ctx, p);
- if (duk_get_length(ctx, -1) == 0) {
- duk_pop(ctx);
- break;
+ /* _Formals may have been missing in the original function, which is
+ * handled using a marker length.
+ */
+ arr_limit = DUK_RAW_READ_U32_BE(p);
+ if (arr_limit != DUK__NO_FORMALS) {
+ duk_push_array(thr); /* _Formals */
+ for (arr_idx = 0; arr_idx < arr_limit; arr_idx++) {
+ p = duk__load_string_raw(thr, p);
+ duk_put_prop_index(thr, -2, arr_idx);
}
- duk_put_prop_index(ctx, -2, arr_idx);
+ duk_compact_m1(thr);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
+ } else {
+ DUK_DD(DUK_DDPRINT("no _Formals in dumped function"));
}
- duk_compact(ctx, -1);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
/* Return with final function pushed on stack top. */
- DUK_DD(DUK_DDPRINT("final loaded function: %!iT", duk_get_tval(ctx, -1)));
- DUK_ASSERT_TOP(ctx, idx_base + 1);
+ DUK_DD(DUK_DDPRINT("final loaded function: %!iT", duk_get_tval(thr, -1)));
+ DUK_ASSERT_TOP(thr, idx_base + 1);
return p;
format_error:
return NULL;
}
-DUK_EXTERNAL void duk_dump_function(duk_context *ctx) {
- duk_hthread *thr;
- duk_hcompiledfunction *func;
+DUK_EXTERNAL void duk_dump_function(duk_hthread *thr) {
+ duk_hcompfunc *func;
duk_bufwriter_ctx bw_ctx_alloc;
duk_bufwriter_ctx *bw_ctx = &bw_ctx_alloc;
duk_uint8_t *p;
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
/* Bound functions don't have all properties so we'd either need to
* lookup the non-bound target function or reject bound functions.
- * For now, bound functions are rejected.
+ * For now, bound functions are rejected with TypeError.
*/
- func = duk_require_hcompiledfunction(ctx, -1);
+ func = duk_require_hcompfunc(thr, -1);
DUK_ASSERT(func != NULL);
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&func->obj));
+ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&func->obj));
/* Estimating the result size beforehand would be costly, so
* start with a reasonable size and extend as needed.
@@ -12323,26 +14065,22 @@ DUK_EXTERNAL void duk_dump_function(duk_context *ctx) {
DUK_BW_INIT_PUSHBUF(thr, bw_ctx, DUK__BYTECODE_INITIAL_ALLOC);
p = DUK_BW_GET_PTR(thr, bw_ctx);
*p++ = DUK__SER_MARKER;
- *p++ = DUK__SER_VERSION;
- p = duk__dump_func(ctx, func, bw_ctx, p);
+ p = duk__dump_func(thr, func, bw_ctx, p);
DUK_BW_SET_PTR(thr, bw_ctx, p);
DUK_BW_COMPACT(thr, bw_ctx);
- DUK_DD(DUK_DDPRINT("serialized result: %!T", duk_get_tval(ctx, -1)));
+ DUK_DD(DUK_DDPRINT("serialized result: %!T", duk_get_tval(thr, -1)));
- duk_remove(ctx, -2); /* [ ... func buf ] -> [ ... buf ] */
+ duk_remove_m2(thr); /* [ ... func buf ] -> [ ... buf ] */
}
-DUK_EXTERNAL void duk_load_function(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_load_function(duk_hthread *thr) {
duk_uint8_t *p_buf, *p, *p_end;
duk_size_t sz;
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- p_buf = (duk_uint8_t *) duk_require_buffer(ctx, -1, &sz);
+ p_buf = (duk_uint8_t *) duk_require_buffer(thr, -1, &sz);
DUK_ASSERT(p_buf != NULL);
/* The caller is responsible for being sure that bytecode being loaded
@@ -12351,522 +14089,444 @@ DUK_EXTERNAL void duk_load_function(duk_context *ctx) {
* (instruction validation would be quite complex to implement).
*
* This signature check is the only sanity check for detecting
- * accidental invalid inputs. The initial 0xFF byte ensures no
- * ordinary string will be accepted by accident.
+ * accidental invalid inputs. The initial byte ensures no ordinary
+ * string or Symbol will be accepted by accident.
*/
p = p_buf;
p_end = p_buf + sz;
- if (sz < 2 || p[0] != DUK__SER_MARKER || p[1] != DUK__SER_VERSION) {
+ if (sz < 1 || p[0] != DUK__SER_MARKER) {
goto format_error;
}
- p += 2;
+ p++;
- p = duk__load_func(ctx, p, p_end);
+ p = duk__load_func(thr, p, p_end);
if (p == NULL) {
goto format_error;
}
- duk_remove(ctx, -2); /* [ ... buf func ] -> [ ... func ] */
+ duk_remove_m2(thr); /* [ ... buf func ] -> [ ... func ] */
return;
format_error:
- DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED);
+ DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BYTECODE);
}
-#undef DUK__SER_MARKER
-#undef DUK__SER_VERSION
-#undef DUK__SER_STRING
-#undef DUK__SER_NUMBER
-#undef DUK__BYTECODE_INITIAL_ALLOC
-
#else /* DUK_USE_BYTECODE_DUMP_SUPPORT */
-DUK_EXTERNAL void duk_dump_function(duk_context *ctx) {
- DUK_ERROR_UNSUPPORTED_DEFMSG((duk_hthread *) ctx);
+DUK_EXTERNAL void duk_dump_function(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ERROR_UNSUPPORTED(thr);
}
-DUK_EXTERNAL void duk_load_function(duk_context *ctx) {
- DUK_ERROR_UNSUPPORTED_DEFMSG((duk_hthread *) ctx);
+DUK_EXTERNAL void duk_load_function(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ERROR_UNSUPPORTED(thr);
}
#endif /* DUK_USE_BYTECODE_DUMP_SUPPORT */
+
+/* automatic undefs */
+#undef DUK__ASSERT_LEFT
+#undef DUK__BYTECODE_INITIAL_ALLOC
+#undef DUK__NO_FORMALS
+#undef DUK__SER_MARKER
+#undef DUK__SER_NUMBER
+#undef DUK__SER_STRING
#line 1 "duk_api_call.c"
/*
* Calls.
*
- * Protected variants should avoid ever throwing an error.
+ * Protected variants should avoid ever throwing an error. Must be careful
+ * to catch errors related to value stack manipulation and property lookup,
+ * not just the call itself.
+ *
+ * The only exception is when arguments are insane, e.g. nargs/nrets are out
+ * of bounds; in such cases an error is thrown for two reasons. First, we
+ * can't always respect the value stack input/output guarantees in such cases
+ * so the caller would end up with the value stack in an unexpected state.
+ * Second, an attempt to create an error might itself fail (although this
+ * could be avoided by pushing a preallocated object/string or a primitive
+ * value).
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
+
+/*
+ * Helpers
+ */
+
+struct duk__pcall_prop_args {
+ duk_idx_t obj_idx;
+ duk_idx_t nargs;
+ duk_small_uint_t call_flags;
+};
+typedef struct duk__pcall_prop_args duk__pcall_prop_args;
+
+struct duk__pcall_method_args {
+ duk_idx_t nargs;
+ duk_small_uint_t call_flags;
+};
+typedef struct duk__pcall_method_args duk__pcall_method_args;
+
+struct duk__pcall_args {
+ duk_idx_t nargs;
+ duk_small_uint_t call_flags;
+};
+typedef struct duk__pcall_args duk__pcall_args;
+
+/* Compute and validate idx_func for a certain 'nargs' and 'other'
+ * parameter count (1 or 2, depending on whether 'this' binding is
+ * present).
+ */
+DUK_LOCAL duk_idx_t duk__call_get_idx_func(duk_hthread *thr, duk_idx_t nargs, duk_idx_t other) {
+ duk_idx_t idx_func;
+
+ /* XXX: byte arithmetic? */
+
+ DUK_ASSERT(other >= 0);
+
+ idx_func = duk_get_top(thr) - nargs - other;
+ if (DUK_UNLIKELY((idx_func | nargs) < 0)) { /* idx_func < 0 || nargs < 0; OR sign bits */
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ /* unreachable */
+ }
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
+ return idx_func;
+}
+
+/* Compute idx_func, assume index will be valid. This is a valid assumption
+ * for protected calls: nargs < 0 is checked explicitly and duk_safe_call()
+ * validates the argument count.
+ */
+DUK_LOCAL duk_idx_t duk__call_get_idx_func_unvalidated(duk_hthread *thr, duk_idx_t nargs, duk_idx_t other) {
+ duk_idx_t idx_func;
+
+ /* XXX: byte arithmetic? */
+
+ DUK_ASSERT(nargs >= 0);
+ DUK_ASSERT(other >= 0);
+
+ idx_func = duk_get_top(thr) - nargs - other;
+ DUK_ASSERT(idx_func >= 0);
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
+ return idx_func;
+}
/* Prepare value stack for a method call through an object property.
* May currently throw an error e.g. when getting the property.
*/
-DUK_LOCAL void duk__call_prop_prep_stack(duk_context *ctx, duk_idx_t normalized_obj_index, duk_idx_t nargs) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_LOCAL void duk__call_prop_prep_stack(duk_hthread *thr, duk_idx_t normalized_obj_idx, duk_idx_t nargs) {
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(nargs >= 0);
- DUK_DDD(DUK_DDDPRINT("duk__call_prop_prep_stack, normalized_obj_index=%ld, nargs=%ld, stacktop=%ld",
- (long) normalized_obj_index, (long) nargs, (long) duk_get_top(ctx)));
+ DUK_DDD(DUK_DDDPRINT("duk__call_prop_prep_stack, normalized_obj_idx=%ld, nargs=%ld, stacktop=%ld",
+ (long) normalized_obj_idx, (long) nargs, (long) duk_get_top(thr)));
/* [... key arg1 ... argN] */
/* duplicate key */
- duk_dup(ctx, -nargs - 1); /* Note: -nargs alone would fail for nargs == 0, this is OK */
- duk_get_prop(ctx, normalized_obj_index);
+ duk_dup(thr, -nargs - 1); /* Note: -nargs alone would fail for nargs == 0, this is OK */
+ (void) duk_get_prop(thr, normalized_obj_idx);
- DUK_DDD(DUK_DDDPRINT("func: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("func: %!T", (duk_tval *) duk_get_tval(thr, -1)));
+
+#if defined(DUK_USE_VERBOSE_ERRORS)
+ if (DUK_UNLIKELY(!duk_is_callable(thr, -1))) {
+ duk_tval *tv_targ;
+ duk_tval *tv_base;
+ duk_tval *tv_key;
+
+ tv_targ = DUK_GET_TVAL_NEGIDX(thr, -1);
+ tv_base = DUK_GET_TVAL_POSIDX(thr, normalized_obj_idx);
+ tv_key = DUK_GET_TVAL_NEGIDX(thr, -nargs - 2);
+ DUK_ASSERT(tv_targ >= thr->valstack_bottom && tv_targ < thr->valstack_top);
+ DUK_ASSERT(tv_base >= thr->valstack_bottom && tv_base < thr->valstack_top);
+ DUK_ASSERT(tv_key >= thr->valstack_bottom && tv_key < thr->valstack_top);
+
+ duk_call_setup_propcall_error(thr, tv_targ, tv_base, tv_key);
+ }
+#endif
/* [... key arg1 ... argN func] */
- duk_replace(ctx, -nargs - 2);
+ duk_replace(thr, -nargs - 2);
/* [... func arg1 ... argN] */
- duk_dup(ctx, normalized_obj_index);
- duk_insert(ctx, -nargs - 1);
+ duk_dup(thr, normalized_obj_idx);
+ duk_insert(thr, -nargs - 1);
/* [... func this arg1 ... argN] */
}
-DUK_EXTERNAL void duk_call(duk_context *ctx, duk_idx_t nargs) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_call(duk_hthread *thr, duk_idx_t nargs) {
duk_small_uint_t call_flags;
duk_idx_t idx_func;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
- idx_func = duk_get_top(ctx) - nargs - 1;
- if (idx_func < 0 || nargs < 0) {
- /* note that we can't reliably pop anything here */
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
- }
+ idx_func = duk__call_get_idx_func(thr, nargs, 1);
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
- /* XXX: awkward; we assume there is space for this, overwrite
- * directly instead?
- */
- duk_push_undefined(ctx);
- duk_insert(ctx, idx_func + 1);
+ duk_insert_undefined(thr, idx_func + 1);
call_flags = 0; /* not protected, respect reclimit, not constructor */
-
- duk_handle_call_unprotected(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
+ duk_handle_call_unprotected(thr, idx_func, call_flags);
}
-DUK_EXTERNAL void duk_call_method(duk_context *ctx, duk_idx_t nargs) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_call_method(duk_hthread *thr, duk_idx_t nargs) {
duk_small_uint_t call_flags;
duk_idx_t idx_func;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
- idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */
- if (idx_func < 0 || nargs < 0) {
- /* note that we can't reliably pop anything here */
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
- }
+ idx_func = duk__call_get_idx_func(thr, nargs, 2);
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
call_flags = 0; /* not protected, respect reclimit, not constructor */
-
- duk_handle_call_unprotected(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
+ duk_handle_call_unprotected(thr, idx_func, call_flags);
}
-DUK_EXTERNAL void duk_call_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs) {
+DUK_EXTERNAL void duk_call_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t nargs) {
/*
* XXX: if duk_handle_call() took values through indices, this could be
* made much more sensible. However, duk_handle_call() needs to fudge
- * the 'this' and 'func' values to handle bound function chains, which
- * is now done "in-place", so this is not a trivial change.
+ * the 'this' and 'func' values to handle bound functions, which is now
+ * done "in-place", so this is not a trivial change.
*/
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj_index = duk_require_normalize_index(ctx, obj_index); /* make absolute */
+ obj_idx = duk_require_normalize_index(thr, obj_idx); /* make absolute */
if (DUK_UNLIKELY(nargs < 0)) {
- DUK_ERROR_API((duk_hthread *) ctx, DUK_STR_INVALID_CALL_ARGS);
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
}
- duk__call_prop_prep_stack(ctx, obj_index, nargs);
+ duk__call_prop_prep_stack(thr, obj_idx, nargs);
- duk_call_method(ctx, nargs);
+ duk_call_method(thr, nargs);
}
-DUK_EXTERNAL duk_int_t duk_pcall(duk_context *ctx, duk_idx_t nargs) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_small_uint_t call_flags;
+DUK_LOCAL duk_ret_t duk__pcall_raw(duk_hthread *thr, void *udata) {
+ duk__pcall_args *args;
duk_idx_t idx_func;
- duk_int_t rc;
+ duk_int_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(udata != NULL);
- idx_func = duk_get_top(ctx) - nargs - 1; /* must work for nargs <= 0 */
- if (idx_func < 0 || nargs < 0) {
- /* We can't reliably pop anything here because the stack input
- * shape is incorrect. So we throw an error; if the caller has
- * no catch point for this, a fatal error will occur. Another
- * alternative would be to just return an error. But then the
- * stack would be in an unknown state which might cause some
- * very hard to diagnose problems later on. Also note that even
- * if we did not throw an error here, the underlying call handler
- * might STILL throw an out-of-memory error or some other internal
- * fatal error.
- */
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
- return DUK_EXEC_ERROR; /* unreachable */
- }
+ args = (duk__pcall_args *) udata;
+ idx_func = duk__call_get_idx_func_unvalidated(thr, args->nargs, 1);
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
- /* awkward; we assume there is space for this */
- duk_push_undefined(ctx);
- duk_insert(ctx, idx_func + 1);
+ duk_insert_undefined(thr, idx_func + 1);
- call_flags = 0; /* respect reclimit, not constructor */
+ ret = duk_handle_call_unprotected(thr, idx_func, args->call_flags);
+ DUK_ASSERT(ret == 0);
+ DUK_UNREF(ret);
- rc = duk_handle_call_protected(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
-
- return rc;
-}
-
-DUK_EXTERNAL duk_int_t duk_pcall_method(duk_context *ctx, duk_idx_t nargs) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_small_uint_t call_flags;
- duk_idx_t idx_func;
- duk_int_t rc;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
-
- idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */
- if (idx_func < 0 || nargs < 0) {
- /* See comments in duk_pcall(). */
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
- return DUK_EXEC_ERROR; /* unreachable */
- }
-
- call_flags = 0; /* respect reclimit, not constructor */
-
- rc = duk_handle_call_protected(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
-
- return rc;
-}
-
-DUK_LOCAL duk_ret_t duk__pcall_prop_raw(duk_context *ctx) {
- duk_idx_t obj_index;
- duk_idx_t nargs;
-
- /* Get the original arguments. Note that obj_index may be a relative
- * index so the stack must have the same top when we use it.
- */
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- obj_index = (duk_idx_t) duk_get_int(ctx, -2);
- nargs = (duk_idx_t) duk_get_int(ctx, -1);
- duk_pop_2(ctx);
-
- obj_index = duk_require_normalize_index(ctx, obj_index); /* make absolute */
- duk__call_prop_prep_stack(ctx, obj_index, nargs);
- duk_call_method(ctx, nargs);
return 1;
}
-DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs) {
- /*
- * Must be careful to catch errors related to value stack manipulation
- * and property lookup, not just the call itself.
- */
+DUK_EXTERNAL duk_int_t duk_pcall(duk_hthread *thr, duk_idx_t nargs) {
+ duk__pcall_args args;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- duk_push_idx(ctx, obj_index);
+ args.nargs = nargs;
if (DUK_UNLIKELY(nargs < 0)) {
- DUK_ERROR_API((duk_hthread *) ctx, DUK_STR_INVALID_CALL_ARGS);
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ return DUK_EXEC_ERROR; /* unreachable */
}
- duk_push_idx(ctx, nargs);
+ args.call_flags = 0;
- /* Inputs: explicit arguments (nargs), +1 for key, +2 for obj_index/nargs passing.
- * If the value stack does not contain enough args, an error is thrown; this matches
- * behavior of the other protected call API functions.
- */
- return duk_safe_call(ctx, duk__pcall_prop_raw, nargs + 1 + 2 /*nargs*/, 1 /*nrets*/);
+ return duk_safe_call(thr, duk__pcall_raw, (void *) &args /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
}
-DUK_EXTERNAL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, duk_idx_t nargs, duk_idx_t nrets) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL duk_ret_t duk__pcall_method_raw(duk_hthread *thr, void *udata) {
+ duk__pcall_method_args *args;
+ duk_idx_t idx_func;
+ duk_int_t ret;
+
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(udata != NULL);
+
+ args = (duk__pcall_method_args *) udata;
+
+ idx_func = duk__call_get_idx_func_unvalidated(thr, args->nargs, 2);
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
+
+ ret = duk_handle_call_unprotected(thr, idx_func, args->call_flags);
+ DUK_ASSERT(ret == 0);
+ DUK_UNREF(ret);
+
+ return 1;
+}
+
+DUK_INTERNAL duk_int_t duk_pcall_method_flags(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags) {
+ duk__pcall_method_args args;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ args.nargs = nargs;
+ if (DUK_UNLIKELY(nargs < 0)) {
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ return DUK_EXEC_ERROR; /* unreachable */
+ }
+ args.call_flags = call_flags;
+
+ return duk_safe_call(thr, duk__pcall_method_raw, (void *) &args /*udata*/, nargs + 2 /*nargs*/, 1 /*nrets*/);
+}
+
+DUK_EXTERNAL duk_int_t duk_pcall_method(duk_hthread *thr, duk_idx_t nargs) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return duk_pcall_method_flags(thr, nargs, 0);
+}
+
+DUK_LOCAL duk_ret_t duk__pcall_prop_raw(duk_hthread *thr, void *udata) {
+ duk__pcall_prop_args *args;
+ duk_idx_t obj_idx;
+ duk_int_t ret;
+
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(udata != NULL);
+
+ args = (duk__pcall_prop_args *) udata;
+
+ obj_idx = duk_require_normalize_index(thr, args->obj_idx); /* make absolute */
+ duk__call_prop_prep_stack(thr, obj_idx, args->nargs);
+
+ ret = duk_handle_call_unprotected_nargs(thr, args->nargs, args->call_flags);
+ DUK_ASSERT(ret == 0);
+ DUK_UNREF(ret);
+ return 1;
+}
+
+DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t nargs) {
+ duk__pcall_prop_args args;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ args.obj_idx = obj_idx;
+ args.nargs = nargs;
+ if (DUK_UNLIKELY(nargs < 0)) {
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ return DUK_EXEC_ERROR; /* unreachable */
+ }
+ args.call_flags = 0;
+
+ return duk_safe_call(thr, duk__pcall_prop_raw, (void *) &args /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
+}
+
+DUK_EXTERNAL duk_int_t duk_safe_call(duk_hthread *thr, duk_safe_call_function func, void *udata, duk_idx_t nargs, duk_idx_t nrets) {
duk_int_t rc;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
- if (duk_get_top(ctx) < nargs || nargs < 0 || nrets < 0) {
- /* See comments in duk_pcall(). */
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
+ /* nargs condition; fail if: top - bottom < nargs
+ * <=> top < bottom + nargs
+ * nrets condition; fail if: end - (top - nargs) < nrets
+ * <=> end - top + nargs < nrets
+ * <=> end + nargs < top + nrets
+ */
+ /* XXX: check for any reserve? */
+
+ if (DUK_UNLIKELY((nargs | nrets) < 0 || /* nargs < 0 || nrets < 0; OR sign bits */
+ thr->valstack_top < thr->valstack_bottom + nargs || /* nargs too large compared to top */
+ thr->valstack_end + nargs < thr->valstack_top + nrets)) { /* nrets too large compared to reserve */
+ DUK_D(DUK_DPRINT("not enough stack reserve for safe call or invalid arguments: "
+ "nargs=%ld < 0 (?), nrets=%ld < 0 (?), top=%ld < bottom=%ld + nargs=%ld (?), "
+ "end=%ld + nargs=%ld < top=%ld + nrets=%ld (?)",
+ (long) nargs,
+ (long) nrets,
+ (long) (thr->valstack_top - thr->valstack),
+ (long) (thr->valstack_bottom - thr->valstack),
+ (long) nargs,
+ (long) (thr->valstack_end - thr->valstack),
+ (long) nargs,
+ (long) (thr->valstack_top - thr->valstack),
+ (long) nrets));
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
return DUK_EXEC_ERROR; /* unreachable */
}
rc = duk_handle_safe_call(thr, /* thread */
func, /* func */
+ udata, /* udata */
nargs, /* num_stack_args */
nrets); /* num_stack_res */
return rc;
}
-DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) {
- /*
- * There are two [[Construct]] operations in the specification:
- *
- * - E5 Section 13.2.2: for Function objects
- * - E5 Section 15.3.4.5.2: for "bound" Function objects
- *
- * The chain of bound functions is resolved in Section 15.3.4.5.2,
- * with arguments "piling up" until the [[Construct]] internal
- * method is called on the final, actual Function object. Note
- * that the "prototype" property is looked up *only* from the
- * final object, *before* calling the constructor.
- *
- * Currently we follow the bound function chain here to get the
- * "prototype" property value from the final, non-bound function.
- * However, we let duk_handle_call() handle the argument "piling"
- * when the constructor is called. The bound function chain is
- * thus now processed twice.
- *
- * When constructing new Array instances, an unnecessary object is
- * created and discarded now: the standard [[Construct]] creates an
- * object, and calls the Array constructor. The Array constructor
- * returns an Array instance, which is used as the result value for
- * the "new" operation; the object created before the Array constructor
- * call is discarded.
- *
- * This would be easy to fix, e.g. by knowing that the Array constructor
- * will always create a replacement object and skip creating the fallback
- * object in that case.
- *
- * Note: functions called via "new" need to know they are called as a
- * constructor. For instance, built-in constructors behave differently
- * depending on how they are called.
- */
+DUK_EXTERNAL void duk_new(duk_hthread *thr, duk_idx_t nargs) {
+ duk_idx_t idx_func;
- /* XXX: merge this with duk_js_call.c, as this function implements
- * core semantics (or perhaps merge the two files altogether).
- */
+ DUK_ASSERT_API_ENTRY(thr);
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *proto;
- duk_hobject *cons;
- duk_hobject *fallback;
- duk_idx_t idx_cons;
- duk_small_uint_t call_flags;
+ idx_func = duk__call_get_idx_func(thr, nargs, 1);
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
- DUK_ASSERT_CTX_VALID(ctx);
+ duk_push_object(thr); /* default instance; internal proto updated by call handling */
+ duk_insert(thr, idx_func + 1);
- /* [... constructor arg1 ... argN] */
-
- idx_cons = duk_require_normalize_index(ctx, -nargs - 1);
-
- DUK_DDD(DUK_DDDPRINT("top=%ld, nargs=%ld, idx_cons=%ld",
- (long) duk_get_top(ctx), (long) nargs, (long) idx_cons));
-
- /* XXX: code duplication */
-
- /*
- * Figure out the final, non-bound constructor, to get "prototype"
- * property.
- */
-
- duk_dup(ctx, idx_cons);
- for (;;) {
- duk_tval *tv;
- tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
- DUK_ASSERT(tv != NULL);
-
- if (DUK_TVAL_IS_OBJECT(tv)) {
- cons = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(cons != NULL);
- if (!DUK_HOBJECT_IS_CALLABLE(cons) || !DUK_HOBJECT_HAS_CONSTRUCTABLE(cons)) {
- /* Checking callability of the immediate target
- * is important, same for constructability.
- * Checking it for functions down the bound
- * function chain is not strictly necessary
- * because .bind() should normally reject them.
- * But it's good to check anyway because it's
- * technically possible to edit the bound function
- * chain via internal keys.
- */
- goto not_constructable;
- }
- if (!DUK_HOBJECT_HAS_BOUND(cons)) {
- break;
- }
- } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
- /* Lightfuncs cannot be bound. */
- break;
- } else {
- /* Anything else is not constructable. */
- goto not_constructable;
- }
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET); /* -> [... cons target] */
- duk_remove(ctx, -2); /* -> [... target] */
- }
- DUK_ASSERT(duk_is_callable(ctx, -1));
- DUK_ASSERT(duk_is_lightfunc(ctx, -1) ||
- (duk_get_hobject(ctx, -1) != NULL && !DUK_HOBJECT_HAS_BOUND(duk_get_hobject(ctx, -1))));
-
- /* [... constructor arg1 ... argN final_cons] */
-
- /*
- * Create "fallback" object to be used as the object instance,
- * unless the constructor returns a replacement value.
- * Its internal prototype needs to be set based on "prototype"
- * property of the constructor.
- */
-
- duk_push_object(ctx); /* class Object, extensible */
-
- /* [... constructor arg1 ... argN final_cons fallback] */
-
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE);
- proto = duk_get_hobject(ctx, -1);
- if (!proto) {
- DUK_DDD(DUK_DDDPRINT("constructor has no 'prototype' property, or value not an object "
- "-> leave standard Object prototype as fallback prototype"));
- } else {
- DUK_DDD(DUK_DDDPRINT("constructor has 'prototype' property with object value "
- "-> set fallback prototype to that value: %!iO", (duk_heaphdr *) proto));
- fallback = duk_get_hobject(ctx, -2);
- DUK_ASSERT(fallback != NULL);
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, fallback, proto);
- }
- duk_pop(ctx);
-
- /* [... constructor arg1 ... argN final_cons fallback] */
-
- /*
- * Manipulate callstack for the call.
- */
-
- duk_dup_top(ctx);
- duk_insert(ctx, idx_cons + 1); /* use fallback as 'this' value */
- duk_insert(ctx, idx_cons); /* also stash it before constructor,
- * in case we need it (as the fallback value)
- */
- duk_pop(ctx); /* pop final_cons */
-
-
- /* [... fallback constructor fallback(this) arg1 ... argN];
- * Note: idx_cons points to first 'fallback', not 'constructor'.
- */
-
- DUK_DDD(DUK_DDDPRINT("before call, idx_cons+1 (constructor) -> %!T, idx_cons+2 (fallback/this) -> %!T, "
- "nargs=%ld, top=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_cons + 1),
- (duk_tval *) duk_get_tval(ctx, idx_cons + 2),
- (long) nargs,
- (long) duk_get_top(ctx)));
-
- /*
- * Call the constructor function (called in "constructor mode").
- */
-
- call_flags = DUK_CALL_FLAG_CONSTRUCTOR_CALL; /* not protected, respect reclimit, is a constructor call */
-
- duk_handle_call_unprotected(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
-
- /* [... fallback retval] */
-
- DUK_DDD(DUK_DDDPRINT("constructor call finished, fallback=%!iT, retval=%!iT",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- /*
- * Determine whether to use the constructor return value as the created
- * object instance or not.
- */
-
- if (duk_is_object(ctx, -1)) {
- duk_remove(ctx, -2);
- } else {
- duk_pop(ctx);
- }
-
- /*
- * Augment created errors upon creation (not when they are thrown or
- * rethrown). __FILE__ and __LINE__ are not desirable here; the call
- * stack reflects the caller which is correct.
- */
-
-#ifdef DUK_USE_AUGMENT_ERROR_CREATE
- duk_hthread_sync_currpc(thr);
- duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/);
-#endif
-
- /* [... retval] */
-
- return;
-
- not_constructable:
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONSTRUCTABLE);
+ duk_handle_call_unprotected(thr, idx_func, DUK_CALL_FLAG_CONSTRUCT);
}
-DUK_LOCAL duk_ret_t duk__pnew_helper(duk_context *ctx) {
- duk_uint_t nargs;
+DUK_LOCAL duk_ret_t duk__pnew_helper(duk_hthread *thr, void *udata) {
+ duk_idx_t nargs;
- nargs = duk_to_uint(ctx, -1);
- duk_pop(ctx);
+ DUK_ASSERT(udata != NULL);
+ nargs = *((duk_idx_t *) udata);
- duk_new(ctx, nargs);
+ duk_new(thr, nargs);
return 1;
}
-DUK_EXTERNAL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs) {
+DUK_EXTERNAL duk_int_t duk_pnew(duk_hthread *thr, duk_idx_t nargs) {
duk_int_t rc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* For now, just use duk_safe_call() to wrap duk_new(). We can't
- * simply use a protected duk_handle_call() because there's post
- * processing which might throw. It should be possible to ensure
- * the post processing never throws (except in internal errors and
- * out of memory etc which are always allowed) and then remove this
- * wrapper.
+ * simply use a protected duk_handle_call() because pushing the
+ * default instance might throw.
*/
if (DUK_UNLIKELY(nargs < 0)) {
- DUK_ERROR_API((duk_hthread *) ctx, DUK_STR_INVALID_CALL_ARGS);
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ return DUK_EXEC_ERROR; /* unreachable */
}
- duk_push_uint(ctx, nargs);
- rc = duk_safe_call(ctx, duk__pnew_helper, nargs + 2 /*nargs*/, 1 /*nrets*/);
+
+ rc = duk_safe_call(thr, duk__pnew_helper, (void *) &nargs /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
return rc;
}
-DUK_EXTERNAL duk_bool_t duk_is_constructor_call(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_is_constructor_call(duk_hthread *thr) {
duk_activation *act;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
+ DUK_ASSERT_API_ENTRY(thr);
- act = duk_hthread_get_current_activation(thr);
+ act = thr->callstack_curr;
if (act != NULL) {
return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0);
}
return 0;
}
-DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+/* XXX: Make this obsolete by adding a function flag for rejecting a
+ * non-constructor call automatically?
+ */
+DUK_INTERNAL void duk_require_constructor_call(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (!duk_is_constructor_call(thr)) {
+ DUK_ERROR_TYPE(thr, DUK_STR_CONSTRUCT_ONLY);
+ }
+}
+
+DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_hthread *thr) {
duk_activation *act;
/* For user code this could just return 1 (strict) always
@@ -12878,32 +14538,28 @@ DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_context *ctx) {
* the internal call sites.
*/
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
+ DUK_ASSERT_API_ENTRY(thr);
- act = duk_hthread_get_current_activation(thr);
- if (act == NULL) {
+ act = thr->callstack_curr;
+ if (act != NULL) {
+ return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0);
+ } else {
/* Strict by default. */
return 1;
}
- return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0);
}
/*
* Duktape/C function magic
*/
-DUK_EXTERNAL duk_int_t duk_get_current_magic(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_int_t duk_get_current_magic(duk_hthread *thr) {
duk_activation *act;
duk_hobject *func;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
+ DUK_ASSERT_API_ENTRY(thr);
- act = duk_hthread_get_current_activation(thr);
+ act = thr->callstack_curr;
if (act) {
func = DUK_ACT_GET_FUNC(act);
if (!func) {
@@ -12914,29 +14570,28 @@ DUK_EXTERNAL duk_int_t duk_get_current_magic(duk_context *ctx) {
}
DUK_ASSERT(func != NULL);
- if (DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
- duk_hnativefunction *nf = (duk_hnativefunction *) func;
+ if (DUK_HOBJECT_IS_NATFUNC(func)) {
+ duk_hnatfunc *nf = (duk_hnatfunc *) func;
return (duk_int_t) nf->magic;
}
}
return 0;
}
-DUK_EXTERNAL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_int_t duk_get_magic(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_hobject *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, index);
+ tv = duk_require_tval(thr, idx);
if (DUK_TVAL_IS_OBJECT(tv)) {
h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
- if (!DUK_HOBJECT_HAS_NATIVEFUNCTION(h)) {
+ if (!DUK_HOBJECT_HAS_NATFUNC(h)) {
goto type_error;
}
- return (duk_int_t) ((duk_hnativefunction *) h)->magic;
+ return (duk_int_t) ((duk_hnatfunc *) h)->magic;
} else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
duk_small_uint_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
@@ -12948,15 +14603,55 @@ DUK_EXTERNAL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t index) {
return 0;
}
-DUK_EXTERNAL void duk_set_magic(duk_context *ctx, duk_idx_t index, duk_int_t magic) {
- duk_hnativefunction *nf;
+DUK_EXTERNAL void duk_set_magic(duk_hthread *thr, duk_idx_t idx, duk_int_t magic) {
+ duk_hnatfunc *nf;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- nf = duk_require_hnativefunction(ctx, index);
+ nf = duk_require_hnatfunc(thr, idx);
DUK_ASSERT(nf != NULL);
nf->magic = (duk_int16_t) magic;
}
+
+/*
+ * Misc helpers
+ */
+
+/* Resolve a bound function on value stack top to a non-bound target
+ * (leave other values as is).
+ */
+DUK_INTERNAL void duk_resolve_nonbound_function(duk_hthread *thr) {
+ duk_tval *tv;
+
+ DUK_ASSERT_HTHREAD_VALID(thr);
+
+ tv = DUK_GET_TVAL_NEGIDX(thr, -1);
+ if (DUK_TVAL_IS_OBJECT(tv)) {
+ duk_hobject *h;
+
+ h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ if (DUK_HOBJECT_HAS_BOUNDFUNC(h)) {
+ duk_push_tval(thr, &((duk_hboundfunc *) h)->target);
+ duk_replace(thr, -2);
+#if 0
+ DUK_TVAL_SET_TVAL(tv, &((duk_hboundfunc *) h)->target);
+ DUK_TVAL_INCREF(thr, tv);
+ DUK_HOBJECT_DECREF_NORZ(thr, h);
+#endif
+ /* Rely on Function.prototype.bind() on never creating a bound
+ * function whose target is not proper. This is now safe
+ * because the target is not even an internal property but a
+ * struct member.
+ */
+ DUK_ASSERT(duk_is_lightfunc(thr, -1) || duk_is_callable(thr, -1));
+ }
+ }
+
+ /* Lightfuncs cannot be bound but are always callable and
+ * constructable.
+ */
+}
#line 1 "duk_api_codec.c"
/*
* Encoding and decoding basic formats: hex, base64.
@@ -12966,19 +14661,27 @@ DUK_EXTERNAL void duk_set_magic(duk_context *ctx, duk_idx_t index, duk_int_t mag
* Base-64: https://tools.ietf.org/html/rfc4648#section-4
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/* Shared handling for encode/decode argument. Fast path handling for
* buffer and string values because they're the most common. In particular,
* avoid creating a temporary string or buffer when possible.
*/
-DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
- DUK_ASSERT(duk_is_valid_index(ctx, index)); /* checked by caller */
- if (duk_is_buffer(ctx, index)) {
- return (const duk_uint8_t *) duk_get_buffer(ctx, index, out_len);
- } else {
- return (const duk_uint8_t *) duk_to_lstring(ctx, index, out_len);
+DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
+ void *ptr;
+ duk_bool_t isbuffer;
+
+ DUK_ASSERT(duk_is_valid_index(thr, idx)); /* checked by caller */
+
+ /* XXX: with def_ptr set to a stack related pointer, isbuffer could
+ * be removed from the helper?
+ */
+ ptr = duk_get_buffer_data_raw(thr, idx, out_len, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, &isbuffer);
+ if (isbuffer) {
+ DUK_ASSERT(*out_len == 0 || ptr != NULL);
+ return (const duk_uint8_t *) ptr;
}
+ return (const duk_uint8_t *) duk_to_lstring(thr, idx, out_len);
}
#if defined(DUK_USE_BASE64_FASTPATH)
@@ -13165,13 +14868,13 @@ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_
t <<= 6;
} else {
DUK_ASSERT(x == -1);
- goto error;
+ goto decode_error;
}
} else {
DUK_ASSERT(x >= 0 && x <= 63);
if (n_equal > 0) {
/* Don't allow actual chars after equal sign. */
- goto error;
+ goto decode_error;
}
t = (t << 6) + x;
}
@@ -13197,7 +14900,7 @@ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_
/* XX== */
dst -= 2;
} else {
- goto error; /* invalid padding */
+ goto decode_error; /* invalid padding */
}
/* Continue parsing after padding, allows concatenated,
@@ -13221,13 +14924,13 @@ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_
* (e.g. "xxxxyy" instead of "xxxxyy==". Currently not
* accepted.
*/
- goto error;
+ goto decode_error;
}
*out_dst_final = dst;
return 1;
- error:
+ decode_error:
return 0;
}
#else /* DUK_USE_BASE64_FASTPATH */
@@ -13269,12 +14972,12 @@ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_
/* allow basic ASCII whitespace */
continue;
} else {
- goto error;
+ goto decode_error;
}
if (n_equal > 0) {
/* Don't allow mixed padding and actual chars. */
- goto error;
+ goto decode_error;
}
t = (t << 6) + y;
skip_add:
@@ -13293,7 +14996,7 @@ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_
} else if (n_equal == 2) {
dst -= 2;
} else {
- goto error; /* invalid padding */
+ goto decode_error; /* invalid padding */
}
/* Here we can choose either to end parsing and ignore
@@ -13316,33 +15019,32 @@ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_
* (e.g. "xxxxyy" instead of "xxxxyy==". Currently not
* accepted.
*/
- goto error;
+ goto decode_error;
}
*out_dst_final = dst;
return 1;
- error:
+ decode_error:
return 0;
}
#endif /* DUK_USE_BASE64_FASTPATH */
-DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL const char *duk_base64_encode(duk_hthread *thr, duk_idx_t idx) {
const duk_uint8_t *src;
duk_size_t srclen;
duk_size_t dstlen;
duk_uint8_t *dst;
const char *ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* XXX: optimize for string inputs: no need to coerce to a buffer
* which makes a copy of the input.
*/
- index = duk_require_normalize_index(ctx, index);
- src = duk__prep_codec_arg(ctx, index, &srclen);
+ idx = duk_require_normalize_index(thr, idx);
+ src = duk__prep_codec_arg(thr, idx, &srclen);
/* Note: for srclen=0, src may be NULL */
/* Computation must not wrap; this limit works for 32-bit size_t:
@@ -13354,21 +15056,20 @@ DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index) {
goto type_error;
}
dstlen = (srclen + 2) / 3 * 4;
- dst = (duk_uint8_t *) duk_push_fixed_buffer(ctx, dstlen);
+ dst = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, dstlen);
duk__base64_encode_helper((const duk_uint8_t *) src, srclen, dst);
- ret = duk_to_string(ctx, -1);
- duk_replace(ctx, index);
+ ret = duk_buffer_to_string(thr, -1); /* Safe, result is ASCII. */
+ duk_replace(thr, idx);
return ret;
type_error:
- DUK_ERROR_TYPE(thr, DUK_STR_ENCODE_FAILED);
+ DUK_ERROR_TYPE(thr, DUK_STR_BASE64_ENCODE_FAILED);
return NULL; /* never here */
}
-DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_base64_decode(duk_hthread *thr, duk_idx_t idx) {
const duk_uint8_t *src;
duk_size_t srclen;
duk_size_t dstlen;
@@ -13376,14 +15077,14 @@ DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t index) {
duk_uint8_t *dst_final;
duk_bool_t retval;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* XXX: optimize for buffer inputs: no need to coerce to a string
* which causes an unnecessary interning.
*/
- index = duk_require_normalize_index(ctx, index);
- src = duk__prep_codec_arg(ctx, index, &srclen);
+ idx = duk_require_normalize_index(thr, idx);
+ src = duk__prep_codec_arg(thr, idx, &srclen);
/* Computation must not wrap, only srclen + 3 is at risk of
* wrapping because after that the number gets smaller.
@@ -13394,7 +15095,7 @@ DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t index) {
goto type_error;
}
dstlen = (srclen + 3) / 4 * 3; /* upper limit, assuming no whitespace etc */
- dst = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, dstlen);
+ dst = (duk_uint8_t *) duk_push_dynamic_buffer(thr, dstlen);
/* Note: for dstlen=0, dst may be NULL */
retval = duk__base64_decode_helper((const duk_uint8_t *) src, srclen, dst, &dst_final);
@@ -13403,15 +15104,15 @@ DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t index) {
}
/* XXX: convert to fixed buffer? */
- (void) duk_resize_buffer(ctx, -1, (duk_size_t) (dst_final - dst));
- duk_replace(ctx, index);
+ (void) duk_resize_buffer(thr, -1, (duk_size_t) (dst_final - dst));
+ duk_replace(thr, idx);
return;
type_error:
- DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED);
+ DUK_ERROR_TYPE(thr, DUK_STR_BASE64_DECODE_FAILED);
}
-DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL const char *duk_hex_encode(duk_hthread *thr, duk_idx_t idx) {
const duk_uint8_t *inp;
duk_size_t len;
duk_size_t i;
@@ -13422,14 +15123,14 @@ DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t index) {
duk_uint16_t *p16;
#endif
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- index = duk_require_normalize_index(ctx, index);
- inp = duk__prep_codec_arg(ctx, index, &len);
+ idx = duk_require_normalize_index(thr, idx);
+ inp = duk__prep_codec_arg(thr, idx, &len);
DUK_ASSERT(inp != NULL || len == 0);
/* Fixed buffer, no zeroing because we'll fill all the data. */
- buf = (duk_uint8_t *) duk_push_buffer_raw(ctx, len * 2, DUK_BUF_FLAG_NOZERO /*flags*/);
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len * 2);
DUK_ASSERT(buf != NULL);
#if defined(DUK_USE_HEX_FASTPATH)
@@ -13462,13 +15163,12 @@ DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t index) {
* caller coerce to string if necessary?
*/
- ret = duk_to_string(ctx, -1);
- duk_replace(ctx, index);
+ ret = duk_buffer_to_string(thr, -1); /* Safe, result is ASCII. */
+ duk_replace(thr, idx);
return ret;
}
-DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_hex_decode(duk_hthread *thr, duk_idx_t idx) {
const duk_uint8_t *inp;
duk_size_t len;
duk_size_t i;
@@ -13480,10 +15180,10 @@ DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t index) {
duk_size_t len_safe;
#endif
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- index = duk_require_normalize_index(ctx, index);
- inp = duk__prep_codec_arg(ctx, index, &len);
+ idx = duk_require_normalize_index(thr, idx);
+ inp = duk__prep_codec_arg(thr, idx, &len);
DUK_ASSERT(inp != NULL || len == 0);
if (len & 0x01) {
@@ -13491,7 +15191,7 @@ DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t index) {
}
/* Fixed buffer, no zeroing because we'll fill all the data. */
- buf = (duk_uint8_t *) duk_push_buffer_raw(ctx, len / 2, DUK_BUF_FLAG_NOZERO /*flags*/);
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len / 2);
DUK_ASSERT(buf != NULL);
#if defined(DUK_USE_HEX_FASTPATH)
@@ -13544,64 +15244,78 @@ DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t index) {
}
#endif /* DUK_USE_HEX_FASTPATH */
- duk_replace(ctx, index);
+ duk_replace(thr, idx);
return;
type_error:
- DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED);
+ DUK_ERROR_TYPE(thr, DUK_STR_HEX_DECODE_FAILED);
}
-DUK_EXTERNAL const char *duk_json_encode(duk_context *ctx, duk_idx_t index) {
-#ifdef DUK_USE_ASSERTIONS
+#if defined(DUK_USE_JSON_SUPPORT)
+DUK_EXTERNAL const char *duk_json_encode(duk_hthread *thr, duk_idx_t idx) {
+#if defined(DUK_USE_ASSERTIONS)
duk_idx_t top_at_entry;
#endif
const char *ret;
- DUK_ASSERT_CTX_VALID(ctx);
-#ifdef DUK_USE_ASSERTIONS
- top_at_entry = duk_get_top(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
+#if defined(DUK_USE_ASSERTIONS)
+ top_at_entry = duk_get_top(thr);
#endif
- index = duk_require_normalize_index(ctx, index);
- duk_bi_json_stringify_helper(ctx,
- index /*idx_value*/,
+ idx = duk_require_normalize_index(thr, idx);
+ duk_bi_json_stringify_helper(thr,
+ idx /*idx_value*/,
DUK_INVALID_INDEX /*idx_replacer*/,
DUK_INVALID_INDEX /*idx_space*/,
0 /*flags*/);
- DUK_ASSERT(duk_is_string(ctx, -1));
- duk_replace(ctx, index);
- ret = duk_get_string(ctx, index);
+ DUK_ASSERT(duk_is_string(thr, -1));
+ duk_replace(thr, idx);
+ ret = duk_get_string(thr, idx);
- DUK_ASSERT(duk_get_top(ctx) == top_at_entry);
+ DUK_ASSERT(duk_get_top(thr) == top_at_entry);
return ret;
}
-DUK_EXTERNAL void duk_json_decode(duk_context *ctx, duk_idx_t index) {
-#ifdef DUK_USE_ASSERTIONS
+DUK_EXTERNAL void duk_json_decode(duk_hthread *thr, duk_idx_t idx) {
+#if defined(DUK_USE_ASSERTIONS)
duk_idx_t top_at_entry;
#endif
- DUK_ASSERT_CTX_VALID(ctx);
-#ifdef DUK_USE_ASSERTIONS
- top_at_entry = duk_get_top(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
+#if defined(DUK_USE_ASSERTIONS)
+ top_at_entry = duk_get_top(thr);
#endif
- index = duk_require_normalize_index(ctx, index);
- duk_bi_json_parse_helper(ctx,
- index /*idx_value*/,
+ idx = duk_require_normalize_index(thr, idx);
+ duk_bi_json_parse_helper(thr,
+ idx /*idx_value*/,
DUK_INVALID_INDEX /*idx_reviver*/,
0 /*flags*/);
- duk_replace(ctx, index);
+ duk_replace(thr, idx);
- DUK_ASSERT(duk_get_top(ctx) == top_at_entry);
+ DUK_ASSERT(duk_get_top(thr) == top_at_entry);
}
+#else /* DUK_USE_JSON_SUPPORT */
+DUK_EXTERNAL const char *duk_json_encode(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(idx);
+ DUK_ERROR_UNSUPPORTED(thr);
+}
+
+DUK_EXTERNAL void duk_json_decode(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(idx);
+ DUK_ERROR_UNSUPPORTED(thr);
+}
+#endif /* DUK_USE_JSON_SUPPORT */
#line 1 "duk_api_compile.c"
/*
* Compilation and evaluation
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
typedef struct duk__compile_raw_args duk__compile_raw_args;
struct duk__compile_raw_args {
@@ -13611,11 +15325,10 @@ struct duk__compile_raw_args {
};
/* Eval is just a wrapper now. */
-DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
- duk_uint_t comp_flags;
+DUK_EXTERNAL duk_int_t duk_eval_raw(duk_hthread *thr, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
duk_int_t rc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* Note: strictness is *not* inherited from the current Duktape/C.
* This would be confusing because the current strictness state
@@ -13626,9 +15339,7 @@ DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, du
/* [ ... source? filename? ] (depends on flags) */
- comp_flags = flags;
- comp_flags |= DUK_COMPILE_EVAL;
- rc = duk_compile_raw(ctx, src_buffer, src_length, comp_flags); /* may be safe, or non-safe depending on flags */
+ rc = duk_compile_raw(thr, src_buffer, src_length, flags | DUK_COMPILE_EVAL); /* may be safe, or non-safe depending on flags */
/* [ ... closure/error ] */
@@ -13637,12 +15348,12 @@ DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, du
goto got_rc;
}
- duk_push_global_object(ctx); /* explicit 'this' binding, see GH-164 */
+ duk_push_global_object(thr); /* explicit 'this' binding, see GH-164 */
if (flags & DUK_COMPILE_SAFE) {
- rc = duk_pcall_method(ctx, 0);
+ rc = duk_pcall_method(thr, 0);
} else {
- duk_call_method(ctx, 0);
+ duk_call_method(thr, 0);
rc = DUK_EXEC_SUCCESS;
}
@@ -13650,21 +15361,20 @@ DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, du
got_rc:
if (flags & DUK_COMPILE_NORESULT) {
- duk_pop(ctx);
+ duk_pop(thr);
}
return rc;
}
/* Helper which can be called both directly and with duk_safe_call(). */
-DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL duk_ret_t duk__do_compile(duk_hthread *thr, void *udata) {
duk__compile_raw_args *comp_args;
duk_uint_t flags;
- duk_small_uint_t comp_flags;
- duk_hcompiledfunction *h_templ;
+ duk_hcompfunc *h_templ;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(udata != NULL);
/* Note: strictness is not inherited from the current Duktape/C
* context. Otherwise it would not be possible to compile
@@ -13673,17 +15383,14 @@ DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx) {
* for discussion.
*/
- /* [ ... source? filename? &comp_args ] (depends on flags) */
+ /* [ ... source? filename? ] (depends on flags) */
- comp_args = (duk__compile_raw_args *) duk_require_pointer(ctx, -1);
+ comp_args = (duk__compile_raw_args *) udata;
flags = comp_args->flags;
- duk_pop(ctx);
-
- /* [ ... source? filename? ] */
if (flags & DUK_COMPILE_NOFILENAME) {
/* Automatic filename: 'eval' or 'input'. */
- duk_push_hstring_stridx(ctx, (flags & DUK_COMPILE_EVAL) ? DUK_STRIDX_EVAL : DUK_STRIDX_INPUT);
+ duk_push_hstring_stridx(thr, (flags & DUK_COMPILE_EVAL) ? DUK_STRIDX_EVAL : DUK_STRIDX_INPUT);
}
/* [ ... source? filename ] */
@@ -13691,14 +15398,10 @@ DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx) {
if (!comp_args->src_buffer) {
duk_hstring *h_sourcecode;
- h_sourcecode = duk_get_hstring(ctx, -2);
+ h_sourcecode = duk_get_hstring(thr, -2);
if ((flags & DUK_COMPILE_NOSOURCE) || /* args incorrect */
(h_sourcecode == NULL)) { /* e.g. duk_push_string_file_raw() pushed undefined */
- /* XXX: when this error is caused by a nonexistent
- * file given to duk_peval_file() or similar, the
- * error message is not the best possible.
- */
- DUK_ERROR_API(thr, DUK_STR_NO_SOURCECODE);
+ DUK_ERROR_TYPE(thr, DUK_STR_NO_SOURCECODE);
}
DUK_ASSERT(h_sourcecode != NULL);
comp_args->src_buffer = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode);
@@ -13706,52 +15409,42 @@ DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx) {
}
DUK_ASSERT(comp_args->src_buffer != NULL);
- /* XXX: unnecessary translation of flags */
- comp_flags = 0;
- if (flags & DUK_COMPILE_EVAL) {
- comp_flags |= DUK_JS_COMPILE_FLAG_EVAL;
- }
if (flags & DUK_COMPILE_FUNCTION) {
- comp_flags |= DUK_JS_COMPILE_FLAG_EVAL |
- DUK_JS_COMPILE_FLAG_FUNCEXPR;
- }
- if (flags & DUK_COMPILE_STRICT) {
- comp_flags |= DUK_JS_COMPILE_FLAG_STRICT;
+ flags |= DUK_COMPILE_EVAL | DUK_COMPILE_FUNCEXPR;
}
/* [ ... source? filename ] */
- duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, comp_flags);
+ duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, flags);
/* [ ... source? func_template ] */
if (flags & DUK_COMPILE_NOSOURCE) {
;
} else {
- duk_remove(ctx, -2);
+ duk_remove_m2(thr);
}
/* [ ... func_template ] */
- h_templ = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
- DUK_ASSERT(h_templ != NULL);
+ h_templ = (duk_hcompfunc *) duk_known_hobject(thr, -1);
duk_js_push_closure(thr,
h_templ,
thr->builtins[DUK_BIDX_GLOBAL_ENV],
thr->builtins[DUK_BIDX_GLOBAL_ENV],
1 /*add_auto_proto*/);
- duk_remove(ctx, -2); /* -> [ ... closure ] */
+ duk_remove_m2(thr); /* -> [ ... closure ] */
/* [ ... closure ] */
return 1;
}
-DUK_EXTERNAL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
+DUK_EXTERNAL duk_int_t duk_compile_raw(duk_hthread *thr, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
duk__compile_raw_args comp_args_alloc;
duk__compile_raw_args *comp_args = &comp_args_alloc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
if ((flags & DUK_COMPILE_STRLEN) && (src_buffer != NULL)) {
/* String length is computed here to avoid multiple evaluation
@@ -13763,9 +15456,8 @@ DUK_EXTERNAL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer,
comp_args->src_buffer = (const duk_uint8_t *) src_buffer;
comp_args->src_length = src_length;
comp_args->flags = flags;
- duk_push_pointer(ctx, (void *) comp_args);
- /* [ ... source? filename? &comp_args ] (depends on flags) */
+ /* [ ... source? filename? ] (depends on flags) */
if (flags & DUK_COMPILE_SAFE) {
duk_int_t rc;
@@ -13777,16 +15469,15 @@ DUK_EXTERNAL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer,
* directly into flags.
*/
nargs = flags & 0x07;
- DUK_ASSERT(nargs == (1 +
- ((flags & DUK_COMPILE_NOSOURCE) ? 0 : 1) +
- ((flags & DUK_COMPILE_NOFILENAME) ? 0 : 1)));
- rc = duk_safe_call(ctx, duk__do_compile, nargs, nrets);
+ DUK_ASSERT(nargs == ((flags & DUK_COMPILE_NOSOURCE) ? 0 : 1) +
+ ((flags & DUK_COMPILE_NOFILENAME) ? 0 : 1));
+ rc = duk_safe_call(thr, duk__do_compile, (void *) comp_args, nargs, nrets);
/* [ ... closure ] */
return rc;
}
- (void) duk__do_compile(ctx);
+ (void) duk__do_compile(thr, (void *) comp_args);
/* [ ... closure ] */
return DUK_EXEC_SUCCESS;
@@ -13796,54 +15487,60 @@ DUK_EXTERNAL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer,
* Debugging related API calls
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-DUK_EXTERNAL void duk_push_context_dump(duk_context *ctx) {
+#if defined(DUK_USE_JSON_SUPPORT)
+DUK_EXTERNAL void duk_push_context_dump(duk_hthread *thr) {
duk_idx_t idx;
duk_idx_t top;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* We don't duk_require_stack() here now, but rely on the caller having
* enough space.
*/
- top = duk_get_top(ctx);
- duk_push_array(ctx);
+ top = duk_get_top(thr);
+ duk_push_array(thr);
for (idx = 0; idx < top; idx++) {
- duk_dup(ctx, idx);
- duk_put_prop_index(ctx, -2, idx);
+ duk_dup(thr, idx);
+ duk_put_prop_index(thr, -2, (duk_uarridx_t) idx);
}
/* XXX: conversion errors should not propagate outwards.
* Perhaps values need to be coerced individually?
*/
- duk_bi_json_stringify_helper(ctx,
- duk_get_top_index(ctx), /*idx_value*/
+ duk_bi_json_stringify_helper(thr,
+ duk_get_top_index(thr), /*idx_value*/
DUK_INVALID_INDEX, /*idx_replacer*/
DUK_INVALID_INDEX, /*idx_space*/
DUK_JSON_FLAG_EXT_CUSTOM |
DUK_JSON_FLAG_ASCII_ONLY |
DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/);
- duk_push_sprintf(ctx, "ctx: top=%ld, stack=%s", (long) top, (const char *) duk_safe_to_string(ctx, -1));
- duk_replace(ctx, -3); /* [ ... arr jsonx(arr) res ] -> [ ... res jsonx(arr) ] */
- duk_pop(ctx);
- DUK_ASSERT(duk_is_string(ctx, -1));
+ duk_push_sprintf(thr, "ctx: top=%ld, stack=%s", (long) top, (const char *) duk_safe_to_string(thr, -1));
+ duk_replace(thr, -3); /* [ ... arr jsonx(arr) res ] -> [ ... res jsonx(arr) ] */
+ duk_pop(thr);
+ DUK_ASSERT(duk_is_string(thr, -1));
}
+#else /* DUK_USE_JSON_SUPPORT */
+DUK_EXTERNAL void duk_push_context_dump(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ERROR_UNSUPPORTED(thr);
+}
+#endif /* DUK_USE_JSON_SUPPORT */
#if defined(DUK_USE_DEBUGGER_SUPPORT)
-DUK_EXTERNAL void duk_debugger_attach_custom(duk_context *ctx,
- duk_debug_read_function read_cb,
- duk_debug_write_function write_cb,
- duk_debug_peek_function peek_cb,
- duk_debug_read_flush_function read_flush_cb,
- duk_debug_write_flush_function write_flush_cb,
- duk_debug_request_function request_cb,
- duk_debug_detached_function detached_cb,
- void *udata) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_debugger_attach(duk_hthread *thr,
+ duk_debug_read_function read_cb,
+ duk_debug_write_function write_cb,
+ duk_debug_peek_function peek_cb,
+ duk_debug_read_flush_function read_flush_cb,
+ duk_debug_write_flush_function write_flush_cb,
+ duk_debug_request_function request_cb,
+ duk_debug_detached_function detached_cb,
+ void *udata) {
duk_heap *heap;
const char *str;
duk_size_t len;
@@ -13854,7 +15551,7 @@ DUK_EXTERNAL void duk_debugger_attach_custom(duk_context *ctx,
DUK_D(DUK_DPRINT("application called duk_debugger_attach()"));
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(read_cb != NULL);
DUK_ASSERT(write_cb != NULL);
/* Other callbacks are optional. */
@@ -13872,59 +15569,51 @@ DUK_EXTERNAL void duk_debugger_attach_custom(duk_context *ctx,
/* Start in paused state. */
heap->dbg_processing = 0;
- heap->dbg_paused = 1;
- heap->dbg_state_dirty = 1;
+ heap->dbg_state_dirty = 0;
heap->dbg_force_restart = 0;
- heap->dbg_step_type = 0;
- heap->dbg_step_thread = NULL;
- heap->dbg_step_csindex = 0;
- heap->dbg_step_startline = 0;
+ heap->dbg_pause_flags = 0;
+ heap->dbg_pause_act = NULL;
+ heap->dbg_pause_startline = 0;
heap->dbg_exec_counter = 0;
heap->dbg_last_counter = 0;
heap->dbg_last_time = 0.0;
+ duk_debug_set_paused(heap); /* XXX: overlap with fields above */
/* Send version identification and flush right afterwards. Note that
* we must write raw, unframed bytes here.
*/
- duk_push_sprintf(ctx, "%ld %ld %s %s\n",
+ duk_push_sprintf(thr, "%ld %ld %s %s\n",
(long) DUK_DEBUG_PROTOCOL_VERSION,
(long) DUK_VERSION,
(const char *) DUK_GIT_DESCRIBE,
(const char *) DUK_USE_TARGET_INFO);
- str = duk_get_lstring(ctx, -1, &len);
+ str = duk_get_lstring(thr, -1, &len);
DUK_ASSERT(str != NULL);
duk_debug_write_bytes(thr, (const duk_uint8_t *) str, len);
duk_debug_write_flush(thr);
- duk_pop(ctx);
+ duk_pop(thr);
}
-DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) {
- duk_hthread *thr;
-
+DUK_EXTERNAL void duk_debugger_detach(duk_hthread *thr) {
DUK_D(DUK_DPRINT("application called duk_debugger_detach()"));
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
/* Can be called multiple times with no harm. */
duk_debug_do_detach(thr->heap);
}
-DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_debugger_cooperate(duk_hthread *thr) {
duk_bool_t processed_messages;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
- if (!DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
+ if (!duk_debug_is_attached(thr->heap)) {
return;
}
- if (thr->callstack_top > 0 || thr->heap->dbg_processing) {
+ if (thr->callstack_curr != NULL || thr->heap->dbg_processing) {
/* Calling duk_debugger_cooperate() while Duktape is being
* called into is not supported. This is not a 100% check
* but prevents any damage in most cases.
@@ -13936,28 +15625,25 @@ DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) {
DUK_UNREF(processed_messages);
}
-DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues) {
- duk_hthread *thr;
+DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_hthread *thr, duk_idx_t nvalues) {
duk_idx_t top;
duk_idx_t idx;
duk_bool_t ret = 0;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
DUK_D(DUK_DPRINT("application called duk_debugger_notify() with nvalues=%ld", (long) nvalues));
- top = duk_get_top(ctx);
+ top = duk_get_top(thr);
if (top < nvalues) {
- DUK_ERROR_API(thr, "not enough stack values for notify");
+ DUK_ERROR_RANGE(thr, "not enough stack values for notify");
return ret; /* unreachable */
}
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
+ if (duk_debug_is_attached(thr->heap)) {
duk_debug_write_notify(thr, DUK_DBG_CMD_APPNOTIFY);
for (idx = top - nvalues; idx < top; idx++) {
- duk_tval *tv = DUK_GET_TVAL_POSIDX(ctx, idx);
+ duk_tval *tv = DUK_GET_TVAL_POSIDX(thr, idx);
duk_debug_write_tval(thr, tv);
}
duk_debug_write_eom(thr);
@@ -13967,49 +15653,49 @@ DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues)
* a transport error was not indicated by the transport write
* callback. This is not a 100% guarantee of course.
*/
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
+ if (duk_debug_is_attached(thr->heap)) {
ret = 1;
}
}
- duk_pop_n(ctx, nvalues);
+ duk_pop_n(thr, nvalues);
return ret;
}
-DUK_EXTERNAL void duk_debugger_pause(duk_context *ctx) {
- duk_hthread *thr;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr != NULL);
+DUK_EXTERNAL void duk_debugger_pause(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
DUK_D(DUK_DPRINT("application called duk_debugger_pause()"));
/* Treat like a debugger statement: ignore when not attached. */
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
- DUK_HEAP_SET_PAUSED(thr->heap);
+ if (duk_debug_is_attached(thr->heap)) {
+ if (duk_debug_is_paused(thr->heap)) {
+ DUK_D(DUK_DPRINT("duk_debugger_pause() called when already paused; ignoring"));
+ } else {
+ duk_debug_set_paused(thr->heap);
- /* Pause on the next opcode executed. This is always safe to do even
- * inside the debugger message loop: the interrupt counter will be reset
- * to its proper value when the message loop exits.
- */
- thr->interrupt_init = 1;
- thr->interrupt_counter = 0;
+ /* Pause on the next opcode executed. This is always safe to do even
+ * inside the debugger message loop: the interrupt counter will be reset
+ * to its proper value when the message loop exits.
+ */
+ thr->interrupt_init = 1;
+ thr->interrupt_counter = 0;
+ }
}
}
#else /* DUK_USE_DEBUGGER_SUPPORT */
-DUK_EXTERNAL void duk_debugger_attach_custom(duk_context *ctx,
- duk_debug_read_function read_cb,
- duk_debug_write_function write_cb,
- duk_debug_peek_function peek_cb,
- duk_debug_read_flush_function read_flush_cb,
- duk_debug_write_flush_function write_flush_cb,
- duk_debug_request_function request_cb,
- duk_debug_detached_function detached_cb,
- void *udata) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_debugger_attach(duk_hthread *thr,
+ duk_debug_read_function read_cb,
+ duk_debug_write_function write_cb,
+ duk_debug_peek_function peek_cb,
+ duk_debug_read_flush_function read_flush_cb,
+ duk_debug_write_flush_function write_flush_cb,
+ duk_debug_request_function request_cb,
+ duk_debug_detached_function detached_cb,
+ void *udata) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_UNREF(read_cb);
DUK_UNREF(write_cb);
DUK_UNREF(peek_cb);
@@ -14018,40 +15704,40 @@ DUK_EXTERNAL void duk_debugger_attach_custom(duk_context *ctx,
DUK_UNREF(request_cb);
DUK_UNREF(detached_cb);
DUK_UNREF(udata);
- DUK_ERROR_API((duk_hthread *) ctx, "no debugger support");
+ DUK_ERROR_TYPE(thr, "no debugger support");
}
-DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ERROR_API((duk_hthread *) ctx, "no debugger support");
+DUK_EXTERNAL void duk_debugger_detach(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ERROR_TYPE(thr, "no debugger support");
}
-DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) {
+DUK_EXTERNAL void duk_debugger_cooperate(duk_hthread *thr) {
/* nop */
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(thr);
}
-DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues) {
+DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_hthread *thr, duk_idx_t nvalues) {
duk_idx_t top;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- top = duk_get_top(ctx);
+ top = duk_get_top(thr);
if (top < nvalues) {
- DUK_ERROR_API((duk_hthread *) ctx, "not enough stack values for notify");
+ DUK_ERROR_RANGE_INVALID_COUNT(thr);
return 0; /* unreachable */
}
/* No debugger support, just pop values. */
- duk_pop_n(ctx, nvalues);
+ duk_pop_n(thr, nvalues);
return 0;
}
-DUK_EXTERNAL void duk_debugger_pause(duk_context *ctx) {
+DUK_EXTERNAL void duk_debugger_pause(duk_hthread *thr) {
/* Treat like debugger statement: nop */
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(thr);
}
#endif /* DUK_USE_DEBUGGER_SUPPORT */
@@ -14060,25 +15746,24 @@ DUK_EXTERNAL void duk_debugger_pause(duk_context *ctx) {
* Heap creation and destruction
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
typedef struct duk_internal_thread_state duk_internal_thread_state;
struct duk_internal_thread_state {
duk_ljstate lj;
- duk_bool_t handling_error;
+ duk_bool_t creating_error;
duk_hthread *curr_thread;
duk_int_t call_recursion_depth;
};
-DUK_EXTERNAL
-duk_context *duk_create_heap(duk_alloc_function alloc_func,
- duk_realloc_function realloc_func,
- duk_free_function free_func,
- void *heap_udata,
- duk_fatal_function fatal_handler) {
+DUK_EXTERNAL duk_hthread *duk_create_heap(duk_alloc_function alloc_func,
+ duk_realloc_function realloc_func,
+ duk_free_function free_func,
+ void *heap_udata,
+ duk_fatal_function fatal_handler) {
duk_heap *heap = NULL;
- duk_context *ctx;
+ duk_hthread *thr;
/* Assume that either all memory funcs are NULL or non-NULL, mixed
* cases will now be unsafe.
@@ -14117,44 +15802,55 @@ duk_context *duk_create_heap(duk_alloc_function alloc_func,
if (!heap) {
return NULL;
}
- ctx = (duk_context *) heap->heap_thread;
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(((duk_hthread *) ctx)->heap != NULL);
- return ctx;
+ thr = heap->heap_thread;
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(thr->heap != NULL);
+ return thr;
}
-DUK_EXTERNAL void duk_destroy_heap(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_destroy_heap(duk_hthread *thr) {
duk_heap *heap;
- if (!ctx) {
+ if (!thr) {
return;
}
+ DUK_ASSERT_API_ENTRY(thr);
heap = thr->heap;
DUK_ASSERT(heap != NULL);
duk_heap_free(heap);
}
-DUK_EXTERNAL void duk_suspend(duk_context *ctx, duk_thread_state *state) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_suspend(duk_hthread *thr, duk_thread_state *state) {
duk_internal_thread_state *snapshot = (duk_internal_thread_state *) (void *) state;
duk_heap *heap;
duk_ljstate *lj;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT(state != NULL); /* unvalidated */
+ /* Currently not supported when called from within a finalizer.
+ * If that is done, the finalizer will remain running indefinitely,
+ * preventing other finalizers from executing. The assert is a bit
+ * wider, checking that it would be OK to run pending finalizers.
+ */
+ DUK_ASSERT(thr->heap->pf_prevent_count == 0);
+
+ /* Currently not supported to duk_suspend() from an errCreate()
+ * call.
+ */
+ DUK_ASSERT(thr->heap->creating_error == 0);
+
heap = thr->heap;
lj = &heap->lj;
- duk_push_tval(ctx, &lj->value1);
- duk_push_tval(ctx, &lj->value2);
+ duk_push_tval(thr, &lj->value1);
+ duk_push_tval(thr, &lj->value2);
+ /* XXX: creating_error == 0 is asserted above, so no need to store. */
DUK_MEMCPY((void *) &snapshot->lj, (const void *) lj, sizeof(duk_ljstate));
- snapshot->handling_error = heap->handling_error;
+ snapshot->creating_error = heap->creating_error;
snapshot->curr_thread = heap->curr_thread;
snapshot->call_recursion_depth = heap->call_recursion_depth;
@@ -14162,42 +15858,47 @@ DUK_EXTERNAL void duk_suspend(duk_context *ctx, duk_thread_state *state) {
lj->type = DUK_LJ_TYPE_UNKNOWN;
DUK_TVAL_SET_UNDEFINED(&lj->value1);
DUK_TVAL_SET_UNDEFINED(&lj->value2);
- heap->handling_error = 0;
+ heap->creating_error = 0;
heap->curr_thread = NULL;
heap->call_recursion_depth = 0;
}
-DUK_EXTERNAL void duk_resume(duk_context *ctx, const duk_thread_state *state) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_resume(duk_hthread *thr, const duk_thread_state *state) {
const duk_internal_thread_state *snapshot = (const duk_internal_thread_state *) (const void *) state;
duk_heap *heap;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT(state != NULL); /* unvalidated */
+ /* Shouldn't be necessary if duk_suspend() is called before
+ * duk_resume(), but assert in case API sequence is incorrect.
+ */
+ DUK_ASSERT(thr->heap->pf_prevent_count == 0);
+ DUK_ASSERT(thr->heap->creating_error == 0);
+
heap = thr->heap;
DUK_MEMCPY((void *) &heap->lj, (const void *) &snapshot->lj, sizeof(duk_ljstate));
- heap->handling_error = snapshot->handling_error;
+ heap->creating_error = snapshot->creating_error;
heap->curr_thread = snapshot->curr_thread;
heap->call_recursion_depth = snapshot->call_recursion_depth;
- duk_pop_2(ctx);
+ duk_pop_2(thr);
}
/* XXX: better place for this */
-DUK_EXTERNAL void duk_set_global_object(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_set_global_object(duk_hthread *thr) {
duk_hobject *h_glob;
duk_hobject *h_prev_glob;
- duk_hobject *h_env;
+ duk_hobjenv *h_env;
duk_hobject *h_prev_env;
- DUK_D(DUK_DPRINT("replace global object with: %!T", duk_get_tval(ctx, -1)));
+ DUK_ASSERT_API_ENTRY(thr);
- h_glob = duk_require_hobject(ctx, -1);
+ DUK_D(DUK_DPRINT("replace global object with: %!T", duk_get_tval(thr, -1)));
+
+ h_glob = duk_require_hobject(thr, -1);
DUK_ASSERT(h_glob != NULL);
/*
@@ -14219,141 +15920,318 @@ DUK_EXTERNAL void duk_set_global_object(duk_context *ctx) {
* same (initial) built-ins.
*/
- (void) duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV),
- -1); /* no prototype, updated below */
-
- duk_dup(ctx, -2);
- duk_dup(ctx, -3);
-
- /* [ ... new_glob new_env new_glob new_glob ] */
-
- duk_xdef_prop_stridx(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
- duk_xdef_prop_stridx(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE);
-
- /* [ ... new_glob new_env ] */
-
- h_env = duk_get_hobject(ctx, -1);
+ h_env = duk_hobjenv_alloc(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV));
DUK_ASSERT(h_env != NULL);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_env) == NULL);
+
+ DUK_ASSERT(h_env->target == NULL);
+ DUK_ASSERT(h_glob != NULL);
+ h_env->target = h_glob;
+ DUK_HOBJECT_INCREF(thr, h_glob);
+ DUK_ASSERT(h_env->has_this == 0);
+
+ /* [ ... new_glob ] */
h_prev_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
- thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_env;
- DUK_HOBJECT_INCREF(thr, h_env);
+ thr->builtins[DUK_BIDX_GLOBAL_ENV] = (duk_hobject *) h_env;
+ DUK_HOBJECT_INCREF(thr, (duk_hobject *) h_env);
DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_env); /* side effects */
DUK_UNREF(h_env); /* without refcounts */
DUK_UNREF(h_prev_env);
- /* [ ... new_glob new_env ] */
+ /* [ ... new_glob ] */
- duk_pop_2(ctx);
+ duk_pop(thr);
/* [ ... ] */
}
-#line 1 "duk_api_logging.c"
+#line 1 "duk_api_inspect.c"
/*
- * Logging
- *
- * Current logging primitive is a sprintf-style log which is convenient
- * for most C code. Another useful primitive would be to log N arguments
- * from value stack (like the Ecmascript binding does).
+ * Inspection
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-DUK_EXTERNAL void duk_log_va(duk_context *ctx, duk_int_t level, const char *fmt, va_list ap) {
- /* stridx_logfunc[] must be static to allow initializer with old compilers like BCC */
- static const duk_uint16_t stridx_logfunc[6] = {
- DUK_STRIDX_LC_TRACE, DUK_STRIDX_LC_DEBUG, DUK_STRIDX_LC_INFO,
- DUK_STRIDX_LC_WARN, DUK_STRIDX_LC_ERROR, DUK_STRIDX_LC_FATAL
- };
+/* For footprint efficient multiple value setting: arrays are much better than
+ * varargs, format string with parsing is often better than string pointer arrays.
+ */
+DUK_LOCAL void duk__inspect_multiple_uint(duk_hthread *thr, const char *fmt, duk_int_t *vals) {
+ duk_int_t val;
+ const char *p;
+ const char *p_curr;
+ duk_size_t len;
- DUK_ASSERT_CTX_VALID(ctx);
+ for (p = fmt;;) {
+ len = DUK_STRLEN(p);
+ p_curr = p;
+ p += len + 1;
+ if (len == 0) {
+ /* Double NUL (= empty key) terminates. */
+ break;
+ }
+ val = *vals++;
+ if (val >= 0) {
+ /* Negative values are markers to skip key. */
+ duk_push_string(thr, p_curr);
+ duk_push_int(thr, val);
+ duk_put_prop(thr, -3);
+ }
+ }
+}
- if (level < 0) {
- level = 0;
- } else if (level > (int) (sizeof(stridx_logfunc) / sizeof(duk_uint16_t)) - 1) {
- level = (int) (sizeof(stridx_logfunc) / sizeof(duk_uint16_t)) - 1;
+/* Raw helper to extract internal information / statistics about a value.
+ * The return value is an object with properties that are version specific.
+ * The properties must not expose anything that would lead to security
+ * issues (e.g. exposing compiled function 'data' buffer might be an issue).
+ * Currently only counts and sizes and such are given so there shouldn't
+ * be security implications.
+ */
+
+#define DUK__IDX_TYPE 0
+#define DUK__IDX_ITAG 1
+#define DUK__IDX_REFC 2
+#define DUK__IDX_HBYTES 3
+#define DUK__IDX_CLASS 4
+#define DUK__IDX_PBYTES 5
+#define DUK__IDX_ESIZE 6
+#define DUK__IDX_ENEXT 7
+#define DUK__IDX_ASIZE 8
+#define DUK__IDX_HSIZE 9
+#define DUK__IDX_BCBYTES 10
+#define DUK__IDX_DBYTES 11
+#define DUK__IDX_TSTATE 12
+#define DUK__IDX_VARIANT 13
+
+DUK_EXTERNAL void duk_inspect_value(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+ duk_heaphdr *h;
+ /* The temporary values should be in an array rather than individual
+ * variables which (in practice) ensures that the compiler won't map
+ * them to registers and emit a lot of unnecessary shuffling code.
+ */
+ duk_int_t vals[14];
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ /* Assume two's complement and set everything to -1. */
+ DUK_MEMSET((void *) &vals, (int) 0xff, sizeof(vals));
+ DUK_ASSERT(vals[DUK__IDX_TYPE] == -1); /* spot check one */
+
+ tv = duk_get_tval_or_unused(thr, idx);
+ h = (DUK_TVAL_IS_HEAP_ALLOCATED(tv) ? DUK_TVAL_GET_HEAPHDR(tv) : NULL);
+
+ vals[DUK__IDX_TYPE] = duk_get_type_tval(tv);
+ vals[DUK__IDX_ITAG] = (duk_int_t) DUK_TVAL_GET_TAG(tv);
+
+ duk_push_bare_object(thr); /* Invalidates 'tv'. */
+ tv = NULL;
+
+ if (h == NULL) {
+ goto finish;
+ }
+ duk_push_pointer(thr, (void *) h);
+ duk_put_prop_string(thr, -2, "hptr");
+
+#if 0
+ /* Covers a lot of information, e.g. buffer and string variants. */
+ duk_push_uint(thr, (duk_uint_t) DUK_HEAPHDR_GET_FLAGS(h));
+ duk_put_prop_string(thr, -2, "hflags");
+#endif
+
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ vals[DUK__IDX_REFC] = (duk_int_t) DUK_HEAPHDR_GET_REFCOUNT(h);
+#endif
+ vals[DUK__IDX_VARIANT] = 0;
+
+ /* Heaphdr size and additional allocation size, followed by
+ * type specific stuff (with varying value count).
+ */
+ switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) {
+ case DUK_HTYPE_STRING: {
+ duk_hstring *h_str = (duk_hstring *) h;
+ vals[DUK__IDX_HBYTES] = (duk_int_t) (sizeof(duk_hstring) + DUK_HSTRING_GET_BYTELEN(h_str) + 1);
+#if defined(DUK_USE_HSTRING_EXTDATA)
+ if (DUK_HSTRING_HAS_EXTDATA(h_str)) {
+ vals[DUK__IDX_VARIANT] = 1;
+ }
+#endif
+ break;
+ }
+ case DUK_HTYPE_OBJECT: {
+ duk_hobject *h_obj = (duk_hobject *) h;
+
+ /* XXX: variants here are maybe pointless; class is enough? */
+ if (DUK_HOBJECT_IS_ARRAY(h_obj)) {
+ vals[DUK__IDX_HBYTES] = sizeof(duk_harray);
+ } else if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) {
+ vals[DUK__IDX_HBYTES] = sizeof(duk_hcompfunc);
+ } else if (DUK_HOBJECT_IS_NATFUNC(h_obj)) {
+ vals[DUK__IDX_HBYTES] = sizeof(duk_hnatfunc);
+ } else if (DUK_HOBJECT_IS_THREAD(h_obj)) {
+ vals[DUK__IDX_HBYTES] = sizeof(duk_hthread);
+ vals[DUK__IDX_TSTATE] = ((duk_hthread *) h_obj)->state;
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+ } else if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
+ vals[DUK__IDX_HBYTES] = sizeof(duk_hbufobj);
+ /* XXX: some size information */
+#endif
+ } else {
+ vals[DUK__IDX_HBYTES] = (duk_small_uint_t) sizeof(duk_hobject);
+ }
+
+ vals[DUK__IDX_CLASS] = (duk_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h_obj);
+ vals[DUK__IDX_PBYTES] = (duk_int_t) DUK_HOBJECT_P_ALLOC_SIZE(h_obj),
+ vals[DUK__IDX_ESIZE] = (duk_int_t) DUK_HOBJECT_GET_ESIZE(h_obj);
+ vals[DUK__IDX_ENEXT] = (duk_int_t) DUK_HOBJECT_GET_ENEXT(h_obj);
+ vals[DUK__IDX_ASIZE] = (duk_int_t) DUK_HOBJECT_GET_ASIZE(h_obj);
+ vals[DUK__IDX_HSIZE] = (duk_int_t) DUK_HOBJECT_GET_HSIZE(h_obj);
+
+ /* Note: e_next indicates the number of gc-reachable entries
+ * in the entry part, and also indicates the index where the
+ * next new property would be inserted. It does *not* indicate
+ * the number of non-NULL keys present in the object. That
+ * value could be counted separately but requires a pass through
+ * the key list.
+ */
+
+ if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) {
+ duk_hbuffer *h_data = (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(thr->heap, (duk_hcompfunc *) h_obj);
+ vals[DUK__IDX_BCBYTES] = (duk_int_t) (h_data ? DUK_HBUFFER_GET_SIZE(h_data) : 0);
+ }
+ break;
+ }
+ case DUK_HTYPE_BUFFER: {
+ duk_hbuffer *h_buf = (duk_hbuffer *) h;
+
+ if (DUK_HBUFFER_HAS_DYNAMIC(h_buf)) {
+ if (DUK_HBUFFER_HAS_EXTERNAL(h_buf)) {
+ vals[DUK__IDX_VARIANT] = 2; /* buffer variant 2: external */
+ vals[DUK__IDX_HBYTES] = (duk_uint_t) (sizeof(duk_hbuffer_external));
+ } else {
+ /* When alloc_size == 0 the second allocation may not
+ * actually exist.
+ */
+ vals[DUK__IDX_VARIANT] = 1; /* buffer variant 1: dynamic */
+ vals[DUK__IDX_HBYTES] = (duk_uint_t) (sizeof(duk_hbuffer_dynamic));
+ }
+ vals[DUK__IDX_DBYTES] = (duk_int_t) (DUK_HBUFFER_GET_SIZE(h_buf));
+ } else {
+ DUK_ASSERT(vals[DUK__IDX_VARIANT] == 0); /* buffer variant 0: fixed */
+ vals[DUK__IDX_HBYTES] = (duk_int_t) (sizeof(duk_hbuffer_fixed) + DUK_HBUFFER_GET_SIZE(h_buf));
+ }
+ break;
+ }
}
- duk_push_hobject_bidx(ctx, DUK_BIDX_LOGGER_CONSTRUCTOR);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_CLOG);
- duk_get_prop_stridx(ctx, -1, stridx_logfunc[level]);
- duk_dup(ctx, -2);
-
- /* [ ... Logger clog logfunc clog ] */
-
- duk_push_vsprintf(ctx, fmt, ap);
-
- /* [ ... Logger clog logfunc clog(=this) msg ] */
-
- duk_call_method(ctx, 1 /*nargs*/);
-
- /* [ ... Logger clog res ] */
-
- duk_pop_3(ctx);
+ finish:
+ duk__inspect_multiple_uint(thr,
+ "type" "\x00" "itag" "\x00" "refc" "\x00" "hbytes" "\x00" "class" "\x00"
+ "pbytes" "\x00" "esize" "\x00" "enext" "\x00" "asize" "\x00" "hsize" "\x00"
+ "bcbytes" "\x00" "dbytes" "\x00" "tstate" "\x00" "variant" "\x00" "\x00",
+ (duk_int_t *) &vals);
}
-DUK_EXTERNAL void duk_log(duk_context *ctx, duk_int_t level, const char *fmt, ...) {
- va_list ap;
+DUK_EXTERNAL void duk_inspect_callstack_entry(duk_hthread *thr, duk_int_t level) {
+ duk_activation *act;
+ duk_uint_fast32_t pc;
+ duk_uint_fast32_t line;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- va_start(ap, fmt);
- duk_log_va(ctx, level, fmt, ap);
- va_end(ap);
+ /* -1 = top callstack entry
+ * -2 = caller of level -1
+ * etc
+ */
+ act = duk_hthread_get_activation_for_level(thr, level);
+ if (act == NULL) {
+ duk_push_undefined(thr);
+ return;
+ }
+ duk_push_bare_object(thr);
+
+ /* Relevant PC is just before current one because PC is
+ * post-incremented. This should match what error augment
+ * code does.
+ */
+ pc = duk_hthread_get_act_prev_pc(thr, act);
+
+ duk_push_tval(thr, &act->tv_func);
+
+ duk_push_uint(thr, (duk_uint_t) pc);
+ duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_PC);
+
+#if defined(DUK_USE_PC2LINE)
+ line = duk_hobject_pc2line_query(thr, -1, pc);
+#else
+ line = 0;
+#endif
+ duk_push_uint(thr, (duk_uint_t) line);
+ duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_LINE_NUMBER);
+
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_LC_FUNCTION);
+ /* Providing access to e.g. act->lex_env would be dangerous: these
+ * internal structures must never be accessible to the application.
+ * Duktape relies on them having consistent data, and this consistency
+ * is only asserted for, not checked for.
+ */
}
+
+/* automatic undefs */
+#undef DUK__IDX_ASIZE
+#undef DUK__IDX_BCBYTES
+#undef DUK__IDX_CLASS
+#undef DUK__IDX_DBYTES
+#undef DUK__IDX_ENEXT
+#undef DUK__IDX_ESIZE
+#undef DUK__IDX_HBYTES
+#undef DUK__IDX_HSIZE
+#undef DUK__IDX_ITAG
+#undef DUK__IDX_PBYTES
+#undef DUK__IDX_REFC
+#undef DUK__IDX_TSTATE
+#undef DUK__IDX_TYPE
+#undef DUK__IDX_VARIANT
#line 1 "duk_api_memory.c"
/*
* Memory calls.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-DUK_EXTERNAL void *duk_alloc_raw(duk_context *ctx, duk_size_t size) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void *duk_alloc_raw(duk_hthread *thr, duk_size_t size) {
+ DUK_ASSERT_API_ENTRY(thr);
return DUK_ALLOC_RAW(thr->heap, size);
}
-DUK_EXTERNAL void duk_free_raw(duk_context *ctx, void *ptr) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_free_raw(duk_hthread *thr, void *ptr) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_FREE_RAW(thr->heap, ptr);
}
-DUK_EXTERNAL void *duk_realloc_raw(duk_context *ctx, void *ptr, duk_size_t size) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void *duk_realloc_raw(duk_hthread *thr, void *ptr, duk_size_t size) {
+ DUK_ASSERT_API_ENTRY(thr);
return DUK_REALLOC_RAW(thr->heap, ptr, size);
}
-DUK_EXTERNAL void *duk_alloc(duk_context *ctx, duk_size_t size) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void *duk_alloc(duk_hthread *thr, duk_size_t size) {
+ DUK_ASSERT_API_ENTRY(thr);
return DUK_ALLOC(thr->heap, size);
}
-DUK_EXTERNAL void duk_free(duk_context *ctx, void *ptr) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_free(duk_hthread *thr, void *ptr) {
+ DUK_ASSERT_API_ENTRY(thr);
- DUK_ASSERT_CTX_VALID(ctx);
-
- DUK_FREE(thr->heap, ptr);
+ DUK_FREE_CHECKED(thr, ptr);
}
-DUK_EXTERNAL void *duk_realloc(duk_context *ctx, void *ptr, duk_size_t size) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void *duk_realloc(duk_hthread *thr, void *ptr, duk_size_t size) {
+ DUK_ASSERT_API_ENTRY(thr);
/*
* Note: since this is an exposed API call, there should be
@@ -14368,11 +16246,10 @@ DUK_EXTERNAL void *duk_realloc(duk_context *ctx, void *ptr, duk_size_t size) {
return DUK_REALLOC(thr->heap, ptr, size);
}
-DUK_EXTERNAL void duk_get_memory_functions(duk_context *ctx, duk_memory_functions *out_funcs) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_get_memory_functions(duk_hthread *thr, duk_memory_functions *out_funcs) {
duk_heap *heap;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(out_funcs != NULL);
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
@@ -14384,35 +16261,25 @@ DUK_EXTERNAL void duk_get_memory_functions(duk_context *ctx, duk_memory_function
out_funcs->udata = heap->heap_udata;
}
-DUK_EXTERNAL void duk_gc(duk_context *ctx, duk_uint_t flags) {
-#ifdef DUK_USE_MARK_AND_SWEEP
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_gc(duk_hthread *thr, duk_uint_t flags) {
duk_heap *heap;
+ duk_small_uint_t ms_flags;
- DUK_UNREF(flags);
-
- /* NULL accepted */
- if (!ctx) {
- return;
- }
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
heap = thr->heap;
DUK_ASSERT(heap != NULL);
DUK_D(DUK_DPRINT("mark-and-sweep requested by application"));
- duk_heap_mark_and_sweep(heap, 0);
-#else
- DUK_D(DUK_DPRINT("mark-and-sweep requested by application but mark-and-sweep not enabled, ignoring"));
- DUK_UNREF(ctx);
- DUK_UNREF(flags);
-#endif
+ DUK_ASSERT(DUK_GC_COMPACT == DUK_MS_FLAG_EMERGENCY); /* Compact flag is 1:1 with emergency flag which forces compaction. */
+ ms_flags = (duk_small_uint_t) flags;
+ duk_heap_mark_and_sweep(heap, ms_flags);
}
#line 1 "duk_api_object.c"
/*
* Object handling: property access and other support functions.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Property handling
@@ -14422,82 +16289,98 @@ DUK_EXTERNAL void duk_gc(duk_context *ctx, duk_uint_t flags) {
* defineProperty, getOwnPropertyDescriptor).
*/
-DUK_EXTERNAL duk_bool_t duk_get_prop(duk_context *ctx, duk_idx_t obj_index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_get_prop(duk_hthread *thr, duk_idx_t obj_idx) {
duk_tval *tv_obj;
duk_tval *tv_key;
duk_bool_t rc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* Note: copying tv_obj and tv_key to locals to shield against a valstack
* resize is not necessary for a property get right now.
*/
- tv_obj = duk_require_tval(ctx, obj_index);
- tv_key = duk_require_tval(ctx, -1);
+ tv_obj = duk_require_tval(thr, obj_idx);
+ tv_key = duk_require_tval(thr, -1);
rc = duk_hobject_getprop(thr, tv_obj, tv_key);
DUK_ASSERT(rc == 0 || rc == 1);
/* a value is left on stack regardless of rc */
- duk_remove(ctx, -2); /* remove key */
+ duk_remove_m2(thr); /* remove key */
+ DUK_ASSERT(duk_is_undefined(thr, -1) || rc == 1);
return rc; /* 1 if property found, 0 otherwise */
}
-DUK_EXTERNAL duk_bool_t duk_get_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_get_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(key != NULL);
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_string(ctx, key);
- return duk_get_prop(ctx, obj_index);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_string(thr, key);
+ return duk_get_prop(thr, obj_idx);
}
-DUK_EXTERNAL duk_bool_t duk_get_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_get_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(key != NULL);
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_uarridx(ctx, arr_index);
- return duk_get_prop(ctx, obj_index);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_lstring(thr, key, key_len);
+ return duk_get_prop(thr, obj_idx);
}
-DUK_INTERNAL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_get_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(stridx >= 0);
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
- DUK_UNREF(thr);
-
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
- return duk_get_prop(ctx, obj_index);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_uarridx(thr, arr_idx);
+ return duk_get_prop(thr, obj_idx);
}
-DUK_INTERNAL duk_bool_t duk_get_prop_stridx_boolean(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_bool_t *out_has_prop) {
+DUK_EXTERNAL duk_bool_t duk_get_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
+ return duk_get_prop(thr, obj_idx);
+}
+
+DUK_INTERNAL duk_bool_t duk_get_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT_STRIDX_VALID(stridx);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
+ return duk_get_prop(thr, obj_idx);
+}
+
+DUK_INTERNAL duk_bool_t duk_get_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
+ return duk_get_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
+ (duk_small_uint_t) (packed_args & 0xffffUL));
+}
+
+DUK_INTERNAL duk_bool_t duk_get_prop_stridx_boolean(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_bool_t *out_has_prop) {
duk_bool_t rc;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(stridx >= 0);
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT_STRIDX_VALID(stridx);
- rc = duk_get_prop_stridx(ctx, obj_index, stridx);
+ rc = duk_get_prop_stridx(thr, obj_idx, stridx);
if (out_has_prop) {
*out_has_prop = rc;
}
- rc = duk_to_boolean(ctx, -1);
+ rc = duk_to_boolean(thr, -1);
DUK_ASSERT(rc == 0 || rc == 1);
- duk_pop(ctx);
+ duk_pop(thr);
return rc;
}
-DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t idx_key) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t idx_key) {
duk_tval *tv_obj;
duk_tval *tv_key;
duk_tval *tv_val;
- duk_small_int_t throw_flag;
+ duk_bool_t throw_flag;
duk_bool_t rc;
/* Note: copying tv_obj and tv_key to locals to shield against a valstack
@@ -14510,254 +16393,323 @@ DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_context *ctx, duk_idx_t obj_idx, d
*/
DUK_ASSERT((idx_key == -2 && (idx_key ^ 1) == -1) ||
(idx_key == -1 && (idx_key ^ 1) == -2));
- tv_obj = duk_require_tval(ctx, obj_idx);
- tv_key = duk_require_tval(ctx, idx_key);
- tv_val = duk_require_tval(ctx, idx_key ^ 1);
- throw_flag = duk_is_strict_call(ctx);
+ /* XXX: Direct access; faster validation. */
+ tv_obj = duk_require_tval(thr, obj_idx);
+ tv_key = duk_require_tval(thr, idx_key);
+ tv_val = duk_require_tval(thr, idx_key ^ 1);
+ throw_flag = duk_is_strict_call(thr);
rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, throw_flag);
DUK_ASSERT(rc == 0 || rc == 1);
- duk_pop_2(ctx); /* remove key and value */
+ duk_pop_2(thr); /* remove key and value */
return rc; /* 1 if property found, 0 otherwise */
}
-DUK_EXTERNAL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_idx) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__put_prop_shared(ctx, obj_idx, -2);
+DUK_EXTERNAL duk_bool_t duk_put_prop(duk_hthread *thr, duk_idx_t obj_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__put_prop_shared(thr, obj_idx, -2);
}
-DUK_EXTERNAL duk_bool_t duk_put_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_put_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(key != NULL);
/* Careful here and with other duk_put_prop_xxx() helpers: the
* target object and the property value may be in the same value
* stack slot (unusual, but still conceptually clear).
*/
- obj_idx = duk_normalize_index(ctx, obj_idx);
- (void) duk_push_string(ctx, key);
- return duk__put_prop_shared(ctx, obj_idx, -1);
+ obj_idx = duk_normalize_index(thr, obj_idx);
+ (void) duk_push_string(thr, key);
+ return duk__put_prop_shared(thr, obj_idx, -1);
}
-DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_put_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(key != NULL);
- obj_idx = duk_require_normalize_index(ctx, obj_idx);
- duk_push_uarridx(ctx, arr_idx);
- return duk__put_prop_shared(ctx, obj_idx, -1);
+ obj_idx = duk_normalize_index(thr, obj_idx);
+ (void) duk_push_lstring(thr, key, key_len);
+ return duk__put_prop_shared(thr, obj_idx, -1);
}
-DUK_INTERNAL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_int_t stridx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(stridx >= 0);
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
- DUK_UNREF(thr);
-
- obj_idx = duk_require_normalize_index(ctx, obj_idx);
- duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
- return duk__put_prop_shared(ctx, obj_idx, -1);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_uarridx(thr, arr_idx);
+ return duk__put_prop_shared(thr, obj_idx, -1);
}
-DUK_EXTERNAL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_put_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
+ return duk__put_prop_shared(thr, obj_idx, -1);
+}
+
+
+DUK_INTERNAL duk_bool_t duk_put_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT_STRIDX_VALID(stridx);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
+ return duk__put_prop_shared(thr, obj_idx, -1);
+}
+
+DUK_INTERNAL duk_bool_t duk_put_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
+ return duk_put_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
+ (duk_small_uint_t) (packed_args & 0xffffUL));
+}
+
+DUK_EXTERNAL duk_bool_t duk_del_prop(duk_hthread *thr, duk_idx_t obj_idx) {
duk_tval *tv_obj;
duk_tval *tv_key;
- duk_small_int_t throw_flag;
+ duk_bool_t throw_flag;
duk_bool_t rc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* Note: copying tv_obj and tv_key to locals to shield against a valstack
* resize is not necessary for a property delete right now.
*/
- tv_obj = duk_require_tval(ctx, obj_index);
- tv_key = duk_require_tval(ctx, -1);
- throw_flag = duk_is_strict_call(ctx);
+ tv_obj = duk_require_tval(thr, obj_idx);
+ tv_key = duk_require_tval(thr, -1);
+ throw_flag = duk_is_strict_call(thr);
rc = duk_hobject_delprop(thr, tv_obj, tv_key, throw_flag);
DUK_ASSERT(rc == 0 || rc == 1);
- duk_pop(ctx); /* remove key */
+ duk_pop(thr); /* remove key */
return rc;
}
-DUK_EXTERNAL duk_bool_t duk_del_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_del_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(key != NULL);
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_string(ctx, key);
- return duk_del_prop(ctx, obj_index);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_string(thr, key);
+ return duk_del_prop(thr, obj_idx);
}
-DUK_EXTERNAL duk_bool_t duk_del_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_del_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(key != NULL);
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_uarridx(ctx, arr_index);
- return duk_del_prop(ctx, obj_index);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_lstring(thr, key, key_len);
+ return duk_del_prop(thr, obj_idx);
}
-DUK_INTERNAL duk_bool_t duk_del_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_del_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(stridx >= 0);
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
- DUK_UNREF(thr);
-
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
- return duk_del_prop(ctx, obj_index);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_uarridx(thr, arr_idx);
+ return duk_del_prop(thr, obj_idx);
}
-DUK_EXTERNAL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_del_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
+ return duk_del_prop(thr, obj_idx);
+}
+
+DUK_INTERNAL duk_bool_t duk_del_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT_STRIDX_VALID(stridx);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
+ return duk_del_prop(thr, obj_idx);
+}
+
+#if 0
+DUK_INTERNAL duk_bool_t duk_del_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
+ return duk_del_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
+ (duk_small_uint_t) (packed_args & 0xffffUL));
+}
+#endif
+
+DUK_EXTERNAL duk_bool_t duk_has_prop(duk_hthread *thr, duk_idx_t obj_idx) {
duk_tval *tv_obj;
duk_tval *tv_key;
duk_bool_t rc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* Note: copying tv_obj and tv_key to locals to shield against a valstack
* resize is not necessary for a property existence check right now.
*/
- tv_obj = duk_require_tval(ctx, obj_index);
- tv_key = duk_require_tval(ctx, -1);
+ tv_obj = duk_require_tval(thr, obj_idx);
+ tv_key = duk_require_tval(thr, -1);
rc = duk_hobject_hasprop(thr, tv_obj, tv_key);
DUK_ASSERT(rc == 0 || rc == 1);
- duk_pop(ctx); /* remove key */
+ duk_pop(thr); /* remove key */
return rc; /* 1 if property found, 0 otherwise */
}
-DUK_EXTERNAL duk_bool_t duk_has_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_has_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(key != NULL);
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_string(ctx, key);
- return duk_has_prop(ctx, obj_index);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_string(thr, key);
+ return duk_has_prop(thr, obj_idx);
}
-DUK_EXTERNAL duk_bool_t duk_has_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_has_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(key != NULL);
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_uarridx(ctx, arr_index);
- return duk_has_prop(ctx, obj_index);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_lstring(thr, key, key_len);
+ return duk_has_prop(thr, obj_idx);
}
-DUK_INTERNAL duk_bool_t duk_has_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_has_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(stridx >= 0);
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
- DUK_UNREF(thr);
-
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
- return duk_has_prop(ctx, obj_index);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_uarridx(thr, arr_idx);
+ return duk_has_prop(thr, obj_idx);
}
-/* Define own property without inheritance looks and such. This differs from
+DUK_EXTERNAL duk_bool_t duk_has_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
+ return duk_has_prop(thr, obj_idx);
+}
+
+DUK_INTERNAL duk_bool_t duk_has_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT_STRIDX_VALID(stridx);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
+ return duk_has_prop(thr, obj_idx);
+}
+
+#if 0
+DUK_INTERNAL duk_bool_t duk_has_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
+ return duk_has_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
+ (duk_small_uint_t) (packed_args & 0xffffUL));
+}
+#endif
+
+/* Define own property without inheritance lookups and such. This differs from
* [[DefineOwnProperty]] because special behaviors (like Array 'length') are
* not invoked by this method. The caller must be careful to invoke any such
* behaviors if necessary.
*/
-DUK_INTERNAL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_index, duk_small_uint_t desc_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_xdef_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t desc_flags) {
duk_hobject *obj;
duk_hstring *key;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_require_hobject(ctx, obj_index);
+ obj = duk_require_hobject(thr, obj_idx);
DUK_ASSERT(obj != NULL);
- key = duk_to_hstring(ctx, -2);
+ key = duk_to_property_key_hstring(thr, -2);
DUK_ASSERT(key != NULL);
- DUK_ASSERT(duk_require_tval(ctx, -1) != NULL);
+ DUK_ASSERT(duk_require_tval(thr, -1) != NULL);
duk_hobject_define_property_internal(thr, obj, key, desc_flags);
- duk_pop(ctx); /* pop key */
+ duk_pop(thr); /* pop key */
}
-DUK_INTERNAL void duk_xdef_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index, duk_small_uint_t desc_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_xdef_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx, duk_small_uint_t desc_flags) {
duk_hobject *obj;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_require_hobject(ctx, obj_index);
+ obj = duk_require_hobject(thr, obj_idx);
DUK_ASSERT(obj != NULL);
- duk_hobject_define_property_internal_arridx(thr, obj, arr_index, desc_flags);
+ duk_hobject_define_property_internal_arridx(thr, obj, arr_idx, desc_flags);
/* value popped by call */
}
-DUK_INTERNAL void duk_xdef_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_xdef_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_uint_t desc_flags) {
duk_hobject *obj;
duk_hstring *key;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(stridx >= 0);
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT_STRIDX_VALID(stridx);
- obj = duk_require_hobject(ctx, obj_index);
+ obj = duk_require_hobject(thr, obj_idx);
DUK_ASSERT(obj != NULL);
key = DUK_HTHREAD_GET_STRING(thr, stridx);
DUK_ASSERT(key != NULL);
- DUK_ASSERT(duk_require_tval(ctx, -1) != NULL);
+ DUK_ASSERT(duk_require_tval(thr, -1) != NULL);
duk_hobject_define_property_internal(thr, obj, key, desc_flags);
/* value popped by call */
}
-DUK_INTERNAL void duk_xdef_prop_stridx_builtin(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_xdef_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
+ duk_xdef_prop_stridx(thr, (duk_idx_t) (duk_int8_t) (packed_args >> 24),
+ (duk_small_uint_t) (packed_args >> 8) & 0xffffUL,
+ (duk_small_uint_t) (packed_args & 0xffL));
+}
+
+#if 0 /*unused*/
+DUK_INTERNAL void duk_xdef_prop_stridx_builtin(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags) {
duk_hobject *obj;
duk_hstring *key;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(stridx >= 0);
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
- DUK_ASSERT_DISABLE(builtin_idx >= 0);
- DUK_ASSERT(builtin_idx < DUK_NUM_BUILTINS);
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT_STRIDX_VALID(stridx);
+ DUK_ASSERT_BIDX_VALID(builtin_idx);
- obj = duk_require_hobject(ctx, obj_index);
+ obj = duk_require_hobject(thr, obj_idx);
DUK_ASSERT(obj != NULL);
key = DUK_HTHREAD_GET_STRING(thr, stridx);
DUK_ASSERT(key != NULL);
- duk_push_hobject(ctx, thr->builtins[builtin_idx]);
+ duk_push_hobject(thr, thr->builtins[builtin_idx]);
duk_hobject_define_property_internal(thr, obj, key, desc_flags);
/* value popped by call */
}
+#endif
/* This is a rare property helper; it sets the global thrower (E5 Section 13.2.3)
* setter/getter into an object property. This is needed by the 'arguments'
* object creation code, function instance creation code, and Function.prototype.bind().
*/
-DUK_INTERNAL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *obj = duk_require_hobject(ctx, obj_index);
- duk_hobject *thrower = thr->builtins[DUK_BIDX_TYPE_ERROR_THROWER];
- duk_hobject_define_accessor_internal(thr, obj, DUK_HTHREAD_GET_STRING(thr, stridx), thrower, thrower, desc_flags);
+DUK_INTERNAL void duk_xdef_prop_stridx_thrower(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_hstring_stridx(thr, stridx);
+ duk_push_hobject_bidx(thr, DUK_BIDX_TYPE_ERROR_THROWER);
+ duk_dup_top(thr);
+ duk_def_prop(thr, obj_idx, DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_FORCE); /* attributes always 0 */
+}
+
+/* Object.getOwnPropertyDescriptor() equivalent C binding. */
+DUK_EXTERNAL void duk_get_prop_desc(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t flags) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(flags); /* no flags defined yet */
+
+ duk_hobject_object_get_own_property_descriptor(thr, obj_idx); /* [ ... key ] -> [ ... desc ] */
}
/* Object.defineProperty() equivalent C binding. */
-DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_def_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t flags) {
duk_idx_t idx_base;
duk_hobject *obj;
duk_hstring *key;
@@ -14767,9 +16719,9 @@ DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t
duk_uint_t is_data_desc;
duk_uint_t is_acc_desc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_require_hobject(ctx, obj_index);
+ obj = duk_require_hobject(thr, obj_idx);
is_data_desc = flags & (DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE);
is_acc_desc = flags & (DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
@@ -14781,12 +16733,12 @@ DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t
goto fail_invalid_desc;
}
- idx_base = duk_get_top_index(ctx);
+ idx_base = duk_get_top_index(thr);
if (flags & DUK_DEFPROP_HAVE_SETTER) {
- duk_require_type_mask(ctx, idx_base, DUK_TYPE_MASK_UNDEFINED |
+ duk_require_type_mask(thr, idx_base, DUK_TYPE_MASK_UNDEFINED |
DUK_TYPE_MASK_OBJECT |
DUK_TYPE_MASK_LIGHTFUNC);
- set = duk_get_hobject_or_lfunc_coerce(ctx, idx_base);
+ set = duk_get_hobject_promote_lfunc(thr, idx_base);
if (set != NULL && !DUK_HOBJECT_IS_CALLABLE(set)) {
goto fail_not_callable;
}
@@ -14795,10 +16747,10 @@ DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t
set = NULL;
}
if (flags & DUK_DEFPROP_HAVE_GETTER) {
- duk_require_type_mask(ctx, idx_base, DUK_TYPE_MASK_UNDEFINED |
+ duk_require_type_mask(thr, idx_base, DUK_TYPE_MASK_UNDEFINED |
DUK_TYPE_MASK_OBJECT |
DUK_TYPE_MASK_LIGHTFUNC);
- get = duk_get_hobject_or_lfunc_coerce(ctx, idx_base);
+ get = duk_get_hobject_promote_lfunc(thr, idx_base);
if (get != NULL && !DUK_HOBJECT_IS_CALLABLE(get)) {
goto fail_not_callable;
}
@@ -14812,21 +16764,23 @@ DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t
} else {
idx_value = (duk_idx_t) -1;
}
- key = duk_require_hstring(ctx, idx_base);
+ key = duk_to_property_key_hstring(thr, idx_base);
+ DUK_ASSERT(key != NULL);
- duk_require_valid_index(ctx, idx_base);
+ duk_require_valid_index(thr, idx_base);
- duk_hobject_define_property_helper(ctx,
+ duk_hobject_define_property_helper(thr,
flags /*defprop_flags*/,
obj,
key,
idx_value,
get,
- set);
+ set,
+ 1 /*throw_flag*/);
/* Clean up stack */
- duk_set_top(ctx, idx_base);
+ duk_set_top(thr, idx_base);
/* [ ... obj ... ] */
@@ -14848,66 +16802,140 @@ DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t
* and are not exposed through the API.
*/
-DUK_EXTERNAL void duk_compact(duk_context *ctx, duk_idx_t obj_index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_compact(duk_hthread *thr, duk_idx_t obj_idx) {
duk_hobject *obj;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_get_hobject(ctx, obj_index);
+ obj = duk_get_hobject(thr, obj_idx);
if (obj) {
/* Note: this may fail, caller should protect the call if necessary */
duk_hobject_compact_props(thr, obj);
}
}
-/* XXX: the duk_hobject_enum.c stack APIs should be reworked */
+DUK_INTERNAL void duk_compact_m1(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
-DUK_EXTERNAL void duk_enum(duk_context *ctx, duk_idx_t obj_index, duk_uint_t enum_flags) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- duk_dup(ctx, obj_index);
- duk_require_hobject_or_lfunc_coerce(ctx, -1);
- duk_hobject_enumerator_create(ctx, enum_flags); /* [target] -> [enum] */
+ duk_compact(thr, -1);
}
-DUK_EXTERNAL duk_bool_t duk_next(duk_context *ctx, duk_idx_t enum_index, duk_bool_t get_value) {
- DUK_ASSERT_CTX_VALID(ctx);
+/* XXX: the duk_hobject_enum.c stack APIs should be reworked */
- duk_require_hobject(ctx, enum_index);
- duk_dup(ctx, enum_index);
- return duk_hobject_enumerator_next(ctx, get_value);
+DUK_EXTERNAL void duk_enum(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t enum_flags) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_dup(thr, obj_idx);
+ duk_require_hobject_promote_mask(thr, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
+ duk_hobject_enumerator_create(thr, enum_flags); /* [target] -> [enum] */
+}
+
+DUK_EXTERNAL duk_bool_t duk_next(duk_hthread *thr, duk_idx_t enum_index, duk_bool_t get_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_require_hobject(thr, enum_index);
+ duk_dup(thr, enum_index);
+ return duk_hobject_enumerator_next(thr, get_value);
+}
+
+DUK_INTERNAL void duk_seal_freeze_raw(duk_hthread *thr, duk_idx_t obj_idx, duk_bool_t is_freeze) {
+ duk_tval *tv;
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_require_tval(thr, obj_idx);
+ DUK_ASSERT(tv != NULL);
+
+ /* Seal/freeze are quite rare in practice so it'd be nice to get the
+ * correct behavior simply via automatic promotion (at the cost of some
+ * memory churn). However, the promoted objects don't behave the same,
+ * e.g. promoted lightfuncs are extensible.
+ */
+
+ switch (DUK_TVAL_GET_TAG(tv)) {
+ case DUK_TAG_BUFFER:
+ /* Plain buffer: already sealed, but not frozen (and can't be frozen
+ * because index properties can't be made non-writable.
+ */
+ if (is_freeze) {
+ goto fail_cannot_freeze;
+ }
+ break;
+ case DUK_TAG_LIGHTFUNC:
+ /* Lightfunc: already sealed and frozen, success. */
+ break;
+ case DUK_TAG_OBJECT:
+ h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ if (is_freeze && DUK_HOBJECT_IS_BUFOBJ(h)) {
+ /* Buffer objects cannot be frozen because there's no internal
+ * support for making virtual array indices non-writable.
+ */
+ DUK_DD(DUK_DDPRINT("cannot freeze a buffer object"));
+ goto fail_cannot_freeze;
+ }
+ duk_hobject_object_seal_freeze_helper(thr, h, is_freeze);
+
+ /* Sealed and frozen objects cannot gain any more properties,
+ * so this is a good time to compact them.
+ */
+ duk_hobject_compact_props(thr, h);
+ break;
+ default:
+ /* ES2015 Sections 19.1.2.5, 19.1.2.17 */
+ break;
+ }
+ return;
+
+ fail_cannot_freeze:
+ DUK_ERROR_TYPE_INVALID_ARGS(thr); /* XXX: proper error message */
+}
+
+DUK_EXTERNAL void duk_seal(duk_hthread *thr, duk_idx_t obj_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_seal_freeze_raw(thr, obj_idx, 0 /*is_freeze*/);
+}
+
+DUK_EXTERNAL void duk_freeze(duk_hthread *thr, duk_idx_t obj_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_seal_freeze_raw(thr, obj_idx, 1 /*is_freeze*/);
}
/*
* Helpers for writing multiple properties
*/
-DUK_EXTERNAL void duk_put_function_list(duk_context *ctx, duk_idx_t obj_index, const duk_function_list_entry *funcs) {
+DUK_EXTERNAL void duk_put_function_list(duk_hthread *thr, duk_idx_t obj_idx, const duk_function_list_entry *funcs) {
const duk_function_list_entry *ent = funcs;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj_index = duk_require_normalize_index(ctx, obj_index);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
if (ent != NULL) {
while (ent->key != NULL) {
- duk_push_c_function(ctx, ent->value, ent->nargs);
- duk_put_prop_string(ctx, obj_index, ent->key);
+ duk_push_c_function(thr, ent->value, ent->nargs);
+ duk_put_prop_string(thr, obj_idx, ent->key);
ent++;
}
}
}
-DUK_EXTERNAL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_index, const duk_number_list_entry *numbers) {
+DUK_EXTERNAL void duk_put_number_list(duk_hthread *thr, duk_idx_t obj_idx, const duk_number_list_entry *numbers) {
const duk_number_list_entry *ent = numbers;
+ duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj_index = duk_require_normalize_index(ctx, obj_index);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
if (ent != NULL) {
while (ent->key != NULL) {
- duk_push_number(ctx, ent->value);
- duk_put_prop_string(ctx, obj_index, ent->key);
+ tv = thr->valstack_top++;
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); /* value stack init policy */
+ DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv, ent->value); /* no need for decref/incref */
+ duk_put_prop_string(thr, obj_idx, ent->key);
ent++;
}
}
@@ -14917,34 +16945,61 @@ DUK_EXTERNAL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_index, con
* Shortcut for accessing global object properties
*/
-DUK_EXTERNAL duk_bool_t duk_get_global_string(duk_context *ctx, const char *key) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_get_global_string(duk_hthread *thr, const char *key) {
duk_bool_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
/* XXX: direct implementation */
- duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]);
- ret = duk_get_prop_string(ctx, -1, key);
- duk_remove(ctx, -2);
+ duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
+ ret = duk_get_prop_string(thr, -1, key);
+ duk_remove_m2(thr);
return ret;
}
-DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_context *ctx, const char *key) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_get_global_lstring(duk_hthread *thr, const char *key, duk_size_t key_len) {
duk_bool_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
/* XXX: direct implementation */
- duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]);
- duk_insert(ctx, -2);
- ret = duk_put_prop_string(ctx, -2, key); /* [ ... global val ] -> [ ... global ] */
- duk_pop(ctx);
+ duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
+ ret = duk_get_prop_lstring(thr, -1, key, key_len);
+ duk_remove_m2(thr);
+ return ret;
+}
+
+DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_hthread *thr, const char *key) {
+ duk_bool_t ret;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
+
+ /* XXX: direct implementation */
+
+ duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
+ duk_insert(thr, -2);
+ ret = duk_put_prop_string(thr, -2, key); /* [ ... global val ] -> [ ... global ] */
+ duk_pop(thr);
+ return ret;
+}
+
+DUK_EXTERNAL duk_bool_t duk_put_global_lstring(duk_hthread *thr, const char *key, duk_size_t key_len) {
+ duk_bool_t ret;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
+
+ /* XXX: direct implementation */
+
+ duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
+ duk_insert(thr, -2);
+ ret = duk_put_prop_lstring(thr, -2, key, key_len); /* [ ... global val ] -> [ ... global ] */
+ duk_pop(thr);
return ret;
}
@@ -14952,38 +17007,35 @@ DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_context *ctx, const char *key)
* Object prototype
*/
-DUK_EXTERNAL void duk_get_prototype(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_get_prototype(duk_hthread *thr, duk_idx_t idx) {
duk_hobject *obj;
duk_hobject *proto;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_require_hobject(ctx, index);
+ obj = duk_require_hobject(thr, idx);
DUK_ASSERT(obj != NULL);
/* XXX: shared helper for duk_push_hobject_or_undefined()? */
proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, obj);
if (proto) {
- duk_push_hobject(ctx, proto);
+ duk_push_hobject(thr, proto);
} else {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
}
}
-DUK_EXTERNAL void duk_set_prototype(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_set_prototype(duk_hthread *thr, duk_idx_t idx) {
duk_hobject *obj;
duk_hobject *proto;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_require_hobject(ctx, index);
+ obj = duk_require_hobject(thr, idx);
DUK_ASSERT(obj != NULL);
- duk_require_type_mask(ctx, -1, DUK_TYPE_MASK_UNDEFINED |
+ duk_require_type_mask(thr, -1, DUK_TYPE_MASK_UNDEFINED |
DUK_TYPE_MASK_OBJECT);
- proto = duk_get_hobject(ctx, -1);
+ proto = duk_get_hobject(thr, -1);
/* proto can also be NULL here (allowed explicitly) */
#if defined(DUK_USE_ROM_OBJECTS)
@@ -14995,29 +17047,65 @@ DUK_EXTERNAL void duk_set_prototype(duk_context *ctx, duk_idx_t index) {
DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, obj, proto);
- duk_pop(ctx);
+ duk_pop(thr);
}
/*
* Object finalizer
*/
+#if defined(DUK_USE_FINALIZER_SUPPORT)
/* XXX: these could be implemented as macros calling an internal function
* directly.
* XXX: same issue as with Duktape.fin: there's no way to delete the property
* now (just set it to undefined).
*/
-DUK_EXTERNAL void duk_get_finalizer(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_get_finalizer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk_get_prop_stridx(ctx, index, DUK_STRIDX_INT_FINALIZER);
+ duk_get_prop_stridx(thr, idx, DUK_STRIDX_INT_FINALIZER);
}
-DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_set_finalizer(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+ duk_bool_t callable;
- duk_put_prop_stridx(ctx, index, DUK_STRIDX_INT_FINALIZER);
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = duk_require_hobject(thr, idx); /* Get before 'put' so that 'idx' is correct. */
+ callable = duk_is_callable(thr, -1);
+ duk_put_prop_stridx(thr, idx, DUK_STRIDX_INT_FINALIZER);
+
+ /* In addition to setting the finalizer property, keep a "have
+ * finalizer" flag in duk_hobject in sync so that refzero can do
+ * a very quick finalizer check by walking the prototype chain
+ * and checking the flag alone. (Note that this means that just
+ * setting _Finalizer on an object won't affect finalizer checks.)
+ *
+ * NOTE: if the argument is a Proxy object, this flag will be set
+ * on the Proxy, not the target. As a result, the target won't get
+ * a finalizer flag and the Proxy also won't be finalized as there's
+ * an explicit Proxy check in finalization now.
+ */
+ if (callable) {
+ DUK_HOBJECT_SET_HAVE_FINALIZER(h);
+ } else {
+ DUK_HOBJECT_CLEAR_HAVE_FINALIZER(h);
+ }
}
+#else /* DUK_USE_FINALIZER_SUPPORT */
+DUK_EXTERNAL void duk_get_finalizer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(idx);
+ DUK_ERROR_UNSUPPORTED(thr);
+}
+
+DUK_EXTERNAL void duk_set_finalizer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(idx);
+ DUK_ERROR_UNSUPPORTED(thr);
+}
+#endif /* DUK_USE_FINALIZER_SUPPORT */
#line 1 "duk_api_stack.c"
/*
* API calls related to general value stack manipulation: resizing the value
@@ -15031,19 +17119,19 @@ DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t index) {
/* XXX: repetition of stack pre-checks -> helper or macro or inline */
/* XXX: shared api error strings, and perhaps even throw code for rare cases? */
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Forward declarations
*/
-DUK_LOCAL_DECL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_uint_t flags);
+DUK_LOCAL_DECL duk_idx_t duk__push_c_function_raw(duk_hthread *thr, duk_c_function func, duk_idx_t nargs, duk_uint_t flags, duk_small_uint_t proto_bidx);
/*
* Global state for working around missing variadic macros
*/
-#ifndef DUK_USE_VARIADIC_MACROS
+#if !defined(DUK_USE_VARIADIC_MACROS)
DUK_EXTERNAL const char *duk_api_global_filename = NULL;
DUK_EXTERNAL duk_int_t duk_api_global_line = 0;
#endif
@@ -15052,34 +17140,99 @@ DUK_EXTERNAL duk_int_t duk_api_global_line = 0;
* Misc helpers
*/
+DUK_LOCAL const char * const duk__symbol_type_strings[4] = {
+ "hidden", "global", "local", "wellknown"
+};
+
+#if !defined(DUK_USE_PACKED_TVAL)
+DUK_LOCAL const duk_uint_t duk__type_from_tag[] = {
+ DUK_TYPE_NUMBER,
+ DUK_TYPE_NUMBER, /* fastint */
+ DUK_TYPE_UNDEFINED,
+ DUK_TYPE_NULL,
+ DUK_TYPE_BOOLEAN,
+ DUK_TYPE_POINTER,
+ DUK_TYPE_LIGHTFUNC,
+ DUK_TYPE_NONE,
+ DUK_TYPE_STRING,
+ DUK_TYPE_OBJECT,
+ DUK_TYPE_BUFFER,
+};
+DUK_LOCAL const duk_uint_t duk__type_mask_from_tag[] = {
+ DUK_TYPE_MASK_NUMBER,
+ DUK_TYPE_MASK_NUMBER, /* fastint */
+ DUK_TYPE_MASK_UNDEFINED,
+ DUK_TYPE_MASK_NULL,
+ DUK_TYPE_MASK_BOOLEAN,
+ DUK_TYPE_MASK_POINTER,
+ DUK_TYPE_MASK_LIGHTFUNC,
+ DUK_TYPE_MASK_NONE,
+ DUK_TYPE_MASK_STRING,
+ DUK_TYPE_MASK_OBJECT,
+ DUK_TYPE_MASK_BUFFER,
+};
+#endif /* !DUK_USE_PACKED_TVAL */
+
+/* Assert that there's room for one value. */
+#define DUK__ASSERT_SPACE() do { \
+ DUK_ASSERT(!(thr->valstack_top >= thr->valstack_end)); \
+ } while (0)
+
/* Check that there's room to push one value. */
#if defined(DUK_USE_VALSTACK_UNSAFE)
/* Faster but value stack overruns are memory unsafe. */
-#define DUK__CHECK_SPACE() do { \
- DUK_ASSERT(!(thr->valstack_top >= thr->valstack_end)); \
- } while (0)
+#define DUK__CHECK_SPACE() DUK__ASSERT_SPACE()
#else
#define DUK__CHECK_SPACE() do { \
if (DUK_UNLIKELY(thr->valstack_top >= thr->valstack_end)) { \
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); \
+ DUK_ERROR_RANGE_PUSH_BEYOND(thr); \
} \
} while (0)
#endif
-DUK_LOCAL_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t index, duk_uint_t tag);
+DUK_LOCAL duk_small_uint_t duk__get_symbol_type(duk_hstring *h) {
+ const duk_uint8_t *data;
+ duk_size_t len;
-DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t index, duk_bool_t require) {
- duk_hthread *thr;
+ DUK_ASSERT(h != NULL);
+ DUK_ASSERT(DUK_HSTRING_HAS_SYMBOL(h));
+ DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(h) >= 1); /* always true, symbol prefix */
+
+ data = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
+ len = DUK_HSTRING_GET_BYTELEN(h);
+ DUK_ASSERT(len >= 1);
+
+ /* XXX: differentiate between 0x82 and 0xff (hidden vs. internal?)? */
+
+ if (data[0] == 0xffU) {
+ return DUK_SYMBOL_TYPE_HIDDEN;
+ } else if (data[0] == 0x82U) {
+ return DUK_SYMBOL_TYPE_HIDDEN;
+ } else if (data[0] == 0x80U) {
+ return DUK_SYMBOL_TYPE_GLOBAL;
+ } else if (data[len - 1] != 0xffU) {
+ return DUK_SYMBOL_TYPE_LOCAL;
+ } else {
+ return DUK_SYMBOL_TYPE_WELLKNOWN;
+ }
+}
+
+DUK_LOCAL const char *duk__get_symbol_type_string(duk_hstring *h) {
+ duk_small_uint_t idx;
+ idx = duk__get_symbol_type(h);
+ DUK_ASSERT(idx < sizeof(duk__symbol_type_strings));
+ return duk__symbol_type_strings[idx];
+}
+
+DUK_LOCAL_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_hthread *thr, duk_idx_t idx, duk_uint_t tag);
+
+DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_hthread *thr, duk_idx_t idx, duk_int_t def_value, duk_bool_t require) {
duk_tval *tv;
duk_small_int_t c;
duk_double_t d;
- thr = (duk_hthread *) ctx;
-
- tv = duk_get_tval(ctx, index);
- if (tv == NULL) {
- goto error_notnumber;
- }
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
/*
* Special cases like NaN and +/- Infinity are handled explicitly
@@ -15126,29 +17279,23 @@ DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t index, duk_b
}
}
- error_notnumber:
-
if (require) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER);
/* not reachable */
}
- return 0;
+
+ return def_value;
}
-DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t index, duk_bool_t require) {
- duk_hthread *thr;
+DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_hthread *thr, duk_idx_t idx, duk_uint_t def_value, duk_bool_t require) {
duk_tval *tv;
duk_small_int_t c;
duk_double_t d;
/* Same as above but for unsigned int range. */
- thr = (duk_hthread *) ctx;
-
- tv = duk_get_tval(ctx, index);
- if (tv == NULL) {
- goto error_notnumber;
- }
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
#if defined(DUK_USE_FASTINT)
if (DUK_TVAL_IS_FASTINT(tv)) {
@@ -15183,13 +17330,12 @@ DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t index, duk
}
}
- error_notnumber:
-
if (require) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER);
/* not reachable */
}
- return 0;
+
+ return def_value;
}
/*
@@ -15201,12 +17347,11 @@ DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t index, duk
* There's some repetition because of this; keep the functions in sync.
*/
-DUK_EXTERNAL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_idx_t duk_normalize_index(duk_hthread *thr, duk_idx_t idx) {
duk_uidx_t vs_size;
- duk_uidx_t uindex;
+ duk_uidx_t uidx;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_INVALID_INDEX < 0);
/* Care must be taken to avoid pointer wrapping in the index
@@ -15220,86 +17365,103 @@ DUK_EXTERNAL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t index) {
vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
- if (index < 0) {
- uindex = vs_size + (duk_uidx_t) index;
+ if (idx < 0) {
+ uidx = vs_size + (duk_uidx_t) idx;
} else {
/* since index non-negative */
- DUK_ASSERT(index != DUK_INVALID_INDEX);
- uindex = (duk_uidx_t) index;
+ DUK_ASSERT(idx != DUK_INVALID_INDEX);
+ uidx = (duk_uidx_t) idx;
}
/* DUK_INVALID_INDEX won't be accepted as a valid index. */
DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
- if (DUK_LIKELY(uindex < vs_size)) {
- return (duk_idx_t) uindex;
+ if (DUK_LIKELY(uidx < vs_size)) {
+ return (duk_idx_t) uidx;
}
return DUK_INVALID_INDEX;
}
-DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_hthread *thr, duk_idx_t idx) {
duk_uidx_t vs_size;
- duk_uidx_t uindex;
+ duk_uidx_t uidx;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_INVALID_INDEX < 0);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
- if (index < 0) {
- uindex = vs_size + (duk_uidx_t) index;
+ if (idx < 0) {
+ uidx = vs_size + (duk_uidx_t) idx;
} else {
- DUK_ASSERT(index != DUK_INVALID_INDEX);
- uindex = (duk_uidx_t) index;
+ DUK_ASSERT(idx != DUK_INVALID_INDEX);
+ uidx = (duk_uidx_t) idx;
}
/* DUK_INVALID_INDEX won't be accepted as a valid index. */
DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
- if (DUK_LIKELY(uindex < vs_size)) {
- return (duk_idx_t) uindex;
+ if (DUK_LIKELY(uidx < vs_size)) {
+ return (duk_idx_t) uidx;
}
- DUK_ERROR_API_INDEX(thr, index);
+ DUK_ERROR_RANGE_INDEX(thr, idx);
return 0; /* unreachable */
}
-DUK_INTERNAL duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_tval *duk_get_tval(duk_hthread *thr, duk_idx_t idx) {
duk_uidx_t vs_size;
- duk_uidx_t uindex;
+ duk_uidx_t uidx;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_INVALID_INDEX < 0);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
- if (index < 0) {
- uindex = vs_size + (duk_uidx_t) index;
+ if (idx < 0) {
+ uidx = vs_size + (duk_uidx_t) idx;
} else {
- DUK_ASSERT(index != DUK_INVALID_INDEX);
- uindex = (duk_uidx_t) index;
+ DUK_ASSERT(idx != DUK_INVALID_INDEX);
+ uidx = (duk_uidx_t) idx;
}
/* DUK_INVALID_INDEX won't be accepted as a valid index. */
DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
- if (DUK_LIKELY(uindex < vs_size)) {
- return thr->valstack_bottom + uindex;
+ if (DUK_LIKELY(uidx < vs_size)) {
+ return thr->valstack_bottom + uidx;
}
return NULL;
}
-DUK_INTERNAL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_uidx_t vs_size;
- duk_uidx_t uindex;
+/* Variant of duk_get_tval() which is guaranteed to return a valid duk_tval
+ * pointer. When duk_get_tval() would return NULL, this variant returns a
+ * pointer to a duk_tval with tag DUK_TAG_UNUSED. This allows the call site
+ * to avoid an unnecessary NULL check which sometimes leads to better code.
+ * The return duk_tval is read only (at least for the UNUSED value).
+ */
+DUK_LOCAL const duk_tval_unused duk__const_tval_unused = DUK_TVAL_UNUSED_INITIALIZER();
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_INTERNAL duk_tval *duk_get_tval_or_unused(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_get_tval(thr, idx);
+ if (tv != NULL) {
+ return tv;
+ }
+ return (duk_tval *) DUK_LOSE_CONST(&duk__const_tval_unused);
+}
+
+DUK_INTERNAL duk_tval *duk_require_tval(duk_hthread *thr, duk_idx_t idx) {
+ duk_uidx_t vs_size;
+ duk_uidx_t uidx;
+
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_INVALID_INDEX < 0);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
@@ -15307,40 +17469,38 @@ DUK_INTERNAL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t index) {
DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
/* Use unsigned arithmetic to optimize comparison. */
- if (index < 0) {
- uindex = vs_size + (duk_uidx_t) index;
+ if (idx < 0) {
+ uidx = vs_size + (duk_uidx_t) idx;
} else {
- DUK_ASSERT(index != DUK_INVALID_INDEX);
- uindex = (duk_uidx_t) index;
+ DUK_ASSERT(idx != DUK_INVALID_INDEX);
+ uidx = (duk_uidx_t) idx;
}
/* DUK_INVALID_INDEX won't be accepted as a valid index. */
DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
- if (DUK_LIKELY(uindex < vs_size)) {
- return thr->valstack_bottom + uindex;
+ if (DUK_LIKELY(uidx < vs_size)) {
+ return thr->valstack_bottom + uidx;
}
- DUK_ERROR_API_INDEX(thr, index);
+ DUK_ERROR_RANGE_INDEX(thr, idx);
return NULL;
}
/* Non-critical. */
-DUK_EXTERNAL duk_bool_t duk_is_valid_index(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_is_valid_index(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_INVALID_INDEX < 0);
- return (duk_normalize_index(ctx, index) >= 0);
+ return (duk_normalize_index(thr, idx) >= 0);
}
/* Non-critical. */
-DUK_EXTERNAL void duk_require_valid_index(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_require_valid_index(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_INVALID_INDEX < 0);
- if (duk_normalize_index(ctx, index) < 0) {
- DUK_ERROR_API_INDEX(thr, index);
+ if (DUK_UNLIKELY(duk_normalize_index(thr, idx) < 0)) {
+ DUK_ERROR_RANGE_INDEX(thr, idx);
return; /* unreachable */
}
}
@@ -15349,26 +17509,38 @@ DUK_EXTERNAL void duk_require_valid_index(duk_context *ctx, duk_idx_t index) {
* Value stack top handling
*/
-DUK_EXTERNAL duk_idx_t duk_get_top(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_idx_t duk_get_top(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
return (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
}
+/* Internal helper to get current top but to require a minimum top value
+ * (TypeError if not met).
+ */
+DUK_INTERNAL duk_idx_t duk_get_top_require_min(duk_hthread *thr, duk_idx_t min_top) {
+ duk_idx_t ret;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
+ if (DUK_UNLIKELY(ret < min_top)) {
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ }
+ return ret;
+}
+
/* Set stack top within currently allocated range, but don't reallocate.
* This is performance critical especially for call handling, so whenever
* changing, profile and look at generated code.
*/
-DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_set_top(duk_hthread *thr, duk_idx_t idx) {
duk_uidx_t vs_size;
duk_uidx_t vs_limit;
- duk_uidx_t uindex;
+ duk_uidx_t uidx;
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_INVALID_INDEX < 0);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
@@ -15376,16 +17548,16 @@ DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t index) {
vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
vs_limit = (duk_uidx_t) (thr->valstack_end - thr->valstack_bottom);
- if (index < 0) {
+ if (idx < 0) {
/* Negative indices are always within allocated stack but
* must not go below zero index.
*/
- uindex = vs_size + (duk_uidx_t) index;
+ uidx = vs_size + (duk_uidx_t) idx;
} else {
/* Positive index can be higher than valstack top but must
* not go above allocated stack (equality is OK).
*/
- uindex = (duk_uidx_t) index;
+ uidx = (duk_uidx_t) idx;
}
/* DUK_INVALID_INDEX won't be accepted as a valid index. */
@@ -15393,15 +17565,15 @@ DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t index) {
DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_limit);
#if defined(DUK_USE_VALSTACK_UNSAFE)
- DUK_ASSERT(uindex <= vs_limit);
+ DUK_ASSERT(uidx <= vs_limit);
DUK_UNREF(vs_limit);
#else
- if (DUK_UNLIKELY(uindex > vs_limit)) {
- DUK_ERROR_API_INDEX(thr, index);
+ if (DUK_UNLIKELY(uidx > vs_limit)) {
+ DUK_ERROR_RANGE_INDEX(thr, idx);
return; /* unreachable */
}
#endif
- DUK_ASSERT(uindex <= vs_limit);
+ DUK_ASSERT(uidx <= vs_limit);
/* Handle change in value stack top. Respect value stack
* initialization policy: 'undefined' above top. Note that
@@ -15409,37 +17581,42 @@ DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t index) {
* so must relookup after DECREF.
*/
- if (uindex >= vs_size) {
+ if (uidx >= vs_size) {
/* Stack size increases or stays the same. */
#if defined(DUK_USE_ASSERTIONS)
duk_uidx_t count;
- count = uindex - vs_size;
+ count = uidx - vs_size;
while (count != 0) {
count--;
tv = thr->valstack_top + count;
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
}
#endif
- thr->valstack_top = thr->valstack_bottom + uindex;
+ thr->valstack_top = thr->valstack_bottom + uidx;
} else {
/* Stack size decreases. */
#if defined(DUK_USE_REFERENCE_COUNTING)
duk_uidx_t count;
+ duk_tval *tv_end;
- count = vs_size - uindex;
+ count = vs_size - uidx;
DUK_ASSERT(count > 0);
- while (count > 0) {
- count--;
- tv = --thr->valstack_top; /* tv -> value just before prev top value; must relookup */
+ tv = thr->valstack_top;
+ tv_end = tv - count;
+ DUK_ASSERT(tv > tv_end); /* Because count > 0. */
+ do {
+ tv--;
DUK_ASSERT(tv >= thr->valstack_bottom);
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
- }
+ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv);
+ } while (tv != tv_end);
+ thr->valstack_top = tv_end;
+ DUK_REFZERO_CHECK_FAST(thr);
#else /* DUK_USE_REFERENCE_COUNTING */
duk_uidx_t count;
duk_tval *tv_end;
- count = vs_size - uindex;
+ count = vs_size - uidx;
tv = thr->valstack_top;
tv_end = tv - count;
DUK_ASSERT(tv > tv_end);
@@ -15452,13 +17629,100 @@ DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t index) {
}
}
-DUK_EXTERNAL duk_idx_t duk_get_top_index(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+/* Internal variant with a non-negative index and no runtime size checks. */
+#if defined(DUK_USE_PREFER_SIZE)
+DUK_INTERNAL void duk_set_top_unsafe(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_set_top(thr, idx);
+}
+#else /* DUK_USE_PREFER_SIZE */
+DUK_INTERNAL void duk_set_top_unsafe(duk_hthread *thr, duk_idx_t idx) {
+ duk_uidx_t uidx;
+ duk_uidx_t vs_size;
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_end >= thr->valstack_bottom);
+ DUK_ASSERT(idx >= 0);
+ DUK_ASSERT(idx <= (duk_idx_t) (thr->valstack_end - thr->valstack_bottom));
+
+ /* XXX: byte arithmetic */
+ uidx = (duk_uidx_t) idx;
+ vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
+
+ if (uidx >= vs_size) {
+ /* Stack size increases or stays the same. */
+#if defined(DUK_USE_ASSERTIONS)
+ duk_uidx_t count;
+
+ count = uidx - vs_size;
+ while (count != 0) {
+ count--;
+ tv = thr->valstack_top + count;
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
+ }
+#endif
+ thr->valstack_top = thr->valstack_bottom + uidx;
+ } else {
+ /* Stack size decreases. */
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ duk_uidx_t count;
+ duk_tval *tv_end;
+
+ count = vs_size - uidx;
+ DUK_ASSERT(count > 0);
+ tv = thr->valstack_top;
+ tv_end = tv - count;
+ DUK_ASSERT(tv > tv_end); /* Because count > 0. */
+ do {
+ tv--;
+ DUK_ASSERT(tv >= thr->valstack_bottom);
+ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv);
+ } while (tv != tv_end);
+ thr->valstack_top = tv_end;
+ DUK_REFZERO_CHECK_FAST(thr);
+#else /* DUK_USE_REFERENCE_COUNTING */
+ duk_uidx_t count;
+ duk_tval *tv_end;
+
+ count = vs_size - uidx;
+ tv = thr->valstack_top;
+ tv_end = tv - count;
+ DUK_ASSERT(tv > tv_end);
+ do {
+ tv--;
+ DUK_TVAL_SET_UNDEFINED(tv);
+ } while (tv != tv_end);
+ thr->valstack_top = tv_end;
+#endif /* DUK_USE_REFERENCE_COUNTING */
+ }
+}
+#endif /* DUK_USE_PREFER_SIZE */
+
+/* Internal helper: set top to 'top', and set [idx_wipe_start,top[ to
+ * 'undefined' (doing nothing if idx_wipe_start == top). Indices are
+ * positive and within value stack reserve. This is used by call handling.
+ */
+DUK_INTERNAL void duk_set_top_and_wipe(duk_hthread *thr, duk_idx_t top, duk_idx_t idx_wipe_start) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(top >= 0);
+ DUK_ASSERT(idx_wipe_start >= 0);
+ DUK_ASSERT(idx_wipe_start <= top);
+ DUK_ASSERT(thr->valstack_bottom + top <= thr->valstack_end);
+ DUK_ASSERT(thr->valstack_bottom + idx_wipe_start <= thr->valstack_end);
+
+ duk_set_top_unsafe(thr, idx_wipe_start);
+ duk_set_top_unsafe(thr, top);
+}
+
+DUK_EXTERNAL duk_idx_t duk_get_top_index(duk_hthread *thr) {
duk_idx_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- ret = ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1;
+ ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1;
if (DUK_UNLIKELY(ret < 0)) {
/* Return invalid index; if caller uses this without checking
* in another API call, the index won't map to a valid stack
@@ -15469,15 +17733,26 @@ DUK_EXTERNAL duk_idx_t duk_get_top_index(duk_context *ctx) {
return ret;
}
-DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+/* Internal variant: call assumes there is at least one element on the value
+ * stack frame; this is only asserted for.
+ */
+DUK_INTERNAL duk_idx_t duk_get_top_index_unsafe(duk_hthread *thr) {
duk_idx_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- ret = ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1;
+ ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1;
+ return ret;
+}
+
+DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_hthread *thr) {
+ duk_idx_t ret;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1;
if (DUK_UNLIKELY(ret < 0)) {
- DUK_ERROR_API_INDEX(thr, -1);
+ DUK_ERROR_RANGE_INDEX(thr, -1);
return 0; /* unreachable */
}
return ret;
@@ -15488,64 +17763,74 @@ DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_context *ctx) {
*
* This resizing happens above the current "top": the value stack can be
* grown or shrunk, but the "top" is not affected. The value stack cannot
- * be resized to a size below the current "top".
+ * be resized to a size below the current reserve.
*
* The low level reallocation primitive must carefully recompute all value
* stack pointers, and must also work if ALL pointers are NULL. The resize
* is quite tricky because the valstack realloc may cause a mark-and-sweep,
* which may run finalizers. Running finalizers may resize the valstack
* recursively (the same value stack we're working on). So, after realloc
- * returns, we know that the valstack "top" should still be the same (there
- * should not be live values above the "top"), but its underlying size and
- * pointer may have changed.
+ * returns, we know that the valstack bottom, top, and reserve should still
+ * be the same (there should not be live values above the "top"), but its
+ * underlying size, alloc_end, and base pointer may have changed.
+ *
+ * 'new_size' is known to be <= DUK_USE_VALSTACK_LIMIT, which ensures that
+ * size_t and pointer arithmetic won't wrap in duk__resize_valstack().
*/
-/* XXX: perhaps refactor this to allow caller to specify some parameters, or
- * at least a 'compact' flag which skips any spare or round-up .. useful for
- * emergency gc.
+/* Low level valstack resize primitive, used for both grow and shrink. All
+ * adjustments for slack etc have already been done. Doesn't throw but does
+ * have allocation side effects.
*/
-
-DUK_LOCAL duk_bool_t duk__resize_valstack(duk_context *ctx, duk_size_t new_size) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_ptrdiff_t old_bottom_offset;
- duk_ptrdiff_t old_top_offset;
- duk_ptrdiff_t old_end_offset_post;
-#ifdef DUK_USE_DEBUG
- duk_ptrdiff_t old_end_offset_pre;
- duk_tval *old_valstack_pre;
- duk_tval *old_valstack_post;
-#endif
+DUK_LOCAL DUK_COLD DUK_NOINLINE duk_bool_t duk__resize_valstack(duk_hthread *thr, duk_size_t new_size) {
+ duk_tval *pre_valstack;
+ duk_tval *pre_bottom;
+ duk_tval *pre_top;
+ duk_tval *pre_end;
+ duk_tval *pre_alloc_end;
+ duk_ptrdiff_t ptr_diff;
duk_tval *new_valstack;
duk_size_t new_alloc_size;
+ duk_tval *tv_prev_alloc_end;
duk_tval *p;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_HTHREAD_VALID(thr);
DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
+ DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end);
DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack) <= new_size); /* can't resize below 'top' */
- DUK_ASSERT(new_size <= thr->valstack_max); /* valstack limit caller has check, prevents wrapping */
+ DUK_ASSERT(new_size <= DUK_USE_VALSTACK_LIMIT); /* valstack limit caller has check, prevents wrapping */
DUK_ASSERT(new_size <= DUK_SIZE_MAX / sizeof(duk_tval)); /* specific assert for wrapping */
- /* get pointer offsets for tweaking below */
- old_bottom_offset = (((duk_uint8_t *) thr->valstack_bottom) - ((duk_uint8_t *) thr->valstack));
- old_top_offset = (((duk_uint8_t *) thr->valstack_top) - ((duk_uint8_t *) thr->valstack));
-#ifdef DUK_USE_DEBUG
- old_end_offset_pre = (((duk_uint8_t *) thr->valstack_end) - ((duk_uint8_t *) thr->valstack)); /* not very useful, used for debugging */
- old_valstack_pre = thr->valstack;
+ /* Pre-realloc pointer copies for asserts and debug logs. */
+ pre_valstack = thr->valstack;
+ pre_bottom = thr->valstack_bottom;
+ pre_top = thr->valstack_top;
+ pre_end = thr->valstack_end;
+ pre_alloc_end = thr->valstack_alloc_end;
+
+ DUK_UNREF(pre_valstack);
+ DUK_UNREF(pre_bottom);
+ DUK_UNREF(pre_top);
+ DUK_UNREF(pre_end);
+ DUK_UNREF(pre_alloc_end);
+
+ /* If finalizer torture enabled, force base pointer change every time
+ * when it would be allowed.
+ */
+#if defined(DUK_USE_FINALIZER_TORTURE)
+ if (thr->heap->pf_prevent_count == 0) {
+ duk_hthread_valstack_torture_realloc(thr);
+ }
#endif
- /* Allocate a new valstack.
- *
- * Note: cannot use a plain DUK_REALLOC() because a mark-and-sweep may
- * invalidate the original thr->valstack base pointer inside the realloc
- * process. See doc/memory-management.rst.
+ /* Allocate a new valstack using DUK_REALLOC_DIRECT() to deal with
+ * a side effect changing the base pointer.
*/
-
new_alloc_size = sizeof(duk_tval) * new_size;
new_valstack = (duk_tval *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_valstack_ptr, (void *) thr, new_alloc_size);
- if (!new_valstack) {
+ if (DUK_UNLIKELY(new_valstack == NULL)) {
/* Because new_size != 0, if condition doesn't need to be
* (new_valstack != NULL || new_size == 0).
*/
@@ -15555,69 +17840,78 @@ DUK_LOCAL duk_bool_t duk__resize_valstack(duk_context *ctx, duk_size_t new_size)
return 0;
}
- /* Note: the realloc may have triggered a mark-and-sweep which may
- * have resized our valstack internally. However, the mark-and-sweep
- * MUST NOT leave the stack bottom/top in a different state. Particular
- * assumptions and facts:
- *
- * - The thr->valstack pointer may be different after realloc,
- * and the offset between thr->valstack_end <-> thr->valstack
- * may have changed.
- * - The offset between thr->valstack_bottom <-> thr->valstack
- * and thr->valstack_top <-> thr->valstack MUST NOT have changed,
- * because mark-and-sweep must adhere to a strict stack policy.
- * In other words, logical bottom and top MUST NOT have changed.
- * - All values above the top are unreachable but are initialized
- * to UNDEFINED, up to the post-realloc valstack_end.
- * - 'old_end_offset' must be computed after realloc to be correct.
+ /* Debug log any changes in pointer(s) by side effects. These don't
+ * necessarily imply any incorrect behavior, but should be rare in
+ * practice.
*/
-
- DUK_ASSERT((((duk_uint8_t *) thr->valstack_bottom) - ((duk_uint8_t *) thr->valstack)) == old_bottom_offset);
- DUK_ASSERT((((duk_uint8_t *) thr->valstack_top) - ((duk_uint8_t *) thr->valstack)) == old_top_offset);
-
- /* success, fixup pointers */
- old_end_offset_post = (((duk_uint8_t *) thr->valstack_end) - ((duk_uint8_t *) thr->valstack)); /* must be computed after realloc */
-#ifdef DUK_USE_DEBUG
- old_valstack_post = thr->valstack;
+#if defined(DUK_USE_DEBUG)
+ if (thr->valstack != pre_valstack) {
+ DUK_D(DUK_DPRINT("valstack base pointer changed during valstack resize: %p -> %p",
+ (void *) pre_valstack, (void *) thr->valstack));
+ }
+ if (thr->valstack_bottom != pre_bottom) {
+ DUK_D(DUK_DPRINT("valstack bottom pointer changed during valstack resize: %p -> %p",
+ (void *) pre_bottom, (void *) thr->valstack_bottom));
+ }
+ if (thr->valstack_top != pre_top) {
+ DUK_D(DUK_DPRINT("valstack top pointer changed during valstack resize: %p -> %p",
+ (void *) pre_top, (void *) thr->valstack_top));
+ }
+ if (thr->valstack_end != pre_end) {
+ DUK_D(DUK_DPRINT("valstack end pointer changed during valstack resize: %p -> %p",
+ (void *) pre_end, (void *) thr->valstack_end));
+ }
+ if (thr->valstack_alloc_end != pre_alloc_end) {
+ DUK_D(DUK_DPRINT("valstack alloc_end pointer changed during valstack resize: %p -> %p",
+ (void *) pre_alloc_end, (void *) thr->valstack_alloc_end));
+ }
#endif
+
+ /* Assertions: offsets for bottom, top, and end (reserve) must not
+ * have changed even with side effects because they are always
+ * restored in unwind. For alloc_end there's no guarantee: it may
+ * have grown or shrunk (but remain above 'end').
+ */
+ DUK_ASSERT(thr->valstack_bottom - thr->valstack == pre_bottom - pre_valstack);
+ DUK_ASSERT(thr->valstack_top - thr->valstack == pre_top - pre_valstack);
+ DUK_ASSERT(thr->valstack_end - thr->valstack == pre_end - pre_valstack);
+ DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end);
+
+ /* Write new pointers. Most pointers can be handled as a pointer
+ * difference.
+ */
+ ptr_diff = (duk_ptrdiff_t) ((duk_uint8_t *) new_valstack - (duk_uint8_t *) thr->valstack);
+ tv_prev_alloc_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_alloc_end + ptr_diff);
thr->valstack = new_valstack;
- thr->valstack_end = new_valstack + new_size;
-#if !defined(DUK_USE_PREFER_SIZE)
- thr->valstack_size = new_size;
-#endif
- thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + old_bottom_offset);
- thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + old_top_offset);
+ thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + ptr_diff);
+ thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_top + ptr_diff);
+ thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_end + ptr_diff);
+ thr->valstack_alloc_end = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + new_alloc_size);
+ /* Assertions: pointer sanity after pointer updates. */
DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
+ DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end);
- /* useful for debugging */
-#ifdef DUK_USE_DEBUG
- if (old_end_offset_pre != old_end_offset_post) {
- DUK_D(DUK_DPRINT("valstack was resized during valstack_resize(), probably by mark-and-sweep; "
- "end offset changed: %lu -> %lu",
- (unsigned long) old_end_offset_pre,
- (unsigned long) old_end_offset_post));
- }
- if (old_valstack_pre != old_valstack_post) {
- DUK_D(DUK_DPRINT("valstack pointer changed during valstack_resize(), probably by mark-and-sweep: %p -> %p",
- (void *) old_valstack_pre,
- (void *) old_valstack_post));
- }
-#endif
+ DUK_D(DUK_DPRINT("resized valstack %lu -> %lu elements (%lu -> %lu bytes): "
+ "base=%p -> %p, bottom=%p -> %p (%ld), top=%p -> %p (%ld), "
+ "end=%p -> %p (%ld), alloc_end=%p -> %p (%ld);"
+ " tv_prev_alloc_end=%p (-> %ld inits; <0 means shrink)",
+ (unsigned long) (pre_alloc_end - pre_valstack),
+ (unsigned long) new_size,
+ (unsigned long) ((duk_uint8_t *) pre_alloc_end - (duk_uint8_t *) pre_valstack),
+ (unsigned long) new_alloc_size,
+ (void *) pre_valstack, (void *) thr->valstack,
+ (void *) pre_bottom, (void *) thr->valstack_bottom, (long) (thr->valstack_bottom - thr->valstack),
+ (void *) pre_top, (void *) thr->valstack_top, (long) (thr->valstack_top - thr->valstack),
+ (void *) pre_end, (void *) thr->valstack_end, (long) (thr->valstack_end - thr->valstack),
+ (void *) pre_alloc_end, (void *) thr->valstack_alloc_end, (long) (thr->valstack_alloc_end - thr->valstack),
+ (void *) tv_prev_alloc_end, (long) (thr->valstack_alloc_end - tv_prev_alloc_end)));
- DUK_DD(DUK_DDPRINT("resized valstack to %lu elements (%lu bytes), bottom=%ld, top=%ld, "
- "new pointers: start=%p end=%p bottom=%p top=%p",
- (unsigned long) new_size, (unsigned long) new_alloc_size,
- (long) (thr->valstack_bottom - thr->valstack),
- (long) (thr->valstack_top - thr->valstack),
- (void *) thr->valstack, (void *) thr->valstack_end,
- (void *) thr->valstack_bottom, (void *) thr->valstack_top));
-
- /* Init newly allocated slots (only). */
- p = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + old_end_offset_post);
- while (p < thr->valstack_end) {
+ /* If allocation grew, init any new slots to 'undefined'. */
+ p = tv_prev_alloc_end;
+ while (p < thr->valstack_alloc_end) {
/* Never executed if new size is smaller. */
DUK_TVAL_SET_UNDEFINED(p);
p++;
@@ -15626,7 +17920,7 @@ DUK_LOCAL duk_bool_t duk__resize_valstack(duk_context *ctx, duk_size_t new_size)
/* Assert for value stack initialization policy. */
#if defined(DUK_USE_ASSERTIONS)
p = thr->valstack_top;
- while (p < thr->valstack_end) {
+ while (p < thr->valstack_alloc_end) {
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(p));
p++;
}
@@ -15635,208 +17929,257 @@ DUK_LOCAL duk_bool_t duk__resize_valstack(duk_context *ctx, duk_size_t new_size)
return 1;
}
-DUK_INTERNAL
-duk_bool_t duk_valstack_resize_raw(duk_context *ctx,
- duk_size_t min_new_size,
- duk_small_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_size_t old_size;
+DUK_LOCAL DUK_COLD DUK_NOINLINE duk_bool_t duk__valstack_grow(duk_hthread *thr, duk_size_t min_bytes, duk_bool_t throw_on_error) {
+ duk_size_t min_size;
duk_size_t new_size;
- duk_bool_t is_shrink = 0;
- duk_small_uint_t shrink_flag = (flags & DUK_VSRESIZE_FLAG_SHRINK);
- duk_small_uint_t compact_flag = (flags & DUK_VSRESIZE_FLAG_COMPACT);
- duk_small_uint_t throw_flag = (flags & DUK_VSRESIZE_FLAG_THROW);
- DUK_DDD(DUK_DDDPRINT("check valstack resize: min_new_size=%lu, curr_size=%ld, curr_top=%ld, "
- "curr_bottom=%ld, shrink=%d, compact=%d, throw=%d",
- (unsigned long) min_new_size,
- (long) (thr->valstack_end - thr->valstack),
- (long) (thr->valstack_top - thr->valstack),
- (long) (thr->valstack_bottom - thr->valstack),
- (int) shrink_flag, (int) compact_flag, (int) throw_flag));
+ DUK_ASSERT(min_bytes / sizeof(duk_tval) * sizeof(duk_tval) == min_bytes);
+ min_size = min_bytes / sizeof(duk_tval); /* from bytes to slots */
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
-
-#if defined(DUK_USE_PREFER_SIZE)
- old_size = (duk_size_t) (thr->valstack_end - thr->valstack);
+#if defined(DUK_USE_VALSTACK_GROW_SHIFT)
+ /* New size is minimum size plus a proportional slack, e.g. shift of
+ * 2 means a 25% slack.
+ */
+ new_size = min_size + (min_size >> DUK_USE_VALSTACK_GROW_SHIFT);
#else
- DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size);
- old_size = thr->valstack_size;
+ /* New size is tight with no slack. This is sometimes preferred in
+ * low memory environments.
+ */
+ new_size = min_size;
#endif
- if (min_new_size <= old_size) {
- is_shrink = 1;
- if (!shrink_flag ||
- old_size - min_new_size < DUK_VALSTACK_SHRINK_THRESHOLD) {
- DUK_DDD(DUK_DDDPRINT("no need to grow or shrink valstack"));
- return 1;
- }
- }
-
- new_size = min_new_size;
- if (!compact_flag) {
- if (is_shrink) {
- /* shrink case; leave some spare */
- new_size += DUK_VALSTACK_SHRINK_SPARE;
- }
-
- /* round up roughly to next 'grow step' */
- new_size = (new_size / DUK_VALSTACK_GROW_STEP + 1) * DUK_VALSTACK_GROW_STEP;
- }
-
- DUK_DD(DUK_DDPRINT("want to %s valstack: %lu -> %lu elements (min_new_size %lu)",
- (const char *) (new_size > old_size ? "grow" : "shrink"),
- (unsigned long) old_size, (unsigned long) new_size,
- (unsigned long) min_new_size));
-
- if (new_size > thr->valstack_max) {
+ if (DUK_UNLIKELY(new_size > DUK_USE_VALSTACK_LIMIT || new_size < min_size /*wrap*/)) {
/* Note: may be triggered even if minimal new_size would not reach the limit,
- * plan limit accordingly (taking DUK_VALSTACK_GROW_STEP into account).
+ * plan limit accordingly.
*/
- if (throw_flag) {
+ if (throw_on_error) {
DUK_ERROR_RANGE(thr, DUK_STR_VALSTACK_LIMIT);
- } else {
- return 0;
}
+ return 0;
}
- /*
- * When resizing the valstack, a mark-and-sweep may be triggered for
- * the allocation of the new valstack. If the mark-and-sweep needs
- * to use our thread for something, it may cause *the same valstack*
- * to be resized recursively. This happens e.g. when mark-and-sweep
- * finalizers are called. This is taken into account carefully in
- * duk__resize_valstack().
- *
- * 'new_size' is known to be <= valstack_max, which ensures that
- * size_t and pointer arithmetic won't wrap in duk__resize_valstack().
- */
-
- if (!duk__resize_valstack(ctx, new_size)) {
- if (is_shrink) {
- DUK_DD(DUK_DDPRINT("valstack resize failed, but is a shrink, ignore"));
- return 1;
- }
-
- DUK_DD(DUK_DDPRINT("valstack resize failed"));
-
- if (throw_flag) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- } else {
- return 0;
+ if (duk__resize_valstack(thr, new_size) == 0) {
+ if (throw_on_error) {
+ DUK_ERROR_ALLOC_FAILED(thr);
}
+ return 0;
}
- DUK_DDD(DUK_DDDPRINT("valstack resize successful"));
+ thr->valstack_end = thr->valstack + min_size;
+ DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end);
+
return 1;
}
-DUK_EXTERNAL duk_bool_t duk_check_stack(duk_context *ctx, duk_idx_t extra) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_size_t min_new_size;
+/* Hot, inlined value stack grow check. Because value stack almost never
+ * grows, the actual resize call is in a NOINLINE helper.
+ */
+DUK_INTERNAL DUK_INLINE void duk_valstack_grow_check_throw(duk_hthread *thr, duk_size_t min_bytes) {
+ duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + min_bytes);
+ if (DUK_LIKELY(thr->valstack_end >= tv)) {
+ return;
+ }
+ if (DUK_LIKELY(thr->valstack_alloc_end >= tv)) {
+ /* Values in [valstack_top,valstack_alloc_end[ are initialized
+ * to 'undefined' so we can just move the end pointer.
+ */
+ thr->valstack_end = tv;
+ return;
+ }
+ (void) duk__valstack_grow(thr, min_bytes, 1 /*throw_on_error*/);
+}
+
+/* Hot, inlined value stack grow check which doesn't throw. */
+DUK_INTERNAL DUK_INLINE duk_bool_t duk_valstack_grow_check_nothrow(duk_hthread *thr, duk_size_t min_bytes) {
+ duk_tval *tv;
+
+ tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + min_bytes);
+ if (DUK_LIKELY(thr->valstack_end >= tv)) {
+ return 1;
+ }
+ if (DUK_LIKELY(thr->valstack_alloc_end >= tv)) {
+ thr->valstack_end = tv;
+ return 1;
+ }
+ return duk__valstack_grow(thr, min_bytes, 0 /*throw_on_error*/);
+}
+
+/* Value stack shrink check, called from mark-and-sweep. */
+DUK_INTERNAL void duk_valstack_shrink_check_nothrow(duk_hthread *thr, duk_bool_t snug) {
+ duk_size_t alloc_bytes;
+ duk_size_t reserve_bytes;
+ duk_size_t shrink_bytes;
+
+ alloc_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_alloc_end - (duk_uint8_t *) thr->valstack);
+ reserve_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack);
+ DUK_ASSERT(alloc_bytes >= reserve_bytes);
+
+ /* We're free to shrink the value stack allocation down to
+ * reserve_bytes but not more. If 'snug' (emergency GC)
+ * shrink whatever we can. Otherwise only shrink if the new
+ * size would be considerably smaller.
+ */
+
+#if defined(DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT)
+ if (snug) {
+ shrink_bytes = reserve_bytes;
+ } else {
+ duk_size_t proportion, slack;
+
+ /* Require that value stack shrinks by at least X% of its
+ * current size. For example, shift of 2 means at least
+ * 25%. The proportion is computed as bytes and may not
+ * be a multiple of sizeof(duk_tval); that's OK here.
+ */
+ proportion = alloc_bytes >> DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT;
+ if (alloc_bytes - reserve_bytes < proportion) {
+ /* Too little would be freed, do nothing. */
+ return;
+ }
+
+ /* Keep a slack after shrinking. The slack is again a
+ * proportion of the current size (the proportion should
+ * of course be smaller than the check proportion above).
+ */
+#if defined(DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT)
+ DUK_ASSERT(DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT > DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT);
+ slack = alloc_bytes >> DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT;
+#else
+ slack = 0;
+#endif
+ shrink_bytes = reserve_bytes +
+ slack / sizeof(duk_tval) * sizeof(duk_tval); /* multiple of duk_tval */
+ }
+#else /* DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT */
+ /* Always snug, useful in some low memory environments. */
+ DUK_UNREF(snug);
+ shrink_bytes = reserve_bytes;
+#endif /* DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT */
+
+ DUK_D(DUK_DPRINT("valstack shrink check: alloc_bytes=%ld, reserve_bytes=%ld, shrink_bytes=%ld (unvalidated)",
+ (long) alloc_bytes, (long) reserve_bytes, (long) shrink_bytes));
+ DUK_ASSERT(shrink_bytes >= reserve_bytes);
+ if (shrink_bytes >= alloc_bytes) {
+ /* Skip if shrink target is same as current one (or higher,
+ * though that shouldn't happen in practice).
+ */
+ return;
+ }
+ DUK_ASSERT(shrink_bytes / sizeof(duk_tval) * sizeof(duk_tval) == shrink_bytes);
+
+ DUK_D(DUK_DPRINT("valstack shrink check: decided to shrink, snug: %ld", (long) snug));
+
+ duk__resize_valstack(thr, shrink_bytes / sizeof(duk_tval));
+}
+
+DUK_EXTERNAL duk_bool_t duk_check_stack(duk_hthread *thr, duk_idx_t extra) {
+ duk_size_t min_new_bytes;
+
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr != NULL);
- if (DUK_UNLIKELY(extra < 0)) {
- /* Clamping to zero makes the API more robust to calling code
- * calculation errors.
- */
- extra = 0;
+ if (DUK_UNLIKELY(extra < 0 || extra > DUK_USE_VALSTACK_LIMIT)) {
+ if (extra < 0) {
+ /* Clamping to zero makes the API more robust to calling code
+ * calculation errors.
+ */
+ extra = 0;
+ } else {
+ /* Cause grow check to fail without wrapping arithmetic. */
+ extra = DUK_USE_VALSTACK_LIMIT;
+ }
}
- min_new_size = (thr->valstack_top - thr->valstack) + extra + DUK_VALSTACK_INTERNAL_EXTRA;
- return duk_valstack_resize_raw(ctx,
- min_new_size, /* min_new_size */
- 0 /* no shrink */ | /* flags */
- 0 /* no compact */ |
- 0 /* no throw */);
+ min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack) +
+ sizeof(duk_tval) * ((duk_size_t) extra + DUK_VALSTACK_INTERNAL_EXTRA);
+ return duk_valstack_grow_check_nothrow(thr, min_new_bytes);
}
-DUK_EXTERNAL void duk_require_stack(duk_context *ctx, duk_idx_t extra) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_size_t min_new_size;
+DUK_EXTERNAL void duk_require_stack(duk_hthread *thr, duk_idx_t extra) {
+ duk_size_t min_new_bytes;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr != NULL);
- if (DUK_UNLIKELY(extra < 0)) {
- /* Clamping to zero makes the API more robust to calling code
- * calculation errors.
- */
- extra = 0;
+ if (DUK_UNLIKELY(extra < 0 || extra > DUK_USE_VALSTACK_LIMIT)) {
+ if (extra < 0) {
+ /* Clamping to zero makes the API more robust to calling code
+ * calculation errors.
+ */
+ extra = 0;
+ } else {
+ /* Cause grow check to fail without wrapping arithmetic. */
+ extra = DUK_USE_VALSTACK_LIMIT;
+ }
}
- min_new_size = (thr->valstack_top - thr->valstack) + extra + DUK_VALSTACK_INTERNAL_EXTRA;
- (void) duk_valstack_resize_raw(ctx,
- min_new_size, /* min_new_size */
- 0 /* no shrink */ | /* flags */
- 0 /* no compact */ |
- DUK_VSRESIZE_FLAG_THROW);
+ min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack) +
+ sizeof(duk_tval) * ((duk_size_t) extra + DUK_VALSTACK_INTERNAL_EXTRA);
+ duk_valstack_grow_check_throw(thr, min_new_bytes);
}
-DUK_EXTERNAL duk_bool_t duk_check_stack_top(duk_context *ctx, duk_idx_t top) {
- duk_hthread *thr;
- duk_size_t min_new_size;
+DUK_EXTERNAL duk_bool_t duk_check_stack_top(duk_hthread *thr, duk_idx_t top) {
+ duk_size_t min_new_bytes;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
- if (DUK_UNLIKELY(top < 0)) {
- /* Clamping to zero makes the API more robust to calling code
- * calculation errors.
- */
- top = 0;
+ if (DUK_UNLIKELY(top < 0 || top > DUK_USE_VALSTACK_LIMIT)) {
+ if (top < 0) {
+ /* Clamping to zero makes the API more robust to calling code
+ * calculation errors.
+ */
+ top = 0;
+ } else {
+ /* Cause grow check to fail without wrapping arithmetic. */
+ top = DUK_USE_VALSTACK_LIMIT;
+ }
}
- min_new_size = (thr->valstack_bottom - thr->valstack) + top + DUK_VALSTACK_INTERNAL_EXTRA;
- return duk_valstack_resize_raw(ctx,
- min_new_size, /* min_new_size */
- 0 /* no shrink */ | /* flags */
- 0 /* no compact */ |
- 0 /* no throw */);
+ DUK_ASSERT(top >= 0);
+ min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) +
+ sizeof(duk_tval) * ((duk_size_t) top + DUK_VALSTACK_INTERNAL_EXTRA);
+ return duk_valstack_grow_check_nothrow(thr, min_new_bytes);
}
-DUK_EXTERNAL void duk_require_stack_top(duk_context *ctx, duk_idx_t top) {
- duk_hthread *thr;
- duk_size_t min_new_size;
+DUK_EXTERNAL void duk_require_stack_top(duk_hthread *thr, duk_idx_t top) {
+ duk_size_t min_new_bytes;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
- if (DUK_UNLIKELY(top < 0)) {
- /* Clamping to zero makes the API more robust to calling code
- * calculation errors.
- */
- top = 0;
+ if (DUK_UNLIKELY(top < 0 || top > DUK_USE_VALSTACK_LIMIT)) {
+ if (top < 0) {
+ /* Clamping to zero makes the API more robust to calling code
+ * calculation errors.
+ */
+ top = 0;
+ } else {
+ /* Cause grow check to fail without wrapping arithmetic. */
+ top = DUK_USE_VALSTACK_LIMIT;
+ }
}
- min_new_size = (thr->valstack_bottom - thr->valstack) + top + DUK_VALSTACK_INTERNAL_EXTRA;
- (void) duk_valstack_resize_raw(ctx,
- min_new_size, /* min_new_size */
- 0 /* no shrink */ | /* flags */
- 0 /* no compact */ |
- DUK_VSRESIZE_FLAG_THROW);
+ DUK_ASSERT(top >= 0);
+ min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) +
+ sizeof(duk_tval) * ((duk_size_t) top + DUK_VALSTACK_INTERNAL_EXTRA);
+ duk_valstack_grow_check_throw(thr, min_new_bytes);
}
/*
* Basic stack manipulation: swap, dup, insert, replace, etc
*/
-DUK_EXTERNAL void duk_swap(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) {
+DUK_EXTERNAL void duk_swap(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
duk_tval *tv1;
duk_tval *tv2;
duk_tval tv_tmp;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv1 = duk_require_tval(ctx, index1);
+ tv1 = duk_require_tval(thr, idx1);
DUK_ASSERT(tv1 != NULL);
- tv2 = duk_require_tval(ctx, index2);
+ tv2 = duk_require_tval(thr, idx2);
DUK_ASSERT(tv2 != NULL);
/* If tv1==tv2 this is a NOP, no check is needed */
@@ -15845,22 +18188,20 @@ DUK_EXTERNAL void duk_swap(duk_context *ctx, duk_idx_t index1, duk_idx_t index2)
DUK_TVAL_SET_TVAL(tv2, &tv_tmp);
}
-DUK_EXTERNAL void duk_swap_top(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_swap_top(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk_swap(ctx, index, -1);
+ duk_swap(thr, idx, -1);
}
-DUK_EXTERNAL void duk_dup(duk_context *ctx, duk_idx_t from_index) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_dup(duk_hthread *thr, duk_idx_t from_idx) {
duk_tval *tv_from;
duk_tval *tv_to;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
- tv_from = duk_require_tval(ctx, from_index);
+ tv_from = duk_require_tval(thr, from_idx);
tv_to = thr->valstack_top++;
DUK_ASSERT(tv_from != NULL);
DUK_ASSERT(tv_to != NULL);
@@ -15868,17 +18209,18 @@ DUK_EXTERNAL void duk_dup(duk_context *ctx, duk_idx_t from_index) {
DUK_TVAL_INCREF(thr, tv_to); /* no side effects */
}
-DUK_EXTERNAL void duk_dup_top(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_dup_top(duk_hthread *thr) {
+#if defined(DUK_USE_PREFER_SIZE)
+ duk_dup(thr, -1);
+#else
duk_tval *tv_from;
duk_tval *tv_to;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
- if (thr->valstack_top - thr->valstack_bottom <= 0) {
- DUK_ERROR_API_INDEX(thr, -1);
+ if (DUK_UNLIKELY(thr->valstack_top - thr->valstack_bottom <= 0)) {
+ DUK_ERROR_RANGE_INDEX(thr, -1);
return; /* unreachable */
}
tv_from = thr->valstack_top - 1;
@@ -15887,19 +18229,45 @@ DUK_EXTERNAL void duk_dup_top(duk_context *ctx) {
DUK_ASSERT(tv_to != NULL);
DUK_TVAL_SET_TVAL(tv_to, tv_from);
DUK_TVAL_INCREF(thr, tv_to); /* no side effects */
+#endif
}
-DUK_EXTERNAL void duk_insert(duk_context *ctx, duk_idx_t to_index) {
+DUK_INTERNAL void duk_dup_0(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_dup(thr, 0);
+}
+DUK_INTERNAL void duk_dup_1(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_dup(thr, 1);
+}
+DUK_INTERNAL void duk_dup_2(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_dup(thr, 2);
+}
+DUK_INTERNAL void duk_dup_m2(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_dup(thr, -2);
+}
+DUK_INTERNAL void duk_dup_m3(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_dup(thr, -3);
+}
+DUK_INTERNAL void duk_dup_m4(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_dup(thr, -4);
+}
+
+DUK_EXTERNAL void duk_insert(duk_hthread *thr, duk_idx_t to_idx) {
duk_tval *p;
duk_tval *q;
duk_tval tv_tmp;
duk_size_t nbytes;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- p = duk_require_tval(ctx, to_index);
+ p = duk_require_tval(thr, to_idx);
DUK_ASSERT(p != NULL);
- q = duk_require_tval(ctx, -1);
+ q = duk_require_tval(thr, -1);
DUK_ASSERT(q != NULL);
DUK_ASSERT(q >= p);
@@ -15912,8 +18280,8 @@ DUK_EXTERNAL void duk_insert(duk_context *ctx, duk_idx_t to_index) {
nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); /* Note: 'q' is top-1 */
- DUK_DDD(DUK_DDDPRINT("duk_insert: to_index=%ld, p=%p, q=%p, nbytes=%lu",
- (long) to_index, (void *) p, (void *) q, (unsigned long) nbytes));
+ DUK_DDD(DUK_DDDPRINT("duk_insert: to_idx=%ld, p=%p, q=%p, nbytes=%lu",
+ (long) to_idx, (void *) p, (void *) q, (unsigned long) nbytes));
/* No net refcount changes. */
@@ -15929,21 +18297,43 @@ DUK_EXTERNAL void duk_insert(duk_context *ctx, duk_idx_t to_index) {
}
}
-DUK_EXTERNAL void duk_replace(duk_context *ctx, duk_idx_t to_index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_insert_undefined(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(idx >= 0); /* Doesn't support negative indices. */
+
+ duk_push_undefined(thr);
+ duk_insert(thr, idx);
+}
+
+DUK_INTERNAL void duk_insert_undefined_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count) {
+ duk_tval *tv, *tv_end;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(idx >= 0); /* Doesn't support negative indices or count. */
+ DUK_ASSERT(count >= 0);
+
+ tv = duk_reserve_gap(thr, idx, count);
+ tv_end = tv + count;
+ while (tv != tv_end) {
+ DUK_TVAL_SET_UNDEFINED(tv);
+ tv++;
+ }
+}
+
+DUK_EXTERNAL void duk_replace(duk_hthread *thr, duk_idx_t to_idx) {
duk_tval *tv1;
duk_tval *tv2;
duk_tval tv_tmp;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv1 = duk_require_tval(ctx, -1);
+ tv1 = duk_require_tval(thr, -1);
DUK_ASSERT(tv1 != NULL);
- tv2 = duk_require_tval(ctx, to_index);
+ tv2 = duk_require_tval(thr, to_idx);
DUK_ASSERT(tv2 != NULL);
/* For tv1 == tv2, both pointing to stack top, the end result
- * is same as duk_pop(ctx).
+ * is same as duk_pop(thr).
*/
DUK_TVAL_SET_TVAL(&tv_tmp, tv2);
DUK_TVAL_SET_TVAL(tv2, tv1);
@@ -15952,37 +18342,34 @@ DUK_EXTERNAL void duk_replace(duk_context *ctx, duk_idx_t to_index) {
DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
}
-DUK_EXTERNAL void duk_copy(duk_context *ctx, duk_idx_t from_index, duk_idx_t to_index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_copy(duk_hthread *thr, duk_idx_t from_idx, duk_idx_t to_idx) {
duk_tval *tv1;
duk_tval *tv2;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr); /* w/o refcounting */
+ DUK_ASSERT_API_ENTRY(thr);
- tv1 = duk_require_tval(ctx, from_index);
+ tv1 = duk_require_tval(thr, from_idx);
DUK_ASSERT(tv1 != NULL);
- tv2 = duk_require_tval(ctx, to_index);
+ tv2 = duk_require_tval(thr, to_idx);
DUK_ASSERT(tv2 != NULL);
/* For tv1 == tv2, this is a no-op (no explicit check needed). */
DUK_TVAL_SET_TVAL_UPDREF(thr, tv2, tv1); /* side effects */
}
-DUK_EXTERNAL void duk_remove(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_remove(duk_hthread *thr, duk_idx_t idx) {
duk_tval *p;
duk_tval *q;
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
duk_tval tv_tmp;
#endif
duk_size_t nbytes;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- p = duk_require_tval(ctx, index);
+ p = duk_require_tval(thr, idx);
DUK_ASSERT(p != NULL);
- q = duk_require_tval(ctx, -1);
+ q = duk_require_tval(thr, -1);
DUK_ASSERT(q != NULL);
DUK_ASSERT(q >= p);
@@ -15993,7 +18380,7 @@ DUK_EXTERNAL void duk_remove(duk_context *ctx, duk_idx_t index) {
* => [ ... | x | x | q ] [ ... ]
*/
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
/* use a temp: decref only when valstack reachable values are correct */
DUK_TVAL_SET_TVAL(&tv_tmp, p);
#endif
@@ -16004,18 +18391,79 @@ DUK_EXTERNAL void duk_remove(duk_context *ctx, duk_idx_t index) {
DUK_TVAL_SET_UNDEFINED(q);
thr->valstack_top--;
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
#endif
}
+DUK_INTERNAL void duk_remove_unsafe(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_remove(thr, idx); /* XXX: no optimization for now */
+}
+
+DUK_INTERNAL void duk_remove_m2(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_remove(thr, -2);
+}
+
+DUK_INTERNAL void duk_remove_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count) {
+#if defined(DUK_USE_PREFER_SIZE)
+ /* XXX: maybe too slow even when preferring size? */
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(count >= 0);
+ DUK_ASSERT(idx >= 0);
+
+ while (count-- > 0) {
+ duk_remove(thr, idx);
+ }
+#else /* DUK_USE_PREFER_SIZE */
+ duk_tval *tv_src;
+ duk_tval *tv_dst;
+ duk_tval *tv_newtop;
+ duk_tval *tv;
+ duk_size_t bytes;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(count >= 0);
+ DUK_ASSERT(idx >= 0);
+
+ tv_dst = thr->valstack_bottom + idx;
+ DUK_ASSERT(tv_dst <= thr->valstack_top);
+ tv_src = tv_dst + count;
+ DUK_ASSERT(tv_src <= thr->valstack_top);
+ bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) tv_src);
+
+ for (tv = tv_dst; tv < tv_src; tv++) {
+ DUK_TVAL_DECREF_NORZ(thr, tv);
+ }
+
+ DUK_MEMMOVE((void *) tv_dst, (const void *) tv_src, bytes);
+
+ tv_newtop = thr->valstack_top - count;
+ for (tv = tv_newtop; tv < thr->valstack_top; tv++) {
+ DUK_TVAL_SET_UNDEFINED(tv);
+ }
+ thr->valstack_top = tv_newtop;
+
+ /* When not preferring size, only NORZ macros are used; caller
+ * is expected to DUK_REFZERO_CHECK().
+ */
+#endif /* DUK_USE_PREFER_SIZE */
+}
+
+DUK_INTERNAL void duk_remove_n_unsafe(duk_hthread *thr, duk_idx_t idx, duk_idx_t count) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_remove_n(thr, idx, count); /* XXX: no optimization for now */
+}
+
/*
* Stack slice primitives
*/
-DUK_EXTERNAL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx, duk_idx_t count, duk_bool_t is_copy) {
- duk_hthread *to_thr = (duk_hthread *) to_ctx;
- duk_hthread *from_thr = (duk_hthread *) from_ctx;
+DUK_EXTERNAL void duk_xcopymove_raw(duk_hthread *to_thr, duk_hthread *from_thr, duk_idx_t count, duk_bool_t is_copy) {
void *src;
duk_size_t nbytes;
duk_tval *p;
@@ -16023,36 +18471,38 @@ DUK_EXTERNAL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx,
/* XXX: several pointer comparison issues here */
- DUK_ASSERT_CTX_VALID(to_ctx);
- DUK_ASSERT_CTX_VALID(from_ctx);
- DUK_ASSERT(to_ctx != NULL);
- DUK_ASSERT(from_ctx != NULL);
+ DUK_ASSERT_API_ENTRY(to_thr);
+ DUK_ASSERT_CTX_VALID(to_thr);
+ DUK_ASSERT_CTX_VALID(from_thr);
+ DUK_ASSERT(to_thr->heap == from_thr->heap);
- if (to_ctx == from_ctx) {
- DUK_ERROR_API(to_thr, DUK_STR_INVALID_CONTEXT);
+ if (DUK_UNLIKELY(to_thr == from_thr)) {
+ DUK_ERROR_TYPE(to_thr, DUK_STR_INVALID_CONTEXT);
return;
}
- if ((count < 0) ||
- (count > (duk_idx_t) to_thr->valstack_max)) {
- /* Maximum value check ensures 'nbytes' won't wrap below. */
- DUK_ERROR_API(to_thr, DUK_STR_INVALID_COUNT);
+ if (DUK_UNLIKELY((duk_uidx_t) count > (duk_uidx_t) DUK_USE_VALSTACK_LIMIT)) {
+ /* Maximum value check ensures 'nbytes' won't wrap below.
+ * Also handles negative count.
+ */
+ DUK_ERROR_RANGE_INVALID_COUNT(to_thr);
return;
}
+ DUK_ASSERT(count >= 0);
- nbytes = sizeof(duk_tval) * count;
- if (nbytes == 0) {
+ nbytes = sizeof(duk_tval) * (duk_size_t) count;
+ if (DUK_UNLIKELY(nbytes == 0)) {
return;
}
DUK_ASSERT(to_thr->valstack_top <= to_thr->valstack_end);
- if ((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes) {
- DUK_ERROR_API(to_thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
+ if (DUK_UNLIKELY((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes)) {
+ DUK_ERROR_RANGE_PUSH_BEYOND(to_thr);
}
src = (void *) ((duk_uint8_t *) from_thr->valstack_top - nbytes);
- if (src < (void *) from_thr->valstack_bottom) {
- DUK_ERROR_API(to_thr, DUK_STR_INVALID_COUNT);
+ if (DUK_UNLIKELY(src < (void *) from_thr->valstack_bottom)) {
+ DUK_ERROR_RANGE_INVALID_COUNT(to_thr);
}
- /* copy values (no overlap even if to_ctx == from_ctx; that's not
+ /* copy values (no overlap even if to_thr == from_thr; that's not
* allowed now anyway)
*/
DUK_ASSERT(nbytes > 0);
@@ -16082,338 +18532,632 @@ DUK_EXTERNAL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx,
}
}
+/* Internal helper: reserve a gap of 'count' elements at 'idx_base' and return a
+ * pointer to the gap. Values in the gap are garbage and MUST be initialized by
+ * the caller before any side effects may occur. The caller must ensure there's
+ * enough stack reserve for 'count' values.
+ */
+DUK_INTERNAL duk_tval *duk_reserve_gap(duk_hthread *thr, duk_idx_t idx_base, duk_idx_t count) {
+ duk_tval *tv_src;
+ duk_tval *tv_dst;
+ duk_size_t gap_bytes;
+ duk_size_t copy_bytes;
+
+ /* Caller is responsible for ensuring there's enough preallocated
+ * value stack.
+ */
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(count >= 0);
+ DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack_top) >= (duk_size_t) count);
+
+ tv_src = thr->valstack_bottom + idx_base;
+ gap_bytes = (duk_size_t) count * sizeof(duk_tval);
+ tv_dst = (duk_tval *) (void *) ((duk_uint8_t *) tv_src + gap_bytes);
+ copy_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) tv_src);
+ thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_top + gap_bytes);
+ DUK_MEMMOVE((void *) tv_dst, (const void *) tv_src, copy_bytes);
+
+ /* Values in the gap are left as garbage: caller must fill them in
+ * and INCREF them before any side effects.
+ */
+ return tv_src;
+}
+
/*
- * Get/require
+ * Get/opt/require
*/
-DUK_EXTERNAL void duk_require_undefined(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_require_undefined(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_UNDEFINED(tv)) {
- return;
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_UNLIKELY(!DUK_TVAL_IS_UNDEFINED(tv))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "undefined", DUK_STR_NOT_UNDEFINED);
}
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "undefined", DUK_STR_NOT_UNDEFINED);
- return; /* not reachable */
}
-DUK_EXTERNAL void duk_require_null(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_require_null(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_NULL(tv)) {
- return;
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_UNLIKELY(!DUK_TVAL_IS_NULL(tv))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "null", DUK_STR_NOT_NULL);
}
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "null", DUK_STR_NOT_NULL);
- return; /* not reachable */
}
-DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t index) {
- duk_bool_t ret = 0; /* default: false */
+DUK_LOCAL DUK_ALWAYS_INLINE duk_bool_t duk__get_boolean_raw(duk_hthread *thr, duk_idx_t idx, duk_bool_t def_value) {
+ duk_bool_t ret;
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_BOOLEAN(tv)) {
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_TVAL_IS_BOOLEAN(tv)) {
ret = DUK_TVAL_GET_BOOLEAN(tv);
+ DUK_ASSERT(ret == 0 || ret == 1);
+ } else {
+ ret = def_value;
+ /* Not guaranteed to be 0 or 1. */
}
- DUK_ASSERT(ret == 0 || ret == 1);
return ret;
}
-DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
+DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_BOOLEAN(tv)) {
- duk_bool_t ret = DUK_TVAL_GET_BOOLEAN(tv);
- DUK_ASSERT(ret == 0 || ret == 1);
- return ret;
- }
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "boolean", DUK_STR_NOT_BOOLEAN);
- return 0; /* not reachable */
+ return duk__get_boolean_raw(thr, idx, 0); /* default: false */
}
-DUK_EXTERNAL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL duk_bool_t duk_get_boolean_default(duk_hthread *thr, duk_idx_t idx, duk_bool_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return duk__get_boolean_raw(thr, idx, def_value);
+}
+
+DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+ duk_bool_t ret;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_LIKELY(DUK_TVAL_IS_BOOLEAN(tv))) {
+ ret = DUK_TVAL_GET_BOOLEAN(tv);
+ DUK_ASSERT(ret == 0 || ret == 1);
+ return ret;
+ } else {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "boolean", DUK_STR_NOT_BOOLEAN);
+ }
+}
+
+DUK_EXTERNAL duk_bool_t duk_opt_boolean(duk_hthread *thr, duk_idx_t idx, duk_bool_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ return def_value;
+ }
+ return duk_require_boolean(thr, idx);
+}
+
+DUK_LOCAL DUK_ALWAYS_INLINE duk_double_t duk__get_number_raw(duk_hthread *thr, duk_idx_t idx, duk_double_t def_value) {
duk_double_union ret;
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
- ret.d = DUK_DOUBLE_NAN; /* default: NaN */
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_NUMBER(tv)) {
- ret.d = DUK_TVAL_GET_NUMBER(tv);
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+#if defined(DUK_USE_FASTINT)
+ if (DUK_TVAL_IS_FASTINT(tv)) {
+ ret.d = (duk_double_t) DUK_TVAL_GET_FASTINT(tv); /* XXX: cast trick */
+ }
+ else
+#endif
+ if (DUK_TVAL_IS_DOUBLE(tv)) {
+ /* When using packed duk_tval, number must be in NaN-normalized form
+ * for it to be a duk_tval, so no need to normalize. NOP for unpacked
+ * duk_tval.
+ */
+ ret.d = DUK_TVAL_GET_DOUBLE(tv);
+ DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret));
+ } else {
+ ret.d = def_value;
+ /* Default value (including NaN) may not be normalized. */
}
- /*
- * Number should already be in NaN-normalized form, but let's
- * normalize anyway.
- */
-
- DUK_DBLUNION_NORMALIZE_NAN_CHECK(&ret);
return ret.d;
}
-DUK_EXTERNAL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_double_t duk_get_number(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__get_number_raw(thr, idx, DUK_DOUBLE_NAN); /* default: NaN */
+}
+
+DUK_EXTERNAL duk_double_t duk_get_number_default(duk_hthread *thr, duk_idx_t idx, duk_double_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__get_number_raw(thr, idx, def_value);
+}
+
+DUK_EXTERNAL duk_double_t duk_require_number(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
+ duk_double_union ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_NUMBER(tv)) {
- duk_double_union ret;
- ret.d = DUK_TVAL_GET_NUMBER(tv);
-
- /*
- * Number should already be in NaN-normalized form,
- * but let's normalize anyway.
- */
-
- DUK_DBLUNION_NORMALIZE_NAN_CHECK(&ret);
- return ret.d;
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_UNLIKELY(!DUK_TVAL_IS_NUMBER(tv))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER);
}
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER);
- return DUK_DOUBLE_NAN; /* not reachable */
+
+ ret.d = DUK_TVAL_GET_NUMBER(tv);
+
+ /* When using packed duk_tval, number must be in NaN-normalized form
+ * for it to be a duk_tval, so no need to normalize. NOP for unpacked
+ * duk_tval.
+ */
+ DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret));
+ return ret.d;
}
-DUK_EXTERNAL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t index) {
- /* Custom coercion for API */
- DUK_ASSERT_CTX_VALID(ctx);
- return (duk_int_t) duk__api_coerce_d2i(ctx, index, 0 /*require*/);
+DUK_EXTERNAL duk_double_t duk_opt_number(duk_hthread *thr, duk_idx_t idx, duk_double_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ /* User provided default is not NaN normalized. */
+ return def_value;
+ }
+ return duk_require_number(thr, idx);
}
-DUK_EXTERNAL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t index) {
- /* Custom coercion for API */
- DUK_ASSERT_CTX_VALID(ctx);
- return (duk_uint_t) duk__api_coerce_d2ui(ctx, index, 0 /*require*/);
+DUK_EXTERNAL duk_int_t duk_get_int(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return (duk_int_t) duk__api_coerce_d2i(thr, idx, 0 /*def_value*/, 0 /*require*/);
}
-DUK_EXTERNAL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t index) {
- /* Custom coercion for API */
- DUK_ASSERT_CTX_VALID(ctx);
- return (duk_int_t) duk__api_coerce_d2i(ctx, index, 1 /*require*/);
+DUK_EXTERNAL duk_uint_t duk_get_uint(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, 0 /*def_value*/, 0 /*require*/);
}
-DUK_EXTERNAL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t index) {
- /* Custom coercion for API */
- DUK_ASSERT_CTX_VALID(ctx);
- return (duk_uint_t) duk__api_coerce_d2ui(ctx, index, 1 /*require*/);
+DUK_EXTERNAL duk_int_t duk_get_int_default(duk_hthread *thr, duk_idx_t idx, duk_int_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return (duk_int_t) duk__api_coerce_d2i(thr, idx, def_value, 0 /*require*/);
}
-DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
+DUK_EXTERNAL duk_uint_t duk_get_uint_default(duk_hthread *thr, duk_idx_t idx, duk_uint_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, def_value, 0 /*require*/);
+}
+
+DUK_EXTERNAL duk_int_t duk_require_int(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return (duk_int_t) duk__api_coerce_d2i(thr, idx, 0 /*def_value*/, 1 /*require*/);
+}
+
+DUK_EXTERNAL duk_uint_t duk_require_uint(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, 0 /*def_value*/, 1 /*require*/);
+}
+
+DUK_EXTERNAL duk_int_t duk_opt_int(duk_hthread *thr, duk_idx_t idx, duk_int_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ return def_value;
+ }
+ return duk_require_int(thr, idx);
+}
+
+DUK_EXTERNAL duk_uint_t duk_opt_uint(duk_hthread *thr, duk_idx_t idx, duk_uint_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ return def_value;
+ }
+ return duk_require_uint(thr, idx);
+}
+
+DUK_EXTERNAL const char *duk_get_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
+ duk_hstring *h;
const char *ret;
- duk_tval *tv;
+ duk_size_t len;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- /* default: NULL, length 0 */
- ret = NULL;
- if (out_len) {
- *out_len = 0;
- }
-
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_STRING(tv)) {
- /* Here we rely on duk_hstring instances always being zero
- * terminated even if the actual string is not.
- */
- duk_hstring *h = DUK_TVAL_GET_STRING(tv);
- DUK_ASSERT(h != NULL);
+ h = duk_get_hstring(thr, idx);
+ if (h != NULL) {
+ len = DUK_HSTRING_GET_BYTELEN(h);
ret = (const char *) DUK_HSTRING_GET_DATA(h);
- if (out_len) {
- *out_len = DUK_HSTRING_GET_BYTELEN(h);
- }
+ } else {
+ len = 0;
+ ret = NULL;
}
+ if (out_len != NULL) {
+ *out_len = len;
+ }
return ret;
}
-DUK_EXTERNAL const char *duk_require_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL const char *duk_require_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
+ duk_hstring *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = duk_require_hstring(thr, idx);
+ DUK_ASSERT(h != NULL);
+ if (out_len) {
+ *out_len = DUK_HSTRING_GET_BYTELEN(h);
+ }
+ return (const char *) DUK_HSTRING_GET_DATA(h);
+}
+
+DUK_INTERNAL const char *duk_require_lstring_notsymbol(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
+ duk_hstring *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = duk_require_hstring_notsymbol(thr, idx);
+ DUK_ASSERT(h != NULL);
+ if (out_len) {
+ *out_len = DUK_HSTRING_GET_BYTELEN(h);
+ }
+ return (const char *) DUK_HSTRING_GET_DATA(h);
+}
+
+DUK_EXTERNAL const char *duk_get_string(duk_hthread *thr, duk_idx_t idx) {
+ duk_hstring *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = duk_get_hstring(thr, idx);
+ if (h != NULL) {
+ return (const char *) DUK_HSTRING_GET_DATA(h);
+ } else {
+ return NULL;
+ }
+}
+
+DUK_EXTERNAL const char *duk_opt_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ if (out_len != NULL) {
+ *out_len = def_len;
+ }
+ return def_ptr;
+ }
+ return duk_require_lstring(thr, idx, out_len);
+}
+
+DUK_EXTERNAL const char *duk_opt_string(duk_hthread *thr, duk_idx_t idx, const char *def_ptr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ return def_ptr;
+ }
+ return duk_require_string(thr, idx);
+}
+
+DUK_EXTERNAL const char *duk_get_lstring_default(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) {
+ duk_hstring *h;
const char *ret;
+ duk_size_t len;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- /* Note: this check relies on the fact that even a zero-size string
- * has a non-NULL pointer.
- */
- ret = duk_get_lstring(ctx, index, out_len);
- if (ret) {
- return ret;
- }
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "string", DUK_STR_NOT_STRING);
- return NULL; /* not reachable */
-}
-
-DUK_EXTERNAL const char *duk_get_string(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- return duk_get_lstring(ctx, index, NULL);
-}
-
-DUK_EXTERNAL const char *duk_require_string(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- return duk_require_lstring(ctx, index, NULL);
-}
-
-DUK_EXTERNAL void *duk_get_pointer(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_POINTER(tv)) {
- void *p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */
- return (void *) p;
+ h = duk_get_hstring(thr, idx);
+ if (h != NULL) {
+ len = DUK_HSTRING_GET_BYTELEN(h);
+ ret = (const char *) DUK_HSTRING_GET_DATA(h);
+ } else {
+ len = def_len;
+ ret = def_ptr;
}
- return NULL;
+ if (out_len != NULL) {
+ *out_len = len;
+ }
+ return ret;
}
-DUK_EXTERNAL void *duk_require_pointer(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL const char *duk_get_string_default(duk_hthread *thr, duk_idx_t idx, const char *def_value) {
+ duk_hstring *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = duk_get_hstring(thr, idx);
+ if (h != NULL) {
+ return (const char *) DUK_HSTRING_GET_DATA(h);
+ } else {
+ return def_value;
+ }
+}
+
+DUK_INTERNAL const char *duk_get_string_notsymbol(duk_hthread *thr, duk_idx_t idx) {
+ duk_hstring *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = duk_get_hstring_notsymbol(thr, idx);
+ if (h) {
+ return (const char *) DUK_HSTRING_GET_DATA(h);
+ } else {
+ return NULL;
+ }
+}
+
+DUK_EXTERNAL const char *duk_require_string(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return duk_require_lstring(thr, idx, NULL);
+}
+
+DUK_INTERNAL const char *duk_require_string_notsymbol(duk_hthread *thr, duk_idx_t idx) {
+ duk_hstring *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = duk_require_hstring_notsymbol(thr, idx);
+ DUK_ASSERT(h != NULL);
+ return (const char *) DUK_HSTRING_GET_DATA(h);
+}
+
+DUK_EXTERNAL void duk_require_object(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_UNLIKELY(!DUK_TVAL_IS_OBJECT(tv))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT);
+ }
+}
+
+DUK_LOCAL void *duk__get_pointer_raw(duk_hthread *thr, duk_idx_t idx, void *def_value) {
+ duk_tval *tv;
+ void *p;
+
+ DUK_ASSERT_CTX_VALID(thr);
+
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (!DUK_TVAL_IS_POINTER(tv)) {
+ return def_value;
+ }
+
+ p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */
+ return p;
+}
+
+DUK_EXTERNAL void *duk_get_pointer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__get_pointer_raw(thr, idx, NULL /*def_value*/);
+}
+
+DUK_EXTERNAL void *duk_opt_pointer(duk_hthread *thr, duk_idx_t idx, void *def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ return def_value;
+ }
+ return duk_require_pointer(thr, idx);
+}
+
+DUK_EXTERNAL void *duk_get_pointer_default(duk_hthread *thr, duk_idx_t idx, void *def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__get_pointer_raw(thr, idx, def_value);
+}
+
+DUK_EXTERNAL void *duk_require_pointer(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+ void *p;
+
+ DUK_ASSERT_API_ENTRY(thr);
/* Note: here we must be wary of the fact that a pointer may be
* valid and be a NULL.
*/
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_POINTER(tv)) {
- void *p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */
- return (void *) p;
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_UNLIKELY(!DUK_TVAL_IS_POINTER(tv))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "pointer", DUK_STR_NOT_POINTER);
}
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "pointer", DUK_STR_NOT_POINTER);
- return NULL; /* not reachable */
+ p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */
+ return p;
}
#if 0 /*unused*/
-DUK_INTERNAL void *duk_get_voidptr(duk_context *ctx, duk_idx_t index) {
+DUK_INTERNAL void *duk_get_voidptr(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
+ duk_heaphdr *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
- duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
- DUK_ASSERT(h != NULL);
- return (void *) h;
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (!DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
+ return NULL;
}
- return NULL;
+ h = DUK_TVAL_GET_HEAPHDR(tv);
+ DUK_ASSERT(h != NULL);
+ return (void *) h;
}
#endif
-DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_bool_t throw_flag) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL void *duk__get_buffer_helper(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag) {
+ duk_hbuffer *h;
+ void *ret;
+ duk_size_t len;
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
+ DUK_ASSERT_CTX_VALID(thr);
if (out_size != NULL) {
*out_size = 0;
}
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_BUFFER(tv)) {
- duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_LIKELY(DUK_TVAL_IS_BUFFER(tv))) {
+ h = DUK_TVAL_GET_BUFFER(tv);
DUK_ASSERT(h != NULL);
- if (out_size) {
- *out_size = DUK_HBUFFER_GET_SIZE(h);
+
+ len = DUK_HBUFFER_GET_SIZE(h);
+ ret = DUK_HBUFFER_GET_DATA_PTR(thr->heap, h);
+ } else {
+ if (throw_flag) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER);
}
- return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */
+ len = def_size;
+ ret = def_ptr;
}
- if (throw_flag) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "buffer", DUK_STR_NOT_BUFFER);
- }
- return NULL;
-}
-
-DUK_EXTERNAL void *duk_get_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
- return duk__get_buffer_helper(ctx, index, out_size, 0 /*throw_flag*/);
-}
-
-DUK_EXTERNAL void *duk_require_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
- return duk__get_buffer_helper(ctx, index, out_size, 1 /*throw_flag*/);
-}
-
-DUK_LOCAL void *duk__get_buffer_data_helper(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_bool_t throw_flag) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
-
if (out_size != NULL) {
- *out_size = 0;
+ *out_size = len;
+ }
+ return ret;
+}
+
+DUK_EXTERNAL void *duk_get_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return duk__get_buffer_helper(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/);
+}
+
+DUK_EXTERNAL void *duk_opt_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ if (out_size != NULL) {
+ *out_size = def_size;
+ }
+ return def_ptr;
+ }
+ return duk_require_buffer(thr, idx, out_size);
+}
+
+DUK_EXTERNAL void *duk_get_buffer_default(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return duk__get_buffer_helper(thr, idx, out_size, def_ptr, def_len, 0 /*throw_flag*/);
+}
+
+DUK_EXTERNAL void *duk_require_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return duk__get_buffer_helper(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/);
+}
+
+/* Get the active buffer data area for a plain buffer or a buffer object.
+ * Return NULL if the the value is not a buffer. Note that a buffer may
+ * have a NULL data pointer when its size is zero, the optional 'out_isbuffer'
+ * argument allows caller to detect this reliably.
+ */
+DUK_INTERNAL void *duk_get_buffer_data_raw(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag, duk_bool_t *out_isbuffer) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (out_isbuffer != NULL) {
+ *out_isbuffer = 0;
+ }
+ if (out_size != NULL) {
+ *out_size = def_size;
}
- tv = duk_get_tval(ctx, index);
- if (tv == NULL) {
- goto fail;
- }
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_BUFFER(tv)) {
duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
DUK_ASSERT(h != NULL);
- if (out_size) {
+ if (out_size != NULL) {
*out_size = DUK_HBUFFER_GET_SIZE(h);
}
+ if (out_isbuffer != NULL) {
+ *out_isbuffer = 1;
+ }
return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */
- } else if (DUK_TVAL_IS_OBJECT(tv)) {
+ }
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+ else if (DUK_TVAL_IS_OBJECT(tv)) {
duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
- if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
+ if (DUK_HOBJECT_IS_BUFOBJ(h)) {
/* XXX: this is probably a useful shared helper: for a
- * duk_hbufferobject, get a validated buffer pointer/length.
+ * duk_hbufobj, get a validated buffer pointer/length.
*/
- duk_hbufferobject *h_bufobj = (duk_hbufferobject *) h;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+ duk_hbufobj *h_bufobj = (duk_hbufobj *) h;
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
if (h_bufobj->buf != NULL &&
- DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)) {
+ DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) {
duk_uint8_t *p;
p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf);
if (out_size != NULL) {
*out_size = (duk_size_t) h_bufobj->length;
}
+ if (out_isbuffer != NULL) {
+ *out_isbuffer = 1;
+ }
return (void *) (p + h_bufobj->offset);
}
/* if slice not fully valid, treat as error */
}
}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
- fail:
if (throw_flag) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "buffer", DUK_STR_NOT_BUFFER);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER);
}
- return NULL;
+ return def_ptr;
}
-DUK_EXTERNAL void *duk_get_buffer_data(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
- return duk__get_buffer_data_helper(ctx, index, out_size, 0 /*throw_flag*/);
+DUK_EXTERNAL void *duk_get_buffer_data(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_get_buffer_data_raw(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, NULL);
}
-DUK_EXTERNAL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
- return duk__get_buffer_data_helper(ctx, index, out_size, 1 /*throw_flag*/);
+DUK_EXTERNAL void *duk_get_buffer_data_default(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_get_buffer_data_raw(thr, idx, out_size, def_ptr, def_size, 0 /*throw_flag*/, NULL);
+}
+
+DUK_EXTERNAL void *duk_opt_buffer_data(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ if (out_size != NULL) {
+ *out_size = def_size;
+ }
+ return def_ptr;
+ }
+ return duk_require_buffer_data(thr, idx, out_size);
+}
+
+DUK_EXTERNAL void *duk_require_buffer_data(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_get_buffer_data_raw(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/, NULL);
}
/* Raw helper for getting a value from the stack, checking its tag.
@@ -16421,318 +19165,435 @@ DUK_EXTERNAL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t index, du
* tag in the packed representation.
*/
-DUK_LOCAL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t index, duk_uint_t tag) {
+DUK_LOCAL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_hthread *thr, duk_idx_t idx, duk_uint_t tag) {
duk_tval *tv;
+ duk_heaphdr *ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && (DUK_TVAL_GET_TAG(tv) == tag)) {
- duk_heaphdr *ret;
- ret = DUK_TVAL_GET_HEAPHDR(tv);
- DUK_ASSERT(ret != NULL); /* tagged null pointers should never occur */
- return ret;
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_TVAL_GET_TAG(tv) != tag) {
+ return (duk_heaphdr *) NULL;
}
- return (duk_heaphdr *) NULL;
+ ret = DUK_TVAL_GET_HEAPHDR(tv);
+ DUK_ASSERT(ret != NULL); /* tagged null pointers should never occur */
+ return ret;
+
}
-DUK_INTERNAL duk_hstring *duk_get_hstring(duk_context *ctx, duk_idx_t index) {
- return (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING);
+DUK_INTERNAL duk_hstring *duk_get_hstring(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING);
}
-DUK_INTERNAL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t index) {
- duk_heaphdr *h;
- h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING);
- if (h == NULL) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "string", DUK_STR_NOT_STRING);
- }
- return (duk_hstring *) h;
-}
+DUK_INTERNAL duk_hstring *duk_get_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx) {
+ duk_hstring *h;
-DUK_INTERNAL duk_hobject *duk_get_hobject(duk_context *ctx, duk_idx_t index) {
- return (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
-}
+ DUK_ASSERT_API_ENTRY(thr);
-DUK_INTERNAL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t index) {
- duk_heaphdr *h;
- h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (h == NULL) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "object", DUK_STR_NOT_OBJECT);
- }
- return (duk_hobject *) h;
-}
-
-DUK_INTERNAL duk_hbuffer *duk_get_hbuffer(duk_context *ctx, duk_idx_t index) {
- return (duk_hbuffer *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER);
-}
-
-DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t index) {
- duk_heaphdr *h;
- h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER);
- if (h == NULL) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "buffer", DUK_STR_NOT_BUFFER);
- }
- return (duk_hbuffer *) h;
-}
-
-DUK_INTERNAL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t index) {
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (h != NULL && !DUK_HOBJECT_IS_THREAD(h)) {
- h = NULL;
- }
- return (duk_hthread *) h;
-}
-
-DUK_INTERNAL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (!(h != NULL && DUK_HOBJECT_IS_THREAD(h))) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "thread", DUK_STR_NOT_THREAD);
- }
- return (duk_hthread *) h;
-}
-
-DUK_INTERNAL duk_hcompiledfunction *duk_get_hcompiledfunction(duk_context *ctx, duk_idx_t index) {
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (h != NULL && !DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
- h = NULL;
- }
- return (duk_hcompiledfunction *) h;
-}
-
-DUK_INTERNAL duk_hcompiledfunction *duk_require_hcompiledfunction(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (!(h != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(h))) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "compiledfunction", DUK_STR_NOT_COMPILEDFUNCTION);
- }
- return (duk_hcompiledfunction *) h;
-}
-
-DUK_INTERNAL duk_hnativefunction *duk_get_hnativefunction(duk_context *ctx, duk_idx_t index) {
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (h != NULL && !DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
- h = NULL;
- }
- return (duk_hnativefunction *) h;
-}
-
-DUK_INTERNAL duk_hnativefunction *duk_require_hnativefunction(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (!(h != NULL && DUK_HOBJECT_IS_NATIVEFUNCTION(h))) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "nativefunction", DUK_STR_NOT_NATIVEFUNCTION);
- }
- return (duk_hnativefunction *) h;
-}
-
-DUK_EXTERNAL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
- duk_hobject *h;
- duk_hnativefunction *f;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (!tv) {
+ h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING);
+ if (DUK_UNLIKELY(h && DUK_HSTRING_HAS_SYMBOL(h))) {
return NULL;
}
- if (!DUK_TVAL_IS_OBJECT(tv)) {
+ return h;
+}
+
+DUK_INTERNAL duk_hstring *duk_require_hstring(duk_hthread *thr, duk_idx_t idx) {
+ duk_hstring *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING);
+ if (DUK_UNLIKELY(h == NULL)) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "string", DUK_STR_NOT_STRING);
+ }
+ return h;
+}
+
+DUK_INTERNAL duk_hstring *duk_require_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx) {
+ duk_hstring *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING);
+ if (DUK_UNLIKELY(h == NULL || DUK_HSTRING_HAS_SYMBOL(h))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "string", DUK_STR_NOT_STRING);
+ }
+ return h;
+}
+
+DUK_INTERNAL duk_hobject *duk_get_hobject(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
+}
+
+DUK_INTERNAL duk_hobject *duk_require_hobject(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
+ if (DUK_UNLIKELY(h == NULL)) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT);
+ }
+ return h;
+}
+
+DUK_INTERNAL duk_hbuffer *duk_get_hbuffer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return (duk_hbuffer *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_BUFFER);
+}
+
+DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_hthread *thr, duk_idx_t idx) {
+ duk_hbuffer *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hbuffer *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_BUFFER);
+ if (DUK_UNLIKELY(h == NULL)) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER);
+ }
+ return h;
+}
+
+DUK_INTERNAL duk_hthread *duk_get_hthread(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
+ if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_THREAD(h))) {
+ h = NULL;
+ }
+ return (duk_hthread *) h;
+}
+
+DUK_INTERNAL duk_hthread *duk_require_hthread(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
+ if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_THREAD(h)))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "thread", DUK_STR_NOT_THREAD);
+ }
+ return (duk_hthread *) h;
+}
+
+DUK_INTERNAL duk_hcompfunc *duk_get_hcompfunc(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
+ if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_COMPFUNC(h))) {
+ h = NULL;
+ }
+ return (duk_hcompfunc *) h;
+}
+
+DUK_INTERNAL duk_hcompfunc *duk_require_hcompfunc(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
+ if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_COMPFUNC(h)))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "compiledfunction", DUK_STR_NOT_COMPFUNC);
+ }
+ return (duk_hcompfunc *) h;
+}
+
+DUK_INTERNAL duk_hnatfunc *duk_get_hnatfunc(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
+ if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_NATFUNC(h))) {
+ h = NULL;
+ }
+ return (duk_hnatfunc *) h;
+}
+
+DUK_INTERNAL duk_hnatfunc *duk_require_hnatfunc(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
+ if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_NATFUNC(h)))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC);
+ }
+ return (duk_hnatfunc *) h;
+}
+
+DUK_EXTERNAL duk_c_function duk_get_c_function(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+ duk_hobject *h;
+ duk_hnatfunc *f;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_UNLIKELY(!DUK_TVAL_IS_OBJECT(tv))) {
return NULL;
}
h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
- if (!DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
+ if (DUK_UNLIKELY(!DUK_HOBJECT_IS_NATFUNC(h))) {
return NULL;
}
- DUK_ASSERT(DUK_HOBJECT_HAS_NATIVEFUNCTION(h));
- f = (duk_hnativefunction *) h;
+ DUK_ASSERT(DUK_HOBJECT_HAS_NATFUNC(h));
+ f = (duk_hnatfunc *) h;
return f->func;
}
-DUK_EXTERNAL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_c_function duk_opt_c_function(duk_hthread *thr, duk_idx_t idx, duk_c_function def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ return def_value;
+ }
+ return duk_require_c_function(thr, idx);
+}
+
+DUK_EXTERNAL duk_c_function duk_get_c_function_default(duk_hthread *thr, duk_idx_t idx, duk_c_function def_value) {
duk_c_function ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- ret = duk_get_c_function(ctx, index);
- if (!ret) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "nativefunction", DUK_STR_NOT_NATIVEFUNCTION);
+ ret = duk_get_c_function(thr, idx);
+ if (ret != NULL) {
+ return ret;
+ }
+
+ return def_value;
+}
+
+DUK_EXTERNAL duk_c_function duk_require_c_function(duk_hthread *thr, duk_idx_t idx) {
+ duk_c_function ret;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ ret = duk_get_c_function(thr, idx);
+ if (DUK_UNLIKELY(!ret)) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC);
}
return ret;
}
-DUK_EXTERNAL void duk_require_function(duk_context *ctx, duk_idx_t index) {
- if (!duk_is_function(ctx, index)) {
- DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, index, "function", DUK_STR_NOT_FUNCTION);
+DUK_EXTERNAL void duk_require_function(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ if (DUK_UNLIKELY(!duk_is_function(thr, idx))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "function", DUK_STR_NOT_FUNCTION);
}
}
-DUK_EXTERNAL duk_context *duk_get_context(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_INTERNAL void duk_require_constructable(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
- return (duk_context *) duk_get_hthread(ctx, index);
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = duk_require_hobject_accept_mask(thr, idx, DUK_TYPE_MASK_LIGHTFUNC);
+ if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_HAS_CONSTRUCTABLE(h))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "constructable", DUK_STR_NOT_CONSTRUCTABLE);
+ }
+ /* Lightfuncs (h == NULL) are constructable. */
}
-DUK_EXTERNAL duk_context *duk_require_context(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_hthread *duk_get_context(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- return (duk_context *) duk_require_hthread(ctx, index);
+ return duk_get_hthread(thr, idx);
}
-DUK_EXTERNAL void *duk_get_heapptr(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
- void *ret;
+DUK_EXTERNAL duk_hthread *duk_require_context(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- DUK_ASSERT_CTX_VALID(ctx);
+ return duk_require_hthread(thr, idx);
+}
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
- ret = (void *) DUK_TVAL_GET_HEAPHDR(tv);
- DUK_ASSERT(ret != NULL);
+DUK_EXTERNAL duk_hthread *duk_opt_context(duk_hthread *thr, duk_idx_t idx, duk_hthread *def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ return def_value;
+ }
+ return duk_require_context(thr, idx);
+}
+
+DUK_EXTERNAL duk_hthread *duk_get_context_default(duk_hthread *thr, duk_idx_t idx, duk_hthread *def_value) {
+ duk_hthread *ret;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ ret = duk_get_context(thr, idx);
+ if (ret != NULL) {
return ret;
}
- return (void *) NULL;
+ return def_value;
}
-DUK_EXTERNAL void *duk_require_heapptr(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void *duk_get_heapptr(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
void *ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, index);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
- if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
- ret = (void *) DUK_TVAL_GET_HEAPHDR(tv);
- DUK_ASSERT(ret != NULL);
+ if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) {
+ return (void *) NULL;
+ }
+
+ ret = (void *) DUK_TVAL_GET_HEAPHDR(tv);
+ DUK_ASSERT(ret != NULL);
+ return ret;
+}
+
+DUK_EXTERNAL void *duk_opt_heapptr(duk_hthread *thr, duk_idx_t idx, void *def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ return def_value;
+ }
+ return duk_require_heapptr(thr, idx);
+}
+
+DUK_EXTERNAL void *duk_get_heapptr_default(duk_hthread *thr, duk_idx_t idx, void *def_value) {
+ void *ret;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ ret = duk_get_heapptr(thr, idx);
+ if (ret != NULL) {
return ret;
}
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "heapobject", DUK_STR_UNEXPECTED_TYPE);
- return (void *) NULL; /* not reachable */
+ return def_value;
}
-#if 0
-/* This would be pointless: we'd return NULL for both lightfuncs and
- * unexpected types.
- */
-DUK_INTERNAL duk_hobject *duk_get_hobject_or_lfunc(duk_context *ctx, duk_idx_t index) {
-}
-#endif
-
-/* Useful for internal call sites where we either expect an object (function)
- * or a lightfunc. Accepts an object (returned as is) or a lightfunc (coerced
- * to an object). Return value is NULL if value is neither an object nor a
- * lightfunc.
- */
-DUK_INTERNAL duk_hobject *duk_get_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL void *duk_require_heapptr(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
+ void *ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, index);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
- if (DUK_TVAL_IS_OBJECT(tv)) {
- return DUK_TVAL_GET_OBJECT(tv);
- } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
- duk_to_object(ctx, index);
- return duk_require_hobject(ctx, index);
+ if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "heapobject", DUK_STR_UNEXPECTED_TYPE);
}
+ ret = (void *) DUK_TVAL_GET_HEAPHDR(tv);
+ DUK_ASSERT(ret != NULL);
+ return ret;
+}
+
+/* Internal helper for getting/requiring a duk_hobject with possible promotion. */
+DUK_LOCAL duk_hobject *duk__get_hobject_promote_mask_raw(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) {
+ duk_uint_t val_mask;
+ duk_hobject *res;
+
+ DUK_ASSERT_CTX_VALID(thr);
+
+ res = duk_get_hobject(thr, idx); /* common case, not promoted */
+ if (DUK_LIKELY(res != NULL)) {
+ DUK_ASSERT(res != NULL);
+ return res;
+ }
+
+ val_mask = duk_get_type_mask(thr, idx);
+ if (val_mask & type_mask) {
+ if (type_mask & DUK_TYPE_MASK_PROMOTE) {
+ res = duk_to_hobject(thr, idx);
+ DUK_ASSERT(res != NULL);
+ return res;
+ } else {
+ return NULL; /* accept without promoting */
+ }
+ }
+
+ if (type_mask & DUK_TYPE_MASK_THROW) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT);
+ }
return NULL;
}
-/* Useful for internal call sites where we either expect an object (function)
- * or a lightfunc. Returns NULL for a lightfunc.
+/* Get a duk_hobject * at 'idx'; if the value is not an object but matches the
+ * supplied 'type_mask', promote it to an object and return the duk_hobject *.
+ * This is useful for call sites which want an object but also accept a plain
+ * buffer and/or a lightfunc which gets automatically promoted to an object.
+ * Return value is NULL if value is neither an object nor a plain type allowed
+ * by the mask.
*/
-DUK_INTERNAL duk_hobject *duk_require_hobject_or_lfunc(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_require_tval(ctx, index);
- DUK_ASSERT(tv != NULL);
- if (DUK_TVAL_IS_OBJECT(tv)) {
- return DUK_TVAL_GET_OBJECT(tv);
- } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
- return NULL;
- }
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "object", DUK_STR_NOT_OBJECT);
- return NULL; /* not reachable */
+DUK_INTERNAL duk_hobject *duk_get_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__get_hobject_promote_mask_raw(thr, idx, type_mask | DUK_TYPE_MASK_PROMOTE);
}
-/* Useful for internal call sites where we either expect an object (function)
- * or a lightfunc. Accepts an object (returned as is) or a lightfunc (coerced
- * to an object). Return value is never NULL.
+/* Like duk_get_hobject_promote_mask() but throw a TypeError instead of
+ * returning a NULL.
*/
-DUK_INTERNAL duk_hobject *duk_require_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_require_tval(ctx, index);
- if (DUK_TVAL_IS_OBJECT(tv)) {
- return DUK_TVAL_GET_OBJECT(tv);
- } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
- duk_to_object(ctx, index);
- return duk_require_hobject(ctx, index);
- }
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "object", DUK_STR_NOT_OBJECT);
- return NULL; /* not reachable */
+DUK_INTERNAL duk_hobject *duk_require_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__get_hobject_promote_mask_raw(thr, idx, type_mask | DUK_TYPE_MASK_THROW | DUK_TYPE_MASK_PROMOTE);
}
-DUK_INTERNAL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum) {
+/* Require a duk_hobject * at 'idx'; if the value is not an object but matches the
+ * supplied 'type_mask', return a NULL instead. Otherwise throw a TypeError.
+ */
+DUK_INTERNAL duk_hobject *duk_require_hobject_accept_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__get_hobject_promote_mask_raw(thr, idx, type_mask | DUK_TYPE_MASK_THROW);
+}
+
+DUK_INTERNAL duk_hobject *duk_get_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum) {
duk_hobject *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */
DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX);
- h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum) {
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
+ if (DUK_UNLIKELY(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum)) {
h = NULL;
}
return h;
}
-DUK_INTERNAL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum) {
- duk_hthread *thr;
+DUK_INTERNAL duk_hobject *duk_require_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum) {
duk_hobject *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */
DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX);
- thr = (duk_hthread *) ctx;
- h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum)) {
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
+ if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum))) {
duk_hstring *h_class;
h_class = DUK_HTHREAD_GET_STRING(thr, DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum));
DUK_UNREF(h_class);
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, (const char *) DUK_HSTRING_GET_DATA(h_class), DUK_STR_UNEXPECTED_TYPE);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, (const char *) DUK_HSTRING_GET_DATA(h_class), DUK_STR_UNEXPECTED_TYPE);
}
return h;
}
-DUK_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL duk_size_t duk_get_length(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (!tv) {
- return 0;
- }
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
switch (DUK_TVAL_GET_TAG(tv)) {
case DUK_TAG_UNDEFINED:
@@ -16740,51 +19601,130 @@ DUK_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t index) {
case DUK_TAG_BOOLEAN:
case DUK_TAG_POINTER:
return 0;
+#if defined(DUK_USE_PREFER_SIZE)
+ /* String and buffer have a virtual non-configurable .length property
+ * which is within size_t range so it can be looked up without specific
+ * type checks. Lightfuncs inherit from %NativeFunctionPrototype%
+ * which provides an inherited .length accessor; it could be overwritten
+ * to produce unexpected types or values, but just number convert and
+ * duk_size_t cast for now.
+ */
+ case DUK_TAG_STRING:
+ case DUK_TAG_BUFFER:
+ case DUK_TAG_LIGHTFUNC: {
+ duk_size_t ret;
+ duk_get_prop_stridx(thr, idx, DUK_STRIDX_LENGTH);
+ ret = (duk_size_t) duk_to_number_m1(thr);
+ duk_pop_unsafe(thr);
+ return ret;
+ }
+#else /* DUK_USE_PREFER_SIZE */
case DUK_TAG_STRING: {
duk_hstring *h = DUK_TVAL_GET_STRING(tv);
DUK_ASSERT(h != NULL);
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
+ return 0;
+ }
return (duk_size_t) DUK_HSTRING_GET_CHARLEN(h);
}
- case DUK_TAG_OBJECT: {
- duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
- return (duk_size_t) duk_hobject_get_length((duk_hthread *) ctx, h);
- }
case DUK_TAG_BUFFER: {
duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
DUK_ASSERT(h != NULL);
return (duk_size_t) DUK_HBUFFER_GET_SIZE(h);
}
case DUK_TAG_LIGHTFUNC: {
- duk_small_uint_t lf_flags;
- lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
- return (duk_size_t) DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
+ /* We could look up the length from the lightfunc duk_tval,
+ * but since Duktape 2.2 lightfunc .length comes from
+ * %NativeFunctionPrototype% which can be overridden, so
+ * look up the property explicitly.
+ */
+ duk_size_t ret;
+ duk_get_prop_stridx(thr, idx, DUK_STRIDX_LENGTH);
+ ret = (duk_size_t) duk_to_number_m1(thr);
+ duk_pop_unsafe(thr);
+ return ret;
+ }
+#endif /* DUK_USE_PREFER_SIZE */
+ case DUK_TAG_OBJECT: {
+ duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ return (duk_size_t) duk_hobject_get_length(thr, h);
}
#if defined(DUK_USE_FASTINT)
case DUK_TAG_FASTINT:
#endif
default:
- /* number */
- DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
+ /* number or 'unused' */
+ DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv) || DUK_TVAL_IS_UNUSED(tv));
return 0;
}
DUK_UNREACHABLE();
}
-DUK_INTERNAL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_size_t length) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h;
+/*
+ * duk_known_xxx() helpers
+ *
+ * Used internally when we're 100% sure that a certain index is valid and
+ * contains an object of a certain type. For example, if we duk_push_object()
+ * we can then safely duk_known_hobject(thr, -1). These helpers just assert
+ * for the index and type, and if the assumptions are not valid, memory unsafe
+ * behavior happens.
+ */
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_LOCAL duk_heaphdr *duk__known_heaphdr(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+ duk_heaphdr *h;
- h = duk_get_hobject(ctx, index);
- if (!h) {
- return;
+ DUK_ASSERT_CTX_VALID(thr);
+ if (idx < 0) {
+ tv = thr->valstack_top + idx;
+ } else {
+ tv = thr->valstack_bottom + idx;
}
+ DUK_ASSERT(tv >= thr->valstack_bottom);
+ DUK_ASSERT(tv < thr->valstack_top);
+ h = DUK_TVAL_GET_HEAPHDR(tv);
+ DUK_ASSERT(h != NULL);
+ return h;
+}
- duk_hobject_set_length(thr, h, (duk_uint32_t) length); /* XXX: typing */
+DUK_INTERNAL duk_hstring *duk_known_hstring(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(duk_get_hstring(thr, idx) != NULL);
+ return (duk_hstring *) duk__known_heaphdr(thr, idx);
+}
+
+DUK_INTERNAL duk_hobject *duk_known_hobject(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(duk_get_hobject(thr, idx) != NULL);
+ return (duk_hobject *) duk__known_heaphdr(thr, idx);
+}
+
+DUK_INTERNAL duk_hbuffer *duk_known_hbuffer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(duk_get_hbuffer(thr, idx) != NULL);
+ return (duk_hbuffer *) duk__known_heaphdr(thr, idx);
+}
+
+DUK_INTERNAL duk_hcompfunc *duk_known_hcompfunc(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(duk_get_hcompfunc(thr, idx) != NULL);
+ return (duk_hcompfunc *) duk__known_heaphdr(thr, idx);
+}
+
+DUK_INTERNAL duk_hnatfunc *duk_known_hnatfunc(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(duk_get_hnatfunc(thr, idx) != NULL);
+ return (duk_hnatfunc *) duk__known_heaphdr(thr, idx);
+}
+
+DUK_EXTERNAL void duk_set_length(duk_hthread *thr, duk_idx_t idx, duk_size_t len) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ idx = duk_normalize_index(thr, idx);
+ duk_push_uint(thr, (duk_uint_t) len);
+ duk_put_prop_stridx(thr, idx, DUK_STRIDX_LENGTH);
}
/*
@@ -16797,40 +19737,99 @@ DUK_INTERNAL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_size_t l
/* E5 Section 8.12.8 */
-DUK_LOCAL duk_bool_t duk__defaultvalue_coerce_attempt(duk_context *ctx, duk_idx_t index, duk_small_int_t func_stridx) {
- if (duk_get_prop_stridx(ctx, index, func_stridx)) {
+DUK_LOCAL duk_bool_t duk__defaultvalue_coerce_attempt(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t func_stridx) {
+ if (duk_get_prop_stridx(thr, idx, func_stridx)) {
/* [ ... func ] */
- if (duk_is_callable(ctx, -1)) {
- duk_dup(ctx, index); /* -> [ ... func this ] */
- duk_call_method(ctx, 0); /* -> [ ... retval ] */
- if (duk_is_primitive(ctx, -1)) {
- duk_replace(ctx, index);
+ if (duk_is_callable(thr, -1)) {
+ duk_dup(thr, idx); /* -> [ ... func this ] */
+ duk_call_method(thr, 0); /* -> [ ... retval ] */
+ if (duk_is_primitive(thr, -1)) {
+ duk_replace(thr, idx);
return 1;
}
/* [ ... retval ]; popped below */
}
}
- duk_pop(ctx); /* [ ... func/retval ] -> [ ... ] */
+ duk_pop_unsafe(thr); /* [ ... func/retval ] -> [ ... ] */
return 0;
}
-DUK_EXTERNAL void duk_to_defaultvalue(duk_context *ctx, duk_idx_t index, duk_int_t hint) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *obj;
- /* inline initializer for coercers[] is not allowed by old compilers like BCC */
- duk_small_int_t coercers[2];
+DUK_EXTERNAL void duk_to_undefined(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_require_tval(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
+}
+
+DUK_EXTERNAL void duk_to_null(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_require_tval(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ DUK_TVAL_SET_NULL_UPDREF(thr, tv); /* side effects */
+}
+
+/* E5 Section 9.1 */
+DUK_EXTERNAL void duk_to_primitive(duk_hthread *thr, duk_idx_t idx, duk_int_t hint) {
+ /* inline initializer for coercers[] is not allowed by old compilers like BCC */
+ duk_small_uint_t coercers[2];
+ duk_small_uint_t class_number;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(hint == DUK_HINT_NONE || hint == DUK_HINT_NUMBER || hint == DUK_HINT_STRING);
+
+ idx = duk_require_normalize_index(thr, idx);
+
+ if (!duk_check_type_mask(thr, idx, DUK_TYPE_MASK_OBJECT |
+ DUK_TYPE_MASK_LIGHTFUNC |
+ DUK_TYPE_MASK_BUFFER)) {
+ /* Any other values stay as is. */
+ DUK_ASSERT(!duk_is_buffer(thr, idx)); /* duk_to_string() relies on this behavior */
+ return;
+ }
+
+ class_number = duk_get_class_number(thr, idx);
+
+ /* XXX: Symbol objects normally coerce via the ES2015-revised ToPrimitive()
+ * algorithm which consults value[@@toPrimitive] and avoids calling
+ * .valueOf() and .toString(). Before that is implemented, special
+ * case Symbol objects to behave as if they had the default @@toPrimitive
+ * algorithm of E6 Section 19.4.3.4, i.e. return the plain symbol value
+ * with no further side effects.
+ */
+
+ if (class_number == DUK_HOBJECT_CLASS_SYMBOL) {
+ duk_hobject *h_obj;
+ duk_hstring *h_str;
+
+ /* XXX: pretty awkward, index based API for internal value access? */
+ h_obj = duk_known_hobject(thr, idx);
+ h_str = duk_hobject_get_internal_value_string(thr->heap, h_obj);
+ if (h_str) {
+ duk_push_hstring(thr, h_str);
+ duk_replace(thr, idx);
+ return;
+ }
+ }
+
+
+ /* Objects are coerced based on E5 specification.
+ * Lightfuncs are coerced because they behave like
+ * objects even if they're internally a primitive
+ * type. Same applies to plain buffers, which behave
+ * like ArrayBuffer objects since Duktape 2.x.
+ */
coercers[0] = DUK_STRIDX_VALUE_OF;
coercers[1] = DUK_STRIDX_TO_STRING;
- index = duk_require_normalize_index(ctx, index);
- obj = duk_require_hobject_or_lfunc(ctx, index);
-
if (hint == DUK_HINT_NONE) {
- if (obj != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_DATE) {
+ if (class_number == DUK_HOBJECT_CLASS_DATE) {
hint = DUK_HINT_STRING;
} else {
hint = DUK_HINT_NUMBER;
@@ -16842,204 +19841,214 @@ DUK_EXTERNAL void duk_to_defaultvalue(duk_context *ctx, duk_idx_t index, duk_int
coercers[1] = DUK_STRIDX_VALUE_OF;
}
- if (duk__defaultvalue_coerce_attempt(ctx, index, coercers[0])) {
+ if (duk__defaultvalue_coerce_attempt(thr, idx, coercers[0])) {
+ DUK_ASSERT(!duk_is_buffer(thr, idx)); /* duk_to_string() relies on this behavior */
return;
}
- if (duk__defaultvalue_coerce_attempt(ctx, index, coercers[1])) {
+ if (duk__defaultvalue_coerce_attempt(thr, idx, coercers[1])) {
+ DUK_ASSERT(!duk_is_buffer(thr, idx)); /* duk_to_string() relies on this behavior */
return;
}
- DUK_ERROR_TYPE(thr, DUK_STR_DEFAULTVALUE_COERCE_FAILED);
-}
-
-DUK_EXTERNAL void duk_to_undefined(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
-
- tv = duk_require_tval(ctx, index);
- DUK_ASSERT(tv != NULL);
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
-}
-
-DUK_EXTERNAL void duk_to_null(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
-
- tv = duk_require_tval(ctx, index);
- DUK_ASSERT(tv != NULL);
- DUK_TVAL_SET_NULL_UPDREF(thr, tv); /* side effects */
-}
-
-/* E5 Section 9.1 */
-DUK_EXTERNAL void duk_to_primitive(duk_context *ctx, duk_idx_t index, duk_int_t hint) {
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(hint == DUK_HINT_NONE || hint == DUK_HINT_NUMBER || hint == DUK_HINT_STRING);
-
- index = duk_require_normalize_index(ctx, index);
-
- if (!duk_check_type_mask(ctx, index, DUK_TYPE_MASK_OBJECT |
- DUK_TYPE_MASK_LIGHTFUNC)) {
- /* everything except object stay as is */
- return;
- }
- duk_to_defaultvalue(ctx, index, hint);
+ DUK_ERROR_TYPE(thr, DUK_STR_TOPRIMITIVE_FAILED);
}
/* E5 Section 9.2 */
-DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_bool_t val;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
+ DUK_ASSERT_API_ENTRY(thr);
- index = duk_require_normalize_index(ctx, index);
-
- tv = duk_require_tval(ctx, index);
+ idx = duk_require_normalize_index(thr, idx);
+ tv = DUK_GET_TVAL_POSIDX(thr, idx);
DUK_ASSERT(tv != NULL);
val = duk_js_toboolean(tv);
DUK_ASSERT(val == 0 || val == 1);
- /* Note: no need to re-lookup tv, conversion is side effect free */
+ /* Note: no need to re-lookup tv, conversion is side effect free. */
DUK_ASSERT(tv != NULL);
DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv, val); /* side effects */
return val;
}
-DUK_EXTERNAL duk_double_t duk_to_number(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_double_t duk_to_number(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_double_t d;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, index);
+ /* XXX: No need to normalize; the whole operation could be inlined here to
+ * avoid 'tv' re-lookup.
+ */
+ idx = duk_require_normalize_index(thr, idx);
+ tv = DUK_GET_TVAL_POSIDX(thr, idx);
DUK_ASSERT(tv != NULL);
- /* XXX: fastint? */
- d = duk_js_tonumber(thr, tv);
+ d = duk_js_tonumber(thr, tv); /* XXX: fastint coercion? now result will always be a non-fastint */
- /* Note: need to re-lookup because ToNumber() may have side effects */
- tv = duk_require_tval(ctx, index);
+ /* ToNumber() may have side effects so must relookup 'tv'. */
+ tv = DUK_GET_TVAL_POSIDX(thr, idx);
DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */
return d;
}
+DUK_INTERNAL duk_double_t duk_to_number_m1(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_to_number(thr, -1);
+}
+DUK_INTERNAL duk_double_t duk_to_number_m2(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_to_number(thr, -2);
+}
+
+DUK_INTERNAL duk_double_t duk_to_number_tval(duk_hthread *thr, duk_tval *tv) {
+#if defined(DUK_USE_PREFER_SIZE)
+ duk_double_t res;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_push_tval(thr, tv);
+ res = duk_to_number_m1(thr);
+ duk_pop_unsafe(thr);
+ return res;
+#else
+ duk_double_t res;
+ duk_tval *tv_dst;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK__ASSERT_SPACE();
+
+ tv_dst = thr->valstack_top++;
+ DUK_TVAL_SET_TVAL(tv_dst, tv);
+ DUK_TVAL_INCREF(thr, tv_dst); /* decref not necessary */
+ res = duk_to_number_m1(thr); /* invalidates tv_dst */
+
+ tv_dst = --thr->valstack_top;
+ DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_dst));
+ DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv_dst)); /* plain number */
+ DUK_TVAL_SET_UNDEFINED(tv_dst); /* valstack init policy */
+
+ return res;
+#endif
+}
+
/* XXX: combine all the integer conversions: they share everything
* but the helper function for coercion.
*/
typedef duk_double_t (*duk__toint_coercer)(duk_hthread *thr, duk_tval *tv);
-DUK_LOCAL duk_double_t duk__to_int_uint_helper(duk_context *ctx, duk_idx_t index, duk__toint_coercer coerce_func) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL duk_double_t duk__to_int_uint_helper(duk_hthread *thr, duk_idx_t idx, duk__toint_coercer coerce_func) {
duk_tval *tv;
duk_double_t d;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
- tv = duk_require_tval(ctx, index);
+ tv = duk_require_tval(thr, idx);
DUK_ASSERT(tv != NULL);
+
+#if defined(DUK_USE_FASTINT)
+ /* If argument is a fastint, guarantee that it remains one.
+ * There's no downgrade check for other cases.
+ */
+ if (DUK_TVAL_IS_FASTINT(tv)) {
+ /* XXX: Unnecessary conversion back and forth. */
+ return (duk_double_t) DUK_TVAL_GET_FASTINT(tv);
+ }
+#endif
d = coerce_func(thr, tv);
/* XXX: fastint? */
/* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
- tv = duk_require_tval(ctx, index);
+ tv = duk_require_tval(thr, idx);
DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */
return d;
}
-DUK_EXTERNAL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t index) {
- /* Value coercion (in stack): ToInteger(), E5 Section 9.4
- * API return value coercion: custom
+DUK_EXTERNAL duk_int_t duk_to_int(duk_hthread *thr, duk_idx_t idx) {
+ /* Value coercion (in stack): ToInteger(), E5 Section 9.4,
+ * API return value coercion: custom.
*/
- DUK_ASSERT_CTX_VALID(ctx);
- (void) duk__to_int_uint_helper(ctx, index, duk_js_tointeger);
- return (duk_int_t) duk__api_coerce_d2i(ctx, index, 0 /*require*/);
+ DUK_ASSERT_API_ENTRY(thr);
+ (void) duk__to_int_uint_helper(thr, idx, duk_js_tointeger);
+ return (duk_int_t) duk__api_coerce_d2i(thr, idx, 0 /*def_value*/, 0 /*require*/);
}
-DUK_EXTERNAL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t index) {
- /* Value coercion (in stack): ToInteger(), E5 Section 9.4
- * API return value coercion: custom
+DUK_EXTERNAL duk_uint_t duk_to_uint(duk_hthread *thr, duk_idx_t idx) {
+ /* Value coercion (in stack): ToInteger(), E5 Section 9.4,
+ * API return value coercion: custom.
*/
- DUK_ASSERT_CTX_VALID(ctx);
- (void) duk__to_int_uint_helper(ctx, index, duk_js_tointeger);
- return (duk_uint_t) duk__api_coerce_d2ui(ctx, index, 0 /*require*/);
+ DUK_ASSERT_API_ENTRY(thr);
+ (void) duk__to_int_uint_helper(thr, idx, duk_js_tointeger);
+ return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, 0 /*def_value*/, 0 /*require*/);
}
-DUK_EXTERNAL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_int32_t duk_to_int32(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_int32_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, index);
+ tv = duk_require_tval(thr, idx);
DUK_ASSERT(tv != NULL);
ret = duk_js_toint32(thr, tv);
/* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
- tv = duk_require_tval(ctx, index);
- DUK_TVAL_SET_FASTINT_I32_UPDREF(thr, tv, ret); /* side effects */
+ tv = duk_require_tval(thr, idx);
+ DUK_TVAL_SET_I32_UPDREF(thr, tv, ret); /* side effects */
return ret;
}
-DUK_EXTERNAL duk_uint32_t duk_to_uint32(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_uint32_t duk_to_uint32(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_uint32_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, index);
+ tv = duk_require_tval(thr, idx);
DUK_ASSERT(tv != NULL);
ret = duk_js_touint32(thr, tv);
/* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
- tv = duk_require_tval(ctx, index);
- DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv, ret); /* side effects */
+ tv = duk_require_tval(thr, idx);
+ DUK_TVAL_SET_U32_UPDREF(thr, tv, ret); /* side effects */
return ret;
}
-DUK_EXTERNAL duk_uint16_t duk_to_uint16(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_uint16_t duk_to_uint16(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_uint16_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, index);
+ tv = duk_require_tval(thr, idx);
DUK_ASSERT(tv != NULL);
ret = duk_js_touint16(thr, tv);
/* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
- tv = duk_require_tval(ctx, index);
- DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv, ret); /* side effects */
+ tv = duk_require_tval(thr, idx);
+ DUK_TVAL_SET_U32_UPDREF(thr, tv, ret); /* side effects */
return ret;
}
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
/* Special coercion for Uint8ClampedArray. */
-DUK_INTERNAL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t index) {
+DUK_INTERNAL duk_uint8_t duk_to_uint8clamped(duk_hthread *thr, duk_idx_t idx) {
duk_double_t d;
duk_double_t t;
duk_uint8_t ret;
+ DUK_ASSERT_API_ENTRY(thr);
+
/* XXX: Simplify this algorithm, should be possible to come up with
* a shorter and faster algorithm by inspecting IEEE representation
* directly.
*/
- d = duk_to_number(ctx, index);
+ d = duk_to_number(thr, idx);
if (d <= 0.0) {
return 0;
} else if (d >= 255) {
@@ -17064,119 +20073,176 @@ DUK_INTERNAL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t index)
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_EXTERNAL const char *duk_to_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL const char *duk_to_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
+ DUK_ASSERT_API_ENTRY(thr);
- (void) duk_to_string(ctx, index);
- return duk_require_lstring(ctx, index, out_len);
+ (void) duk_to_string(thr, idx);
+ DUK_ASSERT(duk_is_string(thr, idx));
+ return duk_require_lstring(thr, idx, out_len);
}
-DUK_LOCAL duk_ret_t duk__safe_to_string_raw(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_LOCAL duk_ret_t duk__safe_to_string_raw(duk_hthread *thr, void *udata) {
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_UNREF(udata);
- duk_to_string(ctx, -1);
+ duk_to_string(thr, -1);
return 1;
}
-DUK_EXTERNAL const char *duk_safe_to_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL const char *duk_safe_to_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
+ DUK_ASSERT_API_ENTRY(thr);
- index = duk_require_normalize_index(ctx, index);
+ idx = duk_require_normalize_index(thr, idx);
/* We intentionally ignore the duk_safe_call() return value and only
* check the output type. This way we don't also need to check that
* the returned value is indeed a string in the success case.
*/
- duk_dup(ctx, index);
- (void) duk_safe_call(ctx, duk__safe_to_string_raw, 1 /*nargs*/, 1 /*nrets*/);
- if (!duk_is_string(ctx, -1)) {
+ duk_dup(thr, idx);
+ (void) duk_safe_call(thr, duk__safe_to_string_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/);
+ if (!duk_is_string(thr, -1)) {
/* Error: try coercing error to string once. */
- (void) duk_safe_call(ctx, duk__safe_to_string_raw, 1 /*nargs*/, 1 /*nrets*/);
- if (!duk_is_string(ctx, -1)) {
+ (void) duk_safe_call(thr, duk__safe_to_string_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/);
+ if (!duk_is_string(thr, -1)) {
/* Double error */
- duk_pop(ctx);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_UC_ERROR);
+ duk_pop_unsafe(thr);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_UC_ERROR);
} else {
;
}
} else {
+ /* String; may be a symbol, accepted. */
;
}
- DUK_ASSERT(duk_is_string(ctx, -1));
- DUK_ASSERT(duk_get_string(ctx, -1) != NULL);
+ DUK_ASSERT(duk_is_string(thr, -1));
- duk_replace(ctx, index);
- return duk_get_lstring(ctx, index, out_len);
+ duk_replace(thr, idx);
+ DUK_ASSERT(duk_get_string(thr, idx) != NULL);
+ return duk_get_lstring(thr, idx, out_len);
+}
+
+DUK_INTERNAL duk_hstring *duk_to_property_key_hstring(duk_hthread *thr, duk_idx_t idx) {
+ duk_hstring *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_to_primitive(thr, idx, DUK_HINT_STRING); /* needed for e.g. Symbol objects */
+ h = duk_get_hstring(thr, idx);
+ if (h == NULL) {
+ /* The "is string?" check may seem unnecessary, but as things
+ * are duk_to_hstring() invokes ToString() which fails for
+ * symbols. But since symbols are already strings for Duktape
+ * C API, we check for that before doing the coercion.
+ */
+ h = duk_to_hstring(thr, idx);
+ }
+ DUK_ASSERT(h != NULL);
+ return h;
}
#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */
-DUK_INTERNAL duk_hstring *duk_safe_to_hstring(duk_context *ctx, duk_idx_t index) {
- (void) duk_safe_to_string(ctx, index);
- DUK_ASSERT(duk_is_string(ctx, index));
- DUK_ASSERT(duk_get_hstring(ctx, index) != NULL);
- return duk_get_hstring(ctx, index);
+DUK_INTERNAL duk_hstring *duk_safe_to_hstring(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ (void) duk_safe_to_string(thr, idx);
+ DUK_ASSERT(duk_is_string(thr, idx));
+ DUK_ASSERT(duk_get_hstring(thr, idx) != NULL);
+ return duk_known_hstring(thr, idx);
}
#endif
-/* Coerce top into Object.prototype.toString() output. */
-DUK_INTERNAL void duk_to_object_class_string_top(duk_context *ctx) {
- duk_hthread *thr;
- duk_uint_t typemask;
+/* Push Object.prototype.toString() output for 'tv'. */
+DUK_INTERNAL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv) {
+ duk_small_uint_t stridx;
duk_hstring *h_strclass;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
+ DUK_ASSERT_API_ENTRY(thr);
- typemask = duk_get_type_mask(ctx, -1);
- if (typemask & DUK_TYPE_MASK_UNDEFINED) {
- h_strclass = DUK_HTHREAD_STRING_UC_UNDEFINED(thr);
- } else if (typemask & DUK_TYPE_MASK_NULL) {
- h_strclass = DUK_HTHREAD_STRING_UC_NULL(thr);
- } else {
- duk_hobject *h_obj;
-
- duk_to_object(ctx, -1);
- h_obj = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h_obj != NULL);
-
- h_strclass = DUK_HOBJECT_GET_CLASS_STRING(thr->heap, h_obj);
+ switch (DUK_TVAL_GET_TAG(tv)) {
+ case DUK_TAG_UNUSED: /* Treat like 'undefined', shouldn't happen. */
+ case DUK_TAG_UNDEFINED: {
+ stridx = DUK_STRIDX_UC_UNDEFINED;
+ break;
}
+ case DUK_TAG_NULL: {
+ stridx = DUK_STRIDX_UC_NULL;
+ break;
+ }
+ case DUK_TAG_BOOLEAN: {
+ stridx = DUK_STRIDX_UC_BOOLEAN;
+ break;
+ }
+ case DUK_TAG_POINTER: {
+ stridx = DUK_STRIDX_UC_POINTER;
+ break;
+ }
+ case DUK_TAG_LIGHTFUNC: {
+ stridx = DUK_STRIDX_UC_FUNCTION;
+ break;
+ }
+ case DUK_TAG_STRING: {
+ duk_hstring *h;
+ h = DUK_TVAL_GET_STRING(tv);
+ DUK_ASSERT(h != NULL);
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
+ stridx = DUK_STRIDX_UC_SYMBOL;
+ } else {
+ stridx = DUK_STRIDX_UC_STRING;
+ }
+ break;
+ }
+ case DUK_TAG_OBJECT: {
+ duk_hobject *h;
+ duk_small_uint_t classnum;
+
+ h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ classnum = DUK_HOBJECT_GET_CLASS_NUMBER(h);
+ stridx = DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum);
+
+ /* XXX: This is not entirely correct anymore; in ES2015 the
+ * default lookup should use @@toStringTag to come up with
+ * e.g. [object Symbol], [object Uint8Array], etc. See
+ * ES2015 Section 19.1.3.6. The downside of implementing that
+ * directly is that the @@toStringTag lookup may have side
+ * effects, so all call sites must be checked for that.
+ * Some may need a side-effect free lookup, e.g. avoiding
+ * getters which are not typical.
+ */
+ break;
+ }
+ case DUK_TAG_BUFFER: {
+ stridx = DUK_STRIDX_UINT8_ARRAY;
+ break;
+ }
+#if defined(DUK_USE_FASTINT)
+ case DUK_TAG_FASTINT:
+ /* Fall through to generic number case. */
+#endif
+ default: {
+ DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); /* number (maybe fastint) */
+ stridx = DUK_STRIDX_UC_NUMBER;
+ break;
+ }
+ }
+ h_strclass = DUK_HTHREAD_GET_STRING(thr, stridx);
DUK_ASSERT(h_strclass != NULL);
- duk_pop(ctx);
- duk_push_sprintf(ctx, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass));
+ duk_push_sprintf(thr, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass));
}
-#if !defined(DUK_USE_PARANOID_ERRORS)
-DUK_INTERNAL void duk_push_hobject_class_string(duk_context *ctx, duk_hobject *h) {
- duk_hthread *thr;
- duk_hstring *h_strclass;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(h != NULL);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_strclass = DUK_HOBJECT_GET_CLASS_STRING(thr->heap, h);
- DUK_ASSERT(h_strclass != NULL);
- duk_push_sprintf(ctx, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass));
-}
-#endif /* !DUK_USE_PARANOID_ERRORS */
-
/* XXX: other variants like uint, u32 etc */
-DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped) {
duk_tval *tv;
duk_tval tv_tmp;
duk_double_t d, dmin, dmax;
duk_int_t res;
duk_bool_t clamped = 0;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, index);
+ tv = duk_require_tval(thr, idx);
DUK_ASSERT(tv != NULL);
d = duk_js_tointeger(thr, tv); /* E5 Section 9.4, ToInteger() */
@@ -17198,12 +20264,12 @@ DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t index,
/* 'd' and 'res' agree here */
/* Relookup in case duk_js_tointeger() ends up e.g. coercing an object. */
- tv = duk_get_tval(ctx, index);
+ tv = duk_get_tval(thr, idx);
DUK_ASSERT(tv != NULL); /* not popped by side effect */
DUK_TVAL_SET_TVAL(&tv_tmp, tv);
#if defined(DUK_USE_FASTINT)
#if (DUK_INT_MAX <= 0x7fffffffL)
- DUK_TVAL_SET_FASTINT_I32(tv, res);
+ DUK_TVAL_SET_I32(tv, res);
#else
/* Clamping needed if duk_int_t is 64 bits. */
if (res >= DUK_FASTINT_MIN && res <= DUK_FASTINT_MAX) {
@@ -17229,79 +20295,93 @@ DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t index,
return res;
}
-DUK_INTERNAL duk_int_t duk_to_int_clamped(duk_context *ctx, duk_idx_t index, duk_idx_t minval, duk_idx_t maxval) {
+DUK_INTERNAL duk_int_t duk_to_int_clamped(duk_hthread *thr, duk_idx_t idx, duk_idx_t minval, duk_idx_t maxval) {
duk_bool_t dummy;
- return duk_to_int_clamped_raw(ctx, index, minval, maxval, &dummy);
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return duk_to_int_clamped_raw(thr, idx, minval, maxval, &dummy);
}
-DUK_INTERNAL duk_int_t duk_to_int_check_range(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval) {
- return duk_to_int_clamped_raw(ctx, index, minval, maxval, NULL); /* out_clamped==NULL -> RangeError if outside range */
+DUK_INTERNAL duk_int_t duk_to_int_check_range(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_to_int_clamped_raw(thr, idx, minval, maxval, NULL); /* out_clamped==NULL -> RangeError if outside range */
}
-DUK_EXTERNAL const char *duk_to_string(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL const char *duk_to_string(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
+ DUK_ASSERT_API_ENTRY(thr);
- index = duk_require_normalize_index(ctx, index);
-
- tv = duk_require_tval(ctx, index);
+ idx = duk_require_normalize_index(thr, idx);
+ tv = DUK_GET_TVAL_POSIDX(thr, idx);
DUK_ASSERT(tv != NULL);
switch (DUK_TVAL_GET_TAG(tv)) {
case DUK_TAG_UNDEFINED: {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_UNDEFINED);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_LC_UNDEFINED);
break;
}
case DUK_TAG_NULL: {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_NULL);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_LC_NULL);
break;
}
case DUK_TAG_BOOLEAN: {
if (DUK_TVAL_GET_BOOLEAN(tv)) {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_TRUE);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_TRUE);
} else {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_FALSE);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_FALSE);
}
break;
}
case DUK_TAG_STRING: {
- /* nop */
- goto skip_replace;
- }
- case DUK_TAG_OBJECT: {
- duk_to_primitive(ctx, index, DUK_HINT_STRING);
- return duk_to_string(ctx, index); /* Note: recursive call */
- }
- case DUK_TAG_BUFFER: {
- duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
-
- /* Note: this allows creation of internal strings. */
-
+ /* Nop for actual strings, TypeError for Symbols.
+ * Because various internals rely on ToString() coercion of
+ * internal strings, -allow- (NOP) string coercion for hidden
+ * symbols.
+ */
+#if 1
+ duk_hstring *h;
+ h = DUK_TVAL_GET_STRING(tv);
DUK_ASSERT(h != NULL);
- duk_push_lstring(ctx,
- (const char *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h),
- (duk_size_t) DUK_HBUFFER_GET_SIZE(h));
- break;
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
+ DUK_ERROR_TYPE(thr, DUK_STR_CANNOT_STRING_COERCE_SYMBOL);
+ } else {
+ goto skip_replace;
+ }
+#else
+ goto skip_replace;
+#endif
+ }
+ case DUK_TAG_BUFFER: /* Go through Uint8Array.prototype.toString() for coercion. */
+ case DUK_TAG_OBJECT: {
+ /* Plain buffers: go through ArrayBuffer.prototype.toString()
+ * for coercion.
+ *
+ * Symbol objects: duk_to_primitive() results in a plain symbol
+ * value, and duk_to_string() then causes a TypeError.
+ */
+ duk_to_primitive(thr, idx, DUK_HINT_STRING);
+ DUK_ASSERT(!duk_is_buffer(thr, idx)); /* ToPrimitive() must guarantee */
+ DUK_ASSERT(!duk_is_object(thr, idx));
+ return duk_to_string(thr, idx); /* Note: recursive call */
}
case DUK_TAG_POINTER: {
void *ptr = DUK_TVAL_GET_POINTER(tv);
if (ptr != NULL) {
- duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) ptr);
+ duk_push_sprintf(thr, DUK_STR_FMT_PTR, (void *) ptr);
} else {
/* Represent a null pointer as 'null' to be consistent with
* the JX format variant. Native '%p' format for a NULL
* pointer may be e.g. '(nil)'.
*/
- duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_NULL);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_LC_NULL);
}
break;
}
case DUK_TAG_LIGHTFUNC: {
/* Should match Function.prototype.toString() */
- duk_push_lightfunc_tostring(ctx, tv);
+ duk_push_lightfunc_tostring(thr, tv);
break;
}
#if defined(DUK_USE_FASTINT)
@@ -17311,8 +20391,8 @@ DUK_EXTERNAL const char *duk_to_string(duk_context *ctx, duk_idx_t index) {
/* number */
DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- duk_push_tval(ctx, tv);
- duk_numconv_stringify(ctx,
+ duk_push_tval(thr, tv);
+ duk_numconv_stringify(thr,
10 /*radix*/,
0 /*precision:shortest*/,
0 /*force_exponential*/);
@@ -17320,34 +20400,76 @@ DUK_EXTERNAL const char *duk_to_string(duk_context *ctx, duk_idx_t index) {
}
}
- duk_replace(ctx, index);
+ duk_replace(thr, idx);
skip_replace:
- return duk_require_string(ctx, index);
+ DUK_ASSERT(duk_is_string(thr, idx));
+ return duk_require_string(thr, idx);
}
-DUK_INTERNAL duk_hstring *duk_to_hstring(duk_context *ctx, duk_idx_t index) {
+DUK_INTERNAL duk_hstring *duk_to_hstring(duk_hthread *thr, duk_idx_t idx) {
duk_hstring *ret;
- DUK_ASSERT_CTX_VALID(ctx);
- duk_to_string(ctx, index);
- ret = duk_get_hstring(ctx, index);
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_to_string(thr, idx);
+ ret = duk_get_hstring(thr, idx);
DUK_ASSERT(ret != NULL);
return ret;
}
-DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_uint_t mode) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_hstring *duk_to_hstring_m1(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_to_hstring(thr, -1);
+}
+
+DUK_INTERNAL duk_hstring *duk_to_hstring_acceptsymbol(duk_hthread *thr, duk_idx_t idx) {
+ duk_hstring *ret;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ ret = duk_get_hstring(thr, idx);
+ if (DUK_UNLIKELY(ret && DUK_HSTRING_HAS_SYMBOL(ret))) {
+ return ret;
+ }
+ return duk_to_hstring(thr, idx);
+}
+
+/* Convert a plain buffer or any buffer object into a string, using the buffer
+ * bytes 1:1 in the internal string representation. For views the active byte
+ * slice (not element slice interpreted as an initializer) is used. This is
+ * necessary in Duktape 2.x because ToString(plainBuffer) no longer creates a
+ * string with the same bytes as in the buffer but rather (usually)
+ * '[object ArrayBuffer]'.
+ */
+DUK_EXTERNAL const char *duk_buffer_to_string(duk_hthread *thr, duk_idx_t idx) {
+ void *ptr_src;
+ duk_size_t len;
+ const char *res;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ idx = duk_require_normalize_index(thr, idx);
+
+ ptr_src = duk_require_buffer_data(thr, idx, &len);
+ DUK_ASSERT(ptr_src != NULL || len == 0);
+
+ res = duk_push_lstring(thr, (const char *) ptr_src, len);
+ duk_replace(thr, idx);
+ return res;
+}
+
+DUK_EXTERNAL void *duk_to_buffer_raw(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, duk_uint_t mode) {
duk_hbuffer *h_buf;
const duk_uint8_t *src_data;
duk_size_t src_size;
duk_uint8_t *dst_data;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
+ DUK_ASSERT_API_ENTRY(thr);
- index = duk_require_normalize_index(ctx, index);
+ idx = duk_require_normalize_index(thr, idx);
- h_buf = duk_get_hbuffer(ctx, index);
+ h_buf = duk_get_hbuffer(thr, idx);
if (h_buf != NULL) {
/* Buffer is kept as is, with the fixed/dynamic nature of the
* buffer only changed if requested. An external buffer
@@ -17373,13 +20495,13 @@ DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size
} else {
/* Non-buffer value is first ToString() coerced, then converted
* to a buffer (fixed buffer is used unless a dynamic buffer is
- * explicitly requested).
+ * explicitly requested). Symbols are rejected with a TypeError.
+ * XXX: C API could maybe allow symbol-to-buffer coercion?
*/
-
- src_data = (const duk_uint8_t *) duk_to_lstring(ctx, index, &src_size);
+ src_data = (const duk_uint8_t *) duk_to_lstring(thr, idx, &src_size);
}
- dst_data = (duk_uint8_t *) duk_push_buffer(ctx, src_size, (mode == DUK_BUF_MODE_DYNAMIC) /*dynamic*/);
+ dst_data = (duk_uint8_t *) duk_push_buffer(thr, src_size, (mode == DUK_BUF_MODE_DYNAMIC) /*dynamic*/);
if (DUK_LIKELY(src_size > 0)) {
/* When src_size == 0, src_data may be NULL (if source
* buffer is dynamic), and dst_data may be NULL (if
@@ -17388,7 +20510,7 @@ DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size
*/
DUK_MEMCPY((void *) dst_data, (const void *) src_data, (size_t) src_size);
}
- duk_replace(ctx, index);
+ duk_replace(thr, idx);
skip_copy:
if (out_size) {
@@ -17397,15 +20519,14 @@ DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size
return dst_data;
}
-DUK_EXTERNAL void *duk_to_pointer(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL void *duk_to_pointer(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
void *res;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- index = duk_require_normalize_index(ctx, index);
-
- tv = duk_require_tval(ctx, index);
+ idx = duk_require_normalize_index(thr, idx);
+ tv = DUK_GET_TVAL_POSIDX(thr, idx);
DUK_ASSERT(tv != NULL);
switch (DUK_TVAL_GET_TAG(tv)) {
@@ -17443,25 +20564,64 @@ DUK_EXTERNAL void *duk_to_pointer(duk_context *ctx, duk_idx_t index) {
break;
}
- duk_push_pointer(ctx, res);
- duk_replace(ctx, index);
+ duk_push_pointer(thr, res);
+ duk_replace(thr, idx);
return res;
}
-DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL void duk__push_func_from_lightfunc(duk_hthread *thr, duk_c_function func, duk_small_uint_t lf_flags) {
+ duk_idx_t nargs;
+ duk_uint_t flags = 0; /* shared flags for a subset of types */
+ duk_small_uint_t lf_len;
+ duk_hnatfunc *nf;
+
+ nargs = (duk_idx_t) DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
+ if (nargs == DUK_LFUNC_NARGS_VARARGS) {
+ nargs = (duk_idx_t) DUK_VARARGS;
+ }
+
+ flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_CONSTRUCTABLE |
+ DUK_HOBJECT_FLAG_CALLABLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_FLAG_NATFUNC |
+ DUK_HOBJECT_FLAG_NEWENV |
+ DUK_HOBJECT_FLAG_STRICT |
+ DUK_HOBJECT_FLAG_NOTAIL |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
+ (void) duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE);
+
+ lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
+ if ((duk_idx_t) lf_len != nargs) {
+ /* Explicit length is only needed if it differs from 'nargs'. */
+ duk_push_int(thr, (duk_int_t) lf_len);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
+ }
+
+#if defined(DUK_USE_FUNC_NAME_PROPERTY)
+ duk_push_lightfunc_name_raw(thr, func, lf_flags);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
+#endif
+
+ nf = duk_known_hnatfunc(thr, -1);
+ nf->magic = (duk_int16_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
+}
+
+DUK_EXTERNAL void duk_to_object(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_uint_t flags = 0; /* shared flags for a subset of types */
duk_small_int_t proto = 0;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- index = duk_require_normalize_index(ctx, index);
-
- tv = duk_require_tval(ctx, index);
+ idx = duk_require_normalize_index(thr, idx);
+ tv = DUK_GET_TVAL_POSIDX(thr, idx);
DUK_ASSERT(tv != NULL);
switch (DUK_TVAL_GET_TAG(tv)) {
+#if !defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+ case DUK_TAG_BUFFER: /* With no bufferobject support, don't object coerce. */
+#endif
case DUK_TAG_UNDEFINED:
case DUK_TAG_NULL: {
DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE);
@@ -17469,54 +20629,53 @@ DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) {
}
case DUK_TAG_BOOLEAN: {
flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BOOLEAN);
proto = DUK_BIDX_BOOLEAN_PROTOTYPE;
goto create_object;
}
case DUK_TAG_STRING: {
- flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING);
- proto = DUK_BIDX_STRING_PROTOTYPE;
+ duk_hstring *h;
+ h = DUK_TVAL_GET_STRING(tv);
+ DUK_ASSERT(h != NULL);
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
+ flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_SYMBOL);
+ proto = DUK_BIDX_SYMBOL_PROTOTYPE;
+ } else {
+ flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING);
+ proto = DUK_BIDX_STRING_PROTOTYPE;
+ }
goto create_object;
}
case DUK_TAG_OBJECT: {
/* nop */
break;
}
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
case DUK_TAG_BUFFER: {
- /* A plain buffer coerces to a Duktape.Buffer because it's the
- * object counterpart of the plain buffer value. But it might
- * still make more sense to produce an ArrayBuffer here?
+ /* A plain buffer object coerces to a full ArrayBuffer which
+ * is not fully transparent behavior (ToObject() should be a
+ * nop for an object). This behavior matches lightfuncs which
+ * also coerce to an equivalent Function object. There are
+ * also downsides to defining ToObject(plainBuffer) as a no-op;
+ * for example duk_to_hobject() could result in a NULL pointer.
*/
+ duk_hbuffer *h_buf;
- duk_hbufferobject *h_bufobj;
- duk_hbuffer *h_val;
-
- h_val = DUK_TVAL_GET_BUFFER(tv);
- DUK_ASSERT(h_val != NULL);
-
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER),
- DUK_BIDX_BUFFER_PROTOTYPE);
- DUK_ASSERT(h_bufobj != NULL);
- DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE((duk_hobject *) h_bufobj));
- DUK_ASSERT(DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_bufobj));
-
- h_bufobj->buf = h_val;
- DUK_HBUFFER_INCREF(thr, h_val);
- DUK_ASSERT(h_bufobj->offset == 0);
- h_bufobj->length = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_val);
- DUK_ASSERT(h_bufobj->shift == 0);
- DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8);
-
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+ h_buf = DUK_TVAL_GET_BUFFER(tv);
+ DUK_ASSERT(h_buf != NULL);
+ duk_hbufobj_push_uint8array_from_plain(thr, h_buf);
goto replace_value;
}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
case DUK_TAG_POINTER: {
flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER);
proto = DUK_BIDX_POINTER_PROTOTYPE;
goto create_object;
@@ -17524,50 +20683,18 @@ DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) {
case DUK_TAG_LIGHTFUNC: {
/* Lightfunc coerces to a Function instance with concrete
* properties. Since 'length' is virtual for Duktape/C
- * functions, don't need to define that.
+ * functions, don't need to define that. The result is made
+ * extensible to mimic what happens to strings in object
+ * coercion:
*
- * The result is made extensible to mimic what happens to
- * strings:
* > Object.isExtensible(Object('foo'))
* true
*/
duk_small_uint_t lf_flags;
- duk_idx_t nargs;
- duk_small_uint_t lf_len;
duk_c_function func;
- duk_hnativefunction *nf;
DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
-
- nargs = (duk_idx_t) DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
- if (nargs == DUK_LFUNC_NARGS_VARARGS) {
- nargs = (duk_idx_t) DUK_VARARGS;
- }
- flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_CONSTRUCTABLE |
- DUK_HOBJECT_FLAG_NATIVEFUNCTION |
- DUK_HOBJECT_FLAG_NEWENV |
- DUK_HOBJECT_FLAG_STRICT |
- DUK_HOBJECT_FLAG_NOTAIL |
- /* DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC: omitted here intentionally */
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
- (void) duk__push_c_function_raw(ctx, func, nargs, flags);
-
- lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
- if ((duk_idx_t) lf_len != nargs) {
- /* Explicit length is only needed if it differs from 'nargs'. */
- duk_push_int(ctx, (duk_int_t) lf_len);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
- }
- duk_push_lightfunc_name(ctx, tv);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
-
- nf = duk_get_hnativefunction(ctx, -1);
- DUK_ASSERT(nf != NULL);
- nf->magic = (duk_int16_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
-
- /* Enable DUKFUNC exotic behavior once properties are set up. */
- DUK_HOBJECT_SET_EXOTIC_DUKFUNC((duk_hobject *) nf);
+ duk__push_func_from_lightfunc(thr, func, lf_flags);
goto replace_value;
}
#if defined(DUK_USE_FASTINT)
@@ -17577,15 +20704,17 @@ DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) {
DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_NUMBER);
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_NUMBER);
proto = DUK_BIDX_NUMBER_PROTOTYPE;
goto create_object;
}
}
+ DUK_ASSERT(duk_is_object(thr, idx));
return;
create_object:
- (void) duk_push_object_helper(ctx, flags, proto);
+ (void) duk_push_object_helper(thr, flags, proto);
/* Note: Boolean prototype's internal value property is not writable,
* but duk_xdef_prop_stridx() disregards the write protection. Boolean
@@ -17594,49 +20723,55 @@ DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) {
* String and buffer special behaviors are already enabled which is not
* ideal, but a write to the internal value is not affected by them.
*/
- duk_dup(ctx, index);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
+ duk_dup(thr, idx);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
replace_value:
- duk_replace(ctx, index);
+ duk_replace(thr, idx);
+ DUK_ASSERT(duk_is_object(thr, idx));
+}
+
+DUK_INTERNAL duk_hobject *duk_to_hobject(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *ret;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_to_object(thr, idx);
+ ret = duk_known_hobject(thr, idx);
+ return ret;
}
/*
* Type checking
*/
-DUK_LOCAL duk_bool_t duk__tag_check(duk_context *ctx, duk_idx_t index, duk_small_uint_t tag) {
+DUK_LOCAL duk_bool_t duk__tag_check(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t tag) {
duk_tval *tv;
- tv = duk_get_tval(ctx, index);
- if (!tv) {
- return 0;
- }
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
return (DUK_TVAL_GET_TAG(tv) == tag);
}
-DUK_LOCAL duk_bool_t duk__obj_flag_any_default_false(duk_context *ctx, duk_idx_t index, duk_uint_t flag_mask) {
+DUK_LOCAL duk_bool_t duk__obj_flag_any_default_false(duk_hthread *thr, duk_idx_t idx, duk_uint_t flag_mask) {
duk_hobject *obj;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_get_hobject(ctx, index);
+ obj = duk_get_hobject(thr, idx);
if (obj) {
return (DUK_HEAPHDR_CHECK_FLAG_BITS((duk_heaphdr *) obj, flag_mask) ? 1 : 0);
}
return 0;
}
-DUK_EXTERNAL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
+DUK_INTERNAL duk_int_t duk_get_type_tval(duk_tval *tv) {
+ DUK_ASSERT(tv != NULL);
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (!tv) {
- return DUK_TYPE_NONE;
- }
+#if defined(DUK_USE_PACKED_TVAL)
switch (DUK_TVAL_GET_TAG(tv)) {
+ case DUK_TAG_UNUSED:
+ return DUK_TYPE_NONE;
case DUK_TAG_UNDEFINED:
return DUK_TYPE_UNDEFINED;
case DUK_TAG_NULL:
@@ -17662,11 +20797,26 @@ DUK_EXTERNAL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t index) {
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
return DUK_TYPE_NUMBER;
}
- DUK_UNREACHABLE();
+#else /* DUK_USE_PACKED_TVAL */
+ DUK_ASSERT(DUK_TVAL_IS_VALID_TAG(tv));
+ DUK_ASSERT(sizeof(duk__type_from_tag) / sizeof(duk_uint_t) == DUK_TAG_MAX - DUK_TAG_MIN + 1);
+ return (duk_int_t) duk__type_from_tag[DUK_TVAL_GET_TAG(tv) - DUK_TAG_MIN];
+#endif /* DUK_USE_PACKED_TVAL */
+}
+
+DUK_EXTERNAL duk_int_t duk_get_type(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+
+ return duk_get_type_tval(tv);
}
#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS)
-DUK_LOCAL const char *duk__type_names[] = {
+DUK_LOCAL const char * const duk__type_names[] = {
"none",
"undefined",
"null",
@@ -17679,33 +20829,58 @@ DUK_LOCAL const char *duk__type_names[] = {
"lightfunc"
};
-DUK_INTERNAL const char *duk_get_type_name(duk_context *ctx, duk_idx_t index) {
+DUK_INTERNAL const char *duk_get_type_name(duk_hthread *thr, duk_idx_t idx) {
duk_int_t type_tag;
- type_tag = duk_get_type(ctx, index);
+ DUK_ASSERT_API_ENTRY(thr);
+
+ type_tag = duk_get_type(thr, idx);
DUK_ASSERT(type_tag >= DUK_TYPE_MIN && type_tag <= DUK_TYPE_MAX);
DUK_ASSERT(DUK_TYPE_MIN == 0 && sizeof(duk__type_names) / sizeof(const char *) == DUK_TYPE_MAX + 1);
return duk__type_names[type_tag];
}
-#endif
+#endif /* DUK_USE_VERBOSE_ERRORS && DUK_USE_PARANOID_ERRORS */
-DUK_EXTERNAL duk_bool_t duk_check_type(duk_context *ctx, duk_idx_t index, duk_int_t type) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_INTERNAL duk_small_uint_t duk_get_class_number(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+ duk_hobject *obj;
- return (duk_get_type(ctx, index) == type) ? 1 : 0;
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+
+ switch (DUK_TVAL_GET_TAG(tv)) {
+ case DUK_TAG_OBJECT:
+ obj = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(obj != NULL);
+ return DUK_HOBJECT_GET_CLASS_NUMBER(obj);
+ case DUK_TAG_BUFFER:
+ /* Buffers behave like Uint8Array objects. */
+ return DUK_HOBJECT_CLASS_UINT8ARRAY;
+ case DUK_TAG_LIGHTFUNC:
+ /* Lightfuncs behave like Function objects. */
+ return DUK_HOBJECT_CLASS_FUNCTION;
+ default:
+ /* Primitive or UNUSED, no class number. */
+ return DUK_HOBJECT_CLASS_NONE;
+ }
}
-DUK_EXTERNAL duk_uint_t duk_get_type_mask(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
+DUK_EXTERNAL duk_bool_t duk_check_type(duk_hthread *thr, duk_idx_t idx, duk_int_t type) {
+ DUK_ASSERT_API_ENTRY(thr);
- DUK_ASSERT_CTX_VALID(ctx);
+ return (duk_get_type(thr, idx) == type) ? 1 : 0;
+}
- tv = duk_get_tval(ctx, index);
- if (!tv) {
- return DUK_TYPE_MASK_NONE;
- }
+DUK_INTERNAL duk_uint_t duk_get_type_mask_tval(duk_tval *tv) {
+ DUK_ASSERT(tv != NULL);
+
+#if defined(DUK_USE_PACKED_TVAL)
switch (DUK_TVAL_GET_TAG(tv)) {
+ case DUK_TAG_UNUSED:
+ return DUK_TYPE_MASK_NONE;
case DUK_TAG_UNDEFINED:
return DUK_TYPE_MASK_UNDEFINED;
case DUK_TAG_NULL:
@@ -17731,15 +20906,28 @@ DUK_EXTERNAL duk_uint_t duk_get_type_mask(duk_context *ctx, duk_idx_t index) {
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
return DUK_TYPE_MASK_NUMBER;
}
- DUK_UNREACHABLE();
+#else /* DUK_USE_PACKED_TVAL */
+ DUK_ASSERT(DUK_TVAL_IS_VALID_TAG(tv));
+ DUK_ASSERT(sizeof(duk__type_mask_from_tag) / sizeof(duk_uint_t) == DUK_TAG_MAX - DUK_TAG_MIN + 1);
+ return duk__type_mask_from_tag[DUK_TVAL_GET_TAG(tv) - DUK_TAG_MIN];
+#endif /* DUK_USE_PACKED_TVAL */
}
-DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_context *ctx, duk_idx_t index, duk_uint_t mask) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_uint_t duk_get_type_mask(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- if (duk_get_type_mask(ctx, index) & mask) {
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+
+ return duk_get_type_mask_tval(tv);
+}
+
+DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t mask) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (DUK_LIKELY((duk_get_type_mask(thr, idx) & mask) != 0U)) {
return 1;
}
if (mask & DUK_TYPE_MASK_THROW) {
@@ -17749,55 +20937,39 @@ DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_context *ctx, duk_idx_t index, d
return 0;
}
-DUK_EXTERNAL duk_bool_t duk_is_undefined(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_UNDEFINED);
+DUK_EXTERNAL duk_bool_t duk_is_undefined(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_UNDEFINED);
}
-DUK_EXTERNAL duk_bool_t duk_is_null(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_NULL);
+DUK_EXTERNAL duk_bool_t duk_is_null(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_NULL);
}
-DUK_EXTERNAL duk_bool_t duk_is_null_or_undefined(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
- duk_small_uint_t tag;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (!tv) {
- return 0;
- }
- tag = DUK_TVAL_GET_TAG(tv);
- return (tag == DUK_TAG_UNDEFINED) || (tag == DUK_TAG_NULL);
+DUK_EXTERNAL duk_bool_t duk_is_boolean(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_BOOLEAN);
}
-DUK_EXTERNAL duk_bool_t duk_is_boolean(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_BOOLEAN);
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_number(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL duk_bool_t duk_is_number(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/*
* Number is special because it doesn't have a specific
* tag in the 8-byte representation.
*/
- /* XXX: shorter version for 12-byte representation? */
+ /* XXX: shorter version for unpacked representation? */
- tv = duk_get_tval(ctx, index);
- if (!tv) {
- return 0;
- }
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
return DUK_TVAL_IS_NUMBER(tv);
}
-DUK_EXTERNAL duk_bool_t duk_is_nan(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL duk_bool_t duk_is_nan(duk_hthread *thr, duk_idx_t idx) {
/* XXX: This will now return false for non-numbers, even though they would
* coerce to NaN (as a general rule). In particular, duk_get_number()
* returns a NaN for non-numbers, so should this function also return
@@ -17806,132 +20978,196 @@ DUK_EXTERNAL duk_bool_t duk_is_nan(duk_context *ctx, duk_idx_t index) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (!tv || !DUK_TVAL_IS_NUMBER(tv)) {
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+
+ /* XXX: for packed duk_tval an explicit "is number" check is unnecessary */
+ if (!DUK_TVAL_IS_NUMBER(tv)) {
return 0;
}
- return DUK_ISNAN(DUK_TVAL_GET_NUMBER(tv));
+ return (duk_bool_t) DUK_ISNAN(DUK_TVAL_GET_NUMBER(tv));
}
-DUK_EXTERNAL duk_bool_t duk_is_string(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_STRING);
+DUK_EXTERNAL duk_bool_t duk_is_string(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_STRING);
}
-DUK_EXTERNAL duk_bool_t duk_is_object(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_OBJECT);
+DUK_INTERNAL duk_bool_t duk_is_string_notsymbol(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_get_hstring_notsymbol(thr, idx) != NULL;
}
-DUK_EXTERNAL duk_bool_t duk_is_buffer(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_BUFFER);
+DUK_EXTERNAL duk_bool_t duk_is_object(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_OBJECT);
+}
+
+DUK_EXTERNAL duk_bool_t duk_is_buffer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_BUFFER);
}
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, idx);
- if (tv == NULL) {
- return 0;
- }
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_BUFFER(tv)) {
return 1;
} else if (DUK_TVAL_IS_OBJECT(tv)) {
duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
- if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
+ if (DUK_HOBJECT_IS_BUFOBJ(h)) {
return 1;
}
}
return 0;
}
#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- return duk_is_buffer(ctx, idx);
+ return duk_is_buffer(thr, idx);
}
+
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_EXTERNAL duk_bool_t duk_is_pointer(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_POINTER);
+DUK_EXTERNAL duk_bool_t duk_is_pointer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_POINTER);
}
-DUK_EXTERNAL duk_bool_t duk_is_lightfunc(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_LIGHTFUNC);
+DUK_EXTERNAL duk_bool_t duk_is_lightfunc(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_LIGHTFUNC);
}
-DUK_EXTERNAL duk_bool_t duk_is_array(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL duk_bool_t duk_is_symbol(duk_hthread *thr, duk_idx_t idx) {
+ duk_hstring *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ h = duk_get_hstring(thr, idx);
+ /* Use DUK_LIKELY() here because caller may be more likely to type
+ * check an expected symbol than not.
+ */
+ if (DUK_LIKELY(h != NULL && DUK_HSTRING_HAS_SYMBOL(h))) {
+ return 1;
+ }
+ return 0;
+}
+
+DUK_EXTERNAL duk_bool_t duk_is_array(duk_hthread *thr, duk_idx_t idx) {
duk_hobject *obj;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_get_hobject(ctx, index);
+ obj = duk_get_hobject(thr, idx);
if (obj) {
return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_ARRAY ? 1 : 0);
}
return 0;
}
-DUK_EXTERNAL duk_bool_t duk_is_function(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL duk_bool_t duk_is_function(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_LIGHTFUNC(tv)) {
+ tv = duk_get_tval_or_unused(thr, idx);
+ if (DUK_TVAL_IS_OBJECT(tv)) {
+ duk_hobject *h;
+ h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ return DUK_HOBJECT_HAS_CALLABLE(h) ? 1 : 0;
+ }
+ if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
return 1;
}
- return duk__obj_flag_any_default_false(ctx,
- index,
- DUK_HOBJECT_FLAG_COMPILEDFUNCTION |
- DUK_HOBJECT_FLAG_NATIVEFUNCTION |
- DUK_HOBJECT_FLAG_BOUND);
+ return 0;
}
-DUK_EXTERNAL duk_bool_t duk_is_c_function(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__obj_flag_any_default_false(ctx,
- index,
- DUK_HOBJECT_FLAG_NATIVEFUNCTION);
+DUK_INTERNAL duk_bool_t duk_is_callable_tval(duk_hthread *thr, duk_tval *tv) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ DUK_UNREF(thr);
+
+ if (DUK_TVAL_IS_OBJECT(tv)) {
+ duk_hobject *h;
+ h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ return DUK_HOBJECT_HAS_CALLABLE(h) ? 1 : 0;
+ }
+ if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
+ return 1;
+ }
+ return 0;
}
-DUK_EXTERNAL duk_bool_t duk_is_ecmascript_function(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__obj_flag_any_default_false(ctx,
- index,
- DUK_HOBJECT_FLAG_COMPILEDFUNCTION);
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_bound_function(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__obj_flag_any_default_false(ctx,
- index,
- DUK_HOBJECT_FLAG_BOUND);
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__obj_flag_any_default_false(ctx,
- index,
- DUK_HOBJECT_FLAG_THREAD);
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL duk_bool_t duk_is_constructable(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_BUFFER(tv)) {
+ tv = duk_get_tval_or_unused(thr, idx);
+ if (DUK_TVAL_IS_OBJECT(tv)) {
+ duk_hobject *h;
+ h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ return DUK_HOBJECT_HAS_CONSTRUCTABLE(h) ? 1 : 0;
+ }
+ if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
+ return 1;
+ }
+ return 0;
+}
+
+DUK_EXTERNAL duk_bool_t duk_is_c_function(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__obj_flag_any_default_false(thr,
+ idx,
+ DUK_HOBJECT_FLAG_NATFUNC);
+}
+
+DUK_EXTERNAL duk_bool_t duk_is_ecmascript_function(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__obj_flag_any_default_false(thr,
+ idx,
+ DUK_HOBJECT_FLAG_COMPFUNC);
+}
+
+DUK_EXTERNAL duk_bool_t duk_is_bound_function(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__obj_flag_any_default_false(thr,
+ idx,
+ DUK_HOBJECT_FLAG_BOUNDFUNC);
+}
+
+DUK_EXTERNAL duk_bool_t duk_is_thread(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *obj;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ obj = duk_get_hobject(thr, idx);
+ if (obj) {
+ return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_THREAD ? 1 : 0);
+ }
+ return 0;
+}
+
+DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_TVAL_IS_BUFFER(tv)) {
duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
DUK_ASSERT(h != NULL);
return (DUK_HBUFFER_HAS_DYNAMIC(h) ? 0 : 1);
@@ -17939,13 +21175,14 @@ DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t index) {
return 0;
}
-DUK_EXTERNAL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL duk_bool_t duk_is_dynamic_buffer(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_BUFFER(tv)) {
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_TVAL_IS_BUFFER(tv)) {
duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
DUK_ASSERT(h != NULL);
return (DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0);
@@ -17953,13 +21190,14 @@ DUK_EXTERNAL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t index)
return 0;
}
-DUK_EXTERNAL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t index) {
+DUK_EXTERNAL duk_bool_t duk_is_external_buffer(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_BUFFER(tv)) {
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_TVAL_IS_BUFFER(tv)) {
duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
DUK_ASSERT(h != NULL);
return (DUK_HBUFFER_HAS_DYNAMIC(h) && DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0);
@@ -17967,20 +21205,22 @@ DUK_EXTERNAL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t index
return 0;
}
-DUK_EXTERNAL duk_errcode_t duk_get_error_code(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_errcode_t duk_get_error_code(duk_hthread *thr, duk_idx_t idx) {
duk_hobject *h;
duk_uint_t sanity;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- h = duk_get_hobject(ctx, index);
+ h = duk_get_hobject(thr, idx);
sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
do {
if (!h) {
return DUK_ERR_NONE;
}
+
+ /* XXX: something more convenient? */
+
if (h == thr->builtins[DUK_BIDX_EVAL_ERROR_PROTOTYPE]) {
return DUK_ERR_EVAL_ERROR;
}
@@ -18013,24 +21253,21 @@ DUK_EXTERNAL duk_errcode_t duk_get_error_code(duk_context *ctx, duk_idx_t index)
* Pushers
*/
-DUK_INTERNAL void duk_push_tval(duk_context *ctx, duk_tval *tv) {
- duk_hthread *thr;
+DUK_INTERNAL void duk_push_tval(duk_hthread *thr, duk_tval *tv) {
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(tv != NULL);
- thr = (duk_hthread *) ctx;
+
DUK__CHECK_SPACE();
tv_slot = thr->valstack_top++;
DUK_TVAL_SET_TVAL(tv_slot, tv);
DUK_TVAL_INCREF(thr, tv); /* no side effects */
}
-DUK_EXTERNAL void duk_push_undefined(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_undefined(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
DUK__CHECK_SPACE();
/* Because value stack init policy is 'undefined above top',
@@ -18040,60 +21277,50 @@ DUK_EXTERNAL void duk_push_undefined(duk_context *ctx) {
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1));
}
-DUK_EXTERNAL void duk_push_null(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_null(duk_hthread *thr) {
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
tv_slot = thr->valstack_top++;
DUK_TVAL_SET_NULL(tv_slot);
}
-DUK_EXTERNAL void duk_push_boolean(duk_context *ctx, duk_bool_t val) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_boolean(duk_hthread *thr, duk_bool_t val) {
duk_tval *tv_slot;
duk_small_int_t b;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
b = (val ? 1 : 0); /* ensure value is 1 or 0 (not other non-zero) */
tv_slot = thr->valstack_top++;
DUK_TVAL_SET_BOOLEAN(tv_slot, b);
}
-DUK_EXTERNAL void duk_push_true(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_true(duk_hthread *thr) {
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
tv_slot = thr->valstack_top++;
DUK_TVAL_SET_BOOLEAN_TRUE(tv_slot);
}
-DUK_EXTERNAL void duk_push_false(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_false(duk_hthread *thr) {
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
tv_slot = thr->valstack_top++;
DUK_TVAL_SET_BOOLEAN_FALSE(tv_slot);
}
/* normalize NaN which may not match our canonical internal NaN */
-DUK_EXTERNAL void duk_push_number(duk_context *ctx, duk_double_t val) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_number(duk_hthread *thr, duk_double_t val) {
duk_tval *tv_slot;
duk_double_union du;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
du.d = val;
DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
@@ -18101,17 +21328,15 @@ DUK_EXTERNAL void duk_push_number(duk_context *ctx, duk_double_t val) {
DUK_TVAL_SET_NUMBER(tv_slot, du.d);
}
-DUK_EXTERNAL void duk_push_int(duk_context *ctx, duk_int_t val) {
+DUK_EXTERNAL void duk_push_int(duk_hthread *thr, duk_int_t val) {
#if defined(DUK_USE_FASTINT)
- duk_hthread *thr;
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
tv_slot = thr->valstack_top++;
#if DUK_INT_MAX <= 0x7fffffffL
- DUK_TVAL_SET_FASTINT_I32(tv_slot, (duk_int32_t) val);
+ DUK_TVAL_SET_I32(tv_slot, (duk_int32_t) val);
#else
if (val >= DUK_FASTINT_MIN && val <= DUK_FASTINT_MAX) {
DUK_TVAL_SET_FASTINT(tv_slot, (duk_int64_t) val);
@@ -18121,12 +21346,10 @@ DUK_EXTERNAL void duk_push_int(duk_context *ctx, duk_int_t val) {
}
#endif
#else /* DUK_USE_FASTINT */
- duk_hthread *thr;
duk_tval *tv_slot;
duk_double_t d;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
d = (duk_double_t) val;
tv_slot = thr->valstack_top++;
@@ -18134,17 +21357,15 @@ DUK_EXTERNAL void duk_push_int(duk_context *ctx, duk_int_t val) {
#endif /* DUK_USE_FASTINT */
}
-DUK_EXTERNAL void duk_push_uint(duk_context *ctx, duk_uint_t val) {
+DUK_EXTERNAL void duk_push_uint(duk_hthread *thr, duk_uint_t val) {
#if defined(DUK_USE_FASTINT)
- duk_hthread *thr;
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
tv_slot = thr->valstack_top++;
#if DUK_UINT_MAX <= 0xffffffffUL
- DUK_TVAL_SET_FASTINT_U32(tv_slot, (duk_uint32_t) val);
+ DUK_TVAL_SET_U32(tv_slot, (duk_uint32_t) val);
#else
if (val <= DUK_FASTINT_MAX) { /* val is unsigned so >= 0 */
/* XXX: take advantage of val being unsigned, no need to mask */
@@ -18155,12 +21376,10 @@ DUK_EXTERNAL void duk_push_uint(duk_context *ctx, duk_uint_t val) {
}
#endif
#else /* DUK_USE_FASTINT */
- duk_hthread *thr;
duk_tval *tv_slot;
duk_double_t d;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
d = (duk_double_t) val;
tv_slot = thr->valstack_top++;
@@ -18168,13 +21387,11 @@ DUK_EXTERNAL void duk_push_uint(duk_context *ctx, duk_uint_t val) {
#endif /* DUK_USE_FASTINT */
}
-DUK_EXTERNAL void duk_push_nan(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_nan(duk_hthread *thr) {
duk_tval *tv_slot;
duk_double_union du;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
DUK_DBLUNION_SET_NAN(&du);
DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
@@ -18182,17 +21399,14 @@ DUK_EXTERNAL void duk_push_nan(duk_context *ctx) {
DUK_TVAL_SET_NUMBER(tv_slot, du.d);
}
-DUK_EXTERNAL const char *duk_push_lstring(duk_context *ctx, const char *str, duk_size_t len) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL const char *duk_push_lstring(duk_hthread *thr, const char *str, duk_size_t len) {
duk_hstring *h;
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* check stack before interning (avoid hanging temp) */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
+ DUK__CHECK_SPACE();
/* NULL with zero length represents an empty string; NULL with higher
* length is also now trated like an empty string although it is
@@ -18204,11 +21418,11 @@ DUK_EXTERNAL const char *duk_push_lstring(duk_context *ctx, const char *str, duk
}
/* Check for maximum string length */
- if (len > DUK_HSTRING_MAX_BYTELEN) {
+ if (DUK_UNLIKELY(len > DUK_HSTRING_MAX_BYTELEN)) {
DUK_ERROR_RANGE(thr, DUK_STR_STRING_TOO_LONG);
}
- h = duk_heap_string_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len);
+ h = duk_heap_strtable_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len);
DUK_ASSERT(h != NULL);
tv_slot = thr->valstack_top++;
@@ -18218,112 +21432,47 @@ DUK_EXTERNAL const char *duk_push_lstring(duk_context *ctx, const char *str, duk
return (const char *) DUK_HSTRING_GET_DATA(h);
}
-DUK_EXTERNAL const char *duk_push_string(duk_context *ctx, const char *str) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL const char *duk_push_string(duk_hthread *thr, const char *str) {
+ DUK_ASSERT_API_ENTRY(thr);
if (str) {
- return duk_push_lstring(ctx, str, DUK_STRLEN(str));
+ return duk_push_lstring(thr, str, DUK_STRLEN(str));
} else {
- duk_push_null(ctx);
+ duk_push_null(thr);
return NULL;
}
}
-#ifdef DUK_USE_FILE_IO
-/* This is a bit clunky because it is ANSI C portable. Should perhaps
- * relocate to another file because this is potentially platform
- * dependent.
- */
-DUK_EXTERNAL const char *duk_push_string_file_raw(duk_context *ctx, const char *path, duk_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_file *f = NULL;
- char *buf;
- long sz; /* ANSI C typing */
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- if (!path) {
- goto fail;
- }
- f = DUK_FOPEN(path, "rb");
- if (!f) {
- goto fail;
- }
- if (DUK_FSEEK(f, 0, SEEK_END) < 0) {
- goto fail;
- }
- sz = DUK_FTELL(f);
- if (sz < 0) {
- goto fail;
- }
- if (DUK_FSEEK(f, 0, SEEK_SET) < 0) {
- goto fail;
- }
- buf = (char *) duk_push_fixed_buffer(ctx, (duk_size_t) sz);
- DUK_ASSERT(buf != NULL);
- if ((duk_size_t) DUK_FREAD(buf, 1, (size_t) sz, f) != (duk_size_t) sz) {
- goto fail;
- }
- (void) DUK_FCLOSE(f); /* ignore fclose() error */
- f = NULL;
- return duk_to_string(ctx, -1);
-
- fail:
- if (f) {
- DUK_FCLOSE(f);
- }
-
- if (flags != 0) {
- DUK_ASSERT(flags == DUK_STRING_PUSH_SAFE); /* only flag now */
- duk_push_undefined(ctx);
- } else {
- /* XXX: string not shared because it is conditional */
- DUK_ERROR_TYPE(thr, "read file error");
- }
- return NULL;
-}
-#else
-DUK_EXTERNAL const char *duk_push_string_file_raw(duk_context *ctx, const char *path, duk_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(path);
-
- if (flags != 0) {
- DUK_ASSERT(flags == DUK_STRING_PUSH_SAFE); /* only flag now */
- duk_push_undefined(ctx);
- } else {
- /* XXX: string not shared because it is conditional */
- DUK_ERROR_UNSUPPORTED(thr, "file I/O disabled");
- }
- return NULL;
-}
-#endif /* DUK_USE_FILE_IO */
-
-DUK_EXTERNAL void duk_push_pointer(duk_context *ctx, void *val) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_pointer(duk_hthread *thr, void *val) {
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
tv_slot = thr->valstack_top++;
DUK_TVAL_SET_POINTER(tv_slot, val);
}
-DUK_LOCAL void duk__push_this_helper(duk_context *ctx, duk_small_uint_t check_object_coercible) {
- duk_hthread *thr;
+DUK_INTERNAL duk_hstring *duk_push_uint_to_hstring(duk_hthread *thr, duk_uint_t i) {
+ duk_hstring *h_tmp;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ /* XXX: this could be a direct DUK_SPRINTF to a buffer followed by duk_push_string() */
+ duk_push_uint(thr, (duk_uint_t) i);
+ h_tmp = duk_to_hstring_m1(thr);
+ DUK_ASSERT(h_tmp != NULL);
+ return h_tmp;
+}
+
+DUK_LOCAL void duk__push_this_helper(duk_hthread *thr, duk_small_uint_t check_object_coercible) {
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
DUK__CHECK_SPACE();
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* because of valstack init policy */
tv_slot = thr->valstack_top++;
- if (DUK_UNLIKELY(thr->callstack_top == 0)) {
+ if (DUK_UNLIKELY(thr->callstack_curr == NULL)) {
if (check_object_coercible) {
goto type_error;
}
@@ -18349,137 +21498,119 @@ DUK_LOCAL void duk__push_this_helper(duk_context *ctx, duk_small_uint_t check_ob
DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE);
}
-DUK_EXTERNAL void duk_push_this(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_push_this(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk__push_this_helper(ctx, 0 /*check_object_coercible*/);
+ duk__push_this_helper(thr, 0 /*check_object_coercible*/);
}
-DUK_INTERNAL void duk_push_this_check_object_coercible(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_INTERNAL void duk_push_this_check_object_coercible(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk__push_this_helper(ctx, 1 /*check_object_coercible*/);
+ duk__push_this_helper(thr, 1 /*check_object_coercible*/);
}
-DUK_INTERNAL duk_hobject *duk_push_this_coercible_to_object(duk_context *ctx) {
+DUK_INTERNAL duk_hobject *duk_push_this_coercible_to_object(duk_hthread *thr) {
duk_hobject *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- duk__push_this_helper(ctx, 1 /*check_object_coercible*/);
- duk_to_object(ctx, -1);
- h = duk_get_hobject(ctx, -1);
+ duk__push_this_helper(thr, 1 /*check_object_coercible*/);
+ h = duk_to_hobject(thr, -1);
DUK_ASSERT(h != NULL);
return h;
}
-DUK_INTERNAL duk_hstring *duk_push_this_coercible_to_string(duk_context *ctx) {
- duk_hstring *h;
+DUK_INTERNAL duk_hstring *duk_push_this_coercible_to_string(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
- DUK_ASSERT_CTX_VALID(ctx);
-
- duk__push_this_helper(ctx, 1 /*check_object_coercible*/);
- duk_to_string(ctx, -1);
- h = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h != NULL);
- return h;
+ duk__push_this_helper(thr, 1 /*check_object_coercible*/);
+ return duk_to_hstring_m1(thr); /* This will reject all Symbol values; accepts Symbol objects. */
}
-DUK_INTERNAL duk_tval *duk_get_borrowed_this_tval(duk_context *ctx) {
- duk_hthread *thr;
-
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_tval *duk_get_borrowed_this_tval(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->callstack_top > 0); /* caller required to know */
+ DUK_ASSERT(thr->callstack_curr != NULL); /* caller required to know */
DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* consequence of above */
DUK_ASSERT(thr->valstack_bottom - 1 >= thr->valstack); /* 'this' binding exists */
return thr->valstack_bottom - 1;
}
-DUK_EXTERNAL void duk_push_current_function(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_push_current_function(duk_hthread *thr) {
duk_activation *act;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
- DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
+ DUK_ASSERT_API_ENTRY(thr);
- act = duk_hthread_get_current_activation(thr);
- if (act) {
- duk_push_tval(ctx, &act->tv_func);
+ act = thr->callstack_curr;
+ if (act != NULL) {
+ duk_push_tval(thr, &act->tv_func);
} else {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
}
}
-DUK_EXTERNAL void duk_push_current_thread(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+DUK_EXTERNAL void duk_push_current_thread(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
if (thr->heap->curr_thread) {
- duk_push_hobject(ctx, (duk_hobject *) thr->heap->curr_thread);
+ duk_push_hobject(thr, (duk_hobject *) thr->heap->curr_thread);
} else {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
}
}
-DUK_EXTERNAL void duk_push_global_object(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_push_global_object(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk_push_hobject_bidx(ctx, DUK_BIDX_GLOBAL);
+ duk_push_hobject_bidx(thr, DUK_BIDX_GLOBAL);
}
/* XXX: size optimize */
-DUK_LOCAL void duk__push_stash(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE)) {
+DUK_LOCAL void duk__push_stash(duk_hthread *thr) {
+ if (!duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE)) {
DUK_DDD(DUK_DDDPRINT("creating heap/global/thread stash on first use"));
- duk_pop(ctx);
- duk_push_object_internal(ctx);
- duk_dup_top(ctx);
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_C); /* [ ... parent stash stash ] -> [ ... parent stash ] */
+ duk_pop_unsafe(thr);
+ duk_push_bare_object(thr);
+ duk_dup_top(thr);
+ duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_C); /* [ ... parent stash stash ] -> [ ... parent stash ] */
}
- duk_remove(ctx, -2);
+ duk_remove_m2(thr);
}
-DUK_EXTERNAL void duk_push_heap_stash(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_push_heap_stash(duk_hthread *thr) {
duk_heap *heap;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
heap = thr->heap;
DUK_ASSERT(heap->heap_object != NULL);
- duk_push_hobject(ctx, heap->heap_object);
- duk__push_stash(ctx);
+ duk_push_hobject(thr, heap->heap_object);
+ duk__push_stash(thr);
}
-DUK_EXTERNAL void duk_push_global_stash(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- duk_push_global_object(ctx);
- duk__push_stash(ctx);
+DUK_EXTERNAL void duk_push_global_stash(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_push_global_object(thr);
+ duk__push_stash(thr);
}
-DUK_EXTERNAL void duk_push_thread_stash(duk_context *ctx, duk_context *target_ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- DUK_ASSERT_CTX_VALID(ctx);
- if (!target_ctx) {
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
+DUK_EXTERNAL void duk_push_thread_stash(duk_hthread *thr, duk_hthread *target_thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ if (DUK_UNLIKELY(target_thr == NULL)) {
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
return; /* not reached */
}
- duk_push_hobject(ctx, (duk_hobject *) target_ctx);
- duk__push_stash(ctx);
+ duk_push_hobject(thr, (duk_hobject *) target_thr);
+ duk__push_stash(thr);
}
/* XXX: duk_ssize_t would be useful here */
-DUK_LOCAL duk_int_t duk__try_push_vsprintf(duk_context *ctx, void *buf, duk_size_t sz, const char *fmt, va_list ap) {
+DUK_LOCAL duk_int_t duk__try_push_vsprintf(duk_hthread *thr, void *buf, duk_size_t sz, const char *fmt, va_list ap) {
duk_int_t len;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_UNREF(thr);
/* NUL terminator handling doesn't matter here */
len = DUK_VSNPRINTF((char *) buf, sz, fmt, ap);
@@ -18492,8 +21623,7 @@ DUK_LOCAL duk_int_t duk__try_push_vsprintf(duk_context *ctx, void *buf, duk_size
return -1;
}
-DUK_EXTERNAL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va_list ap) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL const char *duk_push_vsprintf(duk_hthread *thr, const char *fmt, va_list ap) {
duk_uint8_t stack_buf[DUK_PUSH_SPRINTF_INITIAL_SIZE];
duk_size_t sz = DUK_PUSH_SPRINTF_INITIAL_SIZE;
duk_bool_t pushed_buf = 0;
@@ -18501,13 +21631,13 @@ DUK_EXTERNAL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va
duk_int_t len; /* XXX: duk_ssize_t */
const char *res;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* special handling of fmt==NULL */
if (!fmt) {
duk_hstring *h_str;
- duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
- h_str = DUK_HTHREAD_STRING_EMPTY_STRING(thr); /* rely on interning, must be this string */
+ duk_push_hstring_empty(thr);
+ h_str = duk_known_hstring(thr, -1);
return (const char *) DUK_HSTRING_GET_DATA(h_str);
}
@@ -18528,14 +21658,14 @@ DUK_EXTERNAL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va
buf = stack_buf;
} else if (!pushed_buf) {
pushed_buf = 1;
- buf = duk_push_dynamic_buffer(ctx, sz);
+ buf = duk_push_dynamic_buffer(thr, sz);
} else {
- buf = duk_resize_buffer(ctx, -1, sz);
+ buf = duk_resize_buffer(thr, -1, sz);
}
DUK_ASSERT(buf != NULL);
DUK_VA_COPY(ap_copy, ap);
- len = duk__try_push_vsprintf(ctx, buf, sz, fmt, ap_copy);
+ len = duk__try_push_vsprintf(thr, buf, sz, fmt, ap_copy);
va_end(ap_copy);
if (len >= 0) {
break;
@@ -18543,157 +21673,174 @@ DUK_EXTERNAL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va
/* failed, resize and try again */
sz = sz * 2;
- if (sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT) {
- DUK_ERROR_API(thr, DUK_STR_SPRINTF_TOO_LONG);
+ if (DUK_UNLIKELY(sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT)) {
+ DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG);
}
}
- /* Cannot use duk_to_string() on the buffer because it is usually
- * larger than 'len'. Also, 'buf' is usually a stack buffer.
+ /* Cannot use duk_buffer_to_string() on the buffer because it is
+ * usually larger than 'len'; 'buf' is also usually a stack buffer.
*/
- res = duk_push_lstring(ctx, (const char *) buf, (duk_size_t) len); /* [ buf? res ] */
+ res = duk_push_lstring(thr, (const char *) buf, (duk_size_t) len); /* [ buf? res ] */
if (pushed_buf) {
- duk_remove(ctx, -2);
+ duk_remove_m2(thr);
}
return res;
}
-DUK_EXTERNAL const char *duk_push_sprintf(duk_context *ctx, const char *fmt, ...) {
+DUK_EXTERNAL const char *duk_push_sprintf(duk_hthread *thr, const char *fmt, ...) {
va_list ap;
const char *ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* allow fmt==NULL */
va_start(ap, fmt);
- ret = duk_push_vsprintf(ctx, fmt, ap);
+ ret = duk_push_vsprintf(thr, fmt, ap);
va_end(ap);
return ret;
}
-DUK_INTERNAL duk_idx_t duk_push_object_helper(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_hobject *duk_push_object_helper(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
duk_tval *tv_slot;
duk_hobject *h;
- duk_idx_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(prototype_bidx == -1 ||
(prototype_bidx >= 0 && prototype_bidx < DUK_NUM_BUILTINS));
- /* check stack first */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
+ DUK__CHECK_SPACE();
- h = duk_hobject_alloc(thr->heap, hobject_flags_and_class);
- if (!h) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
+ h = duk_hobject_alloc(thr, hobject_flags_and_class);
+ DUK_ASSERT(h != NULL);
DUK_DDD(DUK_DDDPRINT("created object with flags: 0x%08lx", (unsigned long) h->hdr.h_flags));
tv_slot = thr->valstack_top;
DUK_TVAL_SET_OBJECT(tv_slot, h);
DUK_HOBJECT_INCREF(thr, h); /* no side effects */
- ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
thr->valstack_top++;
/* object is now reachable */
if (prototype_bidx >= 0) {
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[prototype_bidx]);
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, h, thr->builtins[prototype_bidx]);
} else {
DUK_ASSERT(prototype_bidx == -1);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h) == NULL);
}
- return ret;
+ return h;
}
-DUK_INTERNAL duk_idx_t duk_push_object_helper_proto(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_hobject *proto) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_idx_t ret;
+DUK_INTERNAL duk_hobject *duk_push_object_helper_proto(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_hobject *proto) {
duk_hobject *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- ret = duk_push_object_helper(ctx, hobject_flags_and_class, -1);
- h = duk_get_hobject(ctx, -1);
+ h = duk_push_object_helper(thr, hobject_flags_and_class, -1);
DUK_ASSERT(h != NULL);
- DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h) == NULL);
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, proto);
- return ret;
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, h, proto);
+ return h;
}
-DUK_EXTERNAL duk_idx_t duk_push_object(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_idx_t duk_push_object(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
- return duk_push_object_helper(ctx,
+ (void) duk_push_object_helper(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
DUK_BIDX_OBJECT_PROTOTYPE);
+ return duk_get_top_index_unsafe(thr);
}
-DUK_EXTERNAL duk_idx_t duk_push_array(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *obj;
+DUK_EXTERNAL duk_idx_t duk_push_array(duk_hthread *thr) {
+ duk_uint_t flags;
+ duk_harray *obj;
duk_idx_t ret;
+ duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- ret = duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_ARRAY_PART |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAY),
- DUK_BIDX_ARRAY_PROTOTYPE);
+ flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_FLAG_ARRAY_PART |
+ DUK_HOBJECT_FLAG_EXOTIC_ARRAY |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAY);
- obj = duk_require_hobject(ctx, ret);
+ obj = duk_harray_alloc(thr, flags);
+ DUK_ASSERT(obj != NULL);
- /*
- * An array must have a 'length' property (E5 Section 15.4.5.2).
- * The special array behavior flag must only be enabled once the
- * length property has been added.
- *
- * The internal property must be a number (and preferably a
- * fastint if fastint support is enabled).
- */
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_ARRAY_PROTOTYPE]);
- duk_push_int(ctx, 0);
-#if defined(DUK_USE_FASTINT)
- DUK_ASSERT(DUK_TVAL_IS_FASTINT(duk_require_tval(ctx, -1)));
-#endif
-
- duk_hobject_define_property_internal(thr,
- obj,
- DUK_HTHREAD_STRING_LENGTH(thr),
- DUK_PROPDESC_FLAGS_W);
- DUK_HOBJECT_SET_EXOTIC_ARRAY(obj);
+ tv_slot = thr->valstack_top;
+ DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
+ DUK_HOBJECT_INCREF(thr, obj); /* XXX: could preallocate with refcount = 1 */
+ ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
+ thr->valstack_top++;
+ DUK_ASSERT(obj->length == 0); /* Array .length starts at zero. */
return ret;
}
-DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_harray *duk_push_harray(duk_hthread *thr) {
+ /* XXX: API call could do this directly, cast to void in API macro. */
+ duk_harray *a;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ (void) duk_push_array(thr);
+ DUK_ASSERT(DUK_TVAL_IS_OBJECT(thr->valstack_top - 1));
+ a = (duk_harray *) DUK_TVAL_GET_OBJECT(thr->valstack_top - 1);
+ DUK_ASSERT(a != NULL);
+ return a;
+}
+
+/* Push a duk_harray with preallocated size (.length also set to match size).
+ * Caller may then populate array part of the duk_harray directly.
+ */
+DUK_INTERNAL duk_harray *duk_push_harray_with_size(duk_hthread *thr, duk_uint32_t size) {
+ duk_harray *a;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ a = duk_push_harray(thr);
+
+ duk_hobject_realloc_props(thr,
+ (duk_hobject *) a,
+ 0,
+ size,
+ 0,
+ 0);
+ a->length = size;
+ return a;
+}
+
+DUK_INTERNAL duk_tval *duk_push_harray_with_size_outptr(duk_hthread *thr, duk_uint32_t size) {
+ duk_harray *a;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ a = duk_push_harray_with_size(thr, size);
+ DUK_ASSERT(a != NULL);
+ return DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a);
+}
+
+DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_hthread *thr, duk_uint_t flags) {
duk_hthread *obj;
duk_idx_t ret;
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- /* check stack first */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
+ DUK__CHECK_SPACE();
- obj = duk_hthread_alloc(thr->heap,
+ obj = duk_hthread_alloc(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_THREAD |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD));
- if (!obj) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
+ DUK_ASSERT(obj != NULL);
obj->state = DUK_HTHREAD_STATE_INACTIVE;
#if defined(DUK_USE_ROM_STRINGS)
/* Nothing to initialize, strs[] is in ROM. */
@@ -18714,8 +21861,8 @@ DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) {
thr->valstack_top++;
/* important to do this *after* pushing, to make the thread reachable for gc */
- if (!duk_hthread_init_stacks(thr->heap, obj)) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
+ if (DUK_UNLIKELY(!duk_hthread_init_stacks(thr->heap, obj))) {
+ DUK_ERROR_ALLOC_FAILED(thr);
}
/* initialize built-ins - either by copying or creating new ones */
@@ -18725,10 +21872,10 @@ DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) {
duk_hthread_copy_builtin_objects(thr, obj);
}
- /* default prototype (Note: 'obj' must be reachable) */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, obj->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
+ /* default prototype */
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, obj->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
- /* Initial stack size satisfies the stack spare constraints so there
+ /* Initial stack size satisfies the stack slack constraints so there
* is no need to require stack here.
*/
DUK_ASSERT(DUK_VALSTACK_INITIAL_SIZE >=
@@ -18737,30 +21884,26 @@ DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) {
return ret;
}
-DUK_INTERNAL duk_idx_t duk_push_compiledfunction(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hcompiledfunction *obj;
- duk_idx_t ret;
+DUK_INTERNAL duk_hcompfunc *duk_push_hcompfunc(duk_hthread *thr) {
+ duk_hcompfunc *obj;
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- /* check stack first */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
+ DUK__CHECK_SPACE();
/* Template functions are not strictly constructable (they don't
* have a "prototype" property for instance), so leave the
* DUK_HOBJECT_FLAG_CONSRUCTABLE flag cleared here.
*/
- obj = duk_hcompiledfunction_alloc(thr->heap,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_COMPILEDFUNCTION |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION));
- if (!obj) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
+ obj = duk_hcompfunc_alloc(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_CALLABLE |
+ DUK_HOBJECT_FLAG_COMPFUNC |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION));
+ if (DUK_UNLIKELY(obj == NULL)) {
+ DUK_ERROR_ALLOC_FAILED(thr);
}
DUK_DDD(DUK_DDDPRINT("created compiled function object with flags: 0x%08lx", (unsigned long) obj->obj.hdr.h_flags));
@@ -18768,43 +21911,67 @@ DUK_INTERNAL duk_idx_t duk_push_compiledfunction(duk_context *ctx) {
tv_slot = thr->valstack_top;
DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
DUK_HOBJECT_INCREF(thr, obj);
- ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
thr->valstack_top++;
- /* default prototype (Note: 'obj' must be reachable) */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
+ /* default prototype */
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) obj) == NULL);
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
- return ret;
+ return obj;
}
-DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hnativefunction *obj;
+DUK_INTERNAL duk_hboundfunc *duk_push_hboundfunc(duk_hthread *thr) {
+ duk_hboundfunc *obj;
+ duk_tval *tv_slot;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ DUK__CHECK_SPACE();
+ obj = duk_hboundfunc_alloc(thr->heap,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BOUNDFUNC |
+ DUK_HOBJECT_FLAG_CONSTRUCTABLE |
+ DUK_HOBJECT_FLAG_CALLABLE |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION));
+ if (!obj) {
+ DUK_ERROR_ALLOC_FAILED(thr);
+ }
+
+ tv_slot = thr->valstack_top++;
+ DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
+ DUK_HOBJECT_INCREF(thr, obj);
+
+ /* Prototype is left as NULL because the caller always sets it (and
+ * it depends on the target function).
+ */
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) obj) == NULL);
+
+ return obj;
+}
+
+DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_hthread *thr, duk_c_function func, duk_idx_t nargs, duk_uint_t flags, duk_small_uint_t proto_bidx) {
+ duk_hnatfunc *obj;
duk_idx_t ret;
duk_tval *tv_slot;
duk_int16_t func_nargs;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
- /* check stack first */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
- if (func == NULL) {
+ DUK__CHECK_SPACE();
+
+ if (DUK_UNLIKELY(func == NULL)) {
goto api_error;
}
- if (nargs >= 0 && nargs < DUK_HNATIVEFUNCTION_NARGS_MAX) {
+ if (nargs >= 0 && nargs < DUK_HNATFUNC_NARGS_MAX) {
func_nargs = (duk_int16_t) nargs;
} else if (nargs == DUK_VARARGS) {
- func_nargs = DUK_HNATIVEFUNCTION_NARGS_VARARGS;
+ func_nargs = DUK_HNATFUNC_NARGS_VARARGS;
} else {
goto api_error;
}
- obj = duk_hnativefunction_alloc(thr->heap, flags);
- if (!obj) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
+ obj = duk_hnatfunc_alloc(thr, flags);
+ DUK_ASSERT(obj != NULL);
obj->func = func;
obj->nargs = func_nargs;
@@ -18818,75 +21985,80 @@ DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function fu
ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
thr->valstack_top++;
- /* default prototype (Note: 'obj' must be reachable) */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
-
+ DUK_ASSERT_BIDX_VALID(proto_bidx);
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[proto_bidx]);
return ret;
api_error:
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
return 0; /* not reached */
}
-DUK_EXTERNAL duk_idx_t duk_push_c_function(duk_context *ctx, duk_c_function func, duk_int_t nargs) {
+DUK_EXTERNAL duk_idx_t duk_push_c_function(duk_hthread *thr, duk_c_function func, duk_int_t nargs) {
duk_uint_t flags;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_CONSTRUCTABLE |
- DUK_HOBJECT_FLAG_NATIVEFUNCTION |
+ DUK_HOBJECT_FLAG_CALLABLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_FLAG_NATFUNC |
DUK_HOBJECT_FLAG_NEWENV |
DUK_HOBJECT_FLAG_STRICT |
DUK_HOBJECT_FLAG_NOTAIL |
- DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
- return duk__push_c_function_raw(ctx, func, nargs, flags);
+ /* Default prototype is a Duktape specific %NativeFunctionPrototype%
+ * which provides .length and .name getters.
+ */
+ return duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE);
}
-DUK_INTERNAL void duk_push_c_function_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs) {
+DUK_INTERNAL void duk_push_c_function_builtin(duk_hthread *thr, duk_c_function func, duk_int_t nargs) {
duk_uint_t flags;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_CONSTRUCTABLE |
- DUK_HOBJECT_FLAG_NATIVEFUNCTION |
+ DUK_HOBJECT_FLAG_CALLABLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_FLAG_NATFUNC |
DUK_HOBJECT_FLAG_NEWENV |
DUK_HOBJECT_FLAG_STRICT |
DUK_HOBJECT_FLAG_NOTAIL |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
- (void) duk__push_c_function_raw(ctx, func, nargs, flags);
+ /* Must use Function.prototype for standard built-in functions. */
+ (void) duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_FUNCTION_PROTOTYPE);
}
-DUK_INTERNAL void duk_push_c_function_noconstruct_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs) {
+DUK_INTERNAL void duk_push_c_function_builtin_noconstruct(duk_hthread *thr, duk_c_function func, duk_int_t nargs) {
duk_uint_t flags;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_NATIVEFUNCTION |
+ DUK_HOBJECT_FLAG_CALLABLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_FLAG_NATFUNC |
DUK_HOBJECT_FLAG_NEWENV |
DUK_HOBJECT_FLAG_STRICT |
DUK_HOBJECT_FLAG_NOTAIL |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
- (void) duk__push_c_function_raw(ctx, func, nargs, flags);
+ /* Must use Function.prototype for standard built-in functions. */
+ (void) duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_FUNCTION_PROTOTYPE);
}
-DUK_EXTERNAL duk_idx_t duk_push_c_lightfunc(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_idx_t length, duk_int_t magic) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval tv_tmp;
+DUK_EXTERNAL duk_idx_t duk_push_c_lightfunc(duk_hthread *thr, duk_c_function func, duk_idx_t nargs, duk_idx_t length, duk_int_t magic) {
duk_small_uint_t lf_flags;
+ duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- /* check stack first */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
+ DUK__CHECK_SPACE();
if (nargs >= DUK_LFUNC_NARGS_MIN && nargs <= DUK_LFUNC_NARGS_MAX) {
/* as is */
@@ -18895,44 +22067,40 @@ DUK_EXTERNAL duk_idx_t duk_push_c_lightfunc(duk_context *ctx, duk_c_function fun
} else {
goto api_error;
}
- if (!(length >= DUK_LFUNC_LENGTH_MIN && length <= DUK_LFUNC_LENGTH_MAX)) {
+ if (DUK_UNLIKELY(!(length >= DUK_LFUNC_LENGTH_MIN && length <= DUK_LFUNC_LENGTH_MAX))) {
goto api_error;
}
- if (!(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX)) {
+ if (DUK_UNLIKELY(!(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX))) {
goto api_error;
}
- lf_flags = DUK_LFUNC_FLAGS_PACK(magic, length, nargs);
- DUK_TVAL_SET_LIGHTFUNC(&tv_tmp, func, lf_flags);
- duk_push_tval(ctx, &tv_tmp); /* XXX: direct valstack write */
- DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
- return ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1;
+ lf_flags = DUK_LFUNC_FLAGS_PACK((duk_small_int_t) magic, (duk_small_uint_t) length, (duk_small_uint_t) nargs);
+ tv_slot = thr->valstack_top++;
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv_slot));
+ DUK_TVAL_SET_LIGHTFUNC(tv_slot, func, lf_flags);
+ DUK_ASSERT(tv_slot >= thr->valstack_bottom);
+ return (duk_idx_t) (tv_slot - thr->valstack_bottom);
api_error:
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
return 0; /* not reached */
}
-DUK_INTERNAL duk_hbufferobject *duk_push_bufferobject_raw(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hbufferobject *obj;
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+DUK_INTERNAL duk_hbufobj *duk_push_bufobj_raw(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
+ duk_hbufobj *obj;
duk_tval *tv_slot;
- DUK_ASSERT(ctx != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(prototype_bidx >= 0);
- /* check stack first */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
+ DUK__CHECK_SPACE();
- obj = duk_hbufferobject_alloc(thr->heap, hobject_flags_and_class);
- if (!obj) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
+ obj = duk_hbufobj_alloc(thr, hobject_flags_and_class);
+ DUK_ASSERT(obj != NULL);
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[prototype_bidx]);
- DUK_ASSERT_HBUFFEROBJECT_VALID(obj);
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[prototype_bidx]);
+ DUK_ASSERT_HBUFOBJ_VALID(obj);
tv_slot = thr->valstack_top;
DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
@@ -18941,169 +22109,181 @@ DUK_INTERNAL duk_hbufferobject *duk_push_bufferobject_raw(duk_context *ctx, duk_
return obj;
}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/* XXX: There's quite a bit of overlap with buffer creation handling in
* duk_bi_buffer.c. Look for overlap and refactor.
*/
-#define DUK__PACK_ARGS(classnum,protobidx,elemtype,elemshift,isview) \
- (((classnum) << 24) | ((protobidx) << 16) | ((elemtype) << 8) | ((elemshift) << 4) | (isview))
-
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+#define DUK__PACK_ARGS(classnum,protobidx,elemtype,elemshift,istypedarray) \
+ (((classnum) << 24) | ((protobidx) << 16) | ((elemtype) << 8) | ((elemshift) << 4) | (istypedarray))
+
static const duk_uint32_t duk__bufobj_flags_lookup[] = {
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_BUFFER, DUK_BIDX_BUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_DUKTAPE_BUFFER */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_BUFFER, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_NODEJS_BUFFER */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_ARRAYBUFFER, DUK_BIDX_ARRAYBUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_ARRAYBUFFER */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_DATAVIEW, DUK_BIDX_DATAVIEW_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_DATAVIEW */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT8ARRAY, DUK_BIDX_INT8ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_INT8, 0, 1), /* DUK_BUFOBJ_INT8ARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY, DUK_BIDX_UINT8ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_UINT8ARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY, DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED, 0, 1), /* DUK_BUFOBJ_UINT8CLAMPEDARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT16ARRAY, DUK_BIDX_INT16ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_INT16, 1, 1), /* DUK_BUFOBJ_INT16ARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT16ARRAY, DUK_BIDX_UINT16ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT16, 1, 1), /* DUK_BUFOBJ_UINT16ARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT32ARRAY, DUK_BIDX_INT32ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_INT32, 2, 1), /* DUK_BUFOBJ_INT32ARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT32ARRAY, DUK_BIDX_UINT32ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT32, 2, 1), /* DUK_BUFOBJ_UINT32ARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT32ARRAY, DUK_BIDX_FLOAT32ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_FLOAT32, 2, 1), /* DUK_BUFOBJ_FLOAT32ARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT64ARRAY, DUK_BIDX_FLOAT64ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_FLOAT64, 3, 1) /* DUK_BUFOBJ_FLOAT64ARRAY */
-};
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-/* Only allow Duktape.Buffer when support disabled. */
-static const duk_uint32_t duk__bufobj_flags_lookup[] = {
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_BUFFER, DUK_BIDX_BUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0) /* DUK_BUFOBJ_DUKTAPE_BUFFER */
+ /* Node.js Buffers are Uint8Array instances which inherit from Buffer.prototype. */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_ARRAYBUFFER, DUK_BIDX_ARRAYBUFFER_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_ARRAYBUFFER */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_NODEJS_BUFFER */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_DATAVIEW, DUK_BIDX_DATAVIEW_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_DATAVIEW */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT8ARRAY, DUK_BIDX_INT8ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_INT8, 0, 1), /* DUK_BUFOBJ_INT8ARRAY */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY, DUK_BIDX_UINT8ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_UINT8ARRAY */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY, DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8CLAMPED, 0, 1), /* DUK_BUFOBJ_UINT8CLAMPEDARRAY */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT16ARRAY, DUK_BIDX_INT16ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_INT16, 1, 1), /* DUK_BUFOBJ_INT16ARRAY */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT16ARRAY, DUK_BIDX_UINT16ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT16, 1, 1), /* DUK_BUFOBJ_UINT16ARRAY */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT32ARRAY, DUK_BIDX_INT32ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_INT32, 2, 1), /* DUK_BUFOBJ_INT32ARRAY */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT32ARRAY, DUK_BIDX_UINT32ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT32, 2, 1), /* DUK_BUFOBJ_UINT32ARRAY */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT32ARRAY, DUK_BIDX_FLOAT32ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_FLOAT32, 2, 1), /* DUK_BUFOBJ_FLOAT32ARRAY */
+ DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT64ARRAY, DUK_BIDX_FLOAT64ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_FLOAT64, 3, 1) /* DUK_BUFOBJ_FLOAT64ARRAY */
};
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#undef DUK__PACK_ARGS
-DUK_EXTERNAL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) {
- duk_hthread *thr;
- duk_hbufferobject *h_bufobj;
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+DUK_EXTERNAL void duk_push_buffer_object(duk_hthread *thr, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) {
+ duk_hbufobj *h_bufobj;
duk_hbuffer *h_val;
+ duk_hobject *h_arraybuf;
duk_uint32_t tmp;
duk_uint_t classnum;
duk_uint_t protobidx;
duk_uint_t lookupidx;
duk_uint_t uint_offset, uint_length, uint_added;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
+ DUK_ASSERT_API_ENTRY(thr);
- /* The underlying types for offset/length in duk_hbufferobject is
- * duk_uint_t; make sure argument values fit and that offset + length
- * does not wrap.
+ /* The underlying types for offset/length in duk_hbufobj is
+ * duk_uint_t; make sure argument values fit.
*/
uint_offset = (duk_uint_t) byte_offset;
uint_length = (duk_uint_t) byte_length;
if (sizeof(duk_size_t) != sizeof(duk_uint_t)) {
- if ((duk_size_t) uint_offset != byte_offset || (duk_size_t) uint_length != byte_length) {
+ if (DUK_UNLIKELY((duk_size_t) uint_offset != byte_offset || (duk_size_t) uint_length != byte_length)) {
goto range_error;
}
}
- uint_added = uint_offset + uint_length;
- if (uint_added < uint_offset) {
- goto range_error;
- }
- DUK_ASSERT(uint_added >= uint_offset && uint_added >= uint_length);
DUK_ASSERT_DISABLE(flags >= 0); /* flags is unsigned */
- lookupidx = flags & 0x0f; /* 4 low bits */
- if (lookupidx >= sizeof(duk__bufobj_flags_lookup) / sizeof(duk_uint32_t)) {
+ lookupidx = flags;
+ if (DUK_UNLIKELY(lookupidx >= sizeof(duk__bufobj_flags_lookup) / sizeof(duk_uint32_t))) {
goto arg_error;
}
tmp = duk__bufobj_flags_lookup[lookupidx];
classnum = tmp >> 24;
protobidx = (tmp >> 16) & 0xff;
- h_val = duk_require_hbuffer(ctx, idx_buffer);
+ h_arraybuf = duk_get_hobject(thr, idx_buffer);
+ if (h_arraybuf != NULL && /* argument is an object */
+ flags != DUK_BUFOBJ_ARRAYBUFFER && /* creating a view */
+ DUK_HOBJECT_GET_CLASS_NUMBER(h_arraybuf) == DUK_HOBJECT_CLASS_ARRAYBUFFER /* argument is ArrayBuffer */) {
+ duk_uint_t tmp_offset;
+
+ DUK_ASSERT_HBUFOBJ_VALID((duk_hbufobj *) h_arraybuf);
+ h_val = ((duk_hbufobj *) h_arraybuf)->buf;
+ if (DUK_UNLIKELY(h_val == NULL)) {
+ goto arg_error;
+ }
+
+ tmp_offset = uint_offset + ((duk_hbufobj *) h_arraybuf)->offset;
+ if (DUK_UNLIKELY(tmp_offset < uint_offset)) {
+ goto range_error;
+ }
+ uint_offset = tmp_offset;
+
+ /* Note intentional difference to new TypedArray(): we allow
+ * caller to create an uncovered typed array (which is memory
+ * safe); new TypedArray() rejects it.
+ */
+ } else {
+ /* Handle unexpected object arguments here too, for nice error
+ * messages.
+ */
+ h_arraybuf = NULL;
+ h_val = duk_require_hbuffer(thr, idx_buffer);
+ }
+
+ /* Wrap check for offset+length. */
+ uint_added = uint_offset + uint_length;
+ if (DUK_UNLIKELY(uint_added < uint_offset)) {
+ goto range_error;
+ }
+ DUK_ASSERT(uint_added >= uint_offset && uint_added >= uint_length);
+
DUK_ASSERT(h_val != NULL);
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(classnum),
- protobidx);
+ h_bufobj = duk_push_bufobj_raw(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BUFOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(classnum),
+ (duk_small_int_t) protobidx);
DUK_ASSERT(h_bufobj != NULL);
h_bufobj->buf = h_val;
DUK_HBUFFER_INCREF(thr, h_val);
+ h_bufobj->buf_prop = h_arraybuf;
+ DUK_HOBJECT_INCREF_ALLOWNULL(thr, h_arraybuf);
h_bufobj->offset = uint_offset;
h_bufobj->length = uint_length;
h_bufobj->shift = (tmp >> 4) & 0x0f;
h_bufobj->elem_type = (tmp >> 8) & 0xff;
- h_bufobj->is_view = tmp & 0x0f;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+ h_bufobj->is_typedarray = tmp & 0x0f;
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
/* TypedArray views need an automatic ArrayBuffer which must be
- * provided as .buffer property of the view. Just create a new
- * ArrayBuffer sharing the same underlying buffer.
- *
- * The ArrayBuffer offset is always set to zero, so that if one
- * accesses the ArrayBuffer at the view's .byteOffset, the value
- * matches the view at index 0.
+ * provided as .buffer property of the view. The ArrayBuffer is
+ * referenced via duk_hbufobj->buf_prop and an inherited .buffer
+ * accessor returns it. The ArrayBuffer is created lazily on first
+ * access if necessary so we don't need to do anything more here.
*/
- if (flags & DUK_BUFOBJ_CREATE_ARRBUF) {
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
- DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
-
- DUK_ASSERT(h_bufobj != NULL);
-
- h_bufobj->buf = h_val;
- DUK_HBUFFER_INCREF(thr, h_val);
- h_bufobj->offset = 0;
- h_bufobj->length = uint_offset + uint_length; /* Wrap checked above. */
- DUK_ASSERT(h_bufobj->shift == 0);
- h_bufobj->elem_type = DUK_HBUFFEROBJECT_ELEM_UINT8;
- DUK_ASSERT(h_bufobj->is_view == 0);
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
-
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
- duk_compact(ctx, -1);
- }
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
return;
range_error:
- DUK_ERROR_RANGE(thr, DUK_STR_INVALID_CALL_ARGS);
+ DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARGS);
return; /* not reached */
arg_error:
- DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CALL_ARGS);
+ DUK_ERROR_TYPE(thr, DUK_STR_INVALID_ARGS);
return; /* not reached */
}
+#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
+DUK_EXTERNAL void duk_push_buffer_object(duk_hthread *thr, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(idx_buffer);
+ DUK_UNREF(byte_offset);
+ DUK_UNREF(byte_length);
+ DUK_UNREF(flags);
+ DUK_ERROR_UNSUPPORTED(thr);
+}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_EXTERNAL duk_idx_t duk_push_error_object_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_idx_t ret;
+DUK_EXTERNAL duk_idx_t duk_push_error_object_va_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) {
duk_hobject *proto;
-#ifdef DUK_USE_AUGMENT_ERROR_CREATE
- duk_bool_t noblame_fileline;
+#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
+ duk_small_uint_t augment_flags;
#endif
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr != NULL);
DUK_UNREF(filename);
DUK_UNREF(line);
/* Error code also packs a tracedata related flag. */
-#ifdef DUK_USE_AUGMENT_ERROR_CREATE
- noblame_fileline = err_code & DUK_ERRCODE_FLAG_NOBLAME_FILELINE;
+#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
+ augment_flags = 0;
+ if (err_code & DUK_ERRCODE_FLAG_NOBLAME_FILELINE) {
+ augment_flags = DUK_AUGMENT_FLAG_NOBLAME_FILELINE;
+ }
#endif
err_code = err_code & (~DUK_ERRCODE_FLAG_NOBLAME_FILELINE);
/* error gets its 'name' from the prototype */
proto = duk_error_prototype_from_code(thr, err_code);
- ret = duk_push_object_helper_proto(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR),
- proto);
+ (void) duk_push_object_helper_proto(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR),
+ proto);
/* ... and its 'message' from an instance property */
if (fmt) {
- duk_push_vsprintf(ctx, fmt, ap);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
+ duk_push_vsprintf(thr, fmt, ap);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
} else {
/* If no explicit message given, put error code into message field
* (as a number). This is not fully in keeping with the Ecmascript
@@ -19111,72 +22291,68 @@ DUK_EXTERNAL duk_idx_t duk_push_error_object_va_raw(duk_context *ctx, duk_errcod
* constructors use ToString() on their argument). However, it's
* probably more useful than having a separate 'code' property.
*/
- duk_push_int(ctx, err_code);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
+ duk_push_int(thr, err_code);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
}
/* XXX: .code = err_code disabled, not sure if useful */
/* Creation time error augmentation */
-#ifdef DUK_USE_AUGMENT_ERROR_CREATE
+#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
/* filename may be NULL in which case file/line is not recorded */
- duk_err_augment_error_create(thr, thr, filename, line, noblame_fileline); /* may throw an error */
+ duk_err_augment_error_create(thr, thr, filename, line, augment_flags); /* may throw an error */
#endif
- return ret;
+ return duk_get_top_index_unsafe(thr);
}
-DUK_EXTERNAL duk_idx_t duk_push_error_object_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) {
+DUK_EXTERNAL duk_idx_t duk_push_error_object_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) {
va_list ap;
duk_idx_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
va_start(ap, fmt);
- ret = duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
+ ret = duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
va_end(ap);
return ret;
}
#if !defined(DUK_USE_VARIADIC_MACROS)
-DUK_EXTERNAL duk_idx_t duk_push_error_object_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...) {
+DUK_EXTERNAL duk_idx_t duk_push_error_object_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, ...) {
const char *filename = duk_api_global_filename;
duk_int_t line = duk_api_global_line;
va_list ap;
duk_idx_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
duk_api_global_filename = NULL;
duk_api_global_line = 0;
va_start(ap, fmt);
- ret = duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
+ ret = duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
va_end(ap);
return ret;
}
#endif /* DUK_USE_VARIADIC_MACROS */
-DUK_EXTERNAL void *duk_push_buffer_raw(duk_context *ctx, duk_size_t size, duk_small_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void *duk_push_buffer_raw(duk_hthread *thr, duk_size_t size, duk_small_uint_t flags) {
duk_tval *tv_slot;
duk_hbuffer *h;
void *buf_data;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- /* check stack first */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
+ DUK__CHECK_SPACE();
/* Check for maximum buffer length. */
- if (size > DUK_HBUFFER_MAX_BYTELEN) {
+ if (DUK_UNLIKELY(size > DUK_HBUFFER_MAX_BYTELEN)) {
DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG);
}
h = duk_hbuffer_alloc(thr->heap, size, flags, &buf_data);
- if (!h) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
+ if (DUK_UNLIKELY(h == NULL)) {
+ DUK_ERROR_ALLOC_FAILED(thr);
}
tv_slot = thr->valstack_top;
@@ -19187,14 +22363,133 @@ DUK_EXTERNAL void *duk_push_buffer_raw(duk_context *ctx, duk_size_t size, duk_sm
return (void *) buf_data;
}
+DUK_INTERNAL void *duk_push_fixed_buffer_nozero(duk_hthread *thr, duk_size_t len) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_push_buffer_raw(thr, len, DUK_BUF_FLAG_NOZERO);
+}
+
+DUK_INTERNAL void *duk_push_fixed_buffer_zero(duk_hthread *thr, duk_size_t len) {
+ void *ptr;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ ptr = duk_push_buffer_raw(thr, len, 0);
+#if !defined(DUK_USE_ZERO_BUFFER_DATA)
+ /* ES2015 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA
+ * is not set.
+ */
+ DUK_MEMZERO((void *) ptr, (size_t) len);
+#endif
+ return ptr;
+}
+
+#if defined(DUK_USE_ES6_PROXY)
+DUK_EXTERNAL duk_idx_t duk_push_proxy(duk_hthread *thr, duk_uint_t proxy_flags) {
+ duk_hobject *h_target;
+ duk_hobject *h_handler;
+ duk_hproxy *h_proxy;
+ duk_tval *tv_slot;
+ duk_uint_t flags;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(proxy_flags);
+
+ /* DUK__CHECK_SPACE() unnecessary because the Proxy is written to
+ * value stack in-place.
+ */
+#if 0
+ DUK__CHECK_SPACE();
+#endif
+
+ /* Reject a proxy object as the target because it would need
+ * special handling in property lookups. (ES2015 has no such
+ * restriction.)
+ */
+ h_target = duk_require_hobject_promote_mask(thr, -2, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
+ DUK_ASSERT(h_target != NULL);
+ if (DUK_HOBJECT_IS_PROXY(h_target)) {
+ goto fail_args;
+ }
+
+ /* Reject a proxy object as the handler because it would cause
+ * potentially unbounded recursion. (ES2015 has no such
+ * restriction.)
+ *
+ * There's little practical reason to use a lightfunc or a plain
+ * buffer as the handler table: one could only provide traps via
+ * their prototype objects (Function.prototype and ArrayBuffer.prototype).
+ * Even so, as lightfuncs and plain buffers mimic their object
+ * counterparts, they're promoted and accepted here.
+ */
+ h_handler = duk_require_hobject_promote_mask(thr, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
+ DUK_ASSERT(h_handler != NULL);
+ if (DUK_HOBJECT_IS_PROXY(h_handler)) {
+ goto fail_args;
+ }
+
+ /* XXX: Proxy object currently has no prototype, so ToPrimitive()
+ * coercion fails which is a bit confusing.
+ */
+
+ /* CALLABLE and CONSTRUCTABLE flags are copied from the (initial)
+ * target, see ES2015 Sections 9.5.15 and 9.5.13.
+ */
+ flags = DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h_target) &
+ (DUK_HOBJECT_FLAG_CALLABLE | DUK_HOBJECT_FLAG_CONSTRUCTABLE);
+ flags |= DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ;
+ if (flags & DUK_HOBJECT_FLAG_CALLABLE) {
+ flags |= DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION) |
+ DUK_HOBJECT_FLAG_SPECIAL_CALL;
+ } else {
+ flags |= DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT);
+ }
+
+ h_proxy = duk_hproxy_alloc(thr, flags);
+ DUK_ASSERT(h_proxy != NULL);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_proxy) == NULL);
+
+ /* Initialize Proxy target and handler references; avoid INCREF
+ * by stealing the value stack refcounts via direct value stack
+ * manipulation. INCREF is needed for the Proxy itself however.
+ */
+ DUK_ASSERT(h_target != NULL);
+ h_proxy->target = h_target;
+ DUK_ASSERT(h_handler != NULL);
+ h_proxy->handler = h_handler;
+ DUK_ASSERT_HPROXY_VALID(h_proxy);
+
+ DUK_ASSERT(duk_get_hobject(thr, -2) == h_target);
+ DUK_ASSERT(duk_get_hobject(thr, -1) == h_handler);
+ tv_slot = thr->valstack_top - 2;
+ DUK_ASSERT(tv_slot >= thr->valstack_bottom);
+ DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) h_proxy);
+ DUK_HOBJECT_INCREF(thr, (duk_hobject *) h_proxy);
+ tv_slot++;
+ DUK_TVAL_SET_UNDEFINED(tv_slot); /* [ ... target handler ] -> [ ... proxy undefined ] */
+ thr->valstack_top = tv_slot; /* -> [ ... proxy ] */
+
+ DUK_DD(DUK_DDPRINT("created Proxy: %!iT", duk_get_tval(thr, -1)));
+
+ return (duk_idx_t) (thr->valstack_top - thr->valstack_bottom - 1);
+
+ fail_args:
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+}
+#else /* DUK_USE_ES6_PROXY */
+DUK_EXTERNAL duk_idx_t duk_push_proxy(duk_hthread *thr, duk_uint_t proxy_flags) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(proxy_flags);
+ DUK_ERROR_UNSUPPORTED(thr);
+}
+#endif /* DUK_USE_ES6_PROXY */
+
#if defined(DUK_USE_ASSERTIONS)
-DUK_LOCAL void duk__validate_push_heapptr(duk_context *ctx, void *ptr) {
+DUK_LOCAL void duk__validate_push_heapptr(duk_hthread *thr, void *ptr) {
duk_heaphdr *h;
duk_heaphdr *curr;
- duk_hthread *thr;
duk_bool_t found = 0;
- thr = (duk_hthread *) ctx;
h = (duk_heaphdr *) ptr;
if (h == NULL) {
/* Allowed. */
@@ -19213,48 +22508,66 @@ DUK_LOCAL void duk__validate_push_heapptr(duk_context *ctx, void *ptr) {
* by seeing that X's FINALIZED flag is set (which is done before
* the finalizer starts executing).
*/
+#if defined(DUK_USE_FINALIZER_SUPPORT)
for (curr = thr->heap->finalize_list;
curr != NULL;
curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) {
- if (curr == h) {
- if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h)) {
- /* Object is currently being finalized. */
- DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */
- found = 1;
- } else {
- DUK_ASSERT(0);
- }
- }
- }
-
- /* Also check for the refzero_list; must not be there unless it is
- * being finalized when duk_push_heapptr() is called.
- *
- * Corner case: similar to finalize_list.
- */
-#if defined(DUK_USE_REFERENCE_COUNTING)
- for (curr = thr->heap->refzero_list;
- curr != NULL;
- curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) {
- if (curr == h) {
- if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h)) {
- /* Object is currently being finalized. */
- DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */
- found = 1;
- } else {
- DUK_ASSERT(0);
- }
- }
- }
+ /* FINALIZABLE is set for all objects on finalize_list
+ * except for an object being finalized right now. So
+ * can't assert here.
+ */
+#if 0
+ DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(curr));
#endif
- /* If not present in finalize_list or refzero_list, the pointer
+ if (curr == h) {
+ if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h)) {
+ /* Object is currently being finalized. */
+ DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */
+ found = 1;
+ } else {
+ /* Not being finalized but on finalize_list,
+ * allowed since Duktape 2.1.
+ */
+ DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */
+ found = 1;
+ }
+ }
+ }
+#endif /* DUK_USE_FINALIZER_SUPPORT */
+
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ /* Because refzero_list is now processed to completion inline with
+ * no side effects, it's always empty here.
+ */
+ DUK_ASSERT(thr->heap->refzero_list == NULL);
+#endif
+
+ /* If not present in finalize_list (or refzero_list), it
* must be either in heap_allocated or the string table.
*/
- if (DUK_HEAPHDR_GET_TYPE(h) == DUK_HTYPE_STRING) {
- /* String table assert check omitted from 1.x branch
- * backport.
- */
+ if (DUK_HEAPHDR_IS_STRING(h)) {
+ duk_uint32_t i;
+ duk_hstring *str;
+ duk_heap *heap = thr->heap;
+
+ DUK_ASSERT(found == 0);
+ for (i = 0; i < heap->st_size; i++) {
+#if defined(DUK_USE_STRTAB_PTRCOMP)
+ str = DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, heap->strtable16[i]);
+#else
+ str = heap->strtable[i];
+#endif
+ while (str != NULL) {
+ if (str == (duk_hstring *) h) {
+ DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */
+ found = 1;
+ break;
+ }
+ str = str->hdr.h_next;
+ }
+ }
+ DUK_ASSERT(found != 0);
} else {
for (curr = thr->heap->heap_allocated;
curr != NULL;
@@ -19269,11 +22582,11 @@ DUK_LOCAL void duk__validate_push_heapptr(duk_context *ctx, void *ptr) {
}
#endif /* DUK_USE_ASSERTIONS */
-DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_hthread *thr, void *ptr) {
duk_idx_t ret;
+ duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* Reviving an object using a heap pointer is a dangerous API
* operation: if the application doesn't guarantee that the
@@ -19283,121 +22596,168 @@ DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr) {
*/
#if defined(DUK_USE_ASSERTIONS)
- duk__validate_push_heapptr(ctx, ptr);
+ duk__validate_push_heapptr(thr, ptr);
#endif
+ DUK__CHECK_SPACE();
+
ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
+ tv = thr->valstack_top++;
if (ptr == NULL) {
- goto push_undefined;
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
+ return ret;
}
- switch ((int) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) {
+ DUK_ASSERT_HEAPHDR_VALID((duk_heaphdr *) ptr);
+
+ /* If the argument is on finalize_list it has technically been
+ * unreachable before duk_push_heapptr() but it's still safe to
+ * push it. Starting from Duktape 2.1 allow application code to
+ * do so. There are two main cases:
+ *
+ * (1) The object is on the finalize_list and we're called by
+ * the finalizer for the object being finalized. In this
+ * case do nothing: finalize_list handling will deal with
+ * the object queueing. This is detected by the object not
+ * having a FINALIZABLE flag despite being on the finalize_list;
+ * the flag is cleared for the object being finalized only.
+ *
+ * (2) The object is on the finalize_list but is not currently
+ * being processed. In this case the object can be queued
+ * back to heap_allocated with a few flags cleared, in effect
+ * cancelling the finalizer.
+ */
+ if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) ptr))) {
+ duk_heaphdr *curr;
+
+ DUK_D(DUK_DPRINT("duk_push_heapptr() with a pointer on finalize_list, autorescue"));
+
+ curr = (duk_heaphdr *) ptr;
+ DUK_HEAPHDR_CLEAR_FINALIZABLE(curr);
+
+ /* Because FINALIZED is set prior to finalizer call, it will
+ * be set for the object being currently finalized, but not
+ * for other objects on finalize_list.
+ */
+ DUK_HEAPHDR_CLEAR_FINALIZED(curr);
+
+ /* Dequeue object from finalize_list and queue it back to
+ * heap_allocated.
+ */
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) >= 1); /* Preincremented on finalize_list insert. */
+ DUK_HEAPHDR_PREDEC_REFCOUNT(curr);
+#endif
+ DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(thr->heap, curr);
+ DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(thr->heap, curr);
+
+ /* Continue with the rest. */
+ }
+
+ switch (DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) {
case DUK_HTYPE_STRING:
- duk_push_hstring(ctx, (duk_hstring *) ptr);
+ DUK_TVAL_SET_STRING(tv, (duk_hstring *) ptr);
break;
case DUK_HTYPE_OBJECT:
- duk_push_hobject(ctx, (duk_hobject *) ptr);
- break;
- case DUK_HTYPE_BUFFER:
- duk_push_hbuffer(ctx, (duk_hbuffer *) ptr);
+ DUK_TVAL_SET_OBJECT(tv, (duk_hobject *) ptr);
break;
default:
- goto push_undefined;
+ DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr) == DUK_HTYPE_BUFFER);
+ DUK_TVAL_SET_BUFFER(tv, (duk_hbuffer *) ptr);
+ break;
}
- return ret;
- push_undefined:
- duk_push_undefined(ctx);
+ DUK_HEAPHDR_INCREF(thr, (duk_heaphdr *) ptr);
+
return ret;
}
-DUK_INTERNAL duk_idx_t duk_push_object_internal(duk_context *ctx) {
- return duk_push_object_helper(ctx,
+/* Push object with no prototype, i.e. a "bare" object. */
+DUK_EXTERNAL duk_idx_t duk_push_bare_object(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ (void) duk_push_object_helper(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
-1); /* no prototype */
+ return duk_get_top_index_unsafe(thr);
}
-DUK_INTERNAL void duk_push_hstring(duk_context *ctx, duk_hstring *h) {
+DUK_INTERNAL void duk_push_hstring(duk_hthread *thr, duk_hstring *h) {
duk_tval tv;
- DUK_ASSERT_CTX_VALID(ctx);
+
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(h != NULL);
+
DUK_TVAL_SET_STRING(&tv, h);
- duk_push_tval(ctx, &tv);
+ duk_push_tval(thr, &tv);
}
-DUK_INTERNAL void duk_push_hstring_stridx(duk_context *ctx, duk_small_int_t stridx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
- DUK_ASSERT(stridx >= 0 && stridx < DUK_HEAP_NUM_STRINGS);
- duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
+DUK_INTERNAL void duk_push_hstring_stridx(duk_hthread *thr, duk_small_uint_t stridx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT_STRIDX_VALID(stridx);
+ duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
}
-DUK_INTERNAL void duk_push_hobject(duk_context *ctx, duk_hobject *h) {
+DUK_INTERNAL void duk_push_hstring_empty(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, DUK_STRIDX_EMPTY_STRING));
+}
+
+DUK_INTERNAL void duk_push_hobject(duk_hthread *thr, duk_hobject *h) {
duk_tval tv;
- DUK_ASSERT_CTX_VALID(ctx);
+
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(h != NULL);
+
DUK_TVAL_SET_OBJECT(&tv, h);
- duk_push_tval(ctx, &tv);
+ duk_push_tval(thr, &tv);
}
-DUK_INTERNAL void duk_push_hbuffer(duk_context *ctx, duk_hbuffer *h) {
+DUK_INTERNAL void duk_push_hbuffer(duk_hthread *thr, duk_hbuffer *h) {
duk_tval tv;
- DUK_ASSERT_CTX_VALID(ctx);
+
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(h != NULL);
+
DUK_TVAL_SET_BUFFER(&tv, h);
- duk_push_tval(ctx, &tv);
+ duk_push_tval(thr, &tv);
}
-DUK_INTERNAL void duk_push_hobject_bidx(duk_context *ctx, duk_small_int_t builtin_idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+DUK_INTERNAL void duk_push_hobject_bidx(duk_hthread *thr, duk_small_int_t builtin_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(builtin_idx >= 0 && builtin_idx < DUK_NUM_BUILTINS);
DUK_ASSERT(thr->builtins[builtin_idx] != NULL);
- duk_push_hobject(ctx, thr->builtins[builtin_idx]);
+
+ duk_push_hobject(thr, thr->builtins[builtin_idx]);
}
/*
* Poppers
*/
-DUK_EXTERNAL void duk_pop_n(duk_context *ctx, duk_idx_t count) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL DUK_ALWAYS_INLINE void duk__pop_n_unsafe_raw(duk_hthread *thr, duk_idx_t count) {
duk_tval *tv;
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ duk_tval *tv_end;
+#endif
- DUK_ASSERT_CTX_VALID(ctx);
-
- if (DUK_UNLIKELY(count < 0)) {
- DUK_ERROR_API(thr, DUK_STR_INVALID_COUNT);
- return;
- }
-
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- if (DUK_UNLIKELY((duk_size_t) (thr->valstack_top - thr->valstack_bottom) < (duk_size_t) count)) {
- DUK_ERROR_API(thr, DUK_STR_POP_TOO_MANY);
- }
-
- /*
- * Must be very careful here, every DECREF may cause reallocation
- * of our valstack.
- */
-
- /* XXX: inlined DECREF macro would be nice here: no NULL check,
- * refzero queueing but no refzero algorithm run (= no pointer
- * instability), inline code.
- */
-
- /* XXX: optimize loops */
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(count >= 0);
+ DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count);
#if defined(DUK_USE_REFERENCE_COUNTING)
- while (count > 0) {
- count--;
- tv = --thr->valstack_top; /* tv points to element just below prev top */
+ tv = thr->valstack_top;
+ tv_end = tv - count;
+ while (tv != tv_end) {
+ tv--;
DUK_ASSERT(tv >= thr->valstack_bottom);
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
+ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv);
}
+ thr->valstack_top = tv;
+ DUK_REFZERO_CHECK_FAST(thr);
#else
tv = thr->valstack_top;
while (count > 0) {
@@ -19412,59 +22772,403 @@ DUK_EXTERNAL void duk_pop_n(duk_context *ctx, duk_idx_t count) {
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
}
+DUK_EXTERNAL void duk_pop_n(duk_hthread *thr, duk_idx_t count) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+
+ if (DUK_UNLIKELY((duk_uidx_t) (thr->valstack_top - thr->valstack_bottom) < (duk_uidx_t) count)) {
+ DUK_ERROR_RANGE_INVALID_COUNT(thr);
+ return;
+ }
+ DUK_ASSERT(count >= 0);
+
+ duk__pop_n_unsafe_raw(thr, count);
+}
+
+#if defined(DUK_USE_PREFER_SIZE)
+DUK_INTERNAL void duk_pop_n_unsafe(duk_hthread *thr, duk_idx_t count) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n(thr, count);
+}
+#else /* DUK_USE_PREFER_SIZE */
+DUK_INTERNAL void duk_pop_n_unsafe(duk_hthread *thr, duk_idx_t count) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk__pop_n_unsafe_raw(thr, count);
+}
+#endif /* DUK_USE_PREFER_SIZE */
+
+/* Pop N elements without DECREF (in effect "stealing" any actual refcounts). */
+#if defined(DUK_USE_REFERENCE_COUNTING)
+DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_hthread *thr, duk_idx_t count) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(count >= 0);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count);
+
+ tv = thr->valstack_top;
+ while (count > 0) {
+ count--;
+ tv--;
+ DUK_ASSERT(tv >= thr->valstack_bottom);
+ DUK_TVAL_SET_UNDEFINED(tv);
+ }
+ thr->valstack_top = tv;
+
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+}
+#else /* DUK_USE_REFERENCE_COUNTING */
+DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_hthread *thr, duk_idx_t count) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n_unsafe(thr, count);
+}
+#endif /* DUK_USE_REFERENCE_COUNTING */
+
/* Popping one element is called so often that when footprint is not an issue,
* compile a specialized function for it.
*/
#if defined(DUK_USE_PREFER_SIZE)
-DUK_EXTERNAL void duk_pop(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- duk_pop_n(ctx, 1);
+DUK_EXTERNAL void duk_pop(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n(thr, 1);
}
-#else
-DUK_EXTERNAL void duk_pop(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_pop_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n_unsafe(thr, 1);
+}
+DUK_INTERNAL void duk_pop_nodecref_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n_nodecref_unsafe(thr, 1);
+}
+#else /* DUK_USE_PREFER_SIZE */
+DUK_LOCAL DUK_ALWAYS_INLINE void duk__pop_unsafe_raw(duk_hthread *thr) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) {
- DUK_ERROR_API(thr, DUK_STR_POP_TOO_MANY);
- }
+ DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1);
- tv = --thr->valstack_top; /* tv points to element just below prev top */
+ tv = --thr->valstack_top;
DUK_ASSERT(tv >= thr->valstack_bottom);
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
#else
DUK_TVAL_SET_UNDEFINED(tv);
#endif
+
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+}
+DUK_EXTERNAL void duk_pop(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) {
+ DUK_ERROR_RANGE_INVALID_COUNT(thr);
+ }
+
+ duk__pop_unsafe_raw(thr);
+}
+DUK_INTERNAL void duk_pop_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk__pop_unsafe_raw(thr);
+}
+DUK_INTERNAL void duk_pop_nodecref_unsafe(duk_hthread *thr) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1);
+
+ tv = --thr->valstack_top;
+ DUK_ASSERT(tv >= thr->valstack_bottom);
+ DUK_TVAL_SET_UNDEFINED(tv);
+
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
}
#endif /* !DUK_USE_PREFER_SIZE */
-DUK_EXTERNAL void duk_pop_2(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- duk_pop_n(ctx, 2);
+#if defined(DUK_USE_PREFER_SIZE)
+DUK_INTERNAL void duk_pop_undefined(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_nodecref_unsafe(thr);
+}
+#else /* DUK_USE_PREFER_SIZE */
+DUK_INTERNAL void duk_pop_undefined(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1);
+
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1));
+ thr->valstack_top--;
+
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+}
+#endif /* !DUK_USE_PREFER_SIZE */
+
+#if defined(DUK_USE_PREFER_SIZE)
+DUK_EXTERNAL void duk_pop_2(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n(thr, 2);
+}
+DUK_INTERNAL void duk_pop_2_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n_unsafe(thr, 2);
+}
+DUK_INTERNAL void duk_pop_2_nodecref_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n_nodecref_unsafe(thr, 2);
+}
+#else
+DUK_LOCAL DUK_ALWAYS_INLINE void duk__pop_2_unsafe_raw(duk_hthread *thr) {
+ duk_tval *tv;
+
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 2);
+
+ tv = --thr->valstack_top;
+ DUK_ASSERT(tv >= thr->valstack_bottom);
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
+#else
+ DUK_TVAL_SET_UNDEFINED(tv);
+#endif
+ tv = --thr->valstack_top;
+ DUK_ASSERT(tv >= thr->valstack_bottom);
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
+#else
+ DUK_TVAL_SET_UNDEFINED(tv);
+#endif
+
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+}
+DUK_EXTERNAL void duk_pop_2(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ if (DUK_UNLIKELY(thr->valstack_top - 2 < thr->valstack_bottom)) {
+ DUK_ERROR_RANGE_INVALID_COUNT(thr);
+ }
+
+ duk__pop_2_unsafe_raw(thr);
+}
+DUK_INTERNAL void duk_pop_2_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk__pop_2_unsafe_raw(thr);
+}
+DUK_INTERNAL void duk_pop_2_nodecref_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 2);
+
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1));
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 2));
+ thr->valstack_top -= 2;
+
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+}
+#endif /* !DUK_USE_PREFER_SIZE */
+
+DUK_EXTERNAL void duk_pop_3(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n(thr, 3);
}
-DUK_EXTERNAL void duk_pop_3(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- duk_pop_n(ctx, 3);
+DUK_INTERNAL void duk_pop_3_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n_unsafe(thr, 3);
+}
+
+DUK_INTERNAL void duk_pop_3_nodecref_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n_nodecref_unsafe(thr, 3);
+}
+
+/*
+ * Pack and unpack (pack value stack entries into an array and vice versa)
+ */
+
+/* XXX: pack index range? array index offset? */
+DUK_INTERNAL void duk_pack(duk_hthread *thr, duk_idx_t count) {
+ duk_tval *tv_src;
+ duk_tval *tv_dst;
+ duk_tval *tv_curr;
+ duk_tval *tv_limit;
+ duk_idx_t top;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ top = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
+ DUK_ASSERT(top >= 0);
+ if (DUK_UNLIKELY((duk_uidx_t) count > (duk_uidx_t) top)) {
+ /* Also handles negative count. */
+ DUK_ERROR_RANGE_INVALID_COUNT(thr);
+ return;
+ }
+ DUK_ASSERT(count >= 0);
+
+ /* Wrapping is controlled by the check above: value stack top can be
+ * at most DUK_USE_VALSTACK_LIMIT which is low enough so that
+ * multiplying with sizeof(duk_tval) won't wrap.
+ */
+ DUK_ASSERT(count >= 0 && count <= (duk_idx_t) DUK_USE_VALSTACK_LIMIT);
+ DUK_ASSERT((duk_size_t) count <= DUK_SIZE_MAX / sizeof(duk_tval)); /* no wrapping */
+
+ tv_dst = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) count); /* XXX: uninitialized would be OK */
+ DUK_ASSERT(count == 0 || tv_dst != NULL);
+
+ /* Copy value stack values directly to the array part without
+ * any refcount updates: net refcount changes are zero.
+ */
+
+ tv_src = thr->valstack_top - count - 1;
+ DUK_MEMCPY((void *) tv_dst, (const void *) tv_src, (size_t) count * sizeof(duk_tval));
+
+ /* Overwrite result array to final value stack location and wipe
+ * the rest; no refcount operations needed.
+ */
+
+ tv_dst = tv_src; /* when count == 0, same as tv_src (OK) */
+ tv_src = thr->valstack_top - 1;
+ DUK_TVAL_SET_TVAL(tv_dst, tv_src);
+
+ /* XXX: internal helper to wipe a value stack segment? */
+ tv_curr = tv_dst + 1;
+ tv_limit = thr->valstack_top;
+ while (tv_curr != tv_limit) {
+ /* Wipe policy: keep as 'undefined'. */
+ DUK_TVAL_SET_UNDEFINED(tv_curr);
+ tv_curr++;
+ }
+ thr->valstack_top = tv_dst + 1;
+}
+
+DUK_INTERNAL duk_idx_t duk_unpack_array_like(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_require_tval(thr, idx);
+ if (DUK_LIKELY(DUK_TVAL_IS_OBJECT(tv))) {
+ duk_hobject *h;
+ duk_uint32_t len;
+ duk_uint32_t i;
+
+ h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ DUK_UNREF(h);
+
+#if defined(DUK_USE_ARRAY_FASTPATH) /* close enough */
+ if (DUK_LIKELY(DUK_HOBJECT_IS_ARRAY(h) &&
+ ((duk_harray *) h)->length <= DUK_HOBJECT_GET_ASIZE(h))) {
+ duk_harray *h_arr;
+ duk_tval *tv_src;
+ duk_tval *tv_dst;
+
+ h_arr = (duk_harray *) h;
+ len = h_arr->length;
+ if (DUK_UNLIKELY(len >= 0x80000000UL)) {
+ goto fail_over_2g;
+ }
+ duk_require_stack(thr, (duk_idx_t) len);
+
+ /* The potential allocation in duk_require_stack() may
+ * run a finalizer which modifies the argArray so that
+ * e.g. becomes sparse. So, we need to recheck that the
+ * array didn't change size and that there's still a
+ * valid backing array part.
+ *
+ * XXX: alternatively, could prevent finalizers for the
+ * duration.
+ */
+ if (DUK_UNLIKELY(len != h_arr->length ||
+ h_arr->length > DUK_HOBJECT_GET_ASIZE((duk_hobject *) h_arr))) {
+ goto skip_fast;
+ }
+
+ /* Main fast path: arguments array is almost always
+ * an actual array (though it might also be an arguments
+ * object).
+ */
+
+ DUK_DDD(DUK_DDDPRINT("fast path for %ld elements", (long) h_arr->length));
+ tv_src = DUK_HOBJECT_A_GET_BASE(thr->heap, h);
+ tv_dst = thr->valstack_top;
+ while (len-- > 0) {
+ DUK_ASSERT(tv_dst < thr->valstack_end);
+ if (DUK_UNLIKELY(DUK_TVAL_IS_UNUSED(tv_src))) {
+ /* Gaps are very unlikely. Skip over them,
+ * without an ancestor lookup (technically
+ * not compliant).
+ */
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv_dst)); /* valstack policy */
+ } else {
+ DUK_TVAL_SET_TVAL(tv_dst, tv_src);
+ DUK_TVAL_INCREF(thr, tv_dst);
+ }
+ tv_src++;
+ tv_dst++;
+ }
+ DUK_ASSERT(tv_dst <= thr->valstack_end);
+ thr->valstack_top = tv_dst;
+ return (duk_idx_t) h_arr->length;
+ }
+ skip_fast:
+#endif /* DUK_USE_ARRAY_FASTPATH */
+
+ /* Slow path: actual lookups. The initial 'length' lookup
+ * decides the output length, regardless of side effects that
+ * may resize or change the argArray while we read the
+ * indices.
+ */
+ idx = duk_normalize_index(thr, idx);
+ duk_get_prop_stridx(thr, idx, DUK_STRIDX_LENGTH);
+ len = duk_to_uint32(thr, -1); /* ToUint32() coercion required */
+ if (DUK_UNLIKELY(len >= 0x80000000UL)) {
+ goto fail_over_2g;
+ }
+ duk_pop_unsafe(thr);
+ DUK_DDD(DUK_DDDPRINT("slow path for %ld elements", (long) len));
+
+ duk_require_stack(thr, (duk_idx_t) len);
+ for (i = 0; i < len; i++) {
+ duk_get_prop_index(thr, idx, (duk_uarridx_t) i);
+ }
+ return (duk_idx_t) len;
+ } else if (DUK_TVAL_IS_UNDEFINED(tv) || DUK_TVAL_IS_NULL(tv)) {
+ return 0;
+ }
+
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ return 0;
+
+ fail_over_2g:
+ DUK_ERROR_RANGE_INVALID_LENGTH(thr);
+ return 0;
}
/*
* Error throwing
*/
-DUK_EXTERNAL void duk_throw(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_throw_raw(duk_hthread *thr) {
+ duk_tval *tv_val;
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
- if (thr->valstack_top == thr->valstack_bottom) {
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
+ if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) {
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
}
/* Errors are augmented when they are created, not when they are
@@ -19479,77 +23183,125 @@ DUK_EXTERNAL void duk_throw(duk_context *ctx) {
duk_hthread_sync_and_null_currpc(thr);
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
- DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (before throw augment)", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (before throw augment)", (duk_tval *) duk_get_tval(thr, -1)));
duk_err_augment_error_throw(thr);
#endif
- DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (after throw augment)", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (after throw augment)", (duk_tval *) duk_get_tval(thr, -1)));
- duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW);
+ tv_val = DUK_GET_TVAL_NEGIDX(thr, -1);
+ duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, tv_val);
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ duk_err_check_debugger_integration(thr);
+#endif
/* thr->heap->lj.jmpbuf_ptr is checked by duk_err_longjmp() so we don't
- * need to check that here. If the value is NULL, a panic occurs because
- * we can't return.
+ * need to check that here. If the value is NULL, a fatal error occurs
+ * because we can't return.
*/
duk_err_longjmp(thr);
DUK_UNREACHABLE();
}
-DUK_EXTERNAL void duk_fatal(duk_context *ctx, duk_errcode_t err_code, const char *err_msg) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_fatal_raw(duk_hthread *thr, const char *err_msg) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT(thr->heap->fatal_func != NULL);
- DUK_D(DUK_DPRINT("fatal error occurred, code %ld, message %s",
- (long) err_code, (const char *) err_msg));
+ DUK_D(DUK_DPRINT("fatal error occurred: %s", err_msg ? err_msg : "NULL"));
/* fatal_func should be noreturn, but noreturn declarations on function
* pointers has a very spotty support apparently so it's not currently
* done.
*/
- thr->heap->fatal_func(ctx, err_code, err_msg);
+ thr->heap->fatal_func(thr->heap->heap_udata, err_msg);
- DUK_PANIC(DUK_ERR_API_ERROR, "fatal handler returned");
+ /* If the fatal handler returns, all bets are off. It'd be nice to
+ * print something here but since we don't want to depend on stdio,
+ * there's no way to do so portably.
+ */
+ DUK_D(DUK_DPRINT("fatal error handler returned, all bets are off!"));
+ for (;;) {
+ /* loop forever, don't return (function marked noreturn) */
+ }
}
-DUK_EXTERNAL void duk_error_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_error_va_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
- duk_throw(ctx);
+ duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
+ (void) duk_throw(thr);
}
-DUK_EXTERNAL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) {
+DUK_EXTERNAL void duk_error_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) {
va_list ap;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
va_start(ap, fmt);
- duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
+ duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
va_end(ap);
- duk_throw(ctx);
+ (void) duk_throw(thr);
}
#if !defined(DUK_USE_VARIADIC_MACROS)
-DUK_EXTERNAL void duk_error_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...) {
+DUK_NORETURN(DUK_LOCAL_DECL void duk__throw_error_from_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, va_list ap));
+
+DUK_LOCAL void duk__throw_error_from_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, va_list ap) {
const char *filename;
duk_int_t line;
- va_list ap;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
filename = duk_api_global_filename;
line = duk_api_global_line;
duk_api_global_filename = NULL;
duk_api_global_line = 0;
- va_start(ap, fmt);
- duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
- va_end(ap);
- duk_throw(ctx);
+ duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
+ (void) duk_throw(thr);
+}
+
+#define DUK__ERROR_STASH_SHARED(code) do { \
+ va_list ap; \
+ va_start(ap, fmt); \
+ duk__throw_error_from_stash(thr, (code), fmt, ap); \
+ va_end(ap); \
+ /* Never reached; if return 0 here, gcc/clang will complain. */ \
+ } while (0)
+
+DUK_EXTERNAL duk_ret_t duk_error_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK__ERROR_STASH_SHARED(err_code);
+}
+DUK_EXTERNAL duk_ret_t duk_generic_error_stash(duk_hthread *thr, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK__ERROR_STASH_SHARED(DUK_ERR_ERROR);
+}
+DUK_EXTERNAL duk_ret_t duk_eval_error_stash(duk_hthread *thr, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK__ERROR_STASH_SHARED(DUK_ERR_EVAL_ERROR);
+}
+DUK_EXTERNAL duk_ret_t duk_range_error_stash(duk_hthread *thr, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK__ERROR_STASH_SHARED(DUK_ERR_RANGE_ERROR);
+}
+DUK_EXTERNAL duk_ret_t duk_reference_error_stash(duk_hthread *thr, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK__ERROR_STASH_SHARED(DUK_ERR_REFERENCE_ERROR);
+}
+DUK_EXTERNAL duk_ret_t duk_syntax_error_stash(duk_hthread *thr, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK__ERROR_STASH_SHARED(DUK_ERR_SYNTAX_ERROR);
+}
+DUK_EXTERNAL duk_ret_t duk_type_error_stash(duk_hthread *thr, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK__ERROR_STASH_SHARED(DUK_ERR_TYPE_ERROR);
+}
+DUK_EXTERNAL duk_ret_t duk_uri_error_stash(duk_hthread *thr, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK__ERROR_STASH_SHARED(DUK_ERR_URI_ERROR);
}
#endif /* DUK_USE_VARIADIC_MACROS */
@@ -19557,14 +23309,13 @@ DUK_EXTERNAL void duk_error_stash(duk_context *ctx, duk_errcode_t err_code, cons
* Comparison
*/
-DUK_EXTERNAL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_equals(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
duk_tval *tv1, *tv2;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv1 = duk_get_tval(ctx, index1);
- tv2 = duk_get_tval(ctx, index2);
+ tv1 = duk_get_tval(thr, idx1);
+ tv2 = duk_get_tval(thr, idx2);
if ((tv1 == NULL) || (tv2 == NULL)) {
return 0;
}
@@ -19575,13 +23326,13 @@ DUK_EXTERNAL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t
return duk_js_equals(thr, tv1, tv2);
}
-DUK_EXTERNAL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) {
+DUK_EXTERNAL duk_bool_t duk_strict_equals(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
duk_tval *tv1, *tv2;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv1 = duk_get_tval(ctx, index1);
- tv2 = duk_get_tval(ctx, index2);
+ tv1 = duk_get_tval(thr, idx1);
+ tv2 = duk_get_tval(thr, idx2);
if ((tv1 == NULL) || (tv2 == NULL)) {
return 0;
}
@@ -19590,14 +23341,29 @@ DUK_EXTERNAL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t index1, du
return duk_js_strict_equals(tv1, tv2);
}
+DUK_EXTERNAL duk_bool_t duk_samevalue(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
+ duk_tval *tv1, *tv2;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv1 = duk_get_tval(thr, idx1);
+ tv2 = duk_get_tval(thr, idx2);
+ if ((tv1 == NULL) || (tv2 == NULL)) {
+ return 0;
+ }
+
+ /* No coercions or other side effects, so safe */
+ return duk_js_samevalue(tv1, tv2);
+}
+
/*
* instanceof
*/
-DUK_EXTERNAL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) {
+DUK_EXTERNAL duk_bool_t duk_instanceof(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
duk_tval *tv1, *tv2;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* Index validation is strict, which differs from duk_equals().
* The strict behavior mimics how instanceof itself works, e.g.
@@ -19605,23 +23371,19 @@ DUK_EXTERNAL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t index1, duk_i
* be somewhat inconsistent if rval would be allowed to be
* non-existent without a TypeError.
*/
- tv1 = duk_require_tval(ctx, index1);
+ tv1 = duk_require_tval(thr, idx1);
DUK_ASSERT(tv1 != NULL);
- tv2 = duk_require_tval(ctx, index2);
+ tv2 = duk_require_tval(thr, idx2);
DUK_ASSERT(tv2 != NULL);
- return duk_js_instanceof((duk_hthread *) ctx, tv1, tv2);
+ return duk_js_instanceof(thr, tv1, tv2);
}
/*
* Lightfunc
*/
-DUK_INTERNAL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv) {
- duk_c_function func;
-
- DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv));
-
+DUK_INTERNAL void duk_push_lightfunc_name_raw(duk_hthread *thr, duk_c_function func, duk_small_uint_t lf_flags) {
/* Lightfunc name, includes Duktape/C native function pointer, which
* can often be used to locate the function from a symbol table.
* The name also includes the 16-bit duk_tval flags field because it
@@ -19634,20 +23396,37 @@ DUK_INTERNAL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv) {
* is accessed).
*/
- func = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv);
- duk_push_sprintf(ctx, "light_");
- duk_push_string_funcptr(ctx, (duk_uint8_t *) &func, sizeof(func));
- duk_push_sprintf(ctx, "_%04x", (unsigned int) DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv));
- duk_concat(ctx, 3);
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_push_sprintf(thr, "light_");
+ duk_push_string_funcptr(thr, (duk_uint8_t *) &func, sizeof(func));
+ duk_push_sprintf(thr, "_%04x", (unsigned int) lf_flags);
+ duk_concat(thr, 3);
}
-DUK_INTERNAL void duk_push_lightfunc_tostring(duk_context *ctx, duk_tval *tv) {
+DUK_INTERNAL void duk_push_lightfunc_name(duk_hthread *thr, duk_tval *tv) {
+ duk_c_function func;
+ duk_small_uint_t lf_flags;
+
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv));
- duk_push_string(ctx, "function ");
- duk_push_lightfunc_name(ctx, tv);
- duk_push_string(ctx, "() {\"light\"}");
- duk_concat(ctx, 3);
+ DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
+ duk_push_lightfunc_name_raw(thr, func, lf_flags);
+}
+
+DUK_INTERNAL void duk_push_lightfunc_tostring(duk_hthread *thr, duk_tval *tv) {
+ duk_c_function func;
+ duk_small_uint_t lf_flags;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv));
+
+ DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags); /* read before 'tv' potentially invalidated */
+ duk_push_string(thr, "function ");
+ duk_push_lightfunc_name_raw(thr, func, lf_flags);
+ duk_push_string(thr, "() { [lightfunc code] }");
+ duk_concat(thr, 3);
}
/*
@@ -19657,12 +23436,13 @@ DUK_INTERNAL void duk_push_lightfunc_tostring(duk_context *ctx, duk_tval *tv) {
* bytes from memory.
*/
-DUK_INTERNAL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, duk_size_t sz) {
+DUK_INTERNAL void duk_push_string_funcptr(duk_hthread *thr, duk_uint8_t *ptr, duk_size_t sz) {
duk_uint8_t buf[32 * 2];
duk_uint8_t *p, *q;
duk_small_uint_t i;
duk_small_uint_t t;
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(sz <= 32); /* sanity limit for function pointer size */
p = buf;
@@ -19681,10 +23461,9 @@ DUK_INTERNAL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, du
*p++ = duk_lc_digits[t & 0x0f];
}
- duk_push_lstring(ctx, (const char *) buf, sz * 2);
+ duk_push_lstring(thr, (const char *) buf, sz * 2);
}
-#if !defined(DUK_USE_PARANOID_ERRORS)
/*
* Push readable string summarizing duk_tval. The operation is side effect
* free and will only throw from internal errors (e.g. out of memory).
@@ -19692,25 +23471,27 @@ DUK_INTERNAL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, du
* and is not intended to be fast (but small and safe).
*/
-#define DUK__READABLE_STRING_MAXCHARS 32
+/* String limits for summary strings. */
+#define DUK__READABLE_SUMMARY_MAXCHARS 96 /* maximum supported by helper */
+#define DUK__READABLE_STRING_MAXCHARS 32 /* for strings/symbols */
+#define DUK__READABLE_ERRMSG_MAXCHARS 96 /* for error messages */
/* String sanitizer which escapes ASCII control characters and a few other
* ASCII characters, passes Unicode as is, and replaces invalid UTF-8 with
* question marks. No errors are thrown for any input string, except in out
* of memory situations.
*/
-DUK_LOCAL void duk__push_hstring_readable_unicode(duk_context *ctx, duk_hstring *h_input) {
- duk_hthread *thr;
+DUK_LOCAL void duk__push_hstring_readable_unicode(duk_hthread *thr, duk_hstring *h_input, duk_small_uint_t maxchars) {
const duk_uint8_t *p, *p_start, *p_end;
- duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH * DUK__READABLE_STRING_MAXCHARS +
+ duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH * DUK__READABLE_SUMMARY_MAXCHARS +
2 /*quotes*/ + 3 /*periods*/];
duk_uint8_t *q;
duk_ucodepoint_t cp;
duk_small_uint_t nchars;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
DUK_ASSERT(h_input != NULL);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT(maxchars <= DUK__READABLE_SUMMARY_MAXCHARS);
p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
@@ -19723,7 +23504,7 @@ DUK_LOCAL void duk__push_hstring_readable_unicode(duk_context *ctx, duk_hstring
if (p >= p_end) {
break;
}
- if (nchars == DUK__READABLE_STRING_MAXCHARS) {
+ if (nchars == maxchars) {
*q++ = (duk_uint8_t) DUK_ASC_PERIOD;
*q++ = (duk_uint8_t) DUK_ASC_PERIOD;
*q++ = (duk_uint8_t) DUK_ASC_PERIOD;
@@ -19748,74 +23529,189 @@ DUK_LOCAL void duk__push_hstring_readable_unicode(duk_context *ctx, duk_hstring
}
*q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE;
- duk_push_lstring(ctx, (const char *) buf, (duk_size_t) (q - buf));
+ duk_push_lstring(thr, (const char *) buf, (duk_size_t) (q - buf));
}
-DUK_INTERNAL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tval *tv) {
- duk_hthread *thr;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
+DUK_LOCAL const char *duk__push_string_tval_readable(duk_hthread *thr, duk_tval *tv, duk_bool_t error_aware) {
+ DUK_ASSERT_CTX_VALID(thr);
+ /* 'tv' may be NULL */
if (tv == NULL) {
- duk_push_string(ctx, "none");
+ duk_push_string(thr, "none");
} else {
switch (DUK_TVAL_GET_TAG(tv)) {
case DUK_TAG_STRING: {
- duk__push_hstring_readable_unicode(ctx, DUK_TVAL_GET_STRING(tv));
+ duk_hstring *h = DUK_TVAL_GET_STRING(tv);
+ if (DUK_HSTRING_HAS_SYMBOL(h)) {
+ /* XXX: string summary produces question marks
+ * so this is not very ideal.
+ */
+ duk_push_string(thr, "[Symbol ");
+ duk_push_string(thr, duk__get_symbol_type_string(h));
+ duk_push_string(thr, " ");
+ duk__push_hstring_readable_unicode(thr, h, DUK__READABLE_STRING_MAXCHARS);
+ duk_push_string(thr, "]");
+ duk_concat(thr, 5);
+ break;
+ }
+ duk__push_hstring_readable_unicode(thr, h, DUK__READABLE_STRING_MAXCHARS);
break;
}
case DUK_TAG_OBJECT: {
duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
- duk_push_hobject_class_string(ctx, h);
+
+ if (error_aware &&
+ duk_hobject_prototype_chain_contains(thr, h, thr->builtins[DUK_BIDX_ERROR_PROTOTYPE], 1 /*ignore_loop*/)) {
+ /* Get error message in a side effect free way if
+ * possible; if not, summarize as a generic object.
+ * Error message currently gets quoted.
+ */
+ /* XXX: better internal getprop call; get without side effects
+ * but traverse inheritance chain.
+ */
+ duk_tval *tv_msg;
+ tv_msg = duk_hobject_find_existing_entry_tval_ptr(thr->heap, h, DUK_HTHREAD_STRING_MESSAGE(thr));
+ if (tv_msg != NULL && DUK_TVAL_IS_STRING(tv_msg)) {
+ /* It's critical to avoid recursion so
+ * only summarize a string .message.
+ */
+ duk__push_hstring_readable_unicode(thr, DUK_TVAL_GET_STRING(tv_msg), DUK__READABLE_ERRMSG_MAXCHARS);
+ break;
+ }
+ }
+ duk_push_class_string_tval(thr, tv);
break;
}
case DUK_TAG_BUFFER: {
+ /* While plain buffers mimic Uint8Arrays, they summarize differently.
+ * This is useful so that the summarized string accurately reflects the
+ * internal type which may matter for figuring out bugs etc.
+ */
/* XXX: Hex encoded, length limited buffer summary here? */
duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
DUK_ASSERT(h != NULL);
- duk_push_sprintf(ctx, "[buffer:%ld]", (long) DUK_HBUFFER_GET_SIZE(h));
+ duk_push_sprintf(thr, "[buffer:%ld]", (long) DUK_HBUFFER_GET_SIZE(h));
break;
}
case DUK_TAG_POINTER: {
/* Surround with parentheses like in JX, ensures NULL pointer
* is distinguishable from null value ("(null)" vs "null").
*/
- duk_push_tval(ctx, tv);
- duk_push_sprintf(ctx, "(%s)", duk_to_string(ctx, -1));
- duk_remove(ctx, -2);
+ duk_push_tval(thr, tv);
+ duk_push_sprintf(thr, "(%s)", duk_to_string(thr, -1));
+ duk_remove_m2(thr);
break;
}
default: {
- duk_push_tval(ctx, tv);
+ duk_push_tval(thr, tv);
break;
}
}
}
- return duk_to_string(ctx, -1);
+ return duk_to_string(thr, -1);
+}
+DUK_INTERNAL const char *duk_push_string_tval_readable(duk_hthread *thr, duk_tval *tv) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__push_string_tval_readable(thr, tv, 0 /*error_aware*/);
}
-DUK_INTERNAL const char *duk_push_string_readable(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk_push_string_tval_readable(ctx, duk_get_tval(ctx, index));
+DUK_INTERNAL const char *duk_push_string_readable(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_push_string_tval_readable(thr, duk_get_tval(thr, idx));
}
-#endif /* !DUK_USE_PARANOID_ERRORS */
+DUK_INTERNAL const char *duk_push_string_tval_readable_error(duk_hthread *thr, duk_tval *tv) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__push_string_tval_readable(thr, tv, 1 /*error_aware*/);
+}
+
+DUK_INTERNAL void duk_push_symbol_descriptive_string(duk_hthread *thr, duk_hstring *h) {
+ const duk_uint8_t *p;
+ const duk_uint8_t *p_end;
+ const duk_uint8_t *q;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ /* .toString() */
+ duk_push_string(thr, "Symbol(");
+ p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
+ p_end = p + DUK_HSTRING_GET_BYTELEN(h);
+ DUK_ASSERT(p[0] == 0xff || (p[0] & 0xc0) == 0x80);
+ p++;
+ for (q = p; q < p_end; q++) {
+ if (*q == 0xffU) {
+ /* Terminate either at end-of-string (but NUL MUST
+ * be accepted without terminating description) or
+ * 0xFF, which is used to mark start of unique trailer
+ * (and cannot occur in CESU-8 / extended UTF-8).
+ */
+ break;
+ }
+ }
+ duk_push_lstring(thr, (const char *) p, (duk_size_t) (q - p));
+ duk_push_string(thr, ")");
+ duk_concat(thr, 3);
+}
+
+/*
+ * Functions
+ */
+
+#if 0 /* not used yet */
+DUK_INTERNAL void duk_push_hnatfunc_name(duk_hthread *thr, duk_hnatfunc *h) {
+ duk_c_function func;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(h != NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h));
+
+ duk_push_sprintf(thr, "native_");
+ func = h->func;
+ duk_push_string_funcptr(thr, (duk_uint8_t *) &func, sizeof(func));
+ duk_push_sprintf(thr, "_%04x_%04x",
+ (unsigned int) (duk_uint16_t) h->nargs,
+ (unsigned int) (duk_uint16_t) h->magic);
+ duk_concat(thr, 3);
+}
+#endif
+
+/*
+ * duk_tval slice copy
+ */
+
+DUK_INTERNAL void duk_copy_tvals_incref(duk_hthread *thr, duk_tval *tv_dst, duk_tval *tv_src, duk_size_t count) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(thr);
+ DUK_ASSERT(count * sizeof(duk_tval) >= count); /* no wrap */
+ DUK_MEMCPY((void *) tv_dst, (const void *) tv_src, count * sizeof(duk_tval));
+
+ tv = tv_dst;
+ while (count-- > 0) {
+ DUK_TVAL_INCREF(thr, tv);
+ tv++;
+ }
+}
+
+/* automatic undefs */
+#undef DUK__ASSERT_SPACE
#undef DUK__CHECK_SPACE
+#undef DUK__ERROR_STASH_SHARED
#undef DUK__PACK_ARGS
+#undef DUK__READABLE_ERRMSG_MAXCHARS
#undef DUK__READABLE_STRING_MAXCHARS
+#undef DUK__READABLE_SUMMARY_MAXCHARS
#line 1 "duk_api_string.c"
/*
* String manipulation
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in, duk_bool_t is_join) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL void duk__concat_and_join_helper(duk_hthread *thr, duk_idx_t count_in, duk_bool_t is_join) {
duk_uint_t count;
duk_uint_t i;
duk_size_t idx;
@@ -19823,22 +23719,22 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in,
duk_hstring *h;
duk_uint8_t *buf;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
if (DUK_UNLIKELY(count_in <= 0)) {
if (count_in < 0) {
- DUK_ERROR_API(thr, DUK_STR_INVALID_COUNT);
+ DUK_ERROR_RANGE_INVALID_COUNT(thr);
return;
}
DUK_ASSERT(count_in == 0);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
+ duk_push_hstring_empty(thr);
return;
}
count = (duk_uint_t) count_in;
if (is_join) {
duk_size_t t1, t2, limit;
- h = duk_to_hstring(ctx, -((duk_idx_t) count) - 1);
+ h = duk_to_hstring(thr, -((duk_idx_t) count) - 1);
DUK_ASSERT(h != NULL);
/* A bit tricky overflow test, see doc/code-issues.rst. */
@@ -19846,7 +23742,7 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in,
t2 = (duk_size_t) (count - 1);
limit = (duk_size_t) DUK_HSTRING_MAX_BYTELEN;
if (DUK_UNLIKELY(t2 != 0 && t1 > limit / t2)) {
- /* Combined size of separators already overflows */
+ /* Combined size of separators already overflows. */
goto error_overflow;
}
len = (duk_size_t) (t1 * t2);
@@ -19856,8 +23752,7 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in,
for (i = count; i >= 1; i--) {
duk_size_t new_len;
- duk_to_string(ctx, -((duk_idx_t) i));
- h = duk_require_hstring(ctx, -((duk_idx_t) i));
+ h = duk_to_hstring(thr, -((duk_idx_t) i));
new_len = len + (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
/* Impose a string maximum length, need to handle overflow
@@ -19873,74 +23768,119 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in,
DUK_DDD(DUK_DDDPRINT("join/concat %lu strings, total length %lu bytes",
(unsigned long) count, (unsigned long) len));
- /* use stack allocated buffer to ensure reachability in errors (e.g. intern error) */
- buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, len);
+ /* Use stack allocated buffer to ensure reachability in errors
+ * (e.g. intern error).
+ */
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len);
DUK_ASSERT(buf != NULL);
- /* [... (sep) str1 str2 ... strN buf] */
+ /* [ ... (sep) str1 str2 ... strN buf ] */
idx = 0;
for (i = count; i >= 1; i--) {
if (is_join && i != count) {
- h = duk_require_hstring(ctx, -((duk_idx_t) count) - 2); /* extra -1 for buffer */
+ h = duk_require_hstring(thr, -((duk_idx_t) count) - 2); /* extra -1 for buffer */
DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
idx += DUK_HSTRING_GET_BYTELEN(h);
}
- h = duk_require_hstring(ctx, -((duk_idx_t) i) - 1); /* extra -1 for buffer */
+ h = duk_require_hstring(thr, -((duk_idx_t) i) - 1); /* extra -1 for buffer */
DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
idx += DUK_HSTRING_GET_BYTELEN(h);
}
DUK_ASSERT(idx == len);
- /* [... (sep) str1 str2 ... strN buf] */
+ /* [ ... (sep) str1 str2 ... strN buf ] */
- /* get rid of the strings early to minimize memory use before intern */
+ /* Get rid of the strings early to minimize memory use before intern. */
if (is_join) {
- duk_replace(ctx, -((duk_idx_t) count) - 2); /* overwrite sep */
- duk_pop_n(ctx, count);
+ duk_replace(thr, -((duk_idx_t) count) - 2); /* overwrite sep */
+ duk_pop_n(thr, (duk_idx_t) count);
} else {
- duk_replace(ctx, -((duk_idx_t) count) - 1); /* overwrite str1 */
- duk_pop_n(ctx, count-1);
+ duk_replace(thr, -((duk_idx_t) count) - 1); /* overwrite str1 */
+ duk_pop_n(thr, (duk_idx_t) (count - 1));
}
- /* [... buf] */
+ /* [ ... buf ] */
- (void) duk_to_string(ctx, -1);
+ (void) duk_buffer_to_string(thr, -1); /* Safe if inputs are safe. */
- /* [... res] */
+ /* [ ... res ] */
return;
error_overflow:
- DUK_ERROR_RANGE(thr, DUK_STR_CONCAT_RESULT_TOO_LONG);
+ DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG);
}
-DUK_EXTERNAL void duk_concat(duk_context *ctx, duk_idx_t count) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_concat(duk_hthread *thr, duk_idx_t count) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk__concat_and_join_helper(ctx, count, 0 /*is_join*/);
+ duk__concat_and_join_helper(thr, count, 0 /*is_join*/);
}
-DUK_EXTERNAL void duk_join(duk_context *ctx, duk_idx_t count) {
- DUK_ASSERT_CTX_VALID(ctx);
+#if defined(DUK_USE_PREFER_SIZE)
+DUK_INTERNAL void duk_concat_2(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_concat(thr, 2);
+}
+#else /* DUK_USE_PREFER_SIZE */
+DUK_INTERNAL void duk_concat_2(duk_hthread *thr) {
+ duk_hstring *h1;
+ duk_hstring *h2;
+ duk_uint8_t *buf;
+ duk_size_t len1;
+ duk_size_t len2;
+ duk_size_t len;
- duk__concat_and_join_helper(ctx, count, 1 /*is_join*/);
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(duk_get_top(thr) >= 2); /* Trusted caller. */
+
+ h1 = duk_to_hstring(thr, -2);
+ h2 = duk_to_hstring(thr, -1);
+ len1 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1);
+ len2 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2);
+ len = len1 + len2;
+ if (DUK_UNLIKELY(len < len1 || /* wrapped */
+ len > (duk_size_t) DUK_HSTRING_MAX_BYTELEN)) {
+ goto error_overflow;
+ }
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len);
+ DUK_ASSERT(buf != NULL);
+
+ DUK_MEMCPY((void *) buf, (const void *) DUK_HSTRING_GET_DATA(h1), (size_t) len1);
+ DUK_MEMCPY((void *) (buf + len1), (const void *) DUK_HSTRING_GET_DATA(h2), (size_t) len2);
+ (void) duk_buffer_to_string(thr, -1); /* Safe if inputs are safe. */
+
+ /* [ ... str1 str2 buf ] */
+
+ duk_replace(thr, -3);
+ duk_pop_unsafe(thr);
+ return;
+
+ error_overflow:
+ DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG);
+}
+#endif /* DUK_USE_PREFER_SIZE */
+
+DUK_EXTERNAL void duk_join(duk_hthread *thr, duk_idx_t count) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk__concat_and_join_helper(thr, count, 1 /*is_join*/);
}
/* XXX: could map/decode be unified with duk_unicode_support.c code?
* Case conversion needs also the character surroundings though.
*/
-DUK_EXTERNAL void duk_decode_string(duk_context *ctx, duk_idx_t index, duk_decode_char_function callback, void *udata) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_decode_string(duk_hthread *thr, duk_idx_t idx, duk_decode_char_function callback, void *udata) {
duk_hstring *h_input;
const duk_uint8_t *p, *p_start, *p_end;
duk_codepoint_t cp;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- h_input = duk_require_hstring(ctx, index);
+ h_input = duk_require_hstring(thr, idx); /* Accept symbols. */
DUK_ASSERT(h_input != NULL);
p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
@@ -19951,28 +23891,27 @@ DUK_EXTERNAL void duk_decode_string(duk_context *ctx, duk_idx_t index, duk_decod
if (p >= p_end) {
break;
}
- cp = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
+ cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
callback(udata, cp);
}
}
-DUK_EXTERNAL void duk_map_string(duk_context *ctx, duk_idx_t index, duk_map_char_function callback, void *udata) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_map_string(duk_hthread *thr, duk_idx_t idx, duk_map_char_function callback, void *udata) {
duk_hstring *h_input;
duk_bufwriter_ctx bw_alloc;
duk_bufwriter_ctx *bw;
const duk_uint8_t *p, *p_start, *p_end;
duk_codepoint_t cp;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- index = duk_normalize_index(ctx, index);
+ idx = duk_normalize_index(thr, idx);
- h_input = duk_require_hstring(ctx, index);
+ h_input = duk_require_hstring(thr, idx); /* Accept symbols. */
DUK_ASSERT(h_input != NULL);
bw = &bw_alloc;
- DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* reasonable output estimate */
+ DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* Reasonable output estimate. */
p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
@@ -19986,32 +23925,33 @@ DUK_EXTERNAL void duk_map_string(duk_context *ctx, duk_idx_t index, duk_map_char
if (p >= p_end) {
break;
}
- cp = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
+ cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
cp = callback(udata, cp);
DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp);
}
DUK_BW_COMPACT(thr, bw);
- duk_to_string(ctx, -1);
- duk_replace(ctx, index);
+ (void) duk_buffer_to_string(thr, -1); /* Safe, extended UTF-8 encoded. */
+ duk_replace(thr, idx);
}
-DUK_EXTERNAL void duk_substring(duk_context *ctx, duk_idx_t index, duk_size_t start_offset, duk_size_t end_offset) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_substring(duk_hthread *thr, duk_idx_t idx, duk_size_t start_offset, duk_size_t end_offset) {
duk_hstring *h;
duk_hstring *res;
duk_size_t start_byte_offset;
duk_size_t end_byte_offset;
+ duk_size_t charlen;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- index = duk_require_normalize_index(ctx, index);
- h = duk_require_hstring(ctx, index);
+ idx = duk_require_normalize_index(thr, idx); /* Accept symbols. */
+ h = duk_require_hstring(thr, idx);
DUK_ASSERT(h != NULL);
- if (end_offset >= DUK_HSTRING_GET_CHARLEN(h)) {
- end_offset = DUK_HSTRING_GET_CHARLEN(h);
+ charlen = DUK_HSTRING_GET_CHARLEN(h);
+ if (end_offset >= charlen) {
+ end_offset = charlen;
}
if (start_offset > end_offset) {
start_offset = end_offset;
@@ -20022,7 +23962,7 @@ DUK_EXTERNAL void duk_substring(duk_context *ctx, duk_idx_t index, duk_size_t st
DUK_ASSERT_DISABLE(end_offset >= 0);
DUK_ASSERT(end_offset >= start_offset && end_offset <= DUK_HSTRING_GET_CHARLEN(h));
- /* guaranteed by string limits */
+ /* Guaranteed by string limits. */
DUK_ASSERT(start_offset <= DUK_UINT32_MAX);
DUK_ASSERT(end_offset <= DUK_UINT32_MAX);
@@ -20030,31 +23970,30 @@ DUK_EXTERNAL void duk_substring(duk_context *ctx, duk_idx_t index, duk_size_t st
end_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) end_offset);
DUK_ASSERT(end_byte_offset >= start_byte_offset);
- DUK_ASSERT(end_byte_offset - start_byte_offset <= DUK_UINT32_MAX); /* guaranteed by string limits */
+ DUK_ASSERT(end_byte_offset - start_byte_offset <= DUK_UINT32_MAX); /* Guaranteed by string limits. */
- /* no size check is necessary */
- res = duk_heap_string_intern_checked(thr,
- DUK_HSTRING_GET_DATA(h) + start_byte_offset,
- (duk_uint32_t) (end_byte_offset - start_byte_offset));
+ /* No size check is necessary. */
+ res = duk_heap_strtable_intern_checked(thr,
+ DUK_HSTRING_GET_DATA(h) + start_byte_offset,
+ (duk_uint32_t) (end_byte_offset - start_byte_offset));
- duk_push_hstring(ctx, res);
- duk_replace(ctx, index);
+ duk_push_hstring(thr, res);
+ duk_replace(thr, idx);
}
/* XXX: this is quite clunky. Add Unicode helpers to scan backwards and
* forwards with a callback to process codepoints?
*/
-DUK_EXTERNAL void duk_trim(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_trim(duk_hthread *thr, duk_idx_t idx) {
duk_hstring *h;
const duk_uint8_t *p, *p_start, *p_end, *p_tmp1, *p_tmp2; /* pointers for scanning */
const duk_uint8_t *q_start, *q_end; /* start (incl) and end (excl) of trimmed part */
duk_codepoint_t cp;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- index = duk_require_normalize_index(ctx, index);
- h = duk_require_hstring(ctx, index);
+ idx = duk_require_normalize_index(thr, idx); /* Accept symbols. */
+ h = duk_require_hstring(thr, idx);
DUK_ASSERT(h != NULL);
p_start = DUK_HSTRING_GET_DATA(h);
@@ -20071,7 +24010,7 @@ DUK_EXTERNAL void duk_trim(duk_context *ctx, duk_idx_t index) {
}
q_start = p;
if (p == p_end) {
- /* entire string is whitespace */
+ /* Entire string is whitespace. */
q_end = p;
goto scan_done;
}
@@ -20116,124 +24055,154 @@ DUK_EXTERNAL void duk_trim(duk_context *ctx, duk_idx_t index) {
return;
}
- duk_push_lstring(ctx, (const char *) q_start, (duk_size_t) (q_end - q_start));
- duk_replace(ctx, index);
+ duk_push_lstring(thr, (const char *) q_start, (duk_size_t) (q_end - q_start));
+ duk_replace(thr, idx);
}
-DUK_EXTERNAL duk_codepoint_t duk_char_code_at(duk_context *ctx, duk_idx_t index, duk_size_t char_offset) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_codepoint_t duk_char_code_at(duk_hthread *thr, duk_idx_t idx, duk_size_t char_offset) {
duk_hstring *h;
duk_ucodepoint_t cp;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- h = duk_require_hstring(ctx, index);
+ /* XXX: Share code with String.prototype.charCodeAt? Main difference
+ * is handling of clamped offsets.
+ */
+
+ h = duk_require_hstring(thr, idx); /* Accept symbols. */
DUK_ASSERT(h != NULL);
- DUK_ASSERT_DISABLE(char_offset >= 0); /* always true, arg is unsigned */
+ DUK_ASSERT_DISABLE(char_offset >= 0); /* Always true, arg is unsigned. */
if (char_offset >= DUK_HSTRING_GET_CHARLEN(h)) {
return 0;
}
- DUK_ASSERT(char_offset <= DUK_UINT_MAX); /* guaranteed by string limits */
- cp = duk_hstring_char_code_at_raw(thr, h, (duk_uint_t) char_offset);
+ DUK_ASSERT(char_offset <= DUK_UINT_MAX); /* Guaranteed by string limits. */
+ cp = duk_hstring_char_code_at_raw(thr, h, (duk_uint_t) char_offset, 0 /*surrogate_aware*/);
return (duk_codepoint_t) cp;
}
-#line 1 "duk_api_var.c"
+#line 1 "duk_api_time.c"
/*
- * Variable access
+ * Date/time.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-DUK_EXTERNAL void duk_get_var(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_activation *act;
- duk_hstring *h_varname;
- duk_small_int_t throw_flag = 1; /* always throw ReferenceError for unresolvable */
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- h_varname = duk_require_hstring(ctx, -1); /* XXX: tostring? */
- DUK_ASSERT(h_varname != NULL);
-
- act = duk_hthread_get_current_activation(thr);
- if (act) {
- (void) duk_js_getvar_activation(thr, act, h_varname, throw_flag); /* -> [ ... varname val this ] */
- } else {
- /* Outside any activation -> look up from global. */
- DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL);
- (void) duk_js_getvar_envrec(thr, thr->builtins[DUK_BIDX_GLOBAL_ENV], h_varname, throw_flag);
- }
-
- /* [ ... varname val this ] (because throw_flag == 1, always resolved) */
-
- duk_pop(ctx);
- duk_remove(ctx, -2);
-
- /* [ ... val ] */
-
- /* Return value would be pointless: because throw_flag==1, we always
- * throw if the identifier doesn't resolve.
+DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr) {
+ /* Ecmascript time, with millisecond fractions. Exposed via
+ * duk_get_now() for example.
*/
- return;
+ DUK_UNREF(thr);
+ return (duk_double_t) DUK_USE_DATE_GET_NOW(thr);
}
-DUK_EXTERNAL void duk_put_var(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_activation *act;
- duk_hstring *h_varname;
- duk_tval *tv_val;
- duk_small_int_t throw_flag;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- h_varname = duk_require_hstring(ctx, -2); /* XXX: tostring? */
- DUK_ASSERT(h_varname != NULL);
-
- tv_val = duk_require_tval(ctx, -1);
-
- throw_flag = duk_is_strict_call(ctx);
-
- act = duk_hthread_get_current_activation(thr);
- if (act) {
- duk_js_putvar_activation(thr, act, h_varname, tv_val, throw_flag); /* -> [ ... varname val this ] */
- } else {
- /* Outside any activation -> put to global. */
- DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL);
- duk_js_putvar_envrec(thr, thr->builtins[DUK_BIDX_GLOBAL_ENV], h_varname, tv_val, throw_flag);
- }
-
- /* [ ... varname val ] */
-
- duk_pop_2(ctx);
-
- /* [ ... ] */
-
- return;
+DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time_nofrac(duk_hthread *thr) {
+ /* Ecmascript time without millisecond fractions. Exposed via
+ * the Date built-in which doesn't allow fractions.
+ */
+ DUK_UNREF(thr);
+ return (duk_double_t) DUK_FLOOR(DUK_USE_DATE_GET_NOW(thr));
}
-DUK_EXTERNAL duk_bool_t duk_del_var(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- DUK_ERROR_UNIMPLEMENTED_DEFMSG((duk_hthread *) ctx);
- return 0;
+DUK_INTERNAL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr) {
+ DUK_UNREF(thr);
+#if defined(DUK_USE_GET_MONOTONIC_TIME)
+ return (duk_double_t) DUK_USE_GET_MONOTONIC_TIME(thr);
+#else
+ return (duk_double_t) DUK_USE_DATE_GET_NOW(thr);
+#endif
}
-DUK_EXTERNAL duk_bool_t duk_has_var(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_double_t duk_get_now(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(thr);
- DUK_ERROR_UNIMPLEMENTED_DEFMSG((duk_hthread *) ctx);
- return 0;
+ /* This API intentionally allows millisecond fractions. */
+ return duk_time_get_ecmascript_time(thr);
+}
+
+#if 0 /* XXX: worth exposing? */
+DUK_EXTERNAL duk_double_t duk_get_monotonic_time(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(thr);
+
+ return duk_time_get_monotonic_time(thr);
+}
+#endif
+
+DUK_EXTERNAL void duk_time_to_components(duk_hthread *thr, duk_double_t timeval, duk_time_components *comp) {
+ duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
+ duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
+ duk_uint_t flags;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(comp != NULL); /* XXX: or check? */
+ DUK_UNREF(thr);
+
+ /* Convert as one-based, but change month to zero-based to match the
+ * Ecmascript Date built-in behavior 1:1.
+ */
+ flags = DUK_DATE_FLAG_ONEBASED | DUK_DATE_FLAG_NAN_TO_ZERO;
+
+ duk_bi_date_timeval_to_parts(timeval, parts, dparts, flags);
+
+ /* XXX: sub-millisecond accuracy for the API */
+
+ DUK_ASSERT(dparts[DUK_DATE_IDX_MONTH] >= 1.0 && dparts[DUK_DATE_IDX_MONTH] <= 12.0);
+ comp->year = dparts[DUK_DATE_IDX_YEAR];
+ comp->month = dparts[DUK_DATE_IDX_MONTH] - 1.0;
+ comp->day = dparts[DUK_DATE_IDX_DAY];
+ comp->hours = dparts[DUK_DATE_IDX_HOUR];
+ comp->minutes = dparts[DUK_DATE_IDX_MINUTE];
+ comp->seconds = dparts[DUK_DATE_IDX_SECOND];
+ comp->milliseconds = dparts[DUK_DATE_IDX_MILLISECOND];
+ comp->weekday = dparts[DUK_DATE_IDX_WEEKDAY];
+}
+
+DUK_EXTERNAL duk_double_t duk_components_to_time(duk_hthread *thr, duk_time_components *comp) {
+ duk_double_t d;
+ duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
+ duk_uint_t flags;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(comp != NULL); /* XXX: or check? */
+ DUK_UNREF(thr);
+
+ /* Match Date constructor behavior (with UTC time). Month is given
+ * as zero-based. Day-of-month is given as one-based so normalize
+ * it to zero-based as the internal conversion helpers expects all
+ * components to be zero-based.
+ */
+ flags = 0;
+
+ /* XXX: expensive conversion; use array format in API instead, or unify
+ * time provider and time API to use same struct?
+ */
+
+ dparts[DUK_DATE_IDX_YEAR] = comp->year;
+ dparts[DUK_DATE_IDX_MONTH] = comp->month;
+ dparts[DUK_DATE_IDX_DAY] = comp->day - 1.0;
+ dparts[DUK_DATE_IDX_HOUR] = comp->hours;
+ dparts[DUK_DATE_IDX_MINUTE] = comp->minutes;
+ dparts[DUK_DATE_IDX_SECOND] = comp->seconds;
+ dparts[DUK_DATE_IDX_MILLISECOND] = comp->milliseconds;
+ dparts[DUK_DATE_IDX_WEEKDAY] = 0; /* ignored */
+
+ d = duk_bi_date_get_timeval_from_dparts(dparts, flags);
+
+ return d;
}
#line 1 "duk_bi_array.c"
/*
* Array built-ins
*
- * Note that most Array built-ins are intentionally generic and work even
- * when the 'this' binding is not an Array instance. To ensure this,
- * Array algorithms do not assume "magical" Array behavior for the "length"
- * property, for instance.
+ * Most Array built-ins are intentionally generic in Ecmascript, and are
+ * intended to work even when the 'this' binding is not an Array instance.
+ * This Ecmascript feature is also used by much real world code. For this
+ * reason the implementations here don't assume exotic Array behavior or
+ * e.g. presence of a .length property. However, some algorithms have a
+ * fast path for duk_harray backed actual Array instances, enabled when
+ * footprint is not a concern.
*
* XXX: the "Throw" flag should be set for (almost?) all [[Put]] and
* [[Delete]] operations, but it's currently false throughout. Go through
@@ -20246,7 +24215,6 @@ DUK_EXTERNAL duk_bool_t duk_has_var(duk_context *ctx) {
* the unsigned 32-bit range (E5.1 Section 15.4.5.1 throws a RangeError if so)
* some intermediate values may be above 0xffffffff and this may not be always
* correctly handled now (duk_uint32_t is not enough for all algorithms).
- *
* For instance, push() can legitimately write entries beyond length 0xffffffff
* and cause a RangeError only at the end. To do this properly, the current
* push() implementation tracks the array index using a 'double' instead of a
@@ -20263,86 +24231,139 @@ DUK_EXTERNAL duk_bool_t duk_has_var(duk_context *ctx) {
* Both "put" and "define" are used in the E5.1 specification; as a rule,
* "put" is used when modifying an existing array (or a non-array 'this'
* binding) and "define" for setting values into a fresh result array.
- *
- * Also note that Array instance 'length' should be writable, but not
- * enumerable and definitely not configurable: even Duktape code internally
- * assumes that an Array instance will always have a 'length' property.
- * Preventing deletion of the property is critical.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/* Perform an intermediate join when this many elements have been pushed
* on the value stack.
*/
#define DUK__ARRAY_MID_JOIN_LIMIT 4096
-/* Shared entry code for many Array built-ins. Note that length is left
- * on stack (it could be popped, but that's not necessary).
+#if defined(DUK_USE_ARRAY_BUILTIN)
+
+/*
+ * Shared helpers.
*/
-DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32(duk_context *ctx) {
+
+/* Shared entry code for many Array built-ins: the 'this' binding is pushed
+ * on the value stack and object coerced, and the current .length is returned.
+ * Note that length is left on stack (it could be popped, but that's not
+ * usually necessary because call handling will clean it up automatically).
+ */
+DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32(duk_hthread *thr) {
duk_uint32_t len;
- (void) duk_push_this_coercible_to_object(ctx);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH);
- len = duk_to_uint32(ctx, -1);
+ /* XXX: push more directly? */
+ (void) duk_push_this_coercible_to_object(thr);
+ DUK_ASSERT_HOBJECT_VALID(duk_get_hobject(thr, -1));
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_LENGTH);
+ len = duk_to_uint32(thr, -1);
/* -> [ ... ToObject(this) ToUint32(length) ] */
return len;
}
-DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32_limited(duk_context *ctx) {
+DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32_limited(duk_hthread *thr) {
/* Range limited to [0, 0x7fffffff] range, i.e. range that can be
* represented with duk_int32_t. Use this when the method doesn't
* handle the full 32-bit unsigned range correctly.
*/
- duk_uint32_t ret = duk__push_this_obj_len_u32(ctx);
+ duk_uint32_t ret = duk__push_this_obj_len_u32(thr);
if (DUK_UNLIKELY(ret >= 0x80000000UL)) {
- DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_ARRAY_LENGTH_OVER_2G);
+ DUK_ERROR_RANGE_INVALID_LENGTH(thr);
}
return ret;
}
+#if defined(DUK_USE_ARRAY_FASTPATH)
+/* Check if 'this' binding is an Array instance (duk_harray) which satisfies
+ * a few other guarantees for fast path operation. The fast path doesn't
+ * need to handle all operations, even for duk_harrays, but must handle a
+ * significant fraction to improve performance. Return a non-NULL duk_harray
+ * pointer when all fast path criteria are met, NULL otherwise.
+ */
+DUK_LOCAL duk_harray *duk__arraypart_fastpath_this(duk_hthread *thr) {
+ duk_tval *tv;
+ duk_hobject *h;
+ duk_uint_t flags_mask, flags_bits, flags_value;
+
+ DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* because call in progress */
+ tv = DUK_GET_THIS_TVAL_PTR(thr);
+
+ /* Fast path requires that 'this' is a duk_harray. Read only arrays
+ * (ROM backed) are also rejected for simplicity.
+ */
+ if (!DUK_TVAL_IS_OBJECT(tv)) {
+ DUK_DD(DUK_DDPRINT("reject array fast path: not an object"));
+ return NULL;
+ }
+ h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ flags_mask = DUK_HOBJECT_FLAG_ARRAY_PART | \
+ DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \
+ DUK_HEAPHDR_FLAG_READONLY;
+ flags_bits = DUK_HOBJECT_FLAG_ARRAY_PART | \
+ DUK_HOBJECT_FLAG_EXOTIC_ARRAY;
+ flags_value = DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) h);
+ if ((flags_value & flags_mask) != flags_bits) {
+ DUK_DD(DUK_DDPRINT("reject array fast path: object flag check failed"));
+ return NULL;
+ }
+
+ /* In some cases a duk_harray's 'length' may be larger than the
+ * current array part allocation. Avoid the fast path in these
+ * cases, so that all fast path code can safely assume that all
+ * items in the range [0,length[ are backed by the current array
+ * part allocation.
+ */
+ if (((duk_harray *) h)->length > DUK_HOBJECT_GET_ASIZE(h)) {
+ DUK_DD(DUK_DDPRINT("reject array fast path: length > array part size"));
+ return NULL;
+ }
+
+ /* Guarantees for fast path. */
+ DUK_ASSERT(h != NULL);
+ DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(h) == 0 || DUK_HOBJECT_A_GET_BASE(thr->heap, h) != NULL);
+ DUK_ASSERT(((duk_harray *) h)->length <= DUK_HOBJECT_GET_ASIZE(h));
+
+ DUK_DD(DUK_DDPRINT("array fast path allowed for: %!O", (duk_heaphdr *) h));
+ return (duk_harray *) h;
+}
+#endif /* DUK_USE_ARRAY_FASTPATH */
+
/*
* Constructor
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_constructor(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_constructor(duk_hthread *thr) {
duk_idx_t nargs;
+ duk_harray *a;
duk_double_t d;
duk_uint32_t len;
- duk_idx_t i;
+ duk_uint32_t len_prealloc;
- nargs = duk_get_top(ctx);
- duk_push_array(ctx);
+ nargs = duk_get_top(thr);
- if (nargs == 1 && duk_is_number(ctx, 0)) {
+ if (nargs == 1 && duk_is_number(thr, 0)) {
/* XXX: expensive check (also shared elsewhere - so add a shared internal API call?) */
- d = duk_get_number(ctx, 0);
- len = duk_to_uint32(ctx, 0);
+ d = duk_get_number(thr, 0);
+ len = duk_to_uint32(thr, 0);
if (((duk_double_t) len) != d) {
- return DUK_RET_RANGE_ERROR;
+ DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
}
- /* XXX: if 'len' is low, may want to ensure array part is kept:
- * the caller is likely to want a dense array.
+ /* For small lengths create a dense preallocated array.
+ * For large arrays preallocate an initial part.
*/
- duk_push_u32(ctx, len);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); /* [ ToUint32(len) array ToUint32(len) ] -> [ ToUint32(len) array ] */
+ len_prealloc = len < 64 ? len : 64;
+ a = duk_push_harray_with_size(thr, len_prealloc);
+ DUK_ASSERT(a != NULL);
+ a->length = len;
return 1;
}
- /* XXX: optimize by creating array into correct size directly, and
- * operating on the array part directly; values can be memcpy()'d from
- * value stack directly as long as refcounts are increased.
- */
- for (i = 0; i < nargs; i++) {
- duk_dup(ctx, i);
- duk_xdef_prop_index_wec(ctx, -2, (duk_uarridx_t) i);
- }
-
- duk_push_u32(ctx, (duk_uint32_t) nargs);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
+ duk_pack(thr, nargs);
return 1;
}
@@ -20350,11 +24371,11 @@ DUK_INTERNAL duk_ret_t duk_bi_array_constructor(duk_context *ctx) {
* isArray()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_constructor_is_array(duk_hthread *thr) {
duk_hobject *h;
- h = duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_ARRAY);
- duk_push_boolean(ctx, (h != NULL));
+ h = duk_get_hobject_with_class(thr, 0, DUK_HOBJECT_CLASS_ARRAY);
+ duk_push_boolean(thr, (h != NULL));
return 1;
}
@@ -20362,12 +24383,12 @@ DUK_INTERNAL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx) {
* toString()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx) {
- (void) duk_push_this_coercible_to_object(ctx);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_JOIN);
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_hthread *thr) {
+ (void) duk_push_this_coercible_to_object(thr);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_JOIN);
/* [ ... this func ] */
- if (!duk_is_callable(ctx, -1)) {
+ if (!duk_is_callable(thr, -1)) {
/* Fall back to the initial (original) Object.toString(). We don't
* currently have pointers to the built-in functions, only the top
* level global objects (like "Array") so this is now done in a bit
@@ -20379,20 +24400,20 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx) {
* but should have no visible side effects.
*/
DUK_DDD(DUK_DDDPRINT("this.join is not callable, fall back to (original) Object.toString"));
- duk_set_top(ctx, 0);
- return duk_bi_object_prototype_to_string(ctx); /* has access to 'this' binding */
+ duk_set_top(thr, 0);
+ return duk_bi_object_prototype_to_string(thr); /* has access to 'this' binding */
}
/* [ ... this func ] */
- duk_insert(ctx, -2);
+ duk_insert(thr, -2);
/* [ ... func this ] */
DUK_DDD(DUK_DDDPRINT("calling: func=%!iT, this=%!iT",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_call_method(ctx, 0);
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
+ duk_call_method(thr, 0);
return 1;
}
@@ -20401,7 +24422,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx) {
* concat()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_hthread *thr) {
duk_idx_t i, n;
duk_uarridx_t idx, idx_last;
duk_uarridx_t j, len;
@@ -20412,10 +24433,10 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) {
* (as the element is dup()'d anyway).
*/
- (void) duk_push_this_coercible_to_object(ctx);
- duk_insert(ctx, 0);
- n = duk_get_top(ctx);
- duk_push_array(ctx); /* -> [ ToObject(this) item1 ... itemN arr ] */
+ (void) duk_push_this_coercible_to_object(thr);
+ duk_insert(thr, 0);
+ n = duk_get_top(thr);
+ duk_push_array(thr); /* -> [ ToObject(this) item1 ... itemN arr ] */
/* NOTE: The Array special behaviors are NOT invoked by duk_xdef_prop_index()
* (which differs from the official algorithm). If no error is thrown, this
@@ -20427,14 +24448,14 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) {
idx = 0;
idx_last = 0;
for (i = 0; i < n; i++) {
- DUK_ASSERT_TOP(ctx, n + 1);
+ DUK_ASSERT_TOP(thr, n + 1);
/* [ ToObject(this) item1 ... itemN arr ] */
- duk_dup(ctx, i);
- h = duk_get_hobject_with_class(ctx, -1, DUK_HOBJECT_CLASS_ARRAY);
+ duk_dup(thr, i);
+ h = duk_get_hobject_with_class(thr, -1, DUK_HOBJECT_CLASS_ARRAY);
if (!h) {
- duk_xdef_prop_index_wec(ctx, -2, idx++);
+ duk_xdef_prop_index_wec(thr, -2, idx++);
idx_last = idx;
continue;
}
@@ -20444,15 +24465,15 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) {
/* XXX: an array can have length higher than 32 bits; this is not handled
* correctly now.
*/
- len = (duk_uarridx_t) duk_get_length(ctx, -1);
+ len = (duk_uarridx_t) duk_get_length(thr, -1);
for (j = 0; j < len; j++) {
- if (duk_get_prop_index(ctx, -1, j)) {
+ if (duk_get_prop_index(thr, -1, j)) {
/* [ ToObject(this) item1 ... itemN arr item(i) item(i)[j] ] */
- duk_xdef_prop_index_wec(ctx, -3, idx++);
+ duk_xdef_prop_index_wec(thr, -3, idx++);
idx_last = idx;
} else {
idx++;
- duk_pop(ctx);
+ duk_pop_undefined(thr);
#if defined(DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER)
/* According to E5.1 Section 15.4.4.4 nonexistent trailing
* elements do not affect 'length' of the result. Test262
@@ -20466,17 +24487,17 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) {
#endif
}
}
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
}
/* The E5.1 Section 15.4.4.4 algorithm doesn't set the length explicitly
* in the end, but because we're operating with an internal value which
* is known to be an array, this should be equivalent.
*/
- duk_push_uarridx(ctx, idx_last);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
+ duk_push_uarridx(thr, idx_last);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
- DUK_ASSERT_TOP(ctx, n + 1);
+ DUK_ASSERT_TOP(thr, n + 1);
return 1;
}
@@ -20493,53 +24514,54 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) {
* There is no fancy handling; the prefix gets re-joined multiple times.
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_hthread *thr) {
duk_uint32_t len, count;
duk_uint32_t idx;
- duk_small_int_t to_locale_string = duk_get_current_magic(ctx);
+ duk_small_int_t to_locale_string = duk_get_current_magic(thr);
duk_idx_t valstack_required;
/* For join(), nargs is 1. For toLocaleString(), nargs is 0 and
* setting the top essentially pushes an undefined to the stack,
* thus defaulting to a comma separator.
*/
- duk_set_top(ctx, 1);
- if (duk_is_undefined(ctx, 0)) {
- duk_pop(ctx);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_COMMA);
+ duk_set_top(thr, 1);
+ if (duk_is_undefined(thr, 0)) {
+ duk_pop_undefined(thr);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_COMMA);
} else {
- duk_to_string(ctx, 0);
+ duk_to_string(thr, 0);
}
- len = duk__push_this_obj_len_u32(ctx);
+ len = duk__push_this_obj_len_u32(thr);
/* [ sep ToObject(this) len ] */
DUK_DDD(DUK_DDDPRINT("sep=%!T, this=%!T, len=%lu",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1),
+ (duk_tval *) duk_get_tval(thr, 0),
+ (duk_tval *) duk_get_tval(thr, 1),
(unsigned long) len));
/* The extra (+4) is tight. */
- valstack_required = (len >= DUK__ARRAY_MID_JOIN_LIMIT ?
- DUK__ARRAY_MID_JOIN_LIMIT : len) + 4;
- duk_require_stack(ctx, valstack_required);
+ valstack_required = (duk_idx_t) ((len >= DUK__ARRAY_MID_JOIN_LIMIT ?
+ DUK__ARRAY_MID_JOIN_LIMIT : len) + 4);
+ duk_require_stack(thr, valstack_required);
- duk_dup(ctx, 0);
+ duk_dup_0(thr);
/* [ sep ToObject(this) len sep ] */
count = 0;
idx = 0;
for (;;) {
+ DUK_DDD(DUK_DDDPRINT("join idx=%ld", (long) idx));
if (count >= DUK__ARRAY_MID_JOIN_LIMIT || /* intermediate join to avoid valstack overflow */
idx >= len) { /* end of loop (careful with len==0) */
/* [ sep ToObject(this) len sep str0 ... str(count-1) ] */
DUK_DDD(DUK_DDDPRINT("mid/final join, count=%ld, idx=%ld, len=%ld",
(long) count, (long) idx, (long) len));
- duk_join(ctx, (duk_idx_t) count); /* -> [ sep ToObject(this) len str ] */
- duk_dup(ctx, 0); /* -> [ sep ToObject(this) len str sep ] */
- duk_insert(ctx, -2); /* -> [ sep ToObject(this) len sep str ] */
+ duk_join(thr, (duk_idx_t) count); /* -> [ sep ToObject(this) len str ] */
+ duk_dup_0(thr); /* -> [ sep ToObject(this) len str sep ] */
+ duk_insert(thr, -2); /* -> [ sep ToObject(this) len sep str ] */
count = 1;
}
if (idx >= len) {
@@ -20547,20 +24569,18 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx) {
break;
}
- duk_get_prop_index(ctx, 1, (duk_uarridx_t) idx);
- if (duk_is_null_or_undefined(ctx, -1)) {
- duk_pop(ctx);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
+ duk_get_prop_index(thr, 1, (duk_uarridx_t) idx);
+ if (duk_is_null_or_undefined(thr, -1)) {
+ duk_pop_nodecref_unsafe(thr);
+ duk_push_hstring_empty(thr);
} else {
if (to_locale_string) {
- duk_to_object(ctx, -1);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_LOCALE_STRING);
- duk_insert(ctx, -2); /* -> [ ... toLocaleString ToObject(val) ] */
- duk_call_method(ctx, 0);
- duk_to_string(ctx, -1);
- } else {
- duk_to_string(ctx, -1);
+ duk_to_object(thr, -1);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_TO_LOCALE_STRING);
+ duk_insert(thr, -2); /* -> [ ... toLocaleString ToObject(val) ] */
+ duk_call_method(thr, 0);
}
+ duk_to_string(thr, -1);
}
count++;
@@ -20576,27 +24596,129 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx) {
* pop(), push()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_pop(duk_context *ctx) {
+#if defined(DUK_USE_ARRAY_FASTPATH)
+DUK_LOCAL duk_ret_t duk__array_pop_fastpath(duk_hthread *thr, duk_harray *h_arr) {
+ duk_tval *tv_arraypart;
+ duk_tval *tv_val;
+ duk_uint32_t len;
+
+ tv_arraypart = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) h_arr);
+ len = h_arr->length;
+ if (len <= 0) {
+ /* nop, return undefined */
+ return 0;
+ }
+
+ len--;
+ h_arr->length = len;
+
+ /* Fast path doesn't check for an index property inherited from
+ * Array.prototype. This is quite often acceptable; if not,
+ * disable fast path.
+ */
+ DUK_ASSERT_VS_SPACE(thr);
+ tv_val = tv_arraypart + len;
+ if (DUK_TVAL_IS_UNUSED(tv_val)) {
+ /* No net refcount change. Value stack already has
+ * 'undefined' based on value stack init policy.
+ */
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top));
+ DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv_val));
+ } else {
+ /* No net refcount change. */
+ DUK_TVAL_SET_TVAL(thr->valstack_top, tv_val);
+ DUK_TVAL_SET_UNUSED(tv_val);
+ }
+ thr->valstack_top++;
+
+ /* XXX: there's no shrink check in the fast path now */
+
+ return 1;
+}
+#endif /* DUK_USE_ARRAY_FASTPATH */
+
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_pop(duk_hthread *thr) {
duk_uint32_t len;
duk_uint32_t idx;
+#if defined(DUK_USE_ARRAY_FASTPATH)
+ duk_harray *h_arr;
+#endif
- DUK_ASSERT_TOP(ctx, 0);
- len = duk__push_this_obj_len_u32(ctx);
+ DUK_ASSERT_TOP(thr, 0);
+
+#if defined(DUK_USE_ARRAY_FASTPATH)
+ h_arr = duk__arraypart_fastpath_this(thr);
+ if (h_arr) {
+ return duk__array_pop_fastpath(thr, h_arr);
+ }
+#endif
+
+ /* XXX: Merge fastpath check into a related call (push this, coerce length, etc)? */
+
+ len = duk__push_this_obj_len_u32(thr);
if (len == 0) {
- duk_push_int(ctx, 0);
- duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);
+ duk_push_int(thr, 0);
+ duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
return 0;
}
idx = len - 1;
- duk_get_prop_index(ctx, 0, (duk_uarridx_t) idx);
- duk_del_prop_index(ctx, 0, (duk_uarridx_t) idx);
- duk_push_u32(ctx, idx);
- duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);
+ duk_get_prop_index(thr, 0, (duk_uarridx_t) idx);
+ duk_del_prop_index(thr, 0, (duk_uarridx_t) idx);
+ duk_push_u32(thr, idx);
+ duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) {
+#if defined(DUK_USE_ARRAY_FASTPATH)
+DUK_LOCAL duk_ret_t duk__array_push_fastpath(duk_hthread *thr, duk_harray *h_arr) {
+ duk_tval *tv_arraypart;
+ duk_tval *tv_src;
+ duk_tval *tv_dst;
+ duk_uint32_t len;
+ duk_idx_t i, n;
+
+ len = h_arr->length;
+ tv_arraypart = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) h_arr);
+
+ n = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
+ DUK_ASSERT(n >= 0);
+ DUK_ASSERT((duk_uint32_t) n <= DUK_UINT32_MAX);
+ if (DUK_UNLIKELY(len + (duk_uint32_t) n < len)) {
+ DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw"));
+ DUK_DCERROR_RANGE_INVALID_LENGTH(thr); /* != 0 return value returned as is by caller */
+ }
+ if (len + (duk_uint32_t) n > DUK_HOBJECT_GET_ASIZE((duk_hobject *) h_arr)) {
+ /* Array part would need to be extended. Rely on slow path
+ * for now.
+ *
+ * XXX: Rework hobject code a bit and add extend support.
+ */
+ return 0;
+ }
+
+ tv_src = thr->valstack_bottom;
+ tv_dst = tv_arraypart + len;
+ for (i = 0; i < n; i++) {
+ /* No net refcount change; reset value stack values to
+ * undefined to satisfy value stack init policy.
+ */
+ DUK_TVAL_SET_TVAL(tv_dst, tv_src);
+ DUK_TVAL_SET_UNDEFINED(tv_src);
+ tv_src++;
+ tv_dst++;
+ }
+ thr->valstack_top = thr->valstack_bottom;
+ len += (duk_uint32_t) n;
+ h_arr->length = len;
+
+ DUK_ASSERT((duk_uint_t) len == len);
+ duk_push_uint(thr, (duk_uint_t) len);
+ return 1;
+}
+#endif /* DUK_USE_ARRAY_FASTPATH */
+
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_hthread *thr) {
/* Note: 'this' is not necessarily an Array object. The push()
* algorithm is supposed to work for other kinds of objects too,
* so the algorithm has e.g. an explicit update for the 'length'
@@ -20605,9 +24727,24 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) {
duk_uint32_t len;
duk_idx_t i, n;
+#if defined(DUK_USE_ARRAY_FASTPATH)
+ duk_harray *h_arr;
+#endif
- n = duk_get_top(ctx);
- len = duk__push_this_obj_len_u32(ctx);
+#if defined(DUK_USE_ARRAY_FASTPATH)
+ h_arr = duk__arraypart_fastpath_this(thr);
+ if (h_arr) {
+ duk_ret_t rc;
+ rc = duk__array_push_fastpath(thr, h_arr);
+ if (rc != 0) {
+ return rc;
+ }
+ DUK_DD(DUK_DDPRINT("array push() fast path exited, resize case"));
+ }
+#endif
+
+ n = duk_get_top(thr);
+ len = duk__push_this_obj_len_u32(thr);
/* [ arg1 ... argN obj length ] */
@@ -20623,18 +24760,18 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) {
if (len + (duk_uint32_t) n < len) {
DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw"));
- return DUK_RET_RANGE_ERROR;
+ DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
}
for (i = 0; i < n; i++) {
- duk_dup(ctx, i);
- duk_put_prop_index(ctx, -3, len + i);
+ duk_dup(thr, i);
+ duk_put_prop_index(thr, -3, (duk_uarridx_t) (len + (duk_uint32_t) i));
}
- len += n;
+ len += (duk_uint32_t) n;
- duk_push_u32(ctx, len);
- duk_dup_top(ctx);
- duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH);
+ duk_push_u32(thr, len);
+ duk_dup_top(thr);
+ duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_LENGTH);
/* [ arg1 ... argN obj length new_length ] */
return 1;
@@ -20650,7 +24787,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) {
* may use a negative offset.
*/
-DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t idx1, duk_int_t idx2) {
+DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_hthread *thr, duk_int_t idx1, duk_int_t idx2) {
duk_bool_t have1, have2;
duk_bool_t undef1, undef2;
duk_small_int_t ret;
@@ -20679,12 +24816,12 @@ DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t id
return 0;
}
- have1 = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) idx1);
- have2 = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) idx2);
+ have1 = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) idx1);
+ have2 = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) idx2);
DUK_DDD(DUK_DDDPRINT("duk__array_sort_compare: idx1=%ld, idx2=%ld, have1=%ld, have2=%ld, val1=%!T, val2=%!T",
(long) idx1, (long) idx2, (long) have1, (long) have2,
- (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1)));
if (have1) {
if (have2) {
@@ -20703,8 +24840,8 @@ DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t id
}
}
- undef1 = duk_is_undefined(ctx, -2);
- undef2 = duk_is_undefined(ctx, -1);
+ undef1 = duk_is_undefined(thr, -2);
+ undef2 = duk_is_undefined(thr, -1);
if (undef1) {
if (undef2) {
ret = 0;
@@ -20722,40 +24859,41 @@ DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t id
}
}
- if (!duk_is_undefined(ctx, idx_fn)) {
+ if (!duk_is_undefined(thr, idx_fn)) {
duk_double_t d;
- /* no need to check callable; duk_call() will do that */
- duk_dup(ctx, idx_fn); /* -> [ ... x y fn ] */
- duk_insert(ctx, -3); /* -> [ ... fn x y ] */
- duk_call(ctx, 2); /* -> [ ... res ] */
+ /* No need to check callable; duk_call() will do that. */
+ duk_dup(thr, idx_fn); /* -> [ ... x y fn ] */
+ duk_insert(thr, -3); /* -> [ ... fn x y ] */
+ duk_call(thr, 2); /* -> [ ... res ] */
- /* The specification is a bit vague what to do if the return
- * value is not a number. Other implementations seem to
- * tolerate non-numbers but e.g. V8 won't apparently do a
- * ToNumber().
+ /* ES5 is a bit vague about what to do if the return value is
+ * not a number. ES2015 provides a concrete description:
+ * http://www.ecma-international.org/ecma-262/6.0/#sec-sortcompare.
*/
- /* XXX: best behavior for real world compatibility? */
-
- d = duk_to_number(ctx, -1);
+ d = duk_to_number_m1(thr);
if (d < 0.0) {
ret = -1;
} else if (d > 0.0) {
ret = 1;
} else {
+ /* Because NaN compares to false, NaN is handled here
+ * without an explicit check above.
+ */
ret = 0;
}
- duk_pop(ctx);
+ duk_pop_nodecref_unsafe(thr);
DUK_DDD(DUK_DDDPRINT("-> result %ld (from comparefn, after coercion)", (long) ret));
return ret;
}
/* string compare is the default (a bit oddly) */
- h1 = duk_to_hstring(ctx, -2);
- h2 = duk_to_hstring(ctx, -1);
+ /* XXX: any special handling for plain array; causes repeated coercion now? */
+ h1 = duk_to_hstring(thr, -2);
+ h2 = duk_to_hstring_m1(thr);
DUK_ASSERT(h1 != NULL);
DUK_ASSERT(h2 != NULL);
@@ -20763,12 +24901,12 @@ DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t id
goto pop_ret;
pop_ret:
- duk_pop_2(ctx);
+ duk_pop_2_unsafe(thr);
DUK_DDD(DUK_DDDPRINT("-> result %ld", (long) ret));
return ret;
}
-DUK_LOCAL void duk__array_sort_swap(duk_context *ctx, duk_int_t l, duk_int_t r) {
+DUK_LOCAL void duk__array_sort_swap(duk_hthread *thr, duk_int_t l, duk_int_t r) {
duk_bool_t have_l, have_r;
duk_idx_t idx_obj = 1; /* fixed offset in valstack */
@@ -20777,32 +24915,32 @@ DUK_LOCAL void duk__array_sort_swap(duk_context *ctx, duk_int_t l, duk_int_t r)
}
/* swap elements; deal with non-existent elements correctly */
- have_l = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) l);
- have_r = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) r);
+ have_l = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) l);
+ have_r = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) r);
if (have_r) {
/* right exists, [[Put]] regardless whether or not left exists */
- duk_put_prop_index(ctx, idx_obj, (duk_uarridx_t) l);
+ duk_put_prop_index(thr, idx_obj, (duk_uarridx_t) l);
} else {
- duk_del_prop_index(ctx, idx_obj, (duk_uarridx_t) l);
- duk_pop(ctx);
+ duk_del_prop_index(thr, idx_obj, (duk_uarridx_t) l);
+ duk_pop_undefined(thr);
}
if (have_l) {
- duk_put_prop_index(ctx, idx_obj, (duk_uarridx_t) r);
+ duk_put_prop_index(thr, idx_obj, (duk_uarridx_t) r);
} else {
- duk_del_prop_index(ctx, idx_obj, (duk_uarridx_t) r);
- duk_pop(ctx);
+ duk_del_prop_index(thr, idx_obj, (duk_uarridx_t) r);
+ duk_pop_undefined(thr);
}
}
-#if defined(DUK_USE_DDDPRINT)
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
/* Debug print which visualizes the qsort partitioning process. */
-DUK_LOCAL void duk__debuglog_qsort_state(duk_context *ctx, duk_int_t lo, duk_int_t hi, duk_int_t pivot) {
+DUK_LOCAL void duk__debuglog_qsort_state(duk_hthread *thr, duk_int_t lo, duk_int_t hi, duk_int_t pivot) {
char buf[4096];
char *ptr = buf;
duk_int_t i, n;
- n = (duk_int_t) duk_get_length(ctx, 1);
+ n = (duk_int_t) duk_get_length(thr, 1);
if (n > 4000) {
n = 4000;
}
@@ -20828,16 +24966,15 @@ DUK_LOCAL void duk__debuglog_qsort_state(duk_context *ctx, duk_int_t lo, duk_int
}
#endif
-DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL void duk__array_qsort(duk_hthread *thr, duk_int_t lo, duk_int_t hi) {
duk_int_t p, l, r;
/* The lo/hi indices may be crossed and hi < 0 is possible at entry. */
DUK_DDD(DUK_DDDPRINT("duk__array_qsort: lo=%ld, hi=%ld, obj=%!T",
- (long) lo, (long) hi, (duk_tval *) duk_get_tval(ctx, 1)));
+ (long) lo, (long) hi, (duk_tval *) duk_get_tval(thr, 1)));
- DUK_ASSERT_TOP(ctx, 3);
+ DUK_ASSERT_TOP(thr, 3);
/* In some cases it may be that lo > hi, or hi < 0; these
* degenerate cases happen e.g. for empty arrays, and in
@@ -20853,15 +24990,14 @@ DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) {
DUK_ASSERT(hi - lo + 1 >= 2);
/* randomized pivot selection */
- p = lo + (duk_util_tinyrandom_get_bits(thr, 30) % (hi - lo + 1)); /* rnd in [lo,hi] */
+ p = lo + (duk_int_t) (DUK_UTIL_GET_RANDOM_DOUBLE(thr) * (duk_double_t) (hi - lo + 1));
DUK_ASSERT(p >= lo && p <= hi);
- DUK_DDD(DUK_DDDPRINT("lo=%ld, hi=%ld, chose pivot p=%ld",
- (long) lo, (long) hi, (long) p));
+ DUK_DDD(DUK_DDDPRINT("lo=%ld, hi=%ld, chose pivot p=%ld", (long) lo, (long) hi, (long) p));
/* move pivot out of the way */
- duk__array_sort_swap(ctx, p, lo);
+ duk__array_sort_swap(thr, p, lo);
p = lo;
- DUK_DDD(DUK_DDDPRINT("pivot moved out of the way: %!T", (duk_tval *) duk_get_tval(ctx, 1)));
+ DUK_DDD(DUK_DDDPRINT("pivot moved out of the way: %!T", (duk_tval *) duk_get_tval(thr, 1)));
l = lo + 1;
r = hi;
@@ -20873,7 +25009,7 @@ DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) {
if (l >= hi) {
break;
}
- if (duk__array_sort_compare(ctx, l, p) >= 0) { /* !(l < p) */
+ if (duk__array_sort_compare(thr, l, p) >= 0) { /* !(l < p) */
break;
}
l++;
@@ -20884,7 +25020,7 @@ DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) {
if (r <= lo) {
break;
}
- if (duk__array_sort_compare(ctx, p, r) >= 0) { /* !(p < r) */
+ if (duk__array_sort_compare(thr, p, r) >= 0) { /* !(p < r) */
break;
}
r--;
@@ -20896,9 +25032,9 @@ DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) {
DUK_DDD(DUK_DDDPRINT("swap %ld and %ld", (long) l, (long) r));
- duk__array_sort_swap(ctx, l, r);
+ duk__array_sort_swap(thr, l, r);
- DUK_DDD(DUK_DDDPRINT("after swap: %!T", (duk_tval *) duk_get_tval(ctx, 1)));
+ DUK_DDD(DUK_DDDPRINT("after swap: %!T", (duk_tval *) duk_get_tval(thr, 1)));
l++;
r--;
}
@@ -20914,25 +25050,25 @@ DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) {
*/
/* move pivot to its final place */
- DUK_DDD(DUK_DDDPRINT("before final pivot swap: %!T", (duk_tval *) duk_get_tval(ctx, 1)));
- duk__array_sort_swap(ctx, lo, r);
+ DUK_DDD(DUK_DDDPRINT("before final pivot swap: %!T", (duk_tval *) duk_get_tval(thr, 1)));
+ duk__array_sort_swap(thr, lo, r);
-#if defined(DUK_USE_DDDPRINT)
- duk__debuglog_qsort_state(ctx, lo, hi, r);
+#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
+ duk__debuglog_qsort_state(thr, lo, hi, r);
#endif
- DUK_DDD(DUK_DDDPRINT("recurse: pivot=%ld, obj=%!T", (long) r, (duk_tval *) duk_get_tval(ctx, 1)));
- duk__array_qsort(ctx, lo, r - 1);
- duk__array_qsort(ctx, r + 1, hi);
+ DUK_DDD(DUK_DDDPRINT("recurse: pivot=%ld, obj=%!T", (long) r, (duk_tval *) duk_get_tval(thr, 1)));
+ duk__array_qsort(thr, lo, r - 1);
+ duk__array_qsort(thr, r + 1, hi);
}
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_sort(duk_hthread *thr) {
duk_uint32_t len;
/* XXX: len >= 0x80000000 won't work below because a signed type
* is needed by qsort.
*/
- len = duk__push_this_obj_len_u32_limited(ctx);
+ len = duk__push_this_obj_len_u32_limited(thr);
/* stack[0] = compareFn
* stack[1] = ToObject(this)
@@ -20941,11 +25077,11 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx) {
if (len > 0) {
/* avoid degenerate cases, so that (len - 1) won't underflow */
- duk__array_qsort(ctx, (duk_int_t) 0, (duk_int_t) (len - 1));
+ duk__array_qsort(thr, (duk_int_t) 0, (duk_int_t) (len - 1));
}
- DUK_ASSERT_TOP(ctx, 3);
- duk_pop(ctx);
+ DUK_ASSERT_TOP(thr, 3);
+ duk_pop_nodecref_unsafe(thr);
return 1; /* return ToObject(this) */
}
@@ -20962,9 +25098,10 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx) {
* unshift is (close to?) <--> splice(0, 0, [items])?
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_hthread *thr) {
duk_idx_t nargs;
- duk_uint32_t len;
+ duk_uint32_t len_u32;
+ duk_int_t len;
duk_bool_t have_delcount;
duk_int_t item_count;
duk_int_t act_start;
@@ -20973,9 +25110,9 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
DUK_UNREF(have_delcount);
- nargs = duk_get_top(ctx);
+ nargs = duk_get_top(thr);
if (nargs < 2) {
- duk_set_top(ctx, 2);
+ duk_set_top(thr, 2);
nargs = 2;
have_delcount = 0;
} else {
@@ -20985,19 +25122,21 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
/* XXX: len >= 0x80000000 won't work below because we need to be
* able to represent -len.
*/
- len = duk__push_this_obj_len_u32_limited(ctx);
+ len_u32 = duk__push_this_obj_len_u32_limited(thr);
+ len = (duk_int_t) len_u32;
+ DUK_ASSERT(len >= 0);
- act_start = duk_to_int_clamped(ctx, 0, -((duk_int_t) len), (duk_int_t) len);
+ act_start = duk_to_int_clamped(thr, 0, -len, len);
if (act_start < 0) {
act_start = len + act_start;
}
- DUK_ASSERT(act_start >= 0 && act_start <= (duk_int_t) len);
+ DUK_ASSERT(act_start >= 0 && act_start <= len);
-#ifdef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
+#if defined(DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT)
if (have_delcount) {
#endif
- del_count = duk_to_int_clamped(ctx, 1, 0, len - act_start);
-#ifdef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
+ del_count = duk_to_int_clamped(thr, 1, 0, len - act_start);
+#if defined(DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT)
} else {
/* E5.1 standard behavior when deleteCount is not given would be
* to treat it just like if 'undefined' was given, which coerces
@@ -21011,16 +25150,16 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
DUK_ASSERT(nargs >= 2);
item_count = (duk_int_t) (nargs - 2);
- DUK_ASSERT(del_count >= 0 && del_count <= (duk_int_t) len - act_start);
- DUK_ASSERT(del_count + act_start <= (duk_int_t) len);
+ DUK_ASSERT(del_count >= 0 && del_count <= len - act_start);
+ DUK_ASSERT(del_count + act_start <= len);
/* For now, restrict result array into 32-bit length range. */
if (((duk_double_t) len) - ((duk_double_t) del_count) + ((duk_double_t) item_count) > (duk_double_t) DUK_UINT32_MAX) {
DUK_D(DUK_DPRINT("Array.prototype.splice() would go beyond 32-bit length, throw"));
- return DUK_RET_RANGE_ERROR;
+ DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
}
- duk_push_array(ctx);
+ duk_push_array(thr);
/* stack[0] = start
* stack[1] = deleteCount
@@ -21030,19 +25169,19 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
* stack[nargs+2] = result array -1
*/
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
/* Step 9: copy elements-to-be-deleted into the result array */
for (i = 0; i < del_count; i++) {
- if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (act_start + i))) {
- duk_xdef_prop_index_wec(ctx, -2, i); /* throw flag irrelevant (false in std alg) */
+ if (duk_get_prop_index(thr, -3, (duk_uarridx_t) (act_start + i))) {
+ duk_xdef_prop_index_wec(thr, -2, (duk_uarridx_t) i); /* throw flag irrelevant (false in std alg) */
} else {
- duk_pop(ctx);
+ duk_pop_undefined(thr);
}
}
- duk_push_u32(ctx, (duk_uint32_t) del_count);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
+ duk_push_u32(thr, (duk_uint32_t) del_count);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
/* Steps 12 and 13: reorganize elements to make room for itemCount elements */
@@ -21053,27 +25192,27 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
* [ A B C F G H ] (actual result at this point, C will be replaced)
*/
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
n = len - del_count;
for (i = act_start; i < n; i++) {
- if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (i + del_count))) {
- duk_put_prop_index(ctx, -4, (duk_uarridx_t) (i + item_count));
+ if (duk_get_prop_index(thr, -3, (duk_uarridx_t) (i + del_count))) {
+ duk_put_prop_index(thr, -4, (duk_uarridx_t) (i + item_count));
} else {
- duk_pop(ctx);
- duk_del_prop_index(ctx, -3, (duk_uarridx_t) (i + item_count));
+ duk_pop_undefined(thr);
+ duk_del_prop_index(thr, -3, (duk_uarridx_t) (i + item_count));
}
}
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
/* loop iterator init and limit changed from standard algorithm */
n = len - del_count + item_count;
for (i = len - 1; i >= n; i--) {
- duk_del_prop_index(ctx, -3, (duk_uarridx_t) i);
+ duk_del_prop_index(thr, -3, (duk_uarridx_t) i);
}
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
} else if (item_count > del_count) {
/* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 4
* -> [ A B F G H ] (conceptual intermediate step)
@@ -21081,19 +25220,19 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
* [ A B C D E F F G H ] (actual result at this point)
*/
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
/* loop iterator init and limit changed from standard algorithm */
for (i = len - del_count - 1; i >= act_start; i--) {
- if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (i + del_count))) {
- duk_put_prop_index(ctx, -4, (duk_uarridx_t) (i + item_count));
+ if (duk_get_prop_index(thr, -3, (duk_uarridx_t) (i + del_count))) {
+ duk_put_prop_index(thr, -4, (duk_uarridx_t) (i + item_count));
} else {
- duk_pop(ctx);
- duk_del_prop_index(ctx, -3, (duk_uarridx_t) (i + item_count));
+ duk_pop_undefined(thr);
+ duk_del_prop_index(thr, -3, (duk_uarridx_t) (i + item_count));
}
}
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
} else {
/* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 3
* -> [ A B F G H ] (conceptual intermediate step)
@@ -21101,24 +25240,24 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
* [ A B C D E F G H ] (actual result at this point)
*/
}
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
/* Step 15: insert itemCount elements into the hole made above */
for (i = 0; i < item_count; i++) {
- duk_dup(ctx, i + 2); /* args start at index 2 */
- duk_put_prop_index(ctx, -4, (duk_uarridx_t) (act_start + i));
+ duk_dup(thr, i + 2); /* args start at index 2 */
+ duk_put_prop_index(thr, -4, (duk_uarridx_t) (act_start + i));
}
/* Step 16: update length; note that the final length may be above 32 bit range
* (but we checked above that this isn't the case here)
*/
- duk_push_u32(ctx, len - del_count + item_count);
- duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH);
+ duk_push_u32(thr, (duk_uint32_t) (len - del_count + item_count));
+ duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_LENGTH);
/* result array is already at the top of stack */
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
return 1;
}
@@ -21126,13 +25265,13 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
* reverse()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reverse(duk_hthread *thr) {
duk_uint32_t len;
duk_uint32_t middle;
duk_uint32_t lower, upper;
duk_bool_t have_lower, have_upper;
- len = duk__push_this_obj_len_u32(ctx);
+ len = duk__push_this_obj_len_u32(thr);
middle = len / 2;
/* If len <= 1, middle will be 0 and for-loop bails out
@@ -21141,35 +25280,35 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx) {
for (lower = 0; lower < middle; lower++) {
DUK_ASSERT(len >= 2);
- DUK_ASSERT_TOP(ctx, 2);
+ DUK_ASSERT_TOP(thr, 2);
DUK_ASSERT(len >= lower + 1);
upper = len - lower - 1;
- have_lower = duk_get_prop_index(ctx, -2, (duk_uarridx_t) lower);
- have_upper = duk_get_prop_index(ctx, -3, (duk_uarridx_t) upper);
+ have_lower = duk_get_prop_index(thr, -2, (duk_uarridx_t) lower);
+ have_upper = duk_get_prop_index(thr, -3, (duk_uarridx_t) upper);
/* [ ToObject(this) ToUint32(length) lowerValue upperValue ] */
if (have_upper) {
- duk_put_prop_index(ctx, -4, (duk_uarridx_t) lower);
+ duk_put_prop_index(thr, -4, (duk_uarridx_t) lower);
} else {
- duk_del_prop_index(ctx, -4, (duk_uarridx_t) lower);
- duk_pop(ctx);
+ duk_del_prop_index(thr, -4, (duk_uarridx_t) lower);
+ duk_pop_undefined(thr);
}
if (have_lower) {
- duk_put_prop_index(ctx, -3, (duk_uarridx_t) upper);
+ duk_put_prop_index(thr, -3, (duk_uarridx_t) upper);
} else {
- duk_del_prop_index(ctx, -3, (duk_uarridx_t) upper);
- duk_pop(ctx);
+ duk_del_prop_index(thr, -3, (duk_uarridx_t) upper);
+ duk_pop_undefined(thr);
}
- DUK_ASSERT_TOP(ctx, 2);
+ DUK_ASSERT_TOP(thr, 2);
}
- DUK_ASSERT_TOP(ctx, 2);
- duk_pop(ctx); /* -> [ ToObject(this) ] */
+ DUK_ASSERT_TOP(thr, 2);
+ duk_pop_unsafe(thr); /* -> [ ToObject(this) ] */
return 1;
}
@@ -21177,8 +25316,9 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx) {
* slice()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx) {
- duk_uint32_t len;
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_hthread *thr) {
+ duk_uint32_t len_u32;
+ duk_int_t len;
duk_int_t start, end;
duk_int_t i;
duk_uarridx_t idx;
@@ -21187,8 +25327,11 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx) {
/* XXX: len >= 0x80000000 won't work below because we need to be
* able to represent -len.
*/
- len = duk__push_this_obj_len_u32_limited(ctx);
- duk_push_array(ctx);
+ len_u32 = duk__push_this_obj_len_u32_limited(thr);
+ len = (duk_int_t) len_u32;
+ DUK_ASSERT(len >= 0);
+
+ duk_push_array(thr);
/* stack[0] = start
* stack[1] = end
@@ -21197,41 +25340,41 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx) {
* stack[4] = result array
*/
- start = duk_to_int_clamped(ctx, 0, -((duk_int_t) len), (duk_int_t) len);
+ start = duk_to_int_clamped(thr, 0, -len, len);
if (start < 0) {
start = len + start;
}
/* XXX: could duk_is_undefined() provide defaulting undefined to 'len'
* (the upper limit)?
*/
- if (duk_is_undefined(ctx, 1)) {
+ if (duk_is_undefined(thr, 1)) {
end = len;
} else {
- end = duk_to_int_clamped(ctx, 1, -((duk_int_t) len), (duk_int_t) len);
+ end = duk_to_int_clamped(thr, 1, -len, len);
if (end < 0) {
end = len + end;
}
}
- DUK_ASSERT(start >= 0 && (duk_uint32_t) start <= len);
- DUK_ASSERT(end >= 0 && (duk_uint32_t) end <= len);
+ DUK_ASSERT(start >= 0 && start <= len);
+ DUK_ASSERT(end >= 0 && end <= len);
idx = 0;
for (i = start; i < end; i++) {
- DUK_ASSERT_TOP(ctx, 5);
- if (duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) {
- duk_xdef_prop_index_wec(ctx, 4, idx);
+ DUK_ASSERT_TOP(thr, 5);
+ if (duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) {
+ duk_xdef_prop_index_wec(thr, 4, idx);
res_length = idx + 1;
} else {
- duk_pop(ctx);
+ duk_pop_undefined(thr);
}
idx++;
- DUK_ASSERT_TOP(ctx, 5);
+ DUK_ASSERT_TOP(thr, 5);
}
- duk_push_u32(ctx, res_length);
- duk_xdef_prop_stridx(ctx, 4, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
+ duk_push_u32(thr, res_length);
+ duk_xdef_prop_stridx_short(thr, 4, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
- DUK_ASSERT_TOP(ctx, 5);
+ DUK_ASSERT_TOP(thr, 5);
return 1;
}
@@ -21239,18 +25382,18 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx) {
* shift()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_hthread *thr) {
duk_uint32_t len;
duk_uint32_t i;
- len = duk__push_this_obj_len_u32(ctx);
+ len = duk__push_this_obj_len_u32(thr);
if (len == 0) {
- duk_push_int(ctx, 0);
- duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);
+ duk_push_int(thr, 0);
+ duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
return 0;
}
- duk_get_prop_index(ctx, 0, 0);
+ duk_get_prop_index(thr, 0, 0);
/* stack[0] = object (this)
* stack[1] = ToUint32(length)
@@ -21258,22 +25401,22 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx) {
*/
for (i = 1; i < len; i++) {
- DUK_ASSERT_TOP(ctx, 3);
- if (duk_get_prop_index(ctx, 0, (duk_uarridx_t) i)) {
+ DUK_ASSERT_TOP(thr, 3);
+ if (duk_get_prop_index(thr, 0, (duk_uarridx_t) i)) {
/* fromPresent = true */
- duk_put_prop_index(ctx, 0, (duk_uarridx_t) (i - 1));
+ duk_put_prop_index(thr, 0, (duk_uarridx_t) (i - 1));
} else {
/* fromPresent = false */
- duk_del_prop_index(ctx, 0, (duk_uarridx_t) (i - 1));
- duk_pop(ctx);
+ duk_del_prop_index(thr, 0, (duk_uarridx_t) (i - 1));
+ duk_pop_undefined(thr);
}
}
- duk_del_prop_index(ctx, 0, (duk_uarridx_t) (len - 1));
+ duk_del_prop_index(thr, 0, (duk_uarridx_t) (len - 1));
- duk_push_u32(ctx, (duk_uint32_t) (len - 1));
- duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);
+ duk_push_u32(thr, (duk_uint32_t) (len - 1));
+ duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
- DUK_ASSERT_TOP(ctx, 3);
+ DUK_ASSERT_TOP(thr, 3);
return 1;
}
@@ -21281,20 +25424,20 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx) {
* unshift()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_hthread *thr) {
duk_idx_t nargs;
duk_uint32_t len;
duk_uint32_t i;
- nargs = duk_get_top(ctx);
- len = duk__push_this_obj_len_u32(ctx);
+ nargs = duk_get_top(thr);
+ len = duk__push_this_obj_len_u32(thr);
/* stack[0...nargs-1] = unshift args (vararg)
* stack[nargs] = ToObject(this)
* stack[nargs+1] = ToUint32(length)
*/
- DUK_ASSERT_TOP(ctx, nargs + 2);
+ DUK_ASSERT_TOP(thr, nargs + 2);
/* Note: unshift() may operate on indices above unsigned 32-bit range
* and the final length may be >= 2**32. However, we restrict the
@@ -21303,39 +25446,39 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx) {
if (len + (duk_uint32_t) nargs < len) {
DUK_D(DUK_DPRINT("Array.prototype.unshift() would go beyond 32-bit length, throw"));
- return DUK_RET_RANGE_ERROR;
+ DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
}
i = len;
while (i > 0) {
- DUK_ASSERT_TOP(ctx, nargs + 2);
+ DUK_ASSERT_TOP(thr, nargs + 2);
i--;
/* k+argCount-1; note that may be above 32-bit range */
- if (duk_get_prop_index(ctx, -2, (duk_uarridx_t) i)) {
+ if (duk_get_prop_index(thr, -2, (duk_uarridx_t) i)) {
/* fromPresent = true */
/* [ ... ToObject(this) ToUint32(length) val ] */
- duk_put_prop_index(ctx, -3, (duk_uarridx_t) (i + nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */
+ duk_put_prop_index(thr, -3, (duk_uarridx_t) (i + (duk_uint32_t) nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */
} else {
/* fromPresent = false */
/* [ ... ToObject(this) ToUint32(length) val ] */
- duk_pop(ctx);
- duk_del_prop_index(ctx, -2, (duk_uarridx_t) (i + nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */
+ duk_pop_undefined(thr);
+ duk_del_prop_index(thr, -2, (duk_uarridx_t) (i + (duk_uint32_t) nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */
}
- DUK_ASSERT_TOP(ctx, nargs + 2);
+ DUK_ASSERT_TOP(thr, nargs + 2);
}
for (i = 0; i < (duk_uint32_t) nargs; i++) {
- DUK_ASSERT_TOP(ctx, nargs + 2);
- duk_dup(ctx, i); /* -> [ ... ToObject(this) ToUint32(length) arg[i] ] */
- duk_put_prop_index(ctx, -3, (duk_uarridx_t) i);
- DUK_ASSERT_TOP(ctx, nargs + 2);
+ DUK_ASSERT_TOP(thr, nargs + 2);
+ duk_dup(thr, (duk_idx_t) i); /* -> [ ... ToObject(this) ToUint32(length) arg[i] ] */
+ duk_put_prop_index(thr, -3, (duk_uarridx_t) i);
+ DUK_ASSERT_TOP(thr, nargs + 2);
}
- DUK_ASSERT_TOP(ctx, nargs + 2);
- duk_push_u32(ctx, len + nargs);
- duk_dup_top(ctx); /* -> [ ... ToObject(this) ToUint32(length) final_len final_len ] */
- duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH);
+ DUK_ASSERT_TOP(thr, nargs + 2);
+ duk_push_u32(thr, len + (duk_uint32_t) nargs);
+ duk_dup_top(thr); /* -> [ ... ToObject(this) ToUint32(length) final_len final_len ] */
+ duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_LENGTH);
return 1;
}
@@ -21343,22 +25486,22 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx) {
* indexOf(), lastIndexOf()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_hthread *thr) {
duk_idx_t nargs;
duk_int_t i, len;
- duk_int_t from_index;
- duk_small_int_t idx_step = duk_get_current_magic(ctx); /* idx_step is +1 for indexOf, -1 for lastIndexOf */
+ duk_int_t from_idx;
+ duk_small_int_t idx_step = duk_get_current_magic(thr); /* idx_step is +1 for indexOf, -1 for lastIndexOf */
/* lastIndexOf() needs to be a vararg function because we must distinguish
* between an undefined fromIndex and a "not given" fromIndex; indexOf() is
* made vararg for symmetry although it doesn't strictly need to be.
*/
- nargs = duk_get_top(ctx);
- duk_set_top(ctx, 2);
+ nargs = duk_get_top(thr);
+ duk_set_top(thr, 2);
/* XXX: must be able to represent -len */
- len = (duk_int_t) duk__push_this_obj_len_u32_limited(ctx);
+ len = (duk_int_t) duk__push_this_obj_len_u32_limited(thr);
if (len == 0) {
goto not_found;
}
@@ -21385,22 +25528,22 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx) {
* lastIndexOf: clamp fromIndex to [-len - 1, len - 1]
* (if clamped to -len-1 -> fromIndex becomes -1, terminates for-loop directly)
*/
- from_index = duk_to_int_clamped(ctx,
- 1,
- (idx_step > 0 ? -len : -len - 1),
- (idx_step > 0 ? len : len - 1));
- if (from_index < 0) {
+ from_idx = duk_to_int_clamped(thr,
+ 1,
+ (idx_step > 0 ? -len : -len - 1),
+ (idx_step > 0 ? len : len - 1));
+ if (from_idx < 0) {
/* for lastIndexOf, result may be -1 (mark immediate termination) */
- from_index = len + from_index;
+ from_idx = len + from_idx;
}
} else {
/* for indexOf, ToInteger(undefined) would be 0, i.e. correct, but
* handle both indexOf and lastIndexOf specially here.
*/
if (idx_step > 0) {
- from_index = 0;
+ from_idx = 0;
} else {
- from_index = len - 1;
+ from_idx = len - 1;
}
}
@@ -21410,22 +25553,22 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx) {
* stack[3] = length (not needed, but not popped above)
*/
- for (i = from_index; i >= 0 && i < len; i += idx_step) {
- DUK_ASSERT_TOP(ctx, 4);
+ for (i = from_idx; i >= 0 && i < len; i += idx_step) {
+ DUK_ASSERT_TOP(thr, 4);
- if (duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) {
- DUK_ASSERT_TOP(ctx, 5);
- if (duk_strict_equals(ctx, 0, 4)) {
- duk_push_int(ctx, i);
+ if (duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) {
+ DUK_ASSERT_TOP(thr, 5);
+ if (duk_strict_equals(thr, 0, 4)) {
+ duk_push_int(thr, i);
return 1;
}
}
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
}
not_found:
- duk_push_int(ctx, -1);
+ duk_push_int(thr, -1);
return 1;
}
@@ -21444,25 +25587,25 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx) {
* 5 callers the net result is about 100 bytes / caller.
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_hthread *thr) {
duk_uint32_t len;
duk_uint32_t i;
duk_uarridx_t k;
duk_bool_t bval;
- duk_small_int_t iter_type = duk_get_current_magic(ctx);
+ duk_small_int_t iter_type = duk_get_current_magic(thr);
duk_uint32_t res_length = 0;
/* each call this helper serves has nargs==2 */
- DUK_ASSERT_TOP(ctx, 2);
+ DUK_ASSERT_TOP(thr, 2);
- len = duk__push_this_obj_len_u32(ctx);
- duk_require_callable(ctx, 0);
+ len = duk__push_this_obj_len_u32(thr);
+ duk_require_callable(thr, 0);
/* if thisArg not supplied, behave as if undefined was supplied */
if (iter_type == DUK__ITER_MAP || iter_type == DUK__ITER_FILTER) {
- duk_push_array(ctx);
+ duk_push_array(thr);
} else {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
}
/* stack[0] = callback
@@ -21474,9 +25617,9 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
k = 0; /* result index for filter() */
for (i = 0; i < len; i++) {
- DUK_ASSERT_TOP(ctx, 5);
+ DUK_ASSERT_TOP(thr, 5);
- if (!duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) {
+ if (!duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) {
#if defined(DUK_USE_NONSTD_ARRAY_MAP_TRAILER)
/* Real world behavior for map(): trailing non-existent
* elements don't invoke the user callback, but are still
@@ -21491,7 +25634,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
* counted towards result 'length'.
*/
#endif
- duk_pop(ctx);
+ duk_pop_undefined(thr);
continue;
}
@@ -21500,23 +25643,23 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
* effects.
*/
- duk_dup(ctx, 0);
- duk_dup(ctx, 1);
- duk_dup(ctx, -3);
- duk_push_u32(ctx, i);
- duk_dup(ctx, 2); /* [ ... val callback thisArg val i obj ] */
- duk_call_method(ctx, 3); /* -> [ ... val retval ] */
+ duk_dup_0(thr);
+ duk_dup_1(thr);
+ duk_dup_m3(thr);
+ duk_push_u32(thr, i);
+ duk_dup_2(thr); /* [ ... val callback thisArg val i obj ] */
+ duk_call_method(thr, 3); /* -> [ ... val retval ] */
switch (iter_type) {
case DUK__ITER_EVERY:
- bval = duk_to_boolean(ctx, -1);
+ bval = duk_to_boolean(thr, -1);
if (!bval) {
/* stack top contains 'false' */
return 1;
}
break;
case DUK__ITER_SOME:
- bval = duk_to_boolean(ctx, -1);
+ bval = duk_to_boolean(thr, -1);
if (bval) {
/* stack top contains 'true' */
return 1;
@@ -21526,15 +25669,15 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
/* nop */
break;
case DUK__ITER_MAP:
- duk_dup(ctx, -1);
- duk_xdef_prop_index_wec(ctx, 4, (duk_uarridx_t) i); /* retval to result[i] */
+ duk_dup_top(thr);
+ duk_xdef_prop_index_wec(thr, 4, (duk_uarridx_t) i); /* retval to result[i] */
res_length = i + 1;
break;
case DUK__ITER_FILTER:
- bval = duk_to_boolean(ctx, -1);
+ bval = duk_to_boolean(thr, -1);
if (bval) {
- duk_dup(ctx, -2); /* orig value */
- duk_xdef_prop_index_wec(ctx, 4, (duk_uarridx_t) k);
+ duk_dup_m2(thr); /* orig value */
+ duk_xdef_prop_index_wec(thr, 4, (duk_uarridx_t) k);
k++;
res_length = k;
}
@@ -21543,27 +25686,27 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
DUK_UNREACHABLE();
break;
}
- duk_pop_2(ctx);
+ duk_pop_2_unsafe(thr);
- DUK_ASSERT_TOP(ctx, 5);
+ DUK_ASSERT_TOP(thr, 5);
}
switch (iter_type) {
case DUK__ITER_EVERY:
- duk_push_true(ctx);
+ duk_push_true(thr);
break;
case DUK__ITER_SOME:
- duk_push_false(ctx);
+ duk_push_false(thr);
break;
case DUK__ITER_FOREACH:
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
break;
case DUK__ITER_MAP:
case DUK__ITER_FILTER:
- DUK_ASSERT_TOP(ctx, 5);
- DUK_ASSERT(duk_is_array(ctx, -1)); /* topmost element is the result array already */
- duk_push_u32(ctx, res_length);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
+ DUK_ASSERT_TOP(thr, 5);
+ DUK_ASSERT(duk_is_array(thr, -1)); /* topmost element is the result array already */
+ duk_push_u32(thr, res_length);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
break;
default:
DUK_UNREACHABLE();
@@ -21577,23 +25720,21 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
* reduce(), reduceRight()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_hthread *thr) {
duk_idx_t nargs;
duk_bool_t have_acc;
duk_uint32_t i, len;
- duk_small_int_t idx_step = duk_get_current_magic(ctx); /* idx_step is +1 for reduce, -1 for reduceRight */
+ duk_small_int_t idx_step = duk_get_current_magic(thr); /* idx_step is +1 for reduce, -1 for reduceRight */
/* We're a varargs function because we need to detect whether
* initialValue was given or not.
*/
- nargs = duk_get_top(ctx);
+ nargs = duk_get_top(thr);
DUK_DDD(DUK_DDDPRINT("nargs=%ld", (long) nargs));
- duk_set_top(ctx, 2);
- len = duk__push_this_obj_len_u32(ctx);
- if (!duk_is_callable(ctx, 0)) {
- goto type_error;
- }
+ duk_set_top(thr, 2);
+ len = duk__push_this_obj_len_u32(thr);
+ duk_require_callable(thr, 0);
/* stack[0] = callback fn
* stack[1] = initialValue
@@ -21604,11 +25745,11 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx) {
have_acc = 0;
if (nargs >= 2) {
- duk_dup(ctx, 1);
+ duk_dup_1(thr);
have_acc = 1;
}
DUK_DDD(DUK_DDDPRINT("have_acc=%ld, acc=%!T",
- (long) have_acc, (duk_tval *) duk_get_tval(ctx, 3)));
+ (long) have_acc, (duk_tval *) duk_get_tval(thr, 3)));
/* For len == 0, i is initialized to len - 1 which underflows.
* The condition (i < len) will then exit the for-loop on the
@@ -21618,82 +25759,83 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx) {
for (i = (idx_step >= 0 ? 0 : len - 1);
i < len; /* i >= 0 would always be true */
- i += idx_step) {
+ i += (duk_uint32_t) idx_step) {
DUK_DDD(DUK_DDDPRINT("i=%ld, len=%ld, have_acc=%ld, top=%ld, acc=%!T",
(long) i, (long) len, (long) have_acc,
- (long) duk_get_top(ctx),
- (duk_tval *) duk_get_tval(ctx, 4)));
+ (long) duk_get_top(thr),
+ (duk_tval *) duk_get_tval(thr, 4)));
- DUK_ASSERT((have_acc && duk_get_top(ctx) == 5) ||
- (!have_acc && duk_get_top(ctx) == 4));
+ DUK_ASSERT((have_acc && duk_get_top(thr) == 5) ||
+ (!have_acc && duk_get_top(thr) == 4));
- if (!duk_has_prop_index(ctx, 2, (duk_uarridx_t) i)) {
+ if (!duk_has_prop_index(thr, 2, (duk_uarridx_t) i)) {
continue;
}
if (!have_acc) {
- DUK_ASSERT_TOP(ctx, 4);
- duk_get_prop_index(ctx, 2, (duk_uarridx_t) i);
+ DUK_ASSERT_TOP(thr, 4);
+ duk_get_prop_index(thr, 2, (duk_uarridx_t) i);
have_acc = 1;
- DUK_ASSERT_TOP(ctx, 5);
+ DUK_ASSERT_TOP(thr, 5);
} else {
- DUK_ASSERT_TOP(ctx, 5);
- duk_dup(ctx, 0);
- duk_dup(ctx, 4);
- duk_get_prop_index(ctx, 2, (duk_uarridx_t) i);
- duk_push_u32(ctx, i);
- duk_dup(ctx, 2);
+ DUK_ASSERT_TOP(thr, 5);
+ duk_dup_0(thr);
+ duk_dup(thr, 4);
+ duk_get_prop_index(thr, 2, (duk_uarridx_t) i);
+ duk_push_u32(thr, i);
+ duk_dup_2(thr);
DUK_DDD(DUK_DDDPRINT("calling reduce function: func=%!T, prev=%!T, curr=%!T, idx=%!T, obj=%!T",
- (duk_tval *) duk_get_tval(ctx, -5), (duk_tval *) duk_get_tval(ctx, -4),
- (duk_tval *) duk_get_tval(ctx, -3), (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_call(ctx, 4);
- DUK_DDD(DUK_DDDPRINT("-> result: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
- duk_replace(ctx, 4);
- DUK_ASSERT_TOP(ctx, 5);
+ (duk_tval *) duk_get_tval(thr, -5), (duk_tval *) duk_get_tval(thr, -4),
+ (duk_tval *) duk_get_tval(thr, -3), (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
+ duk_call(thr, 4);
+ DUK_DDD(DUK_DDDPRINT("-> result: %!T", (duk_tval *) duk_get_tval(thr, -1)));
+ duk_replace(thr, 4);
+ DUK_ASSERT_TOP(thr, 5);
}
}
if (!have_acc) {
- goto type_error;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
- DUK_ASSERT_TOP(ctx, 5);
+ DUK_ASSERT_TOP(thr, 5);
return 1;
-
- type_error:
- return DUK_RET_TYPE_ERROR;
}
-#undef DUK__ARRAY_MID_JOIN_LIMIT
+#endif /* DUK_USE_ARRAY_BUILTIN */
+/* automatic undefs */
+#undef DUK__ARRAY_MID_JOIN_LIMIT
#undef DUK__ITER_EVERY
-#undef DUK__ITER_SOME
+#undef DUK__ITER_FILTER
#undef DUK__ITER_FOREACH
#undef DUK__ITER_MAP
-#undef DUK__ITER_FILTER
+#undef DUK__ITER_SOME
#line 1 "duk_bi_boolean.c"
/*
* Boolean built-ins
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
+
+#if defined(DUK_USE_BOOLEAN_BUILTIN)
/* Shared helper to provide toString() and valueOf(). Checks 'this', gets
* the primitive value to stack top, and optionally coerces with ToString().
*/
-DUK_INTERNAL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_hthread *thr) {
duk_tval *tv;
duk_hobject *h;
- duk_small_int_t coerce_tostring = duk_get_current_magic(ctx);
+ duk_small_int_t coerce_tostring = duk_get_current_magic(thr);
/* XXX: there is room to use a shared helper here, many built-ins
* check the 'this' type, and if it's an object, check its class,
* then get its internal value, etc.
*/
- duk_push_this(ctx);
- tv = duk_get_tval(ctx, -1);
+ duk_push_this(thr);
+ tv = duk_get_tval(thr, -1);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_BOOLEAN(tv)) {
@@ -21703,58 +25845,74 @@ DUK_INTERNAL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx
DUK_ASSERT(h != NULL);
if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_BOOLEAN) {
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
- DUK_ASSERT(duk_is_boolean(ctx, -1));
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
+ DUK_ASSERT(duk_is_boolean(thr, -1));
goto type_ok;
}
}
- return DUK_RET_TYPE_ERROR;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
+ /* never here */
type_ok:
if (coerce_tostring) {
- duk_to_string(ctx, -1);
+ duk_to_string(thr, -1);
}
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_boolean_constructor(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_boolean_constructor(duk_hthread *thr) {
duk_hobject *h_this;
- DUK_UNREF(thr);
+ duk_to_boolean(thr, 0);
- duk_to_boolean(ctx, 0);
-
- if (duk_is_constructor_call(ctx)) {
+ if (duk_is_constructor_call(thr)) {
/* XXX: helper; rely on Boolean.prototype as being non-writable, non-configurable */
- duk_push_this(ctx);
- h_this = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h_this != NULL);
+ duk_push_this(thr);
+ h_this = duk_known_hobject(thr, -1);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE]);
DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_BOOLEAN);
- duk_dup(ctx, 0); /* -> [ val obj val ] */
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); /* XXX: proper flags? */
+ duk_dup_0(thr); /* -> [ val obj val ] */
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); /* XXX: proper flags? */
} /* unbalanced stack */
return 1;
}
+
+#endif /* DUK_USE_BOOLEAN_BUILTIN */
#line 1 "duk_bi_buffer.c"
/*
- * Duktape.Buffer, Node.js Buffer, and Khronos/ES6 TypedArray built-ins
+ * ES2015 TypedArray and Node.js Buffer built-ins
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
- * Misc helpers
+ * Helpers for buffer handling, enabled with DUK_USE_BUFFEROBJECT_SUPPORT.
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Map DUK_HBUFFEROBJECT_ELEM_xxx to duk_hobject class number.
- * Sync with duk_hbufferobject.h and duk_hobject.h.
+/* Map class number (minus DUK_HOBJECT_CLASS_BUFOBJ_MIN) to a bidx for the
+ * default internal prototype.
+ */
+static const duk_uint8_t duk__buffer_proto_from_classnum[] = {
+ DUK_BIDX_ARRAYBUFFER_PROTOTYPE,
+ DUK_BIDX_DATAVIEW_PROTOTYPE,
+ DUK_BIDX_INT8ARRAY_PROTOTYPE,
+ DUK_BIDX_UINT8ARRAY_PROTOTYPE,
+ DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE,
+ DUK_BIDX_INT16ARRAY_PROTOTYPE,
+ DUK_BIDX_UINT16ARRAY_PROTOTYPE,
+ DUK_BIDX_INT32ARRAY_PROTOTYPE,
+ DUK_BIDX_UINT32ARRAY_PROTOTYPE,
+ DUK_BIDX_FLOAT32ARRAY_PROTOTYPE,
+ DUK_BIDX_FLOAT64ARRAY_PROTOTYPE
+};
+
+/* Map DUK_HBUFOBJ_ELEM_xxx to duk_hobject class number.
+ * Sync with duk_hbufobj.h and duk_hobject.h.
*/
static const duk_uint8_t duk__buffer_class_from_elemtype[9] = {
DUK_HOBJECT_CLASS_UINT8ARRAY,
@@ -21767,11 +25925,9 @@ static const duk_uint8_t duk__buffer_class_from_elemtype[9] = {
DUK_HOBJECT_CLASS_FLOAT32ARRAY,
DUK_HOBJECT_CLASS_FLOAT64ARRAY
};
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Map DUK_HBUFFEROBJECT_ELEM_xxx to prototype object built-in index.
- * Sync with duk_hbufferobject.h.
+/* Map DUK_HBUFOBJ_ELEM_xxx to prototype object built-in index.
+ * Sync with duk_hbufobj.h.
*/
static const duk_uint8_t duk__buffer_proto_from_elemtype[9] = {
DUK_BIDX_UINT8ARRAY_PROTOTYPE,
@@ -21784,11 +25940,8 @@ static const duk_uint8_t duk__buffer_proto_from_elemtype[9] = {
DUK_BIDX_FLOAT32ARRAY_PROTOTYPE,
DUK_BIDX_FLOAT64ARRAY_PROTOTYPE
};
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Map DUK__FLX_xxx to byte size.
- */
+/* Map DUK__FLD_xxx to byte size. */
static const duk_uint8_t duk__buffer_nbytes_from_fldtype[6] = {
1, /* DUK__FLD_8BIT */
2, /* DUK__FLD_16BIT */
@@ -21797,191 +25950,192 @@ static const duk_uint8_t duk__buffer_nbytes_from_fldtype[6] = {
8, /* DUK__FLD_DOUBLE */
0 /* DUK__FLD_VARINT; not relevant here */
};
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Bitfield for each DUK_HBUFFEROBJECT_ELEM_xxx indicating which element types
+/* Bitfield for each DUK_HBUFOBJ_ELEM_xxx indicating which element types
* are compatible with a blind byte copy for the TypedArray set() method (also
* used for TypedArray constructor). Array index is target buffer elem type,
* bitfield indicates compatible source types. The types must have same byte
* size and they must be coercion compatible.
*/
+#if !defined(DUK_USE_PREFER_SIZE)
static duk_uint16_t duk__buffer_elemtype_copy_compatible[9] = {
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT8 */
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT8) |
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED) |
- (1U << DUK_HBUFFEROBJECT_ELEM_INT8),
+ /* xxx -> DUK_HBUFOBJ_ELEM_UINT8 */
+ (1U << DUK_HBUFOBJ_ELEM_UINT8) |
+ (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED) |
+ (1U << DUK_HBUFOBJ_ELEM_INT8),
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED
+ /* xxx -> DUK_HBUFOBJ_ELEM_UINT8CLAMPED
* Note: INT8 is -not- copy compatible, e.g. -1 would coerce to 0x00.
*/
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT8) |
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED),
+ (1U << DUK_HBUFOBJ_ELEM_UINT8) |
+ (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED),
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_INT8 */
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT8) |
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED) |
- (1U << DUK_HBUFFEROBJECT_ELEM_INT8),
+ /* xxx -> DUK_HBUFOBJ_ELEM_INT8 */
+ (1U << DUK_HBUFOBJ_ELEM_UINT8) |
+ (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED) |
+ (1U << DUK_HBUFOBJ_ELEM_INT8),
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT16 */
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT16) |
- (1U << DUK_HBUFFEROBJECT_ELEM_INT16),
+ /* xxx -> DUK_HBUFOBJ_ELEM_UINT16 */
+ (1U << DUK_HBUFOBJ_ELEM_UINT16) |
+ (1U << DUK_HBUFOBJ_ELEM_INT16),
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_INT16 */
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT16) |
- (1U << DUK_HBUFFEROBJECT_ELEM_INT16),
+ /* xxx -> DUK_HBUFOBJ_ELEM_INT16 */
+ (1U << DUK_HBUFOBJ_ELEM_UINT16) |
+ (1U << DUK_HBUFOBJ_ELEM_INT16),
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT32 */
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT32) |
- (1U << DUK_HBUFFEROBJECT_ELEM_INT32),
+ /* xxx -> DUK_HBUFOBJ_ELEM_UINT32 */
+ (1U << DUK_HBUFOBJ_ELEM_UINT32) |
+ (1U << DUK_HBUFOBJ_ELEM_INT32),
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_INT32 */
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT32) |
- (1U << DUK_HBUFFEROBJECT_ELEM_INT32),
+ /* xxx -> DUK_HBUFOBJ_ELEM_INT32 */
+ (1U << DUK_HBUFOBJ_ELEM_UINT32) |
+ (1U << DUK_HBUFOBJ_ELEM_INT32),
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_FLOAT32 */
- (1U << DUK_HBUFFEROBJECT_ELEM_FLOAT32),
+ /* xxx -> DUK_HBUFOBJ_ELEM_FLOAT32 */
+ (1U << DUK_HBUFOBJ_ELEM_FLOAT32),
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_FLOAT64 */
- (1U << DUK_HBUFFEROBJECT_ELEM_FLOAT64)
+ /* xxx -> DUK_HBUFOBJ_ELEM_FLOAT64 */
+ (1U << DUK_HBUFOBJ_ELEM_FLOAT64)
};
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
+#endif /* !DUK_USE_PREFER_SIZE */
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Shared helper. */
-DUK_LOCAL duk_hbufferobject *duk__getrequire_bufobj_this(duk_context *ctx, duk_bool_t throw_flag) {
- duk_hthread *thr;
+DUK_LOCAL duk_hbufobj *duk__hbufobj_promote_this(duk_hthread *thr) {
+ duk_tval *tv_dst;
+ duk_hbufobj *res;
+
+ duk_push_this(thr);
+ DUK_ASSERT(duk_is_buffer(thr, -1));
+ res = (duk_hbufobj *) duk_to_hobject(thr, -1);
+ DUK_ASSERT_HBUFOBJ_VALID(res);
+ DUK_DD(DUK_DDPRINT("promoted 'this' automatically to an ArrayBuffer: %!iT", duk_get_tval(thr, -1)));
+
+ tv_dst = duk_get_borrowed_this_tval(thr);
+ DUK_TVAL_SET_OBJECT_UPDREF(thr, tv_dst, (duk_hobject *) res);
+ duk_pop(thr);
+
+ return res;
+}
+
+#define DUK__BUFOBJ_FLAG_THROW (1 << 0)
+#define DUK__BUFOBJ_FLAG_PROMOTE (1 << 1)
+
+/* Shared helper. When DUK__BUFOBJ_FLAG_PROMOTE is given, the return value is
+ * always a duk_hbufobj *. Without the flag the return value can also be a
+ * plain buffer, and the caller must check for it using DUK_HEAPHDR_IS_BUFFER().
+ */
+DUK_LOCAL duk_heaphdr *duk__getrequire_bufobj_this(duk_hthread *thr, duk_small_uint_t flags) {
duk_tval *tv;
- duk_hbufferobject *h_this;
+ duk_hbufobj *h_this;
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT(thr != NULL);
- tv = duk_get_borrowed_this_tval(ctx);
+ tv = duk_get_borrowed_this_tval(thr);
DUK_ASSERT(tv != NULL);
+
if (DUK_TVAL_IS_OBJECT(tv)) {
- h_this = (duk_hbufferobject *) DUK_TVAL_GET_OBJECT(tv);
+ h_this = (duk_hbufobj *) DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h_this != NULL);
- if (DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_this)) {
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_this);
- return h_this;
+ if (DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) h_this)) {
+ DUK_ASSERT_HBUFOBJ_VALID(h_this);
+ return (duk_heaphdr *) h_this;
+ }
+ } else if (DUK_TVAL_IS_BUFFER(tv)) {
+ if (flags & DUK__BUFOBJ_FLAG_PROMOTE) {
+ /* Promote a plain buffer to a Uint8Array. This is very
+ * inefficient but allows plain buffer to be used wherever an
+ * Uint8Array is used with very small cost; hot path functions
+ * like index read/write calls should provide direct buffer
+ * support to avoid promotion.
+ */
+ /* XXX: make this conditional to a flag if call sites need it? */
+ h_this = duk__hbufobj_promote_this(thr);
+ DUK_ASSERT(h_this != NULL);
+ DUK_ASSERT_HBUFOBJ_VALID(h_this);
+ return (duk_heaphdr *) h_this;
+ } else {
+ /* XXX: ugly, share return pointer for duk_hbuffer. */
+ return (duk_heaphdr *) DUK_TVAL_GET_BUFFER(tv);
}
}
- if (throw_flag) {
+ if (flags & DUK__BUFOBJ_FLAG_THROW) {
DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER);
}
return NULL;
}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Check that 'this' is a duk_hbufferobject and return a pointer to it. */
-DUK_LOCAL duk_hbufferobject *duk__get_bufobj_this(duk_context *ctx) {
- return duk__getrequire_bufobj_this(ctx, 0);
+/* Check that 'this' is a duk_hbufobj and return a pointer to it. */
+DUK_LOCAL duk_hbufobj *duk__get_bufobj_this(duk_hthread *thr) {
+ return (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_PROMOTE);
}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Check that 'this' is a duk_hbufferobject and return a pointer to it
+/* Check that 'this' is a duk_hbufobj and return a pointer to it
* (NULL if not).
*/
-DUK_LOCAL duk_hbufferobject *duk__require_bufobj_this(duk_context *ctx) {
- return duk__getrequire_bufobj_this(ctx, 1);
+DUK_LOCAL duk_hbufobj *duk__require_bufobj_this(duk_hthread *thr) {
+ return (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW | DUK__BUFOBJ_FLAG_PROMOTE);
}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Check that value is a duk_hbufferobject and return a pointer to it. */
-DUK_LOCAL duk_hbufferobject *duk__require_bufobj_value(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr;
+/* Check that value is a duk_hbufobj and return a pointer to it. */
+DUK_LOCAL duk_hbufobj *duk__require_bufobj_value(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- duk_hbufferobject *h_obj;
-
- thr = (duk_hthread *) ctx;
+ duk_hbufobj *h_obj;
/* Don't accept relative indices now. */
- DUK_ASSERT(index >= 0);
+ DUK_ASSERT(idx >= 0);
- tv = duk_require_tval(ctx, index);
+ tv = duk_require_tval(thr, idx);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_OBJECT(tv)) {
- h_obj = (duk_hbufferobject *) DUK_TVAL_GET_OBJECT(tv);
+ h_obj = (duk_hbufobj *) DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h_obj != NULL);
- if (DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_obj)) {
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_obj);
+ if (DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) h_obj)) {
+ DUK_ASSERT_HBUFOBJ_VALID(h_obj);
return h_obj;
}
+ } else if (DUK_TVAL_IS_BUFFER(tv)) {
+ h_obj = (duk_hbufobj *) duk_to_hobject(thr, idx);
+ DUK_ASSERT(h_obj != NULL);
+ DUK_ASSERT_HBUFOBJ_VALID(h_obj);
+ return h_obj;
}
DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER);
return NULL; /* not reachable */
}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_LOCAL void duk__set_bufobj_buffer(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_hbuffer *h_val) {
- duk_hthread *thr;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- DUK_ASSERT(ctx != NULL);
+DUK_LOCAL void duk__set_bufobj_buffer(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_hbuffer *h_val) {
+ DUK_ASSERT(thr != NULL);
DUK_ASSERT(h_bufobj != NULL);
DUK_ASSERT(h_bufobj->buf == NULL); /* no need to decref */
DUK_ASSERT(h_val != NULL);
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
+ DUK_UNREF(thr);
h_bufobj->buf = h_val;
DUK_HBUFFER_INCREF(thr, h_val);
h_bufobj->length = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_val);
DUK_ASSERT(h_bufobj->shift == 0);
- DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8);
+ DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFOBJ_ELEM_UINT8);
+ DUK_ASSERT(h_bufobj->is_typedarray == 0);
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
}
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_LOCAL duk_hbufferobject *duk__push_arraybuffer_with_length(duk_context *ctx, duk_uint_t len) {
- duk_hbuffer *h_val;
- duk_hbufferobject *h_bufobj;
-
- (void) duk_push_fixed_buffer(ctx, (duk_size_t) len);
- h_val = (duk_hbuffer *) duk_get_hbuffer(ctx, -1);
- DUK_ASSERT(h_val != NULL);
-
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
- DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
- DUK_ASSERT(h_bufobj != NULL);
-
- duk__set_bufobj_buffer(ctx, h_bufobj, h_val);
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
-
- return h_bufobj;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
/* Shared offset/length coercion helper. */
-DUK_LOCAL void duk__resolve_offset_opt_length(duk_context *ctx,
- duk_hbufferobject *h_bufarg,
+DUK_LOCAL void duk__resolve_offset_opt_length(duk_hthread *thr,
+ duk_hbufobj *h_bufarg,
duk_idx_t idx_offset,
duk_idx_t idx_length,
duk_uint_t *out_offset,
duk_uint_t *out_length,
duk_bool_t throw_flag) {
- duk_hthread *thr;
duk_int_t offset_signed;
duk_int_t length_signed;
duk_uint_t offset;
duk_uint_t length;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- offset_signed = duk_to_int(ctx, idx_offset);
+ offset_signed = duk_to_int(thr, idx_offset);
if (offset_signed < 0) {
goto fail_range;
}
@@ -21992,11 +26146,11 @@ DUK_LOCAL void duk__resolve_offset_opt_length(duk_context *ctx,
DUK_ASSERT_DISABLE(offset >= 0); /* unsigned */
DUK_ASSERT(offset <= h_bufarg->length);
- if (duk_is_undefined(ctx, idx_length)) {
+ if (duk_is_undefined(thr, idx_length)) {
DUK_ASSERT(h_bufarg->length >= offset);
length = h_bufarg->length - offset; /* >= 0 */
} else {
- length_signed = duk_to_int(ctx, idx_length);
+ length_signed = duk_to_int(thr, idx_length);
if (length_signed < 0) {
goto fail_range;
}
@@ -22021,35 +26175,30 @@ DUK_LOCAL void duk__resolve_offset_opt_length(duk_context *ctx,
return;
fail_range:
- DUK_ERROR_RANGE(thr, DUK_STR_INVALID_CALL_ARGS);
+ DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARGS);
}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
/* Shared lenient buffer length clamping helper. No negative indices, no
* element/byte shifting.
*/
-DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_context *ctx,
- duk_hbufferobject *h_bufobj,
+DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_hthread *thr,
+ duk_int_t buffer_length,
duk_idx_t idx_start,
duk_idx_t idx_end,
duk_int_t *out_start_offset,
duk_int_t *out_end_offset) {
- duk_int_t buffer_length;
duk_int_t start_offset;
duk_int_t end_offset;
DUK_ASSERT(out_start_offset != NULL);
DUK_ASSERT(out_end_offset != NULL);
- buffer_length = (duk_int_t) h_bufobj->length;
-
/* undefined coerces to zero which is correct */
- start_offset = duk_to_int_clamped(ctx, idx_start, 0, buffer_length);
- if (duk_is_undefined(ctx, idx_end)) {
+ start_offset = duk_to_int_clamped(thr, idx_start, 0, buffer_length);
+ if (duk_is_undefined(thr, idx_end)) {
end_offset = buffer_length;
} else {
- end_offset = duk_to_int_clamped(ctx, idx_end, start_offset, buffer_length);
+ end_offset = duk_to_int_clamped(thr, idx_end, start_offset, buffer_length);
}
DUK_ASSERT(start_offset >= 0);
@@ -22061,9 +26210,7 @@ DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_context *ctx,
*out_start_offset = start_offset;
*out_end_offset = end_offset;
}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
/* Shared lenient buffer length clamping helper. Indices are treated as
* element indices (though output values are byte offsets) which only
* really matters for TypedArray views as other buffer object have a zero
@@ -22071,35 +26218,34 @@ DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_context *ctx,
* indices are clamped to zero length; and final indices are clamped
* against input slice. Used for e.g. ArrayBuffer slice().
*/
-DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_context *ctx,
- duk_hbufferobject *h_bufobj,
+DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_hthread *thr,
+ duk_int_t buffer_length,
+ duk_uint8_t buffer_shift,
duk_idx_t idx_start,
duk_idx_t idx_end,
duk_int_t *out_start_offset,
duk_int_t *out_end_offset) {
- duk_int_t buffer_length;
duk_int_t start_offset;
duk_int_t end_offset;
DUK_ASSERT(out_start_offset != NULL);
DUK_ASSERT(out_end_offset != NULL);
- buffer_length = (duk_int_t) h_bufobj->length;
- buffer_length >>= h_bufobj->shift; /* as elements */
+ buffer_length >>= buffer_shift; /* as (full) elements */
/* Resolve start/end offset as element indices first; arguments
* at idx_start/idx_end are element offsets. Working with element
* indices first also avoids potential for wrapping.
*/
- start_offset = duk_to_int(ctx, idx_start);
+ start_offset = duk_to_int(thr, idx_start);
if (start_offset < 0) {
start_offset = buffer_length + start_offset;
}
- if (duk_is_undefined(ctx, idx_end)) {
+ if (duk_is_undefined(thr, idx_end)) {
end_offset = buffer_length;
} else {
- end_offset = duk_to_int(ctx, idx_end);
+ end_offset = duk_to_int(thr, idx_end);
if (end_offset < 0) {
end_offset = buffer_length + end_offset;
}
@@ -22123,60 +26269,98 @@ DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_context *ctx,
DUK_ASSERT(start_offset <= end_offset);
/* Convert indices to byte offsets. */
- start_offset <<= h_bufobj->shift;
- end_offset <<= h_bufobj->shift;
+ start_offset <<= buffer_shift;
+ end_offset <<= buffer_shift;
*out_start_offset = start_offset;
*out_end_offset = end_offset;
}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-/*
- * Indexed read/write helpers (also used from outside this file)
- */
+DUK_INTERNAL void duk_hbufobj_promote_plain(duk_hthread *thr, duk_idx_t idx) {
+ if (duk_is_buffer(thr, idx)) {
+ duk_to_object(thr, idx);
+ }
+}
-DUK_INTERNAL void duk_hbufferobject_push_validated_read(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
+DUK_INTERNAL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_hbuffer *h_buf) {
+ /* Push Uint8Array which will share the same underlying buffer as
+ * the plain buffer argument. Also create an ArrayBuffer with the
+ * same backing for the result .buffer property.
+ */
+
+ duk_push_hbuffer(thr, h_buf);
+ duk_push_buffer_object(thr, -1, 0, (duk_size_t) DUK_HBUFFER_GET_SIZE(h_buf), DUK_BUFOBJ_UINT8ARRAY);
+ duk_remove_m2(thr);
+
+#if 0
+ /* More verbose equivalent; maybe useful if e.g. .buffer is omitted. */
+ h_bufobj = duk_push_bufobj_raw(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BUFOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_UINT8ARRAY),
+ DUK_BIDX_UINT8ARRAY_PROTOTYPE);
+ DUK_ASSERT(h_bufobj != NULL);
+ duk__set_bufobj_buffer(thr, h_bufobj, h_buf);
+ h_bufobj->is_typedarray = 1;
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
+
+ h_arrbuf = duk_push_bufobj_raw(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BUFOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
+ DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
+ DUK_ASSERT(h_arrbuf != NULL);
+ duk__set_bufobj_buffer(thr, h_arrbuf, h_buf);
+ DUK_ASSERT(h_arrbuf->is_typedarray == 0);
+ DUK_ASSERT_HBUFOBJ_VALID(h_arrbuf);
+
+ DUK_ASSERT(h_bufobj->buf_prop == NULL);
+ h_bufobj->buf_prop = (duk_hobject *) h_arrbuf;
+ DUK_ASSERT(h_arrbuf != NULL);
+ DUK_HBUFOBJ_INCREF(thr, h_arrbuf);
+ duk_pop(thr);
+#endif
+}
+
+/* Indexed read helper for buffer objects, also called from outside this file. */
+DUK_INTERNAL void duk_hbufobj_push_validated_read(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
duk_double_union du;
DUK_MEMCPY((void *) du.uc, (const void *) p, (size_t) elem_size);
switch (h_bufobj->elem_type) {
- case DUK_HBUFFEROBJECT_ELEM_UINT8:
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
- case DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED:
-#endif
- duk_push_uint(ctx, (duk_uint_t) du.uc[0]);
+ case DUK_HBUFOBJ_ELEM_UINT8:
+ case DUK_HBUFOBJ_ELEM_UINT8CLAMPED:
+ duk_push_uint(thr, (duk_uint_t) du.uc[0]);
break;
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
- /* These are not needed when only Duktape.Buffer is supported. */
- case DUK_HBUFFEROBJECT_ELEM_INT8:
- duk_push_int(ctx, (duk_int_t) (duk_int8_t) du.uc[0]);
+ case DUK_HBUFOBJ_ELEM_INT8:
+ duk_push_int(thr, (duk_int_t) (duk_int8_t) du.uc[0]);
break;
- case DUK_HBUFFEROBJECT_ELEM_UINT16:
- duk_push_uint(ctx, (duk_uint_t) du.us[0]);
+ case DUK_HBUFOBJ_ELEM_UINT16:
+ duk_push_uint(thr, (duk_uint_t) du.us[0]);
break;
- case DUK_HBUFFEROBJECT_ELEM_INT16:
- duk_push_int(ctx, (duk_int_t) (duk_int16_t) du.us[0]);
+ case DUK_HBUFOBJ_ELEM_INT16:
+ duk_push_int(thr, (duk_int_t) (duk_int16_t) du.us[0]);
break;
- case DUK_HBUFFEROBJECT_ELEM_UINT32:
- duk_push_uint(ctx, (duk_uint_t) du.ui[0]);
+ case DUK_HBUFOBJ_ELEM_UINT32:
+ duk_push_uint(thr, (duk_uint_t) du.ui[0]);
break;
- case DUK_HBUFFEROBJECT_ELEM_INT32:
- duk_push_int(ctx, (duk_int_t) (duk_int32_t) du.ui[0]);
+ case DUK_HBUFOBJ_ELEM_INT32:
+ duk_push_int(thr, (duk_int_t) (duk_int32_t) du.ui[0]);
break;
- case DUK_HBUFFEROBJECT_ELEM_FLOAT32:
- duk_push_number(ctx, (duk_double_t) du.f[0]);
+ case DUK_HBUFOBJ_ELEM_FLOAT32:
+ duk_push_number(thr, (duk_double_t) du.f[0]);
break;
- case DUK_HBUFFEROBJECT_ELEM_FLOAT64:
- duk_push_number(ctx, (duk_double_t) du.d);
+ case DUK_HBUFOBJ_ELEM_FLOAT64:
+ duk_push_number(thr, (duk_double_t) du.d);
break;
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
default:
DUK_UNREACHABLE();
}
}
-DUK_INTERNAL void duk_hbufferobject_validated_write(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
+/* Indexed write helper for buffer objects, also called from outside this file. */
+DUK_INTERNAL void duk_hbufobj_validated_write(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
duk_double_union du;
/* NOTE! Caller must ensure that any side effects from the
@@ -22188,36 +26372,33 @@ DUK_INTERNAL void duk_hbufferobject_validated_write(duk_context *ctx, duk_hbuffe
*/
switch (h_bufobj->elem_type) {
- case DUK_HBUFFEROBJECT_ELEM_UINT8:
- du.uc[0] = (duk_uint8_t) duk_to_uint32(ctx, -1);
+ case DUK_HBUFOBJ_ELEM_UINT8:
+ du.uc[0] = (duk_uint8_t) duk_to_uint32(thr, -1);
break;
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
- /* These are not needed when only Duktape.Buffer is supported. */
- case DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED:
- du.uc[0] = (duk_uint8_t) duk_to_uint8clamped(ctx, -1);
+ case DUK_HBUFOBJ_ELEM_UINT8CLAMPED:
+ du.uc[0] = (duk_uint8_t) duk_to_uint8clamped(thr, -1);
break;
- case DUK_HBUFFEROBJECT_ELEM_INT8:
- du.uc[0] = (duk_uint8_t) duk_to_int32(ctx, -1);
+ case DUK_HBUFOBJ_ELEM_INT8:
+ du.uc[0] = (duk_uint8_t) duk_to_int32(thr, -1);
break;
- case DUK_HBUFFEROBJECT_ELEM_UINT16:
- du.us[0] = (duk_uint16_t) duk_to_uint32(ctx, -1);
+ case DUK_HBUFOBJ_ELEM_UINT16:
+ du.us[0] = (duk_uint16_t) duk_to_uint32(thr, -1);
break;
- case DUK_HBUFFEROBJECT_ELEM_INT16:
- du.us[0] = (duk_uint16_t) duk_to_int32(ctx, -1);
+ case DUK_HBUFOBJ_ELEM_INT16:
+ du.us[0] = (duk_uint16_t) duk_to_int32(thr, -1);
break;
- case DUK_HBUFFEROBJECT_ELEM_UINT32:
- du.ui[0] = (duk_uint32_t) duk_to_uint32(ctx, -1);
+ case DUK_HBUFOBJ_ELEM_UINT32:
+ du.ui[0] = (duk_uint32_t) duk_to_uint32(thr, -1);
break;
- case DUK_HBUFFEROBJECT_ELEM_INT32:
- du.ui[0] = (duk_uint32_t) duk_to_int32(ctx, -1);
+ case DUK_HBUFOBJ_ELEM_INT32:
+ du.ui[0] = (duk_uint32_t) duk_to_int32(thr, -1);
break;
- case DUK_HBUFFEROBJECT_ELEM_FLOAT32:
- du.f[0] = (duk_float_t) duk_to_number(ctx, -1);
+ case DUK_HBUFOBJ_ELEM_FLOAT32:
+ du.f[0] = (duk_float_t) duk_to_number_m1(thr);
break;
- case DUK_HBUFFEROBJECT_ELEM_FLOAT64:
- du.d = (duk_double_t) duk_to_number(ctx, -1);
+ case DUK_HBUFOBJ_ELEM_FLOAT64:
+ du.d = (duk_double_t) duk_to_number_m1(thr);
break;
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
default:
DUK_UNREACHABLE();
}
@@ -22225,187 +26406,110 @@ DUK_INTERNAL void duk_hbufferobject_validated_write(duk_context *ctx, duk_hbuffe
DUK_MEMCPY((void *) p, (const void *) du.uc, (size_t) elem_size);
}
-/*
- * Duktape.Buffer: constructor
+/* Helper to create a fixed buffer from argument value at index 0.
+ * Node.js and allocPlain() compatible.
*/
-
-DUK_INTERNAL duk_ret_t duk_bi_buffer_constructor(duk_context *ctx) {
- duk_hthread *thr;
- duk_size_t buf_size;
- duk_small_int_t buf_dynamic;
- duk_uint8_t *buf_data;
- const duk_uint8_t *src_data;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- /*
- * Constructor arguments are currently somewhat compatible with
- * (keep it that way if possible):
- *
- * http://nodejs.org/api/buffer.html
- *
- * Note that the ToBuffer() coercion (duk_to_buffer()) does NOT match
- * the constructor behavior.
- */
-
- buf_dynamic = duk_get_boolean(ctx, 1); /* default to false */
-
- switch (duk_get_type(ctx, 0)) {
- case DUK_TYPE_NUMBER: {
- /* new buffer of specified size */
- buf_size = (duk_size_t) duk_to_int(ctx, 0);
- (void) duk_push_buffer(ctx, buf_size, buf_dynamic);
- break;
- }
- case DUK_TYPE_BUFFER: {
- /* return input buffer, converted to a Duktape.Buffer object
- * if called as a constructor (no change if called as a
- * function).
- */
- duk_set_top(ctx, 1);
- break;
- }
- case DUK_TYPE_STRING: {
- /* new buffer with string contents */
- src_data = (const duk_uint8_t *) duk_get_lstring(ctx, 0, &buf_size);
- DUK_ASSERT(src_data != NULL); /* even for zero-length string */
- buf_data = (duk_uint8_t *) duk_push_buffer(ctx, buf_size, buf_dynamic);
- DUK_MEMCPY((void *) buf_data, (const void *) src_data, (size_t) buf_size);
- break;
- }
- case DUK_TYPE_OBJECT: {
- /* For all duk_hbufferobjects, get the plain buffer inside
- * without making a copy. This is compatible with Duktape 1.2
- * but means that a slice/view information is ignored and the
- * full underlying buffer is returned.
- *
- * If called as a constructor, a new Duktape.Buffer object
- * pointing to the same plain buffer is created below.
- */
- duk_hbufferobject *h_bufobj;
- h_bufobj = (duk_hbufferobject *) duk_get_hobject(ctx, 0);
- DUK_ASSERT(h_bufobj != NULL);
- if (!DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_bufobj)) {
- return DUK_RET_TYPE_ERROR;
- }
- if (h_bufobj->buf == NULL) {
- return DUK_RET_TYPE_ERROR;
- }
- duk_push_hbuffer(ctx, h_bufobj->buf);
- break;
- }
- case DUK_TYPE_NONE:
- default: {
- return DUK_RET_TYPE_ERROR;
- }
- }
- DUK_ASSERT(duk_is_buffer(ctx, -1));
-
- /* stack is unbalanced, but: [ buf ] */
-
- if (duk_is_constructor_call(ctx)) {
- duk_hbufferobject *h_bufobj;
- duk_hbuffer *h_val;
-
- h_val = duk_get_hbuffer(ctx, -1);
- DUK_ASSERT(h_val != NULL);
-
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER),
- DUK_BIDX_BUFFER_PROTOTYPE);
- DUK_ASSERT(h_bufobj != NULL);
-
- duk__set_bufobj_buffer(ctx, h_bufobj, h_val);
-
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
- }
- /* Note: unbalanced stack on purpose */
-
- return 1;
-}
-
-/*
- * Node.js Buffer: constructor
- */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx) {
- /* Internal class is Object: Object.prototype.toString.call(new Buffer(0))
- * prints "[object Object]".
- */
+DUK_LOCAL duk_hbuffer *duk__hbufobj_fixed_from_argvalue(duk_hthread *thr) {
duk_int_t len;
duk_int_t i;
- duk_hbuffer *h_buf;
- duk_hbufferobject *h_bufobj;
duk_size_t buf_size;
+ duk_uint8_t *buf;
- switch (duk_get_type(ctx, 0)) {
- case DUK_TYPE_BUFFER: {
- /* Custom behavior: plain buffer is used as internal buffer
- * without making a copy (matches Duktape.Buffer).
- */
- duk_set_top(ctx, 1); /* -> [ buffer ] */
+ switch (duk_get_type(thr, 0)) {
+ case DUK_TYPE_NUMBER: {
+ len = duk_to_int_clamped(thr, 0, 0, DUK_INT_MAX);
+ (void) duk_push_fixed_buffer_zero(thr, (duk_size_t) len);
break;
}
- case DUK_TYPE_NUMBER: {
- len = duk_to_int_clamped(ctx, 0, 0, DUK_INT_MAX);
- (void) duk_push_fixed_buffer(ctx, (duk_size_t) len);
- break;
+ case DUK_TYPE_BUFFER: { /* Treat like Uint8Array. */
+ goto slow_copy;
}
case DUK_TYPE_OBJECT: {
- duk_uint8_t *buf;
+ duk_hobject *h;
+ duk_hbufobj *h_bufobj;
- (void) duk_get_prop_string(ctx, 0, "length");
- len = duk_to_int_clamped(ctx, -1, 0, DUK_INT_MAX);
- duk_pop(ctx);
- buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len);
- for (i = 0; i < len; i++) {
- /* XXX: fast path for array arguments? */
- duk_get_prop_index(ctx, 0, (duk_uarridx_t) i);
- buf[i] = (duk_uint8_t) (duk_to_uint32(ctx, -1) & 0xffU);
- duk_pop(ctx);
+ /* For Node.js Buffers "Passing an ArrayBuffer returns a Buffer
+ * that shares allocated memory with the given ArrayBuffer."
+ * https://nodejs.org/api/buffer.html#buffer_buffer_from_buffer_alloc_and_buffer_allocunsafe
+ */
+
+ h = duk_known_hobject(thr, 0);
+ if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAYBUFFER) {
+ DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ(h));
+ h_bufobj = (duk_hbufobj *) h;
+ if (DUK_UNLIKELY(h_bufobj->buf == NULL)) {
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ }
+ if (DUK_UNLIKELY(h_bufobj->offset != 0 || h_bufobj->length != DUK_HBUFFER_GET_SIZE(h_bufobj->buf))) {
+ /* No support for ArrayBuffers with slice
+ * offset/length.
+ */
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ }
+ duk_push_hbuffer(thr, h_bufobj->buf);
+ return h_bufobj->buf;
}
- break;
+ goto slow_copy;
}
case DUK_TYPE_STRING: {
/* ignore encoding for now */
- duk_dup(ctx, 0);
- (void) duk_to_buffer(ctx, -1, &buf_size);
+ duk_require_hstring_notsymbol(thr, 0);
+ duk_dup_0(thr);
+ (void) duk_to_buffer(thr, -1, &buf_size);
break;
}
default:
- return DUK_RET_TYPE_ERROR;
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
}
- DUK_ASSERT(duk_is_buffer(ctx, -1));
- h_buf = duk_get_hbuffer(ctx, -1);
+ done:
+ DUK_ASSERT(duk_is_buffer(thr, -1));
+ return duk_known_hbuffer(thr, -1);
+
+ slow_copy:
+ /* XXX: fast path for typed arrays and other buffer objects? */
+
+ (void) duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
+ len = duk_to_int_clamped(thr, -1, 0, DUK_INT_MAX);
+ duk_pop(thr);
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) len); /* no zeroing, all indices get initialized */
+ for (i = 0; i < len; i++) {
+ /* XXX: fast path for array or buffer arguments? */
+ duk_get_prop_index(thr, 0, (duk_uarridx_t) i);
+ buf[i] = (duk_uint8_t) (duk_to_uint32(thr, -1) & 0xffU);
+ duk_pop(thr);
+ }
+ goto done;
+}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
+
+/*
+ * Node.js Buffer constructor
+ *
+ * Node.js Buffers are just Uint8Arrays with internal prototype set to
+ * Buffer.prototype so they're handled otherwise the same as Uint8Array.
+ * However, the constructor arguments are very different so a separate
+ * constructor entry point is used.
+ */
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_hthread *thr) {
+ duk_hbuffer *h_buf;
+
+ h_buf = duk__hbufobj_fixed_from_argvalue(thr);
DUK_ASSERT(h_buf != NULL);
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER),
- DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
- DUK_ASSERT(h_bufobj != NULL);
+ duk_push_buffer_object(thr,
+ -1,
+ 0,
+ DUK_HBUFFER_FIXED_GET_SIZE((duk_hbuffer_fixed *) h_buf),
+ DUK_BUFOBJ_UINT8ARRAY);
+ duk_push_hobject_bidx(thr, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
+ duk_set_prototype(thr, -2);
- h_bufobj->buf = h_buf;
- DUK_HBUFFER_INCREF(thr, h_buf);
- DUK_ASSERT(h_bufobj->offset == 0);
- h_bufobj->length = (duk_int_t) DUK_HBUFFER_GET_SIZE(h_buf);
- DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8);
-
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+ /* XXX: a more direct implementation */
return 1;
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
@@ -22413,84 +26517,53 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx) {
- duk_hthread *thr;
- duk_hbufferobject *h_bufobj;
+DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_hthread *thr) {
+ duk_hbufobj *h_bufobj;
duk_hbuffer *h_val;
+ duk_int_t len;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
+ DUK_ASSERT_CTX_VALID(thr);
- /* XXX: function flag to make this automatic? */
- if (!duk_is_constructor_call(ctx)) {
- return DUK_RET_TYPE_ERROR;
+ duk_require_constructor_call(thr);
+
+ len = duk_to_int(thr, 0);
+ if (len < 0) {
+ goto fail_length;
}
+ (void) duk_push_fixed_buffer_zero(thr, (duk_size_t) len);
+ h_val = (duk_hbuffer *) duk_known_hbuffer(thr, -1);
- if (duk_is_buffer(ctx, 0)) {
- /* Custom behavior: plain buffer is used as internal buffer
- * without making a copy (matches Duktape.Buffer).
- */
-
- h_val = duk_get_hbuffer(ctx, 0);
- DUK_ASSERT(h_val != NULL);
-
- /* XXX: accept any duk_hbufferobject type as an input also? */
- } else {
- duk_int_t len;
- len = duk_to_int(ctx, 0);
- if (len < 0) {
- goto fail_length;
- }
- (void) duk_push_fixed_buffer(ctx, (duk_size_t) len);
- h_val = (duk_hbuffer *) duk_get_hbuffer(ctx, -1);
- DUK_ASSERT(h_val != NULL);
-
-#if !defined(DUK_USE_ZERO_BUFFER_DATA)
- /* Khronos/ES6 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA
- * is not set.
- */
- DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) h_val));
- DUK_MEMZERO((void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_val), (duk_size_t) len);
-#endif
- }
-
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
- DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
+ h_bufobj = duk_push_bufobj_raw(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BUFOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
+ DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
DUK_ASSERT(h_bufobj != NULL);
- duk__set_bufobj_buffer(ctx, h_bufobj, h_val);
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+ duk__set_bufobj_buffer(thr, h_bufobj, h_val);
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
return 1;
fail_length:
- return DUK_RET_RANGE_ERROR;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
+ DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/* Format of magic, bits:
* 0...1: elem size shift (0-3)
- * 2...5: elem type (DUK_HBUFFEROBJECT_ELEM_xxx)
+ * 2...5: elem type (DUK_HBUFOBJ_ELEM_xxx)
+ *
+ * XXX: add prototype bidx explicitly to magic instead of using a mapping?
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
- duk_hthread *thr;
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_hthread *thr) {
duk_tval *tv;
duk_hobject *h_obj;
- duk_hbufferobject *h_bufobj = NULL;
- duk_hbufferobject *h_bufarr = NULL;
- duk_hbufferobject *h_bufarg = NULL;
+ duk_hbufobj *h_bufobj = NULL;
+ duk_hbufobj *h_bufarg = NULL;
duk_hbuffer *h_val;
duk_small_uint_t magic;
duk_small_uint_t shift;
@@ -22504,23 +26577,21 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
duk_uint_t byte_length;
duk_small_uint_t copy_mode;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
+ /* XXX: The same copy helpers could be shared with at least some
+ * buffer functions.
+ */
- /* XXX: function flag to make this automatic? */
- if (!duk_is_constructor_call(ctx)) {
- return DUK_RET_TYPE_ERROR;
- }
+ duk_require_constructor_call(thr);
/* We could fit built-in index into magic but that'd make the magic
* number dependent on built-in numbering (genbuiltins.py doesn't
* handle that yet). So map both class and prototype from the
* element type.
*/
- magic = duk_get_current_magic(ctx);
- shift = magic & 0x03; /* bits 0...1: shift */
- elem_type = (magic >> 2) & 0x0f; /* bits 2...5: type */
- elem_size = 1 << shift;
+ magic = (duk_small_uint_t) duk_get_current_magic(thr);
+ shift = magic & 0x03U; /* bits 0...1: shift */
+ elem_type = (magic >> 2) & 0x0fU; /* bits 2...5: type */
+ elem_size = 1U << shift;
align_mask = elem_size - 1;
DUK_ASSERT(elem_type < sizeof(duk__buffer_proto_from_elemtype) / sizeof(duk_uint8_t));
proto_bidx = duk__buffer_proto_from_elemtype[elem_type];
@@ -22538,7 +26609,13 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
* created.
*/
- tv = duk_get_tval(ctx, 0);
+ /* XXX: initial iteration to treat a plain buffer like an ArrayBuffer:
+ * coerce to an ArrayBuffer object and use that as .buffer. The underlying
+ * buffer will be the same but result .buffer !== inputPlainBuffer.
+ */
+ duk_hbufobj_promote_plain(thr, 0);
+
+ tv = duk_get_tval(thr, 0);
DUK_ASSERT(tv != NULL); /* arg count */
if (DUK_TVAL_IS_OBJECT(tv)) {
h_obj = DUK_TVAL_GET_OBJECT(tv);
@@ -22552,9 +26629,9 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
duk_int_t byte_offset_signed;
duk_uint_t byte_offset;
- h_bufarg = (duk_hbufferobject *) h_obj;
+ h_bufarg = (duk_hbufobj *) h_obj;
- byte_offset_signed = duk_to_int(ctx, 1);
+ byte_offset_signed = duk_to_int(thr, 1);
if (byte_offset_signed < 0) {
goto fail_arguments;
}
@@ -22564,7 +26641,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
/* Must be >= 0 and multiple of element size. */
goto fail_arguments;
}
- if (duk_is_undefined(ctx, 2)) {
+ if (duk_is_undefined(thr, 2)) {
DUK_ASSERT(h_bufarg->length >= byte_offset);
byte_length = h_bufarg->length - byte_offset;
if ((byte_length & align_mask) != 0) {
@@ -22575,7 +26652,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
}
elem_length = (byte_length >> shift);
} else {
- elem_length_signed = duk_to_int(ctx, 2);
+ elem_length_signed = duk_to_int(thr, 2);
if (elem_length_signed < 0) {
goto fail_arguments;
}
@@ -22599,14 +26676,14 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
DUK_ASSERT(byte_offset + byte_length <= h_bufarg->length);
DUK_ASSERT((elem_length << shift) == byte_length);
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(class_num),
- proto_bidx);
+ h_bufobj = duk_push_bufobj_raw(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BUFOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(class_num),
+ (duk_small_int_t) proto_bidx);
h_val = h_bufarg->buf;
if (h_val == NULL) {
- return DUK_RET_TYPE_ERROR;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
h_bufobj->buf = h_val;
DUK_HBUFFER_INCREF(thr, h_val);
@@ -22614,25 +26691,26 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
h_bufobj->length = byte_length;
h_bufobj->shift = (duk_uint8_t) shift;
h_bufobj->elem_type = (duk_uint8_t) elem_type;
- h_bufobj->is_view = 1;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+ h_bufobj->is_typedarray = 1;
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
/* Set .buffer to the argument ArrayBuffer. */
- duk_dup(ctx, 0);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
- duk_compact(ctx, -1);
+ DUK_ASSERT(h_bufobj->buf_prop == NULL);
+ h_bufobj->buf_prop = (duk_hobject *) h_bufarg;
+ DUK_ASSERT(h_bufarg != NULL);
+ DUK_HBUFOBJ_INCREF(thr, h_bufarg);
return 1;
- } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
- /* TypedArray (or other non-ArrayBuffer duk_hbufferobject).
+ } else if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
+ /* TypedArray (or other non-ArrayBuffer duk_hbufobj).
* Conceptually same behavior as for an Array-like argument,
* with a few fast paths.
*/
- h_bufarg = (duk_hbufferobject *) h_obj;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufarg);
+ h_bufarg = (duk_hbufobj *) h_obj;
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufarg);
elem_length_signed = (duk_int_t) (h_bufarg->length >> h_bufarg->shift);
if (h_bufarg->buf == NULL) {
- return DUK_RET_TYPE_ERROR;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
/* Select copy mode. Must take into account element
@@ -22649,8 +26727,12 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
(long) (elem_length_signed << shift)));
copy_mode = 2; /* default is explicit index read/write copy */
+#if !defined(DUK_USE_PREFER_SIZE)
+ /* With a size optimized build copy_mode 2 is enough.
+ * Modes 0 and 1 are faster but conceptually the same.
+ */
DUK_ASSERT(elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t));
- if (DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg)) {
+ if (DUK_HBUFOBJ_VALID_SLICE(h_bufarg)) {
if ((duk__buffer_elemtype_copy_compatible[elem_type] & (1 << h_bufarg->elem_type)) != 0) {
DUK_DDD(DUK_DDDPRINT("source/target are copy compatible, memcpy"));
DUK_ASSERT(shift == h_bufarg->shift); /* byte sizes will match */
@@ -22660,25 +26742,18 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
copy_mode = 1;
}
}
+#endif /* !DUK_USE_PREFER_SIZE */
} else {
/* Array or Array-like */
- elem_length_signed = (duk_int_t) duk_get_length(ctx, 0);
+ elem_length_signed = (duk_int_t) duk_get_length(thr, 0);
copy_mode = 2;
}
- } else if (DUK_TVAL_IS_BUFFER(tv)) {
- /* Accept plain buffer values like array initializers
- * (new in Duktape 1.4.0).
- */
- duk_hbuffer *h_srcbuf;
- h_srcbuf = DUK_TVAL_GET_BUFFER(tv);
- elem_length_signed = (duk_int_t) DUK_HBUFFER_GET_SIZE(h_srcbuf);
- copy_mode = 2; /* XXX: could add fast path for u8 compatible views */
} else {
/* Non-object argument is simply int coerced, matches
* V8 behavior (except for "null", which we coerce to
* 0 but V8 TypeErrors).
*/
- elem_length_signed = duk_to_int(ctx, 0);
+ elem_length_signed = duk_to_int(thr, 0);
copy_mode = 3;
}
if (elem_length_signed < 0) {
@@ -22697,20 +26772,22 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
/* ArrayBuffer argument is handled specially above; the rest of the
* argument variants are handled by shared code below.
+ *
+ * ArrayBuffer in h_bufobj->buf_prop is intentionally left unset.
+ * It will be automatically created by the .buffer accessor on
+ * first access.
*/
- /* Push a new ArrayBuffer (becomes view .buffer) */
- h_bufarr = duk__push_arraybuffer_with_length(ctx, byte_length);
- DUK_ASSERT(h_bufarr != NULL);
- h_val = h_bufarr->buf;
+ /* Push the resulting view object on top of a plain fixed buffer. */
+ (void) duk_push_fixed_buffer(thr, byte_length);
+ h_val = duk_known_hbuffer(thr, -1);
DUK_ASSERT(h_val != NULL);
- /* Push the resulting view object and attach the ArrayBuffer. */
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(class_num),
- proto_bidx);
+ h_bufobj = duk_push_bufobj_raw(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BUFOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(class_num),
+ (duk_small_int_t) proto_bidx);
h_bufobj->buf = h_val;
DUK_HBUFFER_INCREF(thr, h_val);
@@ -22718,13 +26795,8 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
h_bufobj->length = byte_length;
h_bufobj->shift = (duk_uint8_t) shift;
h_bufobj->elem_type = (duk_uint8_t) elem_type;
- h_bufobj->is_view = 1;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
-
- /* Set .buffer */
- duk_dup(ctx, -2);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
- duk_compact(ctx, -1);
+ h_bufobj->is_typedarray = 1;
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
/* Copy values, the copy method depends on the arguments.
*
@@ -22734,6 +26806,10 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
*/
DUK_DDD(DUK_DDDPRINT("copy mode: %d", (int) copy_mode));
switch (copy_mode) {
+ /* Copy modes 0 and 1 can be omitted in size optimized build,
+ * copy mode 2 handles them (but more slowly).
+ */
+#if !defined(DUK_USE_PREFER_SIZE)
case 0: {
/* Use byte copy. */
@@ -22742,13 +26818,13 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
DUK_ASSERT(h_bufobj != NULL);
DUK_ASSERT(h_bufobj->buf != NULL);
- DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj));
+ DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufobj));
DUK_ASSERT(h_bufarg != NULL);
DUK_ASSERT(h_bufarg->buf != NULL);
- DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg));
+ DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufarg));
- p_dst = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufobj);
- p_src = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg);
+ p_dst = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj);
+ p_src = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg);
DUK_DDD(DUK_DDDPRINT("using memcpy: p_src=%p, p_dst=%p, byte_length=%ld",
(void *) p_src, (void *) p_dst, (long) byte_length));
@@ -22767,16 +26843,16 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
DUK_ASSERT(h_bufobj != NULL);
DUK_ASSERT(h_bufobj->buf != NULL);
- DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj));
+ DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufobj));
DUK_ASSERT(h_bufarg != NULL);
DUK_ASSERT(h_bufarg->buf != NULL);
- DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg));
+ DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufarg));
- src_elem_size = 1 << h_bufarg->shift;
+ src_elem_size = (duk_small_uint_t) (1U << h_bufarg->shift);
dst_elem_size = elem_size;
- p_src = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg);
- p_dst = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufobj);
+ p_src = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg);
+ p_dst = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj);
p_src_end = p_src + h_bufarg->length;
DUK_DDD(DUK_DDDPRINT("using fast copy: p_src=%p, p_src_end=%p, p_dst=%p, "
@@ -22791,14 +26867,15 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
/* A validated read() is always a number, so it's write coercion
* is always side effect free an won't invalidate pointers etc.
*/
- duk_hbufferobject_push_validated_read(ctx, h_bufarg, p_src, src_elem_size);
- duk_hbufferobject_validated_write(ctx, h_bufobj, p_dst, dst_elem_size);
- duk_pop(ctx);
+ duk_hbufobj_push_validated_read(thr, h_bufarg, p_src, src_elem_size);
+ duk_hbufobj_validated_write(thr, h_bufobj, p_dst, dst_elem_size);
+ duk_pop(thr);
p_src += src_elem_size;
p_dst += dst_elem_size;
}
break;
}
+#endif /* !DUK_USE_PREFER_SIZE */
case 2: {
/* Copy values by index reads and writes. Let virtual
* property handling take care of coercion.
@@ -22808,8 +26885,8 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
DUK_DDD(DUK_DDDPRINT("using slow copy"));
for (i = 0; i < elem_length; i++) {
- duk_get_prop_index(ctx, 0, (duk_uarridx_t) i);
- duk_put_prop_index(ctx, -2, (duk_uarridx_t) i);
+ duk_get_prop_index(thr, 0, (duk_uarridx_t) i);
+ duk_put_prop_index(thr, -2, (duk_uarridx_t) i);
}
break;
}
@@ -22819,13 +26896,6 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
* ambiguity with Float32/Float64 because zero bytes also
* represent 0.0.
*/
-#if !defined(DUK_USE_ZERO_BUFFER_DATA)
- /* Khronos/ES6 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA
- * is not set.
- */
- DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) h_val));
- DUK_MEMZERO((void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_val), (duk_size_t) byte_length);
-#endif
DUK_DDD(DUK_DDDPRINT("using no copy"));
break;
@@ -22835,76 +26905,84 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
return 1;
fail_arguments:
- return DUK_RET_RANGE_ERROR;
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr);
}
#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
+/* When bufferobject support is disabled, new Uint8Array() could still be
+ * supported to create a plain fixed buffer. Disabled for now.
+ */
+#if 0
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_hthread *thr) {
+ duk_int_t elem_length_signed;
+ duk_uint_t byte_length;
+
+ /* XXX: The same copy helpers could be shared with at least some
+ * buffer functions.
+ */
+
+ duk_require_constructor_call(thr);
+
+ elem_length_signed = duk_require_int(thr, 0);
+ if (elem_length_signed < 0) {
+ goto fail_arguments;
+ }
+ byte_length = (duk_uint_t) elem_length_signed;
+
+ (void) duk_push_fixed_buffer_zero(thr, (duk_size_t) byte_length);
+ return 1;
+
+ fail_arguments:
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr);
}
+#endif /* 0 */
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx) {
- duk_hbufferobject *h_bufarg;
- duk_hbufferobject *h_bufobj;
+DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_hthread *thr) {
+ duk_hbufobj *h_bufarg;
+ duk_hbufobj *h_bufobj;
duk_hbuffer *h_val;
duk_uint_t offset;
duk_uint_t length;
- /* XXX: function flag to make this automatic? */
- if (!duk_is_constructor_call(ctx)) {
- return DUK_RET_TYPE_ERROR;
+ duk_require_constructor_call(thr);
+
+ h_bufarg = duk__require_bufobj_value(thr, 0);
+ DUK_ASSERT(h_bufarg != NULL);
+ if (DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_bufarg) != DUK_HOBJECT_CLASS_ARRAYBUFFER) {
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
- h_bufarg = duk__require_bufobj_value(ctx, 0);
- DUK_ASSERT(h_bufarg != NULL);
-
- duk__resolve_offset_opt_length(ctx, h_bufarg, 1, 2, &offset, &length, 1 /*throw_flag*/);
+ duk__resolve_offset_opt_length(thr, h_bufarg, 1, 2, &offset, &length, 1 /*throw_flag*/);
DUK_ASSERT(offset <= h_bufarg->length);
DUK_ASSERT(offset + length <= h_bufarg->length);
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATAVIEW),
- DUK_BIDX_DATAVIEW_PROTOTYPE);
+ h_bufobj = duk_push_bufobj_raw(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BUFOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATAVIEW),
+ DUK_BIDX_DATAVIEW_PROTOTYPE);
h_val = h_bufarg->buf;
if (h_val == NULL) {
- return DUK_RET_TYPE_ERROR;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
h_bufobj->buf = h_val;
DUK_HBUFFER_INCREF(thr, h_val);
h_bufobj->offset = h_bufarg->offset + offset;
h_bufobj->length = length;
DUK_ASSERT(h_bufobj->shift == 0);
- DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8);
- h_bufobj->is_view = 1;
+ DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFOBJ_ELEM_UINT8);
+ DUK_ASSERT(h_bufobj->is_typedarray == 0);
- /* The DataView .buffer property is ordinarily set to the argument
- * which is an ArrayBuffer. We accept any duk_hbufferobject as
- * an argument and .buffer will be set to the argument regardless
- * of what it is. This may be a bit confusing if the argument
- * is e.g. a DataView or another TypedArray view.
- *
- * XXX: Copy .buffer property from a DataView/TypedArray argument?
- * Create a fresh ArrayBuffer for Duktape.Buffer and Node.js Buffer
- * arguments? See: test-bug-dataview-buffer-prop.js.
- */
+ DUK_ASSERT(h_bufobj->buf_prop == NULL);
+ h_bufobj->buf_prop = (duk_hobject *) h_bufarg;
+ DUK_ASSERT(h_bufarg != NULL);
+ DUK_HBUFOBJ_INCREF(thr, h_bufarg);
- duk_dup(ctx, 0);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
- duk_compact(ctx, -1);
-
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
return 1;
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
@@ -22912,21 +26990,64 @@ DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_hthread *thr) {
duk_hobject *h_obj;
duk_bool_t ret = 0;
- h_obj = duk_get_hobject(ctx, 0);
- if (h_obj != NULL && DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
- ret = ((duk_hbufferobject *) h_obj)->is_view;
+ if (duk_is_buffer(thr, 0)) {
+ ret = 1;
+ } else {
+ h_obj = duk_get_hobject(thr, 0);
+ if (h_obj != NULL && DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
+ /* DataView needs special casing: ArrayBuffer.isView() is
+ * true, but ->is_typedarray is 0.
+ */
+ ret = ((duk_hbufobj *) h_obj)->is_typedarray ||
+ (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_DATAVIEW);
+ }
}
- duk_push_boolean(ctx, ret);
+ duk_push_boolean(thr, ret);
return 1;
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
+
+/*
+ * Uint8Array.allocPlain()
+ */
+
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+DUK_INTERNAL duk_ret_t duk_bi_uint8array_allocplain(duk_hthread *thr) {
+ duk__hbufobj_fixed_from_argvalue(thr);
+ return 1;
+}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
+
+/*
+ * Uint8Array.plainOf()
+ */
+
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+DUK_INTERNAL duk_ret_t duk_bi_uint8array_plainof(duk_hthread *thr) {
+ duk_hbufobj *h_bufobj;
+
+#if !defined(DUK_USE_PREFER_SIZE)
+ /* Avoid churn if argument is already a plain buffer. */
+ if (duk_is_buffer(thr, 0)) {
+ return 1;
+ }
+#endif
+
+ /* Promotes plain buffers to ArrayBuffers, so for a plain buffer
+ * argument we'll create a pointless temporary (but still work
+ * correctly).
+ */
+ h_bufobj = duk__require_bufobj_value(thr, 0);
+ if (h_bufobj->buf == NULL) {
+ duk_push_undefined(thr);
+ } else {
+ duk_push_hbuffer(thr, h_bufobj->buf);
+ }
+ return 1;
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
@@ -22935,116 +27056,57 @@ DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) {
- duk_hthread *thr;
- duk_hbufferobject *h_this;
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_hthread *thr) {
+ duk_hbufobj *h_this;
duk_int_t start_offset, end_offset;
duk_uint8_t *buf_slice;
duk_size_t slice_length;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_this = duk__get_bufobj_this(ctx);
+ h_this = duk__get_bufobj_this(thr);
if (h_this == NULL) {
/* XXX: happens e.g. when evaluating: String(Buffer.prototype). */
- duk_push_string(ctx, "[object Object]");
+ duk_push_string(thr, "[object Object]");
return 1;
}
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_this);
+ DUK_ASSERT_HBUFOBJ_VALID(h_this);
- /* ignore encoding for now */
+ /* Ignore encoding for now. */
- duk__clamp_startend_nonegidx_noshift(ctx, h_this, 1 /*idx_start*/, 2 /*idx_end*/, &start_offset, &end_offset);
+ duk__clamp_startend_nonegidx_noshift(thr,
+ (duk_int_t) h_this->length,
+ 1 /*idx_start*/,
+ 2 /*idx_end*/,
+ &start_offset,
+ &end_offset);
slice_length = (duk_size_t) (end_offset - start_offset);
- buf_slice = (duk_uint8_t *) duk_push_fixed_buffer(ctx, slice_length);
+ buf_slice = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, slice_length); /* all bytes initialized below */
DUK_ASSERT(buf_slice != NULL);
- if (h_this->buf == NULL) {
- goto type_error;
+ /* Neutered or uncovered, TypeError. */
+ if (h_this->buf == NULL ||
+ !DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, (duk_size_t) start_offset + slice_length)) {
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
- if (DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_this, start_offset + slice_length)) {
- DUK_MEMCPY((void *) buf_slice,
- (const void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
- (size_t) slice_length);
- } else {
- /* not covered, return all zeroes */
- ;
- }
+ /* XXX: ideally we wouldn't make a copy but a view into the buffer for the
+ * decoding process. Or the decoding helper could be changed to accept
+ * the slice info (a buffer pointer is NOT a good approach because guaranteeing
+ * its stability is difficult).
+ */
- duk_to_string(ctx, -1);
- return 1;
+ DUK_ASSERT(DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, (duk_size_t) start_offset + slice_length));
+ DUK_MEMCPY((void *) buf_slice,
+ (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
+ (size_t) slice_length);
- type_error:
- return DUK_RET_TYPE_ERROR;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-/*
- * Duktape.Buffer: toString(), valueOf()
- */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx) {
- duk_hthread *thr;
- duk_tval *tv;
- duk_small_int_t to_string = duk_get_current_magic(ctx);
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- tv = duk_get_borrowed_this_tval(ctx);
- DUK_ASSERT(tv != NULL);
-
- if (DUK_TVAL_IS_BUFFER(tv)) {
- duk_hbuffer *h_buf;
- h_buf = DUK_TVAL_GET_BUFFER(tv);
- DUK_ASSERT(h_buf != NULL);
- duk_push_hbuffer(ctx, h_buf);
- } else if (DUK_TVAL_IS_OBJECT(tv)) {
- duk_hobject *h;
- duk_hbufferobject *h_bufobj;
-
- /* Accept any duk_hbufferobject, though we're only normally
- * called for Duktape.Buffer values.
- */
- h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
- if (!DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
- DUK_DD(DUK_DDPRINT("toString/valueOf() called for a non-bufferobject object"));
- goto type_error;
- }
- h_bufobj = (duk_hbufferobject *) h;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
-
- if (h_bufobj->buf == NULL) {
- DUK_DD(DUK_DDPRINT("toString/valueOf() called for a bufferobject with NULL buf"));
- goto type_error;
- }
- duk_push_hbuffer(ctx, h_bufobj->buf);
- } else {
- goto type_error;
- }
-
- if (to_string) {
- duk_to_string(ctx, -1);
- }
- return 1;
-
- type_error:
- return DUK_RET_TYPE_ERROR;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
+ /* Use the equivalent of: new TextEncoder().encode(this) to convert the
+ * string. Result will be valid UTF-8; non-CESU-8 inputs are currently
+ * interpreted loosely. Value stack convention is a bit odd for now.
+ */
+ duk_replace(thr, 0);
+ duk_set_top(thr, 1);
+ return duk_textdecoder_decode_utf8_nodejs(thr);
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
@@ -23053,48 +27115,40 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx)
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx) {
- duk_hthread *thr;
- duk_hbufferobject *h_this;
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_hthread *thr) {
+ duk_hbufobj *h_this;
duk_uint8_t *buf;
- duk_uint_t i;
+ duk_uint_t i, n;
+ duk_tval *tv;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
- h_this = duk__require_bufobj_this(ctx);
+ h_this = duk__require_bufobj_this(thr);
DUK_ASSERT(h_this != NULL);
- if (h_this->buf == NULL || !DUK_HBUFFEROBJECT_VALID_SLICE(h_this)) {
+ if (h_this->buf == NULL || !DUK_HBUFOBJ_VALID_SLICE(h_this)) {
/* Serialize uncovered backing buffer as a null; doesn't
* really matter as long we're memory safe.
*/
- duk_push_null(ctx);
+ duk_push_null(thr);
return 1;
}
- duk_push_object(ctx);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_UC_BUFFER);
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_TYPE);
+ duk_push_object(thr);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_UC_BUFFER);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_TYPE);
- duk_push_array(ctx);
- for (i = 0; i < h_this->length; i++) {
- /* XXX: regetting the pointer may be overkill - we're writing
- * to a side-effect free array here.
- */
- DUK_ASSERT(h_this->buf != NULL);
- buf = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this);
- duk_push_uint(ctx, (duk_uint_t) buf[i]);
- duk_put_prop_index(ctx, -2, (duk_idx_t) i);
+ /* XXX: uninitialized would be OK */
+ DUK_ASSERT_DISABLE((duk_size_t) h_this->length <= (duk_size_t) DUK_UINT32_MAX);
+ tv = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) h_this->length); /* XXX: needs revision with >4G buffers */
+
+ DUK_ASSERT(h_this->buf != NULL);
+ buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this);
+ for (i = 0, n = h_this->length; i < n; i++) {
+ DUK_TVAL_SET_U32(tv + i, (duk_uint32_t) buf[i]); /* no need for decref or incref */
}
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_DATA);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_DATA);
return 1;
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
@@ -23104,24 +27158,22 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) {
- duk_hthread *thr;
+DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_hthread *thr) {
duk_small_uint_t magic;
- duk_hbufferobject *h_bufarg1;
- duk_hbufferobject *h_bufarg2;
+ duk_hbufobj *h_bufarg1;
+ duk_hbufobj *h_bufarg2;
duk_small_int_t comp_res;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
+ /* XXX: keep support for plain buffers and non-Node.js buffers? */
- magic = duk_get_current_magic(ctx);
- if (magic & 0x02) {
+ magic = (duk_small_uint_t) duk_get_current_magic(thr);
+ if (magic & 0x02U) {
/* Static call style. */
- h_bufarg1 = duk__require_bufobj_value(ctx, 0);
- h_bufarg2 = duk__require_bufobj_value(ctx, 1);
+ h_bufarg1 = duk__require_bufobj_value(thr, 0);
+ h_bufarg2 = duk__require_bufobj_value(thr, 1);
} else {
- h_bufarg1 = duk__require_bufobj_this(ctx);
- h_bufarg2 = duk__require_bufobj_value(ctx, 0);
+ h_bufarg1 = duk__require_bufobj_this(thr);
+ h_bufarg2 = duk__require_bufobj_value(thr, 0);
}
DUK_ASSERT(h_bufarg1 != NULL);
DUK_ASSERT(h_bufarg2 != NULL);
@@ -23132,8 +27184,8 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) {
* matters is to be memory safe.
*/
- if (DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg1) &&
- DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg2)) {
+ if (DUK_HBUFOBJ_VALID_SLICE(h_bufarg1) &&
+ DUK_HBUFOBJ_VALID_SLICE(h_bufarg2)) {
comp_res = duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg1->buf) + h_bufarg1->offset,
(const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg2->buf) + h_bufarg2->offset,
(duk_size_t) h_bufarg1->length,
@@ -23142,21 +27194,16 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) {
comp_res = -1; /* either nonzero value is ok */
}
- if (magic & 0x01) {
+ if (magic & 0x01U) {
/* compare: similar to string comparison but for buffer data. */
- duk_push_int(ctx, comp_res);
+ duk_push_int(thr, comp_res);
} else {
/* equals */
- duk_push_boolean(ctx, (comp_res == 0));
+ duk_push_boolean(thr, (comp_res == 0));
}
return 1;
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
@@ -23164,9 +27211,8 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
- duk_hthread *thr;
- duk_hbufferobject *h_this;
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_hthread *thr) {
+ duk_hbufobj *h_this;
const duk_uint8_t *fill_str_ptr;
duk_size_t fill_str_len;
duk_uint8_t fill_value;
@@ -23175,29 +27221,32 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
duk_size_t fill_length;
duk_uint8_t *p;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_this = duk__require_bufobj_this(ctx);
+ h_this = duk__require_bufobj_this(thr);
DUK_ASSERT(h_this != NULL);
if (h_this->buf == NULL) {
- return DUK_RET_TYPE_ERROR;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
/* [ value offset end ] */
- if (duk_is_string(ctx, 0)) {
- fill_str_ptr = (const duk_uint8_t *) duk_get_lstring(ctx, 0, &fill_str_len);
+ if (duk_is_string_notsymbol(thr, 0)) {
+ fill_str_ptr = (const duk_uint8_t *) duk_get_lstring(thr, 0, &fill_str_len);
DUK_ASSERT(fill_str_ptr != NULL);
} else {
- fill_value = (duk_uint8_t) duk_to_uint32(ctx, 0);
+ /* Symbols get ToNumber() coerced and cause TypeError. */
+ fill_value = (duk_uint8_t) duk_to_uint32(thr, 0);
fill_str_ptr = (const duk_uint8_t *) &fill_value;
fill_str_len = 1;
}
/* Fill offset handling is more lenient than in Node.js. */
- duk__clamp_startend_nonegidx_noshift(ctx, h_this, 1 /*idx_start*/, 2 /*idx_end*/, &fill_offset, &fill_end);
+ duk__clamp_startend_nonegidx_noshift(thr,
+ (duk_int_t) h_this->length,
+ 1 /*idx_start*/,
+ 2 /*idx_end*/,
+ &fill_offset,
+ &fill_end);
DUK_DDD(DUK_DDDPRINT("fill: fill_value=%02x, fill_offset=%ld, fill_end=%ld, view length=%ld",
(unsigned int) fill_value, (long) fill_offset, (long) fill_end, (long) h_this->length));
@@ -23205,7 +27254,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
DUK_ASSERT(fill_end - fill_offset >= 0);
DUK_ASSERT(h_this->buf != NULL);
- p = (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + fill_offset);
+ p = (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + fill_offset);
fill_length = (duk_size_t) (fill_end - fill_offset);
if (fill_str_len == 1) {
/* Handle single character fills as memset() even when
@@ -23215,7 +27264,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
} else if (fill_str_len > 1) {
duk_size_t i, n, t;
- for (i = 0, n = (fill_end - fill_offset), t = 0; i < n; i++) {
+ for (i = 0, n = (duk_size_t) (fill_end - fill_offset), t = 0; i < n; i++) {
p[i] = fill_str_ptr[t++];
if (t >= fill_str_len) {
t = 0;
@@ -23226,14 +27275,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
}
/* Return the Buffer to allow chaining: b.fill(0x11).fill(0x22, 3, 5).toString() */
- duk_push_this(ctx);
+ duk_push_this(thr);
return 1;
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
@@ -23241,24 +27285,21 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) {
- duk_hthread *thr;
- duk_hbufferobject *h_this;
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_hthread *thr) {
+ duk_hbufobj *h_this;
duk_uint_t offset;
duk_uint_t length;
const duk_uint8_t *str_data;
duk_size_t str_len;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_this = duk__require_bufobj_this(ctx);
+ /* XXX: very inefficient support for plain buffers */
+ h_this = duk__require_bufobj_this(thr);
DUK_ASSERT(h_this != NULL);
/* Argument must be a string, e.g. a buffer is not allowed. */
- str_data = (const duk_uint8_t *) duk_require_lstring(ctx, 0, &str_len);
+ str_data = (const duk_uint8_t *) duk_require_lstring_notsymbol(thr, 0, &str_len);
- duk__resolve_offset_opt_length(ctx, h_this, 1, 2, &offset, &length, 0 /*throw_flag*/);
+ duk__resolve_offset_opt_length(thr, h_this, 1, 2, &offset, &length, 0 /*throw_flag*/);
DUK_ASSERT(offset <= h_this->length);
DUK_ASSERT(offset + length <= h_this->length);
@@ -23268,23 +27309,18 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) {
length = (duk_uint_t) str_len;
}
- if (DUK_HBUFFEROBJECT_VALID_SLICE(h_this)) {
+ if (DUK_HBUFOBJ_VALID_SLICE(h_this)) {
/* Cannot overlap. */
- DUK_MEMCPY((void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + offset),
+ DUK_MEMCPY((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + offset),
(const void *) str_data,
(size_t) length);
} else {
DUK_DDD(DUK_DDDPRINT("write() target buffer is not covered, silent ignore"));
}
- duk_push_uint(ctx, length);
+ duk_push_uint(thr, length);
return 1;
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
@@ -23292,10 +27328,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
- duk_hthread *thr;
- duk_hbufferobject *h_this;
- duk_hbufferobject *h_bufarg;
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_hthread *thr) {
+ duk_hbufobj *h_this;
+ duk_hbufobj *h_bufarg;
duk_int_t source_length;
duk_int_t target_length;
duk_int_t target_start, source_start, source_end;
@@ -23304,22 +27339,19 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
/* [ targetBuffer targetStart sourceStart sourceEnd ] */
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_this = duk__require_bufobj_this(ctx);
- h_bufarg = duk__require_bufobj_value(ctx, 0);
+ h_this = duk__require_bufobj_this(thr);
+ h_bufarg = duk__require_bufobj_value(thr, 0);
DUK_ASSERT(h_this != NULL);
DUK_ASSERT(h_bufarg != NULL);
source_length = (duk_int_t) h_this->length;
target_length = (duk_int_t) h_bufarg->length;
- target_start = duk_to_int(ctx, 1);
- source_start = duk_to_int(ctx, 2);
- if (duk_is_undefined(ctx, 3)) {
+ target_start = duk_to_int(thr, 1);
+ source_start = duk_to_int(thr, 2);
+ if (duk_is_undefined(thr, 3)) {
source_end = source_length;
} else {
- source_end = duk_to_int(ctx, 3);
+ source_end = duk_to_int(thr, 3);
}
DUK_DDD(DUK_DDDPRINT("checking copy args: target_start=%ld, target_length=%ld, "
@@ -23343,7 +27375,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
}
if (source_uend >= (duk_uint_t) source_length) {
/* Source end clamped silently to available length. */
- source_uend = source_length;
+ source_uend = (duk_uint_t) source_length;
}
copy_size = source_uend - source_ustart;
if (target_ustart + copy_size > (duk_uint_t) target_length) {
@@ -23372,13 +27404,13 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
/* Ensure copy is covered by underlying buffers. */
DUK_ASSERT(h_bufarg->buf != NULL); /* length check */
DUK_ASSERT(h_this->buf != NULL); /* length check */
- if (DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufarg, target_ustart + copy_size) &&
- DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_this, source_ustart + copy_size)) {
+ if (DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufarg, target_ustart + copy_size) &&
+ DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, source_ustart + copy_size)) {
/* Must use memmove() because copy area may overlap (source and target
* buffer may be the same, or from different slices.
*/
- DUK_MEMMOVE((void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg) + target_ustart),
- (const void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + source_ustart),
+ DUK_MEMMOVE((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg) + target_ustart),
+ (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + source_ustart),
(size_t) copy_size);
} else {
DUK_DDD(DUK_DDDPRINT("buffer copy not covered by underlying buffer(s), ignoring"));
@@ -23389,16 +27421,11 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
* The return value matters because of code like:
* "off += buf.copy(...)".
*/
- duk_push_uint(ctx, copy_size);
+ duk_push_uint(thr, copy_size);
return 1;
fail_bounds:
- return DUK_RET_RANGE_ERROR;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr);
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
@@ -23439,59 +27466,58 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
- duk_hthread *thr;
- duk_hbufferobject *h_this;
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_hthread *thr) {
+ duk_hbufobj *h_this;
duk_hobject *h_obj;
duk_uarridx_t i, n;
duk_int_t offset_signed;
duk_uint_t offset_elems;
duk_uint_t offset_bytes;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_this = duk__require_bufobj_this(ctx);
+ h_this = duk__require_bufobj_this(thr);
DUK_ASSERT(h_this != NULL);
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_this);
+ DUK_ASSERT_HBUFOBJ_VALID(h_this);
if (h_this->buf == NULL) {
DUK_DDD(DUK_DDDPRINT("source neutered, skip copy"));
return 0;
}
- h_obj = duk_require_hobject(ctx, 0);
- DUK_ASSERT(h_obj != NULL);
+ duk_hbufobj_promote_plain(thr, 0);
+ h_obj = duk_require_hobject(thr, 0);
/* XXX: V8 throws a TypeError for negative values. Would it
* be more useful to interpret negative offsets here from the
* end of the buffer too?
*/
- offset_signed = duk_to_int(ctx, 1);
+ offset_signed = duk_to_int(thr, 1);
if (offset_signed < 0) {
- return DUK_RET_TYPE_ERROR;
+ /* For some reason this is a TypeError (at least in V8). */
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
offset_elems = (duk_uint_t) offset_signed;
offset_bytes = offset_elems << h_this->shift;
if ((offset_bytes >> h_this->shift) != offset_elems) {
/* Byte length would overflow. */
/* XXX: easier check with less code? */
- return DUK_RET_RANGE_ERROR;
+ goto fail_args;
}
if (offset_bytes > h_this->length) {
/* Equality may be OK but >length not. Checking
* this explicitly avoids some overflow cases
* below.
*/
- return DUK_RET_RANGE_ERROR;
+ goto fail_args;
}
DUK_ASSERT(offset_bytes <= h_this->length);
- /* Fast path: source is a TypedArray (or any bufferobject). */
+ /* Fast path: source is a TypedArray (or any bufobj). */
- if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
- duk_hbufferobject *h_bufarg;
+ if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
+ duk_hbufobj *h_bufarg;
+#if !defined(DUK_USE_PREFER_SIZE)
duk_uint16_t comp_mask;
+#endif
duk_small_int_t no_overlap = 0;
duk_uint_t src_length;
duk_uint_t dst_length;
@@ -23504,8 +27530,8 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
duk_small_uint_t src_elem_size;
duk_small_uint_t dst_elem_size;
- h_bufarg = (duk_hbufferobject *) h_obj;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufarg);
+ h_bufarg = (duk_hbufobj *) h_obj;
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufarg);
if (h_bufarg->buf == NULL) {
DUK_DDD(DUK_DDDPRINT("target neutered, skip copy"));
@@ -23519,7 +27545,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
if ((dst_length >> h_this->shift) != dst_length_elems) {
/* Byte length would overflow. */
/* XXX: easier check with less code? */
- return DUK_RET_RANGE_ERROR;
+ goto fail_args;
}
DUK_DDD(DUK_DDDPRINT("nominal size check: src_length=%ld, dst_length=%ld",
(long) src_length, (long) dst_length));
@@ -23529,22 +27555,22 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
* side and guaranteed to be >= 0.
*/
DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length"));
- return DUK_RET_RANGE_ERROR;
+ goto fail_args;
}
- if (!DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_this, offset_bytes + dst_length)) {
+ if (!DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, offset_bytes + dst_length)) {
DUK_DDD(DUK_DDDPRINT("copy not covered by underlying target buffer, ignore"));
return 0;
}
- p_src_base = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg);
- p_dst_base = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + offset_bytes;
+ p_src_base = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg);
+ p_dst_base = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + offset_bytes;
/* Check actual underlying buffers for validity and that they
* cover the copy. No side effects are allowed after the check
* so that the validity status doesn't change.
*/
- if (!DUK_HBUFFEROBJECT_VALID_SLICE(h_this) ||
- !DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg)) {
+ if (!DUK_HBUFOBJ_VALID_SLICE(h_this) ||
+ !DUK_HBUFOBJ_VALID_SLICE(h_bufarg)) {
/* The condition could be more narrow and check for the
* copy area only, but there's no need for fine grained
* behavior when the underlying buffer is misconfigured.
@@ -23564,6 +27590,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
* and destination element sizes are necessarily equal.
*/
+#if !defined(DUK_USE_PREFER_SIZE)
DUK_ASSERT(h_this->elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t));
comp_mask = duk__buffer_elemtype_copy_compatible[h_this->elem_type];
if (comp_mask & (1 << h_bufarg->elem_type)) {
@@ -23574,6 +27601,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
return 0;
}
DUK_DDD(DUK_DDDPRINT("fast path: views are not compatible with a byte copy, copy by item"));
+#endif /* !DUK_USE_PREFER_SIZE */
/* We want to avoid making a copy to process set() but that's
* not always possible: the source and the target may overlap
@@ -23610,7 +27638,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
duk_uint8_t *p_src_copy;
DUK_DDD(DUK_DDDPRINT("there is overlap, make a copy of the source"));
- p_src_copy = (duk_uint8_t *) duk_push_fixed_buffer(ctx, src_length);
+ p_src_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, src_length);
DUK_ASSERT(p_src_copy != NULL);
DUK_MEMCPY((void *) p_src_copy, (const void *) p_src_base, (size_t) src_length);
@@ -23622,7 +27650,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
"p_dst_base=%p, dst_length=%ld, valstack top=%ld",
(void *) p_src_base, (long) src_length,
(void *) p_dst_base, (long) dst_length,
- (long) duk_get_top(ctx)));
+ (long) duk_get_top(thr)));
/* Ready to make the copy. We must proceed element by element
* and must avoid any side effects that might cause the buffer
@@ -23632,8 +27660,8 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
* numbers are handled which should be side effect safe.
*/
- src_elem_size = 1 << h_bufarg->shift;
- dst_elem_size = 1 << h_this->shift;
+ src_elem_size = (duk_small_uint_t) (1U << h_bufarg->shift);
+ dst_elem_size = (duk_small_uint_t) (1U << h_this->shift);
p_src = p_src_base;
p_dst = p_dst_base;
p_src_end = p_src_base + src_length;
@@ -23645,9 +27673,9 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
/* A validated read() is always a number, so it's write coercion
* is always side effect free an won't invalidate pointers etc.
*/
- duk_hbufferobject_push_validated_read(ctx, h_bufarg, p_src, src_elem_size);
- duk_hbufferobject_validated_write(ctx, h_this, p_dst, dst_elem_size);
- duk_pop(ctx);
+ duk_hbufobj_push_validated_read(thr, h_bufarg, p_src, src_elem_size);
+ duk_hbufobj_validated_write(thr, h_this, p_dst, dst_elem_size);
+ duk_pop(thr);
p_src += src_elem_size;
p_dst += dst_elem_size;
}
@@ -23658,19 +27686,19 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
* to write coerce target values. We don't need to worry about overlap
* here because the source is not a TypedArray.
*
- * We could use the bufferobject write coercion helper but since the
+ * We could use the bufobj write coercion helper but since the
* property read may have arbitrary side effects, full validity checks
* would be needed for every element anyway.
*/
- n = (duk_uarridx_t) duk_get_length(ctx, 0);
+ n = (duk_uarridx_t) duk_get_length(thr, 0);
DUK_ASSERT(offset_bytes <= h_this->length);
if ((n << h_this->shift) > h_this->length - offset_bytes) {
/* Overflow not an issue because subtraction is used on the right
* side and guaranteed to be >= 0.
*/
DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length"));
- return DUK_RET_RANGE_ERROR;
+ goto fail_args;
}
/* There's no need to check for buffer validity status for the
@@ -23680,28 +27708,26 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
* the results anyway.
*/
- DUK_ASSERT_TOP(ctx, 2);
- duk_push_this(ctx);
+ DUK_ASSERT_TOP(thr, 2);
+ duk_push_this(thr);
for (i = 0; i < n; i++) {
- duk_get_prop_index(ctx, 0, i);
- duk_put_prop_index(ctx, 2, offset_elems + i);
+ duk_get_prop_index(thr, 0, i);
+ duk_put_prop_index(thr, 2, offset_elems + i);
}
}
return 0;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
+
+ fail_args:
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr);
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
* Node.js Buffer.prototype.slice([start], [end])
* ArrayBuffer.prototype.slice(begin, [end])
- * TypedArray.prototype.slice(begin, [end])
+ * TypedArray.prototype.subarray(begin, [end])
*
* The API calls are almost identical; negative indices are counted from end
* of buffer, and final indices are clamped (allowing crossed indices). Main
@@ -23714,27 +27740,86 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
* call (or 'this' argument)
*
* - TypedArray .subarray() arguments are element indices, not byte offsets
+ *
+ * - Plain buffer argument creates a plain buffer slice
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
- duk_hthread *thr;
+DUK_LOCAL void duk__arraybuffer_plain_slice(duk_hthread *thr, duk_hbuffer *h_val) {
+ duk_int_t start_offset, end_offset;
+ duk_uint_t slice_length;
+ duk_uint8_t *p_copy;
+ duk_size_t copy_length;
+
+ duk__clamp_startend_negidx_shifted(thr,
+ (duk_int_t) DUK_HBUFFER_GET_SIZE(h_val),
+ 0 /*buffer_shift*/,
+ 0 /*idx_start*/,
+ 1 /*idx_end*/,
+ &start_offset,
+ &end_offset);
+ DUK_ASSERT(end_offset <= (duk_int_t) DUK_HBUFFER_GET_SIZE(h_val));
+ DUK_ASSERT(start_offset >= 0);
+ DUK_ASSERT(end_offset >= start_offset);
+ slice_length = (duk_uint_t) (end_offset - start_offset);
+
+ p_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) slice_length);
+ DUK_ASSERT(p_copy != NULL);
+ copy_length = slice_length;
+
+ DUK_MEMCPY((void *) p_copy,
+ (const void *) ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_val) + start_offset),
+ copy_length);
+}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
+
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+/* Shared helper for slice/subarray operation.
+ * Magic: 0x01=isView, 0x02=copy, 0x04=Node.js Buffer special handling.
+ */
+DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_hthread *thr) {
duk_small_int_t magic;
duk_small_uint_t res_class_num;
- duk_hobject *res_proto;
- duk_hbufferobject *h_this;
- duk_hbufferobject *h_bufobj;
+ duk_small_int_t res_proto_bidx;
+ duk_hbufobj *h_this;
+ duk_hbufobj *h_bufobj;
duk_hbuffer *h_val;
duk_int_t start_offset, end_offset;
duk_uint_t slice_length;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
+ duk_tval *tv;
/* [ start end ] */
- magic = duk_get_current_magic(ctx);
- h_this = duk__require_bufobj_this(ctx);
+ magic = duk_get_current_magic(thr);
+
+ tv = duk_get_borrowed_this_tval(thr);
+ DUK_ASSERT(tv != NULL);
+
+ if (DUK_TVAL_IS_BUFFER(tv)) {
+ /* For plain buffers return a plain buffer slice. */
+ h_val = DUK_TVAL_GET_BUFFER(tv);
+ DUK_ASSERT(h_val != NULL);
+
+ if (magic & 0x02) {
+ /* Make copy: ArrayBuffer.prototype.slice() uses this. */
+ duk__arraybuffer_plain_slice(thr, h_val);
+ return 1;
+ } else {
+ /* View into existing buffer: cannot be done if the
+ * result is a plain buffer because there's no slice
+ * info. So return an ArrayBuffer instance; coerce
+ * the 'this' binding into an object and behave as if
+ * the original call was for an Object-coerced plain
+ * buffer (handled automatically by duk__require_bufobj_this()).
+ */
+
+ DUK_DDD(DUK_DDDPRINT("slice() doesn't handle view into plain buffer, coerce 'this' to ArrayBuffer object"));
+ /* fall through */
+ }
+ }
+ tv = NULL; /* No longer valid nor needed. */
+
+ h_this = duk__require_bufobj_this(thr);
/* Slice offsets are element (not byte) offsets, which only matters
* for TypedArray views, Node.js Buffer and ArrayBuffer have shift
@@ -23745,40 +27830,53 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
* against the underlying buffer here.
*/
- duk__clamp_startend_negidx_shifted(ctx, h_this, 0 /*idx_start*/, 1 /*idx_end*/, &start_offset, &end_offset);
+ duk__clamp_startend_negidx_shifted(thr,
+ (duk_int_t) h_this->length,
+ (duk_uint8_t) h_this->shift,
+ 0 /*idx_start*/,
+ 1 /*idx_end*/,
+ &start_offset,
+ &end_offset);
DUK_ASSERT(end_offset >= start_offset);
+ DUK_ASSERT(start_offset >= 0);
+ DUK_ASSERT(end_offset >= 0);
slice_length = (duk_uint_t) (end_offset - start_offset);
/* The resulting buffer object gets the same class and prototype as
- * the buffer in 'this', e.g. if the input is a Node.js Buffer the
- * result is a Node.js Buffer; if the input is a Float32Array, the
- * result is a Float32Array.
+ * the buffer in 'this', e.g. if the input is a Uint8Array the
+ * result is a Uint8Array; if the input is a Float32Array, the
+ * result is a Float32Array. The result internal prototype should
+ * be the default prototype for the class (e.g. initial value of
+ * Uint8Array.prototype), not copied from the argument (Duktape 1.x
+ * did that).
*
- * For the class number this seems correct. The internal prototype
- * is not so clear: if 'this' is a bufferobject with a non-standard
- * prototype object, that value gets copied over into the result
- * (instead of using the standard prototype for that object type).
+ * Node.js Buffers have special handling: they're Uint8Arrays as far
+ * as the internal class is concerned, so the new Buffer should also
+ * be an Uint8Array but inherit from Buffer.prototype.
*/
-
res_class_num = DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_this);
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(res_class_num),
- DUK_BIDX_OBJECT_PROTOTYPE); /* replaced */
+ DUK_ASSERT(res_class_num >= DUK_HOBJECT_CLASS_BUFOBJ_MIN); /* type check guarantees */
+ DUK_ASSERT(res_class_num <= DUK_HOBJECT_CLASS_BUFOBJ_MAX);
+ res_proto_bidx = duk__buffer_proto_from_classnum[res_class_num - DUK_HOBJECT_CLASS_BUFOBJ_MIN];
+ if (magic & 0x04) {
+ res_proto_bidx = DUK_BIDX_NODEJS_BUFFER_PROTOTYPE;
+ }
+ h_bufobj = duk_push_bufobj_raw(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BUFOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(res_class_num),
+ res_proto_bidx);
DUK_ASSERT(h_bufobj != NULL);
- res_proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_this); /* may be NULL */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) h_bufobj, res_proto);
DUK_ASSERT(h_bufobj->length == 0);
h_bufobj->shift = h_this->shift; /* inherit */
h_bufobj->elem_type = h_this->elem_type; /* inherit */
- h_bufobj->is_view = magic & 0x01;
- DUK_ASSERT(h_bufobj->is_view == 0 || h_bufobj->is_view == 1);
+ h_bufobj->is_typedarray = magic & 0x01;
+ DUK_ASSERT(h_bufobj->is_typedarray == 0 || h_bufobj->is_typedarray == 1);
h_val = h_this->buf;
if (h_val == NULL) {
- return DUK_RET_TYPE_ERROR;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
if (magic & 0x02) {
@@ -23786,55 +27884,45 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
duk_uint8_t *p_copy;
duk_size_t copy_length;
- p_copy = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) slice_length);
+ p_copy = (duk_uint8_t *) duk_push_fixed_buffer_zero(thr, (duk_size_t) slice_length); /* must be zeroed, not all bytes always copied */
DUK_ASSERT(p_copy != NULL);
/* Copy slice, respecting underlying buffer limits; remainder
* is left as zero.
*/
- copy_length = DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h_this, slice_length);
+ copy_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, slice_length);
DUK_MEMCPY((void *) p_copy,
- (const void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
+ (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
copy_length);
- h_val = duk_get_hbuffer(ctx, -1);
- DUK_ASSERT(h_val != NULL);
+ h_val = duk_known_hbuffer(thr, -1);
h_bufobj->buf = h_val;
DUK_HBUFFER_INCREF(thr, h_val);
h_bufobj->length = slice_length;
DUK_ASSERT(h_bufobj->offset == 0);
- duk_pop(ctx); /* reachable so pop OK */
+ duk_pop(thr); /* reachable so pop OK */
} else {
h_bufobj->buf = h_val;
DUK_HBUFFER_INCREF(thr, h_val);
h_bufobj->length = slice_length;
- h_bufobj->offset = (duk_uint_t) (h_this->offset + start_offset);
+ h_bufobj->offset = h_this->offset + (duk_uint_t) start_offset;
/* Copy the .buffer property, needed for TypedArray.prototype.subarray().
*
* XXX: limit copy only for TypedArray classes specifically?
*/
- duk_push_this(ctx);
- if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LC_BUFFER)) {
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
- duk_pop(ctx);
- } else {
- duk_pop_2(ctx);
- }
+ DUK_ASSERT(h_bufobj->buf_prop == NULL);
+ h_bufobj->buf_prop = h_this->buf_prop; /* may be NULL */
+ DUK_HOBJECT_INCREF_ALLOWNULL(thr, (duk_hobject *) h_bufobj->buf_prop);
}
/* unbalanced stack on purpose */
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
return 1;
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
@@ -23842,21 +27930,16 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_hthread *thr) {
const char *encoding;
/* only accept lowercase 'utf8' now. */
- encoding = duk_to_string(ctx, 0);
- DUK_ASSERT(duk_is_string(ctx, 0)); /* guaranteed by duk_to_string() */
- duk_push_boolean(ctx, DUK_STRCMP(encoding, "utf8") == 0);
+ encoding = duk_to_string(thr, 0);
+ DUK_ASSERT(duk_is_string(thr, 0)); /* guaranteed by duk_to_string() */
+ duk_push_boolean(thr, DUK_STRCMP(encoding, "utf8") == 0);
return 1;
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
@@ -23864,40 +27947,26 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx) {
- duk_hthread *thr;
- duk_tval *tv;
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_hthread *thr) {
duk_hobject *h;
duk_hobject *h_proto;
duk_bool_t ret = 0;
- thr = (duk_hthread *) ctx;
-
- DUK_ASSERT(duk_get_top(ctx) >= 1); /* nargs */
- tv = duk_get_tval(ctx, 0);
- DUK_ASSERT(tv != NULL);
-
- if (DUK_TVAL_IS_OBJECT(tv)) {
- h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
-
+ DUK_ASSERT(duk_get_top(thr) >= 1); /* nargs */
+ h = duk_get_hobject(thr, 0);
+ if (h != NULL) {
h_proto = thr->builtins[DUK_BIDX_NODEJS_BUFFER_PROTOTYPE];
DUK_ASSERT(h_proto != NULL);
h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
- if (h) {
+ if (h != NULL) {
ret = duk_hobject_prototype_chain_contains(thr, h, h_proto, 0 /*ignore_loop*/);
}
}
- duk_push_boolean(ctx, ret);
+ duk_push_boolean(thr, ret);
return 1;
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
@@ -23905,7 +27974,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_hthread *thr) {
const char *str;
duk_size_t len;
@@ -23914,16 +27983,21 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx) {
* unconditionally.
*/
- str = duk_to_lstring(ctx, 0, &len);
+ /* XXX: to be revised; Old Node.js behavior just coerces any buffer
+ * values to string:
+ * $ node
+ * > Buffer.byteLength(new Uint32Array(10))
+ * 20
+ * > Buffer.byteLength(new Uint32Array(100))
+ * 20
+ * (The 20 comes from '[object Uint32Array]'.length
+ */
+
+ str = duk_to_lstring(thr, 0, &len);
DUK_UNREF(str);
- duk_push_size_t(ctx, len);
+ duk_push_size_t(thr, len);
return 1;
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
@@ -23931,81 +28005,77 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) {
- duk_hthread *thr;
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_hthread *thr) {
duk_hobject *h_arg;
- duk_int_t total_length = 0;
- duk_hbufferobject *h_bufobj;
- duk_hbufferobject *h_bufres;
+ duk_uint_t total_length;
+ duk_hbufobj *h_bufobj;
+ duk_hbufobj *h_bufres;
duk_hbuffer *h_val;
duk_uint_t i, n;
duk_uint8_t *p;
duk_size_t space_left;
duk_size_t copy_size;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
/* Node.js accepts only actual Arrays. */
- h_arg = duk_require_hobject(ctx, 0);
+ h_arg = duk_require_hobject(thr, 0);
if (DUK_HOBJECT_GET_CLASS_NUMBER(h_arg) != DUK_HOBJECT_CLASS_ARRAY) {
- return DUK_RET_TYPE_ERROR;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
/* Compute result length and validate argument buffers. */
- n = (duk_uint_t) duk_get_length(ctx, 0);
+ n = (duk_uint_t) duk_get_length(thr, 0);
+ total_length = 0;
for (i = 0; i < n; i++) {
/* Neutered checks not necessary here: neutered buffers have
* zero 'length' so we'll effectively skip them.
*/
- DUK_ASSERT_TOP(ctx, 2); /* [ array totalLength ] */
- duk_get_prop_index(ctx, 0, (duk_uarridx_t) i); /* -> [ array totalLength buf ] */
- h_bufobj = duk__require_bufobj_value(ctx, 2);
+ DUK_ASSERT_TOP(thr, 2); /* [ array totalLength ] */
+ duk_get_prop_index(thr, 0, (duk_uarridx_t) i); /* -> [ array totalLength buf ] */
+ h_bufobj = duk__require_bufobj_value(thr, 2);
DUK_ASSERT(h_bufobj != NULL);
total_length += h_bufobj->length;
- duk_pop(ctx);
- }
- if (n == 1) {
- /* For the case n==1 Node.js doesn't seem to type check
- * the sole member but we do it before returning it.
- * For this case only the original buffer object is
- * returned (not a copy).
- */
- duk_get_prop_index(ctx, 0, 0);
- return 1;
+ if (DUK_UNLIKELY(total_length < h_bufobj->length)) {
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr); /* Wrapped. */
+ }
+ duk_pop(thr);
}
+ /* In Node.js v0.12.1 a 1-element array is special and won't create a
+ * copy, this was fixed later so an explicit check no longer needed.
+ */
/* User totalLength overrides a computed length, but we'll check
- * every copy in the copy loop. Note that duk_to_uint() can
+ * every copy in the copy loop. Note that duk_to_int() can
* technically have arbitrary side effects so we need to recheck
* the buffers in the copy loop.
*/
- if (!duk_is_undefined(ctx, 1) && n > 0) {
+ if (!duk_is_undefined(thr, 1) && n > 0) {
/* For n == 0, Node.js ignores totalLength argument and
* returns a zero length buffer.
*/
- total_length = duk_to_int(ctx, 1);
- }
- if (total_length < 0) {
- return DUK_RET_RANGE_ERROR;
+ duk_int_t total_length_signed;
+ total_length_signed = duk_to_int(thr, 1);
+ if (total_length_signed < 0) {
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr);
+ }
+ total_length = (duk_uint_t) total_length_signed;
}
- h_bufres = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER),
- DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
+ h_bufres = duk_push_bufobj_raw(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BUFOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_UINT8ARRAY),
+ DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
DUK_ASSERT(h_bufres != NULL);
- p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, total_length);
+ p = (duk_uint8_t *) duk_push_fixed_buffer_zero(thr, total_length); /* must be zeroed, all bytes not necessarily written over */
DUK_ASSERT(p != NULL);
- space_left = total_length;
+ space_left = (duk_size_t) total_length;
for (i = 0; i < n; i++) {
- DUK_ASSERT_TOP(ctx, 4); /* [ array totalLength bufres buf ] */
+ DUK_ASSERT_TOP(thr, 4); /* [ array totalLength bufres buf ] */
- duk_get_prop_index(ctx, 0, (duk_uarridx_t) i);
- h_bufobj = duk__require_bufobj_value(ctx, 4);
+ duk_get_prop_index(thr, 0, (duk_uarridx_t) i);
+ h_bufobj = duk__require_bufobj_value(thr, 4);
DUK_ASSERT(h_bufobj != NULL);
copy_size = h_bufobj->length;
@@ -24014,9 +28084,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) {
}
if (h_bufobj->buf != NULL &&
- DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)) {
+ DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) {
DUK_MEMCPY((void *) p,
- (const void *) DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufobj),
+ (const void *) DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj),
copy_size);
} else {
/* Just skip, leaving zeroes in the result. */
@@ -24025,24 +28095,19 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) {
p += copy_size;
space_left -= copy_size;
- duk_pop(ctx);
+ duk_pop(thr);
}
- h_val = duk_get_hbuffer(ctx, -1);
- DUK_ASSERT(h_val != NULL);
+ h_val = duk_known_hbuffer(thr, -1);
- duk__set_bufobj_buffer(ctx, h_bufres, h_val);
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufres);
+ duk__set_bufobj_buffer(thr, h_bufres, h_val);
+ h_bufres->is_typedarray = 1;
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufres);
- duk_pop(ctx); /* pop plain buffer, now reachable through h_bufres */
+ duk_pop(thr); /* pop plain buffer, now reachable through h_bufres */
return 1; /* return h_bufres */
}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
@@ -24070,15 +28135,14 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) {
#define DUK__FLD_TYPEDARRAY (1 << 5)
/* XXX: split into separate functions for each field type? */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
- duk_hthread *thr;
- duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_hthread *thr) {
+ duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(thr);
duk_small_int_t magic_ftype;
duk_small_int_t magic_bigendian;
duk_small_int_t magic_signed;
duk_small_int_t magic_typedarray;
duk_small_int_t endswap;
- duk_hbufferobject *h_this;
+ duk_hbufobj *h_this;
duk_bool_t no_assert;
duk_int_t offset_signed;
duk_uint_t offset;
@@ -24087,15 +28151,12 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
duk_uint8_t *buf;
duk_double_union du;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
magic_ftype = magic & 0x0007;
magic_bigendian = magic & 0x0008;
magic_signed = magic & 0x0010;
magic_typedarray = magic & 0x0020;
- h_this = duk__require_bufobj_this(ctx);
+ h_this = duk__require_bufobj_this(thr); /* XXX: very inefficient for plain buffers */
DUK_ASSERT(h_this != NULL);
buffer_length = h_this->length;
@@ -24107,12 +28168,12 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
if (magic_typedarray) {
no_assert = 0;
#if defined(DUK_USE_INTEGER_LE)
- endswap = !duk_to_boolean(ctx, 1); /* 1=little endian */
+ endswap = !duk_to_boolean(thr, 1); /* 1=little endian */
#else
- endswap = duk_to_boolean(ctx, 1); /* 1=little endian */
+ endswap = duk_to_boolean(thr, 1); /* 1=little endian */
#endif
} else {
- no_assert = duk_to_boolean(ctx, (magic_ftype == DUK__FLD_VARINT) ? 2 : 1);
+ no_assert = duk_to_boolean(thr, (magic_ftype == DUK__FLD_VARINT) ? 2 : 1);
#if defined(DUK_USE_INTEGER_LE)
endswap = magic_bigendian;
#else
@@ -24124,7 +28185,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
* This ensures we can add a small byte length (1-8) to the offset in
* bound checks and not wrap.
*/
- offset_signed = duk_to_int(ctx, 0);
+ offset_signed = duk_to_int(thr, 0);
offset = (duk_uint_t) offset_signed;
if (offset_signed < 0) {
goto fail_bounds;
@@ -24141,12 +28202,12 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
* takes into account the underlying buffer. This value will be
* potentially invalidated by any side effect.
*/
- check_length = DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h_this, buffer_length);
+ check_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, buffer_length);
DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld",
(long) buffer_length, (long) check_length));
if (h_this->buf) {
- buf = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this);
+ buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this);
} else {
/* Neutered. We could go into the switch-case safely with
* buf == NULL because check_length == 0. To avoid scanbuild
@@ -24165,9 +28226,9 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
}
tmp = buf[offset];
if (magic_signed) {
- duk_push_int(ctx, (duk_int_t) ((duk_int8_t) tmp));
+ duk_push_int(thr, (duk_int_t) ((duk_int8_t) tmp));
} else {
- duk_push_uint(ctx, (duk_uint_t) tmp);
+ duk_push_uint(thr, (duk_uint_t) tmp);
}
break;
}
@@ -24182,9 +28243,9 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
tmp = DUK_BSWAP16(tmp);
}
if (magic_signed) {
- duk_push_int(ctx, (duk_int_t) ((duk_int16_t) tmp));
+ duk_push_int(thr, (duk_int_t) ((duk_int16_t) tmp));
} else {
- duk_push_uint(ctx, (duk_uint_t) tmp);
+ duk_push_uint(thr, (duk_uint_t) tmp);
}
break;
}
@@ -24199,9 +28260,9 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
tmp = DUK_BSWAP32(tmp);
}
if (magic_signed) {
- duk_push_int(ctx, (duk_int_t) ((duk_int32_t) tmp));
+ duk_push_int(thr, (duk_int_t) ((duk_int32_t) tmp));
} else {
- duk_push_uint(ctx, (duk_uint_t) tmp);
+ duk_push_uint(thr, (duk_uint_t) tmp);
}
break;
}
@@ -24216,7 +28277,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
tmp = DUK_BSWAP32(tmp);
du.ui[0] = tmp;
}
- duk_push_number(ctx, (duk_double_t) du.f[0]);
+ duk_push_number(thr, (duk_double_t) du.f[0]);
break;
}
case DUK__FLD_DOUBLE: {
@@ -24227,7 +28288,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
if (endswap) {
DUK_DBLUNION_BSWAP64(&du);
}
- duk_push_number(ctx, (duk_double_t) du.d);
+ duk_push_number(thr, (duk_double_t) du.d);
break;
}
case DUK__FLD_VARINT: {
@@ -24245,7 +28306,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
#endif
const duk_uint8_t *p;
- field_bytelen = duk_get_int(ctx, 1); /* avoid side effects! */
+ field_bytelen = duk_get_int(thr, 1); /* avoid side effects! */
if (field_bytelen < 1 || field_bytelen > 6) {
goto fail_field_length;
}
@@ -24281,11 +28342,11 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
if (magic_signed) {
/* Shift to sign extend. */
- shift_tmp = 64 - (field_bytelen * 8);
+ shift_tmp = (duk_small_uint_t) (64U - (duk_small_uint_t) field_bytelen * 8U);
tmp = (tmp << shift_tmp) >> shift_tmp;
}
- duk_push_i64(ctx, tmp);
+ duk_push_i64(thr, tmp);
#else
highbyte = p[i];
if (magic_signed && (highbyte & 0x80) != 0) {
@@ -24303,7 +28364,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
tmp = (tmp * 256.0) + (duk_double_t) p[i];
}
- duk_push_number(ctx, tmp);
+ duk_push_number(thr, tmp);
#endif
break;
}
@@ -24321,30 +28382,23 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
/* Node.js return value for noAssert out-of-bounds reads is
* usually (but not always) NaN. Return NaN consistently.
*/
- duk_push_nan(ctx);
+ duk_push_nan(thr);
return 1;
}
-
- return DUK_RET_RANGE_ERROR;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr);
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
/* XXX: split into separate functions for each field type? */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
- duk_hthread *thr;
- duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_hthread *thr) {
+ duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(thr);
duk_small_int_t magic_ftype;
duk_small_int_t magic_bigendian;
duk_small_int_t magic_signed;
duk_small_int_t magic_typedarray;
duk_small_int_t endswap;
- duk_hbufferobject *h_this;
+ duk_hbufobj *h_this;
duk_bool_t no_assert;
duk_int_t offset_signed;
duk_uint_t offset;
@@ -24354,16 +28408,13 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
duk_double_union du;
duk_int_t nbytes = 0;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
magic_ftype = magic & 0x0007;
magic_bigendian = magic & 0x0008;
magic_signed = magic & 0x0010;
magic_typedarray = magic & 0x0020;
DUK_UNREF(magic_signed);
- h_this = duk__require_bufobj_this(ctx);
+ h_this = duk__require_bufobj_this(thr); /* XXX: very inefficient for plain buffers */
DUK_ASSERT(h_this != NULL);
buffer_length = h_this->length;
@@ -24375,13 +28426,13 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
if (magic_typedarray) {
no_assert = 0;
#if defined(DUK_USE_INTEGER_LE)
- endswap = !duk_to_boolean(ctx, 2); /* 1=little endian */
+ endswap = !duk_to_boolean(thr, 2); /* 1=little endian */
#else
- endswap = duk_to_boolean(ctx, 2); /* 1=little endian */
+ endswap = duk_to_boolean(thr, 2); /* 1=little endian */
#endif
- duk_swap(ctx, 0, 1); /* offset/value order different from Node.js */
+ duk_swap(thr, 0, 1); /* offset/value order different from Node.js */
} else {
- no_assert = duk_to_boolean(ctx, (magic_ftype == DUK__FLD_VARINT) ? 3 : 2);
+ no_assert = duk_to_boolean(thr, (magic_ftype == DUK__FLD_VARINT) ? 3 : 2);
#if defined(DUK_USE_INTEGER_LE)
endswap = magic_bigendian;
#else
@@ -24393,7 +28444,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
* This ensures we can add a small byte length (1-8) to the offset in
* bound checks and not wrap.
*/
- offset_signed = duk_to_int(ctx, 1);
+ offset_signed = duk_to_int(thr, 1);
offset = (duk_uint_t) offset_signed;
/* We need 'nbytes' even for a failed offset; return value must be
@@ -24403,7 +28454,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
DUK_ASSERT(magic_ftype >= 0 && magic_ftype < (duk_small_int_t) (sizeof(duk__buffer_nbytes_from_fldtype) / sizeof(duk_uint8_t)));
nbytes = duk__buffer_nbytes_from_fldtype[magic_ftype];
} else {
- nbytes = duk_get_int(ctx, 2);
+ nbytes = duk_get_int(thr, 2);
if (nbytes < 1 || nbytes > 6) {
goto fail_field_length;
}
@@ -24418,7 +28469,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
DUK_DDD(DUK_DDDPRINT("writefield, value=%!T, buffer_length=%ld, offset=%ld, no_assert=%d, "
"magic=%04x, magic_fieldtype=%d, magic_bigendian=%d, magic_signed=%d, "
"endswap=%d",
- duk_get_tval(ctx, 0), (long) buffer_length, (long) offset, (int) no_assert,
+ duk_get_tval(thr, 0), (long) buffer_length, (long) offset, (int) no_assert,
(unsigned int) magic, (int) magic_ftype, (int) (magic_bigendian >> 3),
(int) (magic_signed >> 4), (int) endswap));
@@ -24426,18 +28477,18 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
* the field type specific coercion below can't have side effects
* that would invalidate check_length.
*/
- duk_to_number(ctx, 0);
+ duk_to_number(thr, 0);
/* Update 'buffer_length' to be the effective, safe limit which
* takes into account the underlying buffer. This value will be
* potentially invalidated by any side effect.
*/
- check_length = DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h_this, buffer_length);
+ check_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, buffer_length);
DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld",
(long) buffer_length, (long) check_length));
if (h_this->buf) {
- buf = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this);
+ buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this);
} else {
/* Neutered. We could go into the switch-case safely with
* buf == NULL because check_length == 0. To avoid scanbuild
@@ -24454,7 +28505,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
goto fail_bounds;
}
/* sign doesn't matter when writing */
- buf[offset] = (duk_uint8_t) duk_to_uint32(ctx, 0);
+ buf[offset] = (duk_uint8_t) duk_to_uint32(thr, 0);
break;
}
case DUK__FLD_16BIT: {
@@ -24462,7 +28513,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
if (offset + 2U > check_length) {
goto fail_bounds;
}
- tmp = (duk_uint16_t) duk_to_uint32(ctx, 0);
+ tmp = (duk_uint16_t) duk_to_uint32(thr, 0);
if (endswap) {
tmp = DUK_BSWAP16(tmp);
}
@@ -24476,7 +28527,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
if (offset + 4U > check_length) {
goto fail_bounds;
}
- tmp = (duk_uint32_t) duk_to_uint32(ctx, 0);
+ tmp = (duk_uint32_t) duk_to_uint32(thr, 0);
if (endswap) {
tmp = DUK_BSWAP32(tmp);
}
@@ -24490,7 +28541,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
if (offset + 4U > check_length) {
goto fail_bounds;
}
- du.f[0] = (duk_float_t) duk_to_number(ctx, 0);
+ du.f[0] = (duk_float_t) duk_to_number(thr, 0);
if (endswap) {
tmp = du.ui[0];
tmp = DUK_BSWAP32(tmp);
@@ -24504,7 +28555,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
if (offset + 8U > check_length) {
goto fail_bounds;
}
- du.d = (duk_double_t) duk_to_number(ctx, 0);
+ du.d = (duk_double_t) duk_to_number(thr, 0);
if (endswap) {
DUK_DBLUNION_BSWAP64(&du);
}
@@ -24554,7 +28605,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
*/
#if defined(DUK_USE_64BIT_OPS)
- tmp = (duk_int64_t) duk_to_number(ctx, 0);
+ tmp = (duk_int64_t) duk_to_number(thr, 0);
p = (duk_uint8_t *) (buf + offset);
do {
i += i_step;
@@ -24563,7 +28614,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
tmp = tmp >> 8; /* unnecessary shift for last byte */
} while (i != i_end);
#else
- tmp = duk_to_number(ctx, 0);
+ tmp = duk_to_number(thr, 0);
p = (duk_uint8_t *) (buf + offset);
do {
i += i_step;
@@ -24585,11 +28636,11 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
*/
if (magic_typedarray) {
/* For TypedArrays 'undefined' return value is specified
- * by ES6 (matches V8).
+ * by ES2015 (matches V8).
*/
return 0;
}
- duk_push_uint(ctx, offset + nbytes);
+ duk_push_uint(thr, offset + (duk_uint_t) nbytes);
return 1;
fail_neutered:
@@ -24605,27 +28656,154 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
if (magic_typedarray) {
return 0;
}
- duk_push_uint(ctx, offset + nbytes);
+ duk_push_uint(thr, offset + (duk_uint_t) nbytes);
return 1;
}
- return DUK_RET_RANGE_ERROR;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr);
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#undef DUK__FLD_8BIT
-#undef DUK__FLD_16BIT
-#undef DUK__FLD_32BIT
-#undef DUK__FLD_FLOAT
-#undef DUK__FLD_DOUBLE
-#undef DUK__FLD_VARINT
-#undef DUK__FLD_BIGENDIAN
-#undef DUK__FLD_SIGNED
-#undef DUK__FLD_TYPEDARRAY
+/*
+ * Accessors for .buffer, .byteLength, .byteOffset
+ */
+
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+DUK_LOCAL duk_hbufobj *duk__autospawn_arraybuffer(duk_hthread *thr, duk_hbuffer *h_buf) {
+ duk_hbufobj *h_res;
+
+ h_res = duk_push_bufobj_raw(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BUFOBJ |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
+ DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
+ DUK_ASSERT(h_res != NULL);
+ DUK_UNREF(h_res);
+
+ duk__set_bufobj_buffer(thr, h_res, h_buf);
+ DUK_ASSERT_HBUFOBJ_VALID(h_res);
+ DUK_ASSERT(h_res->buf_prop == NULL);
+ return h_res;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_hthread *thr) {
+ duk_hbufobj *h_bufobj;
+
+ h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW /*flags*/);
+ DUK_ASSERT(h_bufobj != NULL);
+ if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) {
+ DUK_DD(DUK_DDPRINT("autospawn ArrayBuffer for plain buffer"));
+ (void) duk__autospawn_arraybuffer(thr, (duk_hbuffer *) h_bufobj);
+ return 1;
+ } else {
+ if (h_bufobj->buf_prop == NULL &&
+ DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_bufobj) != DUK_HOBJECT_CLASS_ARRAYBUFFER &&
+ h_bufobj->buf != NULL) {
+ duk_hbufobj *h_arrbuf;
+
+ DUK_DD(DUK_DDPRINT("autospawn ArrayBuffer for typed array or DataView"));
+ h_arrbuf = duk__autospawn_arraybuffer(thr, h_bufobj->buf);
+
+ if (h_bufobj->buf_prop == NULL) {
+ /* Must recheck buf_prop, in case ArrayBuffer
+ * alloc had a side effect which already filled
+ * it!
+ */
+
+ /* Set ArrayBuffer's .byteOffset and .byteLength based
+ * on the view so that Arraybuffer[view.byteOffset]
+ * matches view[0].
+ */
+ h_arrbuf->offset = 0;
+ DUK_ASSERT(h_bufobj->offset + h_bufobj->length >= h_bufobj->offset); /* Wrap check on creation. */
+ h_arrbuf->length = h_bufobj->offset + h_bufobj->length;
+ DUK_ASSERT(h_arrbuf->buf_prop == NULL);
+
+ DUK_ASSERT(h_bufobj->buf_prop == NULL);
+ h_bufobj->buf_prop = (duk_hobject *) h_arrbuf;
+ DUK_HBUFOBJ_INCREF(thr, h_arrbuf); /* Now reachable and accounted for. */
+ }
+
+ /* Left on stack; pushed for the second time below (OK). */
+ }
+ if (h_bufobj->buf_prop) {
+ duk_push_hobject(thr, h_bufobj->buf_prop);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_hthread *thr) {
+ duk_hbufobj *h_bufobj;
+
+ h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW /*flags*/);
+ DUK_ASSERT(h_bufobj != NULL);
+ if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) {
+ duk_push_uint(thr, 0);
+ } else {
+ /* If neutered must return 0; offset is zeroed during
+ * neutering.
+ */
+ duk_push_uint(thr, h_bufobj->offset);
+ }
+ return 1;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_hthread *thr) {
+ duk_hbufobj *h_bufobj;
+
+ h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW /*flags*/);
+ DUK_ASSERT(h_bufobj != NULL);
+ if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) {
+ duk_hbuffer *h_buf;
+
+ h_buf = (duk_hbuffer *) h_bufobj;
+ DUK_ASSERT(DUK_HBUFFER_GET_SIZE(h_buf) <= DUK_UINT_MAX); /* Buffer limits. */
+ duk_push_uint(thr, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_buf));
+ } else {
+ /* If neutered must return 0; length is zeroed during
+ * neutering.
+ */
+ duk_push_uint(thr, h_bufobj->length);
+ }
+ return 1;
+}
+#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
+/* No .buffer getter without ArrayBuffer support. */
+#if 0
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_hthread *thr) {
+ return 0;
+}
+#endif
+
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_hthread *thr) {
+ duk_push_uint(thr, 0);
+ return 1;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_hthread *thr) {
+ duk_hbuffer *h_buf;
+
+ /* XXX: helper? */
+ duk_push_this(thr);
+ h_buf = duk_require_hbuffer(thr, -1);
+ duk_push_uint(thr, DUK_HBUFFER_GET_SIZE(h_buf));
+ return 1;
+}
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
+
+/* automatic undefs */
+#undef DUK__BUFOBJ_FLAG_PROMOTE
+#undef DUK__BUFOBJ_FLAG_THROW
+#undef DUK__FLD_16BIT
+#undef DUK__FLD_32BIT
+#undef DUK__FLD_8BIT
+#undef DUK__FLD_BIGENDIAN
+#undef DUK__FLD_DOUBLE
+#undef DUK__FLD_FLOAT
+#undef DUK__FLD_SIGNED
+#undef DUK__FLD_TYPEDARRAY
+#undef DUK__FLD_VARINT
#line 1 "duk_bi_date.c"
/*
* Date built-ins
@@ -24640,16 +28818,18 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
*
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
+
+/* XXX: currently defines unnecessary symbols when DUK_USE_DATE_BUILTIN is disabled. */
/*
* Forward declarations
*/
-DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval_tzoffset(duk_context *ctx, duk_small_uint_t flags, duk_int_t *out_tzoffset);
-DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval(duk_context *ctx, duk_small_uint_t flags);
-DUK_LOCAL_DECL void duk__twodigit_year_fixup(duk_context *ctx, duk_idx_t idx_val);
-DUK_LOCAL_DECL duk_ret_t duk__set_this_timeval_from_dparts(duk_context *ctx, duk_double_t *dparts, duk_small_uint_t flags);
+DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval_tzoffset(duk_hthread *thr, duk_small_uint_t flags, duk_int_t *out_tzoffset);
+DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval(duk_hthread *thr, duk_small_uint_t flags);
+DUK_LOCAL_DECL void duk__twodigit_year_fixup(duk_hthread *thr, duk_idx_t idx_val);
+DUK_LOCAL_DECL duk_ret_t duk__set_this_timeval_from_dparts(duk_hthread *thr, duk_double_t *dparts, duk_small_uint_t flags);
/*
* Other file level defines
@@ -24690,7 +28870,7 @@ DUK_LOCAL_DECL duk_ret_t duk__set_this_timeval_from_dparts(duk_context *ctx, duk
#define DUK__YEAR(x) ((duk_uint8_t) ((x) - 1970))
DUK_LOCAL duk_uint8_t duk__date_equivyear[14] = {
#if 1
- /* This is based on V8 EquivalentYear() algorithm (see src/genequivyear.py):
+ /* This is based on V8 EquivalentYear() algorithm (see util/genequivyear.py):
* http://code.google.com/p/v8/source/browse/trunk/src/date.h#146
*/
@@ -24717,7 +28897,6 @@ DUK_LOCAL duk_uint8_t duk__date_equivyear[14] = {
DUK__YEAR(1976), DUK__YEAR(1988), DUK__YEAR(1972)
#endif
};
-#undef DUK__YEAR
/*
* ISO 8601 subset parser.
@@ -24814,7 +28993,7 @@ DUK_LOCAL const duk_uint32_t duk__parse_iso8601_control[] = {
*/
};
-DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_context *ctx, const char *str) {
+DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_hthread *thr, const char *str) {
duk_int_t parts[DUK__NUM_ISO8601_PARSER_PARTS];
duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
duk_double_t d;
@@ -24854,7 +29033,7 @@ DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_context *ctx, const ch
DUK_DDD(DUK_DDDPRINT("too many digits -> reject"));
goto reject;
}
- if (part_idx == DUK__PI_MILLISECOND /*msec*/ && ndigits >= 3) {
+ if (part_idx == DUK__PI_MILLISECOND && ndigits >= 3) {
/* ignore millisecond fractions after 3 */
} else {
accum = accum * 10 + ((duk_int_t) ch) - ((duk_int_t) DUK_ASC_0) + 0x00;
@@ -24862,7 +29041,7 @@ DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_context *ctx, const ch
}
} else {
duk_uint_fast32_t match_val;
- duk_small_int_t sep_idx;
+ duk_small_uint_t sep_idx;
if (ndigits <= 0) {
goto reject;
@@ -24986,7 +29165,7 @@ DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_context *ctx, const ch
}
d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
- duk_push_number(ctx, d);
+ duk_push_number(thr, d);
return 1;
}
@@ -25009,7 +29188,7 @@ DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_context *ctx, const ch
* UTC and '2012/01/01' as local time.
*/
-DUK_LOCAL duk_ret_t duk__parse_string(duk_context *ctx, const char *str) {
+DUK_LOCAL duk_ret_t duk__parse_string(duk_hthread *thr, const char *str) {
/* XXX: there is a small risk here: because the ISO 8601 parser is
* very loose, it may end up parsing some datetime values which
* would be better parsed with a platform specific parser.
@@ -25018,7 +29197,7 @@ DUK_LOCAL duk_ret_t duk__parse_string(duk_context *ctx, const char *str) {
DUK_ASSERT(str != NULL);
DUK_DDD(DUK_DDDPRINT("parse datetime from string '%s'", (const char *) str));
- if (duk__parse_string_iso8601_subset(ctx, str) != 0) {
+ if (duk__parse_string_iso8601_subset(thr, str) != 0) {
return 1;
}
@@ -25028,14 +29207,14 @@ DUK_LOCAL duk_ret_t duk__parse_string(duk_context *ctx, const char *str) {
* - Don't push anything on stack and return 0
*/
- if (DUK_USE_DATE_PARSE_STRING(ctx, str) != 0) {
+ if (DUK_USE_DATE_PARSE_STRING(thr, str) != 0) {
return 1;
}
#else
/* No platform-specific parsing, this is not an error. */
#endif
- duk_push_nan(ctx);
+ duk_push_nan(thr);
return 1;
}
@@ -25228,9 +29407,9 @@ DUK_LOCAL duk_double_t duk__make_day(duk_double_t year, duk_double_t month, duk_
return (duk_double_t) day_num + day;
}
-/* Split time value into parts. The time value is assumed to be an internal
- * one, i.e. finite, no fractions. Possible local time adjustment has already
- * been applied when reading the time value.
+/* Split time value into parts. The time value may contain fractions (it may
+ * come from duk_time_to_components() API call) which are truncated. Possible
+ * local time adjustment has already been applied when reading the time value.
*/
DUK_INTERNAL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts, duk_double_t *dparts, duk_small_uint_t flags) {
duk_double_t d1, d2;
@@ -25249,7 +29428,8 @@ DUK_INTERNAL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts,
duk_small_int_t arridx;
DUK_ASSERT(DUK_ISFINITE(d)); /* caller checks */
- DUK_ASSERT(DUK_FLOOR(d) == d); /* no fractions in internal time */
+ d = DUK_FLOOR(d); /* remove fractions if present */
+ DUK_ASSERT(DUK_FLOOR(d) == d);
/* The timevalue must be in valid Ecmascript range, but since a local
* time offset can be applied, we need to allow a +/- 24h leeway to
@@ -25259,7 +29439,7 @@ DUK_INTERNAL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts,
DUK_UNREF(duk_bi_date_timeval_in_leeway_range);
DUK_ASSERT(duk_bi_date_timeval_in_leeway_range(d));
- /* these computations are guaranteed to be exact for the valid
+ /* These computations are guaranteed to be exact for the valid
* E5 time value range, assuming milliseconds without fractions.
*/
d1 = (duk_double_t) DUK_FMOD(d, (double) DUK_DATE_MSEC_DAY);
@@ -25515,21 +29695,20 @@ DUK_INTERNAL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dpar
* internal time value. At the end, stack is: [ ... this timeval ].
* Returns the time value. Local time adjustment is done if requested.
*/
-DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_context *ctx, duk_small_uint_t flags, duk_int_t *out_tzoffset) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_hthread *thr, duk_small_uint_t flags, duk_int_t *out_tzoffset) {
duk_hobject *h;
duk_double_t d;
duk_int_t tzoffset = 0;
- duk_push_this(ctx);
- h = duk_get_hobject(ctx, -1); /* XXX: getter with class check, useful in built-ins */
+ duk_push_this(thr);
+ h = duk_get_hobject(thr, -1); /* XXX: getter with class check, useful in built-ins */
if (h == NULL || DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_DATE) {
DUK_ERROR_TYPE(thr, "expected Date");
}
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
- d = duk_to_number(ctx, -1);
- duk_pop(ctx);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
+ d = duk_to_number_m1(thr);
+ duk_pop(thr);
if (DUK_ISNAN(d)) {
if (flags & DUK_DATE_FLAG_NAN_TO_ZERO) {
@@ -25557,23 +29736,23 @@ DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_context *ctx, duk
return d;
}
-DUK_LOCAL duk_double_t duk__push_this_get_timeval(duk_context *ctx, duk_small_uint_t flags) {
- return duk__push_this_get_timeval_tzoffset(ctx, flags, NULL);
+DUK_LOCAL duk_double_t duk__push_this_get_timeval(duk_hthread *thr, duk_small_uint_t flags) {
+ return duk__push_this_get_timeval_tzoffset(thr, flags, NULL);
}
/* Set timeval to 'this' from dparts, push the new time value onto the
* value stack and return 1 (caller can then tail call us). Expects
* the value stack to contain 'this' on the stack top.
*/
-DUK_LOCAL duk_ret_t duk__set_this_timeval_from_dparts(duk_context *ctx, duk_double_t *dparts, duk_small_uint_t flags) {
+DUK_LOCAL duk_ret_t duk__set_this_timeval_from_dparts(duk_hthread *thr, duk_double_t *dparts, duk_small_uint_t flags) {
duk_double_t d;
/* [ ... this ] */
d = duk_bi_date_get_timeval_from_dparts(dparts, flags);
- duk_push_number(ctx, d); /* -> [ ... this timeval_new ] */
- duk_dup_top(ctx); /* -> [ ... this timeval_new timeval_new ] */
- duk_put_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE);
+ duk_push_number(thr, d); /* -> [ ... this timeval_new ] */
+ duk_dup_top(thr); /* -> [ ... this timeval_new timeval_new ] */
+ duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_INT_VALUE);
/* stack top: new time value, return 1 to allow tail calls */
return 1;
@@ -25603,13 +29782,23 @@ DUK_LOCAL void duk__format_parts_iso8601(duk_int_t *parts, duk_int_t tzoffset, d
/* tzoffset seconds are dropped; 16 bits suffice for
* time offset in minutes
*/
+ const char *fmt;
+ duk_small_int_t tmp, arg_hours, arg_minutes;
+
if (tzoffset >= 0) {
- duk_small_int_t tmp = tzoffset / 60;
- DUK_SNPRINTF(tzstr, sizeof(tzstr), "+%02d:%02d", (int) (tmp / 60), (int) (tmp % 60));
+ tmp = tzoffset;
+ fmt = "+%02d:%02d";
} else {
- duk_small_int_t tmp = -tzoffset / 60;
- DUK_SNPRINTF(tzstr, sizeof(tzstr), "-%02d:%02d", (int) (tmp / 60), (int) (tmp % 60));
+ tmp = -tzoffset;
+ fmt = "-%02d:%02d";
}
+ tmp = tmp / 60;
+ arg_hours = tmp / 60;
+ arg_minutes = tmp % 60;
+ DUK_ASSERT(arg_hours <= 24); /* Even less is actually guaranteed for a valid tzoffset. */
+ arg_hours = arg_hours & 0x3f; /* For [0,24] this is a no-op, but fixes GCC 7 warning, see https://github.com/svaarala/duktape/issues/1602. */
+
+ DUK_SNPRINTF(tzstr, sizeof(tzstr), fmt, (int) arg_hours, (int) arg_minutes);
tzstr[sizeof(tzstr) - 1] = (char) 0;
} else {
tzstr[0] = DUK_ASC_UC_Z;
@@ -25640,7 +29829,7 @@ DUK_LOCAL void duk__format_parts_iso8601(duk_int_t *parts, duk_int_t tzoffset, d
* internal time value, and format date and/or time in a few formats.
* Return value allows tail calls.
*/
-DUK_LOCAL duk_ret_t duk__to_string_helper(duk_context *ctx, duk_small_uint_t flags) {
+DUK_LOCAL duk_ret_t duk__to_string_helper(duk_hthread *thr, duk_small_uint_t flags) {
duk_double_t d;
duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
duk_int_t tzoffset; /* seconds, doesn't fit into 16 bits */
@@ -25649,9 +29838,9 @@ DUK_LOCAL duk_ret_t duk__to_string_helper(duk_context *ctx, duk_small_uint_t fla
DUK_UNREF(rc); /* unreferenced with some options */
- d = duk__push_this_get_timeval_tzoffset(ctx, flags, &tzoffset);
+ d = duk__push_this_get_timeval_tzoffset(thr, flags, &tzoffset);
if (DUK_ISNAN(d)) {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_INVALID_DATE);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_INVALID_DATE);
return 1;
}
DUK_ASSERT(DUK_ISFINITE(d));
@@ -25672,7 +29861,7 @@ DUK_LOCAL duk_ret_t duk__to_string_helper(duk_context *ctx, duk_small_uint_t fla
* - Don't push anything and return 0
*/
- rc = DUK_USE_DATE_FORMAT_STRING(ctx, parts, tzoffset, flags);
+ rc = DUK_USE_DATE_FORMAT_STRING(thr, parts, tzoffset, flags);
if (rc != 0) {
return 1;
}
@@ -25687,7 +29876,7 @@ DUK_LOCAL duk_ret_t duk__to_string_helper(duk_context *ctx, duk_small_uint_t fla
* is shared.
*/
duk__format_parts_iso8601(parts, tzoffset, flags, buf);
- duk_push_string(ctx, (const char *) buf);
+ duk_push_string(thr, (const char *) buf);
return 1;
}
@@ -25696,7 +29885,7 @@ DUK_LOCAL duk_ret_t duk__to_string_helper(duk_context *ctx, duk_small_uint_t fla
* local time), push a specified component as a return value to the
* value stack and return 1 (caller can then tail call us).
*/
-DUK_LOCAL duk_ret_t duk__get_part_helper(duk_context *ctx, duk_small_uint_t flags_and_idx) {
+DUK_LOCAL duk_ret_t duk__get_part_helper(duk_hthread *thr, duk_small_uint_t flags_and_idx) {
duk_double_t d;
duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
duk_small_uint_t idx_part = (duk_small_uint_t) (flags_and_idx >> DUK_DATE_FLAG_VALUE_SHIFT); /* unpack args */
@@ -25704,9 +29893,9 @@ DUK_LOCAL duk_ret_t duk__get_part_helper(duk_context *ctx, duk_small_uint_t flag
DUK_ASSERT_DISABLE(idx_part >= 0); /* unsigned */
DUK_ASSERT(idx_part < DUK_DATE_IDX_NUM_PARTS);
- d = duk__push_this_get_timeval(ctx, flags_and_idx);
+ d = duk__push_this_get_timeval(thr, flags_and_idx);
if (DUK_ISNAN(d)) {
- duk_push_nan(ctx);
+ duk_push_nan(thr);
return 1;
}
DUK_ASSERT(DUK_ISFINITE(d));
@@ -25717,7 +29906,7 @@ DUK_LOCAL duk_ret_t duk__get_part_helper(duk_context *ctx, duk_small_uint_t flag
* only in certain cases. The legacy getYear() getter applies -1900
* unconditionally.
*/
- duk_push_int(ctx, (flags_and_idx & DUK_DATE_FLAG_SUB1900) ? parts[idx_part] - 1900 : parts[idx_part]);
+ duk_push_int(thr, (flags_and_idx & DUK_DATE_FLAG_SUB1900) ? parts[idx_part] - 1900 : parts[idx_part]);
return 1;
}
@@ -25728,7 +29917,7 @@ DUK_LOCAL duk_ret_t duk__get_part_helper(duk_context *ctx, duk_small_uint_t flag
* new time value as a return value to the value stack and return 1
* (caller can then tail call us).
*/
-DUK_LOCAL duk_ret_t duk__set_part_helper(duk_context *ctx, duk_small_uint_t flags_and_maxnargs) {
+DUK_LOCAL duk_ret_t duk__set_part_helper(duk_hthread *thr, duk_small_uint_t flags_and_maxnargs) {
duk_double_t d;
duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
@@ -25737,8 +29926,8 @@ DUK_LOCAL duk_ret_t duk__set_part_helper(duk_context *ctx, duk_small_uint_t flag
duk_small_uint_t idx_first, idx;
duk_small_uint_t i;
- nargs = duk_get_top(ctx);
- d = duk__push_this_get_timeval(ctx, flags_and_maxnargs);
+ nargs = duk_get_top(thr);
+ d = duk__push_this_get_timeval(thr, flags_and_maxnargs);
DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
if (DUK_ISFINITE(d)) {
@@ -25793,10 +29982,10 @@ DUK_LOCAL duk_ret_t duk__set_part_helper(duk_context *ctx, duk_small_uint_t flag
DUK_ASSERT(idx < DUK_DATE_IDX_NUM_PARTS);
if (idx == DUK_DATE_IDX_YEAR && (flags_and_maxnargs & DUK_DATE_FLAG_YEAR_FIXUP)) {
- duk__twodigit_year_fixup(ctx, (duk_idx_t) i);
+ duk__twodigit_year_fixup(thr, (duk_idx_t) i);
}
- dparts[idx] = duk_to_number(ctx, i);
+ dparts[idx] = duk_to_number(thr, (duk_idx_t) i);
if (idx == DUK_DATE_IDX_DAY) {
/* Day-of-month is one-based in the API, but zero-based
@@ -25816,10 +30005,10 @@ DUK_LOCAL duk_ret_t duk__set_part_helper(duk_context *ctx, duk_small_uint_t flag
* for part setters.
*/
if (DUK_ISFINITE(d)) {
- return duk__set_this_timeval_from_dparts(ctx, dparts, flags_and_maxnargs);
+ return duk__set_this_timeval_from_dparts(thr, dparts, flags_and_maxnargs);
} else {
/* Internal timevalue is already NaN, so don't touch it. */
- duk_push_nan(ctx);
+ duk_push_nan(thr);
return 1;
}
}
@@ -25827,7 +30016,7 @@ DUK_LOCAL duk_ret_t duk__set_part_helper(duk_context *ctx, duk_small_uint_t flag
/* Apply ToNumber() to specified index; if ToInteger(val) in [0,99], add
* 1900 and replace value at idx_val.
*/
-DUK_LOCAL void duk__twodigit_year_fixup(duk_context *ctx, duk_idx_t idx_val) {
+DUK_LOCAL void duk__twodigit_year_fixup(duk_hthread *thr, duk_idx_t idx_val) {
duk_double_t d;
/* XXX: idx_val would fit into 16 bits, but using duk_small_uint_t
@@ -25835,25 +30024,25 @@ DUK_LOCAL void duk__twodigit_year_fixup(duk_context *ctx, duk_idx_t idx_val) {
*/
/* E5 Sections 15.9.3.1, B.2.4, B.2.5 */
- duk_to_number(ctx, idx_val);
- if (duk_is_nan(ctx, idx_val)) {
+ duk_to_number(thr, idx_val);
+ if (duk_is_nan(thr, idx_val)) {
return;
}
- duk_dup(ctx, idx_val);
- duk_to_int(ctx, -1);
- d = duk_get_number(ctx, -1); /* get as double to handle huge numbers correctly */
+ duk_dup(thr, idx_val);
+ duk_to_int(thr, -1);
+ d = duk_get_number(thr, -1); /* get as double to handle huge numbers correctly */
if (d >= 0.0 && d <= 99.0) {
d += 1900.0;
- duk_push_number(ctx, d);
- duk_replace(ctx, idx_val);
+ duk_push_number(thr, d);
+ duk_replace(thr, idx_val);
}
- duk_pop(ctx);
+ duk_pop(thr);
}
/* Set datetime parts from stack arguments, defaulting any missing values.
* Day-of-week is not set; it is not required when setting the time value.
*/
-DUK_LOCAL void duk__set_parts_from_args(duk_context *ctx, duk_double_t *dparts, duk_idx_t nargs) {
+DUK_LOCAL void duk__set_parts_from_args(duk_hthread *thr, duk_double_t *dparts, duk_idx_t nargs) {
duk_double_t d;
duk_small_uint_t i;
duk_small_uint_t idx;
@@ -25861,7 +30050,7 @@ DUK_LOCAL void duk__set_parts_from_args(duk_context *ctx, duk_double_t *dparts,
/* Causes a ToNumber() coercion, but doesn't break coercion order since
* year is coerced first anyway.
*/
- duk__twodigit_year_fixup(ctx, 0);
+ duk__twodigit_year_fixup(thr, 0);
/* There are at most 7 args, but we use 8 here so that also
* DUK_DATE_IDX_WEEKDAY gets initialized (to zero) to avoid the potential
@@ -25871,7 +30060,7 @@ DUK_LOCAL void duk__set_parts_from_args(duk_context *ctx, duk_double_t *dparts,
/* Note: rely on index ordering */
idx = DUK_DATE_IDX_YEAR + i;
if ((duk_idx_t) i < nargs) {
- d = duk_to_number(ctx, (duk_idx_t) i);
+ d = duk_to_number(thr, (duk_idx_t) i);
if (idx == DUK_DATE_IDX_DAY) {
/* Convert day from one-based to zero-based (internal). This may
* cause the day part to be negative, which is OK.
@@ -25895,27 +30084,6 @@ DUK_LOCAL void duk__set_parts_from_args(duk_context *ctx, duk_double_t *dparts,
(double) dparts[6], (double) dparts[7]));
}
-/*
- * Helper to format a time value into caller buffer, used by logging.
- * 'out_buf' must be at least DUK_BI_DATE_ISO8601_BUFSIZE long.
- */
-
-DUK_INTERNAL void duk_bi_date_format_timeval(duk_double_t timeval, duk_uint8_t *out_buf) {
- duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
-
- duk_bi_date_timeval_to_parts(timeval,
- parts,
- NULL,
- DUK_DATE_FLAG_ONEBASED);
-
- duk__format_parts_iso8601(parts,
- 0 /*tzoffset*/,
- DUK_DATE_FLAG_TOSTRING_DATE |
- DUK_DATE_FLAG_TOSTRING_TIME |
- DUK_DATE_FLAG_SEP_T /*flags*/,
- out_buf);
-}
-
/*
* Indirect magic value lookup for Date methods.
*
@@ -26049,69 +30217,73 @@ static duk_uint16_t duk__date_magics[] = {
DUK_DATE_FLAG_NAN_TO_ZERO + DUK_DATE_FLAG_YEAR_FIXUP + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
};
-DUK_LOCAL duk_small_uint_t duk__date_get_indirect_magic(duk_context *ctx) {
- duk_small_int_t magicidx = (duk_small_uint_t) duk_get_current_magic(ctx);
- DUK_ASSERT(magicidx >= 0 && magicidx < (duk_small_int_t) (sizeof(duk__date_magics) / sizeof(duk_uint16_t)));
+DUK_LOCAL duk_small_uint_t duk__date_get_indirect_magic(duk_hthread *thr) {
+ duk_small_uint_t magicidx = (duk_small_uint_t) duk_get_current_magic(thr);
+ DUK_ASSERT(magicidx < (duk_small_int_t) (sizeof(duk__date_magics) / sizeof(duk_uint16_t)));
return (duk_small_uint_t) duk__date_magics[magicidx];
}
+#if defined(DUK_USE_DATE_BUILTIN)
/*
* Constructor calls
*/
-DUK_INTERNAL duk_ret_t duk_bi_date_constructor(duk_context *ctx) {
- duk_idx_t nargs = duk_get_top(ctx);
- duk_bool_t is_cons = duk_is_constructor_call(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_date_constructor(duk_hthread *thr) {
+ duk_idx_t nargs = duk_get_top(thr);
+ duk_bool_t is_cons = duk_is_constructor_call(thr);
duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
duk_double_t d;
DUK_DDD(DUK_DDDPRINT("Date constructor, nargs=%ld, is_cons=%ld", (long) nargs, (long) is_cons));
- duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATE),
- DUK_BIDX_DATE_PROTOTYPE);
+ (void) duk_push_object_helper(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATE),
+ DUK_BIDX_DATE_PROTOTYPE);
/* Unlike most built-ins, the internal [[PrimitiveValue]] of a Date
* is mutable.
*/
if (nargs == 0 || !is_cons) {
- d = duk__timeclip(DUK_USE_DATE_GET_NOW(ctx));
- duk_push_number(ctx, d);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
+ d = duk__timeclip(duk_time_get_ecmascript_time_nofrac(thr));
+ duk_push_number(thr, d);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
if (!is_cons) {
/* called as a normal function: return new Date().toString() */
- duk_to_string(ctx, -1);
+ duk_to_string(thr, -1);
}
return 1;
} else if (nargs == 1) {
- duk_to_primitive(ctx, 0, DUK_HINT_NONE);
- if (duk_is_string(ctx, 0)) {
- duk__parse_string(ctx, duk_to_string(ctx, 0));
- duk_replace(ctx, 0); /* may be NaN */
+ const char *str;
+ duk_to_primitive(thr, 0, DUK_HINT_NONE);
+ str = duk_get_string_notsymbol(thr, 0);
+ if (str) {
+ duk__parse_string(thr, str);
+ duk_replace(thr, 0); /* may be NaN */
}
- d = duk__timeclip(duk_to_number(ctx, 0));
- duk_push_number(ctx, d);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
+ d = duk__timeclip(duk_to_number(thr, 0)); /* symbols fail here */
+ duk_push_number(thr, d);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
return 1;
}
- duk__set_parts_from_args(ctx, dparts, nargs);
+ duk__set_parts_from_args(thr, dparts, nargs);
/* Parts are in local time, convert when setting. */
- (void) duk__set_this_timeval_from_dparts(ctx, dparts, DUK_DATE_FLAG_LOCALTIME /*flags*/); /* -> [ ... this timeval ] */
- duk_pop(ctx); /* -> [ ... this ] */
+ (void) duk__set_this_timeval_from_dparts(thr, dparts, DUK_DATE_FLAG_LOCALTIME /*flags*/); /* -> [ ... this timeval ] */
+ duk_pop(thr); /* -> [ ... this ] */
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_date_constructor_parse(duk_context *ctx) {
- return duk__parse_string(ctx, duk_to_string(ctx, 0));
+DUK_INTERNAL duk_ret_t duk_bi_date_constructor_parse(duk_hthread *thr) {
+ return duk__parse_string(thr, duk_to_string(thr, 0));
}
-DUK_INTERNAL duk_ret_t duk_bi_date_constructor_utc(duk_context *ctx) {
- duk_idx_t nargs = duk_get_top(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_date_constructor_utc(duk_hthread *thr) {
+ duk_idx_t nargs = duk_get_top(thr);
duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
duk_double_t d;
@@ -26120,21 +30292,21 @@ DUK_INTERNAL duk_ret_t duk_bi_date_constructor_utc(duk_context *ctx) {
*/
if (nargs < 2) {
- duk_push_nan(ctx);
+ duk_push_nan(thr);
} else {
- duk__set_parts_from_args(ctx, dparts, nargs);
+ duk__set_parts_from_args(thr, dparts, nargs);
d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
- duk_push_number(ctx, d);
+ duk_push_number(thr, d);
}
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_date_constructor_now(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_date_constructor_now(duk_hthread *thr) {
duk_double_t d;
- d = DUK_USE_DATE_GET_NOW(ctx);
+ d = duk_time_get_ecmascript_time_nofrac(thr);
DUK_ASSERT(duk__timeclip(d) == d); /* TimeClip() should never be necessary */
- duk_push_number(ctx, d);
+ duk_push_number(thr, d);
return 1;
}
@@ -26172,44 +30344,44 @@ DUK_INTERNAL duk_ret_t duk_bi_date_constructor_now(duk_context *ctx) {
* toISOString() requires a RangeError for invalid date values.
*/
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_context *ctx) {
- duk_small_uint_t flags = duk__date_get_indirect_magic(ctx);
- return duk__to_string_helper(ctx, flags);
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_hthread *thr) {
+ duk_small_uint_t flags = duk__date_get_indirect_magic(thr);
+ return duk__to_string_helper(thr, flags);
}
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_value_of(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_value_of(duk_hthread *thr) {
/* This native function is also used for Date.prototype.getTime()
* as their behavior is identical.
*/
- duk_double_t d = duk__push_this_get_timeval(ctx, 0 /*flags*/); /* -> [ this ] */
+ duk_double_t d = duk__push_this_get_timeval(thr, 0 /*flags*/); /* -> [ this ] */
DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
- duk_push_number(ctx, d);
+ duk_push_number(thr, d);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_to_json(duk_hthread *thr) {
/* Note: toJSON() is a generic function which works even if 'this'
* is not a Date. The sole argument is ignored.
*/
- duk_push_this(ctx);
- duk_to_object(ctx, -1);
+ duk_push_this(thr);
+ duk_to_object(thr, -1);
- duk_dup_top(ctx);
- duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
- if (duk_is_number(ctx, -1)) {
- duk_double_t d = duk_get_number(ctx, -1);
+ duk_dup_top(thr);
+ duk_to_primitive(thr, -1, DUK_HINT_NUMBER);
+ if (duk_is_number(thr, -1)) {
+ duk_double_t d = duk_get_number(thr, -1);
if (!DUK_ISFINITE(d)) {
- duk_push_null(ctx);
+ duk_push_null(thr);
return 1;
}
}
- duk_pop(ctx);
+ duk_pop(thr);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_ISO_STRING);
- duk_dup(ctx, -2); /* -> [ O toIsoString O ] */
- duk_call_method(ctx, 0);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_TO_ISO_STRING);
+ duk_dup_m2(thr); /* -> [ O toIsoString O ] */
+ duk_call_method(thr, 0);
return 1;
}
@@ -26254,12 +30426,12 @@ DUK_INTERNAL duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx) {
* function (duk_bi_date_prototype_value_of).
*/
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_shared(duk_context *ctx) {
- duk_small_uint_t flags_and_idx = duk__date_get_indirect_magic(ctx);
- return duk__get_part_helper(ctx, flags_and_idx);
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_shared(duk_hthread *thr) {
+ duk_small_uint_t flags_and_idx = duk__date_get_indirect_magic(thr);
+ return duk__get_part_helper(thr, flags_and_idx);
}
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_hthread *thr) {
/*
* Return (t - LocalTime(t)) in minutes:
*
@@ -26278,14 +30450,14 @@ DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ct
duk_int_t tzoffset;
/* Note: DST adjustment is determined using UTC time. */
- d = duk__push_this_get_timeval(ctx, 0 /*flags*/);
+ d = duk__push_this_get_timeval(thr, 0 /*flags*/);
DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
if (DUK_ISNAN(d)) {
- duk_push_nan(ctx);
+ duk_push_nan(thr);
} else {
DUK_ASSERT(DUK_ISFINITE(d));
tzoffset = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d);
- duk_push_int(ctx, -tzoffset / 60);
+ duk_push_int(thr, -tzoffset / 60);
}
return 1;
}
@@ -26339,22 +30511,73 @@ DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ct
* the year will be set regardless of actual argument count.
*/
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_shared(duk_context *ctx) {
- duk_small_uint_t flags_and_maxnargs = duk__date_get_indirect_magic(ctx);
- return duk__set_part_helper(ctx, flags_and_maxnargs);
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_shared(duk_hthread *thr) {
+ duk_small_uint_t flags_and_maxnargs = duk__date_get_indirect_magic(thr);
+ return duk__set_part_helper(thr, flags_and_maxnargs);
}
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_hthread *thr) {
duk_double_t d;
- (void) duk__push_this_get_timeval(ctx, 0 /*flags*/); /* -> [ timeval this ] */
- d = duk__timeclip(duk_to_number(ctx, 0));
- duk_push_number(ctx, d);
- duk_dup_top(ctx);
- duk_put_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE); /* -> [ timeval this timeval ] */
+ (void) duk__push_this_get_timeval(thr, 0 /*flags*/); /* -> [ timeval this ] */
+ d = duk__timeclip(duk_to_number(thr, 0));
+ duk_push_number(thr, d);
+ duk_dup_top(thr);
+ duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_INT_VALUE); /* -> [ timeval this timeval ] */
return 1;
}
+
+#endif /* DUK_USE_DATE_BUILTIN */
+
+/* automatic undefs */
+#undef DUK__CF_ACCEPT
+#undef DUK__CF_ACCEPT_NUL
+#undef DUK__CF_NEG
+#undef DUK__DPRINT_DPARTS
+#undef DUK__DPRINT_PARTS
+#undef DUK__DPRINT_PARTS_AND_DPARTS
+#undef DUK__LOCAL_TZOFFSET_MAXITER
+#undef DUK__NUM_ISO8601_PARSER_PARTS
+#undef DUK__PACK_RULE
+#undef DUK__PI_DAY
+#undef DUK__PI_HOUR
+#undef DUK__PI_MILLISECOND
+#undef DUK__PI_MINUTE
+#undef DUK__PI_MONTH
+#undef DUK__PI_SECOND
+#undef DUK__PI_TZHOUR
+#undef DUK__PI_TZMINUTE
+#undef DUK__PI_YEAR
+#undef DUK__PM_DAY
+#undef DUK__PM_HOUR
+#undef DUK__PM_MILLISECOND
+#undef DUK__PM_MINUTE
+#undef DUK__PM_MONTH
+#undef DUK__PM_SECOND
+#undef DUK__PM_TZHOUR
+#undef DUK__PM_TZMINUTE
+#undef DUK__PM_YEAR
+#undef DUK__RULE_MASK_PART_SEP
+#undef DUK__SI_COLON
+#undef DUK__SI_MINUS
+#undef DUK__SI_NUL
+#undef DUK__SI_PERIOD
+#undef DUK__SI_PLUS
+#undef DUK__SI_SPACE
+#undef DUK__SI_T
+#undef DUK__SI_Z
+#undef DUK__SM_COLON
+#undef DUK__SM_MINUS
+#undef DUK__SM_NUL
+#undef DUK__SM_PERIOD
+#undef DUK__SM_PLUS
+#undef DUK__SM_SPACE
+#undef DUK__SM_T
+#undef DUK__SM_Z
+#undef DUK__UNPACK_RULE
+#undef DUK__WEEKDAY_MOD_ADDER
+#undef DUK__YEAR
#line 1 "duk_bi_date_unix.c"
/*
* Unix-like Date providers
@@ -26362,7 +30585,7 @@ DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx) {
* Generally useful Unix / POSIX / ANSI Date providers.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/* The necessary #includes are in place in duk_config.h. */
@@ -26374,18 +30597,18 @@ DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx) {
#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
/* Get current Ecmascript time (= UNIX/Posix time, but in milliseconds). */
-DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(void) {
struct timeval tv;
duk_double_t d;
if (gettimeofday(&tv, NULL) != 0) {
- DUK_ERROR_INTERNAL_DEFMSG(thr);
+ DUK_D(DUK_DPRINT("gettimeofday() failed"));
+ return 0.0;
}
+ /* As of Duktape 2.2.0 allow fractions. */
d = ((duk_double_t) tv.tv_sec) * 1000.0 +
- ((duk_double_t) (tv.tv_usec / 1000));
- DUK_ASSERT(DUK_FLOOR(d) == d); /* no fractions */
+ ((duk_double_t) tv.tv_usec) / 1000.0;
return d;
}
@@ -26393,23 +30616,26 @@ DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx) {
#if defined(DUK_USE_DATE_NOW_TIME)
/* Not a very good provider: only full seconds are available. */
-DUK_INTERNAL duk_double_t duk_bi_date_get_now_time(duk_context *ctx) {
+DUK_INTERNAL duk_double_t duk_bi_date_get_now_time(void) {
time_t t;
- DUK_UNREF(ctx);
t = time(NULL);
+ if (t == (time_t) -1) {
+ DUK_D(DUK_DPRINT("time() failed"));
+ return 0.0;
+ }
return ((duk_double_t) t) * 1000.0;
}
#endif /* DUK_USE_DATE_NOW_TIME */
-#if defined(DUK_USE_DATE_TZO_GMTIME) || defined(DUK_USE_DATE_TZO_GMTIME_R)
+#if defined(DUK_USE_DATE_TZO_GMTIME) || defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S)
/* Get local time offset (in seconds) for a certain (UTC) instant 'd'. */
DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
time_t t, t1, t2;
duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
struct tm tms[2];
-#ifdef DUK_USE_DATE_TZO_GMTIME
+#if defined(DUK_USE_DATE_TZO_GMTIME)
struct tm *tm_ptr;
#endif
@@ -26492,6 +30718,9 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
#if defined(DUK_USE_DATE_TZO_GMTIME_R)
(void) gmtime_r(&t, &tms[0]);
(void) localtime_r(&t, &tms[1]);
+#elif defined(DUK_USE_DATE_TZO_GMTIME_S)
+ (void) gmtime_s(&t, &tms[0]);
+ (void) localtime_s(&t, &tms[1]);
#elif defined(DUK_USE_DATE_TZO_GMTIME)
tm_ptr = gmtime(&t);
DUK_MEMCPY((void *) &tms[0], tm_ptr, sizeof(struct tm));
@@ -26526,7 +30755,7 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
* an mktime() error return is the cast above. See e.g.:
* http://pubs.opengroup.org/onlinepubs/009695299/functions/mktime.html
*/
- goto error;
+ goto mktime_error;
}
DUK_DDD(DUK_DDDPRINT("t1=%ld (utc), t2=%ld (local)", (long) t1, (long) t2));
@@ -26542,7 +30771,7 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
#endif
return (duk_int_t) difftime(t2, t1);
- error:
+ mktime_error:
/* XXX: return something more useful, so that caller can throw? */
DUK_D(DUK_DPRINT("mktime() failed, d=%lf", (double) d));
return 0;
@@ -26550,12 +30779,12 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
#endif /* DUK_USE_DATE_TZO_GMTIME */
#if defined(DUK_USE_DATE_PRS_STRPTIME)
-DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, const char *str) {
+DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_hthread *thr, const char *str) {
struct tm tm;
time_t t;
char buf[DUK__STRPTIME_BUF_SIZE];
- /* copy to buffer with spare to avoid Valgrind gripes from strptime */
+ /* Copy to buffer with slack to avoid Valgrind gripes from strptime. */
DUK_ASSERT(str != NULL);
DUK_MEMZERO(buf, sizeof(buf)); /* valgrind whine without this */
DUK_SNPRINTF(buf, sizeof(buf), "%s", (const char *) str);
@@ -26575,7 +30804,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, cons
t = mktime(&tm);
DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t));
if (t >= 0) {
- duk_push_number(ctx, ((duk_double_t) t) * 1000.0);
+ duk_push_number(thr, ((duk_double_t) t) * 1000.0);
return 1;
}
}
@@ -26585,7 +30814,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, cons
#endif /* DUK_USE_DATE_PRS_STRPTIME */
#if defined(DUK_USE_DATE_PRS_GETDATE)
-DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const char *str) {
+DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_hthread *thr, const char *str) {
struct tm tm;
duk_small_int_t rc;
time_t t;
@@ -26602,7 +30831,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const
t = mktime(&tm);
DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t));
if (t >= 0) {
- duk_push_number(ctx, (duk_double_t) t);
+ duk_push_number(thr, (duk_double_t) t);
return 1;
}
}
@@ -26612,7 +30841,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const
#endif /* DUK_USE_DATE_PRS_GETDATE */
#if defined(DUK_USE_DATE_FMT_STRFTIME)
-DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags) {
+DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_hthread *thr, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags) {
char buf[DUK__STRFTIME_BUF_SIZE];
struct tm tm;
const char *fmt;
@@ -26631,7 +30860,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, duk_
* supporting a large time range (the full Ecmascript range).
*/
if (sizeof(time_t) < 8 &&
- (parts[DUK_DATE_IDX_YEAR] < 1970 || parts[DUK_DATE_IDX_YEAR] > 2037)) {
+ (parts[DUK_DATE_IDX_YEAR] < 1970 || parts[DUK_DATE_IDX_YEAR] > 2037)) {
/* be paranoid for 32-bit time values (even avoiding negative ones) */
return 0;
}
@@ -26658,13 +30887,27 @@ DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, duk_
(void) strftime(buf, sizeof(buf) - 1, fmt, &tm);
DUK_ASSERT(buf[sizeof(buf) - 1] == 0);
- duk_push_string(ctx, buf);
+ duk_push_string(thr, buf);
return 1;
}
#endif /* DUK_USE_DATE_FMT_STRFTIME */
-#undef DUK__STRPTIME_BUF_SIZE
+#if defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME)
+DUK_INTERNAL duk_double_t duk_bi_date_get_monotonic_time_clock_gettime(void) {
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+ return (duk_double_t) ts.tv_sec * 1000.0 + (duk_double_t) ts.tv_nsec / 1000000.0;
+ } else {
+ DUK_D(DUK_DPRINT("clock_gettime(CLOCK_MONOTONIC) failed"));
+ return 0.0;
+ }
+}
+#endif
+
+/* automatic undefs */
#undef DUK__STRFTIME_BUF_SIZE
+#undef DUK__STRPTIME_BUF_SIZE
#line 1 "duk_bi_date_windows.c"
/*
* Windows Date providers
@@ -26674,7 +30917,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, duk_
* - http://msdn.microsoft.com/en-us/library/windows/desktop/ms725473(v=vs.85).aspx
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/* The necessary #includes are in place in duk_config.h. */
@@ -26690,6 +30933,12 @@ DUK_LOCAL void duk__convert_systime_to_ularge(const SYSTEMTIME *st, ULARGE_INTEG
res->HighPart = ft.dwHighDateTime;
}
}
+
+DUK_LOCAL void duk__convert_filetime_to_ularge(const FILETIME *ft, ULARGE_INTEGER *res) {
+ res->LowPart = ft->dwLowDateTime;
+ res->HighPart = ft->dwHighDateTime;
+}
+
DUK_LOCAL void duk__set_systime_jan1970(SYSTEMTIME *st) {
DUK_MEMZERO((void *) st, sizeof(*st));
st->wYear = 1970;
@@ -26703,30 +30952,52 @@ DUK_LOCAL void duk__set_systime_jan1970(SYSTEMTIME *st) {
}
#endif /* defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS) */
-#ifdef DUK_USE_DATE_NOW_WINDOWS
-DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx) {
+#if defined(DUK_USE_DATE_NOW_WINDOWS)
+DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows(void) {
/* Suggested step-by-step method from documentation of RtlTimeToSecondsSince1970:
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms724928(v=vs.85).aspx
*/
SYSTEMTIME st1, st2;
ULARGE_INTEGER tmp1, tmp2;
- DUK_UNREF(ctx);
-
GetSystemTime(&st1);
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
duk__set_systime_jan1970(&st2);
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
- /* Difference is in 100ns units, convert to milliseconds w/o fractions */
- return (duk_double_t) ((tmp1.QuadPart - tmp2.QuadPart) / 10000LL);
+ /* Difference is in 100ns units, convert to milliseconds, keeping
+ * fractions since Duktape 2.2.0. This is only theoretical because
+ * SYSTEMTIME is limited to milliseconds.
+ */
+ return (duk_double_t) ((LONGLONG) tmp1.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000.0;
}
#endif /* DUK_USE_DATE_NOW_WINDOWS */
+#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS)
+DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows_subms(void) {
+ /* Variant of the basic algorithm using GetSystemTimePreciseAsFileTime()
+ * for more accuracy.
+ */
+ FILETIME ft1;
+ SYSTEMTIME st2;
+ ULARGE_INTEGER tmp1, tmp2;
+
+ GetSystemTimePreciseAsFileTime(&ft1);
+ duk__convert_filetime_to_ularge((const FILETIME *) &ft1, &tmp1);
+
+ duk__set_systime_jan1970(&st2);
+ duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
+
+ /* Difference is in 100ns units, convert to milliseconds, keeping
+ * fractions since Duktape 2.2.0.
+ */
+ return (duk_double_t) ((LONGLONG) tmp1.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000.0;
+}
+#endif /* DUK_USE_DATE_NOW_WINDOWS */
#if defined(DUK_USE_DATE_TZO_WINDOWS)
-DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d) {
+DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d) {
SYSTEMTIME st1;
SYSTEMTIME st2;
SYSTEMTIME st3;
@@ -26761,9 +31032,66 @@ DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st3, &tmp3);
/* Positive if local time ahead of UTC. */
- return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000000LL); /* seconds */
+ return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / DUK_I64_CONSTANT(10000000)); /* seconds */
}
#endif /* DUK_USE_DATE_TZO_WINDOWS */
+
+#if defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST)
+DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_double_t d) {
+ SYSTEMTIME st1;
+ SYSTEMTIME st2;
+ FILETIME ft1;
+ FILETIME ft2;
+ ULARGE_INTEGER tmp1;
+ ULARGE_INTEGER tmp2;
+
+ /* Do a similar computation to duk_bi_date_get_local_tzoffset_windows
+ * but without accounting for daylight savings time. Use this on
+ * Windows platforms (like Durango) that don't support the
+ * SystemTimeToTzSpecificLocalTime() call.
+ */
+
+ /* current time not needed for this computation */
+ DUK_UNREF(d);
+
+ duk__set_systime_jan1970(&st1);
+ duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
+
+ ft1.dwLowDateTime = tmp1.LowPart;
+ ft1.dwHighDateTime = tmp1.HighPart;
+ FileTimeToLocalFileTime((const FILETIME *) &ft1, &ft2);
+
+ FileTimeToSystemTime((const FILETIME *) &ft2, &st2);
+ duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
+
+ return (duk_int_t) (((LONGLONG) tmp2.QuadPart - (LONGLONG) tmp1.QuadPart) / DUK_I64_CONSTANT(10000000)); /* seconds */
+}
+#endif /* DUK_USE_DATE_TZO_WINDOWS_NO_DST */
+
+#if defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC)
+DUK_INTERNAL duk_double_t duk_bi_date_get_monotonic_time_windows_qpc(void) {
+ LARGE_INTEGER count, freq;
+
+ /* There are legacy issues with QueryPerformanceCounter():
+ * - Potential jumps: https://support.microsoft.com/en-us/help/274323/performance-counter-value-may-unexpectedly-leap-forward
+ * - Differences between cores (XP): https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx#qpc_support_in_windows_versions
+ *
+ * We avoid these by enabling QPC by default only for Vista or later.
+ */
+
+ if (QueryPerformanceCounter(&count) && QueryPerformanceFrequency(&freq)) {
+ /* XXX: QueryPerformanceFrequency() can be cached */
+ return (duk_double_t) count.QuadPart / (duk_double_t) freq.QuadPart * 1000.0;
+ } else {
+ /* MSDN: "On systems that run Windows XP or later, the function
+ * will always succeed and will thus never return zero."
+ * Provide minimal error path just in case user enables this
+ * feature in pre-XP Windows.
+ */
+ return 0.0;
+ }
+}
+#endif /* DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC */
#line 1 "duk_bi_duktape.c"
/*
* Duktape built-ins
@@ -26776,243 +31104,81 @@ DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t
* anyway.
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-/* Raw helper to extract internal information / statistics about a value.
- * The return values are version specific and must not expose anything
- * that would lead to security issues (e.g. exposing compiled function
- * 'data' buffer might be an issue). Currently only counts and sizes and
- * such are given so there should not be a security impact.
- */
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
- duk_heaphdr *h;
- duk_int_t i, n;
+#if defined(DUK_USE_DUKTAPE_BUILTIN)
- DUK_UNREF(thr);
-
- /* result array */
- duk_push_array(ctx); /* -> [ val arr ] */
-
- /* type tag (public) */
- duk_push_int(ctx, duk_get_type(ctx, 0));
-
- /* address */
- tv = duk_get_tval(ctx, 0);
- DUK_ASSERT(tv != NULL); /* because arg count is 1 */
- if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
- h = DUK_TVAL_GET_HEAPHDR(tv);
- duk_push_pointer(ctx, (void *) h);
- } else {
- /* internal type tag */
- duk_push_int(ctx, (duk_int_t) DUK_TVAL_GET_TAG(tv));
- goto done;
- }
- DUK_ASSERT(h != NULL);
-
- /* refcount */
-#ifdef DUK_USE_REFERENCE_COUNTING
- duk_push_size_t(ctx, DUK_HEAPHDR_GET_REFCOUNT(h));
-#else
- duk_push_undefined(ctx);
-#endif
-
- /* heaphdr size and additional allocation size, followed by
- * type specific stuff (with varying value count)
- */
- switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) {
- case DUK_HTYPE_STRING: {
- duk_hstring *h_str = (duk_hstring *) h;
- duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hstring) + DUK_HSTRING_GET_BYTELEN(h_str) + 1));
- break;
- }
- case DUK_HTYPE_OBJECT: {
- duk_hobject *h_obj = (duk_hobject *) h;
- duk_small_uint_t hdr_size;
- if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) {
- hdr_size = (duk_small_uint_t) sizeof(duk_hcompiledfunction);
- } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h_obj)) {
- hdr_size = (duk_small_uint_t) sizeof(duk_hnativefunction);
- } else if (DUK_HOBJECT_IS_THREAD(h_obj)) {
- hdr_size = (duk_small_uint_t) sizeof(duk_hthread);
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
- } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
- hdr_size = (duk_small_uint_t) sizeof(duk_hbufferobject);
-#endif
- } else {
- hdr_size = (duk_small_uint_t) sizeof(duk_hobject);
- }
- duk_push_uint(ctx, (duk_uint_t) hdr_size);
- duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_P_ALLOC_SIZE(h_obj));
- duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ESIZE(h_obj));
- /* Note: e_next indicates the number of gc-reachable entries
- * in the entry part, and also indicates the index where the
- * next new property would be inserted. It does *not* indicate
- * the number of non-NULL keys present in the object. That
- * value could be counted separately but requires a pass through
- * the key list.
- */
- duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ENEXT(h_obj));
- duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ASIZE(h_obj));
- duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_HSIZE(h_obj));
- if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) {
- duk_hbuffer *h_data = (duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, (duk_hcompiledfunction *) h_obj);
- if (h_data) {
- duk_push_uint(ctx, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_data));
- } else {
- duk_push_uint(ctx, 0);
- }
- }
- break;
- }
- case DUK_HTYPE_BUFFER: {
- duk_hbuffer *h_buf = (duk_hbuffer *) h;
- if (DUK_HBUFFER_HAS_DYNAMIC(h_buf)) {
- if (DUK_HBUFFER_HAS_EXTERNAL(h_buf)) {
- duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hbuffer_external)));
- } else {
- /* When alloc_size == 0 the second allocation may not
- * actually exist.
- */
- duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hbuffer_dynamic)));
- }
- duk_push_uint(ctx, (duk_uint_t) (DUK_HBUFFER_GET_SIZE(h_buf)));
- } else {
- duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hbuffer_fixed) + DUK_HBUFFER_GET_SIZE(h_buf) + 1));
- }
- break;
-
- }
- }
-
- done:
- /* set values into ret array */
- /* XXX: primitive to make array from valstack slice */
- n = duk_get_top(ctx);
- for (i = 2; i < n; i++) {
- duk_dup(ctx, i);
- duk_put_prop_index(ctx, 1, i - 2);
- }
- duk_dup(ctx, 1);
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_info(duk_hthread *thr) {
+ duk_inspect_value(thr, -1);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_activation *act;
- duk_uint_fast32_t pc;
- duk_uint_fast32_t line;
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_act(duk_hthread *thr) {
duk_int_t level;
- /* -1 = top callstack entry, callstack[callstack_top - 1]
- * -callstack_top = bottom callstack entry, callstack[0]
- */
- level = duk_to_int(ctx, 0);
- if (level >= 0 || -level > (duk_int_t) thr->callstack_top) {
- return 0;
- }
- DUK_ASSERT(level >= -((duk_int_t) thr->callstack_top) && level <= -1);
- act = thr->callstack + thr->callstack_top + level;
-
- duk_push_object(ctx);
-
- duk_push_tval(ctx, &act->tv_func);
-
- /* Relevant PC is just before current one because PC is
- * post-incremented. This should match what error augment
- * code does.
- */
- pc = duk_hthread_get_act_prev_pc(thr, act);
- duk_push_uint(ctx, (duk_uint_t) pc);
-
-#if defined(DUK_USE_PC2LINE)
- line = duk_hobject_pc2line_query(ctx, -2, pc);
-#else
- line = 0;
-#endif
- duk_push_uint(ctx, (duk_uint_t) line);
-
- /* Providing access to e.g. act->lex_env would be dangerous: these
- * internal structures must never be accessible to the application.
- * Duktape relies on them having consistent data, and this consistency
- * is only asserted for, not checked for.
- */
-
- /* [ level obj func pc line ] */
-
- /* XXX: version specific array format instead? */
- duk_xdef_prop_stridx_wec(ctx, -4, DUK_STRIDX_LINE_NUMBER);
- duk_xdef_prop_stridx_wec(ctx, -3, DUK_STRIDX_PC);
- duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_LC_FUNCTION);
+ level = duk_to_int(thr, 0);
+ duk_inspect_callstack_entry(thr, level);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx) {
-#ifdef DUK_USE_MARK_AND_SWEEP
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_hthread *thr) {
duk_small_uint_t flags;
- duk_bool_t rc;
- flags = (duk_small_uint_t) duk_get_uint(ctx, 0);
- rc = duk_heap_mark_and_sweep(thr->heap, flags);
+ flags = (duk_small_uint_t) duk_get_uint(thr, 0);
+ duk_heap_mark_and_sweep(thr->heap, flags);
/* XXX: Not sure what the best return value would be in the API.
- * Return a boolean for now. Note that rc == 0 is success (true).
+ * Return true for now.
*/
- duk_push_boolean(ctx, !rc);
+ duk_push_true(thr);
return 1;
-#else
- DUK_UNREF(ctx);
- return 0;
-#endif
}
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx) {
- (void) duk_require_hobject(ctx, 0);
- if (duk_get_top(ctx) >= 2) {
+#if defined(DUK_USE_FINALIZER_SUPPORT)
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_hthread *thr) {
+ (void) duk_require_hobject(thr, 0);
+ if (duk_get_top(thr) >= 2) {
/* Set: currently a finalizer is disabled by setting it to
* undefined; this does not remove the property at the moment.
* The value could be type checked to be either a function
* or something else; if something else, the property could
- * be deleted.
+ * be deleted. Must use duk_set_finalizer() to keep
+ * DUK_HOBJECT_FLAG_HAVE_FINALIZER in sync.
*/
- duk_set_top(ctx, 2);
- (void) duk_put_prop_stridx(ctx, 0, DUK_STRIDX_INT_FINALIZER);
+ duk_set_top(thr, 2);
+ duk_set_finalizer(thr, 0);
return 0;
} else {
/* Get. */
- DUK_ASSERT(duk_get_top(ctx) == 1);
- duk_get_prop_stridx(ctx, 0, DUK_STRIDX_INT_FINALIZER);
+ DUK_ASSERT(duk_get_top(thr) == 1);
+ duk_get_finalizer(thr, 0);
return 1;
}
}
+#endif /* DUK_USE_FINALIZER_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_hthread *thr) {
duk_hstring *h_str;
- DUK_UNREF(thr);
-
/* Vararg function: must be careful to check/require arguments.
* The JSON helpers accept invalid indices and treat them like
* non-existent optional parameters.
*/
- h_str = duk_require_hstring(ctx, 0);
- duk_require_valid_index(ctx, 1);
+ h_str = duk_require_hstring(thr, 0); /* Could reject symbols, but no point: won't match comparisons. */
+ duk_require_valid_index(thr, 1);
if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
- duk_set_top(ctx, 2);
- duk_hex_encode(ctx, 1);
- DUK_ASSERT_TOP(ctx, 2);
+ duk_set_top(thr, 2);
+ duk_hex_encode(thr, 1);
+ DUK_ASSERT_TOP(thr, 2);
} else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
- duk_set_top(ctx, 2);
- duk_base64_encode(ctx, 1);
- DUK_ASSERT_TOP(ctx, 2);
-#ifdef DUK_USE_JX
+ duk_set_top(thr, 2);
+ duk_base64_encode(thr, 1);
+ DUK_ASSERT_TOP(thr, 2);
+#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JX)
} else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
- duk_bi_json_stringify_helper(ctx,
+ duk_bi_json_stringify_helper(thr,
1 /*idx_value*/,
2 /*idx_replacer*/,
3 /*idx_space*/,
@@ -27020,9 +31186,9 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) {
DUK_JSON_FLAG_ASCII_ONLY |
DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/);
#endif
-#ifdef DUK_USE_JC
+#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JC)
} else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
- duk_bi_json_stringify_helper(ctx,
+ duk_bi_json_stringify_helper(thr,
1 /*idx_value*/,
2 /*idx_replacer*/,
3 /*idx_space*/,
@@ -27030,49 +31196,46 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) {
DUK_JSON_FLAG_ASCII_ONLY /*flags*/);
#endif
} else {
- return DUK_RET_TYPE_ERROR;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_hthread *thr) {
duk_hstring *h_str;
- DUK_UNREF(thr);
-
/* Vararg function: must be careful to check/require arguments.
* The JSON helpers accept invalid indices and treat them like
* non-existent optional parameters.
*/
- h_str = duk_require_hstring(ctx, 0);
- duk_require_valid_index(ctx, 1);
+ h_str = duk_require_hstring(thr, 0); /* Could reject symbols, but no point: won't match comparisons */
+ duk_require_valid_index(thr, 1);
if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
- duk_set_top(ctx, 2);
- duk_hex_decode(ctx, 1);
- DUK_ASSERT_TOP(ctx, 2);
+ duk_set_top(thr, 2);
+ duk_hex_decode(thr, 1);
+ DUK_ASSERT_TOP(thr, 2);
} else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
- duk_set_top(ctx, 2);
- duk_base64_decode(ctx, 1);
- DUK_ASSERT_TOP(ctx, 2);
-#ifdef DUK_USE_JX
+ duk_set_top(thr, 2);
+ duk_base64_decode(thr, 1);
+ DUK_ASSERT_TOP(thr, 2);
+#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JX)
} else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
- duk_bi_json_parse_helper(ctx,
+ duk_bi_json_parse_helper(thr,
1 /*idx_value*/,
2 /*idx_replacer*/,
DUK_JSON_FLAG_EXT_CUSTOM /*flags*/);
#endif
-#ifdef DUK_USE_JC
+#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JC)
} else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
- duk_bi_json_parse_helper(ctx,
+ duk_bi_json_parse_helper(thr,
1 /*idx_value*/,
2 /*idx_replacer*/,
DUK_JSON_FLAG_EXT_COMPATIBLE /*flags*/);
#endif
} else {
- return DUK_RET_TYPE_ERROR;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
return 1;
}
@@ -27081,19 +31244,558 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx) {
* Compact an object
*/
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx) {
- DUK_ASSERT_TOP(ctx, 1);
- duk_compact(ctx, 0);
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_compact(duk_hthread *thr) {
+ DUK_ASSERT_TOP(thr, 1);
+ duk_compact(thr, 0);
return 1; /* return the argument object */
}
+
+#endif /* DUK_USE_DUKTAPE_BUILTIN */
+#line 1 "duk_bi_encoding.c"
+/*
+ * WHATWG Encoding API built-ins
+ *
+ * API specification: https://encoding.spec.whatwg.org/#api
+ * Web IDL: https://www.w3.org/TR/WebIDL/
+ */
+
+/* #include duk_internal.h -> already included */
+
+/*
+ * Data structures for encoding/decoding
+ */
+
+typedef struct {
+ duk_uint8_t *out; /* where to write next byte(s) */
+ duk_codepoint_t lead; /* lead surrogate */
+} duk__encode_context;
+
+typedef struct {
+ /* UTF-8 decoding state */
+ duk_codepoint_t codepoint; /* built up incrementally */
+ duk_uint8_t upper; /* max value of next byte (decode error otherwise) */
+ duk_uint8_t lower; /* min value of next byte (ditto) */
+ duk_uint8_t needed; /* how many more bytes we need */
+ duk_uint8_t bom_handled; /* BOM seen or no longer expected */
+
+ /* Decoder configuration */
+ duk_uint8_t fatal;
+ duk_uint8_t ignore_bom;
+} duk__decode_context;
+
+/* The signed duk_codepoint_t type is used to signal a decoded codepoint
+ * (>= 0) or various other states using negative values.
+ */
+#define DUK__CP_CONTINUE (-1) /* continue to next byte, no completed codepoint */
+#define DUK__CP_ERROR (-2) /* decoding error */
+#define DUK__CP_RETRY (-3) /* decoding error; retry last byte */
+
+/*
+ * Raw helpers for encoding/decoding
+ */
+
+/* Emit UTF-8 (= CESU-8) encoded U+FFFD (replacement char), i.e. ef bf bd. */
+DUK_LOCAL duk_uint8_t *duk__utf8_emit_repl(duk_uint8_t *ptr) {
+ *ptr++ = 0xef;
+ *ptr++ = 0xbf;
+ *ptr++ = 0xbd;
+ return ptr;
+}
+
+DUK_LOCAL void duk__utf8_decode_init(duk__decode_context *dec_ctx) {
+ /* (Re)init the decoding state of 'dec_ctx' but leave decoder
+ * configuration fields untouched.
+ */
+ dec_ctx->codepoint = 0x0000L;
+ dec_ctx->upper = 0xbf;
+ dec_ctx->lower = 0x80;
+ dec_ctx->needed = 0;
+ dec_ctx->bom_handled = 0;
+}
+
+DUK_LOCAL duk_codepoint_t duk__utf8_decode_next(duk__decode_context *dec_ctx, duk_uint8_t x) {
+ /*
+ * UTF-8 algorithm based on the Encoding specification:
+ * https://encoding.spec.whatwg.org/#utf-8-decoder
+ *
+ * Two main states: decoding initial byte vs. decoding continuation
+ * bytes. Shortest length encoding is validated by restricting the
+ * allowed range of first continuation byte using 'lower' and 'upper'.
+ */
+
+ if (dec_ctx->needed == 0) {
+ /* process initial byte */
+ if (x <= 0x7f) {
+ /* U+0000-U+007F, 1 byte (ASCII) */
+ return (duk_codepoint_t) x;
+ } else if (x >= 0xc2 && x <= 0xdf) {
+ /* U+0080-U+07FF, 2 bytes */
+ dec_ctx->needed = 1;
+ dec_ctx->codepoint = x & 0x1f;
+ DUK_ASSERT(dec_ctx->lower == 0x80);
+ DUK_ASSERT(dec_ctx->upper == 0xbf);
+ return DUK__CP_CONTINUE;
+ } else if (x >= 0xe0 && x <= 0xef) {
+ /* U+0800-U+FFFF, 3 bytes */
+ if (x == 0xe0) {
+ dec_ctx->lower = 0xa0;
+ DUK_ASSERT(dec_ctx->upper == 0xbf);
+ } else if (x == 0xed) {
+ DUK_ASSERT(dec_ctx->lower == 0x80);
+ dec_ctx->upper = 0x9f;
+ }
+ dec_ctx->needed = 2;
+ dec_ctx->codepoint = x & 0x0f;
+ return DUK__CP_CONTINUE;
+ } else if (x >= 0xf0 && x <= 0xf4) {
+ /* U+010000-U+10FFFF, 4 bytes */
+ if (x == 0xf0) {
+ dec_ctx->lower = 0x90;
+ DUK_ASSERT(dec_ctx->upper == 0xbf);
+ } else if (x == 0xf4) {
+ DUK_ASSERT(dec_ctx->lower == 0x80);
+ dec_ctx->upper = 0x8f;
+ }
+ dec_ctx->needed = 3;
+ dec_ctx->codepoint = x & 0x07;
+ return DUK__CP_CONTINUE;
+ } else {
+ /* not a legal initial byte */
+ return DUK__CP_ERROR;
+ }
+ } else {
+ /* process continuation byte */
+ if (x >= dec_ctx->lower && x <= dec_ctx->upper) {
+ dec_ctx->lower = 0x80;
+ dec_ctx->upper = 0xbf;
+ dec_ctx->codepoint = (dec_ctx->codepoint << 6) | (x & 0x3f);
+ if (--dec_ctx->needed > 0) {
+ /* need more bytes */
+ return DUK__CP_CONTINUE;
+ } else {
+ /* got a codepoint */
+ duk_codepoint_t ret;
+ DUK_ASSERT(dec_ctx->codepoint <= 0x10ffffL); /* Decoding rules guarantee. */
+ ret = dec_ctx->codepoint;
+ dec_ctx->codepoint = 0x0000L;
+ dec_ctx->needed = 0;
+ return ret;
+ }
+ } else {
+ /* We just encountered an illegal UTF-8 continuation byte. This might
+ * be the initial byte of the next character; if we return a plain
+ * error status and the decoder is in replacement mode, the character
+ * will be masked. We still need to alert the caller to the error
+ * though.
+ */
+ dec_ctx->codepoint = 0x0000L;
+ dec_ctx->needed = 0;
+ dec_ctx->lower = 0x80;
+ dec_ctx->upper = 0xbf;
+ return DUK__CP_RETRY;
+ }
+ }
+}
+
+#if defined(DUK_USE_ENCODING_BUILTINS)
+DUK_LOCAL void duk__utf8_encode_char(void *udata, duk_codepoint_t codepoint) {
+ duk__encode_context *enc_ctx;
+
+ DUK_ASSERT(codepoint >= 0);
+ enc_ctx = (duk__encode_context *) udata;
+ DUK_ASSERT(enc_ctx != NULL);
+
+#if !defined(DUK_USE_PREFER_SIZE)
+ if (codepoint <= 0x7f && enc_ctx->lead == 0x0000L) {
+ /* Fast path for ASCII. */
+ *enc_ctx->out++ = (duk_uint8_t) codepoint;
+ return;
+ }
+#endif
+
+ if (DUK_UNLIKELY(codepoint > 0x10ffffL)) {
+ /* cannot legally encode in UTF-8 */
+ codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
+ } else if (codepoint >= 0xd800L && codepoint <= 0xdfffL) {
+ if (codepoint <= 0xdbffL) {
+ /* high surrogate */
+ duk_codepoint_t prev_lead = enc_ctx->lead;
+ enc_ctx->lead = codepoint;
+ if (prev_lead == 0x0000L) {
+ /* high surrogate, no output */
+ return;
+ } else {
+ /* consecutive high surrogates, consider first one unpaired */
+ codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
+ }
+ } else {
+ /* low surrogate */
+ if (enc_ctx->lead != 0x0000L) {
+ codepoint = (duk_codepoint_t) (0x010000L + ((enc_ctx->lead - 0xd800L) << 10) + (codepoint - 0xdc00L));
+ enc_ctx->lead = 0x0000L;
+ } else {
+ /* unpaired low surrogate */
+ DUK_ASSERT(enc_ctx->lead == 0x0000L);
+ codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
+ }
+ }
+ } else {
+ if (enc_ctx->lead != 0x0000L) {
+ /* unpaired high surrogate: emit replacement character and the input codepoint */
+ enc_ctx->lead = 0x0000L;
+ enc_ctx->out = duk__utf8_emit_repl(enc_ctx->out);
+ }
+ }
+
+ /* Codepoint may be original input, a decoded surrogate pair, or may
+ * have been replaced with U+FFFD.
+ */
+ enc_ctx->out += duk_unicode_encode_xutf8((duk_ucodepoint_t) codepoint, enc_ctx->out);
+}
+#endif /* DUK_USE_ENCODING_BUILTINS */
+
+/* Shared helper for buffer-to-string using a TextDecoder() compatible UTF-8
+ * decoder.
+ */
+DUK_LOCAL duk_ret_t duk__decode_helper(duk_hthread *thr, duk__decode_context *dec_ctx) {
+ const duk_uint8_t *input;
+ duk_size_t len = 0;
+ duk_size_t len_tmp;
+ duk_bool_t stream = 0;
+ duk_codepoint_t codepoint;
+ duk_uint8_t *output;
+ const duk_uint8_t *in;
+ duk_uint8_t *out;
+
+ DUK_ASSERT(dec_ctx != NULL);
+
+ /* Careful with input buffer pointer: any side effects involving
+ * code execution (e.g. getters, coercion calls, and finalizers)
+ * may cause a resize and invalidate a pointer we've read. This
+ * is why the pointer is actually looked up at the last minute.
+ * Argument validation must still happen first to match WHATWG
+ * required side effect order.
+ */
+
+ if (duk_is_undefined(thr, 0)) {
+ duk_push_fixed_buffer_nozero(thr, 0);
+ duk_replace(thr, 0);
+ }
+ (void) duk_require_buffer_data(thr, 0, &len); /* Need 'len', avoid pointer. */
+
+ if (duk_check_type_mask(thr, 1, DUK_TYPE_MASK_UNDEFINED |
+ DUK_TYPE_MASK_NULL |
+ DUK_TYPE_MASK_NONE)) {
+ /* Use defaults, treat missing value like undefined. */
+ } else {
+ duk_require_type_mask(thr, 1, DUK_TYPE_MASK_UNDEFINED |
+ DUK_TYPE_MASK_NULL |
+ DUK_TYPE_MASK_LIGHTFUNC |
+ DUK_TYPE_MASK_BUFFER |
+ DUK_TYPE_MASK_OBJECT);
+ if (duk_get_prop_string(thr, 1, "stream")) {
+ stream = duk_to_boolean(thr, -1);
+ }
+ }
+
+ /* Allowance is 3*len in the general case because all bytes may potentially
+ * become U+FFFD. If the first byte completes a non-BMP codepoint it will
+ * decode to a CESU-8 surrogate pair (6 bytes) so we allow 3 extra bytes to
+ * compensate: (1*3)+3 = 6. Non-BMP codepoints are safe otherwise because
+ * the 4->6 expansion is well under the 3x allowance.
+ *
+ * XXX: As with TextEncoder, need a better buffer allocation strategy here.
+ */
+ if (len >= (DUK_HBUFFER_MAX_BYTELEN / 3) - 3) {
+ DUK_ERROR_TYPE(thr, DUK_STR_RESULT_TOO_LONG);
+ }
+ output = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, 3 + (3 * len)); /* used parts will be always manually written over */
+
+ input = (const duk_uint8_t *) duk_get_buffer_data(thr, 0, &len_tmp);
+ DUK_ASSERT(input != NULL || len == 0);
+ if (DUK_UNLIKELY(len != len_tmp)) {
+ /* Very unlikely but possible: source buffer was resized by
+ * a side effect when fixed buffer was pushed. Output buffer
+ * may not be large enough to hold output, so just fail if
+ * length has changed.
+ */
+ DUK_D(DUK_DPRINT("input buffer resized by side effect, fail"));
+ goto fail_type;
+ }
+
+ /* From this point onwards it's critical that no side effect occur
+ * which may disturb 'input': finalizer execution, property accesses,
+ * active coercions, etc. Even an allocation related mark-and-sweep
+ * may affect the pointer because it may trigger a pending finalizer.
+ */
+
+ in = input;
+ out = output;
+ while (in < input + len) {
+ codepoint = duk__utf8_decode_next(dec_ctx, *in++);
+ if (codepoint < 0) {
+ if (codepoint == DUK__CP_CONTINUE) {
+ continue;
+ }
+
+ /* Decoding error with or without retry. */
+ DUK_ASSERT(codepoint == DUK__CP_ERROR || codepoint == DUK__CP_RETRY);
+ if (codepoint == DUK__CP_RETRY) {
+ --in; /* retry last byte */
+ }
+ /* replacement mode: replace with U+FFFD */
+ codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
+ if (dec_ctx->fatal) {
+ /* fatal mode: throw a TypeError */
+ goto fail_type;
+ }
+ /* Continue with 'codepoint', Unicode replacement. */
+ }
+ DUK_ASSERT(codepoint >= 0x0000L && codepoint <= 0x10ffffL);
+
+ if (!dec_ctx->bom_handled) {
+ dec_ctx->bom_handled = 1;
+ if (codepoint == 0xfeffL && !dec_ctx->ignore_bom) {
+ continue;
+ }
+ }
+
+ out += duk_unicode_encode_cesu8((duk_ucodepoint_t) codepoint, out);
+ DUK_ASSERT(out <= output + (3 + (3 * len)));
+ }
+
+ if (!stream) {
+ if (dec_ctx->needed != 0) {
+ /* truncated sequence at end of buffer */
+ if (dec_ctx->fatal) {
+ goto fail_type;
+ } else {
+ out += duk_unicode_encode_cesu8(DUK_UNICODE_CP_REPLACEMENT_CHARACTER, out);
+ DUK_ASSERT(out <= output + (3 + (3 * len)));
+ }
+ }
+ duk__utf8_decode_init(dec_ctx); /* Initialize decoding state for potential reuse. */
+ }
+
+ /* Output buffer is fixed and thus stable even if there had been
+ * side effects (which there shouldn't be).
+ */
+ duk_push_lstring(thr, (const char *) output, (duk_size_t) (out - output));
+ return 1;
+
+ fail_type:
+ DUK_ERROR_TYPE(thr, DUK_STR_UTF8_DECODE_FAILED);
+ DUK_UNREACHABLE();
+}
+
+/*
+ * Built-in bindings
+ */
+
+#if defined(DUK_USE_ENCODING_BUILTINS)
+DUK_INTERNAL duk_ret_t duk_bi_textencoder_constructor(duk_hthread *thr) {
+ /* TextEncoder currently requires no persistent state, so the constructor
+ * does nothing on purpose.
+ */
+
+ duk_require_constructor_call(thr);
+ return 0;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_hthread *thr) {
+ duk_push_string(thr, "utf-8");
+ return 1;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encode(duk_hthread *thr) {
+ duk__encode_context enc_ctx;
+ duk_size_t len;
+ duk_size_t final_len;
+ duk_uint8_t *output;
+
+ DUK_ASSERT_TOP(thr, 1);
+ if (duk_is_undefined(thr, 0)) {
+ len = 0;
+ } else {
+ duk_hstring *h_input;
+
+ h_input = duk_to_hstring(thr, 0);
+ DUK_ASSERT(h_input != NULL);
+
+ len = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_input);
+ if (len >= DUK_HBUFFER_MAX_BYTELEN / 3) {
+ DUK_ERROR_TYPE(thr, DUK_STR_RESULT_TOO_LONG);
+ }
+ }
+
+ /* Allowance is 3*len because all bytes can potentially be replaced with
+ * U+FFFD -- which rather inconveniently encodes to 3 bytes in UTF-8.
+ * Rely on dynamic buffer data pointer stability: no other code has
+ * access to the data pointer.
+ *
+ * XXX: The buffer allocation strategy used here is rather inefficient.
+ * Maybe switch to a chunk-based strategy, or preprocess the string to
+ * figure out the space needed ahead of time?
+ */
+ DUK_ASSERT(3 * len >= len);
+ output = (duk_uint8_t *) duk_push_dynamic_buffer(thr, 3 * len);
+
+ if (len > 0) {
+ DUK_ASSERT(duk_is_string(thr, 0)); /* True if len > 0. */
+
+ /* XXX: duk_decode_string() is used to process the input
+ * string. For standard Ecmascript strings, represented
+ * internally as CESU-8, this is fine. However, behavior
+ * beyond CESU-8 is not very strict: codepoints using an
+ * extended form of UTF-8 are also accepted, and invalid
+ * codepoint sequences (which are allowed in Duktape strings)
+ * are not handled as well as they could (e.g. invalid
+ * continuation bytes may mask following codepoints).
+ * This is how Ecmascript code would also see such strings.
+ * Maybe replace duk_decode_string() with an explicit strict
+ * CESU-8 decoder here?
+ */
+ enc_ctx.lead = 0x0000L;
+ enc_ctx.out = output;
+ duk_decode_string(thr, 0, duk__utf8_encode_char, (void *) &enc_ctx);
+ if (enc_ctx.lead != 0x0000L) {
+ /* unpaired high surrogate at end of string */
+ enc_ctx.out = duk__utf8_emit_repl(enc_ctx.out);
+ DUK_ASSERT(enc_ctx.out <= output + (3 * len));
+ }
+
+ /* The output buffer is usually very much oversized, so shrink it to
+ * actually needed size. Pointer stability assumed up to this point.
+ */
+ DUK_ASSERT_TOP(thr, 2);
+ DUK_ASSERT(output == (duk_uint8_t *) duk_get_buffer_data(thr, -1, NULL));
+
+ final_len = (duk_size_t) (enc_ctx.out - output);
+ duk_resize_buffer(thr, -1, final_len);
+ /* 'output' and 'enc_ctx.out' are potentially invalidated by the resize. */
+ } else {
+ final_len = 0;
+ }
+
+ /* Standard WHATWG output is a Uint8Array. Here the Uint8Array will
+ * be backed by a dynamic buffer which differs from e.g. Uint8Arrays
+ * created as 'new Uint8Array(N)'. Ecmascript code won't see the
+ * difference but C code will. When bufferobjects are not supported,
+ * returns a plain dynamic buffer.
+ */
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+ duk_push_buffer_object(thr, -1, 0, final_len, DUK_BUFOBJ_UINT8ARRAY);
+#endif
+ return 1;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_textdecoder_constructor(duk_hthread *thr) {
+ duk__decode_context *dec_ctx;
+ duk_bool_t fatal = 0;
+ duk_bool_t ignore_bom = 0;
+
+ DUK_ASSERT_TOP(thr, 2);
+ duk_require_constructor_call(thr);
+ if (!duk_is_undefined(thr, 0)) {
+ /* XXX: For now ignore 'label' (encoding identifier). */
+ duk_to_string(thr, 0);
+ }
+ if (!duk_is_null_or_undefined(thr, 1)) {
+ if (duk_get_prop_string(thr, 1, "fatal")) {
+ fatal = duk_to_boolean(thr, -1);
+ }
+ if (duk_get_prop_string(thr, 1, "ignoreBOM")) {
+ ignore_bom = duk_to_boolean(thr, -1);
+ }
+ }
+
+ duk_push_this(thr);
+
+ /* The decode context is not assumed to be zeroed; all fields are
+ * initialized explicitly.
+ */
+ dec_ctx = (duk__decode_context *) duk_push_fixed_buffer(thr, sizeof(duk__decode_context));
+ dec_ctx->fatal = (duk_uint8_t) fatal;
+ dec_ctx->ignore_bom = (duk_uint8_t) ignore_bom;
+ duk__utf8_decode_init(dec_ctx); /* Initializes remaining fields. */
+
+ duk_put_prop_string(thr, -2, DUK_INTERNAL_SYMBOL("Context"));
+ return 0;
+}
+
+/* Get TextDecoder context from 'this'; leaves garbage on stack. */
+DUK_LOCAL duk__decode_context *duk__get_textdecoder_context(duk_hthread *thr) {
+ duk__decode_context *dec_ctx;
+ duk_push_this(thr);
+ duk_get_prop_string(thr, -1, DUK_INTERNAL_SYMBOL("Context"));
+ dec_ctx = (duk__decode_context *) duk_require_buffer(thr, -1, NULL);
+ DUK_ASSERT(dec_ctx != NULL);
+ return dec_ctx;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_hthread *thr) {
+ duk__decode_context *dec_ctx;
+ duk_int_t magic;
+
+ dec_ctx = duk__get_textdecoder_context(thr);
+ magic = duk_get_current_magic(thr);
+ switch (magic) {
+ case 0:
+ /* Encoding is now fixed, so _Context lookup is only needed to
+ * validate the 'this' binding (TypeError if not TextDecoder-like).
+ */
+ duk_push_string(thr, "utf-8");
+ break;
+ case 1:
+ duk_push_boolean(thr, dec_ctx->fatal);
+ break;
+ default:
+ duk_push_boolean(thr, dec_ctx->ignore_bom);
+ break;
+ }
+
+ return 1;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_hthread *thr) {
+ duk__decode_context *dec_ctx;
+
+ dec_ctx = duk__get_textdecoder_context(thr);
+ return duk__decode_helper(thr, dec_ctx);
+}
+#endif /* DUK_USE_ENCODING_BUILTINS */
+
+/*
+ * Internal helper for Node.js Buffer
+ */
+
+/* Internal helper used for Node.js Buffer .toString(). Value stack convention
+ * is currently odd: it mimics TextDecoder .decode() so that argument must be at
+ * index 0, and decode options (not present for Buffer) at index 1. Return value
+ * is a Duktape/C function return value.
+ */
+DUK_INTERNAL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_hthread *thr) {
+ duk__decode_context dec_ctx;
+
+ dec_ctx.fatal = 0; /* use replacement chars */
+ dec_ctx.ignore_bom = 1; /* ignore BOMs (matches Node.js Buffer .toString()) */
+ duk__utf8_decode_init(&dec_ctx);
+
+ return duk__decode_helper(thr, &dec_ctx);
+}
+
+/* automatic undefs */
+#undef DUK__CP_CONTINUE
+#undef DUK__CP_ERROR
+#undef DUK__CP_RETRY
#line 1 "duk_bi_error.c"
/*
* Error built-ins
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_hthread *thr) {
/* Behavior for constructor and non-constructor call is
* the same except for augmenting the created error. When
* called as a constructor, the caller (duk_new()) will handle
@@ -27101,53 +31803,51 @@ DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx) {
* it here.
*/
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_small_int_t bidx_prototype = duk_get_current_magic(ctx);
+ duk_small_int_t bidx_prototype = duk_get_current_magic(thr);
/* same for both error and each subclass like TypeError */
duk_uint_t flags_and_class = DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR);
- DUK_UNREF(thr);
-
- duk_push_object_helper(ctx, flags_and_class, bidx_prototype);
+ (void) duk_push_object_helper(thr, flags_and_class, bidx_prototype);
/* If message is undefined, the own property 'message' is not set at
* all to save property space. An empty message is inherited anyway.
*/
- if (!duk_is_undefined(ctx, 0)) {
- duk_to_string(ctx, 0);
- duk_dup(ctx, 0); /* [ message error message ] */
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
+ if (!duk_is_undefined(thr, 0)) {
+ duk_to_string(thr, 0);
+ duk_dup_0(thr); /* [ message error message ] */
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
}
/* Augment the error if called as a normal function. __FILE__ and __LINE__
* are not desirable in this case.
*/
-#ifdef DUK_USE_AUGMENT_ERROR_CREATE
- if (!duk_is_constructor_call(ctx)) {
- duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/);
+#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
+ if (!duk_is_constructor_call(thr)) {
+ duk_err_augment_error_create(thr, thr, NULL, 0, DUK_AUGMENT_FLAG_NOBLAME_FILELINE);
}
#endif
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_hthread *thr) {
/* XXX: optimize with more direct internal access */
- duk_push_this(ctx);
- (void) duk_require_hobject_or_lfunc_coerce(ctx, -1);
+ duk_push_this(thr);
+ (void) duk_require_hobject_promote_mask(thr, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
/* [ ... this ] */
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME);
- if (duk_is_undefined(ctx, -1)) {
- duk_pop(ctx);
- duk_push_string(ctx, "Error");
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME);
+ if (duk_is_undefined(thr, -1)) {
+ duk_pop(thr);
+ duk_push_string(thr, "Error");
} else {
- duk_to_string(ctx, -1);
+ duk_to_string(thr, -1);
}
/* [ ... this name ] */
@@ -27156,28 +31856,28 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) {
* accident or are they actually needed? The first ToString()
* could conceivably return 'undefined'.
*/
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE);
- if (duk_is_undefined(ctx, -1)) {
- duk_pop(ctx);
- duk_push_string(ctx, "");
+ duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE);
+ if (duk_is_undefined(thr, -1)) {
+ duk_pop(thr);
+ duk_push_hstring_empty(thr);
} else {
- duk_to_string(ctx, -1);
+ duk_to_string(thr, -1);
}
/* [ ... this name message ] */
- if (duk_get_length(ctx, -2) == 0) {
+ if (duk_get_length(thr, -2) == 0) {
/* name is empty -> return message */
return 1;
}
- if (duk_get_length(ctx, -1) == 0) {
+ if (duk_get_length(thr, -1) == 0) {
/* message is empty -> return name */
- duk_pop(ctx);
+ duk_pop(thr);
return 1;
}
- duk_push_string(ctx, ": ");
- duk_insert(ctx, -2); /* ... name ': ' message */
- duk_concat(ctx, 3);
+ duk_push_string(thr, ": ");
+ duk_insert(thr, -2); /* ... name ': ' message */
+ duk_concat(thr, 3);
return 1;
}
@@ -27203,8 +31903,7 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) {
#define DUK__OUTPUT_TYPE_FILENAME 0
#define DUK__OUTPUT_TYPE_LINENUMBER 1
-DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t output_type) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_hthread *thr, duk_small_int_t output_type) {
duk_idx_t idx_td;
duk_small_int_t i; /* traceback depth fits into 16 bits */
duk_small_int_t t; /* stack type fits into 16 bits */
@@ -27216,39 +31915,38 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
const char *str_directeval = " directeval";
const char *str_empty = "";
- DUK_ASSERT_TOP(ctx, 0); /* fixed arg count */
- DUK_UNREF(thr);
+ DUK_ASSERT_TOP(thr, 0); /* fixed arg count */
- duk_push_this(ctx);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TRACEDATA);
- idx_td = duk_get_top_index(ctx);
+ duk_push_this(thr);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_TRACEDATA);
+ idx_td = duk_get_top_index(thr);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_NEWLINE_4SPACE);
- duk_push_this(ctx);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_NEWLINE_4SPACE);
+ duk_push_this(thr);
/* [ ... this tracedata sep this ] */
/* XXX: skip null filename? */
- if (duk_check_type(ctx, idx_td, DUK_TYPE_OBJECT)) {
+ if (duk_check_type(thr, idx_td, DUK_TYPE_OBJECT)) {
/* Current tracedata contains 2 entries per callstack entry. */
for (i = 0; ; i += 2) {
duk_int_t pc;
- duk_int_t line;
- duk_int_t flags;
+ duk_uint_t line;
+ duk_uint_t flags;
duk_double_t d;
const char *funcname;
const char *filename;
duk_hobject *h_func;
duk_hstring *h_name;
- duk_require_stack(ctx, 5);
- duk_get_prop_index(ctx, idx_td, i);
- duk_get_prop_index(ctx, idx_td, i + 1);
- d = duk_to_number(ctx, -1);
+ duk_require_stack(thr, 5);
+ duk_get_prop_index(thr, idx_td, (duk_uarridx_t) i);
+ duk_get_prop_index(thr, idx_td, (duk_uarridx_t) (i + 1));
+ d = duk_to_number_m1(thr);
pc = (duk_int_t) DUK_FMOD(d, DUK_DOUBLE_2TO32);
- flags = (duk_int_t) DUK_FLOOR(d / DUK_DOUBLE_2TO32);
- t = (duk_small_int_t) duk_get_type(ctx, -2);
+ flags = (duk_uint_t) DUK_FLOOR(d / DUK_DOUBLE_2TO32);
+ t = (duk_small_int_t) duk_get_type(thr, -2);
if (t == DUK_TYPE_OBJECT || t == DUK_TYPE_LIGHTFUNC) {
/*
@@ -27259,13 +31957,15 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
/* [ ... v1(func) v2(pc+flags) ] */
- h_func = duk_get_hobject(ctx, -2); /* NULL for lightfunc */
-
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
- duk_get_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME);
+ /* These may be systematically omitted by Duktape
+ * with certain config options, but allow user to
+ * set them on a case-by-case basis.
+ */
+ duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_NAME);
+ duk_get_prop_stridx_short(thr, -3, DUK_STRIDX_FILE_NAME);
#if defined(DUK_USE_PC2LINE)
- line = duk_hobject_pc2line_query(ctx, -4, (duk_uint_fast32_t) pc);
+ line = (duk_uint_t) duk_hobject_pc2line_query(thr, -4, (duk_uint_fast32_t) pc);
#else
line = 0;
#endif
@@ -27275,35 +31975,37 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
/* When looking for .fileName/.lineNumber, blame first
* function which has a .fileName.
*/
- if (duk_is_string(ctx, -1)) {
+ if (duk_is_string_notsymbol(thr, -1)) {
if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
return 1;
} else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
- duk_push_int(ctx, line);
+ duk_push_uint(thr, line);
return 1;
}
}
/* XXX: Change 'anon' handling here too, to use empty string for anonymous functions? */
/* XXX: Could be improved by coercing to a readable duk_tval (especially string escaping) */
- h_name = duk_get_hstring(ctx, -2); /* may be NULL */
+ h_name = duk_get_hstring_notsymbol(thr, -2); /* may be NULL */
funcname = (h_name == NULL || h_name == DUK_HTHREAD_STRING_EMPTY_STRING(thr)) ?
"[anon]" : (const char *) DUK_HSTRING_GET_DATA(h_name);
- filename = duk_get_string(ctx, -1);
+ filename = duk_get_string_notsymbol(thr, -1);
filename = filename ? filename : "";
DUK_ASSERT(funcname != NULL);
DUK_ASSERT(filename != NULL);
+ h_func = duk_get_hobject(thr, -4); /* NULL for lightfunc */
+
if (h_func == NULL) {
- duk_push_sprintf(ctx, "at %s light%s%s%s%s%s",
+ duk_push_sprintf(thr, "at %s light%s%s%s%s%s",
(const char *) funcname,
(const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
- } else if (DUK_HOBJECT_HAS_NATIVEFUNCTION(h_func)) {
- duk_push_sprintf(ctx, "at %s (%s) native%s%s%s%s%s",
+ } else if (DUK_HOBJECT_HAS_NATFUNC(h_func)) {
+ duk_push_sprintf(thr, "at %s (%s) native%s%s%s%s%s",
(const char *) funcname,
(const char *) filename,
(const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
@@ -27312,19 +32014,21 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
(const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
} else {
- duk_push_sprintf(ctx, "at %s (%s:%ld)%s%s%s%s%s",
+ duk_push_sprintf(thr, "at %s (%s:%lu)%s%s%s%s%s",
(const char *) funcname,
(const char *) filename,
- (long) line,
+ (unsigned long) line,
(const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
}
- duk_replace(ctx, -5); /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */
- duk_pop_n(ctx, 3); /* -> [ ... str ] */
+ duk_replace(thr, -5); /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */
+ duk_pop_3(thr); /* -> [ ... str ] */
} else if (t == DUK_TYPE_STRING) {
+ const char *str_file;
+
/*
* __FILE__ / __LINE__ entry, here 'pc' is line number directly.
* Sometimes __FILE__ / __LINE__ is reported as the source for
@@ -27338,21 +32042,27 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
*/
if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) {
if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
- duk_pop(ctx);
+ duk_pop(thr);
return 1;
} else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
- duk_push_int(ctx, pc);
+ duk_push_int(thr, pc);
return 1;
}
}
- duk_push_sprintf(ctx, "at [anon] (%s:%ld) internal",
- (const char *) duk_get_string(ctx, -2), (long) pc);
- duk_replace(ctx, -3); /* [ ... v1 v2 str ] -> [ ... str v2 ] */
- duk_pop(ctx); /* -> [ ... str ] */
+ /* Tracedata is trusted but avoid any risk of using a NULL
+ * for %s format because it has undefined behavior. Symbols
+ * don't need to be explicitly rejected as they pose no memory
+ * safety issues.
+ */
+ str_file = (const char *) duk_get_string(thr, -2);
+ duk_push_sprintf(thr, "at [anon] (%s:%ld) internal",
+ (const char *) (str_file ? str_file : "null"), (long) pc);
+ duk_replace(thr, -3); /* [ ... v1 v2 str ] -> [ ... str v2 ] */
+ duk_pop(thr); /* -> [ ... str ] */
} else {
/* unknown, ignore */
- duk_pop_2(ctx);
+ duk_pop_2(thr);
break;
}
}
@@ -27362,7 +32072,7 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
* marker so this is the best we can do.
*/
- duk_push_hstring_stridx(ctx, DUK_STRIDX_BRACKETED_ELLIPSIS);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_BRACKETED_ELLIPSIS);
}
}
@@ -27375,7 +32085,7 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
* duk_join() automatically. We don't want to do that
* coercion when providing .fileName or .lineNumber (GH-254).
*/
- duk_join(ctx, duk_get_top(ctx) - (idx_td + 2) /*count, not including sep*/);
+ duk_join(thr, duk_get_top(thr) - (idx_td + 2) /*count, not including sep*/);
return 1;
}
}
@@ -27384,22 +32094,18 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
* save space. For setters the stridx could be encoded into 'magic'.
*/
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx) {
- return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_TRACEBACK);
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_hthread *thr) {
+ return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_TRACEBACK);
}
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx) {
- return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_FILENAME);
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_hthread *thr) {
+ return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_FILENAME);
}
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx) {
- return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_LINENUMBER);
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_hthread *thr) {
+ return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_LINENUMBER);
}
-#undef DUK__OUTPUT_TYPE_TRACEBACK
-#undef DUK__OUTPUT_TYPE_FILENAME
-#undef DUK__OUTPUT_TYPE_LINENUMBER
-
#else /* DUK_USE_TRACEBACKS */
/*
@@ -27414,26 +32120,26 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx
* of the error so this makes sense.
*/
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_hthread *thr) {
/* XXX: remove this native function and map 'stack' accessor
* to the toString() implementation directly.
*/
- return duk_bi_error_prototype_to_string(ctx);
+ return duk_bi_error_prototype_to_string(thr);
}
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx) {
- DUK_UNREF(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_hthread *thr) {
+ DUK_UNREF(thr);
return 0;
}
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx) {
- DUK_UNREF(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_hthread *thr) {
+ DUK_UNREF(thr);
return 0;
}
#endif /* DUK_USE_TRACEBACKS */
-DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_context *ctx, duk_small_uint_t stridx_key) {
+DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_hthread *thr, duk_small_uint_t stridx_key) {
/* Attempt to write 'stack', 'fileName', 'lineNumber' works as if
* user code called Object.defineProperty() to create an overriding
* own property. This allows user code to overwrite .fileName etc
@@ -27441,102 +32147,119 @@ DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_context *ctx, duk_small_uint_t
* See https://github.com/svaarala/duktape/issues/387.
*/
- DUK_ASSERT_TOP(ctx, 1); /* fixed arg count: value */
+ DUK_ASSERT_TOP(thr, 1); /* fixed arg count: value */
- duk_push_this(ctx);
- duk_push_hstring_stridx(ctx, (duk_small_int_t) stridx_key);
- duk_dup(ctx, 0);
+ duk_push_this(thr);
+ duk_push_hstring_stridx(thr, stridx_key);
+ duk_dup_0(thr);
/* [ ... obj key value ] */
DUK_DD(DUK_DDPRINT("error setter: %!T %!T %!T",
- duk_get_tval(ctx, -3), duk_get_tval(ctx, -2), duk_get_tval(ctx, -1)));
+ duk_get_tval(thr, -3), duk_get_tval(thr, -2), duk_get_tval(thr, -1)));
- duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE |
+ duk_def_prop(thr, -3, DUK_DEFPROP_HAVE_VALUE |
DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE |
DUK_DEFPROP_HAVE_ENUMERABLE | /*not enumerable*/
DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE);
return 0;
}
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx) {
- return duk__error_setter_helper(ctx, DUK_STRIDX_STACK);
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_setter(duk_hthread *thr) {
+ return duk__error_setter_helper(thr, DUK_STRIDX_STACK);
}
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx) {
- return duk__error_setter_helper(ctx, DUK_STRIDX_FILE_NAME);
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_setter(duk_hthread *thr) {
+ return duk__error_setter_helper(thr, DUK_STRIDX_FILE_NAME);
}
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx) {
- return duk__error_setter_helper(ctx, DUK_STRIDX_LINE_NUMBER);
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_hthread *thr) {
+ return duk__error_setter_helper(thr, DUK_STRIDX_LINE_NUMBER);
}
+
+/* automatic undefs */
+#undef DUK__OUTPUT_TYPE_FILENAME
+#undef DUK__OUTPUT_TYPE_LINENUMBER
+#undef DUK__OUTPUT_TYPE_TRACEBACK
#line 1 "duk_bi_function.c"
/*
* Function built-ins
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
-DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+/* Needed even when Function built-in is disabled. */
+DUK_INTERNAL duk_ret_t duk_bi_function_prototype(duk_hthread *thr) {
+ /* ignore arguments, return undefined (E5 Section 15.3.4) */
+ DUK_UNREF(thr);
+ return 0;
+}
+
+#if defined(DUK_USE_FUNCTION_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_hthread *thr) {
duk_hstring *h_sourcecode;
duk_idx_t nargs;
duk_idx_t i;
duk_small_uint_t comp_flags;
- duk_hcompiledfunction *func;
+ duk_hcompfunc *func;
duk_hobject *outer_lex_env;
duk_hobject *outer_var_env;
/* normal and constructor calls have identical semantics */
- nargs = duk_get_top(ctx);
+ nargs = duk_get_top(thr);
for (i = 0; i < nargs; i++) {
- duk_to_string(ctx, i);
+ duk_to_string(thr, i); /* Rejects Symbols during coercion. */
}
if (nargs == 0) {
- duk_push_string(ctx, "");
- duk_push_string(ctx, "");
+ duk_push_hstring_empty(thr);
+ duk_push_hstring_empty(thr);
} else if (nargs == 1) {
/* XXX: cover this with the generic >1 case? */
- duk_push_string(ctx, "");
+ duk_push_hstring_empty(thr);
} else {
- duk_insert(ctx, 0); /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */
- duk_push_string(ctx, ",");
- duk_insert(ctx, 1);
- duk_join(ctx, nargs - 1);
+ duk_insert(thr, 0); /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */
+ duk_push_string(thr, ",");
+ duk_insert(thr, 1);
+ duk_join(thr, nargs - 1);
}
/* [ body formals ], formals is comma separated list that needs to be parsed */
- DUK_ASSERT_TOP(ctx, 2);
+ DUK_ASSERT_TOP(thr, 2);
/* XXX: this placeholder is not always correct, but use for now.
* It will fail in corner cases; see test-dev-func-cons-args.js.
*/
- duk_push_string(ctx, "function(");
- duk_dup(ctx, 1);
- duk_push_string(ctx, "){");
- duk_dup(ctx, 0);
- duk_push_string(ctx, "}");
- duk_concat(ctx, 5);
+ duk_push_string(thr, "function(");
+ duk_dup_1(thr);
+ duk_push_string(thr, "){");
+ duk_dup_0(thr);
+ duk_push_string(thr, "}");
+ duk_concat(thr, 5);
/* [ body formals source ] */
- DUK_ASSERT_TOP(ctx, 3);
+ DUK_ASSERT_TOP(thr, 3);
/* strictness is not inherited, intentional */
- comp_flags = DUK_JS_COMPILE_FLAG_FUNCEXPR;
+ comp_flags = DUK_COMPILE_FUNCEXPR;
- duk_push_hstring_stridx(ctx, DUK_STRIDX_COMPILE); /* XXX: copy from caller? */ /* XXX: ignored now */
- h_sourcecode = duk_require_hstring(ctx, -2);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_COMPILE); /* XXX: copy from caller? */ /* XXX: ignored now */
+ h_sourcecode = duk_require_hstring(thr, -2); /* no symbol check needed; -2 is concat'd code */
duk_js_compile(thr,
(const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode),
(duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode),
comp_flags);
- func = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) func));
+
+ /* Force .name to 'anonymous' (ES2015). */
+ duk_push_string(thr, "anonymous");
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
+
+ func = (duk_hcompfunc *) duk_known_hobject(thr, -1);
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) func));
+ DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) func));
/* [ body formals source template ] */
@@ -27553,36 +32276,34 @@ DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_context *ctx) {
return 1;
}
+#endif /* DUK_USE_FUNCTION_BUILTIN */
-DUK_INTERNAL duk_ret_t duk_bi_function_prototype(duk_context *ctx) {
- /* ignore arguments, return undefined (E5 Section 15.3.4) */
- DUK_UNREF(ctx);
- return 0;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx) {
+#if defined(DUK_USE_FUNCTION_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_hthread *thr) {
duk_tval *tv;
/*
* E5 Section 15.3.4.2 places few requirements on the output of
- * this function:
+ * this function: the result is implementation dependent, must
+ * follow FunctionDeclaration syntax (in particular, must have a
+ * name even for anonymous functions or functions with empty name).
+ * The output does NOT need to compile into anything useful.
*
- * - The result is an implementation dependent representation
- * of the function; in particular
+ * E6 Section 19.2.3.5 changes the requirements completely: the
+ * result must either eval() to a functionally equivalent object
+ * OR eval() to a SyntaxError.
*
- * - The result must follow the syntax of a FunctionDeclaration.
- * In particular, the function must have a name (even in the
- * case of an anonymous function or a function with an empty
- * name).
+ * We opt for the SyntaxError approach for now, with a syntax that
+ * mimics V8's native function syntax:
*
- * - Note in particular that the output does NOT need to compile
- * into anything useful.
+ * 'function cos() { [native code] }'
+ *
+ * but extended with [ecmascript code], [bound code], and
+ * [lightfunc code].
*/
-
- /* XXX: faster internal way to get this */
- duk_push_this(ctx);
- tv = duk_get_tval(ctx, -1);
+ duk_push_this(thr);
+ tv = DUK_GET_TVAL_NEGIDX(thr, -1);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_OBJECT(tv)) {
@@ -27590,33 +32311,31 @@ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx) {
const char *func_name;
/* Function name: missing/undefined is mapped to empty string,
- * otherwise coerce to string.
+ * otherwise coerce to string. No handling for invalid identifier
+ * characters or e.g. '{' in the function name. This doesn't
+ * really matter as long as a SyntaxError results. Technically
+ * if the name contained a suitable prefix followed by '//' it
+ * might cause the result to parse without error.
*/
- /* XXX: currently no handling for non-allowed identifier characters,
- * e.g. a '{' in the function name.
- */
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME);
- if (duk_is_undefined(ctx, -1)) {
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME);
+ if (duk_is_undefined(thr, -1)) {
func_name = "";
} else {
- func_name = duk_to_string(ctx, -1);
+ func_name = duk_to_string(thr, -1);
DUK_ASSERT(func_name != NULL);
}
- /* Indicate function type in the function body using a dummy
- * directive.
- */
- if (DUK_HOBJECT_HAS_COMPILEDFUNCTION(obj)) {
- duk_push_sprintf(ctx, "function %s() {\"ecmascript\"}", (const char *) func_name);
- } else if (DUK_HOBJECT_HAS_NATIVEFUNCTION(obj)) {
- duk_push_sprintf(ctx, "function %s() {\"native\"}", (const char *) func_name);
- } else if (DUK_HOBJECT_HAS_BOUND(obj)) {
- duk_push_sprintf(ctx, "function %s() {\"bound\"}", (const char *) func_name);
+ if (DUK_HOBJECT_IS_COMPFUNC(obj)) {
+ duk_push_sprintf(thr, "function %s() { [ecmascript code] }", (const char *) func_name);
+ } else if (DUK_HOBJECT_IS_NATFUNC(obj)) {
+ duk_push_sprintf(thr, "function %s() { [native code] }", (const char *) func_name);
+ } else if (DUK_HOBJECT_IS_BOUNDFUNC(obj)) {
+ duk_push_sprintf(thr, "function %s() { [bound code] }", (const char *) func_name);
} else {
goto type_error;
}
} else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
- duk_push_lightfunc_tostring(ctx, tv);
+ duk_push_lightfunc_tostring(thr, tv);
} else {
goto type_error;
}
@@ -27624,205 +32343,293 @@ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx) {
return 1;
type_error:
- return DUK_RET_TYPE_ERROR;
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
+#endif
-DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx) {
- duk_idx_t len;
- duk_idx_t i;
-
- DUK_ASSERT_TOP(ctx, 2); /* not a vararg function */
-
- duk_push_this(ctx);
- if (!duk_is_callable(ctx, -1)) {
- DUK_DDD(DUK_DDDPRINT("func is not callable"));
- goto type_error;
- }
- duk_insert(ctx, 0);
- DUK_ASSERT_TOP(ctx, 3);
-
- DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argArray=%!iT",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1),
- (duk_tval *) duk_get_tval(ctx, 2)));
-
- /* [ func thisArg argArray ] */
-
- if (duk_is_null_or_undefined(ctx, 2)) {
- DUK_DDD(DUK_DDDPRINT("argArray is null/undefined, no args"));
- len = 0;
- } else if (!duk_is_object(ctx, 2)) {
- goto type_error;
- } else {
- DUK_DDD(DUK_DDDPRINT("argArray is an object"));
-
- /* XXX: make this an internal helper */
- duk_get_prop_stridx(ctx, 2, DUK_STRIDX_LENGTH);
- len = (duk_idx_t) duk_to_uint32(ctx, -1); /* ToUint32() coercion required */
- duk_pop(ctx);
-
- duk_require_stack(ctx, len);
-
- DUK_DDD(DUK_DDDPRINT("argArray length is %ld", (long) len));
- for (i = 0; i < len; i++) {
- duk_get_prop_index(ctx, 2, i);
- }
- }
- duk_remove(ctx, 2);
- DUK_ASSERT_TOP(ctx, 2 + len);
-
- /* [ func thisArg arg1 ... argN ] */
-
- DUK_DDD(DUK_DDDPRINT("apply, func=%!iT, thisArg=%!iT, len=%ld",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1),
- (long) len));
- duk_call_method(ctx, len);
- return 1;
-
- type_error:
- return DUK_RET_TYPE_ERROR;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx) {
- duk_idx_t nargs;
-
- /* Step 1 is not necessary because duk_call_method() will take
- * care of it.
- */
-
- /* vararg function, thisArg needs special handling */
- nargs = duk_get_top(ctx); /* = 1 + arg count */
- if (nargs == 0) {
- duk_push_undefined(ctx);
- nargs++;
- }
- DUK_ASSERT(nargs >= 1);
-
- /* [ thisArg arg1 ... argN ] */
-
- duk_push_this(ctx); /* 'func' in the algorithm */
- duk_insert(ctx, 0);
-
- /* [ func thisArg arg1 ... argN ] */
-
- DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argcount=%ld, top=%ld",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1),
- (long) (nargs - 1),
- (long) duk_get_top(ctx)));
- duk_call_method(ctx, nargs - 1);
- return 1;
-}
-
-/* XXX: the implementation now assumes "chained" bound functions,
- * whereas "collapsed" bound functions (where there is ever only
- * one bound function which directly points to a non-bound, final
- * function) would require a "collapsing" implementation which
- * merges argument lists etc here.
+/* Always present because the native function pointer is needed in call
+ * handling.
*/
-DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx) {
- duk_hobject *h_bound;
- duk_hobject *h_target;
- duk_idx_t nargs;
- duk_idx_t i;
-
- /* vararg function, careful arg handling (e.g. thisArg may not be present) */
- nargs = duk_get_top(ctx); /* = 1 + arg count */
- if (nargs == 0) {
- duk_push_undefined(ctx);
- nargs++;
- }
- DUK_ASSERT(nargs >= 1);
-
- duk_push_this(ctx);
- if (!duk_is_callable(ctx, -1)) {
- DUK_DDD(DUK_DDDPRINT("func is not callable"));
- goto type_error;
- }
-
- /* [ thisArg arg1 ... argN func ] (thisArg+args == nargs total) */
- DUK_ASSERT_TOP(ctx, nargs + 1);
-
- /* create bound function object */
- duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BOUND |
- DUK_HOBJECT_FLAG_CONSTRUCTABLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION),
- DUK_BIDX_FUNCTION_PROTOTYPE);
- h_bound = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h_bound != NULL);
-
- /* [ thisArg arg1 ... argN func boundFunc ] */
- duk_dup(ctx, -2); /* func */
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
-
- duk_dup(ctx, 0); /* thisArg */
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE);
-
- duk_push_array(ctx);
-
- /* [ thisArg arg1 ... argN func boundFunc argArray ] */
-
- for (i = 0; i < nargs - 1; i++) {
- duk_dup(ctx, 1 + i);
- duk_put_prop_index(ctx, -2, i);
- }
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_ARGS, DUK_PROPDESC_FLAGS_NONE);
-
- /* [ thisArg arg1 ... argN func boundFunc ] */
-
- /* bound function 'length' property is interesting */
- h_target = duk_get_hobject(ctx, -2);
- if (h_target == NULL || /* lightfunc */
- DUK_HOBJECT_GET_CLASS_NUMBER(h_target) == DUK_HOBJECT_CLASS_FUNCTION) {
- /* For lightfuncs, simply read the virtual property. */
- duk_int_t tmp;
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH);
- tmp = duk_to_int(ctx, -1) - (nargs - 1); /* step 15.a */
- duk_pop(ctx);
- duk_push_int(ctx, (tmp < 0 ? 0 : tmp));
- } else {
- duk_push_int(ctx, 0);
- }
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE); /* attrs in E5 Section 15.3.5.1 */
-
- /* caller and arguments must use the same thrower, [[ThrowTypeError]] */
- duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
- duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_LC_ARGUMENTS, DUK_PROPDESC_FLAGS_NONE);
-
- /* these non-standard properties are copied for convenience */
- /* XXX: 'copy properties' API call? */
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_WC);
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC);
-
- /* The 'strict' flag is copied to get the special [[Get]] of E5.1
- * Section 15.3.5.4 to apply when a 'caller' value is a strict bound
- * function. Not sure if this is correct, because the specification
- * is a bit ambiguous on this point but it would make sense.
+DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_hthread *thr) {
+ /* .call() is dealt with in call handling by simulating its
+ * effects so this function is actually never called.
*/
- if (h_target == NULL) {
- /* Lightfuncs are always strict. */
- DUK_HOBJECT_SET_STRICT(h_bound);
- } else if (DUK_HOBJECT_HAS_STRICT(h_target)) {
- DUK_HOBJECT_SET_STRICT(h_bound);
+ DUK_UNREF(thr);
+ return DUK_RET_TYPE_ERROR;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_hthread *thr) {
+ /* Like .call(), never actually called. */
+ DUK_UNREF(thr);
+ return DUK_RET_TYPE_ERROR;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_reflect_apply(duk_hthread *thr) {
+ /* Like .call(), never actually called. */
+ DUK_UNREF(thr);
+ return DUK_RET_TYPE_ERROR;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_reflect_construct(duk_hthread *thr) {
+ /* Like .call(), never actually called. */
+ DUK_UNREF(thr);
+ return DUK_RET_TYPE_ERROR;
+}
+
+#if defined(DUK_USE_FUNCTION_BUILTIN)
+/* Create a bound function which points to a target function which may
+ * be bound or non-bound. If the target is bound, the argument lists
+ * and 'this' binding of the functions are merged and the resulting
+ * function points directly to the non-bound target.
+ */
+DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_hthread *thr) {
+ duk_hboundfunc *h_bound;
+ duk_idx_t nargs; /* bound args, not counting 'this' binding */
+ duk_idx_t bound_nargs;
+ duk_int_t bound_len;
+ duk_tval *tv_prevbound;
+ duk_idx_t n_prevbound;
+ duk_tval *tv_res;
+ duk_tval *tv_tmp;
+
+ /* XXX: C API call, e.g. duk_push_bound_function(thr, target_idx, nargs); */
+
+ /* Vararg function, careful arg handling, e.g. thisArg may not
+ * be present.
+ */
+ nargs = duk_get_top(thr) - 1; /* actual args, not counting 'this' binding */
+ if (nargs < 0) {
+ nargs++;
+ duk_push_undefined(thr);
}
- DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_ASSERT(nargs >= 0);
+
+ /* Limit 'nargs' for bound functions to guarantee arithmetic
+ * below will never wrap.
+ */
+ if (nargs > (duk_idx_t) DUK_HBOUNDFUNC_MAX_ARGS) {
+ DUK_DCERROR_RANGE_INVALID_COUNT(thr);
+ }
+
+ duk_push_this(thr);
+ duk_require_callable(thr, -1);
+
+ /* [ thisArg arg1 ... argN func ] (thisArg+args == nargs+1 total) */
+ DUK_ASSERT_TOP(thr, nargs + 2);
+
+ /* Create bound function object. */
+ h_bound = duk_push_hboundfunc(thr);
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&h_bound->target));
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&h_bound->this_binding));
+ DUK_ASSERT(h_bound->args == NULL);
+ DUK_ASSERT(h_bound->nargs == 0);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_bound) == NULL);
+
+ /* [ thisArg arg1 ... argN func boundFunc ] */
+
+ /* If the target is a bound function, argument lists must be
+ * merged. The 'this' binding closest to the target function
+ * wins because in call handling the 'this' gets replaced over
+ * and over again until we call the non-bound function.
+ */
+ tv_prevbound = NULL;
+ n_prevbound = 0;
+ tv_tmp = DUK_GET_TVAL_POSIDX(thr, 0);
+ DUK_TVAL_SET_TVAL(&h_bound->this_binding, tv_tmp);
+ tv_tmp = DUK_GET_TVAL_NEGIDX(thr, -2);
+ DUK_TVAL_SET_TVAL(&h_bound->target, tv_tmp);
+
+ if (DUK_TVAL_IS_OBJECT(tv_tmp)) {
+ duk_hobject *h_target;
+ duk_hobject *bound_proto;
+
+ h_target = DUK_TVAL_GET_OBJECT(tv_tmp);
+ DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(h_target));
+
+ /* Internal prototype must be copied from the target.
+ * For lightfuncs Function.prototype is used and is already
+ * in place.
+ */
+ bound_proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_target);
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) h_bound, bound_proto);
+
+ /* The 'strict' flag is copied to get the special [[Get]] of E5.1
+ * Section 15.3.5.4 to apply when a 'caller' value is a strict bound
+ * function. Not sure if this is correct, because the specification
+ * is a bit ambiguous on this point but it would make sense.
+ */
+ /* Strictness is inherited from target. */
+ if (DUK_HOBJECT_HAS_STRICT(h_target)) {
+ DUK_HOBJECT_SET_STRICT((duk_hobject *) h_bound);
+ }
+
+ if (DUK_HOBJECT_HAS_BOUNDFUNC(h_target)) {
+ duk_hboundfunc *h_boundtarget;
+
+ h_boundtarget = (duk_hboundfunc *) h_target;
+
+ /* The final function should always be non-bound, unless
+ * there's a bug in the internals. Assert for it.
+ */
+ DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(&h_boundtarget->target) ||
+ (DUK_TVAL_IS_OBJECT(&h_boundtarget->target) &&
+ DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(&h_boundtarget->target)) &&
+ !DUK_HOBJECT_IS_BOUNDFUNC(DUK_TVAL_GET_OBJECT(&h_boundtarget->target))));
+
+ DUK_TVAL_SET_TVAL(&h_bound->target, &h_boundtarget->target);
+ DUK_TVAL_SET_TVAL(&h_bound->this_binding, &h_boundtarget->this_binding);
+
+ tv_prevbound = h_boundtarget->args;
+ n_prevbound = h_boundtarget->nargs;
+ }
+ } else {
+ /* Lightfuncs are always strict. */
+ duk_hobject *bound_proto;
+
+ DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_tmp));
+ DUK_HOBJECT_SET_STRICT((duk_hobject *) h_bound);
+ bound_proto = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) h_bound, bound_proto);
+ }
+
+ DUK_TVAL_INCREF(thr, &h_bound->target); /* old values undefined, no decref needed */
+ DUK_TVAL_INCREF(thr, &h_bound->this_binding);
+
+ bound_nargs = n_prevbound + nargs;
+ if (bound_nargs > (duk_idx_t) DUK_HBOUNDFUNC_MAX_ARGS) {
+ DUK_DCERROR_RANGE_INVALID_COUNT(thr);
+ }
+ tv_res = (duk_tval *) DUK_ALLOC_CHECKED(thr, ((duk_size_t) bound_nargs) * sizeof(duk_tval));
+ DUK_ASSERT(tv_res != NULL);
+ DUK_ASSERT(h_bound->args == NULL);
+ DUK_ASSERT(h_bound->nargs == 0);
+ h_bound->args = tv_res;
+ h_bound->nargs = bound_nargs;
+
+ DUK_ASSERT(n_prevbound >= 0);
+ duk_copy_tvals_incref(thr, tv_res, tv_prevbound, (duk_size_t) n_prevbound);
+ DUK_ASSERT(nargs >= 0);
+ duk_copy_tvals_incref(thr, tv_res + n_prevbound, DUK_GET_TVAL_POSIDX(thr, 1), (duk_size_t) nargs);
+
+ /* [ thisArg arg1 ... argN func boundFunc ] */
+
+ /* Bound function 'length' property is interesting.
+ * For lightfuncs, simply read the virtual property.
+ */
+ duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH);
+ bound_len = duk_get_int(thr, -1); /* ES2015: no coercion */
+ if (bound_len < nargs) {
+ bound_len = 0;
+ } else {
+ bound_len -= nargs;
+ }
+ if (sizeof(duk_int_t) > 4 && bound_len > (duk_int_t) DUK_UINT32_MAX) {
+ bound_len = (duk_int_t) DUK_UINT32_MAX;
+ }
+ duk_pop(thr);
+ DUK_ASSERT(bound_len >= 0);
+ tv_tmp = thr->valstack_top++;
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv_tmp));
+ DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv_tmp));
+ DUK_TVAL_SET_U32(tv_tmp, (duk_uint32_t) bound_len); /* in-place update, fastint */
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C); /* attrs in E6 Section 9.2.4 */
+
+ /* XXX: could these be virtual? */
+ /* Caller and arguments must use the same thrower, [[ThrowTypeError]]. */
+ duk_xdef_prop_stridx_thrower(thr, -1, DUK_STRIDX_CALLER);
+ duk_xdef_prop_stridx_thrower(thr, -1, DUK_STRIDX_LC_ARGUMENTS);
+
+ /* Function name and fileName (non-standard). */
+ duk_push_string(thr, "bound "); /* ES2015 19.2.3.2. */
+ duk_get_prop_stridx(thr, -3, DUK_STRIDX_NAME);
+ if (!duk_is_string_notsymbol(thr, -1)) {
+ /* ES2015 has requirement to check that .name of target is a string
+ * (also must check for Symbol); if not, targetName should be the
+ * empty string. ES2015 19.2.3.2.
+ */
+ duk_pop(thr);
+ duk_push_hstring_empty(thr);
+ }
+ duk_concat(thr, 2);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
+#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
+ duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C);
+#endif
+
+ DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", (duk_tval *) duk_get_tval(thr, -1)));
return 1;
+}
+#endif /* DUK_USE_FUNCTION_BUILTIN */
- type_error:
- return DUK_RET_TYPE_ERROR;
+/* %NativeFunctionPrototype% .length getter. */
+DUK_INTERNAL duk_ret_t duk_bi_native_function_length(duk_hthread *thr) {
+ duk_tval *tv;
+ duk_hnatfunc *h;
+ duk_int16_t func_nargs;
+
+ tv = duk_get_borrowed_this_tval(thr);
+ DUK_ASSERT(tv != NULL);
+
+ if (DUK_TVAL_IS_OBJECT(tv)) {
+ h = (duk_hnatfunc *) DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ if (!DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h)) {
+ goto fail_type;
+ }
+ func_nargs = h->nargs;
+ duk_push_int(thr, func_nargs == DUK_HNATFUNC_NARGS_VARARGS ? 0 : func_nargs);
+ } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
+ duk_small_uint_t lf_flags;
+ duk_small_uint_t lf_len;
+
+ lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
+ lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
+ duk_push_uint(thr, lf_len);
+ } else {
+ goto fail_type;
+ }
+ return 1;
+
+ fail_type:
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
+}
+
+/* %NativeFunctionPrototype% .name getter. */
+DUK_INTERNAL duk_ret_t duk_bi_native_function_name(duk_hthread *thr) {
+ duk_tval *tv;
+ duk_hnatfunc *h;
+
+ tv = duk_get_borrowed_this_tval(thr);
+ DUK_ASSERT(tv != NULL);
+
+ if (DUK_TVAL_IS_OBJECT(tv)) {
+ h = (duk_hnatfunc *) DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ if (!DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h)) {
+ goto fail_type;
+ }
+#if 0
+ duk_push_hnatfunc_name(thr, h);
+#endif
+ duk_push_hstring_empty(thr);
+ } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
+ duk_push_lightfunc_name(thr, tv);
+ } else {
+ goto fail_type;
+ }
+ return 1;
+
+ fail_type:
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
#line 1 "duk_bi_global.c"
/*
* Global object built-ins
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
/*
* Encoding/decoding helpers
@@ -27890,7 +32697,7 @@ DUK_LOCAL const duk_uint8_t duk__decode_uri_component_reserved_table[16] = {
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */
};
-#ifdef DUK_USE_SECTION_B
+#if defined(DUK_USE_SECTION_B)
/* E5.1 Section B.2.2, step 7. */
DUK_LOCAL const duk_uint8_t duk__escape_unescaped_table[16] = {
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
@@ -27904,8 +32711,6 @@ DUK_LOCAL const duk_uint8_t duk__escape_unescaped_table[16] = {
};
#endif /* DUK_USE_SECTION_B */
-#undef DUK__MKBITS
-
typedef struct {
duk_hthread *thr;
duk_hstring *h_str;
@@ -27935,15 +32740,14 @@ DUK_LOCAL duk_small_int_t duk__decode_hex_escape(const duk_uint8_t *p, duk_small
return t;
}
-DUK_LOCAL int duk__transform_helper(duk_context *ctx, duk__transform_callback callback, const void *udata) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL int duk__transform_helper(duk_hthread *thr, duk__transform_callback callback, const void *udata) {
duk__transform_context tfm_ctx_alloc;
duk__transform_context *tfm_ctx = &tfm_ctx_alloc;
duk_codepoint_t cp;
tfm_ctx->thr = thr;
- tfm_ctx->h_str = duk_to_hstring(ctx, 0);
+ tfm_ctx->h_str = duk_to_hstring(thr, 0);
DUK_ASSERT(tfm_ctx->h_str != NULL);
DUK_BW_INIT_PUSHBUF(thr, &tfm_ctx->bw, DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str)); /* initial size guess */
@@ -27959,7 +32763,7 @@ DUK_LOCAL int duk__transform_helper(duk_context *ctx, duk__transform_callback ca
DUK_BW_COMPACT(thr, &tfm_ctx->bw);
- duk_to_string(ctx, -1);
+ (void) duk_buffer_to_string(thr, -1); /* Safe if transform is safe. */
return 1;
}
@@ -27992,7 +32796,7 @@ DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ct
goto uri_error;
}
cp1 = cp;
- cp = ((cp1 - 0xd800L) << 10) + (cp2 - 0xdc00L) + 0x10000L;
+ cp = (duk_codepoint_t) (((cp1 - 0xd800L) << 10) + (cp2 - 0xdc00L) + 0x10000L);
} else if (cp > 0x10ffffL) {
/* Although we can allow non-BMP characters (they'll decode
* back into surrogate pairs), we don't allow extended UTF-8
@@ -28011,7 +32815,7 @@ DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ct
len = duk_unicode_encode_xutf8((duk_ucodepoint_t) cp, xutf8_buf);
for (i = 0; i < len; i++) {
- t = (int) xutf8_buf[i];
+ t = (duk_small_int_t) xutf8_buf[i];
DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr,
&tfm_ctx->bw,
DUK_ASC_PERCENT,
@@ -28022,7 +32826,7 @@ DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ct
return;
uri_error:
- DUK_ERROR(tfm_ctx->thr, DUK_ERR_URI_ERROR, "invalid input");
+ DUK_ERROR_URI(tfm_ctx->thr, DUK_STR_INVALID_INPUT);
}
DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
@@ -28150,7 +32954,7 @@ DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ct
DUK_ASSERT(cp < 0x100000L);
DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp >> 10) + 0xd800L));
- DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp & 0x03ffUL) + 0xdc00L));
+ DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp & 0x03ffL) + 0xdc00L));
} else {
DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
}
@@ -28160,10 +32964,10 @@ DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ct
return;
uri_error:
- DUK_ERROR(tfm_ctx->thr, DUK_ERR_URI_ERROR, "invalid input");
+ DUK_ERROR_URI(tfm_ctx->thr, DUK_STR_INVALID_INPUT);
}
-#ifdef DUK_USE_SECTION_B
+#if defined(DUK_USE_SECTION_B)
DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
DUK_UNREF(udata);
@@ -28200,7 +33004,7 @@ DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, c
return;
esc_error:
- DUK_ERROR_TYPE(tfm_ctx->thr, "invalid input");
+ DUK_ERROR_TYPE(tfm_ctx->thr, DUK_STR_INVALID_INPUT);
}
DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
@@ -28238,22 +33042,22 @@ DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx,
* calling activation at all which needs careful handling.
*/
-DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_hthread *thr) {
duk_hstring *h;
duk_activation *act_caller;
duk_activation *act_eval;
- duk_activation *act;
- duk_hcompiledfunction *func;
+ duk_hcompfunc *func;
duk_hobject *outer_lex_env;
duk_hobject *outer_var_env;
duk_bool_t this_to_global = 1;
duk_small_uint_t comp_flags;
duk_int_t level = -2;
+ duk_small_uint_t call_flags;
- DUK_ASSERT(duk_get_top(ctx) == 1 || duk_get_top(ctx) == 2); /* 2 when called by debugger */
+ DUK_ASSERT(duk_get_top(thr) == 1 || duk_get_top(thr) == 2); /* 2 when called by debugger */
DUK_ASSERT(thr->callstack_top >= 1); /* at least this function exists */
- DUK_ASSERT(((thr->callstack + thr->callstack_top - 1)->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0 || /* indirect eval */
+ DUK_ASSERT(thr->callstack_curr != NULL);
+ DUK_ASSERT((thr->callstack_curr->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0 || /* indirect eval */
(thr->callstack_top >= 2)); /* if direct eval, calling activation must exist */
/*
@@ -28264,8 +33068,9 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
* activation doesn't exist, call must be indirect.
*/
- h = duk_get_hstring(ctx, 0);
+ h = duk_get_hstring_notsymbol(thr, 0);
if (!h) {
+ /* Symbol must be returned as is, like any non-string values. */
return 1; /* return arg as-is */
}
@@ -28274,88 +33079,85 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
* for an Ecmascript eval().
*/
DUK_ASSERT(level == -2); /* by default, use caller's environment */
- if (duk_get_top(ctx) >= 2 && duk_is_number(ctx, 1)) {
- level = duk_get_int(ctx, 1);
+ if (duk_get_top(thr) >= 2 && duk_is_number(thr, 1)) {
+ level = duk_get_int(thr, 1);
}
DUK_ASSERT(level <= -2); /* This is guaranteed by debugger code. */
#endif
/* [ source ] */
- comp_flags = DUK_JS_COMPILE_FLAG_EVAL;
- act_eval = thr->callstack + thr->callstack_top - 1; /* this function */
- if (thr->callstack_top >= (duk_size_t) -level) {
+ comp_flags = DUK_COMPILE_EVAL;
+ act_eval = thr->callstack_curr; /* this function */
+ DUK_ASSERT(act_eval != NULL);
+ act_caller = duk_hthread_get_activation_for_level(thr, level);
+ if (act_caller != NULL) {
/* Have a calling activation, check for direct eval (otherwise
* assume indirect eval.
*/
- act_caller = thr->callstack + thr->callstack_top + level; /* caller */
if ((act_caller->flags & DUK_ACT_FLAG_STRICT) &&
(act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL)) {
/* Only direct eval inherits strictness from calling code
* (E5.1 Section 10.1.1).
*/
- comp_flags |= DUK_JS_COMPILE_FLAG_STRICT;
+ comp_flags |= DUK_COMPILE_STRICT;
}
} else {
DUK_ASSERT((act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0);
}
- act_caller = NULL; /* avoid dereference after potential callstack realloc */
- act_eval = NULL;
- duk_push_hstring_stridx(ctx, DUK_STRIDX_INPUT); /* XXX: copy from caller? */
+ duk_push_hstring_stridx(thr, DUK_STRIDX_INPUT); /* XXX: copy from caller? */
duk_js_compile(thr,
(const duk_uint8_t *) DUK_HSTRING_GET_DATA(h),
(duk_size_t) DUK_HSTRING_GET_BYTELEN(h),
comp_flags);
- func = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) func));
+ func = (duk_hcompfunc *) duk_known_hobject(thr, -1);
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) func));
/* [ source template ] */
/* E5 Section 10.4.2 */
- DUK_ASSERT(thr->callstack_top >= 1);
- act = thr->callstack + thr->callstack_top - 1; /* this function */
- if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
+
+ if (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
DUK_ASSERT(thr->callstack_top >= 2);
- act = thr->callstack + thr->callstack_top + level; /* caller */
- if (act->lex_env == NULL) {
- DUK_ASSERT(act->var_env == NULL);
+ DUK_ASSERT(act_caller != NULL);
+ if (act_caller->lex_env == NULL) {
+ DUK_ASSERT(act_caller->var_env == NULL);
DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
/* this may have side effects, so re-lookup act */
- duk_js_init_activation_environment_records_delayed(thr, act);
- act = thr->callstack + thr->callstack_top + level;
+ duk_js_init_activation_environment_records_delayed(thr, act_caller);
}
- DUK_ASSERT(act->lex_env != NULL);
- DUK_ASSERT(act->var_env != NULL);
+ DUK_ASSERT(act_caller->lex_env != NULL);
+ DUK_ASSERT(act_caller->var_env != NULL);
this_to_global = 0;
if (DUK_HOBJECT_HAS_STRICT((duk_hobject *) func)) {
- duk_hobject *new_env;
+ duk_hdecenv *new_env;
duk_hobject *act_lex_env;
DUK_DDD(DUK_DDDPRINT("direct eval call to a strict function -> "
"var_env and lex_env to a fresh env, "
"this_binding to caller's this_binding"));
- act_lex_env = act->lex_env;
- act = NULL; /* invalidated */
+ act_lex_env = act_caller->lex_env;
- (void) duk_push_object_helper_proto(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
- act_lex_env);
- new_env = duk_require_hobject(ctx, -1);
+ new_env = duk_hdecenv_alloc(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
DUK_ASSERT(new_env != NULL);
- DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO",
- (duk_heaphdr *) new_env));
+ duk_push_hobject(thr, (duk_hobject *) new_env);
- outer_lex_env = new_env;
- outer_var_env = new_env;
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL);
+ DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, act_lex_env);
+ DUK_HOBJECT_INCREF_ALLOWNULL(thr, act_lex_env);
+ DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", (duk_heaphdr *) new_env));
- duk_insert(ctx, 0); /* stash to bottom of value stack to keep new_env reachable for duration of eval */
+ outer_lex_env = (duk_hobject *) new_env;
+ outer_var_env = (duk_hobject *) new_env;
+
+ duk_insert(thr, 0); /* stash to bottom of value stack to keep new_env reachable for duration of eval */
/* compiler's responsibility */
DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func));
@@ -28364,8 +33166,8 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
"var_env and lex_env to caller's envs, "
"this_binding to caller's this_binding"));
- outer_lex_env = act->lex_env;
- outer_var_env = act->var_env;
+ outer_lex_env = act_caller->lex_env;
+ outer_var_env = act_caller->var_env;
/* compiler's responsibility */
DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func));
@@ -28378,35 +33180,44 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
}
- act = NULL;
/* Eval code doesn't need an automatic .prototype object. */
duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 0 /*add_auto_proto*/);
- /* [ source template closure ] */
+ /* [ env? source template closure ] */
if (this_to_global) {
DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
- duk_push_hobject_bidx(ctx, DUK_BIDX_GLOBAL);
+ duk_push_hobject_bidx(thr, DUK_BIDX_GLOBAL);
} else {
duk_tval *tv;
DUK_ASSERT(thr->callstack_top >= 2);
- act = thr->callstack + thr->callstack_top + level; /* caller */
- tv = thr->valstack + act->idx_bottom - 1; /* this is just beneath bottom */
+ DUK_ASSERT(act_caller != NULL);
+ tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act_caller->bottom_byteoff - sizeof(duk_tval)); /* this is just beneath bottom */
DUK_ASSERT(tv >= thr->valstack);
- duk_push_tval(ctx, tv);
+ duk_push_tval(thr, tv);
}
DUK_DDD(DUK_DDDPRINT("eval -> lex_env=%!iO, var_env=%!iO, this_binding=%!T",
(duk_heaphdr *) outer_lex_env,
(duk_heaphdr *) outer_var_env,
- duk_get_tval(ctx, -1)));
+ duk_get_tval(thr, -1)));
- /* [ source template closure this ] */
+ /* [ env? source template closure this ] */
- duk_call_method(ctx, 0);
+ call_flags = 0;
+ if (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
+ /* Set DIRECT_EVAL flag for the call; it's not strictly
+ * needed for the 'inner' eval call (the eval body) but
+ * current new.target implementation expects to find it
+ * so it can traverse direct eval chains up to the real
+ * calling function.
+ */
+ call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
+ }
+ duk_handle_call_unprotected_nargs(thr, 0, call_flags);
- /* [ source template result ] */
+ /* [ env? source template result ] */
return 1;
}
@@ -28415,15 +33226,19 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
* Parsing of ints and floats
*/
-DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx) {
+#if defined(DUK_USE_GLOBAL_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_hthread *thr) {
duk_int32_t radix;
duk_small_uint_t s2n_flags;
- DUK_ASSERT_TOP(ctx, 2);
- duk_to_string(ctx, 0);
+ DUK_ASSERT_TOP(thr, 2);
+ duk_to_string(thr, 0); /* Reject symbols. */
- radix = duk_to_int32(ctx, 1);
+ radix = duk_to_int32(thr, 1);
+ /* While parseInt() recognizes 0xdeadbeef, it doesn't recognize
+ * ES2015 0o123 or 0b10001.
+ */
s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
DUK_S2N_FLAG_ALLOW_GARBAGE |
DUK_S2N_FLAG_ALLOW_PLUS |
@@ -28449,23 +33264,22 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx) {
radix = 10;
}
- duk_dup(ctx, 0);
- duk_numconv_parse(ctx, radix, s2n_flags);
+ duk_dup_0(thr);
+ duk_numconv_parse(thr, (duk_small_int_t) radix, s2n_flags);
return 1;
ret_nan:
- duk_push_nan(ctx);
+ duk_push_nan(thr);
return 1;
}
+#endif /* DUK_USE_GLOBAL_BUILTIN */
-DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx) {
+#if defined(DUK_USE_GLOBAL_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_float(duk_hthread *thr) {
duk_small_uint_t s2n_flags;
- duk_int32_t radix;
- DUK_ASSERT_TOP(ctx, 1);
- duk_to_string(ctx, 0);
-
- radix = 10;
+ DUK_ASSERT_TOP(thr, 1);
+ duk_to_string(thr, 0); /* Reject symbols. */
/* XXX: check flags */
s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
@@ -28479,632 +33293,66 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx) {
DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
DUK_S2N_FLAG_ALLOW_LEADING_ZERO;
- duk_numconv_parse(ctx, radix, s2n_flags);
+ duk_numconv_parse(thr, 10 /*radix*/, s2n_flags);
return 1;
}
+#endif /* DUK_USE_GLOBAL_BUILTIN */
/*
* Number checkers
*/
-DUK_INTERNAL duk_ret_t duk_bi_global_object_is_nan(duk_context *ctx) {
- duk_double_t d = duk_to_number(ctx, 0);
- duk_push_boolean(ctx, DUK_ISNAN(d));
+#if defined(DUK_USE_GLOBAL_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_global_object_is_nan(duk_hthread *thr) {
+ duk_double_t d = duk_to_number(thr, 0);
+ duk_push_boolean(thr, (duk_bool_t) DUK_ISNAN(d));
return 1;
}
+#endif /* DUK_USE_GLOBAL_BUILTIN */
-DUK_INTERNAL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx) {
- duk_double_t d = duk_to_number(ctx, 0);
- duk_push_boolean(ctx, DUK_ISFINITE(d));
+#if defined(DUK_USE_GLOBAL_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_global_object_is_finite(duk_hthread *thr) {
+ duk_double_t d = duk_to_number(thr, 0);
+ duk_push_boolean(thr, (duk_bool_t) DUK_ISFINITE(d));
return 1;
}
+#endif /* DUK_USE_GLOBAL_BUILTIN */
/*
* URI handling
*/
-DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_reserved_table);
+#if defined(DUK_USE_GLOBAL_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri(duk_hthread *thr) {
+ return duk__transform_helper(thr, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_reserved_table);
}
-DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri_component(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_component_reserved_table);
+DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri_component(duk_hthread *thr) {
+ return duk__transform_helper(thr, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_component_reserved_table);
}
-DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (const void *) duk__encode_uriunescaped_table);
+DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri(duk_hthread *thr) {
+ return duk__transform_helper(thr, duk__transform_callback_encode_uri, (const void *) duk__encode_uriunescaped_table);
}
-DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (const void *) duk__encode_uricomponent_unescaped_table);
+DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri_component(duk_hthread *thr) {
+ return duk__transform_helper(thr, duk__transform_callback_encode_uri, (const void *) duk__encode_uricomponent_unescaped_table);
}
-#ifdef DUK_USE_SECTION_B
-DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_escape, (const void *) NULL);
+#if defined(DUK_USE_SECTION_B)
+DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_hthread *thr) {
+ return duk__transform_helper(thr, duk__transform_callback_escape, (const void *) NULL);
}
-DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_unescape, (const void *) NULL);
-}
-#else /* DUK_USE_SECTION_B */
-DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
+DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_hthread *thr) {
+ return duk__transform_helper(thr, duk__transform_callback_unescape, (const void *) NULL);
}
#endif /* DUK_USE_SECTION_B */
+#endif /* DUK_USE_GLOBAL_BUILTIN */
-#if defined(DUK_USE_BROWSER_LIKE) && (defined(DUK_USE_FILE_IO) || defined(DUK_USE_DEBUGGER_SUPPORT))
-DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_int_t magic;
- duk_idx_t nargs;
- const duk_uint8_t *buf;
- duk_size_t sz_buf;
- const char nl = (const char) DUK_ASC_LF;
-#ifndef DUK_USE_PREFER_SIZE
- duk_uint8_t buf_stack[256];
-#endif
-#ifdef DUK_USE_FILE_IO
- duk_file *f_out;
-#endif
-
- DUK_UNREF(thr);
-
- magic = duk_get_current_magic(ctx);
- DUK_UNREF(magic);
-
- nargs = duk_get_top(ctx);
-
- /* If argument count is 1 and first argument is a buffer, write the buffer
- * as raw data into the file without a newline; this allows exact control
- * over stdout/stderr without an additional entrypoint (useful for now).
- *
- * Otherwise current print/alert semantics are to ToString() coerce
- * arguments, join them with a single space, and append a newline.
- */
-
- if (nargs == 1 && duk_is_buffer(ctx, 0)) {
- buf = (const duk_uint8_t *) duk_get_buffer(ctx, 0, &sz_buf);
- DUK_ASSERT(buf != NULL);
- } else if (nargs > 0) {
-#ifdef DUK_USE_PREFER_SIZE
- /* Compact but lots of churn. */
- duk_push_hstring_stridx(thr, DUK_STRIDX_SPACE);
- duk_insert(ctx, 0);
- duk_join(ctx, nargs);
- duk_push_string(thr, "\n");
- duk_concat(ctx, 2);
- buf = (const duk_uint8_t *) duk_get_lstring(ctx, -1, &sz_buf);
- DUK_ASSERT(buf != NULL);
-#else /* DUK_USE_PREFER_SIZE */
- /* Higher footprint, less churn. */
- duk_idx_t i;
- duk_size_t sz_str;
- const duk_uint8_t *p_str;
- duk_uint8_t *p;
-
- sz_buf = (duk_size_t) nargs; /* spaces (nargs - 1) + newline */
- for (i = 0; i < nargs; i++) {
- (void) duk_to_lstring(ctx, i, &sz_str);
- sz_buf += sz_str;
- }
-
- if (sz_buf <= sizeof(buf_stack)) {
- p = (duk_uint8_t *) buf_stack;
- } else {
- p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, sz_buf);
- DUK_ASSERT(p != NULL);
- }
-
- buf = (const duk_uint8_t *) p;
- for (i = 0; i < nargs; i++) {
- p_str = (const duk_uint8_t *) duk_get_lstring(ctx, i, &sz_str);
- DUK_ASSERT(p_str != NULL);
- DUK_MEMCPY((void *) p, (const void *) p_str, sz_str);
- p += sz_str;
- *p++ = (duk_uint8_t) (i == nargs - 1 ? DUK_ASC_LF : DUK_ASC_SPACE);
- }
- DUK_ASSERT((const duk_uint8_t *) p == buf + sz_buf);
-#endif /* DUK_USE_PREFER_SIZE */
- } else {
- buf = (const duk_uint8_t *) &nl;
- sz_buf = 1;
- }
-
- /* 'buf' contains the string to write, 'sz_buf' contains the length
- * (which may be zero).
- */
- DUK_ASSERT(buf != NULL);
-
- if (sz_buf == 0) {
- return 0;
- }
-
-#ifdef DUK_USE_FILE_IO
- f_out = (magic ? DUK_STDERR : DUK_STDOUT);
- DUK_FWRITE((const void *) buf, 1, (size_t) sz_buf, f_out);
- DUK_FFLUSH(f_out);
-#endif
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT) && defined(DUK_USE_DEBUGGER_FWD_PRINTALERT)
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
- duk_debug_write_notify(thr, magic ? DUK_DBG_CMD_ALERT : DUK_DBG_CMD_PRINT);
- duk_debug_write_string(thr, (const char *) buf, sz_buf);
- duk_debug_write_eom(thr);
- }
-#endif
- return 0;
-}
-#elif defined(DUK_USE_BROWSER_LIKE) /* print provider */
-DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) {
- DUK_UNREF(ctx);
- return 0;
-}
-#else /* print provider */
-DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* print provider */
-
-/*
- * CommonJS require() and modules support
- */
-
-#if defined(DUK_USE_COMMONJS_MODULES)
-DUK_LOCAL void duk__bi_global_resolve_module_id(duk_context *ctx, const char *req_id, const char *mod_id) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_uint8_t buf[DUK_BI_COMMONJS_MODULE_ID_LIMIT];
- duk_uint8_t *p;
- duk_uint8_t *q;
- duk_uint8_t *q_last; /* last component */
- duk_int_t int_rc;
-
- DUK_ASSERT(req_id != NULL);
- /* mod_id may be NULL */
-
- /*
- * A few notes on the algorithm:
- *
- * - Terms are not allowed to begin with a period unless the term
- * is either '.' or '..'. This simplifies implementation (and
- * is within CommonJS modules specification).
- *
- * - There are few output bound checks here. This is on purpose:
- * the resolution input is length checked and the output is never
- * longer than the input. The resolved output is written directly
- * over the input because it's never longer than the input at any
- * point in the algorithm.
- *
- * - Non-ASCII characters are processed as individual bytes and
- * need no special treatment. However, U+0000 terminates the
- * algorithm; this is not an issue because U+0000 is not a
- * desirable term character anyway.
- */
-
- /*
- * Set up the resolution input which is the requested ID directly
- * (if absolute or no current module path) or with current module
- * ID prepended (if relative and current module path exists).
- *
- * Suppose current module is 'foo/bar' and relative path is './quux'.
- * The 'bar' component must be replaced so the initial input here is
- * 'foo/bar/.././quux'.
- */
-
- if (mod_id != NULL && req_id[0] == '.') {
- int_rc = DUK_SNPRINTF((char *) buf, sizeof(buf), "%s/../%s", mod_id, req_id);
- } else {
- int_rc = DUK_SNPRINTF((char *) buf, sizeof(buf), "%s", req_id);
- }
- if (int_rc >= (duk_int_t) sizeof(buf) || int_rc < 0) {
- /* Potentially truncated, NUL not guaranteed in any case.
- * The (int_rc < 0) case should not occur in practice.
- */
- DUK_DD(DUK_DDPRINT("resolve error: temporary working module ID doesn't fit into resolve buffer"));
- goto resolve_error;
- }
- DUK_ASSERT(DUK_STRLEN((const char *) buf) < sizeof(buf)); /* at most sizeof(buf) - 1 */
-
- DUK_DDD(DUK_DDDPRINT("input module id: '%s'", (const char *) buf));
-
- /*
- * Resolution loop. At the top of the loop we're expecting a valid
- * term: '.', '..', or a non-empty identifier not starting with a period.
- */
-
- p = buf;
- q = buf;
- for (;;) {
- duk_uint_fast8_t c;
-
- /* Here 'p' always points to the start of a term.
- *
- * We can also unconditionally reset q_last here: if this is
- * the last (non-empty) term q_last will have the right value
- * on loop exit.
- */
-
- DUK_ASSERT(p >= q); /* output is never longer than input during resolution */
-
- DUK_DDD(DUK_DDDPRINT("resolve loop top: p -> '%s', q=%p, buf=%p",
- (const char *) p, (void *) q, (void *) buf));
-
- q_last = q;
-
- c = *p++;
- if (DUK_UNLIKELY(c == 0)) {
- DUK_DD(DUK_DDPRINT("resolve error: requested ID must end with a non-empty term"));
- goto resolve_error;
- } else if (DUK_UNLIKELY(c == '.')) {
- c = *p++;
- if (c == '/') {
- /* Term was '.' and is eaten entirely (including dup slashes). */
- goto eat_dup_slashes;
- }
- if (c == '.' && *p == '/') {
- /* Term was '..', backtrack resolved name by one component.
- * q[-1] = previous slash (or beyond start of buffer)
- * q[-2] = last char of previous component (or beyond start of buffer)
- */
- p++; /* eat (first) input slash */
- DUK_ASSERT(q >= buf);
- if (q == buf) {
- DUK_DD(DUK_DDPRINT("resolve error: term was '..' but nothing to backtrack"));
- goto resolve_error;
- }
- DUK_ASSERT(*(q - 1) == '/');
- q--; /* backtrack to last output slash (dups already eliminated) */
- for (;;) {
- /* Backtrack to previous slash or start of buffer. */
- DUK_ASSERT(q >= buf);
- if (q == buf) {
- break;
- }
- if (*(q - 1) == '/') {
- break;
- }
- q--;
- }
- goto eat_dup_slashes;
- }
- DUK_DD(DUK_DDPRINT("resolve error: term begins with '.' but is not '.' or '..' (not allowed now)"));
- goto resolve_error;
- } else if (DUK_UNLIKELY(c == '/')) {
- /* e.g. require('/foo'), empty terms not allowed */
- DUK_DD(DUK_DDPRINT("resolve error: empty term (not allowed now)"));
- goto resolve_error;
- } else {
- for (;;) {
- /* Copy term name until end or '/'. */
- *q++ = c;
- c = *p++;
- if (DUK_UNLIKELY(c == 0)) {
- /* This was the last term, and q_last was
- * updated to match this term at loop top.
- */
- goto loop_done;
- } else if (DUK_UNLIKELY(c == '/')) {
- *q++ = '/';
- break;
- } else {
- /* write on next loop */
- }
- }
- }
-
- eat_dup_slashes:
- for (;;) {
- /* eat dup slashes */
- c = *p;
- if (DUK_LIKELY(c != '/')) {
- break;
- }
- p++;
- }
- }
- loop_done:
- /* Output #1: resolved absolute name */
- DUK_ASSERT(q >= buf);
- duk_push_lstring(ctx, (const char *) buf, (size_t) (q - buf));
-
- /* Output #2: last component name */
- DUK_ASSERT(q >= q_last);
- DUK_ASSERT(q_last >= buf);
- duk_push_lstring(ctx, (const char *) q_last, (size_t) (q - q_last));
-
- DUK_DD(DUK_DDPRINT("after resolving module name: buf=%p, q_last=%p, q=%p",
- (void *) buf, (void *) q_last, (void *) q));
- return;
-
- resolve_error:
- DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "cannot resolve module id: %s", (const char *) req_id);
-}
-#endif /* DUK_USE_COMMONJS_MODULES */
-
-#if defined(DUK_USE_COMMONJS_MODULES)
-/* Stack indices for better readability */
-#define DUK__IDX_REQUESTED_ID 0 /* Module id requested */
-#define DUK__IDX_REQUIRE 1 /* Current require() function */
-#define DUK__IDX_REQUIRE_ID 2 /* The base ID of the current require() function, resolution base */
-#define DUK__IDX_RESOLVED_ID 3 /* Resolved, normalized absolute module ID */
-#define DUK__IDX_LASTCOMP 4 /* Last component name in resolved path */
-#define DUK__IDX_DUKTAPE 5 /* Duktape object */
-#define DUK__IDX_MODLOADED 6 /* Duktape.modLoaded[] module cache */
-#define DUK__IDX_UNDEFINED 7 /* 'undefined', artifact of lookup */
-#define DUK__IDX_FRESH_REQUIRE 8 /* New require() function for module, updated resolution base */
-#define DUK__IDX_EXPORTS 9 /* Default exports table */
-#define DUK__IDX_MODULE 10 /* Module object containing module.exports, etc */
-
-DUK_INTERNAL duk_ret_t duk_bi_global_object_require(duk_context *ctx) {
- const char *str_req_id; /* requested identifier */
- const char *str_mod_id; /* require.id of current module */
- duk_int_t pcall_rc;
-
- /* NOTE: we try to minimize code size by avoiding unnecessary pops,
- * so the stack looks a bit cluttered in this function. DUK_ASSERT_TOP()
- * assertions are used to ensure stack configuration is correct at each
- * step.
- */
-
- /*
- * Resolve module identifier into canonical absolute form.
- */
-
- str_req_id = duk_require_string(ctx, DUK__IDX_REQUESTED_ID);
- duk_push_current_function(ctx);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_ID);
- str_mod_id = duk_get_string(ctx, DUK__IDX_REQUIRE_ID); /* ignore non-strings */
- DUK_DDD(DUK_DDDPRINT("resolve module id: requested=%!T, currentmodule=%!T",
- duk_get_tval(ctx, DUK__IDX_REQUESTED_ID),
- duk_get_tval(ctx, DUK__IDX_REQUIRE_ID)));
- duk__bi_global_resolve_module_id(ctx, str_req_id, str_mod_id);
- str_req_id = NULL;
- str_mod_id = NULL;
- DUK_DDD(DUK_DDDPRINT("resolved module id: requested=%!T, currentmodule=%!T, result=%!T, lastcomp=%!T",
- duk_get_tval(ctx, DUK__IDX_REQUESTED_ID),
- duk_get_tval(ctx, DUK__IDX_REQUIRE_ID),
- duk_get_tval(ctx, DUK__IDX_RESOLVED_ID),
- duk_get_tval(ctx, DUK__IDX_LASTCOMP)));
-
- /* [ requested_id require require.id resolved_id last_comp ] */
- DUK_ASSERT_TOP(ctx, DUK__IDX_LASTCOMP + 1);
-
- /*
- * Cached module check.
- *
- * If module has been loaded or its loading has already begun without
- * finishing, return the same cached value ('exports'). The value is
- * registered when module load starts so that circular references can
- * be supported to some extent.
- */
-
- duk_push_hobject_bidx(ctx, DUK_BIDX_DUKTAPE);
- duk_get_prop_stridx(ctx, DUK__IDX_DUKTAPE, DUK_STRIDX_MOD_LOADED); /* Duktape.modLoaded */
- (void) duk_require_hobject(ctx, DUK__IDX_MODLOADED);
- DUK_ASSERT_TOP(ctx, DUK__IDX_MODLOADED + 1);
-
- duk_dup(ctx, DUK__IDX_RESOLVED_ID);
- if (duk_get_prop(ctx, DUK__IDX_MODLOADED)) {
- /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded Duktape.modLoaded[id] ] */
- DUK_DD(DUK_DDPRINT("module already loaded: %!T",
- duk_get_tval(ctx, DUK__IDX_RESOLVED_ID)));
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_EXPORTS); /* return module.exports */
- return 1;
- }
- DUK_ASSERT_TOP(ctx, DUK__IDX_UNDEFINED + 1);
-
- /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined ] */
-
- /*
- * Module not loaded (and loading not started previously).
- *
- * Create a new require() function with 'id' set to resolved ID
- * of module being loaded. Also create 'exports' and 'module'
- * tables but don't register exports to the loaded table yet.
- * We don't want to do that unless the user module search callbacks
- * succeeds in finding the module.
- */
-
- DUK_D(DUK_DPRINT("loading module %!T, resolution base %!T, requested ID %!T -> resolved ID %!T, last component %!T",
- duk_get_tval(ctx, DUK__IDX_RESOLVED_ID),
- duk_get_tval(ctx, DUK__IDX_REQUIRE_ID),
- duk_get_tval(ctx, DUK__IDX_REQUESTED_ID),
- duk_get_tval(ctx, DUK__IDX_RESOLVED_ID),
- duk_get_tval(ctx, DUK__IDX_LASTCOMP)));
-
- /* Fresh require: require.id is left configurable (but not writable)
- * so that is not easy to accidentally tweak it, but it can still be
- * done with Object.defineProperty().
- *
- * XXX: require.id could also be just made non-configurable, as there
- * is no practical reason to touch it.
- */
- duk_push_c_function(ctx, duk_bi_global_object_require, 1 /*nargs*/);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_REQUIRE);
- duk_xdef_prop_stridx(ctx, DUK__IDX_FRESH_REQUIRE, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
- duk_dup(ctx, DUK__IDX_RESOLVED_ID);
- duk_xdef_prop_stridx(ctx, DUK__IDX_FRESH_REQUIRE, DUK_STRIDX_ID, DUK_PROPDESC_FLAGS_C); /* a fresh require() with require.id = resolved target module id */
-
- /* Module table:
- * - module.exports: initial exports table (may be replaced by user)
- * - module.id is non-writable and non-configurable, as the CommonJS
- * spec suggests this if possible
- * - module.filename: not set, defaults to resolved ID if not explicitly
- * set by modSearch() (note capitalization, not .fileName, matches Node.js)
- * - module.name: not set, defaults to last component of resolved ID if
- * not explicitly set by modSearch()
- */
- duk_push_object(ctx); /* exports */
- duk_push_object(ctx); /* module */
- duk_dup(ctx, DUK__IDX_EXPORTS);
- duk_xdef_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_EXPORTS, DUK_PROPDESC_FLAGS_WC); /* module.exports = exports */
- duk_dup(ctx, DUK__IDX_RESOLVED_ID); /* resolved id: require(id) must return this same module */
- duk_xdef_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_ID, DUK_PROPDESC_FLAGS_NONE); /* module.id = resolved_id */
- duk_compact(ctx, DUK__IDX_MODULE); /* module table remains registered to modLoaded, minimize its size */
- DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 1);
-
- DUK_DD(DUK_DDPRINT("module table created: %!T", duk_get_tval(ctx, DUK__IDX_MODULE)));
-
- /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module ] */
-
- /* Register the module table early to modLoaded[] so that we can
- * support circular references even in modSearch(). If an error
- * is thrown, we'll delete the reference.
- */
- duk_dup(ctx, DUK__IDX_RESOLVED_ID);
- duk_dup(ctx, DUK__IDX_MODULE);
- duk_put_prop(ctx, DUK__IDX_MODLOADED); /* Duktape.modLoaded[resolved_id] = module */
-
- /*
- * Call user provided module search function and build the wrapped
- * module source code (if necessary). The module search function
- * can be used to implement pure Ecmacsript, pure C, and mixed
- * Ecmascript/C modules.
- *
- * The module search function can operate on the exports table directly
- * (e.g. DLL code can register values to it). It can also return a
- * string which is interpreted as module source code (if a non-string
- * is returned the module is assumed to be a pure C one). If a module
- * cannot be found, an error must be thrown by the user callback.
- *
- * Because Duktape.modLoaded[] already contains the module being
- * loaded, circular references for C modules should also work
- * (although expected to be quite rare).
- */
-
- duk_push_string(ctx, "(function(require,exports,module){");
-
- /* Duktape.modSearch(resolved_id, fresh_require, exports, module). */
- duk_get_prop_stridx(ctx, DUK__IDX_DUKTAPE, DUK_STRIDX_MOD_SEARCH); /* Duktape.modSearch */
- duk_dup(ctx, DUK__IDX_RESOLVED_ID);
- duk_dup(ctx, DUK__IDX_FRESH_REQUIRE);
- duk_dup(ctx, DUK__IDX_EXPORTS);
- duk_dup(ctx, DUK__IDX_MODULE); /* [ ... Duktape.modSearch resolved_id last_comp fresh_require exports module ] */
- pcall_rc = duk_pcall(ctx, 4 /*nargs*/); /* -> [ ... source ] */
- DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 3);
-
- if (pcall_rc != DUK_EXEC_SUCCESS) {
- /* Delete entry in Duktape.modLoaded[] and rethrow. */
- goto delete_rethrow;
- }
-
- /* If user callback did not return source code, module loading
- * is finished (user callback initialized exports table directly).
- */
- if (!duk_is_string(ctx, -1)) {
- /* User callback did not return source code, so module loading
- * is finished: just update modLoaded with final module.exports
- * and we're done.
- */
- goto return_exports;
- }
-
- /* Finish the wrapped module source. Force module.filename as the
- * function .fileName so it gets set for functions defined within a
- * module. This also ensures loggers created within the module get
- * the module ID (or overridden filename) as their default logger name.
- * (Note capitalization: .filename matches Node.js while .fileName is
- * used elsewhere in Duktape.)
- */
- duk_push_string(ctx, "\n})"); /* Newline allows module last line to contain a // comment. */
- duk_concat(ctx, 3);
- if (!duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_FILENAME)) {
- /* module.filename for .fileName, default to resolved ID if
- * not present.
- */
- duk_pop(ctx);
- duk_dup(ctx, DUK__IDX_RESOLVED_ID);
- }
- duk_eval_raw(ctx, NULL, 0, DUK_COMPILE_EVAL);
-
- /* Module has now evaluated to a wrapped module function. Force its
- * .name to match module.name (defaults to last component of resolved
- * ID) so that it is shown in stack traces too. Note that we must not
- * introduce an actual name binding into the function scope (which is
- * usually the case with a named function) because it would affect the
- * scope seen by the module and shadow accesses to globals of the same name.
- * This is now done by compiling the function as anonymous and then forcing
- * its .name without setting a "has name binding" flag.
- */
-
- duk_push_hstring_stridx(ctx, DUK_STRIDX_NAME);
- if (!duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_NAME)) {
- /* module.name for .name, default to last component if
- * not present.
- */
- duk_pop(ctx);
- duk_dup(ctx, DUK__IDX_LASTCOMP);
- }
- duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_FORCE);
-
- /*
- * Call the wrapped module function.
- *
- * Use a protected call so that we can update Duktape.modLoaded[resolved_id]
- * even if the module throws an error.
- */
-
- /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module mod_func ] */
- DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 2);
-
- duk_dup(ctx, DUK__IDX_EXPORTS); /* exports (this binding) */
- duk_dup(ctx, DUK__IDX_FRESH_REQUIRE); /* fresh require (argument) */
- duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_EXPORTS); /* relookup exports from module.exports in case it was changed by modSearch */
- duk_dup(ctx, DUK__IDX_MODULE); /* module (argument) */
- DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 6);
-
- /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module mod_func exports fresh_require exports module ] */
-
- pcall_rc = duk_pcall_method(ctx, 3 /*nargs*/);
- if (pcall_rc != DUK_EXEC_SUCCESS) {
- /* Module loading failed. Node.js will forget the module
- * registration so that another require() will try to load
- * the module again. Mimic that behavior.
- */
- goto delete_rethrow;
- }
-
- /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module result(ignored) ] */
- DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 2);
-
- /* fall through */
-
- return_exports:
- duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_EXPORTS);
- duk_compact(ctx, -1); /* compact the exports table */
- return 1; /* return module.exports */
-
- delete_rethrow:
- duk_dup(ctx, DUK__IDX_RESOLVED_ID);
- duk_del_prop(ctx, DUK__IDX_MODLOADED); /* delete Duktape.modLoaded[resolved_id] */
- duk_throw(ctx); /* rethrow original error */
- return 0; /* not reachable */
-}
-
-#undef DUK__IDX_REQUESTED_ID
-#undef DUK__IDX_REQUIRE
-#undef DUK__IDX_REQUIRE_ID
-#undef DUK__IDX_RESOLVED_ID
-#undef DUK__IDX_LASTCOMP
-#undef DUK__IDX_DUKTAPE
-#undef DUK__IDX_MODLOADED
-#undef DUK__IDX_UNDEFINED
-#undef DUK__IDX_FRESH_REQUIRE
-#undef DUK__IDX_EXPORTS
-#undef DUK__IDX_MODULE
-#else
-DUK_INTERNAL duk_ret_t duk_bi_global_object_require(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_COMMONJS_MODULES */
+/* automatic undefs */
+#undef DUK__CHECK_BITMASK
+#undef DUK__MKBITS
#line 1 "duk_bi_json.c"
/*
* JSON built-ins.
@@ -29122,7 +33370,9 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_require(duk_context *ctx) {
* indeed correct!
*/
-/* include removed: duk_internal.h */
+/* #include duk_internal.h -> already included */
+
+#if defined(DUK_USE_JSON_SUPPORT)
/*
* Local defines and forward declarations.
@@ -29136,13 +33386,15 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_require(duk_context *ctx) {
DUK_LOCAL_DECL void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx);
DUK_LOCAL_DECL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx);
+#if defined(DUK_USE_JX)
DUK_LOCAL_DECL duk_uint8_t duk__dec_peek(duk_json_dec_ctx *js_ctx);
+#endif
DUK_LOCAL_DECL duk_uint8_t duk__dec_get(duk_json_dec_ctx *js_ctx);
DUK_LOCAL_DECL duk_uint8_t duk__dec_get_nonwhite(duk_json_dec_ctx *js_ctx);
DUK_LOCAL_DECL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n);
DUK_LOCAL_DECL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx);
DUK_LOCAL_DECL void duk__dec_string(duk_json_dec_ctx *js_ctx);
-#ifdef DUK_USE_JX
+#if defined(DUK_USE_JX)
DUK_LOCAL_DECL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx);
DUK_LOCAL_DECL void duk__dec_pointer(duk_json_dec_ctx *js_ctx);
DUK_LOCAL_DECL void duk__dec_buffer(duk_json_dec_ctx *js_ctx);
@@ -29177,11 +33429,16 @@ DUK_LOCAL_DECL void duk__enc_double(duk_json_enc_ctx *js_ctx);
DUK_LOCAL_DECL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv);
#endif
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
-DUK_LOCAL_DECL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h);
+DUK_LOCAL_DECL void duk__enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h);
DUK_LOCAL_DECL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr);
-DUK_LOCAL_DECL void duk__enc_bufferobject(duk_json_enc_ctx *js_ctx, duk_hbufferobject *h_bufobj);
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+DUK_LOCAL_DECL void duk__enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj);
#endif
-DUK_LOCAL_DECL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth);
+#endif
+#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
+DUK_LOCAL_DECL void duk__enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h);
+#endif
+DUK_LOCAL_DECL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth);
/*
* Helper tables
@@ -29345,10 +33602,12 @@ DUK_LOCAL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx) {
js_ctx->p = p;
}
+#if defined(DUK_USE_JX)
DUK_LOCAL duk_uint8_t duk__dec_peek(duk_json_dec_ctx *js_ctx) {
DUK_ASSERT(js_ctx->p <= js_ctx->p_end);
return *js_ctx->p;
}
+#endif
DUK_LOCAL duk_uint8_t duk__dec_get(duk_json_dec_ctx *js_ctx) {
DUK_ASSERT(js_ctx->p <= js_ctx->p_end);
@@ -29378,7 +33637,7 @@ DUK_LOCAL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx,
DUK_ASSERT(duk_hex_dectab[0] == -1);
t = duk_hex_dectab[x & 0xff];
if (DUK_LIKELY(t >= 0)) {
- res = (res * 16) + t;
+ res = (res * 16) + (duk_uint_fast32_t) t;
} else {
/* catches EOF and invalid digits */
goto syntax_error;
@@ -29404,8 +33663,7 @@ DUK_LOCAL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t st
* have internal NULs.
*/
- DUK_ASSERT_DISABLE(stridx >= 0); /* unsigned */
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
+ DUK_ASSERT_STRIDX_VALID(stridx);
h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx);
DUK_ASSERT(h != NULL);
@@ -29440,7 +33698,7 @@ DUK_LOCAL duk_small_int_t duk__dec_string_escape(duk_json_dec_ctx *js_ctx, duk_u
* will match the default case (syntax error).
*/
cp = (duk_uint_fast32_t) duk__dec_get(js_ctx);
- switch ((int) cp) {
+ switch (cp) {
case DUK_ASC_BACKSLASH: break;
case DUK_ASC_DOUBLEQUOTE: break;
case DUK_ASC_SLASH: break;
@@ -29453,7 +33711,7 @@ DUK_LOCAL duk_small_int_t duk__dec_string_escape(duk_json_dec_ctx *js_ctx, duk_u
cp = duk__dec_decode_hex_escape(js_ctx, 4);
break;
}
-#ifdef DUK_USE_JX
+#if defined(DUK_USE_JX)
case DUK_ASC_UC_U: {
if (js_ctx->flag_ext_custom) {
cp = duk__dec_decode_hex_escape(js_ctx, 8);
@@ -29483,7 +33741,6 @@ DUK_LOCAL duk_small_int_t duk__dec_string_escape(duk_json_dec_ctx *js_ctx, duk_u
DUK_LOCAL void duk__dec_string(duk_json_dec_ctx *js_ctx) {
duk_hthread *thr = js_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_bufwriter_ctx bw_alloc;
duk_bufwriter_ctx *bw;
duk_uint8_t *q;
@@ -29576,7 +33833,7 @@ DUK_LOCAL void duk__dec_string(duk_json_dec_ctx *js_ctx) {
#endif /* DUK_USE_JSON_DECSTRING_FASTPATH */
DUK_BW_SETPTR_AND_COMPACT(js_ctx->thr, bw, q);
- duk_to_string(ctx, -1);
+ (void) duk_buffer_to_string(thr, -1); /* Safe if input string is safe. */
/* [ ... str ] */
@@ -29587,13 +33844,12 @@ DUK_LOCAL void duk__dec_string(duk_json_dec_ctx *js_ctx) {
DUK_UNREACHABLE();
}
-#ifdef DUK_USE_JX
+#if defined(DUK_USE_JX)
/* Decode a plain string consisting entirely of identifier characters.
* Used to parse plain keys (e.g. "foo: 123").
*/
DUK_LOCAL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx) {
duk_hthread *thr = js_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
const duk_uint8_t *p;
duk_small_int_t x;
@@ -29626,17 +33882,16 @@ DUK_LOCAL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx) {
p++;
}
- duk_push_lstring(ctx, (const char *) js_ctx->p, (duk_size_t) (p - js_ctx->p));
+ duk_push_lstring(thr, (const char *) js_ctx->p, (duk_size_t) (p - js_ctx->p));
js_ctx->p = p;
/* [ ... str ] */
}
#endif /* DUK_USE_JX */
-#ifdef DUK_USE_JX
+#if defined(DUK_USE_JX)
DUK_LOCAL void duk__dec_pointer(duk_json_dec_ctx *js_ctx) {
duk_hthread *thr = js_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
const duk_uint8_t *p;
duk_small_int_t x;
void *voidptr;
@@ -29674,7 +33929,7 @@ DUK_LOCAL void duk__dec_pointer(duk_json_dec_ctx *js_ctx) {
voidptr = NULL;
(void) DUK_SSCANF((const char *) js_ctx->p, DUK_STR_FMT_PTR, &voidptr);
- duk_push_pointer(ctx, voidptr);
+ duk_push_pointer(thr, voidptr);
js_ctx->p = p + 1; /* skip ')' */
/* [ ... ptr ] */
@@ -29687,10 +33942,9 @@ DUK_LOCAL void duk__dec_pointer(duk_json_dec_ctx *js_ctx) {
}
#endif /* DUK_USE_JX */
-#ifdef DUK_USE_JX
+#if defined(DUK_USE_JX)
DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) {
duk_hthread *thr = js_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
const duk_uint8_t *p;
duk_uint8_t *buf;
duk_size_t src_len;
@@ -29727,11 +33981,12 @@ DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) {
p++;
}
+ /* XXX: this is not very nice; unnecessary copy is made. */
src_len = (duk_size_t) (p - js_ctx->p);
- buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, src_len);
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, src_len);
DUK_ASSERT(buf != NULL);
DUK_MEMCPY((void *) buf, (const void *) js_ctx->p, src_len);
- duk_hex_decode(ctx, -1);
+ duk_hex_decode(thr, -1);
js_ctx->p = p + 1; /* skip '|' */
@@ -29747,7 +34002,7 @@ DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) {
/* Parse a number, other than NaN or +/- Infinity */
DUK_LOCAL void duk__dec_number(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
const duk_uint8_t *p_start;
const duk_uint8_t *p;
duk_uint8_t x;
@@ -29792,35 +34047,35 @@ DUK_LOCAL void duk__dec_number(duk_json_dec_ctx *js_ctx) {
js_ctx->p = p;
DUK_ASSERT(js_ctx->p > p_start);
- duk_push_lstring(ctx, (const char *) p_start, (duk_size_t) (p - p_start));
+ duk_push_lstring(thr, (const char *) p_start, (duk_size_t) (p - p_start));
s2n_flags = DUK_S2N_FLAG_ALLOW_EXP |
DUK_S2N_FLAG_ALLOW_MINUS | /* but don't allow leading plus */
DUK_S2N_FLAG_ALLOW_FRAC;
DUK_DDD(DUK_DDDPRINT("parse_number: string before parsing: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_numconv_parse(ctx, 10 /*radix*/, s2n_flags);
- if (duk_is_nan(ctx, -1)) {
+ (duk_tval *) duk_get_tval(thr, -1)));
+ duk_numconv_parse(thr, 10 /*radix*/, s2n_flags);
+ if (duk_is_nan(thr, -1)) {
duk__dec_syntax_error(js_ctx);
}
- DUK_ASSERT(duk_is_number(ctx, -1));
+ DUK_ASSERT(duk_is_number(thr, -1));
DUK_DDD(DUK_DDDPRINT("parse_number: final number: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
/* [ ... num ] */
}
DUK_LOCAL void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
- duk_require_stack(ctx, DUK_JSON_DEC_REQSTACK);
+ duk_hthread *thr = js_ctx->thr;
+ duk_require_stack(thr, DUK_JSON_DEC_REQSTACK);
/* c recursion check */
- DUK_ASSERT(js_ctx->recursion_depth >= 0);
+ DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0); /* unsigned */
DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
- DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_JSONDEC_RECLIMIT);
+ DUK_ERROR_RANGE(thr, DUK_STR_JSONDEC_RECLIMIT);
}
js_ctx->recursion_depth++;
}
@@ -29834,7 +34089,7 @@ DUK_LOCAL void duk__dec_objarr_exit(duk_json_dec_ctx *js_ctx) {
}
DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_int_t key_count; /* XXX: a "first" flag would suffice */
duk_uint8_t x;
@@ -29842,7 +34097,7 @@ DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
duk__dec_objarr_entry(js_ctx);
- duk_push_object(ctx);
+ duk_push_object(thr);
/* Initial '{' has been checked and eaten by caller. */
@@ -29851,7 +34106,7 @@ DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
x = duk__dec_get_nonwhite(js_ctx);
DUK_DDD(DUK_DDDPRINT("parse_object: obj=%!T, x=%ld, key_count=%ld",
- (duk_tval *) duk_get_tval(ctx, -1),
+ (duk_tval *) duk_get_tval(thr, -1),
(long) x, (long) key_count));
/* handle comma and closing brace */
@@ -29876,7 +34131,7 @@ DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
if (x == DUK_ASC_DOUBLEQUOTE) {
duk__dec_string(js_ctx);
-#ifdef DUK_USE_JX
+#if defined(DUK_USE_JX)
} else if (js_ctx->flag_ext_custom &&
duk_unicode_is_identifier_start((duk_codepoint_t) x)) {
duk__dec_plain_string(js_ctx);
@@ -29896,7 +34151,7 @@ DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
/* [ ... obj key val ] */
- duk_xdef_prop_wec(ctx, -3);
+ duk_xdef_prop_wec(thr, -3);
/* [ ... obj ] */
@@ -29906,7 +34161,7 @@ DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
/* [ ... obj ] */
DUK_DDD(DUK_DDDPRINT("parse_object: final object is %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
duk__dec_objarr_exit(js_ctx);
return;
@@ -29917,7 +34172,7 @@ DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
}
DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_uarridx_t arr_idx;
duk_uint8_t x;
@@ -29925,7 +34180,7 @@ DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
duk__dec_objarr_entry(js_ctx);
- duk_push_array(ctx);
+ duk_push_array(thr);
/* Initial '[' has been checked and eaten by caller. */
@@ -29934,7 +34189,7 @@ DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
x = duk__dec_get_nonwhite(js_ctx);
DUK_DDD(DUK_DDDPRINT("parse_array: arr=%!T, x=%ld, arr_idx=%ld",
- (duk_tval *) duk_get_tval(ctx, -1),
+ (duk_tval *) duk_get_tval(thr, -1),
(long) x, (long) arr_idx));
/* handle comma and closing bracket */
@@ -29961,7 +34216,7 @@ DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
/* [ ... arr val ] */
- duk_xdef_prop_index_wec(ctx, -2, arr_idx);
+ duk_xdef_prop_index_wec(thr, -2, arr_idx);
arr_idx++;
}
@@ -29969,12 +34224,12 @@ DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
* set the values.
*/
- duk_set_length(ctx, -1, arr_idx);
+ duk_set_length(thr, -1, arr_idx);
/* [ ... arr ] */
DUK_DDD(DUK_DDDPRINT("parse_array: final array is %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
duk__dec_objarr_exit(js_ctx);
return;
@@ -29985,7 +34240,7 @@ DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
}
DUK_LOCAL void duk__dec_value(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_uint8_t x;
x = duk__dec_get_nonwhite(js_ctx);
@@ -29997,10 +34252,10 @@ DUK_LOCAL void duk__dec_value(duk_json_dec_ctx *js_ctx) {
if (x == DUK_ASC_DOUBLEQUOTE) {
duk__dec_string(js_ctx);
} else if ((x >= DUK_ASC_0 && x <= DUK_ASC_9) || (x == DUK_ASC_MINUS)) {
-#ifdef DUK_USE_JX
+#if defined(DUK_USE_JX)
if (js_ctx->flag_ext_custom && x == DUK_ASC_MINUS && duk__dec_peek(js_ctx) == DUK_ASC_UC_I) {
duk__dec_req_stridx(js_ctx, DUK_STRIDX_MINUS_INFINITY); /* "-Infinity", '-' has been eaten */
- duk_push_number(ctx, -DUK_DOUBLE_INFINITY);
+ duk_push_number(thr, -DUK_DOUBLE_INFINITY);
} else {
#else
{ /* unconditional block */
@@ -30011,23 +34266,23 @@ DUK_LOCAL void duk__dec_value(duk_json_dec_ctx *js_ctx) {
}
} else if (x == DUK_ASC_LC_T) {
duk__dec_req_stridx(js_ctx, DUK_STRIDX_TRUE);
- duk_push_true(ctx);
+ duk_push_true(thr);
} else if (x == DUK_ASC_LC_F) {
duk__dec_req_stridx(js_ctx, DUK_STRIDX_FALSE);
- duk_push_false(ctx);
+ duk_push_false(thr);
} else if (x == DUK_ASC_LC_N) {
duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_NULL);
- duk_push_null(ctx);
-#ifdef DUK_USE_JX
+ duk_push_null(thr);
+#if defined(DUK_USE_JX)
} else if (js_ctx->flag_ext_custom && x == DUK_ASC_LC_U) {
duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_UNDEFINED);
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
} else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_N) {
duk__dec_req_stridx(js_ctx, DUK_STRIDX_NAN);
- duk_push_nan(ctx);
+ duk_push_nan(thr);
} else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_I) {
duk__dec_req_stridx(js_ctx, DUK_STRIDX_INFINITY);
- duk_push_number(ctx, DUK_DOUBLE_INFINITY);
+ duk_push_number(thr, DUK_DOUBLE_INFINITY);
} else if (js_ctx->flag_ext_custom && x == DUK_ASC_LPAREN) {
duk__dec_pointer(js_ctx);
} else if (js_ctx->flag_ext_custom && x == DUK_ASC_PIPE) {
@@ -30057,67 +34312,65 @@ DUK_LOCAL void duk__dec_value(duk_json_dec_ctx *js_ctx) {
* there is a reasonable limit on C recursion depth and hence object depth.
*/
DUK_LOCAL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_hobject *h;
duk_uarridx_t i, arr_len;
DUK_DDD(DUK_DDDPRINT("walk: top=%ld, holder=%!T, name=%!T",
- (long) duk_get_top(ctx),
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (long) duk_get_top(thr),
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
- duk_dup_top(ctx);
- duk_get_prop(ctx, -3); /* -> [ ... holder name val ] */
+ duk_dup_top(thr);
+ duk_get_prop(thr, -3); /* -> [ ... holder name val ] */
- h = duk_get_hobject(ctx, -1);
+ h = duk_get_hobject(thr, -1);
if (h != NULL) {
if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) {
- arr_len = (duk_uarridx_t) duk_get_length(ctx, -1);
+ arr_len = (duk_uarridx_t) duk_get_length(thr, -1);
for (i = 0; i < arr_len; i++) {
/* [ ... holder name val ] */
DUK_DDD(DUK_DDDPRINT("walk: array, top=%ld, i=%ld, arr_len=%ld, holder=%!T, name=%!T, val=%!T",
- (long) duk_get_top(ctx), (long) i, (long) arr_len,
- (duk_tval *) duk_get_tval(ctx, -3), (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (long) duk_get_top(thr), (long) i, (long) arr_len,
+ (duk_tval *) duk_get_tval(thr, -3), (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
- /* XXX: push_uint_string / push_u32_string */
- duk_dup_top(ctx);
- duk_push_uint(ctx, (duk_uint_t) i);
- duk_to_string(ctx, -1); /* -> [ ... holder name val val ToString(i) ] */
+ duk_dup_top(thr);
+ (void) duk_push_uint_to_hstring(thr, (duk_uint_t) i); /* -> [ ... holder name val val ToString(i) ] */
duk__dec_reviver_walk(js_ctx); /* -> [ ... holder name val new_elem ] */
- if (duk_is_undefined(ctx, -1)) {
- duk_pop(ctx);
- duk_del_prop_index(ctx, -1, i);
+ if (duk_is_undefined(thr, -1)) {
+ duk_pop(thr);
+ duk_del_prop_index(thr, -1, i);
} else {
/* XXX: duk_xdef_prop_index_wec() would be more appropriate
* here but it currently makes some assumptions that might
* not hold (e.g. that previous property is not an accessor).
*/
- duk_put_prop_index(ctx, -2, i);
+ duk_put_prop_index(thr, -2, i);
}
}
} else {
/* [ ... holder name val ] */
- duk_enum(ctx, -1, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/);
- while (duk_next(ctx, -1 /*enum_index*/, 0 /*get_value*/)) {
+ duk_enum(thr, -1, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/);
+ while (duk_next(thr, -1 /*enum_index*/, 0 /*get_value*/)) {
DUK_DDD(DUK_DDDPRINT("walk: object, top=%ld, holder=%!T, name=%!T, val=%!T, enum=%!iT, obj_key=%!T",
- (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, -5),
- (duk_tval *) duk_get_tval(ctx, -4), (duk_tval *) duk_get_tval(ctx, -3),
- (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
+ (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, -5),
+ (duk_tval *) duk_get_tval(thr, -4), (duk_tval *) duk_get_tval(thr, -3),
+ (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1)));
/* [ ... holder name val enum obj_key ] */
- duk_dup(ctx, -3);
- duk_dup(ctx, -2);
+ duk_dup_m3(thr);
+ duk_dup_m2(thr);
/* [ ... holder name val enum obj_key val obj_key ] */
duk__dec_reviver_walk(js_ctx);
/* [ ... holder name val enum obj_key new_elem ] */
- if (duk_is_undefined(ctx, -1)) {
- duk_pop(ctx);
- duk_del_prop(ctx, -3);
+ if (duk_is_undefined(thr, -1)) {
+ duk_pop(thr);
+ duk_del_prop(thr, -3);
} else {
/* XXX: duk_xdef_prop_index_wec() would be more appropriate
* here but it currently makes some assumptions that might
@@ -30128,21 +34381,21 @@ DUK_LOCAL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx) {
* does not happen normally, but a clever reviver can trigger
* that, see complex reviver case in: test-bug-json-parse-__proto__.js.
*/
- duk_put_prop(ctx, -4);
+ duk_put_prop(thr, -4);
}
}
- duk_pop(ctx); /* pop enum */
+ duk_pop(thr); /* pop enum */
}
}
/* [ ... holder name val ] */
- duk_dup(ctx, js_ctx->idx_reviver);
- duk_insert(ctx, -4); /* -> [ ... reviver holder name val ] */
- duk_call_method(ctx, 2); /* -> [ ... res ] */
+ duk_dup(thr, js_ctx->idx_reviver);
+ duk_insert(thr, -4); /* -> [ ... reviver holder name val ] */
+ duk_call_method(thr, 2); /* -> [ ... res ] */
DUK_DDD(DUK_DDDPRINT("walk: top=%ld, result=%!T",
- (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, -1)));
+ (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, -1)));
}
/*
@@ -30179,8 +34432,7 @@ DUK_LOCAL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *str) {
DUK_LOCAL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx) {
duk_hstring *h;
- DUK_ASSERT_DISABLE(stridx >= 0); /* unsigned */
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
+ DUK_ASSERT_STRIDX_VALID(stridx);
h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx);
DUK_ASSERT(h != NULL);
@@ -30211,9 +34463,9 @@ DUK_LOCAL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uin
* (nybble_count << 16) | (escape_char1) | (escape_char2)
*/
-#ifdef DUK_USE_JX
+#if defined(DUK_USE_JX)
if (DUK_LIKELY(cp < 0x100UL)) {
- if (DUK_UNLIKELY(js_ctx->flag_ext_custom)) {
+ if (DUK_UNLIKELY(js_ctx->flag_ext_custom != 0U)) {
tmp = DUK__MKESC(2, DUK_ASC_BACKSLASH, DUK_ASC_LC_X);
} else {
tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U);
@@ -30223,8 +34475,8 @@ DUK_LOCAL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uin
if (DUK_LIKELY(cp < 0x10000UL)) {
tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U);
} else {
-#ifdef DUK_USE_JX
- if (DUK_LIKELY(js_ctx->flag_ext_custom)) {
+#if defined(DUK_USE_JX)
+ if (DUK_LIKELY(js_ctx->flag_ext_custom != 0U)) {
tmp = DUK__MKESC(8, DUK_ASC_BACKSLASH, DUK_ASC_UC_U);
} else
#endif
@@ -30417,7 +34669,7 @@ DUK_LOCAL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_st
p = p_tmp + 1;
}
-#ifdef DUK_USE_NONSTD_JSON_ESC_U2028_U2029
+#if defined(DUK_USE_NONSTD_JSON_ESC_U2028_U2029)
if (js_ctx->flag_ascii_only || cp == 0x2028 || cp == 0x2029) {
#else
if (js_ctx->flag_ascii_only) {
@@ -30441,7 +34693,6 @@ DUK_LOCAL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_st
*/
DUK_LOCAL void duk__enc_double(duk_json_enc_ctx *js_ctx) {
duk_hthread *thr;
- duk_context *ctx;
duk_tval *tv;
duk_double_t d;
duk_small_int_t c;
@@ -30453,10 +34704,9 @@ DUK_LOCAL void duk__enc_double(duk_json_enc_ctx *js_ctx) {
DUK_ASSERT(js_ctx != NULL);
thr = js_ctx->thr;
DUK_ASSERT(thr != NULL);
- ctx = (duk_context *) thr;
/* Caller must ensure 'tv' is indeed a double and not a fastint! */
- tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv = DUK_GET_TVAL_NEGIDX(thr, -1);
DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
d = DUK_TVAL_GET_DOUBLE(tv);
@@ -30473,16 +34723,15 @@ DUK_LOCAL void duk__enc_double(duk_json_enc_ctx *js_ctx) {
*/
if (DUK_UNLIKELY(c == DUK_FP_ZERO && s != 0 &&
(js_ctx->flag_ext_custom_or_compatible))) {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_MINUS_ZERO); /* '-0' */
+ duk_push_hstring_stridx(thr, DUK_STRIDX_MINUS_ZERO); /* '-0' */
} else
#endif /* DUK_USE_JX || DUK_USE_JC */
{
n2s_flags = 0;
/* [ ... number ] -> [ ... string ] */
- duk_numconv_stringify(ctx, 10 /*radix*/, 0 /*digits*/, n2s_flags);
+ duk_numconv_stringify(thr, 10 /*radix*/, 0 /*digits*/, n2s_flags);
}
- h_str = duk_to_hstring(ctx, -1);
- DUK_ASSERT(h_str != NULL);
+ h_str = duk_known_hstring(thr, -1);
DUK__EMIT_HSTR(js_ctx, h_str);
return;
}
@@ -30624,8 +34873,8 @@ DUK_LOCAL void duk__enc_buffer_data(duk_json_enc_ctx *js_ctx, duk_uint8_t *buf_d
* variants is to be as useful to a programmer as possible.
*/
- /* The #ifdef clutter here needs to handle the three cases:
- * (1) JX+JC, (2) JX only, (3) JC only.
+ /* The #if defined() clutter here needs to handle the three
+ * cases: (1) JX+JC, (2) JX only, (3) JC only.
*/
/* Note: space must cater for both JX and JC. */
@@ -30662,13 +34911,60 @@ DUK_LOCAL void duk__enc_buffer_data(duk_json_enc_ctx *js_ctx, duk_uint8_t *buf_d
DUK_BW_SET_PTR(thr, &js_ctx->bw, q);
}
-DUK_LOCAL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) {
+DUK_LOCAL void duk__enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) {
duk__enc_buffer_data(js_ctx,
(duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h),
(duk_size_t) DUK_HBUFFER_GET_SIZE(h));
}
#endif /* DUK_USE_JX || DUK_USE_JC */
+#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
+DUK_LOCAL void duk__enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) {
+ duk_size_t i, n;
+ const duk_uint8_t *buf;
+ duk_uint8_t *q;
+
+ n = DUK_HBUFFER_GET_SIZE(h);
+ if (n == 0) {
+ DUK__EMIT_2(js_ctx, DUK_ASC_LCURLY, DUK_ASC_RCURLY);
+ return;
+ }
+
+ DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY);
+
+ /* Maximum encoded length with 32-bit index: 1 + 10 + 2 + 3 + 1 + 1 = 18,
+ * with 64-bit index: 1 + 20 + 2 + 3 + 1 + 1 = 28. 32 has some slack.
+ *
+ * Note that because the output buffer is reallocated from time to time,
+ * side effects (such as finalizers) affecting the buffer 'h' must be
+ * disabled. This is the case in the JSON.stringify() fast path.
+ */
+
+ buf = (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h);
+ if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
+ for (i = 0; i < n; i++) {
+ duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth + 1);
+ q = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, 32);
+ q += DUK_SPRINTF((char *) q, "\"%lu\": %u,", (unsigned long) i, (unsigned int) buf[i]);
+ DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, q);
+ }
+ } else {
+ q = DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw);
+ for (i = 0; i < n; i++) {
+ q = DUK_BW_ENSURE_RAW(js_ctx->thr, &js_ctx->bw, 32, q);
+ q += DUK_SPRINTF((char *) q, "\"%lu\":%u,", (unsigned long) i, (unsigned int) buf[i]);
+ }
+ DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, q);
+ }
+ DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
+
+ if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
+ duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
+ }
+ DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
+}
+#endif /* DUK_USE_JSON_STRINGIFY_FASTPATH */
+
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) {
char buf[64]; /* XXX: how to figure correct size? */
@@ -30679,8 +34975,8 @@ DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) {
DUK_MEMZERO(buf, sizeof(buf));
- /* The #ifdef clutter here needs to handle the three cases:
- * (1) JX+JC, (2) JX only, (3) JC only.
+ /* The #if defined() clutter here needs to handle the three
+ * cases: (1) JX+JC, (2) JX only, (3) JC only.
*/
#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
if (js_ctx->flag_ext_custom)
@@ -30706,26 +35002,28 @@ DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) {
}
#endif /* DUK_USE_JX || DUK_USE_JC */
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
-DUK_LOCAL void duk__enc_bufferobject(duk_json_enc_ctx *js_ctx, duk_hbufferobject *h_bufobj) {
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
+DUK_LOCAL void duk__enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj) {
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
- if (h_bufobj->buf == NULL || !DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)) {
+ if (h_bufobj->buf == NULL || !DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) {
DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
} else {
/* Handle both full and partial slice (as long as covered). */
duk__enc_buffer_data(js_ctx,
- (duk_uint8_t *) DUK_HBUFFEROBJECT_GET_SLICE_BASE(js_ctx->thr->heap, h_bufobj),
+ (duk_uint8_t *) DUK_HBUFOBJ_GET_SLICE_BASE(js_ctx->thr->heap, h_bufobj),
(duk_size_t) h_bufobj->length);
}
}
#endif /* DUK_USE_JX || DUK_USE_JC */
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/* Indent helper. Calling code relies on js_ctx->recursion_depth also being
* directly related to indent depth.
*/
#if defined(DUK_USE_PREFER_SIZE)
-DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth) {
+DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth) {
DUK_ASSERT(js_ctx->h_gap != NULL);
DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */
@@ -30735,7 +35033,7 @@ DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth
}
}
#else /* DUK_USE_PREFER_SIZE */
-DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth) {
+DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth) {
const duk_uint8_t *gap_data;
duk_size_t gap_len;
duk_size_t avail_bytes; /* bytes of indent available for copying */
@@ -30789,20 +35087,19 @@ DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth
/* Shared entry handling for object/array serialization. */
DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_hobject *h_target;
duk_uint_fast32_t i, n;
- *entry_top = duk_get_top(ctx);
+ *entry_top = duk_get_top(thr);
- duk_require_stack(ctx, DUK_JSON_ENC_REQSTACK);
+ duk_require_stack(thr, DUK_JSON_ENC_REQSTACK);
/* Loop check using a hybrid approach: a fixed-size visited[] array
* with overflow in a loop check object.
*/
- h_target = duk_get_hobject(ctx, -1); /* object or array */
- DUK_ASSERT(h_target != NULL);
+ h_target = duk_known_hobject(thr, -1); /* object or array */
n = js_ctx->recursion_depth;
if (DUK_UNLIKELY(n > DUK_JSON_ENC_LOOPARRAY)) {
@@ -30811,37 +35108,37 @@ DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_
for (i = 0; i < n; i++) {
if (DUK_UNLIKELY(js_ctx->visiting[i] == h_target)) {
DUK_DD(DUK_DDPRINT("slow path loop detect"));
- DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CYCLIC_INPUT);
+ DUK_ERROR_TYPE(thr, DUK_STR_CYCLIC_INPUT);
}
}
if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) {
js_ctx->visiting[js_ctx->recursion_depth] = h_target;
} else {
- duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target);
- duk_dup_top(ctx); /* -> [ ... voidp voidp ] */
- if (duk_has_prop(ctx, js_ctx->idx_loop)) {
- DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CYCLIC_INPUT);
+ duk_push_sprintf(thr, DUK_STR_FMT_PTR, (void *) h_target);
+ duk_dup_top(thr); /* -> [ ... voidp voidp ] */
+ if (duk_has_prop(thr, js_ctx->idx_loop)) {
+ DUK_ERROR_TYPE(thr, DUK_STR_CYCLIC_INPUT);
}
- duk_push_true(ctx); /* -> [ ... voidp true ] */
- duk_put_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */
+ duk_push_true(thr); /* -> [ ... voidp true ] */
+ duk_put_prop(thr, js_ctx->idx_loop); /* -> [ ... ] */
}
/* C recursion check. */
- DUK_ASSERT(js_ctx->recursion_depth >= 0);
+ DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0); /* unsigned */
DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
- DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_JSONENC_RECLIMIT);
+ DUK_ERROR_RANGE(thr, DUK_STR_JSONENC_RECLIMIT);
}
js_ctx->recursion_depth++;
DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T",
- (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop)));
+ (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop)));
}
/* Shared exit handling for object/array serialization. */
DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_hobject *h_target;
/* C recursion check. */
@@ -30852,21 +35149,20 @@ DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_t
/* Loop check. */
- h_target = duk_get_hobject(ctx, *entry_top - 1); /* original target at entry_top - 1 */
- DUK_ASSERT(h_target != NULL);
+ h_target = duk_known_hobject(thr, *entry_top - 1); /* original target at entry_top - 1 */
if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) {
/* Previous entry was inside visited[], nothing to do. */
} else {
- duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target);
- duk_del_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */
+ duk_push_sprintf(thr, DUK_STR_FMT_PTR, (void *) h_target);
+ duk_del_prop(thr, js_ctx->idx_loop); /* -> [ ... ] */
}
/* Restore stack top after unbalanced code paths. */
- duk_set_top(ctx, *entry_top);
+ duk_set_top(thr, *entry_top);
DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T",
- (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop)));
+ (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop)));
}
/* The JO(value) operation: encode object.
@@ -30874,7 +35170,7 @@ DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_t
* Stack policy: [ object ] -> [ object ].
*/
DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_hstring *h_key;
duk_idx_t entry_top;
duk_idx_t idx_obj;
@@ -30883,7 +35179,7 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
duk_uarridx_t arr_len, i;
duk_size_t prev_size;
- DUK_DDD(DUK_DDDPRINT("duk__enc_object: obj=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("duk__enc_object: obj=%!T", (duk_tval *) duk_get_tval(thr, -1)));
duk__enc_objarr_entry(js_ctx, &entry_top);
@@ -30893,14 +35189,14 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
idx_keys = js_ctx->idx_proplist;
} else {
/* XXX: would be nice to enumerate an object at specified index */
- duk_dup(ctx, idx_obj);
- (void) duk_hobject_get_enumerated_keys(ctx, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/); /* [ ... target ] -> [ ... target keys ] */
- idx_keys = duk_require_normalize_index(ctx, -1);
+ duk_dup(thr, idx_obj);
+ (void) duk_hobject_get_enumerated_keys(thr, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/); /* [ ... target ] -> [ ... target keys ] */
+ idx_keys = duk_require_normalize_index(thr, -1);
/* leave stack unbalanced on purpose */
}
DUK_DDD(DUK_DDDPRINT("idx_keys=%ld, h_keys=%!T",
- (long) idx_keys, (duk_tval *) duk_get_tval(ctx, idx_keys)));
+ (long) idx_keys, (duk_tval *) duk_get_tval(thr, idx_keys)));
/* Steps 8-10 have been merged to avoid a "partial" variable. */
@@ -30912,17 +35208,18 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
* that it can be reallocated).
*/
- arr_len = (duk_uarridx_t) duk_get_length(ctx, idx_keys);
+ arr_len = (duk_uarridx_t) duk_get_length(thr, idx_keys);
emitted = 0;
for (i = 0; i < arr_len; i++) {
- duk_get_prop_index(ctx, idx_keys, i); /* -> [ ... key ] */
+ duk_get_prop_index(thr, idx_keys, i); /* -> [ ... key ] */
DUK_DDD(DUK_DDDPRINT("object property loop: holder=%!T, key=%!T",
- (duk_tval *) duk_get_tval(ctx, idx_obj),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, idx_obj),
+ (duk_tval *) duk_get_tval(thr, -1)));
- h_key = duk_get_hstring(ctx, -1);
+ h_key = duk_known_hstring(thr, -1);
DUK_ASSERT(h_key != NULL);
+ DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(h_key)); /* proplist filtering; enum options */
prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw);
if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
@@ -30954,14 +35251,14 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
DUK_ASSERT(js_ctx->recursion_depth >= 1);
- duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
+ duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
}
}
DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
duk__enc_objarr_exit(js_ctx, &entry_top);
- DUK_ASSERT_TOP(ctx, entry_top);
+ DUK_ASSERT_TOP(thr, entry_top);
}
/* The JA(value) operation: encode array.
@@ -30969,14 +35266,14 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
* Stack policy: [ array ] -> [ array ].
*/
DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_idx_t entry_top;
duk_idx_t idx_arr;
duk_bool_t emitted;
duk_uarridx_t i, arr_len;
DUK_DDD(DUK_DDDPRINT("duk__enc_array: array=%!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
duk__enc_objarr_entry(js_ctx, &entry_top);
@@ -30986,11 +35283,11 @@ DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
DUK__EMIT_1(js_ctx, DUK_ASC_LBRACKET);
- arr_len = (duk_uarridx_t) duk_get_length(ctx, idx_arr);
+ arr_len = (duk_uarridx_t) duk_get_length(thr, idx_arr);
emitted = 0;
for (i = 0; i < arr_len; i++) {
DUK_DDD(DUK_DDDPRINT("array entry loop: array=%!T, index=%ld, arr_len=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_arr),
+ (duk_tval *) duk_get_tval(thr, idx_arr),
(long) i, (long) arr_len));
if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
@@ -30998,9 +35295,7 @@ DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
}
- /* XXX: duk_push_uint_string() */
- duk_push_uint(ctx, (duk_uint_t) i);
- duk_to_string(ctx, -1); /* -> [ ... key ] */
+ (void) duk_push_uint_to_hstring(thr, (duk_uint_t) i); /* -> [ ... key ] */
/* [ ... key ] */
@@ -31022,14 +35317,14 @@ DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
DUK_ASSERT(js_ctx->recursion_depth >= 1);
- duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
+ duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
}
}
DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET);
duk__enc_objarr_exit(js_ctx, &entry_top);
- DUK_ASSERT_TOP(ctx, entry_top);
+ DUK_ASSERT_TOP(thr, entry_top);
}
/* The Str(key, holder) operation.
@@ -31037,165 +35332,157 @@ DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
* Stack policy: [ ... key ] -> [ ... ]
*/
DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h_tmp;
+ duk_hthread *thr = js_ctx->thr;
duk_tval *tv;
duk_tval *tv_holder;
duk_tval *tv_key;
duk_small_int_t c;
DUK_DDD(DUK_DDDPRINT("duk__enc_value: idx_holder=%ld, holder=%!T, key=%!T",
- (long) idx_holder, (duk_tval *) duk_get_tval(ctx, idx_holder),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (long) idx_holder, (duk_tval *) duk_get_tval(thr, idx_holder),
+ (duk_tval *) duk_get_tval(thr, -1)));
- DUK_UNREF(thr);
-
- tv_holder = DUK_GET_TVAL_POSIDX(ctx, idx_holder);
+ tv_holder = DUK_GET_TVAL_POSIDX(thr, idx_holder);
DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_holder));
- tv_key = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv_key = DUK_GET_TVAL_NEGIDX(thr, -1);
DUK_ASSERT(DUK_TVAL_IS_STRING(tv_key));
+ DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(DUK_TVAL_GET_STRING(tv_key))); /* Caller responsible. */
(void) duk_hobject_getprop(thr, tv_holder, tv_key);
/* -> [ ... key val ] */
- DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1)));
- h_tmp = duk_get_hobject_or_lfunc_coerce(ctx, -1);
- if (h_tmp != NULL) {
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_JSON);
- h_tmp = duk_get_hobject_or_lfunc_coerce(ctx, -1); /* toJSON() can also be a lightfunc */
-
- if (h_tmp != NULL && DUK_HOBJECT_IS_CALLABLE(h_tmp)) {
+ /* Standard JSON checks for .toJSON() only for actual objects; for
+ * example, setting Number.prototype.toJSON and then serializing a
+ * number won't invoke the .toJSON() method. However, lightfuncs and
+ * plain buffers mimic objects so we check for their .toJSON() method.
+ */
+ if (duk_check_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT |
+ DUK_TYPE_MASK_LIGHTFUNC |
+ DUK_TYPE_MASK_BUFFER)) {
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_TO_JSON);
+ if (duk_is_callable(thr, -1)) { /* toJSON() can also be a lightfunc */
DUK_DDD(DUK_DDDPRINT("value is object, has callable toJSON() -> call it"));
- /* XXX: duk_dup_unvalidated(ctx, -2) etc. */
- duk_dup(ctx, -2); /* -> [ ... key val toJSON val ] */
- duk_dup(ctx, -4); /* -> [ ... key val toJSON val key ] */
- duk_call_method(ctx, 1); /* -> [ ... key val val' ] */
- duk_remove(ctx, -2); /* -> [ ... key val' ] */
+ /* XXX: duk_dup_unvalidated(thr, -2) etc. */
+ duk_dup_m2(thr); /* -> [ ... key val toJSON val ] */
+ duk_dup_m4(thr); /* -> [ ... key val toJSON val key ] */
+ duk_call_method(thr, 1); /* -> [ ... key val val' ] */
+ duk_remove_m2(thr); /* -> [ ... key val' ] */
} else {
- duk_pop(ctx); /* -> [ ... key val ] */
+ duk_pop(thr); /* -> [ ... key val ] */
}
}
/* [ ... key val ] */
- DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1)));
if (js_ctx->h_replacer) {
/* XXX: Here a "slice copy" would be useful. */
DUK_DDD(DUK_DDDPRINT("replacer is set, call replacer"));
- duk_push_hobject(ctx, js_ctx->h_replacer); /* -> [ ... key val replacer ] */
- duk_dup(ctx, idx_holder); /* -> [ ... key val replacer holder ] */
- duk_dup(ctx, -4); /* -> [ ... key val replacer holder key ] */
- duk_dup(ctx, -4); /* -> [ ... key val replacer holder key val ] */
- duk_call_method(ctx, 2); /* -> [ ... key val val' ] */
- duk_remove(ctx, -2); /* -> [ ... key val' ] */
+ duk_push_hobject(thr, js_ctx->h_replacer); /* -> [ ... key val replacer ] */
+ duk_dup(thr, idx_holder); /* -> [ ... key val replacer holder ] */
+ duk_dup_m4(thr); /* -> [ ... key val replacer holder key ] */
+ duk_dup_m4(thr); /* -> [ ... key val replacer holder key val ] */
+ duk_call_method(thr, 2); /* -> [ ... key val val' ] */
+ duk_remove_m2(thr); /* -> [ ... key val' ] */
}
/* [ ... key val ] */
- DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1)));
- tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv = DUK_GET_TVAL_NEGIDX(thr, -1);
if (DUK_TVAL_IS_OBJECT(tv)) {
duk_hobject *h;
h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
- if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- duk_hbufferobject *h_bufobj;
- h_bufobj = (duk_hbufferobject *) h;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
-
- /* Conceptually we'd extract the plain underlying buffer
- * or its slice and then do a type mask check below to
- * see if we should reject it. Do the mask check here
- * instead to avoid making a copy of the buffer slice.
- */
-
- if (js_ctx->mask_for_undefined & DUK_TYPE_MASK_BUFFER) {
- DUK_DDD(DUK_DDDPRINT("-> bufferobject (-> plain buffer) will result in undefined (type mask check)"));
- goto pop2_undef;
- }
- DUK_DDD(DUK_DDDPRINT("-> bufferobject won't result in undefined, encode directly"));
- duk__enc_bufferobject(js_ctx, h_bufobj);
+ if (DUK_HOBJECT_IS_BUFOBJ(h) &&
+ js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE)) {
+ /* With JX/JC a bufferobject gets serialized specially. */
+ duk_hbufobj *h_bufobj;
+ h_bufobj = (duk_hbufobj *) h;
+ DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
+ duk__enc_bufobj(js_ctx, h_bufobj);
goto pop2_emitted;
-#else
- DUK_DDD(DUK_DDDPRINT("no JX/JC support, bufferobject/buffer will always result in undefined"));
- goto pop2_undef;
-#endif
- } else {
- c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h);
- switch ((int) c) {
- case DUK_HOBJECT_CLASS_NUMBER: {
- DUK_DDD(DUK_DDDPRINT("value is a Number object -> coerce with ToNumber()"));
- duk_to_number(ctx, -1);
- /* The coercion potentially invokes user .valueOf() and .toString()
- * but can't result in a function value because [[DefaultValue]] would
- * reject such a result: test-dev-json-stringify-coercion-1.js.
- */
- DUK_ASSERT(!duk_is_callable(ctx, -1));
- break;
- }
- case DUK_HOBJECT_CLASS_STRING: {
- DUK_DDD(DUK_DDDPRINT("value is a String object -> coerce with ToString()"));
- duk_to_string(ctx, -1);
- /* Same coercion behavior as for Number. */
- DUK_ASSERT(!duk_is_callable(ctx, -1));
- break;
- }
+ }
+ /* Otherwise bufferobjects get serialized as normal objects. */
+#endif /* JX || JC */
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
+ c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h);
+ switch (c) {
+ case DUK_HOBJECT_CLASS_NUMBER: {
+ DUK_DDD(DUK_DDDPRINT("value is a Number object -> coerce with ToNumber()"));
+ duk_to_number_m1(thr);
+ /* The coercion potentially invokes user .valueOf() and .toString()
+ * but can't result in a function value because ToPrimitive() would
+ * reject such a result: test-dev-json-stringify-coercion-1.js.
+ */
+ DUK_ASSERT(!duk_is_callable(thr, -1));
+ break;
+ }
+ case DUK_HOBJECT_CLASS_STRING: {
+ DUK_DDD(DUK_DDDPRINT("value is a String object -> coerce with ToString()"));
+ duk_to_string(thr, -1);
+ /* Same coercion behavior as for Number. */
+ DUK_ASSERT(!duk_is_callable(thr, -1));
+ break;
+ }
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- case DUK_HOBJECT_CLASS_POINTER:
+ case DUK_HOBJECT_CLASS_POINTER:
#endif
- case DUK_HOBJECT_CLASS_BOOLEAN: {
- DUK_DDD(DUK_DDDPRINT("value is a Boolean/Buffer/Pointer object -> get internal value"));
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
- duk_remove(ctx, -2);
- break;
- }
- default: {
- /* Normal object which doesn't get automatically coerced to a
- * primitive value. Functions are checked for specially. The
- * primitive value coercions for Number, String, Pointer, and
- * Boolean can't result in functions so suffices to check here.
- */
- DUK_ASSERT(h != NULL);
- if (DUK_HOBJECT_IS_CALLABLE(h)) {
+ case DUK_HOBJECT_CLASS_BOOLEAN: {
+ DUK_DDD(DUK_DDDPRINT("value is a Boolean/Buffer/Pointer object -> get internal value"));
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
+ duk_remove_m2(thr);
+ break;
+ }
+ default: {
+ /* Normal object which doesn't get automatically coerced to a
+ * primitive value. Functions are checked for specially. The
+ * primitive value coercions for Number, String, Pointer, and
+ * Boolean can't result in functions so suffices to check here.
+ * Symbol objects are handled like plain objects (their primitive
+ * value is NOT looked up like for e.g. String objects).
+ */
+ DUK_ASSERT(h != NULL);
+ if (DUK_HOBJECT_IS_CALLABLE(h)) {
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
- DUK_JSON_FLAG_EXT_COMPATIBLE)) {
- /* We only get here when doing non-standard JSON encoding */
- DUK_DDD(DUK_DDDPRINT("-> function allowed, serialize to custom format"));
- DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible);
- DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
- goto pop2_emitted;
- } else {
- DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)"));
- goto pop2_undef;
- }
-#else /* DUK_USE_JX || DUK_USE_JC */
+ if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
+ DUK_JSON_FLAG_EXT_COMPATIBLE)) {
+ /* We only get here when doing non-standard JSON encoding */
+ DUK_DDD(DUK_DDDPRINT("-> function allowed, serialize to custom format"));
+ DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible);
+ DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
+ goto pop2_emitted;
+ } else {
DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)"));
goto pop2_undef;
-#endif /* DUK_USE_JX || DUK_USE_JC */
}
+#else /* DUK_USE_JX || DUK_USE_JC */
+ DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)"));
+ goto pop2_undef;
+#endif /* DUK_USE_JX || DUK_USE_JC */
}
- } /* end switch */
}
+ } /* end switch */
}
/* [ ... key val ] */
- DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1)));
- if (duk_check_type_mask(ctx, -1, js_ctx->mask_for_undefined)) {
+ if (duk_check_type_mask(thr, -1, js_ctx->mask_for_undefined)) {
/* will result in undefined */
DUK_DDD(DUK_DDDPRINT("-> will result in undefined (type mask check)"));
goto pop2_undef;
}
- tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv = DUK_GET_TVAL_NEGIDX(thr, -1);
switch (DUK_TVAL_GET_TAG(tv)) {
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
@@ -31224,7 +35511,9 @@ DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_hold
case DUK_TAG_STRING: {
duk_hstring *h = DUK_TVAL_GET_STRING(tv);
DUK_ASSERT(h != NULL);
-
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
+ goto pop2_undef;
+ }
duk__enc_quote_string(js_ctx, h);
break;
}
@@ -31244,13 +35533,27 @@ DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_hold
}
break;
}
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- /* When JX/JC not in use, the type mask above will avoid this case if needed. */
+ /* Because plain buffers mimics Uint8Array, they have enumerable
+ * index properties [0,byteLength[. Because JSON only serializes
+ * enumerable own properties, no properties can be serialized for
+ * plain buffers (all virtual properties are non-enumerable). However,
+ * there may be a .toJSON() method which was already handled above.
+ */
case DUK_TAG_BUFFER: {
- duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv));
+#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
+ if (js_ctx->flag_ext_custom_or_compatible) {
+ duk__enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv));
+ break;
+ }
+#endif
+
+ /* Could implement a fastpath, but the fast path would need
+ * to handle realloc side effects correctly.
+ */
+ duk_to_object(thr, -1);
+ duk__enc_object(js_ctx);
break;
}
-#endif /* DUK_USE_JX || DUK_USE_JC */
case DUK_TAG_LIGHTFUNC: {
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
/* We only get here when doing non-standard JSON encoding */
@@ -31282,24 +35585,37 @@ DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_hold
}
}
+#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
pop2_emitted:
- duk_pop_2(ctx); /* [ ... key val ] -> [ ... ] */
+#endif
+ duk_pop_2(thr); /* [ ... key val ] -> [ ... ] */
return 1; /* emitted */
pop2_undef:
- duk_pop_2(ctx); /* [ ... key val ] -> [ ... ] */
+ duk_pop_2(thr); /* [ ... key val ] -> [ ... ] */
return 0; /* not emitted */
}
/* E5 Section 15.12.3, main algorithm, step 4.b.ii steps 1-4. */
DUK_LOCAL duk_bool_t duk__enc_allow_into_proplist(duk_tval *tv) {
- duk_hobject *h;
duk_small_int_t c;
+ /* XXX: some kind of external internal type checker?
+ * - type mask; symbol flag; class mask
+ */
DUK_ASSERT(tv != NULL);
- if (DUK_TVAL_IS_STRING(tv) || DUK_TVAL_IS_NUMBER(tv)) {
+ if (DUK_TVAL_IS_STRING(tv)) {
+ duk_hstring *h;
+ h = DUK_TVAL_GET_STRING(tv);
+ DUK_ASSERT(h != NULL);
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
+ return 0;
+ }
+ return 1;
+ } else if (DUK_TVAL_IS_NUMBER(tv)) {
return 1;
} else if (DUK_TVAL_IS_OBJECT(tv)) {
+ duk_hobject *h;
h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h);
@@ -31359,9 +35675,11 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
}
case DUK_TAG_STRING: {
duk_hstring *h;
-
h = DUK_TVAL_GET_STRING(tv);
DUK_ASSERT(h != NULL);
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
+ goto emit_undefined;
+ }
duk__enc_quote_string(js_ctx, h);
break;
}
@@ -31370,7 +35688,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
duk_tval *tv_val;
duk_bool_t emitted = 0;
duk_uint32_t c_bit, c_all, c_array, c_unbox, c_undef,
- c_func, c_bufobj, c_object;
+ c_func, c_bufobj, c_object, c_abort;
/* For objects JSON.stringify() only looks for own, enumerable
* properties which is nice for the fast path here.
@@ -31403,7 +35721,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
* it (though it's OK to abort the fast path).
*/
- DUK_ASSERT(js_ctx->recursion_depth >= 0);
+ DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0); /* unsigned */
DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
DUK_DD(DUK_DDPRINT("fast path recursion limit"));
@@ -31435,7 +35753,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
* but does at the moment, probably not worth fixing.
*/
if (duk_hobject_hasprop_raw(js_ctx->thr, obj, DUK_HTHREAD_STRING_TO_JSON(js_ctx->thr)) ||
- DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj)) {
+ DUK_HOBJECT_IS_PROXY(obj)) {
DUK_DD(DUK_DDPRINT("object has a .toJSON property or object is a Proxy, abort fast path"));
goto abort_fastpath;
}
@@ -31456,11 +35774,12 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
c_unbox = DUK_HOBJECT_CMASK_NUMBER |
DUK_HOBJECT_CMASK_STRING |
DUK_HOBJECT_CMASK_BOOLEAN |
- DUK_HOBJECT_CMASK_POINTER;
+ DUK_HOBJECT_CMASK_POINTER; /* Symbols are not unboxed. */
c_func = DUK_HOBJECT_CMASK_FUNCTION;
- c_bufobj = DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS;
+ c_bufobj = DUK_HOBJECT_CMASK_ALL_BUFOBJS;
c_undef = 0;
- c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef);
+ c_abort = 0;
+ c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef | c_abort);
}
else
#endif
@@ -31469,16 +35788,20 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
c_array = DUK_HOBJECT_CMASK_ARRAY;
c_unbox = DUK_HOBJECT_CMASK_NUMBER |
DUK_HOBJECT_CMASK_STRING |
- DUK_HOBJECT_CMASK_BOOLEAN;
+ DUK_HOBJECT_CMASK_BOOLEAN; /* Symbols are not unboxed. */
c_func = 0;
c_bufobj = 0;
c_undef = DUK_HOBJECT_CMASK_FUNCTION |
- DUK_HOBJECT_CMASK_POINTER |
- DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS;
- c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef);
+ DUK_HOBJECT_CMASK_POINTER;
+ /* As the fast path doesn't currently properly support
+ * duk_hbufobj virtual properties, abort fast path if
+ * we encounter them in plain JSON mode.
+ */
+ c_abort = DUK_HOBJECT_CMASK_ALL_BUFOBJS;
+ c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef | c_abort);
}
- c_bit = DUK_HOBJECT_GET_CLASS_MASK(obj);
+ c_bit = (duk_uint32_t) DUK_HOBJECT_GET_CLASS_MASK(obj);
if (c_bit & c_object) {
/* All other object types. */
DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY);
@@ -31500,6 +35823,15 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
if (!k) {
continue;
}
+ if (DUK_HSTRING_HAS_ARRIDX(k)) {
+ /* If an object has array index keys we would need
+ * to sort them into the ES2015 enumeration order to
+ * be consistent with the slow path. Abort the fast
+ * path and handle in the slow path for now.
+ */
+ DUK_DD(DUK_DDPRINT("property key is an array index, abort fast path"));
+ goto abort_fastpath;
+ }
if (!DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(js_ctx->thr->heap, obj, i)) {
continue;
}
@@ -31510,7 +35842,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
DUK_DD(DUK_DDPRINT("property is an accessor, abort fast path"));
goto abort_fastpath;
}
- if (DUK_HSTRING_HAS_INTERNAL(k)) {
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(k))) {
continue;
}
@@ -31536,8 +35868,8 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
}
/* If any non-Array value had enumerable virtual own
- * properties, they should be serialized here. Standard
- * types don't.
+ * properties, they should be serialized here (actually,
+ * before the explicit properties). Standard types don't.
*/
if (emitted) {
@@ -31545,7 +35877,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
DUK_ASSERT(js_ctx->recursion_depth >= 1);
- duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
+ duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
}
}
DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
@@ -31561,62 +35893,58 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
goto abort_fastpath;
}
- arr_len = (duk_uint_fast32_t) duk_hobject_get_length(js_ctx->thr, obj);
+ arr_len = (duk_uint_fast32_t) ((duk_harray *) obj)->length;
asize = (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(obj);
- if (arr_len > asize) {
- /* Array length is larger than 'asize'. This shouldn't
- * happen in practice. Bail out just in case.
- */
- DUK_DD(DUK_DDPRINT("arr_len > asize, abort fast path"));
- goto abort_fastpath;
- }
/* Array part may be larger than 'length'; if so, iterate
- * only up to array 'length'.
+ * only up to array 'length'. Array part may also be smaller
+ * than 'length' in some cases.
*/
for (i = 0; i < arr_len; i++) {
- DUK_ASSERT(i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(obj));
-
- tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(js_ctx->thr->heap, obj, i);
+ duk_tval *tv_arrval;
+ duk_hstring *h_tmp;
+ duk_bool_t has_inherited;
if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
}
- if (DUK_UNLIKELY(DUK_TVAL_IS_UNUSED(tv_val))) {
- /* Gap in array; check for inherited property,
- * bail out if one exists. This should be enough
- * to support gappy arrays for all practical code.
- */
- duk_hstring *h_tmp;
- duk_bool_t has_inherited;
-
- /* XXX: refactor into an internal helper, pretty awkward */
- duk_push_uint((duk_context *) js_ctx->thr, (duk_uint_t) i);
- h_tmp = duk_to_hstring((duk_context *) js_ctx->thr, -1);
- DUK_ASSERT(h_tmp != NULL);
- has_inherited = duk_hobject_hasprop_raw(js_ctx->thr, obj, h_tmp);
- duk_pop((duk_context *) js_ctx->thr);
-
- if (has_inherited) {
- DUK_D(DUK_DPRINT("gap in array, conflicting inherited property, abort fast path"));
- goto abort_fastpath;
- }
-
- /* Ordinary gap, undefined encodes to 'null' in
- * standard JSON (and no JX/JC support here now).
- */
- DUK_D(DUK_DPRINT("gap in array, no conflicting inherited property, remain on fast path"));
-#if defined(DUK_USE_JX)
- DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
-#else
- DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
-#endif
- } else {
- if (duk__json_stringify_fast_value(js_ctx, tv_val) == 0) {
- DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
+ if (DUK_LIKELY(i < asize)) {
+ tv_arrval = DUK_HOBJECT_A_GET_VALUE_PTR(js_ctx->thr->heap, obj, i);
+ if (DUK_LIKELY(!DUK_TVAL_IS_UNUSED(tv_arrval))) {
+ /* Expected case: element is present. */
+ if (duk__json_stringify_fast_value(js_ctx, tv_arrval) == 0) {
+ DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
+ }
+ goto elem_done;
}
}
+ /* Gap in array; check for inherited property,
+ * bail out if one exists. This should be enough
+ * to support gappy arrays for all practical code.
+ */
+
+ h_tmp = duk_push_uint_to_hstring(js_ctx->thr, (duk_uint_t) i);
+ has_inherited = duk_hobject_hasprop_raw(js_ctx->thr, obj, h_tmp);
+ duk_pop(js_ctx->thr);
+ if (has_inherited) {
+ DUK_D(DUK_DPRINT("gap in array, conflicting inherited property, abort fast path"));
+ goto abort_fastpath;
+ }
+
+ /* Ordinary gap, undefined encodes to 'null' in
+ * standard JSON, but JX/JC use their form for
+ * undefined to better preserve the typing.
+ */
+ DUK_D(DUK_DPRINT("gap in array, no conflicting inherited property, remain on fast path"));
+#if defined(DUK_USE_JX)
+ DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
+#else
+ DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
+#endif
+ /* fall through */
+
+ elem_done:
DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
emitted = 1;
}
@@ -31626,7 +35954,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
DUK_ASSERT(js_ctx->recursion_depth >= 1);
- duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
+ duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
}
}
DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET);
@@ -31635,6 +35963,8 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
* automatic unboxing. Rely on internal value being
* sane (to avoid infinite recursion).
*/
+ DUK_ASSERT((c_bit & DUK_HOBJECT_CMASK_SYMBOL) == 0); /* Symbols are not unboxed. */
+
#if 1
/* The code below is incorrect if .toString() or .valueOf() have
* have been overridden. The correct approach would be to look up
@@ -31664,9 +35994,14 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
} else if (c_bit & c_func) {
DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
} else if (c_bit & c_bufobj) {
- duk__enc_bufferobject(js_ctx, (duk_hbufferobject *) obj);
+ duk__enc_bufobj(js_ctx, (duk_hbufobj *) obj);
#endif
+#endif
+ } else if (c_bit & c_abort) {
+ DUK_DD(DUK_DDPRINT("abort fast path for unsupported type"));
+ goto abort_fastpath;
} else {
DUK_ASSERT((c_bit & c_undef) != 0);
@@ -31683,16 +36018,34 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
break;
}
case DUK_TAG_BUFFER: {
+ /* Plain buffers are treated like Uint8Arrays: they have
+ * enumerable indices. Other virtual properties are not
+ * enumerable, and inherited properties are not serialized.
+ * However, there can be a replacer (not relevant here) or
+ * a .toJSON() method (which we need to check for explicitly).
+ */
+
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+ if (duk_hobject_hasprop_raw(js_ctx->thr,
+ js_ctx->thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE],
+ DUK_HTHREAD_STRING_TO_JSON(js_ctx->thr))) {
+ DUK_DD(DUK_DDPRINT("value is a plain buffer and there's an inherited .toJSON, abort fast path"));
+ goto abort_fastpath;
+ }
+#endif
+
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
if (js_ctx->flag_ext_custom_or_compatible) {
- duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv));
+ duk__enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv));
break;
- } else {
- goto emit_undefined;
}
-#else
- goto emit_undefined;
#endif
+
+ /* Plain buffers mimic Uint8Arrays, and have enumerable index
+ * properties.
+ */
+ duk__enc_buffer_json_fastpath(js_ctx, DUK_TVAL_GET_BUFFER(tv));
+ break;
}
case DUK_TAG_POINTER: {
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
@@ -31731,9 +36084,9 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
/* XXX: Stack discipline is annoying, could be changed in numconv. */
- duk_push_tval((duk_context *) js_ctx->thr, tv);
+ duk_push_tval(js_ctx->thr, tv);
duk__enc_double(js_ctx);
- duk_pop((duk_context *) js_ctx->thr);
+ duk_pop(js_ctx->thr);
#if 0
/* Could also rely on native sprintf(), but it will handle
@@ -31758,24 +36111,24 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
abort_fastpath:
/* Error message doesn't matter: the error is ignored anyway. */
DUK_DD(DUK_DDPRINT("aborting fast path"));
- DUK_ERROR_INTERNAL_DEFMSG(js_ctx->thr);
+ DUK_ERROR_INTERNAL(js_ctx->thr);
return 0; /* unreachable */
}
-DUK_LOCAL duk_ret_t duk__json_stringify_fast(duk_context *ctx) {
+DUK_LOCAL duk_ret_t duk__json_stringify_fast(duk_hthread *thr, void *udata) {
duk_json_enc_ctx *js_ctx;
duk_tval *tv;
- DUK_ASSERT(ctx != NULL);
- tv = DUK_GET_TVAL_NEGIDX(ctx, -2);
- DUK_ASSERT(DUK_TVAL_IS_POINTER(tv));
- js_ctx = (duk_json_enc_ctx *) DUK_TVAL_GET_POINTER(tv);
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(udata != NULL);
+
+ js_ctx = (duk_json_enc_ctx *) udata;
DUK_ASSERT(js_ctx != NULL);
- tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv = DUK_GET_TVAL_NEGIDX(thr, -1);
if (duk__json_stringify_fast_value(js_ctx, tv) == 0) {
DUK_DD(DUK_DDPRINT("top level value not supported, fail fast path"));
- return DUK_RET_ERROR; /* error message doesn't matter, ignored anyway */
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr); /* Error message is ignored, so doesn't matter. */
}
return 0;
@@ -31787,16 +36140,15 @@ DUK_LOCAL duk_ret_t duk__json_stringify_fast(duk_context *ctx) {
*/
DUK_INTERNAL
-void duk_bi_json_parse_helper(duk_context *ctx,
+void duk_bi_json_parse_helper(duk_hthread *thr,
duk_idx_t idx_value,
duk_idx_t idx_reviver,
duk_small_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
duk_json_dec_ctx js_ctx_alloc;
duk_json_dec_ctx *js_ctx = &js_ctx_alloc;
duk_hstring *h_text;
-#ifdef DUK_USE_ASSERTIONS
- duk_idx_t entry_top = duk_get_top(ctx);
+#if defined(DUK_USE_ASSERTIONS)
+ duk_idx_t entry_top = duk_get_top(thr);
#endif
/* negative top-relative indices not allowed now */
@@ -31804,14 +36156,14 @@ void duk_bi_json_parse_helper(duk_context *ctx,
DUK_ASSERT(idx_reviver == DUK_INVALID_INDEX || idx_reviver >= 0);
DUK_DDD(DUK_DDDPRINT("JSON parse start: text=%!T, reviver=%!T, flags=0x%08lx, stack_top=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_value),
- (duk_tval *) duk_get_tval(ctx, idx_reviver),
+ (duk_tval *) duk_get_tval(thr, idx_value),
+ (duk_tval *) duk_get_tval(thr, idx_reviver),
(unsigned long) flags,
- (long) duk_get_top(ctx)));
+ (long) duk_get_top(thr)));
DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc));
js_ctx->thr = thr;
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
/* nothing now */
#endif
js_ctx->recursion_limit = DUK_USE_JSON_DEC_RECLIMIT;
@@ -31832,7 +36184,7 @@ void duk_bi_json_parse_helper(duk_context *ctx,
js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE);
#endif
- h_text = duk_to_hstring(ctx, idx_value); /* coerce in-place */
+ h_text = duk_to_hstring(thr, idx_value); /* coerce in-place; rejects Symbols */
DUK_ASSERT(h_text != NULL);
/* JSON parsing code is allowed to read [p_start,p_end]: p_end is
@@ -31855,47 +36207,46 @@ void duk_bi_json_parse_helper(duk_context *ctx,
duk__dec_syntax_error(js_ctx);
}
- if (duk_is_callable(ctx, idx_reviver)) {
+ if (duk_is_callable(thr, idx_reviver)) {
DUK_DDD(DUK_DDDPRINT("applying reviver: %!T",
- (duk_tval *) duk_get_tval(ctx, idx_reviver)));
+ (duk_tval *) duk_get_tval(thr, idx_reviver)));
js_ctx->idx_reviver = idx_reviver;
- duk_push_object(ctx);
- duk_dup(ctx, -2); /* -> [ ... val root val ] */
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_EMPTY_STRING); /* default attrs ok */
- duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING); /* -> [ ... val root "" ] */
+ duk_push_object(thr);
+ duk_dup_m2(thr); /* -> [ ... val root val ] */
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_EMPTY_STRING); /* default attrs ok */
+ duk_push_hstring_stridx(thr, DUK_STRIDX_EMPTY_STRING); /* -> [ ... val root "" ] */
DUK_DDD(DUK_DDDPRINT("start reviver walk, root=%!T, name=%!T",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
duk__dec_reviver_walk(js_ctx); /* [ ... val root "" ] -> [ ... val val' ] */
- duk_remove(ctx, -2); /* -> [ ... val' ] */
+ duk_remove_m2(thr); /* -> [ ... val' ] */
} else {
DUK_DDD(DUK_DDDPRINT("reviver does not exist or is not callable: %!T",
- (duk_tval *) duk_get_tval(ctx, idx_reviver)));
+ (duk_tval *) duk_get_tval(thr, idx_reviver)));
}
/* Final result is at stack top. */
DUK_DDD(DUK_DDDPRINT("JSON parse end: text=%!T, reviver=%!T, flags=0x%08lx, result=%!T, stack_top=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_value),
- (duk_tval *) duk_get_tval(ctx, idx_reviver),
+ (duk_tval *) duk_get_tval(thr, idx_value),
+ (duk_tval *) duk_get_tval(thr, idx_reviver),
(unsigned long) flags,
- (duk_tval *) duk_get_tval(ctx, -1),
- (long) duk_get_top(ctx)));
+ (duk_tval *) duk_get_tval(thr, -1),
+ (long) duk_get_top(thr)));
- DUK_ASSERT(duk_get_top(ctx) == entry_top + 1);
+ DUK_ASSERT(duk_get_top(thr) == entry_top + 1);
}
DUK_INTERNAL
-void duk_bi_json_stringify_helper(duk_context *ctx,
+void duk_bi_json_stringify_helper(duk_hthread *thr,
duk_idx_t idx_value,
duk_idx_t idx_replacer,
duk_idx_t idx_space,
duk_small_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
duk_json_enc_ctx js_ctx_alloc;
duk_json_enc_ctx *js_ctx = &js_ctx_alloc;
duk_hobject *h;
@@ -31908,13 +36259,13 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
DUK_ASSERT(idx_space == DUK_INVALID_INDEX || idx_space >= 0);
DUK_DDD(DUK_DDDPRINT("JSON stringify start: value=%!T, replacer=%!T, space=%!T, flags=0x%08lx, stack_top=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_value),
- (duk_tval *) duk_get_tval(ctx, idx_replacer),
- (duk_tval *) duk_get_tval(ctx, idx_space),
+ (duk_tval *) duk_get_tval(thr, idx_value),
+ (duk_tval *) duk_get_tval(thr, idx_replacer),
+ (duk_tval *) duk_get_tval(thr, idx_space),
(unsigned long) flags,
- (long) duk_get_top(ctx)));
+ (long) duk_get_top(thr)));
- entry_top = duk_get_top(ctx);
+ entry_top = duk_get_top(thr);
/*
* Context init
@@ -31922,7 +36273,7 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc));
js_ctx->thr = thr;
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
js_ctx->h_replacer = NULL;
js_ctx->h_gap = NULL;
#endif
@@ -31935,17 +36286,17 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
js_ctx->flags = flags;
js_ctx->flag_ascii_only = flags & DUK_JSON_FLAG_ASCII_ONLY;
js_ctx->flag_avoid_key_quotes = flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES;
-#ifdef DUK_USE_JX
+#if defined(DUK_USE_JX)
js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM;
#endif
-#ifdef DUK_USE_JC
+#if defined(DUK_USE_JC)
js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE;
#endif
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE);
#endif
- /* The #ifdef clutter here handles the JX/JC enable/disable
+ /* The #if defined() clutter here handles the JX/JC enable/disable
* combinations properly.
*/
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
@@ -31984,15 +36335,19 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
else
#endif /* DUK_USE_JX || DUK_USE_JC */
{
+ /* Plain buffer is treated like ArrayBuffer and serialized.
+ * Lightfuncs are treated like objects, but JSON explicitly
+ * skips serializing Function objects so we can just reject
+ * lightfuncs here.
+ */
js_ctx->mask_for_undefined = DUK_TYPE_MASK_UNDEFINED |
DUK_TYPE_MASK_POINTER |
- DUK_TYPE_MASK_BUFFER |
DUK_TYPE_MASK_LIGHTFUNC;
}
DUK_BW_INIT_PUSHBUF(thr, &js_ctx->bw, DUK__JSON_STRINGIFY_BUFSIZE);
- js_ctx->idx_loop = duk_push_object_internal(ctx);
+ js_ctx->idx_loop = duk_push_bare_object(thr);
DUK_ASSERT(js_ctx->idx_loop >= 0);
/* [ ... buf loop ] */
@@ -32001,7 +36356,7 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
* Process replacer/proplist (2nd argument to JSON.stringify)
*/
- h = duk_get_hobject(ctx, idx_replacer);
+ h = duk_get_hobject(thr, idx_replacer);
if (h != NULL) {
if (DUK_HOBJECT_IS_CALLABLE(h)) {
js_ctx->h_replacer = h;
@@ -32015,30 +36370,30 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
duk_uarridx_t plist_idx = 0;
duk_small_uint_t enum_flags;
- js_ctx->idx_proplist = duk_push_array(ctx); /* XXX: array internal? */
+ js_ctx->idx_proplist = duk_push_array(thr); /* XXX: array internal? */
enum_flags = DUK_ENUM_ARRAY_INDICES_ONLY |
DUK_ENUM_SORT_ARRAY_INDICES; /* expensive flag */
- duk_enum(ctx, idx_replacer, enum_flags);
- while (duk_next(ctx, -1 /*enum_index*/, 1 /*get_value*/)) {
+ duk_enum(thr, idx_replacer, enum_flags);
+ while (duk_next(thr, -1 /*enum_index*/, 1 /*get_value*/)) {
/* [ ... proplist enum_obj key val ] */
- if (duk__enc_allow_into_proplist(duk_get_tval(ctx, -1))) {
+ if (duk__enc_allow_into_proplist(duk_get_tval(thr, -1))) {
/* XXX: duplicates should be eliminated here */
DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> accept",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_to_string(ctx, -1); /* extra coercion of strings is OK */
- duk_put_prop_index(ctx, -4, plist_idx); /* -> [ ... proplist enum_obj key ] */
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
+ duk_to_string(thr, -1); /* extra coercion of strings is OK */
+ duk_put_prop_index(thr, -4, plist_idx); /* -> [ ... proplist enum_obj key ] */
plist_idx++;
- duk_pop(ctx);
+ duk_pop(thr);
} else {
DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> reject",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_pop_2(ctx);
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
+ duk_pop_2(thr);
}
}
- duk_pop(ctx); /* pop enum */
+ duk_pop(thr); /* pop enum */
/* [ ... proplist ] */
}
@@ -32050,17 +36405,17 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
* Process space (3rd argument to JSON.stringify)
*/
- h = duk_get_hobject(ctx, idx_space);
+ h = duk_get_hobject(thr, idx_space);
if (h != NULL) {
- int c = DUK_HOBJECT_GET_CLASS_NUMBER(h);
+ duk_small_uint_t c = DUK_HOBJECT_GET_CLASS_NUMBER(h);
if (c == DUK_HOBJECT_CLASS_NUMBER) {
- duk_to_number(ctx, idx_space);
+ duk_to_number(thr, idx_space);
} else if (c == DUK_HOBJECT_CLASS_STRING) {
- duk_to_string(ctx, idx_space);
+ duk_to_string(thr, idx_space);
}
}
- if (duk_is_number(ctx, idx_space)) {
+ if (duk_is_number(thr, idx_space)) {
duk_small_int_t nspace;
/* spaces[] must be static to allow initializer with old compilers like BCC */
static const char spaces[10] = {
@@ -32070,25 +36425,26 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
}; /* XXX: helper */
/* ToInteger() coercion; NaN -> 0, infinities are clamped to 0 and 10 */
- nspace = (duk_small_int_t) duk_to_int_clamped(ctx, idx_space, 0 /*minval*/, 10 /*maxval*/);
+ nspace = (duk_small_int_t) duk_to_int_clamped(thr, idx_space, 0 /*minval*/, 10 /*maxval*/);
DUK_ASSERT(nspace >= 0 && nspace <= 10);
- duk_push_lstring(ctx, spaces, (duk_size_t) nspace);
- js_ctx->h_gap = duk_get_hstring(ctx, -1);
- DUK_ASSERT(js_ctx->h_gap != NULL);
- } else if (duk_is_string(ctx, idx_space)) {
- /* XXX: substring in-place at idx_place? */
- duk_dup(ctx, idx_space);
- duk_substring(ctx, -1, 0, 10); /* clamp to 10 chars */
- js_ctx->h_gap = duk_get_hstring(ctx, -1);
+ duk_push_lstring(thr, spaces, (duk_size_t) nspace);
+ js_ctx->h_gap = duk_known_hstring(thr, -1);
DUK_ASSERT(js_ctx->h_gap != NULL);
+ } else if (duk_is_string_notsymbol(thr, idx_space)) {
+ duk_dup(thr, idx_space);
+ duk_substring(thr, -1, 0, 10); /* clamp to 10 chars */
+ js_ctx->h_gap = duk_known_hstring(thr, -1);
} else {
/* nop */
}
if (js_ctx->h_gap != NULL) {
- /* if gap is empty, behave as if not given at all */
- if (DUK_HSTRING_GET_CHARLEN(js_ctx->h_gap) == 0) {
+ /* If gap is empty, behave as if not given at all. Check
+ * against byte length because character length is more
+ * expensive.
+ */
+ if (DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) == 0) {
js_ctx->h_gap = NULL;
}
}
@@ -32104,9 +36460,7 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
if (js_ctx->h_replacer == NULL && /* replacer is a mutation risk */
js_ctx->idx_proplist == -1) { /* proplist is very rare */
duk_int_t pcall_rc;
-#ifdef DUK_USE_MARK_AND_SWEEP
- duk_small_uint_t prev_mark_and_sweep_base_flags;
-#endif
+ duk_small_uint_t prev_ms_base_flags;
DUK_DD(DUK_DDPRINT("try JSON.stringify() fast path"));
@@ -32125,22 +36479,21 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
* limited loop detection).
*/
- duk_push_pointer(ctx, (void *) js_ctx);
- duk_dup(ctx, idx_value);
+ duk_dup(thr, idx_value);
-#if defined(DUK_USE_MARK_AND_SWEEP)
/* Must prevent finalizers which may have arbitrary side effects. */
- prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags;
- thr->heap->mark_and_sweep_base_flags |=
- DUK_MS_FLAG_NO_FINALIZERS | /* avoid attempts to add/remove object keys */
- DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid attempt to compact any objects */
-#endif
+ prev_ms_base_flags = thr->heap->ms_base_flags;
+ thr->heap->ms_base_flags |=
+ DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* Avoid attempt to compact any objects. */
+ thr->heap->pf_prevent_count++; /* Prevent finalizers. */
+ DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */
- pcall_rc = duk_safe_call(ctx, duk__json_stringify_fast, 2 /*nargs*/, 0 /*nret*/);
+ pcall_rc = duk_safe_call(thr, duk__json_stringify_fast, (void *) js_ctx /*udata*/, 1 /*nargs*/, 0 /*nret*/);
+
+ DUK_ASSERT(thr->heap->pf_prevent_count > 0);
+ thr->heap->pf_prevent_count--;
+ thr->heap->ms_base_flags = prev_ms_base_flags;
-#if defined(DUK_USE_MARK_AND_SWEEP)
- thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
-#endif
if (pcall_rc == DUK_EXEC_SUCCESS) {
DUK_DD(DUK_DDPRINT("fast path successful"));
DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw);
@@ -32162,22 +36515,22 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
* Create wrapper object and serialize
*/
- idx_holder = duk_push_object(ctx);
- duk_dup(ctx, idx_value);
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_EMPTY_STRING);
+ idx_holder = duk_push_object(thr);
+ duk_dup(thr, idx_value);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_EMPTY_STRING);
DUK_DDD(DUK_DDDPRINT("before: flags=0x%08lx, loop=%!T, replacer=%!O, "
"proplist=%!T, gap=%!O, holder=%!T",
(unsigned long) js_ctx->flags,
- (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop),
+ (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop),
(duk_heaphdr *) js_ctx->h_replacer,
- (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(ctx, js_ctx->idx_proplist) : NULL),
+ (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(thr, js_ctx->idx_proplist) : NULL),
(duk_heaphdr *) js_ctx->h_gap,
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
/* serialize the wrapper with empty string key */
- duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
+ duk_push_hstring_empty(thr);
/* [ ... buf loop (proplist) (gap) holder "" ] */
@@ -32186,7 +36539,7 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_holder) == 0)) { /* [ ... holder key ] -> [ ... holder ] */
/* Result is undefined. */
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
} else {
/* Convert buffer to result string. */
DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw);
@@ -32195,11 +36548,11 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
DUK_DDD(DUK_DDDPRINT("after: flags=0x%08lx, loop=%!T, replacer=%!O, "
"proplist=%!T, gap=%!O, holder=%!T",
(unsigned long) js_ctx->flags,
- (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop),
+ (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop),
(duk_heaphdr *) js_ctx->h_replacer,
- (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(ctx, js_ctx->idx_proplist) : NULL),
+ (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(thr, js_ctx->idx_proplist) : NULL),
(duk_heaphdr *) js_ctx->h_gap,
- (duk_tval *) duk_get_tval(ctx, idx_holder)));
+ (duk_tval *) duk_get_tval(thr, idx_holder)));
/* The stack has a variable shape here, so force it to the
* desired one explicitly.
@@ -32208,35 +36561,37 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
replace_finished:
#endif
- duk_replace(ctx, entry_top);
- duk_set_top(ctx, entry_top + 1);
+ duk_replace(thr, entry_top);
+ duk_set_top(thr, entry_top + 1);
DUK_DDD(DUK_DDDPRINT("JSON stringify end: value=%!T, replacer=%!T, space=%!T, "
"flags=0x%08lx, result=%!T, stack_top=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_value),
- (duk_tval *) duk_get_tval(ctx, idx_replacer),
- (duk_tval *) duk_get_tval(ctx, idx_space),
+ (duk_tval *) duk_get_tval(thr, idx_value),
+ (duk_tval *) duk_get_tval(thr, idx_replacer),
+ (duk_tval *) duk_get_tval(thr, idx_space),
(unsigned long) flags,
- (duk_tval *) duk_get_tval(ctx, -1),
- (long) duk_get_top(ctx)));
+ (duk_tval *) duk_get_tval(thr, -1),
+ (long) duk_get_top(thr)));
- DUK_ASSERT(duk_get_top(ctx) == entry_top + 1);
+ DUK_ASSERT(duk_get_top(thr) == entry_top + 1);
}
+#if defined(DUK_USE_JSON_BUILTIN)
+
/*
* Entry points
*/
-DUK_INTERNAL duk_ret_t duk_bi_json_object_parse(duk_context *ctx) {
- duk_bi_json_parse_helper(ctx,
+DUK_INTERNAL duk_ret_t duk_bi_json_object_parse(duk_hthread *thr) {
+ duk_bi_json_parse_helper(thr,
0 /*idx_value*/,
1 /*idx_replacer*/,
0 /*flags*/);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx) {
- duk_bi_json_stringify_helper(ctx,
+DUK_INTERNAL duk_ret_t duk_bi_json_object_stringify(duk_hthread *thr) {
+ duk_bi_json_stringify_helper(thr,
0 /*idx_value*/,
1 /*idx_replacer*/,
2 /*idx_space*/,
@@ -32244,318 +36599,29 @@ DUK_INTERNAL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx) {
return 1;
}
+#endif /* DUK_USE_JSON_BUILTIN */
+
+#endif /* DUK_USE_JSON_SUPPORT */
+
+/* automatic undefs */
+#undef DUK__EMIT_1
+#undef DUK__EMIT_2
+#undef DUK__EMIT_CSTR
+#undef DUK__EMIT_HSTR
+#undef DUK__EMIT_STRIDX
#undef DUK__JSON_DECSTR_BUFSIZE
#undef DUK__JSON_DECSTR_CHUNKSIZE
#undef DUK__JSON_ENCSTR_CHUNKSIZE
-#undef DUK__JSON_STRINGIFY_BUFSIZE
#undef DUK__JSON_MAX_ESC_LEN
-#line 1 "duk_bi_logger.c"
-/*
- * Logging support
- */
-
-/* include removed: duk_internal.h */
-
-/* 3-letter log level strings */
-DUK_LOCAL const duk_uint8_t duk__log_level_strings[] = {
- (duk_uint8_t) DUK_ASC_UC_T, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_C,
- (duk_uint8_t) DUK_ASC_UC_D, (duk_uint8_t) DUK_ASC_UC_B, (duk_uint8_t) DUK_ASC_UC_G,
- (duk_uint8_t) DUK_ASC_UC_I, (duk_uint8_t) DUK_ASC_UC_N, (duk_uint8_t) DUK_ASC_UC_F,
- (duk_uint8_t) DUK_ASC_UC_W, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_N,
- (duk_uint8_t) DUK_ASC_UC_E, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_R,
- (duk_uint8_t) DUK_ASC_UC_F, (duk_uint8_t) DUK_ASC_UC_T, (duk_uint8_t) DUK_ASC_UC_L
-};
-
-/* Constructor */
-DUK_INTERNAL duk_ret_t duk_bi_logger_constructor(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_idx_t nargs;
-
- /* Calling as a non-constructor is not meaningful. */
- if (!duk_is_constructor_call(ctx)) {
- return DUK_RET_TYPE_ERROR;
- }
-
- nargs = duk_get_top(ctx);
- duk_set_top(ctx, 1);
-
- duk_push_this(ctx);
-
- /* [ name this ] */
-
- if (nargs == 0) {
- /* Automatic defaulting of logger name from caller. This would
- * work poorly with tail calls, but constructor calls are currently
- * never tail calls, so tail calls are not an issue now.
- */
-
- if (thr->callstack_top >= 2) {
- duk_activation *act_caller = thr->callstack + thr->callstack_top - 2;
- duk_hobject *func_caller;
-
- func_caller = DUK_ACT_GET_FUNC(act_caller);
- if (func_caller) {
- /* Stripping the filename might be a good idea
- * ("/foo/bar/quux.js" -> logger name "quux"),
- * but now used verbatim.
- */
- duk_push_hobject(ctx, func_caller);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME);
- duk_replace(ctx, 0);
- }
- }
- }
- /* the stack is unbalanced here on purpose; we only rely on the
- * initial two values: [ name this ].
- */
-
- if (duk_is_string(ctx, 0)) {
- duk_dup(ctx, 0);
- duk_put_prop_stridx(ctx, 1, DUK_STRIDX_LC_N);
- } else {
- /* don't set 'n' at all, inherited value is used as name */
- }
-
- duk_compact(ctx, 1);
-
- return 0; /* keep default instance */
-}
-
-/* Default function to format objects. Tries to use toLogString() but falls
- * back to toString(). Any errors are propagated out without catching.
- */
-DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_fmt(duk_context *ctx) {
- if (duk_get_prop_stridx(ctx, 0, DUK_STRIDX_TO_LOG_STRING)) {
- /* [ arg toLogString ] */
-
- duk_dup(ctx, 0);
- duk_call_method(ctx, 0);
-
- /* [ arg result ] */
- return 1;
- }
-
- /* [ arg undefined ] */
- duk_pop(ctx);
- duk_to_string(ctx, 0);
- return 1;
-}
-
-/* Default function to write a formatted log line. Writes to stderr,
- * appending a newline to the log line.
- *
- * The argument is a buffer whose visible size contains the log message.
- * This function should avoid coercing the buffer to a string to avoid
- * string table traffic.
- */
-DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_raw(duk_context *ctx) {
- const char *data;
- duk_size_t data_len;
-
- DUK_UNREF(ctx);
- DUK_UNREF(data);
- DUK_UNREF(data_len);
-
-#ifdef DUK_USE_FILE_IO
- data = (const char *) duk_require_buffer(ctx, 0, &data_len);
- DUK_FWRITE((const void *) data, 1, data_len, DUK_STDERR);
- DUK_FPUTC((int) '\n', DUK_STDERR);
- DUK_FFLUSH(DUK_STDERR);
-#else
- /* nop */
-#endif
- return 0;
-}
-
-/* Log frontend shared helper, magic value indicates log level. Provides
- * frontend functions: trace(), debug(), info(), warn(), error(), fatal().
- * This needs to have small footprint, reasonable performance, minimal
- * memory churn, etc.
- */
-DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_log_shared(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_double_t now;
- duk_small_int_t entry_lev = duk_get_current_magic(ctx);
- duk_small_int_t logger_lev;
- duk_int_t nargs;
- duk_int_t i;
- duk_size_t tot_len;
- const duk_uint8_t *arg_str;
- duk_size_t arg_len;
- duk_uint8_t *buf, *p;
- const duk_uint8_t *q;
- duk_uint8_t date_buf[DUK_BI_DATE_ISO8601_BUFSIZE];
- duk_size_t date_len;
- duk_small_int_t rc;
-
- DUK_ASSERT(entry_lev >= 0 && entry_lev <= 5);
- DUK_UNREF(thr);
-
- /* XXX: sanitize to printable (and maybe ASCII) */
- /* XXX: better multiline */
-
- /*
- * Logger arguments are:
- *
- * magic: log level (0-5)
- * this: logger
- * stack: plain log args
- *
- * We want to minimize memory churn so a two-pass approach
- * is used: first pass formats arguments and computes final
- * string length, second pass copies strings either into a
- * pre-allocated and reused buffer (short messages) or into a
- * newly allocated fixed buffer. If the backend function plays
- * nice, it won't coerce the buffer to a string (and thus
- * intern it).
- */
-
- nargs = duk_get_top(ctx);
-
- /* [ arg1 ... argN this ] */
-
- /*
- * Log level check
- */
-
- duk_push_this(ctx);
-
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LC_L);
- logger_lev = (duk_small_int_t) duk_get_int(ctx, -1);
- if (entry_lev < logger_lev) {
- return 0;
- }
- /* log level could be popped but that's not necessary */
-
- now = DUK_USE_DATE_GET_NOW(ctx);
- duk_bi_date_format_timeval(now, date_buf);
- date_len = DUK_STRLEN((const char *) date_buf);
-
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LC_N);
- duk_to_string(ctx, -1);
- DUK_ASSERT(duk_is_string(ctx, -1));
-
- /* [ arg1 ... argN this loggerLevel loggerName ] */
-
- /*
- * Pass 1
- */
-
- /* Line format: