porffor 0.60.5 → 0.60.6

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 CHANGED
@@ -350,8 +350,11 @@ export default ({ funcs, globals, data, pages }) => {
350
350
  const typedReturns = f.returnType == null;
351
351
 
352
352
  const shouldInline = false; // f.internal;
353
- if (f.name === '#main') out += `int main(${prependMain.has('argv') ? 'int argc, char* argv[]' : ''}) {\n`;
354
- else out += `${!typedReturns ? (returns ? CValtype[f.returns[0]] : 'void') : 'struct ReturnValue'} ${shouldInline ? 'inline ' : ''}${sanitize(f.name)}(${f.params.map((x, i) => `${CValtype[x]} ${invLocals[i]}`).join(', ')}) {\n`;
353
+ if (f.name === '#main') {
354
+ out += `int ${Prefs.lambda ? 'user_main' : 'main'}(${prependMain.has('argv') ? 'int argc, char* argv[]' : ''}) {\n`;
355
+ } else {
356
+ out += `${!typedReturns ? (returns ? CValtype[f.returns[0]] : 'void') : 'struct ReturnValue'} ${shouldInline ? 'inline ' : ''}${sanitize(f.name)}(${f.params.map((x, i) => `${CValtype[x]} ${invLocals[i]}`).join(', ')}) {\n`;
357
+ }
355
358
 
356
359
  if (f.name === '__Porffor_promise_runJobs') {
357
360
  out += '}';
@@ -969,6 +972,175 @@ extern ${importFunc.returns.length > 0 ? CValtype[importFunc.returns[0]] : 'void
969
972
  return `${!typedReturns ? (returns ? CValtype[f.returns[0]] : 'void') : 'struct ReturnValue'} ${shouldInline ? 'inline ' : ''}${ffiFuncs[f.name] ? '(*' : ''}${sanitize(f.name)}${ffiFuncs[f.name] ? ')' : ''}(${rawParams(f).map((x, i) => `${CValtype[x]} ${invLocals[i]}`).join(', ')});`;
970
973
  }).join('\n'));
971
974
 
