porffor 0.60.5 → 0.60.7

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 += '}';
@@ -426,6 +429,7 @@ export default ({ funcs, globals, data, pages }) => {
426
429
  for (const name in symbols) {
427
430
  line(`*(void**)(&${name}) = dlsym(_dl, "${name}")`);
428
431
  ffiFuncs[name] = symbols[name];
432
+ cified.add(name, true);
429
433
  }
430
434
 
431
435
  continue;
@@ -639,9 +643,13 @@ extern ${importFunc.returns.length > 0 ? CValtype[importFunc.returns[0]] : 'void
639
643
 
640
644
  case 'time': {
641
645
  const id = tmpId++;
642
- line(`time_t _time_t${id}`);
643
- line(`time(&_time_t${id})`);
644
- line(`f64 _time_out${id} = (f64)_time_t${id} * 1000.0`);
646
+ platformSpecific(`
647
+ time_t _time_t${id};
648
+ time(&_time_t${id});
649
+ f64 _time_out${id} = (f64)_time_t${id} * 1000.0;`, `
650
+ struct timespec _ts${id};
651
+ clock_gettime(CLOCK_REALTIME, &_ts${id});
652
+ f64 _time_out${id} = (f64)_ts${id}.tv_sec * 1000.0 + (f64)_ts${id}.tv_nsec / 1.0e6;`);
645
653
  vals.push(`_time_out${id}`);
646
654
 
647
655
  includes.set('time.h', true);
@@ -969,6 +977,175 @@ extern ${importFunc.returns.length > 0 ? CValtype[importFunc.returns[0]] : 'void
969
977
  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
978
  }).join('\n'));
971
979
 
980
+ if (Prefs.lambda) {
981
+ includes.set('stdio.h', true);
982
+ includes.set('stdlib.h', true);
983
+ includes.set('string.h', true);
984
+ includes.set('unistd.h', true);
985
+ includes.set('netdb.h', true);
986
+ includes.set('sys/socket.h', true);
987
+ includes.set('signal.h', true);
988
+ includes.set('execinfo.h', true);
989
+
990
+ let copyGlobals = '';
991
+ let restoreGlobals = '';
992
+ for (const x in globals) {
993
+ const g = globals[x];
994
+
995
+ copyGlobals += `${CValtype[g.type]} copy_${sanitize(x)} = ${sanitize(x)};\n`;
996
+ restoreGlobals += `${sanitize(x)} = copy_${sanitize(x)};\n`;
997
+ }
998
+
999
+ const lambdaWrapper = `
1000
+ #define BUF_SIZE 65536
1001
+
1002
+ // minimal http send/receive
1003
+ static int send_http(const char *host, const char *port, const char *req, char *resp, size_t resp_size) {
1004
+ struct addrinfo hints = {0}, *res;
1005
+ int sock;
1006
+ hints.ai_family = AF_UNSPEC;
1007
+ hints.ai_socktype = SOCK_STREAM;
1008
+ if (getaddrinfo(host, port, &hints, &res) != 0) return -1;
1009
+
1010
+ sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
1011
+ if (sock < 0) return -1;
1012
+ if (connect(sock, res->ai_addr, res->ai_addrlen) != 0) {
1013
+ close(sock);
1014
+ freeaddrinfo(res);
1015
+ return -1;
1016
+ }
1017
+
1018
+ write(sock, req, strlen(req));
1019
+
1020
+ int len = 0;
1021
+ if (resp) {
1022
+ len = read(sock, resp, resp_size - 1);
1023
+ if (len >= 0) resp[len] = '\\0';
1024
+ }
1025
+
1026
+ close(sock);
1027
+ freeaddrinfo(res);
1028
+ return len;
1029
+ }
1030
+
1031
+ void crash_handler(int sig) {
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);
1037
+ }
1038
+
1039
+ 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
+ user_main();
1046
+
1047
+ i32 _memory_pages = _memoryPages;
1048
+ char* _memory_clone = calloc(1, _memory_pages * ${PageSize});
1049
+ memcpy(_memory_clone, _memory, _memory_pages * ${PageSize});
1050
+
1051
+ ${copyGlobals}
1052
+
1053
+ char *api = getenv("AWS_LAMBDA_RUNTIME_API");
1054
+ if (!api) {
1055
+ // Not in Lambda — error
1056
+ printf("AWS_LAMBDA_RUNTIME_API not set\\n");
1057
+ exit(1);
1058
+ }
1059
+
1060
+ char host[256], port[16] = "80";
1061
+ char *colon = strchr(api, ':');
1062
+ if (colon) {
1063
+ strncpy(host, api, colon - api);
1064
+ host[colon - api] = '\\0';
1065
+ strncpy(port, colon + 1, sizeof(port) - 1);
1066
+ } else {
1067
+ strncpy(host, api, sizeof(host) - 1);
1068
+ }
1069
+
1070
+ char req[BUF_SIZE], resp[BUF_SIZE];
1071
+ char request_id[128];
1072
+
1073
+ i32 request_count = 0;
1074
+ while (1) {
1075
+ // 1. GET next event
1076
+ snprintf(req, sizeof(req),
1077
+ "GET /2018-06-01/runtime/invocation/next HTTP/1.1\\r\\n"
1078
+ "Host: %s\\r\\n\\r\\n", host);
1079
+ if (send_http(host, port, req, resp, sizeof(resp)) <= 0) {
1080
+ fprintf(stderr, "send_http failed\\n");
1081
+ break;
1082
+ }
1083
+
1084
+ char *rid = strstr(resp, "Lambda-Runtime-Aws-Request-Id: ");
1085
+ if (!rid) {
1086
+ fprintf(stderr, "No Request ID header in response:\\n%s\\n", resp);
1087
+ break;
1088
+ }
1089
+
1090
+ rid += strlen("Lambda-Runtime-Aws-Request-Id: ");
1091
+ char *end = strchr(rid, '\\r');
1092
+ if (!end) {
1093
+ fprintf(stderr, "No CR after Request ID in response:\\n%s\\n", resp);
1094
+ break;
1095
+ }
1096
+ size_t rid_len = end - rid;
1097
+ strncpy(request_id, rid, rid_len);
1098
+ request_id[rid_len] = '\\0';
1099
+
1100
+ // 2. Parse event data from response body
1101
+ char *body = strstr(resp, "\\r\\n\\r\\n");
1102
+ void *event = NULL;
1103
+ if (body) {
1104
+ body += 4; // skip \\r\\n\\r\\n
1105
+ event = body;
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
+
1117
+ // Call handler function and JSON.stringify the result
1118
+ // size_t eventLen = strlen(event);
1119
+ // i32 eventPtr = __Porffor_allocateBytes(eventLen + 4);
1120
+ // memcpy((char*)eventPtr, &eventLen, 4);
1121
+ // memcpy((char*)eventPtr + 4, event, eventLen);
1122
+
1123
+ // char* resp = _memory + (i32)__Porffor_handler((f64)eventPtr, 195).value + 4;
1124
+ i32 ret = (i32)__Porffor_handler().value;
1125
+ char* ret_str = _memory + ret + 4;
1126
+ i32 ret_str_len = *((i32*)(ret_str - 4));
1127
+
1128
+ // 3. POST response
1129
+ snprintf(req, sizeof(req),
1130
+ "POST /2018-06-01/runtime/invocation/%s/response HTTP/1.1\\r\\n"
1131
+ "Host: %s\\r\\n"
1132
+ "Content-Type: text/plain\\r\\n"
1133
+ "Content-Length: %zu\\r\\n\\r\\n"
1134
+ "%s", request_id, host, ret_str_len, ret_str);
1135
+ send_http(host, port, req, resp, sizeof(resp));
1136
+ }
1137
+ return 0;
1138
+ }`;
1139
+ out += lambdaWrapper;
1140
+
1141
+ // preallocate 1 chunk allocator chunk
1142
+ // out = out.replace(`_memory = calloc(1, _memoryPages * ${PageSize});\n`, `
1143
+ // jjporfjjchunkPtr = _memoryPages * 65536;
1144
+ // jjporfjjchunkOffset = 0;
1145
+ // _memoryPages += 16;
1146
+ // _memory = calloc(1, _memoryPages * ${PageSize});`);
1147
+ }
1148
+
972
1149
  const makeIncludes = includes => [...includes.keys()].map(x => `#include <${x}>\n`).join('');
973
1150
  out = platformSpecific(makeIncludes(winIncludes), makeIncludes(unixIncludes), false) + '\n' + makeIncludes(includes) + '\n' + alwaysPreface + [...prepend.values()].join('\n') + '\n\n' + out;
974
1151
 
@@ -2638,7 +2638,8 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2638
2638
  args.push({
2639
2639
  type: 'ArrayExpression',
2640
2640
  elements: restArgs,
2641
- _doNotMarkTypeUsed: true
2641
+ _doNotMarkTypeUsed: true,
2642
+ _staticAlloc: func.internal
2642
2643
  });
2643
2644
  }
2644
2645
  }
@@ -5594,7 +5595,7 @@ const generateArray = (scope, decl, global = false, name = '$undeclared', static
5594
5595
  const out = [];
5595
5596
  let pointer;
5596
5597
 
5597
- if (staticAlloc) {
5598
+ if (staticAlloc || decl._staticAlloc) {
5598
5599
  const uniqueName = name === '$undeclared' ? name + uniqId() : name;
5599
5600
 
5600
5601
  const ptr = allocPage({ scope, pages }, uniqueName);
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.7",
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.7';
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();
File without changes