2022-01-07 22:09:52 -05:00
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
2021-02-04 17:18:32 -05:00
"use strict" ;
2019-03-26 08:22:07 -04:00
2020-03-28 13:03:49 -04:00
( ( window ) => {
2021-07-02 06:18:30 -04:00
const {
Error ,
RangeError ,
ReferenceError ,
SyntaxError ,
TypeError ,
URIError ,
Map ,
Array ,
ArrayPrototypeFill ,
2021-10-10 11:20:30 -04:00
ArrayPrototypeMap ,
2021-10-07 12:39:27 -04:00
ErrorCaptureStackTrace ,
2021-07-02 06:18:30 -04:00
Promise ,
2021-10-10 11:20:30 -04:00
ObjectEntries ,
2021-07-02 06:18:30 -04:00
ObjectFromEntries ,
MapPrototypeGet ,
MapPrototypeDelete ,
MapPrototypeSet ,
PromisePrototypeThen ,
2022-02-16 13:53:17 -05:00
PromisePrototypeFinally ,
StringPrototypeSlice ,
2021-07-02 06:18:30 -04:00
ObjectAssign ,
2021-11-25 13:49:09 -05:00
SymbolFor ,
2021-07-02 06:18:30 -04:00
} = window . _ _bootstrap . primordials ;
2022-03-14 13:44:15 -04:00
const ops = window . Deno . core . ops ;
2022-03-19 05:26:54 -04:00
const opIds = Object . keys ( ops ) . reduce ( ( a , v , i ) => {
a [ v ] = i ;
return a ;
} , { } ) ;
2021-07-02 06:18:30 -04:00
2019-08-05 07:23:41 -04:00
// Available on start due to bindings.
2022-03-14 13:44:15 -04:00
const { refOp _ , unrefOp _ } = window . Deno . core ;
2019-03-26 08:22:07 -04:00
2021-05-03 11:30:41 -04:00
const errorMap = { } ;
// Builtin v8 / JS errors
registerErrorClass ( "Error" , Error ) ;
registerErrorClass ( "RangeError" , RangeError ) ;
registerErrorClass ( "ReferenceError" , ReferenceError ) ;
registerErrorClass ( "SyntaxError" , SyntaxError ) ;
registerErrorClass ( "TypeError" , TypeError ) ;
registerErrorClass ( "URIError" , URIError ) ;
2021-03-31 10:37:38 -04:00
let nextPromiseId = 1 ;
2021-04-07 08:38:54 -04:00
const promiseMap = new Map ( ) ;
const RING _SIZE = 4 * 1024 ;
const NO _PROMISE = null ; // Alias to null is faster than plain nulls
2021-07-02 06:18:30 -04:00
const promiseRing = ArrayPrototypeFill ( new Array ( RING _SIZE ) , NO _PROMISE ) ;
2021-11-25 13:49:09 -05:00
// TODO(bartlomieju): it future use `v8::Private` so it's not visible
// to users. Currently missing bindings.
const promiseIdSymbol = SymbolFor ( "Deno.core.internalPromiseId" ) ;
2019-04-24 21:43:06 -04:00
2022-02-16 13:53:17 -05:00
let opCallTracingEnabled = false ;
const opCallTraces = new Map ( ) ;
function enableOpCallTracing ( ) {
opCallTracingEnabled = true ;
}
2022-02-25 10:14:46 -05:00
function isOpCallTracingEnabled ( ) {
return opCallTracingEnabled ;
}
2021-04-07 08:38:54 -04:00
function setPromise ( promiseId ) {
const idx = promiseId % RING _SIZE ;
// Move old promise from ring to map
const oldPromise = promiseRing [ idx ] ;
if ( oldPromise !== NO _PROMISE ) {
const oldPromiseId = promiseId - RING _SIZE ;
2021-07-02 06:18:30 -04:00
MapPrototypeSet ( promiseMap , oldPromiseId , oldPromise ) ;
2021-04-07 08:38:54 -04:00
}
// Set new promise
return promiseRing [ idx ] = newPromise ( ) ;
}
function getPromise ( promiseId ) {
// Check if out of ring bounds, fallback to map
const outOfBounds = promiseId < nextPromiseId - RING _SIZE ;
if ( outOfBounds ) {
2021-07-02 06:18:30 -04:00
const promise = MapPrototypeGet ( promiseMap , promiseId ) ;
MapPrototypeDelete ( promiseMap , promiseId ) ;
2021-04-07 08:38:54 -04:00
return promise ;
}
// Otherwise take from ring
const idx = promiseId % RING _SIZE ;
const promise = promiseRing [ idx ] ;
promiseRing [ idx ] = NO _PROMISE ;
return promise ;
}
function newPromise ( ) {
let resolve , reject ;
const promise = new Promise ( ( resolve _ , reject _ ) => {
resolve = resolve _ ;
reject = reject _ ;
} ) ;
promise . resolve = resolve ;
promise . reject = reject ;
return promise ;
}
2022-03-11 11:18:49 -05:00
function hasPromise ( promiseId ) {
// Check if out of ring bounds, fallback to map
const outOfBounds = promiseId < nextPromiseId - RING _SIZE ;
if ( outOfBounds ) {
return MapPrototypeHas ( promiseMap , promiseId ) ;
}
// Otherwise check it in ring
const idx = promiseId % RING _SIZE ;
return promiseRing [ idx ] != NO _PROMISE ;
}
2021-08-19 11:19:00 -04:00
function opresolve ( ) {
2021-03-31 10:37:38 -04:00
for ( let i = 0 ; i < arguments . length ; i += 2 ) {
2021-04-09 11:55:33 -04:00
const promiseId = arguments [ i ] ;
const res = arguments [ i + 1 ] ;
const promise = getPromise ( promiseId ) ;
promise . resolve ( res ) ;
2019-03-14 19:17:52 -04:00
}
}
2021-04-21 20:50:50 -04:00
function registerErrorClass ( className , errorClass ) {
2021-05-03 11:30:41 -04:00
registerErrorBuilder ( className , ( msg ) => new errorClass ( msg ) ) ;
}
function registerErrorBuilder ( className , errorBuilder ) {
2021-04-21 20:50:50 -04:00
if ( typeof errorMap [ className ] !== "undefined" ) {
throw new TypeError ( ` Error class for " ${ className } " already registered ` ) ;
2021-03-20 12:51:08 -04:00
}
2021-05-03 11:30:41 -04:00
errorMap [ className ] = errorBuilder ;
2019-03-14 19:17:52 -04:00
}
2021-04-09 11:55:33 -04:00
function unwrapOpResult ( res ) {
// .$err_class_name is a special key that should only exist on errors
if ( res ? . $err _class _name ) {
const className = res . $err _class _name ;
2021-05-03 11:30:41 -04:00
const errorBuilder = errorMap [ className ] ;
2021-10-07 12:39:27 -04:00
const err = errorBuilder ? errorBuilder ( res . message ) : new Error (
` Unregistered error class: " ${ className } " \n ${ res . message } \n Classes of errors returned from ops should be registered via Deno.core.registerErrorClass(). ` ,
) ;
2021-11-04 11:44:34 -04:00
// Set .code if error was a known OS error, see error_codes.rs
if ( res . code ) {
err . code = res . code ;
}
2021-10-07 12:39:27 -04:00
// Strip unwrapOpResult() and errorBuilder() calls from stack trace
ErrorCaptureStackTrace ( err , unwrapOpResult ) ;
throw err ;
2020-08-07 16:47:18 -04:00
}
2021-04-09 11:55:33 -04:00
return res ;
2020-08-07 16:47:18 -04:00
}
2021-05-18 07:43:21 -04:00
function opAsync ( opName , arg1 = null , arg2 = null ) {
2021-03-31 10:37:38 -04:00
const promiseId = nextPromiseId ++ ;
2022-03-14 13:44:15 -04:00
const maybeError = ops [ opName ] ( opIds [ opName ] , promiseId , arg1 , arg2 ) ;
2021-03-31 10:37:38 -04:00
// Handle sync error (e.g: error parsing args)
2021-04-09 11:55:33 -04:00
if ( maybeError ) return unwrapOpResult ( maybeError ) ;
2022-02-16 13:53:17 -05:00
let p = PromisePrototypeThen ( setPromise ( promiseId ) , unwrapOpResult ) ;
if ( opCallTracingEnabled ) {
// Capture a stack trace by creating a new `Error` object. We remove the
// first 6 characters (the `Error\n` prefix) to get just the stack trace.
const stack = StringPrototypeSlice ( new Error ( ) . stack , 6 ) ;
MapPrototypeSet ( opCallTraces , promiseId , { opName , stack } ) ;
p = PromisePrototypeFinally (
p ,
( ) => MapPrototypeDelete ( opCallTraces , promiseId ) ,
) ;
}
2021-11-25 13:49:09 -05:00
// Save the id on the promise so it can later be ref'ed or unref'ed
p [ promiseIdSymbol ] = promiseId ;
return p ;
2020-08-07 16:47:18 -04:00
}
2022-03-14 13:44:15 -04:00
function opSync ( opName , arg1 , arg2 ) {
return unwrapOpResult ( ops [ opName ] ( opIds [ opName ] , arg1 , arg2 ) ) ;
2021-03-20 12:51:08 -04:00
}
2022-03-11 11:18:49 -05:00
function refOp ( promiseId ) {
if ( ! hasPromise ( promiseId ) ) {
return ;
}
refOp _ ( promiseId ) ;
}
function unrefOp ( promiseId ) {
if ( ! hasPromise ( promiseId ) ) {
return ;
}
unrefOp _ ( promiseId ) ;
}
2020-09-17 12:09:50 -04:00
function resources ( ) {
2021-07-02 06:18:30 -04:00
return ObjectFromEntries ( opSync ( "op_resources" ) ) ;
2020-09-17 12:09:50 -04:00
}
2021-03-31 10:37:38 -04:00
2021-11-09 13:26:17 -05:00
function read ( rid , buf ) {
return opAsync ( "op_read" , rid , buf ) ;
}
function write ( rid , buf ) {
return opAsync ( "op_write" , rid , buf ) ;
}
function shutdown ( rid ) {
return opAsync ( "op_shutdown" , rid ) ;
}
2020-09-17 12:09:50 -04:00
function close ( rid ) {
2021-04-12 15:55:05 -04:00
opSync ( "op_close" , rid ) ;
2020-09-17 12:09:50 -04:00
}
2021-09-10 18:47:09 -04:00
function tryClose ( rid ) {
opSync ( "op_try_close" , rid ) ;
}
2021-05-02 19:30:03 -04:00
function print ( str , isErr = false ) {
2021-05-15 09:22:57 -04:00
opSync ( "op_print" , str , isErr ) ;
2021-05-02 19:30:03 -04:00
}
2021-10-10 11:20:30 -04:00
function metrics ( ) {
const [ aggregate , perOps ] = opSync ( "op_metrics" ) ;
aggregate . ops = ObjectFromEntries ( ArrayPrototypeMap (
2022-03-14 13:44:15 -04:00
ObjectEntries ( opIds ) ,
2021-10-10 11:20:30 -04:00
( [ opName , opId ] ) => [ opName , perOps [ opId ] ] ,
) ) ;
return aggregate ;
}
2021-06-28 19:43:03 -04:00
// Some "extensions" rely on "BadResource" and "Interrupted" errors in the
// JS code (eg. "deno_net") so they are provided in "Deno.core" but later
// reexported on "Deno.errors"
class BadResource extends Error {
constructor ( msg ) {
super ( msg ) ;
this . name = "BadResource" ;
}
}
2022-02-01 12:06:11 -05:00
const BadResourcePrototype = BadResource . prototype ;
2021-06-28 19:43:03 -04:00
class Interrupted extends Error {
constructor ( msg ) {
super ( msg ) ;
this . name = "Interrupted" ;
}
}
2022-02-01 12:06:11 -05:00
const InterruptedPrototype = Interrupted . prototype ;
2021-06-28 19:43:03 -04:00
2021-04-30 08:13:23 -04:00
// Extra Deno.core.* exports
2021-07-02 06:18:30 -04:00
const core = ObjectAssign ( globalThis . Deno . core , {
2021-04-12 15:55:05 -04:00
opAsync ,
opSync ,
2020-09-17 12:09:50 -04:00
close ,
2021-09-10 18:47:09 -04:00
tryClose ,
2021-11-09 13:26:17 -05:00
read ,
write ,
shutdown ,
2021-05-02 19:30:03 -04:00
print ,
2020-09-17 12:09:50 -04:00
resources ,
2021-10-10 11:20:30 -04:00
metrics ,
2021-05-03 11:30:41 -04:00
registerErrorBuilder ,
2020-08-07 16:47:18 -04:00
registerErrorClass ,
2021-08-19 11:19:00 -04:00
opresolve ,
2021-06-28 19:43:03 -04:00
BadResource ,
2022-02-01 12:06:11 -05:00
BadResourcePrototype ,
2021-06-28 19:43:03 -04:00
Interrupted ,
2022-02-01 12:06:11 -05:00
InterruptedPrototype ,
2022-02-16 13:53:17 -05:00
enableOpCallTracing ,
2022-02-25 10:14:46 -05:00
isOpCallTracingEnabled ,
2022-02-16 13:53:17 -05:00
opCallTraces ,
2022-03-11 11:18:49 -05:00
refOp ,
unrefOp ,
2020-05-12 11:09:28 -04:00
} ) ;
2021-07-02 06:18:30 -04:00
ObjectAssign ( globalThis . _ _bootstrap , { core } ) ;
ObjectAssign ( globalThis . Deno , { core } ) ;
} ) ( globalThis ) ;