975
+ if (Prefs.lambda) {
976
+ includes.set('stdio.h', true);
977
+ includes.set('stdlib.h', true);
978
+ includes.set('string.h', true);
979
+ includes.set('unistd.h', true);
980
+ includes.set('netdb.h', true);
981
+ includes.set('sys/socket.h', true);
982
+ includes.set('signal.h', true);
983
+ includes.set('execinfo.h', true);
984
+
985
+ let copyGlobals = '';
986
+ let restoreGlobals = '';
987
+ for (const x in globals) {
988
+ const g = globals[x];
989
+
990
+ copyGlobals += `${CValtype[g.type]} copy_${sanitize(x)} = ${sanitize(x)};\n`;
991
+ restoreGlobals += `${sanitize(x)} = copy_${sanitize(x)};\n`;
992
+ }
993
+
994
+ const lambdaWrapper = `
995
+ #define BUF_SIZE 65536
996
+
997
+ // minimal http send/receive
998
+ static int send_http(const char *host, const char *port, const char *req, char *resp, size_t resp_size) {
999
+ struct addrinfo hints = {0}, *res;
1000
+ int sock;
1001
+ hints.ai_family = AF_UNSPEC;
1002
+ hints.ai_socktype = SOCK_STREAM;
1003
+ if (getaddrinfo(host, port, &hints, &res) != 0) return -1;
1004
+
1005
+ sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
1006
+ if (sock < 0) return -1;
1007
+ if (connect(sock, res->ai_addr, res->ai_addrlen) != 0) {
1008
+ close(sock);
1009
+ freeaddrinfo(res);
1010
+ return -1;
1011
+ }
1012
+
1013
+ write(sock, req, strlen(req));
1014
+
1015
+ int len = 0;
1016
+ if (resp) {
1017
+ len = read(sock, resp, resp_size - 1);
1018
+ if (len >= 0) resp[len] = '\\0';
1019
+ }
1020
+
1021
+ close(sock);
1022
+ freeaddrinfo(res);
1023
+ return len;
1024
+ }
1025
+
1026
+ void crash_handler(int sig) {
1027
+ void *array[20];
1028
+ size_t size = backtrace(array, 20);
1029
+ fprintf(stderr, "Caught signal %d\\n", sig);
1030
+ backtrace_symbols_fd(array, size, STDERR_FILENO);
1031
+ _exit(1);
1032
+ }
1033
+
1034
+ int main(void) {
1035
+ signal(SIGSEGV, crash_handler);
1036
+ signal(SIGABRT, crash_handler);
1037
+ signal(SIGBUS, crash_handler);
1038
+ signal(SIGILL, crash_handler);
1039
+
1040
+ user_main();
1041
+
1042
+ i32 _memory_pages = _memoryPages;
1043
+ char* _memory_clone = calloc(1, _memory_pages * ${PageSize});
1044
+ memcpy(_memory_clone, _memory, _memory_pages * ${PageSize});
1045
+
1046
+ ${copyGlobals}
1047
+
1048
+ char *api = getenv("AWS_LAMBDA_RUNTIME_API");
1049
+ if (!api) {
1050
+ // Not in Lambda — error
1051
+ printf("AWS_LAMBDA_RUNTIME_API not set\\n");
1052
+ exit(1);
1053
+ }
1054
+
1055
+ char host[256], port[16] = "80";
1056
+ char *colon = strchr(api, ':');
1057
+ if (colon) {
1058
+ strncpy(host, api, colon - api);
1059
+ host[colon - api] = '\\0';
1060
+ strncpy(port, colon + 1, sizeof(port) - 1);
1061
+ } else {
1062
+ strncpy(host, api, sizeof(host) - 1);
1063
+ }
1064
+
1065
+ char req[BUF_SIZE], resp[BUF_SIZE];
1066
+ char request_id[128];
1067
+
1068
+ i32 request_count = 0;
1069
+ while (1) {
1070
+ // 1. GET next event
1071
+ snprintf(req, sizeof(req),
1072
+ "GET /2018-06-01/runtime/invocation/next HTTP/1.1\\r\\n"
1073
+ "Host: %s\\r\\n\\r\\n", host);
1074
+ if (send_http(host, port, req, resp, sizeof(resp)) <= 0) {
1075
+ fprintf(stderr, "send_http failed\\n");
1076
+ break;
1077
+ }
1078
+
1079
+ char *rid = strstr(resp, "Lambda-Runtime-Aws-Request-Id: ");
1080
+ if (!rid) {
1081
+ fprintf(stderr, "No Request ID header in response:\\n%s\\n", resp);
1082
+ break;
1083
+ }
1084
+
1085
+ rid += strlen("Lambda-Runtime-Aws-Request-Id: ");
1086
+ char *end = strchr(rid, '\\r');
1087
+ if (!end) {
1088
+ fprintf(stderr, "No CR after Request ID in response:\\n%s\\n", resp);
1089
+ break;
1090
+ }
1091
+ size_t rid_len = end - rid;
1092
+ strncpy(request_id, rid, rid_len);
1093
+ request_id[rid_len] = '\\0';
1094
+
1095
+ // 2. Parse event data from response body
1096
+ char *body = strstr(resp, "\\r\\n\\r\\n");
1097
+ void *event = NULL;
1098
+ if (body) {
1099
+ body += 4; // skip \\r\\n\\r\\n
1100
+ event = body;
1101
+ }
1102
+
1103
+ if (request_count++ > 0) {
1104
+ _memoryPages = _memory_pages;
1105
+ free(_memory);
1106
+ _memory = calloc(1, _memory_pages * ${PageSize});
1107
+ memcpy(_memory, _memory_clone, _memory_pages * ${PageSize});
1108
+
1109
+ ${restoreGlobals}
1110
+ }
1111
+
1112
+ // Call handler function and JSON.stringify the result
1113
+ // size_t eventLen = strlen(event);
1114
+ // i32 eventPtr = __Porffor_allocateBytes(eventLen + 4);
1115
+ // memcpy((char*)eventPtr, &eventLen, 4);
1116
+ // memcpy((char*)eventPtr + 4, event, eventLen);
1117
+
1118
+ // char* resp = _memory + (i32)__Porffor_handler((f64)eventPtr, 195).value + 4;
1119
+ i32 ret = (i32)__Porffor_handler().value;
1120
+ char* ret_str = _memory + ret + 4;
1121
+ i32 ret_str_len = *((i32*)(ret_str - 4));
1122
+
1123
+ // 3. POST response
1124
+ snprintf(req, sizeof(req),
1125
+ "POST /2018-06-01/runtime/invocation/%s/response HTTP/1.1\\r\\n"
1126
+ "Host: %s\\r\\n"
1127
+ "Content-Type: text/plain\\r\\n"
1128
+ "Content-Length: %zu\\r\\n\\r\\n"
1129
+ "%s", request_id, host, ret_str_len, ret_str);
1130
+ send_http(host, port, req, resp, sizeof(resp));
1131
+ }
1132
+ return 0;
1133
+ }`;
1134
+ out += lambdaWrapper;
1135
+
1136
+ // preallocate 1 chunk allocator chunk
1137
+ // out = out.replace(`_memory = calloc(1, _memoryPages * ${PageSize});\n`, `
1138
+ // jjporfjjchunkPtr = _memoryPages * 65536;
1139
+ // jjporfjjchunkOffset = 0;
1140
+ // _memoryPages += 16;
1141
+ // _memory = calloc(1, _memoryPages * ${PageSize});`);
1142
+ }
1143
+
972
1144
  const makeIncludes = includes => [...includes.keys()].map(x => `#include <${x}>\n`).join('');
