diff --git a/src/core/core.ts b/src/core/core.ts index 2de05b0..1973467 100644 --- a/src/core/core.ts +++ b/src/core/core.ts @@ -117,8 +117,9 @@ export namespace HashHelpers } export function hashCodeAny(key: any): int { - let keyLocal = key; - const anyPtr = Deref(> Ref(keyLocal)); + // the parameter's own slot: a copy of it in a local is a second reference, which -mm=own + // cannot give an exported function's parameter + const anyPtr = Deref(> Ref(key)); let anyStruct: Reference<[size: index, type: string, data: byte]> = anyPtr; return hashCodeBinary(Ref(anyStruct.data), anyStruct.size); } diff --git a/src/lib.d.ts b/src/lib.d.ts index 4f1135a..d24dd4e 100644 --- a/src/lib.d.ts +++ b/src/lib.d.ts @@ -15,6 +15,7 @@ declare namespace __Boolean { function toString(this: boolean): string; } +@final declare class Boolean { private value: boolean; @@ -36,6 +37,7 @@ declare namespace __Number { function toString(this: number, radix?: int): string; } +@final declare class Number { static EPSILON: number; @@ -101,6 +103,7 @@ declare namespace __BigInt { function toString(this: bigint): string; } +@final declare class BigInt { private value: bigint; @@ -113,6 +116,7 @@ declare class BigInt { valueOf(): bigint; } +@final declare class Date { private timestamp: time_t; @@ -217,6 +221,7 @@ declare class Date { [Symbol.toPrimitive](hint: string) : string | number; } +@final declare class MatchIndicesResults { private match: Opaque | null; @@ -232,6 +237,7 @@ declare class MatchIndicesResults get length(): index; } +@final declare class MatchResults { private indices_: MatchIndicesResults; @@ -253,6 +259,7 @@ declare class MatchResults get indices(): MatchIndicesResults/* | undefined*/; } +@final declare class RegExp { dotAll: boolean; @@ -357,6 +364,7 @@ declare namespace __String { function valueOf(this: string): string; } +@final declare class String { private value: string; @@ -639,6 +647,7 @@ declare namespace Math { function trunc(x: number): number; } +@final declare class Headers { private names: string[]; private values: string[]; @@ -660,6 +669,7 @@ declare class Headers { toRawString(): string; } +@final declare class Response { status: int; headers: Headers; diff --git a/src/lib.linux.ts b/src/lib.linux.ts index 044820d..50d2791 100644 --- a/src/lib.linux.ts +++ b/src/lib.linux.ts @@ -5,14 +5,14 @@ type errno_t = i32; type time_t = long; // locale -declare function setlocale (category: int, locale: string): void; -declare function newlocale (category: int, locale: string, base: Opaque | null): Opaque; -declare function uselocale (locale: Opaque): Opaque; -declare function freelocale (locale: Opaque): void; +@nodrops declare function setlocale (category: int, locale: string): void; +@nodrops declare function newlocale (category: int, locale: string, base: Opaque | null): Opaque; +@nodrops declare function uselocale (locale: Opaque): Opaque; +@nodrops declare function freelocale (locale: Opaque): void; // LC_TIME @varargs -declare function snprintf(out: string, n: index, format: string): void; +@nodrops declare function snprintf(out: string, n: index, format: string): void; export function convertNumber(bufferSize: int, format: string, value: number): string { @@ -36,13 +36,13 @@ export function convertInteger(bufferSize: int, format: string, value: i32): str // Date & Time -declare function tzset(); +@nodrops declare function tzset(); export function init_time() { tzset(); } type timeval = [tv_sec: i64, tv_usec: i32]; -declare function timespec_get(tv: Reference, base: int): int; +@nodrops declare function timespec_get(tv: Reference, base: int): int; const TIME_UTC = 1; export function getMilliseconds(): i64 { @@ -60,7 +60,7 @@ type tm = [tm_sec: i32, tm_min: i32, tm_hour: i32, tm_mday: i32, tm_mon: i32, tm // struct, and strftime's %z and %Z read the last two, so every C call takes this one. type c_tm = [tm_sec: i32, tm_min: i32, tm_hour: i32, tm_mday: i32, tm_mon: i32, tm_year: i32, tm_wday: i32, tm_yday: i32, tm_isdst: i32, tm_gmtoff: index, tm_zone: index]; -declare function timegm(tv: Reference): long; +@nodrops declare function timegm(tv: Reference): long; export function makegmtime(year: i32, month: i32, day: i32, hour: i32, minutes: i32, seconds: i32, milliseconds: i32): i64 { let tm1: c_tm = [seconds, minutes, hour, day, month, year, 0, 0, 0, 0, 0]; const sec = timegm(Ref(tm1)); @@ -73,7 +73,7 @@ export function makegmtime(year: i32, month: i32, day: i32, hour: i32, minutes: return sec * 1000 + milliseconds; // return ms } -declare function mktime(tv: Reference): long; +@nodrops declare function mktime(tv: Reference): long; export function maketime(year: i32, month: i32, day: i32, hour: i32, minutes: i32, seconds: i32, milliseconds: i32): i64 { // tm_isdst -1: a local time is in daylight saving time or not as the date says (0 would read // a summer date as standard time, an hour off) @@ -88,8 +88,8 @@ export function maketime(year: i32, month: i32, day: i32, hour: i32, minutes: i3 return sec * 1000 + milliseconds; // return ms } -declare function gmtime_r(time: Reference, tm: Reference) : Reference; -declare function localtime_r(time: Reference, tm: Reference) : Reference; +@nodrops declare function gmtime_r(time: Reference, tm: Reference) : Reference; +@nodrops declare function localtime_r(time: Reference, tm: Reference) : Reference; function c_time(time: long, isUtc: boolean): c_tm { let tmDest: c_tm = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; let timeInSec: time_t = time / 1000; @@ -120,7 +120,7 @@ export function gettimezone(): i32 { } // returns `buffer`: a pointer, not copied -declare function ctime_r(time: Reference, buffer: string): Opaque; +@nodrops declare function ctime_r(time: Reference, buffer: string): Opaque; export function timestamp_to_string(maxsize: index, time: long): string { let timeInSec: time_t = time / 1000; let buffer : char[] = []; @@ -130,7 +130,7 @@ export function timestamp_to_string(maxsize: index, time: long): string { return s; } -declare function asctime_r(time: Reference, buffer: string): Opaque; +@nodrops declare function asctime_r(time: Reference, buffer: string): Opaque; export function time_to_string(maxsize: index, time: long, isUtc: boolean): string { let tm = c_time(time, isUtc); @@ -141,7 +141,7 @@ export function time_to_string(maxsize: index, time: long, isUtc: boolean): stri return s; } -declare function strftime(out: string, maxsize: index, format: string, tm: Reference): index; +@nodrops declare function strftime(out: string, maxsize: index, format: string, tm: Reference): index; export function time_format(maxsize: index, format: string, time: long, isUtc: boolean): string { let tm = c_time(time, isUtc); @@ -152,7 +152,7 @@ export function time_format(maxsize: index, format: string, time: long, isUtc: b return s; } -declare function strftime_l(out: string, maxsize: index, format: string, tm: Reference, locale: Opaque): index; +@nodrops declare function strftime_l(out: string, maxsize: index, format: string, tm: Reference, locale: Opaque): index; export function time_format_locale(maxsize: index, format: string, time: long, locale: string, isUtc: boolean): string { let tm = c_time(time, isUtc); diff --git a/src/lib.ts b/src/lib.ts index e83834a..89a8ef7 100644 --- a/src/lib.ts +++ b/src/lib.ts @@ -28,6 +28,7 @@ namespace __Boolean { } } +@final export class Boolean { public constructor(private value: boolean) { } @@ -65,6 +66,7 @@ namespace __Number { } } +@final export class Number { public static EPSILON = 2 ** (-52); @@ -158,6 +160,7 @@ namespace __BigInt { } } +@final export class BigInt { public constructor(private value: bigint) { } @@ -175,6 +178,7 @@ export class BigInt { } } +@final export class Date { private timestamp: time_t; constructor (valueOrYear?: time_t | i32, monthIndex?: i32, day = 1, hours = 0, minutes = 0, seconds = 0, milliseconds = 0) { @@ -436,6 +440,7 @@ export class Date { } } +@final export class MatchIndicesResults { constructor(private match: Opaque | null = null, private lastIndex: index = 0) { @@ -455,6 +460,7 @@ export class MatchIndicesResults } } +@final export class MatchResults { private indices_: MatchIndicesResults = null; @@ -479,10 +485,13 @@ export class MatchResults // TODO: finish it //if (!this.hasIndices) // return undefined; - return this.indices_ ??= new MatchIndicesResults(this.match, this.lastIndex); + // a new one each time: it holds no state of its own, and a cached one in a field could + // only be lent out, never returned, under -mm=own + return new MatchIndicesResults(this.match, this.lastIndex); } } +@final export class RegExp { dotAll = false; @@ -1284,6 +1293,7 @@ class StringIterator implements ClassIterator { } */ +@final export class String { public constructor(private value: string) { @@ -1780,6 +1790,7 @@ enum States { View = 8, } +@final export class ArrayBuffer { private arrayOfView: char[]; @@ -1831,7 +1842,7 @@ export class ArrayBuffer { const newArrayBuffer = new ArrayBuffer(0); newArrayBuffer.states = this.states | States.NonResizable; newArrayBuffer.maxByteLength = this.maxByteLength; - newArrayBuffer.arrayOfView = this.arrayOfView.view(start, end); + newArrayBuffer.arrayOfView = this.copyOf(start, end); return newArrayBuffer; } @@ -1840,7 +1851,11 @@ export class ArrayBuffer { const newArrayBuffer = new ArrayBuffer(0); newArrayBuffer.states = this.states; newArrayBuffer.maxByteLength = this.maxByteLength; - newArrayBuffer.arrayOfView = this.detach(); + if (this.arrayOfView != null) { + newArrayBuffer.arrayOfView = this.copyOf(0, this.arrayOfView.length); + } + + this.detach(); return newArrayBuffer; } @@ -1850,21 +1865,33 @@ export class ArrayBuffer { return newArrayBuffer; } + // The bytes [start, end) in an array of their own. A slice is a copy, as in JavaScript, and a + // transfer copies too: the bytes cannot move out of the field into another object under + // -mm=own, where a read of a field only borrows it. + private copyOf(start: int, end: int): char[] { + let copy: char[] = []; + copy.length = end - start; + for (let i = start; i < end; i++) { + copy[i - start] = this.arrayOfView[i]; + } + + return copy; + } + private detach() { this.states |= States.Detached; - const inst = this.arrayOfView; this.arrayOfView = null; - return inst; } + // the assignment releases the bytes under rc and own, and leaves them to the collector under gc [Symbol.dispose]() { if (this.arrayOfView != null && !this.detached) { - delete this.arrayOfView; this.arrayOfView = null; } } } +@final export class Headers { private names: string[]; private values: string[]; @@ -1874,7 +1901,9 @@ export class Headers { this.values = []; if (init != undefined) { - for (const [k, v] of init) this.set(k, v); + // copies: set may overwrite an element of this.values, and under -mm=own a call that + // may destroy anything cannot be lent the caller's strings + for (const [k, v] of init) this.set(k + "", v + ""); } } @@ -1963,6 +1992,7 @@ export class Headers { } } +@final export class Response { public constructor( public status: int, diff --git a/src/lib.win32.ts b/src/lib.win32.ts index d524eb4..5404a66 100644 --- a/src/lib.win32.ts +++ b/src/lib.win32.ts @@ -5,12 +5,12 @@ type errno_t = i32; type time_t = long; // locale -declare function _create_locale (category: int, locale: string): Opaque; -declare function _free_locale (locale: Opaque): void; +@nodrops declare function _create_locale (category: int, locale: string): Opaque; +@nodrops declare function _free_locale (locale: Opaque): void; // LC_TIME @varargs -declare function sprintf_s(out: string, n: index, format: string): void; +@nodrops declare function sprintf_s(out: string, n: index, format: string): void; export function convertNumber(bufferSize: int, format: string, value: number): string { @@ -33,13 +33,13 @@ export function convertInteger(bufferSize: int, format: string, value: i32): str } // Date & Time -declare function _tzset(); +@nodrops declare function _tzset(); export function init_time() { _tzset(); } type timeval64 = [tv_sec: i64, tv_usec: i32]; -declare function _timespec64_get(tv: Reference, base: int): int; +@nodrops declare function _timespec64_get(tv: Reference, base: int): int; const TIME_UTC = 1; export function getMilliseconds(): i64 { @@ -49,7 +49,7 @@ export function getMilliseconds(): i64 { } type tm = [tm_sec: i32, tm_min: i32, tm_hour: i32, tm_mday: i32, tm_mon: i32, tm_year: i32, tm_wday: i32, tm_yday: i32, tm_isdst: i32]; -declare function _mkgmtime64(tv: Reference): long; +@nodrops declare function _mkgmtime64(tv: Reference): long; export function makegmtime(year: i32, month: i32, day: i32, hour: i32, minutes: i32, seconds: i32, milliseconds: i32): i64 { let tm1: tm = [seconds, minutes, hour, day, month, year, 0, 0, 0]; const sec = _mkgmtime64(Ref(tm1)); @@ -62,7 +62,7 @@ export function makegmtime(year: i32, month: i32, day: i32, hour: i32, minutes: return sec * 1000 + milliseconds; // return ms } -declare function _mktime64(tv: Reference): long; +@nodrops declare function _mktime64(tv: Reference): long; export function maketime(year: i32, month: i32, day: i32, hour: i32, minutes: i32, seconds: i32, milliseconds: i32): i64 { // tm_isdst -1: a local time is in daylight saving time or not as the date says (0 would read // a summer date as standard time, an hour off) @@ -77,7 +77,7 @@ export function maketime(year: i32, month: i32, day: i32, hour: i32, minutes: i3 return sec * 1000 + milliseconds; // return ms } -declare function _gmtime64_s(tm: Reference, time: Reference) : errno_t; +@nodrops declare function _gmtime64_s(tm: Reference, time: Reference) : errno_t; export function gmtime(time: long): tm { let tmDest: tm = [0, 0, 0, 0, 0, 0, 0, 0, 0]; let timeInSec: long = time / 1000; @@ -85,7 +85,7 @@ export function gmtime(time: long): tm { return tmDest; // return ms } -declare function _localtime64_s(tm: Reference, time: Reference) : errno_t; +@nodrops declare function _localtime64_s(tm: Reference, time: Reference) : errno_t; export function localtime(time: long): tm { let tmDest: tm = [0, 0, 0, 0, 0, 0, 0, 0, 0]; let timeInSec: long = time / 1000; @@ -93,7 +93,7 @@ export function localtime(time: long): tm { return tmDest; // return ms } -declare function _get_timezone(time: Reference): int; +@nodrops declare function _get_timezone(time: Reference): int; export function gettimezone(): i32 { let time = 0; const error = _get_timezone(Ref(time)); @@ -101,7 +101,7 @@ export function gettimezone(): i32 { } // errno_t, not a string: declared `string`, a nonzero error would be copied as one -declare function _ctime64_s(buffer: string, numberOfElements: index, time: Reference): int; +@nodrops declare function _ctime64_s(buffer: string, numberOfElements: index, time: Reference): int; export function timestamp_to_string(maxsize: index, time: long): string { let timeInSec: time_t = time / 1000; let buffer : char[] = []; @@ -112,7 +112,7 @@ export function timestamp_to_string(maxsize: index, time: long): string { } // errno_t -declare function asctime_s(buffer: string, numberOfElements: index, time: Reference): int; +@nodrops declare function asctime_s(buffer: string, numberOfElements: index, time: Reference): int; export function time_to_string(maxsize: index, time: long, isUtc: boolean): string { let tm = isUtc ? gmtime(time) : localtime(time); @@ -123,7 +123,7 @@ export function time_to_string(maxsize: index, time: long, isUtc: boolean): stri return s; } -declare function strftime(out: string, maxsize: index, format: string, tm: Reference): index; +@nodrops declare function strftime(out: string, maxsize: index, format: string, tm: Reference): index; export function time_format(maxsize: index, format: string, time: long, isUtc: boolean): string { let tm = isUtc ? gmtime(time) : localtime(time); @@ -134,7 +134,7 @@ export function time_format(maxsize: index, format: string, time: long, isUtc: b return s; } -declare function _strftime_l(out: string, maxsize: index, format: string, tm: Reference, locale: Opaque): index; +@nodrops declare function _strftime_l(out: string, maxsize: index, format: string, tm: Reference, locale: Opaque): index; export function time_format_locale(maxsize: index, format: string, time: long, locale: string, isUtc: boolean): string { let tm = isUtc ? gmtime(time) : localtime(time); diff --git a/src/native/lib.native.d.ts b/src/native/lib.native.d.ts index 20a6b8d..0ec4f0b 100644 --- a/src/native/lib.native.d.ts +++ b/src/native/lib.native.d.ts @@ -1,95 +1,99 @@ +// `@nodrops`: a C function that destroys nothing the TypeScript program owns, so -mm=own may lend +// it a borrow (a field, an element) and keep using that borrow after the call. Only for functions +// that never call back into TypeScript; the GC_* ones below can run finalizers and have none. + // IO -declare function write(fileNo: int, s: string, count: int); +@nodrops declare function write(fileNo: int, s: string, count: int); // Buffered counterpart of write(), sharing stdio's buffer with print()/puts() so the // two cannot reorder relative to each other. See src/wrappers/io.cpp. -declare function stdio_write(fileNo: int, s: string, count: int); +@nodrops declare function stdio_write(fileNo: int, s: string, count: int); // Time (in seconds) -declare function time(destTime: Reference); +@nodrops declare function time(destTime: Reference); // String -declare function strtol(str: string, end: Reference, base: int): int; -declare function strtod(str: string, end: Reference): double; -declare function strncmp(str: string, other: string, count: index): int; +@nodrops declare function strtol(str: string, end: Reference, base: int): int; +@nodrops declare function strtod(str: string, end: Reference): double; +@nodrops declare function strncmp(str: string, other: string, count: index): int; // a pointer into `str`, not a string of its own: a `string` result from C is copied -declare function strstr(str: string, other: string): Opaque; -declare function strcoll(str: string, other: string): int; -declare function setlocale (category: int, locale: string): Opaque; -declare function toupper(c: int): int; -declare function tolower(c: int): int; -declare function isspace(argument: int): int; +@nodrops declare function strstr(str: string, other: string): Opaque; +@nodrops declare function strcoll(str: string, other: string): int; +@nodrops declare function setlocale (category: int, locale: string): Opaque; +@nodrops declare function toupper(c: int): int; +@nodrops declare function tolower(c: int): int; +@nodrops declare function isspace(argument: int): int; // Random -declare function srand(seed: int); +@nodrops declare function srand(seed: int); -declare function rand(): int; +@nodrops declare function rand(): int; // Math -declare function fabs(x: number): number; +@nodrops declare function fabs(x: number): number; -declare function acos(x: number): number; +@nodrops declare function acos(x: number): number; -declare function acosh(x: number): number; +@nodrops declare function acosh(x: number): number; -declare function asin(x: number): number; +@nodrops declare function asin(x: number): number; -declare function asinh(x: number): number; +@nodrops declare function asinh(x: number): number; -declare function atan(x: number): number; +@nodrops declare function atan(x: number): number; -declare function atan2(y: number, x: number): number; +@nodrops declare function atan2(y: number, x: number): number; -declare function atanh(x: number): number; +@nodrops declare function atanh(x: number): number; -declare function cbrt(x: number): number; +@nodrops declare function cbrt(x: number): number; -declare function ceil(x: number): number; +@nodrops declare function ceil(x: number): number; -declare function cos(x: number): number; +@nodrops declare function cos(x: number): number; -declare function cosh(x: number): number; +@nodrops declare function cosh(x: number): number; -declare function exp(x: number): number; +@nodrops declare function exp(x: number): number; -declare function expm1(x: number): number; +@nodrops declare function expm1(x: number): number; -declare function floor(x: number): number; +@nodrops declare function floor(x: number): number; -declare function log(x: number): number; +@nodrops declare function log(x: number): number; -declare function log10(x: number): number; +@nodrops declare function log10(x: number): number; -declare function log1p(x: number): number; +@nodrops declare function log1p(x: number): number; -declare function log2(x: number): number; +@nodrops declare function log2(x: number): number; -declare function min(x: number, y: number): number; +@nodrops declare function min(x: number, y: number): number; -declare function max(x: number, y: number): number; +@nodrops declare function max(x: number, y: number): number; -declare function pow(x: number, y: number): number; +@nodrops declare function pow(x: number, y: number): number; -declare function round(x: number): number; +@nodrops declare function round(x: number): number; -declare function sin(x: number): number; +@nodrops declare function sin(x: number): number; -declare function sinh(x: number): number; +@nodrops declare function sinh(x: number): number; -declare function sqrt(x: number): number; +@nodrops declare function sqrt(x: number): number; -declare function tan(x: number): number; +@nodrops declare function tan(x: number): number; -declare function tanh(x: number): number; +@nodrops declare function tanh(x: number): number; -declare function trunc(x: number): number; +@nodrops declare function trunc(x: number): number; // memory -declare function memcpy(dest: Opaque, src: Opaque, bytes: index): Opaque; -declare function memmove(dest: Opaque, src: Opaque, bytes: index): Opaque; +@nodrops declare function memcpy(dest: Opaque, src: Opaque, bytes: index): Opaque; +@nodrops declare function memmove(dest: Opaque, src: Opaque, bytes: index): Opaque; // wrappers/memory.cpp: memcpy_s on Windows, __memcpy_chk elsewhere - ends the process rather // than copy more than `destSize` bytes -declare function boundedCopy(dest: Opaque, destSize: index, src: Opaque, count: index): void; -declare function memcmp(dest: Opaque, src: Opaque, bytes: index): int; +@nodrops declare function boundedCopy(dest: Opaque, destSize: index, src: Opaque, count: index): void; +@nodrops declare function memcmp(dest: Opaque, src: Opaque, bytes: index): int; // gc weak references declare function GC_general_register_disappearing_link(link: Reference, obj: Opaque): int; @@ -97,34 +101,34 @@ declare function GC_unregister_disappearing_link(link: Reference): int; declare function GC_gcollect(): void; // datetime -declare function parse_date(dateStr: string): time_t; +@nodrops declare function parse_date(dateStr: string): time_t; // regex -declare function regexp_test(expr: string, flags: string, s: string): int; -declare function regexp_exec(expr: string, flags: string, s: string, cm: Opaque): Opaque; -declare function regexp_match_results_size(cm: Opaque): index; -declare function regexp_match_results_prefix_length(cm: Opaque): index; -declare function regexp_match_results_suffix_position(cm: Opaque): index; -declare function regexp_match_results_sub_match_str_length(cm: Opaque, subIndex: index): index; -declare function regexp_match_results_sub_match_str_copy_to(cm: Opaque, subIndex: index, buffer: string, count: index); -declare function regexp_match_results_sub_match_position(cm: Opaque, subIndex: index): index; -declare function regexp_match_results_sub_match_length(cm: Opaque, subIndex: index): index; +@nodrops declare function regexp_test(expr: string, flags: string, s: string): int; +@nodrops declare function regexp_exec(expr: string, flags: string, s: string, cm: Opaque): Opaque; +@nodrops declare function regexp_match_results_size(cm: Opaque): index; +@nodrops declare function regexp_match_results_prefix_length(cm: Opaque): index; +@nodrops declare function regexp_match_results_suffix_position(cm: Opaque): index; +@nodrops declare function regexp_match_results_sub_match_str_length(cm: Opaque, subIndex: index): index; +@nodrops declare function regexp_match_results_sub_match_str_copy_to(cm: Opaque, subIndex: index, buffer: string, count: index); +@nodrops declare function regexp_match_results_sub_match_position(cm: Opaque, subIndex: index): index; +@nodrops declare function regexp_match_results_sub_match_length(cm: Opaque, subIndex: index): index; // malloc'ed C strings, given back with regexp_free_string: kept as pointers, not copied -declare function regexp_match_results_format(cm: Opaque, replacement: string): Opaque; -declare function regexp_replace(expr: string, flags: string, s: string, replacement: string): Opaque; -declare function regexp_free_string(s: Opaque): void; -declare function regexp_free(cm: Opaque): void; +@nodrops declare function regexp_match_results_format(cm: Opaque, replacement: string): Opaque; +@nodrops declare function regexp_replace(expr: string, flags: string, s: string, replacement: string): Opaque; +@nodrops declare function regexp_free_string(s: Opaque): void; +@nodrops declare function regexp_free(cm: Opaque): void; // thread -declare function std_this_thread_sleep_for(milliseconds: u32): void; +@nodrops declare function std_this_thread_sleep_for(milliseconds: u32): void; // http -declare function http_request(method: string, url: string, headers: string, body: string, bodyLength: index): Opaque; -declare function http_response_success(r: Opaque): boolean; -declare function http_response_error_code(r: Opaque): int; -declare function http_response_status(r: Opaque): int; -declare function http_response_headers_length(r: Opaque): index; -declare function http_response_headers_copy_to(r: Opaque, buffer: string, count: index): void; -declare function http_response_body_length(r: Opaque): index; -declare function http_response_body_copy_to(r: Opaque, buffer: string, count: index): void; -declare function http_response_free(r: Opaque): void; +@nodrops declare function http_request(method: string, url: string, headers: string, body: string, bodyLength: index): Opaque; +@nodrops declare function http_response_success(r: Opaque): boolean; +@nodrops declare function http_response_error_code(r: Opaque): int; +@nodrops declare function http_response_status(r: Opaque): int; +@nodrops declare function http_response_headers_length(r: Opaque): index; +@nodrops declare function http_response_headers_copy_to(r: Opaque, buffer: string, count: index): void; +@nodrops declare function http_response_body_length(r: Opaque): index; +@nodrops declare function http_response_body_copy_to(r: Opaque, buffer: string, count: index): void; +@nodrops declare function http_response_free(r: Opaque): void;