porffor 0.60.24 → 0.60.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compiler/2c.js +70 -59
- package/compiler/codegen.js +4 -1
- package/compiler/cyclone.js +1 -2
- package/compiler/semantic.js +39 -12
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/runtime/index.js +1 -1
- package/runtime/lambda.js +19 -2
package/compiler/2c.js
CHANGED
|
@@ -985,7 +985,6 @@ f64 _time_out${id} = (f64)_ts${id}.tv_sec * 1000.0 + (f64)_ts${id}.tv_nsec / 1.0
|
|
|
985
985
|
includes.set('netdb.h', true);
|
|
986
986
|
includes.set('sys/socket.h', true);
|
|
987
987
|
includes.set('signal.h', true);
|
|
988
|
-
includes.set('execinfo.h', true);
|
|
989
988
|
|
|
990
989
|
let copyGlobals = '';
|
|
991
990
|
let restoreGlobals = '';
|
|
@@ -997,51 +996,64 @@ f64 _time_out${id} = (f64)_ts${id}.tv_sec * 1000.0 + (f64)_ts${id}.tv_nsec / 1.0
|
|
|
997
996
|
}
|
|
998
997
|
|
|
999
998
|
const lambdaWrapper = `
|
|
1000
|
-
#define BUF_SIZE
|
|
999
|
+
#define BUF_SIZE 8192
|
|
1001
1000
|
|
|
1002
|
-
|
|
1003
|
-
static int
|
|
1004
|
-
|
|
1005
|
-
|
|
1001
|
+
static struct addrinfo* runtime_addr = NULL;
|
|
1002
|
+
static int runtime_sock = -1;
|
|
1003
|
+
|
|
1004
|
+
static int init_runtime_addr(const char* host, const char* port) {
|
|
1005
|
+
struct addrinfo hints = {0};
|
|
1006
1006
|
hints.ai_family = AF_UNSPEC;
|
|
1007
1007
|
hints.ai_socktype = SOCK_STREAM;
|
|
1008
|
-
|
|
1008
|
+
return getaddrinfo(host, port, &hints, &runtime_addr);
|
|
1009
|
+
}
|
|
1009
1010
|
|
|
1010
|
-
|
|
1011
|
-
if (
|
|
1012
|
-
if (
|
|
1013
|
-
|
|
1014
|
-
|
|
1011
|
+
static int get_sock(void) {
|
|
1012
|
+
if (runtime_sock >= 0) return runtime_sock;
|
|
1013
|
+
if (!runtime_addr) return -1;
|
|
1014
|
+
|
|
1015
|
+
runtime_sock = socket(runtime_addr->ai_family, runtime_addr->ai_socktype,
|
|
1016
|
+
runtime_addr->ai_protocol);
|
|
1017
|
+
if (runtime_sock < 0) return -1;
|
|
1018
|
+
|
|
1019
|
+
int optval = 1;
|
|
1020
|
+
setsockopt(runtime_sock, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
|
|
1021
|
+
|
|
1022
|
+
if (connect(runtime_sock, runtime_addr->ai_addr, runtime_addr->ai_addrlen) != 0) {
|
|
1023
|
+
close(runtime_sock);
|
|
1024
|
+
runtime_sock = -1;
|
|
1015
1025
|
return -1;
|
|
1016
1026
|
}
|
|
1027
|
+
return runtime_sock;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
static int send_http(const char* req, size_t req_size, char* resp, size_t resp_size) {
|
|
1031
|
+
int sock = get_sock();
|
|
1032
|
+
if (sock < 0) return -1;
|
|
1017
1033
|
|
|
1018
|
-
write(sock, req,
|
|
1034
|
+
ssize_t w = write(sock, req, req_size);
|
|
1035
|
+
if (w != req_size) return -1;
|
|
1019
1036
|
|
|
1020
1037
|
int len = 0;
|
|
1021
1038
|
if (resp) {
|
|
1022
1039
|
len = read(sock, resp, resp_size - 1);
|
|
1023
|
-
if (len
|
|
1040
|
+
if (len < 0) {
|
|
1041
|
+
close(sock);
|
|
1042
|
+
runtime_sock = -1;
|
|
1043
|
+
return -1;
|
|
1044
|
+
}
|
|
1045
|
+
resp[len] = '\\0';
|
|
1024
1046
|
}
|
|
1025
1047
|
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
}
|
|
1048
|
+
if (len == 0) {
|
|
1049
|
+
close(sock);
|
|
1050
|
+
runtime_sock = -1;
|
|
1051
|
+
}
|
|
1030
1052
|
|
|
1031
|
-
|
|
1032
|
-
void *array[20];
|
|
1033
|
-
size_t size = backtrace(array, 20);
|
|
1034
|
-
fprintf(stderr, "Caught signal %d\\n", sig);
|
|
1035
|
-
backtrace_symbols_fd(array, size, STDERR_FILENO);
|
|
1036
|
-
_exit(1);
|
|
1053
|
+
return len;
|
|
1037
1054
|
}
|
|
1038
1055
|
|
|
1039
1056
|
int main(void) {
|
|
1040
|
-
signal(SIGSEGV, crash_handler);
|
|
1041
|
-
signal(SIGABRT, crash_handler);
|
|
1042
|
-
signal(SIGBUS, crash_handler);
|
|
1043
|
-
signal(SIGILL, crash_handler);
|
|
1044
|
-
|
|
1045
1057
|
user_main();
|
|
1046
1058
|
|
|
1047
1059
|
i32 _memory_pages = _memoryPages;
|
|
@@ -1052,31 +1064,34 @@ int main(void) {
|
|
|
1052
1064
|
|
|
1053
1065
|
char *api = getenv("AWS_LAMBDA_RUNTIME_API");
|
|
1054
1066
|
if (!api) {
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
exit(1);
|
|
1067
|
+
printf("AWS_LAMBDA_RUNTIME_API not set\\n");
|
|
1068
|
+
exit(1);
|
|
1058
1069
|
}
|
|
1059
1070
|
|
|
1060
1071
|
char host[256], port[16] = "80";
|
|
1061
1072
|
char *colon = strchr(api, ':');
|
|
1062
1073
|
if (colon) {
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1074
|
+
strncpy(host, api, colon - api);
|
|
1075
|
+
host[colon - api] = '\\0';
|
|
1076
|
+
strncpy(port, colon + 1, sizeof(port) - 1);
|
|
1066
1077
|
} else {
|
|
1067
|
-
|
|
1078
|
+
strncpy(host, api, sizeof(host) - 1);
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
if (init_runtime_addr(host, port) != 0) {
|
|
1082
|
+
fprintf(stderr, "Failed to resolve runtime host\\n");
|
|
1083
|
+
return 1;
|
|
1068
1084
|
}
|
|
1069
1085
|
|
|
1070
1086
|
char req[BUF_SIZE], resp[BUF_SIZE];
|
|
1071
1087
|
char request_id[128];
|
|
1072
|
-
|
|
1073
|
-
i32 request_count = 0;
|
|
1074
1088
|
while (1) {
|
|
1075
1089
|
// 1. GET next event
|
|
1076
|
-
snprintf(req, sizeof(req),
|
|
1090
|
+
int req_size = snprintf(req, sizeof(req),
|
|
1077
1091
|
"GET /2018-06-01/runtime/invocation/next HTTP/1.1\\r\\n"
|
|
1078
|
-
"Host: %s\\r\\n
|
|
1079
|
-
|
|
1092
|
+
"Host: %s\\r\\n"
|
|
1093
|
+
"Connection: keep-alive\\r\\n\\r\\n", host);
|
|
1094
|
+
if (send_http(req, (size_t)req_size, resp, sizeof(resp)) <= 0) {
|
|
1080
1095
|
fprintf(stderr, "send_http failed\\n");
|
|
1081
1096
|
break;
|
|
1082
1097
|
}
|
|
@@ -1098,21 +1113,12 @@ int main(void) {
|
|
|
1098
1113
|
request_id[rid_len] = '\\0';
|
|
1099
1114
|
|
|
1100
1115
|
// 2. Parse event data from response body
|
|
1101
|
-
char *body = strstr(resp, "\\r\\n\\r\\n");
|
|
1102
|
-
void *event = NULL;
|
|
1103
|
-
if (body) {
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
if (request_count++ > 0) {
|
|
1109
|
-
_memoryPages = _memory_pages;
|
|
1110
|
-
free(_memory);
|
|
1111
|
-
_memory = calloc(1, _memory_pages * ${PageSize});
|
|
1112
|
-
memcpy(_memory, _memory_clone, _memory_pages * ${PageSize});
|
|
1113
|
-
|
|
1114
|
-
${restoreGlobals}
|
|
1115
|
-
}
|
|
1116
|
+
// char *body = strstr(resp, "\\r\\n\\r\\n");
|
|
1117
|
+
// void *event = NULL;
|
|
1118
|
+
// if (body) {
|
|
1119
|
+
// body += 4; // skip \\r\\n\\r\\n
|
|
1120
|
+
// event = body;
|
|
1121
|
+
// }
|
|
1116
1122
|
|
|
1117
1123
|
// Call handler function and JSON.stringify the result
|
|
1118
1124
|
// size_t eventLen = strlen(event);
|
|
@@ -1120,19 +1126,24 @@ int main(void) {
|
|
|
1120
1126
|
// memcpy((char*)eventPtr, &eventLen, 4);
|
|
1121
1127
|
// memcpy((char*)eventPtr + 4, event, eventLen);
|
|
1122
1128
|
|
|
1123
|
-
// char* resp = _memory + (i32)__Porffor_handler((f64)eventPtr, 195).value + 4;
|
|
1124
1129
|
i32 ret = (i32)__Porffor_handler().value;
|
|
1125
1130
|
char* ret_str = _memory + ret + 4;
|
|
1126
1131
|
i32 ret_str_len = *((i32*)(ret_str - 4));
|
|
1127
1132
|
|
|
1128
1133
|
// 3. POST response
|
|
1129
|
-
snprintf(req, sizeof(req),
|
|
1134
|
+
req_size = snprintf(req, sizeof(req),
|
|
1130
1135
|
"POST /2018-06-01/runtime/invocation/%s/response HTTP/1.1\\r\\n"
|
|
1131
1136
|
"Host: %s\\r\\n"
|
|
1137
|
+
"Connection: close\\r\\n"
|
|
1132
1138
|
"Content-Type: text/plain\\r\\n"
|
|
1133
1139
|
"Content-Length: %zu\\r\\n\\r\\n"
|
|
1134
1140
|
"%s", request_id, host, ret_str_len, ret_str);
|
|
1135
|
-
send_http(
|
|
1141
|
+
send_http(req, (size_t)req_size, NULL, 0);
|
|
1142
|
+
|
|
1143
|
+
// reset js state after response
|
|
1144
|
+
memcpy(_memory, _memory_clone, _memory_pages * ${PageSize});
|
|
1145
|
+
|
|
1146
|
+
${restoreGlobals}
|
|
1136
1147
|
}
|
|
1137
1148
|
return 0;
|
|
1138
1149
|
}`;
|
package/compiler/codegen.js
CHANGED
|
@@ -2393,7 +2393,10 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
|
2393
2393
|
|
|
2394
2394
|
protoBC.default = decl.optional ?
|
|
2395
2395
|
withType(scope, [ number(UNDEFINED) ], TYPES.undefined) :
|
|
2396
|
-
|
|
2396
|
+
generate(scope, {
|
|
2397
|
+
...decl,
|
|
2398
|
+
_protoInternalCall: true
|
|
2399
|
+
});
|
|
2397
2400
|
|
|
2398
2401
|
// fallback to object prototype impl as a basic prototype chain hack
|
|
2399
2402
|
if (protoBC[TYPES.object]) {
|
package/compiler/cyclone.js
CHANGED
|
@@ -91,7 +91,7 @@ export default ({ name, wasm, locals: _locals, params }, _globals) => {
|
|
|
91
91
|
// if (Prefs.f === name) console.log(invOpcodes[opcode], stack);
|
|
92
92
|
switch (opcode) {
|
|
93
93
|
case Opcodes.if: {
|
|
94
|
-
if (stack.length < 1) {
|
|
94
|
+
if (stack.length < 1) { reset(); break; }
|
|
95
95
|
const cond = bool(pop());
|
|
96
96
|
|
|
97
97
|
// find else split and end
|
|
@@ -598,7 +598,6 @@ export default ({ name, wasm, locals: _locals, params }, _globals) => {
|
|
|
598
598
|
case Opcodes.block:
|
|
599
599
|
case Opcodes.loop:
|
|
600
600
|
case Opcodes.try:
|
|
601
|
-
case Opcodes.if:
|
|
602
601
|
case Opcodes.else:
|
|
603
602
|
case Opcodes.catch:
|
|
604
603
|
case Opcodes.end: {
|
package/compiler/semantic.js
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
// todo: sloppy vs strict mode
|
|
2
|
-
// todo: function/class decls ?
|
|
3
|
-
// todo: function params
|
|
4
|
-
|
|
5
1
|
const varId = name => {
|
|
6
2
|
const lastFunc = scopes[scopes.lastFuncs.at(-1)];
|
|
7
3
|
lastFunc._variableIds ??= Object.create(null);
|
|
@@ -14,7 +10,18 @@ const varId = name => {
|
|
|
14
10
|
};
|
|
15
11
|
|
|
16
12
|
const declVar = (name, kind, node) => {
|
|
17
|
-
|
|
13
|
+
let parent;
|
|
14
|
+
if (kind === 'var') {
|
|
15
|
+
parent = scopes[scopes.lastFuncs.at(-1)];
|
|
16
|
+
// same id for redecl
|
|
17
|
+
if (parent._variables?.[name]) {
|
|
18
|
+
parent._variables[name].node = node;
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
} else {
|
|
22
|
+
parent = scopes.at(-1);
|
|
23
|
+
}
|
|
24
|
+
|
|
18
25
|
parent._variables ??= Object.create(null);
|
|
19
26
|
parent._variables[name] = { node, id: varId(name) };
|
|
20
27
|
};
|
|
@@ -53,9 +60,14 @@ const analyzePattern = (kind, node) => {
|
|
|
53
60
|
};
|
|
54
61
|
|
|
55
62
|
let scopes;
|
|
56
|
-
const analyze = node => {
|
|
63
|
+
const analyze = (node, strict = false) => {
|
|
57
64
|
if (!node) return;
|
|
58
65
|
|
|
66
|
+
const top = scopes.at(-1);
|
|
67
|
+
if (node.directive === 'use strict') {
|
|
68
|
+
top._strict = true;
|
|
69
|
+
}
|
|
70
|
+
|
|
59
71
|
let openedScope = false;
|
|
60
72
|
switch (node.type) {
|
|
61
73
|
case 'ForStatement':
|
|
@@ -77,18 +89,31 @@ const analyze = node => {
|
|
|
77
89
|
for (const x of node.declarations) analyzePattern(node.kind, x.id);
|
|
78
90
|
break;
|
|
79
91
|
|
|
92
|
+
case 'ClassDeclaration':
|
|
93
|
+
if (node.id?.name) declVar(node.id.name, 'let', node);
|
|
94
|
+
break;
|
|
95
|
+
|
|
80
96
|
case 'FunctionDeclaration':
|
|
97
|
+
if (node.id?.name) if (strict) {
|
|
98
|
+
declVar(node.id.name, 'let', node);
|
|
99
|
+
} else {
|
|
100
|
+
declVar(node.id.name, 'var', node);
|
|
101
|
+
}
|
|
81
102
|
case 'FunctionExpression':
|
|
82
103
|
case 'ArrowFunctionExpression':
|
|
83
104
|
scopes.lastFuncs.push(scopes.length);
|
|
105
|
+
scopes.push(node);
|
|
106
|
+
openedScope = true;
|
|
107
|
+
|
|
108
|
+
for (const p of node.params) analyzePattern('var', p);
|
|
84
109
|
break;
|
|
85
110
|
}
|
|
86
111
|
|
|
87
112
|
for (const x in node) {
|
|
88
113
|
if (node[x] != null && typeof node[x] === 'object') {
|
|
89
|
-
if (node[x].type) analyze(node[x]);
|
|
114
|
+
if (node[x].type) analyze(node[x], strict || top._strict);
|
|
90
115
|
if (Array.isArray(node[x])) {
|
|
91
|
-
for (const y of node[x]) analyze(y);
|
|
116
|
+
for (const y of node[x]) analyze(y, strict || top._strict);
|
|
92
117
|
}
|
|
93
118
|
}
|
|
94
119
|
}
|
|
@@ -138,19 +163,21 @@ const annotate = node => {
|
|
|
138
163
|
case 'CallExpression':
|
|
139
164
|
if (node.callee.name === 'eval' || (node.callee.type === 'SequenceExpression' && node.callee.expressions.at(-1)?.name === 'eval')) {
|
|
140
165
|
if (node.callee.type === 'SequenceExpression' || node.optional) {
|
|
141
|
-
// indirect eval,
|
|
142
|
-
node._semanticScopes = [ node ];
|
|
166
|
+
// indirect eval, only top scope
|
|
167
|
+
node._semanticScopes = [ scopes[0], node ];
|
|
143
168
|
node._semanticScopes.lastFuncs = [ 0 ];
|
|
144
169
|
} else {
|
|
145
170
|
// direct eval, use existing scope
|
|
146
171
|
node._semanticScopes = Object.assign([], scopes);
|
|
172
|
+
node._semanticScopes.push(node);
|
|
147
173
|
}
|
|
148
174
|
}
|
|
149
175
|
|
|
150
176
|
case 'NewExpression':
|
|
151
177
|
if (node.callee.name === 'Function') {
|
|
152
|
-
//
|
|
153
|
-
node._semanticScopes =
|
|
178
|
+
// new Function(...) - use global scope and self as scope
|
|
179
|
+
node._semanticScopes = [ scopes[0], node ];
|
|
180
|
+
node._semanticScopes.lastFuncs = [ 0, 1 ];
|
|
154
181
|
}
|
|
155
182
|
break;
|
|
156
183
|
}
|
package/jsr.json
CHANGED
package/package.json
CHANGED
package/runtime/index.js
CHANGED
package/runtime/lambda.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import { execSync } from 'node:child_process';
|
|
4
4
|
import compile from '../compiler/wrap.js';
|
|
5
|
+
import { log } from '../compiler/log.js';
|
|
5
6
|
|
|
6
7
|
// Parse arguments
|
|
7
8
|
const args = process.argv.slice(2);
|
|
@@ -29,8 +30,24 @@ Prefs.lambda = true;
|
|
|
29
30
|
|
|
30
31
|
compile(source, true);
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
let compiler = process.env.CC;
|
|
34
|
+
if (!compiler) {
|
|
35
|
+
try {
|
|
36
|
+
execSync('musl-gcc --version');
|
|
37
|
+
compiler = 'musl-gcc';
|
|
38
|
+
} catch {
|
|
39
|
+
// todo: this should be in future docs somewhere and linked instead
|
|
40
|
+
log.warning('lambda', `musl-gcc is recommended for Lambda as it noticably improves deployed performance. install it or explicitly specify a compiler via CC to hide this warning. defaulting to gcc.`);
|
|
41
|
+
compiler = 'gcc';
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (Prefs.d) {
|
|
46
|
+
execSync(`${compiler} -lm -O0 -g -flto -march=x86-64-v3 -o ${binaryPath} ${cPath}`, { stdio: 'inherit' });
|
|
47
|
+
} else {
|
|
48
|
+
execSync(`${compiler} ${compiler === 'musl-gcc' ? '-static' : ''} -lm -O3 -fomit-frame-pointer -s -flto -march=x86-64-v3 -ffunction-sections -fdata-sections -Wl,--gc-sections -o ${binaryPath} ${cPath}`, { stdio: 'inherit' });
|
|
49
|
+
execSync(`strip ${binaryPath}`, { stdio: 'inherit' });
|
|
50
|
+
}
|
|
34
51
|
|
|
35
52
|
try {
|
|
36
53
|
execSync(`zip -r "${outputZip}" ${binaryPath}`, { stdio: 'inherit' });
|