973
1145
  out = platformSpecific(makeIncludes(winIncludes), makeIncludes(unixIncludes), false) + '\n' + makeIncludes(includes) + '\n' + alwaysPreface + [...prepend.values()].join('\n') + '\n\n' + out;
974
1146
 
package/compiler/index.js CHANGED
@@ -284,7 +284,7 @@ int m()`);
284
284
  console.log(`\u001b[2m[${total.toFixed(0)}ms]\u001b[0m \u001b[32mcompiled ${globalThis.file} \u001b[90m->\u001b[0m \u001b[92m${outFile}\u001b[90m (${(fs.statSync(outFile).size / 1000).toFixed(1)}KB)\u001b[0m`);
285
285
  }
286
286
 
287
- if (process.version) process.exit();
287
+ if (process.version && !Prefs.lambda) process.exit();
288
288
  }
289
289
 
290
290
  if (target === 'native') {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "porffor",
3
3
  "description": "An ahead-of-time JavaScript compiler",
4
- "version": "0.60.5",
4
+ "version": "0.60.6",
5
5
  "author": "Oliver Medhurst <honk@goose.icu>",
6
6
  "license": "MIT",
7
7
  "scripts": {},
package/runtime/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from 'node:fs';
3
- globalThis.version = '0.60.5';
3
+ globalThis.version = '0.60.6';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
@@ -9,7 +9,7 @@ if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
9
9
 
10
10
  const start = performance.now();
11
11
 
12
- if (process.argv.includes('--help') || process.argv.includes('-h')) {
12
+ const help = () => {
13
13
  // description + version
14
14
  console.log(`\x1B[1m\x1B[35mPorffor\x1B[0m is a JavaScript/TypeScript engine/compiler/runtime. \x1B[2m(${globalThis.version})\x1B[0m`);
15
15
 
@@ -23,6 +23,7 @@ if (process.argv.includes('--help') || process.argv.includes('-h')) {
23
23
  wasm: [ 34, 'foo.js foo.wasm', 'Compile to a Wasm binary' ],
24
24
  c: [ 94, 'foo.js foo.c', 'Compile to C source code' ],
25
25
  native: [ 94, 'foo.js foo', 'Compile to a native binary' ],
26
+ lambda: [ 36, 'foo.js function.zip', 'Compile Lambda code to a deployable zip' ],
26
27
 
27
28
  'Analyze': [],
28
29
  profile: [ 93, 'foo.js', 'View detailed func-by-func performance' ],
@@ -81,6 +82,10 @@ if (process.argv.includes('--help') || process.argv.includes('-h')) {
81
82
 
82
83
  console.log();
83
84
  process.exit(0);
85
+ };
86
+
87
+ if (process.argv.includes('--help') || process.argv.includes('-h')) {
88
+ help();
84
89
  }
85
90
 
86
91
  const done = async () => {
@@ -90,7 +95,9 @@ const done = async () => {
90
95
  };
91
96
 
92
97
  let file = process.argv.slice(2).find(x => x[0] !== '-');
93
- if (['precompile', 'run', 'wasm', 'native', 'c', 'profile', 'debug', 'dissect'].includes(file)) {
98
+ if (file === 'help') help();
99
+
100
+ if (['precompile', 'run', 'wasm', 'native', 'c', 'lambda', 'profile', 'debug'].includes(file)) {
94
101
  // remove this arg
95
102
  process.argv.splice(process.argv.indexOf(file), 1);
96
103
 
@@ -113,9 +120,10 @@ if (['precompile', 'run', 'wasm', 'native', 'c', 'profile', 'debug', 'dissect'].
113
120
  process.argv.push(`--target=${file}`);
114
121
  }
115
122
 
116
- // if (file === 'dissect') {
117
- // process.argv.push('--asur', '--wasm-debug');
118
- // }
123
+ if (file === 'lambda') {
124
+ await import('./lambda.js');
125
+ await done();
126
+ }
119
127
 
120
128
  file = process.argv.slice(2).find(x => x[0] !== '-');
121
129
 
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import { execSync } from 'node:child_process';
4
+ import compile from '../compiler/wrap.js';
5
+
6
+ // Parse arguments
7
+ const args = process.argv.slice(2);
8
+ const sourceFile = args.find(x => x[0] !== '-' && !x.includes('='));
9
+ const outputZip = args.find(x => x[0] !== '-' && !x.includes('=') && x !== sourceFile);
10
+
11
+ console.log(`Compiling ${sourceFile} to AWS Lambda function...`);
12
+
13
+ // Read source file
14
+ const source = `${fs.readFileSync(sourceFile, 'utf8').replace('handler = async', 'handler =')}
15
+
16
+ export const __Porffor_handler = () => {
17
+ const res = handler();
18
+ if (Porffor.type(res) == Porffor.TYPES.bytestring) return res;
19
+ return JSON.stringify(res);
20
+ };`;
21
+
22
+ const binaryPath = 'bootstrap';
23
+ const cPath = 'bootstrap.c';
24
+
25
+ Prefs.allocator = 'oneshot'; // oneshot is faster for lambda
26
+ Prefs.target = 'c';
27
+ Prefs.o = cPath;
28
+ Prefs.lambda = true;
29
+
30
+ compile(source, true);
31
+
32
+ if (Prefs.d) execSync(`gcc -lm -O0 -g -flto -march=x86-64-v3 -o ${binaryPath} ${cPath}`, { stdio: 'inherit' });
33
+ else execSync(`gcc -lm -Os -s -flto -march=x86-64-v3 -o ${binaryPath} ${cPath}`, { stdio: 'inherit' });
34
+
35
+ try {
36
+ execSync(`zip -r "${outputZip}" ${binaryPath}`, { stdio: 'inherit' });
37
+ console.log(`Lambda function packaged to ${outputZip}`);
38
+ } catch (e) {
39
+ console.error('Error creating zip file:', e.message);
40
+ process.exit(1);
41
+ } finally {
42
+ if (!Prefs.d) {
43
+ fs.rmSync(binaryPath, { force: true });
44
+ fs.rmSync(cPath, { force: true });
45
+ }
46
+ }
package/foo.js DELETED
@@ -1,9 +0,0 @@
1
- const func = () => {
2
- let before = 0;
3
-
4
- TypeError('wow');
5
-
6
- let after = 1;
7
- };
8
-
9
- func();