From 24b2a187d42bac3bad99364644ebe3b6705bc3cd Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Mon, 1 Apr 2019 17:30:57 +0200 Subject: [PATCH 001/512] The WASI bindings are now in the AssemblyScript standard library --- assemblyscript/modules/wasa/assembly/wasa.ts | 2 +- .../modules/wasa/assembly/wasi_unstable.ts | 690 ------------------ 2 files changed, 1 insertion(+), 691 deletions(-) delete mode 100644 assemblyscript/modules/wasa/assembly/wasi_unstable.ts diff --git a/assemblyscript/modules/wasa/assembly/wasa.ts b/assemblyscript/modules/wasa/assembly/wasa.ts index 51599a1f5..b0d04990d 100644 --- a/assemblyscript/modules/wasa/assembly/wasa.ts +++ b/assemblyscript/modules/wasa/assembly/wasa.ts @@ -20,7 +20,7 @@ import { fd, fdflags, fd_close, -} from './wasi_unstable'; +} from 'bindings/wasi'; export type Descriptor = fd; diff --git a/assemblyscript/modules/wasa/assembly/wasi_unstable.ts b/assemblyscript/modules/wasa/assembly/wasi_unstable.ts deleted file mode 100644 index 5645f547a..000000000 --- a/assemblyscript/modules/wasa/assembly/wasi_unstable.ts +++ /dev/null @@ -1,690 +0,0 @@ -// see: https://wasi.dev - -/* tslint:disable:max-line-length */ - -type uintptr = usize; -type size = usize; - -/** Read command-line argument data. */ -export declare function args_get(argv: uintptr, argv_buf: uintptr): errno; -/** Return command-line argument data sizes. */ -export declare function args_sizes_get(argc: uintptr, argv_buf_size_ptr: uintptr): errno; - -/** Return the resolution of a clock. */ -export declare function clock_res_get(clock: clockid, resolution: uintptr): errno; -/** Return the time value of a clock. */ -export declare function clock_time_get(clock: clockid, precision: timestamp, time: uintptr): errno; - -/** Read environment variable data. */ -export declare function environ_get(environ: uintptr, environ_buf: uintptr): errno; -/** Return command-line argument data sizes. */ -export declare function environ_sizes_get(environ_count: uintptr, environ_buf_size: uintptr): errno; - -/** Provide file advisory information on a file descriptor. */ -export declare function fd_advise(fd: fd, offset: filesize, len: filesize, advice: advice): errno; -/** Provide file advisory information on a file descriptor. */ -export declare function fd_allocate(fd: fd, offset: filesize, len: filesize): errno; -/** Close a file descriptor. */ -export declare function fd_close(fd: fd): errno; -/** Synchronize the data of a file to disk. */ -export declare function fd_datasync(fd: fd): errno; -/** Get the attributes of a file descriptor. */ -export declare function fd_fdstat_get(fd: fd, buf: uintptr): errno; -/** Adjust the flags associated with a file descriptor. */ -export declare function fd_fdstat_set_flags(fd: fd, flags: fdflags): errno; -/** Adjust the rights associated with a file descriptor. */ -export declare function fd_fdstat_set_rights(fd: fd, fs_rights_base: rights, fs_rights_inheriting: rights): errno; -/** Return the attributes of an open file. */ -export declare function fd_filestat_get(fd: fd, buf: uintptr): errno; -/** Adjust the size of an open file. If this increases the file's size, the extra bytes are filled with zeros. */ -export declare function fd_filestat_set_size(fd: fd, size: filesize): errno; -/** Adjust the timestamps of an open file or directory. */ -export declare function fd_filestat_set_times(fd: fd, st_atim: timestamp, st_mtim: timestamp, fstflags: fstflags): errno; -/** Read from a file descriptor, without using and updating the file descriptor's offset. */ -export declare function fd_pread(fd: fd, iovs: uintptr, iovs_len: size, offset: filesize, nread: uintptr): errno; -/** Return a description of the given preopened file descriptor. */ -export declare function fd_prestat_get(fd: fd, buf: uintptr): errno; -/** Return a description of the given preopened file descriptor. */ -export declare function fd_prestat_dir_name(fd: fd, path: uintptr, path_len: size): errno; -/** Write to a file descriptor, without using and updating the file descriptor's offset. */ -export declare function fd_pwrite(fd: fd, iovs: uintptr, iovs_len: size, offset: filesize, nwritten: uintptr): errno; -/** Read from a file descriptor. */ -export declare function fd_read(fd: fd, iovs: uintptr, iovs_len: size, nread: uintptr): errno; -/** Read directory entries from a directory. */ -export declare function fd_readdir(fd: fd, buf: uintptr, buf_len: size, cookie: dircookie, buf_used: uintptr): errno; -/** Atomically replace a file descriptor by renumbering another file descriptor. */ -export declare function fd_renumber(from: fd, to: fd): errno; -/** Move the offset of a file descriptor. */ -export declare function fd_seek(fd: fd, offset: filedelta, whence: whence, newoffset: uintptr): errno; -/** Synchronize the data and metadata of a file to disk. */ -export declare function fd_sync(fd: fd): errno; -/** Return the current offset of a file descriptor. */ -export declare function fd_tell(fd: fd, newoffset: uintptr): errno; -/** Write to a file descriptor. */ -export declare function fd_write(fd: fd, iovs: uintptr, iovs_len: size, nwritten: uintptr): errno; - -/* Create a directory. */ -export declare function path_create_directory(fd: fd, path: uintptr, path_len: size): errno; -/** Return the attributes of a file or directory. */ -export declare function path_filestat_get(fd: fd, flags: lookupflags, path: uintptr, path_len: size, buf: uintptr): errno; -/** Adjust the timestamps of a file or directory. */ -export declare function path_filestat_set_times(fd: fd, flags: lookupflags, path: uintptr, path_len: size, st_atim: timestamp, st_mtim: timestamp, fstflags: fstflags): errno; -/** Create a hard link. */ -export declare function path_link(fd0: fd, flags0: lookupflags, path0: uintptr, path_len0: size, fd1: fd, path1: uintptr, path_len: size): errno; -/** Open a file or directory. */ -export declare function path_open(dirfd: fd, dirflags: lookupflags, path: uintptr, path_len: size, oflags: oflags, fs_rights_base: rights, fs_rights_inheriting: rights, fs_flags: fdflags, fd: fd): errno; -/** Read the contents of a symbolic link. */ -export declare function path_readlink(fd: fd, path: uintptr, path_len: size, buf: uintptr, buf_len: size, buf_used: uintptr): errno; -/** Remove a directory. */ -export declare function path_remove_directory(fd: fd, path: uintptr, path_len: size): errno; -/** Rename a file or directory. */ -export declare function path_rename(fd0: fd, path0: uintptr, path_len0: size, fd1: fd, path1: uintptr, path_len1: size): errno; -/** Create a symbolic link. */ -export declare function path_symlink(path0: uintptr, path_len0: size, fd: fd, path1: uintptr, path_len1: size): errno; -/** Unlink a file. */ -export declare function path_unlink_file(fd: fd, path: uintptr, path_len: size): errno; - -/** Concurrently poll for the occurrence of a set of events. */ -export declare function poll_oneoff(in_: uintptr, out: uintptr, nsubscriptions: size, nevents: uintptr): errno; - -/** Terminate the process normally. An exit code of 0 indicates successful termination of the program. The meanings of other values is dependent on the environment. */ -export declare function proc_exit(rval: u32): void; -/** Send a signal to the process of the calling thread. */ -export declare function proc_raise(sig: signal): errno; - -/** Write high-quality random data into a buffer. */ -export declare function random_get(buf: uintptr, buf_len: size): errno; - -/** Temporarily yield execution of the calling thread. */ -export declare function sched_yield(): errno; - -/** Receive a message from a socket. */ -export declare function sock_recv(sock: fd, ri_data: uintptr, ri_data_len: size, ri_flags: riflags, ro_datalen: uintptr, ro_flags: roflags): errno; -/** Send a message on a socket. */ -export declare function sock_send(sock: fd, si_data: uintptr, si_data_len: size, si_flags: siflags, so_datalen: uintptr): errno; -/** Shut down socket send and receive channels. */ -export declare function sock_shutdown(sock: fd, how: sdflags): errno; - -// === Types ====================================================================================== - -/** File or memory access pattern advisory information. */ -export namespace advice { - /** The application has no advice to give on its behavior with respect to the specified data. */ - @inline export const NORMAL: advice = 0; - /** The application expects to access the specified data sequentially from lower offsets to higher offsets. */ - @inline export const SEQUENTIAL : advice = 1; - /** The application expects to access the specified data in a random order. */ - @inline export const RANDOM: advice = 2; - /** The application expects to access the specified data in the near future. */ - @inline export const WILLNEED: advice = 3; - /** The application expects that it will not access the specified data in the near future. */ - @inline export const DONTNEED: advice = 4; - /** The application expects to access the specified data once and then not reuse it thereafter. */ - @inline export const NOREUSE: advice = 5; -} -export type advice = u8; - -/** Identifiers for clocks. */ -export namespace clockid { - /** The clock measuring real time. Time value zero corresponds with 1970-01-01T00:00:00Z. */ - @inline export const REALTIME: clockid = 0; - /** The store-wide monotonic clock. Absolute value has no meaning. */ - @inline export const MONOTONIC: clockid = 1; - /** The CPU-time clock associated with the current process. */ - @inline export const PROCESS_CPUTIME_ID: clockid = 2; - /** The CPU-time clock associated with the current thread. */ - @inline export const THREAD_CPUTIME_ID: clockid = 3; -} -export type clockid = u32; - -/** Identifier for a device containing a file system. Can be used in combination with `inode` to uniquely identify a file or directory in the filesystem. */ -export type device = u64; - -/** A reference to the offset of a directory entry. */ -export type dircookie = u64; - -/** A directory entry. */ -@unmanaged export class dirent { - /** The offset of the next directory entry stored in this directory. */ - next: dircookie; - /** The serial number of the file referred to by this directory entry. */ - ino: inode; - /** The length of the name of the directory entry. */ - namlen: u32; - /** The type of the file referred to by this directory entry. */ - type: filetype; - private __padding0: u16; -} - -/** Error codes returned by functions. */ -export namespace errno { - /** No error occurred. System call completed successfully. */ - @inline export const SUCCESS: errno = 0; - /** Argument list too long. */ - @inline export const TOOBIG: errno = 1; - /** Permission denied. */ - @inline export const ACCES: errno = 2; - /** Address in use. */ - @inline export const ADDRINUSE: errno = 3; - /** Address not available. */ - @inline export const ADDRNOTAVAIL: errno = 4; - /** Address family not supported. */ - @inline export const AFNOSUPPORT: errno = 5; - /** Resource unavailable, or operation would block. */ - @inline export const AGAIN: errno = 6; - /** Connection already in progress. */ - @inline export const ALREADY: errno = 7; - /** Bad file descriptor. */ - @inline export const BADF: errno = 8; - /** Bad message. */ - @inline export const BADMSG: errno = 9; - /** Device or resource busy. */ - @inline export const BUSY: errno = 10; - /** Operation canceled. */ - @inline export const CANCELED: errno = 11; - /** No child processes. */ - @inline export const CHILD: errno = 12; - /** Connection aborted. */ - @inline export const CONNABORTED: errno = 13; - /** Connection refused. */ - @inline export const CONNREFUSED: errno = 14; - /** Connection reset. */ - @inline export const CONNRESET: errno = 15; - /** Resource deadlock would occur. */ - @inline export const DEADLK: errno = 16; - /** Destination address required. */ - @inline export const DESTADDRREQ: errno = 17; - /** Mathematics argument out of domain of function. */ - @inline export const DOM: errno = 18; - /** Reserved. */ - @inline export const DQUOT: errno = 19; - /** File exists. */ - @inline export const EXIST: errno = 20; - /** Bad address. */ - @inline export const FAULT: errno = 21; - /** File too large. */ - @inline export const FBIG: errno = 22; - /** Host is unreachable. */ - @inline export const HOSTUNREACH: errno = 23; - /** Identifier removed. */ - @inline export const IDRM: errno = 24; - /** Illegal byte sequence. */ - @inline export const ILSEQ: errno = 25; - /** Operation in progress. */ - @inline export const INPROGRESS: errno = 26; - /** Interrupted function. */ - @inline export const INTR: errno = 27; - /** Invalid argument. */ - @inline export const INVAL: errno = 28; - /** I/O error. */ - @inline export const IO: errno = 29; - /** Socket is connected. */ - @inline export const ISCONN: errno = 30; - /** Is a directory. */ - @inline export const ISDIR: errno = 31; - /** Too many levels of symbolic links. */ - @inline export const LOOP: errno = 32; - /** File descriptor value too large. */ - @inline export const MFILE: errno = 33; - /** Too many links. */ - @inline export const MLINK: errno = 34; - /** Message too large. */ - @inline export const MSGSIZE: errno = 35; - /** Reserved. */ - @inline export const MULTIHOP: errno = 36; - /** Filename too long. */ - @inline export const NAMETOOLONG: errno = 37; - /** Network is down. */ - @inline export const NETDOWN: errno = 38; - /** Connection aborted by network. */ - @inline export const NETRESET: errno = 39; - /** Network unreachable. */ - @inline export const NETUNREACH: errno = 40; - /** Too many files open in system. */ - @inline export const NFILE: errno = 41; - /** No buffer space available. */ - @inline export const NOBUFS: errno = 42; - /** No such device. */ - @inline export const NODEV: errno = 43; - /** No such file or directory. */ - @inline export const NOENT: errno = 44; - /** Executable file format error. */ - @inline export const NOEXEC: errno = 45; - /** No locks available. */ - @inline export const NOLCK: errno = 46; - /** Reserved. */ - @inline export const NOLINK: errno = 47; - /** Not enough space. */ - @inline export const NOMEM: errno = 48; - /** No message of the desired type. */ - @inline export const NOMSG: errno = 49; - /** Protocol not available. */ - @inline export const NOPROTOOPT: errno = 50; - /** No space left on device. */ - @inline export const NOSPC: errno = 51; - /** Function not supported. */ - @inline export const NOSYS: errno = 52; - /** The socket is not connected. */ - @inline export const NOTCONN: errno = 53; - /** Not a directory or a symbolic link to a directory. */ - @inline export const NOTDIR: errno = 54; - /** Directory not empty. */ - @inline export const NOTEMPTY: errno = 55; - /** State not recoverable. */ - @inline export const NOTRECOVERABLE: errno = 56; - /** Not a socket. */ - @inline export const NOTSOCK: errno = 57; - /** Not supported, or operation not supported on socket. */ - @inline export const NOTSUP: errno = 58; - /** Inappropriate I/O control operation. */ - @inline export const NOTTY: errno = 59; - /** No such device or address. */ - @inline export const NXIO: errno = 60; - /** Value too large to be stored in data type. */ - @inline export const OVERFLOW: errno = 61; - /** Previous owner died. */ - @inline export const OWNERDEAD: errno = 62; - /** Operation not permitted. */ - @inline export const PERM: errno = 63; - /** Broken pipe. */ - @inline export const PIPE: errno = 64; - /** Protocol error. */ - @inline export const PROTO: errno = 65; - /** Protocol not supported. */ - @inline export const PROTONOSUPPORT: errno = 66; - /** Protocol wrong type for socket. */ - @inline export const PROTOTYPE: errno = 67; - /** Result too large. */ - @inline export const RANGE: errno = 68; - /** Read-only file system. */ - @inline export const ROFS: errno = 69; - /** Invalid seek. */ - @inline export const SPIPE: errno = 70; - /** No such process. */ - @inline export const SRCH: errno = 71; - /** Reserved. */ - @inline export const STALE: errno = 72; - /** Connection timed out. */ - @inline export const TIMEDOUT: errno = 73; - /** Text file busy. */ - @inline export const TXTBSY: errno = 74; - /** Cross-device link. */ - @inline export const XDEV: errno = 75; - /** Extension: Capabilities insufficient. */ - @inline export const NOTCAPABLE: errno = 76; -} -export type errno = u16; - -/** An event that occurred. */ -@unmanaged export abstract class event { - /** User-provided value that got attached to `subscription#userdata`. */ - userdata: userdata; - /** If non-zero, an error that occurred while processing the subscription request. */ - error: errno; - /* The type of the event that occurred. */ - type: eventtype; - private __padding0: u16; -} - -/** An event that occurred when type is `eventtype.FD_READ` or `eventtype.FD_WRITE`. */ -@unmanaged export class rwevent extends event { - /* The number of bytes available for reading or writing. */ - nbytes: filesize; - /* The state of the file descriptor. */ - flags: eventrwflags; - private __padding1: u32; -} - -/** The state of the file descriptor subscribed to with `eventtype.FD_READ` or `eventtype.FD_WRITE`. */ -export namespace eventrwflags { - /** The peer of this socket has closed or disconnected. */ - @inline export const HANGUP: eventrwflags = 1; -} -export type eventrwflags = u16; - -/** Type of a subscription to an event or its occurrence. */ -export namespace eventtype { - /** The time value of clock has reached the timestamp. */ - @inline export const CLOCK: eventtype = 0; - /** File descriptor has data available for reading. */ - @inline export const FD_READ: eventtype = 1; - /** File descriptor has capacity available for writing */ - @inline export const FD_WRITE: eventtype = 2; -} -export type eventtype = u8; - -/** Exit code generated by a process when exiting. */ -export type exitcode = u32; - -/** A file descriptor number. */ -export type fd = u32; - -/** File descriptor flags. */ -export namespace fdflags { - /** Append mode: Data written to the file is always appended to the file's end. */ - @inline export const APPEND: fdflags = 1; - /** Write according to synchronized I/O data integrity completion. Only the data stored in the file is synchronized. */ - @inline export const DSYNC: fdflags = 2; - /** Non-blocking mode. */ - @inline export const NONBLOCK: fdflags = 4; - /** Synchronized read I/O operations. */ - @inline export const RSYNC: fdflags = 8; - /** Write according to synchronized I/O file integrity completion. */ - @inline export const SYNC: fdflags = 16; -} -export type fdflags = u16; - -/** File descriptor attributes. */ -@unmanaged export class fdstat { - /** File type. */ - filetype: filetype; - /** File descriptor flags. */ - flags: fdflags; - /** Rights that apply to this file descriptor. */ - rights_base: rights; - /** Maximum set of rights that may be installed on new file descriptors that are created through this file descriptor, e.g., through `path_open`. */ - rights_inheriting: rights; -} - -/** Relative offset within a file. */ -export type filedelta = i64; - -/** Non-negative file size or length of a region within a file. */ -export type filesize = u64; - -/** File attributes. */ -@unmanaged export class filestat { - /** Device ID of device containing the file. */ - dev: device; - /** File serial number. */ - ino: inode; - /** File type. */ - filetype: filetype; - /** Number of hard links to the file. */ - nlink: linkcount; - /** For regular files, the file size in bytes. For symbolic links, the length in bytes of the pathname contained in the symbolic link. */ - size: filesize; - /** Last data access timestamp. */ - atim: timestamp; - /** Last data modification timestamp. */ - mtim: timestamp; - /** Last file status change timestamp. */ - ctim: timestamp; -} - -/** The type of a file descriptor or file. */ -export namespace filetype { - /** The type of the file descriptor or file is unknown or is different from any of the other types specified. */ - @inline export const UNKNOWN: filetype = 0; - /** The file descriptor or file refers to a block device inode. */ - @inline export const BLOCK_DEVICE: filetype = 1; - /** The file descriptor or file refers to a character device inode. */ - @inline export const CHARACTER_DEVICE: filetype = 2; - /** The file descriptor or file refers to a directory inode. */ - @inline export const DIRECTORY: filetype = 3; - /** The file descriptor or file refers to a regular file inode. */ - @inline export const REGULAR_FILE: filetype = 4; - /** The file descriptor or file refers to a datagram socket. */ - @inline export const SOCKET_DGRAM: filetype = 5; - /** The file descriptor or file refers to a byte-stream socket. */ - @inline export const SOCKET_STREAM: filetype = 6; - /** The file refers to a symbolic link inode. */ - @inline export const SYMBOLIC_LINK: filetype = 7; -} -export type filetype = u8; - -/** Which file time attributes to adjust. */ -export namespace fstflags { - /** Adjust the last data access timestamp to the value stored in `filestat#st_atim`. */ - @inline export const SET_ATIM: fstflags = 1; - /** Adjust the last data access timestamp to the time of clock `clockid.REALTIME`. */ - @inline export const SET_ATIM_NOW: fstflags = 2; - /** Adjust the last data modification timestamp to the value stored in `filestat#st_mtim`. */ - @inline export const SET_MTIM: fstflags = 4; - /** Adjust the last data modification timestamp to the time of clock `clockid.REALTIME`. */ - @inline export const SET_MTIM_NOW: fstflags = 8; -} -export type fstflags = u16; - -/** File serial number that is unique within its file system. */ -export type inode = u64; - -/** A region of memory for scatter/gather reads. */ -@unmanaged export class iovec { - /** The address of the buffer to be filled. */ - buf: uintptr; - /** The length of the buffer to be filled. */ - buf_len: size; -} - -/** Number of hard links to an inode. */ -export type linkcount = u32; - -/** Flags determining the method of how paths are resolved. */ -export namespace lookupflags { - /** As long as the resolved path corresponds to a symbolic link, it is expanded. */ - @inline export const SYMLINK_FOLLOW: lookupflags = 1; -} -export type lookupflags = u32; - -/** Open flags. */ -export namespace oflags { - /** Create file if it does not exist. */ - @inline export const CREAT: oflags = 1; - /** Fail if not a directory. */ - @inline export const DIRECTORY: oflags = 2; - /** Fail if file already exists. */ - @inline export const EXCL: oflags = 4; - /** Truncate file to size 0. */ - @inline export const TRUNC: oflags = 8; -} -export type oflags = u16; - -/** Flags provided to `sock_recv`. */ -export namespace riflags { - /** Returns the message without removing it from the socket's receive queue. */ - @inline export const PEEK: riflags = 1; - /** On byte-stream sockets, block until the full amount of data can be returned. */ - @inline export const WAITALL: riflags = 2; -} -export type riflags = u16; - -/** File descriptor rights, determining which actions may be performed. */ -export namespace rights { - /** The right to invoke `fd_datasync`. */ - @inline export const FD_DATASYNC: rights = 1; - /** The right to invoke `fd_read` and `sock_recv`. */ - @inline export const FD_READ: rights = 2; - /** The right to invoke `fd_seek`. This flag implies `rights.FD_TELL`. */ - @inline export const FD_SEEK: rights = 4; - /** The right to invoke `fd_fdstat_set_flags`. */ - @inline export const FD_FDSTAT_SET_FLAGS: rights = 8; - /** The right to invoke `fd_sync`. */ - @inline export const FD_SYNC: rights = 16; - /** The right to invoke `fd_seek` in such a way that the file offset remains unaltered (i.e., `whence.CUR` with offset zero), or to invoke `fd_tell`). */ - @inline export const FD_TELL: rights = 32; - /** The right to invoke `fd_write` and `sock_send`. If `rights.FD_SEEK` is set, includes the right to invoke `fd_pwrite`. */ - @inline export const FD_WRITE: rights = 64; - /** The right to invoke `fd_advise`. */ - @inline export const FD_ADVISE: rights = 128; - /** The right to invoke `fd_allocate`. */ - @inline export const FD_ALLOCATE: rights = 256; - /** The right to invoke `path_create_directory`. */ - @inline export const PATH_CREATE_DIRECTORY: rights = 512; - /** If `rights.PATH_OPEN` is set, the right to invoke `path_open` with `oflags.CREAT`. */ - @inline export const PATH_CREATE_FILE: rights = 1024; - /** The right to invoke `path_link` with the file descriptor as the source directory. */ - @inline export const PATH_LINK_SOURCE: rights = 2048; - /** The right to invoke `path_link` with the file descriptor as the target directory. */ - @inline export const PATH_LINK_TARGET: rights = 4096; - /** The right to invoke `path_open`. */ - @inline export const PATH_OPEN: rights = 8192; - /** The right to invoke `fd_readdir`. */ - @inline export const FD_READDIR: rights = 16384; - /** The right to invoke `path_readlink`. */ - @inline export const PATH_READLINK: rights = 32768; - /** The right to invoke `path_rename` with the file descriptor as the source directory. */ - @inline export const PATH_RENAME_SOURCE: rights = 65536; - /** The right to invoke `path_rename` with the file descriptor as the target directory. */ - @inline export const PATH_RENAME_TARGET: rights = 131072; - /** The right to invoke `path_filestat_get`. */ - @inline export const PATH_FILESTAT_GET: rights = 262144; - /** The right to change a file's size (there is no `path_filestat_set_size`). If `rights.PATH_OPEN` is set, includes the right to invoke `path_open` with `oflags.TRUNC`. */ - @inline export const PATH_FILESTAT_SET_SIZE: rights = 524288; - /** The right to invoke `path_filestat_set_times`. */ - @inline export const PATH_FILESTAT_SET_TIMES: rights = 1048576; - /** The right to invoke `fd_filestat_get`. */ - @inline export const FD_FILESTAT_GET: rights = 2097152; - /** The right to invoke `fd_filestat_set_size`. */ - @inline export const FD_FILESTAT_SET_SIZE: rights = 4194304; - /** The right to invoke `fd_filestat_set_times`. */ - @inline export const FD_FILESTAT_SET_TIMES: rights = 8388608; - /** The right to invoke `path_symlink`. */ - @inline export const RIGHT_PATH_SYMLINK: rights = 16777216; - /** The right to invoke `path_remove_directory`. */ - @inline export const PATH_REMOVE_DIRECTORY: rights = 33554432; - /** The right to invoke `path_unlink_file`. */ - @inline export const PATH_UNLINK_FILE: rights = 67108864; - /** If `rights.FD_READ` is set, includes the right to invoke `poll_oneoff` to subscribe to `eventtype.FD_READ`. If `rights.FD_WRITE` is set, includes the right to invoke `poll_oneoff` to subscribe to `eventtype.FD_WRITE`. */ - @inline export const POLL_FD_READWRITE: rights = 134217728; - /** The right to invoke `sock_shutdown`. */ - @inline export const SOCK_SHUTDOWN: rights = 268435456; -} -export type rights = u64; - -/** Flags returned by `sock_recv`. */ -export namespace roflags { - /** Message data has been truncated. */ - @inline export const DATA_TRUNCATED: roflags = 1; -} -export type roflags = u16; - -/** Which channels on a socket to shut down. */ -export namespace sdflags { - /** Disables further receive operations. */ - @inline export const RD: sdflags = 1; - /** Disables further send operations. */ - @inline export const WR: sdflags = 2; -} -export type sdflags = u8; - -/** Flags provided to `sock_send`. */ -export namespace siflags { - // As there are currently no flags defined, it must be set to zero. -} -export type siflags = u16; - -/** Signal condition. */ -export namespace signal { - /** Hangup. */ - @inline export const HUP: signal = 1; - /** Terminate interrupt signal. */ - @inline export const INT: signal = 2; - /** Terminal quit signal. */ - @inline export const QUIT: signal = 3; - /** Illegal instruction. */ - @inline export const ILL: signal = 4; - /** Trace/breakpoint trap. */ - @inline export const TRAP: signal = 5; - /** Process abort signal. */ - @inline export const ABRT: signal = 6; - /** Access to an undefined portion of a memory object. */ - @inline export const BUS: signal = 7; - /** Erroneous arithmetic operation. */ - @inline export const FPE: signal = 8; - /** Kill. */ - @inline export const KILL: signal = 9; - /** User-defined signal 1. */ - @inline export const USR1: signal = 10; - /** Invalid memory reference. */ - @inline export const SEGV: signal = 11; - /** User-defined signal 2. */ - @inline export const USR2: signal = 12; - /** Write on a pipe with no one to read it. */ - @inline export const PIPE: signal = 13; - /** Alarm clock. */ - @inline export const ALRM: signal = 14; - /** Termination signal. */ - @inline export const TERM: signal = 15; - /** Child process terminated, stopped, or continued. */ - @inline export const CHLD: signal = 16; - /** Continue executing, if stopped. */ - @inline export const CONT: signal = 17; - /** Stop executing. */ - @inline export const STOP: signal = 18; - /** Terminal stop signal. */ - @inline export const TSTP: signal = 19; - /** Background process attempting read. */ - @inline export const TTIN: signal = 20; - /** Background process attempting write. */ - @inline export const TTOU: signal = 21; - /** High bandwidth data is available at a socket. */ - @inline export const URG: signal = 22; - /** CPU time limit exceeded. */ - @inline export const XCPU: signal = 23; - /** File size limit exceeded. */ - @inline export const XFSZ: signal = 24; - /** Virtual timer expired. */ - @inline export const VTALRM: signal = 25; - @inline export const PROF: signal = 26; - @inline export const WINCH: signal = 27; - @inline export const POLL: signal = 28; - @inline export const PWR: signal = 29; - /** Bad system call. */ - @inline export const SYS: signal = 30; -} -export type signal = u8; - -/** Flags determining how to interpret the timestamp provided in `subscription_t::u.clock.timeout. */ -export namespace subclockflags { - /** If set, treat the timestamp provided in `clocksubscription` as an absolute timestamp. */ - @inline export const ABSTIME: subclockflags = 1; -} -export type subclockflags = u16; - -/** Subscription to an event. */ -@unmanaged export abstract class subscription { - /** User-provided value that is attached to the subscription. */ - userdata: userdata; - /** The type of the event to which to subscribe. */ - type: eventtype; - private __padding0: u32; -} - -/* Subscription to an event of type `eventtype.CLOCK`.**/ -@unmanaged export class clocksubscription extends subscription { - /** The user-defined unique identifier of the clock. */ - identifier: userdata; - /** The clock against which to compare the timestamp. */ - clock_id: clockid; - /** The absolute or relative timestamp. */ - timeout: timestamp; - /** The amount of time that the implementation may wait additionally to coalesce with other events. */ - precision: timestamp; - /** Flags specifying whether the timeout is absolute or relative. */ - flags: subclockflags; - private __padding1: u32; -} - -/* Subscription to an event of type `eventtype.FD_READ` or `eventtype.FD_WRITE`.**/ -@unmanaged export class fdsubscription extends subscription { - /** The file descriptor on which to wait for it to become ready for reading or writing. */ - fd: fd; -} - -/** Timestamp in nanoseconds. */ -export type timestamp = u64; - -/** User-provided value that may be attached to objects that is retained when extracted from the implementation. */ -export type userdata = u64; - -/** The position relative to which to set the offset of the file descriptor. */ -export namespace whence { - /** Seek relative to current position. */ - @inline export const CUR: whence = 0; - /** Seek relative to end-of-file. */ - @inline export const END: whence = 1; - /** Seek relative to start-of-file. */ - @inline export const SET: whence = 2; -} -export type whence = u8; From b4cf6a97c9e21373acd62a24f94ad44f706f049f Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sat, 30 Mar 2019 17:30:19 +0100 Subject: [PATCH 002/512] Implement the __wasi_poll_oneoff system call --- Cargo.lock | 2 + lucet-wasi/bindings.json | 3 +- lucet-wasi/src/c_api.rs | 5 +- lucet-wasi/src/hostcalls.rs | 243 +++++++++++++++++++++++++++++++++ lucet-wasi/src/lib.rs | 1 - lucet-wasi/src/memory.rs | 77 +++++++++++ lucet-wasi/tests/guests/poll.c | 32 +++++ lucet-wasi/tests/tests.rs | 7 + 8 files changed, 364 insertions(+), 6 deletions(-) create mode 100644 lucet-wasi/tests/guests/poll.c diff --git a/Cargo.lock b/Cargo.lock index 80ccc074d..0ee28a1ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,3 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. [[package]] name = "aho-corasick" version = "0.6.10" diff --git a/lucet-wasi/bindings.json b/lucet-wasi/bindings.json index 1ef1660d3..d96e68ad8 100644 --- a/lucet-wasi/bindings.json +++ b/lucet-wasi/bindings.json @@ -16,6 +16,7 @@ "fd_seek": "__wasi_fd_seek", "fd_write": "__wasi_fd_write", "path_open": "__wasi_path_open", + "poll_oneoff": "__wasi_poll_oneoff", "random_get": "__wasi_random_get" } -} +} \ No newline at end of file diff --git a/lucet-wasi/src/c_api.rs b/lucet-wasi/src/c_api.rs index c81ca0c49..484b6c090 100644 --- a/lucet-wasi/src/c_api.rs +++ b/lucet-wasi/src/c_api.rs @@ -37,9 +37,7 @@ pub unsafe extern "C" fn lucet_wasi_ctx_args( } #[no_mangle] -pub unsafe extern "C" fn lucet_wasi_ctx_inherit_env( - wasi_ctx: *mut lucet_wasi_ctx, -) -> lucet_error { +pub unsafe extern "C" fn lucet_wasi_ctx_inherit_env(wasi_ctx: *mut lucet_wasi_ctx) -> lucet_error { assert_nonnull!(wasi_ctx); let mut b = Box::from_raw(wasi_ctx as *mut WasiCtxBuilder); *b = b.inherit_env(); @@ -78,7 +76,6 @@ pub unsafe extern "C" fn lucet_region_new_instance_with_wasi_ctx( }) } - /// Call this if you're having trouble with `__wasi_*` symbols not being exported. /// /// This is pretty hackish; we will hopefully be able to avoid this altogether once [this diff --git a/lucet-wasi/src/hostcalls.rs b/lucet-wasi/src/hostcalls.rs index 3eff88d6d..dd6b53625 100644 --- a/lucet-wasi/src/hostcalls.rs +++ b/lucet-wasi/src/hostcalls.rs @@ -13,10 +13,18 @@ use crate::ctx::WasiCtx; use crate::fdentry::{determine_type_rights, FdEntry}; use crate::memory::*; use crate::{host, wasm32}; + use cast::From as _0; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; + +use nix::convert_ioctl_res; +use nix::libc::c_int; use std::ffi::{OsStr, OsString}; +use std::iter::{Take, Zip}; use std::os::unix::prelude::{FromRawFd, OsStrExt, OsStringExt, RawFd}; +use std::slice::Iter; +use std::time::SystemTime; +use std::{cmp, slice}; #[no_mangle] pub extern "C" fn __wasi_proc_exit(vmctx: *mut lucet_vmctx, rval: wasm32::__wasi_exitcode_t) -> ! { @@ -980,6 +988,241 @@ pub extern "C" fn __wasi_random_get( return wasm32::__WASI_ESUCCESS; } +// define the `fionread()` function, equivalent to `ioctl(fd, FIONREAD, *bytes)` +nix::ioctl_read_bad!(fionread, nix::libc::FIONREAD, c_int); + +fn wasi_clock_to_relative_ns_delay( + wasi_clock: host::__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, +) -> u128 { + if wasi_clock.flags != wasm32::__WASI_SUBSCRIPTION_CLOCK_ABSTIME { + return wasi_clock.timeout as u128; + } + let now: u128 = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .expect("Current date is before the epoch") + .as_nanos(); + let deadline = wasi_clock.timeout as u128; + deadline.saturating_sub(now) +} + +#[derive(Debug, Copy, Clone)] +struct ClockEventData { + delay: u128, + userdata: host::__wasi_userdata_t, +} +#[derive(Debug, Copy, Clone)] +struct FdEventData { + fd: c_int, + type_: host::__wasi_eventtype_t, + userdata: host::__wasi_userdata_t, +} + +fn __wasi_poll_oneoff_handle_timeout_event( + vmctx: &mut Vmctx, + output_slice: &mut [wasm32::__wasi_event_t], + nevents: wasm32::uintptr_t, + timeout: Option, +) -> wasm32::__wasi_errno_t { + if let Some(ClockEventData { userdata, .. }) = timeout { + let output_event = host::__wasi_event_t { + userdata, + type_: wasm32::__WASI_EVENTTYPE_CLOCK, + error: wasm32::__WASI_ESUCCESS, + u: host::__wasi_event_t___wasi_event_u { + fd_readwrite: host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { + nbytes: 0, + flags: 0, + }, + }, + }; + output_slice[0] = enc_event(output_event); + if let Err(e) = unsafe { enc_pointee(vmctx, nevents, 1) } { + return e; + } + } else { + // shouldn't happen + if let Err(e) = unsafe { enc_pointee(vmctx, nevents, 0) } { + return e; + } + } + return wasm32::__WASI_ESUCCESS; +} + +fn __wasi_poll_oneoff_handle_fd_event( + vmctx: &mut Vmctx, + output_slice: &mut [wasm32::__wasi_event_t], + nevents: wasm32::uintptr_t, + events: Take, Iter<'_, nix::poll::PollFd>>>, +) -> wasm32::__wasi_errno_t { + let mut output_slice_cur = output_slice.iter_mut(); + let mut revents_count = 0; + for (fd_event, poll_fd) in events { + let revents = match poll_fd.revents() { + Some(revents) => revents, + None => continue, + }; + let mut nbytes = 0; + if fd_event.type_ == wasm32::__WASI_EVENTTYPE_FD_READ { + let _ = unsafe { fionread(fd_event.fd, &mut nbytes) }; + } + let output_event = if revents.contains(nix::poll::EventFlags::POLLNVAL) { + host::__wasi_event_t { + userdata: fd_event.userdata, + type_: fd_event.type_, + error: wasm32::__WASI_EBADF, + u: host::__wasi_event_t___wasi_event_u { + fd_readwrite: + host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { + nbytes: 0, + flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP, + }, + }, + } + } else if revents.contains(nix::poll::EventFlags::POLLERR) { + host::__wasi_event_t { + userdata: fd_event.userdata, + type_: fd_event.type_, + error: wasm32::__WASI_EIO, + u: host::__wasi_event_t___wasi_event_u { + fd_readwrite: + host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { + nbytes: 0, + flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP, + }, + }, + } + } else if revents.contains(nix::poll::EventFlags::POLLHUP) { + host::__wasi_event_t { + userdata: fd_event.userdata, + type_: fd_event.type_, + error: wasm32::__WASI_ESUCCESS, + u: host::__wasi_event_t___wasi_event_u { + fd_readwrite: + host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { + nbytes: 0, + flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP, + }, + }, + } + } else if revents.contains(nix::poll::EventFlags::POLLIN) + | revents.contains(nix::poll::EventFlags::POLLOUT) + { + host::__wasi_event_t { + userdata: fd_event.userdata, + type_: fd_event.type_, + error: wasm32::__WASI_ESUCCESS, + u: host::__wasi_event_t___wasi_event_u { + fd_readwrite: + host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { + nbytes: nbytes as host::__wasi_filesize_t, + flags: 0, + }, + }, + } + } else { + continue; + }; + *output_slice_cur.next().unwrap() = enc_event(output_event); + revents_count += 1; + } + if let Err(e) = unsafe { enc_pointee(vmctx, nevents, revents_count) } { + return e; + } + wasm32::__WASI_ESUCCESS +} + +#[no_mangle] +pub extern "C" fn __wasi_poll_oneoff( + vmctx: *mut lucet_vmctx, + input: wasm32::uintptr_t, + output: wasm32::uintptr_t, + nsubscriptions: wasm32::size_t, + nevents: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + if nsubscriptions as u64 > wasm32::__wasi_filesize_t::max_value() { + return wasm32::__WASI_EINVAL; + } + let mut vmctx = unsafe { Vmctx::from_raw(vmctx) }; + unsafe { enc_pointee(&mut vmctx, nevents, 0) }.unwrap(); + let input_slice_ = + unsafe { dec_slice_of::(&mut vmctx, input, nsubscriptions) } + .unwrap(); + let input_slice = unsafe { slice::from_raw_parts(input_slice_.0, input_slice_.1) }; + + let output_slice_ = + unsafe { dec_slice_of::(&mut vmctx, output, nsubscriptions) } + .unwrap(); + let output_slice = unsafe { slice::from_raw_parts_mut(output_slice_.0, output_slice_.1) }; + + let input: Vec<_> = input_slice.iter().map(|x| dec_subscription(x)).collect(); + + let timeout = input + .iter() + .filter_map(|event| match event { + Ok(event) if event.type_ == wasm32::__WASI_EVENTTYPE_CLOCK => Some(ClockEventData { + delay: wasi_clock_to_relative_ns_delay(unsafe { event.u.clock }) / 1_000_000, + userdata: event.userdata, + }), + _ => None, + }) + .min_by_key(|event| event.delay); + let fd_events: Vec<_> = input + .iter() + .filter_map(|event| match event { + Ok(event) + if event.type_ == wasm32::__WASI_EVENTTYPE_FD_READ + || event.type_ == wasm32::__WASI_EVENTTYPE_FD_WRITE => + { + Some(FdEventData { + fd: unsafe { event.u.fd_readwrite.fd } as c_int, + type_: event.type_, + userdata: event.userdata, + }) + } + _ => None, + }) + .collect(); + if fd_events.is_empty() && timeout.is_none() { + return wasm32::__WASI_ESUCCESS; + } + let mut poll_fds: Vec<_> = fd_events + .iter() + .map(|event| { + let mut flags = nix::poll::EventFlags::empty(); + match event.type_ { + wasm32::__WASI_EVENTTYPE_FD_READ => flags.insert(nix::poll::EventFlags::POLLIN), + wasm32::__WASI_EVENTTYPE_FD_WRITE => flags.insert(nix::poll::EventFlags::POLLOUT), + // An event on a file descriptor can currently only be of type FD_READ or FD_WRITE + // Nothing else has been defined in the specification, and these are also the only two + // events we filtered before. If we get something else here, the code has a serious bug. + _ => unreachable!(), + }; + nix::poll::PollFd::new(event.fd, flags) + }) + .collect(); + let timeout = timeout.map(|ClockEventData { delay, userdata }| ClockEventData { + delay: cmp::min(delay, c_int::max_value() as u128), + userdata, + }); + let poll_timeout = timeout.map(|timeout| timeout.delay as c_int).unwrap_or(-1); + let ready = loop { + match nix::poll::poll(&mut poll_fds, poll_timeout) { + Err(_) => { + if nix::errno::Errno::last() == nix::errno::Errno::EINTR { + continue; + } + return wasm32::errno_from_nix(nix::errno::Errno::last()); + } + Ok(ready) => break ready as usize, + } + }; + if ready == 0 { + return __wasi_poll_oneoff_handle_timeout_event(&mut vmctx, output_slice, nevents, timeout); + } + let events = fd_events.iter().zip(poll_fds.iter()).take(ready); + __wasi_poll_oneoff_handle_fd_event(&mut vmctx, output_slice, nevents, events) +} + #[doc(hidden)] pub fn ensure_linked() { unsafe { diff --git a/lucet-wasi/src/lib.rs b/lucet-wasi/src/lib.rs index 5dccecd80..de17160fe 100644 --- a/lucet-wasi/src/lib.rs +++ b/lucet-wasi/src/lib.rs @@ -7,4 +7,3 @@ pub mod memory; pub mod wasm32; pub use ctx::{WasiCtx, WasiCtxBuilder}; - diff --git a/lucet-wasi/src/memory.rs b/lucet-wasi/src/memory.rs index c521ca729..fad4cb6e8 100644 --- a/lucet-wasi/src/memory.rs +++ b/lucet-wasi/src/memory.rs @@ -357,3 +357,80 @@ dec_enc_scalar!( enc_whence, enc_whence_byref ); + +dec_enc_scalar!( + __wasi_subclockflags_t, + dec_subclockflags, + dec_subclockflags_byref, + enc_subclockflags, + enc_subclockflags_byref +); + +dec_enc_scalar!( + __wasi_eventrwflags_t, + dec_eventrwflags, + dec_eventrwflags_byref, + enc_eventrwflags, + enc_eventrwflags_byref +); + +dec_enc_scalar!( + __wasi_eventtype_t, + dec_eventtype, + dec_eventtype_byref, + enc_eventtype, + enc_eventtype_byref +); + +dec_enc_scalar!( + __wasi_userdata_t, + dec_userdata, + dec_userdata_byref, + enc_userdata, + enc_userdata_byref +); + +pub fn dec_subscription( + subscription: &wasm32::__wasi_subscription_t, +) -> Result { + let userdata = dec_userdata(subscription.userdata); + let type_ = dec_eventtype(subscription.type_); + let u_orig = subscription.__bindgen_anon_1; + let u = match type_ { + wasm32::__WASI_EVENTTYPE_CLOCK => host::__wasi_subscription_t___wasi_subscription_u { + clock: unsafe { + host::__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t { + identifier: u_orig.clock.identifier, + clock_id: dec_clockid(u_orig.clock.clock_id), + timeout: dec_timestamp(u_orig.clock.timeout), + precision: dec_timestamp(u_orig.clock.precision), + flags: dec_subclockflags(u_orig.clock.flags), + } + }, + }, + wasm32::__WASI_EVENTTYPE_FD_READ | wasm32::__WASI_EVENTTYPE_FD_WRITE => host::__wasi_subscription_t___wasi_subscription_u { + fd_readwrite: host::__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t { + fd: dec_fd(unsafe{u_orig.fd_readwrite.fd}) + } + }, + _ => return Err(wasm32::__WASI_EINVAL) + }; + Ok(host::__wasi_subscription_t { userdata, type_, u }) +} + +pub fn enc_event(event: host::__wasi_event_t) -> wasm32::__wasi_event_t { + let fd_readwrite = unsafe { event.u.fd_readwrite }; + wasm32::__wasi_event_t { + userdata: enc_userdata(event.userdata), + type_: enc_eventtype(event.type_), + error: enc_errno(event.error), + __bindgen_anon_1: wasm32::__wasi_event_t__bindgen_ty_1 { + fd_readwrite: wasm32::__wasi_event_t__bindgen_ty_1__bindgen_ty_1 { + nbytes: enc_filesize(fd_readwrite.nbytes), + flags: enc_eventrwflags(fd_readwrite.flags), + __bindgen_padding_0: [0; 3], + }, + }, + __bindgen_padding_0: 0, + } +} diff --git a/lucet-wasi/tests/guests/poll.c b/lucet-wasi/tests/guests/poll.c new file mode 100644 index 000000000..dc45ab58e --- /dev/null +++ b/lucet-wasi/tests/guests/poll.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +int main(void) +{ + struct pollfd fds[2]; + time_t before, now; + int ret; + + fds[0] = (struct pollfd){ .fd = 1, .events = POLLOUT, .revents = 0 }; + fds[1] = (struct pollfd){ .fd = 2, .events = POLLOUT, .revents = 0 }; + + ret = poll(fds, 2, -1); + assert(ret == 2); + assert(fds[0].revents == POLLOUT); + assert(fds[1].revents == POLLOUT); + + fds[0] = (struct pollfd){ .fd = 0, .events = POLLIN, .revents = 0 }; + time(&before); + ret = poll(fds, 1, 2000); + time(&now); + assert(ret == 0); + assert(now - before >= 2); + + sleep(1); + time(&now); + assert(now - before >= 3); + + return 0; +} \ No newline at end of file diff --git a/lucet-wasi/tests/tests.rs b/lucet-wasi/tests/tests.rs index 39ebea505..7874088af 100644 --- a/lucet-wasi/tests/tests.rs +++ b/lucet-wasi/tests/tests.rs @@ -356,3 +356,10 @@ fn pseudoquine() { assert_eq!(stdout, expected); } + +#[test] +fn poll() { + let ctx = WasiCtxBuilder::new().args(&["poll"]).build().unwrap(); + let exitcode = run("poll.c", ctx).unwrap(); + assert_eq!(exitcode, 0); +} From 79787b473c83e2f621d7eeff5c3275e429ae7349 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Tue, 2 Apr 2019 01:41:37 +0200 Subject: [PATCH 003/512] Nits --- lucet-wasi/src/hostcalls.rs | 14 ++++++-------- lucet-wasi/src/memory.rs | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/lucet-wasi/src/hostcalls.rs b/lucet-wasi/src/hostcalls.rs index dd6b53625..431c815e9 100644 --- a/lucet-wasi/src/hostcalls.rs +++ b/lucet-wasi/src/hostcalls.rs @@ -20,9 +20,7 @@ use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use nix::convert_ioctl_res; use nix::libc::c_int; use std::ffi::{OsStr, OsString}; -use std::iter::{Take, Zip}; use std::os::unix::prelude::{FromRawFd, OsStrExt, OsStringExt, RawFd}; -use std::slice::Iter; use std::time::SystemTime; use std::{cmp, slice}; @@ -1037,22 +1035,22 @@ fn __wasi_poll_oneoff_handle_timeout_event( }; output_slice[0] = enc_event(output_event); if let Err(e) = unsafe { enc_pointee(vmctx, nevents, 1) } { - return e; + return enc_errno(e); } } else { // shouldn't happen if let Err(e) = unsafe { enc_pointee(vmctx, nevents, 0) } { - return e; + return enc_errno(e); } } - return wasm32::__WASI_ESUCCESS; + wasm32::__WASI_ESUCCESS } -fn __wasi_poll_oneoff_handle_fd_event( +fn __wasi_poll_oneoff_handle_fd_event<'t>( vmctx: &mut Vmctx, output_slice: &mut [wasm32::__wasi_event_t], nevents: wasm32::uintptr_t, - events: Take, Iter<'_, nix::poll::PollFd>>>, + events: impl Iterator, ) -> wasm32::__wasi_errno_t { let mut output_slice_cur = output_slice.iter_mut(); let mut revents_count = 0; @@ -1126,7 +1124,7 @@ fn __wasi_poll_oneoff_handle_fd_event( revents_count += 1; } if let Err(e) = unsafe { enc_pointee(vmctx, nevents, revents_count) } { - return e; + return enc_errno(e); } wasm32::__WASI_ESUCCESS } diff --git a/lucet-wasi/src/memory.rs b/lucet-wasi/src/memory.rs index fad4cb6e8..89cf9cfed 100644 --- a/lucet-wasi/src/memory.rs +++ b/lucet-wasi/src/memory.rs @@ -400,7 +400,7 @@ pub fn dec_subscription( wasm32::__WASI_EVENTTYPE_CLOCK => host::__wasi_subscription_t___wasi_subscription_u { clock: unsafe { host::__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t { - identifier: u_orig.clock.identifier, + identifier: dec_userdata(u_orig.clock.identifier), clock_id: dec_clockid(u_orig.clock.clock_id), timeout: dec_timestamp(u_orig.clock.timeout), precision: dec_timestamp(u_orig.clock.precision), From 0b85602ce3fcba8dcf85cfff28813217bd7e979a Mon Sep 17 00:00:00 2001 From: Darin Morrison Date: Mon, 1 Apr 2019 18:57:41 -0700 Subject: [PATCH 004/512] Add .editorconfig --- .editorconfig | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..677e36e29 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true From 4f72dbaa56a98b9a415c11a632159944cdd105e6 Mon Sep 17 00:00:00 2001 From: Darin Morrison Date: Mon, 1 Apr 2019 19:21:38 -0700 Subject: [PATCH 005/512] Add .gitattributes --- .gitattributes | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..ed234a686 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +# Auto detect text and normalize to LF on commit regardless of "core.autocrlf". +# See: https://help.github.com/en/articles/dealing-with-line-endings#example +* text=auto eol=lf From 08ddebc2266e3882d6b678b07456e0ee09bf8888 Mon Sep 17 00:00:00 2001 From: Darin Morrison Date: Mon, 1 Apr 2019 23:02:50 -0700 Subject: [PATCH 006/512] Pin rustup toolchain to stable --- rust-toolchain | 1 + 1 file changed, 1 insertion(+) create mode 100644 rust-toolchain diff --git a/rust-toolchain b/rust-toolchain new file mode 100644 index 000000000..2bf5ad044 --- /dev/null +++ b/rust-toolchain @@ -0,0 +1 @@ +stable From 07f2d8154d5cff83704bdb6118c11d185fc44289 Mon Sep 17 00:00:00 2001 From: Takanori Ishibashi Date: Wed, 3 Apr 2019 23:28:05 +0900 Subject: [PATCH 007/512] Fix url in comments --- lucetc/src/compiler/data.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lucetc/src/compiler/data.rs b/lucetc/src/compiler/data.rs index bec0a74ec..728e87246 100644 --- a/lucetc/src/compiler/data.rs +++ b/lucetc/src/compiler/data.rs @@ -14,7 +14,7 @@ use failure::Error; /// The program that consumes the resulting ELF object is responsible for /// using it to initialize WASM linear memory regions. /// -/// [0] https://webassembly.github.io/spec/syntax/modules.html#data-segments +/// [0] https://webassembly.github.io/spec/core/syntax/modules.html#data-segments /// /// WARNING: At present, this code /// - Does limited validation of data segments From 238860469a683a138b19c362744b47c84f711431 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Wed, 3 Apr 2019 14:08:14 -0700 Subject: [PATCH 008/512] [lucet-wasi-fuzz] add basic Csmith fuzzing --- Cargo.lock | 135 ++++++++++++++++ Cargo.toml | 1 + Dockerfile | 4 +- Makefile | 4 + lucet-wasi-fuzz/Cargo.toml | 20 +++ lucet-wasi-fuzz/src/main.rs | 233 +++++++++++++++++++++++++++ lucet-wasi/tests/test_helpers/mod.rs | 3 +- 7 files changed, 397 insertions(+), 3 deletions(-) create mode 100644 lucet-wasi-fuzz/Cargo.toml create mode 100644 lucet-wasi-fuzz/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 0ee28a1ef..86b4c8faa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,6 +16,14 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "arrayvec" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "assert_matches" version = "1.3.0" @@ -255,6 +263,42 @@ dependencies = [ "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-deque" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-utils" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "either" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "env_logger" version = "0.6.1" @@ -545,6 +589,26 @@ dependencies = [ "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lucet-wasi-fuzz" +version = "0.1.0" +dependencies = [ + "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "lucet-runtime 0.1.0", + "lucet-wasi 0.1.0", + "lucet-wasi-sdk 0.1.0", + "lucetc 0.1.0", + "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -611,6 +675,11 @@ dependencies = [ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "nodrop" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "nom" version = "4.2.2" @@ -662,6 +731,14 @@ name = "num-traits" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "num_cpus" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "parity-wasm" version = "0.35.7" @@ -708,6 +785,14 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "progress" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "terminal_size 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "pwasm-validation" version = "0.1.0" @@ -837,6 +922,27 @@ dependencies = [ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rayon" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rayon-core" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rdrand" version = "0.4.0" @@ -1089,6 +1195,15 @@ dependencies = [ "wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "terminal_size" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "termion" version = "1.5.1" @@ -1184,6 +1299,14 @@ dependencies = [ "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "wasmonkey" version = "0.1.4" @@ -1263,6 +1386,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" "checksum assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7deb0a829ca7bcfaf5da70b073a8d128619259a7be8216a355e23f00763059e5" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" @@ -1284,6 +1408,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cmake 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "6ec65ee4f9c9d16f335091d23693457ed4928657ba4982289d7fafee03bc614a" "checksum colored 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e9a455e156a4271e12fd0246238c380b1e223e3736663c7a18ed8b6362028a9" +"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" +"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" +"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" +"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" "checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a" "checksum errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2a071601ed01b988f896ab14b95e67335d1eeb50190932a1320f7fe3cadc84e" "checksum errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067" @@ -1310,12 +1438,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum memory_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" "checksum nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46f0f3210768d796e8fa79ec70ee6af172dacbe7147f5e69be5240a47778302b" +"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum nom 4.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22293d25d3f33a8567cc8a1dc20f40c7eeb761ce83d0fcca059858580790cac3" "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" "checksum num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d9fe8fcafd1b86a37ce8a1cfa15ae504817e0c8c2e7ad42767371461ac1d316d" "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" +"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba" "checksum parity-wasm 0.35.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3e1e076c4e01399b6cd0793a8df42f90bba3ae424671ef421d1608a943155d93" "checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" "checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" @@ -1323,6 +1453,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum precision 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "83f0b3de90e9edd6382604f4f28509ce25272deb065b94045fc47abcde567d55" "checksum printtable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "69967dae4cac71681361899d9905d3d2985fc989d7afb32a8dff3aed5461ecdf" "checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" +"checksum progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b820305721858696053a7fd0215cfeeee16ecaaf96b7a209945428e02f1c44" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" @@ -1336,6 +1467,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d" +"checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473" +"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" @@ -1364,6 +1497,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6923974ce4eb5bd28814756256d8ab71c28dd6e7483313fe7ab6614306bf633" "checksum tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b86c784c88d98c801132806dadd3819ed29d8600836c4088e855cdf3e178ed8a" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" +"checksum terminal_size 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "023345d35850b69849741bd9a5432aa35290e3d8eb76af8717026f270d1cf133" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" @@ -1378,6 +1512,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "74e463a508e390cc7447e70f640fbf44ad52e1bd095314ace1fdf99516d32add" "checksum wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a6265b25719e82598d104b3717375e37661d41753e2c84cde3f51050c7ed7e3c" +"checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" diff --git a/Cargo.toml b/Cargo.toml index b35341d9c..c3d18c537 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ members = [ "lucet-runtime/lucet-runtime-tests", "lucet-spectest", "lucet-wasi", + "lucet-wasi-fuzz", "lucet-wasi-sdk", "lucetc", "sightglass", diff --git a/Dockerfile b/Dockerfile index c6e3215de..cab53b5fd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,9 @@ RUN apt-get update \ ca-certificates \ software-properties-common \ libssl-dev \ - pkg-config \ + pkg-config \ + csmith \ + libcsmith-dev \ && rm -rf /var/lib/apt/lists/* # Setting a consistent LD_LIBRARY_PATH across the entire environment prevents unnecessary Cargo diff --git a/Makefile b/Makefile index b703e2e84..d1a503f82 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,10 @@ test: indent-check -p lucet-wasi-sdk \ -p lucet-wasi +.PHONY: fuzz +fuzz: + cargo run --release -p lucet-wasi-fuzz + .PHONY: bench bench: make -C benchmarks/shootout clean diff --git a/lucet-wasi-fuzz/Cargo.toml b/lucet-wasi-fuzz/Cargo.toml new file mode 100644 index 000000000..a3d76d364 --- /dev/null +++ b/lucet-wasi-fuzz/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "lucet-wasi-fuzz" +version = "0.1.0" +authors = ["Adam C. Foltzer "] +edition = "2018" + +[dependencies] +clap = "2.32" +failure = "0.1" +libc = "0.2" +lucetc = { path = "../lucetc" } +lucet-runtime = { path = "../lucet-runtime" } +lucet-wasi = { path = "../lucet-wasi" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk" } +nix = "0.13" +progress = "0.2" +rand = "0.6" +rayon = "1.0" +tempfile = "3.0" +wait-timeout = "0.2" diff --git a/lucet-wasi-fuzz/src/main.rs b/lucet-wasi-fuzz/src/main.rs new file mode 100644 index 000000000..63de6521b --- /dev/null +++ b/lucet-wasi-fuzz/src/main.rs @@ -0,0 +1,233 @@ +use failure::{bail, format_err, Error}; +use libc::c_ulong; +use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region}; +use lucet_wasi::host::__wasi_exitcode_t; +use lucet_wasi::{WasiCtx, WasiCtxBuilder}; +use lucet_wasi_sdk::Link; +use lucetc::{Bindings, Lucetc}; +use rand::prelude::random; +use rayon::prelude::*; +use std::fs::File; +use std::io::Read; +use std::os::unix::io::{FromRawFd, IntoRawFd}; +use std::path::Path; +use std::process::{Command, Stdio}; +use std::sync::{Arc, Mutex}; +use std::time::Duration; +use tempfile::TempDir; +use wait_timeout::ChildExt; + +const LUCET_WASI_FUZZ_ROOT: &'static str = env!("CARGO_MANIFEST_DIR"); + +type Seed = c_ulong; + +fn main() { + lucet_runtime::lucet_internal_ensure_linked(); + + let num_tests = 1000; + + let mut progress = progress::Bar::new(); + progress.set_job_title(&format!("Running {} tests", num_tests)); + + let progress = Arc::new(Mutex::new(progress)); + let num_finished = Arc::new(Mutex::new(0)); + + let res = (0..num_tests) + .into_par_iter() + .try_for_each(|_| match run_one() { + Ok(TestResult::Passed) | Ok(TestResult::Ignored) => { + let mut num_finished = num_finished.lock().unwrap(); + *num_finished += 1; + let percentage = (*num_finished as f32 / num_tests as f32) * 100.0; + progress + .lock() + .unwrap() + .reach_percent(percentage.floor() as i32); + Ok(()) + } + Ok(fail) => Err(fail), + Err(error) => Err(TestResult::Errored { error }), + }); + + progress.lock().unwrap().jobs_done(); + + match res { + Err(TestResult::Failed { + seed, + expected, + actual, + }) => { + println!("test failed with seed {}\n", seed); + println!("native: {}", String::from_utf8_lossy(&expected)); + println!("lucet-wasi: {}", String::from_utf8_lossy(&actual)); + std::process::exit(1) + } + Err(TestResult::Errored { error }) => println!("test errored: {}", error), + Err(_) => unreachable!(), + Ok(()) => println!("all tests passed"), + } +} + +fn gen_c>(gen_c_path: P) -> Result { + let seed = random::(); + Command::new("csmith") + .arg("-s") + .arg(format!("{}", seed)) + .arg("-o") + .arg(gen_c_path.as_ref()) + .status()?; + Ok(seed) +} + +fn run_native>(tmpdir: &TempDir, gen_c_path: P) -> Result>, Error> { + let gen_path = tmpdir.path().join("gen"); + + Command::new("cc") + .arg("-I/usr/include/csmith") + .arg(gen_c_path.as_ref()) + .arg("-o") + .arg(&gen_path) + .output()?; + + let mut native_child = Command::new(&gen_path).stdout(Stdio::piped()).spawn()?; + + let exitcode = match native_child.wait_timeout(Duration::from_millis(1000))? { + Some(status) => status.code(), + None => { + native_child.kill()?; + native_child.wait()?.code() + } + }; + + match exitcode { + None => { + // native code diverged or took too long, so was killed by the timeout + return Ok(None); + } + Some(0) => (), + Some(code) => { + println!("native code returned non-zero exit code: {}", code); + return Ok(None); + } + } + + let mut native_stdout = vec![]; + native_child + .stdout + .ok_or(format_err!("couldn't get stdout"))? + .read_to_end(&mut native_stdout)?; + + Ok(Some(native_stdout)) +} + +enum TestResult { + Passed, + Ignored, + Failed { + seed: Seed, + expected: Vec, + actual: Vec, + }, + Errored { + error: Error, + }, +} + +fn run_one() -> Result { + let tmpdir = TempDir::new().unwrap(); + + let gen_c_path = tmpdir.path().join("gen.c"); + + let seed = gen_c(&gen_c_path)?; + + let native_stdout = if let Some(stdout) = run_native(&tmpdir, &gen_c_path)? { + stdout + } else { + return Ok(TestResult::Ignored); + }; + + let (exitcode, wasm_stdout) = run_with_stdout(&tmpdir, &gen_c_path)?; + + assert_eq!(exitcode, 0); + + if &wasm_stdout != &native_stdout { + Ok(TestResult::Failed { + seed, + expected: native_stdout, + actual: wasm_stdout, + }) + } else { + Ok(TestResult::Passed) + } +} + +fn run_with_stdout>( + tmpdir: &TempDir, + path: P, +) -> Result<(__wasi_exitcode_t, Vec), Error> { + let ctx = WasiCtxBuilder::new().args(&["gen"]); + + let (pipe_out, pipe_in) = nix::unistd::pipe()?; + + let ctx = unsafe { ctx.raw_fd(1, pipe_in) }.build()?; + + let exitcode = run(tmpdir, path, ctx)?; + + let mut stdout_file = unsafe { File::from_raw_fd(pipe_out) }; + let mut stdout = vec![]; + stdout_file.read_to_end(&mut stdout)?; + nix::unistd::close(stdout_file.into_raw_fd())?; + + Ok((exitcode, stdout)) +} + +fn run>( + tmpdir: &TempDir, + path: P, + ctx: WasiCtx, +) -> Result<__wasi_exitcode_t, Error> { + let region = MmapRegion::create(1, &Limits::default())?; + let module = wasi_test(tmpdir, path)?; + + let mut inst = region + .new_instance_builder(module) + .with_embed_ctx(ctx) + .build()?; + + match inst.run(b"_start", &[]) { + // normal termination implies 0 exit code + Ok(_) => Ok(0), + Err(lucet_runtime::Error::RuntimeTerminated( + lucet_runtime::TerminationDetails::Provided(any), + )) => Ok(*any + .downcast_ref::<__wasi_exitcode_t>() + .expect("termination yields an exitcode")), + Err(e) => bail!("runtime error: {}", e), + } +} + +fn wasi_test>(tmpdir: &TempDir, c_file: P) -> Result, Error> { + let wasm_build = Link::new(&[c_file]).cflag("-I/usr/include/csmith"); + + let wasm_file = tmpdir.path().join("out.wasm"); + + wasm_build.link(wasm_file.clone())?; + + let bindings = Bindings::from_file( + Path::new(LUCET_WASI_FUZZ_ROOT) + .parent() + .unwrap() + .join("lucet-wasi") + .join("bindings.json"), + )?; + + let native_build = Lucetc::new(wasm_file)?.bindings(bindings)?; + + let so_file = tmpdir.path().join("out.so"); + + native_build.shared_object_file(so_file.clone())?; + + let dlmodule = DlModule::load(so_file)?; + + Ok(dlmodule as Arc) +} diff --git a/lucet-wasi/tests/test_helpers/mod.rs b/lucet-wasi/tests/test_helpers/mod.rs index 0eac093a5..bff706a7f 100644 --- a/lucet-wasi/tests/test_helpers/mod.rs +++ b/lucet-wasi/tests/test_helpers/mod.rs @@ -1,6 +1,5 @@ use failure::{bail, Error}; -use lucet_runtime::{DlModule, Module}; -use lucet_runtime::{Limits, MmapRegion, Region}; +use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region}; use lucet_wasi::host::__wasi_exitcode_t; use lucet_wasi::{WasiCtx, WasiCtxBuilder}; use lucet_wasi_sdk::Link; From 6af5e1948a69e9e2b604b3a4d84c2992aaaebc2a Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Wed, 3 Apr 2019 14:44:08 -0700 Subject: [PATCH 009/512] [lucet-wasi-fuzz] add CLI with configurable seed and num_tests Adds a very short fuzzing run to the `test` target --- .gitignore | 3 +++ Cargo.lock | 2 +- Makefile | 3 ++- lucet-wasi-fuzz/Cargo.toml | 1 + lucet-wasi-fuzz/src/main.rs | 48 +++++++++++++++++++++++++++++++------ 5 files changed, 48 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 6e0f37c3c..182e70040 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ target/ *.rs.bk *.pyc host + +# csmith-generated +/platform.info diff --git a/Cargo.lock b/Cargo.lock index 86b4c8faa..408251216 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -589,7 +589,6 @@ dependencies = [ "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -607,6 +606,7 @@ dependencies = [ "progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/Makefile b/Makefile index d1a503f82..1e03ec237 100644 --- a/Makefile +++ b/Makefile @@ -26,10 +26,11 @@ test: indent-check -p lucet-idl \ -p lucet-wasi-sdk \ -p lucet-wasi + cargo run -p lucet-wasi-fuzz -- --num-tests=3 .PHONY: fuzz fuzz: - cargo run --release -p lucet-wasi-fuzz + cargo run --release -p lucet-wasi-fuzz -- --num-tests=1000 .PHONY: bench bench: diff --git a/lucet-wasi-fuzz/Cargo.toml b/lucet-wasi-fuzz/Cargo.toml index a3d76d364..299fe04b7 100644 --- a/lucet-wasi-fuzz/Cargo.toml +++ b/lucet-wasi-fuzz/Cargo.toml @@ -16,5 +16,6 @@ nix = "0.13" progress = "0.2" rand = "0.6" rayon = "1.0" +structopt = "0.2" tempfile = "3.0" wait-timeout = "0.2" diff --git a/lucet-wasi-fuzz/src/main.rs b/lucet-wasi-fuzz/src/main.rs index 63de6521b..559254bc2 100644 --- a/lucet-wasi-fuzz/src/main.rs +++ b/lucet-wasi-fuzz/src/main.rs @@ -14,6 +14,7 @@ use std::path::Path; use std::process::{Command, Stdio}; use std::sync::{Arc, Mutex}; use std::time::Duration; +use structopt::StructOpt; use tempfile::TempDir; use wait_timeout::ChildExt; @@ -21,11 +22,44 @@ const LUCET_WASI_FUZZ_ROOT: &'static str = env!("CARGO_MANIFEST_DIR"); type Seed = c_ulong; +#[derive(StructOpt, Debug)] +#[structopt(name = "lucet-wasi-fuzz")] +struct Config { + #[structopt(short = "n", long = "num-tests", default_value = "100")] + num_tests: usize, + #[structopt(long = "seed")] + seed: Option, +} + fn main() { lucet_runtime::lucet_internal_ensure_linked(); - let num_tests = 1000; + let config = Config::from_args(); + + if let Some(seed) = config.seed { + run_one_seed(seed); + } else { + run_many(config.num_tests); + } +} + +fn run_one_seed(seed: Seed) { + match run_one(Some(seed)) { + Ok(TestResult::Passed) => println!("test passed"), + Ok(TestResult::Ignored) => println!("native build/execution failed"), + Ok(TestResult::Failed { + expected, actual, .. + }) => { + println!("test failed:\n"); + println!("native: {}", String::from_utf8_lossy(&expected)); + println!("lucet-wasi: {}", String::from_utf8_lossy(&actual)); + std::process::exit(1); + } + Ok(TestResult::Errored { error }) | Err(error) => println!("test errored: {}", error), + } +} +fn run_many(num_tests: usize) { let mut progress = progress::Bar::new(); progress.set_job_title(&format!("Running {} tests", num_tests)); @@ -34,7 +68,7 @@ fn main() { let res = (0..num_tests) .into_par_iter() - .try_for_each(|_| match run_one() { + .try_for_each(|_| match run_one(None) { Ok(TestResult::Passed) | Ok(TestResult::Ignored) => { let mut num_finished = num_finished.lock().unwrap(); *num_finished += 1; @@ -68,15 +102,14 @@ fn main() { } } -fn gen_c>(gen_c_path: P) -> Result { - let seed = random::(); +fn gen_c>(gen_c_path: P, seed: Seed) -> Result<(), Error> { Command::new("csmith") .arg("-s") .arg(format!("{}", seed)) .arg("-o") .arg(gen_c_path.as_ref()) .status()?; - Ok(seed) + Ok(()) } fn run_native>(tmpdir: &TempDir, gen_c_path: P) -> Result>, Error> { @@ -133,12 +166,13 @@ enum TestResult { }, } -fn run_one() -> Result { +fn run_one(seed: Option) -> Result { let tmpdir = TempDir::new().unwrap(); let gen_c_path = tmpdir.path().join("gen.c"); - let seed = gen_c(&gen_c_path)?; + let seed = seed.unwrap_or(random::()); + gen_c(&gen_c_path, seed)?; let native_stdout = if let Some(stdout) = run_native(&tmpdir, &gen_c_path)? { stdout From b16ea502dcafec6c38cd41648a122f775cfba18d Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 4 Apr 2019 01:27:49 +0200 Subject: [PATCH 010/512] Build a "lucet" layer on top of "lucet-dev" We end up with two images. The former being just the base development environment, suitable for CI. The later having the release builds populated in /opt/lucet. This is the one we can upload to the Docker Hub, as people can use it to get immediately started with Lucet without having to recompile it. Also remove the wasi debian package after installation by the way. --- Dockerfile | 2 +- devenv_build_container.sh | 46 ++++++++++++++++++++++++++++++++++----- devenv_run.sh | 2 +- devenv_start.sh | 13 +++-------- 4 files changed, 45 insertions(+), 18 deletions(-) diff --git a/Dockerfile b/Dockerfile index c6e3215de..3900be73c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -31,6 +31,6 @@ ENV PATH=/usr/local/bin:$PATH RUN cargo install --root /usr/local cargo-audit cargo-watch RUN curl -sS -L -O https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-3/wasi-sdk_3.0_amd64.deb \ - && dpkg -i wasi-sdk_3.0_amd64.deb + && dpkg -i wasi-sdk_3.0_amd64.deb && rm -f wasi-sdk_3.0_amd64.deb ENV WASI_SDK=/opt/wasi-sdk diff --git a/devenv_build_container.sh b/devenv_build_container.sh index 467642a91..f2299c24c 100755 --- a/devenv_build_container.sh +++ b/devenv_build_container.sh @@ -5,12 +5,46 @@ git submodule update --init 2>/dev/null ||: if docker image inspect lucet-dev:latest > /dev/null; then - if [ -z "$DEVENV_FORCE_REBUILD" ]; then - echo "A lucet-dev image is already present" - echo "Hit Ctrl-C right now if you don't want to rebuild it" - echo "or skip this wait by setting the DEVENV_FORCE_REBUILD variable" - sleep 30 - fi + if [ -z "$DEVENV_FORCE_REBUILD" ]; then + echo "A lucet-dev image is already present" + echo "Hit Ctrl-C right now if you don't want to rebuild it" + echo "or skip this wait by setting the DEVENV_FORCE_REBUILD variable" + sleep 30 + fi fi +echo "Building lucet-dev:latest" docker build -t lucet-dev:latest . + +if [ -n "$DEVENV_NO_INSTALL" ]; then + docker tag lucet-dev:latest lucet:latest + exit +fi + +if docker image inspect lucet:latest > /dev/null; then + if [ -z "$DEVENV_FORCE_REBUILD" ]; then + echo "A lucet image is already present" + echo "Hit Ctrl-C right now if you don't want to rebuild it" + echo "or skip this wait by setting the DEVENV_FORCE_REBUILD variable" + sleep 30 + fi +fi + +echo "Now creating lucet:latest on top of lucet-dev:latest" +docker run --name=lucet-dev --detach --mount type=bind,src="$(cd $(dirname ${0}); pwd -P),target=/lucet" \ + lucet-dev:latest /bin/sleep 99999999 > /dev/null + +echo "Building and installing optimized files in [$HOST_LUCET_MOUNT_POINT]" +docker exec -t -w "$HOST_LUCET_MOUNT_POINT" lucet-dev make install + +echo "Cleaning" +docker exec -t -w "$HOST_LUCET_MOUNT_POINT" lucet-dev make clean + +echo "Tagging the new image" +docker container commit lucet-dev lucet:latest + +echo "Cleaning" +docker kill lucet-dev +docker rm lucet-dev + +echo "Done" diff --git a/devenv_run.sh b/devenv_run.sh index 8281dff6e..4ea5d79f0 100755 --- a/devenv_run.sh +++ b/devenv_run.sh @@ -2,7 +2,7 @@ . "$(dirname ${BASH_SOURCE:-$0})/config.inc" -if ! docker ps -f name=lucet | grep -Fq lucet ; then +if ! docker ps -f name='^lucet$' | grep -Fq lucet ; then ${HOST_BASE_PREFIX}/devenv_start.sh fi diff --git a/devenv_start.sh b/devenv_start.sh index c69f79896..423469b33 100755 --- a/devenv_start.sh +++ b/devenv_start.sh @@ -2,21 +2,14 @@ . "$(dirname ${BASH_SOURCE:-$0})/config.inc" -if ! docker image inspect lucet-dev:latest > /dev/null; then +if ! docker image inspect lucet:latest > /dev/null; then ${HOST_BASE_PREFIX}/devenv_build_container.sh fi -if docker ps -f name=lucet | grep -Fq lucet ; then +if docker ps -f name='^lucet$' | grep -Fq lucet ; then echo "container is already running" >&2 exit 1 fi docker run --name=lucet --detach --mount type=bind,src="$(cd $(dirname ${0}); pwd -P),target=/lucet" \ - lucet-dev:latest /bin/sleep 99999999 > /dev/null - -if [ -z "$DEVENV_NO_INSTALL" ]; then - if ! docker exec -t -w "$HOST_LUCET_MOUNT_POINT" lucet stat "$LUCET_PREFIX" > /dev/null ; then - echo "Lucet hasn't been installed yet... installing..." - docker exec -t -w "$HOST_LUCET_MOUNT_POINT" lucet make install - fi -fi + lucet:latest /bin/sleep 99999999 > /dev/null From 60e0fb126c8017cd4d23fe6ca4982042c714b3d2 Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Thu, 4 Apr 2019 15:04:07 -0700 Subject: [PATCH 011/512] teach lucet-wasi to be smarter about build failure modes not only can sed fail (not likely), but if wasi-sdk is not present the failure mode is kind of opaque --- lucet-wasi/build.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lucet-wasi/build.rs b/lucet-wasi/build.rs index b51ec3159..e22dce5da 100644 --- a/lucet-wasi/build.rs +++ b/lucet-wasi/build.rs @@ -6,8 +6,13 @@ use std::process::{Command, Stdio}; fn main() { let wasi_sdk = Path::new(&env::var("WASI_SDK").unwrap_or("/opt/wasi-sdk".to_owned())).to_path_buf(); + + assert!(wasi_sdk.exists(), "wasi-sdk not present at {:?}", wasi_sdk); + let wasi_sdk_core_h = wasi_sdk.join("share/sysroot/include/wasi/core.h"); + assert!(wasi_sdk_core_h.exists(), "wasi-sdk core.h not present at {:?}", wasi_sdk_core_h); + println!("cargo:rerun-if-changed={}", wasi_sdk_core_h.display()); let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); @@ -17,13 +22,21 @@ fn main() { // `bindgen` doesn't understand typed constant macros like `UINT8_C(123)`, so this fun regex // strips them off to yield a copy of `wasi/core.h` with bare constants. - Command::new("sed") + let sed_result = Command::new("sed") .arg("-E") .arg(r#"s/U?INT[0-9]+_C\(((0x)?[0-9]+)\)/\1/g"#) .arg(wasi_sdk_core_h) .stdout(Stdio::from(core_h)) .status() - .unwrap(); + .expect("can execute sed"); + + if !sed_result.success() { + // something failed, but how? + match sed_result.code() { + Some(code) => panic!("sed failed with code {}", code), + None => panic!("sed exited abnormally") + } + } let host_builder = bindgen::Builder::default() .clang_arg("-nostdinc") From f793a64f20953bab9dc67a89c1a3e3281da0d1cf Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Thu, 4 Apr 2019 16:09:53 -0700 Subject: [PATCH 012/512] fix wasi-sdk path and lucetc option changes --- benchmarks/shootout/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmarks/shootout/Makefile b/benchmarks/shootout/Makefile index 3c335e087..d78fb5059 100644 --- a/benchmarks/shootout/Makefile +++ b/benchmarks/shootout/Makefile @@ -1,6 +1,6 @@ LUCET_ROOT:=$(abspath ../..) -WASI_SDK?=/opt/wasi +WASI_SDK?=/opt/wasi-sdk WASI_CC=$(WASI_SDK)/bin/clang LUCETC:=$(LUCET_ROOT)/target/release/lucetc @@ -16,7 +16,7 @@ SHOOTOUT_SRCS:=$(shell ls $(SHOOTOUT)/*.c) SHOOTOUT_NATIVE_OBJS:= SHOOTOUT_LUCET_OBJS:= -LUCETC_FLAGS:=--opt-level best --reserved-size 4294967296 +LUCETC_FLAGS:=--opt-level best --max-reserved-size 4294967296 COMMON_CFLAGS:=--std=c99 -Ofast -Wall -W -I$(SIGHTGLASS)/include SHOOTOUT_NATIVE_CFLAGS:=-march=native -fPIC \ From f9f58b69dafaed3cce217762bb7db6b256b878a3 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Thu, 4 Apr 2019 16:31:23 -0700 Subject: [PATCH 013/512] [lucet-wasi-fuzz] creduce driver and test predicate improvements Notably, when compiling the native code with `-m32`, the error rate is low enough that a run of 10,000 tests yielded no failures. --- .gitignore | 3 - Cargo.lock | 2 + Dockerfile | 8 +- Makefile | 4 +- lucet-wasi-fuzz/Cargo.toml | 2 + lucet-wasi-fuzz/src/main.rs | 232 ++++++++++++++++++++++++++++++------ platform.info | 2 + 7 files changed, 206 insertions(+), 47 deletions(-) create mode 100644 platform.info diff --git a/.gitignore b/.gitignore index 182e70040..6e0f37c3c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,3 @@ target/ *.rs.bk *.pyc host - -# csmith-generated -/platform.info diff --git a/Cargo.lock b/Cargo.lock index 408251216..ae32cdd2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -603,9 +603,11 @@ dependencies = [ "lucet-wasi-sdk 0.1.0", "lucetc 0.1.0", "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Dockerfile b/Dockerfile index cab53b5fd..93db8bc64 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,9 +14,11 @@ RUN apt-get update \ ca-certificates \ software-properties-common \ libssl-dev \ - pkg-config \ - csmith \ - libcsmith-dev \ + pkg-config \ + csmith \ + libcsmith-dev \ + creduce \ + gcc-multilib \ && rm -rf /var/lib/apt/lists/* # Setting a consistent LD_LIBRARY_PATH across the entire environment prevents unnecessary Cargo diff --git a/Makefile b/Makefile index 1e03ec237..b13506f62 100644 --- a/Makefile +++ b/Makefile @@ -26,11 +26,11 @@ test: indent-check -p lucet-idl \ -p lucet-wasi-sdk \ -p lucet-wasi - cargo run -p lucet-wasi-fuzz -- --num-tests=3 + cargo run -p lucet-wasi-fuzz -- fuzz --num-tests=3 .PHONY: fuzz fuzz: - cargo run --release -p lucet-wasi-fuzz -- --num-tests=1000 + cargo run --release -p lucet-wasi-fuzz -- fuzz --num-tests=1000 .PHONY: bench bench: diff --git a/lucet-wasi-fuzz/Cargo.toml b/lucet-wasi-fuzz/Cargo.toml index 299fe04b7..05d7939ab 100644 --- a/lucet-wasi-fuzz/Cargo.toml +++ b/lucet-wasi-fuzz/Cargo.toml @@ -13,8 +13,10 @@ lucet-runtime = { path = "../lucet-runtime" } lucet-wasi = { path = "../lucet-wasi" } lucet-wasi-sdk = { path = "../lucet-wasi-sdk" } nix = "0.13" +num_cpus = "1.10" progress = "0.2" rand = "0.6" +regex = "1.1" rayon = "1.0" structopt = "0.2" tempfile = "3.0" diff --git a/lucet-wasi-fuzz/src/main.rs b/lucet-wasi-fuzz/src/main.rs index 559254bc2..6e7900fee 100644 --- a/lucet-wasi-fuzz/src/main.rs +++ b/lucet-wasi-fuzz/src/main.rs @@ -1,4 +1,4 @@ -use failure::{bail, format_err, Error}; +use failure::{bail, ensure, format_err, Error}; use libc::c_ulong; use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region}; use lucet_wasi::host::__wasi_exitcode_t; @@ -7,11 +7,12 @@ use lucet_wasi_sdk::Link; use lucetc::{Bindings, Lucetc}; use rand::prelude::random; use rayon::prelude::*; +use regex::Regex; use std::fs::File; -use std::io::Read; -use std::os::unix::io::{FromRawFd, IntoRawFd}; -use std::path::Path; -use std::process::{Command, Stdio}; +use std::io::{Read, Write}; +use std::os::unix::prelude::{FromRawFd, IntoRawFd, OpenOptionsExt}; +use std::path::{Path, PathBuf}; +use std::process::{exit, Command, Stdio}; use std::sync::{Arc, Mutex}; use std::time::Duration; use structopt::StructOpt; @@ -24,23 +25,158 @@ type Seed = c_ulong; #[derive(StructOpt, Debug)] #[structopt(name = "lucet-wasi-fuzz")] -struct Config { - #[structopt(short = "n", long = "num-tests", default_value = "100")] - num_tests: usize, - #[structopt(long = "seed")] - seed: Option, +enum Config { + /// Test the Lucet toolchain against native code execution using Csmith + #[structopt(name = "fuzz")] + Fuzz { + #[structopt(short = "n", long = "num-tests", default_value = "100")] + /// The number of tests to run + num_tests: usize, + }, + + /// Reduce a test case, starting from the given Csmith seed + #[structopt(name = "creduce")] + Creduce { seed: Seed }, + + /// Creduce interestingness check (probably not useful directly) + #[structopt(name = "creduce-interesting")] + CreduceInteresting { creduce_src: PathBuf }, + + /// Run a test case with the given Csmith seed + #[structopt(name = "test-seed")] + TestSeed { seed: Seed }, } fn main() { lucet_runtime::lucet_internal_ensure_linked(); - let config = Config::from_args(); + match Config::from_args() { + Config::Fuzz { num_tests } => run_many(num_tests), + Config::Creduce { seed } => run_creduce_driver(seed), + Config::CreduceInteresting { creduce_src } => run_creduce_interestingness(creduce_src), + Config::TestSeed { seed } => run_one_seed(seed), + } +} - if let Some(seed) = config.seed { - run_one_seed(seed); - } else { - run_many(config.num_tests); +fn run_creduce_driver(seed: Seed) { + let tmpdir = TempDir::new().unwrap(); + + // make the driver script + + let mut script = std::fs::OpenOptions::new() + .create(true) + .write(true) + .mode(0o777) + .open(tmpdir.path().join("script.sh")) + .unwrap(); + + let current_exe = std::env::current_exe().unwrap(); + + write!( + script, + "{}", + format!( + "#!/usr/bin/env sh\n{} creduce-interesting gen.c", + current_exe.display() + ), + ) + .unwrap(); + + drop(script); + + // reproduce the generated program, and then preprocess it + + let st = Command::new("csmith") + .arg("-s") + .arg(format!("{}", seed)) + .arg("-o") + .arg(tmpdir.path().join("gen-original.c")) + .status() + .unwrap(); + assert!(st.success()); + + let st = Command::new("clang") + .arg("-I/usr/include/csmith") + .arg("-m32") + .arg("-E") + .arg("-P") + .arg(tmpdir.path().join("gen-original.c")) + .arg("-o") + .arg(tmpdir.path().join("gen.c")) + .status() + .unwrap(); + assert!(st.success()); + + let st = Command::new("creduce") + .current_dir(tmpdir.path()) + .arg("--n") + .arg(format!("{}", std::cmp::max(1, num_cpus::get() - 1))) + .arg("script.sh") + .arg("gen.c") + .status() + .unwrap(); + assert!(st.success()); + + print!( + "{}", + std::fs::read_to_string(tmpdir.path().join("gen.c")).unwrap() + ); +} + +fn run_creduce_interestingness>(src: P) { + let tmpdir = TempDir::new().unwrap(); + + match run_both(&tmpdir, src, None) { + Ok(TestResult::Passed) => println!("test passed"), + Ok(TestResult::Ignored) => println!("native build/execution failed"), + Ok(TestResult::Failed { + expected, actual, .. + }) => { + println!("test failed:\n"); + let expected = String::from_utf8_lossy(&expected); + let actual = String::from_utf8_lossy(&actual); + println!("native: {}", &expected); + println!("lucet-wasi: {}", &actual); + + let re = Regex::new(r"^checksum = ([[:xdigit:]]{8})").unwrap(); + + // a coarse way to stop creduce from producing degenerate cases that happen to yield + // different output + + let expected_checksum = if let Some(caps) = re.captures(&expected) { + if let Some(cap) = caps.get(1) { + cap.as_str().to_owned() + } else { + // not interesting: no checksum captured from native output + exit(1); + } + } else { + // not interesting: no checksum captured from native output + exit(1); + }; + + let actual_checksum = if let Some(caps) = re.captures(&actual) { + if let Some(cap) = caps.get(1) { + cap.as_str().to_owned() + } else { + // interesting: checksum captured from native output but not wasm + exit(0) + } + } else { + // interesting: checksum captured from native output but not wasm + exit(0) + }; + + if expected_checksum == actual_checksum { + // they match; not interesting + exit(1); + } else { + exit(0); + } + } + Ok(TestResult::Errored { error }) | Err(error) => println!("test errored: {}", error), } + exit(1); } fn run_one_seed(seed: Seed) { @@ -53,7 +189,7 @@ fn run_one_seed(seed: Seed) { println!("test failed:\n"); println!("native: {}", String::from_utf8_lossy(&expected)); println!("lucet-wasi: {}", String::from_utf8_lossy(&actual)); - std::process::exit(1); + exit(1); } Ok(TestResult::Errored { error }) | Err(error) => println!("test errored: {}", error), } @@ -91,10 +227,10 @@ fn run_many(num_tests: usize) { expected, actual, }) => { - println!("test failed with seed {}\n", seed); + println!("test failed with seed {}\n", seed.unwrap()); println!("native: {}", String::from_utf8_lossy(&expected)); println!("lucet-wasi: {}", String::from_utf8_lossy(&actual)); - std::process::exit(1) + exit(1); } Err(TestResult::Errored { error }) => println!("test errored: {}", error), Err(_) => unreachable!(), @@ -112,15 +248,51 @@ fn gen_c>(gen_c_path: P, seed: Seed) -> Result<(), Error> { Ok(()) } +fn run_both>( + tmpdir: &TempDir, + src: P, + seed: Option, +) -> Result { + let native_stdout = if let Some(stdout) = run_native(&tmpdir, src.as_ref())? { + stdout + } else { + return Ok(TestResult::Ignored); + }; + + let (exitcode, wasm_stdout) = run_with_stdout(&tmpdir, src.as_ref())?; + + assert_eq!(exitcode, 0); + + if &wasm_stdout != &native_stdout { + Ok(TestResult::Failed { + seed, + expected: native_stdout, + actual: wasm_stdout, + }) + } else { + Ok(TestResult::Passed) + } +} + fn run_native>(tmpdir: &TempDir, gen_c_path: P) -> Result>, Error> { let gen_path = tmpdir.path().join("gen"); - Command::new("cc") + let res = Command::new("clang") + .arg("-m32") + .arg("-std=c11") + .arg("-Werror=format") + .arg("-Werror=uninitialized") + .arg("-Werror=conditional-uninitialized") .arg("-I/usr/include/csmith") .arg(gen_c_path.as_ref()) .arg("-o") .arg(&gen_path) .output()?; + ensure!(res.status.success(), "native C compilation failed"); + + if String::from_utf8_lossy(&res.stderr).contains("too few arguments in call") { + bail!("saw \"too few arguments in call\" warning"); + } let mut native_child = Command::new(&gen_path).stdout(Stdio::piped()).spawn()?; @@ -157,7 +329,7 @@ enum TestResult { Passed, Ignored, Failed { - seed: Seed, + seed: Option, expected: Vec, actual: Vec, }, @@ -174,25 +346,7 @@ fn run_one(seed: Option) -> Result { let seed = seed.unwrap_or(random::()); gen_c(&gen_c_path, seed)?; - let native_stdout = if let Some(stdout) = run_native(&tmpdir, &gen_c_path)? { - stdout - } else { - return Ok(TestResult::Ignored); - }; - - let (exitcode, wasm_stdout) = run_with_stdout(&tmpdir, &gen_c_path)?; - - assert_eq!(exitcode, 0); - - if &wasm_stdout != &native_stdout { - Ok(TestResult::Failed { - seed, - expected: native_stdout, - actual: wasm_stdout, - }) - } else { - Ok(TestResult::Passed) - } + run_both(&tmpdir, &gen_c_path, Some(seed)) } fn run_with_stdout>( diff --git a/platform.info b/platform.info new file mode 100644 index 000000000..9fc6494b6 --- /dev/null +++ b/platform.info @@ -0,0 +1,2 @@ +integer size = 4 +pointer size = 4 From 9388e75f4cf22bfde96aea9e61285d086e87a0f5 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Thu, 4 Apr 2019 16:52:42 -0700 Subject: [PATCH 014/512] add clang to the devenv image to support fuzzing --- Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Dockerfile b/Dockerfile index 93db8bc64..e8f7c5773 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,8 +19,11 @@ RUN apt-get update \ libcsmith-dev \ creduce \ gcc-multilib \ + clang-6.0 \ && rm -rf /var/lib/apt/lists/* +RUN update-alternatives --install /usr/bin/clang clang /usr/bin/clang-6.0 100 + # Setting a consistent LD_LIBRARY_PATH across the entire environment prevents unnecessary Cargo # rebuilds. ENV LD_LIBRARY_PATH=/usr/local/lib From 6621d7190956a527f1943f2c06f33c6aedc99e21 Mon Sep 17 00:00:00 2001 From: awortman-fastly <49215183+awortman-fastly@users.noreply.github.com> Date: Fri, 5 Apr 2019 12:19:43 -0700 Subject: [PATCH 015/512] Update Makefile --- benchmarks/shootout/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/shootout/Makefile b/benchmarks/shootout/Makefile index d78fb5059..22a2fcbdd 100644 --- a/benchmarks/shootout/Makefile +++ b/benchmarks/shootout/Makefile @@ -16,7 +16,7 @@ SHOOTOUT_SRCS:=$(shell ls $(SHOOTOUT)/*.c) SHOOTOUT_NATIVE_OBJS:= SHOOTOUT_LUCET_OBJS:= -LUCETC_FLAGS:=--opt-level best --max-reserved-size 4294967296 +LUCETC_FLAGS:=--opt-level best --min-reserved-size 4294967296 COMMON_CFLAGS:=--std=c99 -Ofast -Wall -W -I$(SIGHTGLASS)/include SHOOTOUT_NATIVE_CFLAGS:=-march=native -fPIC \ From fbd9a73adef4dc820e724b0188bb23237e1efc0e Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Mon, 8 Apr 2019 20:23:48 +0200 Subject: [PATCH 016/512] Update sightglass --- sightglass | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sightglass b/sightglass index eb9706139..4999f901b 160000 --- a/sightglass +++ b/sightglass @@ -1 +1 @@ -Subproject commit eb97061395e617671cfeaf4b3a44367f558c918e +Subproject commit 4999f901b3d686a911dfe24b588d6397ca2b193a From 5ca597ddcd27f10ecb33bd766743046c68c3322d Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Mon, 8 Apr 2019 18:25:44 -0700 Subject: [PATCH 017/512] lucet-wasi-sdk: disable threading in lld (wasi-ld) it appears that as of this moment both of the following are true: * lld's wasm linker may deadlock if linking with threads enabled * lld's wasm linker builds with threads enabled by default some references found in tracking this down: https://bugs.llvm.org/show_bug.cgi?id=37064 the following looks to not be wasm-related in particular: https://bugs.llvm.org/show_bug.cgi?id=34806 but similar patterns seem to exist in the wasm driver used by lld, even if they've since been fixed for other targets. --- lucet-wasi-sdk/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lucet-wasi-sdk/src/lib.rs b/lucet-wasi-sdk/src/lib.rs index 9e633ca0c..a5048c84c 100644 --- a/lucet-wasi-sdk/src/lib.rs +++ b/lucet-wasi-sdk/src/lib.rs @@ -108,12 +108,14 @@ pub struct Link { impl Link { pub fn new>(input: &[P]) -> Self { - Link { + let mut link = Link { input: input.iter().map(|p| PathBuf::from(p.as_ref())).collect(), cflags: Vec::new(), ldflags: Vec::new(), print_output: false, - } + }; + link.with_ldflag("--no-threads"); + link } pub fn cflag>(mut self, cflag: S) -> Self { From cb876caa5d017483f563c9327ebaa6dd597c9a4a Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 9 Apr 2019 14:03:28 -0700 Subject: [PATCH 018/512] [lucet-wasi-sdk] [lucetc] make builder interfaces more composable --- Cargo.lock | 1 + .../lucet-runtime-tests/src/build.rs | 16 +- .../lucet-runtime-tests/src/stack.rs | 2 +- lucet-wasi-fuzz/src/main.rs | 8 +- lucet-wasi-sdk/Cargo.lock | 216 ---------------- lucet-wasi-sdk/Cargo.toml | 3 +- lucet-wasi-sdk/src/lib.rs | 233 +++++++++++++----- lucet-wasi/tests/test_helpers/mod.rs | 12 +- lucetc/src/bindings.rs | 14 +- lucetc/src/lib.rs | 179 +++++++++----- lucetc/src/main.rs | 18 +- lucetc/tests/wasi-sdk.rs | 10 +- 12 files changed, 328 insertions(+), 384 deletions(-) delete mode 100644 lucet-wasi-sdk/Cargo.lock diff --git a/Cargo.lock b/Cargo.lock index 408251216..1cd6feb30 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -616,6 +616,7 @@ name = "lucet-wasi-sdk" version = "0.1.0" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lucetc 0.1.0", "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/lucet-runtime/lucet-runtime-tests/src/build.rs b/lucet-runtime/lucet-runtime-tests/src/build.rs index 5de367884..56167acd8 100644 --- a/lucet-runtime/lucet-runtime-tests/src/build.rs +++ b/lucet-runtime/lucet-runtime-tests/src/build.rs @@ -1,7 +1,7 @@ use failure::Error; use lucet_runtime_internals::module::DlModule; -use lucet_wasi_sdk::Link; -use lucetc::{Bindings, Lucetc}; +use lucet_wasi_sdk::{CompileOpts, Link, LinkOpts}; +use lucetc::{Bindings, Lucetc, LucetcOpts}; use std::path::{Path, PathBuf}; use std::sync::Arc; use tempfile::TempDir; @@ -30,10 +30,10 @@ where let workdir = TempDir::new().expect("create working directory"); let wasm_build = Link::new(&[c_file]) - .cflag("-nostartfiles") - .ldflag("--no-entry") - .ldflag("--allow-undefined") - .ldflag("--export-all"); + .with_cflag("-nostartfiles") + .with_ldflag("--no-entry") + .with_ldflag("--allow-undefined") + .with_ldflag("--export-all"); let wasm_file = workdir.path().join("out.wasm"); @@ -41,7 +41,7 @@ where let bindings = Bindings::from_file(bindings_file.as_ref())?; - let native_build = Lucetc::new(wasm_file)?.bindings(bindings)?; + let native_build = Lucetc::new(wasm_file).with_bindings(bindings); let so_file = workdir.path().join("out.so"); @@ -67,7 +67,7 @@ where let bindings = Bindings::from_file(&bindings_file)?; - let native_build = Lucetc::new(wasm_file)?.bindings(bindings)?; + let native_build = Lucetc::new(wasm_file).with_bindings(bindings); let so_file = workdir.path().join("out.so"); diff --git a/lucet-runtime/lucet-runtime-tests/src/stack.rs b/lucet-runtime/lucet-runtime-tests/src/stack.rs index 69beee8e2..daa58cff6 100644 --- a/lucet-runtime/lucet-runtime-tests/src/stack.rs +++ b/lucet-runtime/lucet-runtime-tests/src/stack.rs @@ -14,7 +14,7 @@ pub fn stack_testcase(num_locals: usize) -> Result, Error> { let mut wasm_file = File::create(&wasm_path)?; wasm_file.write_all(generate_test_wat(num_locals).as_bytes())?; - let native_build = Lucetc::new(wasm_path)?; + let native_build = Lucetc::new(wasm_path); let so_file = workdir.path().join("out.so"); diff --git a/lucet-wasi-fuzz/src/main.rs b/lucet-wasi-fuzz/src/main.rs index 559254bc2..50075e5c5 100644 --- a/lucet-wasi-fuzz/src/main.rs +++ b/lucet-wasi-fuzz/src/main.rs @@ -3,8 +3,8 @@ use libc::c_ulong; use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region}; use lucet_wasi::host::__wasi_exitcode_t; use lucet_wasi::{WasiCtx, WasiCtxBuilder}; -use lucet_wasi_sdk::Link; -use lucetc::{Bindings, Lucetc}; +use lucet_wasi_sdk::{CompileOpts, Link}; +use lucetc::{Bindings, Lucetc, LucetcOpts}; use rand::prelude::random; use rayon::prelude::*; use std::fs::File; @@ -241,7 +241,7 @@ fn run>( } fn wasi_test>(tmpdir: &TempDir, c_file: P) -> Result, Error> { - let wasm_build = Link::new(&[c_file]).cflag("-I/usr/include/csmith"); + let wasm_build = Link::new(&[c_file]).with_cflag("-I/usr/include/csmith"); let wasm_file = tmpdir.path().join("out.wasm"); @@ -255,7 +255,7 @@ fn wasi_test>(tmpdir: &TempDir, c_file: P) -> Result for CompileError { + fn from(e: std::io::Error) -> CompileError { + CompileError::IO { e } + } } impl CompileError { @@ -42,35 +59,49 @@ pub struct Compile { print_output: bool, } -impl Compile { - pub fn new>(input: P) -> Self { - Compile { - input: PathBuf::from(input.as_ref()), - cflags: Vec::new(), - print_output: false, - } +pub trait CompileOpts { + fn cflag>(&mut self, cflag: S); + fn with_cflag>(self, cflag: S) -> Self; + + fn include>(&mut self, include: S); + fn with_include>(self, include: S) -> Self; +} + +impl CompileOpts for Compile { + fn cflag>(&mut self, cflag: S) { + self.cflags.push(cflag.as_ref().to_owned()); } - pub fn cflag>(mut self, cflag: S) -> Self { - self.with_cflag(cflag); + fn with_cflag>(mut self, cflag: S) -> Self { + self.cflag(cflag); self } - pub fn with_cflag>(&mut self, cflag: S) { - self.cflags.push(cflag.as_ref().to_owned()); + fn include>(&mut self, include: S) { + self.cflags.push(format!("-I{}", include.as_ref())); } - pub fn include>(mut self, include: S) -> Self { - self.with_include(include); + fn with_include>(mut self, include: S) -> Self { + self.include(include); self } +} - pub fn with_include>(&mut self, include: S) { - self.cflags.push(format!("-I{}", include.as_ref())); +impl Compile { + pub fn new>(input: P) -> Self { + Compile { + input: PathBuf::from(input.as_ref()), + cflags: Vec::new(), + print_output: false, + } } - pub fn print_output(mut self, print: bool) -> Self { + pub fn print_output(&mut self, print: bool) { self.print_output = print; + } + + pub fn with_print_output(mut self, print: bool) -> Self { + self.print_output(print); self } @@ -116,44 +147,12 @@ impl Link { } } - pub fn cflag>(mut self, cflag: S) -> Self { - self.with_cflag(cflag); - self - } - - pub fn with_cflag>(&mut self, cflag: S) { - self.cflags.push(cflag.as_ref().to_owned()); - } - - pub fn include>(mut self, include: S) -> Self { - self.with_include(include); - self - } - - pub fn with_include>(&mut self, include: S) { - self.cflags.push(format!("-I{}", include.as_ref())); - } - - pub fn ldflag>(mut self, ldflag: S) -> Self { - self.with_ldflag(ldflag); - self - } - - pub fn with_ldflag>(&mut self, ldflag: S) { - self.ldflags.push(ldflag.as_ref().to_owned()); - } - - pub fn export>(mut self, export: S) -> Self { - self.with_export(export); - self - } - - pub fn with_export>(&mut self, export: S) { - self.ldflags.push(format!("--export={}", export.as_ref())); + pub fn print_output(&mut self, print: bool) { + self.print_output = print; } - pub fn print_output(mut self, print: bool) -> Self { - self.print_output = print; + pub fn with_print_output(mut self, print: bool) -> Self { + self.print_output(print); self } @@ -186,6 +185,120 @@ impl Link { } } +pub trait AsLink { + fn as_link(&mut self) -> &mut Link; +} + +impl AsLink for Link { + fn as_link(&mut self) -> &mut Link { + self + } +} + +pub trait LinkOpts { + fn ldflag>(&mut self, ldflag: S); + fn with_ldflag>(self, ldflag: S) -> Self; + + fn export>(&mut self, export: S); + fn with_export>(self, export: S) -> Self; +} + +impl LinkOpts for T { + fn ldflag>(&mut self, ldflag: S) { + self.as_link().ldflags.push(ldflag.as_ref().to_owned()); + } + + fn with_ldflag>(mut self, ldflag: S) -> Self { + self.ldflag(ldflag); + self + } + + fn export>(&mut self, export: S) { + self.as_link() + .ldflags + .push(format!("--export={}", export.as_ref())); + } + + fn with_export>(mut self, export: S) -> Self { + self.export(export); + self + } +} + +impl CompileOpts for T { + fn cflag>(&mut self, cflag: S) { + self.as_link().cflags.push(cflag.as_ref().to_owned()); + } + + fn with_cflag>(mut self, cflag: S) -> Self { + self.cflag(cflag); + self + } + + fn include>(&mut self, include: S) { + self.as_link() + .cflags + .push(format!("-I{}", include.as_ref())); + } + + fn with_include>(mut self, include: S) -> Self { + self.include(include); + self + } +} + +pub struct Lucetc { + link: Link, + lucetc: lucetc::Lucetc, + tmpdir: TempDir, + wasm_file: PathBuf, +} + +impl Lucetc { + pub fn new>(input: &[P]) -> Self { + let link = Link { + input: input.iter().map(|p| PathBuf::from(p.as_ref())).collect(), + cflags: Vec::new(), + ldflags: Vec::new(), + print_output: false, + }; + let tmpdir = TempDir::new().expect("temporary directory creation failed"); + let wasm_file = tmpdir.path().join("out.wasm"); + let lucetc = lucetc::Lucetc::new(&wasm_file); + Lucetc { + link, + lucetc, + tmpdir, + wasm_file, + } + } + + pub fn print_output(mut self, print: bool) -> Self { + self.link.print_output = print; + self + } + + pub fn build>(self, output: P) -> Result<(), CompileError> { + self.link.link(&self.wasm_file)?; + self.lucetc + .shared_object_file(output.as_ref()) + .map_err(|e| CompileError::Lucetc { e })?; + Ok(self.tmpdir.close()?) + } +} + +impl AsLink for Lucetc { + fn as_link(&mut self) -> &mut Link { + &mut self.link + } +} + +impl lucetc::AsLucetc for Lucetc { + fn as_lucetc(&mut self) -> &mut lucetc::Lucetc { + &mut self.lucetc + } +} + #[cfg(test)] mod tests { use super::*; @@ -217,8 +330,8 @@ mod tests { assert!(objfile.exists(), "object file created"); let mut linker = Link::new(&[objfile]); - linker.with_cflag("-nostartfiles"); - linker.with_ldflag("--no-entry"); + linker.cflag("-nostartfiles"); + linker.ldflag("--no-entry"); let wasmfile = tmp.path().join("a.wasm"); @@ -240,9 +353,9 @@ mod tests { assert!(objfile.exists(), "object file created"); let mut linker = Link::new(&[objfile]); - linker.with_cflag("-nostartfiles"); - linker.with_ldflag("--no-entry"); - linker.with_ldflag("--allow-undefined"); + linker.cflag("-nostartfiles"); + linker.ldflag("--no-entry"); + linker.ldflag("--allow-undefined"); let wasmfile = tmp.path().join("b.wasm"); @@ -256,8 +369,8 @@ mod tests { let tmp = TempDir::new().expect("create temporary directory"); let mut linker = Link::new(&[test_file("a.c"), test_file("b.c")]); - linker.with_cflag("-nostartfiles"); - linker.with_ldflag("--no-entry"); + linker.cflag("-nostartfiles"); + linker.ldflag("--no-entry"); let wasmfile = tmp.path().join("ab.wasm"); diff --git a/lucet-wasi/tests/test_helpers/mod.rs b/lucet-wasi/tests/test_helpers/mod.rs index bff706a7f..5c32b9c28 100644 --- a/lucet-wasi/tests/test_helpers/mod.rs +++ b/lucet-wasi/tests/test_helpers/mod.rs @@ -2,8 +2,8 @@ use failure::{bail, Error}; use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region}; use lucet_wasi::host::__wasi_exitcode_t; use lucet_wasi::{WasiCtx, WasiCtxBuilder}; -use lucet_wasi_sdk::Link; -use lucetc::{Bindings, Lucetc}; +use lucet_wasi_sdk::{CompileOpts, Link}; +use lucetc::{Bindings, Lucetc, LucetcOpts}; use std::fs::File; use std::io::Read; use std::os::unix::io::{FromRawFd, IntoRawFd}; @@ -35,9 +35,9 @@ pub fn wasi_test>(c_file: P) -> Result, Error> { let workdir = TempDir::new().expect("create working directory"); let wasm_build = Link::new(&[c_file]) - .cflag("-Wall") - .cflag("-Werror") - .print_output(true); + .with_cflag("-Wall") + .with_cflag("-Werror") + .with_print_output(true); let wasm_file = workdir.path().join("out.wasm"); @@ -45,7 +45,7 @@ pub fn wasi_test>(c_file: P) -> Result, Error> { let bindings = Bindings::from_file(Path::new(LUCET_WASI_ROOT).join("bindings.json"))?; - let native_build = Lucetc::new(wasm_file)?.bindings(bindings)?; + let native_build = Lucetc::new(wasm_file).with_bindings(bindings); let so_file = workdir.path().join("out.so"); diff --git a/lucetc/src/bindings.rs b/lucetc/src/bindings.rs index 54774d6e3..e6cbf0a1e 100644 --- a/lucetc/src/bindings.rs +++ b/lucetc/src/bindings.rs @@ -71,19 +71,19 @@ impl Bindings { Ok(Self::from_str(&contents)?) } - pub fn extend(&mut self, other: Bindings) -> Result<(), Error> { + pub fn extend(&mut self, other: &Bindings) -> Result<(), Error> { //self.bindings.extend(other.bindings); - for (modname, othermodbindings) in other.bindings { - match self.bindings.entry(modname) { + for (modname, othermodbindings) in other.bindings.iter() { + match self.bindings.entry(modname.clone()) { Entry::Occupied(mut e) => { let existing = e.get_mut(); for (bindname, binding) in othermodbindings { - match existing.entry(bindname) { + match existing.entry(bindname.clone()) { Entry::Vacant(e) => { - e.insert(binding); + e.insert(binding.clone()); } Entry::Occupied(e) => { - if &binding != e.get() { + if binding != e.get() { Err(format_err!( "cannot re-bind {} from {} to {}", e.key(), @@ -96,7 +96,7 @@ impl Bindings { } } Entry::Vacant(e) => { - e.insert(othermodbindings); + e.insert(othermodbindings.clone()); } } } diff --git a/lucetc/src/lib.rs b/lucetc/src/lib.rs index 856c1af57..7b3a41593 100644 --- a/lucetc/src/lib.rs +++ b/lucetc/src/lib.rs @@ -17,7 +17,6 @@ use crate::patch::patch_module; use crate::program::Program; use failure::{format_err, Error, ResultExt}; use parity_wasm::elements::Module; -use std::collections::HashMap; use std::path::{Path, PathBuf}; use tempfile; @@ -28,92 +27,147 @@ pub use crate::{ }; pub struct Lucetc { - module: Module, - name: String, - bindings: Bindings, + input: PathBuf, + bindings: Vec, opt_level: OptLevel, heap: HeapSettings, - builtins_path: Option, + builtins_paths: Vec, } -/* -*/ +pub trait AsLucetc { + fn as_lucetc(&mut self) -> &mut Lucetc; +} -impl Lucetc { - pub fn new>(input: P) -> Result { - let input = input.as_ref(); - let module = read_module(input)?; - let name = String::from( - input - .file_stem() - .ok_or(format_err!("input filename {:?} is not a file", input))? - .to_str() - .ok_or(format_err!("input filename {:?} is not valid utf8", input))?, - ); - Ok(Self { - module, - name, - bindings: Bindings::empty(), - opt_level: OptLevel::default(), - heap: HeapSettings::default(), - builtins_path: None, - }) +impl AsLucetc for Lucetc { + fn as_lucetc(&mut self) -> &mut Lucetc { + self } +} + +pub trait LucetcOpts { + fn bindings(&mut self, bindings: Bindings); + fn with_bindings(self, bindings: Bindings) -> Self; - pub fn bindings(mut self, bindings: Bindings) -> Result { - self.with_bindings(bindings)?; - Ok(self) + fn opt_level(&mut self, opt_level: OptLevel); + fn with_opt_level(self, opt_level: OptLevel) -> Self; + + fn builtins>(&mut self, builtins_path: P); + fn with_builtins>(self, builtins_path: P) -> Self; + + fn min_reserved_size(&mut self, min_reserved_size: u64); + fn with_min_reserved_size(self, min_reserved_size: u64) -> Self; + + fn max_reserved_size(&mut self, max_reserved_size: u64); + fn with_max_reserved_size(self, max_reserved_size: u64) -> Self; + + fn guard_size(&mut self, guard_size: u64); + fn with_guard_size(self, guard_size: u64) -> Self; +} + +impl LucetcOpts for T { + fn bindings(&mut self, bindings: Bindings) { + self.as_lucetc().bindings.push(bindings); } - pub fn with_bindings(&mut self, bindings: Bindings) -> Result<(), Error> { - self.bindings.extend(bindings) + + fn with_bindings(mut self, bindings: Bindings) -> Self { + self.bindings(bindings); + self } - pub fn opt_level(mut self, opt_level: OptLevel) -> Self { - self.with_opt_level(opt_level); + fn opt_level(&mut self, opt_level: OptLevel) { + self.as_lucetc().opt_level = opt_level; + } + + fn with_opt_level(mut self, opt_level: OptLevel) -> Self { + self.opt_level(opt_level); self } - pub fn with_opt_level(&mut self, opt_level: OptLevel) { - self.opt_level = opt_level; + + fn builtins>(&mut self, builtins_path: P) { + self.as_lucetc() + .builtins_paths + .push(builtins_path.as_ref().to_owned()); } - pub fn builtins>(mut self, builtins: P) -> Result { - self.with_builtins(builtins)?; - Ok(self) + fn with_builtins>(mut self, builtins_path: P) -> Self { + self.builtins(builtins_path); + self } - pub fn with_builtins>(&mut self, builtins_path: P) -> Result<(), Error> { - let (newmodule, builtins_map) = patch_module(self.module.clone(), builtins_path)?; - self.module = newmodule; - self.bindings.extend(Bindings::env(builtins_map))?; - Ok(()) + + fn min_reserved_size(&mut self, min_reserved_size: u64) { + self.as_lucetc().heap.min_reserved_size = min_reserved_size; } - pub fn min_reserved_size(mut self, min_reserved_size: u64) -> Self { - self.with_min_reserved_size(min_reserved_size); + fn with_min_reserved_size(mut self, min_reserved_size: u64) -> Self { + self.min_reserved_size(min_reserved_size); self } - pub fn with_min_reserved_size(&mut self, min_reserved_size: u64) { - self.heap.min_reserved_size = min_reserved_size; + + fn max_reserved_size(&mut self, max_reserved_size: u64) { + self.as_lucetc().heap.max_reserved_size = max_reserved_size; } - pub fn max_reserved_size(mut self, max_reserved_size: u64) -> Self { - self.with_max_reserved_size(max_reserved_size); + fn with_max_reserved_size(mut self, max_reserved_size: u64) -> Self { + self.max_reserved_size(max_reserved_size); self } - pub fn with_max_reserved_size(&mut self, max_reserved_size: u64) { - self.heap.max_reserved_size = max_reserved_size; + + fn guard_size(&mut self, guard_size: u64) { + self.as_lucetc().heap.guard_size = guard_size; } - pub fn guard_size(mut self, guard_size: u64) -> Self { - self.with_guard_size(guard_size); + fn with_guard_size(mut self, guard_size: u64) -> Self { + self.guard_size(guard_size); self } - pub fn with_guard_size(&mut self, guard_size: u64) { - self.heap.guard_size = guard_size; +} + +impl Lucetc { + pub fn new>(input: P) -> Self { + let input = input.as_ref(); + Self { + input: input.to_owned(), + bindings: vec![], + opt_level: OptLevel::default(), + heap: HeapSettings::default(), + builtins_paths: vec![], + } + } + + fn build(&self) -> Result<(String, Module, Bindings), Error> { + let name = String::from( + self.input + .file_stem() + .ok_or(format_err!("input filename {:?} is empty", self.input))? + .to_str() + .ok_or(format_err!( + "input filename {:?} is not valid utf8", + self.input + ))?, + ); + let mut builtins_bindings = vec![]; + let mut module = read_module(&self.input)?; + + for builtins in self.builtins_paths.iter() { + let (newmodule, builtins_map) = patch_module(module, builtins)?; + module = newmodule; + builtins_bindings.push(Bindings::env(builtins_map)); + } + + let mut bindings = Bindings::empty(); + + for binding in builtins_bindings.iter().chain(self.bindings.iter()) { + bindings.extend(binding)?; + } + + Ok((name, module, bindings)) } pub fn object_file>(self, output: P) -> Result<(), Error> { - let prog = Program::new(self.module, self.bindings, self.heap.clone())?; - let comp = compile(&prog, &self.name, self.opt_level)?; + let (name, module, bindings) = self.build()?; + + let prog = Program::new(module, bindings, self.heap)?; + let comp = compile(&prog, &name, self.opt_level)?; let obj = comp.codegen()?; obj.write(output.as_ref()).context("writing object file")?; @@ -122,17 +176,10 @@ impl Lucetc { } pub fn clif_ir>(self, output: P) -> Result<(), Error> { - let (module, builtins_map) = if let Some(ref builtins_path) = self.builtins_path { - patch_module(self.module, builtins_path)? - } else { - (self.module, HashMap::new()) - }; - - let mut bindings = self.bindings.clone(); - bindings.extend(Bindings::env(builtins_map))?; + let (name, module, bindings) = self.build()?; let prog = Program::new(module, bindings, self.heap.clone())?; - let comp = compile(&prog, &self.name, self.opt_level)?; + let comp = compile(&prog, &name, self.opt_level)?; comp.cranelift_funcs() .write(&output) diff --git a/lucetc/src/main.rs b/lucetc/src/main.rs index 28f116c21..88539167a 100644 --- a/lucetc/src/main.rs +++ b/lucetc/src/main.rs @@ -3,7 +3,7 @@ mod options; use crate::options::{CodegenOutput, Options}; use failure::{format_err, Error, ResultExt}; use log::info; -use lucetc::{Bindings, Lucetc}; +use lucetc::{Bindings, Lucetc, LucetcOpts}; use std::io::{self, Write}; use std::path::PathBuf; @@ -38,28 +38,28 @@ pub fn run(opts: &Options) -> Result<(), Error> { let file_bindings = Bindings::from_file(file).context(format!("bindings file {:?}", file))?; bindings - .extend(file_bindings) + .extend(&file_bindings) .context(format!("adding bindings from {:?}", file))?; } - let mut c = Lucetc::new(PathBuf::from(input))? - .bindings(bindings)? - .opt_level(opts.opt_level); + let mut c = Lucetc::new(PathBuf::from(input)) + .with_bindings(bindings) + .with_opt_level(opts.opt_level); if let Some(ref builtins) = opts.builtins_path { - c.with_builtins(builtins)?; + c.builtins(builtins); } if let Some(min_reserved_size) = opts.min_reserved_size { - c.with_min_reserved_size(min_reserved_size); + c.min_reserved_size(min_reserved_size); } if let Some(max_reserved_size) = opts.max_reserved_size { - c.with_max_reserved_size(max_reserved_size); + c.max_reserved_size(max_reserved_size); } if let Some(guard_size) = opts.guard_size { - c.with_guard_size(guard_size); + c.guard_size(guard_size); } match opts.codegen { diff --git a/lucetc/tests/wasi-sdk.rs b/lucetc/tests/wasi-sdk.rs index 88fe9acfa..882b41133 100644 --- a/lucetc/tests/wasi-sdk.rs +++ b/lucetc/tests/wasi-sdk.rs @@ -1,5 +1,5 @@ use failure::{Error, ResultExt}; -use lucet_wasi_sdk::Link; +use lucet_wasi_sdk::{CompileOpts, Link, LinkOpts}; use lucetc::bindings::Bindings; use lucetc::load; use parity_wasm::elements::Module; @@ -22,11 +22,11 @@ fn module_from_c(cfiles: &[&str], exports: &[&str]) -> Result { wasm.push("out.wasm"); let mut linker = Link::new(&cfiles) - .cflag("-nostartfiles") - .ldflag("--no-entry") - .ldflag("--allow-undefined"); + .with_cflag("-nostartfiles") + .with_ldflag("--no-entry") + .with_ldflag("--allow-undefined"); for export in exports { - linker.with_ldflag(&format!("--export={}", export)); + linker.ldflag(&format!("--export={}", export)); } linker.link(wasm.clone())?; From 0fb49ad75b334e0c92d27c2f8951694ede3d8423 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 9 Apr 2019 14:12:16 -0700 Subject: [PATCH 019/512] [benchmarks] add start of Lucet microbenchmark suite --- Cargo.lock | 123 ++++++++++++++++++ Cargo.toml | 1 + Makefile | 1 + benchmarks/lucet-microbenchmarks/Cargo.toml | 20 +++ .../benches/microbenchmarks.rs | 6 + benchmarks/lucet-microbenchmarks/src/lib.rs | 71 ++++++++++ 6 files changed, 222 insertions(+) create mode 100644 benchmarks/lucet-microbenchmarks/Cargo.toml create mode 100644 benchmarks/lucet-microbenchmarks/benches/microbenchmarks.rs create mode 100644 benchmarks/lucet-microbenchmarks/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 1cd6feb30..c44a97674 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -263,6 +263,42 @@ dependencies = [ "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "criterion" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "csv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "tinytemplate 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "criterion-plot" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-deque" version = "0.2.0" @@ -294,6 +330,25 @@ dependencies = [ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "csv" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "csv-core" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "either" version = "1.5.2" @@ -446,6 +501,14 @@ name = "indexmap" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "itertools" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itoa" version = "0.4.3" @@ -500,6 +563,18 @@ dependencies = [ name = "lucet-idl" version = "0.1.0" +[[package]] +name = "lucet-microbenchmarks" +version = "0.1.0" +dependencies = [ + "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "lucet-runtime 0.1.0", + "lucet-wasi 0.1.0", + "lucet-wasi-sdk 0.1.0", + "lucetc 0.1.0", + "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "lucet-module-data" version = "0.1.0" @@ -653,6 +728,9 @@ dependencies = [ name = "memchr" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "memoffset" @@ -913,6 +991,15 @@ dependencies = [ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_xoshiro" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "raw-cpuid" version = "6.1.0" @@ -1011,6 +1098,14 @@ name = "ryu" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "same-file" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "scopeguard" version = "0.3.3" @@ -1231,6 +1326,15 @@ dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tinytemplate" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "toml" version = "0.4.10" @@ -1308,6 +1412,16 @@ dependencies = [ "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "walkdir" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "wasmonkey" version = "0.1.4" @@ -1409,9 +1523,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cmake 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "6ec65ee4f9c9d16f335091d23693457ed4928657ba4982289d7fafee03bc614a" "checksum colored 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e9a455e156a4271e12fd0246238c380b1e223e3736663c7a18ed8b6362028a9" +"checksum criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0363053954f3e679645fc443321ca128b7b950a6fe288cf5f9335cc22ee58394" +"checksum criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76f9212ddf2f4a9eb2d401635190600656a1f88a932ef53d06e7fa4c7e02fb8e" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" +"checksum csv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f0782c7154d8dd08f4adeb5aa22ab178c10281915f7da68d10bb646f03aaee73" +"checksum csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5cdef62f37e6ffe7d1f07a381bc0db32b7a3ff1cac0de56cb0d81e71f53d65" "checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" "checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a" "checksum errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2a071601ed01b988f896ab14b95e67335d1eeb50190932a1320f7fe3cadc84e" @@ -1429,6 +1547,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" "checksum hwloc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2934f84993b8b4bcae9b6a4e5f0aca638462dda9c7b4f26a570241494f21e0f4" "checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" +"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" @@ -1467,6 +1586,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +"checksum rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03b418169fb9c46533f326efd6eed2576699c44ca92d3052a066214a8d828929" "checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d" "checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473" "checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" @@ -1479,6 +1599,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" +"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f84d114ef17fd144153d608fba7c446b0145d038985e7a8cc5d08bb0ce20383" "checksum scroll_derive 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1aa96c45e7f5a91cb7fabe7b279f02fea7126239fc40b732316e8b6a2d0fcb" @@ -1502,6 +1623,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" +"checksum tinytemplate 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7655088894274afb52b807bd3c87072daa1fedd155068b8705cabfd628956115" "checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" "checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" @@ -1514,6 +1636,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "74e463a508e390cc7447e70f640fbf44ad52e1bd095314ace1fdf99516d32add" "checksum wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a6265b25719e82598d104b3717375e37661d41753e2c84cde3f51050c7ed7e3c" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" diff --git a/Cargo.toml b/Cargo.toml index c3d18c537..72c6a3703 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ members = [ "lucet-wasi-sdk", "lucetc", "sightglass", + "benchmarks/lucet-microbenchmarks", ] exclude = ["cranelift"] diff --git a/Makefile b/Makefile index 1e03ec237..698796e83 100644 --- a/Makefile +++ b/Makefile @@ -34,6 +34,7 @@ fuzz: .PHONY: bench bench: + cargo bench -p lucet-microbenchmarks make -C benchmarks/shootout clean make -C benchmarks/shootout bench diff --git a/benchmarks/lucet-microbenchmarks/Cargo.toml b/benchmarks/lucet-microbenchmarks/Cargo.toml new file mode 100644 index 000000000..d10ae14c6 --- /dev/null +++ b/benchmarks/lucet-microbenchmarks/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "lucet-microbenchmarks" +version = "0.1.0" +authors = ["Adam C. Foltzer "] +edition = "2018" + +[dependencies] +criterion = "0.2" +lucetc = { path = "../../lucetc" } +lucet-runtime = { path = "../../lucet-runtime" } +lucet-wasi = { path = "../../lucet-wasi" } +lucet-wasi-sdk = { path = "../../lucet-wasi-sdk" } +tempfile = "3.0" + +[lib] +bench = false + +[[bench]] +name = "microbenchmarks" +harness = false diff --git a/benchmarks/lucet-microbenchmarks/benches/microbenchmarks.rs b/benchmarks/lucet-microbenchmarks/benches/microbenchmarks.rs new file mode 100644 index 000000000..3df1d3416 --- /dev/null +++ b/benchmarks/lucet-microbenchmarks/benches/microbenchmarks.rs @@ -0,0 +1,6 @@ +#[macro_use] +extern crate criterion; + +use lucet_microbenchmarks::benches; + +criterion_main!(benches); diff --git a/benchmarks/lucet-microbenchmarks/src/lib.rs b/benchmarks/lucet-microbenchmarks/src/lib.rs new file mode 100644 index 000000000..2126dd952 --- /dev/null +++ b/benchmarks/lucet-microbenchmarks/src/lib.rs @@ -0,0 +1,71 @@ +#[macro_use] +extern crate criterion; + +use criterion::Criterion; +use lucet_runtime::{DlModule, InstanceHandle, Limits, MmapRegion, Module, Region}; +use lucet_wasi_sdk::{CompileOpts, Lucetc}; +use lucetc::{Bindings, LucetcOpts}; +use std::path::Path; +use std::sync::Arc; +use tempfile::TempDir; + +fn wasi_bindings() -> Bindings { + Bindings::from_file("../../lucet-wasi/bindings.json").unwrap() +} + +fn compile_hello>(so_file: P) { + let wasm_build = Lucetc::new(&["../../lucet-wasi/examples/hello.c"]) + .print_output(true) + .with_cflag("-Wall") + .with_cflag("-Werror") + .with_bindings(wasi_bindings()); + + wasm_build.build(&so_file).unwrap(); +} + +fn load_mkregion_and_instantiate_body(so_file: &Path) -> InstanceHandle { + let module = DlModule::load(so_file).unwrap(); + let region = MmapRegion::create(1, &Limits::default()).unwrap(); + region.new_instance(module).unwrap() +} + +fn load_mkregion_and_instantiate(c: &mut Criterion) { + let workdir = TempDir::new().expect("create working directory"); + + let so_file = workdir.path().join("out.so"); + compile_hello(&so_file); + + c.bench_function("load_mkregion_and_instantiate hello", move |b| { + b.iter(|| load_mkregion_and_instantiate_body(&so_file)) + }); + + workdir.close().unwrap(); +} + +fn instantiate_body(module: Arc, region: Arc) -> InstanceHandle { + region.new_instance(module).unwrap() +} + +fn instantiate(c: &mut Criterion) { + let workdir = TempDir::new().expect("create working directory"); + + let so_file = workdir.path().join("out.so"); + compile_hello(&so_file); + + let module = DlModule::load(&so_file).unwrap(); + let region = MmapRegion::create(1, &Limits::default()).unwrap(); + + c.bench_function("instantiate hello", move |b| { + b.iter(|| instantiate_body(module.clone(), region.clone())) + }); + + workdir.close().unwrap(); +} + +criterion_group!(benches, load_mkregion_and_instantiate, instantiate); + +#[no_mangle] +extern "C" fn lucet_microbenchmarks_ensure_linked() { + lucet_runtime::lucet_internal_ensure_linked(); + lucet_wasi::hostcalls::ensure_linked(); +} From 046809be6bea48b5e1a7923ccb90693d2975a3d8 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 9 Apr 2019 14:56:23 -0700 Subject: [PATCH 020/512] [lucet-wasi-sdk] always use `--no-threads` for `wasm-ld`; add test --- lucet-wasi-sdk/src/lib.rs | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/lucet-wasi-sdk/src/lib.rs b/lucet-wasi-sdk/src/lib.rs index a7215c34f..cc77a5caf 100644 --- a/lucet-wasi-sdk/src/lib.rs +++ b/lucet-wasi-sdk/src/lib.rs @@ -141,10 +141,11 @@ impl Link { pub fn new>(input: &[P]) -> Self { Link { input: input.iter().map(|p| PathBuf::from(p.as_ref())).collect(), - cflags: Vec::new(), - ldflags: Vec::new(), + cflags: vec![], + ldflags: vec![], print_output: false, } + .with_ldflag("--no-threads") } pub fn print_output(&mut self, print: bool) { @@ -256,12 +257,7 @@ pub struct Lucetc { impl Lucetc { pub fn new>(input: &[P]) -> Self { - let link = Link { - input: input.iter().map(|p| PathBuf::from(p.as_ref())).collect(), - cflags: Vec::new(), - ldflags: Vec::new(), - print_output: false, - }; + let link = Link::new(input); let tmpdir = TempDir::new().expect("temporary directory creation failed"); let wasm_file = tmpdir.path().join("out.wasm"); let lucetc = lucetc::Lucetc::new(&wasm_file); @@ -378,4 +374,19 @@ mod tests { assert!(wasmfile.exists(), "wasm file created"); } + + #[test] + fn compile_to_lucet() { + let tmp = TempDir::new().expect("create temporary directory"); + + let mut lucetc = Lucetc::new(&[test_file("a.c"), test_file("b.c")]); + lucetc.cflag("-nostartfiles"); + lucetc.ldflag("--no-entry"); + + let so_file = tmp.path().join("ab.so"); + + lucetc.build(&so_file).expect("compile ab.so"); + + assert!(so_file.exists(), "so file created"); + } } From d29591d583bdb2d651d91faa944e9187edb98900 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 9 Apr 2019 16:20:57 -0700 Subject: [PATCH 021/512] [benchmarks] add parallel instantiation benchmark --- Cargo.lock | 2 + benchmarks/lucet-microbenchmarks/Cargo.toml | 2 + benchmarks/lucet-microbenchmarks/src/lib.rs | 86 ++++++++++++++++--- .../lucet-runtime-internals/src/instance.rs | 3 + 4 files changed, 80 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c44a97674..9226f7ec2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -572,6 +572,8 @@ dependencies = [ "lucet-wasi 0.1.0", "lucet-wasi-sdk 0.1.0", "lucetc 0.1.0", + "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/benchmarks/lucet-microbenchmarks/Cargo.toml b/benchmarks/lucet-microbenchmarks/Cargo.toml index d10ae14c6..01c21b67e 100644 --- a/benchmarks/lucet-microbenchmarks/Cargo.toml +++ b/benchmarks/lucet-microbenchmarks/Cargo.toml @@ -10,6 +10,8 @@ lucetc = { path = "../../lucetc" } lucet-runtime = { path = "../../lucet-runtime" } lucet-wasi = { path = "../../lucet-wasi" } lucet-wasi-sdk = { path = "../../lucet-wasi-sdk" } +num_cpus = "1.0" +rayon = "1.0" tempfile = "3.0" [lib] diff --git a/benchmarks/lucet-microbenchmarks/src/lib.rs b/benchmarks/lucet-microbenchmarks/src/lib.rs index 2126dd952..5d774774d 100644 --- a/benchmarks/lucet-microbenchmarks/src/lib.rs +++ b/benchmarks/lucet-microbenchmarks/src/lib.rs @@ -5,6 +5,7 @@ use criterion::Criterion; use lucet_runtime::{DlModule, InstanceHandle, Limits, MmapRegion, Module, Region}; use lucet_wasi_sdk::{CompileOpts, Lucetc}; use lucetc::{Bindings, LucetcOpts}; +use rayon::prelude::*; use std::path::Path; use std::sync::Arc; use tempfile::TempDir; @@ -23,30 +24,30 @@ fn compile_hello>(so_file: P) { wasm_build.build(&so_file).unwrap(); } -fn load_mkregion_and_instantiate_body(so_file: &Path) -> InstanceHandle { - let module = DlModule::load(so_file).unwrap(); - let region = MmapRegion::create(1, &Limits::default()).unwrap(); - region.new_instance(module).unwrap() -} - fn load_mkregion_and_instantiate(c: &mut Criterion) { + fn body(so_file: &Path) -> InstanceHandle { + let module = DlModule::load(so_file).unwrap(); + let region = MmapRegion::create(1, &Limits::default()).unwrap(); + region.new_instance(module).unwrap() + } + let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); compile_hello(&so_file); c.bench_function("load_mkregion_and_instantiate hello", move |b| { - b.iter(|| load_mkregion_and_instantiate_body(&so_file)) + b.iter(|| body(&so_file)) }); workdir.close().unwrap(); } -fn instantiate_body(module: Arc, region: Arc) -> InstanceHandle { - region.new_instance(module).unwrap() -} - fn instantiate(c: &mut Criterion) { + fn body(module: Arc, region: Arc) -> InstanceHandle { + region.new_instance(module).unwrap() + } + let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); @@ -56,13 +57,72 @@ fn instantiate(c: &mut Criterion) { let region = MmapRegion::create(1, &Limits::default()).unwrap(); c.bench_function("instantiate hello", move |b| { - b.iter(|| instantiate_body(module.clone(), region.clone())) + b.iter(|| body(module.clone(), region.clone())) }); workdir.close().unwrap(); } -criterion_group!(benches, load_mkregion_and_instantiate, instantiate); +fn par_instantiate(c: &mut Criterion) { + const INSTANCES_PER_RUN: usize = 2000; + + fn setup() -> (Arc, Vec>) { + let region = MmapRegion::create(INSTANCES_PER_RUN, &Limits::default()).unwrap(); + let mut handles = vec![]; + handles.resize_with(INSTANCES_PER_RUN, || None); + (region, handles) + } + + fn body( + num_threads: usize, + module: Arc, + region: Arc, + handles: &mut [Option], + ) { + rayon::ThreadPoolBuilder::new() + .num_threads(num_threads) + .build() + .unwrap() + .install(|| { + handles + .par_iter_mut() + .for_each(|handle| *handle = Some(region.new_instance(module.clone()).unwrap())) + }) + } + + let workdir = TempDir::new().expect("create working directory"); + + let so_file = workdir.path().join("out.so"); + compile_hello(&so_file); + + let module = DlModule::load(&so_file).unwrap(); + + let bench = criterion::ParameterizedBenchmark::new( + "par_instantiate hello", + move |b, &num_threads| { + b.iter_batched( + setup, + |(region, mut handles)| { + body(num_threads, module.clone(), region, handles.as_mut_slice()) + }, + criterion::BatchSize::SmallInput, + ) + }, + (1..=num_cpus::get()).collect::>(), + ) + .sample_size(10); + + c.bench("benches", bench); + + workdir.close().unwrap(); +} + +criterion_group!( + benches, + load_mkregion_and_instantiate, + instantiate, + par_instantiate +); #[no_mangle] extern "C" fn lucet_microbenchmarks_ensure_linked() { diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index 1fa60ba40..355e47f63 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -55,6 +55,9 @@ pub struct InstanceHandle { inst: NonNull, } +// raw pointer lint +unsafe impl Send for InstanceHandle {} + /// Create a new `InstanceHandle`. /// /// This is not meant for public consumption, but rather is used to make implementations of From a421c8ea51d01da87f91c16b8e038d151f935395 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Wed, 10 Apr 2019 09:30:53 -0700 Subject: [PATCH 022/512] add Makefile exception to .editorconfig --- .editorconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.editorconfig b/.editorconfig index 677e36e29..67a786058 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,3 +7,6 @@ indent_size = 4 indent_style = space insert_final_newline = true trim_trailing_whitespace = true + +[Makefile] +indent_style = tab From ad9e5a4c8d489a3bb37d8fe2bf4278196dc83319 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Wed, 10 Apr 2019 12:06:55 -0700 Subject: [PATCH 023/512] [benchmarks] add more benchmarks and use an in-dir hello.c --- Cargo.lock | 2 + benchmarks/lucet-microbenchmarks/Cargo.toml | 2 + .../benches/microbenchmarks.rs | 4 +- .../lucet-microbenchmarks/guests/hello.c | 6 + benchmarks/lucet-microbenchmarks/src/lib.rs | 268 ++++++++++++++---- .../lucet-microbenchmarks/src/modules.rs | 125 ++++++++ benchmarks/lucet-microbenchmarks/src/par.rs | 125 ++++++++ 7 files changed, 472 insertions(+), 60 deletions(-) create mode 100644 benchmarks/lucet-microbenchmarks/guests/hello.c create mode 100644 benchmarks/lucet-microbenchmarks/src/modules.rs create mode 100644 benchmarks/lucet-microbenchmarks/src/par.rs diff --git a/Cargo.lock b/Cargo.lock index 9226f7ec2..806f50c09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -569,9 +569,11 @@ version = "0.1.0" dependencies = [ "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-runtime 0.1.0", + "lucet-runtime-internals 0.1.0", "lucet-wasi 0.1.0", "lucet-wasi-sdk 0.1.0", "lucetc 0.1.0", + "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/benchmarks/lucet-microbenchmarks/Cargo.toml b/benchmarks/lucet-microbenchmarks/Cargo.toml index 01c21b67e..6fe76a20e 100644 --- a/benchmarks/lucet-microbenchmarks/Cargo.toml +++ b/benchmarks/lucet-microbenchmarks/Cargo.toml @@ -8,8 +8,10 @@ edition = "2018" criterion = "0.2" lucetc = { path = "../../lucetc" } lucet-runtime = { path = "../../lucet-runtime" } +lucet-runtime-internals = { path = "../../lucet-runtime/lucet-runtime-internals" } lucet-wasi = { path = "../../lucet-wasi" } lucet-wasi-sdk = { path = "../../lucet-wasi-sdk" } +nix = "0.13" num_cpus = "1.0" rayon = "1.0" tempfile = "3.0" diff --git a/benchmarks/lucet-microbenchmarks/benches/microbenchmarks.rs b/benchmarks/lucet-microbenchmarks/benches/microbenchmarks.rs index 3df1d3416..1dbafed9e 100644 --- a/benchmarks/lucet-microbenchmarks/benches/microbenchmarks.rs +++ b/benchmarks/lucet-microbenchmarks/benches/microbenchmarks.rs @@ -1,6 +1,6 @@ #[macro_use] extern crate criterion; -use lucet_microbenchmarks::benches; +use lucet_microbenchmarks::{benches, par}; -criterion_main!(benches); +criterion_main!(benches, par); diff --git a/benchmarks/lucet-microbenchmarks/guests/hello.c b/benchmarks/lucet-microbenchmarks/guests/hello.c new file mode 100644 index 000000000..9fbdadbd5 --- /dev/null +++ b/benchmarks/lucet-microbenchmarks/guests/hello.c @@ -0,0 +1,6 @@ +#include + +int main() +{ + printf("Hello, benchmarks!\n"); +} diff --git a/benchmarks/lucet-microbenchmarks/src/lib.rs b/benchmarks/lucet-microbenchmarks/src/lib.rs index 5d774774d..68d0bbb1b 100644 --- a/benchmarks/lucet-microbenchmarks/src/lib.rs +++ b/benchmarks/lucet-microbenchmarks/src/lib.rs @@ -1,29 +1,27 @@ #[macro_use] extern crate criterion; +mod modules; +mod par; + +pub use par::par; + +use crate::modules::{compile_hello, fib_mock, many_args_mock, null_mock}; use criterion::Criterion; use lucet_runtime::{DlModule, InstanceHandle, Limits, MmapRegion, Module, Region}; -use lucet_wasi_sdk::{CompileOpts, Lucetc}; -use lucetc::{Bindings, LucetcOpts}; -use rayon::prelude::*; +use lucet_wasi::WasiCtxBuilder; use std::path::Path; use std::sync::Arc; use tempfile::TempDir; -fn wasi_bindings() -> Bindings { - Bindings::from_file("../../lucet-wasi/bindings.json").unwrap() -} - -fn compile_hello>(so_file: P) { - let wasm_build = Lucetc::new(&["../../lucet-wasi/examples/hello.c"]) - .print_output(true) - .with_cflag("-Wall") - .with_cflag("-Werror") - .with_bindings(wasi_bindings()); - - wasm_build.build(&so_file).unwrap(); -} - +/// End-to-end instance instantiation. +/// +/// This is meant to simulate our startup time when we start from scratch, with no module loaded and +/// no region created at all. This would be unusual for a server application, but reflects what +/// one-shot command-line tools like `lucet-wasi` do. +/// +/// To minimize the effects of filesystem cache on the `DlModule::load()`, this runs `sync` between +/// each iteration. fn load_mkregion_and_instantiate(c: &mut Criterion) { fn body(so_file: &Path) -> InstanceHandle { let module = DlModule::load(so_file).unwrap(); @@ -37,12 +35,20 @@ fn load_mkregion_and_instantiate(c: &mut Criterion) { compile_hello(&so_file); c.bench_function("load_mkregion_and_instantiate hello", move |b| { - b.iter(|| body(&so_file)) + b.iter_batched( + || nix::unistd::sync(), + |_| body(&so_file), + criterion::BatchSize::PerIteration, + ) }); workdir.close().unwrap(); } +/// Instance instantiation. +/// +/// This simulates a typical case for a server process like Terrarium: the region and module stay +/// initialized, but a new instance is created for each request. fn instantiate(c: &mut Criterion) { fn body(module: Arc, region: Arc) -> InstanceHandle { region.new_instance(module).unwrap() @@ -63,31 +69,77 @@ fn instantiate(c: &mut Criterion) { workdir.close().unwrap(); } -fn par_instantiate(c: &mut Criterion) { - const INSTANCES_PER_RUN: usize = 2000; +/// Instance destruction. +/// +/// Instances have some cleanup to do with memory management and freeing their slot on their region. +fn drop_instance(c: &mut Criterion) { + fn body(_inst: InstanceHandle) {} + + let workdir = TempDir::new().expect("create working directory"); - fn setup() -> (Arc, Vec>) { - let region = MmapRegion::create(INSTANCES_PER_RUN, &Limits::default()).unwrap(); - let mut handles = vec![]; - handles.resize_with(INSTANCES_PER_RUN, || None); - (region, handles) + let so_file = workdir.path().join("out.so"); + compile_hello(&so_file); + + let module = DlModule::load(&so_file).unwrap(); + let region = MmapRegion::create(1, &Limits::default()).unwrap(); + + c.bench_function("drop_instance hello", move |b| { + b.iter_batched( + || region.new_instance(module.clone()).unwrap(), + |inst| body(inst), + criterion::BatchSize::PerIteration, + ) + }); + + workdir.close().unwrap(); +} + +/// Run a trivial guest function. +/// +/// This is primarily a measurement of the signal handler installation and removal, and the context +/// switching overhead. +fn run_null(c: &mut Criterion) { + fn body(inst: &mut InstanceHandle) { + inst.run(b"f", &[]).unwrap(); } - fn body( - num_threads: usize, - module: Arc, - region: Arc, - handles: &mut [Option], - ) { - rayon::ThreadPoolBuilder::new() - .num_threads(num_threads) - .build() - .unwrap() - .install(|| { - handles - .par_iter_mut() - .for_each(|handle| *handle = Some(region.new_instance(module.clone()).unwrap())) - }) + let module = null_mock(); + let region = MmapRegion::create(1, &Limits::default()).unwrap(); + + c.bench_function("run_null", move |b| { + b.iter_batched_ref( + || region.new_instance(module.clone()).unwrap(), + |inst| body(inst), + criterion::BatchSize::PerIteration, + ) + }); +} + +/// Run a computation-heavy guest function from a mock module. +/// +/// Since this is running code in a mock module, the cost of the computation should overwhelm the +/// cost of the Lucet runtime. +fn run_fib(c: &mut Criterion) { + fn body(inst: &mut InstanceHandle) { + inst.run(b"f", &[]).unwrap(); + } + + let module = fib_mock(); + let region = MmapRegion::create(1, &Limits::default()).unwrap(); + + c.bench_function("run_fib", move |b| { + b.iter_batched_ref( + || region.new_instance(module.clone()).unwrap(), + |inst| body(inst), + criterion::BatchSize::PerIteration, + ) + }); +} + +/// Run a trivial WASI program. +fn run_hello(c: &mut Criterion) { + fn body(inst: &mut InstanceHandle) { + inst.run(b"_start", &[]).unwrap(); } let workdir = TempDir::new().expect("create working directory"); @@ -96,32 +148,132 @@ fn par_instantiate(c: &mut Criterion) { compile_hello(&so_file); let module = DlModule::load(&so_file).unwrap(); + let region = MmapRegion::create(1, &Limits::default()).unwrap(); - let bench = criterion::ParameterizedBenchmark::new( - "par_instantiate hello", - move |b, &num_threads| { - b.iter_batched( - setup, - |(region, mut handles)| { - body(num_threads, module.clone(), region, handles.as_mut_slice()) - }, - criterion::BatchSize::SmallInput, - ) - }, - (1..=num_cpus::get()).collect::>(), - ) - .sample_size(10); - - c.bench("benches", bench); + c.bench_function("run_hello", move |b| { + b.iter_batched_ref( + || { + let null = std::fs::File::open("/dev/null").unwrap(); + let ctx = WasiCtxBuilder::new() + .args(&["hello"]) + .fd(1, null) + .build() + .unwrap(); + region + .new_instance_builder(module.clone()) + .with_embed_ctx(ctx) + .build() + .unwrap() + }, + |inst| body(inst), + criterion::BatchSize::PerIteration, + ) + }); +} - workdir.close().unwrap(); +/// Run a trivial guest function that takes a bunch of arguments. +/// +/// This is primarily interesting as a comparison to `run_null`; the difference is the overhead of +/// installing the arguments into the guest registers and stack. +/// +/// `rustfmt` hates this function. +fn run_many_args(c: &mut Criterion) { + fn body(inst: &mut InstanceHandle) { + inst.run( + b"f", + &[ + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + ], + ) + .unwrap(); + } + + let module = many_args_mock(); + let region = MmapRegion::create(1, &Limits::default()).unwrap(); + + c.bench_function("run_many_args", move |b| { + b.iter_batched_ref( + || region.new_instance(module.clone()).unwrap(), + |inst| body(inst), + criterion::BatchSize::PerIteration, + ) + }); } criterion_group!( benches, load_mkregion_and_instantiate, instantiate, - par_instantiate + drop_instance, + run_null, + run_fib, + run_hello, + run_many_args ); #[no_mangle] diff --git a/benchmarks/lucet-microbenchmarks/src/modules.rs b/benchmarks/lucet-microbenchmarks/src/modules.rs new file mode 100644 index 000000000..6f05235d2 --- /dev/null +++ b/benchmarks/lucet-microbenchmarks/src/modules.rs @@ -0,0 +1,125 @@ +use lucet_runtime::vmctx::lucet_vmctx; +use lucet_runtime::Module; +use lucet_runtime_internals::module::MockModuleBuilder; +use lucet_wasi_sdk::{CompileOpts, Lucetc}; +use lucetc::{Bindings, LucetcOpts}; +use std::path::Path; +use std::sync::Arc; + +fn wasi_bindings() -> Bindings { + Bindings::from_file("../../lucet-wasi/bindings.json").unwrap() +} + +pub fn compile_hello>(so_file: P) { + let wasm_build = Lucetc::new(&["guests/hello.c"]) + .print_output(true) + .with_cflag("-Wall") + .with_cflag("-Werror") + .with_bindings(wasi_bindings()); + + wasm_build.build(&so_file).unwrap(); +} + +pub fn null_mock() -> Arc { + extern "C" fn f(_vmctx: *mut lucet_vmctx) {} + + MockModuleBuilder::new() + .with_export_func(b"f", f as *const extern "C" fn()) + .build() +} + +pub fn fib_mock() -> Arc { + extern "C" fn f(_vmctx: *mut lucet_vmctx) { + fn fib(n: u32) -> u32 { + if n == 0 { + 0 + } else if n == 1 { + 1 + } else { + fib(n - 1) + fib(n - 2) + } + } + assert_eq!(fib(25), 75025); + } + + MockModuleBuilder::new() + .with_export_func(b"f", f as *const extern "C" fn()) + .build() +} + +pub fn many_args_mock() -> Arc { + extern "C" fn f( + _vmctx: *mut lucet_vmctx, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + ) { + } + + MockModuleBuilder::new() + .with_export_func(b"f", f as *const extern "C" fn()) + .build() +} diff --git a/benchmarks/lucet-microbenchmarks/src/par.rs b/benchmarks/lucet-microbenchmarks/src/par.rs new file mode 100644 index 000000000..cb4bc529b --- /dev/null +++ b/benchmarks/lucet-microbenchmarks/src/par.rs @@ -0,0 +1,125 @@ +use crate::modules::{compile_hello, fib_mock, null_mock}; +use criterion::Criterion; +use lucet_runtime::{DlModule, InstanceHandle, Limits, MmapRegion, Module, Region}; +use rayon::prelude::*; +use std::sync::Arc; +use tempfile::TempDir; + +/// Parallel instantiation. +/// +/// This measures how well the region handles concurrent instantiations from multiple +/// threads. Scaling is not necessarily the point here, due to the locks on the region freelist and +/// memory management syscalls, but we do want to make sure the concurrent case isn't slower than +/// single-threaded. +fn par_instantiate(c: &mut Criterion) { + const INSTANCES_PER_RUN: usize = 2000; + + fn setup() -> (Arc, Vec>) { + let region = MmapRegion::create(INSTANCES_PER_RUN, &Limits::default()).unwrap(); + let mut handles = vec![]; + handles.resize_with(INSTANCES_PER_RUN, || None); + (region, handles) + } + + fn body( + num_threads: usize, + module: Arc, + region: Arc, + handles: &mut [Option], + ) { + rayon::ThreadPoolBuilder::new() + .num_threads(num_threads) + .build() + .unwrap() + .install(|| { + handles + .par_iter_mut() + .for_each(|handle| *handle = Some(region.new_instance(module.clone()).unwrap())) + }) + } + + let workdir = TempDir::new().expect("create working directory"); + + let so_file = workdir.path().join("out.so"); + compile_hello(&so_file); + + let module = DlModule::load(&so_file).unwrap(); + + let bench = criterion::ParameterizedBenchmark::new( + "par_instantiate hello", + move |b, &num_threads| { + b.iter_batched( + setup, + |(region, mut handles)| { + body(num_threads, module.clone(), region, handles.as_mut_slice()) + }, + criterion::BatchSize::SmallInput, + ) + }, + (1..=num_cpus::get_physical()).collect::>(), + ) + .sample_size(10); + + c.bench("par", bench); + + workdir.close().unwrap(); +} + +/// Run a function in parallel. +fn par_run(name: &str, instances_per_run: usize, module: Arc, c: &mut Criterion) { + let setup = move || { + let region = MmapRegion::create(instances_per_run, &Limits::default()).unwrap(); + + (0..instances_per_run) + .into_iter() + .map(|_| region.new_instance(module.clone()).unwrap()) + .collect::>() + }; + + fn body(num_threads: usize, handles: &mut [InstanceHandle]) { + rayon::ThreadPoolBuilder::new() + .num_threads(num_threads) + .build() + .unwrap() + .install(|| { + handles.par_iter_mut().for_each(|handle| { + handle.run(b"f", &[]).unwrap(); + }) + }) + } + + let bench = criterion::ParameterizedBenchmark::new( + name, + move |b, &num_threads| { + b.iter_batched_ref( + setup.clone(), + |handles| body(num_threads, handles.as_mut_slice()), + criterion::BatchSize::SmallInput, + ) + }, + (1..=num_cpus::get_physical()).collect::>(), + ) + .sample_size(10); + + c.bench("par", bench); +} + +/// Run a trivial function in parallel. +/// +/// This measures how well the region handles concurrent executions from multiple threads. Since the +/// body of the function is empty, scaling is not necessarily the point here, rather we want to make +/// sure that the locks for signal handling don't unduly slow the program down with multiple +/// threads. +fn par_run_null(c: &mut Criterion) { + par_run("par_run_null", 1000, null_mock(), c); +} + +/// Run a computation-heavy function in parallel. +/// +/// Since running multiple independent fibonaccis is embarassingly parallel, this should scale close +/// to linearly. +fn par_run_fib(c: &mut Criterion) { + par_run("par_run_fib", 1000, fib_mock(), c); +} + +criterion_group!(par, par_instantiate, par_run_null, par_run_fib,); From 98c83fc803cfd6e6bce83558ee3023787dcbb3a4 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Wed, 10 Apr 2019 16:22:53 -0700 Subject: [PATCH 024/512] [benchmarks] [lucet-runtime] parameterize benchmarks over Region This required adding a new `RegionCreate` trait that is separate, because we can't have receiverless methods on trait objects. --- .../benches/microbenchmarks.rs | 14 +++-- benchmarks/lucet-microbenchmarks/src/lib.rs | 60 +++++++++---------- benchmarks/lucet-microbenchmarks/src/par.rs | 37 +++++++----- .../src/region/mmap.rs | 8 ++- .../lucet-runtime-internals/src/region/mod.rs | 12 +++- lucet-runtime/src/lib.rs | 2 +- 6 files changed, 80 insertions(+), 53 deletions(-) diff --git a/benchmarks/lucet-microbenchmarks/benches/microbenchmarks.rs b/benchmarks/lucet-microbenchmarks/benches/microbenchmarks.rs index 1dbafed9e..4c9cff4cd 100644 --- a/benchmarks/lucet-microbenchmarks/benches/microbenchmarks.rs +++ b/benchmarks/lucet-microbenchmarks/benches/microbenchmarks.rs @@ -1,6 +1,12 @@ -#[macro_use] -extern crate criterion; +use criterion::Criterion; +use lucet_microbenchmarks::{par_benches, seq_benches}; +use lucet_runtime::MmapRegion; -use lucet_microbenchmarks::{benches, par}; +fn main() { + let mut c = Criterion::default().configure_from_args(); -criterion_main!(benches, par); + seq_benches::(&mut c); + par_benches::(&mut c); + + c.final_summary(); +} diff --git a/benchmarks/lucet-microbenchmarks/src/lib.rs b/benchmarks/lucet-microbenchmarks/src/lib.rs index 68d0bbb1b..0ad485b50 100644 --- a/benchmarks/lucet-microbenchmarks/src/lib.rs +++ b/benchmarks/lucet-microbenchmarks/src/lib.rs @@ -1,14 +1,11 @@ -#[macro_use] -extern crate criterion; - mod modules; mod par; -pub use par::par; +pub use par::par_benches; use crate::modules::{compile_hello, fib_mock, many_args_mock, null_mock}; use criterion::Criterion; -use lucet_runtime::{DlModule, InstanceHandle, Limits, MmapRegion, Module, Region}; +use lucet_runtime::{DlModule, InstanceHandle, Limits, Module, Region, RegionCreate}; use lucet_wasi::WasiCtxBuilder; use std::path::Path; use std::sync::Arc; @@ -22,10 +19,10 @@ use tempfile::TempDir; /// /// To minimize the effects of filesystem cache on the `DlModule::load()`, this runs `sync` between /// each iteration. -fn load_mkregion_and_instantiate(c: &mut Criterion) { - fn body(so_file: &Path) -> InstanceHandle { +fn load_mkregion_and_instantiate(c: &mut Criterion) { + fn body(so_file: &Path) -> InstanceHandle { let module = DlModule::load(so_file).unwrap(); - let region = MmapRegion::create(1, &Limits::default()).unwrap(); + let region = R::create(1, &Limits::default()).unwrap(); region.new_instance(module).unwrap() } @@ -37,7 +34,7 @@ fn load_mkregion_and_instantiate(c: &mut Criterion) { c.bench_function("load_mkregion_and_instantiate hello", move |b| { b.iter_batched( || nix::unistd::sync(), - |_| body(&so_file), + |_| body::(&so_file), criterion::BatchSize::PerIteration, ) }); @@ -49,8 +46,8 @@ fn load_mkregion_and_instantiate(c: &mut Criterion) { /// /// This simulates a typical case for a server process like Terrarium: the region and module stay /// initialized, but a new instance is created for each request. -fn instantiate(c: &mut Criterion) { - fn body(module: Arc, region: Arc) -> InstanceHandle { +fn instantiate(c: &mut Criterion) { + fn body(module: Arc, region: Arc) -> InstanceHandle { region.new_instance(module).unwrap() } @@ -60,7 +57,7 @@ fn instantiate(c: &mut Criterion) { compile_hello(&so_file); let module = DlModule::load(&so_file).unwrap(); - let region = MmapRegion::create(1, &Limits::default()).unwrap(); + let region = R::create(1, &Limits::default()).unwrap(); c.bench_function("instantiate hello", move |b| { b.iter(|| body(module.clone(), region.clone())) @@ -72,7 +69,7 @@ fn instantiate(c: &mut Criterion) { /// Instance destruction. /// /// Instances have some cleanup to do with memory management and freeing their slot on their region. -fn drop_instance(c: &mut Criterion) { +fn drop_instance(c: &mut Criterion) { fn body(_inst: InstanceHandle) {} let workdir = TempDir::new().expect("create working directory"); @@ -81,7 +78,7 @@ fn drop_instance(c: &mut Criterion) { compile_hello(&so_file); let module = DlModule::load(&so_file).unwrap(); - let region = MmapRegion::create(1, &Limits::default()).unwrap(); + let region = R::create(1, &Limits::default()).unwrap(); c.bench_function("drop_instance hello", move |b| { b.iter_batched( @@ -98,13 +95,13 @@ fn drop_instance(c: &mut Criterion) { /// /// This is primarily a measurement of the signal handler installation and removal, and the context /// switching overhead. -fn run_null(c: &mut Criterion) { +fn run_null(c: &mut Criterion) { fn body(inst: &mut InstanceHandle) { inst.run(b"f", &[]).unwrap(); } let module = null_mock(); - let region = MmapRegion::create(1, &Limits::default()).unwrap(); + let region = R::create(1, &Limits::default()).unwrap(); c.bench_function("run_null", move |b| { b.iter_batched_ref( @@ -119,13 +116,13 @@ fn run_null(c: &mut Criterion) { /// /// Since this is running code in a mock module, the cost of the computation should overwhelm the /// cost of the Lucet runtime. -fn run_fib(c: &mut Criterion) { +fn run_fib(c: &mut Criterion) { fn body(inst: &mut InstanceHandle) { inst.run(b"f", &[]).unwrap(); } let module = fib_mock(); - let region = MmapRegion::create(1, &Limits::default()).unwrap(); + let region = R::create(1, &Limits::default()).unwrap(); c.bench_function("run_fib", move |b| { b.iter_batched_ref( @@ -137,7 +134,7 @@ fn run_fib(c: &mut Criterion) { } /// Run a trivial WASI program. -fn run_hello(c: &mut Criterion) { +fn run_hello(c: &mut Criterion) { fn body(inst: &mut InstanceHandle) { inst.run(b"_start", &[]).unwrap(); } @@ -148,7 +145,7 @@ fn run_hello(c: &mut Criterion) { compile_hello(&so_file); let module = DlModule::load(&so_file).unwrap(); - let region = MmapRegion::create(1, &Limits::default()).unwrap(); + let region = R::create(1, &Limits::default()).unwrap(); c.bench_function("run_hello", move |b| { b.iter_batched_ref( @@ -177,7 +174,7 @@ fn run_hello(c: &mut Criterion) { /// installing the arguments into the guest registers and stack. /// /// `rustfmt` hates this function. -fn run_many_args(c: &mut Criterion) { +fn run_many_args(c: &mut Criterion) { fn body(inst: &mut InstanceHandle) { inst.run( b"f", @@ -254,7 +251,7 @@ fn run_many_args(c: &mut Criterion) { } let module = many_args_mock(); - let region = MmapRegion::create(1, &Limits::default()).unwrap(); + let region = R::create(1, &Limits::default()).unwrap(); c.bench_function("run_many_args", move |b| { b.iter_batched_ref( @@ -265,16 +262,15 @@ fn run_many_args(c: &mut Criterion) { }); } -criterion_group!( - benches, - load_mkregion_and_instantiate, - instantiate, - drop_instance, - run_null, - run_fib, - run_hello, - run_many_args -); +pub fn seq_benches(c: &mut Criterion) { + load_mkregion_and_instantiate::(c); + instantiate::(c); + drop_instance::(c); + run_null::(c); + run_fib::(c); + run_hello::(c); + run_many_args::(c); +} #[no_mangle] extern "C" fn lucet_microbenchmarks_ensure_linked() { diff --git a/benchmarks/lucet-microbenchmarks/src/par.rs b/benchmarks/lucet-microbenchmarks/src/par.rs index cb4bc529b..4fa9067b2 100644 --- a/benchmarks/lucet-microbenchmarks/src/par.rs +++ b/benchmarks/lucet-microbenchmarks/src/par.rs @@ -1,6 +1,6 @@ use crate::modules::{compile_hello, fib_mock, null_mock}; use criterion::Criterion; -use lucet_runtime::{DlModule, InstanceHandle, Limits, MmapRegion, Module, Region}; +use lucet_runtime::{DlModule, InstanceHandle, Limits, Module, Region, RegionCreate}; use rayon::prelude::*; use std::sync::Arc; use tempfile::TempDir; @@ -11,20 +11,20 @@ use tempfile::TempDir; /// threads. Scaling is not necessarily the point here, due to the locks on the region freelist and /// memory management syscalls, but we do want to make sure the concurrent case isn't slower than /// single-threaded. -fn par_instantiate(c: &mut Criterion) { +fn par_instantiate(c: &mut Criterion) { const INSTANCES_PER_RUN: usize = 2000; - fn setup() -> (Arc, Vec>) { - let region = MmapRegion::create(INSTANCES_PER_RUN, &Limits::default()).unwrap(); + fn setup() -> (Arc, Vec>) { + let region = R::create(INSTANCES_PER_RUN, &Limits::default()).unwrap(); let mut handles = vec![]; handles.resize_with(INSTANCES_PER_RUN, || None); (region, handles) } - fn body( + fn body( num_threads: usize, module: Arc, - region: Arc, + region: Arc, handles: &mut [Option], ) { rayon::ThreadPoolBuilder::new() @@ -50,7 +50,7 @@ fn par_instantiate(c: &mut Criterion) { move |b, &num_threads| { b.iter_batched( setup, - |(region, mut handles)| { + |(region, mut handles): (Arc, _)| { body(num_threads, module.clone(), region, handles.as_mut_slice()) }, criterion::BatchSize::SmallInput, @@ -66,9 +66,14 @@ fn par_instantiate(c: &mut Criterion) { } /// Run a function in parallel. -fn par_run(name: &str, instances_per_run: usize, module: Arc, c: &mut Criterion) { +fn par_run( + name: &str, + instances_per_run: usize, + module: Arc, + c: &mut Criterion, +) { let setup = move || { - let region = MmapRegion::create(instances_per_run, &Limits::default()).unwrap(); + let region = R::create(instances_per_run, &Limits::default()).unwrap(); (0..instances_per_run) .into_iter() @@ -110,16 +115,20 @@ fn par_run(name: &str, instances_per_run: usize, module: Arc, c: &mu /// body of the function is empty, scaling is not necessarily the point here, rather we want to make /// sure that the locks for signal handling don't unduly slow the program down with multiple /// threads. -fn par_run_null(c: &mut Criterion) { - par_run("par_run_null", 1000, null_mock(), c); +fn par_run_null(c: &mut Criterion) { + par_run::("par_run_null", 1000, null_mock(), c); } /// Run a computation-heavy function in parallel. /// /// Since running multiple independent fibonaccis is embarassingly parallel, this should scale close /// to linearly. -fn par_run_fib(c: &mut Criterion) { - par_run("par_run_fib", 1000, fib_mock(), c); +fn par_run_fib(c: &mut Criterion) { + par_run::("par_run_fib", 1000, fib_mock(), c); } -criterion_group!(par, par_instantiate, par_run_null, par_run_fib,); +pub fn par_benches(c: &mut Criterion) { + par_instantiate::(c); + par_run_null::(c); + par_run_fib::(c); +} diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs index 2d96d570f..1b78c1126 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs @@ -3,7 +3,7 @@ use crate::embed_ctx::CtxMap; use crate::error::Error; use crate::instance::{new_instance_handle, Instance, InstanceHandle}; use crate::module::Module; -use crate::region::{Region, RegionInternal}; +use crate::region::{Region, RegionCreate, RegionInternal}; use libc::{c_void, SIGSTKSZ}; use nix::sys::mman::{madvise, mmap, munmap, MapFlags, MmapAdvise, ProtFlags}; use std::ptr; @@ -193,6 +193,12 @@ impl Drop for MmapRegion { } } +impl RegionCreate for MmapRegion { + fn create(instance_capacity: usize, limits: &Limits) -> Result, Error> { + MmapRegion::create(instance_capacity, limits) + } +} + impl MmapRegion { /// Create a new `MmapRegion` that can support a given number instances, each subject to the /// same runtime limits. diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mod.rs b/lucet-runtime/lucet-runtime-internals/src/region/mod.rs index 46734e9d7..6346a1edd 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mod.rs @@ -1,6 +1,6 @@ pub mod mmap; -use crate::alloc::{Alloc, Slot}; +use crate::alloc::{Alloc, Limits, Slot}; use crate::embed_ctx::CtxMap; use crate::error::Error; use crate::instance::InstanceHandle; @@ -54,6 +54,16 @@ pub trait RegionInternal: Send + Sync { fn as_dyn_internal(&self) -> &dyn RegionInternal; } +/// A trait for regions that are created with a fixed capacity and limits. +/// +/// This is not part of [`Region`](trait.Region.html) so that `Region` types can be made into trait +/// objects. +pub trait RegionCreate: Region { + /// Create a new `Region` that can support a given number instances, each subject to the same + /// runtime limits. + fn create(instance_capacity: usize, limits: &Limits) -> Result, Error>; +} + /// A builder for instances; created by /// [`Region::new_instance_builder()`](trait.Region.html#method.new_instance_builder). pub struct InstanceBuilder<'a> { diff --git a/lucet-runtime/src/lib.rs b/lucet-runtime/src/lib.rs index 9eeeabc48..54debbb02 100644 --- a/lucet-runtime/src/lib.rs +++ b/lucet-runtime/src/lib.rs @@ -204,7 +204,7 @@ pub use lucet_runtime_internals::instance::{ }; pub use lucet_runtime_internals::module::{DlModule, Module}; pub use lucet_runtime_internals::region::mmap::MmapRegion; -pub use lucet_runtime_internals::region::{InstanceBuilder, Region}; +pub use lucet_runtime_internals::region::{InstanceBuilder, Region, RegionCreate}; pub use lucet_runtime_internals::trapcode::{TrapCode, TrapCodeType}; pub use lucet_runtime_internals::val::{UntypedRetVal, Val}; pub use lucet_runtime_internals::WASM_PAGE_SIZE; From 3c3c38cfd9c93f901dd68ad45922e1efca469c0c Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Wed, 10 Apr 2019 16:25:41 -0700 Subject: [PATCH 025/512] add lucet-microbenchmarks to test target This doesn't actually run the benchmarks, but makes sure they continue to compile. --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 698796e83..1fd87305c 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,8 @@ test: indent-check -p lucetc \ -p lucet-idl \ -p lucet-wasi-sdk \ - -p lucet-wasi + -p lucet-wasi \ + -p lucet-microbenchmarks cargo run -p lucet-wasi-fuzz -- --num-tests=3 .PHONY: fuzz From c3c3dfb8b1bbd7d5da619eac2179ead01a0b4d1e Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 11 Apr 2019 02:34:09 +0200 Subject: [PATCH 026/512] Don't consider assets/*.png files as text git corrupts them on Windows. Recompress them by the way. --- assets/lucet_dfds.xml | 0 assets/security_dfd_cl.png | Bin 22152 -> 11993 bytes assets/security_dfd_pe.png | Bin 18621 -> 10122 bytes 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 assets/lucet_dfds.xml mode change 100755 => 100644 assets/security_dfd_cl.png mode change 100755 => 100644 assets/security_dfd_pe.png diff --git a/assets/lucet_dfds.xml b/assets/lucet_dfds.xml old mode 100755 new mode 100644 diff --git a/assets/security_dfd_cl.png b/assets/security_dfd_cl.png old mode 100755 new mode 100644 index f6793ee196cdd33964895d318cc105eacc62cc4a..ffd874ea065083f1cc9d802ca288f7691ddaabc5 GIT binary patch literal 11993 zcmbWdWmFVi^e(J~G*Tknol=UVbc1w*l=KMF0-|(xBMlPL>5$S55|Tp+(%sE_Mt|#F z_uh5?U+$M#vzWsd(Dz!4ADi0_VLRN*jg@!EqytKSaI zHha3Y52wY&RXeUo3$8481fB29I2|mt$+~`d>9n>nnp+Q<@8^I*p_L68h$z?&Kkylq zHy%C_M^#av4b^FI-o$&@bUZ9rppvQlqev!_tZ$P=yKHb1_J_xEn1HF!;GndAL9alW z+;#KUH*H0ZMeG$%HxeB7fk#U9v+U6 ze>lL|nz!n?-#pdeVoP{+y8V>Zn$5UH2*seuy^`WJwf{jGZ=K!DSWSiIH!VT8y_>CX zmdnKvcQ+()+nF{I*QtK1q|AnCGoVky?NfXY+}gtLt-dmqqV$;e#KD>IKUAL_xbV)r@H^_jlKI_H%bD zl=p?Ix!pNZVLJvGPdRpGYqu**I&hk(tOxu1ZKf--(@(md8pCRBlXj~t1_)WZWBl?Q zft0TF47=5qBd$K17l$iDx}g`R8>4>P&Mqf^l8oO9KfM{1p-eH;g+K8^LN^xabEM*| z&#NUy&8a11l7~ODCI0j$U>wzswMaHwr366G5h9=(Tt`+2`k`eKzw&TnFj%6jbnAvc zJw&{4f_-;nLy=$UPhgc85iiD0dxT9!R6~&>^znwjbs}LbYhV(Q#UFY5=on}L+d=T?USGs}Sx%&E8R;`lh7Vk#BRvh+vq9JaQBD*S4B?QDj z&m3lW%N5NU#`;p&uO7qoAQMJv{HrV_& z6NSJss7D~A@zu16pE(R(NNB>Z)+kAu>bl!d?rg{`N;vS%QVy@Rv!6$B5cBISUcE3L zCN(0K2zRSps!pm71zK{lT{f5PNqV7~5?vnORDZh7ywPllpjWpT3DVlXHaM(B?Psbi zfX&ug^w(RBwkJpn=CZDnNmfb&lWySs?cM}TMu{bnO}Cu{7Bwl)b4YdH<(1ufdq%3y zywX61!5Wb+;9`ouEUfqLvim9GN@TF`=ifI>k=qy|#pWD+{`(;j!B$15@MQZs5J=W)Y^Yf4BO=K}%HH@LI zi6K|nBm~m>^%K&e|uq=Yg6ljv=Oq%q$kt*l;*T=fg_xkT{ zuhZ1@j#xM>&ZltOJL3j@`LaM{bJr%p62QjGG}9RS`SBKY5V)M(kFj=&$pmQue+To( zR~%OU*WAMoa&a6MdS&G3SKfZh%&OE0F^;87+b_Cw`C@T@cl&_}>@=2)%6pXx;-{Qh z1#c?iIQc^vRPZo0yaFE?8JGK#qgsIz{4X&T6>f~E)Yb&x!#__Id_?nt%f*QW&-p*C zql@@|TD;(OJcO6?y$$^X0sa5m4*!#E|HS_v#geRyODXbF8ay z1$1>AutLm#cZSf*$M+5nlJUG9Y}{{2OH0!)Gl2dXNa{Ht2*M`UYj7@t)PifleL^lM zu;^Vd7cILrRlW$44rcjW7=Bo2 z@{oz5kkWktfmz9HFSgzTcku1Mx!Nw@pz*0X8cgBI?)k!HCJpuj0lmF{q1kgJl`jlq zDRyl*ofT0Iq)eL8EPbHI{#3cKtLqtv;DgyVW65!Ges!Z+292)lSK83`7QbUavgz&Z zod#A1Ql@HEv*)>1sb0eT%Xkk{%i%A?8iDGVq|ey~xq2eW6)KIIKcpzDKd2<*cUS`H zF|@y58g4AIyt47g2q1@sh(O1JO%vGlC&!#z_h2Dbqf5C(Q{ZgFM%PRIi-DL1xi|)0 zE^Jd%LcKt8+&5&!mlSacR$H6n1-qs=8a?~-QnWMLk79utlJ!uY-W^$kJjzppby&UPpD4D@ zPcW9e&$Zhm_LSB-9>{_4I@adBEG@R$dlRh^owlzkqPGOu0 zSJ06l{I-oD)y=eX(a4_TMVB=DP-0+bp_w$j`jhDf*UNI&h`lbRNhaW)9 zkqJ(~YK1+|bXqYGA4+UJf44yP6*H%|Ux8d54wY!UvvQFert{?RPdA=|*ZCbHI;xt7 z#Hw9JXA`WVSr5lk!Hn{1PvDUN6~f0NrwI=PzY*r@d3;kKe*dTY!}W|HI6W!5a7Frk-2 z0}6EgC{kB8%792zaRI{xP+(i+Z-D!f3os41t_knIn(_B!-ruYPNcZpOuC^2&<*v{M zEV-`9QvG+Wx2}J8&$%d6@0qERs;BnYSZwtfNMv`R1R@9jUip)hzTY}!FG~S3E|<%e z#^2@QsFVN$Ht$poIK!8rQV$=VP8o~d9CS212G=ZE`TnYAZBdpY!*dTBC2}QuE(RWf zNh>}tRT1`KyR`N0>f4?lh%%}$pwvs9N>i!Jqd)&nq+8mpPxm->CXM}p{jOE9z2dJH z&+g9ZTZhJ9ghum*)|g&66u86-6gl!~4VH+{h|U2u@jEuY|Fbi<9?-MC)aLhM!9BM)25fs`I{j?D z4TW=~v(jw%{$_+e-*H!O-RFKP2>~BDW)qtmXWg z-vqvCrC(Q9P=#8tAaGh^zFF;!xxbof)rbIB<1RtsM>FlCr$_x) zqFkYip2i>ll!&R@;ul{HCvsd)dY`^rp1Hj_zHWdY2SMBTjjwW%h&y$AeGL70v5c}f z$)f4iI?6Lv2n`DWvdEF>z8ZAz@;Qze|CaRb^Ulpf#9@0W5~Z!_8jtGZ#d~jMwCRCF zK{rZm_B9uZm2Ba+Bc%G}fEaV;5HC;M<4pQlp~X(5MdXT(Sk8M4tu zw0n*PQ~cckH;)_~t z#%t{2QaE%y`vj$0LySSETQB_{r8hnzMBrq`^u87dBb4HdNNV_)2&MCnCZwJkL3XNz zAw3_>!fgJSs${@3Bp;UdyW%vE*JjTYxD*hCwe>G|F+ug$9S?uR`| zf`dTbmW$tEAj7;S$BUJYab2Qbjo4=}T3fv^+BV4>#WNSrx0vEs?^4wOe7wuHmwiYi-}P0MY&%{)MM1`Ah!C3^`LnyQ+bG_TBO-ZLLR8xQb6bW# zgfn){>|m~$IwG}EN0vk?waU9ur9r^?pm`$(rODUo(ZHoVZSfCZzH9?)>WNP7Y{{lD z-ip`AWX1P41?37N*wWY*&0;WbrH>+)o%Jqz28%OE9QhA_3(hYzx7cQR`CIc(60zs- z1{#TK%Szx-uU{CLr#%<325$H6xcQ@R3=(+~`|)mjO#nsozlWqLP2pMheHZN}5J9nS z`hwP;mMo)_#F|C*(;tbT;Zm+ZY~gyrzWlG~)t1Km3@`b}+UAq6eOHUW>+|q<%VhCM z{~Vsg$)h_VGWo`JM5h^RXV}Hp>X^K}Zo{q;hDW#V%rNgrQS$9X!olaeTI%q|AUxxA}@E58mrCgyeq)ARORVJ0AGNT z8=FR~4Uu?x=C?l|E}l+5mco@5 z?`v#w0bZZG8-yq?P_z;_9{%paO@wDDe_8a@7w<%(N5eR%BdnGykIUBP8{NiTVJ+T* z_yT8JzqSG90T^v#zVTdezp3Nu!|4|J35tc=?rcI#Ok1Qgs)_KJ&YMecZcdw>4FCvQ zT7+0LVt$Ww)m=J+aV>L6H?@IyvM9l^4Kutns{SdB(|QqrQg|y6sayS)`Youh`v(R( z#QJL@`DFpx3H#u(2P2kYwH3KoLL>>c=#RIaC>$LTy*B{mbzK$CS0QC>LXsDdL5-LM z7ENyEbU`-`ZLkT;@IdMeoi98kQ3Q00WrM6I#c%`blBMmJ{Cs^=5x%qh+CrGs8kxog zg5x-t%!Rt1%4hq!b|sHX@FY-J-Xo7g(L+F8jiK-+PcDuhHO-2%igQ;(S01G6pd$62 zBz;yqsS9Y>P`13p&pY$wyX*a)Uz_seaV|^DwWYF#Kp5b47;~#%R5}34{CRYtfGf*- zKliRx_Z#k0NF0OGVD@Z-%XahUqER>mSbu{$&S&dPiYE;=^~=Kr!UWa@#0bQG=uc!1 z8~=qS+kvK@QK>)gnm1=dS130}@Y$fo3fFXJj|PsqagEWxG)|jFSgmum-c&*68>l4$ ze}<>Mbb3ovG*@YcV!@!8{E0K3FuN9kmRSYA8qg(LB0M~CmBT7u_}j#K|HSah!%>SE z0l%B$>sD!nKCV8=hUf;>Txn>76j>#(vyw0TjyVbCdbKR2udet4IaS6Y66zh+)`rro z`NraF5=^T6;Ys)1r~SRTcP^xO5`K@ceiplvrFc-D^C&qZt*)+S#W3EO{l>SI^me+T zC0;h2--*wD`tq;ENv(8h%Mn zSJF7DoiZW?kUZsw7zE@GR7dO_UD6j@&pS!~25@nJX#U2a0Dz|ceUW9BeN856R8L*@ zpFiaTIC*oqE_(mcqMzU&ka2OpakM;sJ0JMn+tc7Z@LxFIVO12*yCZd^9fWoLCBTg6 z{{L^1xv}WLxR`reyoW1H8n6zjfOWwa$pSz@@}hmjkPQx1=)OV>8CezTsn;}$HA3XF z{vwlL0`pNC%XQ`Xz-hIm|F+&#fj}UQuDf>7A0RElOF*HvU)sjrJ>+iuhhG|X;3(?Q z@*Gm|&UijB+2MTNEs06hm)NhoajyZe11(ou-z3REwNffb3nb4YP_)*s%z;QKTFus2 zqlxCrC(ukkPqfV1yg$0WV#Vkz?1Bjo*Az2GzDx9P>DTi@)_meMt85_te1e zaA>5KOfL8ZGVe@kDh}$mwUNy7zct?lobmhaxFP~DnYNKfK45bAY$m>+FL=Idxm;t> zEItq&C@~R6yN%CY1uRzVpRt6zEoP^%nrHQSs&stgUzKcUs_4fbTbP?qfPxKhARs(Z za+~)~6sZ>}H*WH6Yzur(vzV;719edjCjIuWZ*Ft;^}_cz$KwSmoOhYobebwD`gtu- z`UslM=~kcngXNB*2S5}Hcp-7VPdQ)XHCO)*lxvHAk40n?MO`+>RYZsS`j|5^{W&Ov zmzY>y5wxnD|;EZ|G`1fUil0t}`IC##Qj( zjeWm48t^>bO2|51=HB`#7I+p4mD)-JRc&aTNk`!A-FfT&L=n7{!uQ$&`qjT%y!)C4 zA>lHWq#4%E_8r`%b_yeS0Zt|$RS`ZVD2oDT60Go z#q-P%h+HlcMSl`!rqJTP*TR?^OUwFn{m9FY25aDC%|>+?4B!VVtulkYXUTw}lP&(1 zvrljs!e=|#`-;0h8eHo7H1J*!Fc*C8z3&$5?9(8!UzYTb%6)Ea-y4x0hJa*cZDWw4 z-wSqHU(fU@)2&|HtzR?(hA-lMb#R|~cTx~U`B6tgrR&RMk&92LlCj3-fQv)HB*KY` z;w4ru7WZ4f~Q$wY*>A%;`YIt+PB1rhq)jv%zc&m0J39Kr8Btu#Oa%BK^3%_ zHKOyW#BE{rvlIJLy;_Zjp$NpbMeZ}e=LVTMkNaTlersoiys=U83rhY0DLnKImCFGu z`^)imDX^Go^S)Scl8SUZG+=6QSJgT%=ut``F5$=37@3xvBLz)ACMtxOt(Es!Aai@Y zYQV8uP>h%O?^$MGfK$EV98;mC2#{JbOQPVRXab0@(gXR+%N30hrhm^{WCy7w!3fk@ z0YN3d|FsU0?ss>Y*Wph*&-d638=UPTHOn)~{c;C)apC%uK!sT%!rdfV?@%%B52Jiw zm1aRK64`GUNTgvZX_@0?hK;~$Ro*5*17rqw=P@<-HU_)WI*t0jr)*e@sWmjs`lz`WEl8uLlhuw!nf)maf70Sq!$7onUe(lxp z*1uhFAVP_>qPe}gyw47zprK4?B2D}w6XAP%eXcFLEmo6)e+t-eDS^)Fk*`Xz#e=|_ z%7D{m_yyA5UJ;)Je2+~nnc=|@kr~IB>2*{+A_6S3mQjA~ zEErgrnJq+aMT%g+{Zmsrs9;rp3xVL_`U3ax?y!fFIHGS}uUMmq%dA_{eU(kLuE}<) z3{=vY*;AKYI6`lJWnfmK;x_&kTe_z#FT0DGmnW}XD4 zMftXzD&TeDKyYm;xYKL)y2-6W9jHoJ%{!(D=axN84q-fxPXQE!2A*zD3AT8UyiZ9K z5EN_#x7yUSVbkuu@fjK297LF=Yda56cwPo7zp$U})HO{A_5PEfogw7G4I~F3#L#oM zR!RsdqXMCgje-c6q4&BdYXI`B_>V^N}w${q?cEXsZjqq%?p6bkoGd;rs9(MEW2 zR3~_E296BOizILT`erE;raA0CHJE-kcCnWBE;0Bq8FV8_#ti#*zzts@$U%?x&DF_f z*iE!rSaOVc6J%b1tdy6R{2oc)E+@T>AiYGl;?3ti_9x}u*JmZmQr1d13wgXER*FCO zY9`k~OOGjBzZRejI~w#`5VzIF5q=4XAMALT)SZB`f<{?NKoSXx`PQw(ug=8EE3YZp zonmLCNWGwe14XOMsCm}g<>*lIp?N~clw*R~%&Q=Z&47zvyOnL0Ao%U8@e5eTLv!P# z2dtL{o_te1-B1lus-!h;;O{HSUUQQgQxv>ZX5VErwuaTeqwKmEtbN+9|E{?!t^;Ax zWUw62qR3Zhp}tdtrCMfO^&}GcF;j%)LY^(SES^$h+*VsbB&IYnO1YnENqD%qqor+; znhv{3YnV$3K|Tm=Fj;s>W*h1A!8SF}pQrV5jTBpo{f|?E8@+h%DAA*~vd?E01ZZLu zDa~PLSLALm)jSF3jU`Ek+-Q!$AX;*TWxQ9vK!?L6(5thb(8`=p_c`=&h~OA!gaR4b zWbA`Tv&Wc^+F>Q@>S&@!@U+KZ1J^ZL8ZWo7bmD`42r@KcLQC)CG%nAfp)HFnag}%p zQI#9Bbqx-8=I~A!($Sk~uHA7$PF!ORB(2bow?;hmd6miej-bEg_43h&gQAy0{WW+c zrbsU}iYTNSt=qRxL0@x?FI0Oy z$@n8zNY~?z`xCRu>VqvdyOS6UWyO#3+y@scQO5|O=ek5lnL(f9UwY#4)2bi@I+;ap z7-y0CwF^B?#w-7HT@(GHjp43dn`hs+;cEowzoK;SM1GZ~j^K849#wEUB+gO11KKK>mo0**bp4y<_Ym$5(AV%Aqd&y)Ts!$Zo7v;LJLhZ|iUolsHs z+WuIpo$E)mzfEf=>D0DT=e%DY#nw)-dXBzo^Oj)?<$Pv9Kt_lD&q7%UUQmicOFIkX z4LkJxb{)Q$@}VcAt7#ra>Tw+na?(d=n0GUp$WS1P4|{Qp`>wv^%6!@0hk~y>OJmf8 z0^lRtTWjYVLzekHVvPq|Xv;KPQNR4DtUD{a88S4Ak*KBT0?_K*8+C6hSF&m+BAC^` zRt(yXHWfv-etXo|$oyb}OkE4T;>|lF48zw%+L+3-s6NP5TW@{ygxU3Ks5VG%?>g^q zC`J#a&3SvY%OvzfA)A*7Z|O~XsjMY2il)B% zqRLhEHJIWvEi3t=EL>SucfUVG6(BtPEo=pmGdons-M%)h2x)KN@)$y{dmJrcs`{C{ z`B!+iOK*gqRJ> z6P7~OLWnh_2;`;aDoaKfI}d(rPs^u{x1a9!!5q2VKJntMEp2!1_9!B-7=H_Ah~$veIw(oR@sF>RgDdw4oo13$qaitHaL;`Me%< zdHi4(akCQMnW+w%g2W~Z8s|)|y$Z(csvR*_9ZIM4yhZY^m_3-B<~YAOVJmT_?J>zB zS{ueno(N!IwnY~d`p`6#j+YG0M~dxkckIA=Vc_yhGrM~1fZ9$Nou=o?iqIxpUd?{K z1toioXqupffH%WI?a3j-60|+d5QL)5-<>r1A_0Tm%+}$Z! z?Xk~=U$ZxiMe=$dWH}DI5z_@n$=A_b2+y+9o)T z?2+5tOJYOrA@N<2y)e-0J<=8tvll@Jz5>(J%e>4+xuOWp{+jdv@_;bf#rFg3+-{ip zTn?xhZZkS!)X~CM4OrV>=xsElnvXOB}U&bvtC)qx{eVuzqeW0fN(8&3`5(_9t$V$ThnA_@k{jYtrKDk?0( zrSvH~bo+2=r4OETU5^e0b0s~HS$YzprY94SbyQhAEX7-oV(Z3~or|B0K6~+`gl;9g zQ;(Ep6roa8FNw5k#=vpHLr?k$8$RiK!#;-&FTIxAvpG6! z$wR}8ql#68c2gVh+{uI9mu1XqduF?)~SL}(ix2bb&F`Qw}c2F%c@pz^t_ zY#+M^-rR_G-vzhIg-M(63$NXWbt6l8SwJ5#{L%aA!k3?abqCV~4T&755Ou!QLf^_8 zlz3;Dp(}^tD*yYk22+z%CjLm{ku!D-t(>sNR-shMstT#EzZUH;ZiX?UwD_)t=Ja3` zQh7wDpd{(-vtj*^7Ia?X(vXqp^W+dVcHe%x+8@vUcsy`GJLsmv>8dCAASam;@bicZ zik8v;I^yq5Qen4~q@f3X7z&7DK5dLn`YW>Yyj{;-WQBKx=`(iqV)HRWXMhTEg#TnW;Np$3Vks|PBBP6`!XRxOr`6g z=%t9%WnvOEt_KE8ehIe=3+MaSS2)Top{B`h_%?7m;(BiNdPuy3KvZgbi^HiP7S0az z!_*Mu%EQwjSef@l$urD-Gjl6+q(PKTm^5tX?rQn?;UdkLkoZ27Fblt&i zF^gHFHLKdFlYChDLHeug3T1EbLo5>B;F;y;_V3kRHj2SlYlGtI){UC(TKbZIwC$%7 zreRFCXmqN?ZOF_rQF)d)@_!@^(B#33~lC!Frf)U7m$`YUK=7t6kzvBE$Bvy0s3;L&5eVW!uV^k9;P>6iMsby1~R+7 zgfU?(_yaI*w^{hlL~^fG!O!lXv}|zO&v+{udPxf?A+qb0GUI*46q^6|EmO#T%Q>wb zF3ScHIl#P7C51GK=xXJ)4+hxj{j^2>fH~N-fkerhW&aKaqC9k>se895V*e2v(fpaB z^#8VqQ{IdKOAMJjcL@+~{mNImJG3TKWrp>z_X=bxKW-|y(v4rQDciuA6kljFQ^aV% z<0sB+Y=bkmV+x%4ZI3s9X8Q@$15QYN?F_apvUQf}8>#ve4DSE8|{XZv;If$yn#HHGgD0U2C|EVu2s`> zC~>g^`ve4sGk1MZ9+y^|I5IiL0B9`$HX-SKk|AJ0PMrl5A6UoavA{)*gEk)}Mw!^E zfXgHj{@@IVH}wr)N}rp<$`I%GcPDXi(un1~;F^jc5EWUoK{J1FR2!K6OMPyiikBpB z4q6K83~|r^%OOyI5*0{iz_kJ_>*{^OYM2_Qe2Tt147SM`QFEZS*K3X0k_582KjwLZ`=Y5Ra_1bWUIa$+^4w2;r>__wOP*yO{7OSBx#qfgIwkt8X(i-2X zZ~$fm=ZMDsQlcnt0XODs6>ESg>=V{1p&x(_l!k8ugLA8=1#qvi zk%0Ir2YlUpgNwp6aSAkk+K+)E78)=JCxwS>%bQ(qPp9G#D5k2tE|!C)j6ChRm6uxH zd>${){9g{D3E>C46&PvQ2W%yrB03%s6(!7lXc|c&9BP~oT4v@bH8#Jtblyh_#u>q_ zlP3Q!?c4*{ev#{)YQ_wA-^V{}eifhY&bfhoRLK}wSuqOa!8|PJ2?*F=pRNOPTkdvX zTtH59jgZ+Ku)DH0Euhc_15z-@9&${x!;RdiI;+tfaKnBmkKwG0cR}wfryCC|w(7uB zyL>>PPZT+=r@P^WW`b5y|IO^~TzVX%1*AM#zg940XqVc0aA?TF{{r+K8*LesQZ+!! zhG)=|DmEj5Ra^NBe@r%sF_`+Z%=E4U?8${n?<=!Tkvq#2z7k7T3nn>_dEUQNaJO&% zf8$%OQ{lusf%=?(r{SzI6Q#dQ0Gh*sM*73@VA_k3y5SU_pd--CXwMxoNOz9E1o2PU zWoshK4;7bZZP4+<+22W+WP-72zzTsWVDQgeLL3Mw>FLc5%i@Hf3s&L0sdl!t(A;=w zru))i=@t6MC~jqsr(7}U-Nb2=01|SjLYnZDo+u?QZX66?-pp#*O_u2H0LoD;?+|d) zKP6~?cg<8UD8lDxbnJfKA_wT#*`+iFqRA_g^dWM9*=RJ;??t;ppn{=jP~k|;`1WwV%4RBE2&XN-*GkYxApIxs*c zi1sS*xd50blqFH8=$_2ImASwfN_%ck!qS_C2|5L(M$H1^vJa)zUWvp=BZQ(-cXZPh zUg&|xjBtfF^S~q`Br7;E#O7pgp48CUD_5JtK|3}|0ufir4)lUcJ(fPBob4}C&a$fo zPan^_4U@jxcn$^;6?rAGzy$N>S>!TF3^2}(Uvu<{Qkb5`k?G%z5>4`;;yfa}KZZ&z diFbH^X1Ep;-1%J?jI2M9lTwx}6My6T{{gxTOuhgB literal 22152 zcmd?Q1zVKu8a4_DIDo_ef`D{O2`Jqutu!J-gS1Eu9U@)QNSP?zJ#@DSNOwvO-SFM> zuC?B8@4vA3af}`)GtYBBSDxp2T@(IXT@fFb5*G~(4PWV*oF*C?1`Pas0Ko=-XPESf zprPTu^3v9Kb$~0rHGT71&B?;j9u3V+ud8VJS@QMAyZxMe(u{TAHySo(bENhfNY0O` z3kq6}zEH*e466wl&;CW&do=%L_kb32v#Wr6Q|wZDk`_~%F7*QIa}!Z(U=QsP{_?_p zkYC#d2ZlwnarD+n=&9Jy{3LO9)7CyAJNMxt?MHz*xA6{1NbGe8+F$<)p~6sySNXJw z*xoi12Lx9^=E$pw1!w@zy=$zd8<|^j&iRqiRlh8@$ua|M(_iaQKi$dsyh~qD{cC05ZLfT9P;f-8 zar9;AdUr}CO{k>(<0Gm|HF3vvY&@CH1g1#r`xP$6B=Pov(;`=bR;z0R0ePjAC1lO^HTcq_!%Xcda)A;Y5 zJ*(^T_O&#fU0c_IFL`6*uGd~w$q zd?C=WeJpoM%ZpENF;U}+u3~~*=aN2I@AyocmU7t8k5pyTkxX7RYgX^@QftZEoEe{R zjZOR><;B@I%~&PkEip}jcj%U1Fv%q{LbZe(=?0pm2wM6AZoVl|4`1ule3|-=W6}*>@B!wdLB} zAJD&3$r3k}@e0b6+NVyZzW>&K$cjgZQ+PyOsGeBa?0lZ~!Qf}M&NlGI>|KzjJyy#=sz$Uf zwZKAWkn+Ne`HEM>pYZ#+1-Xax zUh>bL7&mUt2oWAv_ws0|tNwYkM=xppDg%15)3y_cK)&etQy+e0)E<@0E zvD`S<hgC|6{ z;m%!4vY*T`o{|4Xtm;zpln1?|verCUi>#F%Q>TOHq;48A$Wvuv6KhCu8Vf|{2!S1;r9x92)?S; zsyUi$YVm%ka>;ULB#r#=sljYk!Hl!~p)FjQttiC6`o7htK{#%U5HX&!O(gEPo3ZcB z?7NRd0#osYOE%i6))99$R_=83d~~1?JNo5y*DB8&a=9+Xr4N;hnD<0lAt@T)|0M8{ z4RUj~&v|blToaA_idCz!dam*Ak8NmZ@P=)?Yw(_nqmra$yAxj!{b#--pP(2b8A&U; zAuPo@>^?P~LAQ$Ee^s(oR4IRrs;H0@ZWfXM-OZ7#6^_ea6#Si&EB4drrKO(su;fZD zq(sh}SDpJubJo|lKGN2Yf8l1j5bcr;aX337(uONplTJo@T0^2NepY|TCHbqC1KDGI z`}F$0H@Bc*<|FH`V&l2dNxUr>sWeIHQdIKi59;jD^qeg?Bbum$kFi$CN_nTBgwJUk z5*jn6tXJ>z?&Qs51>$WA;dMRMyxervF~}`Zh+UVDYFj%K{e+OqEIE@9N}(6rqUanz z-2aPwowCU~UA$nT(0G3{@@cKPVesU(jkKwFVKVbi8HK`xZ>$VstbEGTPSb66mPOQG zuWd;j+)HXzz0;TbQ|uKjmB*9n{`{Sd4sFD4;dnfg<1=$Xu>T=Fq{qLfM|9hasRKK+ zK6%tPlfZxyhkC%;po+Zhc$$Rs!^xA2wbRamrSFS4pC2NA92r{`<-TF|{-SDokNh|F zlf1V&yPMEZkrV9~q#x!BT`B9NW!_QQ89sFTh}P=LZE8m0Bgii0zK&HyTG3(fO9Hd| zg-N8h#Sm038r^sCfqef^16|8com0^u)jMyJ803TF7HqinL`8>Q77mF{+dn|}aGMI9 zH?z2>7tPW4@D*%*W$ZVU=3}SIiYCtcG}WSd@eor_nE`H1mInNRO-J6Xs^egB$58Rz zgsn9R;{^7v_+fof+j2)ViEju>Sc+O7DvPnXG#S3cRP#0ClO1I5YvvrznH@i7q4ggb zx}y42#kP95Z)#|Mk#-tyE@Va4lQYESwD@q2oL?)f-a@w3;n{dMGUU=TPvm5Q#Q6)} zOLML^dgq)s-+tP!@%7jyGP@froe{ZoDd{Eh3{XC!yxb`clEu=^|~R6rsH!&_G#6hDLdbBmy??vYjL|m&FLzK zX)9$0I*fl`6s*scTRE1a+|Z#!|9ic`WI|X#{(TEW95V(n%mAaXFDwA^-5cruDmZ`P3dW&L{o+LlZ_GvzFs9ZwHyxgq{kU5te+N{AAyo^K}82 zHC54@v*muldDd@6zdWFBM3wot-qD5HXYwc{+`AIV_7uL{xjH&^EZ z)`Ji2etnYeEczZH|DVVG^c;0FnKw}ng?~rCINhBsbeeBGxw+gk-1<{EJD;bWYlcV8 zU2%OfUHtlCT7<<^6nlA@WuKL$Pt((-C?qtx$z zEKkR!X?Zcvpgf1fPL=m}&QfcnP&G#};&XZw_acR1U$`Xs$Uq4F380 zde6TaJXpP0Se5_PGHs_e*TV%_|FqtuE)|b^|4o5sgn2x>;AyyEi zm}nj<+U^OBYJ5HXh5Gd(dp$VlHt@W=vsURryG#^>KFr_RGDkhrmKB)TorXJyq9Ipd zXj$GcR%G)hHTSzN$2o*2H=Y0J&ll?2i(I06h{Nr?{Gus!IG27&Gfu94_}~7Mo$2YO zn`54>smd(^0|JRN6Z0we6eIUiGOm}TIMquO%!uEIrdnM8byS>3YhUD^Ooq?Zepl6y z#AQ2m2e|BrXI!_a?}e-2Z0H$1TXt{??*3v2-y%*M$!L?mKe>i{t)8*(n9(~ML4>60 zvD@}U>Cby}^m4<03JrHadbn!2WRTxtgezVX`Cw;mn~3C7`wyoOMk&y!Tr%$86qfi))nqE;K^z>`JXFg1G-Li$k!))WfhfqS|E_JA&xViW)C$Q@BLjah#<; z)w4Q^@g$J<$5d~Gvu3@Kz8DT-eF>K@K0EBChZC8=8<%i+bcL3p8EJj#;aNuu?+EMm zAdfM%5?ItS&}2S+_%hw%`f1%W((&#{3PhRM_hKabW+g{<-g{5ndp*;`{!f9yu74KN zYo~JjVd%z0`G!t3G3@VoNiNxcPuOj^*zt?rl?V@Zv0J}a;IcmGnD;@SOH2wL|3wdt zfh|V-L|?E{{}tSmrb1sDxgR_pO6&L9ZR?Ml8vO6~lmeZ6-N6yTdu@C!QUmvKn^rF&e2}XcOA|w= zm70Y-z%;A)b@lg0b_QH4D#elbf1x0O;mL}CgjgGM24lCPmufZn`5IO`W`bJhHfX+r zgB!GVF0+8RI_Ps8877oCYsTRrb{j1+s_$M-ibB@iTx=OhiD*Tu+ASH$-s_C`87wO5?EO|POKcKrhh*Muzk|GfKyQD0r}1)E6pkQDQ%e_cyGBm6Fa(yGch!}> zF`@i`g$5DR$e`~u(R~Hq7uAXntC}pgCf}K5j@7%6c$4>^;{K@wXC)JPfDnR&!g2P; zaCy*GL(IGsCIs#!%jdbsf1292SSc7TPuJSUUHi+5p2i&^#GpMv~wYCP|B;OomN{=cB%FLT^! zD@TJ6alTsDU#3o_+J8G`6)W9hQn0*Sag>FJm(!06raVpP|4>CBfEFDv{9wtAQwEW%6$E!1XNeK>+9;Qi*$2>;MQ_<#Yaa zYxrv@wfA=ENjr&#{%oBa|6DidKa=31g`kU5G$nJ>Vf;m9A$NS9A|`HT^YM6kreED8 z`wvo)@SqKU(7jO*w+evh;qW43|Ld_ly<*2o+p#hn5*Gb;*!X;d=)+@mZg!X8T?N{? zniNf0s7um;OA+A;En|A~v-RhFpu7(w_KY*Uv7lKb^#i3ge=Gg!c z{y;dtm_@}R=-5@}F~XfjPT(CUzg2h)06mbEu-$|`N0l8*rcnY^e0Gyy08aBg)47x4 zPpyk}{X!7lJ=3;%BE77xtvFeNQpOmeR)9PI<}f)m9P1j^zWv?++NL^_FS6yXfa}I{ z6q2~NHwnP;a$`0C-T+StPFL6@q*pzZ@TnO{$-Rz#}b_IPnN*Q=UeSo8kJV|wn*=yxXoGIa!$DfZ9{pGIsVPbc5%aBYBJ zOdnMAocshnJTlHVBViDR&G00D(B=Q+s8L;l=HT%Ao04rv{RABv_{jLP{Li@@~KpQ5xsIh}yyzd$@u$SJ zt)>-^M{7U$G~%xUCW%Z~d!qSxkH6i60di^w@J^+5 zmS?ADrJ2zlh-;T1LUctLxRJ}i)1sZLVuNxkVi=ZP&*WZBu--}9Rs;hP4CCeGgSk?! zKjrbk;{bUt>5B2;D=l0DhPj5R37F?>qB$T6v#v`82IVLib^@ZIF5n7~v|qO4MGhpa z>J_}^okGsR$cUsSvyO;ArRIw10uCReX(c6gkF&fs+1EcX&P9>Vy5kfF@lH0oYPWJc zmi-(OCIx}Kwls%e^OkZaG9glb+sz?r8;<`Nau;pxchP##@X3)nzX~hNFRJSmaGcp_ zPh~C3(a3gW&2){Y_CdCA(>1=TeftN{x773S9)>^mYyD~J{T+2QTH)|ECIm5+-fFKH zaD6}jpZjv3-avc~lq@WlKZla3XX91;7#?whr~92P-d*>NnCrshbvs{85tRvJ64N@~ z8m|U;YZ{!vSS|+bT9MXwG@LVsDx7L-uA$z@_jrt3198<3FQt47K!VFia;(_Fv;M7N z3A28&SUuP2`^!3?urt~mRp6^cjoe(Qa&O8i^;}GJrhHZIh~N~^Jb_>mf5x>w6}vwL zrM{=L;|@^~<9#ao2mJ4AE&Iqorp~_l10Tl|wLa$Y2MM-1q@Vl!pXjy4Xn$Avdbrhd zkj4io?GQn^Im|sXs06>iJCVQ65J!R0?m6peZMCUe_?e}djMyH(MVHV%BaaEglnL~R z&KEk_a&#$}6=l3BM{W*KqQL*#OyWFH|GgKYicba-nFiQxyYx?z+^5G7kZ=@t$!Osw zrbl`Wq^N#I3)+-Vv!?FX_R$moa zQw=6jJqkGE8T|gBe*O=JIB|^iOltxARD)>B$@-ikCX~56r9fs7Vk@bU1|k@L)mIzz zC0ns(XLzXTy+iSQx&&~4J|#W3NU6`n`VAswWzJ34xJdyQ|Ja%r=NY``@xQH5j!p%< zyA1PX%D=6c2pxxK5;R6BD@cW%wScJ%%3dh*#{B?qJ#bwZwTD8)&@(3=oY8CE0e37z zp`^=xH+d-AJq(fZ(#M?!C_^CSrCR&Qxh;Xgo~1U2;9E^sr6uuXzkyn!tQ1&+YSfpI ze1FuX|9J(X8g=UD=d%Bvt`*g&w;2m=!lk%zGQ9F8?TS~+usnTtH0@>bwUL;PjptUN zu$#2FK=9CTic6xtUC?7lGkr>mmVTHdRhcUrO5lDnX>E9UvU6vQ`>6sZA2<_-mW56+ zKoDuV0=>A(bS0=-4=8&fg3PpA7Z-)^0`FDSv116+Be#k_@Kg0A5A>|M4V#dp@|uT$ z=pUN%IUFz%)Gj0md_o+DRAyAwVgBa{;)DVvd@uCBD<^GxiG5XOcuoiGg=_I?ObrzY z5X!)*O1tS`9FhW1Sf%YgPBCIoFoNF3Tal*^dRvv_Q@hb_`@x4TM1eby0{zm~kAhB) zeJMQT6i_xcfQ7K0&TJMyRsxzm*V8}~(*3GHz+I$*oz&d@fze^H^}YM;_37QpaN87! z1?nLbN&q}23S__#oO|s)Wn;yf$;8I+T<#MnQGdQF5~6gHpJ7tcP=Eq{F6vtU6FH}t zC;`v1H?g!(Rh}bUDiHPC5_CO}e||fTnWLI!_Ej;qswaVUy^g)E5n_=E?)2xwRuIE; z6HLF$0sCbIeup>%lRLCc^+t8BrC!IIllS#r(X%i-N2z|ej@@IX&~85TLi>I`ky08y98h!HDp1=KsM1eUZUb`qQRAxRW^p`Zz{8dwsv-+5Uc zD;cwmIn*+en`5y>B{{d`}&hila0rzRH zeHx#Wv`KmLw1%@UlYW=XFm+)E&<=IWt<((5t)gFtNwt6wdNlD_uggVdVOVh>3*Ndt ze|uw8QL?l*sx`2Sa9MA)+czs8%pAzk5acitIbLHmq;1_=3>|>^2|F(yZxvh3``Lw< zC_izSFsX9Qouu(jy`I07m;3E|npUbD-$d>8`peUf!D>(bUGnmA7=OM#?|vPq|JFL3 z>ov~H+uu`QWq?|<7=_|SNHv0_>^+5QUmiwEDYfQH-zn!d>Q|ST+-|wcI9Fm<6yC02 zEwT$^~yK6zChK2Xc~u;Zbqw6YO9l353Bm!&G}`ydK+23@Vm#$vA5j% ze`#M4|Mh>53niFqyE*6^;BFY*j#ueV=Hy+zC1F)Sz)CMPyytyJwv!F}GsQj67Oh;? zdzX{ih1@rOwG2vJ+5=GGOZ;6&4zpDn1l7akpRg6Y!1!QtnNXW9W4~~*4RY?NFpM0Q zNqge`KtoUNhvj%YPty6A`L5rSz?&y`qYPsgVIe(fbfW(1(yw-@W1qF^TWP1ZPQw=ZVle zDMC+YNcJrj3#G*t_od-P5M%Y`+M2U7ns`I)B&p!n*+gnNKfL z-P`X3cQ5;^;=c`{;nf`-{vyxBgQM}VmCLK{3H0Rl>IVfzZ0e&X_AKP1+*>64cr2{T zZlycSL_T=8v7W;Fndg%0YVXAL-e`~gwO4tr)Q(cy&MPU;edEh*^FNjOlT=Qr&}>p_axx7#y_nxw z%RO{yn%}kS3ORqnvJW;HU(+t?h*jEIpS0qAsPYWFExm}dNh}T4`*O{rH&|d;9d;V$ zx?O5@=dMC7w^RGOrNVFK@5x6(R2P$&5MIX-s@EMPFb#1_P{NrABLDIu_#iw% zQ)$U<(*f&|0(2{g3yBN1r4CbN66w|_Gux9^Pi<4Lcbq=_ecDc+3rFY(q_RFjm>tvZ znM{^hdGA@%AUnuE=zo#C6<%^PrQF)gAGoD0vSEv_}0t5qLI9snMhy5i;>McSCbAo>rV0Sqm`EkV(F`4LQzk{a37=xj# z4>lb*Bn;@M?Y_|E_vH76*E~dVFo|GQ7BmQEoMQO3;zLjA^Y(6fcW8Qh%RaT0sw}Yw zS@CVYuDn@`iE}#?+S17YVl!CM4sfNCwSn~MgVjC~?ype{M7qGnrql+<95t9${b6BT zJc~v$4;PHsB`m{IaOvI0jiAN%75C`k;Tw#kXQG#0A12T zmczabhc2&9&nY#&)legWECly|J&x%1MtVi<@q2 zc^c2Y;8Q;7R(rvaaWh}@y|T`2>m@mvfhe_~Q+hu*+giP4*Yaj%HA`~Xy1!6BMfC~2yu zqdWho&8Gp;E{4ro4QANfElV|JZN-ZnKiglPg&BwCz4)p?G4ei)PR#5f|53|b+6llU zx7z;%px=p_;B9~YLp>8TD(-*44>0xX*?N!az&m$EiYI~Su-^VkX_cqx>aAemCpj*@lD@z$~sjM=f2%xl37%8H!W^Fq(&Vl^nq6EHvqh?N`~` zY0*8#2Fxx}0jUL%JdG1;rPH_S#H|s3n?>9<^$m10KMH?v1ERt7_GG!kz{jWD3U<3Q zwd!H?c?fv%k1VfV&riEG%LJm=MHBhJw8+#gxC@Gt5jf4?y-2J1!Hblcrl%j332?mSBU&BSug zS+~yBW}T}oQXxvO0vVy#Xx>-!O`8AN72(BRl{PLUc3=%U+JVRfC*lc5B%9bWT~i6Uub-~5&u0ch7_y1|en zvNidHQgdvDMj!lx=kEqq+Ktz7F{H9^vU}!JruCZZFd9Bb91e*^LLS#BJhIL*bcYRiK4l_}Y#!s24g&l^ToXiKH*UroK6L@o7F`AD+b zTY9AO%g4_(vyX3EndugFYRrqXBBdN51%~9p0rm2cGp~&G25gOCUvT!4vk9-Ysa#Mb z^VIwkS(wx!^jB}^^VswMVT!eMr!^f(y<(U{G2$S?_n?Q>aojtH%V6;*6UJX)$0YTS zc`6_(M*Ip+9O7qbin6sZ#3@KFwCqr(6W zc9%v1iSp4WSbjc3+yhW3+lAOu{!=J1Fd+)-Y}C4>kARN6{Yg^fjyrWU}x4xB6+Vc50XGHX^hF3;=(vr1x7gZJaV6MKbbYN_Rz&d zU8;MTnF>W1aRU#B1gZGi0Z4oIo1v0X9%Ea`I7gLY8fc^uPjhP^!6^Y^utjRaV^z!` zHIob1a><()p_X^O6MZTj!Ty4P*U{^AG0(E%x4oPg@8zUg^Wzi@eea{l_dVi`smlDZ zLc?)tfkGfE5T%1m=KRmRf{qJQ$V}1tK@QgUM>xFTiHQh{>R2!WS&#sx+kf-wVGeZ6 zp-g%3|DpMUdn!p>h62SGUpphDszAP2 zMphItqI`s6{!k9>uOX0CD7xJE)A3j4U^#}(_Smt0$Ew|*9mGyMn2|AWf#~Vx3Ve?@ zkf+U?|4O)e=hv7oG*#TY3MG#1%*sD9s;h9AsTn3RM$O%bVP*dr!vH;_xxAxd33TNs zsmt#wDKA0j|Au1$ePfY{E>=&dOQ(St6+TfUXKl1M3ptd+*`=Uu|3|1d1w#G(kQdst za&*}^1+Q#S#_vG?fOgE9!eZkcSJ3)>=FX0p-(yQ39v6R zi;@LCB!;gh>21F!hrKaY`}m}E9&Gg7m0k_!Y$PW)AI6AYSOe0o0cy!*+~!ASa$D9p zqC!{T0yDXGyR4_bRA-C2wn=u~EYp z0+q%nj5a{eWg~tIAd!b#`PZ{F>nxkg?Q)IYW9x#T)xLp8x=}vtmPrBjeEBtQrI?W5 zSr%pl@nZ~2XrMMuNvTD)gzxtC>AZ(@cNX20+qjWdp@`%8K)N6~4gv+&z#zoFJB}VT zg0SBHm?z{9>1H{!F2Mc%{k>TNG3>qB@TT=3{)Y!jl<;2j8QJb0>}GkH2$%v~Ub*P|#8a-n6{`#JFr#bc8Ik|5Ng(&LZE zt0`8ev(^HxuOCm5{MPMekrgTNoGFy4P{Jt|6VQJuo{CB1d-TF1Q5l79VnlaKG`}lj z6@A9sU%vL*F74Vz%|If#>)1{m?0+?HH=Mqmk0Gj(5};_69ysK_Uj|OGTDzZj-oo$( zjQFRe?^3UbDP8W?JC#t9e|?IY4Yx*)eYidKzfGAwsdAv&hmRGcO}htgZ9;k-^XCoB@dGR@xQf{K#- zcr~(Z_m z3Vt76G7F|p=bi|a5csNjC2E_?W8Qb1#{X*H$Nolrdgin2UD5q^l0v)jqRFl4i2GI^ zGo}Kz+9yR6WgI;$vI3vzH)8DHc1b59djm{kAMmzfJ<>?y>&VR269a0zo_i;S^#l;% zOo1TRBZa4JnS=9&-=OBr=jm*Yf^hLJxJ?aMhbkZGaG36=6d3L8WU}dFNx=MJ2Gq&) zsAyfF$FYQNv`!y)GsY(B9|FC|7Ep`cBE8S;y6mz_m~YZu-1Q%b8+Ba9tZ!|X4-L*$ zd>yps?71?#F&0Q86}aC^hdycHQ$q~1c_M~M4l6kI*_IDh47_hyaP%Bk0v$u{_F}v# zge8Xqx`a8U@$pGdjMzc9T-lFg>k$^Pe#U65j025RV+mGDD|;p-Q0p>*x{?9`0}a2G zYX9F3c*;3|AhX&8p)4F&*=XsX9nF;s0)B%cW`8>CQH?4p0bZGsMoDUGL;ClXRV+ak z8I-!|@(4K1%@o3p(othbe(S-CJA`7toL;OBF`y&jRe9D9lc7CJX8y%}JWVrdUpcTs z1MD>gC?48HRmce#l&Jx!i6tMk)o1i-9F(^8dIhuBBJSI-3k|DJjC8TeWCJpj!Bp}H zG4t@LQLz4FKHrO@;3e{e#3s_t&W9xUIArrrGm3rzawnN7m`?$C77p=QsoCR`8@!VeDIi6yRAI$llO$ z@{!3seK+6BooaUwo6}&vm{6-?^hSE6zf@S|ly6QPN&J>Sp{Gu1$f8jB;a zp-ovgP>z~Vi;)jXVSXf~M&;H+Rd)!4no&l4jPCyZ7F1COP|GM9HE*z zj3#&ioFGb&W6xKO&7FQ^jk;Kco|rC5T9&+8B*YnycwWDmmwzudO%n-8B34%6+ ze}PLD*ywxt@;&bTs0YN~cW}UF-famex%FR*e`i(M^DgJVs;$t=+`He)vK(uo;J`PJ z&-!jBMeU**l)oobOp4w8AD{LWR|s%%X^xt-=t<%3epuEMA1a;w1O&P|6>)^-?b zJS^`8mfu5itcSQI6(ubZFVGv%s>A_cnFersWLgH%e0^zWxqSPxmxV;I7@T=YjV&yr ztfxJ+wg#M;d5}9d;~`G)gjs@i43-&MP@UHYo2MrX%k(d+0)~3QfSgwc&=xr^z;RP*##R0D3Wf6THYPJY#SAiq(=n!Z`Vn` z!xnh6AayxCf3r5#5lLiLGnv320iXm7zn;Y>~{*r`i7ba%$=V*in0hFYja zEs9nF`R24lh6tsbpvK04TwTw!g-~g@!X)F6Y=y6Ce>)=f74%Rvv&wn7v&Pv;C579q z>(PEd|H=tL{Z3VSp>flk`>dOu=Q$#iP!S44?kWBGalYZ-uhmO!j=8K?6{4Znx72Fmp&vB+PUfMvi+ zFh>yia01xuBv_M}v3?i23odU9CQfdv3jq@{1-v=~>nzkt;JG_MTxpXK!DjGAm=h0P zzUCs1`e488ZOeK9ZqzTId9lk4TV&D--K|GGQR(?l$3S&1*#>7EO% zq=yb67uy^*etq7h_voVb&MYZ1Gj~@6 zPK^9giVV1dYY~VaJzuw32n;bXx5d-Ip2Ip2JM8D*rBAo@Lcz%_?_FmaqVMgH$BuA0 z=z@)kO0wLbea2(@#Yf^!$*jSSU`^wcIMCtny%bPde(X1!v?<1W{Fw)3Z%>ZoL%-T<64EKRL!h4BeOxq+Hg{*U8qAM=%y12%e(vLJAGYZs_EOuOX9mdTAEQ6ZP zvEGz^MXh0YzOPM*0UaFxE+M@UuoAqr{lOQbG>tV2{zZ=d6jU2gC$aitEuPb6@so)* zcwqB#U*FwvFboOhrK=SRs@mdJHyQDiL3nu92 zkuL8Kv11?a&nzOwmf2;+phKN^Af~#2X;!~Ya6c62ipGgWKZmM`K_}yEidzR zx#|JbNMMJ>SrVCD5Kz;_G2|BmKZupQfm?fIEUL_~owRbIb4+_q%6+469~3`* zrFS?e_8NF0GoN<9qYv%$C887odE?Z1XZ(i-Eo&oOSKiy~nqmtl~*tJ%hy z%t4z#OhUl%mJ72&NoZ{yx#3kHwAu7OE17lq(kMV!Xf*pTNvPg+MN+i^#J`R(6RROI zg$MqqMNKH2BjuTD^tOk2ki>oTg`)7@Lnp(TUq~Nnmww(N zYIrMw$i}BcaxCPpc5iY!sdxAro*vvca%Tkdq5%5yCovE>Kt|beliThbMU_M*#O}|7{ zOv)3rBKztZ?8v$s&-jbCyjS$MZjF@Sr3&yh^@i~77PdFO6%Quk$(pJ5EN#ZF^{`^- zVY$|du2RC`xxI>i1l3+Vp0X>Z@GgCGCp^YR=E=S(3k)lkOb{Z5+wp@E$7Id44gVdL zbXN>@WYF^Y0tw^0Eh^Js>*!FZlQ-hHw3mcj*b|Pn7ESP+j+Y>GXfr(N$iH7^>TcG4gm!UhkXh?5XchM6raQ|JtbF#fw-TbPJaczcvH z4-;lEIpnwSdWP1DG$VXE(tO2#W@NG`jQqVT>!ihjoHz=|WqmG=m%b01JBkwI>P}B1 zFAfmI)gZ}Y4gSE2m`IyXw_R}x`%*pU)z{$pf^Z~kd%x8X>dcMFb;zR7{|ChV#!bxG zQgrN|y=KICvo{^_sT2)Oe0vam8T}VZ!SjM{=T@f@}tNJh6Tz?_1!8PH@SInPuC^<^&+<;5ihf#x%C@Qut&u zV@PPqU&IM~#LiBo~(lJRNqtQud#u|OUm}h;6Fr1G^R(mjxyz~UNP@2h z?auWE#pf3{PI*qG(l;khS3B(?V8K@3L_uF+-JJXutaotFH|bs;@(YP-+nd9McPdLE z&FPecOqftf#tJhWp24l<5LtV4T30b_IOWefE$wQb0m0qPSyCG(B2|7acKp^z3<~X|jSAiSqbciOSY$YH@=M4~--14ELx z+hip~vXN&?5-P$~=t~|&LzM=;gAH*hFSnn}f<7(wVhA*lcwEpkOlV6~>dpu0lfqabv&qDQPW zyeZrJLZ04zn_AgiA0N(?u9}sHA|*ZiM>>48!70TAtEOwH@3eUGEio^RAd&kyAMKa$ zlceluYUVI7o7{NE!bP*szUfo-bRLMYyv5f&TYP$yBS_4i@Hz`D|J78VZiLEwv0Pr8 zt{MQ}LdwXR4Ex3E{(=1=*#{&;++ZSp`iy~h!}E8pVeL!f^i>4KrbPmn17T{rm^tgi zUDLFg@W7ST__mc&R+!^{)Q2v9Yb3@6(jf1A z29{AVpRDk_l|$u|$6E?VN7d*hC_T#$I74HoiFS@^g4$f875qA0yeaN}mZ~w_kd)L( zr9hq_ydvd{HHRbh=9!1t)Ey_N)0~YO{Fl(rD}SoQoXTA^?PUCPP9^wvyO$MbZit!} zWRxompwGGtr*Xpg!M!_*tgbb)08OyOX#fY1+FRi(;A_(vs$gAiIUyUyi253)?-s5i znHF3fdF`G05}89qq_i&}z@+<5hr2ys!O~nyBZr;{*3QT~)-h+vDX`$A>OBjH33pg} zE@w_pnDtkmBd7*MAV=s-l-I*PR4NK*Urlv@ffJhAKHL%@B%IT&i4*mMhcnA0DMfP$ zlg}Z6xw1XImw_g_q5q4Zl)_KN+d)@yjwB`3T0W!5>X7#kOlOj_0c~77*hG2QSTEc^ z^@RC`2X-DmmAZXvnb7m0uTrgZnu#oy=45rJZJjHMULoz0nIpP({H+EvcIqWnxW1`a zT{|%eLvtd}spxLt%x%s3+hR*+GMLJ)=`e>}!q*4&iKuw``>iektlpGi)&=(wo%N4G z!)+Kf0`^Urh?2hlp4;c?sYneaqG~S-XO*78H0hd}AQ~c(uB^$zNwqYW52_B|U&v{W z4z6Y-V|$);;wg<-G2cfsbdF1*!j7a0<6V-D=r(g>v4q;LEO)k%bLiAA(#N87)}OL)sS}zh!Tf4mCMAY(#wfwQwWGEbn}nN7f|ua zBZx|7v9(Totld~SjLya41a&~T8(=A4rMXCJK7NkLHgT8{uz944(b`E!J1*enyFDgpw zdOCA?s9HJnM7OMQOgp({Im!Bpo6eT-PEC}UdB?iro#)E*bx57eWtYT|m~bk#BE#xI z>KAQlXoRGKM7o5fFMwdfN!M)H@q``5O`{KAM;17%3B=3mmqx^<6Re(z*58)TQ(U($ z2SApwgP+MfeEW``R`AgH-4RIOY-R^dxOh37b-lq?;|WE_hG8Mz&QQA z;(qH~)cbNiOj+8*Fe9^SeWk9P3Rqmty2C0K#vV^3L5Z4#acOUPo^S#?i9lM<33lzS z{e%TV&CF9;>Xm0YEq{H$+4}ngZ}Lo;=G9D3*JEGa8P0xPjHM-Fk3r?zp6K!H3GA^3 z9D234(?w<^G3on*Z_Vi0TT62Z3Y#1UK7+-MclQX<+(Y0I%>8Lo?2XqEr%3Z-R_}f1 zCCm}2TwL!a^N+mgN7Hd){n;GpQPoPEbNYMsqpveK*GwZ*HtzI!=B{=mrl5h+r} z=Hrq|8J72Yol7?VEKr6?Mc;d=u$wm+qILm=wV!*QMBwvxL|Z4{r7C@j;EdBh4-pK+ zx9S zn02a@Xth9wg6B>@u8}8JVRX#Xn=qkvsXuL3jeo@*;CETi?+BKNIWZoM<2cjO5PDZG zVUg24bt?uOrRE-IA>5BWTDDhZH=Cm@T^0khlu|ad4a{$Ab0$SARCi2Pwx8-Kwe~D~ z$x(VB8_P1hQjLwDju!1zNyJi=iJ}Yo8pUzt5P%(2tHH>bH0!BKr$sZypFQWY+_g={ z$ywAfuf;%|+;gwZvRslz90Q4Uo6KauC-u3?p!herL35MQ17qC>MuW7RL-X8xh;f$r z@4mCy1)_{~zGugF>~!Pl%^dJtM)HI6nugO{?PcjmZ-SwEyCsJNhzkGOHC8`7SA>h76^ZT?j3>a zA8Jg_IV$5eD5t?&K{UxY5mK>CO1htBjq>`d?vXjYWC_mHIf1z>+{Clc7?Kbn&eyqF z*EliVbUn=JON%IWJUT?SL-2H0kjZGEwhH}GDlPy^3R2;zy7$tfQdU0BUi-tKYsN+s zy&D@+Q!O{b@iWy6J#sW|^YfTO&Y?7s-$HjyWHOa(r5um2&YVN-2_OwC>3eSzWbz?9 z&72ID#f4sP;jU8MY|cvXdlAn_E3z#f`}%h;M`Ihh;QY{!sdVf0!pzW-fAra_%d67{67AGAh1aq!%EaC4dLLbIo)5nmK$8KUzwYO!vw@1yamCipOKYwiUsM zlp!b99*))L&mI?apeim^Ic`BqO@29x{m{$*SD@ExRJxzTNOp!b>hP^UtuN}uPf4ur zgRz(oXM>?x#MFw_`2VqN8sW1&PRU&_@zMR;Rm5Ql_;z1$A@E_ zs?9gMd97g{-z-e}Z;pJ%-w}c1#d7qJ+~3HeH#3A4{9&d)G&B<`U%Vo6+j`w=A9 z%NCxs=X4tV-#NZuL0DRdc^#|T>A6;B=g&jQ2!~N*wF6zX^+_6sx5S9L!_9EA_qK|# zuu*CFb8;E*Iy3ig5&Hxx%|_0{bhg~vi{t6BCD;m0xD?%3wU5VmWp3%rKs1t~IazA> zl79UzsaC33E2v|bp@5zUe07s*l$5V$4cCJ=>SU`tmwqB<2^EdG55La+(nUY#rz`Ls z)Yf?08T~b}@e=dCohA?ErGoOC&&7`dIV(8x!Qt1ttM}K14|cSMYu&s-<53{`&vxWm zqekxiF#{LIu;RIoT@(6Ja6@1#Un%Y`!!N^0jhWJ(ckJt+d#cBmr)!~FDbeS=eu895 zs96IvSBH3hb>s?(VPoVCV!xrL6OGkE7VY>)1b+Ol2;76~$q%b>3v0S+|F8=fhxxbC z*-df-7JACeOWL79hpsD3Ug%TgRO;I2(DkkOW-wSl6AE|i$yRiy!cG;k)m5{^A^7J% z@kzLcWTuLf4-;;d7 zgO1(fmo>q-TG)MY24ZM+3_3RzmtY-1`{4i}2&mApf*z3(L@J>j)OLwt?O3>*`%52h z2>6yfx=bF$xn~?w;v}XqV`o~W{Hz}Qsrh>Y1ZN(OTodmKtl|QoB&~M&3cLSI3Ok)j6lu z*b6A~jyuP4Stt?YBt$=9MXH@hrP|TzW#>gX^bLmpo_$k}^T&hu>ketd&W#c(pLnjC zGqJzM=UMWR3jR(Mmuot;We)stOZebdDIVTWTCpj9m6%2NdP5D(!~pbzb&UGrykd*R%Z{ zt-D)|u%s)rQ+$v-M#PuzUh+~h53Isp_wnCj?z;-0(cIemf&(^r0#}R)HQoa~Z?|2z z=m+q>?&YpW?$^`SSg7Wo=3R|HSzs%X^qmdo4w1DS+4L;i9lsS^gPsO#$UOcED6z(! zMMws5_)?qG`=0!xLv5Out*{a$FL#)_5YnsLPBeAKUVGofm$`ExS72+0Y^gu zP7@_2#=))XOdpKTg!or|_p#49)gCQ8%6VfZ1W0L4M&h5ouJCiA#fy9vyWBdYM(#T3 zc9y9O&tG6d9!fHmnrNiYDP8;u5=8+Cjyht5e9o0QN_+Yk2D+#Gosr)Xp(sC#S2_9~M&cF6p!C)v%Iv~!eF5rl1 z-se>oD$sE2MI$ZFXv9=nH;XgMev`s1tnsYrJS zY{n%t@sp;Ke@hb5BW3=)NyN(`tNBPST{nLxCwTEs-T^0ug>sSE(Z(BCb^`_Lfn^6Z0$l!hbTWMmF1u0o)dl|4z>m{6rY0&r}i|za)P`WZe5AG9 zZha0wIulwg*mN73m#G^a*7mILRM`@hg-;u}JSntS5!PDYdqCujT$^Kd+N>Z*AtD7M z{K{Mft%quWsr|kV-ZDXhzIan_{(ZWwVKv~52bZ#0-kuyDQ^LA5Esxh!R)$d7&HW;K zMUk~j8!y!r8kC4cBD+uzkg)Xx*f;syljQ)$sx+UeA(G0;8Z}QAw~in@3*bn$bw7>l zAxU*Xf}c$|tyy+wzc6?GKNhRwsZ8!~N}9k>$QQl_hINSQkq91-+PrwV;N-PTuxoci zAw(S<727Xx8NDg)k~7!X$bMKqgRAEnIn5?8x0h}qi(`?)>We$z^Oo?*bop1PIPv26 zB4O1e9GK6f?S*%^6)jv5{x|4DUv1MzxZ)uvW0r2QuBTbMGN7F3BMxWMrJ^ODIKE31HMmYTSSQY z5KGnoUU<62OE?xyYhDBAeGW>6X!Gyt>o1gmd;GLHevMIEYDs;t4+S`srh5##i{v@r zvZv?g0~}CPg$QXlMM25aW1yx4;Zc_I-w=1}22qeQBJK!Z2)7!5yQF^iDcF-p3bcME z*L!$ny69LU5%z-Mk+AnppfIKr3lrjv+Ib-R*}mQJok*lV5;6cO@@n>3IhhOPjJ4gq7n-YAg z0zu<%!8p%-%gq9ZA9;4?UP#blX`QI%RHR&INL(od6g?szmknvLf(vH`S#GfkDC z6c9x0t^SKm%DMs%XtztSgm=l8fmDr19Cm)#_+wgQbt>KVEx3?lTP56Pq4b8DEOkJ) zS_gpd1I1>;16?HTO5lK4l;Mi^J> zRZKL-yX9-jA%^bzei2;ThQDvbRU=u~jVd7XSCIyo&9vBeU9c7P=3I#?eqkae7U?gN zqnoMJoPc8xsx7?;xLcb+_< zSCSDIfw;}=r@5Eoji3LPf#qar6hNxwByiVX7FFXI;o&NG1^Z*u1QKdOUWsPD%A)LE zL1w_hyL$diB1*ypTm0Pz#L_Q;IBHL^x!<{nyJ%8CAB0XZ^=6XXBa++&M@Kmp6_p^Z z=?Cctj*YF3*K>|TC2P;A{7@s_v-@C)O8fg`iGrE@uwG?>n>=qW4n3?En&3yvzu0Xg zrYeko2ZI>7tY>IcP^mydykW$gg=fZK^-=-TUc6~;=USV2zRzb{lX}nrub+BeaMOOb z^Ko?wUI+0mY*DZWj#izG?rWkVwUX!{m9;+B)()f1bSR5nIYa}sz>W?)S8n)gdo-{0 z=Ae-&5$z=zUv+BppM+-UWqfRGK9Rxs&bY?j?di~Boh^lTsebGIYJ{+4^4;taHhxTr zUnCm6x?vuSp))5z&%zRul;=;0b{)Ck=l&#)&4%4l%Y`Q1l|I?asv)6WoehOFzWte+ zzUKqKUJCd30+Nt=mzxiz1Mjq94zv^)BwTxKC={uJP%e`1YFD9)UNJjU;*0VU>3QfWDjjqDS9k?!Uy`=G(wL0G4Z+=MQ zcTE@eZXtsYOHo)awg`%7-=}g~PN=Hunqnu4d_}geaA9DvJ6dYvsr7&~y6kf=xUB-Z zF5a7O^1FIGuZO^+d%IoO4)?z6y1F8kI!%Wg-L@hax%o!4* z`<)VcvA0Z}$LWR7r18`6u<2C6doIZ?peHpW2$#Nc-S0UrI8JuH!FhGz3{I4F`(lM;08hbxKX@-y-hvkuvxT1`#`(syUGTU6rn(OSI=^bF>zu`dt6^QXI=vqQ z8Ymp`Ttp-ljasp`0v73IJLdA6?Jf2)wSfEtf6i%u>(dKeotAym;JrI6op>~KrEIX=7aXOZc{h7iLx3%s zQ6!yxM`t-7-wu%}nN5piQz(6))+@TJG)=*#EpJZklgUqTv&=$ENg&Siv^O$el1Pr# z9!vZKZqskC?C`dSPJj7smx|W-;R%1O)pWE0%dGH8H}%!c#r{@h<4?q#`ar)?l@O%7 z{C0)L{eX_LcAK)lI>84iBx5f_rnV98r0L9?I-xo4mATP@*v%R&8b0hN@o9unc1CL+ zJH|OMAIAhVX$ly8S*EzZ^A5t2T0du53t^ z-F|F4L9c2^&-kH8jd}7=(N%cC$cR8w6KutLAE;ZV*Q}GFrwqEdi8kGiZSI?uVrlx~ z8iA(WK{U{b;VMJ6XY^EGcIb`7H|O06svj5hn;TtKfA}{ep!Mjko7<_oJL5&G``6IT zJ=Z?W?z~#7WBh`0;E3UZQC7MbFM~t1COpjk?E4P+l#HO{IpGG4XAM{ zBJ4ktIW67%x&09q?t(auBy9~%MSCs=75Kz8Q8Fh(!~>rU1tU7Bt?6dh3*O&+Q=U^L z%wLH08#^{64>$mYmkDlPu0}@JJ>(qE`~bI+ z>RfEuCqjsKsJKr90P-g0!aBFjT=%X(8Qg-3$`63~e}?RKQB+`SfB}U6?*OPx6!mfV z>wx~p3;lIPz&`q6Jr0p*=>HD??^OTJGHiTgF#RqbPuUQg{CpQ$q}KDIGCLA2BywwN zIE72zERxnAqT$yOO}j9X!~T`&_5YRtmTRu~AKIO{guj0V@m-qA03sTmjH@r4tp69u zw=cQ>O!@8KAE}^r|Do+_a9+4R|1XkU3H1MP;a=P;(PQT5jt15!nk9x}d+n4Y@>h5q z?OHeOy57IS0}K9lt!v4WVJ3*0%F_N4Zu!W*kK(_QgCPDxLI=HYYjo}VFA~eLI1H1= zH7sWidj6$N%y-oP%Y`lg(>>tjf04xgkZQIVH$nb~(Z@p6f2agb0x#Q8{{Qvxu6JXP zBgXvIR=|Ih@Z&$61mM}+(As`VS+svPR-!AEbbGvrU^k2H;_$MxW#(q<#~R7u-1b1y zDj9!#4?#}L;Z(&!7hSU# zMB`akAhzB>GQG{N=S@@VZB9S^eh6z*>pka0M$FTK!@ih{%hrrrnIGg+-!P^*F*&NJ zIv7@eM11D7aLe#?xgBy6@s6^srW01JXOfk?TmTNP=!fNKoU%`&iQFBlKE9zuxVt|q z)}aT-7YFAD&66oSY_-Q{+Y4l_qzQxM!xSvzR1;Lm~`b9&F$>TL4MA%1(#0@gI!_tLhqX{ zyzZLJ2AU4$BfPOm))Ws@4=@VKyOEmcPOa(>ZpiqJz#j%<%si=s6ldxdyW*!8#Qo^Q zxK;4=pv)Ic@JmkD2yXeYU~VV0&&LYAVjmY&bg;N^z@)DGIy1TQ6-CA*qRkA&*56oD z-S$7eJ^t|d;l*COFt`{h24-?-YjCch&lC%o@*Em%FJg

XXTMOOAuz4|7x`Rz=mI ztNzVMQ%a$TZJYLRC1u6*q%4)RcO+%5<>D;i?$UhN|CZPbw@WKG|C7tkBh}L6h>2(PAID{1%BO z6{K0E(DdZw#ZqBMv+PRTk(%`0OL~6{jfI-sE8^9hgz!TJg4&?&{v`Tv8CNtZyPIeM zS?<^yr=z7Q>?7Rg2s6aK-~13%JVqR1=tPLWK(F>Yn^G+|-GW{R? zLVfOh(DxUrCDU&HAxdKJ)UFWy$E*D7&HzZx`_K}fi8cl+h{pW? zzI>KAAop7B{}YigSA&A>-?{w!{)40{tu1vHasLVs1V3#KBQgC8%>U+Sfah@N&6QvH z^7J2Ienk^beqN{=L-a4?7rgrWU|4CDRA(CUe}Nbv2fT>Fba~tEu-LzDQQXV*fK{vd z<4Q-+kkHNEj|iceCihby26#A*@D>14f>PK9@x6HxXR-HQ#qX(a%ml1@0BR-(SlIw) z<~e*4_AtnQSZy)B1EgrSWBE#V*XM_=5BKSU(3Y!}5ZmT+{Fgg)(T>JM4JjIC7`qR5 zhu&2f+FVvsN51GR^@lAt3!ay{n(W{;M@LyexOY4*2QTiJfKZmpVNII6WK>bOS*=8C zNbqv*`h1szXRyI}7a5aOqsnZ6W02=-o)f^5Kk<82A`{W`tdTioLnXYuIarlM2)??G zeJ7dgT$|-a+gB7s-aQ{g6d-?F1fqV6@xmIbX$K%xV6REm1~Z8ZycE7Y8uGqB1^zTY z*G9%5cDk50$F+`a8wX~L@;;)Q$`m_jt#v(I5Qg_CrhnckNcE&1?ov_UUEj{jV0j}e z=^MyZ2N+`ToC1i=s3TDSc7-5~&zY}_2?Sg3j-uY5trOl%b(D-C*L@Nn`Yg)kQF|cX zRPf5htnH?%JrH11=^ex~YrApU%v68MW(HQX@W`7nvDM+>p43Beyim1j-Op_8N0cwI z62K4PBQOO6X*`RrR)KPkqVV0@vcX_Hh-g5D_dSeQdVm?E@D<25o9?f7AK*jYSKdID z3*v>y$n*f2as!Z#)O|CaDAB%TSpD8xU&lTuDQCafp<;ybd>_>BE8uZ;CKnh{ekEmzHjTT4Mf!UcQ>aGwqB0eH;1J?l?0iRW%QW0yv+BJO;T3)>l z6dS5&XGb}kY!`(dT0HnHCzx959M*f?&Te_CHfC*GO|R%k1kV15S#1l`jtn=t9=4bd zks}k-SWboyi@4+iS*))jFD~XngR`aD2vVDC#a)`~0t|X-Gn-&~`;q(wSH52J^Fpz zd&9mr-+Bm~-7BY&Y#H%_E0;=QdnL^!gn{Wz6?`0OoW2CsO=_+sKUhF%%e94Tx>x|_ zdZS$yzsufMgh9ROU<{Jio8A}iO)`-YY;)m<_?2AQ8yYme+9hcuH$wFNxBE|PR09CPlYTo<;f#@168mN_vd6wDvh4@!6+{X zf95ezi|kKVnJcF8fr8!+@m08%dVnsx`7zn?DaqR}HrT6ttj$n*G$lv|ITkBpl{aG) zg~ohPZ;Tvj<-bZ%;JGL;RT|{fhdC z(felNdB#3clyU7TQwa;z4&~N*s!k`qBxmKDj14k!h zH;qx>-+tk_%F(#AFj7vSLgH7&a6WavMeCI5_fQC`+)E;M8ZVx0?!}`UEa@0*(*6vc zyZ)v9>|3wE6V$=zsPE+|+F;VJObF2p;I9UE0&@M@T*)wE{MQPF?F!fO z{>RoOu7gP28n(hDwHrWTj{~$3i@Im`jVXeNqpJY^93dI(OVaS>eZnzLOlCdaXf_Gb zB48TTo`$~9ZCl`G$cv&(pvm!P$JrvG9dXY{3153({q|%pZtIZ{i#cd)#(TI}i_dXD zuwM%Lal^Evb2G0UesOoXNH6H_%OwLLB<2duX;gc$Q|qVwmXe{IUf6)>fYgtcTBMD; z4#I={W0f#DYNf07{=AGC^Mk-rXnnn1a3q?%mNu8dw;lgADS}XI3Xh|<7SEd zjOtwo$wX~GKblp(mM%(lp3rBczCCu7%L(C} z(G*t2Ql&lB$OwoCRf0(x8Xv5`xX(D6^+WS9tmTZ0RlD) zy4!khTPft|P0#e?v38#<8~4w93OdCV%;nnS1PXhx7pRz#C5Z>>^*zsYu;d2PssZg| zs~D<3vLHsHT`4Sv_w8Ou{nivW0{pRnvq0Djtz|0BS}USH4~zBb%I+3Vy=!VI1>w6h zH2lmVM>kja^pICPqAc+o6P7;iU1{LetHmAV!A!_z7~n#eCHw zwYEiDp!Cixl2@!XVrYs%r~-ZThZ3Xuw-J>zT1ntsuK)lF&gmxvUW9g zgu1|w$c-uyVHTj$Y6*Oqs#Sm2%_q6}-O!JJfbM|Fcr-Hia}4>dAOgzGoMcwHa&#F9 zv82}M2st_&)hUZ;!2VH4{g86|J|8w;YAgw@CEhmR9=?Yx>otE?x`@au%w2LZmn`~M z6lQ%Mqn2{UnivhvF#YX%uw^}YP~6ZQwaC>}_&Xu2fOVdFj&4^LNWB;eYue8DZ8h95 z2FO9{Q9F8-h0Nw3%``d{y`qq4LIN{<7O!qx)x?`;Y^DdGo0ucEOA>m;JIQ+*+<21c zec($?E^Aq|apF~LYv0HiS#*u4r;9mOdsrY-R>n`+Eswql`uIXbq*nD@I$+6IyS(m9X%9cuO+hM z{3C>}yVudRu|i>8cZQMCCgXv=);12y^UoT+^ruS1l}pNK;|^>d{#hX1E;w|TO14XE zjylsZgJ3p$_9XoVh*I!_47W}iLhO4A7NvWbk~jjHuZl(}wa*kaKJ+!5<4_@70DYD? zj`4TEDkf7Upu=ij%sM)WNY^;W;r4z5nhH6Mv%&=$UjX17%tAYjQ8;nWobWGXm~U_w zPCvT_O7}vmp&U4jL=&aDv%;#-Aomm01I-|va)8X*?qmI74_q4>LhKbUm*tx^wjr!M!%Qr z)pO*xP3wQP>)Ul&BZECJ6@&=|&(F)y(-cVqtiM7G`S|9HSB*^AjdyNO5?bFj!UAw( z(p?waQ^0$>v}R<>SZwIvbX3dhv+ZA}J#|=Y)oMTT(sP~MeL9q14_Z^}YbXx!+vYw) zvro9~6hv_UdOu#~rAouCe33lsGib!86_ARBfO&SK$-|@gm;j&@wAanMkc=ilaGv_G zrM&&rZr2vfO-pnFERwE1-mBw%w2VxgDXoK*alMjxJket37IM0Yg9Nq?4q|aQ$~|`D zD)CJS^cljWb}F~>mx28N{54MBTMREv#`{Vf9-T4>kAXfR{qC9a8hVDGN!raIZ~K=k zDMcYTP0*bWkCa;rz$mxfYYTilnYJ7xksM_FN7rV>(x!}};q&dUUc@v1(fTOx2l-cu z9?L&d_`%%-n0o$X2iVFw^>UFV7UQ>!Oe}lk-3EyML7Gx(qCP0;5rNmki@u|H>UVwb z7yd~6g1P7PW2`3;f;_e8v z<_@Eg@NkPW96)Dn`dN;7@XUKB)0_PbWAcmGAKA}@ew(m*bvHWicIBDqn?$zdRyZmz zmuI?ZR~91K=ZA}b0P+GN?z;1|72W7L(TQN0LJ+!%4r$LDzs&BZc@1ne+RVM;*w2L| z%&kjV(Iw$3FJtiKHxgsX#l83U(THm7M<(1OMI2>;G-f$UYqQ0o5XrPhI?~=Tf{Y(u zv$~>F{3r^-j)f())9ju@8yBTeWZ1#=B1!D+wx@HjtsqKnJInc-Ps1icH5HC$XAW{j zLo$-?$T6Y?xycY7E9Kp}yopz=(Go_{DYh-VG1u+Gaxtj2upR?@zK_SAkSW!mQv!9z zte!t4q=wqY?O|v)F?!MX@-C;7_0twj>~#L`D_}Y7%F7>!xR~PLjI8xbzQsc_$tZ7- z*Rn!bdJBOl%WNQwbq}G}kN8NL=*>1HQA@fsJb3`*OD*TAP={_GDh^W6dOJO^zEu{P zVbU|37+Rz)B}6I+`)q*;~S8v!(}>rdCd3zx&SQn`7QnessRr`VIbzUXh3l;(1pUk zHC3K$mp91V7<}h{$2k)v9kSdI-1ArtnnxaMsE%VfkL0uHX7n-k-Z31>>hS`(e3rM7 zYyj^8Syw9Q2}D}%m^HAt{BsSrqZycly&e2hOU)g1^>|R=w4YRi9mnL)oVb@fN?%ev zI(HI8LLHZgNaEPq`15kAF-cvYObDHNIS|ar7?>0;B6YpqpjR^ML1R?^T;SaKN2a~V z=&81EIh}-ug8{J9B96G5^4!CTM@R?OK#_>(c@F|eUhEU#_i=Fe*T>`&n3dDPzMFmq z`T&)AG(88(qs6`Dp0||AvjkJjEd$pZ!av1JqhS`oXjzVF&OKI}jIn8O>AP~v1&G8~ zwuE0BaC{i=3`-q++^xr$_)01k7fJ04kCRrdRS#vpZ&P&^F-87HxFx`p7_$taV_B3< z2F)I{mZP*fOlOEA@fZo%@|R8p-*J3Jd8rmt01MIbuUcyW^v8ln z-|tQEyiOXY81O;AZzsCRU<}`HpjSs|Ek$|`J+xdt?kyq@FWTCk!+P}c%V~e$Br_y# zs0~GTzw}K6`xf9T2%bZ7OM8kKsbzy$POO}NoBjrbGacyACOeLJGho$OZ!)jG z4Cr|QiYN8vG!%Jnu2d(%`D*O39J+V5KYLj{s<1o!Lu#-kig>{f36W9lb?|q9?v-sK z|0D^|8xoX*IoPSDd78v$6*a|-o{q#GxKlzPlKgCFS09RUVLTB zxL-4gN%-dRJ`WM8Igmaz`Ay_2tpfLH){@qGinnMklz=i{;QPO{6*g(EM+P=67C;Hl zdZro%MD;|gPNVYN^U%X);I0h?pVLp%mXbv>O`FU9O!N7Kwmk|q$Y_G8%+(g?_Qs+SG@@Ms zmk5-8NLo&o<`|)B_1~7AZVVV30=2t-Si7De^rHF;G9%DVgb?C(Y#>Q20xgC2{yFVz zAV7Lf<5$cEic4<4!^xPnswovrQU(&)zLL2f%mtx&169?A0N=GKw#Uwe^0JZ7m~e;F z@k*x+M%Y~aE~WPIZ&8Xzzs{cbnUA&5^;%!xEdu2gRf&q576sK<$C54rG?OF zGXUKGVwOSxEwp+Iv%Ja3g2fj8$bQ@N4UePq>q5Ofb=!)#y4GV0WV?;fu1QO@xqFxY zu<7d(d;bP-j|sT5BRcSgQE3&{1ls~>yYpi->BvUO2HpkW~9 z+dRc^3$vk}cdBm=WL43fP6m`?J6p@lHm~vQSM{fKy5ktyoOTH$>;>SG7G<&haWK$1 zV6j=hP&TR9%X;iQ17-Z~kHK<}55O%p?pxuhib{2?bMiXij@=U(2?g;|Q3K!q11*8K A3IG5A literal 18621 zcmdSAWmlX{7d03N(m-&R;1Yrbhv4q+9^9>Qhv4o`kOY^;f;++8-8Hxb2|gEho_Ecf znO`tpSTs%dRduA!K6{@ESCp4PMkGLd^X3h*l%%Ngn>SGN!0&4yIN+!KqjcMwH;B5P zs+!KW?h;@_2MalS6H}WvZ(KC`$MU69d@~F(v{Vri8>!Y3-5V@7G0(_04|p0~boe5h zl+Do4`yI9#nf?kbKI_csT?7g~rOlh_?Ff9h4I~A@sC1BC;R-i?x(l58gaQZiB4_CE zZovPA6|zjS_J`MRUk3aP=@-b){}|F?dG9{2m-ke&=a6%>`weI-{rI+^^6(V_IHlrIf|Jdx6;xw$-K3DVcN zdW$ZMv)p`tHcyiM zLvzlP=-DjL*SMo3)c;c8L*~3x9VOpJ>5J=Hy~fD!&o+bj$+Cdqcm|V~Nmj~ENQb-Z zM!vy03006l{@u@Z7)RjiH1B(!UG2T%eY9ZY;f#iVP)UldGzZTS=&t%FwOHiI5@ zJSA}JZ_XKMv8ZEC5;3>706c{Bqa@Q#)@eL@SwDyGZ4@QzyN}^=%w?Px+X^D>fAb>R z37??L)T?TFQEWr9$CPRw`!qCVd5<+QqLp_kpHI#(GbrzQvF`qwrVI^BkBeR0{5*m% zgc}|pV{Lx(A_{+_AnA*9bj_>tbd=SOSx;4D<{fvGrn%H>q2LnAIu?C0k=y-tTC(iH zQsFLqB}fJ8BJh*4f$tJ$bu0gP`k@GoCr=or)^bISO@Hmfp^)E@ustOI;1{o{sNpZ7 zGucySt-TeAAw$RE39A%+f$JlOgO63^NAA7sr9ENEI( za%K1`Nu@`vb!Xeq^&RhotDyhxs=h5cTsJ~uyLSHm^>iDRBYJ-$-z~7mS zR(t#mW_aw~;%`!S)Bo0VGbf&cXH?1wYt*Bh;LE#PYg%h_REM2+{h9kanRK`ca-5vb<|Eb= zM+-k%auO9-=X-Z@4NS^KsD`YqeVLX_et-SkDzARQZb`)sPZvPjTr$s5EEW)@2u7wU z=WCWpBJ1|kF<``sJR{swD|@=93IjK_6;I`=W&AM5GaiF7hW=>wg(f1ti()*xij<;P zKKHMDc}#>mWd9PENUe1@|GkByaN=DBUOuijtu0H1ULz)~$ms86=|$gP!N+-1+*s{A zKZK*Nc*@FP5O)d(nPlN=uWvpPkp(YCxQ(^)3A>zcH;7}>@FpfS{;gUkK$6(LU&ecy0MIKPjuv(EO2h~I)Okgn( zX^#mAH+XDesbR|#YxygKb3^#^^%|-9v&D4LU)`}x({?^%L-bg~Cr1P4&wA+oSWwZ+ zI3ljBbI_y*3RxiDTGNek+MTkM3-y}{&Yp@U5aS5`b zPTFUlWJDc(PBkx7do02P)e$0VPf@=9i8RMRs8$-HisrOyJmHNq!ga;UMBNaLk|H`! z^d<=L+#qvIvLxtPgohX4U4sP*M>#pH-cdt7xc|Y4+p{c~8zz@%j7R zb;7%#7X3Fj>5pwG)^XXFuX*2U=@fM@VPcBuE5h$iw$q z&EOhgPnWv9z4WFm-X*`WN3~v>cx21T6L(aVmHk-d%B0<((i+9x*yW|G^HTWtDPV&_ z%xkuNbVk>VYU(0Nk?(!&xI$7OFXjiBZ7KThT?R(Jaj)xMH&kok6+E5l;UY!D00z`t z6;NKTO}**)q{x|G+S7{2jKG7|pj4+yH={pi;QBcOl`R?p#>lX7tqmnpr>!WS?SKxy z?>Ux5g^RnWWH#flglLYF3>-e4&onw4LbT}~rfLu#ECSLU@dAsprlqGPWIK6Kzfafj z(%;NiUF&zzsb~0s-JYK2+olX53j1bi|3@=6J2ACwx$H>La8%C54me_kyR;uy6%MIl zf;)854(V$K7WHUMHmjvMb`Adr^ zql%ZT?80J_a^?h&_=IBaXK*p83Jv`v{8{ymnZRgcdIJj~@d@}z^Z}dr_`^>lA4eQN zn@BDlK8n(;%K3?N@V6}JnzsG=GbiJ?_0jk+ zwtjALH9E99WRs4qt(`hCKWDp{Go35kAOyOPq#pWPTNVc;+w-(fU)b~@@Zi5)f2 zaFHM3C*j=m-BZd?pc%3MRXFS@7oOjU-I75psrBx0o+zfxv6_#eWT~Qw+)8`2OJ4qj zjFJAR$uni~2?os!5kIl?yk(HAriIC&;ET;#$PJlj42DiCg^<_mK{9`|j>8Ia`u z2<&qthU~XK)vUqpGW_|EAH%X z%{r zb(L>*+Th!tF`3obhIX%_j^+lt)ePglD125~IS>enj1(rwA1&-%0JkV4-moMFc!35j zEC}L)5rwe8{CgJ-8l8d^9F3>wLi761!26`?;HSf~%Hw$hzi+U++yT5iD{eHZT-6M!ziTV*|X&c(n2KtD+Iar7Ya|gSdZ_^liR~V zQBKx8+q(CkI`=llVw8Z}b-#5v*AxR^53fI?oZsLdHbY64@}&}O!l_cK*yl8jQ)2x7 zZo(VW%zs5<)Leb*lKN_~Tp@JHAl*R9`={G=o&K2jC)e`^ZabcxQ1A<4xOyf|W86iy zEhqJ^b6Vz$h;-#&L_$$qm`<%L+vZ{b^HTp+;NHdJdAgcDLG}9^_&~_?_sx2MfVkiMOu zebx|upZf)?vWmS^sML9VuhHQBR4p_7mixo9Rov+6uh+oWo4ow(7qIEY*7*4rm3Kmu zHRqGz*Y_Sf@i$k~3N6+b&iKDlbnFg%L*u$Yd|w6bDWsw5_jCN(TlD{n_=y3~OtNn1 zJA5N}5^o30MbBKV^@rPzmlORyPQcAJe=BQ-KHgjoGx0FF0xq%k9K0gp<&UC zP$DDhD4ZtSfpXYnV?qSgB{9nDw5gx;d8?20tnF6+b|etx^MGC3_1q$aj2;!?0U^3S z2#JsJcb?19Ty1o+^@UkiXDn*doSxfiLR?kM^S;2#VsH`yQ>xX;a)VnC|LuxXXn@-M zf7#3uE=ax;!MQiM`TTI^CMxW8IY?6>lgc<(qCz9VA4Cy~N^;6e%v)Gdzci#5y8rX( zW_h`+vi-1C8WewYUQepA^xkd7(C>aahp6l7aCZ1<6f@l5Ay^eb=Fe7W+?=*Gg9O2q z7>7+PG2d|jJn^RixXSrNx_nO0D~kuf{IJ}9*qnryQx5S}MComsFw z3LXP_D9{|~0&d=k^)5Vq;=hvu4MZsnDcIq9>Yi*qQX(FlXKPv~o=57IqG_Z03d z+ZG!~%Csi66&?=q&PHP?}a;OaUAAVEzxq+(wNSgd>O zzsEHL?9r9aXi^yOGRzuyi)OUyc~r6bk`B`fBpYPCVcoYSytvu*&j~pgQaPRdzdAK<_5^jydw03nDr5u>xHQYQoH@fkn4P4rkwt~hv{>3(heZL?@dnov4$J32Y14`t)tY45_fxfF zWECdRr`SC~mW@=98lP>>#!~i+wH_I;Ds6mN#L$YMKBUM7+#hWMgI%baSAJ%5KuJDacROI%f$nqKE-p5-j zG;m@RgT#>$+dCw@HItQhCmxii3>4a-42w_O8%(-5*Nrb*;{+mW2RlG?V78-GCO|hv zmkjNNe4oEn6_nH`lUYTJ-%`GqB8_7et}79Rw<%l_$7x-JrEtDjIT~;6IM75DI}$3= zwi4v(BZ(WE?V=Qh{xwvQOpsTX0H*Inf#-zn_M3Qd7Q5;|%1swM$pU#K{T55?9pN^a z$^z~gY2Lx_AF+0qeE1SJHjl467vsA}SYX=aY3-Zn+--fojBg~c&g zC%0FtOE-R&RHt+oYERX3)tX-VbXn2ye1B>mS8d(OKajWXX*GQ{7MO6iXH~Qcv)S^c^aSd#Q~%`48@eM|VlAKWXknlaZ+J zIYU*9eS6qG0vP2oOt5^106RCw`!YN}S47ff(KOY?M2Nx=-agSqvQ>A^QLBY&GE8>q zV!NNG+XmwJ-uee6Z11W&&QZR5MkHgiMQ^Ne+fAl@yW=gajET`MN+< zBaF9D-K&<5C=zQ0Wf(yV>QF^7aeRrzyD8u>dlvdBO5RRg5*Aa)f(sPaYt15FTb zs*YU~{efT&BGfDR5)34pK-*dR@_EwXf5>Ya6sF4x5e#Sg2gMFV1a~s{ze$q+gK7g@ z(B$(`bc$PmuU|iYkA~J%s6dk-`R`#YG5!PW+lWbjUzZL=7RL{uyo2d*N{oMCDhhyk zqm9s1?f)=fJ}Oka^}REB`2SxY{Q&_c1cm)*mM)y;0AGomv`s9$@IC?^*j3a<=@Ayi z#E;O$jV?3W&Y_y4FKp0^qZg8^!uHVg4)%wZ-hL2Mn2>!|5~R z^I5dIzmQ3DN2YBu0rJ;gy@_F4-y+E9Q5ygd$*3=gcx&PlwU2?!41xxI|wa~b>K($8@%nw>3f}X<} zePF7}0d|eUxi2#06KySvy||ebtu=3kFrcS&Qhp}$Xo*3ZRGQ#;388%+GF*<#=IY8i z2mils=J@Fk;OT><0urf!ZP8oOxz+sJmgc|s-x3$xA>iyjH2C)t915g^+sAo-8S<)e zelxc zCvPiIq{To0j9T-S><#p~k2!~N$YM7VQtbb6M*`puIv4Az|Jfe~a0jL09P9s5N&|>C zrvf|VdM%jx)wyGX7Yxb&V-PaHAh=d@q#|U1;}t&@oRS|fxO|Kkl(tAf1_h-5=aD(U z$2c!WD z2Mt;X=Khv*+1IPKq8@`$OBiryLOqzQ?BDwTor9!Oz#62!SC}LGJD3=OgK1BAl)%IS z#`k6QIF!Wsv%E#8GC1!l1w%~oT}9InT#z8`f3eu|Uo66R40=@BExR#-T?PyAD;eR`@at8tjxzY$(@t?yJ0RLyOZE1O~ zoo|}mu35W|^O-q~s>MC_lZ*l=$p%QuQ4TtR4EuIwukC2zUW$m#`K8j6vzz77)5ag4 zPy|A>O{KP;Qw=zHt|q1wwC$Rf`u{B3n~n3C*I)FR{TUoPB`p4l%IL~1QGYauEzWd*@M&yYpze?bdt+I7#WIr9v4j-qRkL+dD zMug(7D%<+S9Yu3y@IAY`gLjjX$N5xSN`?4`=ZO3Ep@n$Geo>;3PC}X{{b?W$feiROc&FkK> z)*8ax@?clnPn@~9PMw){(ptN?;*_c9AQZrbpt9y>&?VA#qs@vk(Kj48vRuy)6heo9 zbo<+o!`)$X&9lLX&mXrjwChhnDq{X%(9W_wQe&2zK2&7w7z@wc4s^=ze5~voU+uKN z$L%dz`(tKBIr@SW6^5I8S1IORkOt)a^E>i+qK`nE{;NG|jJH-X7B``Q`m7)ohgZ3k z5`>|E#Iiv(?lur`bk^ZV-E_&bGr+#?XK=2mp_%6(Jo>RL4PaVEoR9mQdbyVr!%cZIw&SwIox_r<}vA`#slgH0k@e7$*GcF@3%p z1=x(epuHcl(%T*jhGx@+>3nzj_?s?sV_HbmD>>?5TX}nr`hCx32b3Hp@MzwY2x`;H zFzBnv^4n}{W~uw@gVqw*Q`blv!zb9+M%WaoXH*Li6 zryEwU-Q;eV5Cp7fUleZ2ww@q?s;&szhY+l?PrTgpoU^J%9 zxs-wHzuQQLOW+;Pc|EgXdKFDvDz4y!Soy8?4xcZTwXbS3$!m2)89!3VpG}l4<{vX^&eY*OVxKBQI>?CpUd-LgE$sQ z5TxUn2UT?iJbx}a_G1fox~*wRf{os%uxqqxg*8o8aK&M)U20pa!D!LrHi$xY&x79h zkYibI$i}7RR*j9iISUS?x$J`7<SI?{bjM%T2@ATPg0(VR5+3O!m)X?HUBjG9mA1A6sXXVPlhz zKs=Ywx6!x)513j`*H7qHW(>H{H^>SpOgFz0X1d)7f;zQ7S%)N3vN_sovxF?7^yYUd zpm__c;PH|XCJam9{96X0aDF z@Gd(ge4eP4-T6pife&?~i_u&llwpz_Vu|%}BhsZq85w$KH`*NE1`XO|$SFnNbI&j0 zfnsIErFCcV;egP`_fo2BdADpSr7&vqlkta8n#OAT)V}(HjdtUzn|s<&np>Y|4?}Rx z-z`JRk~4OO1BS{QU4x39(*vLomgv4kiS9(^#A=!HW`4{>gJyWeAt`9m`!59z&WBVq%Hg_B-z|`9 z;b6Eb%&%uh)%EH^Fpc};i zxMDpn`mA5Qv;Suqxv$GmEe*k9eq9FML{M|$8V0m>ENw7Q=3U8Px=E|%_00gvw0`KL zA!Lr-@)e6jQiEwi|3SGj;SHdOs%uNZK9)gO#&Am6yTAyn$Ko{Y>AVoM{lnos{s8WS zQ=BdM_i~32faUGim6M@j0RKGlLE2$L$nb2!#ZnOX>OdSYZQuZVs?~fhV2Si1Y>|`* z!u$r+VzOA_Fx@}JF40Y&VLY!s5%MmS+b$oT&g)$RD=I@h<@PHbVBd$!-PG{!T&Ol1 zW-zZmuEAc(mpO{@zfyO@-cfoJZ%teWVg6sMRt`AII9TJ`|6URU$azoch``AOB%5x; z0nT5n?pJr~I4wm5g3iZb{7yv-!p->xxdR%eP=WJkW-yAKw+`qx+Ds)hkSR+B>H?BV z@+kfP0k?9NFa*K(2Nd}YlAEgL3_zP_i%+3P24hD4$+vZJN+y$`E=lo!czPBMz|4fg z(F8&NtdoxbSSRBrnbtqZno9CoZH|GO&F~jZI(zrZ*eT#wu1n$_nbP; zlieEPO91_58OwVaMll^q>^V@s=6OWTqU(FNYfap{Gnkk;aG!3T?dWp`@JjUnk+fhG z$)N7^67L)*)F#Gqn&dk5n}ZfCSF$NZPlg5y4e-X%-#iaXZn}|}7PPG^W<@;#+FSu^ zHT8HKpq}l>FAy-PHA7L}AAgTztPyzJM6Kpid2bFM(7KR6z|O-#D-|p#2D&<$ABO;F zL&B!b^Sbo++6N|aIM6e|^3)?SHj)lOW;OcI1`_2WbXm=^FgRgB-hcBJcT;i4T;&W2 z*(~C|xh`390FC7>9|N+-*ykg9i5r@4&dQfY1-kZwZxdE9|5yNq*g2L_u%d+d?EHz4 zlTnSL86aJbdoUG#0+PqbtDxXC!Yom`BZ7xfbZ!KY#dfK>;P6-ZWpF4>xQz-)uts6H z7Fa@J9Xnrz658*{9~({ewwV#=?;Sd!>bD~3KF2y-^x`T6%Z?&k-0kP^fT@oD?q%A` z%daIJFf;|wyyUko1AF$!oW>-C3IH&oj)PF`-G1eR#hi{k-_de|{iXgF7>fSdrpL?S z6Tg=S1DLkp-{fMRNMyEVO!0CV;kvBW?HIggpjJQ=s0Va|rD3Ly<972prB7eBqdDs} z^gVj#be%@aQAEI*={Dd({4m|4^Y}D2%Y?S8DVZC97heYC5F0|9ssN+|u|?ne1Da)k zhPLSmL+_)XYJewp@3d>&gll&k9*Pd=sH|VIIyEIq_9hN} z)r}6|M)tD3PCuw&SQ<2}x@N{xLc>K*XhxcTb=XTcU&?uT+!x1FKJ6pT%u?GWpNA2E zK4yPBGI+77Y`e*z!)=&V*IAra5U?Ft@u=dK_(1=KdH4NqZp}U+?W->Hdal>A z8q0|a{EPHWHFqRh7azV`%wF9dRd#&l1-*yse*+am%(wK}?bJr;Yh7drouh-v zX^OHo;O!`+i5k)UrPIlP40oB*(eBQzM_M?`iok-|=h;h<)jRB%pK3g9&5u2%G~pz+W7}{5K26 z94?2dw>&un(c||NTNy9V`XwMY^A1&6v6Ye!S>! zk&+nC=3A|gt~Tx;6NU^#&bxLa(BKhHNkw%%2%LAm{Wh}l&@b>jDMxyK{K}wj{~E8y z;-$!Tno*KiEJ)S2LSkyIA{6LACFWg-0c1mCI21=#h}f{2VFvTBsBnpH{9jSVkAE-h zUaWp_-0ZNFe7+o@_(5Xy?F#2faBBL8P0de6Q3%4qhaP|x)n;G^6#;q=`}oSQxK~;2 z2$b9w%5(BFk&dmCBj%NOr|Ktio)Ef81v-#;ta+ESwbdA&Q?7@NK-8$gH&SdrJ6@j7 zPTd9^N(xfIFfxX21FnD~=edvNANHO^Clz^3g=7YkRFF*`B&U0q7dhsK4oHcI8*vTcw z@!r;&5gyy;1>@Az&Fe3F3^Sx0Jsi-~s#hQyFmsZ>`<<@@6q`;l@HF4;%Jz4(_O0s}uPY$he+wI7X;s#H7;Wuh@uIx@-g;PCmc{7_ zY;;^Wq3c?6;Cv@h!POeld-St+M_Rxg5|p4d-g}gP0#MeB?~sJHd+(n?Z5Yys9NkSp z{s^SuuDMVnrTjp6AMab zscxBb4L{tyc|(l$It##^CM3x!5nbnU)deHR-~$?<7K6CdO4odCSOLqVV(VJ|S|(&Q ziyB_2D6EcIs5X|+C@Iouu#?k6%VvvW@rMF?E7T{=N!af?jxBwA_STw7qTCA1SKJRUAo22?nwX&sa$;~(P+`?h#6Ce1W@XCs7gD3v z<(G$!7pJvTK>4?Q9#K|+hr`riX&Q8v!ytWNJSis6AfyR*1Q6;!XewF8lK=v5kZLj?fmA+ zmSs&0LO7V@=qDhOwNj{by9McU<2q;B);ltZf>N%ho}V6gSdeb|>(E#dL&b2kdZ-+P z9NgPhB;4HrDb{T~Z%D>bSVa?T+8Rm(4oh?@NLB}rr`xyRWx2gmVusu4-lo2aYLF@X z^kNL%?N$Ru2*s?=uE^SGIm=+~YJ9q}Qk&WGiCV7=XmEE7)E6Wt?OzBU)B?c@L3<)m zNr*Eg$YsdL+YSQmU?$*7HV5s-KWST*?dreKw+bi3Ft!}m6!s@-Me?Erqwe3=sYoWl zzz#(3i+n~SHMDwh8^9*t2}V7Lw~f5*uPZOuicS#RAsm!*k3`Eji~Yo$r|tJXy~#w0 zsk#Tlj$D{4y|0;pnBfv;J|}W8St^Xim*jr;0aJl@Goi$r0@%h7u@*H3rOssivK@~^ zZXDfqzyfg4YEfJY_I=v4B5}VbA2-IhBippN6USlevzJTdEj`{}K9R5`gTQtoDaSM+%k9`IY?#$;W zeMRBMF7Y&6==?s0@vDkP0mu*R`R;EVwi!==evUn;EiK7wAUtYQYiNy@=%0H#=+p^& z*3{^sm980QsGFeMgz&Yn?_8QLIGFv)>)F&^u9i+IALX4%qx<`2Icg5isJm>tU~!$5kn48P9@}-wFfAtlz7s-sbo{-`RDGs#Rua zzw<1U%1&CR&!n%+1;1j+&f=0Ak*=?w_SF-@C4$N4bY@xnJA1;-p6=75iSWa#%F$KA z0`r;cra*Dd;>1v}0;P87M-^7wEDk_bGNnqck&3q-ZWIIevd`;ocmFc!O<8J@{*d++ zGbm83JoqcB2@;^e9Wica_|%%<7u7g^5{AWY%piP=Kd+kg9jidw5@w;MSKp#OeRhU? zMn?{u|7f;oGK~1q6fk*;W8^Vny;oI3f=}-2#EA~icUOjvKfaK@5*SH8$lfxa%1)_8#R zgGm7V@bgN?(}}$+fcQ8(TvZvrqltc$Y7maZ=l5_@-6_w2$d&BbwAT|yN|d;0rB z3l{dX^x)7=P&bYe$r}SsT_f*vRDs70Y8xU&C6`D^`{z4R9WJYQaXH(8sYJSAej=l; z^@aAX3}%i|%J_u*r1_oN4b=2vSJ|!~)Pr2NIeAv7d2wN^ooME_roltsTv-jf zVH)a+|NbP3!9Ws$5Yg=`v~TWqIlZFfB2;~G^DM^@9?CYmlW%T_>>+2ZwN~h9?r13e zM@mScoxq7?ZG)bd?V`p2-3FU;bTkUiBF{fl@VyMu@D|2aia>e)xp50Gjt;>~6_d`+ zeP36GB0N%x-bD+Wa!0)SQlb9x$%Mj$X+$IIXUBP502505m(^e787{ zTDXJ9gea^(^6Y_MO?`AkF^?Qez^Z@`&m?BWS{5v_5kUuW(At^lf;7(-bH3;vx{Ih2 zNmc_RP|XhXVzQ4OUG5N@!EFMFn4Og!X1gg^F-F&?!d5=Th-Hks2P?|l!vsJLZrmtw zAFRh!AzQVI5xPJJczDShhgz92Udn`^jnX1sE9Gi@KDL85+NeDN97&FOMBmrN&vgTf zcF!+A0MSYKoIZ)2lk&DixV1pO2qA&)+C)l!6AenAgNXcm-0yihSRuUvlenCx>E^`R zb;Z$4jTl|?2tAN&q+*kCQxP6?2;kB(UmNzrQ31S45FyR*`<5VC?$dZg+ub?cL5+=k zl2Z9(a*bBSOC&DMuP@V8J|IG9s>tlY1E4|JC+BkSk`R(gIc;w!&Tpf^U*}B91k&u$!wbbn8+AmT0^{V0;!aM z<+_enhxQf;U%YcA62$TL^(JI7k<In?*a_oP$7lMRFZZ~Bwl&#go|BSn>Cy&9Z;nY6(OZBvi~FBy|;Lg3*nFT$4L zCi|A-mfYFTY5Bg*_X{8VnDm{Hhjb!zeTwn7s7GWejDDH>W9Ix77~h$p{4N4aClu2O zsth>=>n{Ja+-|if?Ij~L$4*6xr#4O8F-C)2FU}Inu-K<3J?J7)pNYagp2@z`TsFgn zimu|uOOeU$L88I(9ilDj(U0l_8t*#&97$GAuie1nxi=tywOIUVX{Khvu49RlQ- zlHUa(BhvsfSgmNeK3f;S78y)HbGJcDzy0ztr46p_&RnRRuHxsE&HaxZS}8A4s?V;+ zzY|i2zD)qsf2T(4I5s(D>*D}LY-9iR$?|+fW4Ve#Lsm2GR&k2sfT{y6J5f!dLkbn-iLWhW5qU zo@k`TNhe}#{43AFaLm=~aaGuhSxTJQTBQ)yqZWEX#TT3e@85Z$M3Z2&w~NcKBblx+ zg9$cbX0&-cpagb4eg9*z{BkOt4+C*MD2qQp>DziRNAf@;vZsVPdM%+DZ_C&kb*)wW zZp(AgL{VCJv8=o%!jPmqyrxi=GPFXN3qi}~H4R*5^ec8Em}`9ACa4V)Lzm~pOMUjZ zG-*gCjS)|P->lne9wh(g>R=<04?)bfko5pb4>Leztl0AlX_0@l9GHkb!0)lC*jQ?WlRty zwUwhNx0M8qH|i^6$*Ui4phedtTp9?6Y;~!-Sk5@k4rUKNt4bf4&P^2zqx;>IkdL0a zKcvpoIu5LhvQH4w8{I=HkB5lkox|_bEJNMJN)@#L%mYglukkRP239dY@Om(kb#NIZ z360ksjtj%!|JsbEwU`(H$u;;U7LEes4fip$w54Rg=-zL>~`JHm39)hKm3efMB zp}LSVu3M}vhSahnq7~=>o9A=8p^>|-x6g65-NWu>K|dFbe~YvoA5iF|_SM;(_hT|a zc-})rQMG_-$JKIz7xT)Bjz&K7 z8GaG|wOe}qlM-{W_bQOHCqXo!Vh>SH3NbU!T+A}Dye09m?=$b@yZSsw2j0a_QSgT< zVfi`>gH;16U~x|GFyWGm>L5QESv3eS+ga^Oj{W~NpHDW1B@F1kO6 ztqAVRn(C`aM6o?(e*N7}Ad}9djOePTPuL9$QzS{Fpd=HonW7z)M0w-)BTQgEt`4QE zrU%v$Tu!WYC@NR{ZKSzl+$5AJaJijy9c;dO*;=Af)QnlI=_XDcmJN*^$GjsGRG3n@ z)Loa0JJ|-vTK=*soN6Z7)Gp9c8DAo#QwHRFON8x}qRFD4L@g6%)XmE92kl$`XqK%5 zP(u&;y;lX9dd(y^X6obHfh0*38FVbpO*TT`KDz7Pdml!q<(}4kDKK$7=G^1(Hy5NP z<*HyrIU9gCbMK^gtMVgcN;mpY$M!8k1<4bAl@1I@b!;vwVtceq_@#)^MBFTL6oWzZ z?n0Civ)aj=L#J1o0Uh^}-44Gn9OGz@&M zGpHM1QL(svBEyX&91$7nT*Oy_2KOI~18~r19rhfS35zK@>Xb~i9`djyE_8xosH4Ao zvApe9o9l+jqs!Gw8V0g+x?{dqNzExQo{Fi4oUoL;akyoFRO@}b`Q+!zK&Ja0%Vv2~ zKjOP$Na6&z;d`iCqCfC*)@Eaob6w1N?& zz0TSimX$kGwf}&sV)~`{-TC6{K3?N2{!v*_!s3uRkp1XATNCTm9fSb+ju%=|*?d^) zx)A_Rz|omuqpkhgMq|9dNGH}LF4@AQbTIyL9H)>syL}spq zr|Jx7#VK}?V>ykX+2VJ03GAqu>&MAr_SiSpE~0+k9(@Dnr9dq5@dUpIns2&-1)!F0 zR+k+NeX=eygp^2uRl#Mc7^cxy}$EY=EBzn>?3_(GTMV5gA8|9rP7CUwWr2|i^g86y+ z+|Oae0S#*`Kl0b)dDK=o!%4g~A8yYKF504f-(FjAbEbSyps#>y>m^r^{+ukAq9Mxt z+9=ty&boh3c5h~mtUN6f%k9&yn~|hK2uc*0K?M1S3WTz8$Xd<%GG3q!WH=Mdfo>Vs0(iV-Hzof%}^p|s#pK9W|T+=`+k_( zTtoOj4r|cj$2ou5g{Lt=OmhWX08REMV7Ddii3{Bl52$@Od{oYQY#MPWkG#-e(ha@PU_8j-mf6R($QPUHn%8U@Q^=*Kui;B13!W*CMV7*xqtH>s8{Y&^No!Nob}?4>U$2Bn~zI|3UkF| z6jrugM#O6-T#H{$0rIysaOp+pNw`Z0&3H;@?s_Kcv1U+f61|C|rq0^tTH*^Zj_CU| zA|4Z^n*xa3T*98ucl&w)!Q~wF%QgVUwfi3DeyPko0noVW*I43q0F9d@3NfS?p9ckK zqy3)f0>%opJuPnZhoFf8?YVF7xt#sxOy6zQW$@G(8A*A>6Nye7r!w(X_^q`7uE*$r zs(cFdcxvzVBIQoA`MjF7djOd`;UW7*TyGAz7Btfi=)za(`qF~-mh&nMm%FP#3fF1I zo?=7O3i~%##vK7lll@zGl%K$zBp$ITY*9m7;8Ku69dId;ps4&9(6UMrm7v8!1+!lR z=G*%c8nQS<7{;a@3_#kOJ}$2vt6?4EqQGV$gF(=I3-_)H=+Qr{8E-4I8X;_<5BvZQ zKGPRrQahMzzxJv<&lx300n3!|Zl>T~EEu5d{ZxtZ1a@k)4dJ;#?3hVS? ze#6LyN^q{nYieM_eb)&BMgnH4)lXh|m@wO`-;?z~G%VS*oS3zoHkUD=3H26(@w{K2 zZf^iNv3V*O=qL(Z4yJn1y|c#4B}ojKAV1c+Bhq@0E{y=XkzTvVWQ-WvWsLXRXP45~ zOMi0t4gXgF!vj40$tIgPqUCGll~=AA&-dPY&-Kk0TZ24_@3PA-w(!CW*W7>II;gYW z>Nf5K9^B|QDRND~i1Y{{V3Q}CwQg-T&pfFB+I*d|Ni@p7m=C}ND~6DzWS<7oH(&8d2%`p;oWlN+pb+ZTW6hh(ljK=l5qqY!6rqn z5gH-ny4G52*`0UZX?O#^-F4SpM(s^zW+K-J0asT-KnMtdlp-K|NGznjPGP{vWfn)&ptB}LOONoWcS{C zuS+oD9LqxwJ=9J-@kAGD=3ruucIw`}yDhcUQV~k6t`b2&nWu@s9Qi|}x5y#QONS!Y z2sIssT#rBgc$+qDn%hjz8rI7%zicb6xT4$i-@0{cx6z*V)KgCx=UTq-!V9+Prkgrq z-C~O^B9vBLC5pg|8D<-A9BYl?M8}hthe>aF(RAeF6uCwSDIs4@DY@sKdu;vn*Kg|i z?z``{tFF4rt+`H`G|6_~eRp>P2#xS?pFVxu2Ky_oymA(42phlj(o444W}7J-9HE}- z*44CWX6!GWYp%M9pa)lhfb>=cXu3t@8leqPH??EOj;^k2w{G2K9>FZa3Up0k~H+R2>=LU}Ou9#Tn%byf+rIw#YrFmS+imT&*OuoRv7XeO5D)@FAWj5Ct`Vb)*V(skUl;E64X>27 z);Z>w!&R^8+_`hp{~+93Zn?$%k25)k4IAeE$2C;cS#ZGxOYWVGSZsBd1OiV!NlLic z*=Hy5G(96K1f;j9kjzy-BG;JIO*Nb8)2G{f^UY^VEV0BaPa%B#%{Sjzt5&UM`yb(8 z+Tx2Z9+PD1wr&V0^R#Zz*YsfNttR;Ldb7wiubS7m>x011p=P~$)#urIYV`<6Z`EU$ q(>q13IaR!dEd+#s5D)_KA@KiAxVPvDqR{>T0000 Date: Thu, 11 Apr 2019 02:35:10 +0200 Subject: [PATCH 027/512] Update the main Cargo.lock file --- Cargo.lock | 283 ++++++++++++++++++++++++++++------------------------- 1 file changed, 147 insertions(+), 136 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 408251216..a5818cb65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,8 +1,6 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. [[package]] name = "aho-corasick" -version = "0.6.10" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -13,7 +11,7 @@ name = "ansi_term" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -34,9 +32,9 @@ name = "atty" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -46,15 +44,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -62,8 +60,8 @@ name = "backtrace-sys" version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -82,7 +80,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -91,18 +89,18 @@ version = "0.47.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cexpr 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "clang-sys 0.26.4 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -128,15 +126,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cc" -version = "1.0.31" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cexpr" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "nom 4.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -150,20 +148,20 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "clap" -version = "2.32.0" +version = "2.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -178,10 +176,10 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.35" +version = "0.1.38" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -192,6 +190,17 @@ dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "core_affinity" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cranelift-bforest" version = "0.29.0" @@ -307,7 +316,7 @@ dependencies = [ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -317,8 +326,8 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -327,7 +336,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -357,7 +366,7 @@ name = "failure" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -367,8 +376,8 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -435,7 +444,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -467,7 +476,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.50" +version = "0.2.51" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -475,8 +484,8 @@ name = "libloading" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -506,7 +515,7 @@ version = "0.1.0" dependencies = [ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -516,7 +525,7 @@ dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module-data 0.1.0", "lucet-runtime-internals 0.1.0", "lucet-runtime-tests 0.1.0", @@ -531,10 +540,10 @@ version = "0.1.0" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module-data 0.1.0", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -548,7 +557,7 @@ dependencies = [ name = "lucet-runtime-tests" version = "0.1.0" dependencies = [ - "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-runtime-internals 0.1.0", @@ -561,12 +570,12 @@ dependencies = [ name = "lucet-spectest" version = "0.1.0" dependencies = [ - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-runtime 0.1.0", "lucetc 0.1.0", "parity-wasm 0.35.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -578,10 +587,10 @@ version = "0.1.0" dependencies = [ "bindgen 0.47.3 (registry+https://github.com/rust-lang/crates.io-index)", "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-runtime 0.1.0", "lucet-runtime-internals 0.1.0", "lucet-wasi-sdk 0.1.0", @@ -595,9 +604,9 @@ dependencies = [ name = "lucet-wasi-fuzz" version = "0.1.0" dependencies = [ - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-runtime 0.1.0", "lucet-wasi 0.1.0", "lucet-wasi-sdk 0.1.0", @@ -625,7 +634,7 @@ version = "0.1.0" dependencies = [ "bimap 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-codegen 0.29.0", "cranelift-faerie 0.29.0", "cranelift-frontend 0.29.0", @@ -640,7 +649,7 @@ dependencies = [ "lucet-wasi-sdk 0.1.0", "parity-wasm 0.35.7 (registry+https://github.com/rust-lang/crates.io-index)", "pwasm-validation 0.1.0", - "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -669,9 +678,9 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -682,7 +691,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "nom" -version = "4.2.2" +version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -705,8 +714,8 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -736,7 +745,7 @@ name = "num_cpus" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -767,8 +776,8 @@ name = "precision" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -810,7 +819,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "quote" -version = "0.6.11" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", @@ -822,7 +831,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -831,7 +840,7 @@ dependencies = [ "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -877,9 +886,9 @@ name = "rand_jitter" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -889,10 +898,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -918,7 +927,7 @@ version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -939,7 +948,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -953,7 +962,7 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.1.51" +version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -961,24 +970,24 @@ name = "redox_termios" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex" -version = "1.1.2" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -989,7 +998,7 @@ name = "remove_dir_all" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1030,8 +1039,8 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1049,20 +1058,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.89" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.89" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1072,7 +1081,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1080,18 +1089,19 @@ name = "sightglass" version = "0.1.0" dependencies = [ "bencher 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "core_affinity 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", "hwloc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "precision 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "printtable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1105,12 +1115,12 @@ name = "string-interner" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "strsim" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1118,7 +1128,7 @@ name = "structopt" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "structopt-derive 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1129,17 +1139,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" -version = "0.15.29" +version = "0.15.30" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1149,8 +1159,8 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1180,11 +1190,11 @@ version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1200,8 +1210,8 @@ name = "terminal_size" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1209,14 +1219,14 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "textwrap" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1232,10 +1242,10 @@ dependencies = [ [[package]] name = "toml" -version = "0.4.10" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1283,8 +1293,8 @@ name = "wabt" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1294,8 +1304,8 @@ name = "wabt-sys" version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", - "cmake 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1304,20 +1314,20 @@ name = "wait-timeout" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmonkey" version = "0.1.4" dependencies = [ - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.35.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1329,7 +1339,7 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1339,7 +1349,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1361,7 +1371,7 @@ name = "winapi-util" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1374,7 +1384,7 @@ name = "wincolor" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1384,13 +1394,13 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5" +"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" "checksum assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7deb0a829ca7bcfaf5da70b073a8d128619259a7be8216a355e23f00763059e5" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" -"checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4" +"checksum backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f106c02a3604afcdc0df5d36cc47b44b55917dbaf3d808f71c163a0ddba64637" "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" "checksum bencher 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdb4953a096c551ce9ace855a604d702e6e62d77fac690575ae347571717f5" "checksum bimap 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6b282b982237078bfac61a948a2198f185aceea8b9a6e794b70b96fd31923d3d" @@ -1400,14 +1410,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" -"checksum cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ce8bb087aacff865633f0bd5aeaed910fe2fe55b55f4739527f2e023a2e53d" -"checksum cexpr 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "644d693ecfa91955ed32dcc7eda4914e1be97a641fb6f0645a37348e20b230da" +"checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83" +"checksum cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7fa24eb00d5ffab90eaeaf1092ac85c04c64aaf358ea6f84505b8116d24c6af" "checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" "checksum clang-sys 0.26.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ef0c1bcf2e99c649104bd7a7012d8f8802684400e03db0ec0af48583c6fa0e4" -"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" +"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum cmake 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "6ec65ee4f9c9d16f335091d23693457ed4928657ba4982289d7fafee03bc614a" +"checksum cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "96210eec534fc3fbfc0452a63769424eaa80205fda6cea98e5b61cb3d97bcec8" "checksum colored 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e9a455e156a4271e12fd0246238c380b1e223e3736663c7a18ed8b6362028a9" +"checksum core_affinity 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6d162c6e463c31dbf78fefa99d042156c1c74d404e299cfe3df2923cb857595b" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" @@ -1431,7 +1442,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" -"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1" +"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917" "checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" @@ -1439,7 +1450,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum memory_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" "checksum nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46f0f3210768d796e8fa79ec70ee6af172dacbe7147f5e69be5240a47778302b" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" -"checksum nom 4.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22293d25d3f33a8567cc8a1dc20f40c7eeb761ce83d0fcca059858580790cac3" +"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" "checksum num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d9fe8fcafd1b86a37ce8a1cfa15ae504817e0c8c2e7ad42767371461ac1d316d" "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" @@ -1455,7 +1466,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" "checksum progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b820305721858696053a7fd0215cfeeee16ecaaf96b7a209945428e02f1c44" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" -"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" +"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" @@ -1470,10 +1481,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473" "checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" +"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53ee8cfdddb2e0291adfb9f13d31d3bbe0a03c9a402c01b1e24188d86c35b24f" -"checksum regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2f35eedad5295fdf00a63d7d4b238135723f92b434ec06774dad15c7ab0861" +"checksum regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "559008764a17de49a3146b234641644ed37d118d1ef641a0bb573d146edc6ce0" +"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" "checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" @@ -1483,15 +1494,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum scroll_derive 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1aa96c45e7f5a91cb7fabe7b279f02fea7126239fc40b732316e8b6a2d0fcb" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "92514fb95f900c9b5126e32d020f5c6d40564c27a5ea6d1d7d9f157a96623560" -"checksum serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6eabf4b5914e88e24eea240bb7c9f9a2cbc1bbbe8d961d381975ec3c6b806c" +"checksum serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "aa5f7c20820475babd2c077c3ab5f8c77a31c15e16ea38687b4c02d3e48680f4" +"checksum serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "58fc82bec244f168b23d1963b45c8bf5726e9a15a9d146a067f9081aeed2de79" "checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" "checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" "checksum string-interner 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "abb38a0d8fe673c40b10b6b75abcb076a958cc10fb894f14993d9737c4c87000" -"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" +"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3d0760c312538987d363c36c42339b55f5ee176ea8808bbe4543d484a291c8d1" "checksum structopt-derive 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "528aeb7351d042e6ffbc2a6fb76a86f9b622fdf7c25932798e7a82cb03bc94c6" -"checksum syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1825685f977249735d510a242a6727b46efe914bb67e38d30c071b1b72b1d5c2" +"checksum syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)" = "66c8865bf5a7cbb662d8b011950060b3c8743dca141b054bf7195b20d314d8e2" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" "checksum target-lexicon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4af5e2227f0b887d591d3724b796a96eff04226104d872f5b3883fcd427d64b9" "checksum target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6923974ce4eb5bd28814756256d8ab71c28dd6e7483313fe7ab6614306bf633" @@ -1499,9 +1510,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" "checksum terminal_size 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "023345d35850b69849741bd9a5432aa35290e3d8eb76af8717026f270d1cf133" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" +"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" -"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" +"checksum toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87c5890a989fa47ecdc7bcb4c63a77a82c18f306714104b1decfd722db17b39e" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" "checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" @@ -1515,7 +1526,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" From dc3eeb3d765d0aa290e292f19d6f99beddf1e346 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 11 Apr 2019 16:12:57 +0200 Subject: [PATCH 028/512] Old versions of Docker didn't support regexes in filters --- devenv_run.sh | 2 +- devenv_start.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/devenv_run.sh b/devenv_run.sh index 4ea5d79f0..1605a7b96 100755 --- a/devenv_run.sh +++ b/devenv_run.sh @@ -2,7 +2,7 @@ . "$(dirname ${BASH_SOURCE:-$0})/config.inc" -if ! docker ps -f name='^lucet$' | grep -Fq lucet ; then +if ! docker ps -f name='lucet' --format '{{.Names}}' | grep -q '^lucet$' ; then ${HOST_BASE_PREFIX}/devenv_start.sh fi diff --git a/devenv_start.sh b/devenv_start.sh index 423469b33..7b6e93934 100755 --- a/devenv_start.sh +++ b/devenv_start.sh @@ -6,7 +6,7 @@ if ! docker image inspect lucet:latest > /dev/null; then ${HOST_BASE_PREFIX}/devenv_build_container.sh fi -if docker ps -f name='^lucet$' | grep -Fq lucet ; then +if docker ps -f name='lucet' --format '{{.Names}}' | grep -q '^lucet$' ; then echo "container is already running" >&2 exit 1 fi From af93b2f1f44ef1547594711c7707298febda93cc Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 11 Apr 2019 16:13:32 +0200 Subject: [PATCH 029/512] Simplify Travis builds Also, `devenv_run.sh` automatically installing dependencies is the expected behavior. So, use Travis to verify that this is the case by the way. --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7d8d027e1..7955ca525 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,10 +6,6 @@ env: services: - docker -before_install: - - ./devenv_build_container.sh - - ./devenv_start.sh - script: - ./devenv_run.sh make indent-check test audit - git diff --exit-code From 872e73e9d49e14741f77d31f2c5159899c6c2394 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 11 Apr 2019 16:19:15 +0200 Subject: [PATCH 030/512] We don't need hwloc any more --- Dockerfile | 1 - README.md | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 291c5570a..e0703ef92 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,6 @@ RUN apt-get update \ curl \ git \ libbsd-dev \ - libhwloc-dev \ doxygen \ python-sphinx \ cmake \ diff --git a/README.md b/README.md index 1514dfd2d..511794bed 100644 --- a/README.md +++ b/README.md @@ -175,8 +175,7 @@ Lucet requires: * [`wasi-sdk`](https://github.com/CraneStation/wasi-sdk), providing a Clang toolchain with wasm-ld, the WASI reference sysroot, and a libc based on WASI syscalls. -* GNU Make, CMake, & various standard Unix utilities for the build system -* `libhwloc`, for sightglass to pin benchmarks to a single core +* GNU Make, CMake, & various standard Unix utilities for the build system. ### Getting started From 7521ba95e8187b4a666a60544887cef89b0ffa5a Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 11 Apr 2019 17:04:09 +0200 Subject: [PATCH 031/512] Replace -W,-export-dynamic with -rdynamic The MacOS linker requires `-export_dynamic` instead of `-export-dynamic`. Due to `-export-dynamic` being in the global `cargo` config, tools from Lucet that could be compiled on macOS cannot be compiled any more. This also prevents RLS from working properly. -rdynamic works everywhere. --- .cargo/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cargo/config b/.cargo/config index d592b9764..52e8b726c 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,2 +1,2 @@ [build] -rustflags = ["-C", "link-args=-Wl,--export-dynamic"] +rustflags = ["-C", "link-args=-rdynamic"] From 76fafb195b0ad57e4c8b8ab730aa0e7f436027f0 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Thu, 11 Apr 2019 16:02:43 -0700 Subject: [PATCH 032/512] [benchmarks] add more benchmarks and some supporting functions --- Cargo.lock | 10 +- Cargo.toml | 2 +- Makefile | 4 +- README.md | 3 + .../Cargo.toml | 4 +- .../benches/benchmarks.rs} | 3 +- .../guests/hello.c | 0 benchmarks/lucet-benchmarks/src/context.rs | 70 +++++++++ benchmarks/lucet-benchmarks/src/lib.rs | 14 ++ .../src/modules.rs | 56 +++++++- .../src/par.rs | 16 ++- .../lib.rs => lucet-benchmarks/src/seq.rs} | 136 ++++++++++++++---- .../src/module/mock.rs | 5 + .../src/region/mmap.rs | 4 + .../lucet-runtime-internals/src/region/mod.rs | 3 + 15 files changed, 289 insertions(+), 41 deletions(-) rename benchmarks/{lucet-microbenchmarks => lucet-benchmarks}/Cargo.toml (89%) rename benchmarks/{lucet-microbenchmarks/benches/microbenchmarks.rs => lucet-benchmarks/benches/benchmarks.rs} (70%) rename benchmarks/{lucet-microbenchmarks => lucet-benchmarks}/guests/hello.c (100%) create mode 100644 benchmarks/lucet-benchmarks/src/context.rs create mode 100644 benchmarks/lucet-benchmarks/src/lib.rs rename benchmarks/{lucet-microbenchmarks => lucet-benchmarks}/src/modules.rs (61%) rename benchmarks/{lucet-microbenchmarks => lucet-benchmarks}/src/par.rs (93%) rename benchmarks/{lucet-microbenchmarks/src/lib.rs => lucet-benchmarks/src/seq.rs} (69%) diff --git a/Cargo.lock b/Cargo.lock index 806f50c09..ed75f8d7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -560,11 +560,7 @@ dependencies = [ ] [[package]] -name = "lucet-idl" -version = "0.1.0" - -[[package]] -name = "lucet-microbenchmarks" +name = "lucet-benchmarks" version = "0.1.0" dependencies = [ "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -579,6 +575,10 @@ dependencies = [ "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lucet-idl" +version = "0.1.0" + [[package]] name = "lucet-module-data" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 72c6a3703..34eed17b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ members = [ "lucet-wasi-sdk", "lucetc", "sightglass", - "benchmarks/lucet-microbenchmarks", + "benchmarks/lucet-benchmarks", ] exclude = ["cranelift"] diff --git a/Makefile b/Makefile index 1fd87305c..4f26c0047 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ test: indent-check -p lucet-idl \ -p lucet-wasi-sdk \ -p lucet-wasi \ - -p lucet-microbenchmarks + -p lucet-benchmarks cargo run -p lucet-wasi-fuzz -- --num-tests=3 .PHONY: fuzz @@ -35,7 +35,7 @@ fuzz: .PHONY: bench bench: - cargo bench -p lucet-microbenchmarks + cargo bench -p lucet-benchmarks make -C benchmarks/shootout clean make -C benchmarks/shootout bench diff --git a/README.md b/README.md index 1514dfd2d..ca5790fca 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,9 @@ Sightglass ships with a set of microbenchmarks called `shootout`. The scripts to build the shootout tests with native and various versions of the Lucet toolchain are in `/benchmarks/shootout`. +Furthermore, there is a suite of benchmarks of various Lucet runtime functions, +such as instance creation and teardown, in `/benchmarks/lucet-benchmarks`. + ## Development Environment ### Operating System diff --git a/benchmarks/lucet-microbenchmarks/Cargo.toml b/benchmarks/lucet-benchmarks/Cargo.toml similarity index 89% rename from benchmarks/lucet-microbenchmarks/Cargo.toml rename to benchmarks/lucet-benchmarks/Cargo.toml index 6fe76a20e..5ec47f3c2 100644 --- a/benchmarks/lucet-microbenchmarks/Cargo.toml +++ b/benchmarks/lucet-benchmarks/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "lucet-microbenchmarks" +name = "lucet-benchmarks" version = "0.1.0" authors = ["Adam C. Foltzer "] edition = "2018" @@ -20,5 +20,5 @@ tempfile = "3.0" bench = false [[bench]] -name = "microbenchmarks" +name = "benchmarks" harness = false diff --git a/benchmarks/lucet-microbenchmarks/benches/microbenchmarks.rs b/benchmarks/lucet-benchmarks/benches/benchmarks.rs similarity index 70% rename from benchmarks/lucet-microbenchmarks/benches/microbenchmarks.rs rename to benchmarks/lucet-benchmarks/benches/benchmarks.rs index 4c9cff4cd..3ff3f6f78 100644 --- a/benchmarks/lucet-microbenchmarks/benches/microbenchmarks.rs +++ b/benchmarks/lucet-benchmarks/benches/benchmarks.rs @@ -1,10 +1,11 @@ use criterion::Criterion; -use lucet_microbenchmarks::{par_benches, seq_benches}; +use lucet_benchmarks::{context_benches, par_benches, seq_benches}; use lucet_runtime::MmapRegion; fn main() { let mut c = Criterion::default().configure_from_args(); + context_benches(&mut c); seq_benches::(&mut c); par_benches::(&mut c); diff --git a/benchmarks/lucet-microbenchmarks/guests/hello.c b/benchmarks/lucet-benchmarks/guests/hello.c similarity index 100% rename from benchmarks/lucet-microbenchmarks/guests/hello.c rename to benchmarks/lucet-benchmarks/guests/hello.c diff --git a/benchmarks/lucet-benchmarks/src/context.rs b/benchmarks/lucet-benchmarks/src/context.rs new file mode 100644 index 000000000..9e4116d11 --- /dev/null +++ b/benchmarks/lucet-benchmarks/src/context.rs @@ -0,0 +1,70 @@ +use criterion::Criterion; +use lucet_runtime_internals::context::{Context, ContextHandle}; + +/// Time the initialization of a context. +fn context_init(c: &mut Criterion) { + extern "C" fn f() {} + + let mut stack = vec![0u64; 1024].into_boxed_slice(); + + c.bench_function("context_init", move |b| { + b.iter(|| { + let mut parent = ContextHandle::new(); + ContextHandle::create_and_init( + &mut *stack, + &mut parent, + f as *const extern "C" fn(), + &[], + ) + .unwrap(); + }) + }); +} + +/// Time the swap from an already-initialized context to a guest function and back. +fn context_swap_return(c: &mut Criterion) { + extern "C" fn f() {} + + c.bench_function("context_swap_return", move |b| { + b.iter_batched( + || { + let mut stack = vec![0u64; 1024].into_boxed_slice(); + let mut parent = ContextHandle::new(); + let child = ContextHandle::create_and_init( + &mut *stack, + &mut parent, + f as *const extern "C" fn(), + &[], + ) + .unwrap(); + (stack, parent, child) + }, + |(stack, mut parent, child)| unsafe { + Context::swap(&mut parent, &child); + stack + }, + criterion::BatchSize::PerIteration, + ) + }); +} + +/// Time the call to sigprocmask as used in `Context::init()`. +fn context_sigprocmask(c: &mut Criterion) { + use nix::sys::signal; + c.bench_function("context_sigprocmask", |b| { + b.iter_batched( + || signal::SigSet::empty(), + |mut sigset| { + signal::sigprocmask(signal::SigmaskHow::SIG_SETMASK, None, Some(&mut sigset)) + .unwrap() + }, + criterion::BatchSize::PerIteration, + ) + }); +} + +pub fn context_benches(c: &mut Criterion) { + context_init(c); + context_swap_return(c); + context_sigprocmask(c); +} diff --git a/benchmarks/lucet-benchmarks/src/lib.rs b/benchmarks/lucet-benchmarks/src/lib.rs new file mode 100644 index 000000000..1943b08dc --- /dev/null +++ b/benchmarks/lucet-benchmarks/src/lib.rs @@ -0,0 +1,14 @@ +mod context; +mod modules; +mod par; +mod seq; + +pub use context::context_benches; +pub use par::par_benches; +pub use seq::seq_benches; + +#[no_mangle] +extern "C" fn lucet_benchmarks_ensure_linked() { + lucet_runtime::lucet_internal_ensure_linked(); + lucet_wasi::hostcalls::ensure_linked(); +} diff --git a/benchmarks/lucet-microbenchmarks/src/modules.rs b/benchmarks/lucet-benchmarks/src/modules.rs similarity index 61% rename from benchmarks/lucet-microbenchmarks/src/modules.rs rename to benchmarks/lucet-benchmarks/src/modules.rs index 6f05235d2..7e655a795 100644 --- a/benchmarks/lucet-microbenchmarks/src/modules.rs +++ b/benchmarks/lucet-benchmarks/src/modules.rs @@ -1,6 +1,5 @@ use lucet_runtime::vmctx::lucet_vmctx; -use lucet_runtime::Module; -use lucet_runtime_internals::module::MockModuleBuilder; +use lucet_runtime_internals::module::{HeapSpec, MockModuleBuilder, Module}; use lucet_wasi_sdk::{CompileOpts, Lucetc}; use lucetc::{Bindings, LucetcOpts}; use std::path::Path; @@ -28,6 +27,59 @@ pub fn null_mock() -> Arc { .build() } +pub fn large_dense_heap_mock() -> Arc { + extern "C" fn f(_vmctx: *mut lucet_vmctx) {} + + const HEAP_LEN: usize = 4 * 1024 * 1024; + const HEAP_SPEC: HeapSpec = HeapSpec { + reserved_size: HEAP_LEN as u64, + guard_size: 4 * 1024 * 1024, + initial_size: HEAP_LEN as u64, + max_size: None, + }; + + let mut heap = vec![0x00; HEAP_LEN]; + (0..HEAP_LEN).into_iter().for_each(|i| { + heap[i] = (i % 256) as u8; + }); + + MockModuleBuilder::new() + .with_export_func(b"f", f as *const extern "C" fn()) + .with_initial_heap(heap.as_slice()) + .with_heap_spec(HEAP_SPEC) + .build() +} + +pub fn large_sparse_heap_mock() -> Arc { + extern "C" fn f(_vmctx: *mut lucet_vmctx) {} + + const HEAP_LEN: usize = 4 * 1024 * 1024; + const HEAP_SPEC: HeapSpec = HeapSpec { + reserved_size: HEAP_LEN as u64, + guard_size: 4 * 1024 * 1024, + initial_size: HEAP_LEN as u64, + max_size: None, + }; + + let mut heap = vec![0x00; HEAP_LEN]; + + // fill every eighth page with data + (0..HEAP_LEN) + .into_iter() + .step_by(4096 * 8) + .for_each(|base| { + for i in base..base + 4096 { + heap[i] = (i % 256) as u8; + } + }); + + MockModuleBuilder::new() + .with_export_func(b"f", f as *const extern "C" fn()) + .with_initial_heap(heap.as_slice()) + .with_heap_spec(HEAP_SPEC) + .build() +} + pub fn fib_mock() -> Arc { extern "C" fn f(_vmctx: *mut lucet_vmctx) { fn fib(n: u32) -> u32 { diff --git a/benchmarks/lucet-microbenchmarks/src/par.rs b/benchmarks/lucet-benchmarks/src/par.rs similarity index 93% rename from benchmarks/lucet-microbenchmarks/src/par.rs rename to benchmarks/lucet-benchmarks/src/par.rs index 4fa9067b2..7c3ca13ac 100644 --- a/benchmarks/lucet-microbenchmarks/src/par.rs +++ b/benchmarks/lucet-benchmarks/src/par.rs @@ -46,7 +46,7 @@ fn par_instantiate(c: &mut Criterion) { let module = DlModule::load(&so_file).unwrap(); let bench = criterion::ParameterizedBenchmark::new( - "par_instantiate hello", + format!("par_instantiate ({})", R::type_name()), move |b, &num_threads| { b.iter_batched( setup, @@ -116,7 +116,12 @@ fn par_run( /// sure that the locks for signal handling don't unduly slow the program down with multiple /// threads. fn par_run_null(c: &mut Criterion) { - par_run::("par_run_null", 1000, null_mock(), c); + par_run::( + &format!("par_run_null ({})", R::type_name()), + 1000, + null_mock(), + c, + ); } /// Run a computation-heavy function in parallel. @@ -124,7 +129,12 @@ fn par_run_null(c: &mut Criterion) { /// Since running multiple independent fibonaccis is embarassingly parallel, this should scale close /// to linearly. fn par_run_fib(c: &mut Criterion) { - par_run::("par_run_fib", 1000, fib_mock(), c); + par_run::( + &format!("par_run_fib ({})", R::type_name()), + 1000, + fib_mock(), + c, + ); } pub fn par_benches(c: &mut Criterion) { diff --git a/benchmarks/lucet-microbenchmarks/src/lib.rs b/benchmarks/lucet-benchmarks/src/seq.rs similarity index 69% rename from benchmarks/lucet-microbenchmarks/src/lib.rs rename to benchmarks/lucet-benchmarks/src/seq.rs index 0ad485b50..cce0a7d32 100644 --- a/benchmarks/lucet-microbenchmarks/src/lib.rs +++ b/benchmarks/lucet-benchmarks/src/seq.rs @@ -1,9 +1,4 @@ -mod modules; -mod par; - -pub use par::par_benches; - -use crate::modules::{compile_hello, fib_mock, many_args_mock, null_mock}; +use crate::modules::*; use criterion::Criterion; use lucet_runtime::{DlModule, InstanceHandle, Limits, Module, Region, RegionCreate}; use lucet_wasi::WasiCtxBuilder; @@ -31,13 +26,16 @@ fn load_mkregion_and_instantiate(c: &mut Criterion) { let so_file = workdir.path().join("out.so"); compile_hello(&so_file); - c.bench_function("load_mkregion_and_instantiate hello", move |b| { - b.iter_batched( - || nix::unistd::sync(), - |_| body::(&so_file), - criterion::BatchSize::PerIteration, - ) - }); + c.bench_function( + &format!("load_mkregion_and_instantiate ({})", R::type_name()), + move |b| { + b.iter_batched( + || nix::unistd::sync(), + |_| body::(&so_file), + criterion::BatchSize::PerIteration, + ) + }, + ); workdir.close().unwrap(); } @@ -59,13 +57,55 @@ fn instantiate(c: &mut Criterion) { let module = DlModule::load(&so_file).unwrap(); let region = R::create(1, &Limits::default()).unwrap(); - c.bench_function("instantiate hello", move |b| { + c.bench_function(&format!("instantiate ({})", R::type_name()), move |b| { b.iter(|| body(module.clone(), region.clone())) }); workdir.close().unwrap(); } +/// Instance instantiation with a large, dense heap. +fn instantiate_large_dense(c: &mut Criterion) { + fn body(module: Arc, region: Arc) -> InstanceHandle { + region.new_instance(module).unwrap() + } + + let module = large_dense_heap_mock(); + + let limits = Limits { + heap_memory_size: 1024 * 1024 * 1024, + ..Limits::default() + }; + + let region = R::create(1, &limits).unwrap(); + + c.bench_function( + &format!("instantiate_large_dense ({})", R::type_name()), + move |b| b.iter(|| body(module.clone(), region.clone())), + ); +} + +/// Instance instantiation with a large, sparse heap. +fn instantiate_large_sparse(c: &mut Criterion) { + fn body(module: Arc, region: Arc) -> InstanceHandle { + region.new_instance(module).unwrap() + } + + let module = large_sparse_heap_mock(); + + let limits = Limits { + heap_memory_size: 1024 * 1024 * 1024, + ..Limits::default() + }; + + let region = R::create(1, &limits).unwrap(); + + c.bench_function( + &format!("instantiate_large_sparse ({})", R::type_name()), + move |b| b.iter(|| body(module.clone(), region.clone())), + ); +} + /// Instance destruction. /// /// Instances have some cleanup to do with memory management and freeing their slot on their region. @@ -80,7 +120,7 @@ fn drop_instance(c: &mut Criterion) { let module = DlModule::load(&so_file).unwrap(); let region = R::create(1, &Limits::default()).unwrap(); - c.bench_function("drop_instance hello", move |b| { + c.bench_function(&format!("drop_instance ({})", R::type_name()), move |b| { b.iter_batched( || region.new_instance(module.clone()).unwrap(), |inst| body(inst), @@ -91,6 +131,54 @@ fn drop_instance(c: &mut Criterion) { workdir.close().unwrap(); } +/// Instance destruction with a large, dense heap. +fn drop_instance_large_dense(c: &mut Criterion) { + fn body(_inst: InstanceHandle) {} + + let limits = Limits { + heap_memory_size: 1024 * 1024 * 1024, + ..Limits::default() + }; + + let module = large_dense_heap_mock(); + let region = R::create(1, &limits).unwrap(); + + c.bench_function( + &format!("drop_instance_large_dense ({})", R::type_name()), + move |b| { + b.iter_batched( + || region.new_instance(module.clone()).unwrap(), + |inst| body(inst), + criterion::BatchSize::PerIteration, + ) + }, + ); +} + +/// Instance destruction with a large, sparse heap. +fn drop_instance_large_sparse(c: &mut Criterion) { + fn body(_inst: InstanceHandle) {} + + let limits = Limits { + heap_memory_size: 1024 * 1024 * 1024, + ..Limits::default() + }; + + let module = large_sparse_heap_mock(); + let region = R::create(1, &limits).unwrap(); + + c.bench_function( + &format!("drop_instance_large_sparse ({})", R::type_name()), + move |b| { + b.iter_batched( + || region.new_instance(module.clone()).unwrap(), + |inst| body(inst), + criterion::BatchSize::PerIteration, + ) + }, + ); +} + /// Run a trivial guest function. /// /// This is primarily a measurement of the signal handler installation and removal, and the context @@ -103,7 +191,7 @@ fn run_null(c: &mut Criterion) { let module = null_mock(); let region = R::create(1, &Limits::default()).unwrap(); - c.bench_function("run_null", move |b| { + c.bench_function(&format!("run_null ({})", R::type_name()), move |b| { b.iter_batched_ref( || region.new_instance(module.clone()).unwrap(), |inst| body(inst), @@ -124,7 +212,7 @@ fn run_fib(c: &mut Criterion) { let module = fib_mock(); let region = R::create(1, &Limits::default()).unwrap(); - c.bench_function("run_fib", move |b| { + c.bench_function(&format!("run_fib ({})", R::type_name()), move |b| { b.iter_batched_ref( || region.new_instance(module.clone()).unwrap(), |inst| body(inst), @@ -147,7 +235,7 @@ fn run_hello(c: &mut Criterion) { let module = DlModule::load(&so_file).unwrap(); let region = R::create(1, &Limits::default()).unwrap(); - c.bench_function("run_hello", move |b| { + c.bench_function(&format!("run_hello ({})", R::type_name()), move |b| { b.iter_batched_ref( || { let null = std::fs::File::open("/dev/null").unwrap(); @@ -253,7 +341,7 @@ fn run_many_args(c: &mut Criterion) { let module = many_args_mock(); let region = R::create(1, &Limits::default()).unwrap(); - c.bench_function("run_many_args", move |b| { + c.bench_function(&format!("run_many_args ({})", R::type_name()), move |b| { b.iter_batched_ref( || region.new_instance(module.clone()).unwrap(), |inst| body(inst), @@ -265,15 +353,13 @@ fn run_many_args(c: &mut Criterion) { pub fn seq_benches(c: &mut Criterion) { load_mkregion_and_instantiate::(c); instantiate::(c); + instantiate_large_dense::(c); + instantiate_large_sparse::(c); drop_instance::(c); + drop_instance_large_dense::(c); + drop_instance_large_sparse::(c); run_null::(c); run_fib::(c); run_hello::(c); run_many_args::(c); } - -#[no_mangle] -extern "C" fn lucet_microbenchmarks_ensure_linked() { - lucet_runtime::lucet_internal_ensure_linked(); - lucet_wasi::hostcalls::ensure_linked(); -} diff --git a/lucet-runtime/lucet-runtime-internals/src/module/mock.rs b/lucet-runtime/lucet-runtime-internals/src/module/mock.rs index 857fbb88b..08e567371 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/mock.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/mock.rs @@ -125,6 +125,11 @@ impl MockModuleBuilder { } pub fn build(self) -> Arc { + assert!( + self.sparse_page_data.len() * 4096 <= self.heap_spec.initial_size as usize, + "heap must fit in heap spec initial size" + ); + let table_elements = self .table_elements .into_iter() diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs index 1b78c1126..2d3236d94 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs @@ -197,6 +197,10 @@ impl RegionCreate for MmapRegion { fn create(instance_capacity: usize, limits: &Limits) -> Result, Error> { MmapRegion::create(instance_capacity, limits) } + + fn type_name() -> &'static str { + "MmapRegion" + } } impl MmapRegion { diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mod.rs b/lucet-runtime/lucet-runtime-internals/src/region/mod.rs index 6346a1edd..0224d289a 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mod.rs @@ -62,6 +62,9 @@ pub trait RegionCreate: Region { /// Create a new `Region` that can support a given number instances, each subject to the same /// runtime limits. fn create(instance_capacity: usize, limits: &Limits) -> Result, Error>; + + /// Get the type name of the region; useful for testing. + fn type_name() -> &'static str; } /// A builder for instances; created by From 53ad21203d2ac033b398ab3c2e26bff67527d131 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Thu, 11 Apr 2019 16:42:01 -0700 Subject: [PATCH 033/512] [lucet-runtime] use an associated constant for the region type name --- benchmarks/lucet-benchmarks/src/par.rs | 6 ++--- benchmarks/lucet-benchmarks/src/seq.rs | 22 +++++++++---------- .../src/region/mmap.rs | 6 ++--- .../lucet-runtime-internals/src/region/mod.rs | 6 ++--- 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/benchmarks/lucet-benchmarks/src/par.rs b/benchmarks/lucet-benchmarks/src/par.rs index 7c3ca13ac..036a3c9c0 100644 --- a/benchmarks/lucet-benchmarks/src/par.rs +++ b/benchmarks/lucet-benchmarks/src/par.rs @@ -46,7 +46,7 @@ fn par_instantiate(c: &mut Criterion) { let module = DlModule::load(&so_file).unwrap(); let bench = criterion::ParameterizedBenchmark::new( - format!("par_instantiate ({})", R::type_name()), + format!("par_instantiate ({})", R::TYPE_NAME), move |b, &num_threads| { b.iter_batched( setup, @@ -117,7 +117,7 @@ fn par_run( /// threads. fn par_run_null(c: &mut Criterion) { par_run::( - &format!("par_run_null ({})", R::type_name()), + &format!("par_run_null ({})", R::TYPE_NAME), 1000, null_mock(), c, @@ -130,7 +130,7 @@ fn par_run_null(c: &mut Criterion) { /// to linearly. fn par_run_fib(c: &mut Criterion) { par_run::( - &format!("par_run_fib ({})", R::type_name()), + &format!("par_run_fib ({})", R::TYPE_NAME), 1000, fib_mock(), c, diff --git a/benchmarks/lucet-benchmarks/src/seq.rs b/benchmarks/lucet-benchmarks/src/seq.rs index cce0a7d32..ffca2d13e 100644 --- a/benchmarks/lucet-benchmarks/src/seq.rs +++ b/benchmarks/lucet-benchmarks/src/seq.rs @@ -27,7 +27,7 @@ fn load_mkregion_and_instantiate(c: &mut Criterion) { compile_hello(&so_file); c.bench_function( - &format!("load_mkregion_and_instantiate ({})", R::type_name()), + &format!("load_mkregion_and_instantiate ({})", R::TYPE_NAME), move |b| { b.iter_batched( || nix::unistd::sync(), @@ -57,7 +57,7 @@ fn instantiate(c: &mut Criterion) { let module = DlModule::load(&so_file).unwrap(); let region = R::create(1, &Limits::default()).unwrap(); - c.bench_function(&format!("instantiate ({})", R::type_name()), move |b| { + c.bench_function(&format!("instantiate ({})", R::TYPE_NAME), move |b| { b.iter(|| body(module.clone(), region.clone())) }); @@ -80,7 +80,7 @@ fn instantiate_large_dense(c: &mut Criterion) { let region = R::create(1, &limits).unwrap(); c.bench_function( - &format!("instantiate_large_dense ({})", R::type_name()), + &format!("instantiate_large_dense ({})", R::TYPE_NAME), move |b| b.iter(|| body(module.clone(), region.clone())), ); } @@ -101,7 +101,7 @@ fn instantiate_large_sparse(c: &mut Criterion) { let region = R::create(1, &limits).unwrap(); c.bench_function( - &format!("instantiate_large_sparse ({})", R::type_name()), + &format!("instantiate_large_sparse ({})", R::TYPE_NAME), move |b| b.iter(|| body(module.clone(), region.clone())), ); } @@ -120,7 +120,7 @@ fn drop_instance(c: &mut Criterion) { let module = DlModule::load(&so_file).unwrap(); let region = R::create(1, &Limits::default()).unwrap(); - c.bench_function(&format!("drop_instance ({})", R::type_name()), move |b| { + c.bench_function(&format!("drop_instance ({})", R::TYPE_NAME), move |b| { b.iter_batched( || region.new_instance(module.clone()).unwrap(), |inst| body(inst), @@ -144,7 +144,7 @@ fn drop_instance_large_dense(c: &mut Criterion) { let region = R::create(1, &limits).unwrap(); c.bench_function( - &format!("drop_instance_large_dense ({})", R::type_name()), + &format!("drop_instance_large_dense ({})", R::TYPE_NAME), move |b| { b.iter_batched( || region.new_instance(module.clone()).unwrap(), @@ -168,7 +168,7 @@ fn drop_instance_large_sparse(c: &mut Criterion) { let region = R::create(1, &limits).unwrap(); c.bench_function( - &format!("drop_instance_large_sparse ({})", R::type_name()), + &format!("drop_instance_large_sparse ({})", R::TYPE_NAME), move |b| { b.iter_batched( || region.new_instance(module.clone()).unwrap(), @@ -191,7 +191,7 @@ fn run_null(c: &mut Criterion) { let module = null_mock(); let region = R::create(1, &Limits::default()).unwrap(); - c.bench_function(&format!("run_null ({})", R::type_name()), move |b| { + c.bench_function(&format!("run_null ({})", R::TYPE_NAME), move |b| { b.iter_batched_ref( || region.new_instance(module.clone()).unwrap(), |inst| body(inst), @@ -212,7 +212,7 @@ fn run_fib(c: &mut Criterion) { let module = fib_mock(); let region = R::create(1, &Limits::default()).unwrap(); - c.bench_function(&format!("run_fib ({})", R::type_name()), move |b| { + c.bench_function(&format!("run_fib ({})", R::TYPE_NAME), move |b| { b.iter_batched_ref( || region.new_instance(module.clone()).unwrap(), |inst| body(inst), @@ -235,7 +235,7 @@ fn run_hello(c: &mut Criterion) { let module = DlModule::load(&so_file).unwrap(); let region = R::create(1, &Limits::default()).unwrap(); - c.bench_function(&format!("run_hello ({})", R::type_name()), move |b| { + c.bench_function(&format!("run_hello ({})", R::TYPE_NAME), move |b| { b.iter_batched_ref( || { let null = std::fs::File::open("/dev/null").unwrap(); @@ -341,7 +341,7 @@ fn run_many_args(c: &mut Criterion) { let module = many_args_mock(); let region = R::create(1, &Limits::default()).unwrap(); - c.bench_function(&format!("run_many_args ({})", R::type_name()), move |b| { + c.bench_function(&format!("run_many_args ({})", R::TYPE_NAME), move |b| { b.iter_batched_ref( || region.new_instance(module.clone()).unwrap(), |inst| body(inst), diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs index 2d3236d94..fa7e867fa 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs @@ -194,13 +194,11 @@ impl Drop for MmapRegion { } impl RegionCreate for MmapRegion { + const TYPE_NAME: &'static str = "MmapRegion"; + fn create(instance_capacity: usize, limits: &Limits) -> Result, Error> { MmapRegion::create(instance_capacity, limits) } - - fn type_name() -> &'static str { - "MmapRegion" - } } impl MmapRegion { diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mod.rs b/lucet-runtime/lucet-runtime-internals/src/region/mod.rs index 0224d289a..7099ed639 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mod.rs @@ -59,12 +59,12 @@ pub trait RegionInternal: Send + Sync { /// This is not part of [`Region`](trait.Region.html) so that `Region` types can be made into trait /// objects. pub trait RegionCreate: Region { + /// The type name of the region; useful for testing. + const TYPE_NAME: &'static str; + /// Create a new `Region` that can support a given number instances, each subject to the same /// runtime limits. fn create(instance_capacity: usize, limits: &Limits) -> Result, Error>; - - /// Get the type name of the region; useful for testing. - fn type_name() -> &'static str; } /// A builder for instances; created by From d8669babaa8d4645ae2ec6e7c1ad6175793efc8c Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 12 Apr 2019 17:09:51 +0200 Subject: [PATCH 034/512] Make lucetc work on macOS Also allow the linker and its flags to be overridden using standard environment variables. --- lucetc/src/lib.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/lucetc/src/lib.rs b/lucetc/src/lib.rs index 856c1af57..93adc887e 100644 --- a/lucetc/src/lib.rs +++ b/lucetc/src/lib.rs @@ -18,6 +18,7 @@ use crate::program::Program; use failure::{format_err, Error, ResultExt}; use parity_wasm::elements::Module; use std::collections::HashMap; +use std::env; use std::path::{Path, PathBuf}; use tempfile; @@ -150,15 +151,26 @@ impl Lucetc { } } +const LD_DEFAULT: &str = "ld"; + +#[cfg(not(target_os = "macos"))] +const LDFLAGS_DEFAULT: &str = "-shared"; + +#[cfg(target_os = "macos")] +const LDFLAGS_DEFAULT: &str = "-dylib -dead_strip -export_dynamic -undefined dynamic_lookup"; + fn link_so(objpath: P, sopath: Q) -> Result<(), Error> where P: AsRef, Q: AsRef, { use std::process::Command; - let mut cmd_ld = Command::new("ld"); + let mut cmd_ld = Command::new(env::var("LD").unwrap_or(LD_DEFAULT.into())); cmd_ld.arg(objpath.as_ref()); - cmd_ld.arg("-shared"); + let env_ldflags = env::var("LDFLAGS").unwrap_or(LDFLAGS_DEFAULT.into()); + for flag in env_ldflags.split_whitespace() { + cmd_ld.arg(flag); + } cmd_ld.arg("-o"); cmd_ld.arg(sopath.as_ref()); From bf6a8ddf78af4767bb5761f93096067efba1656b Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 15 Apr 2019 13:20:05 -0700 Subject: [PATCH 035/512] [packaging] use the new cargo-deb feature to rename the packages --- lucet-runtime/Cargo.toml | 2 +- lucet-wasi/Cargo.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lucet-runtime/Cargo.toml b/lucet-runtime/Cargo.toml index 0197eeebc..b4c4b7cdf 100644 --- a/lucet-runtime/Cargo.toml +++ b/lucet-runtime/Cargo.toml @@ -26,6 +26,7 @@ name = "lucet_runtime" crate-type = ["rlib", "staticlib", "cdylib"] [package.metadata.deb] +name = "fst-lucet-runtime" maintainer = "Adam C. Foltzer " depends = "$auto" priority = "optional" @@ -34,5 +35,4 @@ assets = [ ["target/release/liblucet_runtime.rlib", "/opt/fst-lucet-runtime/lib/", "644"], ["target/release/liblucet_runtime.so", "/opt/fst-lucet-runtime/lib/", "755"], ["include/*.h", "/opt/fst-lucet-runtime/include/", "644"], - ["README.rst", "/opt/fst-lucet-runtime/share/doc/lucet-runtime/", "644"], ] diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index b20379ee2..8d9ba2025 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -29,6 +29,7 @@ name = "lucet_wasi" crate-type = ["rlib", "staticlib", "cdylib"] [package.metadata.deb] +name = "fst-lucet-wasi" maintainer = "Adam C. Foltzer " depends = "$auto" priority = "optional" From 3c12474d5003dd6896de5c11bb9f4cab8c47bd3b Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 16 Apr 2019 10:39:32 -0700 Subject: [PATCH 036/512] [lucet-wasi] use /dev/null by default for stdio handles When we clean up these interfaces, it'd be nice to make these pseudo files rather than opening an actual file decriptor, so there are no system calls involved in creating a new WASI context. --- lucet-wasi/src/ctx.rs | 20 ++++++++++++++++---- lucet-wasi/src/main.rs | 5 ++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/lucet-wasi/src/ctx.rs b/lucet-wasi/src/ctx.rs index fcb9bed5b..889ecfc99 100644 --- a/lucet-wasi/src/ctx.rs +++ b/lucet-wasi/src/ctx.rs @@ -19,15 +19,16 @@ pub struct WasiCtxBuilder { impl WasiCtxBuilder { /// Builder for a new `WasiCtx`. pub fn new() -> Self { + let null = dev_null(); WasiCtxBuilder { fds: HashMap::new(), preopens: HashMap::new(), args: vec![], env: HashMap::new(), } - .fd_dup(0, stdin()) - .fd_dup(1, stdout()) - .fd_dup(2, stderr()) + .fd_dup(0, &null) + .fd_dup(1, &null) + .fd_dup(2, &null) } pub fn args(mut self, args: &[&str]) -> Self { @@ -57,6 +58,12 @@ impl WasiCtxBuilder { self } + pub fn inherit_stdio(self) -> Self { + self.fd_dup(0, &stdin()) + .fd_dup(1, &stdout()) + .fd_dup(2, &stderr()) + } + pub fn inherit_env(mut self) -> Self { self.env = std::env::vars() .map(|(k, v)| { @@ -104,7 +111,7 @@ impl WasiCtxBuilder { /// context, so it will not be closed when the `WasiCtx` is dropped. /// /// TODO: handle `dup` errors - pub fn fd_dup(self, wasm_fd: host::__wasi_fd_t, fd: F) -> Self { + pub fn fd_dup(self, wasm_fd: host::__wasi_fd_t, fd: &F) -> Self { // safe because we're getting a valid RawFd from the F directly unsafe { self.raw_fd(wasm_fd, dup(fd.as_raw_fd()).unwrap()) } } @@ -189,6 +196,7 @@ impl WasiCtx { pub fn new(args: &[&str]) -> WasiCtx { WasiCtxBuilder::new() .args(args) + .inherit_stdio() .inherit_env() .build() .expect("default options don't fail") @@ -230,3 +238,7 @@ impl WasiCtx { Ok(fd) } } + +fn dev_null() -> File { + File::open("/dev/null").expect("failed to open /dev/null") +} diff --git a/lucet-wasi/src/main.rs b/lucet-wasi/src/main.rs index eb9837c6b..67ee5b90c 100644 --- a/lucet-wasi/src/main.rs +++ b/lucet-wasi/src/main.rs @@ -175,7 +175,10 @@ fn run(config: Config) { let args = std::iter::once(config.lucet_module) .chain(config.guest_args.into_iter()) .collect::>(); - let mut ctx = WasiCtxBuilder::new().args(&args).inherit_env(); + let mut ctx = WasiCtxBuilder::new() + .args(&args) + .inherit_stdio() + .inherit_env(); for (dir, guest_path) in config.preopen_dirs { ctx = ctx.preopened_dir(dir, guest_path); } From a77f2a1be87ad89728249bc5ae84df55026eacc1 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 16 Apr 2019 11:00:43 -0700 Subject: [PATCH 037/512] [lucetc] add exact reserved size setting --- lucetc/src/lib.rs | 19 +++++++++++++++++++ lucetc/src/main.rs | 5 +++++ lucetc/src/options.rs | 15 +++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/lucetc/src/lib.rs b/lucetc/src/lib.rs index 5ff59bef2..d69d7a06c 100644 --- a/lucetc/src/lib.rs +++ b/lucetc/src/lib.rs @@ -61,6 +61,15 @@ pub trait LucetcOpts { fn max_reserved_size(&mut self, max_reserved_size: u64); fn with_max_reserved_size(self, max_reserved_size: u64) -> Self; + /// Set the reserved size exactly. + /// + /// Equivalent to setting the minimum and maximum reserved sizes to the same value. + fn reserved_size(&mut self, reserved_size: u64); + /// Set the reserved size exactly. + /// + /// Equivalent to setting the minimum and maximum reserved sizes to the same value. + fn with_reserved_size(self, reserved_size: u64) -> Self; + fn guard_size(&mut self, guard_size: u64); fn with_guard_size(self, guard_size: u64) -> Self; } @@ -113,6 +122,16 @@ impl LucetcOpts for T { self } + fn reserved_size(&mut self, reserved_size: u64) { + self.as_lucetc().heap.min_reserved_size = reserved_size; + self.as_lucetc().heap.max_reserved_size = reserved_size; + } + + fn with_reserved_size(mut self, reserved_size: u64) -> Self { + self.reserved_size(reserved_size); + self + } + fn guard_size(&mut self, guard_size: u64) { self.as_lucetc().heap.guard_size = guard_size; } diff --git a/lucetc/src/main.rs b/lucetc/src/main.rs index 88539167a..c8f0fe82d 100644 --- a/lucetc/src/main.rs +++ b/lucetc/src/main.rs @@ -58,6 +58,11 @@ pub fn run(opts: &Options) -> Result<(), Error> { c.max_reserved_size(max_reserved_size); } + // this comes after min and max, so it overrides them if present + if let Some(reserved_size) = opts.reserved_size { + c.reserved_size(reserved_size); + } + if let Some(guard_size) = opts.guard_size { c.guard_size(guard_size); } diff --git a/lucetc/src/options.rs b/lucetc/src/options.rs index 46ade8c18..427b0a45b 100644 --- a/lucetc/src/options.rs +++ b/lucetc/src/options.rs @@ -38,6 +38,7 @@ pub struct Options { pub builtins_path: Option, pub min_reserved_size: Option, pub max_reserved_size: Option, + pub reserved_size: Option, pub guard_size: Option, pub opt_level: OptLevel, } @@ -80,6 +81,12 @@ impl Options { None }; + let reserved_size = if let Some(reserved_str) = m.value_of("reserved_size") { + Some(parse_humansized(reserved_str)?) + } else { + None + }; + let guard_size = if let Some(guard_str) = m.value_of("guard_size") { Some(parse_humansized(guard_str)?) } else { @@ -102,6 +109,7 @@ impl Options { builtins_path, min_reserved_size, max_reserved_size, + reserved_size, guard_size, opt_level, }) @@ -154,6 +162,13 @@ impl Options { .multiple(false) .help("maximum size of usable linear memory region. must be multiple of 4k. default: 4 GiB"), ) + .arg( + Arg::with_name("reserved_size") + .long("--reserved-size") + .takes_value(true) + .multiple(false) + .help("exact size of usable linear memory region, overriding --{min,max}-reserved-size. must be multiple of 4k"), + ) .arg( Arg::with_name("guard_size") .long("--guard-size") From 928b21da71e27bb6a3b0f58e66fb7b1f67dcb80c Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Tue, 16 Apr 2019 12:32:46 -0700 Subject: [PATCH 038/512] lucet-runtime-tests: this crate only defines test functions for lucet-runtime As a result, it includes a (and possibly more in the future) reference to functions in lucet-runtime (currently, lucet_vmctx_get_heap), and cannot be built independently of lucet-runtime. `cargo test` will attempt to do exactly this and result in an unhelpful build error about undefined symbols, while trying to produce a binary to test that is tightly coupled to lucet-runtime anyway. This change disables tests for lucet-runtime-tests to keep cargo from trying to build tests for this crate. --- lucet-runtime/lucet-runtime-tests/Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lucet-runtime/lucet-runtime-tests/Cargo.toml b/lucet-runtime/lucet-runtime-tests/Cargo.toml index 237489586..3e813935b 100644 --- a/lucet-runtime/lucet-runtime-tests/Cargo.toml +++ b/lucet-runtime/lucet-runtime-tests/Cargo.toml @@ -4,6 +4,9 @@ version = "0.1.0" authors = ["Adam C. Foltzer "] edition = "2018" +[lib] +test = false + [dependencies] failure = "0.1" lazy_static = "1.1" From 2d63073b4ca313575342733876cd8d66ecac13af Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 16 Apr 2019 13:07:28 -0700 Subject: [PATCH 039/512] [lucet-runtime-tests] Add explanation for why we disable tests for this crate --- lucet-runtime/lucet-runtime-tests/Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lucet-runtime/lucet-runtime-tests/Cargo.toml b/lucet-runtime/lucet-runtime-tests/Cargo.toml index 3e813935b..1efa7aba0 100644 --- a/lucet-runtime/lucet-runtime-tests/Cargo.toml +++ b/lucet-runtime/lucet-runtime-tests/Cargo.toml @@ -5,6 +5,8 @@ authors = ["Adam C. Foltzer "] edition = "2018" [lib] +# This crate only defines tests in macros, it does not contain any tests itself. This flag prevents +# `cargo test -p lucet-runtime-tests` from trying to link an executable with undefined symbols. test = false [dependencies] From 757f904559298c9b688e84f8368f8568bcb137b3 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 17 Apr 2019 00:58:07 +0200 Subject: [PATCH 040/512] Update sightglass again --- sightglass | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sightglass b/sightglass index eb9706139..4999f901b 160000 --- a/sightglass +++ b/sightglass @@ -1 +1 @@ -Subproject commit eb97061395e617671cfeaf4b3a44367f558c918e +Subproject commit 4999f901b3d686a911dfe24b588d6397ca2b193a From 608ca14af15c8f41d7b6738fbdf41f42b150a83d Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 16 Apr 2019 16:01:03 -0700 Subject: [PATCH 041/512] [lucet-wasi-sdk] refine API and be more verbose with commands --- lucet-wasi-sdk/src/lib.rs | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/lucet-wasi-sdk/src/lib.rs b/lucet-wasi-sdk/src/lib.rs index cc77a5caf..218e714dc 100644 --- a/lucet-wasi-sdk/src/lib.rs +++ b/lucet-wasi-sdk/src/lib.rs @@ -63,8 +63,8 @@ pub trait CompileOpts { fn cflag>(&mut self, cflag: S); fn with_cflag>(self, cflag: S) -> Self; - fn include>(&mut self, include: S); - fn with_include>(self, include: S) -> Self; + fn include>(&mut self, include: S); + fn with_include>(self, include: S) -> Self; } impl CompileOpts for Compile { @@ -77,11 +77,12 @@ impl CompileOpts for Compile { self } - fn include>(&mut self, include: S) { - self.cflags.push(format!("-I{}", include.as_ref())); + fn include>(&mut self, include: S) { + self.cflags + .push(format!("-I{}", include.as_ref().display())); } - fn with_include>(mut self, include: S) -> Self { + fn with_include>(mut self, include: S) -> Self { self.include(include); self } @@ -125,6 +126,9 @@ impl Compile { for cflag in self.cflags.iter() { cmd.arg(cflag); } + if self.print_output { + println!("running: {:?}", cmd); + } let run = cmd.output().expect("clang executable exists"); CompileError::check(run, self.print_output) } @@ -181,6 +185,9 @@ impl Link { for ldflag in self.ldflags.iter() { cmd.arg(format!("-Wl,{}", ldflag)); } + if self.print_output { + println!("running: {:?}", cmd); + } let run = cmd.output().expect("clang executable exists"); CompileError::check(run, self.print_output) } @@ -236,13 +243,13 @@ impl CompileOpts for T { self } - fn include>(&mut self, include: S) { + fn include>(&mut self, include: S) { self.as_link() .cflags - .push(format!("-I{}", include.as_ref())); + .push(format!("-I{}", include.as_ref().display())); } - fn with_include>(mut self, include: S) -> Self { + fn with_include>(mut self, include: S) -> Self { self.include(include); self } @@ -269,8 +276,12 @@ impl Lucetc { } } - pub fn print_output(mut self, print: bool) -> Self { + pub fn print_output(&mut self, print: bool) { self.link.print_output = print; + } + + pub fn with_print_output(mut self, print: bool) -> Self { + self.print_output(print); self } From c2e72a53af2e5d736721681526c4b46cee0ff36f Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 17 Apr 2019 01:06:07 +0200 Subject: [PATCH 042/512] Cargo.lock update after sightglass update --- Cargo.lock | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dd3db4db5..15e6767e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -190,6 +190,17 @@ dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "core_affinity" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cranelift-bforest" version = "0.29.0" @@ -1179,6 +1190,7 @@ version = "0.1.0" dependencies = [ "bencher 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "core_affinity 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", "hwloc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1189,7 +1201,7 @@ dependencies = [ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1339,7 +1351,7 @@ dependencies = [ [[package]] name = "toml" -version = "0.4.10" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1525,6 +1537,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "96210eec534fc3fbfc0452a63769424eaa80205fda6cea98e5b61cb3d97bcec8" "checksum colored 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e9a455e156a4271e12fd0246238c380b1e223e3736663c7a18ed8b6362028a9" +"checksum core_affinity 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6d162c6e463c31dbf78fefa99d042156c1c74d404e299cfe3df2923cb857595b" "checksum criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0363053954f3e679645fc443321ca128b7b950a6fe288cf5f9335cc22ee58394" "checksum criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76f9212ddf2f4a9eb2d401635190600656a1f88a932ef53d06e7fa4c7e02fb8e" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" @@ -1626,7 +1639,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum tinytemplate 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7655088894274afb52b807bd3c87072daa1fedd155068b8705cabfd628956115" -"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" +"checksum toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87c5890a989fa47ecdc7bcb4c63a77a82c18f306714104b1decfd722db17b39e" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" "checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" From e2ccc66450096b86859cdc440b002a4bb00130ab Mon Sep 17 00:00:00 2001 From: Daisuke FUJI Date: Wed, 17 Apr 2019 18:18:16 +0900 Subject: [PATCH 043/512] Fix setenv script name --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 93efc5df1..e738bc6a9 100644 --- a/README.md +++ b/README.md @@ -273,7 +273,7 @@ lucet-wasi hello.so * `./devenv_run.sh [] [...]` runs a command in the container. If a command is not provided, an interactive shell is spawned. In this container, Lucet tools are installed in `/opt/lucet` by default. The command - `source /opt/lucet/bin/lucet_setenv.sh` can be used to initialize the + `source /opt/lucet/bin/devenv_setenv.sh` can be used to initialize the environment. * `./devenv_start.sh` and `./devenv_stop.sh` start and stop the container. From 0ee302f4e0cc205f6fdb60009e369ff2e36c1e04 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 17 Apr 2019 11:15:29 -0700 Subject: [PATCH 044/512] gitattributes: note that png and jpg are binary files the assets/*.png files were getting CRLF'd up during rebases --- .gitattributes | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitattributes b/.gitattributes index ed234a686..e7178ff96 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,7 @@ # Auto detect text and normalize to LF on commit regardless of "core.autocrlf". # See: https://help.github.com/en/articles/dealing-with-line-endings#example * text=auto eol=lf + +# Denote all files that are truly binary and should not be modified. +*.png binary +*.jpg binary From 0008397b6e27a0f002b8641b20a1e543abdcb1a8 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 17 Apr 2019 12:33:44 -0700 Subject: [PATCH 045/512] gitattributes: wasm is also binary --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index e7178ff96..c652b4d86 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,3 +5,4 @@ # Denote all files that are truly binary and should not be modified. *.png binary *.jpg binary +*.wasm binary From ca2ad6687286d364da738849ce46af6b2a60350e Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Mon, 15 Apr 2019 19:56:54 +0200 Subject: [PATCH 046/512] Preliminary macOS port --- .../lucet-runtime-internals/src/c_api.rs | 3 +- .../src/context/context_asm.S | 35 +++- .../lucet-runtime-internals/src/instance.rs | 3 +- .../src/instance/signals.rs | 12 +- .../lucet-runtime-internals/src/lib.rs | 1 + .../src/region/mmap.rs | 2 +- .../src/sysdeps/linux.rs | 52 ++++++ .../src/sysdeps/macos.rs | 174 ++++++++++++++++++ .../src/sysdeps/mod.rs | 11 ++ .../lucet-runtime-tests/src/guest_fault.rs | 2 +- .../src/guest_fault/traps.S | 31 +++- lucet-wasi/build.rs | 41 +++-- lucet-wasi/src/host.rs | 10 +- lucet-wasi/src/hostcalls.rs | 8 +- 14 files changed, 352 insertions(+), 33 deletions(-) create mode 100644 lucet-runtime/lucet-runtime-internals/src/sysdeps/linux.rs create mode 100644 lucet-runtime/lucet-runtime-internals/src/sysdeps/macos.rs create mode 100644 lucet-runtime/lucet-runtime-internals/src/sysdeps/mod.rs diff --git a/lucet-runtime/lucet-runtime-internals/src/c_api.rs b/lucet-runtime/lucet-runtime-internals/src/c_api.rs index 327f325e7..7e4609638 100644 --- a/lucet-runtime/lucet-runtime-internals/src/c_api.rs +++ b/lucet-runtime/lucet-runtime-internals/src/c_api.rs @@ -196,6 +196,7 @@ pub mod lucet_state { use crate::c_api::lucet_val; use crate::instance::{State, TerminationDetails}; use crate::module::AddrDetails; + use crate::sysdeps::UContext; use crate::trapcode::{TrapCode, TrapCodeType}; use libc::{c_char, c_void}; use num_derive::FromPrimitive; @@ -307,7 +308,7 @@ pub mod lucet_state { pub rip_addr: libc::uintptr_t, pub rip_addr_details: lucet_module_addr_details, pub signal_info: libc::siginfo_t, - pub context: libc::ucontext_t, + pub context: UContext, } #[repr(C)] diff --git a/lucet-runtime/lucet-runtime-internals/src/context/context_asm.S b/lucet-runtime/lucet-runtime-internals/src/context/context_asm.S index 7c6d01cf3..7f409ffca 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/context_asm.S +++ b/lucet-runtime/lucet-runtime-internals/src/context/context_asm.S @@ -31,9 +31,14 @@ .text .globl lucet_context_bootstrap +#ifdef __ELF__ .type lucet_context_bootstrap,@function +#else +.globl _lucet_context_bootstrap +#endif .align 16 lucet_context_bootstrap: +_lucet_context_bootstrap: /* Move each of the context-saved registers into the corresponding call * argument register. See lucet_register enum for docs */ mov %r12, %rsi @@ -43,27 +48,44 @@ lucet_context_bootstrap: mov %rbx, %r9 /* the next thing on the stack is the guest function - return to it */ ret +#ifdef __ELF__ .size lucet_context_bootstrap,.-lucet_context_bootstrap - +#endif .text .globl lucet_context_backstop +#ifdef __ELF__ .type lucet_context_backstop,@function +#else +.globl _lucet_context_backstop +#endif .align 16 lucet_context_backstop: +_lucet_context_backstop: mov -16(%rbp), %rdi /* parent context to arg 1 */ mov -8(%rbp), %rsi /* own context to arg 2 */ mov %rax, (8*8 + 8*16 + 8*0)(%rdi) /* store return values before swapping back -- offset is offsetof(struct lucet_context, retvals) */ mov %rdx, (8*8 + 8*16 + 8*1)(%rdi) movdqu %xmm0, (8*8 + 8*16 + 8*2)(%rdi) /* floating-point return value */ +#ifdef __ELF__ jmp lucet_context_swap@PLT +#else + jmp lucet_context_swap +#endif +#ifdef __ELF__ .size lucet_context_backstop,.-lucet_context_backstop +#endif .text .globl lucet_context_swap +#ifdef __ELF__ .type lucet_context_swap,@function +#else +.globl _lucet_context_swap +#endif .align 16 lucet_context_swap: +_lucet_context_swap: // store everything in offsets from rdi (1st arg) mov %rbx, (0*8)(%rdi) mov %rsp, (1*8)(%rdi) @@ -103,13 +125,20 @@ lucet_context_swap: movdqu (8*8 + 7*16)(%rsi), %xmm7 ret +#ifdef __ELF__ .size lucet_context_swap,.-lucet_context_swap +#endif .text .globl lucet_context_set +#ifdef __ELF__ .type lucet_context_set,@function +#else +.globl _lucet_context_set +#endif .align 16 lucet_context_set: +_lucet_context_set: // load everything from offsets from rdi (1st arg) mov (0*8)(%rdi), %rbx mov (1*8)(%rdi), %rsp @@ -131,7 +160,11 @@ lucet_context_set: // load rdi from itself last mov (3*8)(%rdi), %rdi ret +#ifdef __ELF__ .size lucet_context_set,.-lucet_context_set +#endif /* Mark that we don't need executable stack. */ +#if defined(__linux__) && defined(__ELF__) .section .note.GNU-stack,"",%progbits +#endif diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index 355e47f63..f308a1096 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -9,6 +9,7 @@ use crate::embed_ctx::CtxMap; use crate::error::Error; use crate::instance::siginfo_ext::SiginfoExt; use crate::module::{self, Global, Module}; +use crate::sysdeps::UContext; use crate::trapcode::{TrapCode, TrapCodeType}; use crate::val::{UntypedRetVal, Val}; use crate::WASM_PAGE_SIZE; @@ -623,7 +624,7 @@ pub enum State { Fault { details: FaultDetails, siginfo: libc::siginfo_t, - context: libc::ucontext_t, + context: UContext, }, Terminated { details: TerminationDetails, diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs index fc98d1b69..7bd40dead 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs @@ -2,6 +2,7 @@ use crate::context::Context; use crate::instance::{ FaultDetails, Instance, State, TerminationDetails, CURRENT_INSTANCE, HOST_CTX, }; +use crate::sysdeps::UContextPtr; use crate::trapcode::{TrapCode, TrapCodeType}; use failure::Error; use lazy_static::lazy_static; @@ -109,12 +110,9 @@ extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext // Safety: when using a SA_SIGINFO sigaction, the third argument can be cast to a `ucontext_t` // pointer per the manpage - let ctx = unsafe { - (ucontext_ptr as *mut libc::ucontext_t) - .as_ref() - .expect("ucontext must not be null") - }; - let rip = ctx.uc_mcontext.gregs[libc::REG_RIP as usize] as *const c_void; + assert!(!ucontext_ptr.is_null()); + let ctx = UContextPtr::new(ucontext_ptr); + let rip = ctx.get_ip(); let switch_to_host = CURRENT_INSTANCE.with(|current_instance| { let mut current_instance = current_instance.borrow_mut(); @@ -178,7 +176,7 @@ extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext // safety: pointer is checked for null at the top of the function, and the // manpage guarantees that a siginfo_t will be passed as the second argument siginfo: unsafe { *siginfo_ptr }, - context: *ctx, + context: ctx.into(), }; true } diff --git a/lucet-runtime/lucet-runtime-internals/src/lib.rs b/lucet-runtime/lucet-runtime-internals/src/lib.rs index bea486467..40480ad58 100644 --- a/lucet-runtime/lucet-runtime-internals/src/lib.rs +++ b/lucet-runtime/lucet-runtime-internals/src/lib.rs @@ -18,6 +18,7 @@ pub mod embed_ctx; pub mod instance; pub mod module; pub mod region; +pub mod sysdeps; pub mod trapcode; pub mod val; pub mod vmctx; diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs index fa7e867fa..8e6d92c39 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs @@ -236,7 +236,7 @@ impl MmapRegion { ptr::null_mut(), region.limits.total_memory_size(), ProtFlags::PROT_NONE, - MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, + MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, 0, 0, )? diff --git a/lucet-runtime/lucet-runtime-internals/src/sysdeps/linux.rs b/lucet-runtime/lucet-runtime-internals/src/sysdeps/linux.rs new file mode 100644 index 000000000..fe8d05138 --- /dev/null +++ b/lucet-runtime/lucet-runtime-internals/src/sysdeps/linux.rs @@ -0,0 +1,52 @@ +use libc::{c_void, ucontext_t, REG_RIP}; + +#[derive(Clone, Copy, Debug)] +pub struct UContextPtr(*const ucontext_t); + +impl UContextPtr { + #[inline] + pub fn new(ptr: *const c_void) -> Self { + assert!(!ptr.is_null(), "non-null context"); + UContextPtr(ptr as *const ucontext_t) + } + + #[inline] + pub fn get_ip(&self) -> *const c_void { + let mcontext = &unsafe { *(self.0) }.uc_mcontext; + mcontext.gregs[REG_RIP as usize] as *const _ + } +} + +#[derive(Clone, Copy)] +pub struct UContext { + context: ucontext_t, +} + +impl UContext { + #[inline] + pub fn new(ptr: *const c_void) -> Self { + UContext { + context: *unsafe { + (ptr as *const ucontext_t) + .as_ref() + .expect("non-null context") + }, + } + } +} + +impl Into for UContextPtr { + #[inline] + fn into(self) -> UContext { + UContext { + context: unsafe { *(self.0) }, + } + } +} + +impl Into for UContext { + #[inline] + fn into(self) -> UContextPtr { + UContextPtr::new(&self.context as *const _ as *const _) + } +} diff --git a/lucet-runtime/lucet-runtime-internals/src/sysdeps/macos.rs b/lucet-runtime/lucet-runtime-internals/src/sysdeps/macos.rs new file mode 100644 index 000000000..65c663c55 --- /dev/null +++ b/lucet-runtime/lucet-runtime-internals/src/sysdeps/macos.rs @@ -0,0 +1,174 @@ +use libc::{c_int, c_short, c_void, sigset_t, size_t}; +#[derive(Clone, Copy, Debug)] +#[repr(C)] +pub struct sigaltstack { + pub ss_sp: *const c_void, + pub ss_size: size_t, + pub ss_flags: c_int, +} + +#[derive(Clone, Copy, Debug)] +#[repr(C)] +pub struct x86_exception_state64 { + pub trapno: u16, + pub cpu: u16, + pub err: u32, + pub faultvaddr: u64, +} + +#[derive(Clone, Copy, Debug)] +#[repr(C)] +pub struct x86_thread_state64 { + pub rax: u64, + pub rbx: u64, + pub rcx: u64, + pub rdx: u64, + pub rdi: u64, + pub rsi: u64, + pub rbp: u64, + pub rsp: u64, + pub r8: u64, + pub r9: u64, + pub r10: u64, + pub r11: u64, + pub r12: u64, + pub r13: u64, + pub r14: u64, + pub r15: u64, + pub rip: u64, + pub rflags: u64, + pub cs: u64, + pub fs: u64, + pub gs: u64, +} + +#[derive(Clone, Copy, Debug)] +#[repr(C)] +pub struct mmst_reg { + pub mmst_reg: [u8; 10], + pub rsrv: [u8; 6], +} + +#[derive(Clone, Copy, Debug)] +#[repr(C)] +pub struct xmm_reg([u8; 16]); + +#[derive(Clone, Copy, Debug)] +#[repr(C)] +pub struct x86_float_state64 { + pub fpu_reserved: [c_int; 2], + pub fpu_fcw: c_short, + pub fpu_fsw: c_short, + pub fpu_ftw: u8, + pub fpu_rsrv1: u8, + pub fpu_fop: u16, + pub fpu_ip: u32, + pub fpu_cs: u16, + pub fpu_rsrv2: u16, + pub fpu_dp: u32, + pub fpu_ds: u16, + pub fpu_rsrv3: u16, + pub fpu_mxcsr: u32, + pub fpu_mxcsrmask: u32, + pub fpu_stmm0: mmst_reg, + pub fpu_stmm1: mmst_reg, + pub fpu_stmm2: mmst_reg, + pub fpu_stmm3: mmst_reg, + pub fpu_stmm4: mmst_reg, + pub fpu_stmm5: mmst_reg, + pub fpu_stmm6: mmst_reg, + pub fpu_stmm7: mmst_reg, + pub fpu_xmm0: xmm_reg, + pub fpu_xmm1: xmm_reg, + pub fpu_xmm2: xmm_reg, + pub fpu_xmm3: xmm_reg, + pub fpu_xmm4: xmm_reg, + pub fpu_xmm5: xmm_reg, + pub fpu_xmm6: xmm_reg, + pub fpu_xmm7: xmm_reg, + pub fpu_xmm8: xmm_reg, + pub fpu_xmm9: xmm_reg, + pub fpu_xmm10: xmm_reg, + pub fpu_xmm11: xmm_reg, + pub fpu_xmm12: xmm_reg, + pub fpu_xmm13: xmm_reg, + pub fpu_xmm14: xmm_reg, + pub fpu_xmm15: xmm_reg, + pub fpu_rsrv4_0: [u8; 16], + pub fpu_rsrv4_1: [u8; 16], + pub fpu_rsrv4_2: [u8; 16], + pub fpu_rsrv4_3: [u8; 16], + pub fpu_rsrv4_4: [u8; 16], + pub fpu_rsrv4_5: [u8; 16], + pub fpu_reserved1: c_int, +} + +#[derive(Clone, Copy, Debug)] +#[repr(C)] +pub struct mcontext64 { + pub es: x86_exception_state64, + pub ss: x86_thread_state64, + pub fs: x86_float_state64, +} +#[derive(Clone, Copy, Debug)] +#[repr(C)] +pub struct ucontext_t { + pub uc_onstack: c_int, + pub uc_sigmask: sigset_t, + pub uc_stack: sigaltstack, + pub uc_link: *const ucontext_t, + pub uc_mcsize: size_t, + pub uc_mcontext: *const mcontext64, + mcontext_data: mcontext64, +} + +#[derive(Clone, Copy, Debug)] +pub struct UContextPtr(*const ucontext_t); + +impl UContextPtr { + #[inline] + pub fn new(ptr: *const c_void) -> Self { + assert!(!ptr.is_null(), "non-null context"); + UContextPtr(ptr as *const ucontext_t) + } + + #[inline] + pub fn get_ip(&self) -> *const c_void { + let mcontext = &unsafe { *(self.0) }.mcontext_data; + mcontext.ss.rip as *const _ + } +} + +#[derive(Clone, Copy)] +pub struct UContext { + context: ucontext_t, +} + +impl UContext { + #[inline] + pub fn new(ptr: *const c_void) -> Self { + UContext { + context: *unsafe { + (ptr as *const ucontext_t) + .as_ref() + .expect("non-null context") + }, + } + } +} + +impl Into for UContextPtr { + #[inline] + fn into(self) -> UContext { + UContext { + context: unsafe { *(self.0) }, + } + } +} + +impl Into for UContext { + #[inline] + fn into(self) -> UContextPtr { + UContextPtr::new(&self.context as *const _ as *const _) + } +} diff --git a/lucet-runtime/lucet-runtime-internals/src/sysdeps/mod.rs b/lucet-runtime/lucet-runtime-internals/src/sysdeps/mod.rs new file mode 100644 index 000000000..8f9247c4f --- /dev/null +++ b/lucet-runtime/lucet-runtime-internals/src/sysdeps/mod.rs @@ -0,0 +1,11 @@ +#[cfg(target_os = "macos")] +mod macos; + +#[cfg(target_os = "linux")] +mod linux; + +#[cfg(target_os = "macos")] +pub use macos::*; + +#[cfg(target_os = "linux")] +pub use linux::*; diff --git a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs index fc8347fb9..104f77e02 100644 --- a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs +++ b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs @@ -143,7 +143,7 @@ macro_rules! guest_fault_tests { ptr::null_mut(), 4096, ProtFlags::PROT_NONE, - MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, + MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, 0, 0, ) diff --git a/lucet-runtime/lucet-runtime-tests/src/guest_fault/traps.S b/lucet-runtime/lucet-runtime-tests/src/guest_fault/traps.S index 1cd602d78..f7df486ec 100644 --- a/lucet-runtime/lucet-runtime-tests/src/guest_fault/traps.S +++ b/lucet-runtime/lucet-runtime-tests/src/guest_fault/traps.S @@ -1,8 +1,13 @@ .text .globl guest_func_illegal_instr # -- Begin function guest_func_illegal_instr +#ifdef __ELF__ + .type guest_func_illegal_instr,@function +#else + .globl _guest_func_illegal_instr +#endif .p2align 4, 0x90 - .type guest_func_illegal_instr,@function guest_func_illegal_instr: # @guest_func_illegal_instr +_guest_func_illegal_instr: .cfi_startproc # %bb.0: pushq %rbp @@ -18,13 +23,20 @@ guest_func_illegal_instr: # @guest_func_illegal_instr .cfi_def_cfa %rsp, 8 retq .Lfunc_end0: - .size guest_func_illegal_instr, .Lfunc_end0-guest_func_illegal_instr +#ifdef ___ELF__ + .size guest_func_illegal_instr, .Lfunc_end0-guest_func_illegal_instr +#endif .cfi_endproc # -- End function .globl guest_func_oob # -- Begin function guest_func_oob - .p2align 4, 0x90 +#ifdef __ELF__ .type guest_func_oob,@function +#else + .globl _guest_func_oob +#endif + .p2align 4, 0x90 guest_func_oob: # @guest_func_oob +_guest_func_oob: .cfi_startproc # %bb.0: pushq %rbp @@ -35,7 +47,11 @@ guest_func_oob: # @guest_func_oob subq $16, %rsp movq %rdi, -8(%rbp) movq -8(%rbp), %rdi +#ifdef __ELF__ callq lucet_vmctx_get_heap@PLT +#else + callq _lucet_vmctx_get_heap +#endif movq %rax, -16(%rbp) movq -16(%rbp), %rax movb $0, 65537(%rax) @@ -44,8 +60,11 @@ guest_func_oob: # @guest_func_oob .cfi_def_cfa %rsp, 8 retq .Lfunc_end1: - .size guest_func_oob, .Lfunc_end1-guest_func_oob +#ifdef __ELF__ + .size guest_func_oob, .Lfunc_end1-guest_func_oob +#endif .cfi_endproc - # -- End function - .ident "clang version 7.0.1-svn348686-1~exp1~20181221231927.53 (branches/release_70)" + +#if defined(__linux__) && defined(__ELF__) .section ".note.GNU-stack","",@progbits +#endif diff --git a/lucet-wasi/build.rs b/lucet-wasi/build.rs index e22dce5da..11bd974cc 100644 --- a/lucet-wasi/build.rs +++ b/lucet-wasi/build.rs @@ -6,14 +6,34 @@ use std::process::{Command, Stdio}; fn main() { let wasi_sdk = Path::new(&env::var("WASI_SDK").unwrap_or("/opt/wasi-sdk".to_owned())).to_path_buf(); + let wasi_sysroot = match env::var("WASI_SYSROOT") { + Ok(wasi_sysroot) => Path::new(&wasi_sysroot).to_path_buf(), + Err(_) => wasi_sdk.join("share/sysroot"), + }; + let clang_root = match env::var("CLANG_ROOT") { + Ok(clang_root) => Path::new(&clang_root).to_path_buf(), + Err(_) => wasi_sdk.join("lib/clang/8.0.0"), + }; + assert!( + wasi_sysroot.exists(), + "wasi-sysroot not present at {:?}", + wasi_sysroot + ); + assert!( + clang_root.exists(), + "clang-root not present at {:?}", + clang_root + ); - assert!(wasi_sdk.exists(), "wasi-sdk not present at {:?}", wasi_sdk); + let wasi_sysroot_core_h = wasi_sysroot.join("include/wasi/core.h"); - let wasi_sdk_core_h = wasi_sdk.join("share/sysroot/include/wasi/core.h"); + assert!( + wasi_sysroot_core_h.exists(), + "wasi-sysroot core.h not present at {:?}", + wasi_sysroot_core_h + ); - assert!(wasi_sdk_core_h.exists(), "wasi-sdk core.h not present at {:?}", wasi_sdk_core_h); - - println!("cargo:rerun-if-changed={}", wasi_sdk_core_h.display()); + println!("cargo:rerun-if-changed={}", wasi_sysroot_core_h.display()); let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); @@ -25,7 +45,7 @@ fn main() { let sed_result = Command::new("sed") .arg("-E") .arg(r#"s/U?INT[0-9]+_C\(((0x)?[0-9]+)\)/\1/g"#) - .arg(wasi_sdk_core_h) + .arg(wasi_sysroot_core_h) .stdout(Stdio::from(core_h)) .status() .expect("can execute sed"); @@ -34,18 +54,15 @@ fn main() { // something failed, but how? match sed_result.code() { Some(code) => panic!("sed failed with code {}", code), - None => panic!("sed exited abnormally") + None => panic!("sed exited abnormally"), } } let host_builder = bindgen::Builder::default() .clang_arg("-nostdinc") .clang_arg("-D__wasi__") - .clang_arg(format!( - "-isystem={}/share/sysroot/include/", - wasi_sdk.display() - )) - .clang_arg(format!("-I{}/lib/clang/8.0.0/include/", wasi_sdk.display())) + .clang_arg(format!("-isystem={}/include/", wasi_sysroot.display())) + .clang_arg(format!("-I{}/include/", clang_root.display())) .header(core_h_path.to_str().unwrap()) .whitelist_type("__wasi_.*") .whitelist_var("__WASI_.*"); diff --git a/lucet-wasi/src/host.rs b/lucet-wasi/src/host.rs index 09ac169c1..d7e085d14 100644 --- a/lucet-wasi/src/host.rs +++ b/lucet-wasi/src/host.rs @@ -98,6 +98,12 @@ pub fn errno_from_nix(errno: nix::errno::Errno) -> __wasi_errno_t { e as __wasi_errno_t } +#[cfg(target_os = "linux")] +const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_RSYNC; + +#[cfg(not(target_os = "linux"))] +const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_SYNC; + pub fn nix_from_fdflags(fdflags: __wasi_fdflags_t) -> nix::fcntl::OFlag { use nix::fcntl::OFlag; let mut nix_flags = OFlag::empty(); @@ -111,7 +117,7 @@ pub fn nix_from_fdflags(fdflags: __wasi_fdflags_t) -> nix::fcntl::OFlag { nix_flags.insert(OFlag::O_NONBLOCK); } if fdflags & (__WASI_FDFLAG_RSYNC as __wasi_fdflags_t) != 0 { - nix_flags.insert(OFlag::O_RSYNC); + nix_flags.insert(O_RSYNC); } if fdflags & (__WASI_FDFLAG_SYNC as __wasi_fdflags_t) != 0 { nix_flags.insert(OFlag::O_SYNC); @@ -131,7 +137,7 @@ pub fn fdflags_from_nix(oflags: nix::fcntl::OFlag) -> __wasi_fdflags_t { if oflags.contains(OFlag::O_NONBLOCK) { fdflags |= __WASI_FDFLAG_NONBLOCK; } - if oflags.contains(OFlag::O_RSYNC) { + if oflags.contains(O_RSYNC) { fdflags |= __WASI_FDFLAG_RSYNC; } if oflags.contains(OFlag::O_SYNC) { diff --git a/lucet-wasi/src/hostcalls.rs b/lucet-wasi/src/hostcalls.rs index 431c815e9..fab47b37c 100644 --- a/lucet-wasi/src/hostcalls.rs +++ b/lucet-wasi/src/hostcalls.rs @@ -24,6 +24,12 @@ use std::os::unix::prelude::{FromRawFd, OsStrExt, OsStringExt, RawFd}; use std::time::SystemTime; use std::{cmp, slice}; +#[cfg(target_os = "linux")] +const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_RSYNC; + +#[cfg(not(target_os = "linux"))] +const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_SYNC; + #[no_mangle] pub extern "C" fn __wasi_proc_exit(vmctx: *mut lucet_vmctx, rval: wasm32::__wasi_exitcode_t) -> ! { let mut vmctx = unsafe { Vmctx::from_raw(vmctx) }; @@ -618,7 +624,7 @@ pub extern "C" fn __wasi_path_open( if nix_all_oflags.contains(OFlag::O_DSYNC) { needed_inheriting |= host::__WASI_RIGHT_FD_DATASYNC as host::__wasi_rights_t; } - if nix_all_oflags.intersects(OFlag::O_RSYNC | OFlag::O_SYNC) { + if nix_all_oflags.intersects(O_RSYNC | OFlag::O_SYNC) { needed_inheriting |= host::__WASI_RIGHT_FD_SYNC as host::__wasi_rights_t; } From 545e1f79bdfa78554dab182b834f8cc2c9215dd0 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Mon, 15 Apr 2019 20:56:48 +0200 Subject: [PATCH 047/512] For some reason, nix forgot to define unistd::sync() on macOS --- benchmarks/lucet-benchmarks/src/seq.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/lucet-benchmarks/src/seq.rs b/benchmarks/lucet-benchmarks/src/seq.rs index ffca2d13e..baa3c484b 100644 --- a/benchmarks/lucet-benchmarks/src/seq.rs +++ b/benchmarks/lucet-benchmarks/src/seq.rs @@ -30,7 +30,7 @@ fn load_mkregion_and_instantiate(c: &mut Criterion) { &format!("load_mkregion_and_instantiate ({})", R::TYPE_NAME), move |b| { b.iter_batched( - || nix::unistd::sync(), + || unsafe { nix::libc::sync() }, |_| body::(&so_file), criterion::BatchSize::PerIteration, ) From 6bed5e84791e68e0eb8b30eb9b9d91e7d53d2ae4 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Tue, 16 Apr 2019 17:30:21 +0200 Subject: [PATCH 048/512] Make expect() messages more explicit --- .../lucet-runtime-internals/src/instance/signals.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs index 7bd40dead..acba588a8 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs @@ -53,7 +53,8 @@ impl Instance { SigStackFlags::empty(), libc::SIGSTKSZ, ); - let saved_sigstack = unsafe { sigaltstack(&guest_sigstack).expect("sigaltstack succeeds") }; + let saved_sigstack = + unsafe { sigaltstack(&guest_sigstack).expect("saving sigaltstack succeeds") }; let mut ostate = LUCET_SIGNAL_STATE.lock().unwrap(); if let Some(ref mut state) = *ostate { @@ -74,7 +75,7 @@ impl Instance { if state.counter == 0 { unsafe { // restore the host signal stack - sigaltstack(&saved_sigstack).expect("sigaltstack succeeds"); + sigaltstack(&saved_sigstack).expect("sigaltstack restoration succeeds"); restore_host_signal_state(state); } true From ea9f41343d9955aa400bed2e708359ef9be0c099 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 18 Apr 2019 11:42:25 +0200 Subject: [PATCH 049/512] Check that INSTANCE_PADDING is correct This hard-coded padding size has been the cause of headaches in the original C version, because it may need to be adjusted every time a change is made to the `Instance` structure. Furthermore, the context is platform-dependent, so the padding cannot be one-size-fits-all. The globals pointer must be right at the end of the page, and the last member of the structure. This is documented, but not enforced in code. Reintroduce the checks making sure that this is the case. The `INSTANCE_PADDING` constant remains fragile, and we can probably find a better way to handle this. Even on Linux, I'm not convinced that the current value is correct on non-x86_64 architectures. The check can save quite a bit of debugging time when it's off. Also add the current value for macOS. We probably don't want a catchall value, as it is likely to be wrong on untested platforms. --- .../lucet-runtime-internals/src/instance.rs | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index f308a1096..23742c572 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -3,7 +3,7 @@ pub mod signals; pub use crate::instance::signals::{signal_handler_none, SignalBehavior, SignalHandler}; -use crate::alloc::Alloc; +use crate::alloc::{host_page_size, Alloc}; use crate::context::Context; use crate::embed_ctx::CtxMap; use crate::error::Error; @@ -23,7 +23,11 @@ use std::ptr::{self, NonNull}; use std::sync::Arc; pub const LUCET_INSTANCE_MAGIC: u64 = 746932922; + +#[cfg(target_os = "linux")] pub const INSTANCE_PADDING: usize = 2328; +#[cfg(target_os = "macos")] +pub const INSTANCE_PADDING: usize = 2648; thread_local! { /// The host context. @@ -458,7 +462,7 @@ impl Instance { impl Instance { fn new(alloc: Alloc, module: Arc, embed_ctx: CtxMap) -> Self { let globals_ptr = alloc.slot().globals as *mut i64; - Instance { + let inst = Instance { magic: LUCET_INSTANCE_MAGIC, embed_ctx: embed_ctx, module, @@ -473,7 +477,19 @@ impl Instance { entrypoint: ptr::null(), _reserved: [0; INSTANCE_PADDING], globals_ptr, - } + }; + + // Verify that globals_ptr is right before the end of a page, and that + // it is the last member of the structure. + let globals_ptr_offset = + &inst.globals_ptr as *const _ as usize - &inst as *const _ as usize; + let page_size = host_page_size(); + assert_eq!( + globals_ptr_offset + std::mem::size_of_val(&inst.globals_ptr), + page_size + ); + assert_eq!(std::mem::size_of_val(&inst), page_size); + inst } /// Run a function in guest context at the given entrypoint. From c89d889f35976ab97372d3d1e4afa1b6a614f4ec Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 18 Apr 2019 16:29:30 +0200 Subject: [PATCH 050/512] macOS: don't include the context data in the ucontext struct --- .../lucet-runtime-internals/src/instance.rs | 2 +- .../src/sysdeps/linux.rs | 13 +++---- .../src/sysdeps/macos.rs | 36 +++++++++---------- 3 files changed, 22 insertions(+), 29 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index 23742c572..ad86914e0 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -27,7 +27,7 @@ pub const LUCET_INSTANCE_MAGIC: u64 = 746932922; #[cfg(target_os = "linux")] pub const INSTANCE_PADDING: usize = 2328; #[cfg(target_os = "macos")] -pub const INSTANCE_PADDING: usize = 2648; +pub const INSTANCE_PADDING: usize = 2642; thread_local! { /// The host context. diff --git a/lucet-runtime/lucet-runtime-internals/src/sysdeps/linux.rs b/lucet-runtime/lucet-runtime-internals/src/sysdeps/linux.rs index fe8d05138..597df9edd 100644 --- a/lucet-runtime/lucet-runtime-internals/src/sysdeps/linux.rs +++ b/lucet-runtime/lucet-runtime-internals/src/sysdeps/linux.rs @@ -11,7 +11,7 @@ impl UContextPtr { } #[inline] - pub fn get_ip(&self) -> *const c_void { + pub fn get_ip(self) -> *const c_void { let mcontext = &unsafe { *(self.0) }.uc_mcontext; mcontext.gregs[REG_RIP as usize] as *const _ } @@ -33,6 +33,10 @@ impl UContext { }, } } + + pub fn as_ptr(&mut self) -> UContextPtr { + UContextPtr::new(&self.context as *const _ as *const _) + } } impl Into for UContextPtr { @@ -43,10 +47,3 @@ impl Into for UContextPtr { } } } - -impl Into for UContext { - #[inline] - fn into(self) -> UContextPtr { - UContextPtr::new(&self.context as *const _ as *const _) - } -} diff --git a/lucet-runtime/lucet-runtime-internals/src/sysdeps/macos.rs b/lucet-runtime/lucet-runtime-internals/src/sysdeps/macos.rs index 65c663c55..dec08e56a 100644 --- a/lucet-runtime/lucet-runtime-internals/src/sysdeps/macos.rs +++ b/lucet-runtime/lucet-runtime-internals/src/sysdeps/macos.rs @@ -119,7 +119,6 @@ pub struct ucontext_t { pub uc_link: *const ucontext_t, pub uc_mcsize: size_t, pub uc_mcontext: *const mcontext64, - mcontext_data: mcontext64, } #[derive(Clone, Copy, Debug)] @@ -133,8 +132,8 @@ impl UContextPtr { } #[inline] - pub fn get_ip(&self) -> *const c_void { - let mcontext = &unsafe { *(self.0) }.mcontext_data; + pub fn get_ip(self) -> *const c_void { + let mcontext = &unsafe { *(*self.0).uc_mcontext }; mcontext.ss.rip as *const _ } } @@ -142,33 +141,30 @@ impl UContextPtr { #[derive(Clone, Copy)] pub struct UContext { context: ucontext_t, + mcontext: mcontext64, } impl UContext { #[inline] pub fn new(ptr: *const c_void) -> Self { - UContext { - context: *unsafe { - (ptr as *const ucontext_t) - .as_ref() - .expect("non-null context") - }, - } + let context = *unsafe { + (ptr as *const ucontext_t) + .as_ref() + .expect("non-null context") + }; + let mcontext = unsafe { *context.uc_mcontext }; + UContext { context, mcontext } } -} -impl Into for UContextPtr { - #[inline] - fn into(self) -> UContext { - UContext { - context: unsafe { *(self.0) }, - } + pub fn as_ptr(&mut self) -> UContextPtr { + self.context.uc_mcontext = &self.mcontext; + UContextPtr::new(&self.context as *const _ as *const _) } } -impl Into for UContext { +impl Into for UContextPtr { #[inline] - fn into(self) -> UContextPtr { - UContextPtr::new(&self.context as *const _ as *const _) + fn into(self) -> UContext { + UContext::new(self.0 as *const _) } } From 3cd013ee055a4fe58360bdd71acdeea0a63bd267 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 18 Apr 2019 12:01:02 +0200 Subject: [PATCH 051/512] Update README.md now that we have basic support for macOS --- README.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index e738bc6a9..80ce48dea 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,8 @@ Lucet supports running WebAssembly programs written in C (via `clang`), Rust, and AssemblyScript. It does not yet support the entire WebAssembly spec, but full support is [coming in the near future](#lucet-spectest). -Lucet's runtime currently only supports x86-64 based Linux systems. +Lucet's runtime currently only supports x86-64 based Linux systems, with +experimental support for macOS. ## Contents @@ -163,12 +164,8 @@ such as instance creation and teardown, in `/benchmarks/lucet-benchmarks`. ### Operating System -Lucet is developed and tested on Linux. We expect it to work on any POSIX -system which supports ELF. - -Experimentally, we have shown that supporting Mac OS (which uses the Mach-O -executable format instead of ELF) is possible, but it is not supported at this -time. +Lucet is developed and tested on Linux and macOS. We expect it to work on any +POSIX system which supports shared libraries. ### Dependencies From cb3ed91636c196e06e2af711089869ede57fbe4d Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 18 Apr 2019 14:14:42 +0200 Subject: [PATCH 052/512] Nits --- .../src/instance/signals.rs | 2 +- lucet-wasi-sdk/src/lib.rs | 25 ++++++---- lucet-wasi/build.rs | 47 ++++++++++++++----- 3 files changed, 52 insertions(+), 22 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs index acba588a8..0fe7a97e0 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs @@ -111,7 +111,7 @@ extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext // Safety: when using a SA_SIGINFO sigaction, the third argument can be cast to a `ucontext_t` // pointer per the manpage - assert!(!ucontext_ptr.is_null()); + assert!(!ucontext_ptr.is_null(), "ucontext_ptr must not be null"); let ctx = UContextPtr::new(ucontext_ptr); let rip = ctx.get_ip(); diff --git a/lucet-wasi-sdk/src/lib.rs b/lucet-wasi-sdk/src/lib.rs index cc77a5caf..6f1fce361 100644 --- a/lucet-wasi-sdk/src/lib.rs +++ b/lucet-wasi-sdk/src/lib.rs @@ -46,11 +46,20 @@ impl CompileError { } } -fn wasi_sdk_clang() -> PathBuf { - let mut base = PathBuf::from(env::var("WASI_SDK").unwrap_or("/opt/wasi-sdk".to_owned())); - base.push("bin"); - base.push("clang"); - base +fn wasi_sdk() -> PathBuf { + Path::new(&env::var("WASI_SDK").unwrap_or("/opt/wasi-sdk".to_owned())).to_path_buf() +} + +fn wasm_clang() -> PathBuf { + match env::var("CLANG") { + Ok(clang) => Path::new(&clang).to_path_buf(), + Err(_) => { + let mut path = wasi_sdk(); + path.push("bin"); + path.push("clang"); + path + } + } } pub struct Compile { @@ -106,7 +115,7 @@ impl Compile { } pub fn compile>(&self, output: P) -> Result<(), CompileError> { - let clang = wasi_sdk_clang(); + let clang = wasm_clang(); if !clang.exists() { Err(CompileError::FileNotFound( clang.to_string_lossy().into_owned(), @@ -158,7 +167,7 @@ impl Link { } pub fn link>(&self, output: P) -> Result<(), CompileError> { - let clang = wasi_sdk_clang(); + let clang = wasm_clang(); if !clang.exists() { Err(CompileError::FileNotFound( clang.to_string_lossy().into_owned(), @@ -301,7 +310,7 @@ mod tests { use tempfile::TempDir; #[test] fn wasi_sdk_installed() { - let clang = wasi_sdk_clang(); + let clang = wasm_clang(); assert!(clang.exists(), "clang executable exists"); } diff --git a/lucet-wasi/build.rs b/lucet-wasi/build.rs index 11bd974cc..0e39fb489 100644 --- a/lucet-wasi/build.rs +++ b/lucet-wasi/build.rs @@ -3,26 +3,47 @@ use std::fs::File; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; -fn main() { - let wasi_sdk = - Path::new(&env::var("WASI_SDK").unwrap_or("/opt/wasi-sdk".to_owned())).to_path_buf(); - let wasi_sysroot = match env::var("WASI_SYSROOT") { +fn wasi_sdk() -> PathBuf { + Path::new(&env::var("WASI_SDK").unwrap_or("/opt/wasi-sdk".to_owned())).to_path_buf() +} + +fn wasi_sysroot() -> PathBuf { + match env::var("WASI_SYSROOT") { Ok(wasi_sysroot) => Path::new(&wasi_sysroot).to_path_buf(), - Err(_) => wasi_sdk.join("share/sysroot"), - }; - let clang_root = match env::var("CLANG_ROOT") { - Ok(clang_root) => Path::new(&clang_root).to_path_buf(), - Err(_) => wasi_sdk.join("lib/clang/8.0.0"), - }; + Err(_) => { + let mut path = wasi_sdk(); + path.push("share"); + path.push("sysroot"); + path + } + } +} + +fn wasm_clang_root() -> PathBuf { + match env::var("CLANG_ROOT") { + Ok(clang) => Path::new(&clang).to_path_buf(), + Err(_) => { + let mut path = wasi_sdk(); + path.push("lib"); + path.push("clang"); + path.push("8.0.0"); + path + } + } +} + +fn main() { + let wasi_sysroot = wasi_sysroot(); + let wasm_clang_root = wasm_clang_root(); assert!( wasi_sysroot.exists(), "wasi-sysroot not present at {:?}", wasi_sysroot ); assert!( - clang_root.exists(), + wasm_clang_root.exists(), "clang-root not present at {:?}", - clang_root + wasm_clang_root ); let wasi_sysroot_core_h = wasi_sysroot.join("include/wasi/core.h"); @@ -62,7 +83,7 @@ fn main() { .clang_arg("-nostdinc") .clang_arg("-D__wasi__") .clang_arg(format!("-isystem={}/include/", wasi_sysroot.display())) - .clang_arg(format!("-I{}/include/", clang_root.display())) + .clang_arg(format!("-I{}/include/", wasm_clang_root.display())) .header(core_h_path.to_str().unwrap()) .whitelist_type("__wasi_.*") .whitelist_var("__WASI_.*"); From 5800a5e4155713129ba9a23f8f90b8ba1e8023c9 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 18 Apr 2019 14:32:14 +0200 Subject: [PATCH 053/512] Make lucet-wasi-sdk work with a standard LLVM install --- lucet-wasi-sdk/src/lib.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lucet-wasi-sdk/src/lib.rs b/lucet-wasi-sdk/src/lib.rs index 6f1fce361..429bf8420 100644 --- a/lucet-wasi-sdk/src/lib.rs +++ b/lucet-wasi-sdk/src/lib.rs @@ -5,6 +5,8 @@ use std::path::{Path, PathBuf}; use std::process::{Command, Output}; use tempfile::TempDir; +const WASI_TARGET: &str = "wasm32-unknown-wasi"; + #[derive(Debug, Fail)] pub enum CompileError { #[fail(display = "File not found: {}", _0)] @@ -50,6 +52,18 @@ fn wasi_sdk() -> PathBuf { Path::new(&env::var("WASI_SDK").unwrap_or("/opt/wasi-sdk".to_owned())).to_path_buf() } +fn wasi_sysroot() -> PathBuf { + match env::var("WASI_SYSROOT") { + Ok(wasi_sysroot) => Path::new(&wasi_sysroot).to_path_buf(), + Err(_) => { + let mut path = wasi_sdk(); + path.push("share"); + path.push("sysroot"); + path + } + } +} + fn wasm_clang() -> PathBuf { match env::var("CLANG") { Ok(clang) => Path::new(&clang).to_path_buf(), @@ -127,6 +141,8 @@ impl Compile { ))?; } let mut cmd = Command::new(clang); + cmd.arg(format!("--target={}", WASI_TARGET)); + cmd.arg(format!("--sysroot={}", wasi_sysroot().display())); cmd.arg("-c"); cmd.arg(self.input.clone()); cmd.arg("-o"); From d36bd105ab97572d16db905fdb4a3a2ea00225f3 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 18 Apr 2019 20:08:54 +0200 Subject: [PATCH 054/512] Don't use hard-coded padding sizes any more for the Instance struct --- .../lucet-runtime-internals/Cargo.toml | 2 +- .../lucet-runtime-internals/src/alloc/mod.rs | 2 +- .../lucet-runtime-internals/src/instance.rs | 81 ++++++++----------- 3 files changed, 34 insertions(+), 51 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index fb108348f..8d0fa76d0 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -12,6 +12,7 @@ failure = "0.1" lazy_static = "1.1" libc = "0.2.47" libloading = "0.5" +memoffset = "0.2" nix = "0.13" num-derive = "0.2" num-traits = "0.2" @@ -19,7 +20,6 @@ xfailure = "0.1" [dev-dependencies] byteorder = "1.2" -memoffset = "0.2" [build-dependencies] cc = "1.0" diff --git a/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs b/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs index d9d7bb55a..b45d1fd0a 100644 --- a/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs @@ -5,7 +5,7 @@ use libc::{c_void, SIGSTKSZ}; use nix::unistd::{sysconf, SysconfVar}; use std::sync::{Arc, Once, Weak}; -const HOST_PAGE_SIZE_EXPECTED: usize = 4096; +pub const HOST_PAGE_SIZE_EXPECTED: usize = 4096; static mut HOST_PAGE_SIZE: usize = 0; static HOST_PAGE_SIZE_INIT: Once = Once::new(); diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index ad86914e0..198865c59 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -3,7 +3,7 @@ pub mod signals; pub use crate::instance::signals::{signal_handler_none, SignalBehavior, SignalHandler}; -use crate::alloc::{host_page_size, Alloc}; +use crate::alloc::{Alloc, HOST_PAGE_SIZE_EXPECTED}; use crate::context::Context; use crate::embed_ctx::CtxMap; use crate::error::Error; @@ -14,6 +14,7 @@ use crate::trapcode::{TrapCode, TrapCodeType}; use crate::val::{UntypedRetVal, Val}; use crate::WASM_PAGE_SIZE; use libc::{c_void, siginfo_t, uintptr_t, SIGBUS, SIGSEGV}; +use memoffset::offset_of; use std::any::Any; use std::cell::{RefCell, UnsafeCell}; use std::ffi::{CStr, CString}; @@ -24,11 +25,6 @@ use std::sync::Arc; pub const LUCET_INSTANCE_MAGIC: u64 = 746932922; -#[cfg(target_os = "linux")] -pub const INSTANCE_PADDING: usize = 2328; -#[cfg(target_os = "macos")] -pub const INSTANCE_PADDING: usize = 2642; - thread_local! { /// The host context. /// @@ -156,6 +152,7 @@ impl Drop for InstanceHandle { /// and their fields are never moved in memory, otherwise raw pointers in the metadata could be /// unsafely invalidated. #[repr(C)] +#[repr(align(4096))] pub struct Instance { /// Used to catch bugs in pointer math used to find the address of the instance magic: u64, @@ -197,14 +194,7 @@ pub struct Instance { /// Pointer to the function used as the entrypoint (for use in backtraces) entrypoint: *const extern "C" fn(), - /// Padding to ensure the pointer to globals at the end of the page occupied by the `Instance` - _reserved: [u8; INSTANCE_PADDING], - - /// Pointer to the globals - /// - /// This is accessed through the `vmctx` pointer, which points to the heap that begins - /// immediately after this struct, so it has to come at the very end. - globals_ptr: *const i64, + _padding: (), } /// APIs that are internal, but useful to implementors of extension modules; you probably don't want @@ -462,7 +452,7 @@ impl Instance { impl Instance { fn new(alloc: Alloc, module: Arc, embed_ctx: CtxMap) -> Self { let globals_ptr = alloc.slot().globals as *mut i64; - let inst = Instance { + let mut inst = Instance { magic: LUCET_INSTANCE_MAGIC, embed_ctx: embed_ctx, module, @@ -475,23 +465,38 @@ impl Instance { c_fatal_handler: None, signal_handler: Box::new(signal_handler_none) as Box, entrypoint: ptr::null(), - _reserved: [0; INSTANCE_PADDING], - globals_ptr, + _padding: (), }; + inst.set_globals_ptr(globals_ptr); - // Verify that globals_ptr is right before the end of a page, and that - // it is the last member of the structure. - let globals_ptr_offset = - &inst.globals_ptr as *const _ as usize - &inst as *const _ as usize; - let page_size = host_page_size(); - assert_eq!( - globals_ptr_offset + std::mem::size_of_val(&inst.globals_ptr), - page_size - ); - assert_eq!(std::mem::size_of_val(&inst), page_size); + assert_eq!(mem::size_of::(), HOST_PAGE_SIZE_EXPECTED); + let unpadded_size = offset_of!(Instance, _padding); + assert!(unpadded_size <= HOST_PAGE_SIZE_EXPECTED - mem::size_of::<*mut i64>()); inst } + // The globals pointer must be stored right before the end of the structure, padded to the page size, + // so that it is 8 bytes before the heap. + // For this reason, the alignment of the structure is set to 4096, and we define accessors that + // read/write the globals pointer as bytes [4096-8..4096] of that structure represented as raw bytes. + #[inline] + pub fn get_globals_ptr(&self) -> *const i64 { + unsafe { + *((self as *const _ as *const u8) + .offset((HOST_PAGE_SIZE_EXPECTED - mem::size_of::<*mut i64>()) as isize) + as *const *const i64) + } + } + + #[inline] + pub fn set_globals_ptr(&mut self, globals_ptr: *const i64) { + unsafe { + *((self as *mut _ as *mut u8) + .offset((HOST_PAGE_SIZE_EXPECTED - mem::size_of::<*mut i64>()) as isize) + as *mut *const i64) = globals_ptr; + } + } + /// Run a function in guest context at the given entrypoint. fn run_func( &mut self, @@ -844,25 +849,3 @@ extern "C" { fn strsignal_wrapper(sig: libc::c_int) -> CString { unsafe { CStr::from_ptr(strsignal(sig)).to_owned() } } - -#[cfg(test)] -mod tests { - use super::*; - use memoffset::offset_of; - - #[test] - fn instance_size_correct() { - assert_eq!(mem::size_of::(), 4096); - } - - #[test] - fn instance_globals_offset_correct() { - let offset = offset_of!(Instance, globals_ptr) as isize; - if offset != 4096 - 8 { - let diff = 4096 - 8 - offset; - let new_padding = INSTANCE_PADDING as isize + diff; - panic!("new padding should be: {:?}", new_padding); - } - assert_eq!(offset_of!(Instance, globals_ptr), 4096 - 8); - } -} From 1a2fb87b9e2b4b05eb9eef96c75b1900da94325f Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 18 Apr 2019 20:44:14 +0200 Subject: [PATCH 055/512] Explain what _padding is for --- lucet-runtime/lucet-runtime-internals/src/instance.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index 198865c59..a89872dcf 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -194,6 +194,9 @@ pub struct Instance { /// Pointer to the function used as the entrypoint (for use in backtraces) entrypoint: *const extern "C" fn(), + /// `_padding` must be the last member of the structure. + /// This marks where the padding starts to make the structure exactly 4096 bytes long. + /// It is also used to compute the size of the structure up to that point, i.e. without padding. _padding: (), } From 6458b21430d43e6ed3026d71eba4a54cd50b8fda Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 19 Apr 2019 15:20:31 +0200 Subject: [PATCH 056/512] ucontext is not POSIX, but an X/Open extension - define _XOPEN_SOURCE Also move the ucontext.h inclusion to where it is used --- lucet-runtime/include/lucet.h | 1 - lucet-runtime/include/lucet_types.h | 5 +++++ lucet-runtime/lucet-runtime-internals/src/sysdeps/macos.rs | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lucet-runtime/include/lucet.h b/lucet-runtime/include/lucet.h index f464771f2..2c3385cd8 100644 --- a/lucet-runtime/include/lucet.h +++ b/lucet-runtime/include/lucet.h @@ -6,7 +6,6 @@ #include #include #include -#include #include "lucet_types.h" #include "lucet_val.h" diff --git a/lucet-runtime/include/lucet_types.h b/lucet-runtime/include/lucet_types.h index 717369af8..4465f8766 100644 --- a/lucet-runtime/include/lucet_types.h +++ b/lucet-runtime/include/lucet_types.h @@ -1,10 +1,15 @@ #ifndef LUCET_TYPES_H #define LUCET_TYPES_H +#ifndef _XOPEN_SOURCE +# define _XOPEN_SOURCE 500 +#endif + #include #include #include #include +#include enum lucet_error { lucet_error_ok, diff --git a/lucet-runtime/lucet-runtime-internals/src/sysdeps/macos.rs b/lucet-runtime/lucet-runtime-internals/src/sysdeps/macos.rs index dec08e56a..3ea2e1c86 100644 --- a/lucet-runtime/lucet-runtime-internals/src/sysdeps/macos.rs +++ b/lucet-runtime/lucet-runtime-internals/src/sysdeps/macos.rs @@ -139,6 +139,7 @@ impl UContextPtr { } #[derive(Clone, Copy)] +#[repr(C)] pub struct UContext { context: ucontext_t, mcontext: mcontext64, From 0963936f8dce23738d76eb6b2480dc844aad0086 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 19 Apr 2019 15:24:11 +0200 Subject: [PATCH 057/512] Apple prefers to --- lucet-runtime/include/lucet_types.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lucet-runtime/include/lucet_types.h b/lucet-runtime/include/lucet_types.h index 4465f8766..7d032339a 100644 --- a/lucet-runtime/include/lucet_types.h +++ b/lucet-runtime/include/lucet_types.h @@ -9,7 +9,12 @@ #include #include #include -#include + +#ifdef __APPLE__ +# include +#else +# include +#endif enum lucet_error { lucet_error_ok, From e7921cdf51b4a96a954c62faa2556892b5936ca4 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 19 Apr 2019 15:25:34 +0200 Subject: [PATCH 058/512] Replace static link flags with link options Instead of hard-coded, linker-specific command-line flags, define a portable set of options to express the intent. These options are then converted into the correct set of command-line flags for the given linker. We may eventually want to do the same thing for the compiler, but this is not really necessary for now since clang is all we support. --- lucet-builtins/Makefile | 1 + .../lucet-runtime-tests/src/build.rs | 8 +- lucet-wasi-sdk/src/lib.rs | 90 +++++++++++++++---- lucetc/tests/wasi-sdk.rs | 8 +- 4 files changed, 84 insertions(+), 23 deletions(-) diff --git a/lucet-builtins/Makefile b/lucet-builtins/Makefile index 3913d3011..8efea1fd6 100644 --- a/lucet-builtins/Makefile +++ b/lucet-builtins/Makefile @@ -17,6 +17,7 @@ build/%.o: src/%.c $(CC) $(COMMON_CFLAGS) -c $^ -o $@ build/libbuiltins.so: $(LIBBUILTINS_OBJS) + $(CC) -Wl,-U,_lucet_vmctx_current_memory -Wl,-U,_lucet_vmctx_get_heap -shared $^ -o $@ 2> /dev/null || \ $(CC) -shared $^ -o $@ .PHONY: clean diff --git a/lucet-runtime/lucet-runtime-tests/src/build.rs b/lucet-runtime/lucet-runtime-tests/src/build.rs index 56167acd8..479da2d3e 100644 --- a/lucet-runtime/lucet-runtime-tests/src/build.rs +++ b/lucet-runtime/lucet-runtime-tests/src/build.rs @@ -1,6 +1,6 @@ use failure::Error; use lucet_runtime_internals::module::DlModule; -use lucet_wasi_sdk::{CompileOpts, Link, LinkOpts}; +use lucet_wasi_sdk::{CompileOpts, Link, LinkOpt, LinkOpts}; use lucetc::{Bindings, Lucetc, LucetcOpts}; use std::path::{Path, PathBuf}; use std::sync::Arc; @@ -31,9 +31,9 @@ where let wasm_build = Link::new(&[c_file]) .with_cflag("-nostartfiles") - .with_ldflag("--no-entry") - .with_ldflag("--allow-undefined") - .with_ldflag("--export-all"); + .with_link_opt(LinkOpt::NoDefaultEntryPoint) + .with_link_opt(LinkOpt::AllowUndefinedAll) + .with_link_opt(LinkOpt::ExportAll); let wasm_file = workdir.path().join("out.wasm"); diff --git a/lucet-wasi-sdk/src/lib.rs b/lucet-wasi-sdk/src/lib.rs index 429bf8420..cf2638f54 100644 --- a/lucet-wasi-sdk/src/lib.rs +++ b/lucet-wasi-sdk/src/lib.rs @@ -170,7 +170,7 @@ impl Link { ldflags: vec![], print_output: false, } - .with_ldflag("--no-threads") + .with_link_opt(LinkOpt::DefaultOpts) } pub fn print_output(&mut self, print: bool) { @@ -221,28 +221,88 @@ impl AsLink for Link { } } +#[derive(Clone, Copy, Debug)] +pub enum LinkOpt<'t> { + /// Allow references to an undefined function that will be resolved later by the dynamic linker + AllowUndefined(&'t str), + + /// Allow references to any undefined function. They will be resolved later by the dynamic linker + AllowUndefinedAll, + + /// Default options, possibly enabling workarounds for temporary bugs + DefaultOpts, + + /// Export a symbol + Export(&'t str), + + /// Preserve all the symbols during LTO, even if they are not used + ExportAll, + + /// Do not assume that the library has a predefined entry point + NoDefaultEntryPoint, + + /// Create a shared library + Shared, + + /// Do not put debug information (STABS or DWARF) in the output file + StripDebug, + + /// Remove functions and data that are unreachable by the entry point or exported symbols + StripUnused, +} + +impl<'t> LinkOpt<'t> { + #[cfg(target_os = "macos")] + fn as_ldflags(&self) -> Vec { + match self { + LinkOpt::AllowUndefined(_symbol) => vec![], + LinkOpt::AllowUndefinedAll => vec!["-undefined,dynamic_lookup".to_string()], + LinkOpt::DefaultOpts => vec![], + LinkOpt::Export(symbol) => vec![format!("-exported_symbol,{}", symbol).to_string()], + LinkOpt::ExportAll => vec!["-export_dynamic".to_string()], + LinkOpt::NoDefaultEntryPoint => vec![], + LinkOpt::Shared => vec!["-dylib".to_string()], + LinkOpt::StripDebug => vec!["-S".to_string()], + LinkOpt::StripUnused => vec!["-dead_strip".to_string()], + } + } + + #[cfg(not(target_os = "macos"))] + fn as_ldflags(&self) -> Vec { + match self { + LinkOpt::AllowUndefined(symbol) => vec![format!("-U,_{}", symbol).to_string()], + LinkOpt::AllowUndefinedAll => vec!["--allow-undefined".to_string()], + LinkOpt::DefaultOpts => vec!["--no-threads".to_string()], + LinkOpt::Export(symbol) => vec![format!("--export={}", symbol).to_string()], + LinkOpt::ExportAll => vec!["--export-all".to_string()], + LinkOpt::NoDefaultEntryPoint => vec!["--no-entry".to_string()], + LinkOpt::Shared => vec!["--shared".to_string()], + LinkOpt::StripDebug => vec!["-S".to_string()], + LinkOpt::StripUnused => vec!["--strip-discarded".to_string()], + } + } +} + pub trait LinkOpts { - fn ldflag>(&mut self, ldflag: S); - fn with_ldflag>(self, ldflag: S) -> Self; + fn link_opt(&mut self, link_opt: LinkOpt); + fn with_link_opt(self, link_opt: LinkOpt) -> Self; fn export>(&mut self, export: S); fn with_export>(self, export: S) -> Self; } impl LinkOpts for T { - fn ldflag>(&mut self, ldflag: S) { - self.as_link().ldflags.push(ldflag.as_ref().to_owned()); + fn link_opt(&mut self, link_opt: LinkOpt) { + self.as_link().ldflags.extend(link_opt.as_ldflags()); } - fn with_ldflag>(mut self, ldflag: S) -> Self { - self.ldflag(ldflag); + fn with_link_opt(mut self, link_opt: LinkOpt) -> Self { + self.link_opt(link_opt); self } fn export>(&mut self, export: S) { - self.as_link() - .ldflags - .push(format!("--export={}", export.as_ref())); + self.link_opt(LinkOpt::Export(export.as_ref())); } fn with_export>(mut self, export: S) -> Self { @@ -352,7 +412,7 @@ mod tests { let mut linker = Link::new(&[objfile]); linker.cflag("-nostartfiles"); - linker.ldflag("--no-entry"); + linker.link_opt(LinkOpt::NoDefaultEntryPoint); let wasmfile = tmp.path().join("a.wasm"); @@ -375,8 +435,8 @@ mod tests { let mut linker = Link::new(&[objfile]); linker.cflag("-nostartfiles"); - linker.ldflag("--no-entry"); - linker.ldflag("--allow-undefined"); + linker.link_opt(LinkOpt::NoDefaultEntryPoint); + linker.link_opt(LinkOpt::AllowUndefinedAll); let wasmfile = tmp.path().join("b.wasm"); @@ -391,7 +451,7 @@ mod tests { let mut linker = Link::new(&[test_file("a.c"), test_file("b.c")]); linker.cflag("-nostartfiles"); - linker.ldflag("--no-entry"); + linker.link_opt(LinkOpt::NoDefaultEntryPoint); let wasmfile = tmp.path().join("ab.wasm"); @@ -406,7 +466,7 @@ mod tests { let mut lucetc = Lucetc::new(&[test_file("a.c"), test_file("b.c")]); lucetc.cflag("-nostartfiles"); - lucetc.ldflag("--no-entry"); + lucetc.link_opt(LinkOpt::NoDefaultEntryPoint); let so_file = tmp.path().join("ab.so"); diff --git a/lucetc/tests/wasi-sdk.rs b/lucetc/tests/wasi-sdk.rs index 882b41133..92355ba3e 100644 --- a/lucetc/tests/wasi-sdk.rs +++ b/lucetc/tests/wasi-sdk.rs @@ -1,5 +1,5 @@ use failure::{Error, ResultExt}; -use lucet_wasi_sdk::{CompileOpts, Link, LinkOpts}; +use lucet_wasi_sdk::{CompileOpts, Link, LinkOpt, LinkOpts}; use lucetc::bindings::Bindings; use lucetc::load; use parity_wasm::elements::Module; @@ -23,10 +23,10 @@ fn module_from_c(cfiles: &[&str], exports: &[&str]) -> Result { let mut linker = Link::new(&cfiles) .with_cflag("-nostartfiles") - .with_ldflag("--no-entry") - .with_ldflag("--allow-undefined"); + .with_link_opt(LinkOpt::NoDefaultEntryPoint) + .with_link_opt(LinkOpt::AllowUndefinedAll); for export in exports { - linker.ldflag(&format!("--export={}", export)); + linker.export(export); } linker.link(wasm.clone())?; From 7b9dc66f538cfc0a95eeca92b51e9e45d1049ee2 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 19 Apr 2019 15:11:22 -0700 Subject: [PATCH 059/512] gitignore: core.* --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 182e70040..ac3addcea 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ target/ *.rs.bk *.pyc host +core.* # csmith-generated /platform.info From 7710062ef9ccb98c2e95c1f7a92327c31dd6d72c Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sat, 20 Apr 2019 20:59:56 +0200 Subject: [PATCH 060/512] Add a comment to clarify why there are two invocations of $(CC) --- lucet-builtins/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/lucet-builtins/Makefile b/lucet-builtins/Makefile index 8efea1fd6..6ddbcfde0 100644 --- a/lucet-builtins/Makefile +++ b/lucet-builtins/Makefile @@ -17,6 +17,7 @@ build/%.o: src/%.c $(CC) $(COMMON_CFLAGS) -c $^ -o $@ build/libbuiltins.so: $(LIBBUILTINS_OBJS) + # -U is not supported by the GNU linker. Retry without this option if the first command fails. $(CC) -Wl,-U,_lucet_vmctx_current_memory -Wl,-U,_lucet_vmctx_get_heap -shared $^ -o $@ 2> /dev/null || \ $(CC) -shared $^ -o $@ From 5e158462ac98f8a2ed48026c75ecfab8c2c3d281 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sat, 20 Apr 2019 23:04:52 +0200 Subject: [PATCH 061/512] Add sysroot to the linker flags Some tests directly use the `Link` structure to compile, not just link. Also, the wasi-sdk crate is designed to only compile to wasm, so don't bother about other targets. Also remove `AllowUndefined()` that doesn't seem to be supported by `wasm-ld`. --- lucet-wasi-sdk/src/lib.rs | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/lucet-wasi-sdk/src/lib.rs b/lucet-wasi-sdk/src/lib.rs index cf2638f54..646a090e5 100644 --- a/lucet-wasi-sdk/src/lib.rs +++ b/lucet-wasi-sdk/src/lib.rs @@ -198,6 +198,8 @@ impl Link { } cmd.arg(input.clone()); } + cmd.arg(format!("--target={}", WASI_TARGET)); + cmd.arg(format!("--sysroot={}", wasi_sysroot().display())); cmd.arg("-o"); cmd.arg(output.as_ref()); for cflag in self.cflags.iter() { @@ -223,9 +225,6 @@ impl AsLink for Link { #[derive(Clone, Copy, Debug)] pub enum LinkOpt<'t> { - /// Allow references to an undefined function that will be resolved later by the dynamic linker - AllowUndefined(&'t str), - /// Allow references to any undefined function. They will be resolved later by the dynamic linker AllowUndefinedAll, @@ -252,32 +251,15 @@ pub enum LinkOpt<'t> { } impl<'t> LinkOpt<'t> { - #[cfg(target_os = "macos")] - fn as_ldflags(&self) -> Vec { - match self { - LinkOpt::AllowUndefined(_symbol) => vec![], - LinkOpt::AllowUndefinedAll => vec!["-undefined,dynamic_lookup".to_string()], - LinkOpt::DefaultOpts => vec![], - LinkOpt::Export(symbol) => vec![format!("-exported_symbol,{}", symbol).to_string()], - LinkOpt::ExportAll => vec!["-export_dynamic".to_string()], - LinkOpt::NoDefaultEntryPoint => vec![], - LinkOpt::Shared => vec!["-dylib".to_string()], - LinkOpt::StripDebug => vec!["-S".to_string()], - LinkOpt::StripUnused => vec!["-dead_strip".to_string()], - } - } - - #[cfg(not(target_os = "macos"))] fn as_ldflags(&self) -> Vec { match self { - LinkOpt::AllowUndefined(symbol) => vec![format!("-U,_{}", symbol).to_string()], LinkOpt::AllowUndefinedAll => vec!["--allow-undefined".to_string()], LinkOpt::DefaultOpts => vec!["--no-threads".to_string()], LinkOpt::Export(symbol) => vec![format!("--export={}", symbol).to_string()], LinkOpt::ExportAll => vec!["--export-all".to_string()], LinkOpt::NoDefaultEntryPoint => vec!["--no-entry".to_string()], LinkOpt::Shared => vec!["--shared".to_string()], - LinkOpt::StripDebug => vec!["-S".to_string()], + LinkOpt::StripDebug => vec!["--strip-debug".to_string()], LinkOpt::StripUnused => vec!["--strip-discarded".to_string()], } } From 7823d2f968d3ad66dc18281571c6999c65a47abf Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sat, 20 Apr 2019 23:25:26 +0200 Subject: [PATCH 062/512] Bail out if helpers/install.sh is run on a non-Linux system --- helpers/install.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/helpers/install.sh b/helpers/install.sh index c2e2e9e6a..ff6c61e1a 100755 --- a/helpers/install.sh +++ b/helpers/install.sh @@ -1,5 +1,10 @@ #! /bin/sh +if [ "$(uname -s)" != "Linux" ]; then + echo "Installation on this operating system cannot be done using that script yet." >&2 + exit 1 +fi + LUCET_SRC_PREFIX=${LUCET_SRC_PREFIX:-"$(readlink -e $(dirname $(dirname ${0})))"} if [ ! -x "${LUCET_SRC_PREFIX}/helpers/install.sh" ]; then echo "Unable to find the current script base directory" >&2 @@ -108,4 +113,4 @@ rm -f "$wrapper_file" cd "$LUCET_SRC_PREFIX" || exit 1 find assemblyscript -type d -exec install -d -v "${LUCET_SHARE_DIR}/{}" \; find assemblyscript -type f -exec install -p -v -m 0644 "{}" "${LUCET_SHARE_DIR}/{}" \; -) \ No newline at end of file +) From 1a37cd4be01ab21a26b15f32444df40628493e6e Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 22 Apr 2019 13:23:07 -0700 Subject: [PATCH 063/512] lucet-runtime: fix deb packaging by deleting ref to deleted file --- lucet-runtime/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/lucet-runtime/Cargo.toml b/lucet-runtime/Cargo.toml index 0197eeebc..cd3baa7c2 100644 --- a/lucet-runtime/Cargo.toml +++ b/lucet-runtime/Cargo.toml @@ -34,5 +34,4 @@ assets = [ ["target/release/liblucet_runtime.rlib", "/opt/fst-lucet-runtime/lib/", "644"], ["target/release/liblucet_runtime.so", "/opt/fst-lucet-runtime/lib/", "755"], ["include/*.h", "/opt/fst-lucet-runtime/include/", "644"], - ["README.rst", "/opt/fst-lucet-runtime/share/doc/lucet-runtime/", "644"], ] From 99edfdcefaa9f493f2c4a3a12beab599dc91e809 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 22 Apr 2019 14:25:40 -0700 Subject: [PATCH 064/512] [lucet-wasi-fuzz] use a fixed seed for the fuzzer in `make test` The use of the fuzzer in this make target is to prevent bitrot of the fuzzer, not meant to actually find bugs, so fixing its value doesn't hurt and makes it more deterministic. --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b13506f62..8dddd5d84 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,8 @@ test: indent-check -p lucet-idl \ -p lucet-wasi-sdk \ -p lucet-wasi - cargo run -p lucet-wasi-fuzz -- fuzz --num-tests=3 + # run a single seed through the fuzzer to stave off bitrot + cargo run -p lucet-wasi-fuzz -- test-seed 410757864950 .PHONY: fuzz fuzz: From 10b432c62398989864db653838147a5f92408e50 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Tue, 9 Apr 2019 19:43:16 +0200 Subject: [PATCH 065/512] Just a massive update to lucet-idl This PR changes pretty much everything over the previous code. --- Cargo.lock | 5 + lucet-idl/Cargo.lock | 257 +++++++++++ lucet-idl/Cargo.toml | 7 + lucet-idl/README.md | 220 +++++++++ lucet-idl/src/backend.rs | 24 + lucet-idl/src/cache.rs | 45 ++ lucet-idl/src/cgenerator/catom.rs | 128 ++++++ .../src/cgenerator/gen_accessors_alias.rs | 37 ++ .../src/cgenerator/gen_accessors_atom.rs | 120 +++++ .../src/cgenerator/gen_accessors_enum.rs | 158 +++++++ lucet-idl/src/cgenerator/gen_accessors_ptr.rs | 52 +++ .../src/cgenerator/gen_accessors_struct.rs | 202 +++++++++ .../cgenerator/gen_accessors_tagged_union.rs | 256 +++++++++++ lucet-idl/src/cgenerator/gen_alias.rs | 58 +++ lucet-idl/src/cgenerator/gen_enum.rs | 78 ++++ lucet-idl/src/cgenerator/gen_prelude.rs | 96 ++++ lucet-idl/src/cgenerator/gen_struct.rs | 111 +++++ lucet-idl/src/cgenerator/gen_tagged_union.rs | 180 ++++++++ lucet-idl/src/cgenerator/macros.rs | 57 +++ lucet-idl/src/cgenerator/mod.rs | 425 ++++++++++++++++++ lucet-idl/src/config.rs | 78 ++++ lucet-idl/src/data_description_helper.rs | 171 +++++++ lucet-idl/src/errors.rs | 35 ++ lucet-idl/src/generators/generator.rs | 108 +++++ lucet-idl/src/generators/hierarchy.rs | 76 ++++ lucet-idl/src/generators/mod.rs | 5 + lucet-idl/src/lexer.rs | 9 +- lucet-idl/src/main.rs | 50 ++- lucet-idl/src/parser.rs | 4 +- lucet-idl/src/pretty_writer.rs | 105 +++++ lucet-idl/src/rustgenerator/mod.rs | 136 ++++++ lucet-idl/src/target.rs | 67 +++ lucet-idl/src/validate.rs | 126 +++--- 33 files changed, 3419 insertions(+), 67 deletions(-) create mode 100644 lucet-idl/Cargo.lock create mode 100644 lucet-idl/README.md create mode 100644 lucet-idl/src/backend.rs create mode 100644 lucet-idl/src/cache.rs create mode 100644 lucet-idl/src/cgenerator/catom.rs create mode 100644 lucet-idl/src/cgenerator/gen_accessors_alias.rs create mode 100644 lucet-idl/src/cgenerator/gen_accessors_atom.rs create mode 100644 lucet-idl/src/cgenerator/gen_accessors_enum.rs create mode 100644 lucet-idl/src/cgenerator/gen_accessors_ptr.rs create mode 100644 lucet-idl/src/cgenerator/gen_accessors_struct.rs create mode 100644 lucet-idl/src/cgenerator/gen_accessors_tagged_union.rs create mode 100644 lucet-idl/src/cgenerator/gen_alias.rs create mode 100644 lucet-idl/src/cgenerator/gen_enum.rs create mode 100644 lucet-idl/src/cgenerator/gen_prelude.rs create mode 100644 lucet-idl/src/cgenerator/gen_struct.rs create mode 100644 lucet-idl/src/cgenerator/gen_tagged_union.rs create mode 100644 lucet-idl/src/cgenerator/macros.rs create mode 100644 lucet-idl/src/cgenerator/mod.rs create mode 100644 lucet-idl/src/config.rs create mode 100644 lucet-idl/src/data_description_helper.rs create mode 100644 lucet-idl/src/errors.rs create mode 100644 lucet-idl/src/generators/generator.rs create mode 100644 lucet-idl/src/generators/hierarchy.rs create mode 100644 lucet-idl/src/generators/mod.rs create mode 100644 lucet-idl/src/pretty_writer.rs create mode 100644 lucet-idl/src/rustgenerator/mod.rs create mode 100644 lucet-idl/src/target.rs diff --git a/Cargo.lock b/Cargo.lock index 15e6767e8..03fbb8af8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -587,6 +587,11 @@ dependencies = [ [[package]] name = "lucet-idl" version = "0.1.0" +dependencies = [ + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "lucet-module-data" diff --git a/lucet-idl/Cargo.lock b/lucet-idl/Cargo.lock new file mode 100644 index 000000000..309a2bce5 --- /dev/null +++ b/lucet-idl/Cargo.lock @@ -0,0 +1,257 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "autocfg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "backtrace" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitflags" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cc" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "clap" +version = "2.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure_derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.50" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lucet-idl" +version = "0.1.0" +dependencies = [ + "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "redox_syscall" +version = "0.1.51" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_termios" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "strsim" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "syn" +version = "0.15.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "synstructure" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termion" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "textwrap" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-width" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "vec_map" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "xfailure" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" +"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" +"checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4" +"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" +"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ce8bb087aacff865633f0bd5aeaed910fe2fe55b55f4739527f2e023a2e53d" +"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" +"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" +"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" +"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" +"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1" +"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" +"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" +"checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" +"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" +"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" +"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" +"checksum syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1825685f977249735d510a242a6727b46efe914bb67e38d30c071b1b72b1d5c2" +"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" +"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" +"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" +"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" +"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da90eac47bf1d7871b75004b9b631d107df15f37669383b23f0b5297bc7516b6" diff --git a/lucet-idl/Cargo.toml b/lucet-idl/Cargo.toml index 270fe204b..e238f6a6e 100644 --- a/lucet-idl/Cargo.toml +++ b/lucet-idl/Cargo.toml @@ -10,4 +10,11 @@ edition = "2018" [lib] crate-type=["rlib"] +[[bin]] +name = "lucet-idl" +path = "src/main.rs" + [dependencies] +clap = "2" +failure = "0.1" +xfailure = "0.1" diff --git a/lucet-idl/README.md b/lucet-idl/README.md new file mode 100644 index 000000000..4cd1cb560 --- /dev/null +++ b/lucet-idl/README.md @@ -0,0 +1,220 @@ +# Lucet-IDL + +This is an IDL. A tool that reads descriptions of data types, and spits out these types' definitions, plus a bunch of functions to represent them as a serialized, platform-independent way. + +## Usage + +```text +USAGE: + lucet-idl [FLAGS] [OPTIONS] --input + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + -z, --zero-native-pointers Do not serialize native pointers + +OPTIONS: + -b, --backend Backend, one of: c [default: c] + -i, --input Path to the input file + -t, --target Target, one of: x86, x86_64, x86_64_32, generic [default: Generic] +``` + +## The description language in one example + +```text +// Primitive types: +// `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`, `f32`, `f64`. + +// Enumerations + +enum color { + red, blue, green +} + +// Aliases + +type colour = color +type col = colour + +// Structures + +struct st { + a: i8, + b: **i32, + c: color, + self: *st +} + +// Tagged unions + +taggedunion mixedbag { + a: col, + b: f64, + c: st, + d: () +} +``` + +## Sample output + +[Output (C backend) for the example above](https://gist.github.com/jedisct1/db5f81aa5e21b280d6f0f0350215889e). + +## Generated type definitions (C) + +### Structures + +No matter what the target and backend are, the generator will attempt to align data the same way as the reference target (C on x86_64). + +Using the example above, the `st` structure above gets defined as: + +```c +struct st { + int8_t a; + uint8_t ___pad8_1[7]; + int32_t **b; + ___POINTER_PAD(8) // pad pointer `b` at offset 8 to match alignment of the reference target (8 bytes) + color /* (enum ___color) */ c; + struct st *self; + ___POINTER_PAD(24) // pad pointer `self` at offset 24 to match alignment of the reference target (8 bytes) +}; + +#define BYTES_ST 32 +``` + +Explicit padding has been added after the first element `a` so that `b` is 64-bit aligned. + +However, native pointers can be 32-bit even though we require them to be 64-bit aligned. + +The `___POINTER_PAD` macro adds extra padding after a pointer on platforms where pointers are not 64-bit long. + +The `self` pointer will always be 64-bit aligned, as the previous member `c` is 64-bit aligned, and 64-bit long. Therefore, no extra padding is added before, but optional padding is added after the pointer itself. + +For every structure, a macro representing the number of bytes required to store it is defined as `BYTES_`, such as `BYTES_ST` in the example above. + +### Enumerations + +Enumerations are stored as a signed 64-bit integer: + +```c +typedef int64_t color; // enum, should be in the [0...2] range +enum ___color { + COLOR_RED, // 0 + COLOR_BLUE, // 1 + COLOR_GREEN, // 2 +}; + +#define BYTES_COLOR 8 +``` + +### Tagged unions + +Tagged unions allow different types to be stored in the same memory space. + +The `mixedbag` tagged union generates the following definition: + +```c +#define TYPE_MIXEDBAG_A 1 +#define TYPE_MIXEDBAG_B 2 +#define TYPE_MIXEDBAG_C 3 + +struct mixedbag { + uint32_t ___type; // tagged union type, should be in the [1...4] range + uint8_t ___pad8_4[4]; + union { + col a; // - type 1 + double b; // - type 2 + struct st c; // - type 3 + // void d; - type 4 + } variant; +}; + +#define BYTES_MIXEDBAG 40 +``` + +Like structures, explicit padding is added to try to match the alignment rules of the reference platform. + +`BYTES_MIXEDBAG` is the number of bytes required to store the whole tagged union. + +## Accessors (C) + +The generated types are designed to be directly used by applications. + +However, they can also be represented as platform-independent serialized data. + +In particular, the `st` structure above generates the following accessors: + +```c +static inline void store_st(unsigned char buf[static BYTES_ST], const struct st *v); + +static inline void load_st(struct st *v_p, const unsigned char buf[static BYTES_ST]); +``` + +On platforms that can share the same endianness and alignment rules as the target platform, +these operations translate into a single `memcpy()` call. + +On other platforms, individual values are re-aligned and byte-swapped accordingly. + +Accessors for individual values are also generated. + +The suffix of a function name represents the hierarchy of the value. For example, the +following functions can directly access the `a` value of the `st` structure `b` within +the `mixedbag` tagged union: + +```c +static inline void store_mixedbag_c_a(unsigned char buf[static BYTES_MIXEDBAG], const int8_t v); + +static inline void load_mixedbag_c_a(int8_t *v_p, const unsigned char buf[static BYTES_MIXEDBAG]); +``` + +Subsets of types can thus be directly loaded and modified from a serialized representation. + +Tagged unions generate different sets of functions: + +### Tagged unions: non-void members + +```c +static inline bool is_mixedbag_a(const unsigned char buf[static BYTES_COLOR]); +``` + +This returns `TRUE` if the current type is `a`. + +```c +static inline void ref_mixedbag_a( + const unsigned char **ibuf_p, + const unsigned char buf[static BYTES_MIXEDBAG]); + +static inline void mut_mixedbag_a( + unsigned char **ibuf_p, + unsigned char buf[static BYTES_MIXEDBAG]); +``` + +These functions return a pointer to a serialized representation of the tagged union, +assuming that it currently olds the `a` type. If this is not the case, an +`assert()`ion will be hit. + +```c +static inline void store_mixedbag_as_a( + unsigned char buf[static BYTES_MIXEDBAG], + const struct mixedbag *t); +``` + +This function serializes the tagged union into `buf`, possibly forcing the type to be `a`. + +### Tagged union: void members + +Member `d` of the `mixedbag` tagged union doesn't have any value. + +The following set of accessors are generated: + +```c +static inline bool is_mixedbag_d(const unsigned char buf[static 4]); + +static inline void set_mixedbag_d(unsigned char buf[static 4]); +``` + +## Pointers + +Pointers are not automatically dereferenced. Their value can be replaced with zeros in +serialized representations. + +The `--zero-native-pointers` command-line option enables it. diff --git a/lucet-idl/src/backend.rs b/lucet-idl/src/backend.rs new file mode 100644 index 000000000..4313fb59a --- /dev/null +++ b/lucet-idl/src/backend.rs @@ -0,0 +1,24 @@ +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub enum Backend { + C, +} + +impl Default for Backend { + fn default() -> Self { + Backend::C + } +} + +impl> From for Backend { + fn from(s: T) -> Self { + match s.as_ref() { + "c" => Backend::C, + _ => Backend::default(), + } + } +} + +#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)] +pub struct BackendConfig { + pub zero_native_pointers: bool, +} diff --git a/lucet-idl/src/cache.rs b/lucet-idl/src/cache.rs new file mode 100644 index 000000000..7eacfe22d --- /dev/null +++ b/lucet-idl/src/cache.rs @@ -0,0 +1,45 @@ +use lucet_idl::validate::*; +use std::collections::HashMap; + +/// Cached information for a given structure member +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct CachedStructMemberEntry { + pub offset: usize, +} + +/// Cached information for a given type +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct CachedTypeEntry { + pub type_size: usize, + pub type_align: usize, + pub members: Vec, +} + +impl CachedTypeEntry { + pub fn store_members(&mut self, entries: Vec) { + self.members = entries; + } + + pub fn load_member(&self, member_id: usize) -> Option<&CachedStructMemberEntry> { + self.members.get(member_id) + } +} + +/// Cache information about a type given its id +#[derive(Clone, Debug, Default)] +pub struct Cache { + type_map: HashMap, +} + +impl Cache { + pub fn store_type(&mut self, id: DataTypeId, entry: CachedTypeEntry) -> &mut CachedTypeEntry { + if self.type_map.insert(id, entry).is_some() { + panic!("Type {:?} had already been cached", id) + } + self.type_map.get_mut(&id).unwrap() + } + + pub fn load_type(&self, id: DataTypeId) -> Option<&CachedTypeEntry> { + self.type_map.get(&id) + } +} diff --git a/lucet-idl/src/cgenerator/catom.rs b/lucet-idl/src/cgenerator/catom.rs new file mode 100644 index 000000000..8c23e3168 --- /dev/null +++ b/lucet-idl/src/cgenerator/catom.rs @@ -0,0 +1,128 @@ +use super::super::target::*; +use lucet_idl::types::*; + +/// Information about a C native type +pub struct CAtom { + pub native_type_name: &'static str, + pub native_type_size: usize, + pub native_type_align: usize, +} + +impl From for CAtom { + fn from(atom_type: AtomType) -> Self { + match atom_type { + AtomType::U8 => CAtom { + native_type_name: "uint8_t", + native_type_size: 1, + native_type_align: 1, + }, + AtomType::U16 => CAtom { + native_type_name: "uint16_t", + native_type_size: 2, + native_type_align: 2, + }, + AtomType::U32 => CAtom { + native_type_name: "uint32_t", + native_type_size: 4, + native_type_align: 4, + }, + AtomType::U64 => CAtom { + native_type_name: "uint64_t", + native_type_size: 8, + native_type_align: 8, // x86_64 alignment rule + }, + AtomType::I8 => CAtom { + native_type_name: "int8_t", + native_type_size: 1, + native_type_align: 1, + }, + AtomType::I16 => CAtom { + native_type_name: "int16_t", + native_type_size: 2, + native_type_align: 2, + }, + AtomType::I32 => CAtom { + native_type_name: "int32_t", + native_type_size: 4, + native_type_align: 4, + }, + AtomType::I64 => CAtom { + native_type_name: "int64_t", + native_type_size: 8, + native_type_align: 8, // x86_64 alignment rule + }, + AtomType::F32 => CAtom { + native_type_name: "float", + native_type_size: 4, + native_type_align: 4, + }, + AtomType::F64 => CAtom { + native_type_name: "double", + native_type_size: 8, + native_type_align: 8, // x86_64 alignment rule + }, + } + } +} + +impl CAtom { + /// Native type used for pointers + pub fn ptr() -> Self { + CAtom { + native_type_name: "void *", + native_type_size: 8, + native_type_align: 8, // x86_64 alignment rule + } + } + + /// Native type used for the type in tagged unions + pub fn tagged_union_type() -> Self { + CAtom::from(AtomType::U32) + } + + /// Native type used for enums + /// It can't be an `int` as it would not be portable across architectures + pub fn enum_() -> Self { + CAtom::from(AtomType::I64) + } + + /// C atom type to generic atom type + pub fn as_atom_type(&self) -> Option { + match self.native_type_name { + "uint8_t" => Some(AtomType::U8), + "uint16_t" => Some(AtomType::U16), + "uint32_t" => Some(AtomType::U32), + "uint64_t" => Some(AtomType::U64), + "int8_t" => Some(AtomType::I8), + "int16_t" => Some(AtomType::I16), + "int32_t" => Some(AtomType::I32), + "int64_t" => Some(AtomType::I64), + "float" => Some(AtomType::F32), + "double" => Some(AtomType::F64), + _ => None, + } + } + + /// Return an expression to swap byte order + /// No need to swap anything if we have a single byte or if we explicitly + /// target an architecture that matches the reference target for the type + pub fn bswap(&self, _target: Target, vstr: &str) -> String { + if self.native_type_size < 2 { + vstr.to_string() + } else { + format!("___bswap_{}({})", self.native_type_name, vstr) + } + } + + /// Return an expression to force little-endian order + pub fn little_endian(&self, target: Target, vstr: &str) -> String { + let atom_type = self.as_atom_type(); + if self.native_type_size < 2 + || (atom_type.is_some() && target.uses_reference_target_endianness()) + { + vstr.to_string() + } else { + format!("___le_{}({})", self.native_type_name, vstr) + } + } +} diff --git a/lucet-idl/src/cgenerator/gen_accessors_alias.rs b/lucet-idl/src/cgenerator/gen_accessors_alias.rs new file mode 100644 index 000000000..9898a8c96 --- /dev/null +++ b/lucet-idl/src/cgenerator/gen_accessors_alias.rs @@ -0,0 +1,37 @@ +use super::*; + +pub fn generate( + cgenerator: &mut CGenerator, + data_description_helper: &DataDescriptionHelper, + cache: &Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + hierarchy: &Hierarchy, +) -> Result<(), IDLError> { + if hierarchy.depth() > 1 { + return Ok(()); + } + let name = &data_type_entry.name; + let (type_, _attrs) = if let DataType::Alias { to: type_, attrs } = &data_type_entry.data_type { + (type_, attrs) + } else { + unreachable!() + }; + let type_info = cgenerator.type_info(data_description_helper, cache, type_); + + pretty_writer.indent()?; + pretty_writer + .write(format!("// `{}` is an alias for `{}`", name, type_info.type_name).as_ref())?; + if type_info.indirections == 0 { + let leaf_type_info = + cgenerator.type_info(data_description_helper, cache, type_info.leaf_data_type_ref); + if leaf_type_info.type_name != type_info.type_name { + pretty_writer + .write(format!(", itself equivalent to `{}`", leaf_type_info.type_name).as_ref())?; + } + } + pretty_writer.write(b".")?.eol()?; + pretty_writer.write_line(b"// No dedicated accessors have been generated.")?; + pretty_writer.eob()?; + Ok(()) +} diff --git a/lucet-idl/src/cgenerator/gen_accessors_atom.rs b/lucet-idl/src/cgenerator/gen_accessors_atom.rs new file mode 100644 index 000000000..dff778842 --- /dev/null +++ b/lucet-idl/src/cgenerator/gen_accessors_atom.rs @@ -0,0 +1,120 @@ +use super::*; + +pub fn generate( + cgenerator: &mut CGenerator, + _data_description_helper: &DataDescriptionHelper, + pretty_writer: &mut PrettyWriter, + atom_type: AtomType, + hierarchy: &Hierarchy, +) -> Result<(), IDLError> { + let fn_name = hierarchy.fn_name(); + let root_name = hierarchy.root_name(); + let root_macro_size_name = macros::macro_for("BYTES", &root_name); + let current_offset = hierarchy.current_offset(); + let catom = CAtom::from(atom_type); + let mut pretty_writer_i1 = pretty_writer.new_block(); + let mut preprocessor_writer = PrettyWriter::new_from_writer(pretty_writer); + let uses_reference_target_endianness = cgenerator + .target + .uses_reference_target_endianness_for_atom_type(atom_type); + + // --- store_*() + + pretty_writer + .write_line( + format!( + "static inline void store_{}(unsigned char buf[static {}], const {} v)", + fn_name, root_macro_size_name, catom.native_type_name + ) + .as_bytes(), + )? + .write_line(b"{")?; + pretty_writer_i1.write_line( + format!( + "_Static_assert({} >= {} + {}, \"unexpected size\");", + root_macro_size_name, current_offset, catom.native_type_size + ) + .as_bytes(), + )?; + if !uses_reference_target_endianness { + preprocessor_writer.write_line(b"#ifdef ___REFERENCE_COMPATIBLE_ENCODING")?; + } + pretty_writer_i1.write_line( + format!( + "memcpy(&buf[{}], &v, {});", + current_offset, catom.native_type_size + ) + .as_bytes(), + )?; + + if !uses_reference_target_endianness { + preprocessor_writer.write_line(b"#else")?; + pretty_writer_i1 + .write_line( + format!( + "{} t = {};", + catom.native_type_name, + catom.little_endian(cgenerator.target, "v") + ) + .as_bytes(), + )? + .write_line( + format!( + "memcpy(&buf[{}], &t, {});", + current_offset, catom.native_type_size + ) + .as_bytes(), + )?; + preprocessor_writer.write_line(b"#endif")?; + } + + pretty_writer.write_line(b"}")?.eob()?; + + // --- load_*() + + pretty_writer + .write_line( + format!( + "static inline void load_{}({} *v_p, const unsigned char buf[static {}])", + fn_name, catom.native_type_name, root_macro_size_name + ) + .as_bytes(), + )? + .write_line(b"{")?; + pretty_writer_i1.write_line( + format!( + "_Static_assert({} >= {} + {}, \"unexpected size\");", + root_macro_size_name, current_offset, catom.native_type_size + ) + .as_bytes(), + )?; + if !uses_reference_target_endianness { + preprocessor_writer.write_line(b"#ifdef ___REFERENCE_COMPATIBLE_ENCODING")?; + } + pretty_writer_i1.write_line( + format!( + "memcpy(v_p, &buf[{}], {});", + current_offset, catom.native_type_size + ) + .as_bytes(), + )?; + if !uses_reference_target_endianness { + preprocessor_writer.write_line(b"#else")?; + pretty_writer_i1 + .write_line(format!("{} t = 0;", catom.native_type_name).as_bytes())? + .write_line( + format!( + "memcpy(&t, &buf[{}], {});", + current_offset, catom.native_type_size + ) + .as_bytes(), + )? + .write_line( + format!("*v_p = {};", catom.little_endian(cgenerator.target, "t")).as_bytes(), + )?; + preprocessor_writer.write_line(b"#endif")?; + } + pretty_writer.write_line(b"}")?.eob()?; + + Ok(()) +} diff --git a/lucet-idl/src/cgenerator/gen_accessors_enum.rs b/lucet-idl/src/cgenerator/gen_accessors_enum.rs new file mode 100644 index 000000000..4512812c0 --- /dev/null +++ b/lucet-idl/src/cgenerator/gen_accessors_enum.rs @@ -0,0 +1,158 @@ +use super::*; + +pub fn generate( + cgenerator: &mut CGenerator, + data_description_helper: &DataDescriptionHelper, + cache: &Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + hierarchy: &Hierarchy, +) -> Result<(), IDLError> { + let (named_members, _attrs) = if let DataType::Enum { + members: named_members, + attrs, + } = &data_type_entry.data_type + { + (named_members, attrs) + } else { + unreachable!() + }; + let root_name = hierarchy.root_name(); + let fn_name = hierarchy.fn_name(); + let root_macro_size_name = macros::macro_for("BYTES", &root_name); + let current_offset = hierarchy.current_offset(); + + let catom = CAtom::enum_(); + let mut preprocessor_writer = PrettyWriter::new_from_writer(pretty_writer); + let uses_reference_target_endianness = cgenerator + .target + .uses_reference_target_endianness_for_atom_type(catom.as_atom_type().unwrap()); + + pretty_writer.eob()?; + + if hierarchy.depth() > 1 { + pretty_writer.write_line( + format!( + "// Accessors for the `{}` enumeration in `{}`", + data_type_entry.name, + hierarchy.idl_name() + ) + .as_bytes(), + )?; + } else { + pretty_writer.write_line( + format!( + "// Platform-independent accessors for the `{}` enumeration", + data_type_entry.name + ) + .as_bytes(), + )?; + } + pretty_writer.eob()?; + + let mut pretty_writer_i1 = pretty_writer.new_block(); + + // --- store_*() + + pretty_writer + .write_line( + format!( + "static inline void store_{}(unsigned char buf[static {}], const {} v)", + fn_name, root_macro_size_name, catom.native_type_name + ) + .as_bytes(), + )? + .write_line(b"{")?; + pretty_writer_i1.write_line( + format!( + "_Static_assert({} >= {} + {}, \"unexpected size\");", + root_macro_size_name, current_offset, catom.native_type_size + ) + .as_bytes(), + )?; + pretty_writer_i1 + .write_line(format!("assert(v >= 0 && v < {});", named_members.len()).as_ref())? + .eob()?; + if !uses_reference_target_endianness { + preprocessor_writer.write_line(b"#ifdef ___REFERENCE_COMPATIBLE_ENCODING")?; + } + pretty_writer_i1.write_line( + format!( + "memcpy(&buf[{}], &v, {});", + current_offset, catom.native_type_size + ) + .as_bytes(), + )?; + + if !uses_reference_target_endianness { + preprocessor_writer.write_line(b"#else")?; + pretty_writer_i1 + .write_line( + format!( + "{} t = {};", + catom.native_type_name, + catom.little_endian(cgenerator.target, "v") + ) + .as_bytes(), + )? + .write_line( + format!( + "memcpy(&buf[{}], &t, {});", + current_offset, catom.native_type_size + ) + .as_bytes(), + )?; + preprocessor_writer.write_line(b"#endif")?; + } + pretty_writer.write_line(b"}")?.eob()?; + + // --- load_*() + + pretty_writer + .write_line( + format!( + "static inline void load_{}({} *v_p, const unsigned char buf[static {}])", + fn_name, catom.native_type_name, root_macro_size_name + ) + .as_bytes(), + )? + .write_line(b"{")?; + pretty_writer_i1.write_line( + format!( + "_Static_assert({} >= {} + {}, \"unexpected size\");", + root_macro_size_name, current_offset, catom.native_type_size + ) + .as_bytes(), + )?; + if !uses_reference_target_endianness { + preprocessor_writer.write_line(b"#ifdef ___REFERENCE_COMPATIBLE_ENCODING")?; + } + pretty_writer_i1.write_line( + format!( + "memcpy(v_p, &buf[{}], {});", + current_offset, catom.native_type_size + ) + .as_bytes(), + )?; + if !uses_reference_target_endianness { + preprocessor_writer.write_line(b"#else")?; + pretty_writer_i1 + .write_line(format!("{} t = 0;", catom.native_type_name).as_bytes())? + .write_line( + format!( + "memcpy(&t, &buf[{}], {});", + current_offset, catom.native_type_size + ) + .as_bytes(), + )? + .write_line( + format!("*v_p = {};", catom.little_endian(cgenerator.target, "t")).as_bytes(), + )?; + preprocessor_writer.write_line(b"#endif")?; + } + pretty_writer_i1 + .write_line(format!("assert(*v_p >= 0 && *v_p < {});", named_members.len()).as_ref())?; + pretty_writer.write_line(b"}")?.eob()?; + + Ok(()) +} diff --git a/lucet-idl/src/cgenerator/gen_accessors_ptr.rs b/lucet-idl/src/cgenerator/gen_accessors_ptr.rs new file mode 100644 index 000000000..5d89f22b4 --- /dev/null +++ b/lucet-idl/src/cgenerator/gen_accessors_ptr.rs @@ -0,0 +1,52 @@ +use super::*; + +pub fn generate( + cgenerator: &mut CGenerator, + data_description_helper: &DataDescriptionHelper, + cache: &Cache, + pretty_writer: &mut PrettyWriter, + type_: &DataTypeRef, + hierarchy: &Hierarchy, +) -> Result<(), IDLError> { + let type_info = cgenerator.type_info(data_description_helper, cache, type_); + let leaf_type_info = + cgenerator.type_info(data_description_helper, cache, type_info.leaf_data_type_ref); + assert_eq!(leaf_type_info.indirections, 0); + if type_info.indirections > 1 { + pretty_writer.write_line( + format!( + "// `{}` is a sequence of {} pointers to `{}`.", + hierarchy.idl_name(), + type_info.indirections, + leaf_type_info.type_name + ) + .as_ref(), + )?; + } else if type_info.indirections == 1 { + pretty_writer.write_line( + format!( + "// `{}` is a native pointer to a pointer to `{}`.", + hierarchy.idl_name(), + leaf_type_info.type_name + ) + .as_ref(), + )?; + } else { + pretty_writer.write_line( + format!( + "// `{}` is a native pointer to `{}`.", + hierarchy.idl_name(), + leaf_type_info.type_name + ) + .as_ref(), + )?; + } + pretty_writer.write_line(b"// Accessors are intentionally not defined for it: ")?; + pretty_writer + .write_line( + b"// it is only designed to be used internally, and its value will not be serialized.", + )? + .eob()?; + + Ok(()) +} diff --git a/lucet-idl/src/cgenerator/gen_accessors_struct.rs b/lucet-idl/src/cgenerator/gen_accessors_struct.rs new file mode 100644 index 000000000..2f8cce95d --- /dev/null +++ b/lucet-idl/src/cgenerator/gen_accessors_struct.rs @@ -0,0 +1,202 @@ +use super::*; + +pub fn generate( + cgenerator: &mut CGenerator, + data_description_helper: &DataDescriptionHelper, + cache: &Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + hierarchy: &Hierarchy, +) -> Result<(), IDLError> { + let root_name = hierarchy.root_name(); + let root_macro_size_name = macros::macro_for("BYTES", &root_name); + let current_offset = hierarchy.current_offset(); + + let (named_members, _attrs) = if let DataType::Struct { + members: named_members, + attrs, + } = &data_type_entry.data_type + { + (named_members, attrs) + } else { + unreachable!() + }; + pretty_writer + .eob()? + .write_line( + format!( + "// Platform-independent accessors for the members of the `{}` structure", + data_type_entry.name + ) + .as_bytes(), + )? + .eob()?; + for (i, named_member) in named_members.iter().enumerate() { + let offset = cache + .load_type(data_type_entry.id) + .unwrap() + .load_member(i) + .unwrap() + .offset; + let type_: &DataTypeRef = &named_member.type_; + let hierarchy = hierarchy.push(named_member.name.to_string(), current_offset + offset); + cgenerator.gen_accessors_for_data_type_ref( + data_description_helper, + cache, + &mut pretty_writer.new_block(), + type_, + &named_member.name, + &hierarchy, + )?; + } + + pretty_writer + .eob()? + .write_line( + format!( + "// Platform-independent accessors for the whole `{}` structure", + data_type_entry.name + ) + .as_bytes(), + )? + .eob()?; + let cached = cache.load_type(data_type_entry.id).unwrap(); + let fn_name = hierarchy.fn_name(); + let mut pretty_writer_i1 = pretty_writer.new_block(); + let mut pretty_writer_preprocessor = pretty_writer.new_from_writer(); + let is_reference_alignment_compatible = cgenerator.target.is_reference_alignment_compatible(); + let struct_macro_size_name = macros::macro_for("BYTES", &data_type_entry.name.name); + + // --- store_*() + + pretty_writer + .write_line( + format!( + "static inline void store_{}(unsigned char buf[static {}], const struct {} *v)", + fn_name, root_macro_size_name, data_type_entry.name + ) + .as_bytes(), + )? + .write_line(b"{")?; + pretty_writer_i1.write_line( + format!( + "_Static_assert({} == {}, \"unexpected size\");", + struct_macro_size_name, cached.type_size + ) + .as_bytes(), + )?; + if !is_reference_alignment_compatible { + pretty_writer_preprocessor.write_line(b"#ifdef ___REFERENCE_COMPATIBLE_ENCODING")?; + } + pretty_writer_i1.write_line( + format!("memcpy(&buf[{}], v, {});", current_offset, cached.type_size).as_bytes(), + )?; + if !is_reference_alignment_compatible { + pretty_writer_preprocessor.write_line(b"#else")?; + for (i, named_member) in named_members.iter().enumerate() { + let offset = cache + .load_type(data_type_entry.id) + .unwrap() + .load_member(i) + .unwrap() + .offset; + let hierarchy = hierarchy.push(named_member.name.to_string(), offset); + let fn_name = hierarchy.fn_name(); + let type_ = &named_member.type_; + let is_eventually_an_atom_or_enum = + cgenerator.is_type_eventually_an_atom_or_enum(data_description_helper, type_); + if let DataTypeRef::Ptr(_) = type_ { + pretty_writer_preprocessor.write_line(b"# ifdef ZERO_NATIVE_POINTERS")?; + pretty_writer_i1.write_line( + format!( + "memset(&buf[{} + {}], 0, sizeof v->{});", + current_offset, offset, named_member.name + ) + .as_bytes(), + )?; + pretty_writer_preprocessor.write_line(b"# else")?; + pretty_writer_i1.write_line( + format!( + "memcpy(&buf[{} + {}], &v->{}, sizeof v->{});", + current_offset, offset, named_member.name, named_member.name + ) + .as_bytes(), + )?; + pretty_writer_preprocessor.write_line(b"# endif")?; + } else if is_eventually_an_atom_or_enum { + pretty_writer_i1.write_line( + format!("store_{}(buf, v->{});", fn_name, named_member.name).as_bytes(), + )?; + } else { + pretty_writer_i1.write_line( + format!("store_{}(buf, &v->{});", fn_name, named_member.name).as_bytes(), + )?; + } + } + pretty_writer_preprocessor.write_line(b"#endif")?; + } + pretty_writer.write_line(b"}")?.eob()?; + + // --- load_*() + + pretty_writer + .write_line( + format!( + "static inline void load_{}(struct {} *v_p, const unsigned char buf[static {}])", + fn_name, data_type_entry.name, root_macro_size_name + ) + .as_bytes(), + )? + .write_line(b"{")?; + pretty_writer_i1.write_line( + format!( + "_Static_assert({} == {}, \"unexpected size\");", + struct_macro_size_name, cached.type_size + ) + .as_bytes(), + )?; + if !is_reference_alignment_compatible { + pretty_writer_preprocessor.write_line(b"#ifdef ___REFERENCE_COMPATIBLE_ENCODING")?; + } + pretty_writer_i1.write_line( + format!( + "memcpy(v_p, &buf[{}], {});", + current_offset, cached.type_size + ) + .as_bytes(), + )?; + if !is_reference_alignment_compatible { + pretty_writer_preprocessor.write_line(b"#else")?; + for (i, named_member) in named_members.iter().enumerate() { + let offset = cache + .load_type(data_type_entry.id) + .unwrap() + .load_member(i) + .unwrap() + .offset; + let hierarchy = hierarchy.push(named_member.name.to_string(), offset); + let fn_name = hierarchy.fn_name(); + let type_ = &named_member.type_; + match type_ { + DataTypeRef::Atom(_) | DataTypeRef::Defined(_) => { + pretty_writer_i1.write_line( + format!("load_{}(&v_p->{}, buf);", fn_name, named_member.name).as_bytes(), + )?; + } + DataTypeRef::Ptr(_) => { + pretty_writer_i1.write_line( + format!( + "memcpy(&v_p->{}, &buf[{} + {}], sizeof v_p->{});", + named_member.name, current_offset, offset, named_member.name + ) + .as_bytes(), + )?; + } + } + } + pretty_writer_preprocessor.write_line(b"#endif")?; + } + pretty_writer.write_line(b"}")?.eob()?; + + Ok(()) +} diff --git a/lucet-idl/src/cgenerator/gen_accessors_tagged_union.rs b/lucet-idl/src/cgenerator/gen_accessors_tagged_union.rs new file mode 100644 index 000000000..3971aaa3d --- /dev/null +++ b/lucet-idl/src/cgenerator/gen_accessors_tagged_union.rs @@ -0,0 +1,256 @@ +use super::*; + +pub fn generate( + cgenerator: &mut CGenerator, + data_type_entry: &DataTypeEntry<'_>, + data_description_helper: &DataDescriptionHelper, + cache: &Cache, + pretty_writer: &mut PrettyWriter, + internal_union_type_id: usize, + named_member: &NamedMember>, + hierarchy: &Hierarchy, +) -> Result<(), IDLError> { + let fn_name = hierarchy.fn_name(); + let root_name = hierarchy.root_name(); + let root_macro_size_name = macros::macro_for("BYTES", &root_name); + let name = &named_member.name; + let member_type = named_member.type_.as_ref(); + let cached_type_entry = cache + .load_type(data_type_entry.id) + .expect("Type not cached"); + let first_member_offset = cached_type_entry + .load_member(0) + .expect("No member entry") + .offset; + let mut member_type_size = 0; + if let Some(member_type) = member_type { + let type_info = cgenerator.type_info(data_description_helper, cache, member_type); + member_type_size = type_info.type_size; + } + let mut pretty_writer_i1 = pretty_writer.new_block(); + let mut pretty_writer_preprocessor = pretty_writer.new_from_writer(); + let member_macro_size_name = if let Some(member_type) = member_type { + let unaliased_member_type = cgenerator.unalias(data_description_helper, member_type); + macros::macro_for_data_type_ref(data_description_helper, "BYTES", unaliased_member_type) + } else { + CAtom::tagged_union_type().native_type_size.to_string() + }; + pretty_writer.write_line( + format!( + "// The following set of functions accesses a tagged union `{}` as the internal type `{}`", + fn_name, name + ) + .as_ref(), + )?; + pretty_writer.eob()?; + + // --- is_*() + + pretty_writer.write_line( + format!( + "static inline bool is_{}_{}(const unsigned char buf[static {}])", + fn_name, name, member_macro_size_name + ) + .as_ref(), + )?; + pretty_writer.write_line(b"{")?; + pretty_writer_i1 + .write_line(format!("{} type;", CAtom::tagged_union_type().native_type_name).as_ref())? + .eob()?; + pretty_writer_i1.write_line( + format!( + "_Static_assert({} >= sizeof type, \"unexpected size\");", + member_macro_size_name + ) + .as_ref(), + )?; + pretty_writer_i1 + .write_line(b"memcpy(&type, &buf[0], sizeof type);")? + .eob()?; + pretty_writer_i1.write_line( + format!( + "return type == {};", + CAtom::tagged_union_type() + .little_endian(cgenerator.target, &format!("{}", internal_union_type_id)) + ) + .as_ref(), + )?; + pretty_writer.write_line(b"}")?.eob()?; + + // --- set_*() + + if member_type.is_none() { + pretty_writer.write_line( + format!( + "static inline void set_{}_{}(unsigned char buf[static {}])", + fn_name, name, member_macro_size_name + ) + .as_ref(), + )?; + pretty_writer.write_line(b"{")?; + pretty_writer_i1 + .write_line( + format!( + "const {} type = {};", + CAtom::tagged_union_type().native_type_name, + CAtom::tagged_union_type() + .little_endian(cgenerator.target, &format!("{}", internal_union_type_id)) + ) + .as_bytes(), + )? + .eob()?; + + pretty_writer_i1.write_line(b"memcpy(&buf[0], &type, sizeof type);")?; + pretty_writer.write_line(b"}")?.eob()?; + return Ok(()); + } + + // --- ref_*() + + pretty_writer.write_line(format!("static inline void ref_{}_{}(", fn_name, name).as_ref())?; + pretty_writer + .continuation()? + .write(b"const unsigned char **ibuf_p,")? + .eol()?; + pretty_writer + .continuation()? + .write(format!("const unsigned char buf[static {}])", root_macro_size_name).as_ref())? + .eol()?; + pretty_writer.write_line(b"{")?; + pretty_writer_i1.write_line(format!("assert(is_{}_{}(buf));", fn_name, name).as_ref())?; + pretty_writer_i1 + .write_line(format!("*ibuf_p = &buf[offsetof(struct {}, variant)];", fn_name).as_ref())?; + pretty_writer_i1.eob()?; + pretty_writer_i1.write_line( + format!( + "_Static_assert({} >= offsetof(struct {}, variant) + {}, \"unexpected size\");", + root_macro_size_name, fn_name, member_type_size + ) + .as_ref(), + )?; + pretty_writer.write_line(b"}")?.eob()?; + + // --- mut_*() + + pretty_writer.write_line(format!("static inline void mut_{}_{}(", fn_name, name).as_ref())?; + pretty_writer + .continuation()? + .write(b"unsigned char **ibuf_p,")? + .eol()?; + pretty_writer + .continuation()? + .write(format!("unsigned char buf[static {}])", root_macro_size_name).as_ref())? + .eol()?; + pretty_writer.write_line(b"{")?; + pretty_writer_i1.write_line(format!("assert(is_{}_{}(buf));", fn_name, name).as_ref())?; + pretty_writer_i1 + .write_line(format!("*ibuf_p = &buf[offsetof(struct {}, variant)];", fn_name).as_ref())?; + pretty_writer_i1.eob()?; + pretty_writer_i1.write_line( + format!( + "_Static_assert({} >= offsetof(struct {}, variant) + {}, \"unexpected size\");", + root_macro_size_name, fn_name, member_type_size + ) + .as_ref(), + )?; + pretty_writer.write_line(b"}")?.eob()?; + + // --- Accessors for inner members + + let type_ = member_type.expect("Empty member"); + let hierarchy1 = hierarchy.push(named_member.name.to_string(), first_member_offset); + cgenerator.gen_accessors_for_data_type_ref( + data_description_helper, + cache, + pretty_writer, + type_, + &named_member.name, + &hierarchy1, + )?; + + // --- Accessors for the whole tagged union + + let type_size = cached_type_entry.type_size; + let union_macro_size_name = macros::macro_for("BYTES", &fn_name); + let is_eventually_an_atom_or_enum = + cgenerator.is_type_eventually_an_atom_or_enum(data_description_helper, type_); + + pretty_writer + .write_line( + format!( + "// Store the whole `{}` tagged union, when used as type `{}`", + fn_name, name + ) + .as_ref(), + )? + .eob()?; + pretty_writer.write_line( + format!( + "static inline void store_{}_as_{}(unsigned char buf[static {}], const struct {} *t)", + fn_name, name, union_macro_size_name, fn_name + ) + .as_ref(), + )?; + pretty_writer.write_line(b"{")?; + pretty_writer_i1.write_line( + format!( + "_Static_assert({} == {}, \"unexpected size\");", + union_macro_size_name, type_size + ) + .as_ref(), + )?; + pretty_writer_i1 + .write_line(format!("assert(t->___type == {});", internal_union_type_id).as_ref())? + .eob()?; + pretty_writer_i1.write_line( + format!( + "const {} type = {}; // {}", + CAtom::tagged_union_type().native_type_name, + CAtom::tagged_union_type() + .little_endian(cgenerator.target, &format!("{}", internal_union_type_id)), + name + ) + .as_bytes(), + )?; + pretty_writer_i1 + .write_line(b"memcpy(&buf[0], &type, sizeof type);")? + .eob()?; + if let DataTypeRef::Ptr(_) = type_ { + pretty_writer_preprocessor.write_line(b"# ifdef ZERO_NATIVE_POINTERS")?; + pretty_writer_i1.write_line( + format!( + "memset(&buf[offsetof(struct {}, variant)], 0, sizeof *t);", + fn_name + ) + .as_ref(), + )?; + pretty_writer_preprocessor.write_line(b"# else")?; + pretty_writer_i1.write_line( + format!( + "memcpy(&buf[offsetof(struct {}, variant)], &t->variant.{}, sizeof *t);", + fn_name, name + ) + .as_ref(), + )?; + pretty_writer_preprocessor.write_line(b"# endif")?; + } else if is_eventually_an_atom_or_enum { + pretty_writer_i1.write_line( + format!( + "store_{}_{}(&buf[offsetof(struct {}, variant)], t->variant.{});", + fn_name, name, fn_name, name + ) + .as_ref(), + )?; + } else { + pretty_writer_i1.write_line( + format!( + "store_{}_{}(&buf[offsetof(struct {}, variant)], &t->variant.{});", + fn_name, name, fn_name, name + ) + .as_ref(), + )?; + } + pretty_writer.write_line(b"}")?; + + Ok(()) +} diff --git a/lucet-idl/src/cgenerator/gen_alias.rs b/lucet-idl/src/cgenerator/gen_alias.rs new file mode 100644 index 000000000..528749477 --- /dev/null +++ b/lucet-idl/src/cgenerator/gen_alias.rs @@ -0,0 +1,58 @@ +use super::*; + +// The most important thing in alias generation is to cache the size +// and alignment rules of what it ultimately points to +pub fn generate( + cgenerator: &mut CGenerator, + data_description_helper: &DataDescriptionHelper, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, +) -> Result<(), IDLError> { + let (type_, _attrs) = if let DataType::Alias { to: type_, attrs } = &data_type_entry.data_type { + (type_, attrs) + } else { + unreachable!() + }; + let type_info = cgenerator.type_info(data_description_helper, cache, type_); + pretty_writer.indent()?; + pretty_writer.write(format!("typedef {}", type_info.type_name).as_bytes())?; + pretty_writer.space()?; + for _ in 0..type_info.indirections { + pretty_writer.write(b"*")?; + } + pretty_writer.write(data_type_entry.name.name.as_bytes())?; + pretty_writer.write(b";")?; + if type_info.indirections == 0 { + let leaf_type_info = + cgenerator.type_info(data_description_helper, cache, type_info.leaf_data_type_ref); + if leaf_type_info.type_name != type_info.type_name { + pretty_writer.write(b" // equivalent to ")?; + pretty_writer.write(leaf_type_info.type_name.as_bytes())?; + } + } + pretty_writer.eol()?; + pretty_writer.eob()?; + cache.store_type( + data_type_entry.id, + CachedTypeEntry { + type_size: type_info.type_size, + type_align: type_info.type_align, + members: vec![], + }, + ); + + // Add an assertion to check that resolved size is the one we computed + if type_info.indirections == 0 { + pretty_writer.write_line( + format!( + "_Static_assert(sizeof({}) == {}, \"unexpected alias size\");", + data_type_entry.name.name, type_info.type_size + ) + .as_bytes(), + )?; + pretty_writer.eob()?; + } + + Ok(()) +} diff --git a/lucet-idl/src/cgenerator/gen_enum.rs b/lucet-idl/src/cgenerator/gen_enum.rs new file mode 100644 index 000000000..5c763fa55 --- /dev/null +++ b/lucet-idl/src/cgenerator/gen_enum.rs @@ -0,0 +1,78 @@ +use super::*; + +// Enums generate both a specific typedef, and a traditional C-style enum +// The typedef is required to use a native type which is consistent across all architectures +pub fn generate( + cgenerator: &mut CGenerator, + _data_description_helper: &DataDescriptionHelper, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, +) -> Result<(), IDLError> { + let (named_members, _attrs) = if let DataType::Enum { + members: named_members, + attrs, + } = &data_type_entry.data_type + { + (named_members, attrs) + } else { + unreachable!() + }; + + let enum_native_type = CAtom::enum_(); + let (type_align, type_size, type_name) = ( + enum_native_type.native_type_align, + enum_native_type.native_type_size, + enum_native_type.native_type_name, + ); + + pretty_writer.write_line( + format!( + "typedef {} {}; // enum, should be in the [0...{}] range", + type_name, + data_type_entry.name.name, + named_members.len() - 1 + ) + .as_bytes(), + )?; + pretty_writer.write_line(format!("enum ___{} {{", data_type_entry.name.name).as_bytes())?; + let mut pretty_writer_i1 = pretty_writer.new_block(); + for (i, named_member) in named_members.iter().enumerate() { + pretty_writer_i1.write_line( + format!( + "{}, // {}", + macros::macro_for(&data_type_entry.name.name, &named_member.name), + i + ) + .as_bytes(), + )?; + } + pretty_writer.write_line(b"};")?; + pretty_writer.eob()?; + pretty_writer.write_line( + format!( + "_Static_assert(sizeof({}) == {}, \"unexpected enumeration size\");", + data_type_entry.name.name, type_size + ) + .as_bytes(), + )?; + pretty_writer.eob()?; + macros::define( + cgenerator, + pretty_writer, + "BYTES", + &data_type_entry.name.name, + type_size, + )?; + pretty_writer.eob()?; + + cache.store_type( + data_type_entry.id, + CachedTypeEntry { + type_size, + type_align, + members: vec![], + }, + ); + Ok(()) +} diff --git a/lucet-idl/src/cgenerator/gen_prelude.rs b/lucet-idl/src/cgenerator/gen_prelude.rs new file mode 100644 index 000000000..3edddd76c --- /dev/null +++ b/lucet-idl/src/cgenerator/gen_prelude.rs @@ -0,0 +1,96 @@ +use super::*; + +pub fn generate( + pretty_writer: &mut PrettyWriter, + target: Target, + backend_config: BackendConfig, +) -> Result<(), IDLError> { + let prelude = r" +#include +#include +#include +#include +#include +#include "; + + for line in prelude.lines() { + pretty_writer.write_line(line.as_ref())?; + } + pretty_writer.eob()?; + + if backend_config.zero_native_pointers { + pretty_writer.write_line( + r"#define ZERO_NATIVE_POINTERS // Avoid serializing native pointers".as_ref(), + )?; + } else if !(target.is_reference_alignment_compatible() + && target.uses_reference_target_endianness()) + { + pretty_writer.write_line( + r"// #define ZERO_NATIVE_POINTERS // Define to avoid serializing native pointers" + .as_ref(), + )?; + } + + let prelude = r" +#ifndef ___REFERENCE_COMPATIBLE_ALIGNMENT +# if defined(__amd64) || defined(__amd64__) || defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) || \ + defined(__EMSCRIPTEN__) +# define ___REFERENCE_COMPATIBLE_ALIGNMENT +# endif +#endif + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define ___le_uint16_t(X) (X) +# define ___le_uint32_t(X) (X) +# define ___le_uint64_t(X) (X) +# define ___le_int16_t(X) (X) +# define ___le_int32_t(X) (X) +# define ___le_int64_t(X) (X) +# define ___le_float(X) (X) +# define ___le_double(X) (X) +#else +# define ___bswap16(X) __builtin_bswap16(X) +# define ___bswap32(X) __builtin_bswap32(X) +# define ___bswap64(X) __builtin_bswap64(X) + +# define ___le_uint16_t(X) ___bswap16(X) +# define ___le_uint32_t(X) ___bswap32(X) +# define ___le_uint64_t(X) ___bswap64(X) +# define ___le_int16_t(X) ((int16_t) ___bswap16((uint16_t) (X))) +# define ___le_int32_t(X) ((int32_t) ___bswap32((uint32_t) (X))) +# define ___le_int64_t(X) ((int64_t) ___bswap64((uint64_t) (X))) + +static inline float ___le_float(float X) { + uint32_t X_; float Xf; memcpy(&X_, &X, sizeof X_); + X_ = ___le_uint32_t(X_); memcpy(&Xf, &X_, sizeof Xf); + return Xf; +} + +static inline double ___le_double(double X) { + uint64_t X_; double Xd; memcpy(&X_, &X, sizeof X_); + X_ = ___le_uint64_t(X_); memcpy(&Xd, &X_, sizeof Xd); + return Xd; +} +#endif + +#if !defined(ZERO_NATIVE_POINTERS) && defined(___REFERENCE_COMPATIBLE_ALIGNMENT) && \ + __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define ___REFERENCE_COMPATIBLE_ENCODING +#endif + +#define BYTES_PTR 8 + +#if UINTPTR_MAX > 0xFFFFFFFFULL +# define ___POINTER_PAD(O) +#elif UINTPTR_MAX > 0xFFFFUL +# define ___POINTER_PAD(O) uint8_t ___ptrpad_ ## O ## _[4]; +#else +# define ___POINTER_PAD(O) uint8_t ___ptrpad_ ## O ## _[6]; +#endif +"; + for line in prelude.lines() { + pretty_writer.write_line(line.as_ref())?; + } + pretty_writer.eob()?; + Ok(()) +} diff --git a/lucet-idl/src/cgenerator/gen_struct.rs b/lucet-idl/src/cgenerator/gen_struct.rs new file mode 100644 index 000000000..9c876ab55 --- /dev/null +++ b/lucet-idl/src/cgenerator/gen_struct.rs @@ -0,0 +1,111 @@ +use super::*; +use std::cmp; + +pub fn generate( + cgenerator: &mut CGenerator, + data_description_helper: &DataDescriptionHelper, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, +) -> Result<(), IDLError> { + let (named_members, _attrs) = if let DataType::Struct { + members: named_members, + attrs, + } = &data_type_entry.data_type + { + (named_members, attrs) + } else { + unreachable!() + }; + pretty_writer.write_line(format!("struct {} {{", data_type_entry.name.name).as_bytes())?; + let mut pretty_writer_i1 = pretty_writer.new_block(); + let mut offset: usize = 0; + let mut first_member_align = 0; + let mut members_offsets = vec![]; + for named_member in named_members { + let type_info = cgenerator.type_info(data_description_helper, cache, &named_member.type_); + let type_align = type_info.type_align; + let type_size = type_info.type_size; + let padding = (type_align - 1) - ((offset + (type_align - 1)) % type_align); + if padding > 0 { + pretty_writer_i1.write_line( + format!("uint8_t ___pad{}_{}[{}];", type_align, offset, padding).as_bytes(), + )?; + offset += padding; + } + members_offsets.push(offset); + pretty_writer_i1.indent()?; + pretty_writer_i1.write(type_info.type_name.as_bytes())?; + pretty_writer_i1.space()?; + for _ in 0..type_info.indirections { + pretty_writer_i1.write(b"*")?; + } + pretty_writer_i1.write(named_member.name.as_bytes())?; + pretty_writer_i1.write(b";")?; + pretty_writer_i1.eol()?; + + cgenerator.pointer_pad( + &mut pretty_writer_i1, + type_info.indirections, + offset, + &named_member.name, + )?; + + offset += type_size; + first_member_align = cmp::max(first_member_align, type_align); + } + pretty_writer.write_line(b"};")?; + pretty_writer.eob()?; + + // cache the total structure size, as well as its alignment, which is equal + // to the alignment of the first member of that structure + let struct_align = first_member_align; + let struct_size = offset; + let cached = cache.store_type( + data_type_entry.id, + CachedTypeEntry { + type_size: struct_size, + type_align: struct_align, + members: vec![], + }, + ); + + // Cache members offsets + cached.store_members( + members_offsets + .iter() + .map(|&offset| CachedStructMemberEntry { offset }) + .collect::>(), + ); + + // Add assertions to check that the target platform matches the expected alignment + // Also add a macro definition for the structure size + // Skip the first member, as it will always be at the beginning of the structure + for (i, named_member) in named_members.iter().enumerate().skip(1) { + pretty_writer.write_line( + format!( + "_Static_assert(offsetof(struct {}, {}) == {}, \"unexpected offset\");", + data_type_entry.name.name, named_member.name, members_offsets[i] + ) + .as_bytes(), + )?; + } + pretty_writer.write_line( + format!( + "_Static_assert(sizeof(struct {}) == {}, \"unexpected structure size\");", + data_type_entry.name.name, struct_size + ) + .as_bytes(), + )?; + pretty_writer.eob()?; + macros::define( + cgenerator, + pretty_writer, + "BYTES", + &data_type_entry.name.name, + struct_size, + )?; + pretty_writer.eob()?; + + Ok(()) +} diff --git a/lucet-idl/src/cgenerator/gen_tagged_union.rs b/lucet-idl/src/cgenerator/gen_tagged_union.rs new file mode 100644 index 000000000..91cb40275 --- /dev/null +++ b/lucet-idl/src/cgenerator/gen_tagged_union.rs @@ -0,0 +1,180 @@ +use super::*; + +pub fn generate( + cgenerator: &mut CGenerator, + data_description_helper: &DataDescriptionHelper, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, +) -> Result<(), IDLError> { + let (named_members, _attrs) = if let DataType::TaggedUnion { + members: named_members, + attrs, + } = &data_type_entry.data_type + { + (named_members, attrs) + } else { + unreachable!() + }; + + for (i, named_member) in named_members.iter().enumerate() { + let internal_union_type_id = i + 1; + macros::define( + cgenerator, + pretty_writer, + "TYPE", + format!("{}_{}", data_type_entry.name.name, named_member.name).as_str(), + internal_union_type_id, + )?; + } + pretty_writer.eob()?; + pretty_writer.write_line(format!("struct {} {{", data_type_entry.name.name).as_bytes())?; + let mut pretty_writer_i1 = pretty_writer.new_block(); + let mut offset: usize = 0; + + // The first member of the structure is the variant type + // This will also define the required alignment for the tagged union + // Variant types start at `1` and not `0` to help find possibly uninitialized variable + let tagged_union_type_native_type = CAtom::tagged_union_type(); + let (tagged_union_type_align, tagged_union_type_size, tagged_union_type_name) = ( + tagged_union_type_native_type.native_type_align, + tagged_union_type_native_type.native_type_size, + tagged_union_type_native_type.native_type_name, + ); + let first_member_align = Some(tagged_union_type_align); + pretty_writer_i1.indent()?; + pretty_writer_i1.write(tagged_union_type_name.as_bytes())?; + pretty_writer_i1.space()?; + pretty_writer_i1.write( + format!( + "___type; // tagged union type, should be in the [1...{}] range", + named_members.len() + ) + .as_bytes(), + )?; + pretty_writer_i1.eol()?; + offset += tagged_union_type_size; + + let mut includes_pointers = false; + + // The size of the union is the size of the largest member. + // Ditto for the alignment. + // In order to know how much padding is required between the variant type and the + // union, find these maximum values first. + // We also need to find if we have at least one pointer. In that case, additional + // padding at the end of the structure may be required for targets with 32-bit + // pointers. + let mut max_align = 0; + let mut max_size = 0; + for named_member in named_members { + if let Some(type_) = named_member.type_.as_ref() { + let type_info = cgenerator.type_info(data_description_helper, cache, type_); + if type_info.type_align > max_align { + max_align = type_info.type_align; + } + if type_info.type_size > max_size { + max_size = type_info.type_size; + } + if type_info.indirections > 0 { + includes_pointers = true; + } + } + } + + // Add optional padding between the variant type and the union + let padding = (max_align - 1) - ((offset + (max_align - 1)) % max_align); + if padding > 0 { + pretty_writer_i1.write_line( + format!("uint8_t ___pad{}_{}[{}];", max_align, offset, padding).as_bytes(), + )?; + offset += padding; + } + + let variant_offset = offset; + + pretty_writer_i1.write_line(b"union {")?; + let mut pretty_writer_i2 = pretty_writer_i1.new_block(); + for (i, named_member) in named_members.iter().enumerate() { + let internal_union_type_id = i + 1; + if named_member.type_.is_none() { + // Untyped union member + pretty_writer_i2.write_line( + format!( + "// void {}; - type {}", + named_member.name, internal_union_type_id + ) + .as_bytes(), + )?; + continue; + } + let type_ = named_member.type_.as_ref().unwrap(); + let type_info = cgenerator.type_info(data_description_helper, cache, type_); + pretty_writer_i2.indent()?; + pretty_writer_i2.write(type_info.type_name.as_bytes())?; + pretty_writer_i2.space()?; + for _ in 0..type_info.indirections { + pretty_writer_i2.write(b"*")?; + } + pretty_writer_i2.write(named_member.name.as_bytes())?; + pretty_writer_i2.write(b";")?; + pretty_writer_i2.space()?; + pretty_writer_i2.write(format!("// - type {}", internal_union_type_id).as_bytes())?; + pretty_writer_i2.eol()?; + } + + pretty_writer_i1.write_line(b"} variant;")?; + offset += max_size; + + // If the tagged enum includes pointers, we may have to extend its size + // to match what it would be on a target with 64-bit pointers + if includes_pointers { + cgenerator.pointer_pad(&mut pretty_writer_i1, 1, offset, "inside tagged union")?; + } + + pretty_writer.write_line(b"};")?; + pretty_writer.eob()?; + + let struct_align = first_member_align.unwrap(); + let struct_size = offset; + cache.store_type( + data_type_entry.id, + CachedTypeEntry { + type_size: struct_size, + type_align: struct_align, + members: vec![CachedStructMemberEntry { + offset: variant_offset, + }], + }, + ); + + // Add an assertion to check that the variant is properly aligned + pretty_writer.write_line( + format!( + "_Static_assert(offsetof(struct {}, variant) == {}, \"unexpected variant offset\");", + data_type_entry.name.name, variant_offset + ) + .as_bytes(), + )?; + + // Add an assertion to check that the structure size matches what we expect + pretty_writer.write_line( + format!( + "_Static_assert(sizeof(struct {}) == {}, \"unexpected tagged union structure size\");", + data_type_entry.name.name, struct_size + ) + .as_bytes(), + )?; + pretty_writer.eob()?; + + // Add a macro for the tagged union size + macros::define( + cgenerator, + pretty_writer, + "BYTES", + &data_type_entry.name.name, + struct_size, + )?; + pretty_writer.eob()?; + + Ok(()) +} diff --git a/lucet-idl/src/cgenerator/macros.rs b/lucet-idl/src/cgenerator/macros.rs new file mode 100644 index 000000000..151bba108 --- /dev/null +++ b/lucet-idl/src/cgenerator/macros.rs @@ -0,0 +1,57 @@ +use super::*; + +// Return the name of a macro according to a name and a prefix + +pub fn macro_for(prefix: &str, name: &str) -> String { + let mut macro_name = String::new(); + macro_name.push_str(&prefix.to_uppercase()); + macro_name.push('_'); + let mut previous_was_uppercase = name.chars().nth(0).expect("Empty name").is_uppercase(); + for c in name.chars() { + let is_uppercase = c.is_uppercase(); + if is_uppercase != previous_was_uppercase { + macro_name.push('_'); + } + for uc in c.to_uppercase() { + macro_name.push(uc); + } + previous_was_uppercase = is_uppercase; + } + macro_name +} + +// Generate a macro definition + +pub fn define( + _cgenerator: &mut CGenerator, + pretty_writer: &mut PrettyWriter, + prefix: &str, + name: &str, + value: V, +) -> Result<(), IDLError> { + let macro_name = macro_for(prefix, name); + let mut pretty_writer_preprocessor = pretty_writer.new_from_writer(); + pretty_writer_preprocessor + .write_line(format!("#define {} {}", macro_name, value.to_string()).as_ref())?; + Ok(()) +} + +// Return a macro name for a type reference + +pub fn macro_for_data_type_ref( + data_description_helper: &DataDescriptionHelper, + prefix: &str, + data_type_ref: &DataTypeRef, +) -> String { + match data_type_ref { + DataTypeRef::Atom(atom_type) => { + let native_type_size = CAtom::from(*atom_type).native_type_size; + format!("{}", native_type_size) + } + DataTypeRef::Ptr(_) => macro_for(prefix, "PTR"), + DataTypeRef::Defined(data_type_id) => { + let data_type_entry = data_description_helper.get(*data_type_id); + macro_for(prefix, &data_type_entry.name.name) + } + } +} diff --git a/lucet-idl/src/cgenerator/mod.rs b/lucet-idl/src/cgenerator/mod.rs new file mode 100644 index 000000000..ee43a5c22 --- /dev/null +++ b/lucet-idl/src/cgenerator/mod.rs @@ -0,0 +1,425 @@ +#![allow(dead_code)] +#![allow(unused_variables)] + +mod catom; +mod gen_accessors_alias; +mod gen_accessors_atom; +mod gen_accessors_enum; +mod gen_accessors_ptr; +mod gen_accessors_struct; +mod gen_accessors_tagged_union; +mod gen_alias; +mod gen_enum; +mod gen_prelude; +mod gen_struct; +mod gen_tagged_union; +mod macros; + +pub(crate) use self::catom::*; +use super::backend::*; +use super::cache::*; +use super::data_description_helper::*; +use super::errors::*; +use super::generators::*; +use super::pretty_writer::*; +use super::target::*; +use lucet_idl::types::*; +use lucet_idl::validate::*; +use std::io::prelude::*; + +#[derive(Clone, Debug)] +struct CTypeInfo<'t> { + /// The native type name + type_name: String, + /// Alignment rules for that type + type_align: usize, + /// The native type size + type_size: usize, + /// How many pointer indirections are required to get to the atomic type + indirections: usize, + /// The leaf type node + leaf_data_type_ref: &'t DataTypeRef, +} + +/// Generator for the C backend +pub struct CGenerator { + pub target: Target, + pub backend_config: BackendConfig, +} + +impl Generator for CGenerator { + fn gen_prelude(&mut self, pretty_writer: &mut PrettyWriter) -> Result<(), IDLError> { + pretty_writer + .eob()? + .write_line(b"// ---------- Prelude ----------")? + .eob()?; + gen_prelude::generate(pretty_writer, self.target, self.backend_config)?; + Ok(()) + } + + fn gen_type_header( + &mut self, + _data_description_helper: &DataDescriptionHelper, + _cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + ) -> Result<(), IDLError> { + pretty_writer + .eob()? + .write_line( + format!("// ---------- {} ----------", data_type_entry.name.name).as_bytes(), + )? + .eob()?; + Ok(()) + } + + // The most important thing in alias generation is to cache the size + // and alignment rules of what it ultimately points to + fn gen_alias( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + ) -> Result<(), IDLError> { + gen_alias::generate( + self, + data_description_helper, + cache, + pretty_writer, + data_type_entry, + ) + } + + fn gen_struct( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + ) -> Result<(), IDLError> { + gen_struct::generate( + self, + data_description_helper, + cache, + pretty_writer, + data_type_entry, + ) + } + + // Enums generate both a specific typedef, and a traditional C-style enum + // The typedef is required to use a native type which is consistent across all architectures + fn gen_enum( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + ) -> Result<(), IDLError> { + gen_enum::generate( + self, + data_description_helper, + cache, + pretty_writer, + data_type_entry, + ) + } + + fn gen_tagged_union( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + ) -> Result<(), IDLError> { + gen_tagged_union::generate( + self, + data_description_helper, + cache, + pretty_writer, + data_type_entry, + ) + } + + fn gen_accessors_struct( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + hierarchy: &Hierarchy, + ) -> Result<(), IDLError> { + gen_accessors_struct::generate( + self, + data_description_helper, + cache, + pretty_writer, + data_type_entry, + hierarchy, + ) + } + + fn gen_accessors_tagged_union( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + hierarchy: &Hierarchy, + ) -> Result<(), IDLError> { + let (named_members, _attrs) = if let DataType::TaggedUnion { + members: named_members, + attrs, + } = &data_type_entry.data_type + { + (named_members, attrs) + } else { + unreachable!() + }; + for (i, named_member) in named_members.iter().enumerate() { + let internal_union_type_id = 1 + i; + gen_accessors_tagged_union::generate( + self, + data_type_entry, + data_description_helper, + cache, + pretty_writer, + internal_union_type_id, + &named_member, + &hierarchy, + )?; + } + Ok(()) + } + + fn gen_accessors_enum( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + hierarchy: &Hierarchy, + ) -> Result<(), IDLError> { + gen_accessors_enum::generate( + self, + data_description_helper, + cache, + pretty_writer, + data_type_entry, + hierarchy, + ) + } + + fn gen_accessors_alias( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + hierarchy: &Hierarchy, + ) -> Result<(), IDLError> { + gen_accessors_alias::generate( + self, + data_description_helper, + cache, + pretty_writer, + data_type_entry, + hierarchy, + ) + } +} + +impl CGenerator { + /// Traverse a `DataTypeRef` chain, and return information + /// about the leaf node as well as the native type to use + /// for this data type + fn type_info<'t>( + &self, + data_description_helper: &'t DataDescriptionHelper, + cache: &Cache, + mut type_: &'t DataTypeRef, + ) -> CTypeInfo<'t> { + let mut indirections = 0; + let (mut type_align, mut type_size) = (None, None); + let mut type_name = None; + loop { + match &type_ { + DataTypeRef::Ptr(to) => { + type_ = to.as_ref(); + // Only keep counting indirections if we are not resolving an alias + if type_name.is_none() { + indirections += 1; + } + continue; + } + DataTypeRef::Atom(atom_type) => { + let native_atom = CAtom::from(*atom_type); + type_align = type_align.or_else(|| Some(native_atom.native_type_align)); + type_size = type_size.or_else(|| Some(native_atom.native_type_size)); + type_name = + type_name.or_else(|| Some(native_atom.native_type_name.to_string())); + } + DataTypeRef::Defined(data_type_id) => { + if indirections == 0 { + let cached = cache.load_type(*data_type_id).unwrap(); + type_align = type_align.or_else(|| Some(cached.type_align)); + type_size = type_size.or_else(|| Some(cached.type_size)); + } + let data_type_entry = data_description_helper.get(*data_type_id); + match data_type_entry.data_type { + DataType::Struct { .. } => { + type_name = type_name + .or_else(|| Some(format!("struct {}", data_type_entry.name.name))) + } + DataType::TaggedUnion { .. } => { + type_name = type_name + .or_else(|| Some(format!("struct {}", data_type_entry.name.name))) + } + DataType::Enum { .. } => { + type_name = type_name.or_else(|| { + Some(format!( + "{} /* (enum ___{}) */", + data_type_entry.name.name, data_type_entry.name.name + )) + }) + } + DataType::Alias { to, .. } => { + type_name = + type_name.or_else(|| Some(data_type_entry.name.name.to_string())); + type_ = to; + continue; + } + }; + } + } + break; + } + // No matter what the base type is, pointers always have the same size + if indirections > 0 { + type_align = Some(CAtom::ptr().native_type_align); + type_size = Some(CAtom::ptr().native_type_size); + } + CTypeInfo { + type_name: type_name.unwrap(), + type_align: type_align.unwrap(), + type_size: type_size.unwrap(), + indirections, + leaf_data_type_ref: type_, + } + } + + // Return `true` if the type is an atom, an emum, or an alias to one of these + pub fn is_type_eventually_an_atom_or_enum( + &self, + data_description_helper: &DataDescriptionHelper, + type_: &DataTypeRef, + ) -> bool { + let inner_type = match type_ { + DataTypeRef::Atom(_) => return true, + DataTypeRef::Ptr(_) => return false, + DataTypeRef::Defined(inner_type) => inner_type, + }; + let inner_data_type_entry = data_description_helper.get(*inner_type); + let inner_data_type = inner_data_type_entry.data_type; + match inner_data_type { + DataType::Struct { .. } | DataType::TaggedUnion { .. } => false, + DataType::Enum { .. } => true, + DataType::Alias { to, .. } => { + self.is_type_eventually_an_atom_or_enum(data_description_helper, to) + } + } + } + + /// Return the type refererence, with aliases being resolved + pub fn unalias<'t>( + &self, + data_description_helper: &'t DataDescriptionHelper, + type_: &'t DataTypeRef, + ) -> &'t DataTypeRef { + let inner_type = match type_ { + DataTypeRef::Atom(_) | DataTypeRef::Ptr(_) => return type_, + DataTypeRef::Defined(inner_type) => inner_type, + }; + let inner_data_type_entry = data_description_helper.get(*inner_type); + let inner_data_type = inner_data_type_entry.data_type; + if let DataType::Alias { to, .. } = inner_data_type { + self.unalias(data_description_helper, to) + } else { + type_ + } + } + + /// Possibly add some padding so that pointers are aligned like the reference platform + pub fn pointer_pad( + &mut self, + pretty_writer: &mut PrettyWriter, + indirections: usize, + offset: usize, + name: &str, + ) -> Result<(), IDLError> { + if indirections == 0 { + return Ok(()); + } + if self.target.is_reference_target() { + return Ok(()); + } + pretty_writer.write_line( + format!( + "___POINTER_PAD({}) // pad pointer `{}` at offset {} to match alignment of the reference target ({} bytes)", + offset, + name, + offset, + CAtom::ptr().native_type_align + ) + .as_bytes(), + )?; + Ok(()) + } + + fn gen_accessors_for_id( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &Cache, + pretty_writer: &mut PrettyWriter, + id: DataTypeId, + hierarchy: &Hierarchy, + ) -> Result<(), IDLError> { + data_description_helper.gen_accessors_for_id(self, cache, pretty_writer, id, hierarchy) + } + + fn gen_accessors_for_data_type_ref( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &Cache, + pretty_writer: &mut PrettyWriter, + type_: &DataTypeRef, + name: &str, + hierarchy: &Hierarchy, + ) -> Result<(), IDLError> { + let type_ = self.unalias(data_description_helper, type_); + match type_ { + DataTypeRef::Atom(atom_type) => gen_accessors_atom::generate( + self, + data_description_helper, + pretty_writer, + *atom_type, + &hierarchy, + ), + DataTypeRef::Ptr(type_) => gen_accessors_ptr::generate( + self, + data_description_helper, + cache, + pretty_writer, + type_, + &hierarchy, + ), + DataTypeRef::Defined(data_type_id) => self.gen_accessors_for_id( + data_description_helper, + cache, + pretty_writer, + *data_type_id, + &hierarchy, + ), + } + } +} diff --git a/lucet-idl/src/config.rs b/lucet-idl/src/config.rs new file mode 100644 index 000000000..2be0b54ea --- /dev/null +++ b/lucet-idl/src/config.rs @@ -0,0 +1,78 @@ +use super::backend::*; +use super::errors::*; +use super::target::*; +use clap::{App, Arg}; +use std::path::PathBuf; + +#[derive(Default, Clone, Debug)] +pub struct Config { + pub input_path: PathBuf, + pub output_path: Option, + pub target: Target, + pub backend: Backend, + pub backend_config: BackendConfig, +} + +impl Config { + pub fn parse() -> Result { + let matches = App::new("lucet-idl") + .version("1.0") + .about("lucet_idl code generator") + .arg( + Arg::with_name("input_file") + .short("i") + .long("input") + .takes_value(true) + .required(true) + .help("Path to the input file"), + ) + .arg( + Arg::with_name("target") + .short("t") + .long("target") + .default_value("Generic") + .takes_value(true) + .required(false) + .help("Target, one of: x86, x86_64, x86_64_32, generic"), + ) + .arg( + Arg::with_name("backend") + .short("b") + .long("backend") + .default_value("c") + .takes_value(true) + .required(false) + .help("Backend, one of: c, rust"), + ) + .arg( + Arg::with_name("zero-native-pointers") + .short("z") + .long("zero-native-pointers") + .takes_value(false) + .required(false) + .help("Do not serialize native pointers"), + ) + .get_matches(); + let input_path = PathBuf::from( + matches + .value_of("input_file") + .ok_or(IDLError::UsageError("Input file required"))?, + ); + let mut target = Target::from(matches.value_of("target").unwrap()); + let backend = Backend::from(matches.value_of("backend").unwrap()); + let zero_native_pointers = matches.is_present("zero-native-pointers"); + if zero_native_pointers { + target = Target::Generic; + } + let backend_config = BackendConfig { + zero_native_pointers, + }; + Ok(Config { + input_path, + output_path: None, + target, + backend, + backend_config, + }) + } +} diff --git a/lucet-idl/src/data_description_helper.rs b/lucet-idl/src/data_description_helper.rs new file mode 100644 index 000000000..fdec4ba48 --- /dev/null +++ b/lucet-idl/src/data_description_helper.rs @@ -0,0 +1,171 @@ +use super::cache::*; +use super::errors::*; +use super::generators::*; +use super::pretty_writer::*; +use lucet_idl::validate::*; +use std::io::prelude::*; + +/// A convenient structure holding a data type, its name and +/// its internal IDL representation +#[derive(Debug, Clone)] +pub struct DataTypeEntry<'t> { + pub id: DataTypeId, + pub name: &'t Name, + pub data_type: &'t DataType, +} + +/// Transforms a `DataDescription` +/// We definitely need a better name for it +#[derive(Debug, Clone)] +pub struct DataDescriptionHelper { + pub data_description: DataDescription, +} + +impl DataDescriptionHelper { + /// Retrieve information about a data type given its identifier + pub fn get(&self, id: DataTypeId) -> DataTypeEntry<'_> { + let name = &self.data_description.names[id.0]; + let data_type = &self.data_description.data_types[&id.0]; + DataTypeEntry { + id, + name, + data_type, + } + } + + /// Generate native code for a data type whose identifier is `id` + /// `Generator` is currently an alias for `CGenerator`, but will be turned into + /// a trait for dynamic dispatch when the first backend gets a reasonably stable API. + pub fn gen_for_id( + &self, + generator: &mut dyn Generator, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + id: DataTypeId, + ) -> Result<(), IDLError> { + let data_type_entry = self.get(id); + self.gen_type_header(generator, cache, pretty_writer, &data_type_entry)?; + match &data_type_entry.data_type { + DataType::Struct { .. } => { + self.gen_struct(generator, cache, pretty_writer, &data_type_entry) + } + DataType::TaggedUnion { .. } => { + self.gen_tagged_union(generator, cache, pretty_writer, &data_type_entry) + } + DataType::Alias { .. } => { + self.gen_alias(generator, cache, pretty_writer, &data_type_entry) + } + DataType::Enum { .. } => { + self.gen_enum(generator, cache, pretty_writer, &data_type_entry) + } + }?; + self.gen_accessors_for_id( + generator, + cache, + pretty_writer, + id, + &Hierarchy::new(data_type_entry.name.name.to_string(), 0), + )?; + Ok(()) + } + + /// Generate a comment describing the type being defined right after + fn gen_type_header( + &self, + generator: &mut dyn Generator, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + ) -> Result<(), IDLError> { + generator.gen_type_header(&self, cache, pretty_writer, data_type_entry)?; + Ok(()) + } + + fn gen_enum( + &self, + generator: &mut dyn Generator, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + ) -> Result<(), IDLError> { + generator.gen_enum(&self, cache, pretty_writer, data_type_entry)?; + Ok(()) + } + + fn gen_struct( + &self, + generator: &mut dyn Generator, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + ) -> Result<(), IDLError> { + generator.gen_struct(&self, cache, pretty_writer, data_type_entry)?; + Ok(()) + } + + fn gen_tagged_union( + &self, + generator: &mut dyn Generator, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + ) -> Result<(), IDLError> { + generator.gen_tagged_union(&self, cache, pretty_writer, data_type_entry)?; + Ok(()) + } + + fn gen_alias( + &self, + generator: &mut dyn Generator, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + ) -> Result<(), IDLError> { + generator.gen_alias(&self, cache, pretty_writer, data_type_entry)?; + Ok(()) + } + + /// Generate accessors for a data type whose identifier is `id` + /// `hierarchy` is used to derive function names from nested types + pub fn gen_accessors_for_id( + &self, + generator: &mut dyn Generator, + cache: &Cache, + pretty_writer: &mut PrettyWriter, + id: DataTypeId, + hierarchy: &Hierarchy, + ) -> Result<(), IDLError> { + let data_type_entry = self.get(id); + match &data_type_entry.data_type { + DataType::Struct { .. } => generator.gen_accessors_struct( + &self, + cache, + pretty_writer, + &data_type_entry, + hierarchy, + ), + DataType::TaggedUnion { .. } => generator.gen_accessors_tagged_union( + &self, + cache, + pretty_writer, + &data_type_entry, + hierarchy, + ), + DataType::Alias { .. } => generator.gen_accessors_alias( + &self, + cache, + pretty_writer, + &data_type_entry, + hierarchy, + ), + DataType::Enum { .. } => generator.gen_accessors_enum( + &self, + cache, + pretty_writer, + &data_type_entry, + hierarchy, + ), + }?; + Ok(()) + } +} diff --git a/lucet-idl/src/errors.rs b/lucet-idl/src/errors.rs new file mode 100644 index 000000000..462f6b386 --- /dev/null +++ b/lucet-idl/src/errors.rs @@ -0,0 +1,35 @@ +use lucet_idl::{parser, validate}; +use std::io; + +#[allow(dead_code)] +#[derive(Debug, Fail)] +pub enum IDLError { + #[fail(display = "Internal error: {}", _0)] + InternalError(&'static str), + #[fail(display = "Incorrect usage: {}", _0)] + UsageError(&'static str), + #[fail(display = "{}", _0)] + ParseError(#[cause] parser::ParseError), + #[fail(display = "{}", _0)] + ValidationError(#[cause] validate::ValidationError), + #[fail(display = "{}", _0)] + Io(#[cause] io::Error), +} + +impl From for IDLError { + fn from(e: io::Error) -> Self { + IDLError::Io(e) + } +} + +impl From for IDLError { + fn from(e: parser::ParseError) -> Self { + IDLError::ParseError(e) + } +} + +impl From for IDLError { + fn from(e: validate::ValidationError) -> Self { + IDLError::ValidationError(e) + } +} diff --git a/lucet-idl/src/generators/generator.rs b/lucet-idl/src/generators/generator.rs new file mode 100644 index 000000000..bd21588fe --- /dev/null +++ b/lucet-idl/src/generators/generator.rs @@ -0,0 +1,108 @@ +use super::super::cache::*; +use super::super::cgenerator::*; +use super::super::config::*; +use super::super::data_description_helper::*; +use super::super::errors::*; +use super::super::pretty_writer::*; +use super::super::rustgenerator::*; +use super::hierarchy::*; +use std::io::prelude::*; + +pub trait Generator { + fn gen_prelude(&mut self, pretty_writer: &mut PrettyWriter) -> Result<(), IDLError>; + + fn gen_type_header( + &mut self, + _data_description_helper: &DataDescriptionHelper, + _cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + ) -> Result<(), IDLError>; + + fn gen_alias( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + ) -> Result<(), IDLError>; + + fn gen_struct( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + ) -> Result<(), IDLError>; + + fn gen_enum( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + ) -> Result<(), IDLError>; + + fn gen_tagged_union( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + ) -> Result<(), IDLError>; + + fn gen_accessors_struct( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + hierarchy: &Hierarchy, + ) -> Result<(), IDLError>; + + fn gen_accessors_tagged_union( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + hierarchy: &Hierarchy, + ) -> Result<(), IDLError>; + + fn gen_accessors_enum( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + hierarchy: &Hierarchy, + ) -> Result<(), IDLError>; + + fn gen_accessors_alias( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + hierarchy: &Hierarchy, + ) -> Result<(), IDLError>; +} + +pub struct Generators; + +impl Generators { + pub fn c(config: &Config) -> CGenerator { + CGenerator { + target: config.target, + backend_config: config.backend_config, + } + } + + #[allow(dead_code)] + pub fn rust(config: &Config) -> RustGenerator { + RustGenerator { + target: config.target, + backend_config: config.backend_config, + } + } +} diff --git a/lucet-idl/src/generators/hierarchy.rs b/lucet-idl/src/generators/hierarchy.rs new file mode 100644 index 000000000..e92b76369 --- /dev/null +++ b/lucet-idl/src/generators/hierarchy.rs @@ -0,0 +1,76 @@ +use std::rc::Rc; + +#[derive(Debug, Clone)] +pub struct HierarchyEntry { + name: Rc, + offset: usize, +} + +impl HierarchyEntry { + pub fn new(name: String, offset: usize) -> Self { + HierarchyEntry { + name: Rc::new(name), + offset, + } + } +} + +#[derive(Debug, Clone)] +pub struct Hierarchy(Vec); + +impl Hierarchy { + pub fn new(name: String, offset: usize) -> Self { + Hierarchy(vec![HierarchyEntry::new(name, offset)]) + } + + pub fn push(&self, name: String, offset: usize) -> Self { + let mut cloned = self.clone(); + cloned.0.push(HierarchyEntry::new(name, offset)); + cloned + } + + pub fn depth(&self) -> usize { + self.0.len() + } + + pub fn idl_name(&self) -> String { + self.0 + .iter() + .map(|x| x.name.as_str()) + .collect::>() + .join(".") + } + + pub fn fn_name(&self) -> String { + self.0 + .iter() + .map(|x| x.name.as_str()) + .collect::>() + .join("_") + } + + #[allow(dead_code)] + pub fn parent_name(&self) -> String { + let len = self.0.len(); + assert!(len > 1); + self.0 + .iter() + .take(len - 1) + .map(|x| x.name.as_str()) + .collect::>() + .join("_") + } + + pub fn root_name(&self) -> String { + self.0 + .iter() + .take(1) + .map(|x| x.name.as_str()) + .collect::>() + .join("_") + } + + pub fn current_offset(&self) -> usize { + self.0.last().expect("Empty hierarchy").offset + } +} diff --git a/lucet-idl/src/generators/mod.rs b/lucet-idl/src/generators/mod.rs new file mode 100644 index 000000000..bfb9345ef --- /dev/null +++ b/lucet-idl/src/generators/mod.rs @@ -0,0 +1,5 @@ +mod generator; +mod hierarchy; + +pub use generator::*; +pub use hierarchy::*; diff --git a/lucet-idl/src/lexer.rs b/lucet-idl/src/lexer.rs index a2f7e9199..53057987b 100644 --- a/lucet-idl/src/lexer.rs +++ b/lucet-idl/src/lexer.rs @@ -35,7 +35,7 @@ pub struct LocatedToken<'a> { pub location: Location, } -fn token(token: Token, location: Location) -> Result { +fn token(token: Token<'_>, location: Location) -> Result, LocatedError> { Ok(LocatedToken { token, location }) } @@ -67,7 +67,7 @@ pub struct Lexer<'a> { } impl<'a> Lexer<'a> { - pub fn new(s: &'a str) -> Lexer { + pub fn new(s: &'a str) -> Lexer<'_> { let mut lex = Lexer { source: s, chars: s.char_indices(), @@ -207,6 +207,7 @@ impl<'a> Lexer<'a> { token(Token::Quote(text), loc) } + #[allow(clippy::should_implement_trait)] pub fn next(&mut self) -> Option, LocatedError>> { loop { let loc = self.loc(); @@ -260,10 +261,10 @@ mod tests { use super::*; fn token( - token: Token, + token: Token<'_>, line: usize, column: usize, - ) -> Option> { + ) -> Option, LocatedError>> { Some(super::token(token, Location { line, column })) } diff --git a/lucet-idl/src/main.rs b/lucet-idl/src/main.rs index e7a11a969..170947390 100644 --- a/lucet-idl/src/main.rs +++ b/lucet-idl/src/main.rs @@ -1,3 +1,51 @@ +#[macro_use] +extern crate failure; + +mod backend; +mod cache; +mod cgenerator; +mod config; +mod data_description_helper; +mod errors; +mod generators; +mod pretty_writer; +mod rustgenerator; +mod target; + +use self::cache::*; +use self::generators::*; + +use self::config::*; +use self::data_description_helper::*; +use self::errors::*; +use self::pretty_writer::*; +use lucet_idl::parser::*; +use lucet_idl::validate::*; +use std::fs::File; +use std::io; +use std::io::prelude::*; + +fn doit() -> Result<(), IDLError> { + let config = Config::parse()?; + let mut source = String::new(); + File::open(&config.input_path)?.read_to_string(&mut source)?; + let mut parser = Parser::new(&source); + let decls = parser.match_decls()?; + let data_description = DataDescription::validate(&decls)?; + let deps = data_description + .ordered_dependencies() + .map_err(|_| IDLError::InternalError("Unable to resolve dependencies"))?; + let data_description_helper = DataDescriptionHelper { data_description }; + let mut cache = Cache::default(); + let mut generator = Generators::c(&config); + let mut pretty_writer = PrettyWriter::new(io::stdout()); + generator.gen_prelude(&mut pretty_writer)?; + for id in deps { + data_description_helper.gen_for_id(&mut generator, &mut cache, &mut pretty_writer, id)?; + } + Ok(()) +} + fn main() { - println!("Hello, world!"); + doit().unwrap(); } diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index 63c04a865..17ff2ae7a 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -96,7 +96,7 @@ pub struct ParseError { } impl fmt::Display for ParseError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "Parse error at line {} column {}: {}", @@ -146,7 +146,7 @@ pub struct Parser<'a> { } impl<'a> Parser<'a> { - pub fn new(text: &'a str) -> Parser { + pub fn new(text: &'a str) -> Parser<'_> { Parser { lex: Lexer::new(text), lookahead: None, diff --git a/lucet-idl/src/pretty_writer.rs b/lucet-idl/src/pretty_writer.rs new file mode 100644 index 000000000..90123332b --- /dev/null +++ b/lucet-idl/src/pretty_writer.rs @@ -0,0 +1,105 @@ +use super::errors::*; +use std::cell::RefCell; +use std::convert::Into; +use std::io::prelude::*; +use std::rc::Rc; + +/// Write indented code +/// #[derive(Clone)] +pub struct PrettyWriter { + writer: Rc>, + indent: u32, + indent_bytes: Vec, +} + +impl PrettyWriter { + /// Create a new `PrettyWriter` with `indent` initial units of indentation + pub fn new_with_indent(writer: W, indent: u32) -> Self { + PrettyWriter { + writer: Rc::new(RefCell::new(writer)), + indent, + indent_bytes: b" ".to_vec(), + } + } + + /// Create a new `PrettyWriter` with no initial indentation + pub fn new(writer: W) -> Self { + PrettyWriter::new_with_indent(writer, 0) + } + + /// Create a writer based on a existing writer, but with no indentation` + pub fn new_from_writer(&mut self) -> Self { + PrettyWriter { + writer: self.writer.clone(), + indent: 0, + indent_bytes: self.indent_bytes.clone(), + } + } + + /// Create an indented block within the current `PrettyWriter` + pub fn new_block(&mut self) -> Self { + PrettyWriter { + writer: self.writer.clone(), + indent: self.indent + 1, + indent_bytes: self.indent_bytes.clone(), + } + } + + fn _write_all(writer: &mut W, buf: &[u8]) -> Result<(), IDLError> { + writer.write_all(buf).map_err(Into::into) + } + + /// Return the current indentation level + #[allow(dead_code)] + pub fn indent_level(&self) -> u32 { + self.indent + } + + /// Output an indentation string + pub fn indent(&mut self) -> Result<&mut Self, IDLError> { + let indent_bytes = &self.indent_bytes.clone(); + { + let mut writer = self.writer.borrow_mut(); + for _ in 0..self.indent { + Self::_write_all(&mut writer, indent_bytes)? + } + } + Ok(self) + } + + /// Output a space + pub fn space(&mut self) -> Result<&mut Self, IDLError> { + Self::_write_all(&mut self.writer.borrow_mut(), b" ")?; + Ok(self) + } + + /// Output an end of line + pub fn eol(&mut self) -> Result<&mut Self, IDLError> { + Self::_write_all(&mut self.writer.borrow_mut(), b"\n")?; + Ok(self) + } + + /// Output a block separator + pub fn eob(&mut self) -> Result<&mut Self, IDLError> { + self.eol() + } + + /// Continuation + pub fn continuation(&mut self) -> Result<&mut Self, IDLError> { + self.indent()?; + let indent_bytes = &self.indent_bytes.clone(); + Self::_write_all(&mut self.writer.borrow_mut(), indent_bytes)?; + Ok(self) + } + + /// Write raw data + pub fn write(&mut self, buf: &[u8]) -> Result<&mut Self, IDLError> { + Self::_write_all(&mut self.writer.borrow_mut(), buf)?; + Ok(self) + } + + /// Indent, write raw data and terminate with an end of line + pub fn write_line(&mut self, buf: &[u8]) -> Result<&mut Self, IDLError> { + self.indent()?.write(buf)?.eol() + } +} diff --git a/lucet-idl/src/rustgenerator/mod.rs b/lucet-idl/src/rustgenerator/mod.rs new file mode 100644 index 000000000..9972b9d19 --- /dev/null +++ b/lucet-idl/src/rustgenerator/mod.rs @@ -0,0 +1,136 @@ +#![allow(dead_code)] +#![allow(unused_variables)] + +use super::backend::*; +use super::cache::*; +use super::data_description_helper::*; +use super::errors::*; +use super::generators::*; +use super::pretty_writer::*; +use super::target::*; +use lucet_idl::validate::*; +use std::io::prelude::*; + +#[derive(Clone, Debug)] +struct CTypeInfo<'t> { + /// The native type name + type_name: String, + /// Alignment rules for that type + type_align: usize, + /// The native type size + type_size: usize, + /// How many pointer indirections are required to get to the atomic type + indirections: usize, + /// The leaf type node + leaf_data_type_ref: &'t DataTypeRef, +} + +/// Generator for the C backend +pub struct RustGenerator { + pub target: Target, + pub backend_config: BackendConfig, +} + +impl Generator for RustGenerator { + fn gen_prelude(&mut self, pretty_writer: &mut PrettyWriter) -> Result<(), IDLError> { + unimplemented!() + } + + fn gen_type_header( + &mut self, + _data_description_helper: &DataDescriptionHelper, + _cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + ) -> Result<(), IDLError> { + unimplemented!() + } + + // The most important thing in alias generation is to cache the size + // and alignment rules of what it ultimately points to + fn gen_alias( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + ) -> Result<(), IDLError> { + unimplemented!() + } + + fn gen_struct( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + ) -> Result<(), IDLError> { + unimplemented!() + } + + // Enums generate both a specific typedef, and a traditional C-style enum + // The typedef is required to use a native type which is consistent across all architectures + fn gen_enum( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + ) -> Result<(), IDLError> { + unimplemented!() + } + + fn gen_tagged_union( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + ) -> Result<(), IDLError> { + unimplemented!() + } + + fn gen_accessors_struct( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + hierarchy: &Hierarchy, + ) -> Result<(), IDLError> { + unimplemented!() + } + + fn gen_accessors_tagged_union( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + hierarchy: &Hierarchy, + ) -> Result<(), IDLError> { + unimplemented!() + } + + fn gen_accessors_enum( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + hierarchy: &Hierarchy, + ) -> Result<(), IDLError> { + unimplemented!() + } + + fn gen_accessors_alias( + &mut self, + data_description_helper: &DataDescriptionHelper, + cache: &Cache, + pretty_writer: &mut PrettyWriter, + data_type_entry: &DataTypeEntry<'_>, + hierarchy: &Hierarchy, + ) -> Result<(), IDLError> { + unimplemented!() + } +} diff --git a/lucet-idl/src/target.rs b/lucet-idl/src/target.rs new file mode 100644 index 000000000..8a020079c --- /dev/null +++ b/lucet-idl/src/target.rs @@ -0,0 +1,67 @@ +use lucet_idl::types::*; + +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub enum Target { + X86, + X86_64_64, + X86_64_32, + Generic, +} + +impl Default for Target { + fn default() -> Self { + Target::Generic + } +} + +impl> From for Target { + fn from(s: T) -> Self { + match s.as_ref() { + "x86" => Target::X86, + "x86_64_64" | "x86_64" => Target::X86_64_64, + "x86_64_32" => Target::X86_64_32, + "generic" => Target::Generic, + _ => Target::default(), + } + } +} + +#[allow(dead_code)] +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub enum Endianness { + BigEndian, + LittleEndian, + Generic, +} + +impl Target { + pub fn reference_target() -> Target { + Target::X86_64_64 + } + + pub fn endianness(self) -> Endianness { + match self { + Target::Generic => Endianness::Generic, + _ => Endianness::LittleEndian, + } + } + + pub fn is_reference_target(self) -> bool { + self == Self::reference_target() + } + + pub fn is_reference_alignment_compatible(self) -> bool { + self != Target::Generic + } + + pub fn uses_reference_target_endianness(self) -> bool { + self.endianness() == Self::reference_target().endianness() + } + + pub fn uses_reference_target_endianness_for_atom_type(self, atom_type: AtomType) -> bool { + match atom_type { + AtomType::U8 | AtomType::I8 => true, + _ => self.uses_reference_target_endianness(), + } + } +} diff --git a/lucet-idl/src/validate.rs b/lucet-idl/src/validate.rs index 185cd84f6..3947175fd 100644 --- a/lucet-idl/src/validate.rs +++ b/lucet-idl/src/validate.rs @@ -4,20 +4,20 @@ use std::collections::HashMap; use std::error::Error; use std::fmt; -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub struct DatatypeId(pub usize); +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] +pub struct DataTypeId(pub usize); -impl fmt::Display for DatatypeId { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Display for DataTypeId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) } } #[derive(Debug, PartialEq, Eq, Clone)] -pub enum DatatypeRef { - Defined(DatatypeId), +pub enum DataTypeRef { + Defined(DataTypeId), Atom(AtomType), - Ptr(Box), + Ptr(Box), } #[derive(Debug, PartialEq, Eq, Clone)] @@ -28,13 +28,13 @@ pub struct NamedMember { } #[derive(Debug, PartialEq, Eq, Clone)] -pub enum Datatype { +pub enum DataType { Struct { - members: Vec>, + members: Vec>, attrs: Vec, }, TaggedUnion { - members: Vec>>, + members: Vec>>, attrs: Vec, }, Enum { @@ -42,7 +42,7 @@ pub enum Datatype { attrs: Vec, }, Alias { - to: DatatypeRef, + to: DataTypeRef, attrs: Vec, }, } @@ -53,10 +53,16 @@ pub struct Name { pub location: Location, } +impl fmt::Display for Name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.name) + } +} + #[derive(Debug, PartialEq, Eq, Clone)] pub struct DataDescription { pub names: Vec, - pub datatypes: HashMap, + pub data_types: HashMap, } #[derive(Debug, PartialEq, Eq, Clone)] @@ -81,7 +87,7 @@ pub enum ValidationError { } impl fmt::Display for ValidationError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ValidationError::NameAlreadyExists { name, @@ -117,7 +123,7 @@ impl DataDescription { fn new() -> Self { Self { names: Vec::new(), - datatypes: HashMap::new(), + data_types: HashMap::new(), } } @@ -125,7 +131,7 @@ impl DataDescription { &mut self, name: &str, location: &Location, - ) -> Result { + ) -> Result { if let Some(existing) = self.id_for_name(&name) { let prev = self .names @@ -142,25 +148,25 @@ impl DataDescription { name: name.to_owned(), location: *location, }); - Ok(DatatypeId(id)) + Ok(DataTypeId(id)) } } - fn id_for_name(&self, name: &str) -> Option { + fn id_for_name(&self, name: &str) -> Option { for (id, n) in self.names.iter().enumerate() { if n.name == name { - return Some(DatatypeId(id)); + return Some(DataTypeId(id)); } } None } - fn get_ref(&self, syntax_ref: &SyntaxRef) -> Result { + fn get_ref(&self, syntax_ref: &SyntaxRef) -> Result { match syntax_ref { - SyntaxRef::Atom { atom, .. } => Ok(DatatypeRef::Atom(*atom)), - SyntaxRef::Ptr { to, .. } => Ok(DatatypeRef::Ptr(Box::new(self.get_ref(&to)?))), + SyntaxRef::Atom { atom, .. } => Ok(DataTypeRef::Atom(*atom)), + SyntaxRef::Ptr { to, .. } => Ok(DataTypeRef::Ptr(Box::new(self.get_ref(&to)?))), SyntaxRef::Name { name, location } => match self.id_for_name(name) { - Some(id) => Ok(DatatypeRef::Defined(id)), + Some(id) => Ok(DataTypeRef::Defined(id)), None => Err(ValidationError::NameNotFound { name: name.clone(), use_location: *location, @@ -169,13 +175,13 @@ impl DataDescription { } } - fn define_datatype(&mut self, id: DatatypeId, dt: Datatype) { - if let Some(prev_def) = self.datatypes.insert(id.0, dt) { + fn define_data_type(&mut self, id: DataTypeId, dt: DataType) { + if let Some(prev_def) = self.data_types.insert(id.0, dt) { panic!("id {} already defined: {:?}", id, prev_def) } } - fn define_decl(&mut self, id: DatatypeId, decl: &SyntaxDecl) -> Result<(), ValidationError> { + fn define_decl(&mut self, id: DataTypeId, decl: &SyntaxDecl) -> Result<(), ValidationError> { match decl { SyntaxDecl::Struct { name, @@ -200,7 +206,7 @@ impl DataDescription { previous_location: existing.location, })? } - // Get the DatatypeRef for the member, which ensures that it refers only to + // Get the DataTypeRef for the member, which ensures that it refers only to // defined types: let type_ = self.get_ref(&mem.type_)?; // build the struct with this as the member: @@ -210,9 +216,9 @@ impl DataDescription { attrs: mem.attrs.clone(), }) } - self.define_datatype( + self.define_data_type( id, - Datatype::Struct { + DataType::Struct { members: dtype_members, attrs: attrs.clone(), }, @@ -241,7 +247,7 @@ impl DataDescription { previous_location: existing.location, })? } - // Get the DatatypeRef for the member, which ensures that it refers only to + // Get the DataTypeRef for the member, which ensures that it refers only to // defined types: let type_ = if let Some(ref t) = var.type_ { Some(self.get_ref(t)?) @@ -255,9 +261,9 @@ impl DataDescription { attrs: var.attrs.clone(), }) } - self.define_datatype( + self.define_data_type( id, - Datatype::TaggedUnion { + DataType::TaggedUnion { members: dtype_members, attrs: attrs.clone(), }, @@ -293,9 +299,9 @@ impl DataDescription { attrs: var.attrs.clone(), }) } - self.define_datatype( + self.define_data_type( id, - Datatype::Enum { + DataType::Enum { members: dtype_members, attrs: attrs.clone(), }, @@ -303,9 +309,9 @@ impl DataDescription { } SyntaxDecl::Alias { what, attrs, .. } => { let to = self.get_ref(what)?; - self.define_datatype( + self.define_data_type( id, - Datatype::Alias { + DataType::Alias { to, attrs: attrs.clone(), }, @@ -317,35 +323,35 @@ impl DataDescription { fn dfs_walk( &self, - id: DatatypeId, + id: DataTypeId, visited: &mut [bool], - ordered: &mut Option<&mut Vec>, + ordered: &mut Option<&mut Vec>, ) -> Result<(), ()> { if visited[id.0] { Err(())? } visited[id.0] = true; - match self.datatypes.get(&id.0).expect("datatype is defined") { - Datatype::Struct { members, .. } => { + match self.data_types.get(&id.0).expect("data_type is defined") { + DataType::Struct { members, .. } => { for mem in members { - if let DatatypeRef::Defined(id) = mem.type_ { + if let DataTypeRef::Defined(id) = mem.type_ { self.dfs_walk(id, visited, ordered)? } } } - Datatype::TaggedUnion { members, .. } => { + DataType::TaggedUnion { members, .. } => { for mem in members { - if let Some(DatatypeRef::Defined(id)) = mem.type_ { + if let Some(DataTypeRef::Defined(id)) = mem.type_ { self.dfs_walk(id, visited, ordered)? } } } - Datatype::Alias { to, .. } => { - if let DatatypeRef::Defined(id) = to { + DataType::Alias { to, .. } => { + if let DataTypeRef::Defined(id) = to { self.dfs_walk(*id, visited, ordered)? } } - Datatype::Enum { .. } => {} + DataType::Enum { .. } => {} } if let Some(ordered) = ordered.as_mut() { if !ordered.contains(&id) { @@ -356,23 +362,23 @@ impl DataDescription { Ok(()) } - pub fn ordered_dependencies(&self) -> Result, ()> { + pub fn ordered_dependencies(&self) -> Result, ()> { let mut visited = Vec::new(); visited.resize(self.names.len(), false); let mut ordered = Vec::with_capacity(visited.capacity()); - for id in self.datatypes.keys() { - let _ = self.dfs_walk(DatatypeId(*id), &mut visited, &mut Some(&mut ordered)); + for id in self.data_types.keys() { + let _ = self.dfs_walk(DataTypeId(*id), &mut visited, &mut Some(&mut ordered)); } Ok(ordered) } - fn dfs_find_cycle(&self, id: DatatypeId) -> Result<(), ()> { + fn dfs_find_cycle(&self, id: DataTypeId) -> Result<(), ()> { let mut visited = Vec::new(); visited.resize(self.names.len(), false); self.dfs_walk(id, &mut visited, &mut None) } - fn ensure_finite(&self, id: DatatypeId, decl: &SyntaxDecl) -> Result<(), ValidationError> { + fn ensure_finite(&self, id: DataTypeId, decl: &SyntaxDecl) -> Result<(), ValidationError> { self.dfs_find_cycle(id) .map_err(|_| ValidationError::Infinite { name: decl.name().to_owned(), @@ -382,7 +388,7 @@ impl DataDescription { pub fn validate(decls: &[SyntaxDecl]) -> Result { let mut desc = Self::new(); - let mut idents: Vec = Vec::new(); + let mut idents: Vec = Vec::new(); for decl in decls { idents.push(desc.introduce_name(decl.name(), decl.location())?) } @@ -417,18 +423,18 @@ mod tests { { let d = data_description("struct foo { a: i32, b: f32 }").unwrap(); - let members = match &d.datatypes[&0] { - Datatype::Struct { members, .. } => members, + let members = match &d.data_types[&0] { + DataType::Struct { members, .. } => members, _ => panic!("Unexpected type"), }; assert_eq!(members[0].name, "a"); assert_eq!(members[1].name, "b"); match &members[0].type_ { - DatatypeRef::Atom(AtomType::I32) => (), + DataTypeRef::Atom(AtomType::I32) => (), _ => panic!("Unexpected type"), }; match &members[1].type_ { - DatatypeRef::Atom(AtomType::F32) => (), + DataTypeRef::Atom(AtomType::F32) => (), _ => panic!("Unexpected type"), }; } @@ -493,14 +499,14 @@ mod tests { { let d = data_description("taggedunion foo { a: i32, b: () }").unwrap(); - let members = match &d.datatypes[&0] { - Datatype::TaggedUnion { members, .. } => members, + let members = match &d.data_types[&0] { + DataType::TaggedUnion { members, .. } => members, _ => panic!("Unexpected type"), }; assert_eq!(members[0].name, "a"); assert_eq!(members[1].name, "b"); match &members[0].type_ { - Some(DatatypeRef::Atom(AtomType::I32)) => (), + Some(DataTypeRef::Atom(AtomType::I32)) => (), _ => panic!("Unexpected type"), }; match &members[1].type_ { @@ -575,8 +581,8 @@ mod tests { { let d = data_description("enum foo { a, b }").unwrap(); - let members = match &d.datatypes[&0] { - Datatype::Enum { members, .. } => members, + let members = match &d.data_types[&0] { + DataType::Enum { members, .. } => members, _ => panic!("Unexpected type"), }; assert_eq!(members[0].name, "a"); From 86796300d9aa50fe84dba18683d82db69451b6aa Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 22 Apr 2019 15:08:27 -0700 Subject: [PATCH 066/512] update Cargo.lock --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 6db99b7c6..dfbc46233 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -695,7 +695,7 @@ dependencies = [ "progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", From ca727efc7e2908577427b464943939b1b9e5d81f Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 23 Apr 2019 11:59:37 -0700 Subject: [PATCH 067/512] lucet-wasi: fix c_api header to compile with strict prototypes --- lucet-wasi/include/lucet_wasi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lucet-wasi/include/lucet_wasi.h b/lucet-wasi/include/lucet_wasi.h index 577b21a2d..92d4d05d8 100644 --- a/lucet-wasi/include/lucet_wasi.h +++ b/lucet-wasi/include/lucet_wasi.h @@ -5,7 +5,7 @@ struct lucet_wasi_ctx; -struct lucet_wasi_ctx *lucet_wasi_ctx_create(); +struct lucet_wasi_ctx *lucet_wasi_ctx_create(void); enum lucet_error lucet_wasi_ctx_args(struct lucet_wasi_ctx *wasi_ctx, size_t argc, char **argv); From 62d3d74864c08e8c6a70a11c486949f12e060215 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 23 Apr 2019 13:41:10 -0700 Subject: [PATCH 068/512] lucet-wasi tests: temporary fix for getrusage prototype which is unavailable in wasi-sdk 4.0 due to a bug, which is fixed upstream --- lucet-wasi/tests/guests/getrusage.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lucet-wasi/tests/guests/getrusage.c b/lucet-wasi/tests/guests/getrusage.c index 84e2bb7ce..7ff12fe12 100644 --- a/lucet-wasi/tests/guests/getrusage.c +++ b/lucet-wasi/tests/guests/getrusage.c @@ -1,6 +1,11 @@ #include #include +// Temporary fix until +// https://github.com/CraneStation/wasi-sysroot/pull/24/ +// is available in wasi-sdk package +extern int getrusage(int who, struct rusage *usage); + int main() { struct rusage ru1; From a084eff00d1cb8c29ed1f3b0583b161d206f273f Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 23 Apr 2019 13:58:50 -0700 Subject: [PATCH 069/512] dockerfile: upgrade to wasi-sdk 4.0 --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 05c20b9bc..9df79430e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -36,7 +36,7 @@ RUN curl -sS -L -O https://static.rust-lang.org/dist/rust-1.33.0-x86_64-unknown- ENV PATH=/usr/local/bin:$PATH RUN cargo install --root /usr/local cargo-audit cargo-watch -RUN curl -sS -L -O https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-3/wasi-sdk_3.0_amd64.deb \ - && dpkg -i wasi-sdk_3.0_amd64.deb && rm -f wasi-sdk_3.0_amd64.deb +RUN curl -sS -L -O https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-4/wasi-sdk_4.0_amd64.deb \ + && dpkg -i wasi-sdk_4.0_amd64.deb && rm -f wasi-sdk_4.0_amd64.deb ENV WASI_SDK=/opt/wasi-sdk From dfef46dff35e4ee56a5671e272718ea77d79a1c0 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 24 Apr 2019 00:34:00 +0200 Subject: [PATCH 070/512] Short reads from readv(2) don't mean EOF fd_read() should not close the descriptor after a short read. EOF is only reached when readv(2) returns 0. Fixes #128 --- lucet-wasi/src/hostcalls.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lucet-wasi/src/hostcalls.rs b/lucet-wasi/src/hostcalls.rs index fab47b37c..9d88ba458 100644 --- a/lucet-wasi/src/hostcalls.rs +++ b/lucet-wasi/src/hostcalls.rs @@ -499,14 +499,12 @@ pub extern "C" fn __wasi_fd_read( .map(|iov| unsafe { host::ciovec_to_nix_mut(iov) }) .collect(); - let full_nread = iovs.iter().map(|iov| iov.as_slice().len()).sum(); - let host_nread = match readv(fe.fd_object.rawfd, &mut iovs) { Ok(len) => len, Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), }; - if host_nread < full_nread { + if host_nread == 0 { // we hit eof, so remove the fdentry from the context let mut fe = ctx.fds.remove(&fd).expect("file entry is still there"); fe.fd_object.needs_close = false; From d03aaad7b198ab4e4eff442e213871801df5c36f Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 24 Apr 2019 09:42:37 -0700 Subject: [PATCH 071/512] Merge pch/return_to_clifwasm into master, closing #44 Squashed commit of the following: commit 8d80e780f46428e1d39549ab7f4fc40f65349406 Author: Pat Hickey Date: Tue Apr 23 17:58:37 2019 -0700 rustfmt commit 6b0c8f503277fa98e719e243eaf03ceb0a5d3acf Author: Pat Hickey Date: Tue Apr 23 17:11:07 2019 -0700 lucetc: comments in sparsedata commit ef5234dbb253286492ebbe3718258233400daf18 Author: Pat Hickey Date: Tue Apr 23 17:06:54 2019 -0700 lucetc: s/POINTER_SIZE/NATIVE_POINTER_SIZE/g and also add a helpful assertions in translate_memory_ funcs commit c96c70818960665545e4af8fc9598a0ea6dc95c3 Author: Pat Hickey Date: Tue Apr 23 17:06:34 2019 -0700 lucetc: doc comment commit cf308727ea505ae1de630f472cd8eb4b5b03402c Merge: 49b6f44 8f0b1ce Author: Pat Hickey Date: Tue Apr 23 15:28:08 2019 -0700 Merge remote-tracking branch 'origin/master' into pch/return_to_clifwasm commit 49b6f44492758adef441512b0366619f1bc81d1e Author: Pat Hickey Date: Mon Apr 22 17:22:17 2019 -0700 c_api: fixup commit 9d6aec10a8fd2ccacee339802c9a022abf55a303 Author: Pat Hickey Date: Mon Apr 22 17:09:54 2019 -0700 lucetc: table putelem is a fn not a closure commit 054e516b817b34932d9992ae7004985e9f80079b Author: Pat Hickey Date: Mon Apr 22 17:06:28 2019 -0700 lucetc: clean up sparsedata creation commit 264f801a1c2cda496d0368f1b1de09a565e0e853 Author: Pat Hickey Date: Mon Apr 22 16:59:00 2019 -0700 lucet-runtime: move signal-safe fault detail determination into signal handler commit e8d4d568cd41173f1bb6885c474a246c28c38e7c Author: Pat Hickey Date: Mon Apr 22 16:49:21 2019 -0700 makefile: convenience target to watch and run interesting tests if you just run `cargo watch --exec test` itll run spectest which will fail, a known issue commit a00b706537032578d730cf21ef34a9c2cc316478 Author: Pat Hickey Date: Mon Apr 22 16:33:44 2019 -0700 lucet-runtime: distinct error for when no linear memory exists commit 6276741044e30587122bf347e17be4abc2cb325c Author: Pat Hickey Date: Mon Apr 22 16:25:23 2019 -0700 pin goblin to 0.0.21 commit 15cef4042ee5ea34e0e4610e888d6a45dffd48fe Merge: eb29ad7 899b191 Author: Pat Hickey Date: Mon Apr 22 14:47:35 2019 -0700 Merge branch 'master' into pch/return_to_clifwasm commit eb29ad74b2cad4b2bd9d73dd73b6cc015a6ccddb Author: Pat Hickey Date: Fri Apr 19 14:34:27 2019 -0700 gitignore core.* commit 74161bfba981d337b1a64702ed7bbf4f3dd83832 Author: Pat Hickey Date: Fri Apr 19 13:44:01 2019 -0700 dlmodule: delete unused elem_size commit 077686c6c73f53873c0389514b92c380d83f604a Author: Pat Hickey Date: Fri Apr 19 13:41:50 2019 -0700 lucet-runtime: fail bail in expand heap if no heap exists commit 80ce206cdbd11e216ae489ab6f12dea32f6a0f5f Author: Pat Hickey Date: Fri Apr 19 13:40:36 2019 -0700 lucet-runtime: delete README.rst from package assets commit a894bfdef67d6a4f2d0f47cc1a18636324269770 Author: Pat Hickey Date: Tue Apr 16 15:19:19 2019 -0700 lucet-runtime: representation of table len changed to elements change required by cranelift-wasm commit 8776cae286359d5e8c2d56515a11cdb93427868d Author: Pat Hickey Date: Tue Apr 16 15:19:00 2019 -0700 lucetc: expose table symbols required by ModuleInternal::table_elements() commit 10c66a73f8f2e5900bdecd6155e1b7233f6113d8 Author: Pat Hickey Date: Tue Apr 16 14:49:23 2019 -0700 lucetc: fix rebase onto new options model commit eb3b9bf3203946c142d64db50a511f9abc6729b4 Author: Pat Hickey Date: Tue Apr 16 12:36:16 2019 -0700 fixup commit e77413647509a8c4471e8c9a9d04be5f1498d080 Author: Adam Foltzer Date: Tue Apr 16 12:11:26 2019 -0700 lucet-runtime-tests: disable building a test executable it only provides macros used elsewhere commit 8893945ad7447712f3964cf7aa5c38cc63b3194e Author: Pat Hickey Date: Tue Apr 16 11:39:27 2019 -0700 lucetc: wasi-sdk test fixes commit c115a2c63c900c691a485d4af43c2e5cf1b01029 Author: Pat Hickey Date: Tue Apr 16 11:39:09 2019 -0700 lucet-runtime: test fixes commit 66b698c00aed72372cb698b205cd6b05565955d4 Author: Pat Hickey Date: Tue Apr 16 10:50:29 2019 -0700 rustfmt commit eace7ff3a1c36241ddcdd53b63229b9a566b19ca Author: Pat Hickey Date: Thu Apr 11 18:10:06 2019 -0700 lucetc: undeclared table 0 is accepted, begrudgingly the spec tests say we must commit 651bdd1c857c29e75edf9a80765b2f5a531f8cdf Author: Pat Hickey Date: Thu Apr 11 17:50:33 2019 -0700 lucet-spectest: delete unnecessary instance wrapper, don't reset after err commit db4078b9ad4a0fd2a3fa0ff0686e65e6dbb54024 Author: Pat Hickey Date: Thu Apr 11 17:49:51 2019 -0700 lucet-runtime: permit running instance that had non-fatal fault there's no reason not to do this, and the spec tests actually require it commit 6d6b78a04a7a9e335a723e37babd56f78a1b6e05 Author: Pat Hickey Date: Thu Apr 11 17:31:44 2019 -0700 fixup bf0a2ca commit 0bbfd6ab8818bf5d76c830bc4320a12401d49151 Author: Pat Hickey Date: Thu Apr 11 17:02:13 2019 -0700 lucetc/runtime - refactor trap codes we had a fatal error in one of the spec tests because i made a big mess of the trap codes. this hopefully corrects the error: * the unreachable instruction was getting encoded as an "unknown" trapcode. this was because all of the code having to do with the representation of trapcodes was a hot mess, which is on me. * we get rid of trapcodes being a pair (struct) of code and the other 16 bits that were in the "user" code. now we reject all user codes. we have no use for them. * if a trapcode is unknown, in rust its a None. in the C API we still have a variant for unknown commit 04153b908dd8944041949ed3bde653775900d020 Author: Pat Hickey Date: Thu Apr 11 16:57:22 2019 -0700 lucet-analyze: support printing out the trap table commit 0baff6a9ab28cd339513c2a919ce55ff7c8f6d3e Author: Pat Hickey Date: Thu Apr 11 16:55:29 2019 -0700 lucet-spectest: add some comments, disable names test because too noisy commit 4049eb3bbc5134d73d0b428fea291d05676da0dc Author: Pat Hickey Date: Thu Apr 11 16:55:09 2019 -0700 lucet-spectest: print the command running so that if they segfault we have a clue commit 1ebfc65c50c8444c00ef4047414d74ad97ead9fa Author: Pat Hickey Date: Thu Apr 11 15:01:35 2019 -0700 lucetc: bound check table correctly by loading bound from symbol commit ab1ff7c35a99912310f37ca4f8d2fe79a5edd344 Author: Pat Hickey Date: Thu Apr 11 14:45:18 2019 -0700 lucet-runtime: check multiplication for overflow the memory_trap.wast spectest caught this commit 8f564df16f73cde65d945ecee8e6364a12cb395a Author: Adam Foltzer Date: Thu Apr 11 14:17:26 2019 -0700 lucet-runtime: add a test to cover missed case previous commit fixes a bug where alloc reset fails if the heap never grew. this tests that case commit ba1ac0be5973f416dbc28e3ac5b5140e68383c74 Author: Pat Hickey Date: Thu Apr 11 14:13:22 2019 -0700 lucet-runtime: correct implementation of heap reset the lucet-spectest address.wast test triggered this bug by calling reset on an instance that did not grow the heap. all of the runtime tests that tested reset behavior previously grew the heap, so that the mprotect was always triggered. commit 8ed45b4ce8efba67abe9c64c8f479fede4684515 Author: Pat Hickey Date: Wed Apr 10 16:02:31 2019 -0700 lucet-spectest: catch unsupported cases of unexpected failures wtf was i doing when i wrote this the first time around. this code is horrific commit cb36f454915cddb45d1b90606f686538e230909b Author: Pat Hickey Date: Wed Apr 10 15:34:00 2019 -0700 lucetc: simplify error kinds theres no need for strings in them, we already have strings in the error messages themselves commit 5353e41d90a182987c0eba269845f5ed36d3a14e Author: Pat Hickey Date: Wed Apr 10 14:57:46 2019 -0700 lucet-spectest: port to new lucetc commit 346506fd9c74248fb5c78c751d2cce23c82d479a Author: Pat Hickey Date: Wed Apr 10 14:26:19 2019 -0700 lucetc: add check to sparsedata construction to ensure in initial heap commit 969c542fd728cb0bb70597b0ad17778632273add Author: Pat Hickey Date: Wed Apr 10 13:22:35 2019 -0700 delete pwasm-validation submodule commit b54127b2512601252506eaca3a476711a6632d5c Author: Pat Hickey Date: Wed Apr 10 13:19:54 2019 -0700 lucetc: use wasmparser to validate before cranelift-wasm parses and delete dependency on pwasm-validation commit b211fd34237513ccad07bf3dc0c5c4c14fda9856 Author: Pat Hickey Date: Wed Apr 10 11:43:37 2019 -0700 lucetc: map cranelift-wasm translation errors to the correct error kinds commit fda3d9e74f5695039feb8baa9e0d2eed389e60bc Author: Pat Hickey Date: Wed Apr 10 11:30:53 2019 -0700 lucetc: uncomment remaining wasm module_data tests commit 363748f9ff6e81e52e9e96916b13699d1e835c58 Author: Pat Hickey Date: Wed Apr 10 11:27:34 2019 -0700 lucetc: fix up globals wasm tests commit cecb4f82ab1a9040afa3d82c05fff6c269049feb Author: Pat Hickey Date: Wed Apr 10 10:55:57 2019 -0700 lucetc: fix heap & table indexing, distinguish func error types commit 9361d1f2b0aed249021a87b5ba5fa1ff3b99e5b7 Author: Pat Hickey Date: Tue Apr 9 17:20:39 2019 -0700 lucetc: test suites compile again commit 6a41de61f6aa2e32be352c58d1fc63879f1ea1a6 Author: Pat Hickey Date: Tue Apr 9 17:20:36 2019 -0700 fixup commit 8f5df1317513049c033d52e144d80a931662ba64 Author: Pat Hickey Date: Thu Apr 4 14:58:49 2019 -0700 lucetc: port wasi-sdk tests to new interface they fail at codegen :( commit 3db73b40d38fad12e1fb3e39a6024d67498f1b92 Author: Pat Hickey Date: Thu Apr 4 14:27:35 2019 -0700 lucetc: switch to linear memory spec, as part of the decls commit b8e2f256e2e3f2576b0ba8dc4e618d10aae57a70 Author: Pat Hickey Date: Thu Apr 4 14:27:25 2019 -0700 lucet-module-data: forgot an export commit 23f27a118a82966b7e3a531a635caa797e68d0c4 Author: Pat Hickey Date: Thu Apr 4 11:39:35 2019 -0700 lucet-runtime: switch to LinearMemorySpec commit 30a6457f1abab26b5a54fa49c5d1a8ce1fd1a40d Author: Pat Hickey Date: Wed Apr 3 15:45:45 2019 -0700 lucet-module-data: linear memory spec is optional if no memory is declared for the module, there should be neither a heap spec nor a way to initialize memory, otherwise there should be both. commit 0b4b8368ccd2726de10f208a2b30d22cb2abcf62 Author: Pat Hickey Date: Mon Apr 1 16:27:04 2019 -0700 lucetc: get rid of implicit Error -> LucetcError promotion commit b0f84cbb6b478792824a9fab0371c5716f701aaa Author: Pat Hickey Date: Mon Apr 1 16:19:48 2019 -0700 lucetc: table errors dont need additional context commit 8ca748af863d27c7da5e575c6768074db8ea48a0 Author: Pat Hickey Date: Mon Apr 1 16:18:40 2019 -0700 lucetc: replace "Other" error kind with real info commit f283d5cbd2e01e8b1c2ac3b385bbf8fa7734d345 Author: Pat Hickey Date: Mon Apr 1 16:02:15 2019 -0700 lucetc: backport reserved size fixes commit 73039753e0a4308239ae8351a3e2484ed95f15ce Author: Pat Hickey Date: Mon Apr 1 15:38:22 2019 -0700 lucetc: move new stuff to root. rustfmt. commit 103e70a77d15cd4d6ccff0e9c32ff3d94a3bc7d4 Author: Pat Hickey Date: Mon Apr 1 15:34:06 2019 -0700 lucetc: clean out the old junk commit 90f6a703970f7f555141ee68a92290e333e5b278 Author: Pat Hickey Date: Mon Apr 1 15:29:45 2019 -0700 lucetc: move remaining compiler and program definitions into new commit 67219e738aaf2305fe0de4a9afe7e3cb8a3245bd Author: Pat Hickey Date: Mon Apr 1 15:19:17 2019 -0700 move stack probe to new structure commit 87e9893c979331ed3e5428d2f6dd715bb6b627d7 Author: Pat Hickey Date: Mon Apr 1 15:16:02 2019 -0700 lucetc: move pointer consts to their own place commit 57da276ca8a4709b3d239a4ce95af02ff16cc45e Author: Pat Hickey Date: Mon Apr 1 11:39:42 2019 -0700 lucetc: output moved to new:: commit 9899f424fd0485b7a436b4eb24ff805c76c03098 Author: Pat Hickey Date: Thu Mar 28 16:51:05 2019 -0700 lucetc: move compiler to own module commit 34207240df852d92740b95ae2dd45f58618f5d41 Author: Pat Hickey Date: Wed Mar 27 14:40:52 2019 -0700 lucetc: fix declaration of table to get element pointer size right commit 699a37e3c5aa77dbc448a55e73401c33b70735d5 Author: Pat Hickey Date: Wed Mar 27 12:46:53 2019 -0700 lucetc: empty heap spec and data init if no memory defined commit 26f15a7851fd6cd0c9c79f4b2623cc6868d20c37 Author: Pat Hickey Date: Wed Mar 27 12:36:02 2019 -0700 lucetc: emit start func commit acb21819518a5247801b73dabf32ed6f7a0071dc Author: Pat Hickey Date: Wed Mar 27 12:20:03 2019 -0700 lucetc: various serious bugfixes * werent setting func names or signatures before creating them! wow * don't create table if none declared * fix conventions for Name methods commit 498cd10829228ced125b243a4925e96da6a6b789 Author: Pat Hickey Date: Tue Mar 26 17:10:36 2019 -0700 rustfmt commit 6baeaebd048608fd689495083e412d365315c64e Author: Pat Hickey Date: Tue Mar 26 17:10:08 2019 -0700 lucetc: add vmctx to signatures and direct calls commit 337152e33066836c8ed991c4fa40678bc8e36c00 Author: Pat Hickey Date: Tue Mar 26 16:35:37 2019 -0700 lucetc: finish output of module data and tables commit 8c0531f0f9b8e3b60cd1600686c4b397d83681d9 Author: Pat Hickey Date: Mon Mar 25 18:05:31 2019 -0700 lucetc: port sparse data to clifwasm commit 39eacc94cc5a129bd6a881b6d2f4696c57e2a926 Author: Pat Hickey Date: Mon Mar 25 16:45:04 2019 -0700 lucetc: thread through memory specs, implement icalls commit 24a99e53b151c81ab550cc58197eb07f6959d49b Author: Pat Hickey Date: Fri Mar 22 18:37:57 2019 -0700 lucetc: implement more of cranelift_wasm FuncEnvironment commit 3ffd64817319296ed2a54982729a596c14afa1a8 Author: Pat Hickey Date: Thu Mar 21 17:52:49 2019 -0700 lucetc: new style for tracking runtime functions commit 6d126b84102d582e5d45de096c37b153bed6a2a5 Author: Pat Hickey Date: Thu Mar 21 14:44:27 2019 -0700 lucetc: declarations in clifmodule for funcs, table data commit 5514f8ba6ff5955d86cd567baded0f95e2f7d0c5 Author: Pat Hickey Date: Wed Mar 20 14:38:25 2019 -0700 lucetc: make a place for ModuleInfo to turn into ClifModule declarations commit 85ca9bbb1e4062c709937e53b8b82e29bb8a791e Author: Pat Hickey Date: Tue Mar 19 12:20:53 2019 -0700 lucetc: eliminate tests that execute code in mock vm the lucet-runtime-tests provide good coverage of all of these concerns commit 9e5fd82dd9cc8ef1833c469d15f4165e9e6107bf Author: Pat Hickey Date: Mon Mar 18 19:17:22 2019 -0700 rustfmt commit 2af6f37c39e0c1c4b1999708fb77f00ed9b6eb5d Author: Pat Hickey Date: Mon Mar 18 17:49:25 2019 -0700 lucetc: scaffold out FuncEnvironment and compiler loop commit f2a1274c554f76925df565cf116e7b5901f79444 Author: Pat Hickey Date: Mon Mar 18 16:21:22 2019 -0700 lucetc: implement ModuleEnvironment commit 8f7356f5018d3e6a3e8f8ce835ca94e33c99fdf5 Author: Pat Hickey Date: Mon Mar 18 11:45:13 2019 -0700 lucetc: delete runtime-c globals serializer commit b756b0a142c8e0827dd5151c53deca386bcf4db5 Author: Pat Hickey Date: Mon Mar 18 11:44:10 2019 -0700 lucetc: delete runtime-c linear memory serializers commit ee8adba1bf4eb9cf1701bef66ef7de9259e668ed Author: Pat Hickey Date: Mon Mar 18 11:42:00 2019 -0700 lucetc: delete runtime-c memory spec serializer commit 372fc5299af25d818a63caa88f10efb55c45e667 Author: Pat Hickey Date: Mon Mar 18 11:22:58 2019 -0700 depend on cranelift-wasm --- .gitmodules | 3 - Cargo.lock | 119 +- Makefile | 12 + lucet-analyze/Cargo.toml | 2 +- lucet-analyze/src/main.rs | 27 +- lucet-builtins/wasmonkey/Cargo.toml | 2 +- lucet-module-data/src/lib.rs | 4 +- lucet-module-data/src/linear_memory.rs | 32 + lucet-module-data/src/module_data.rs | 63 +- .../lucet-runtime-internals/src/alloc/mod.rs | 34 +- .../src/alloc/tests.rs | 49 +- .../lucet-runtime-internals/src/c_api.rs | 67 +- .../lucet-runtime-internals/src/error.rs | 5 + .../lucet-runtime-internals/src/instance.rs | 47 +- .../src/instance/signals.rs | 53 +- .../lucet-runtime-internals/src/module.rs | 52 +- .../lucet-runtime-internals/src/module/dl.rs | 22 +- .../src/module/mock.rs | 21 +- .../src/region/mmap.rs | 12 +- .../lucet-runtime-internals/src/trapcode.rs | 42 +- lucet-runtime/lucet-runtime-tests/Cargo.toml | 1 + .../lucet-runtime-tests/src/guest_fault.rs | 11 +- lucet-runtime/lucet-runtime-tests/src/host.rs | 4 +- .../lucet-runtime-tests/src/stack.rs | 4 +- lucet-runtime/src/c_api.rs | 3 +- lucet-runtime/src/lib.rs | 4 +- lucet-spectest/Cargo.toml | 1 - lucet-spectest/src/bindings.rs | 2 +- lucet-spectest/src/instance.rs | 113 -- lucet-spectest/src/lib.rs | 120 +- lucet-spectest/src/script.rs | 72 +- lucet-spectest/tests/wasm-spec.rs | 7 +- lucetc/Cargo.toml | 17 +- lucetc/src/compiler.rs | 245 ++++ lucetc/src/compiler/data.rs | 125 -- lucetc/src/compiler/entity/bases.rs | 61 - lucetc/src/compiler/entity/cache.rs | 90 -- lucetc/src/compiler/entity/global.rs | 8 - lucetc/src/compiler/entity/mod.rs | 169 --- lucetc/src/compiler/function.rs | 127 -- lucetc/src/compiler/globals.rs | 87 -- lucetc/src/compiler/memory.rs | 40 - lucetc/src/compiler/mod.rs | 306 ----- lucetc/src/compiler/module_data.rs | 52 - lucetc/src/compiler/opcode.rs | 1175 ----------------- lucetc/src/compiler/state.rs | 192 --- lucetc/src/compiler/table.rs | 67 - lucetc/src/decls.rs | 358 +++++ lucetc/src/error.rs | 58 +- lucetc/src/function.rs | 261 ++++ lucetc/src/heap.rs | 16 + lucetc/src/lib.rs | 141 +- lucetc/src/load.rs | 9 +- lucetc/src/module.rs | 263 ++++ lucetc/src/{compiler => }/name.rs | 8 +- lucetc/src/output.rs | 60 + lucetc/src/pointer.rs | 4 + lucetc/src/program/data/mod.rs | 70 - lucetc/src/program/data/sparse.rs | 85 -- lucetc/src/program/function.rs | 179 --- lucetc/src/program/globals.rs | 130 -- lucetc/src/program/init_expr.rs | 33 - lucetc/src/program/memory.rs | 58 - lucetc/src/program/mod.rs | 393 ------ lucetc/src/program/names.rs | 135 -- lucetc/src/program/runtime.rs | 45 - lucetc/src/program/table.rs | 114 -- lucetc/src/program/types.rs | 61 - lucetc/src/runtime.rs | 48 + lucetc/src/sparsedata.rs | 103 ++ lucetc/src/{compiler => }/stack_probe.rs | 0 lucetc/src/table.rs | 122 ++ lucetc/src/{compiler => }/traps.rs | 4 +- lucetc/tests/harnesses/call.c | 10 - lucetc/tests/harnesses/current_memory.c | 25 - lucetc/tests/harnesses/data_segment.c | 92 -- lucetc/tests/harnesses/fibonacci.c | 18 - lucetc/tests/harnesses/globals.c | 21 - lucetc/tests/harnesses/globals.h | 28 - lucetc/tests/harnesses/globals_definition.c | 36 - lucetc/tests/harnesses/grow_memory.c | 28 - lucetc/tests/harnesses/heap_spec.h | 12 - lucetc/tests/harnesses/heap_spec_definition.c | 14 - lucetc/tests/harnesses/heap_spec_import.c | 16 - lucetc/tests/harnesses/icall.c | 43 - lucetc/tests/harnesses/icall_import.c | 48 - lucetc/tests/harnesses/icall_sparse.c | 40 - lucetc/tests/harnesses/import_many.c | 44 - lucetc/tests/harnesses/locals.c | 16 - lucetc/tests/harnesses/locals_csr.c | 16 - lucetc/tests/harnesses/strstr.c | 11 - lucetc/tests/harnesses/vm.c | 40 - lucetc/tests/harnesses/vm.h | 24 - lucetc/tests/wasi-sdk.rs | 81 +- lucetc/tests/wasm.rs | 305 ++--- pwasm-validation | 1 - 96 files changed, 2215 insertions(+), 5283 deletions(-) delete mode 100644 lucet-spectest/src/instance.rs create mode 100644 lucetc/src/compiler.rs delete mode 100644 lucetc/src/compiler/data.rs delete mode 100644 lucetc/src/compiler/entity/bases.rs delete mode 100644 lucetc/src/compiler/entity/cache.rs delete mode 100644 lucetc/src/compiler/entity/global.rs delete mode 100644 lucetc/src/compiler/entity/mod.rs delete mode 100644 lucetc/src/compiler/function.rs delete mode 100644 lucetc/src/compiler/globals.rs delete mode 100644 lucetc/src/compiler/memory.rs delete mode 100644 lucetc/src/compiler/mod.rs delete mode 100644 lucetc/src/compiler/module_data.rs delete mode 100644 lucetc/src/compiler/opcode.rs delete mode 100644 lucetc/src/compiler/state.rs delete mode 100644 lucetc/src/compiler/table.rs create mode 100644 lucetc/src/decls.rs create mode 100644 lucetc/src/function.rs create mode 100644 lucetc/src/heap.rs create mode 100644 lucetc/src/module.rs rename lucetc/src/{compiler => }/name.rs (84%) create mode 100644 lucetc/src/output.rs create mode 100644 lucetc/src/pointer.rs delete mode 100644 lucetc/src/program/data/mod.rs delete mode 100644 lucetc/src/program/data/sparse.rs delete mode 100644 lucetc/src/program/function.rs delete mode 100644 lucetc/src/program/globals.rs delete mode 100644 lucetc/src/program/init_expr.rs delete mode 100644 lucetc/src/program/memory.rs delete mode 100644 lucetc/src/program/mod.rs delete mode 100644 lucetc/src/program/names.rs delete mode 100644 lucetc/src/program/runtime.rs delete mode 100644 lucetc/src/program/table.rs delete mode 100644 lucetc/src/program/types.rs create mode 100644 lucetc/src/runtime.rs create mode 100644 lucetc/src/sparsedata.rs rename lucetc/src/{compiler => }/stack_probe.rs (100%) create mode 100644 lucetc/src/table.rs rename lucetc/src/{compiler => }/traps.rs (95%) delete mode 100644 lucetc/tests/harnesses/call.c delete mode 100644 lucetc/tests/harnesses/current_memory.c delete mode 100644 lucetc/tests/harnesses/data_segment.c delete mode 100644 lucetc/tests/harnesses/fibonacci.c delete mode 100644 lucetc/tests/harnesses/globals.c delete mode 100644 lucetc/tests/harnesses/globals.h delete mode 100644 lucetc/tests/harnesses/globals_definition.c delete mode 100644 lucetc/tests/harnesses/grow_memory.c delete mode 100644 lucetc/tests/harnesses/heap_spec.h delete mode 100644 lucetc/tests/harnesses/heap_spec_definition.c delete mode 100644 lucetc/tests/harnesses/heap_spec_import.c delete mode 100644 lucetc/tests/harnesses/icall.c delete mode 100644 lucetc/tests/harnesses/icall_import.c delete mode 100644 lucetc/tests/harnesses/icall_sparse.c delete mode 100644 lucetc/tests/harnesses/import_many.c delete mode 100644 lucetc/tests/harnesses/locals.c delete mode 100644 lucetc/tests/harnesses/locals_csr.c delete mode 100644 lucetc/tests/harnesses/strstr.c delete mode 100644 lucetc/tests/harnesses/vm.c delete mode 100644 lucetc/tests/harnesses/vm.h delete mode 160000 pwasm-validation diff --git a/.gitmodules b/.gitmodules index 91aa6c61b..f81bc9a8b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,9 +7,6 @@ [submodule "lucet-spectest/spec"] path = lucet-spectest/spec url = https://github.com/webassembly/spec -[submodule "pwasm-validation"] - path = pwasm-validation - url = https://github.com/pchickey/pwasm-validator [submodule "sightglass"] path = sightglass url = https://github.com/fastly/sightglass diff --git a/Cargo.lock b/Cargo.lock index da55c7fa3..860848c33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,11 +22,6 @@ dependencies = [ "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "assert_matches" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "atty" version = "0.2.11" @@ -51,7 +46,7 @@ dependencies = [ "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -71,8 +66,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bimap" -version = "0.1.5" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "bincode" @@ -100,7 +98,7 @@ dependencies = [ "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -272,6 +270,20 @@ dependencies = [ "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cranelift-wasm" +version = "0.29.0" +dependencies = [ + "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen 0.29.0", + "cranelift-entity 0.29.0", + "cranelift-frontend 0.29.0", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "criterion" version = "0.2.11" @@ -281,7 +293,7 @@ dependencies = [ "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "csv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "csv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", @@ -341,7 +353,7 @@ dependencies = [ [[package]] name = "csv" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -371,7 +383,7 @@ dependencies = [ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -432,7 +444,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -461,6 +473,16 @@ dependencies = [ "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "goblin" +version = "0.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hashbrown" version = "0.1.8" @@ -658,7 +680,6 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-runtime 0.1.0", "lucetc 0.1.0", - "parity-wasm 0.35.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -700,7 +721,7 @@ dependencies = [ "progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -719,7 +740,7 @@ dependencies = [ name = "lucetc" version = "0.1.0" dependencies = [ - "bimap 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-codegen 0.29.0", @@ -727,6 +748,7 @@ dependencies = [ "cranelift-frontend 0.29.0", "cranelift-module 0.29.0", "cranelift-native 0.29.0", + "cranelift-wasm 0.29.0", "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "faerie 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -735,13 +757,13 @@ dependencies = [ "lucet-module-data 0.1.0", "lucet-wasi-sdk 0.1.0", "parity-wasm 0.35.7 (registry+https://github.com/rust-lang/crates.io-index)", - "pwasm-validation 0.1.0", "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "wasmonkey 0.1.4", + "wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -757,11 +779,6 @@ name = "memoffset" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "memory_units" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "nix" version = "0.13.0" @@ -805,7 +822,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -892,16 +909,6 @@ dependencies = [ "terminal_size 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "pwasm-validation" -version = "0.1.0" -dependencies = [ - "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memory_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-wasm 0.35.7 (registry+https://github.com/rust-lang/crates.io-index)", - "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "quick-error" version = "1.2.2" @@ -1074,7 +1081,7 @@ dependencies = [ [[package]] name = "regex" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1102,7 +1109,7 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1147,7 +1154,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1178,7 +1185,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1199,7 +1206,7 @@ dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "core_affinity 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)", "hwloc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1247,12 +1254,12 @@ dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" -version = "0.15.30" +version = "0.15.31" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1267,20 +1274,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "target-lexicon" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "target-lexicon" version = "0.3.0" @@ -1459,6 +1456,11 @@ dependencies = [ "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "wasmparser" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "which" version = "2.0.1" @@ -1523,13 +1525,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" -"checksum assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7deb0a829ca7bcfaf5da70b073a8d128619259a7be8216a355e23f00763059e5" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" "checksum backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f106c02a3604afcdc0df5d36cc47b44b55917dbaf3d808f71c163a0ddba64637" "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" "checksum bencher 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdb4953a096c551ce9ace855a604d702e6e62d77fac690575ae347571717f5" -"checksum bimap 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6b282b982237078bfac61a948a2198f185aceea8b9a6e794b70b96fd31923d3d" +"checksum bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "505e45beaf0a1462f5548fe885edf2d83e62022b2ce8b10fef0f7686b48c9266" "checksum bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f2fb9e29e72fd6bc12071533d5dc7664cb01480c59406f656d7ac25c7bd8ff7" "checksum bindgen 0.47.3 (registry+https://github.com/rust-lang/crates.io-index)" = "df683a55b54b41d5ea8ebfaebb5aa7e6b84e3f3006a78f010dadc9ca88469260" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" @@ -1550,7 +1551,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" -"checksum csv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f0782c7154d8dd08f4adeb5aa22ab178c10281915f7da68d10bb646f03aaee73" +"checksum csv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9044e25afb0924b5a5fc5511689b0918629e85d68ea591e5e87fbf1e85ea1b3b" "checksum csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5cdef62f37e6ffe7d1f07a381bc0db32b7a3ff1cac0de56cb0d81e71f53d65" "checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" "checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a" @@ -1563,6 +1564,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6a4013e9182f2345c6b7829b9ef6e670bce0dfca12c6f974457ed2160c2c7fe9" +"checksum goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "7f55d53401eb2fd30afd025c570b1946b6966344acf21b42e31286f3bf89e6a8" "checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bec6e801ef7367625bd94ad7e2965e6027189f3e9deef422388d993af2814a0" @@ -1578,7 +1580,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" -"checksum memory_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" "checksum nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46f0f3210768d796e8fa79ec70ee6af172dacbe7147f5e69be5240a47778302b" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" @@ -1615,10 +1616,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "559008764a17de49a3146b234641644ed37d118d1ef641a0bb573d146edc6ce0" +"checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58" "checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" -"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" +"checksum rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc78bfd5acd7bf3e89cffcf899e5cb1a52d6fafa8dec2739ad70c9577a57288" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" @@ -1635,9 +1636,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3d0760c312538987d363c36c42339b55f5ee176ea8808bbe4543d484a291c8d1" "checksum structopt-derive 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "528aeb7351d042e6ffbc2a6fb76a86f9b622fdf7c25932798e7a82cb03bc94c6" -"checksum syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)" = "66c8865bf5a7cbb662d8b011950060b3c8743dca141b054bf7195b20d314d8e2" +"checksum syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)" = "d2b4cfac95805274c6afdb12d8f770fa2d27c045953e7b630a81801953699a9a" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" -"checksum target-lexicon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4af5e2227f0b887d591d3724b796a96eff04226104d872f5b3883fcd427d64b9" "checksum target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6923974ce4eb5bd28814756256d8ab71c28dd6e7483313fe7ab6614306bf633" "checksum tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b86c784c88d98c801132806dadd3819ed29d8600836c4088e855cdf3e178ed8a" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" @@ -1659,6 +1659,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a6265b25719e82598d104b3717375e37661d41753e2c84cde3f51050c7ed7e3c" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" +"checksum wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5e01c420bc7d36e778bd242e1167b079562ba8b34087122cc9057187026d060" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" diff --git a/Makefile b/Makefile index 8568366f4..ce0fbb17a 100644 --- a/Makefile +++ b/Makefile @@ -57,3 +57,15 @@ indent: .PHONY: indent-check indent-check: helpers/indent.sh check + +.PHONY: watch +watch: + cargo watch --exec "test \ + -p lucet-runtime-internals \ + -p lucet-runtime \ + -p lucet-module-data \ + -p lucetc \ + -p lucet-idl \ + -p lucet-wasi-sdk \ + -p lucet-wasi \ + -p lucet-benchmarks" diff --git a/lucet-analyze/Cargo.toml b/lucet-analyze/Cargo.toml index 086ed97d6..64e400480 100644 --- a/lucet-analyze/Cargo.toml +++ b/lucet-analyze/Cargo.toml @@ -8,6 +8,6 @@ license = "Apache-2.0 WITH LLVM-exception" edition = "2018" [dependencies] -goblin="~0.0.17" +goblin="0.0.21" byteorder="1.2.1" colored="1.6.1" diff --git a/lucet-analyze/src/main.rs b/lucet-analyze/src/main.rs index b52e87a76..51026bd55 100644 --- a/lucet-analyze/src/main.rs +++ b/lucet-analyze/src/main.rs @@ -49,7 +49,7 @@ struct TrapManifestRow { #[derive(Debug)] struct TrapSite { offset: u32, - reason: u32, + trapcode: u32, } #[derive(Debug)] @@ -332,29 +332,25 @@ impl<'a> ArtifactSummary<'a> { for _ in 0..trap_manifest_len { let func_start = rdr.read_u64::().unwrap(); let func_len = rdr.read_u64::().unwrap(); - let _traps = rdr.read_u64::().unwrap(); + let traps = rdr.read_u64::().unwrap(); let traps_len = rdr.read_u64::().unwrap(); let func_name = self .get_func_name_for_addr(func_start) .unwrap_or("(not found)"); - let sites = Vec::new(); + let mut sites = Vec::new(); - // TODO: This doesn't work yet for unknown reasons - // // Find the table - // let serialized_table = self.read_memory(traps, 8 * traps_len).unwrap(); - // let mut table_rdr = Cursor::new(serialized_table); + // Find the table + let serialized_table = self.read_memory(traps, 8 * traps_len).unwrap(); + let mut table_rdr = Cursor::new(serialized_table); // Iterate through each site - // for _ in 0..traps_len { - // let offset = table_rdr.read_u32::().unwrap(); - // let reason = table_rdr.read_u32::().unwrap(); + for _ in 0..traps_len { + let offset = table_rdr.read_u32::().unwrap(); + let trapcode = table_rdr.read_u32::().unwrap(); - // sites.push(TrapSite { - // offset: offset, - // reason: reason, - // }); - // } + sites.push(TrapSite { offset, trapcode }); + } manifest.records.push(TrapManifestRow { func_name: func_name.to_string(), @@ -513,6 +509,7 @@ fn print_summary(summary: ArtifactSummary) { if let Some(trap_manifest) = summary.trap_manifest { for row in trap_manifest.records { println!(" {:25} {} traps", row.func_name, row.trap_count); + println!(" {:?}", row.sites); } } else { println!(" {}", "MISSING!".red().bold()); diff --git a/lucet-builtins/wasmonkey/Cargo.toml b/lucet-builtins/wasmonkey/Cargo.toml index 62195fba1..8540880ba 100644 --- a/lucet-builtins/wasmonkey/Cargo.toml +++ b/lucet-builtins/wasmonkey/Cargo.toml @@ -11,7 +11,7 @@ categories = ["wasm"] [dependencies] clap = "2.32" failure = "0.1" -goblin = "~0.0.19" +goblin = "0.0.21" lazy_static = "1.2" parity-wasm = "0.35" serde = "1.0" diff --git a/lucet-module-data/src/lib.rs b/lucet-module-data/src/lib.rs index 624f685f7..949e7e6c1 100644 --- a/lucet-module-data/src/lib.rs +++ b/lucet-module-data/src/lib.rs @@ -10,12 +10,12 @@ mod module_data; pub use crate::error::Error; pub use crate::globals::{Global, GlobalDef, GlobalSpec}; -pub use crate::linear_memory::{HeapSpec, SparseData}; +pub use crate::linear_memory::{HeapSpec, SparseData, LinearMemorySpec}; pub use crate::module_data::ModuleData; /// Owned variants of the module data types, useful for serialization and testing. pub mod owned { pub use crate::globals::OwnedGlobalSpec; - pub use crate::linear_memory::OwnedSparseData; + pub use crate::linear_memory::{OwnedSparseData, OwnedLinearMemorySpec}; pub use crate::module_data::OwnedModuleData; } diff --git a/lucet-module-data/src/linear_memory.rs b/lucet-module-data/src/linear_memory.rs index 5dd79702d..1bc3e44d5 100644 --- a/lucet-module-data/src/linear_memory.rs +++ b/lucet-module-data/src/linear_memory.rs @@ -1,6 +1,38 @@ use crate::Error; use serde::{Deserialize, Serialize}; +/// Specification of the linear memory of a module +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct LinearMemorySpec<'a> { + /// Specification of the heap used to implement the linear memory + pub heap: HeapSpec, + /// Initialization values for linear memory + #[serde(borrow)] + pub initializer: SparseData<'a>, +} + +/// Specification of the linear memory of a module +/// +/// This is a version of [`LinearMemorySpec`](../struct.LinearMemorySpec.html) with an +/// `OwnedSparseData` for the initializer. +/// This type is useful when directly building up a value to be serialized. +pub struct OwnedLinearMemorySpec { + /// Specification of the heap used to implement the linear memory + pub heap: HeapSpec, + /// Initialization values for linear memory + pub initializer: OwnedSparseData, +} + + +impl OwnedLinearMemorySpec { + pub fn to_ref<'a>(&'a self) -> LinearMemorySpec<'a> { + LinearMemorySpec { + heap: self.heap.clone(), + initializer: self.initializer.to_ref(), + } + } +} + /// Specifications about the heap of a Lucet module. #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct HeapSpec { diff --git a/lucet-module-data/src/module_data.rs b/lucet-module-data/src/module_data.rs index b0710961f..69cb9ce79 100644 --- a/lucet-module-data/src/module_data.rs +++ b/lucet-module-data/src/module_data.rs @@ -1,6 +1,6 @@ use crate::{ globals::GlobalSpec, - linear_memory::{HeapSpec, SparseData}, + linear_memory::{HeapSpec, LinearMemorySpec, SparseData}, Error, }; use serde::{Deserialize, Serialize}; @@ -15,32 +15,37 @@ use serde::{Deserialize, Serialize}; /// functions themselves. #[derive(Debug, Serialize, Deserialize)] pub struct ModuleData<'a> { - heap_spec: HeapSpec, #[serde(borrow)] - sparse_data: SparseData<'a>, + linear_memory: Option>, #[serde(borrow)] globals_spec: Vec>, } impl<'a> ModuleData<'a> { pub fn new( - heap_spec: HeapSpec, - sparse_data: SparseData<'a>, + linear_memory: Option>, globals_spec: Vec>, ) -> Self { Self { - heap_spec, - sparse_data, + linear_memory, globals_spec, } } - pub fn heap_spec(&self) -> &HeapSpec { - &self.heap_spec + pub fn heap_spec(&self) -> Option<&HeapSpec> { + if let Some(ref linear_memory) = self.linear_memory { + Some(&linear_memory.heap) + } else { + None + } } - pub fn sparse_data(&self) -> &SparseData<'a> { - &self.sparse_data + pub fn sparse_data(&self) -> Option<&SparseData<'a>> { + if let Some(ref linear_memory) = self.linear_memory { + Some(&linear_memory.initializer) + } else { + None + } } pub fn globals_spec(&self) -> &[GlobalSpec<'a>] { @@ -58,7 +63,10 @@ impl<'a> ModuleData<'a> { } } -use crate::{globals::OwnedGlobalSpec, linear_memory::OwnedSparseData}; +use crate::{ + globals::OwnedGlobalSpec, + linear_memory::{OwnedLinearMemorySpec, OwnedSparseData}, +}; /// The metadata (and some data) for a Lucet module. /// @@ -66,20 +74,17 @@ use crate::{globals::OwnedGlobalSpec, linear_memory::OwnedSparseData}; /// rather than references to support zero-copy deserialization. This type is useful when directly /// building up a value to be serialized. pub struct OwnedModuleData { - heap_spec: HeapSpec, - sparse_data: OwnedSparseData, + linear_memory: Option, globals_spec: Vec, } impl OwnedModuleData { pub fn new( - heap_spec: HeapSpec, - sparse_data: OwnedSparseData, + linear_memory: Option, globals_spec: Vec, ) -> Self { Self { - heap_spec, - sparse_data, + linear_memory, globals_spec, } } @@ -88,22 +93,28 @@ impl OwnedModuleData { /// `OwnedModuleData`. pub fn to_ref<'a>(&'a self) -> ModuleData<'a> { ModuleData::new( - self.heap_spec.clone(), - self.sparse_data.to_ref(), + if let Some(ref owned_linear_memory) = self.linear_memory { + Some(owned_linear_memory.to_ref()) + } else { + None + }, self.globals_spec.iter().map(|gs| gs.to_ref()).collect(), ) } pub fn empty() -> Self { - Self::new( - HeapSpec::new(0, 0, 0, None), - OwnedSparseData::new(vec![]).unwrap(), - vec![], - ) + Self::new(None, vec![]) } pub fn with_heap_spec(mut self, heap_spec: HeapSpec) -> Self { - self.heap_spec = heap_spec; + if let Some(ref mut linear_memory) = self.linear_memory { + linear_memory.heap = heap_spec; + } else { + self.linear_memory = Some(OwnedLinearMemorySpec { + heap: heap_spec, + initializer: OwnedSparseData::new(vec![]).unwrap(), + }); + } self } } diff --git a/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs b/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs index b45d1fd0a..f2a24bad1 100644 --- a/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs @@ -154,25 +154,27 @@ impl Alloc { // the above makes sure this expression does not underflow let guard_remaining = self.heap_inaccessible_size - expand_pagealigned as usize; - let heap_spec = module.heap_spec(); - // The compiler specifies how much guard (memory which traps on access) must be beyond the - // end of the accessible memory. We cannot perform an expansion that would make this region - // smaller than the compiler expected it to be. - if guard_remaining < heap_spec.guard_size as usize { - bail_limits_exceeded!("expansion would leave guard memory too small"); - } + if let Some(heap_spec) = module.heap_spec() { + // The compiler specifies how much guard (memory which traps on access) must be beyond the + // end of the accessible memory. We cannot perform an expansion that would make this region + // smaller than the compiler expected it to be. + if guard_remaining < heap_spec.guard_size as usize { + bail_limits_exceeded!("expansion would leave guard memory too small"); + } - // The compiler indicates that the module has specified a maximum memory size. Don't let - // the heap expand beyond that: - if let Some(max_size) = heap_spec.max_size { - if self.heap_accessible_size + expand_pagealigned as usize > max_size as usize { - bail_limits_exceeded!( - "expansion would exceed module-specified heap limit: {:?}", - max_size - ); + // The compiler indicates that the module has specified a maximum memory size. Don't let + // the heap expand beyond that: + if let Some(max_size) = heap_spec.max_size { + if self.heap_accessible_size + expand_pagealigned as usize > max_size as usize { + bail_limits_exceeded!( + "expansion would exceed module-specified heap limit: {:?}", + max_size + ); + } } + } else { + return Err(Error::NoLinearMemory("cannot expand heap".to_owned())); } - // The runtime sets a limit on how much of the heap can be backed by real memory. Don't let // the heap expand beyond that: if self.heap_accessible_size + expand_pagealigned as usize > slot.limits.heap_memory_size { diff --git a/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs b/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs index 603f8ef92..eff5eb376 100644 --- a/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs +++ b/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs @@ -377,8 +377,7 @@ macro_rules! alloc_tests { peek_n_poke(®ion); } - /// This test shows that the reset method clears the heap and restores it to the spec - /// initial size. + /// This test shows that the reset method clears the heap and resets its protections. #[test] fn alloc_reset() { let region = TestRegion::create(1, &LIMITS).expect("region created"); @@ -402,6 +401,52 @@ macro_rules! alloc_tests { heap[heap_len - 1] = 0xFF; assert_eq!(heap[heap_len - 1], 0xFF); + // Making a new mock module here because the borrow checker doesn't like referencing + // `inst.module` while `inst.alloc()` is borrowed mutably. The `Instance` tests don't have + // this weirdness + inst.alloc_mut() + .reset_heap(module.as_ref()) + .expect("reset succeeds"); + + let reset_heap_len = inst.alloc().heap_len(); + assert_eq!(reset_heap_len, THREEPAGE_INITIAL_SIZE as usize); + + let heap = unsafe { inst.alloc_mut().heap_mut() }; + + assert_eq!(heap[0], 0); + heap[0] = 0xFF; + assert_eq!(heap[0], 0xFF); + + assert_eq!(heap[reset_heap_len - 1], 0); + heap[reset_heap_len - 1] = 0xFF; + assert_eq!(heap[reset_heap_len - 1], 0xFF); + } + + /// This test shows that the reset method clears the heap and restores it to the spec + /// initial size after growing the heap. + #[test] + fn alloc_grow_reset() { + let region = TestRegion::create(1, &LIMITS).expect("region created"); + let module = MockModuleBuilder::new() + .with_heap_spec(THREE_PAGE_MAX_HEAP) + .build(); + let mut inst = region + .new_instance(module.clone()) + .expect("new_instance succeeds"); + + let heap_len = inst.alloc().heap_len(); + assert_eq!(heap_len, THREEPAGE_INITIAL_SIZE as usize); + + let heap = unsafe { inst.alloc_mut().heap_mut() }; + + assert_eq!(heap[0], 0); + heap[0] = 0xFF; + assert_eq!(heap[0], 0xFF); + + assert_eq!(heap[heap_len - 1], 0); + heap[heap_len - 1] = 0xFF; + assert_eq!(heap[heap_len - 1], 0xFF); + let new_heap_area = inst .alloc_mut() .expand_heap( diff --git a/lucet-runtime/lucet-runtime-internals/src/c_api.rs b/lucet-runtime/lucet-runtime-internals/src/c_api.rs index 7e4609638..716ca8dfe 100644 --- a/lucet-runtime/lucet-runtime-internals/src/c_api.rs +++ b/lucet-runtime/lucet-runtime-internals/src/c_api.rs @@ -69,6 +69,7 @@ pub enum lucet_error { RegionFull, Module, LimitsExceeded, + NoLinearMemory, SymbolNotFound, FuncNotFound, RuntimeFault, @@ -85,6 +86,7 @@ impl From for lucet_error { Error::RegionFull(_) => lucet_error::RegionFull, Error::ModuleError(_) => lucet_error::Module, Error::LimitsExceeded(_) => lucet_error::LimitsExceeded, + Error::NoLinearMemory(_) => lucet_error::NoLinearMemory, Error::SymbolNotFound(_) => lucet_error::SymbolNotFound, Error::FuncNotFound(_, _) => lucet_error::FuncNotFound, Error::RuntimeFault(_) => lucet_error::RuntimeFault, @@ -197,7 +199,7 @@ pub mod lucet_state { use crate::instance::{State, TerminationDetails}; use crate::module::AddrDetails; use crate::sysdeps::UContext; - use crate::trapcode::{TrapCode, TrapCodeType}; + use crate::trapcode::TrapCode; use libc::{c_char, c_void}; use num_derive::FromPrimitive; use std::ffi::CString; @@ -313,7 +315,7 @@ pub mod lucet_state { #[repr(C)] #[derive(Clone, Copy, Debug)] - pub enum lucet_trapcode_type { + pub enum lucet_trapcode { StackOverflow, HeapOutOfBounds, OutOfBounds, @@ -324,53 +326,34 @@ pub mod lucet_state { BadConversionToInteger, Interrupt, TableOutOfBounds, - User, + Unreachable, Unknown, } - impl From for lucet_trapcode_type { - fn from(ty: TrapCodeType) -> lucet_trapcode_type { + impl From> for lucet_trapcode { + fn from(ty: Option) -> lucet_trapcode { (&ty).into() } } - impl From<&TrapCodeType> for lucet_trapcode_type { - fn from(ty: &TrapCodeType) -> lucet_trapcode_type { - match ty { - TrapCodeType::StackOverflow => lucet_trapcode_type::StackOverflow, - TrapCodeType::HeapOutOfBounds => lucet_trapcode_type::HeapOutOfBounds, - TrapCodeType::OutOfBounds => lucet_trapcode_type::OutOfBounds, - TrapCodeType::IndirectCallToNull => lucet_trapcode_type::IndirectCallToNull, - TrapCodeType::BadSignature => lucet_trapcode_type::BadSignature, - TrapCodeType::IntegerOverflow => lucet_trapcode_type::IntegerOverflow, - TrapCodeType::IntegerDivByZero => lucet_trapcode_type::IntegerDivByZero, - TrapCodeType::BadConversionToInteger => lucet_trapcode_type::BadConversionToInteger, - TrapCodeType::Interrupt => lucet_trapcode_type::Interrupt, - TrapCodeType::TableOutOfBounds => lucet_trapcode_type::TableOutOfBounds, - TrapCodeType::User => lucet_trapcode_type::User, - TrapCodeType::Unknown => lucet_trapcode_type::Unknown, - } - } - } - - #[repr(C)] - #[derive(Clone, Copy, Debug)] - pub struct lucet_trapcode { - code: lucet_trapcode_type, - tag: u16, - } - - impl From for lucet_trapcode { - fn from(trap: TrapCode) -> lucet_trapcode { - (&trap).into() - } - } - - impl From<&TrapCode> for lucet_trapcode { - fn from(trap: &TrapCode) -> lucet_trapcode { - lucet_trapcode { - code: trap.ty.into(), - tag: trap.tag, + impl From<&Option> for lucet_trapcode { + fn from(ty: &Option) -> lucet_trapcode { + if let Some(ty) = ty { + match ty { + TrapCode::StackOverflow => lucet_trapcode::StackOverflow, + TrapCode::HeapOutOfBounds => lucet_trapcode::HeapOutOfBounds, + TrapCode::OutOfBounds => lucet_trapcode::OutOfBounds, + TrapCode::IndirectCallToNull => lucet_trapcode::IndirectCallToNull, + TrapCode::BadSignature => lucet_trapcode::BadSignature, + TrapCode::IntegerOverflow => lucet_trapcode::IntegerOverflow, + TrapCode::IntegerDivByZero => lucet_trapcode::IntegerDivByZero, + TrapCode::BadConversionToInteger => lucet_trapcode::BadConversionToInteger, + TrapCode::Interrupt => lucet_trapcode::Interrupt, + TrapCode::TableOutOfBounds => lucet_trapcode::TableOutOfBounds, + TrapCode::Unreachable => lucet_trapcode::Unreachable, + } + } else { + lucet_trapcode::Unknown } } } diff --git a/lucet-runtime/lucet-runtime-internals/src/error.rs b/lucet-runtime/lucet-runtime-internals/src/error.rs index ce2e2dee6..07c8c3caa 100644 --- a/lucet-runtime/lucet-runtime-internals/src/error.rs +++ b/lucet-runtime/lucet-runtime-internals/src/error.rs @@ -20,6 +20,11 @@ pub enum Error { #[fail(display = "Instance limits exceeded: {}", _0)] LimitsExceeded(String), + /// A method call attempted to modify linear memory for an instance that + /// does not have linear memory + #[fail(display = "No linear memory available: {}", _0)] + NoLinearMemory(String), + /// An attempt to look up a WebAssembly function by its symbol name failed. #[fail(display = "Symbol not found: {}", _0)] SymbolNotFound(String), diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index a89872dcf..b679ee17c 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -10,7 +10,7 @@ use crate::error::Error; use crate::instance::siginfo_ext::SiginfoExt; use crate::module::{self, Global, Module}; use crate::sysdeps::UContext; -use crate::trapcode::{TrapCode, TrapCodeType}; +use crate::trapcode::TrapCode; use crate::val::{UntypedRetVal, Val}; use crate::WASM_PAGE_SIZE; use libc::{c_void, siginfo_t, uintptr_t, SIGBUS, SIGSEGV}; @@ -184,7 +184,7 @@ pub struct Instance { signal_handler: Box< dyn Fn( &Instance, - &TrapCode, + &Option, libc::c_int, *const siginfo_t, *const c_void, @@ -333,9 +333,15 @@ impl Instance { /// /// On success, returns the number of pages that existed before the call. pub fn grow_memory(&mut self, additional_pages: u32) -> Result { + let additional_bytes = + additional_pages + .checked_mul(WASM_PAGE_SIZE) + .ok_or(lucet_format_err!( + "additional pages larger than wasm address space", + ))?; let orig_len = self .alloc - .expand_heap(additional_pages * WASM_PAGE_SIZE, self.module.as_ref())?; + .expand_heap(additional_bytes, self.module.as_ref())?; Ok(orig_len / WASM_PAGE_SIZE) } @@ -422,7 +428,13 @@ impl Instance { pub fn set_signal_handler(&mut self, handler: H) where H: 'static - + Fn(&Instance, &TrapCode, libc::c_int, *const siginfo_t, *const c_void) -> SignalBehavior, + + Fn( + &Instance, + &Option, + libc::c_int, + *const siginfo_t, + *const c_void, + ) -> SignalBehavior, { self.signal_handler = Box::new(handler) as Box; } @@ -507,8 +519,8 @@ impl Instance { args: &[Val], ) -> Result { lucet_ensure!( - self.state.is_ready(), - "instance must be ready; this is a bug" + self.state.is_ready() || (self.state.is_fault() && !self.state.is_fatal()), + "instance must be ready or non-fatally faulted" ); if func.is_null() { return Err(Error::InvalidArgument( @@ -613,28 +625,17 @@ impl Instance { details: FaultDetails { rip_addr, - trapcode, - ref mut fatal, ref mut rip_addr_details, .. }, - siginfo, .. } = self.state { // We do this after returning from the signal handler because it requires `dladdr` // calls, which are not signal safe + // FIXME after lucet-module is complete it should be possible to fill this in without + // consulting the process symbol table *rip_addr_details = self.module.addr_details(rip_addr as *const c_void)?.clone(); - - // If the trap table lookup returned unknown, it is a fatal error - let unknown_fault = trapcode.ty == TrapCodeType::Unknown; - - // If the trap was a segv or bus fault and the addressed memory was outside the - // guard pages, it is also a fatal error - let outside_guard = (siginfo.si_signo == SIGSEGV || siginfo.si_signo == SIGBUS) - && !self.alloc.addr_in_heap_guard(siginfo.si_addr()); - - *fatal = unknown_fault || outside_guard; } Ok(()) } @@ -664,7 +665,7 @@ pub struct FaultDetails { /// If true, the instance's `fatal_handler` will be called. pub fatal: bool, /// Information about the type of fault that occurred. - pub trapcode: TrapCode, + pub trapcode: Option, /// The instruction pointer where the fault occurred. pub rip_addr: uintptr_t, /// Extra information about the instruction pointer's location, if available. @@ -679,7 +680,11 @@ impl std::fmt::Display for FaultDetails { write!(f, "fault ")?; } - self.trapcode.fmt(f)?; + if let Some(trapcode) = self.trapcode { + write!(f, "{:?} ", trapcode)?; + } else { + write!(f, "TrapCode::UNKNOWN ")?; + } write!(f, "code at address {:p}", self.rip_addr as *const c_void)?; diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs index 0fe7a97e0..98d540e40 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs @@ -1,12 +1,13 @@ use crate::context::Context; use crate::instance::{ - FaultDetails, Instance, State, TerminationDetails, CURRENT_INSTANCE, HOST_CTX, + siginfo_ext::SiginfoExt, FaultDetails, Instance, State, TerminationDetails, CURRENT_INSTANCE, + HOST_CTX, }; use crate::sysdeps::UContextPtr; -use crate::trapcode::{TrapCode, TrapCodeType}; +use crate::trapcode::TrapCode; use failure::Error; use lazy_static::lazy_static; -use libc::{c_int, c_void, siginfo_t}; +use libc::{c_int, c_void, siginfo_t, SIGBUS, SIGSEGV}; use nix::sys::signal::{ pthread_sigmask, raise, sigaction, SaFlags, SigAction, SigHandler, SigSet, SigmaskHow, Signal, }; @@ -29,12 +30,17 @@ pub enum SignalBehavior { Terminate, } -pub type SignalHandler = - dyn Fn(&Instance, &TrapCode, libc::c_int, *const siginfo_t, *const c_void) -> SignalBehavior; +pub type SignalHandler = dyn Fn( + &Instance, + &Option, + libc::c_int, + *const siginfo_t, + *const c_void, +) -> SignalBehavior; pub fn signal_handler_none( _inst: &Instance, - _trapcode: &TrapCode, + _trapcode: &Option, _signum: libc::c_int, _siginfo_ptr: *const siginfo_t, _ucontext_ptr: *const c_void, @@ -139,15 +145,7 @@ extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext .as_mut() }; - let trapcode = inst - .module - .lookup_trapcode(rip) - // if we couldn't find a code in the manifest, return an unknown trapcode that will be - // converted to a fatal trap when we switch back to the host - .unwrap_or(TrapCode { - ty: TrapCodeType::Unknown, - tag: 0, - }); + let trapcode = inst.module.lookup_trapcode(rip); let behavior = (inst.signal_handler)(inst, &trapcode, signum, siginfo_ptr, ucontext_ptr); match behavior { @@ -163,20 +161,29 @@ extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext true } SignalBehavior::Default => { + // safety: pointer is checked for null at the top of the function, and the + // manpage guarantees that a siginfo_t will be passed as the second argument + let siginfo = unsafe { *siginfo_ptr }; + let rip_addr = rip as usize; + // If the trap table lookup returned unknown, it is a fatal error + let unknown_fault = trapcode.is_none(); + + // If the trap was a segv or bus fault and the addressed memory was outside the + // guard pages, it is also a fatal error + let outside_guard = (siginfo.si_signo == SIGSEGV || siginfo.si_signo == SIGBUS) + && !inst.alloc.addr_in_heap_guard(siginfo.si_addr()); + // record the fault and jump back to the host context inst.state = State::Fault { details: FaultDetails { - // fatal field is set false here by default - have to wait until - // `verify_trap_safety` to have enough information to determine whether trap was - // fatal. It is not signal safe to access some of the required information. - fatal: false, + fatal: unknown_fault || outside_guard, trapcode: trapcode, - rip_addr: rip as usize, + rip_addr, + // Details set to `None` here: have to wait until `verify_trap_safety` to + // fill in these details, because access may not be signal safe. rip_addr_details: None, }, - // safety: pointer is checked for null at the top of the function, and the - // manpage guarantees that a siginfo_t will be passed as the second argument - siginfo: unsafe { *siginfo_ptr }, + siginfo, context: ctx.into(), }; true diff --git a/lucet-runtime/lucet-runtime-internals/src/module.rs b/lucet-runtime/lucet-runtime-internals/src/module.rs index 6722df0ca..3d9251e25 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module.rs @@ -89,7 +89,7 @@ pub struct AddrDetails { pub trait Module: ModuleInternal {} pub trait ModuleInternal: Send + Sync { - fn heap_spec(&self) -> &HeapSpec; + fn heap_spec(&self) -> Option<&HeapSpec>; /// Get the WebAssembly globals of the module. /// @@ -143,32 +143,36 @@ pub trait ModuleInternal: Send + Sync { /// Returns a `Result<(), Error>` rather than a boolean in order to provide a richer accounting /// of what may be invalid. fn validate_runtime_spec(&self, limits: &Limits) -> Result<(), Error> { - let heap = self.heap_spec(); - // Assure that the total reserved + guard regions fit in the address space. - // First check makes sure they fit our 32-bit model, and ensures the second - // check doesn't overflow. - if heap.reserved_size > std::u32::MAX as u64 + 1 - || heap.guard_size > std::u32::MAX as u64 + 1 - { - return Err(lucet_incorrect_module!( - "heap spec sizes would overflow: {:?}", - heap - )); - } + // Modules without heap specs will not access the heap + if let Some(heap) = self.heap_spec() { + // Assure that the total reserved + guard regions fit in the address space. + // First check makes sure they fit our 32-bit model, and ensures the second + // check doesn't overflow. + if heap.reserved_size > std::u32::MAX as u64 + 1 + || heap.guard_size > std::u32::MAX as u64 + 1 + { + return Err(lucet_incorrect_module!( + "heap spec sizes would overflow: {:?}", + heap + )); + } - if heap.reserved_size as usize + heap.guard_size as usize > limits.heap_address_space_size { - bail_limits_exceeded!("heap spec reserved and guard size: {:?}", heap); - } + if heap.reserved_size as usize + heap.guard_size as usize + > limits.heap_address_space_size + { + bail_limits_exceeded!("heap spec reserved and guard size: {:?}", heap); + } - if heap.initial_size as usize > limits.heap_memory_size { - bail_limits_exceeded!("heap spec initial size: {:?}", heap); - } + if heap.initial_size as usize > limits.heap_memory_size { + bail_limits_exceeded!("heap spec initial size: {:?}", heap); + } - if heap.initial_size > heap.reserved_size { - return Err(lucet_incorrect_module!( - "initial heap size greater than reserved size: {:?}", - heap - )); + if heap.initial_size > heap.reserved_size { + return Err(lucet_incorrect_module!( + "initial heap size greater than reserved size: {:?}", + heap + )); + } } if self.globals().len() * std::mem::size_of::() > limits.globals_size { diff --git a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs index 3991e06bb..4ab668f41 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs @@ -103,7 +103,7 @@ impl DlModule { impl Module for DlModule {} impl ModuleInternal for DlModule { - fn heap_spec(&self) -> &HeapSpec { + fn heap_spec(&self) -> Option<&HeapSpec> { self.module_data.heap_spec() } @@ -112,11 +112,15 @@ impl ModuleInternal for DlModule { } fn get_sparse_page_data(&self, page: usize) -> Option<&[u8]> { - *self.module_data.sparse_data().get_page(page) + if let Some(ref sparse_data) = self.module_data.sparse_data() { + *sparse_data.get_page(page) + } else { + None + } } fn sparse_page_data_len(&self) -> usize { - self.module_data.sparse_data().len() + self.module_data.sparse_data().map(|d| d.len()).unwrap_or(0) } fn table_elements(&self) -> Result<&[TableElement], Error> { @@ -131,18 +135,10 @@ impl ModuleInternal for DlModule { })? }; let len = unsafe { **p_table_segment_len }; - let elem_size = mem::size_of::(); - if len > std::u32::MAX as usize * elem_size { + if len > std::u32::MAX as usize { lucet_incorrect_module!("table segment too long: {}", len); } - if len % elem_size != 0 { - lucet_incorrect_module!( - "table segment length {} not a multiple of table element size: {}", - len, - elem_size - ); - } - Ok(unsafe { from_raw_parts(*p_table_segment, **p_table_segment_len as usize / elem_size) }) + Ok(unsafe { from_raw_parts(*p_table_segment, **p_table_segment_len as usize) }) } fn get_export_func(&self, sym: &[u8]) -> Result<*const extern "C" fn(), Error> { diff --git a/lucet-runtime/lucet-runtime-internals/src/module/mock.rs b/lucet-runtime/lucet-runtime-internals/src/module/mock.rs index 08e567371..ed1034d77 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/mock.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/mock.rs @@ -3,7 +3,9 @@ use crate::module::{ AddrDetails, GlobalSpec, HeapSpec, Module, ModuleInternal, TableElement, TrapManifestRecord, }; use libc::c_void; -use lucet_module_data::owned::{OwnedGlobalSpec, OwnedModuleData, OwnedSparseData}; +use lucet_module_data::owned::{ + OwnedGlobalSpec, OwnedLinearMemorySpec, OwnedModuleData, OwnedSparseData, +}; use lucet_module_data::ModuleData; use std::collections::{BTreeMap, HashMap}; use std::sync::Arc; @@ -155,8 +157,11 @@ impl MockModuleBuilder { }) .collect(); let owned_module_data = OwnedModuleData::new( - self.heap_spec, - OwnedSparseData::new(self.sparse_page_data).expect("sparse data pages are valid"), + Some(OwnedLinearMemorySpec { + heap: self.heap_spec, + initializer: OwnedSparseData::new(self.sparse_page_data) + .expect("sparse data pages are valid"), + }), globals_spec, ); let serialized_module_data = owned_module_data @@ -196,7 +201,7 @@ unsafe impl Sync for MockModule {} impl Module for MockModule {} impl ModuleInternal for MockModule { - fn heap_spec(&self) -> &HeapSpec { + fn heap_spec(&self) -> Option<&HeapSpec> { self.module_data.heap_spec() } @@ -205,11 +210,15 @@ impl ModuleInternal for MockModule { } fn get_sparse_page_data(&self, page: usize) -> Option<&[u8]> { - *self.module_data.sparse_data().get_page(page) + if let Some(ref sparse_data) = self.module_data.sparse_data() { + *sparse_data.get_page(page) + } else { + None + } } fn sparse_page_data_len(&self) -> usize { - self.module_data.sparse_data().len() + self.module_data.sparse_data().map(|d| d.len()).unwrap_or(0) } fn table_elements(&self) -> Result<&[TableElement], Error> { diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs index 8e6d92c39..7a39ba845 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs @@ -131,10 +131,13 @@ impl RegionInternal for MmapRegion { } } - let initial_size = module.heap_spec().initial_size as usize; + let initial_size = module + .heap_spec() + .map(|h| h.initial_size as usize) + .unwrap_or(0); // reset the heap to the initial size, and mprotect those pages appropriately - if alloc.heap_accessible_size != initial_size { + if initial_size > 0 { unsafe { mprotect( heap, @@ -142,10 +145,9 @@ impl RegionInternal for MmapRegion { ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, )? }; - alloc.heap_accessible_size = initial_size; - alloc.heap_inaccessible_size = - alloc.slot().limits.heap_address_space_size - initial_size; } + alloc.heap_accessible_size = initial_size; + alloc.heap_inaccessible_size = alloc.slot().limits.heap_address_space_size - initial_size; // Initialize the heap using the module sparse page data. There cannot be more pages in the // sparse page data than will fit in the initial heap size. diff --git a/lucet-runtime/lucet-runtime-internals/src/trapcode.rs b/lucet-runtime/lucet-runtime-internals/src/trapcode.rs index 50c91061b..23cf5dd07 100644 --- a/lucet-runtime/lucet-runtime-internals/src/trapcode.rs +++ b/lucet-runtime/lucet-runtime-internals/src/trapcode.rs @@ -1,40 +1,11 @@ use num_derive::FromPrimitive; use num_traits::FromPrimitive; -/// The details associated with a WebAssembly -/// [trap](http://webassembly.github.io/spec/core/intro/overview.html#trap). -#[derive(Copy, Clone, Debug)] -pub struct TrapCode { - pub ty: TrapCodeType, - /// Mainly for internal testing, this field will likely be deprecated soon. - pub tag: u16, -} - -impl std::fmt::Display for TrapCode { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - if self.ty == TrapCodeType::User { - write!(f, "{:?}({})", self.ty, self.tag) - } else { - write!(f, "{:?}", self.ty) - } - } -} - -impl TrapCode { - pub fn try_from_u32(trapcode_bin: u32) -> Option { - let trapcode_type = (trapcode_bin & 0x0000FFFF) as u16; - TrapCodeType::from_u16(trapcode_type).map(|ty| { - let tag = (trapcode_bin >> 16) as u16; - TrapCode { ty, tag } - }) - } -} - /// The type of a WebAssembly /// [trap](http://webassembly.github.io/spec/core/intro/overview.html#trap). -#[repr(u16)] +#[repr(u32)] #[derive(Copy, Clone, Debug, FromPrimitive, PartialEq)] -pub enum TrapCodeType { +pub enum TrapCode { StackOverflow = 0, HeapOutOfBounds = 1, OutOfBounds = 2, @@ -45,6 +16,11 @@ pub enum TrapCodeType { BadConversionToInteger = 7, Interrupt = 8, TableOutOfBounds = 9, - User = 0xFFFF, - Unknown = 0xFFFE, + Unreachable = 10, +} + +impl TrapCode { + pub fn try_from_u32(v: u32) -> Option { + Self::from_u32(v) + } } diff --git a/lucet-runtime/lucet-runtime-tests/Cargo.toml b/lucet-runtime/lucet-runtime-tests/Cargo.toml index 1efa7aba0..ac72c9a07 100644 --- a/lucet-runtime/lucet-runtime-tests/Cargo.toml +++ b/lucet-runtime/lucet-runtime-tests/Cargo.toml @@ -17,5 +17,6 @@ lucet-runtime-internals = { path = "../lucet-runtime-internals" } lucet-wasi-sdk = { path = "../../lucet-wasi-sdk" } lucetc = { path = "../../lucetc" } + [build-dependencies] cc = "1.0" diff --git a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs index 104f77e02..6e55084bc 100644 --- a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs +++ b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs @@ -119,7 +119,6 @@ macro_rules! guest_fault_tests { use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime::{ DlModule, Error, FaultDetails, Instance, Limits, Region, SignalBehavior, TrapCode, - TrapCodeType, }; use nix::sys::mman::{mmap, MapFlags, ProtFlags}; use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal}; @@ -196,7 +195,7 @@ macro_rules! guest_fault_tests { match inst.run(b"illegal_instr", &[]) { Err(Error::RuntimeFault(details)) => { - assert_eq!(details.trapcode.ty, TrapCodeType::BadSignature); + assert_eq!(details.trapcode, Some(TrapCode::BadSignature)); } res => panic!("unexpected result: {:?}", res), } @@ -220,7 +219,7 @@ macro_rules! guest_fault_tests { match inst.run(b"oob", &[]) { Err(Error::RuntimeFault(details)) => { - assert_eq!(details.trapcode.ty, TrapCodeType::HeapOutOfBounds); + assert_eq!(details.trapcode, Some(TrapCode::HeapOutOfBounds)); } res => panic!("unexpected result: {:?}", res), } @@ -267,7 +266,7 @@ macro_rules! guest_fault_tests { fn fatal_continue_signal_handler() { fn signal_handler_continue( _inst: &Instance, - _trapcode: &TrapCode, + _trapcode: &Option, signum: libc::c_int, _siginfo_ptr: *const siginfo_t, _ucontext_ptr: *const c_void, @@ -314,7 +313,7 @@ macro_rules! guest_fault_tests { fn fatal_terminate_signal_handler() { fn signal_handler_terminate( _inst: &Instance, - _trapcode: &TrapCode, + _trapcode: &Option, signum: libc::c_int, _siginfo_ptr: *const siginfo_t, _ucontext_ptr: *const c_void, @@ -405,7 +404,7 @@ macro_rules! guest_fault_tests { match inst.run(b"illegal_instr", &[]) { Err(Error::RuntimeFault(details)) => { - assert_eq!(details.trapcode.ty, TrapCodeType::BadSignature); + assert_eq!(details.trapcode, Some(TrapCode::BadSignature)); } res => panic!("unexpected result: {:?}", res), } diff --git a/lucet-runtime/lucet-runtime-tests/src/host.rs b/lucet-runtime/lucet-runtime-tests/src/host.rs index 635c50d6f..8f833b377 100644 --- a/lucet-runtime/lucet-runtime-tests/src/host.rs +++ b/lucet-runtime/lucet-runtime-tests/src/host.rs @@ -3,7 +3,7 @@ macro_rules! host_tests { ( $TestRegion:path ) => { use libc::c_void; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; - use lucet_runtime::{DlModule, Error, Limits, Region, TrapCodeType}; + use lucet_runtime::{DlModule, Error, Limits, Region, TrapCode}; use std::sync::Arc; use $TestRegion as TestRegion; use $crate::build::test_module_c; @@ -112,7 +112,7 @@ macro_rules! host_tests { match inst.run(b"trigger_div_error", &[0u64.into()]) { Err(Error::RuntimeFault(details)) => { - assert_eq!(details.trapcode.ty, TrapCodeType::IntegerDivByZero); + assert_eq!(details.trapcode, Some(TrapCode::IntegerDivByZero)); } res => { panic!("unexpected result: {:?}", res); diff --git a/lucet-runtime/lucet-runtime-tests/src/stack.rs b/lucet-runtime/lucet-runtime-tests/src/stack.rs index daa58cff6..3e448918a 100644 --- a/lucet-runtime/lucet-runtime-tests/src/stack.rs +++ b/lucet-runtime/lucet-runtime-tests/src/stack.rs @@ -84,7 +84,7 @@ fn generate_test_wat(num_locals: usize) -> String { macro_rules! stack_tests { ( $TestRegion:path ) => { use lucet_runtime::{ - DlModule, Error, InstanceHandle, Limits, Region, TrapCodeType, UntypedRetVal, Val, + DlModule, Error, InstanceHandle, Limits, Region, TrapCode, UntypedRetVal, Val, }; use std::sync::Arc; use $TestRegion as TestRegion; @@ -108,7 +108,7 @@ macro_rules! stack_tests { Err(Error::RuntimeFault(details)) => { // We should get a nonfatal trap due to the stack overflow. assert_eq!(details.fatal, false); - assert_eq!(details.trapcode.ty, TrapCodeType::StackOverflow); + assert_eq!(details.trapcode, Some(TrapCode::StackOverflow)); if probestack { // Make sure we overflowed in the stack probe as expected // diff --git a/lucet-runtime/src/c_api.rs b/lucet-runtime/src/c_api.rs index 79b0a222c..17e943943 100644 --- a/lucet-runtime/src/c_api.rs +++ b/lucet-runtime/src/c_api.rs @@ -39,6 +39,7 @@ pub extern "C" fn lucet_error_name(e: c_int) -> *const c_char { RegionFull => "lucet_error_region_full\0".as_ptr() as _, Module => "lucet_error_module\0".as_ptr() as _, LimitsExceeded => "lucet_error_limits_exceeded\0".as_ptr() as _, + NoLinearMemory => "lucet_error_no_linear_memory\0".as_ptr() as _, SymbolNotFound => "lucet_error_symbol_not_found\0".as_ptr() as _, FuncNotFound => "lucet_error_func_not_found\0".as_ptr() as _, RuntimeFault => "lucet_error_runtime_fault\0".as_ptr() as _, @@ -293,7 +294,7 @@ pub unsafe extern "C" fn lucet_instance_set_signal_handler( inst: *mut lucet_instance, signal_handler: lucet_signal_handler, ) -> lucet_error { - let handler = move |inst: &Instance, trap: &TrapCode, signum, siginfo, context| { + let handler = move |inst: &Instance, trap: &Option, signum, siginfo, context| { let inst = inst as *const Instance as *mut lucet_instance; let trap = trap.into(); let trap_ptr = &trap as *const lucet_state::lucet_trapcode; diff --git a/lucet-runtime/src/lib.rs b/lucet-runtime/src/lib.rs index 54debbb02..4ffb79505 100644 --- a/lucet-runtime/src/lib.rs +++ b/lucet-runtime/src/lib.rs @@ -152,7 +152,7 @@ //! //! fn signal_handler_count( //! _inst: &Instance, -//! _trapcode: &TrapCode, +//! _trapcode: &Option, //! _signum: libc::c_int, //! _siginfo_ptr: *const libc::siginfo_t, //! _ucontext_ptr: *const libc::c_void, @@ -205,7 +205,7 @@ pub use lucet_runtime_internals::instance::{ pub use lucet_runtime_internals::module::{DlModule, Module}; pub use lucet_runtime_internals::region::mmap::MmapRegion; pub use lucet_runtime_internals::region::{InstanceBuilder, Region, RegionCreate}; -pub use lucet_runtime_internals::trapcode::{TrapCode, TrapCodeType}; +pub use lucet_runtime_internals::trapcode::TrapCode; pub use lucet_runtime_internals::val::{UntypedRetVal, Val}; pub use lucet_runtime_internals::WASM_PAGE_SIZE; diff --git a/lucet-spectest/Cargo.toml b/lucet-spectest/Cargo.toml index 86ee785eb..c7c8f15c9 100644 --- a/lucet-spectest/Cargo.toml +++ b/lucet-spectest/Cargo.toml @@ -17,7 +17,6 @@ path = "src/main.rs" [dependencies] lucetc = { path = "../lucetc" } lucet-runtime = { path = "../lucet-runtime" } -parity-wasm = "0.35" wabt = "0.7" serde = "1.0" serde_json = "1.0" diff --git a/lucet-spectest/src/bindings.rs b/lucet-spectest/src/bindings.rs index 8a0fe06d3..51b65c9cc 100644 --- a/lucet-spectest/src/bindings.rs +++ b/lucet-spectest/src/bindings.rs @@ -1,4 +1,4 @@ -use lucetc::bindings::Bindings; +use lucetc::Bindings; use serde_json::json; pub fn spec_test_bindings() -> Bindings { diff --git a/lucet-spectest/src/instance.rs b/lucet-spectest/src/instance.rs deleted file mode 100644 index d91650719..000000000 --- a/lucet-spectest/src/instance.rs +++ /dev/null @@ -1,113 +0,0 @@ -use failure::{format_err, Error}; -use lucet_runtime::{ - Error as RuntimeError, Module as LucetModule, Region as LucetRegion, UntypedRetVal, Val, -}; -use lucetc::program::Program; -pub use parity_wasm::elements::ValueType; -use parity_wasm::elements::{Internal, Type}; -use std::sync::Arc; - -// some of the fields of this are not used, but they need to be stored -// because lifetimes -#[allow(dead_code)] -pub struct Instance { - program: Program, - lucet_module: Arc, - lucet_region: Arc, - lucet_instance: lucet_runtime::InstanceHandle, -} - -impl Instance { - pub fn new( - program: Program, - lucet_module: Arc, - lucet_region: Arc, - lucet_instance: lucet_runtime::InstanceHandle, - ) -> Self { - Self { - program, - lucet_module, - lucet_region, - lucet_instance, - } - } - - pub fn run(&mut self, field: &str, args: &[Val]) -> Result { - let res = self.lucet_instance.run(field.as_bytes(), args); - if let Err(_) = res { - self.lucet_instance - .reset() - .expect("possible to reset instance"); - } - res - } - - pub fn type_of(&self, field: &str) -> Result { - if let Some(ref export_section) = self.program.module().export_section() { - export_section - .entries() - .iter() - .find(|entry| entry.field() == field) - .map(|entry| match entry.internal() { - Internal::Function(func_ix) => self.func_type(*func_ix), - Internal::Global(global_ix) => self.global_type(*global_ix), - _ => Err(format_err!( - "cannot take type of export \"{}\": {:?}", - field, - entry.internal() - ))?, - }) - .ok_or_else(|| format_err!("cannot find export named \"{}\"", field))? - } else { - Err(format_err!("no exports to find \"{}\" in", field)) - } - } - - fn func_type(&self, func_ix: u32) -> Result { - if let Some(func_section) = self.program.module().function_section() { - if let Some(func_entry) = func_section.entries().get(func_ix as usize) { - if let Some(type_section) = self.program.module().type_section() { - if let Some(Type::Function(func_type)) = - type_section.types().get(func_entry.type_ref() as usize) - { - Ok(ExportType::Function( - func_type.params().to_vec(), - func_type.return_type(), - )) - } else { - Err(format_err!( - "type ix {} out of bounds", - func_entry.type_ref() - )) - } - } else { - Err(format_err!("no type section!")) - } - } else { - Err(format_err!("func ix {} out of bounds", func_ix)) - } - } else { - Err(format_err!("no func section!")) - } - } - - fn global_type(&self, global_ix: u32) -> Result { - if let Some(global_section) = self.program.module().global_section() { - if let Some(global_entry) = global_section.entries().get(global_ix as usize) { - Ok(ExportType::Global( - global_entry.global_type().content_type(), - )) - } else { - Err(format_err!("no such global {}", global_ix)) - } - } else { - Err(format_err!("no section to find global {}", global_ix)) - } - } -} - -#[derive(Debug)] -pub enum ExportType { - Function(Vec, Option), - Global(ValueType), -} diff --git a/lucet-spectest/src/lib.rs b/lucet-spectest/src/lib.rs index 307388b2e..f555349a9 100644 --- a/lucet-spectest/src/lib.rs +++ b/lucet-spectest/src/lib.rs @@ -1,5 +1,4 @@ pub mod error; -pub mod instance; pub mod script; pub use crate::error::{SpecTestError, SpecTestErrorKind}; @@ -8,10 +7,9 @@ pub use crate::result::{command_description, SpecScriptResult}; mod bindings; mod result; -use crate::instance::{ExportType, ValueType}; use crate::script::{ScriptEnv, ScriptError}; use failure::{format_err, Error, ResultExt}; -use lucet_runtime::{Error as RuntimeError, TrapCodeType, UntypedRetVal, Val}; +use lucet_runtime::{Error as RuntimeError, TrapCode, UntypedRetVal, Val}; use std::fs; use std::path::PathBuf; use wabt::script::{Action, CommandKind, ScriptParser, Value}; @@ -28,9 +26,13 @@ pub fn run_spec_test(spec_path: &PathBuf) -> Result { Ok(()) => res.pass(cmd), Err(e) => match e.get_context() { SpecTestErrorKind::UnsupportedCommand | SpecTestErrorKind::UnsupportedLucetc => { + println!("skipped unsupported command"); res.skip(cmd, e) } - _ => res.fail(cmd, e), + _ => { + println!("command failed"); + res.fail(cmd, e) + } }, } } @@ -38,61 +40,72 @@ pub fn run_spec_test(spec_path: &PathBuf) -> Result { Ok(res) } +fn unexpected_failure(e: ScriptError) -> SpecTestError { + if e.unsupported() { + Error::from(e) + .context(SpecTestErrorKind::UnsupportedLucetc) + .into() + } else { + Error::from(e) + .context(SpecTestErrorKind::UnexpectedFailure) + .into() + } +} + fn step(script: &mut ScriptEnv, cmd: &CommandKind) -> Result<(), SpecTestError> { match cmd { CommandKind::Module { ref module, ref name, } => { + println!("module {:?}", name); let module = module.clone().into_vec(); - script.instantiate(module, name).map_err(|e| { - if e.unsupported() { - Error::from(e).context(SpecTestErrorKind::UnsupportedLucetc) - } else { - Error::from(e).context(SpecTestErrorKind::UnexpectedFailure) - } - })?; + script + .instantiate(&module, name) + .map_err(unexpected_failure)?; Ok(()) } CommandKind::AssertInvalid { ref module, .. } => { + println!("assert_invalid"); let module = module.clone().into_vec(); - match script.instantiate(module, &None) { + match script.instantiate(&module, &None) { Err(ScriptError::ValidationError(_)) => Ok(()), Ok(_) => { script.delete_last(); Err(SpecTestErrorKind::UnexpectedSuccess)? } - Err(e) => Err(Error::from(e).context(SpecTestErrorKind::UnexpectedFailure))?, + Err(e) => Err(unexpected_failure(e))?, } } CommandKind::AssertMalformed { ref module, .. } => { + println!("assert_malformed"); let module = module.clone().into_vec(); - match script.instantiate(module, &None) { - Err(ScriptError::DeserializeError(_)) | Err(ScriptError::ValidationError(_)) => { - Ok(()) - } + match script.instantiate(&module, &None) { + Err(ScriptError::ValidationError(_)) => Ok(()), Ok(_) => Err(SpecTestErrorKind::UnexpectedSuccess)?, - Err(e) => Err(Error::from(e).context(SpecTestErrorKind::UnexpectedFailure))?, + Err(e) => Err(unexpected_failure(e))?, } } CommandKind::AssertUninstantiable { module, .. } => { + println!("assert_uninstantiable"); let module = module.clone().into_vec(); - match script.instantiate(module, &None) { - Err(ScriptError::DeserializeError(_)) => Ok(()), // XXX This is probably the wrong ScriptError to look for - FIXME + match script.instantiate(&module, &None) { + Err(ScriptError::InstantiateError(_)) => Ok(()), Ok(_) => Err(SpecTestErrorKind::UnexpectedSuccess)?, - Err(e) => Err(Error::from(e).context(SpecTestErrorKind::UnexpectedFailure))?, + Err(e) => Err(unexpected_failure(e))?, } } CommandKind::AssertUnlinkable { module, .. } => { + println!("assert_unlinkable"); let module = module.clone().into_vec(); - match script.instantiate(module, &None) { - Err(ScriptError::CompileError(_)) => Ok(()), // XXX could other errors trigger this too? + match script.instantiate(&module, &None) { + Err(ScriptError::ValidationError(_)) => Ok(()), Ok(_) => Err(SpecTestErrorKind::UnexpectedSuccess)?, - Err(e) => Err(Error::from(e).context(SpecTestErrorKind::UnexpectedFailure))?, + Err(e) => Err(unexpected_failure(e))?, } } @@ -100,9 +113,8 @@ fn step(script: &mut ScriptEnv, cmd: &CommandKind) -> Result<(), SpecTestError> ref name, ref as_name, } => { - script - .register(name, as_name) - .context(SpecTestErrorKind::UnexpectedFailure)?; + println!("register {:?} {}", name, as_name); + script.register(name, as_name).map_err(unexpected_failure)?; Ok(()) } @@ -112,10 +124,11 @@ fn step(script: &mut ScriptEnv, cmd: &CommandKind) -> Result<(), SpecTestError> ref field, ref args, } => { + println!("invoke {:?} {} {:?}", module, field, args); let args = translate_args(args); let _res = script .run(module, field, args) - .context(SpecTestErrorKind::UnexpectedFailure)?; + .map_err(unexpected_failure)?; Ok(()) } _ => Err(SpecTestErrorKind::UnsupportedCommand)?, @@ -127,14 +140,15 @@ fn step(script: &mut ScriptEnv, cmd: &CommandKind) -> Result<(), SpecTestError> ref field, ref args, } => { + println!("assert_exhaustion {:?} {} {:?}", module, field, args); let args = translate_args(args); let res = script.run(module, field, args); match res { Ok(_) => Err(SpecTestErrorKind::UnexpectedSuccess)?, Err(ScriptError::RuntimeError(RuntimeError::RuntimeFault(details))) => { - match details.trapcode.ty { - TrapCodeType::StackOverflow => Ok(()), + match details.trapcode { + Some(TrapCode::StackOverflow) => Ok(()), e => Err(format_err!( "AssertExhaustion expects stack overflow, got {:?}", e @@ -143,7 +157,7 @@ fn step(script: &mut ScriptEnv, cmd: &CommandKind) -> Result<(), SpecTestError> } } - Err(e) => Err(Error::from(e).context(SpecTestErrorKind::UnexpectedFailure))?, + Err(e) => Err(unexpected_failure(e))?, } } _ => Err(SpecTestErrorKind::UnsupportedCommand)?, @@ -158,10 +172,14 @@ fn step(script: &mut ScriptEnv, cmd: &CommandKind) -> Result<(), SpecTestError> ref field, ref args, } => { + println!( + "assert_return (invoke {:?} {} {:?}) {:?}", + module, field, args, expected + ); let args = translate_args(args); let res = script .run(module, field, args) - .context(SpecTestErrorKind::UnexpectedFailure)?; + .map_err(unexpected_failure)?; check_retval(expected, res)?; Ok(()) } @@ -175,37 +193,16 @@ fn step(script: &mut ScriptEnv, cmd: &CommandKind) -> Result<(), SpecTestError> ref field, ref args, } => { + println!("assert_nan"); let args = translate_args(args); let res = script .run(module, field, args) - .context(SpecTestErrorKind::UnexpectedFailure)?; - let res_type = script - .instance_named(module) - .expect("just used that instance") - .type_of(field) - .expect("field has type"); - match res_type { - ExportType::Function(_, Some(ValueType::F32)) => { - if res.as_f32().is_nan() { - Ok(()) - } else { - Err(format_err!("expected NaN, got {}", res.as_f32())) - .context(SpecTestErrorKind::IncorrectResult)? - } - } - ExportType::Function(_, Some(ValueType::F64)) => { - if res.as_f64().is_nan() { - Ok(()) - } else { - Err(format_err!("expected NaN, got {}", res.as_f64())) - .context(SpecTestErrorKind::IncorrectResult)? - } - } - _ => Err(format_err!( - "expected a function returning point, got {:?}", - res_type - )) - .context(SpecTestErrorKind::UnexpectedFailure)?, + .map_err(unexpected_failure)?; + if res.as_f32().is_nan() || res.as_f64().is_nan() { + Ok(()) + } else { + Err(format_err!("expected NaN, got {}", res)) + .context(SpecTestErrorKind::IncorrectResult)? } } _ => Err(format_err!("non-invoke action")) @@ -217,11 +214,12 @@ fn step(script: &mut ScriptEnv, cmd: &CommandKind) -> Result<(), SpecTestError> field, args, } => { + println!("assert_trap (invoke {:?} {} {:?})", module, field, args); let args = translate_args(args); let res = script.run(module, field, args); match res { Err(ScriptError::RuntimeError(_luceterror)) => Ok(()), - Err(e) => Err(Error::from(e).context(SpecTestErrorKind::UnexpectedFailure))?, + Err(e) => Err(unexpected_failure(e)), Ok(_) => Err(SpecTestErrorKind::UnexpectedSuccess)?, } } diff --git a/lucet-spectest/src/script.rs b/lucet-spectest/src/script.rs index 16821bdc8..3fea710f0 100644 --- a/lucet-spectest/src/script.rs +++ b/lucet-spectest/src/script.rs @@ -1,22 +1,13 @@ use crate::bindings; -use crate::instance::Instance; use failure::{format_err, Error, Fail}; use lucet_runtime::{self, MmapRegion, Module as LucetModule, Region, UntypedRetVal, Val}; -use lucetc::{ - compile, - compiler::OptLevel, - error::{LucetcError, LucetcErrorKind}, - program::{HeapSettings, Program}, -}; -use parity_wasm::{self, deserialize_buffer}; +use lucetc::{Compiler, HeapSettings, LucetcError, LucetcErrorKind, OptLevel}; use std::io; use std::process::Command; use std::sync::Arc; #[derive(Fail, Debug)] pub enum ScriptError { - #[fail(display = "Deserialization error: {}", _0)] - DeserializeError(parity_wasm::elements::Error), #[fail(display = "Validation error: {}", _0)] ValidationError(LucetcError), #[fail(display = "Program creation error: {}", _0)] @@ -41,8 +32,9 @@ impl ScriptError { pub fn unsupported(&self) -> bool { match self { ScriptError::ProgramError(ref lucetc_err) + | ScriptError::ValidationError(ref lucetc_err) | ScriptError::CompileError(ref lucetc_err) => match lucetc_err.get_context() { - &LucetcErrorKind::Unsupported(_) => true, + &LucetcErrorKind::Unsupported => true, _ => false, }, _ => false, @@ -57,7 +49,7 @@ impl From for ScriptError { } pub struct ScriptEnv { - instances: Vec<(Option, Instance)>, + instances: Vec<(Option, lucet_runtime::InstanceHandle)>, } fn program_error(e: LucetcError) -> ScriptError { @@ -73,36 +65,20 @@ impl ScriptEnv { instances: Vec::new(), } } - pub fn instantiate( - &mut self, - module: Vec, - name: &Option, - ) -> Result<(), ScriptError> { + pub fn instantiate(&mut self, module: &[u8], name: &Option) -> Result<(), ScriptError> { let bindings = bindings::spec_test_bindings(); - - let module = deserialize_buffer(&module).map_err(ScriptError::DeserializeError)?; - - let program = - Program::new(module, bindings, HeapSettings::default()).map_err(program_error)?; + let compiler = Compiler::new(module, OptLevel::Best, &bindings, HeapSettings::default()) + .map_err(program_error)?; let dir = tempfile::Builder::new().prefix("codegen").tempdir()?; let objfile_path = dir.path().join("a.o"); let sofile_path = dir.path().join("a.so"); - { - let compiler = compile( - &program, - &name.clone().unwrap_or("default".to_owned()), - OptLevel::Default, - ) - .map_err(ScriptError::CompileError)?; - - let object = compiler.codegen().map_err(ScriptError::CodegenError)?; - - object - .write(&objfile_path) - .map_err(ScriptError::CodegenError)?; - } + compiler + .object_file() + .map_err(ScriptError::CompileError)? + .write(&objfile_path) + .map_err(ScriptError::CodegenError)?; let mut cmd_ld = Command::new("ld"); cmd_ld.arg(objfile_path.clone()); @@ -121,24 +97,27 @@ impl ScriptEnv { let lucet_module: Arc = lucet_runtime::DlModule::load(sofile_path).map_err(ScriptError::LoadError)?; - let lucet_region = - MmapRegion::create(1, &lucet_runtime::Limits::default()).expect("valid region"); + let lucet_region = MmapRegion::create( + 1, + &lucet_runtime::Limits { + heap_memory_size: 4 * 1024 * 1024 * 1024, + ..lucet_runtime::Limits::default() + }, + ) + .expect("valid region"); let lucet_instance = lucet_region .new_instance(lucet_module.clone()) .map_err(ScriptError::InstantiateError)?; - self.instances.push(( - name.clone(), - Instance::new(program, lucet_module, lucet_region, lucet_instance), - )); + self.instances.push((name.clone(), lucet_instance)); Ok(()) } fn instance_named_mut( &mut self, name: &Option, - ) -> Result<&mut (Option, Instance), ScriptError> { + ) -> Result<&mut (Option, lucet_runtime::InstanceHandle), ScriptError> { Ok(match name { // None means the last defined module should be used None => self @@ -153,7 +132,10 @@ impl ScriptEnv { }) } - pub fn instance_named(&self, name: &Option) -> Result<&Instance, ScriptError> { + pub fn instance_named( + &self, + name: &Option, + ) -> Result<&lucet_runtime::InstanceHandle, ScriptError> { Ok(match name { // None means the last defined module should be used None => self @@ -177,7 +159,7 @@ impl ScriptEnv { args: Vec, ) -> Result { let (_, ref mut inst) = self.instance_named_mut(name)?; - inst.run(&field, &args) + inst.run(field.as_bytes(), &args) .map_err(|e| ScriptError::RuntimeError(e)) } diff --git a/lucet-spectest/tests/wasm-spec.rs b/lucet-spectest/tests/wasm-spec.rs index d4a49baf2..29403c558 100644 --- a/lucet-spectest/tests/wasm-spec.rs +++ b/lucet-spectest/tests/wasm-spec.rs @@ -35,7 +35,7 @@ core_spec_test!(break_drop, "break-drop"); // PASS core_spec_test!(br_if); // PASS core_spec_test!(br_table); // PASS core_spec_test!(br); // PASS -core_spec_test!(call_indirect); // FAIL: BadSignature runtime error in AssertReturn +core_spec_test!(call_indirect); // FAIL: BadSignature runtime error in AssertReturn. BUG: we check type index equality, but the same type may exist at multiple indexes. core_spec_test!(call); // PASS core_spec_test!(comments); // PASS core_spec_test!(const_, "const"); // PASS @@ -76,14 +76,15 @@ core_spec_test!(memory_grow); // FAIL but i think its because a test asked for 4 core_spec_test!(memory_redundancy); // PASS core_spec_test!(memory_trap); // FAIL incorrect result core_spec_test!(memory); // FAIL panic related to heap guard -core_spec_test!(names); // FAIL lots of symbol not found errors + // too noisy to keep enabled: + // core_spec_test!(names); // FAIL hundreds of errors because we dont support unicode names yet. core_spec_test!(nop); // PASS core_spec_test!(return_, "return"); // PASS core_spec_test!(select); // PASS core_spec_test!(set_local); // PASS core_spec_test!(skip_stack_guard_page, "skip-stack-guard-page"); // PASS but takes over 1 minute core_spec_test!(stack); // PASS -core_spec_test!(start); // FAIL we dont support start functions yet, so results are incorrect +core_spec_test!(start); // FAIL imports print functions core_spec_test!(store_retval); // PASS core_spec_test!(switch); // PASS core_spec_test!(tee_local); // PASS diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index 67bfa74af..c6f16a360 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -15,17 +15,18 @@ name = "lucetc" path = "src/main.rs" [dependencies] -lucet-module-data = { path = "../lucet-module-data" } -clap="2.32" -log = "0.4" -env_logger = "0.6" -parity-wasm = "0.35" cranelift-codegen = { path = "../cranelift/cranelift-codegen" } cranelift-native = { path = "../cranelift/cranelift-native" } cranelift-frontend = { path = "../cranelift/cranelift-frontend" } cranelift-module = { path = "../cranelift/cranelift-module" } cranelift-faerie = { path = "../cranelift/cranelift-faerie" } -target-lexicon = "0.2" +cranelift-wasm = { path = "../cranelift/cranelift-wasm" } +target-lexicon = "0.3" +lucet-module-data = { path = "../lucet-module-data" } +wasmparser = "0.23" +clap="2.32" +log = "0.4" +env_logger = "0.6" faerie = "0.9.1" failure = "0.1" serde = "1.0" @@ -34,9 +35,9 @@ byteorder = "1.2" wasmonkey = { path = "../lucet-builtins/wasmonkey" } wabt = "0.7" tempfile = "3.0" -bimap = "0.1" -pwasm-validation = { path = "../pwasm-validation" } +bimap = "0.2" human-size = "0.4" +parity-wasm = "0.35" [dev-dependencies] lucet-wasi-sdk = { path = "../lucet-wasi-sdk" } diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs new file mode 100644 index 000000000..87927a1ec --- /dev/null +++ b/lucetc/src/compiler.rs @@ -0,0 +1,245 @@ +use crate::bindings::Bindings; +use crate::decls::ModuleDecls; +use crate::error::{LucetcError, LucetcErrorKind}; +use crate::function::FuncInfo; +use crate::heap::HeapSettings; +use crate::module::ModuleInfo; +use crate::output::{CraneliftFuncs, ObjectFile}; +use crate::runtime::Runtime; +use crate::stack_probe; +use crate::table::write_table_data; +use cranelift_codegen::{ + ir, + isa::TargetIsa, + settings::{self, Configurable}, + Context as ClifContext, +}; +use cranelift_faerie::{FaerieBackend, FaerieBuilder, FaerieTrapCollection}; +use cranelift_module::{Backend as ClifBackend, Module as ClifModule}; +use cranelift_native; +use cranelift_wasm::{translate_module, FuncTranslator, WasmError}; +use failure::{format_err, Fail, ResultExt}; +use lucet_module_data::ModuleData; + +#[derive(Debug, Clone, Copy)] +pub enum OptLevel { + Default, + Best, + Fastest, +} + +impl Default for OptLevel { + fn default() -> OptLevel { + OptLevel::Default + } +} + +impl OptLevel { + pub fn to_flag(&self) -> &str { + match self { + OptLevel::Default => "default", + OptLevel::Best => "best", + OptLevel::Fastest => "fastest", + } + } +} + +pub struct Compiler<'a> { + decls: ModuleDecls<'a>, + clif_module: ClifModule, + opt_level: OptLevel, +} + +impl<'a> Compiler<'a> { + pub fn new( + wasm_binary: &'a [u8], + opt_level: OptLevel, + bindings: &Bindings, + heap_settings: HeapSettings, + ) -> Result { + let isa = Self::target_isa(opt_level); + + let frontend_config = isa.frontend_config(); + let mut module_info = ModuleInfo::new(frontend_config.clone()); + + // As of cranelift-wasm 0.29, which uses wasmparser 0.23, the parser used inside + // cranelift-wasm does not validate. We need to run the validating parser on the binary + // first. The InvalidWebAssembly error below will never trigger. + use wasmparser::validate; + if !validate(wasm_binary, None) { + Err(format_err!("wasmparser validation rejected module")) + .context(LucetcErrorKind::Validation)?; + } + + translate_module(wasm_binary, &mut module_info).map_err(|e| match e { + WasmError::InvalidWebAssembly { .. } => e.context(LucetcErrorKind::Validation), // This will trigger once cranelift-wasm upgrades to a validating wasm parser. + WasmError::Unsupported { .. } => e.context(LucetcErrorKind::Unsupported), + WasmError::ImplLimitExceeded { .. } => e.context(LucetcErrorKind::TranslatingModule), + })?; + + let libcalls = Box::new(move |libcall| match libcall { + ir::LibCall::Probestack => stack_probe::STACK_PROBE_SYM.to_owned(), + _ => (FaerieBuilder::default_libcall_names())(libcall), + }); + + let mut clif_module: ClifModule = ClifModule::new( + FaerieBuilder::new( + isa, + "lucet_guest".to_owned(), + FaerieTrapCollection::Enabled, + libcalls, + ) + .context(LucetcErrorKind::Validation)?, + ); + + let runtime = Runtime::lucet(frontend_config); + let decls = ModuleDecls::new( + module_info, + &mut clif_module, + bindings, + runtime, + heap_settings, + )?; + + Ok(Self { + decls, + clif_module, + opt_level, + }) + } + + pub fn module_data(&self) -> ModuleData { + self.decls.get_module_data() + } + + pub fn object_file(mut self) -> Result { + let mut func_translator = FuncTranslator::new(); + + for (ref func, (code, code_offset)) in self.decls.function_bodies() { + let mut func_info = FuncInfo::new(&self.decls); + let mut clif_context = ClifContext::new(); + clif_context.func.name = func.name.as_externalname(); + clif_context.func.signature = func.signature.clone(); + + func_translator + .translate(code, *code_offset, &mut clif_context.func, &mut func_info) + .map_err(|e| format_err!("in {}: {:?}", func.name.symbol(), e)) + .context(LucetcErrorKind::FunctionTranslation)?; + + self.clif_module + .define_function(func.name.as_funcid().unwrap(), &mut clif_context) + .map_err(|e| format_err!("in {}: {:?}", func.name.symbol(), e)) + .context(LucetcErrorKind::FunctionDefinition)?; + } + + write_module_data(&mut self.clif_module, &self.decls)?; + write_startfunc_data(&mut self.clif_module, &self.decls)?; + write_table_data(&mut self.clif_module, &self.decls)?; + + let obj = ObjectFile::new(self.clif_module.finish()).context(LucetcErrorKind::Output)?; + Ok(obj) + } + + pub fn cranelift_funcs(self) -> Result { + use std::collections::HashMap; + + let mut funcs = HashMap::new(); + let mut func_translator = FuncTranslator::new(); + + for (ref func, (code, code_offset)) in self.decls.function_bodies() { + let mut func_info = FuncInfo::new(&self.decls); + let mut clif_context = ClifContext::new(); + clif_context.func.name = func.name.as_externalname(); + clif_context.func.signature = func.signature.clone(); + + func_translator + .translate(code, *code_offset, &mut clif_context.func, &mut func_info) + .map_err(|e| format_err!("in {}: {:?}", func.name.symbol(), e)) + .context(LucetcErrorKind::FunctionTranslation)?; + + funcs.insert(func.name.clone(), clif_context.func); + } + Ok(CraneliftFuncs::new(funcs, Self::target_isa(self.opt_level))) + } + + fn target_isa(opt_level: OptLevel) -> Box { + let mut flags_builder = settings::builder(); + let isa_builder = + cranelift_native::builder().expect("host machine is not a supported target"); + flags_builder.enable("enable_verifier").unwrap(); + flags_builder.enable("is_pic").unwrap(); + flags_builder.set("opt_level", opt_level.to_flag()).unwrap(); + isa_builder.finish(settings::Flags::new(flags_builder)) + } +} + +fn write_module_data( + clif_module: &mut ClifModule, + decls: &ModuleDecls, +) -> Result<(), LucetcError> { + use byteorder::{LittleEndian, WriteBytesExt}; + use cranelift_module::{DataContext, Linkage}; + + let module_data_serialized: Vec = decls + .get_module_data() + .serialize() + .context(LucetcErrorKind::ModuleData)?; + { + let mut serialized_len: Vec = Vec::new(); + serialized_len + .write_u32::(module_data_serialized.len() as u32) + .unwrap(); + let mut data_len_ctx = DataContext::new(); + data_len_ctx.define(serialized_len.into_boxed_slice()); + + let data_len_decl = clif_module + .declare_data("lucet_module_data_len", Linkage::Export, false) + .context(LucetcErrorKind::ModuleData)?; + clif_module + .define_data(data_len_decl, &data_len_ctx) + .context(LucetcErrorKind::ModuleData)?; + } + + { + let mut module_data_ctx = DataContext::new(); + module_data_ctx.define(module_data_serialized.into_boxed_slice()); + + let module_data_decl = clif_module + .declare_data("lucet_module_data", Linkage::Export, true) + .context(LucetcErrorKind::ModuleData)?; + clif_module + .define_data(module_data_decl, &module_data_ctx) + .context(LucetcErrorKind::ModuleData)?; + } + Ok(()) +} + +fn write_startfunc_data( + clif_module: &mut ClifModule, + decls: &ModuleDecls, +) -> Result<(), LucetcError> { + use cranelift_module::{DataContext, Linkage}; + + let error_kind = LucetcErrorKind::MetadataSerializer; + + if let Some(func_ix) = decls.get_start_func() { + let name = clif_module + .declare_data("guest_start", Linkage::Export, false) + .context(error_kind.clone())?; + let mut ctx = DataContext::new(); + ctx.define_zeroinit(8); + + let start_func = decls + .get_func(func_ix) + .expect("start func is valid func id"); + let fid = start_func + .name + .as_funcid() + .ok_or(format_err!("start index pointed to a non-function")) + .context(error_kind.clone())?; + let fref = clif_module.declare_func_in_data(fid, &mut ctx); + ctx.write_function_addr(0, fref); + clif_module.define_data(name, &ctx).context(error_kind)?; + } + Ok(()) +} diff --git a/lucetc/src/compiler/data.rs b/lucetc/src/compiler/data.rs deleted file mode 100644 index 240c60ced..000000000 --- a/lucetc/src/compiler/data.rs +++ /dev/null @@ -1,125 +0,0 @@ -use crate::compiler::Compiler; -use byteorder::{LittleEndian, WriteBytesExt}; -use cranelift_module::{DataContext, Linkage}; -use failure::Error; - -/// Formats and stores WASM data segment initializers[0] from the program to -/// symbols in the data section of obj. -/// -/// - The segment initialization data is stored to the "wasm_data_segment" -/// symbol -/// - The total number of bytes stored to "wasm_data_segment" symbol is -/// stored in the "wasm_data_segment_length" symbol -/// -/// The program that consumes the resulting ELF object is responsible for -/// using it to initialize WASM linear memory regions. -/// -/// [0] https://webassembly.github.io/spec/core/syntax/modules.html#data-segments -/// -/// WARNING: At present, this code -/// - Does limited validation of data segments -/// - Does not coalesce data segments -/// - Uses an implicit data format for the serialized segment data, defined -/// only in the code below -pub fn compile_data_initializers(compiler: &mut Compiler) -> Result<(), Error> { - let mut serialized: Vec = Vec::new(); - - for initializer in compiler.prog.data_initializers()? { - // Data segment has been validated in program::data. - // memory_index is always 0 per spec, so we dont put it in data. - let memory_index: u32 = 0; - serialized.write_u32::(memory_index).unwrap(); - serialized - .write_u32::(initializer.offset) - .unwrap(); - serialized - .write_u32::(initializer.data.len() as u32) - .unwrap(); - serialized.extend_from_slice(initializer.data); - - // Pad to 8 bytes: this aligns the data for architectures with 4 or - // 8 byte word sizes (i.e. everything we are likely to support at - // least until we replaced this with an engineered serialization - // format) - - let pad = vec![0u8; (8 - serialized.len() % 8) % 8]; - serialized.extend(pad); - } - - let mut serialized_len: Vec = Vec::new(); - serialized_len - .write_u32::(serialized.len() as u32) - .unwrap(); - let mut seg_len_ctx = DataContext::new(); - seg_len_ctx.define(serialized_len.into_boxed_slice()); - - let writeable = false; - let seg_len_decl = - compiler - .module - .declare_data("wasm_data_segments_len", Linkage::Export, writeable)?; - compiler.module.define_data(seg_len_decl, &seg_len_ctx)?; - - let mut seg_ctx = DataContext::new(); - seg_ctx.define(serialized.into_boxed_slice()); - let seg_decl = - compiler - .module - .declare_data("wasm_data_segments", Linkage::Export, writeable)?; - compiler.module.define_data(seg_decl, &seg_ctx)?; - - Ok(()) -} - -use std::io::Cursor; - -pub fn compile_sparse_page_data(compiler: &mut Compiler) -> Result<(), Error> { - use crate::program::data::sparse::OwnedSparseData; - let owned_data = OwnedSparseData::new( - &compiler.prog.data_initializers()?, - compiler.prog.heap_spec()?, - ); - let sparse_data = owned_data.sparse_data(); - - let mut table_ctx = DataContext::new(); - let mut table_data: Cursor> = - Cursor::new(Vec::with_capacity(sparse_data.pages().len() * 8 + 8)); - - // The table is an array of 64-bit elements: - // [0] the number subsequent elements - // [1..] a pointer to a 4096-byte array of the contents of the page, - // or null if it is initialized as zero. - - table_data - .write_u64::(sparse_data.pages().len() as u64) - .unwrap(); - for (dix, d) in sparse_data.pages().iter().enumerate() { - if let Some(vs) = d { - // Define the 4096-byte array for the contents of the page - let seg_decl = compiler.module.declare_data( - &format!("guest_sparse_page_data_{}", dix), - Linkage::Local, - false, - )?; - let mut seg_ctx = DataContext::new(); - seg_ctx.define(vs.to_vec().into_boxed_slice()); - compiler.module.define_data(seg_decl, &seg_ctx)?; - - // Put a relocation to that array into the table: - let seg_gv = compiler - .module - .declare_data_in_data(seg_decl, &mut table_ctx); - table_ctx.write_data_addr(table_data.position() as u32, seg_gv, 0); - } - table_data.write_u64::(0)?; - } - - table_ctx.define(table_data.into_inner().into_boxed_slice()); - let table_decl = - compiler - .module - .declare_data("guest_sparse_page_data", Linkage::Export, false)?; - compiler.module.define_data(table_decl, &table_ctx)?; - - Ok(()) -} diff --git a/lucetc/src/compiler/entity/bases.rs b/lucetc/src/compiler/entity/bases.rs deleted file mode 100644 index 47e6e2da7..000000000 --- a/lucetc/src/compiler/entity/bases.rs +++ /dev/null @@ -1,61 +0,0 @@ -use super::POINTER_SIZE; -use crate::compiler::Compiler; -use cranelift_codegen::ir::{self, types::I64, GlobalValueData}; - -// VMContext points directly to the heap (offset 0). -// Directly before the heap is a pointer to the globals (offset -POINTER_SIZE). -const GLOBAL_BASE_OFFSET: i32 = -1 * POINTER_SIZE as i32; - -pub struct GlobalBases { - heap: Option, - globals: Option, - table: Option, -} - -impl GlobalBases { - pub fn new() -> Self { - Self { - heap: None, - globals: None, - table: None, - } - } - - pub fn table(&mut self, func: &mut ir::Function, compiler: &Compiler) -> ir::GlobalValue { - self.table.unwrap_or_else(|| { - let table = &compiler.prog.tables()[0]; - let gv = func.create_global_value(GlobalValueData::Symbol { - name: compiler - .get_table(table) - .expect("table must be declared") - .into(), - offset: 0.into(), // Symbol points directly to table. - colocated: true, - }); - self.table = Some(gv); - gv - }) - } - - pub fn heap(&mut self, func: &mut ir::Function, _compiler: &Compiler) -> ir::GlobalValue { - self.heap.unwrap_or_else(|| { - let gv = func.create_global_value(GlobalValueData::VMContext); - self.heap = Some(gv); - gv - }) - } - - pub fn globals(&mut self, func: &mut ir::Function, _compiler: &Compiler) -> ir::GlobalValue { - self.globals.unwrap_or_else(|| { - let vmctx = func.create_global_value(GlobalValueData::VMContext); - let gv = func.create_global_value(GlobalValueData::Load { - base: vmctx, - offset: GLOBAL_BASE_OFFSET.into(), - global_type: I64, - readonly: false, - }); - self.globals = Some(gv); - gv - }) - } -} diff --git a/lucetc/src/compiler/entity/cache.rs b/lucetc/src/compiler/entity/cache.rs deleted file mode 100644 index 1b8462fb8..000000000 --- a/lucetc/src/compiler/entity/cache.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::compiler::entity::{ - FunctionIndex, GlobalIndex, GlobalValue, MemoryIndex, SignatureIndex, -}; -use crate::program::{Function, FunctionSig}; -use cranelift_codegen::ir; -use failure::Error; -use std::collections::HashMap; - -#[derive(Debug, PartialEq, Eq, Hash)] -pub enum FunctionCacheIndex { - Wasm(FunctionIndex), - Runtime(String), -} - -pub struct Cache<'p> { - /// Collection of global variables that have been brought into scope - globals: HashMap, - /// Collection of heaps that have been brought into scope - heaps: HashMap, - /// Collection of indirect call signatures that have been brought into scope, - /// and the signatures themselves - signatures: HashMap, - /// Collection of functions that have been brought into scope, and the functions - /// themselves - functions: HashMap, -} - -impl<'p> Cache<'p> { - pub fn new() -> Self { - Self { - globals: HashMap::new(), - heaps: HashMap::new(), - signatures: HashMap::new(), - functions: HashMap::new(), - } - } - - pub fn global(&mut self, index: GlobalIndex, makeglob: F) -> Result - where - F: FnOnce() -> Result, - { - let r = entry_or_insert_result(&mut self.globals, index, makeglob); - Ok(*r?) - } - - pub fn heap(&mut self, index: MemoryIndex, makeheap: F) -> Result - where - F: FnOnce() -> Result, - { - let r = entry_or_insert_result(&mut self.heaps, index, makeheap); - Ok(*r?) - } - - pub fn signature( - &mut self, - index: SignatureIndex, - makesig: F, - ) -> Result<&(ir::SigRef, FunctionSig), Error> - where - F: FnOnce() -> Result<(ir::SigRef, FunctionSig), Error>, - { - entry_or_insert_result(&mut self.signatures, index, makesig) - } - - pub fn function( - &mut self, - index: FunctionCacheIndex, - makefunc: F, - ) -> Result<&(ir::FuncRef, &'p Function), Error> - where - F: FnOnce() -> Result<(ir::FuncRef, &'p Function), Error>, - { - entry_or_insert_result(&mut self.functions, index, makefunc) - } -} - -use std::collections::hash_map::Entry; -use std::hash::Hash; - -fn entry_or_insert_result(map: &mut HashMap, key: K, mkval: F) -> Result<&V, E> -where - K: Eq + Hash, - F: FnOnce() -> Result, -{ - let entry = map.entry(key); - Ok(match entry { - Entry::Occupied(entry) => entry.into_mut(), - Entry::Vacant(entry) => entry.insert(mkval()?), - }) -} diff --git a/lucetc/src/compiler/entity/global.rs b/lucetc/src/compiler/entity/global.rs deleted file mode 100644 index 00f406225..000000000 --- a/lucetc/src/compiler/entity/global.rs +++ /dev/null @@ -1,8 +0,0 @@ -use cranelift_codegen::ir; - -/// Value of WebAssembly global variable -#[derive(Clone, Copy, Debug)] -pub struct GlobalValue { - pub var: ir::GlobalValue, - pub ty: ir::Type, -} diff --git a/lucetc/src/compiler/entity/mod.rs b/lucetc/src/compiler/entity/mod.rs deleted file mode 100644 index 32b97125b..000000000 --- a/lucetc/src/compiler/entity/mod.rs +++ /dev/null @@ -1,169 +0,0 @@ -mod bases; -mod cache; -mod global; - -pub use self::global::GlobalValue; - -use self::bases::GlobalBases; -use self::cache::{Cache, FunctionCacheIndex}; -use crate::compiler::Compiler; -use crate::program::{CtonSignature, Function, FunctionSig, Program, TableDef}; -use cranelift_codegen::ir; -use cranelift_codegen::ir::types::{I32, I64}; -use cranelift_module::Linkage; -use failure::{format_err, Error, ResultExt}; -use std::fmt; - -pub type GlobalIndex = u32; -pub type MemoryIndex = u32; -pub type SignatureIndex = u32; -pub type FunctionIndex = u32; -pub type TableIndex = u32; - -fn global_var_offset(index: isize) -> isize { - index * POINTER_SIZE as isize -} - -// For readability -pub const POINTER_SIZE: usize = 8; -pub const NATIVE_POINTER: ir::Type = I64; - -pub struct EntityCreator<'p> { - program: &'p Program, - bases: GlobalBases, - cache: Cache<'p>, -} - -impl<'p> EntityCreator<'p> { - pub fn new(program: &'p Program) -> Self { - Self { - program: program, - bases: GlobalBases::new(), - cache: Cache::new(), - } - } - - pub fn get_global( - &mut self, - func: &mut ir::Function, - index: GlobalIndex, - compiler: &Compiler, - ) -> Result { - let global = self - .program - .globals() - .get(index as usize) - .ok_or_else(|| format_err!("global out of range: {}", index))?; - let base = self.bases.globals(func, compiler); - self.cache.global(index, || { - let offset = global_var_offset(index as isize); - let gv = func.create_global_value(ir::GlobalValueData::IAddImm { - base: base, - offset: (offset as i64).into(), - global_type: NATIVE_POINTER, - }); - Ok(GlobalValue { - var: gv, - ty: global.cton_type(), - }) - }) - } - - pub fn get_heap( - &mut self, - func: &mut ir::Function, - index: MemoryIndex, - compiler: &Compiler, - ) -> Result { - let base = self.bases.heap(func, compiler); - let heap_spec = self.program.heap_spec()?; - - self.cache.heap(index, || { - if index != 0 { - return Err(format_err!( - "can only create heap for memory index 0; got {}", - index - )); - } - Ok(func.create_heap(ir::HeapData { - base, - min_size: heap_spec.initial_size.into(), - offset_guard_size: heap_spec.guard_size.into(), - style: ir::HeapStyle::Static { - bound: heap_spec.reserved_size.into(), - }, - index_type: I32, - })) - }) - } - - pub fn get_table( - &mut self, - ix: TableIndex, - func: &mut ir::Function, - compiler: &Compiler, - ) -> Result<(TableDef, ir::GlobalValue), Error> { - let tbl = self.program.get_table(ix)?; - let base = self.bases.table(func, compiler); - Ok((tbl.clone(), base)) - } - - pub fn get_indirect_sig( - &mut self, - func: &mut ir::Function, - index: SignatureIndex, - ) -> Result<&(ir::SigRef, FunctionSig), Error> { - let sig = self.program.get_signature(index)?; - self.cache.signature(index, || { - let sigref = func.import_signature(sig.cton_signature()); - Ok((sigref, sig)) - }) - } - - pub fn get_direct_func( - &mut self, - func: &mut ir::Function, - index: FunctionIndex, - compiler: &Compiler, - ) -> Result<&(ir::FuncRef, &'p Function), Error> { - let f = self.program.get_function(index)?; - self.cache - .function(FunctionCacheIndex::Wasm(index), move || { - let import = func.import_signature(f.signature()); - let fref = func.import_function(ir::ExtFuncData { - name: compiler.get_function(f).context("direct call")?.into(), - signature: import, - colocated: match f.linkage() { - Linkage::Import => false, - _ => true, - }, - }); - Ok((fref, f)) - }) - } - - pub fn get_runtime_func( - &mut self, - func: &mut ir::Function, - name: String, - compiler: &Compiler, - ) -> Result<&(ir::FuncRef, &'p Function), Error> { - let f = self.program.get_runtime_function(&name)?; - self.cache - .function(FunctionCacheIndex::Runtime(name), move || { - let import = func.import_signature(f.signature()); - let fref = func.import_function(ir::ExtFuncData { - name: compiler.get_function(f).context("runtime call")?.into(), - signature: import, - colocated: false, - }); - Ok((fref, f)) - }) - } -} - -impl<'p> fmt::Debug for EntityCreator<'p> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "EntityCreator") - } -} diff --git a/lucetc/src/compiler/function.rs b/lucetc/src/compiler/function.rs deleted file mode 100644 index 9e485bbeb..000000000 --- a/lucetc/src/compiler/function.rs +++ /dev/null @@ -1,127 +0,0 @@ -use crate::compiler::entity::EntityCreator; -use crate::compiler::opcode::translate_opcode; -use crate::compiler::state::TranslationState; -use crate::compiler::Compiler; -use crate::program::types::cton_valuetype; -use crate::program::FunctionDef; -use cranelift_codegen::ir::{self, InstBuilder}; -use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; -use failure::{format_err, Error}; -use parity_wasm::elements::{self, FuncBody, ValueType}; - -pub fn compile_function<'p>( - compiler: &mut Compiler<'p>, - function: &FunctionDef, - body: &FuncBody, -) -> Result<(), Error> { - let sig = function.signature(); - - let name = compiler.get_function(function)?; - let mut func = ir::Function::with_name_signature(name.clone().into(), sig.clone()); - - { - let mut ctx: FunctionBuilderContext = FunctionBuilderContext::new(); - let mut builder = FunctionBuilder::new(&mut func, &mut ctx); - - // Create entry block. - let entry_block = builder.create_ebb(); - builder.append_ebb_params_for_function_params(entry_block); - builder.switch_to_block(entry_block); - builder.seal_block(entry_block); - builder.ensure_inserted_ebb(); - - let mut vargen = VariableGen::new(); - - // Declare a local for each wasm parameter. - for (param_ix, param_type) in sig.params.iter().enumerate() { - if param_type.purpose == ir::ArgumentPurpose::Normal { - let var = vargen.mint(); - builder.declare_var(var, param_type.value_type); - let value = builder.ebb_params(entry_block)[param_ix]; - builder.def_var(var, value); - } - } - // local decls - declare_locals(&mut builder, &mut vargen, body.locals()); - - // Create exit block. - let exit_block = builder.create_ebb(); - builder.append_ebb_params_for_function_returns(exit_block); - - // TranslationState is used to track control frames, the wasm stack, and translate - // wasm entities into cretone entities (entities means globals, heaps, sigs, funcs). - // The exit block is the final dest of all control frames, and return values are the - // bottom of the wasm stack. - let mut translation = TranslationState::new(&sig, exit_block); - - let mut entity_creator = EntityCreator::new(&compiler.prog); - - // Function body - let mut op_iter = body.code().elements().iter(); - while !translation.control_stack.is_empty() { - let op = op_iter - .next() - .ok_or(format_err!("ran out of opcodes before control stack"))?; - translate_opcode( - op, - &mut builder, - &mut translation, - &mut entity_creator, - compiler, - )?; - } - - // The end of the iteration left us in the exit block. As long as that block is reachable, - // need to manually pass the wasm stack to the return instruction. - if translation.reachable { - debug_assert!(builder.is_pristine()); - if !builder.is_unreachable() { - builder.ins().return_(&translation.stack); - } - } - - builder.finalize(); - } - - compiler.define_function(name, func)?; - Ok(()) -} - -fn declare_locals( - builder: &mut FunctionBuilder, - vargen: &mut VariableGen, - locals: &[elements::Local], -) { - for local in locals { - let localtype = local.value_type(); - let zeroval = match localtype { - ValueType::I32 => builder.ins().iconst(ir::types::I32, 0), - ValueType::I64 => builder.ins().iconst(ir::types::I64, 0), - ValueType::F32 => builder.ins().f32const(ir::immediates::Ieee32::with_bits(0)), - ValueType::F64 => builder.ins().f64const(ir::immediates::Ieee64::with_bits(0)), - ValueType::V128 => unimplemented!(), - }; - for _ in 0..local.count() { - let lvar = vargen.mint(); - builder.declare_var(lvar, cton_valuetype(&localtype)); - builder.def_var(lvar, zeroval); - } - } -} - -/// `VariableGen` is a source of fresh `Variable`s. It is never used directly by Cretonne. -#[derive(Debug)] -struct VariableGen { - index: u32, -} - -impl VariableGen { - pub fn new() -> Self { - Self { index: 0 } - } - pub fn mint(&mut self) -> Variable { - let var = Variable::with_u32(self.index); - self.index += 1; - var - } -} diff --git a/lucetc/src/compiler/globals.rs b/lucetc/src/compiler/globals.rs deleted file mode 100644 index ccdf2d060..000000000 --- a/lucetc/src/compiler/globals.rs +++ /dev/null @@ -1,87 +0,0 @@ -use crate::compiler::Compiler; -use crate::program::globals::Global; -use byteorder::{LittleEndian, WriteBytesExt}; -use cranelift_module::{DataContext, Linkage}; -use failure::Error; -use std::io::Cursor; - -pub fn compile_global_specs(compiler: &mut Compiler) -> Result<(), Error> { - let globals = compiler.prog.globals(); - let len = globals.len(); - - let mut spec_contents: Cursor> = Cursor::new(Vec::with_capacity(8 + 24 * len)); - spec_contents.write_u64::(len as u64).unwrap(); - - let mut spec_ctx = DataContext::new(); - - for ref g in globals { - spec_contents.write_u64::(flags(g)).unwrap(); - spec_contents.write_u64::(initval(g)).unwrap(); - if let Some(name) = name(&g) { - let sym_name = &format!("lucet_globals_name_{}", name); - // Declare data with the name - let name_decl = compiler - .module - .declare_data(sym_name, Linkage::Local, false)?; - // Put a relocation to the name into the spec - let sym_gv = compiler - .module - .declare_data_in_data(name_decl, &mut spec_ctx); - let position = spec_contents.position(); - assert!(position < ::max_value() as u64); - spec_ctx.write_data_addr(position as u32, sym_gv, 0); - - // Define the name in the module - let mut name_ctx = DataContext::new(); - name_ctx.define(sym_name.clone().into_bytes().into_boxed_slice()); - compiler.module.define_data(name_decl, &name_ctx)?; - } - spec_contents - .write_u64::(0) // Reloc goes here - .unwrap(); - } - spec_ctx.define(spec_contents.into_inner().into_boxed_slice()); - let spec_decl = compiler - .module - .declare_data("lucet_globals_spec", Linkage::Export, false)?; - compiler.module.define_data(spec_decl, &spec_ctx)?; - - Ok(()) -} - -fn flags(g: &Global) -> u64 { - let mut flags = 0; - match g { - &Global::Import(_) => { - flags |= 1; - } - _ => {} - } - match name(g) { - Some(_) => { - flags |= 2; - } - _ => {} - } - flags -} - -fn initval(g: &Global) -> u64 { - match g { - &Global::Def(ref def) => def.value() as u64, - _ => 0, - } -} - -fn name(g: &Global) -> Option { - match g { - &Global::Def(ref def) => def.export().map(|s| s.to_owned()), - &Global::Import(ref import) => { - if let Some(ex) = import.export() { - Some(ex.to_owned()) - } else { - Some(format!("{}::{}", import.module(), import.field())) - } - } - } -} diff --git a/lucetc/src/compiler/memory.rs b/lucetc/src/compiler/memory.rs deleted file mode 100644 index c71614e34..000000000 --- a/lucetc/src/compiler/memory.rs +++ /dev/null @@ -1,40 +0,0 @@ -use super::Compiler; -use crate::program::memory::HeapSpec; -use byteorder::{LittleEndian, WriteBytesExt}; -use cranelift_module::{DataContext, Linkage}; -use failure::Error; - -pub fn compile_memory_specs(compiler: &mut Compiler) -> Result<(), Error> { - let heap = compiler.prog.heap_spec()?; - - let mut heap_spec_ctx = DataContext::new(); - heap_spec_ctx.define(serialize_spec(&heap).into_boxed_slice()); - let heap_spec_decl = compiler - .module - .declare_data("lucet_heap_spec", Linkage::Export, false)?; - compiler - .module - .define_data(heap_spec_decl, &heap_spec_ctx)?; - Ok(()) -} - -fn serialize_spec(spec: &HeapSpec) -> Vec { - let mut serialized: Vec = Vec::with_capacity(5 * 8); - - serialized - .write_u64::(spec.reserved_size) - .unwrap(); - serialized - .write_u64::(spec.guard_size) - .unwrap(); - serialized - .write_u64::(spec.initial_size) - .unwrap(); - serialized - .write_u64::(spec.max_size.unwrap_or(0)) - .unwrap(); - serialized - .write_u64::(if spec.max_size.is_none() { 0 } else { 1 }) - .unwrap(); - serialized -} diff --git a/lucetc/src/compiler/mod.rs b/lucetc/src/compiler/mod.rs deleted file mode 100644 index 4377c0cfc..000000000 --- a/lucetc/src/compiler/mod.rs +++ /dev/null @@ -1,306 +0,0 @@ -pub mod data; -pub mod entity; -pub mod function; -pub mod globals; -pub mod memory; -pub mod module_data; -pub mod opcode; -pub mod state; -pub mod table; -pub mod traps; - -mod name; -mod stack_probe; - -pub use self::name::Name; - -use crate::compiler::traps::write_trap_manifest; -use crate::program::{Function, Program, TableDef}; -use byteorder::{LittleEndian, WriteBytesExt}; -use cranelift_codegen::settings::{self, Configurable}; -use cranelift_codegen::{ir, isa, print_errors::pretty_error, CodegenError}; -use cranelift_faerie::{FaerieBackend, FaerieBuilder, FaerieProduct, FaerieTrapCollection}; -use cranelift_module::{DataContext, Linkage, Module, ModuleError}; -use cranelift_native; -use faerie::Artifact; -use failure::{format_err, Error, ResultExt}; -use std::collections::HashMap; -use std::fs::File; -use std::io::Write; -use std::path::Path; - -#[derive(Debug, Clone, Copy)] -pub enum OptLevel { - Default, - Best, - Fastest, -} - -impl Default for OptLevel { - fn default() -> OptLevel { - OptLevel::Default - } -} - -impl OptLevel { - fn to_flag(&self) -> &str { - match self { - OptLevel::Default => "default", - OptLevel::Best => "best", - OptLevel::Fastest => "fastest", - } - } -} - -fn isa(opt_level: OptLevel) -> Box { - let mut flags_builder = settings::builder(); - let isa_builder = cranelift_native::builder().expect("host machine is not a supported target"); - flags_builder.enable("enable_verifier").unwrap(); - flags_builder.enable("is_pic").unwrap(); - flags_builder.set("opt_level", opt_level.to_flag()).unwrap(); - isa_builder.finish(settings::Flags::new(flags_builder)) -} - -pub struct Compiler<'p> { - pub prog: &'p Program, - funcs: HashMap, - module: Module, - opt_level: OptLevel, -} - -impl<'p> Compiler<'p> { - pub fn new(name: String, prog: &'p Program, opt_level: OptLevel) -> Result { - let libcalls = Box::new(move |libcall| match libcall { - ir::LibCall::Probestack => stack_probe::STACK_PROBE_SYM.to_owned(), - _ => (FaerieBuilder::default_libcall_names())(libcall), - }); - - let mut compiler = Self { - funcs: HashMap::new(), - module: Module::new(FaerieBuilder::new( - isa(opt_level), - name, - FaerieTrapCollection::Enabled, - libcalls, - )?), - prog: prog, - opt_level: opt_level, - }; - - for f in prog.import_functions() { - compiler.declare_function(f)?; - } - - let start_section = prog.module().start_section(); - for f in prog.defined_functions() { - let name = compiler.declare_function(f)?; - if Some(f.wasmidx) == start_section { - compiler.define_start_symbol(&name)?; - } - } - - for f in prog.runtime_functions() { - compiler.declare_function(f)?; - } - - for t in prog.tables() { - compiler.declare_table(t)?; - } - Ok(compiler) - } - - pub fn isa(&self) -> Box { - isa(self.opt_level) - } - - /// Add a `guest_start` data symbol pointing to the `start` section. - /// - /// We want to have the symbol `guest_start` point to the function - /// designated in the `start` section of the wasm module, but we - /// also want whatever function that is to be callable by its - /// normal symbol. Since ELF doesn't support aliasing function - /// symbols, we add a data symbol with a reloc pointer to the - /// function's normal symbol. - pub fn define_start_symbol(&mut self, start_func: &Name) -> Result<(), Error> { - let name = self.declare_data("guest_start", Linkage::Export, false)?; - let mut ctx = DataContext::new(); - ctx.define_zeroinit(8); - let fid = start_func - .into_funcid() - .ok_or(format_err!("start index pointed to a non-function"))?; - let fref = self.module.declare_func_in_data(fid, &mut ctx); - ctx.write_function_addr(0, fref); - self.define_data(name, &ctx) - } - - pub fn declare_function(&mut self, func: &Function) -> Result { - let funcid = self - .module - .declare_function(&func.symbol(), func.linkage(), &func.signature()) - .context(format!("declaration of {}", func.symbol()))?; - Ok(Name::new_func(func.symbol().to_owned(), funcid)) - } - - pub fn declare_table(&mut self, table: &TableDef) -> Result { - let mut serialized_len: Vec = Vec::new(); - serialized_len - .write_u64::(table.len() as u64) - .unwrap(); - let mut len_ctx = DataContext::new(); - len_ctx.define(serialized_len.into_boxed_slice()); - let len_decl = self - .module - .declare_data(&table.len_symbol(), Linkage::Export, false)?; - self.module.define_data(len_decl, &len_ctx)?; - - let dataid = self - .module - .declare_data(&table.symbol(), Linkage::Export, false)?; - Ok(Name::new_data(table.symbol(), dataid)) - } - - pub fn declare_data( - &mut self, - sym: &str, - linkage: Linkage, - mutable: bool, - ) -> Result { - let dataid = self.module.declare_data(sym, linkage, mutable)?; - Ok(Name::new_data(sym.to_owned(), dataid)) - } - - pub fn get_function(&self, func: &Function) -> Result { - let ident = self - .module - .get_name(&func.symbol()) - .ok_or(format_err!("function named {} undeclared", func.symbol()))?; - Ok(Name::new(func.symbol().to_owned(), ident)) - } - - pub fn get_table(&self, table: &TableDef) -> Result { - let ident = self - .module - .get_name(&table.symbol()) - .ok_or(format_err!("table named {} undeclared", table.symbol()))?; - Ok(Name::new(table.symbol(), ident)) - } - - pub fn get_data(&self, name: &str) -> Result { - let ident = self - .module - .get_name(name) - .ok_or(format_err!("data named {} undeclared", name,))?; - Ok(Name::new(name.to_owned(), ident)) - } - - pub fn define_function(&mut self, name: Name, func: ir::Function) -> Result<(), Error> { - use std::collections::hash_map::Entry; - match self.funcs.entry(name.clone()) { - Entry::Occupied(_entry) => { - return Err(format_err!( - "function {} has duplicate definition", - name.symbol() - )); - } - Entry::Vacant(entry) => { - entry.insert(func); - } - } - Ok(()) - } - - pub fn define_data(&mut self, name: Name, data: &DataContext) -> Result<(), Error> { - let id = name - .into_dataid() - .ok_or(format_err!("data defined with invalid name {:?}", name))?; - self.module.define_data(id, data)?; - Ok(()) - } - - pub fn cranelift_funcs(self) -> CraneliftFuncs { - let isa = self.isa(); - CraneliftFuncs { - funcs: self.funcs, - isa: isa, - } - } - - pub fn codegen(self) -> Result { - use cranelift_codegen::Context; - - let isa = &*self.isa(); - let mut ctx = Context::new(); - let mut module = self.module; - - for (name, func) in self.funcs.iter() { - ctx.func = func.clone(); - let id = name - .into_funcid() - .ok_or(format_err!("function defined with invalid name {:?}", name,))?; - module.define_function(id, &mut ctx).map_err(|e| match e { - ModuleError::Compilation(ce) => match ce { - CodegenError::Verifier(_) => - // Verifier errors are never recoverable. This is the last - // time we'll have enough information still around to pretty-print - { - format_err!( - "code generation error:\n{}", - pretty_error(func, Some(isa), ce) - ) - } - _ => ModuleError::Compilation(ce).into(), - }, - _ => e.into(), - })?; - ctx.clear(); - } - - ObjectFile::new(module.finish()) - } -} - -pub struct CraneliftFuncs { - funcs: HashMap, - isa: Box, -} - -impl CraneliftFuncs { - /// This outputs a .clif file - pub fn write>(&self, path: P) -> Result<(), Error> { - use cranelift_codegen::write_function; - let mut buffer = String::new(); - for (n, func) in self.funcs.iter() { - buffer.push_str(&format!("; {}\n", n.symbol())); - write_function(&mut buffer, func, Some(self.isa.as_ref())) - .context(format_err!("writing func {:?}", n))? - } - let mut file = File::create(path)?; - file.write_all(buffer.as_bytes())?; - Ok(()) - } -} - -pub struct ObjectFile { - artifact: Artifact, -} -impl ObjectFile { - pub fn new(mut product: FaerieProduct) -> Result { - stack_probe::declare_and_define(&mut product)?; - let trap_manifest = &product - .trap_manifest - .expect("trap manifest will be present"); - write_trap_manifest(trap_manifest, &mut product.artifact)?; - Ok(Self { - artifact: product.artifact, - }) - } - pub fn write>(&self, path: P) -> Result<(), Error> { - let _ = path.as_ref().file_name().ok_or(format_err!( - "path {:?} needs to have filename", - path.as_ref() - )); - let file = File::create(path)?; - self.artifact.write(file)?; - Ok(()) - } -} diff --git a/lucetc/src/compiler/module_data.rs b/lucetc/src/compiler/module_data.rs deleted file mode 100644 index 6fa5280fa..000000000 --- a/lucetc/src/compiler/module_data.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::compiler::Compiler; -use crate::program::data::sparse::OwnedSparseData; -use byteorder::{LittleEndian, WriteBytesExt}; -use cranelift_module::{DataContext, Linkage}; -use failure::Error; -use lucet_module_data::ModuleData; - -pub fn compile_module_data(compiler: &mut Compiler) -> Result<(), Error> { - let module_data_serialized: Vec = { - let heap_spec = compiler.prog.heap_spec()?; - let compiled_data = OwnedSparseData::new( - &compiler.prog.data_initializers()?, - compiler.prog.heap_spec()?, - ); - let sparse_data = compiled_data.sparse_data(); - - let globals = compiler.prog.globals(); - let globals_spec = globals.iter().map(|g| g.to_spec()).collect(); - - let module_data = ModuleData::new(heap_spec, sparse_data, globals_spec); - module_data.serialize()? - }; - - { - let mut serialized_len: Vec = Vec::new(); - serialized_len - .write_u32::(module_data_serialized.len() as u32) - .unwrap(); - let mut data_len_ctx = DataContext::new(); - data_len_ctx.define(serialized_len.into_boxed_slice()); - - let data_len_decl = - compiler - .module - .declare_data("lucet_module_data_len", Linkage::Export, false)?; - compiler.module.define_data(data_len_decl, &data_len_ctx)?; - } - - { - let mut module_data_ctx = DataContext::new(); - module_data_ctx.define(module_data_serialized.into_boxed_slice()); - - let module_data_decl = - compiler - .module - .declare_data("lucet_module_data", Linkage::Export, true)?; - compiler - .module - .define_data(module_data_decl, &module_data_ctx)?; - } - Ok(()) -} diff --git a/lucetc/src/compiler/opcode.rs b/lucetc/src/compiler/opcode.rs deleted file mode 100644 index c780c8ebf..000000000 --- a/lucetc/src/compiler/opcode.rs +++ /dev/null @@ -1,1175 +0,0 @@ -// This file is derived from cranelift/lib/wasm/src/code_translator.rs -// at commit 5a952497b9144f8a9437a4fb3af73b03b5be8dde - -use crate::compiler::entity::{EntityCreator, NATIVE_POINTER, POINTER_SIZE}; -use crate::compiler::state::{ControlVariant, TranslationState}; -use crate::compiler::Compiler; -use crate::program::types::cton_valuetype; -use crate::program::CtonSignature; -use cranelift_codegen::ir::condcodes::{FloatCC, IntCC}; -use cranelift_codegen::ir::types::{F32, F64, I32, I64}; -use cranelift_codegen::ir::{self, InstBuilder, JumpTableData, MemFlags}; -use cranelift_codegen::packed_option::ReservedValue; -use cranelift_frontend::{FunctionBuilder, Variable}; -use failure::{format_err, Error}; -use parity_wasm::elements::{BlockType, Instruction}; -use std::{i32, u32}; - -pub fn translate_opcode( - op: &Instruction, - builder: &mut FunctionBuilder, - state: &mut TranslationState, - entity_creator: &mut EntityCreator, - compiler: &Compiler, -) -> Result<(), Error> { - if !state.reachable { - return translate_unreachable_opcode(op, builder, state); - } - - match *op { - /********************************** Locals **************************************** - * `get_local` and `set_local` are treated as non-SSA variables and will completely - * diseappear in the Cretonne Code - ***********************************************************************************/ - Instruction::GetLocal(local_index) => { - state.push1(builder.use_var(Variable::with_u32(local_index))) - } - Instruction::SetLocal(local_index) => { - let val = state.pop1(); - builder.def_var(Variable::with_u32(local_index), val); - } - Instruction::TeeLocal(local_index) => { - let val = state.peek1(); - builder.def_var(Variable::with_u32(local_index), val); - } - - /********************************** Globals **************************************** - * `get_global` and `set_global` are handled by the environment. - ***********************************************************************************/ - Instruction::GetGlobal(global_index) => { - let global = entity_creator.get_global(builder.func, global_index, compiler)?; - let addr = builder.ins().global_value(NATIVE_POINTER, global.var); - let flags = ir::MemFlags::new(); - let val = builder.ins().load(global.ty, flags, addr, 0); - state.push1(val); - } - - Instruction::SetGlobal(global_index) => { - let global = entity_creator.get_global(builder.func, global_index, compiler)?; - let addr = builder.ins().global_value(NATIVE_POINTER, global.var); - let flags = ir::MemFlags::new(); - let val = state.pop1(); - builder.ins().store(flags, val, addr, 0); - } - - /********************************* Stack misc *************************************** - * `drop`, `nop`, `select`. - ***********************************************************************************/ - // Stack Misc - Instruction::Nop => {} - Instruction::Drop => { - state.pop1(); - } - Instruction::Select => { - let (whentrue, whenfalse, cond) = state.pop3(); - state.push1(builder.ins().select(cond, whentrue, whenfalse)); - } - - /***************************** Control flow blocks ********************************** - * When starting a control flow block, we create a new `Ebb` that will hold the code - * after the block, and we push a frame on the control stack. Depending on the type - * of block, we create a new `Ebb` for the body of the block with an associated - * jump instruction. - * - * The `End` instruction pops the last control frame from the control stack, seals - * the destination block (since `br` instructions targeting it only appear inside the - * block and have already been translated) and modify the value stack to use the - * possible `Ebb`'s arguments values. - ***********************************************************************************/ - Instruction::Unreachable => { - // Generates a trap instr and sets state so translate_unreachable_opcode is - // used until the control flow frame is complete. - builder.ins().trap(ir::TrapCode::User(0)); - state.reachable = false; - } - // Create a new Ebb for the continuation, push frame onto control type. - Instruction::Block(ty) => { - let next = builder.create_ebb(); - if let Some(ty) = cton_blocktype(&ty) { - builder.append_ebb_param(next, ty); - } - state.push_control_frame(ControlVariant::_block(), next, num_return_values(&ty)); - } - Instruction::Loop(ty) => { - let loop_body = builder.create_ebb(); - let next = builder.create_ebb(); - if let Some(ty) = cton_blocktype(&ty) { - builder.append_ebb_param(next, ty); - } - builder.ins().jump(loop_body, &[]); - state.push_control_frame( - ControlVariant::_loop(loop_body), - next, - num_return_values(&ty), - ); - builder.switch_to_block(loop_body); - } - Instruction::If(ty) => { - let val = state.pop1(); - let if_not = builder.create_ebb(); - // No arguments to jump: - // When If has no Else cuause, ty is EmptyBlock. - // When there is an Else clause, this jump destination will be - // overwritten, and the ultimate continuation will get the correct - // arguments from the Else ebb. - let branch_inst = builder.ins().brz(val, if_not, &[]); - if let Some(ty) = cton_blocktype(&ty) { - builder.append_ebb_param(if_not, ty); - } - let reachable = state.reachable; - state.push_control_frame( - ControlVariant::_if(branch_inst, reachable), - if_not, - num_return_values(&ty), - ); - } - - Instruction::Else => { - let last = state.control_stack.len() - 1; - let (branch_inst, ref mut reachable_from_top) = match state.control_stack[last].variant - { - ControlVariant::If { - branch_inst, - reachable_from_top, - .. - } => (branch_inst, reachable_from_top), - _ => panic!("impossible: else instruction when not in `if`"), - }; - // The if h as an else, so there's no branch to end from the top. - *reachable_from_top = false; - let retcnt = state.control_stack[last].num_return_values; - let dest = state.control_stack[last].destination; - builder.ins().jump(dest, state.peekn(retcnt)); - state.dropn(retcnt); - // Retarget the If branch to the else block - let else_ebb = builder.create_ebb(); - builder.change_jump_destination(branch_inst, else_ebb); - builder.seal_block(else_ebb); - builder.switch_to_block(else_ebb); - // When the End of this else block is reached, it will terminate the - // If just as above, to the destination. - } - - Instruction::End => { - let frame = state - .control_stack - .pop() - .expect("end instruction has populated ctrl stack"); - let return_count = frame.num_return_values; - if !builder.is_unreachable() || !builder.is_pristine() { - builder - .ins() - .jump(frame.following_code(), state.peekn(return_count)); - } - builder.switch_to_block(frame.following_code()); - builder.seal_block(frame.following_code()); - // Loop body needs to be sealed as well - if let ControlVariant::Loop { body } = frame.variant { - builder.seal_block(body); - } - state.stack.truncate(frame.original_stack_size); - let following_params = builder.ebb_params(frame.following_code()); - state.stack.extend_from_slice(following_params); - } - /**************************** Branch instructions ********************************* - * The branch instructions all have as arguments a target nesting level, which - * corresponds to how many control stack frames do we have to pop to get the - * destination `Ebb`. - * - * Once the destination `Ebb` is found, we sometimes have to declare a certain depth - * of the stack unreachable, because some branch instructions are terminator. - * - * The `br_table` case is much more complicated because Cretonne's `br_table` instruction - * does not support jump arguments like all the other branch instructions. That is why, in - * the case where we would use jump arguments for every other branch instructions, we - * need to split the critical edges leaving the `br_tables` by creating one `Ebb` per - * table destination; the `br_table` will point to these newly created `Ebbs` and these - * `Ebb`s contain only a jump instruction pointing to the final destination, this time with - * jump arguments. - * - * This system is also implemented in Cretonne's SSA construction algorithm, because - * `use_var` located in a destination `Ebb` of a `br_table` might trigger the addition - * of jump arguments in each predecessor branch instruction, one of which might be a - * `br_table`. - ***********************************************************************************/ - Instruction::Br(relative_depth) => { - let i = state.control_stack.len() - 1 - (relative_depth as usize); - let (return_count, br_destination) = { - let frame = &mut state.control_stack[i]; - // We signal that all the code that follows until the next End is unreachable - frame.set_branched_to_exit(); - let return_count = if frame.is_loop() { - 0 - } else { - frame.num_return_values - }; - (return_count, frame.br_destination()) - }; - builder - .ins() - .jump(br_destination, state.peekn(return_count)); - state.dropn(return_count); - state.reachable = false; - } - Instruction::BrIf(relative_depth) => { - let val = state.pop1(); - let i = state.control_stack.len() - 1 - (relative_depth as usize); - let (return_count, br_destination) = { - let frame = &mut state.control_stack[i]; - // The values returned by the branch are still available for the reachable - // code that comes after it - frame.set_branched_to_exit(); - let return_count = if frame.is_loop() { - 0 - } else { - frame.num_return_values - }; - (return_count, frame.br_destination()) - }; - builder - .ins() - .brnz(val, br_destination, state.peekn(return_count)); - } - Instruction::BrTable(ref data_table) => { - let depths = &data_table.table; - let default = data_table.default; - use std::collections::hash_map::{self, HashMap}; - let mut min_depth: u32 = default; - for depth in depths.iter() { - if *depth < min_depth { - min_depth = *depth; - } - } - let jump_args_count = { - let i = state.control_stack.len() - 1 - (min_depth as usize); - let min_depth_frame = &state.control_stack[i]; - if min_depth_frame.is_loop() { - 0 - } else { - min_depth_frame.num_return_values - } - }; - if jump_args_count == 0 { - // No jump arguments - let val = state.pop1(); - let mut data = JumpTableData::with_capacity(depths.len()); - for depth in depths.iter() { - let ebb = { - let i = state.control_stack.len() - 1 - (*depth as usize); - let frame = &mut state.control_stack[i]; - frame.set_branched_to_exit(); - frame.br_destination() - }; - data.push_entry(ebb); - } - let jt = builder.create_jump_table(data); - let ebb = { - let i = state.control_stack.len() - 1 - (default as usize); - let frame = &mut state.control_stack[i]; - frame.set_branched_to_exit(); - frame.br_destination() - }; - builder.ins().br_table(val, ebb, jt); - } else { - // Here we have jump arguments, but Cretonne's br_table doesn't support them - // We then proceed to split the edges going out of the br_table - let val = state.pop1(); - let return_count = jump_args_count; - let mut data = JumpTableData::with_capacity(depths.len()); - let mut dest_ebb_sequence = Vec::new(); - let mut dest_ebb_map = HashMap::new(); - for depth in depths.iter() { - let branch_ebb = match dest_ebb_map.entry(*depth as usize) { - hash_map::Entry::Occupied(entry) => *entry.get(), - hash_map::Entry::Vacant(entry) => { - let ebb = builder.create_ebb(); - dest_ebb_sequence.push((*depth as usize, ebb)); - *entry.insert(ebb) - } - }; - data.push_entry(branch_ebb); - } - let jt = builder.create_jump_table(data); - let default_ebb = { - let i = state.control_stack.len() - 1 - (default as usize); - let frame = &mut state.control_stack[i]; - frame.set_branched_to_exit(); - frame.br_destination() - }; - dest_ebb_sequence.push((default as usize, default_ebb)); - builder.ins().br_table(val, default_ebb, jt); - for (depth, dest_ebb) in dest_ebb_sequence { - builder.switch_to_block(dest_ebb); - builder.seal_block(dest_ebb); - let i = state.control_stack.len() - 1 - depth; - let real_dest_ebb = { - let frame = &mut state.control_stack[i]; - frame.set_branched_to_exit(); - frame.br_destination() - }; - builder.ins().jump(real_dest_ebb, state.peekn(return_count)); - } - state.dropn(return_count); - } - state.reachable = false; - } - Instruction::Return => { - let (return_count, br_destination) = { - let frame = &mut state.control_stack[0]; - frame.set_branched_to_exit(); - let return_count = frame.num_return_values; - (return_count, frame.br_destination()) - }; - { - let args = state.peekn(return_count); - builder.ins().jump(br_destination, args); - } - state.dropn(return_count); - state.reachable = false; - } - - /************************************ Calls **************************************** - * The call instructions pop off their arguments from the stack and append their - * return values to it. - ************************************ Calls ****************************************/ - Instruction::Call(callee_index) => { - let &(ref callee_ref, ref callee_func) = - entity_creator.get_direct_func(builder.func, callee_index, compiler)?; - - let sig = callee_func.signature(); - let num_args = normal_args(&sig); - let call_args = with_vmctx(builder.func, state.peekn(num_args))?; - - let call = builder.cursor().ins().call(*callee_ref, &call_args); - - state.dropn(num_args); - state.pushn(builder.inst_results(call)); - } - - Instruction::CallIndirect(type_index, _reserved) => { - let table_index = 0; - let (table, table_base) = - entity_creator.get_table(table_index, builder.func, compiler)?; - let &(ref sig_ref, ref fnsig) = - entity_creator.get_indirect_sig(builder.func, type_index)?; - let num_args = normal_args(&fnsig.cton_signature()); - - let callee = state.pop1(); - - // Indirect calls are performed by looking up the callee function and type in a table that - // is present in the same object file. - // The table is an array of pairs of (type index, function pointer). Both elements in the - // pair are the size of a pointer. - // The array is indexed by the callee, as an integer. The callee passed in above is a - // symbolic value because it is only known at run-time. - // We bounds-check the callee, look up the type index, check that it is equal to the type - // index for the call, and then call the function at the pointer. - - let call: Result = { - let mut pos = builder.cursor(); - - // `callee` is an integer value that may represent a valid offset into the - // icall table. - let calleebound = table.elements().len(); - // First see if the callee is even a valid index into the table. - let inbounds = pos.ins().icmp_imm( - ir::condcodes::IntCC::UnsignedLessThan, - callee, - calleebound as i64, - ); - pos.ins().trapz(inbounds, ir::TrapCode::IndirectCallToNull); - - let table_addr = pos.ins().global_value(NATIVE_POINTER, table_base); - let callee_64 = pos.ins().uextend(ir::Type::int(64).unwrap(), callee); - // Get the type index from memory: - let table_type_offs = pos.ins().imul_imm(callee_64, 2 * POINTER_SIZE as i64); - let table_type = pos.ins().iadd(table_addr, table_type_offs); - let typ = pos.ins().load( - ir::Type::int(64).unwrap(), - ir::MemFlags::new(), - table_type, - 0, - ); - let valid_type = - pos.ins() - .icmp_imm(ir::condcodes::IntCC::Equal, typ, type_index as i64); - pos.ins().trapz(valid_type, ir::TrapCode::BadSignature); - // Get the function ptr from memory: - let func_addr = pos.ins().load( - NATIVE_POINTER, - ir::MemFlags::new(), - table_type, - 8, // Size of i64 above - ); - - let call_args = with_vmctx(pos.func, state.peekn(num_args))?; - - Ok(pos.ins().call_indirect(*sig_ref, func_addr, &call_args)) - }; - let call = call?; - state.dropn(num_args); - state.pushn(builder.inst_results(call)); - } - - /******************************* Memory management *********************************** - * Memory management calls out to functions that come from the runtime. - ************************************************************************************/ - Instruction::GrowMemory(_reserved) => { - let &(ref callee_ref, ref _callee_func) = entity_creator.get_runtime_func( - builder.func, - "lucet_vmctx_grow_memory".into(), - compiler, - )?; - - let new_pages = state.pop1(); - - let call_args = with_vmctx(builder.func, &[new_pages])?; - - let call = builder.cursor().ins().call(*callee_ref, &call_args); - - state.pushn(builder.inst_results(call)); - } - - Instruction::CurrentMemory(_reserved) => { - let &(ref callee_ref, ref _callee_func) = entity_creator.get_runtime_func( - builder.func, - "lucet_vmctx_current_memory".into(), - compiler, - )?; - - let call_args = with_vmctx(builder.func, &[])?; - - let call = builder.cursor().ins().call(*callee_ref, &call_args); - - state.pushn(builder.inst_results(call)); - } - - /******************************* Load instructions *********************************** - * Wasm specifies an integer alignment flag but we drop it in Cretonne. - * The memory base address is provided by the environment. - * TODO: differentiate between 32 bit and 64 bit architecture, to put the uextend or not - ************************************************************************************/ - Instruction::I32Load8U(_flags, offset) => { - translate_load( - offset, - ir::Opcode::Uload8, - I32, - builder, - state, - entity_creator, - compiler, - )?; - } - Instruction::I32Load16U(_flags, offset) => { - translate_load( - offset, - ir::Opcode::Uload16, - I32, - builder, - state, - entity_creator, - compiler, - )?; - } - Instruction::I32Load8S(_flags, offset) => { - translate_load( - offset, - ir::Opcode::Sload8, - I32, - builder, - state, - entity_creator, - compiler, - )?; - } - Instruction::I32Load16S(_flags, offset) => { - translate_load( - offset, - ir::Opcode::Sload16, - I32, - builder, - state, - entity_creator, - compiler, - )?; - } - Instruction::I64Load8U(_flags, offset) => { - translate_load( - offset, - ir::Opcode::Uload8, - I64, - builder, - state, - entity_creator, - compiler, - )?; - } - Instruction::I64Load16U(_flags, offset) => { - translate_load( - offset, - ir::Opcode::Uload16, - I64, - builder, - state, - entity_creator, - compiler, - )?; - } - Instruction::I64Load8S(_flags, offset) => { - translate_load( - offset, - ir::Opcode::Sload8, - I64, - builder, - state, - entity_creator, - compiler, - )?; - } - Instruction::I64Load16S(_flags, offset) => { - translate_load( - offset, - ir::Opcode::Sload16, - I64, - builder, - state, - entity_creator, - compiler, - )?; - } - Instruction::I64Load32S(_flags, offset) => { - translate_load( - offset, - ir::Opcode::Sload32, - I64, - builder, - state, - entity_creator, - compiler, - )?; - } - Instruction::I64Load32U(_flags, offset) => { - translate_load( - offset, - ir::Opcode::Uload32, - I64, - builder, - state, - entity_creator, - compiler, - )?; - } - Instruction::I32Load(_flags, offset) => { - translate_load( - offset, - ir::Opcode::Load, - I32, - builder, - state, - entity_creator, - compiler, - )?; - } - Instruction::F32Load(_flags, offset) => { - translate_load( - offset, - ir::Opcode::Load, - F32, - builder, - state, - entity_creator, - compiler, - )?; - } - Instruction::I64Load(_flags, offset) => { - translate_load( - offset, - ir::Opcode::Load, - I64, - builder, - state, - entity_creator, - compiler, - )?; - } - Instruction::F64Load(_flags, offset) => { - translate_load( - offset, - ir::Opcode::Load, - F64, - builder, - state, - entity_creator, - compiler, - )?; - } - /****************************** Store instructions *********************************** - * Wasm specifies an integer alignment flag but we drop it in Cretonne. - * The memory base address is provided by the environment. - * TODO: differentiate between 32 bit and 64 bit architecture, to put the uextend or not - ************************************************************************************/ - Instruction::I32Store(_flags, offset) - | Instruction::I64Store(_flags, offset) - | Instruction::F32Store(_flags, offset) - | Instruction::F64Store(_flags, offset) => { - translate_store( - offset, - ir::Opcode::Store, - builder, - state, - entity_creator, - compiler, - )?; - } - Instruction::I32Store8(_flags, offset) | Instruction::I64Store8(_flags, offset) => { - translate_store( - offset, - ir::Opcode::Istore8, - builder, - state, - entity_creator, - compiler, - )?; - } - Instruction::I32Store16(_flags, offset) | Instruction::I64Store16(_flags, offset) => { - translate_store( - offset, - ir::Opcode::Istore16, - builder, - state, - entity_creator, - compiler, - )?; - } - Instruction::I64Store32(_flags, offset) => { - translate_store( - offset, - ir::Opcode::Istore32, - builder, - state, - entity_creator, - compiler, - )?; - } - /****************************** Nullary Opcodes ************************************/ - Instruction::I32Const(value) => state.push1(builder.ins().iconst(I32, i64::from(value))), - Instruction::I64Const(value) => state.push1(builder.ins().iconst(I64, value)), - Instruction::F32Const(value) => { - state.push1(builder.ins().f32const(f32_translation(value))); - } - Instruction::F64Const(value) => { - state.push1(builder.ins().f64const(f64_translation(value))); - } - /******************************* Unary Opcodes *************************************/ - Instruction::I32Clz | Instruction::I64Clz => { - let arg = state.pop1(); - state.push1(builder.ins().clz(arg)); - } - Instruction::I32Ctz | Instruction::I64Ctz => { - let arg = state.pop1(); - state.push1(builder.ins().ctz(arg)); - } - Instruction::I32Popcnt | Instruction::I64Popcnt => { - let arg = state.pop1(); - state.push1(builder.ins().popcnt(arg)); - } - Instruction::I64ExtendSI32 => { - let val = state.pop1(); - state.push1(builder.ins().sextend(I64, val)); - } - Instruction::I64ExtendUI32 => { - let val = state.pop1(); - state.push1(builder.ins().uextend(I64, val)); - } - Instruction::I32WrapI64 => { - let val = state.pop1(); - state.push1(builder.ins().ireduce(I32, val)); - } - Instruction::F32Sqrt | Instruction::F64Sqrt => { - let arg = state.pop1(); - state.push1(builder.ins().sqrt(arg)); - } - Instruction::F32Ceil | Instruction::F64Ceil => { - let arg = state.pop1(); - state.push1(builder.ins().ceil(arg)); - } - Instruction::F32Floor | Instruction::F64Floor => { - let arg = state.pop1(); - state.push1(builder.ins().floor(arg)); - } - Instruction::F32Trunc | Instruction::F64Trunc => { - let arg = state.pop1(); - state.push1(builder.ins().trunc(arg)); - } - Instruction::F32Nearest | Instruction::F64Nearest => { - let arg = state.pop1(); - state.push1(builder.ins().nearest(arg)); - } - Instruction::F32Abs | Instruction::F64Abs => { - let val = state.pop1(); - state.push1(builder.ins().fabs(val)); - } - Instruction::F32Neg | Instruction::F64Neg => { - let arg = state.pop1(); - state.push1(builder.ins().fneg(arg)); - } - Instruction::F64ConvertUI64 | Instruction::F64ConvertUI32 => { - let val = state.pop1(); - state.push1(builder.ins().fcvt_from_uint(F64, val)); - } - Instruction::F64ConvertSI64 | Instruction::F64ConvertSI32 => { - let val = state.pop1(); - state.push1(builder.ins().fcvt_from_sint(F64, val)); - } - Instruction::F32ConvertSI64 | Instruction::F32ConvertSI32 => { - let val = state.pop1(); - state.push1(builder.ins().fcvt_from_sint(F32, val)); - } - Instruction::F32ConvertUI64 | Instruction::F32ConvertUI32 => { - let val = state.pop1(); - state.push1(builder.ins().fcvt_from_uint(F32, val)); - } - Instruction::F64PromoteF32 => { - let val = state.pop1(); - state.push1(builder.ins().fpromote(F64, val)); - } - Instruction::F32DemoteF64 => { - let val = state.pop1(); - state.push1(builder.ins().fdemote(F32, val)); - } - Instruction::I64TruncSF64 | Instruction::I64TruncSF32 => { - let val = state.pop1(); - state.push1(builder.ins().fcvt_to_sint(I64, val)); - } - Instruction::I32TruncSF64 | Instruction::I32TruncSF32 => { - let val = state.pop1(); - state.push1(builder.ins().fcvt_to_sint(I32, val)); - } - Instruction::I64TruncUF64 | Instruction::I64TruncUF32 => { - let val = state.pop1(); - state.push1(builder.ins().fcvt_to_uint(I64, val)); - } - Instruction::I32TruncUF64 | Instruction::I32TruncUF32 => { - let val = state.pop1(); - state.push1(builder.ins().fcvt_to_uint(I32, val)); - } - Instruction::F32ReinterpretI32 => { - let val = state.pop1(); - state.push1(builder.ins().bitcast(F32, val)); - } - Instruction::F64ReinterpretI64 => { - let val = state.pop1(); - state.push1(builder.ins().bitcast(F64, val)); - } - Instruction::I32ReinterpretF32 => { - let val = state.pop1(); - state.push1(builder.ins().bitcast(I32, val)); - } - Instruction::I64ReinterpretF64 => { - let val = state.pop1(); - state.push1(builder.ins().bitcast(I64, val)); - } - /****************************** Binary Opcodes ************************************/ - Instruction::I32Add | Instruction::I64Add => { - let (arg1, arg2) = state.pop2(); - state.push1(builder.ins().iadd(arg1, arg2)); - } - Instruction::I32And | Instruction::I64And => { - let (arg1, arg2) = state.pop2(); - state.push1(builder.ins().band(arg1, arg2)); - } - Instruction::I32Or | Instruction::I64Or => { - let (arg1, arg2) = state.pop2(); - state.push1(builder.ins().bor(arg1, arg2)); - } - Instruction::I32Xor | Instruction::I64Xor => { - let (arg1, arg2) = state.pop2(); - state.push1(builder.ins().bxor(arg1, arg2)); - } - Instruction::I32Shl | Instruction::I64Shl => { - let (arg1, arg2) = state.pop2(); - state.push1(builder.ins().ishl(arg1, arg2)); - } - Instruction::I32ShrS | Instruction::I64ShrS => { - let (arg1, arg2) = state.pop2(); - state.push1(builder.ins().sshr(arg1, arg2)); - } - Instruction::I32ShrU | Instruction::I64ShrU => { - let (arg1, arg2) = state.pop2(); - state.push1(builder.ins().ushr(arg1, arg2)); - } - Instruction::I32Rotl | Instruction::I64Rotl => { - let (arg1, arg2) = state.pop2(); - state.push1(builder.ins().rotl(arg1, arg2)); - } - Instruction::I32Rotr | Instruction::I64Rotr => { - let (arg1, arg2) = state.pop2(); - state.push1(builder.ins().rotr(arg1, arg2)); - } - Instruction::F32Add | Instruction::F64Add => { - let (arg1, arg2) = state.pop2(); - state.push1(builder.ins().fadd(arg1, arg2)); - } - Instruction::I32Sub | Instruction::I64Sub => { - let (arg1, arg2) = state.pop2(); - state.push1(builder.ins().isub(arg1, arg2)); - } - Instruction::F32Sub | Instruction::F64Sub => { - let (arg1, arg2) = state.pop2(); - state.push1(builder.ins().fsub(arg1, arg2)); - } - Instruction::I32Mul | Instruction::I64Mul => { - let (arg1, arg2) = state.pop2(); - state.push1(builder.ins().imul(arg1, arg2)); - } - Instruction::F32Mul | Instruction::F64Mul => { - let (arg1, arg2) = state.pop2(); - state.push1(builder.ins().fmul(arg1, arg2)); - } - Instruction::F32Div | Instruction::F64Div => { - let (arg1, arg2) = state.pop2(); - state.push1(builder.ins().fdiv(arg1, arg2)); - } - Instruction::I32DivS | Instruction::I64DivS => { - let (arg1, arg2) = state.pop2(); - state.push1(builder.ins().sdiv(arg1, arg2)); - } - Instruction::I32DivU | Instruction::I64DivU => { - let (arg1, arg2) = state.pop2(); - state.push1(builder.ins().udiv(arg1, arg2)); - } - Instruction::I32RemS | Instruction::I64RemS => { - let (arg1, arg2) = state.pop2(); - state.push1(builder.ins().srem(arg1, arg2)); - } - Instruction::I32RemU | Instruction::I64RemU => { - let (arg1, arg2) = state.pop2(); - state.push1(builder.ins().urem(arg1, arg2)); - } - Instruction::F32Min | Instruction::F64Min => { - let (arg1, arg2) = state.pop2(); - state.push1(builder.ins().fmin(arg1, arg2)); - } - Instruction::F32Max | Instruction::F64Max => { - let (arg1, arg2) = state.pop2(); - state.push1(builder.ins().fmax(arg1, arg2)); - } - Instruction::F32Copysign | Instruction::F64Copysign => { - let (arg1, arg2) = state.pop2(); - state.push1(builder.ins().fcopysign(arg1, arg2)); - } - /**************************** Comparison Opcodes **********************************/ - Instruction::I32LtS | Instruction::I64LtS => { - let (arg1, arg2) = state.pop2(); - let val = builder.ins().icmp(IntCC::SignedLessThan, arg1, arg2); - state.push1(builder.ins().bint(I32, val)); - } - Instruction::I32LtU | Instruction::I64LtU => { - let (arg1, arg2) = state.pop2(); - let val = builder.ins().icmp(IntCC::UnsignedLessThan, arg1, arg2); - state.push1(builder.ins().bint(I32, val)); - } - Instruction::I32LeS | Instruction::I64LeS => { - let (arg1, arg2) = state.pop2(); - let val = builder.ins().icmp(IntCC::SignedLessThanOrEqual, arg1, arg2); - state.push1(builder.ins().bint(I32, val)); - } - Instruction::I32LeU | Instruction::I64LeU => { - let (arg1, arg2) = state.pop2(); - let val = builder - .ins() - .icmp(IntCC::UnsignedLessThanOrEqual, arg1, arg2); - state.push1(builder.ins().bint(I32, val)); - } - Instruction::I32GtS | Instruction::I64GtS => { - let (arg1, arg2) = state.pop2(); - let val = builder.ins().icmp(IntCC::SignedGreaterThan, arg1, arg2); - state.push1(builder.ins().bint(I32, val)); - } - Instruction::I32GtU | Instruction::I64GtU => { - let (arg1, arg2) = state.pop2(); - let val = builder.ins().icmp(IntCC::UnsignedGreaterThan, arg1, arg2); - state.push1(builder.ins().bint(I32, val)); - } - Instruction::I32GeS | Instruction::I64GeS => { - let (arg1, arg2) = state.pop2(); - let val = builder - .ins() - .icmp(IntCC::SignedGreaterThanOrEqual, arg1, arg2); - state.push1(builder.ins().bint(I32, val)); - } - Instruction::I32GeU | Instruction::I64GeU => { - let (arg1, arg2) = state.pop2(); - let val = builder - .ins() - .icmp(IntCC::UnsignedGreaterThanOrEqual, arg1, arg2); - state.push1(builder.ins().bint(I32, val)); - } - Instruction::I32Eqz | Instruction::I64Eqz => { - let arg = state.pop1(); - let val = builder.ins().icmp_imm(IntCC::Equal, arg, 0); - state.push1(builder.ins().bint(I32, val)); - } - Instruction::I32Eq | Instruction::I64Eq => { - let (arg1, arg2) = state.pop2(); - let val = builder.ins().icmp(IntCC::Equal, arg1, arg2); - state.push1(builder.ins().bint(I32, val)); - } - Instruction::F32Eq | Instruction::F64Eq => { - let (arg1, arg2) = state.pop2(); - let val = builder.ins().fcmp(FloatCC::Equal, arg1, arg2); - state.push1(builder.ins().bint(I32, val)); - } - Instruction::I32Ne | Instruction::I64Ne => { - let (arg1, arg2) = state.pop2(); - let val = builder.ins().icmp(IntCC::NotEqual, arg1, arg2); - state.push1(builder.ins().bint(I32, val)); - } - Instruction::F32Ne | Instruction::F64Ne => { - let (arg1, arg2) = state.pop2(); - let val = builder.ins().fcmp(FloatCC::NotEqual, arg1, arg2); - state.push1(builder.ins().bint(I32, val)); - } - Instruction::F32Gt | Instruction::F64Gt => { - let (arg1, arg2) = state.pop2(); - let val = builder.ins().fcmp(FloatCC::GreaterThan, arg1, arg2); - state.push1(builder.ins().bint(I32, val)); - } - Instruction::F32Ge | Instruction::F64Ge => { - let (arg1, arg2) = state.pop2(); - let val = builder.ins().fcmp(FloatCC::GreaterThanOrEqual, arg1, arg2); - state.push1(builder.ins().bint(I32, val)); - } - Instruction::F32Lt | Instruction::F64Lt => { - let (arg1, arg2) = state.pop2(); - let val = builder.ins().fcmp(FloatCC::LessThan, arg1, arg2); - state.push1(builder.ins().bint(I32, val)); - } - Instruction::F32Le | Instruction::F64Le => { - let (arg1, arg2) = state.pop2(); - let val = builder.ins().fcmp(FloatCC::LessThanOrEqual, arg1, arg2); - state.push1(builder.ins().bint(I32, val)); - } - _ => panic!("Unimplemented opcode: {:?}", *op), - } - - Ok(()) -} - -fn translate_unreachable_opcode( - op: &Instruction, - builder: &mut FunctionBuilder, - state: &mut TranslationState, -) -> Result<(), Error> { - // Don't translate any ops for this code, because it is unreachable. - // Just record the phantom stack for this code so we know when unreachable code ends. - match *op { - Instruction::If(_) => { - state.push_control_frame( - ControlVariant::_if(ir::Inst::reserved_value(), false), - ir::Ebb::reserved_value(), - 0, - ); - } - Instruction::Loop(_) | Instruction::Block(_) => { - state.push_control_frame(ControlVariant::_block(), ir::Ebb::reserved_value(), 0); - } - Instruction::Else => { - let i = state.control_stack.len() - 1; - match state.control_stack[i].variant { - ControlVariant::If { - branch_inst, - ref mut reachable_from_top, - .. - } => { - if *reachable_from_top { - // We have reached a branch from the top of the if to the else - state.reachable = true; - // And because there's an else, there can no longer be a branch from the - // top directly to the end. - *reachable_from_top = false; - // Retarget the If branch to the else block - let else_ebb = builder.create_ebb(); - builder.change_jump_destination(branch_inst, else_ebb); - builder.seal_block(else_ebb); - builder.switch_to_block(else_ebb); - } - } - _ => panic!("impossible: else instruction when not in `if`"), - } - } - Instruction::End => { - let stack = &mut state.stack; - let control_stack = &mut state.control_stack; - let frame = control_stack.pop().unwrap(); - - // Now we have split off the stack the values not used by unreachable code that hasn't - // been translated - stack.truncate(frame.original_stack_size); - let reachable_anyway = match frame.variant { - ControlVariant::Loop { body, .. } => { - // Have to seal the body loop block - builder.seal_block(body); - // Loops cant have branches to the end - false - } - ControlVariant::If { - reachable_from_top, .. - } => { - // A reachable if without an else has a branch from the top directly to the - // bottom - reachable_from_top - } - // Blocks are already handled - ControlVariant::Block { .. } => false, - }; - - if frame.exit_is_branched_to() || reachable_anyway { - builder.switch_to_block(frame.following_code()); - builder.seal_block(frame.following_code()); - // Add the return values of the block only if the next block is reachable - stack.extend_from_slice(builder.ebb_params(frame.following_code())); - state.reachable = true; - } - } - _ => {} // All other opcodes are not translated - } - Ok(()) -} - -fn cton_blocktype(bt: &BlockType) -> Option { - match bt { - &BlockType::Value(vt) => Some(cton_valuetype(&vt)), - &BlockType::NoResult => None, - } -} - -fn num_return_values(bt: &BlockType) -> usize { - match cton_blocktype(bt) { - Some(_) => 1, - None => 0, - } -} - -// Translate a load instruction. -// XXX we could take the flags argument from the wasm load instruction, -// and use that to generate a cton memflags. -fn translate_load<'m>( - offset: u32, - opcode: ir::Opcode, - result_ty: ir::Type, - builder: &mut FunctionBuilder, - state: &mut TranslationState, - entity_creator: &mut EntityCreator<'m>, - compiler: &Compiler, -) -> Result<(), Error> { - let addr32 = state.pop1(); - // We don't yet support multiple linear memories. - let heap = entity_creator.get_heap(builder.func, 0, compiler)?; - let (base, offset) = get_heap_addr(heap, addr32, offset, NATIVE_POINTER, builder); - let flags = MemFlags::new(); - let (load, dfg) = builder - .ins() - .Load(opcode, result_ty, flags, offset.into(), base); - state.push1(dfg.first_result(load)); - Ok(()) -} - -// Translate a store instruction. -// XXX we could take the flags argument from the wasm store instruction, -// and use that to generate a cton memflags. -fn translate_store<'m>( - offset: u32, - opcode: ir::Opcode, - builder: &mut FunctionBuilder, - state: &mut TranslationState, - entity_creator: &mut EntityCreator<'m>, - compiler: &Compiler, -) -> Result<(), Error> { - let (addr32, val) = state.pop2(); - let val_ty = builder.func.dfg.value_type(val); - - // We don't yet support multiple linear memories. - let heap = entity_creator.get_heap(builder.func, 0, compiler)?; - let (base, offset) = get_heap_addr(heap, addr32, offset, NATIVE_POINTER, builder); - let flags = MemFlags::new(); - builder - .ins() - .Store(opcode, val_ty, flags, offset.into(), val, base); - Ok(()) -} - -// Get the address+offset to use for a heap access. -fn get_heap_addr( - heap: ir::Heap, - addr32: ir::Value, - offset: u32, - addr_ty: ir::Type, - builder: &mut FunctionBuilder, -) -> (ir::Value, i32) { - use std::cmp::min; - - let guard_size: u64 = builder.func.heaps[heap].offset_guard_size.into(); - assert!(guard_size > 0, "Heap guard pages currently required"); - - // Generate `heap_addr` instructions that are friendly to CSE by checking offsets that are - // multiples of the guard size. Add one to make sure that we check the pointer itself is in - // bounds. - // - // For accesses on the outer skirts of the guard pages, we expect that we get a trap - // even if the access goes beyond the guard pages. This is because the first byte pointed to is - // inside the guard pages. - let check_size = min( - u32::MAX as u64, - 1 + (offset as u64 / guard_size) * guard_size, - ) as u32; - let base = builder.ins().heap_addr(addr_ty, heap, addr32, check_size); - - // Native load/store instructions take a signed `Offset32` immediate, so adjust the base - // pointer if necessary. - if offset > i32::MAX as u32 { - // Offset doesn't fit in the load/store instruction. - let adj = builder.ins().iadd_imm(base, i64::from(i32::MAX) + 1); - (adj, (offset - (i32::MAX as u32 + 1)) as i32) - } else { - (base, offset as i32) - } -} - -fn f32_translation(x: u32) -> ir::immediates::Ieee32 { - ir::immediates::Ieee32::with_bits(x) -} - -fn f64_translation(x: u64) -> ir::immediates::Ieee64 { - ir::immediates::Ieee64::with_bits(x) -} - -fn normal_args(sig: &ir::Signature) -> usize { - sig.params - .iter() - .filter(|a| a.purpose == ir::ArgumentPurpose::Normal) - .count() -} - -fn with_vmctx(func: &ir::Function, base_args: &[ir::Value]) -> Result, Error> { - let mut args: Vec = Vec::with_capacity(base_args.len() + 1); - args.extend_from_slice(base_args); - args.insert( - 0, - func.special_param(ir::ArgumentPurpose::VMContext) - .ok_or(format_err!( - "getting vm context parameter insert in call args" - ))?, - ); - Ok(args) -} diff --git a/lucetc/src/compiler/state.rs b/lucetc/src/compiler/state.rs deleted file mode 100644 index 9990e8611..000000000 --- a/lucetc/src/compiler/state.rs +++ /dev/null @@ -1,192 +0,0 @@ -use cranelift_codegen::ir::{self, Value}; - -#[derive(Debug)] -pub struct TranslationState { - /// WebAssembly stack - pub stack: Vec, - /// WebAssembly control structures - pub control_stack: Vec, - pub reachable: bool, -} - -impl TranslationState { - /// Create a translation state for compiling a function with a given signature. - /// The exit block is the last block in the function and contains the return instruction. - pub fn new(sig: &ir::Signature, exit_block: ir::Ebb) -> Self { - let mut state = Self::empty(); - state.push_control_frame( - ControlVariant::_block(), - exit_block, - sig.returns - .iter() - .filter(|arg| arg.purpose == ir::ArgumentPurpose::Normal) - .count(), - ); - state - } - - fn empty() -> Self { - Self { - stack: Vec::new(), - control_stack: Vec::new(), - reachable: true, - } - } - - /// Push a value - pub fn push1(&mut self, val: Value) { - self.stack.push(val) - } - - /// Push multiple values - pub fn pushn(&mut self, vals: &[Value]) { - self.stack.extend_from_slice(vals) - } - - /// Pop one value - pub fn pop1(&mut self) -> Value { - self.stack.pop().unwrap() - } - - /// Peek at value on top of stack - pub fn peek1(&mut self) -> Value { - *self.stack.last().unwrap() - } - - /// Pop two values, return in order they were pushed - pub fn pop2(&mut self) -> (Value, Value) { - let v2 = self.stack.pop().unwrap(); - let v1 = self.stack.pop().unwrap(); - (v1, v2) - } - - /// Pop three values, return in order they were pushed - pub fn pop3(&mut self) -> (Value, Value, Value) { - let v3 = self.stack.pop().unwrap(); - let v2 = self.stack.pop().unwrap(); - let v1 = self.stack.pop().unwrap(); - (v1, v2, v3) - } - - /// Drop the top `n` values on the stack. - /// Use `peekn` to look at them before dropping - pub fn dropn(&mut self, n: usize) { - let new_len = self.stack.len() - n; - self.stack.truncate(new_len); - } - - /// Peek at top `n` values in order they were pushed - pub fn peekn(&self, n: usize) -> &[Value] { - &self.stack[self.stack.len() - n..] - } - - pub fn push_control_frame( - &mut self, - variant: ControlVariant, - following_code: ir::Ebb, - num_return_values: usize, - ) { - let frame = ControlStackFrame { - variant: variant, - destination: following_code, - original_stack_size: self.stack.len(), - num_return_values: num_return_values, - }; - self.control_stack.push(frame); - } -} - -#[derive(Debug)] -pub struct ControlStackFrame { - pub variant: ControlVariant, - pub destination: ir::Ebb, - pub num_return_values: usize, - pub original_stack_size: usize, -} - -impl ControlStackFrame { - pub fn following_code(&self) -> ir::Ebb { - self.destination - } - pub fn br_destination(&self) -> ir::Ebb { - match self.variant { - ControlVariant::If { .. } | ControlVariant::Block { .. } => self.destination, - ControlVariant::Loop { body } => body, - } - } - pub fn is_loop(&self) -> bool { - match self.variant { - ControlVariant::Loop { .. } => true, - _ => false, - } - } - pub fn exit_is_branched_to(&self) -> bool { - match self.variant { - ControlVariant::If { - exit_is_branched_to, - .. - } - | ControlVariant::Block { - exit_is_branched_to, - .. - } => exit_is_branched_to, - ControlVariant::Loop { .. } => false, - } - } - - pub fn set_branched_to_exit(&mut self) { - match self.variant { - ControlVariant::If { - ref mut exit_is_branched_to, - .. - } - | ControlVariant::Block { - ref mut exit_is_branched_to, - .. - } => *exit_is_branched_to = true, - ControlVariant::Loop { .. } => {} - } - } -} - -#[derive(Debug)] -/// Use the constructor methods defined in the impl to preserve -/// invariants. The methods have leading underscores so they do not -/// collide with rust keywords. -pub enum ControlVariant { - If { - branch_inst: ir::Inst, - exit_is_branched_to: bool, - reachable_from_top: bool, - }, - Block { - exit_is_branched_to: bool, - }, - Loop { - body: ir::Ebb, - }, -} - -impl ControlVariant { - /// Constructor for the If variant. exit_is_branched_to must be false until it is set - /// explicitly. - pub fn _if(branch_inst: ir::Inst, reachable_from_top: bool) -> ControlVariant { - ControlVariant::If { - branch_inst: branch_inst, - exit_is_branched_to: false, - reachable_from_top: reachable_from_top, - } - } - /// Constructor for the Block variant. exit_is_branched_to must be false until it is set - /// explicitly. - pub fn _block() -> ControlVariant { - ControlVariant::Block { - exit_is_branched_to: false, - } - } - /// Constructor for the Loop variant. Doesn't have the exit_is_branched_to but I didn't want to - /// leave an odd variant without a constructor. - pub fn _loop(body: ir::Ebb) -> ControlVariant { - ControlVariant::Loop { body: body } - } -} diff --git a/lucetc/src/compiler/table.rs b/lucetc/src/compiler/table.rs deleted file mode 100644 index 9dcac8b3e..000000000 --- a/lucetc/src/compiler/table.rs +++ /dev/null @@ -1,67 +0,0 @@ -use crate::compiler::Compiler; -use crate::program::table::{TableDef, TableElem}; -use byteorder::{LittleEndian, WriteBytesExt}; -use cranelift_module::DataContext; -use failure::{format_err, Error, ResultExt}; -use std::io::Cursor; - -pub fn compile_table<'p>(compiler: &mut Compiler<'p>, table: &TableDef) -> Result<(), Error> { - // Indirect calls are performed by looking up the callee function and type in a table that - // is present in the same object file. - // The table is an array of pairs of (type index, function pointer). Both elements in the - // pair are the size of a pointer. - // This function creates that table as a section in the object. - - // For readability: - let ptr_size = 8; - - let mut table_data = Cursor::new(Vec::with_capacity(table.elements().len() * 2 * ptr_size)); - let putelem = - { |table: &mut Cursor>, elem: u64| table.write_u64::(elem).unwrap() }; - let mut table_ctx = DataContext::new(); - - // table.elems is a vector that gives every entry of the table, either specifying the - // wasm function index or that no element was given for that table entry. - for table_elem in table.elements() { - match table_elem { - &TableElem::FunctionIx(ref func_index) => { - // Note: this is the only place we validate that the table entry points to a valid - // function. If this is ever removed, make sure this check happens elsewhere. - let func = compiler - .prog - .get_function(*func_index) - .context("function index for table element")?; - let sig_ix = func - .signature_index() - .ok_or(format_err!("table function should have a signature index"))?; - - // First element in row is the SignatureIndex for the function - putelem(&mut table_data, sig_ix as u64); - - // Second element in row is the pointer to the function. The Reloc is doing the work - // here. We put a 0 in the table data itself to be overwritten at link time. - let funcname = compiler.get_function(func)?; - let funcref = table_ctx.import_function(funcname.into()); - let position = table_data.position(); - assert!(position < ::max_value() as u64); - table_ctx.write_function_addr(position as u32, funcref); - putelem(&mut table_data, 0); - } - &TableElem::Empty => { - // First element is the signature index. These will always be 32 bits in wasm, so - // u64::max will always be out of bounds. - putelem(&mut table_data, ::max_value()); - // Second element is the function pointer. No relocation here, it will always be - // null. - putelem(&mut table_data, 0); - } - } - } - table_ctx.define(table_data.into_inner().into_boxed_slice()); - let table_id = compiler - .get_table(table)? - .into_dataid() - .expect("tables are data"); - compiler.module.define_data(table_id, &table_ctx)?; - Ok(()) -} diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs new file mode 100644 index 000000000..0fe2eafc4 --- /dev/null +++ b/lucetc/src/decls.rs @@ -0,0 +1,358 @@ +use crate::bindings::Bindings; +use crate::error::{LucetcError, LucetcErrorKind}; +use crate::heap::HeapSettings; +use crate::module::ModuleInfo; +pub use crate::module::{Exportable, TableElems}; +use crate::name::Name; +use crate::runtime::{Runtime, RuntimeFunc}; +use cranelift_codegen::entity::{EntityRef, PrimaryMap}; +use cranelift_codegen::ir; +use cranelift_codegen::isa::TargetFrontendConfig; +use cranelift_module::{Backend as ClifBackend, Linkage, Module as ClifModule}; +use cranelift_wasm::{ + FuncIndex, Global, GlobalIndex, GlobalInit, MemoryIndex, ModuleEnvironment, SignatureIndex, + Table, TableIndex, +}; +use failure::{format_err, Error, ResultExt}; +use lucet_module_data::{ + owned::OwnedLinearMemorySpec, Global as GlobalVariant, GlobalDef, GlobalSpec, HeapSpec, + ModuleData, +}; +use std::collections::HashMap; + +#[derive(Debug)] +pub struct FunctionDecl<'a> { + pub import_name: Option<(&'a str, &'a str)>, + pub export_names: Vec<&'a str>, + pub signature_index: SignatureIndex, + pub signature: &'a ir::Signature, + pub name: Name, +} + +impl<'a> FunctionDecl<'a> { + pub fn defined(&self) -> bool { + self.import_name.is_none() + } + pub fn imported(&self) -> bool { + !self.defined() + } +} + +#[derive(Debug)] +/// Function provided by lucet-runtime to be called from generated code, e.g. memory size & grow +/// functions. +pub struct RuntimeDecl<'a> { + pub signature: &'a ir::Signature, + pub name: Name, +} + +#[derive(Debug)] +pub struct TableDecl<'a> { + pub import_name: Option<(&'a str, &'a str)>, + pub export_names: Vec<&'a str>, + pub table: &'a Table, + pub elems: &'a [TableElems], + pub contents_name: Name, + pub len_name: Name, +} + +pub struct ModuleDecls<'a> { + info: ModuleInfo<'a>, + runtime: Runtime, + function_names: PrimaryMap, + table_names: PrimaryMap, + runtime_names: HashMap, + globals_spec: Vec>, + linear_memory_spec: Option, +} + +impl<'a> ModuleDecls<'a> { + pub fn new( + info: ModuleInfo<'a>, + clif_module: &mut ClifModule, + bindings: &Bindings, + runtime: Runtime, + heap_settings: HeapSettings, + ) -> Result { + let function_names = Self::declare_funcs(&info, clif_module, bindings)?; + let table_names = Self::declare_tables(&info, clif_module)?; + let runtime_names = Self::declare_runtime(&runtime, clif_module)?; + let globals_spec = Self::declare_globals_spec(&info)?; + let linear_memory_spec = Self::declare_linear_memory_spec(&info, heap_settings)?; + Ok(Self { + info, + function_names, + table_names, + runtime_names, + runtime, + globals_spec, + linear_memory_spec, + }) + } + + // ********************* Constructor auxillary functions *********************** + + fn declare_funcs( + info: &ModuleInfo<'a>, + clif_module: &mut ClifModule, + bindings: &Bindings, + ) -> Result, LucetcError> { + let mut function_names = PrimaryMap::new(); + for ix in 0..info.functions.len() { + let func_index = FuncIndex::new(ix); + let exportable_sigix = info.functions.get(func_index).unwrap(); + let signature = info.signatures.get(exportable_sigix.entity).unwrap(); + let name = if let Some((import_mod, import_field)) = info.imported_funcs.get(func_index) + { + let import_symbol = bindings + .translate(import_mod, import_field) + .context(LucetcErrorKind::TranslatingModule)?; + let funcid = clif_module + .declare_function(&import_symbol, Linkage::Import, signature) + .context(LucetcErrorKind::TranslatingModule)?; + Name::new_func(import_symbol, funcid) + } else { + if exportable_sigix.export_names.is_empty() { + let def_symbol = format!("guest_func_{}", ix); + let funcid = clif_module + .declare_function(&def_symbol, Linkage::Local, signature) + .context(LucetcErrorKind::TranslatingModule)?; + Name::new_func(def_symbol, funcid) + } else { + let export_symbol = format!("guest_func_{}", exportable_sigix.export_names[0]); + let funcid = clif_module + .declare_function(&export_symbol, Linkage::Export, signature) + .context(LucetcErrorKind::TranslatingModule)?; + Name::new_func(export_symbol, funcid) + } + }; + function_names.push(name); + } + Ok(function_names) + } + + fn declare_tables( + info: &ModuleInfo<'a>, + clif_module: &mut ClifModule, + ) -> Result, LucetcError> { + let mut table_names = PrimaryMap::new(); + for ix in 0..info.tables.len() { + let def_symbol = format!("guest_table_{}", ix); + let def_data_id = clif_module + .declare_data(&def_symbol, Linkage::Export, false) + .context(LucetcErrorKind::TranslatingModule)?; + let def_name = Name::new_data(def_symbol, def_data_id); + + let len_symbol = format!("guest_table_{}_len", ix); + let len_data_id = clif_module + .declare_data(&len_symbol, Linkage::Export, false) + .context(LucetcErrorKind::TranslatingModule)?; + let len_name = Name::new_data(len_symbol, len_data_id); + + table_names.push((def_name, len_name)); + } + Ok(table_names) + } + + fn declare_runtime( + runtime: &Runtime, + clif_module: &mut ClifModule, + ) -> Result, LucetcError> { + let mut runtime_names: HashMap = HashMap::new(); + for (func, (symbol, signature)) in runtime.functions.iter() { + let funcid = clif_module + .declare_function(&symbol, Linkage::Import, signature) + .context(LucetcErrorKind::TranslatingModule)?; + let name = Name::new_func(symbol.clone(), funcid); + + runtime_names.insert(*func, name); + } + Ok(runtime_names) + } + + fn declare_linear_memory_spec( + info: &ModuleInfo<'a>, + heap_settings: HeapSettings, + ) -> Result, LucetcError> { + use crate::sparsedata::owned_sparse_data_from_initializers; + if let Some(heap_spec) = Self::declare_heap_spec(info, heap_settings)? { + let data_initializers = info + .data_initializers + .get(&MemoryIndex::new(0)) + .expect("heap spec implies data initializers should exist"); + let sparse_data = owned_sparse_data_from_initializers(data_initializers, &heap_spec)?; + + Ok(Some(OwnedLinearMemorySpec { + heap: heap_spec, + initializer: sparse_data, + })) + } else { + Ok(None) + } + } + + fn declare_globals_spec(info: &ModuleInfo<'a>) -> Result>, LucetcError> { + let mut globals = Vec::new(); + for ix in 0..info.globals.len() { + let ix = GlobalIndex::new(ix); + let g_decl = info.globals.get(ix).unwrap(); + let g_import = info.imported_globals.get(ix); + let g_variant = if let Some((module, field)) = g_import { + GlobalVariant::Import { module, field } + } else { + let init_val = match g_decl.entity.initializer { + // Need to fix global spec in ModuleData and the runtime to support more: + GlobalInit::I32Const(i) => i as i64, + GlobalInit::I64Const(i) => i, + _ => Err(format_err!( + "non-integer global initializer: {:?}", + g_decl.entity + )) + .context(LucetcErrorKind::Unsupported)?, + }; + GlobalVariant::Def { + def: GlobalDef::new(init_val), + } + }; + globals.push(GlobalSpec::new(g_variant, None)); + } + Ok(globals) + } + + fn declare_heap_spec( + info: &ModuleInfo<'a>, + heap_settings: HeapSettings, + ) -> Result, LucetcError> { + match info.memories.len() { + 0 => Ok(None), + 1 => { + let memory = info + .memories + .get(MemoryIndex::new(0)) + .expect("memory in range") + .entity; + + let wasm_page: u64 = 64 * 1024; + let initial_size = memory.minimum as u64 * wasm_page; + + let reserved_size = std::cmp::max(initial_size, heap_settings.min_reserved_size); + if reserved_size > heap_settings.max_reserved_size { + Err(format_err!( + "module reserved size ({}) exceeds max reserved size ({})", + reserved_size, + heap_settings.max_reserved_size + )) + .context(LucetcErrorKind::MemorySpecs)?; + } + // Find the max size permitted by the heap and the memory spec + let max_size = memory.maximum.map(|pages| pages as u64 * wasm_page); + Ok(Some(HeapSpec { + reserved_size, + guard_size: heap_settings.guard_size, + initial_size: initial_size, + max_size: max_size, + })) + } + _ => Err(format_err!("lucetc only supports memory 0")) + .context(LucetcErrorKind::Unsupported)?, + } + } + // ********************* Public Interface ************************** + + pub fn target_config(&self) -> TargetFrontendConfig { + self.info.target_config() + } + + pub fn function_bodies(&self) -> impl Iterator { + Box::new( + self.info + .function_bodies + .iter() + .map(move |(fidx, code)| (self.get_func(*fidx).unwrap(), code)), + ) + } + + pub fn get_func(&self, func_index: FuncIndex) -> Result { + let name = self + .function_names + .get(func_index) + .ok_or_else(|| format_err!("func index out of bounds: {:?}", func_index))?; + let exportable_sigix = self.info.functions.get(func_index).unwrap(); + let signature_index = exportable_sigix.entity; + let signature = self.info.signatures.get(signature_index).unwrap(); + let import_name = self.info.imported_funcs.get(func_index); + Ok(FunctionDecl { + signature, + signature_index, + export_names: exportable_sigix.export_names.clone(), + import_name: import_name.cloned(), + name: name.clone(), + }) + } + + pub fn get_start_func(&self) -> Option { + self.info.start_func.clone() + } + + pub fn get_runtime(&self, runtime_func: RuntimeFunc) -> Result { + let (_, signature) = self + .runtime + .functions + .get(&runtime_func) + .ok_or_else(|| format_err!("runtime func not supported: {:?}", runtime_func))?; + let name = self.runtime_names.get(&runtime_func).unwrap(); + Ok(RuntimeDecl { + signature, + name: name.clone(), + }) + } + + pub fn get_table(&self, table_index: TableIndex) -> Result { + let (contents_name, len_name) = self + .table_names + .get(table_index) + .ok_or_else(|| format_err!("table index out of bounds: {:?}", table_index))?; + let exportable_tbl = self.info.tables.get(table_index).unwrap(); + let import_name = self.info.imported_tables.get(table_index); + let elems = self.info.table_elems.get(&table_index).unwrap().as_slice(); + Ok(TableDecl { + table: &exportable_tbl.entity, + elems, + export_names: exportable_tbl.export_names.clone(), + import_name: import_name.cloned(), + contents_name: contents_name.clone(), + len_name: len_name.clone(), + }) + } + + pub fn get_signature(&self, signature_index: SignatureIndex) -> Result<&ir::Signature, Error> { + self.info + .signatures + .get(signature_index) + .ok_or_else(|| format_err!("signature out of bounds: {:?}", signature_index)) + } + + pub fn get_global(&self, global_index: GlobalIndex) -> Result<&Exportable, Error> { + self.info + .globals + .get(global_index) + .ok_or_else(|| format_err!("global out of bounds: {:?}", global_index)) + } + + pub fn get_heap(&self) -> Option<&HeapSpec> { + if let Some(ref spec) = self.linear_memory_spec { + Some(&spec.heap) + } else { + None + } + } + + pub fn get_module_data(&self) -> ModuleData { + let linear_memory = if let Some(ref spec) = self.linear_memory_spec { + Some(spec.to_ref()) + } else { + None + }; + ModuleData::new(linear_memory, self.globals_spec.clone()) + } +} diff --git a/lucetc/src/error.rs b/lucetc/src/error.rs index 29b13de31..788be41f3 100644 --- a/lucetc/src/error.rs +++ b/lucetc/src/error.rs @@ -1,5 +1,4 @@ -use failure::{Backtrace, Context, Error, Fail}; -use pwasm_validation; +use failure::{Backtrace, Context, Fail}; use std::fmt::{self, Display}; #[derive(Debug)] @@ -42,41 +41,28 @@ impl Display for LucetcError { } } -impl From for LucetcError { - fn from(e: Error) -> LucetcError { - e.context(LucetcErrorKind::UnknownKind).into() - } -} - -impl From for LucetcError { - fn from(e: pwasm_validation::Error) -> LucetcError { - e.context(LucetcErrorKind::Validation).into() - } -} - -#[derive(Debug, Fail, PartialEq, Eq)] +#[derive(Debug, Fail, PartialEq, Eq, Clone)] pub enum LucetcErrorKind { - #[fail(display = "Data Initializers")] - DataInitializers, - #[fail(display = "Memory specs")] - MemorySpecs, - #[fail(display = "Global specs")] - GlobalSpecs, - #[fail(display = "Module data")] - ModuleData, - #[fail(display = "Function {}", _0)] - Function(String), - #[fail(display = "Table {}", _0)] - Table(String), + #[fail(display = "Input")] + Input, #[fail(display = "Validation")] Validation, - - #[fail(display = "Unsupported: {}", _0)] - Unsupported(String), - - #[fail(display = "{}", _0)] - Other(String), - - #[fail(display = "Unknown error:")] - UnknownKind, + #[fail(display = "Translating module")] + TranslatingModule, + #[fail(display = "Module data")] + ModuleData, + #[fail(display = "Metadata Serializer")] // specifically non-ModuleData; this will go away soon + MetadataSerializer, + #[fail(display = "Function Translation")] + FunctionTranslation, + #[fail(display = "Function Definition")] + FunctionDefinition, + #[fail(display = "Table")] + Table, + #[fail(display = "Memory Specs")] + MemorySpecs, + #[fail(display = "Output")] + Output, + #[fail(display = "Unsupported")] + Unsupported, } diff --git a/lucetc/src/function.rs b/lucetc/src/function.rs new file mode 100644 index 000000000..244472445 --- /dev/null +++ b/lucetc/src/function.rs @@ -0,0 +1,261 @@ +use super::runtime::RuntimeFunc; +use crate::decls::ModuleDecls; +use crate::pointer::{NATIVE_POINTER, NATIVE_POINTER_SIZE}; +use cranelift_codegen::cursor::FuncCursor; +use cranelift_codegen::entity::EntityRef; +use cranelift_codegen::ir::{self, InstBuilder}; +use cranelift_codegen::isa::TargetFrontendConfig; +use cranelift_wasm::{ + FuncEnvironment, FuncIndex, GlobalIndex, GlobalVariable, MemoryIndex, SignatureIndex, + TableIndex, WasmResult, +}; +use std::collections::HashMap; + +// VMContext points directly to the heap (offset 0). +// Directly before the heao is a pointer to the globals (offset -NATIVE_POINTER_SIZE). +const GLOBAL_BASE_OFFSET: i32 = -1 * NATIVE_POINTER_SIZE as i32; + +pub struct FuncInfo<'a> { + module_decls: &'a ModuleDecls<'a>, + vmctx_value: Option, + global_base_value: Option, + runtime_funcs: HashMap, +} + +impl<'a> FuncInfo<'a> { + pub fn new(module_decls: &'a ModuleDecls<'a>) -> Self { + Self { + module_decls, + vmctx_value: None, + global_base_value: None, + runtime_funcs: HashMap::new(), + } + } + + pub fn get_vmctx(&mut self, func: &mut ir::Function) -> ir::GlobalValue { + self.vmctx_value.unwrap_or_else(|| { + let vmctx_value = func.create_global_value(ir::GlobalValueData::VMContext); + self.vmctx_value = Some(vmctx_value); + vmctx_value + }) + } + + pub fn get_global_base(&mut self, func: &mut ir::Function) -> ir::GlobalValue { + self.global_base_value.unwrap_or_else(|| { + let vmctx = self.get_vmctx(func); + let global_base_value = func.create_global_value(ir::GlobalValueData::Load { + base: vmctx, + offset: GLOBAL_BASE_OFFSET.into(), + global_type: ir::types::I64, + readonly: false, + }); + self.global_base_value = Some(global_base_value); + global_base_value + }) + } + + pub fn get_runtime_func( + &mut self, + runtime_func: RuntimeFunc, + func: &mut ir::Function, + ) -> ir::FuncRef { + self.runtime_funcs + .get(&runtime_func) + .cloned() + .unwrap_or_else(|| { + let decl = self + .module_decls + .get_runtime(runtime_func) + .expect("runtime function not available"); + let signature = func.import_signature(decl.signature.clone()); + let fref = func.import_function(ir::ExtFuncData { + name: decl.name.into(), + signature, + colocated: false, + }); + self.runtime_funcs.insert(runtime_func, fref); + fref + }) + } +} + +impl<'a> FuncEnvironment for FuncInfo<'a> { + fn target_config(&self) -> TargetFrontendConfig { + self.module_decls.target_config() + } + + fn make_global(&mut self, func: &mut ir::Function, index: GlobalIndex) -> GlobalVariable { + let global_base = self.get_global_base(func); + let global = self.module_decls.get_global(index).expect("valid global"); + let index = index.as_u32() as i32; + let offset = (index * NATIVE_POINTER_SIZE as i32).into(); + GlobalVariable::Memory { + gv: global_base, + offset, + ty: global.entity.ty, + } + } + + fn make_heap(&mut self, func: &mut ir::Function, index: MemoryIndex) -> ir::Heap { + assert_eq!(index, MemoryIndex::new(0), "only memory 0 is supported"); + let heap_spec = self.module_decls.get_heap().expect("valid heap"); + let vmctx = self.get_vmctx(func); + func.create_heap(ir::HeapData { + base: vmctx, + min_size: heap_spec.initial_size.into(), + offset_guard_size: heap_spec.guard_size.into(), + style: ir::HeapStyle::Static { + bound: heap_spec.reserved_size.into(), + }, + index_type: ir::types::I32, + }) + } + + fn make_table(&mut self, func: &mut ir::Function, index: TableIndex) -> ir::Table { + let index_type = ir::types::I64; + let table_decl = self.module_decls.get_table(index).expect("valid table"); + let base_gv = func.create_global_value(ir::GlobalValueData::Symbol { + name: table_decl.contents_name.into(), + offset: 0.into(), + colocated: true, + }); + let bound_ptr_gv = func.create_global_value(ir::GlobalValueData::Symbol { + name: table_decl.len_name.into(), + offset: 0.into(), + colocated: true, + }); + let bound_gv = func.create_global_value(ir::GlobalValueData::Load { + base: bound_ptr_gv, + global_type: index_type, + offset: 0.into(), + readonly: true, + }); + let element_size = ((NATIVE_POINTER_SIZE * 2) as u64).into(); + let min_size = (table_decl.table.minimum as u64).into(); + func.create_table(ir::TableData { + base_gv, + bound_gv, + element_size, + index_type, + min_size, + }) + } + + fn translate_call_indirect( + &mut self, + mut pos: FuncCursor, + _table_index: TableIndex, + table: ir::Table, + sig_index: SignatureIndex, + sig_ref: ir::SigRef, + callee: ir::Value, + call_args: &[ir::Value], + ) -> WasmResult { + let callee_u64 = pos.ins().sextend(ir::types::I64, callee); + let table_entry_addr = pos.ins().table_addr(ir::types::I64, table, callee_u64, 0); + // First element at the table entry is the signature index of the function + let table_entry_sig_offset = 0; + let table_entry_sig_ix = pos.ins().load( + ir::types::I64, + ir::MemFlags::trusted(), + table_entry_addr, + table_entry_sig_offset, + ); + // Check it against sig_index, trap if wrong + let valid_type = pos.ins().icmp_imm( + ir::condcodes::IntCC::Equal, + table_entry_sig_ix, + sig_index.as_u32() as i64, + ); + pos.ins().trapz(valid_type, ir::TrapCode::BadSignature); + + // Second element at the table entry is the function pointer + let table_entry_fptr_offset = NATIVE_POINTER_SIZE as i32; + let table_entry_fptr = pos.ins().load( + NATIVE_POINTER, + ir::MemFlags::trusted(), + table_entry_addr, + table_entry_fptr_offset, + ); + + let mut args: Vec = Vec::with_capacity(call_args.len() + 1); + args.extend_from_slice(call_args); + args.insert( + 0, + pos.func + .special_param(ir::ArgumentPurpose::VMContext) + .expect("vmctx available"), + ); + + Ok(pos.ins().call_indirect(sig_ref, table_entry_fptr, &args)) + } + + fn make_indirect_sig(&mut self, func: &mut ir::Function, index: SignatureIndex) -> ir::SigRef { + let sig = self.module_decls.get_signature(index).unwrap().clone(); + func.import_signature(sig) + } + + fn make_direct_func(&mut self, func: &mut ir::Function, index: FuncIndex) -> ir::FuncRef { + let func_decl = self.module_decls.get_func(index).unwrap(); + let signature = func.import_signature(func_decl.signature.clone()); + let colocated = !func_decl.imported(); + func.import_function(ir::ExtFuncData { + name: func_decl.name.into(), + signature, + colocated, + }) + } + + fn translate_call( + &mut self, + mut pos: FuncCursor, + _callee_index: FuncIndex, + callee: ir::FuncRef, + call_args: &[ir::Value], + ) -> WasmResult { + let mut args: Vec = Vec::with_capacity(call_args.len() + 1); + args.extend_from_slice(call_args); + args.insert( + 0, + pos.func + .special_param(ir::ArgumentPurpose::VMContext) + .expect("vmctx available"), + ); + Ok(pos.ins().call(callee, &args)) + } + + fn translate_memory_grow( + &mut self, + mut pos: FuncCursor<'_>, + index: MemoryIndex, + _heap: ir::Heap, + val: ir::Value, + ) -> WasmResult { + assert!(index == MemoryIndex::new(0)); + // TODO memory grow function doesnt take heap index as argument + let mem_grow_func = self.get_runtime_func(RuntimeFunc::MemGrow, &mut pos.func); + let vmctx = pos + .func + .special_param(ir::ArgumentPurpose::VMContext) + .unwrap(); + let inst = pos.ins().call(mem_grow_func, &[vmctx, val]); + Ok(*pos.func.dfg.inst_results(inst).first().unwrap()) + } + + fn translate_memory_size( + &mut self, + mut pos: FuncCursor, + index: MemoryIndex, + _heap: ir::Heap, + ) -> WasmResult { + assert!(index == MemoryIndex::new(0)); + // TODO memory size function doesnt take heap index as argument + let mem_size_func = self.get_runtime_func(RuntimeFunc::MemSize, &mut pos.func); + let vmctx = pos + .func + .special_param(ir::ArgumentPurpose::VMContext) + .unwrap(); + let inst = pos.ins().call(mem_size_func, &[vmctx]); + Ok(*pos.func.dfg.inst_results(inst).first().unwrap()) + } +} diff --git a/lucetc/src/heap.rs b/lucetc/src/heap.rs new file mode 100644 index 000000000..0e99673d4 --- /dev/null +++ b/lucetc/src/heap.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct HeapSettings { + pub min_reserved_size: u64, + pub max_reserved_size: u64, + pub guard_size: u64, +} + +impl Default for HeapSettings { + fn default() -> Self { + Self { + min_reserved_size: 4 * 1024 * 1024, + max_reserved_size: 6 * 1024 * 1024 * 1024, + guard_size: 4 * 1024 * 1024, + } + } +} diff --git a/lucetc/src/lib.rs b/lucetc/src/lib.rs index 5ff59bef2..21ed7c59b 100644 --- a/lucetc/src/lib.rs +++ b/lucetc/src/lib.rs @@ -1,31 +1,34 @@ -pub mod bindings; -pub mod compiler; -pub mod error; -pub mod load; -pub mod patch; -pub mod program; - -use crate::compiler::data::{compile_data_initializers, compile_sparse_page_data}; -use crate::compiler::function::compile_function; -use crate::compiler::globals::compile_global_specs; -use crate::compiler::memory::compile_memory_specs; -use crate::compiler::module_data::compile_module_data; -use crate::compiler::table::compile_table; -use crate::error::{LucetcError, LucetcErrorKind}; -use crate::load::read_module; -use crate::patch::patch_module; -use crate::program::Program; -use failure::{format_err, Error, ResultExt}; -use parity_wasm::elements::Module; -use std::env; -use std::path::{Path, PathBuf}; -use tempfile; +mod bindings; +mod compiler; +mod decls; +mod error; +mod function; +mod heap; +mod load; +mod module; +mod name; +mod output; +mod patch; +mod pointer; +mod runtime; +mod sparsedata; +mod stack_probe; +mod table; +mod traps; pub use crate::{ bindings::Bindings, - compiler::{Compiler, OptLevel}, - program::memory::HeapSettings, + compiler::Compiler, + compiler::OptLevel, + error::{LucetcError, LucetcErrorKind}, + heap::HeapSettings, + load::read_module, + patch::patch_module, }; +use failure::{format_err, Error, ResultExt}; +use std::env; +use std::path::{Path, PathBuf}; +use tempfile; pub struct Lucetc { input: PathBuf, @@ -135,24 +138,20 @@ impl Lucetc { } } - fn build(&self) -> Result<(String, Module, Bindings), Error> { - let name = String::from( - self.input - .file_stem() - .ok_or(format_err!("input filename {:?} is empty", self.input))? - .to_str() - .ok_or(format_err!( - "input filename {:?} is not valid utf8", - self.input - ))?, - ); - let mut builtins_bindings = vec![]; - let mut module = read_module(&self.input)?; + fn build(&self) -> Result<(Vec, Bindings), Error> { + use parity_wasm::elements::{deserialize_buffer, serialize}; - for builtins in self.builtins_paths.iter() { - let (newmodule, builtins_map) = patch_module(module, builtins)?; - module = newmodule; - builtins_bindings.push(Bindings::env(builtins_map)); + let mut builtins_bindings = vec![]; + let mut module_binary = read_module(&self.input)?; + + if !self.builtins_paths.is_empty() { + let mut module = deserialize_buffer(&module_binary)?; + for builtins in self.builtins_paths.iter() { + let (newmodule, builtins_map) = patch_module(module, builtins)?; + module = newmodule; + builtins_bindings.push(Bindings::env(builtins_map)); + } + module_binary = serialize(module)?; } let mut bindings = Bindings::empty(); @@ -161,35 +160,43 @@ impl Lucetc { bindings.extend(binding)?; } - Ok((name, module, bindings)) + Ok((module_binary, bindings)) } - pub fn object_file>(self, output: P) -> Result<(), Error> { - let (name, module, bindings) = self.build()?; + pub fn object_file>(&self, output: P) -> Result<(), Error> { + let (module_contents, bindings) = self.build()?; - let prog = Program::new(module, bindings, self.heap)?; - let comp = compile(&prog, &name, self.opt_level)?; + let compiler = Compiler::new( + &module_contents, + self.opt_level, + &bindings, + self.heap.clone(), + )?; + let obj = compiler.object_file()?; - let obj = comp.codegen()?; obj.write(output.as_ref()).context("writing object file")?; - Ok(()) } - pub fn clif_ir>(self, output: P) -> Result<(), Error> { - let (name, module, bindings) = self.build()?; + pub fn clif_ir>(&self, output: P) -> Result<(), Error> { + let (module_contents, bindings) = self.build()?; - let prog = Program::new(module, bindings, self.heap.clone())?; - let comp = compile(&prog, &name, self.opt_level)?; + let compiler = Compiler::new( + &module_contents, + self.opt_level, + &bindings, + self.heap.clone(), + )?; - comp.cranelift_funcs() + compiler + .cranelift_funcs()? .write(&output) .context("writing clif file")?; Ok(()) } - pub fn shared_object_file>(self, output: P) -> Result<(), Error> { + pub fn shared_object_file>(&self, output: P) -> Result<(), Error> { let dir = tempfile::Builder::new().prefix("lucetc").tempdir()?; let objpath = dir.path().join("tmp.o"); self.object_file(objpath.clone())?; @@ -234,29 +241,3 @@ where } Ok(()) } - -pub fn compile<'p>( - program: &'p Program, - name: &str, - opt_level: OptLevel, -) -> Result, LucetcError> { - let mut compiler = Compiler::new(name.to_owned(), &program, opt_level)?; - - compile_data_initializers(&mut compiler).context(LucetcErrorKind::DataInitializers)?; - compile_sparse_page_data(&mut compiler).context(LucetcErrorKind::DataInitializers)?; - compile_memory_specs(&mut compiler).context(LucetcErrorKind::MemorySpecs)?; - compile_global_specs(&mut compiler).context(LucetcErrorKind::GlobalSpecs)?; - compile_module_data(&mut compiler).context(LucetcErrorKind::ModuleData)?; - - for function in program.defined_functions() { - let body = program.function_body(&function); - compile_function(&mut compiler, &function, body) - .context(LucetcErrorKind::Function(function.symbol().to_owned()))?; - } - for table in program.tables() { - compile_table(&mut compiler, &table) - .context(LucetcErrorKind::Table(table.symbol().to_owned()))?; - } - - Ok(compiler) -} diff --git a/lucetc/src/load.rs b/lucetc/src/load.rs index 6b49365e5..5b6140078 100644 --- a/lucetc/src/load.rs +++ b/lucetc/src/load.rs @@ -1,20 +1,17 @@ use failure::*; -use parity_wasm::deserialize_buffer; -pub use parity_wasm::elements::Module; use std::fs::File; use std::io::Read; use std::path::Path; use wabt::wat2wasm; -pub fn read_module>(path: P) -> Result { +pub fn read_module>(path: P) -> Result, Error> { let contents = read_to_u8s(path)?; - let wasm = if wasm_preamble(&contents) { + let converted = if wasm_preamble(&contents) { contents } else { wat2wasm(contents)? }; - let module_res = deserialize_buffer(&wasm); - module_res.map_err(|e| format_err!("deserializing wasm module: {}", e)) + Ok(converted) } pub fn read_to_u8s>(path: P) -> Result, Error> { diff --git a/lucetc/src/module.rs b/lucetc/src/module.rs new file mode 100644 index 000000000..aeb734b83 --- /dev/null +++ b/lucetc/src/module.rs @@ -0,0 +1,263 @@ +//! Implements ModuleEnvironment for cranelift-wasm. Code derived from cranelift-wasm/environ/dummy.rs +use crate::pointer::NATIVE_POINTER; +use cranelift_codegen::entity::{EntityRef, PrimaryMap}; +use cranelift_codegen::ir; +use cranelift_codegen::isa::TargetFrontendConfig; +use cranelift_wasm::{ + FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, ModuleEnvironment, SignatureIndex, Table, + TableElementType, TableIndex, WasmResult, +}; +use std::collections::{hash_map::Entry, HashMap}; + +#[derive(Debug, Clone)] +pub struct Exportable<'a, T> { + pub entity: T, + pub export_names: Vec<&'a str>, +} + +impl<'a, T> Exportable<'a, T> { + pub fn new(entity: T) -> Self { + Self { + entity, + export_names: Vec::new(), + } + } + pub fn push_export(&mut self, name: &'a str) { + self.export_names.push(name); + } +} + +#[derive(Debug, Clone)] +pub struct TableElems { + pub base: Option, + pub offset: usize, + pub elements: Box<[FuncIndex]>, +} + +#[derive(Debug, Clone)] +pub struct DataInitializer<'a> { + pub base: Option, + pub offset: usize, + pub data: &'a [u8], +} + +pub struct ModuleInfo<'a> { + /// Target description used for codegen + pub target_config: TargetFrontendConfig, + /// Provided by `declare_signature` + pub signatures: PrimaryMap, + /// Provided by `declare_func_import` + pub imported_funcs: PrimaryMap, + /// Provided by `declare_global_import` + pub imported_globals: PrimaryMap, + /// Provided by `declare_table_import` + pub imported_tables: PrimaryMap, + /// Provided by `declare_memory_import` + pub imported_memories: PrimaryMap, + /// Function signatures: imported and local + pub functions: PrimaryMap>, + /// Provided by `declare_table` + pub tables: PrimaryMap>, + /// Provided by `declare_memory` + pub memories: PrimaryMap>, + /// Provided by `declare_global` + pub globals: PrimaryMap>, + /// Provided by `declare_start_func` + pub start_func: Option, + + /// Function bodies: local only + pub function_bodies: HashMap, + + /// Table elements: local only + pub table_elems: HashMap>, + + /// Data initializers: local only + pub data_initializers: HashMap>>, +} + +impl<'a> ModuleInfo<'a> { + pub fn new(target_config: TargetFrontendConfig) -> Self { + Self { + target_config, + signatures: PrimaryMap::new(), + imported_funcs: PrimaryMap::new(), + imported_globals: PrimaryMap::new(), + imported_tables: PrimaryMap::new(), + imported_memories: PrimaryMap::new(), + functions: PrimaryMap::new(), + tables: PrimaryMap::new(), + memories: PrimaryMap::new(), + globals: PrimaryMap::new(), + start_func: None, + function_bodies: HashMap::new(), + table_elems: HashMap::new(), + data_initializers: HashMap::new(), + } + } +} + +impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { + fn target_config(&self) -> TargetFrontendConfig { + self.target_config + } + + fn declare_signature(&mut self, mut sig: ir::Signature) { + sig.params.insert( + 0, + ir::AbiParam::special(NATIVE_POINTER, ir::ArgumentPurpose::VMContext), + ); + self.signatures.push(sig); + } + + fn declare_func_import(&mut self, sig_index: SignatureIndex, module: &'a str, field: &'a str) { + debug_assert_eq!( + self.functions.len(), + self.imported_funcs.len(), + "import functions are declared first" + ); + self.functions.push(Exportable::new(sig_index)); + self.imported_funcs.push((module, field)); + } + + fn declare_global_import(&mut self, global: Global, module: &'a str, field: &'a str) { + debug_assert_eq!( + self.globals.len(), + self.imported_globals.len(), + "import globals are declared first" + ); + self.globals.push(Exportable::new(global)); + self.imported_globals.push((module, field)); + } + + fn declare_table_import(&mut self, table: Table, module: &'a str, field: &'a str) { + debug_assert_eq!( + self.tables.len(), + self.imported_tables.len(), + "import tables are declared first" + ); + self.tables.push(Exportable::new(table)); + self.imported_tables.push((module, field)); + } + + fn declare_memory_import(&mut self, memory: Memory, module: &'a str, field: &'a str) { + debug_assert_eq!( + self.memories.len(), + self.imported_memories.len(), + "import memories are declared first" + ); + self.data_initializers + .insert(MemoryIndex::new(self.memories.len()), vec![]); + self.memories.push(Exportable::new(memory)); + self.imported_memories.push((module, field)); + } + + fn declare_func_type(&mut self, sig_index: SignatureIndex) { + self.functions.push(Exportable::new(sig_index)); + } + + fn declare_table(&mut self, table: Table) { + self.table_elems + .insert(TableIndex::new(self.tables.len()), vec![]); + self.tables.push(Exportable::new(table)); + } + + fn declare_memory(&mut self, memory: Memory) { + self.data_initializers + .insert(MemoryIndex::new(self.memories.len()), vec![]); + self.memories.push(Exportable::new(memory)); + } + + fn declare_global(&mut self, global: Global) { + self.globals.push(Exportable::new(global)); + } + + fn declare_func_export(&mut self, func_index: FuncIndex, name: &'a str) { + self.functions + .get_mut(func_index) + .expect("export of declared function") + .push_export(name); + } + + fn declare_table_export(&mut self, table_index: TableIndex, name: &'a str) { + self.tables + .get_mut(table_index) + .expect("export of declared table") + .push_export(name); + } + + fn declare_memory_export(&mut self, memory_index: MemoryIndex, name: &'a str) { + self.memories + .get_mut(memory_index) + .expect("export of declared memory") + .push_export(name); + } + + fn declare_global_export(&mut self, global_index: GlobalIndex, name: &'a str) { + self.globals + .get_mut(global_index) + .expect("export of declared global") + .push_export(name); + } + + fn declare_start_func(&mut self, func_index: FuncIndex) { + debug_assert!( + self.start_func.is_none(), + "start func can only be defined once" + ); + self.start_func = Some(func_index); + } + + fn define_function_body(&mut self, body_bytes: &'a [u8], body_offset: usize) -> WasmResult<()> { + let func_index = FuncIndex::new(self.imported_funcs.len() + self.function_bodies.len()); + self.function_bodies + .insert(func_index, (body_bytes, body_offset)); + Ok(()) + } + + fn declare_table_elements( + &mut self, + table_index: TableIndex, + base: Option, + offset: usize, + elements: Box<[FuncIndex]>, + ) { + let table_elems = TableElems { + base, + offset, + elements, + }; + match self.table_elems.entry(table_index) { + Entry::Occupied(mut occ) => occ.get_mut().push(table_elems), + Entry::Vacant(vac) => { + if self.tables.len() == 0 && table_index == TableIndex::new(0) { + let table = Table { + ty: TableElementType::Func, + minimum: 0, + maximum: None, + }; + self.tables.push(Exportable::new(table)); + vac.insert(vec![table_elems]); + } else { + panic!("creation of elements for undeclared table! only table 0 is implicitly declared") // Do we implicitly declare them all???? i sure hope not + } + } + } + } + + fn declare_data_initialization( + &mut self, + memory_index: MemoryIndex, + base: Option, + offset: usize, + data: &'a [u8], + ) { + let data_init = DataInitializer { base, offset, data }; + match self.data_initializers.entry(memory_index) { + Entry::Occupied(mut occ) => occ.get_mut().push(data_init), + Entry::Vacant(_) => panic!( + "data initializer for undeclared memory {:?}: {:?}", + memory_index, data_init + ), + } + } +} diff --git a/lucetc/src/compiler/name.rs b/lucetc/src/name.rs similarity index 84% rename from lucetc/src/compiler/name.rs rename to lucetc/src/name.rs index cfcc24808..8238cf3ea 100644 --- a/lucetc/src/compiler/name.rs +++ b/lucetc/src/name.rs @@ -27,19 +27,23 @@ impl Name { &self.symbol } - pub fn into_funcid(&self) -> Option { + pub fn as_funcid(&self) -> Option { match self.id { FuncOrDataId::Func(id) => Some(id), FuncOrDataId::Data(_) => None, } } - pub fn into_dataid(&self) -> Option { + pub fn as_dataid(&self) -> Option { match self.id { FuncOrDataId::Data(id) => Some(id), FuncOrDataId::Func(_) => None, } } + + pub fn as_externalname(&self) -> ExternalName { + ExternalName::from(self.id) + } } impl From for ExternalName { diff --git a/lucetc/src/output.rs b/lucetc/src/output.rs new file mode 100644 index 000000000..9ff984bc9 --- /dev/null +++ b/lucetc/src/output.rs @@ -0,0 +1,60 @@ +use crate::name::Name; +use crate::stack_probe; +use crate::traps::write_trap_manifest; +use cranelift_codegen::{ir, isa}; +use cranelift_faerie::FaerieProduct; +use faerie::Artifact; +use failure::{format_err, Error, ResultExt}; +use std::collections::HashMap; +use std::fs::File; +use std::io::Write; +use std::path::Path; + +pub struct CraneliftFuncs { + funcs: HashMap, + isa: Box, +} + +impl CraneliftFuncs { + pub fn new(funcs: HashMap, isa: Box) -> Self { + Self { funcs, isa } + } + /// This outputs a .clif file + pub fn write>(&self, path: P) -> Result<(), Error> { + use cranelift_codegen::write_function; + let mut buffer = String::new(); + for (n, func) in self.funcs.iter() { + buffer.push_str(&format!("; {}\n", n.symbol())); + write_function(&mut buffer, func, Some(self.isa.as_ref())) + .context(format_err!("writing func {:?}", n))? + } + let mut file = File::create(path)?; + file.write_all(buffer.as_bytes())?; + Ok(()) + } +} + +pub struct ObjectFile { + artifact: Artifact, +} +impl ObjectFile { + pub fn new(mut product: FaerieProduct) -> Result { + stack_probe::declare_and_define(&mut product)?; + let trap_manifest = &product + .trap_manifest + .expect("trap manifest will be present"); + write_trap_manifest(trap_manifest, &mut product.artifact)?; + Ok(Self { + artifact: product.artifact, + }) + } + pub fn write>(&self, path: P) -> Result<(), Error> { + let _ = path.as_ref().file_name().ok_or(format_err!( + "path {:?} needs to have filename", + path.as_ref() + )); + let file = File::create(path)?; + self.artifact.write(file)?; + Ok(()) + } +} diff --git a/lucetc/src/pointer.rs b/lucetc/src/pointer.rs new file mode 100644 index 000000000..d90b26146 --- /dev/null +++ b/lucetc/src/pointer.rs @@ -0,0 +1,4 @@ +use cranelift_codegen::ir; + +pub const NATIVE_POINTER: ir::Type = ir::types::I64; +pub const NATIVE_POINTER_SIZE: usize = 8; diff --git a/lucetc/src/program/data/mod.rs b/lucetc/src/program/data/mod.rs deleted file mode 100644 index 6a75ac03a..000000000 --- a/lucetc/src/program/data/mod.rs +++ /dev/null @@ -1,70 +0,0 @@ -pub mod sparse; - -use super::init_expr::const_init_expr; -use failure::{format_err, Error, ResultExt}; -use parity_wasm::elements::Module; - -#[derive(Debug)] -pub struct DataInit<'m> { - pub offset: u32, - pub data: &'m [u8], -} - -impl<'m> DataInit<'m> { - pub fn linear_memory_range(&self, start: usize, end: usize) -> &'m [u8] { - let offs = self.offset as usize; - assert!(end >= start); - assert!(start >= offs); - assert!(start < offs + self.data.len()); - assert!(end >= offs); - assert!(end <= offs + self.data.len()); - &self.data[(start - offs)..(end - offs)] - } -} - -pub fn module_data<'m>(module: &'m Module) -> Result>, Error> { - let mut initializers = Vec::new(); - // XXX check the location of these init sections against the size of the memory imported or - // declared. That means we need to actually care about memories that we see in module.rs - if let Some(data_section) = module.data_section() { - for (segment_ix, segment) in data_section.entries().iter().enumerate() { - if segment.index() != 0 { - // https://webassembly.github.io/spec/syntax/modules.html#data-segments - return Err(format_err!( - "In the current version of WebAssembly, at most one memory is \ - allowed in a module. Consequently, the only valid memidx is 0 \ - (segment index={})", - segment.index(), - )); - } - - // Take the offset, and treat it as an unsigned 32 bit number. - // XXX need a type checked const_init_expr - this should always be a u32. - let offset = const_init_expr( - segment - .offset() - .as_ref() - .ok_or(format_err!("Offset not found"))? - .code(), - ) - .context(format!("data segment {}", segment_ix))? as u32; - - let max_lm_size: i64 = 0xFFFFFFFF; // 4GiB, per spec - - // Compare them at i64 so that they do not overflow - if (offset as i64) + (segment.value().len() as i64) > max_lm_size { - return Err(format_err!( - "initalizer does not fit in linear memory offset={} len={}", - offset, - segment.value().len() - )); - } - - initializers.push(DataInit { - offset: offset, - data: segment.value(), - }) - } - } - Ok(initializers) -} diff --git a/lucetc/src/program/data/sparse.rs b/lucetc/src/program/data/sparse.rs deleted file mode 100644 index c8468ceda..000000000 --- a/lucetc/src/program/data/sparse.rs +++ /dev/null @@ -1,85 +0,0 @@ -use super::DataInit; -use crate::program::memory::HeapSpec; -use std::collections::hash_map::Entry; -use std::collections::HashMap; - -pub use lucet_module_data::SparseData; - -const PAGE_SIZE: usize = 4096; - -fn split<'m>(di: &DataInit<'m>) -> Vec<(usize, DataInit<'m>)> { - let start = di.offset as usize; - let end = start + di.data.len(); - let mut offs = start; - let mut out = Vec::new(); - - while offs < end { - let page = offs / PAGE_SIZE; - let page_offs = offs % PAGE_SIZE; - let next = usize::min((page + 1) * PAGE_SIZE, end); - - let subslice = di.linear_memory_range(offs, next); - out.push(( - page, - DataInit { - offset: page_offs as u32, - data: subslice, - }, - )); - offs = next; - } - out -} - -pub struct OwnedSparseData { - pagemap: HashMap>, - heap: HeapSpec, -} - -impl OwnedSparseData { - pub fn new<'m>(data: &[DataInit<'m>], heap: HeapSpec) -> Self { - let mut pagemap: HashMap> = HashMap::new(); - - for d in data { - let chunks = split(d); - for (pagenumber, chunk) in chunks { - let base = chunk.offset as usize; - match pagemap.entry(pagenumber) { - Entry::Occupied(occ) => { - let occ = occ.into_mut(); - for (offs, data) in chunk.data.iter().enumerate() { - occ[base + offs] = *data; - } - assert!(occ.len() == PAGE_SIZE); - } - Entry::Vacant(vac) => { - let vac = vac.insert(Vec::new()); - vac.resize(PAGE_SIZE, 0); - for (offs, data) in chunk.data.iter().enumerate() { - vac[base + offs] = *data; - } - assert!(vac.len() == PAGE_SIZE); - } - } - } - } - Self { pagemap, heap } - } - - pub fn sparse_data(&self) -> SparseData { - assert_eq!(self.heap.initial_size as usize % PAGE_SIZE, 0); - let highest_page = self.heap.initial_size as usize / PAGE_SIZE; - - let mut out = Vec::new(); - for page_ix in 0..highest_page { - if let Some(chunk) = self.pagemap.get(&page_ix) { - assert!(chunk.len() == 4096); - out.push(Some(chunk.as_slice())) - } else { - out.push(None) - } - } - assert_eq!(out.len() * 4096, self.heap.initial_size as usize); - SparseData::new(out).expect("sparse data invariants held") - } -} diff --git a/lucetc/src/program/function.rs b/lucetc/src/program/function.rs deleted file mode 100644 index c9f902434..000000000 --- a/lucetc/src/program/function.rs +++ /dev/null @@ -1,179 +0,0 @@ -use crate::bindings::Bindings; -use crate::program::types::{CtonSignature, FunctionSig}; -use cranelift_codegen::ir; -use cranelift_module::Linkage; -use failure::Error; -use parity_wasm::elements::{FunctionType, ImportEntry}; - -pub trait Function { - fn signature(&self) -> ir::Signature; - fn signature_index(&self) -> Option; - fn linkage(&self) -> Linkage; - fn symbol(&self) -> &str; -} - -impl Function for FunctionImport { - fn signature(&self) -> ir::Signature { - self.signature() - } - fn signature_index(&self) -> Option { - Some(self.signature_index()) - } - fn linkage(&self) -> Linkage { - self.linkage() - } - fn symbol(&self) -> &str { - self.symbol() - } -} - -impl Function for FunctionDef { - fn signature(&self) -> ir::Signature { - self.signature() - } - fn signature_index(&self) -> Option { - Some(self.signature_index()) - } - fn linkage(&self) -> Linkage { - self.linkage() - } - fn symbol(&self) -> &str { - self.symbol() - } -} - -impl Function for FunctionRuntime { - fn signature(&self) -> ir::Signature { - self.signature() - } - fn signature_index(&self) -> Option { - None - } - fn linkage(&self) -> Linkage { - self.linkage() - } - fn symbol(&self) -> &str { - self.symbol() - } -} - -#[derive(Debug, Clone)] -pub struct FunctionDef { - pub wasmidx: u32, - sig: FunctionSig, - exported: bool, - symbol: String, -} - -impl FunctionDef { - pub fn new(wasmidx: u32, sig: FunctionSig, exported: bool, symbol: String) -> Self { - Self { - wasmidx, - sig, - exported, - symbol, - } - } - - pub fn signature(&self) -> ir::Signature { - self.sig.cton_signature() - } - - pub fn signature_index(&self) -> u32 { - self.sig.sig_ix - } - - pub fn symbol(&self) -> &str { - &self.symbol - } - - pub fn linkage(&self) -> Linkage { - if self.exported { - Linkage::Export - } else { - Linkage::Local - } - } -} - -#[derive(Debug, Clone)] -pub struct FunctionImport { - wasmidx: u32, - module: String, - field: String, - sig: FunctionSig, - symbol: String, -} - -impl FunctionImport { - pub fn new( - wasmidx: u32, - importentry: &ImportEntry, - sig: FunctionSig, - bindings: &Bindings, - ) -> Result { - let module = String::from(importentry.module()); - let field = String::from(importentry.field()); - let symbol = bindings.translate(&module, &field)?; - Ok(Self { - wasmidx, - module, - field, - sig, - symbol, - }) - } - - pub fn module(&self) -> &str { - self.module.as_str() - } - - pub fn field(&self) -> &str { - self.field.as_str() - } - - pub fn signature(&self) -> ir::Signature { - self.sig.cton_signature() - } - - pub fn signature_index(&self) -> u32 { - self.sig.sig_ix - } - - pub fn symbol(&self) -> &str { - &self.symbol - } - - pub fn linkage(&self) -> Linkage { - Linkage::Import - } -} - -#[derive(Debug, Clone)] -pub struct FunctionRuntime { - ix: u32, - symbol: String, - ty: FunctionType, -} - -impl FunctionRuntime { - pub fn new(ix: u32, symbol: &str, ty: FunctionType) -> Self { - Self { - ix: ix, - symbol: String::from(symbol), - ty: ty, - } - } - - pub fn signature(&self) -> ir::Signature { - self.ty.cton_signature() - } - - pub fn symbol(&self) -> &str { - &self.symbol - } - - pub fn linkage(&self) -> Linkage { - Linkage::Import - } -} diff --git a/lucetc/src/program/globals.rs b/lucetc/src/program/globals.rs deleted file mode 100644 index fd272f434..000000000 --- a/lucetc/src/program/globals.rs +++ /dev/null @@ -1,130 +0,0 @@ -use super::init_expr::const_init_expr; -use super::types::cton_valuetype; -use crate::error::LucetcError; -use cranelift_codegen::ir; -use parity_wasm::elements::{GlobalType, ImportEntry, InitExpr}; - -#[derive(Debug, Clone)] -pub struct GlobalImport { - module: String, - field: String, - pub global_type: GlobalType, - export: Option, -} - -impl GlobalImport { - pub fn new(importentry: &ImportEntry, global_type: GlobalType, export: Option) -> Self { - Self { - module: String::from(importentry.module()), - field: String::from(importentry.field()), - global_type, - export, - } - } - - pub fn cton_type(&self) -> ir::Type { - cton_valuetype(&self.global_type.content_type()) - } - - pub fn module(&self) -> &str { - self.module.as_str() - } - - pub fn field(&self) -> &str { - self.field.as_str() - } - - pub fn export(&self) -> Option<&str> { - match self.export { - Some(ref ex) => Some(ex.as_str()), - None => None, - } - } -} - -#[derive(Debug, Clone)] -pub struct GlobalDef { - global_type: GlobalType, - value: i64, - export: Option, -} - -impl GlobalDef { - pub fn new( - global_type: GlobalType, - init_expr: &InitExpr, - export: Option, - ) -> Result { - let value = const_init_expr(init_expr.code())?; - Ok(Self { - global_type: global_type, - value: value, - export: export, - }) - } - pub fn cton_type(&self) -> ir::Type { - cton_valuetype(&self.global_type.content_type()) - } - pub fn value(&self) -> i64 { - self.value - } - pub fn export(&self) -> Option<&str> { - match self.export { - Some(ref ex) => Some(ex.as_str()), - None => None, - } - } -} - -pub enum Global { - Import(GlobalImport), - Def(GlobalDef), -} - -impl Global { - pub fn cton_type(&self) -> ir::Type { - match self { - &Global::Import(ref globalimport) => globalimport.cton_type(), - &Global::Def(ref globaldef) => globaldef.cton_type(), - } - } - - pub fn as_import(&self) -> Option<&GlobalImport> { - match self { - Global::Import(i) => Some(i), - Global::Def(_) => None, - } - } - - pub fn as_def(&self) -> Option<&GlobalDef> { - match self { - Global::Import(_) => None, - Global::Def(d) => Some(d), - } - } - - pub fn export(&self) -> Option<&str> { - match self { - Global::Import(i) => i.export(), - Global::Def(d) => d.export(), - } - } -} - -use lucet_module_data as data; - -impl Global { - pub fn to_spec(&self) -> data::GlobalSpec { - let global = match self { - Global::Import(i) => data::Global::Import { - module: i.module(), - field: i.field(), - }, - Global::Def(d) => data::Global::Def { - def: data::GlobalDef::new(d.value()), - }, - }; - let export = self.export(); - data::GlobalSpec::new(global, export) - } -} diff --git a/lucetc/src/program/init_expr.rs b/lucetc/src/program/init_expr.rs deleted file mode 100644 index 95ace328d..000000000 --- a/lucetc/src/program/init_expr.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::error::{LucetcError, LucetcErrorKind}; -use failure::{format_err, ResultExt}; -use parity_wasm::elements::Instruction; - -pub fn const_init_expr(opcodes: &[Instruction]) -> Result { - let len = opcodes.len(); - if !(len >= 1 && opcodes[len - 1] == Instruction::End) { - Err(format_err!( - "invalid init expr: must be terminated with End opcode, got {:?}", - opcodes - ))?; - } - - if len > 2 { - Err(format_err!( - "init expr is too long to be a single const, got {:?}", - opcodes - )) - .context(LucetcErrorKind::Unsupported( - "non-const init expr".to_owned(), - ))?; - } - - match opcodes[0] { - Instruction::I32Const(i32_const) => Ok(i32_const as i64), - Instruction::I64Const(i64_const) => Ok(i64_const), - _ => Err(format_err!( - "init expr is not a const integer expr, got {:?}", - opcodes - )) - .context(LucetcErrorKind::Unsupported("non-int init expr".to_owned()))?, - } -} diff --git a/lucetc/src/program/memory.rs b/lucetc/src/program/memory.rs deleted file mode 100644 index 81df83f9b..000000000 --- a/lucetc/src/program/memory.rs +++ /dev/null @@ -1,58 +0,0 @@ -use failure::{bail, Error}; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MemorySpec { - pub initial_pages: u32, - pub max_pages: Option, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct HeapSettings { - pub min_reserved_size: u64, - pub max_reserved_size: u64, - pub guard_size: u64, -} - -impl Default for HeapSettings { - fn default() -> Self { - Self { - min_reserved_size: 4 * 1024 * 1024, - max_reserved_size: 6 * 1024 * 1024 * 1024, - guard_size: 4 * 1024 * 1024, - } - } -} - -pub use lucet_module_data::HeapSpec; -pub fn create_heap_spec(mem: &MemorySpec, heap: &HeapSettings) -> Result { - let wasm_page: u64 = 64 * 1024; - - let initial_size = mem.initial_pages as u64 * wasm_page; - - let reserved_size = std::cmp::max(initial_size, heap.min_reserved_size); - - if reserved_size > heap.max_reserved_size { - bail!( - "module reserved size ({}) exceeds max reserved size ({})", - initial_size, - heap.max_reserved_size, - ); - } - - // Find the max size permitted by the heap and the memory spec - let max_size = mem.max_pages.map(|pages| pages as u64 * wasm_page); - Ok(HeapSpec { - reserved_size, - guard_size: heap.guard_size, - initial_size: initial_size, - max_size: max_size, - }) -} -pub fn empty_heap_spec() -> HeapSpec { - HeapSpec { - reserved_size: 0, - guard_size: 0, - initial_size: 0, - max_size: None, - } -} diff --git a/lucetc/src/program/mod.rs b/lucetc/src/program/mod.rs deleted file mode 100644 index 80143c10e..000000000 --- a/lucetc/src/program/mod.rs +++ /dev/null @@ -1,393 +0,0 @@ -pub mod data; -pub mod function; -pub mod globals; -pub mod init_expr; -pub mod memory; -pub mod names; -pub mod runtime; -pub mod table; -pub mod types; - -pub use self::data::{module_data, DataInit}; -pub use self::function::{Function, FunctionDef, FunctionImport, FunctionRuntime}; -pub use self::globals::{Global, GlobalDef, GlobalImport}; -pub use self::memory::{create_heap_spec, empty_heap_spec, HeapSettings, HeapSpec, MemorySpec}; -pub use self::names::{module_names, ModuleNames}; -pub use self::runtime::Runtime; -pub use self::table::{TableBuilder, TableDef}; -pub use self::types::{CtonSignature, FunctionSig}; - -use crate::bindings::Bindings; -use crate::error::{LucetcError, LucetcErrorKind}; -use crate::program::init_expr::const_init_expr; -use failure::{format_err, ResultExt}; -use parity_wasm::elements::{External, FuncBody, MemoryType, Module, TableElementType, Type}; -use pwasm_validation::validate_module; -use std::collections::{hash_map::Entry, HashMap}; - -pub struct Program { - module: Module, - - globals: Vec, - tables: Vec, - runtime: Runtime, - heap_settings: HeapSettings, - - defined_funcs: Vec, - defined_memory: Option, - - import_functions: Vec, - import_memory: Option, -} - -impl Program { - pub fn new( - module: Module, - bindings: Bindings, - heap_settings: HeapSettings, - ) -> Result { - let module = module.parse_names().map_err(|(es, _)| { - format_err!("could not parse some of the name sections: {:?}", es) - })?; - - let module = validate_module(module)?.unwrap(); - let names = module_names(&module)?; - let imports = module_imports(&module, bindings, &names)?; - let defs = module_definitions(&module, &imports, &names)?; - let tables = module_tables(&module, imports.tables)?; - let globals = module_globals(imports.globals, defs.globals); - let runtime = Runtime::liblucet_runtime_c(); - Ok(Self { - module, - globals, - tables, - runtime, - heap_settings, - defined_funcs: defs.funcs, - defined_memory: defs.memory, - - import_functions: imports.functions, - import_memory: imports.memory, - }) - } - - pub fn module(&self) -> &Module { - &self.module - } - - pub fn get_function(&self, index: u32) -> Result<&Function, LucetcError> { - if let Some(fnindex) = index.checked_sub(self.import_functions.len() as u32) { - if let Some(def) = self.defined_funcs.get(fnindex as usize) { - Ok(def) - } else { - Err(format_err!("function index {} is out of bounds", index))? - } - } else { - Ok(self - .import_functions - .get(index as usize) - .expect("function import index was checked")) - } - } - - pub fn globals(&self) -> &[Global] { - self.globals.as_ref() - } - - pub fn get_signature(&self, index: u32) -> Result { - module_get_signature(&self.module, index) - } - - pub fn tables(&self) -> &[TableDef] { - &self.tables - } - - pub fn get_table(&self, index: u32) -> Result<&TableDef, LucetcError> { - let tbl = self - .tables - .get(index as usize) - .ok_or_else(|| format_err!("table out of range: {}", index))?; - Ok(tbl) - } - - pub fn runtime_functions(&self) -> &[FunctionRuntime] { - self.runtime.functions() - } - - pub fn get_runtime_function(&self, name: &str) -> Result<&FunctionRuntime, LucetcError> { - self.runtime.get_symbol(name) - } - - pub fn heap_spec(&self) -> Result { - if let Some(ref mem_spec) = self.import_memory { - Ok(create_heap_spec(mem_spec, &self.heap_settings) - .context(LucetcErrorKind::MemorySpecs)?) - } else if let Some(ref mem_spec) = self.defined_memory { - Ok(create_heap_spec(mem_spec, &self.heap_settings) - .context(LucetcErrorKind::MemorySpecs)?) - } else { - Ok(empty_heap_spec()) - } - } - - pub fn data_initializers(&self) -> Result, LucetcError> { - let v = module_data(&self.module)?; - Ok(v) - } - - pub fn function_body(&self, def: &FunctionDef) -> &FuncBody { - let bodies = self - .module - .code_section() - .map(|s| s.bodies()) - .unwrap_or(&[]); - let fn_index_base = self.import_functions.len(); - &bodies - .get(def.wasmidx as usize - fn_index_base) - .expect("functiondef points to valid body") - } - - pub fn defined_functions(&self) -> &[FunctionDef] { - self.defined_funcs.as_ref() - } - - pub fn import_functions(&self) -> &[FunctionImport] { - self.import_functions.as_ref() - } -} - -pub struct ModuleTables { - pub tables: Vec, -} - -enum TableDecl { - Import(TableDef), - Def(TableBuilder), -} - -fn memory_spec(mem: &MemoryType) -> MemorySpec { - let limits = mem.limits(); - MemorySpec { - initial_pages: limits.initial(), - max_pages: limits.maximum(), - } -} - -fn module_get_signature(module: &Module, index: u32) -> Result { - let type_entry = module - .type_section() - .ok_or_else(|| LucetcErrorKind::Other("no types in this module".to_owned()))? - .types() - .get(index as usize) - .ok_or_else(|| LucetcErrorKind::Other(format!("no signature for {}", index)))?; - match type_entry { - &Type::Function(ref ftype) => Ok(FunctionSig::new(index, ftype)), - } -} - -struct ModuleImports { - memory: Option, - functions: Vec, - globals: Vec, - tables: Vec, -} - -impl ModuleImports { - pub fn function_index_base(&self) -> u32 { - self.functions.len() as u32 - } - pub fn global_index_base(&self) -> u32 { - self.globals.len() as u32 - } -} - -fn module_imports( - module: &Module, - bindings: Bindings, - names: &ModuleNames, -) -> Result { - let mut memory = None; - let mut functions = Vec::new(); - let mut globals = Vec::new(); - let mut tables = Vec::new(); - if let Some(import_section) = module.import_section() { - for entry in import_section.entries().iter() { - match entry.external() { - &External::Function(typeix) => { - let functionix = functions.len() as u32; - let ftype = module_get_signature(&module, typeix)?; - functions.push(FunctionImport::new(functionix, entry, ftype, &bindings)?) - } - &External::Global(ref gty) => { - let globalix = globals.len() as u32; - globals.push(GlobalImport::new( - entry, - gty.clone(), - names.global_symbol(globalix), - )) - } - - &External::Table(ref tty) => { - let tableix = tables.len() as u32; - let builder = - TableBuilder::new(tableix, tty.limits().initial(), tty.limits().maximum())?; - tables.push(builder.finalize()); - } - &External::Memory(ref mem) => memory = Some(memory_spec(mem)), - } - } - } - Ok(ModuleImports { - memory, - functions, - globals, - tables, - }) -} - -struct ModuleDefs { - funcs: Vec, - globals: Vec, - memory: Option, -} - -fn module_definitions( - module: &Module, - imports: &ModuleImports, - names: &ModuleNames, -) -> Result { - let mut memory = None; - - let decls = module - .function_section() - .map(|s| s.entries()) - .unwrap_or(&[]); - let mut funcs = Vec::new(); - for (ix, decl) in decls.iter().enumerate() { - let funcindex = ix as u32 + imports.function_index_base(); - - funcs.push(FunctionDef::new( - funcindex, - module_get_signature(&module, decl.type_ref()).expect("signature for func must exist"), - names.function_exported(funcindex), - names.function_symbol(funcindex), - )) - } - - if let Some(memory_types) = module.memory_section().map(|s| s.entries()) { - if memory_types.len() > 1 { - Err(format_err!("multiple memories are not supported"))? - } - for memory_type in memory_types.iter() { - memory = Some(memory_spec(memory_type)) - } - } - - let mut globals = Vec::new(); - if let Some(global_decls) = module.global_section().map(|s| s.entries()) { - for (ix, decl) in global_decls.iter().enumerate() { - let globalindex = ix as u32 + imports.global_index_base(); - globals.push(GlobalDef::new( - decl.global_type().clone(), - decl.init_expr(), - names.global_symbol(globalindex), - )?) - } - } - Ok(ModuleDefs { - funcs, - globals, - memory, - }) -} - -fn module_tables( - module: &Module, - import_tables: Vec, -) -> Result, LucetcError> { - let mut tables = HashMap::new(); - for tbl in import_tables.iter() { - tables.insert(tbl.index(), TableDecl::Import(tbl.clone())); - } - if let Some(table_section) = module.table_section() { - for table_type in table_section.entries().iter() { - match table_type.elem_type() { - TableElementType::AnyFunc => { - let section_index = 0; - match tables.entry(section_index) { - Entry::Occupied(occ) => match occ.get() { - TableDecl::Import(_) => Err(format_err!( - "Cannot define table {}: already declared as import", - section_index - ))?, - TableDecl::Def(_) => Err(format_err!( - "Cannot define table {}: already defined", - section_index - ))?, - }, - Entry::Vacant(vac) => { - vac.insert(TableDecl::Def(TableBuilder::new( - section_index, - table_type.limits().initial(), - table_type.limits().maximum(), - )?)); - } - } - } - } - } - if let Some(element_section) = module.elements_section() { - for (segment_ix, element_segment) in element_section.entries().iter().enumerate() { - let table_ix = element_segment.index(); - let offs: i64 = const_init_expr( - element_segment - .offset() - .as_ref() - .ok_or(format_err!("Offset not found"))? - .code(), - ) - .context(LucetcErrorKind::Other(format!( - "in element segment offset for table {}, segment {}", - table_ix, segment_ix - )))?; - // Ensure its safe to make into an i32: - assert!(offs >= ::min_value() as i64 && offs <= ::max_value() as i64); - match tables.get_mut(&table_ix) { - Some(TableDecl::Def(ref mut builder)) => builder - .push_elements(offs as i32, element_segment.members().to_vec()) - .context(LucetcErrorKind::Other(format!( - "in elements for table {}, segment {}", - table_ix, segment_ix - )))?, - Some(TableDecl::Import(_)) => Err(format_err!( - "Cannot define element for imported table {}", - table_ix - ))?, - None => Err(format_err!( - "Cannot define element for undeclared table {}", - table_ix - ))?, - } - } - } - } - let tables = tables - .values() - .map(|decl| match decl { - TableDecl::Import(def) => def.clone(), - TableDecl::Def(builder) => builder.finalize(), - }) - .collect(); - Ok(tables) -} - -fn module_globals(imports: Vec, defs: Vec) -> Vec { - let mut globals = Vec::new(); - for g in imports { - globals.push(Global::Import(g.clone())); - } - for g in defs { - globals.push(Global::Def(g.clone())); - } - globals -} diff --git a/lucetc/src/program/names.rs b/lucetc/src/program/names.rs deleted file mode 100644 index aa14e5e6b..000000000 --- a/lucetc/src/program/names.rs +++ /dev/null @@ -1,135 +0,0 @@ -use crate::error::LucetcError; -use bimap::BiMap; -use parity_wasm::elements::{Internal, Module, NameSection, Section}; -use std::collections::HashMap; - -pub struct ModuleNames { - func_exports: Vec, - func_names: BiMap, - glob_exports: HashMap, -} - -impl ModuleNames { - pub fn function_symbol(&self, ix: u32) -> String { - let n = self.func_names.get_by_left(&ix); - if self.function_exported(ix) { - format!("guest_func_{}", n.expect("exported name must be defined")) - } else { - if let Some(n) = n { - format!("guest_internalfunc_{}", n) - } else { - format!("guest_internalfunc_{}", ix) - } - } - } - pub fn function_exported(&self, ix: u32) -> bool { - self.func_exports.contains(&ix) - } - pub fn global_symbol(&self, ix: u32) -> Option { - self.glob_exports.get(&(ix as usize)).cloned() - } -} - -fn define_unique_name(func_names: &mut BiMap, ix: u32, n: String) { - assert!(!func_names.contains_left(&ix)); - if func_names.contains_right(&n) { - // Name is not unique, search for one: - let mut suffix: usize = 1; - loop { - let n_uniq = format!("{}_{}", n, suffix); - if !func_names.contains_right(&n_uniq) { - func_names.insert(ix, n_uniq); - break; - } - suffix += 1; - } - } else { - func_names.insert(ix, n); - } -} - -pub fn module_names(module: &Module) -> Result { - let mut func_exports = Vec::new(); - let mut func_names = BiMap::new(); - let mut glob_exports = HashMap::new(); - - if let Some(export_entries) = module.export_section().map(|s| s.entries()) { - for entry in export_entries.iter() { - match *entry.internal() { - Internal::Function(idx) => { - func_exports.push(idx); - func_names.insert(idx, entry.field().to_owned()); - } - Internal::Global(idx) => { - glob_exports.insert(idx as usize, String::from(entry.field())); - } - Internal::Table(_) => {} // We do not do anything with exported tables - Internal::Memory(_) => {} // We do not do anything with exported memories - } - } - } - - for section in module.sections() { - match *section { - Section::Name(ref name_section) => match *name_section { - NameSection::Function(ref func_sect) => { - for (idx, name) in func_sect.names() { - if !func_names.contains_left(&idx) { - define_unique_name(&mut func_names, idx, name.clone()); - func_names.insert(idx, name.to_owned()); - } - } - } - _ => {} - }, - _ => {} - } - } - - Ok(ModuleNames { - func_exports, - glob_exports, - func_names, - }) -} - -#[cfg(test)] -mod tests { - use super::define_unique_name; - use bimap::BiMap; - #[test] - fn trivial() { - let mut func_names = BiMap::new(); - func_names.insert(0, "zero".to_owned()); - define_unique_name(&mut func_names, 1, "one".to_owned()); - assert_eq!(func_names.get_by_left(&1), Some(&"one".to_owned())); - } - - #[test] - fn one_dup() { - let mut func_names = BiMap::new(); - func_names.insert(0, "foo".to_owned()); - define_unique_name(&mut func_names, 1, "foo".to_owned()); - assert_eq!(func_names.get_by_left(&1), Some(&"foo_1".to_owned())); - } - - #[test] - fn two_dup() { - let mut func_names = BiMap::new(); - func_names.insert(0, "foo".to_owned()); - define_unique_name(&mut func_names, 1, "foo".to_owned()); - define_unique_name(&mut func_names, 2, "foo".to_owned()); - assert_eq!(func_names.get_by_left(&1), Some(&"foo_1".to_owned())); - assert_eq!(func_names.get_by_left(&2), Some(&"foo_2".to_owned())); - } - - #[test] - fn dup_of_base() { - let mut func_names = BiMap::new(); - func_names.insert(0, "foo_1".to_owned()); - define_unique_name(&mut func_names, 1, "foo".to_owned()); - define_unique_name(&mut func_names, 2, "foo".to_owned()); - assert_eq!(func_names.get_by_left(&1), Some(&"foo".to_owned())); - assert_eq!(func_names.get_by_left(&2), Some(&"foo_2".to_owned())); - } -} diff --git a/lucetc/src/program/runtime.rs b/lucetc/src/program/runtime.rs deleted file mode 100644 index c4b7de332..000000000 --- a/lucetc/src/program/runtime.rs +++ /dev/null @@ -1,45 +0,0 @@ -use super::function::FunctionRuntime; -use crate::error::LucetcError; -use failure::format_err; -use parity_wasm::elements::{FunctionType, ValueType}; - -#[derive(Debug, Clone)] -pub struct Runtime { - funcs: Vec, -} - -impl Runtime { - pub fn liblucet_runtime_c() -> Self { - let current_memory_type = FunctionType::new(Vec::new(), Some(ValueType::I32)); - let grow_memory_type = FunctionType::new(vec![ValueType::I32], Some(ValueType::I32)); - Self { - funcs: vec![ - FunctionRuntime::new(0, "lucet_vmctx_current_memory", current_memory_type), - FunctionRuntime::new(1, "lucet_vmctx_grow_memory", grow_memory_type), - ], - } - } - - pub fn functions(&self) -> &[FunctionRuntime] { - self.funcs.as_ref() - } - - pub fn get_index(&self, ix: u32) -> Result { - let rt = self - .funcs - .get(ix as usize) - .map(|f| f.clone()) - .ok_or(format_err!("runtime function {} out of bounds", ix))?; - Ok(rt) - } - - pub fn get_symbol(&self, symbol: &str) -> Result<&FunctionRuntime, LucetcError> { - let symbol = String::from(symbol); - for f in self.funcs.iter() { - if f.symbol() == symbol { - return Ok(f); - } - } - Err(format_err!("runtime function \"{}\" not found", symbol))? - } -} diff --git a/lucetc/src/program/table.rs b/lucetc/src/program/table.rs deleted file mode 100644 index 804e22ee9..000000000 --- a/lucetc/src/program/table.rs +++ /dev/null @@ -1,114 +0,0 @@ -use failure::{format_err, Error}; -use std::cmp; -use std::collections::HashMap; - -#[derive(Debug, Clone)] -pub struct TableBuilder { - index: u32, - min_size: u32, - max_size: Option, - /// Map from icall index to function - elems: HashMap, -} - -impl TableBuilder { - pub fn new(index: u32, min_size: u32, max_size: Option) -> Result { - if let Some(max_size) = max_size { - if min_size > max_size { - return Err(format_err!( - "table size max ({}) less than min ({})", - max_size, - min_size - )); - } - } - Ok(Self { - index: index, - min_size: min_size, - max_size: max_size, - elems: HashMap::new(), - }) - } - - pub fn push_elements(&mut self, offset: i32, elems: Vec) -> Result<(), Error> { - if offset < 0 { - return Err(format_err!( - "table elements given at negative offset {}", - offset - )); - } - - for (i, e) in elems.iter().enumerate() { - if i > ::max_value() as usize { - return Err(format_err!("table element at {} out-of-bounds", i)); - } - // Note: we do not validate that `e` is the index of a valid function. We count on - // `compiler::table` to check on this. - if let Some(max_size) = self.max_size { - if (i as u32) >= max_size { - return Err(format_err!( - "table element at {} beyond declared maximum size {}", - i, - max_size - )); - } - } - self.elems.insert(offset as usize + i, *e); - } - Ok(()) - } - - fn capacity(&self) -> usize { - // Guaranteed by `push_elements` to be <= (max - 1) if there is a max. - let highest_index = *self.elems.keys().max().unwrap_or(&0); - // Make table big enough to represent greatest index, or the given minimum size. - cmp::max(highest_index + 1, self.min_size as usize) - } - - pub fn finalize(&self) -> TableDef { - let capacity = self.capacity(); - let mut elems = Vec::with_capacity(capacity); - for index in 0..capacity { - match self.elems.get(&index) { - Some(value) => elems.push(TableElem::FunctionIx(*value)), - None => elems.push(TableElem::Empty), - } - } - - TableDef { - index: self.index, - elems: elems, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum TableElem { - Empty, - FunctionIx(u32), -} - -#[derive(Debug, Clone)] -pub struct TableDef { - index: u32, - elems: Vec, -} - -impl TableDef { - pub fn index(&self) -> u32 { - self.index - } - pub fn elements(&self) -> &[TableElem] { - &self.elems - } - pub fn symbol(&self) -> String { - format!("guest_table_{}", self.index) - } - pub fn len(&self) -> u64 { - assert!(self.elems.len() <= ::std::u32::MAX as usize); - self.elems.len() as u64 * (2 * 8) - } - pub fn len_symbol(&self) -> String { - format!("{}_len", self.symbol()) - } -} diff --git a/lucetc/src/program/types.rs b/lucetc/src/program/types.rs deleted file mode 100644 index d6e03d10b..000000000 --- a/lucetc/src/program/types.rs +++ /dev/null @@ -1,61 +0,0 @@ -use cranelift_codegen::{ir, isa}; -use parity_wasm::elements::{FunctionType, ValueType}; - -#[derive(Debug, Clone)] -pub struct FunctionSig { - pub sig_ix: u32, - ftype: FunctionType, -} - -impl FunctionSig { - pub fn new(sig_ix: u32, ftype: &FunctionType) -> Self { - Self { - sig_ix: sig_ix, - ftype: ftype.clone(), - } - } -} - -pub fn cton_valuetype(t: &ValueType) -> ir::Type { - match t { - &ValueType::I32 => ir::types::I32, - &ValueType::I64 => ir::types::I64, - &ValueType::F32 => ir::types::F32, - &ValueType::F64 => ir::types::F64, - &ValueType::V128 => unimplemented!(), - } -} - -pub trait CtonSignature { - fn cton_signature(&self) -> ir::Signature; -} - -impl CtonSignature for FunctionType { - fn cton_signature(&self) -> ir::Signature { - let mut sig = ir::Signature::new(isa::CallConv::SystemV); - sig.params.insert( - 0, - ir::AbiParam { - value_type: ir::types::I64, - purpose: ir::ArgumentPurpose::VMContext, - extension: ir::ArgumentExtension::None, - location: ir::ArgumentLoc::Unassigned, - }, - ); - sig.params.extend( - self.params() - .iter() - .map(|t| ir::AbiParam::new(cton_valuetype(t))), - ); - if let Some(t) = self.return_type() { - sig.returns.push(ir::AbiParam::new(cton_valuetype(&t))); - } - sig - } -} - -impl CtonSignature for FunctionSig { - fn cton_signature(&self) -> ir::Signature { - self.ftype.cton_signature() - } -} diff --git a/lucetc/src/runtime.rs b/lucetc/src/runtime.rs new file mode 100644 index 000000000..7f2a2aba5 --- /dev/null +++ b/lucetc/src/runtime.rs @@ -0,0 +1,48 @@ +use cranelift_codegen::ir::{types, AbiParam, ArgumentPurpose, Signature}; +use cranelift_codegen::isa::TargetFrontendConfig; +use std::collections::HashMap; + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)] +pub enum RuntimeFunc { + MemSize, + MemGrow, +} + +pub struct Runtime { + pub functions: HashMap, +} + +impl Runtime { + pub fn lucet(target: TargetFrontendConfig) -> Self { + let mut functions = HashMap::new(); + functions.insert( + RuntimeFunc::MemSize, + ( + "lucet_vmctx_current_memory".to_owned(), + Signature { + params: vec![AbiParam::special( + target.pointer_type(), + ArgumentPurpose::VMContext, + )], + returns: vec![AbiParam::new(types::I32)], + call_conv: target.default_call_conv, + }, + ), + ); + functions.insert( + RuntimeFunc::MemGrow, + ( + "lucet_vmctx_grow_memory".to_owned(), + Signature { + params: vec![ + AbiParam::special(target.pointer_type(), ArgumentPurpose::VMContext), + AbiParam::new(types::I32), // wasm pages to grow + ], + returns: vec![AbiParam::new(types::I32)], + call_conv: target.default_call_conv, + }, + ), + ); + Self { functions } + } +} diff --git a/lucetc/src/sparsedata.rs b/lucetc/src/sparsedata.rs new file mode 100644 index 000000000..418923dfb --- /dev/null +++ b/lucetc/src/sparsedata.rs @@ -0,0 +1,103 @@ +use crate::error::{LucetcError, LucetcErrorKind}; +use crate::module::DataInitializer; +use failure::{format_err, ResultExt}; +use lucet_module_data::owned::OwnedSparseData; +use lucet_module_data::HeapSpec; +use std::collections::hash_map::Entry; +use std::collections::HashMap; + +pub use lucet_module_data::SparseData; + +const PAGE_SIZE: usize = 4096; + +fn linear_memory_range<'a>(di: &DataInitializer<'a>, start: usize, end: usize) -> &'a [u8] { + let offs = di.offset as usize; + // The range of linear memory we're interested in is: + // valid: end is past the start + assert!(end >= start); + // in this initializer: starts at or past the offset of this initializer, + assert!(start >= offs); + // and before the end of this initializer, + assert!(start < offs + di.data.len()); + // ends past the offset of this initializer (redundant: implied by end >= start), + assert!(end >= offs); + // and ends before or at the end of this initializer. + assert!(end <= offs + di.data.len()); + &di.data[(start - offs)..(end - offs)] +} + +fn split<'a>(di: &DataInitializer<'a>) -> Vec<(usize, DataInitializer<'a>)> { + // Divide a data initializer for linear memory into a set of data initializers for pages, and + // the index of the page they cover. + // The input initializer can cover many pages. Each output initializer covers exactly one. + let start = di.offset as usize; + let end = start + di.data.len(); + let mut offs = start; + let mut out = Vec::new(); + + while offs < end { + let page = offs / PAGE_SIZE; + let page_offs = offs % PAGE_SIZE; + let next = usize::min((page + 1) * PAGE_SIZE, end); + + let subslice = linear_memory_range(di, offs, next); + out.push(( + page, + DataInitializer { + base: None, + offset: page_offs, + data: subslice, + }, + )); + offs = next; + } + out +} + +pub fn owned_sparse_data_from_initializers<'a>( + initializers: &[DataInitializer<'a>], + heap: &HeapSpec, +) -> Result { + let mut pagemap: HashMap> = HashMap::new(); + + for initializer in initializers { + if initializer.base.is_some() { + Err(format_err!( + "cannot create sparse data: data initializer uses global as base" + )) + .context(LucetcErrorKind::Unsupported)? + } + let chunks = split(initializer); + for (pagenumber, chunk) in chunks { + if pagenumber > heap.initial_size as usize / PAGE_SIZE { + Err(format_err!( + "cannot initialize data beyond linear memory's initial size" + )) + .context(LucetcErrorKind::Validation)?; + } + let base = chunk.offset as usize; + let page = match pagemap.entry(pagenumber) { + Entry::Occupied(occ) => occ.into_mut(), + Entry::Vacant(vac) => vac.insert(vec![0; PAGE_SIZE]), + }; + page[base..base + chunk.data.len()].copy_from_slice(chunk.data); + debug_assert!(page.len() == PAGE_SIZE); + } + } + + assert_eq!(heap.initial_size as usize % PAGE_SIZE, 0); + let highest_page = heap.initial_size as usize / PAGE_SIZE; + + let mut out = Vec::new(); + for page_ix in 0..highest_page { + if let Some(chunk) = pagemap.remove(&page_ix) { + assert!(chunk.len() == 4096); + out.push(Some(chunk)) + } else { + out.push(None) + } + } + assert_eq!(out.len() * 4096, heap.initial_size as usize); + let o = OwnedSparseData::new(out).context(LucetcErrorKind::ModuleData)?; + Ok(o) +} diff --git a/lucetc/src/compiler/stack_probe.rs b/lucetc/src/stack_probe.rs similarity index 100% rename from lucetc/src/compiler/stack_probe.rs rename to lucetc/src/stack_probe.rs diff --git a/lucetc/src/table.rs b/lucetc/src/table.rs new file mode 100644 index 000000000..8ae16b595 --- /dev/null +++ b/lucetc/src/table.rs @@ -0,0 +1,122 @@ +use crate::decls::{ModuleDecls, TableDecl}; +use crate::error::{LucetcError, LucetcErrorKind}; +use crate::pointer::NATIVE_POINTER_SIZE; +use byteorder::{LittleEndian, WriteBytesExt}; +use cranelift_codegen::entity::EntityRef; +use cranelift_module::{Backend as ClifBackend, DataContext, Module as ClifModule}; +use cranelift_wasm::{FuncIndex, TableElementType, TableIndex}; +use failure::{format_err, ResultExt}; +use std::io::Cursor; + +#[derive(Debug, Clone)] +enum Elem { + Func(FuncIndex), + Empty, +} + +fn table_elements(decl: &TableDecl) -> Result, LucetcError> { + match decl.table.ty { + TableElementType::Func => Ok(()), + _ => Err(format_err!("table with non-function elements: {:?}", decl)) + .context(LucetcErrorKind::Unsupported), + }?; + + let mut elems = Vec::new(); + + for initializer in decl.elems.iter() { + if initializer.base.is_some() { + Err(format_err!( + "table elements with global index base: {:?}", + initializer + )) + .context(LucetcErrorKind::Unsupported)? + } + let final_len = initializer.offset + initializer.elements.len(); + if final_len > elems.len() { + elems.resize(final_len, Elem::Empty); + } + for (ix, func_ix) in initializer.elements.iter().enumerate() { + elems[initializer.offset + ix] = Elem::Func(*func_ix); + } + } + + Ok(elems) +} + +pub fn write_table_data( + clif_module: &mut ClifModule, + decls: &ModuleDecls, +) -> Result<(), LucetcError> { + if let Ok(table_decl) = decls.get_table(TableIndex::new(0)) { + // Indirect calls are performed by looking up the callee function and type in a table that + // is present in the same object file. + // The table is an array of pairs of (type index, function pointer). Both elements in the + // pair are the size of a pointer. + // This function creates that table as a section in the object. + let elements = table_elements(&table_decl)?; + + let mut table_data = + Cursor::new(Vec::with_capacity(elements.len() * 2 * NATIVE_POINTER_SIZE)); + fn putelem(table: &mut Cursor>, elem: u64) { + table.write_u64::(elem).unwrap() + } + + let mut table_ctx = DataContext::new(); + + // table.elems is a vector that gives every entry of the table, either specifying the + // wasm function index or that no element was given for that table entry. + for elem in elements.iter() { + match elem { + Elem::Func(func_index) => { + // Note: this is the only place we validate that the table entry points to a valid + // function. If this is ever removed, make sure this check happens elsewhere. + let func = decls + .get_func(*func_index) + .context(LucetcErrorKind::Table)?; + // First element in row is the SignatureIndex for the function + putelem(&mut table_data, func.signature_index.as_u32() as u64); + + // Second element in row is the pointer to the function. The Reloc is doing the work + // here. We put a 0 in the table data itself to be overwritten at link time. + let funcref = table_ctx.import_function(func.name.into()); + let position = table_data.position(); + assert!(position < ::max_value() as u64); + table_ctx.write_function_addr(position as u32, funcref); + putelem(&mut table_data, 0); + } + // EMPTY: + Elem::Empty => { + // First element is the signature index. These will always be 32 bits in wasm, so + // u64::max will always be out of bounds. + putelem(&mut table_data, ::max_value()); + // Second element is the function pointer. No relocation here, it will always be + // null. + putelem(&mut table_data, 0); + } + } + } + table_ctx.define(table_data.into_inner().into_boxed_slice()); + let table_id = table_decl + .contents_name + .as_dataid() + .expect("tables are data"); + clif_module + .define_data(table_id, &table_ctx) + .context(LucetcErrorKind::Table)?; + + { + // Define the length of the table as a u64: + let mut len_data = Cursor::new(Vec::with_capacity(8)); + len_data + .write_u64::(elements.len() as u64) + .unwrap(); + let mut table_len_ctx = DataContext::new(); + table_len_ctx.define(len_data.into_inner().into_boxed_slice()); + let table_len_id = table_decl.len_name.as_dataid().expect("tables are data"); + clif_module + .define_data(table_len_id, &table_len_ctx) + .context(LucetcErrorKind::Table)?; + } + } + Ok(()) +} diff --git a/lucetc/src/compiler/traps.rs b/lucetc/src/traps.rs similarity index 95% rename from lucetc/src/compiler/traps.rs rename to lucetc/src/traps.rs index 7efe1893d..f8c667a3d 100644 --- a/lucetc/src/compiler/traps.rs +++ b/lucetc/src/traps.rs @@ -121,7 +121,7 @@ fn serialize_trapcode(code: ir::TrapCode) -> u32 { ir::TrapCode::BadConversionToInteger => 7, ir::TrapCode::Interrupt => 8, ir::TrapCode::TableOutOfBounds => 9, - ir::TrapCode::UnreachableCodeReached => (u16::max_value() - 1) as u32, // XXX this used to be User(0) - ir::TrapCode::User(x) => ((u16::max_value() - 1) as u32) | ((x as u32) << 16), + ir::TrapCode::UnreachableCodeReached => 10 as u32, + ir::TrapCode::User(_) => panic!("we should never emit a user trapcode"), } } diff --git a/lucetc/tests/harnesses/call.c b/lucetc/tests/harnesses/call.c deleted file mode 100644 index ca6692326..000000000 --- a/lucetc/tests/harnesses/call.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "vm.h" - -void guest_func_main(struct vmctx *); - -int main() -{ - struct VM *vm = make_vm(); - guest_func_main(get_vmctx(vm)); - return 0; -} diff --git a/lucetc/tests/harnesses/current_memory.c b/lucetc/tests/harnesses/current_memory.c deleted file mode 100644 index d5aab68fc..000000000 --- a/lucetc/tests/harnesses/current_memory.c +++ /dev/null @@ -1,25 +0,0 @@ -#include "vm.h" -#include -#include - -void guest_func_main(struct vmctx *); - -bool got_call = false; - -uint32_t lucet_vmctx_current_memory(struct vmctx *unused) -{ - got_call = true; - return 1234; -} - -int main() -{ - struct VM *vm = make_vm(); - guest_func_main(get_vmctx(vm)); - - uint32_t res = *(uint32_t *) vm->heap; - assert(got_call); - assert(res == 1234); - - return 0; -} diff --git a/lucetc/tests/harnesses/data_segment.c b/lucetc/tests/harnesses/data_segment.c deleted file mode 100644 index f6fdf1486..000000000 --- a/lucetc/tests/harnesses/data_segment.c +++ /dev/null @@ -1,92 +0,0 @@ -#include "vm.h" -#include -#include -#include -#include - -// IMPORTANT: this is a copy of the definition of this struct in liblucet. -// If changes are made to this, make sure they are also made in liblucet! -struct wasm_data_segment { - uint32_t memory_index; - uint32_t offset; - uint32_t length; - char data[]; -}; - -void guest_func_main(struct vmctx *); - -extern char wasm_data_segments[]; -extern int wasm_data_segments_len; - -int main() -{ - // Run guest program and ensure the result is correct (see corresponding .wat - // for details) - struct VM *vm = make_vm(); - guest_func_main(get_vmctx(vm)); - - uint32_t output = ((uint32_t *) vm->heap)[0]; - uint32_t expected_output = 0; - if (output != expected_output) { - printf("Output was %u\n", output); - return 1; - } - - // Define expected data segment initialization data - - int n_expected = 3; - struct wasm_data_segment *expected[n_expected]; - - const char bytes_0[] = { '9', '9', '9', '9', '9' }; - struct wasm_data_segment *ds = malloc(sizeof(struct wasm_data_segment) + sizeof(bytes_0)); - memcpy(ds, - &(struct wasm_data_segment const){ - .memory_index = 0, .offset = 0, .length = sizeof(bytes_0) }, - sizeof(struct wasm_data_segment)); - memcpy((char *) ds + sizeof(struct wasm_data_segment), bytes_0, sizeof(bytes_0)); - expected[0] = ds; - - const char bytes_1[] = { 0xaa, 0xbb }; // see .wat for defn - ds = malloc(sizeof(struct wasm_data_segment) + sizeof(bytes_1)); - memcpy(ds, - &(struct wasm_data_segment const){ - .memory_index = 0, .offset = 0, .length = sizeof(bytes_1) }, - sizeof(struct wasm_data_segment)); - memcpy((char *) ds + sizeof(struct wasm_data_segment), bytes_1, sizeof(bytes_1)); - expected[1] = ds; - - const char bytes_2[] = { 0xcc, 0xdd }; // see .wat for defn - ds = malloc(sizeof(struct wasm_data_segment) + sizeof(bytes_2)); - memcpy(ds, - &(struct wasm_data_segment const){ - .memory_index = 0, .offset = 1, .length = sizeof(bytes_2) }, - sizeof(struct wasm_data_segment)); - memcpy((char *) ds + sizeof(struct wasm_data_segment), bytes_2, sizeof(bytes_2)); - expected[2] = ds; - - // Make sure data segment initialization data in ELF matches expectation - - int i = 0; // current data segment - int p = 0; // current position in wasm_data_segment - while (p < wasm_data_segments_len) { - struct wasm_data_segment *deserialized = - (struct wasm_data_segment *) &wasm_data_segments[p]; - assert(deserialized->length == expected[i]->length); - assert(deserialized->memory_index == expected[i]->memory_index); - assert(deserialized->offset == expected[i]->offset); - - int j; - for (j = 0; j < deserialized->length; j++) { - assert(deserialized->data[j] == expected[i]->data[j]); - } - p += sizeof(struct wasm_data_segment) + deserialized->length; - p += (8 - p % 8) % 8; - i += 1; - } - - for (i = 0; i < n_expected; i++) { - free(expected[i]); - } - - return 0; -} diff --git a/lucetc/tests/harnesses/fibonacci.c b/lucetc/tests/harnesses/fibonacci.c deleted file mode 100644 index 008d44148..000000000 --- a/lucetc/tests/harnesses/fibonacci.c +++ /dev/null @@ -1,18 +0,0 @@ -#include "vm.h" - -void guest_func_main(struct vmctx *); - -int main() -{ - struct VM *vm = make_vm(); - guest_func_main(get_vmctx(vm)); - - // fibonacci.wat writes the result of to mem location 0 as an i32. - uint32_t output = ((uint32_t *) vm->heap)[0]; - uint32_t expected = 21; - if (output != expected) { - printf("Output was %u\n", output); - return 1; - } - return 0; -} diff --git a/lucetc/tests/harnesses/globals.c b/lucetc/tests/harnesses/globals.c deleted file mode 100644 index 2090138b6..000000000 --- a/lucetc/tests/harnesses/globals.c +++ /dev/null @@ -1,21 +0,0 @@ - -#include "globals.h" -#include -#include - -void initialize_globals(struct VM *vm, struct global_table const *tbl) -{ - uint64_t num = tbl->num_descriptors; - assert(num < GLOBALS_SIZE); - - for (int i = 0; i < num; i++) { - struct global_description *descriptor = - (struct global_description *) ((uintptr_t) tbl + sizeof(uint64_t) + - (i * sizeof(struct global_description))); - if (!(descriptor->flags & GLOBALS_FLAG_IMPORT)) { - vm->globals[i] = descriptor->initial_value; - } else { - errx(1, "%s() unit testing of imports is not supported", __FUNCTION__); - } - } -} diff --git a/lucetc/tests/harnesses/globals.h b/lucetc/tests/harnesses/globals.h deleted file mode 100644 index f597373e8..000000000 --- a/lucetc/tests/harnesses/globals.h +++ /dev/null @@ -1,28 +0,0 @@ - -#ifndef GLOBALS_H -#define GLOBALS_H - -#include "vm.h" - -// Each global is either an internal definition (which has an initial value), or -// an import, whose initial value is determined elsewhere. The 0th bit is set -// when it is an import. -#define GLOBALS_FLAG_IMPORT (1 << 0) -// Each global that is an import, and some globals that are internally defined, -// have a name. This bit is set when the char* name field points to a valid -// name. -#define GLOBALS_FLAG_VALID_NAME (1 << 1) - -struct global_description { - uint64_t flags; - int64_t initial_value; - char * name; -}; - -struct global_table { - uint64_t num_descriptors; -}; - -void initialize_globals(struct VM *, struct global_table const *); - -#endif // GLOBALS_H diff --git a/lucetc/tests/harnesses/globals_definition.c b/lucetc/tests/harnesses/globals_definition.c deleted file mode 100644 index d9e4aa2ae..000000000 --- a/lucetc/tests/harnesses/globals_definition.c +++ /dev/null @@ -1,36 +0,0 @@ - -#include "globals.h" -#include "vm.h" -#include -#include - -extern const struct global_table lucet_globals_spec; - -void guest_func_main(struct vmctx *); - -int main() -{ - struct VM *vm = make_vm(); - - assert(vm->globals[0] == 0); - assert(vm->globals[1] == 0); - assert(vm->globals[2] == 0); - - initialize_globals(vm, &lucet_globals_spec); - - assert(vm->globals[0] == 4); - assert(vm->globals[1] == 5); - assert(vm->globals[2] == 6); - - guest_func_main(get_vmctx(vm)); - - assert(vm->globals[0] == 3); - assert(vm->globals[1] == 2); - - uint32_t *heap_globals = (uint32_t *) vm->heap; - assert(heap_globals[0] == 4); - assert(heap_globals[1] == 5); - assert(heap_globals[2] == 6); - - return 0; -} diff --git a/lucetc/tests/harnesses/grow_memory.c b/lucetc/tests/harnesses/grow_memory.c deleted file mode 100644 index 599de80f7..000000000 --- a/lucetc/tests/harnesses/grow_memory.c +++ /dev/null @@ -1,28 +0,0 @@ -#include "vm.h" -#include -#include - -void guest_func_main(struct vmctx *); - -uint32_t arg = 0; -bool got_call = false; - -uint32_t lucet_vmctx_grow_memory(struct VM *unused, uint32_t pages) -{ - got_call = true; - arg = pages; - return 1234; -} - -int main() -{ - struct VM *vm = make_vm(); - guest_func_main(get_vmctx(vm)); - - uint32_t res = *(uint32_t *) vm->heap; - assert(got_call); - assert(res == 1234); - assert(arg = 5678); - - return 0; -} diff --git a/lucetc/tests/harnesses/heap_spec.h b/lucetc/tests/harnesses/heap_spec.h deleted file mode 100644 index 2b47f5ae3..000000000 --- a/lucetc/tests/harnesses/heap_spec.h +++ /dev/null @@ -1,12 +0,0 @@ - -#include - -struct lucet_heap_spec { - uint64_t reserved_size; - uint64_t guard_size; - uint64_t initial_size; - uint64_t max_size; - uint64_t max_size_valid; // Just a boolean -}; - -extern struct lucet_heap_spec lucet_heap_spec; diff --git a/lucetc/tests/harnesses/heap_spec_definition.c b/lucetc/tests/harnesses/heap_spec_definition.c deleted file mode 100644 index 583fa5839..000000000 --- a/lucetc/tests/harnesses/heap_spec_definition.c +++ /dev/null @@ -1,14 +0,0 @@ -#include "heap_spec.h" -#include - -int main() -{ - // These constants should match up with the unit test in tests/wasm.rs - assert(lucet_heap_spec.reserved_size == 4 * 1024 * 1024); - assert(lucet_heap_spec.guard_size == 4 * 1024 * 1024); - assert(lucet_heap_spec.initial_size == 5 * 64 * 1024); - assert(lucet_heap_spec.max_size == 0); - assert(lucet_heap_spec.max_size_valid == 0); - - return 0; -} diff --git a/lucetc/tests/harnesses/heap_spec_import.c b/lucetc/tests/harnesses/heap_spec_import.c deleted file mode 100644 index 16284b4dc..000000000 --- a/lucetc/tests/harnesses/heap_spec_import.c +++ /dev/null @@ -1,16 +0,0 @@ -#include -#include - -#include "heap_spec.h" - -int main() -{ - // These constants should match up with the unit test in tests/wasm.rs - assert(lucet_heap_spec.reserved_size == 4 * 1024 * 1024); - assert(lucet_heap_spec.guard_size == (4 * 1024 * 1024)); - assert(lucet_heap_spec.initial_size == (6 * 64 * 1024)); - assert(lucet_heap_spec.max_size == (10 * 64 * 1024)); - assert(lucet_heap_spec.max_size_valid == 1); - - return 0; -} diff --git a/lucetc/tests/harnesses/icall.c b/lucetc/tests/harnesses/icall.c deleted file mode 100644 index 6212d7f3a..000000000 --- a/lucetc/tests/harnesses/icall.c +++ /dev/null @@ -1,43 +0,0 @@ -#include "vm.h" -#include -#include -#include - -uint32_t guest_func_foo(struct vmctx *, uint32_t icall_dest); - -struct table_elem { - uint64_t type_tag; - void * function_ptr; -}; -extern struct table_elem guest_table_0[]; -extern uint8_t guest_table_0_len[8]; - -int main() -{ - struct VM *vm = make_vm(); - uint32_t res_0 = guest_func_foo(get_vmctx(vm), 0); - uint32_t res_1 = guest_func_foo(get_vmctx(vm), 1); - assert(res_0 == 1); - assert(res_1 == 2); - - // Check table length - assert(guest_table_0_len[0] == 3 * 2 * 8); - assert(guest_table_0_len[1] == 0); - assert(guest_table_0_len[2] == 0); - assert(guest_table_0_len[3] == 0); - assert(guest_table_0_len[4] == 0); - assert(guest_table_0_len[5] == 0); - assert(guest_table_0_len[6] == 0); - assert(guest_table_0_len[7] == 0); - - // Table functions 0 and 1 have the same type. Function 2 has a different type. - assert(guest_table_0[0].type_tag == guest_table_0[1].type_tag); - assert(guest_table_0[0].type_tag != guest_table_0[2].type_tag); - - // All table functions point to a valid function - assert(guest_table_0[0].function_ptr != NULL); - assert(guest_table_0[1].function_ptr != NULL); - assert(guest_table_0[2].function_ptr != NULL); - - return 0; -} diff --git a/lucetc/tests/harnesses/icall_import.c b/lucetc/tests/harnesses/icall_import.c deleted file mode 100644 index 87596f568..000000000 --- a/lucetc/tests/harnesses/icall_import.c +++ /dev/null @@ -1,48 +0,0 @@ -#include "vm.h" -#include -#include -#include -#include - -uint32_t guest_func_launchpad(struct vmctx *, uint32_t icall_dest, uint32_t input_a, - uint32_t input_b); - -bool expect_icall_to_env = false; -struct vmctx *expected_vmctx = NULL; - -uint32_t icalltarget(struct vmctx *ctx, uint32_t input_a, uint32_t input_b) -{ - assert(expect_icall_to_env); - assert(ctx == expected_vmctx); - return input_a * input_b; -} - -int main() -{ - struct VM *vm = make_vm(); - - // Table entry 0 adds the two inputs - uint32_t res_0 = guest_func_launchpad(get_vmctx(vm), 0, 123, 456); - assert(res_0 == (123 + 456)); - - uint32_t res_1 = guest_func_launchpad(get_vmctx(vm), 0, 789, 10); - assert(res_1 == (789 + 10)); - - // Table entry 1 subtracts the two inputs - uint32_t res_2 = guest_func_launchpad(get_vmctx(vm), 1, 123, 456); - assert(res_2 == (123 - 456)); - - uint32_t res_3 = guest_func_launchpad(get_vmctx(vm), 1, 789, 10); - assert(res_3 == (789 - 10)); - - // table entry #2 has wrong type. - - // Table entry 3 should call `icalltarget` above. That function multiplies - // its two inputs. - expect_icall_to_env = true; - expected_vmctx = get_vmctx(vm); - uint32_t res_4 = guest_func_launchpad(get_vmctx(vm), 3, 123, 456); - assert(res_4 == (123 * 456)); - - return 0; -} diff --git a/lucetc/tests/harnesses/icall_sparse.c b/lucetc/tests/harnesses/icall_sparse.c deleted file mode 100644 index 26808b18c..000000000 --- a/lucetc/tests/harnesses/icall_sparse.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "vm.h" -#include -#include -#include - -uint32_t guest_func_foo(struct vmctx *, uint32_t icall_dest); - -struct table_elem { - uint64_t type_tag; - void * function_ptr; -}; -extern struct table_elem guest_table_0[]; - -int main() -{ - struct VM *vm = make_vm(); - uint32_t res_0 = guest_func_foo(get_vmctx(vm), 1); - uint32_t res_1 = guest_func_foo(get_vmctx(vm), 2); - assert(res_0 == 1); - assert(res_1 == 2); - - // Table elements 0, 4, and 5 are empty. - assert(guest_table_0[0].type_tag == UINT64_MAX); - assert(guest_table_0[0].function_ptr == NULL); - assert(guest_table_0[4].type_tag == UINT64_MAX); - assert(guest_table_0[4].function_ptr == NULL); - assert(guest_table_0[5].type_tag == UINT64_MAX); - assert(guest_table_0[5].function_ptr == NULL); - - // Table functions 1 and 2 have the same type. Function 3 has a different type. - assert(guest_table_0[1].type_tag == guest_table_0[2].type_tag); - assert(guest_table_0[1].type_tag != guest_table_0[3].type_tag); - - // Non-empty table functions point to a valid function - assert(guest_table_0[1].function_ptr != NULL); - assert(guest_table_0[2].function_ptr != NULL); - assert(guest_table_0[3].function_ptr != NULL); - - return 0; -} diff --git a/lucetc/tests/harnesses/import_many.c b/lucetc/tests/harnesses/import_many.c deleted file mode 100644 index 7db33dd26..000000000 --- a/lucetc/tests/harnesses/import_many.c +++ /dev/null @@ -1,44 +0,0 @@ -#include "vm.h" -#include - -void guest_func_main(struct vmctx *); - -uint32_t stage; - -uint32_t imp_0(void) -{ - assert(stage == 0); - stage = 1; - return 1; -} - -uint32_t imp_1(void) -{ - assert(stage == 1); - stage = 2; - return 2; -} - -uint32_t imp_2(void) -{ - assert(stage == 2); - stage = 3; - return 3; -} - -uint32_t imp_3(void) -{ - assert(stage == 3); - stage = 4; - return 4; -} - -int main() -{ - struct VM *vm = make_vm(); - stage = 0; - guest_func_main(get_vmctx(vm)); - assert(stage == 4); - - return 0; -} diff --git a/lucetc/tests/harnesses/locals.c b/lucetc/tests/harnesses/locals.c deleted file mode 100644 index f5ecdc54c..000000000 --- a/lucetc/tests/harnesses/locals.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "vm.h" - -uint32_t guest_func_main(struct vmctx *); - -int main() -{ - struct VM *vm = make_vm(); - uint32_t ret = guest_func_main(get_vmctx(vm)); - uint32_t expected = 74; - if (ret != expected) { - printf("Output was %u, expected %u\n", ret, expected); - return 1; - } - - return 0; -} diff --git a/lucetc/tests/harnesses/locals_csr.c b/lucetc/tests/harnesses/locals_csr.c deleted file mode 100644 index 5d575d88e..000000000 --- a/lucetc/tests/harnesses/locals_csr.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "vm.h" - -uint32_t guest_func_main(struct vmctx *); - -int main() -{ - struct VM *vm = make_vm(); - uint32_t ret = guest_func_main(get_vmctx(vm)); - uint32_t expected = 34; - if (ret != expected) { - printf("Output was %u, expected %u\n", ret, expected); - return 1; - } - - return 0; -} diff --git a/lucetc/tests/harnesses/strstr.c b/lucetc/tests/harnesses/strstr.c deleted file mode 100644 index b11c8172e..000000000 --- a/lucetc/tests/harnesses/strstr.c +++ /dev/null @@ -1,11 +0,0 @@ -#include "vm.h" - -void guest_func_strstr(struct vmctx *); - -int main() -{ - struct VM *vm = make_vm(); - guest_func_strstr(get_vmctx(vm), 0, 0, 0); - - return 0; -} diff --git a/lucetc/tests/harnesses/vm.c b/lucetc/tests/harnesses/vm.c deleted file mode 100644 index 0f95e4e3f..000000000 --- a/lucetc/tests/harnesses/vm.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "vm.h" -#include -#include -#include - -static struct VM vm; - -struct VM *make_vm(void) -{ - memset(vm.heap, 0, HEAP_SIZE); - memset(vm.heap, 0, GLOBALS_SIZE * sizeof(int64_t)); - vm.global_ptr = vm.globals; - return &vm; -} - -struct vmctx *get_vmctx(struct VM *the_vm) -{ - return (struct vmctx *) &the_vm->heap; -} - -struct VM *get_vm(struct vmctx *the_vmctx) -{ - assert(the_vmctx == get_vmctx(&vm)); - return &vm; -} - -uint32_t lucet_vmctx_grow_memory(struct vmctx *ctx, uint32_t pages) __attribute__((weak)); -uint32_t lucet_vmctx_grow_memory(struct vmctx *ctx, uint32_t pages) -{ - assert(get_vm(ctx) == &vm); - (void) pages; - return 0; -} - -uint32_t lucet_vmctx_current_memory(struct vmctx *ctx) __attribute__((weak)); -uint32_t lucet_vmctx_current_memory(struct vmctx *ctx) -{ - assert(get_vm(ctx) == &vm); - return 1; -} diff --git a/lucetc/tests/harnesses/vm.h b/lucetc/tests/harnesses/vm.h deleted file mode 100644 index 43e410d61..000000000 --- a/lucetc/tests/harnesses/vm.h +++ /dev/null @@ -1,24 +0,0 @@ - -#ifndef VM_H -#define VM_H - -#include - -#define GLOBALS_SIZE 128 -#define HEAP_SIZE (64 * 1024) - -struct VM { - int64_t globals[GLOBALS_SIZE]; - int64_t *global_ptr; // This should be initialized to point at &vm.globals - char heap[HEAP_SIZE]; -}; - -struct VM *make_vm(void); - -struct vmctx; - -struct vmctx *get_vmctx(struct VM *); - -struct VM *get_vm(struct vmctx *); - -#endif // VM_H diff --git a/lucetc/tests/wasi-sdk.rs b/lucetc/tests/wasi-sdk.rs index 92355ba3e..ba1b72ce3 100644 --- a/lucetc/tests/wasi-sdk.rs +++ b/lucetc/tests/wasi-sdk.rs @@ -1,14 +1,14 @@ use failure::{Error, ResultExt}; use lucet_wasi_sdk::{CompileOpts, Link, LinkOpt, LinkOpts}; -use lucetc::bindings::Bindings; -use lucetc::load; -use parity_wasm::elements::Module; +use lucetc::Bindings; use std::collections::HashMap; +use std::fs::File; +use std::io::Read; use std::path::PathBuf; use std::str; use tempfile; -fn module_from_c(cfiles: &[&str], exports: &[&str]) -> Result { +fn module_from_c(cfiles: &[&str], exports: &[&str]) -> Result, Error> { let cfiles: Vec = cfiles .iter() .map(|ref name| PathBuf::from(format!("tests/wasi-sdk/{}.c", name))) @@ -30,8 +30,10 @@ fn module_from_c(cfiles: &[&str], exports: &[&str]) -> Result { } linker.link(wasm.clone())?; - let m = load::read_module(&wasm).context(format!("loading module built from {:?}", cfiles))?; - Ok(m) + let mut wasm_file = File::open(wasm)?; + let mut wasm_contents = Vec::new(); + wasm_file.read_to_end(&mut wasm_contents)?; + Ok(wasm_contents) } fn b_only_test_bindings() -> Bindings { @@ -47,50 +49,53 @@ fn b_only_test_bindings() -> Bindings { mod programs { use super::{b_only_test_bindings, module_from_c}; - use cranelift_module::Linkage; - use lucetc::bindings::Bindings; - use lucetc::compile; - use lucetc::compiler::OptLevel; - use lucetc::program::{HeapSettings, Program}; - - fn num_import_globals(p: &Program) -> usize { - p.globals() - .iter() - .filter_map(|g| g.as_import()) - .collect::>() - .len() - } - - fn num_export_functions(p: &Program) -> usize { - p.defined_functions() - .iter() - .filter(|f| f.linkage() == Linkage::Export) - .collect::>() - .len() - } + use lucetc::{Bindings, Compiler, HeapSettings, OptLevel}; #[test] fn empty() { let m = module_from_c(&["empty"], &[]).expect("build module for empty"); let b = Bindings::empty(); let h = HeapSettings::default(); - let p = Program::new(m, b, h).expect("create program for empty"); + let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile empty"); + let mdata = c.module_data(); + assert!(mdata.heap_spec().is_some()); + // clang creates 3 globals, all internal: + assert_eq!(mdata.globals_spec().len(), 3); + assert_eq!( + mdata + .globals_spec() + .iter() + .filter(|g| g.export().is_some()) + .collect::>() + .len(), + 0 + ); + + /* FIXME: module data doesn't contain the information to check these properties: assert_eq!(p.import_functions().len(), 0, "import functions"); assert_eq!(num_import_globals(&p), 0, "import globals"); assert_eq!(num_export_functions(&p), 0, "export functions"); - let _c = compile(&p, "empty".into(), OptLevel::Best).expect("compile empty"); + */ + + let _obj = c.object_file().expect("generate code from empty"); } #[test] fn just_a() { let m = module_from_c(&["a"], &["a"]).expect("build module for a"); + let b = Bindings::empty(); let h = HeapSettings::default(); - let p = Program::new(m, b, h).expect("create program for a"); + let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile a"); + let _mdata = c.module_data(); + + /* FIXME: module data doesn't contain the information to check these properties: assert_eq!(p.import_functions().len(), 0, "import functions"); assert_eq!(num_import_globals(&p), 0, "import globals"); assert_eq!(num_export_functions(&p), 1, "export functions"); - let _c = compile(&p, "a_only".into(), OptLevel::Best).expect("compile a"); + */ + + let _obj = c.object_file().expect("generate code from a"); } #[test] @@ -98,11 +103,14 @@ mod programs { let m = module_from_c(&["b"], &["b"]).expect("build module for b"); let b = b_only_test_bindings(); let h = HeapSettings::default(); - let p = Program::new(m, b, h).expect("create program for b"); + let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile b"); + let _mdata = c.module_data(); + /* FIXME: module data doesn't contain the information to check these properties: assert_eq!(p.import_functions().len(), 1, "import functions"); assert_eq!(num_import_globals(&p), 0, "import globals"); assert_eq!(num_export_functions(&p), 1, "export functions"); - let _c = compile(&p, "b_only".into(), OptLevel::Best).expect("compile b"); + */ + let _obj = c.object_file().expect("generate code from b"); } #[test] @@ -110,11 +118,14 @@ mod programs { let m = module_from_c(&["a", "b"], &["a", "b"]).expect("build module for a & b"); let b = Bindings::empty(); let h = HeapSettings::default(); - let p = Program::new(m, b, h).expect("create program for a & b"); + let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile a & b"); + let _mdata = c.module_data(); + /* FIXME: module data doesn't contain the information to check these properties: assert_eq!(p.import_functions().len(), 0, "import functions"); assert_eq!(num_import_globals(&p), 0, "import globals"); assert_eq!(num_export_functions(&p), 2, "export functions"); - let _c = compile(&p, "a_and_b".into(), OptLevel::Best).expect("compile a & b"); + */ + let _obj = c.object_file().expect("generate code from a & b"); } } diff --git a/lucetc/tests/wasm.rs b/lucetc/tests/wasm.rs index bf896b390..f92a91d04 100644 --- a/lucetc/tests/wasm.rs +++ b/lucetc/tests/wasm.rs @@ -1,12 +1,16 @@ -use lucetc::bindings::Bindings; -use lucetc::load; -use parity_wasm::elements::Module; +use lucetc::Bindings; use std::collections::HashMap; use std::path::PathBuf; -fn load(name: &str) -> Module { +fn load_wat_module(name: &str) -> Vec { + use std::fs::File; + use std::io::Read; + use wabt::wat2wasm; let watfile = PathBuf::from(&format!("tests/wasm/{}.wat", name)); - load::read_module(&watfile).expect(&format!("loading module from {:?}", watfile)) + let mut contents = Vec::new(); + let mut file = File::open(&watfile).expect("open module file"); + file.read_to_end(&mut contents).expect("read module file"); + wat2wasm(contents).expect("convert module to wasm binary format") } fn test_bindings() -> Bindings { @@ -25,56 +29,59 @@ fn test_bindings() -> Bindings { Bindings::env(imports) } -mod programs { - /// Tests of the `Program` datastructure. - use super::load; - use lucetc::bindings::Bindings; - use lucetc::program::{table::TableElem, HeapSettings, Program}; - use parity_wasm::elements::ValueType; +mod module_data { + /// Tests of the `ModuleData` generated by the lucetc Compiler + use super::load_wat_module; + use lucetc::{Bindings, Compiler, HeapSettings, LucetcErrorKind, OptLevel}; use std::path::PathBuf; #[test] fn fibonacci() { - let m = load("fibonacci"); + let m = load_wat_module("fibonacci"); let b = super::test_bindings(); let h = HeapSettings::default(); - let p = Program::new(m, b, h).expect(&format!("instantiating program")); + let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compiling fibonacci"); + assert_eq!(c.module_data().globals_spec().len(), 0); + /* TODO can't express these with module data assert_eq!(p.import_functions().len(), 0); - assert_eq!(p.globals().len(), 0); assert_eq!(p.defined_functions().len(), 1); assert_eq!( p.defined_functions().get(0).unwrap().symbol(), "guest_func_main" ); + */ } #[test] fn arith() { - let m = load("arith"); + let m = load_wat_module("arith"); let b = Bindings::empty(); let h = HeapSettings::default(); - let p = Program::new(m, b, h).expect(&format!("instantiating program")); + let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compiling arith"); + assert_eq!(c.module_data().globals_spec().len(), 0); + /* TODO can't express these with module data assert_eq!(p.import_functions().len(), 0); - assert_eq!(p.globals().len(), 0); assert_eq!(p.defined_functions().len(), 1); assert_eq!( p.defined_functions().get(0).unwrap().symbol(), "guest_func_main" ); + */ } - #[test] fn icall_import() { - let m = load("icall_import"); + let m = load_wat_module("icall_import"); let b = Bindings::from_file(&PathBuf::from( "tests/bindings/icall_import_test_bindings.json", )) .unwrap(); let h = HeapSettings::default(); - let p = Program::new(m, b, h).expect(&format!("instantiating program")); + let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile icall"); + let _module_data = c.module_data(); + /* TODO can't express these with module data assert_eq!(p.import_functions().len(), 1); assert_eq!(p.import_functions()[0].module(), "env"); assert_eq!(p.import_functions()[0].field(), "icalltarget"); @@ -101,15 +108,18 @@ mod programs { Some(&TableElem::FunctionIx(0)) ); // righttype_imported assert_eq!(p.get_table(0).unwrap().elements().get(4), None); + */ } #[test] fn icall() { - let m = load("icall"); + let m = load_wat_module("icall"); let b = Bindings::empty(); let h = HeapSettings::default(); - let p = Program::new(m, b, h).expect(&format!("instantiating program")); + let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile icall"); + let _module_data = c.module_data(); + /* TODO can't express these with module data assert_eq!( p.get_table(0).unwrap().elements().get(0), Some(&TableElem::FunctionIx(1)) @@ -123,15 +133,18 @@ mod programs { Some(&TableElem::FunctionIx(3)) ); // wrongtype assert_eq!(p.get_table(0).unwrap().elements().get(4), None); + */ } #[test] fn icall_sparse() { - let m = load("icall_sparse"); + let m = load_wat_module("icall_sparse"); let b = Bindings::empty(); let h = HeapSettings::default(); - let p = Program::new(m, b, h).expect(&format!("instantiating program")); + let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile icall_sparse"); + let _module_data = c.module_data(); + /* TODO can't express these with module data assert_eq!( p.get_table(0).unwrap().elements().get(0), Some(&TableElem::Empty) @@ -157,134 +170,147 @@ mod programs { Some(&TableElem::Empty) ); assert_eq!(p.get_table(0).unwrap().elements().get(6), None); + */ } #[test] fn globals_import() { - let m = load("globals_import"); + use lucet_module_data::Global as GlobalVariant; + let m = load_wat_module("globals_import"); let b = Bindings::empty(); let h = HeapSettings::default(); - let p = Program::new(m, b, h).expect(&format!("instantiating program")); - assert_eq!(p.globals().len(), 1); - let g = p.globals()[0].as_import().expect("global is an import"); - assert_eq!(g.module(), "env"); - assert_eq!(g.field(), "x"); - assert_eq!(g.global_type.content_type(), ValueType::I32); + + let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile globals_import"); + let module_data = c.module_data(); + let gspec = module_data.globals_spec(); + + assert_eq!(gspec.len(), 1); + let g = gspec.get(0).unwrap().global(); + match g { + GlobalVariant::Import { module, field } => { + assert_eq!(*module, "env"); + assert_eq!(*field, "x"); + } + _ => panic!("global should be an import"), + } } #[test] fn heap_spec_import() { - use lucetc::program::memory::HeapSpec; - let m = load("heap_spec_import"); + use lucet_module_data::HeapSpec; + let m = load_wat_module("heap_spec_import"); let b = Bindings::empty(); let h = HeapSettings::default(); - let p = Program::new(m, b, h).expect(&format!("instantiating program")); + let c = + Compiler::new(&m, OptLevel::Best, &b, h.clone()).expect("compiling heap_spec_import"); + assert_eq!( - p.heap_spec().unwrap(), - HeapSpec { - // reserved and guard is liblucet_runtime_c standard - reserved_size: 4 * 1024 * 1024, - guard_size: 4 * 1024 * 1024, + c.module_data().heap_spec(), + Some(&HeapSpec { + // reserved and guard are given by HeapSettings + reserved_size: h.min_reserved_size, + guard_size: h.guard_size, // initial size of import specified as 6 wasm pages initial_size: 6 * 64 * 1024, // max size of import is specified as 10 wasm pages max_size: Some(10 * 64 * 1024), - } + }) ); } #[test] fn heap_spec_definition() { - use lucetc::program::memory::HeapSpec; - let m = load("heap_spec_definition"); + use lucet_module_data::HeapSpec; + let m = load_wat_module("heap_spec_definition"); let b = Bindings::empty(); let h = HeapSettings::default(); - let p = Program::new(m, b, h).expect(&format!("instantiating program")); + let c = Compiler::new(&m, OptLevel::Best, &b, h.clone()) + .expect("compiling heap_spec_definition"); + assert_eq!( - p.heap_spec().unwrap(), - HeapSpec { - // reserved and guard is liblucet_runtime_c standard - reserved_size: 4 * 1024 * 1024, - guard_size: 4 * 1024 * 1024, + c.module_data().heap_spec(), + Some(&HeapSpec { + // reserved and guard are given by HeapSettings + reserved_size: h.min_reserved_size, + guard_size: h.guard_size, // initial size defined as 5 wasm pages initial_size: 5 * 64 * 1024, // no max size defined max_size: None, - } + }) ); } #[test] fn heap_spec_none() { - use lucetc::program::memory::HeapSpec; - let m = load("heap_spec_none"); + let m = load_wat_module("heap_spec_none"); let b = Bindings::empty(); let h = HeapSettings::default(); - let p = Program::new(m, b, h).expect(&format!("instantiating program")); - assert_eq!( - p.heap_spec().unwrap(), - HeapSpec { - reserved_size: 0, - guard_size: 0, - initial_size: 0, - max_size: None, - } - ); + let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compiling heap_spec_none"); + assert_eq!(c.module_data().heap_spec(), None,); } #[test] fn oversize_data_segment() { - let m = load("oversize_data_segment"); + let m = load_wat_module("oversize_data_segment"); let b = Bindings::empty(); let h = HeapSettings::default(); - let p = Program::new(m, b, h).expect("instantiating is ok"); + let c = Compiler::new(&m, OptLevel::Best, &b, h); assert!( - p.data_initializers().is_err(), - "data_initializers method returns error because data initializers are oversized" + c.is_err(), + "compilation error because data initializers are oversized" ); + assert_eq!(*c.err().unwrap().get_context(), LucetcErrorKind::Validation); } // XXX adding more negative tests like the one above is valuable - lets do it - use lucetc::error::LucetcErrorKind; #[test] fn invalid_module() { + use std::fs::File; + use std::io::Read; // I used the `wast2json` tool to produce the file invalid.wasm from an assert_invalid part // of a spectest (call.wast) let wasmfile = PathBuf::from("tests/wasm/invalid.wasm"); - let m = load::read_module(&wasmfile).expect(&format!("loading module from {:?}", wasmfile)); + let mut m = Vec::new(); + let mut file = File::open(&wasmfile).expect("open module file"); + file.read_to_end(&mut m).expect("read contents of module"); + let b = Bindings::empty(); let h = HeapSettings::default(); - let p = Program::new(m, b, h); - assert!(p.is_err()); - assert_eq!(*p.err().unwrap().get_context(), LucetcErrorKind::Validation); + let c = Compiler::new(&m, OptLevel::Best, &b, h); + assert!( + c.is_err(), + "compilation error because wasm module is invalid" + ); + assert_eq!(*c.err().unwrap().get_context(), LucetcErrorKind::Validation); } #[test] fn start_section() { - let m = load("start_section"); + let m = load_wat_module("start_section"); let b = Bindings::empty(); let h = HeapSettings::default(); - let p = Program::new(m, b, h).expect(&format!("instantiating program")); + let _c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile start_section"); + /* assert!( p.module().start_section().is_some(), "start section is defined" ); + */ } } mod compile { // Tests for compilation completion - use super::load; - use lucetc::compile; - use lucetc::compiler::OptLevel; - use lucetc::program::{HeapSettings, Program}; + use super::load_wat_module; + use lucetc::{Compiler, HeapSettings, OptLevel}; fn run_compile_test(file: &str) { - let m = load(file); + let m = load_wat_module(file); let b = super::test_bindings(); let h = HeapSettings::default(); - let p = Program::new(m, b, h).expect(&format!("make program for {}", file)); - compile(&p, file.into(), OptLevel::Best).expect(&format!("compile {}", file)); + let c = Compiler::new(&m, OptLevel::Best, &b, h).expect(&format!("compile {}", file)); + let _obj = c.object_file().expect(&format!("codegen {}", file)); } macro_rules! compile_test { ($base_name:ident) => { @@ -315,124 +341,3 @@ mod compile { compile_test!(unreachable_code); compile_test!(start_section); } - -mod execute { - // Tests for compilation correctness - use super::load; - use lucetc::compile; - use lucetc::compiler::OptLevel; - use lucetc::program::{HeapSettings, Program}; - use std::process::Command; - use std::str; - - fn run_execute_test(file: &str) { - // Compile the wasm file - let m = load(file); - let b = super::test_bindings(); - let h = HeapSettings::default(); - let p = Program::new(m, b, h).expect(&format!("make program for {}", file)); - let comp = compile(&p, file, OptLevel::Best).expect(&format!("compile test for {}", file)); - - // Set up output fils - let tmp_dir = tempfile::Builder::new() - .prefix("execute_test_out") - .tempdir() - .expect("Failed to create temp dir"); - let obj_path = tmp_dir.path().join(format!("{}.o", file)); - let obj_file = obj_path - .to_str() - .expect("failed to convert obj_file pathbuf to str"); - - let exec_path = tmp_dir.path().join(format!("{}_test", file)); - let exec_file = exec_path - .to_str() - .expect("failed to convert exec_file pathbuf to str"); - - // Write the compiled object - let obj = comp.codegen().expect("generate code"); - obj.write(&obj_path).expect("write object file"); - - // Mark the wasm table as global, so we can inspect it in the tests. - let objcopy = Command::new("objcopy") - .arg("--globalize-symbol=guest_table_0") - .arg(obj_file) - .output() - .expect("failed to execute objcopy"); - if !objcopy.status.success() { - let stdout = str::from_utf8(&objcopy.stdout).unwrap(); - let stderr = str::from_utf8(&objcopy.stderr).unwrap(); - println!( - "objcopy status: {}", - objcopy.status.code().expect("status code error") - ); - println!("objcopy stdout: {}", stdout); - println!("objcopy stderr: {}", stderr); - } - assert!(objcopy.status.success(), "objcopy failed!"); - - // Invoke GCC to compile and link the harness and the object. - let harness_file = format!("tests/harnesses/{}.c", file); - let output = Command::new("gcc") - .arg("--std=c99") - .arg(harness_file) - .arg("tests/harnesses/vm.c") - .arg("tests/harnesses/globals.c") - .arg(obj_file) - .args(&["-o", exec_file]) - .output() - .expect("failed to execute GCC"); - - if !output.status.success() { - let stdout = str::from_utf8(&output.stdout).unwrap(); - let stderr = str::from_utf8(&output.stderr).unwrap(); - println!( - "GCC status: {}", - output.status.code().expect("status code error") - ); - println!("GCC stdout: {}", stdout); - println!("GCC stderr: {}", stderr); - } - assert!(output.status.success(), "GCC failed!"); - - // Finally, invoke the test itself. - let output = Command::new(exec_file) - .output() - .expect("failed to run execute test"); - - if !output.status.success() { - match output.status.code() { - Some(code) => println!("Test status: {}", code), - None => println!("Test terminated by signal"), - }; - let stdout = str::from_utf8(&output.stdout).unwrap(); - let stderr = str::from_utf8(&output.stderr).unwrap(); - println!("Test stdout: {}", stdout); - println!("Test stderr: {}", stderr); - } - assert!(output.status.success(), "Execute test failed!"); - } - - macro_rules! execute_test { - ($base_name:ident) => { - #[test] - pub fn $base_name() { - run_execute_test(stringify!($base_name)); - } - }; - } - - execute_test!(fibonacci); - execute_test!(call); - execute_test!(icall); - execute_test!(locals); - execute_test!(locals_csr); - execute_test!(data_segment); - execute_test!(import_many); - execute_test!(icall_import); - execute_test!(icall_sparse); - execute_test!(current_memory); - execute_test!(grow_memory); - execute_test!(heap_spec_import); - execute_test!(heap_spec_definition); - execute_test!(globals_definition); -} diff --git a/pwasm-validation b/pwasm-validation deleted file mode 160000 index 1ce475f3a..000000000 --- a/pwasm-validation +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1ce475f3a19776c901752c54e2446409967bf21e From 577a541353485db42e5c80d7abc502dea70fc33d Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Wed, 24 Apr 2019 11:54:22 -0700 Subject: [PATCH 072/512] [lucet-runtime] add macros for hostcalls and instance termination This makes it possible to properly unwind within hostcalls, though panics that travel across the host/guest boundary will still not behave properly due to stack layout. --- benchmarks/lucet-benchmarks/src/modules.rs | 2 +- .../src/hostcall_macros.rs | 91 + .../lucet-runtime-internals/src/lib.rs | 2 + .../lucet-runtime-internals/src/vmctx.rs | 97 +- .../guests/host/bindings.json | 3 +- .../lucet-runtime-tests/src/entrypoint.rs | 34 +- .../lucet-runtime-tests/src/guest_fault.rs | 89 +- lucet-runtime/lucet-runtime-tests/src/host.rs | 79 +- .../lucet-runtime-tests/src/strcmp.rs | 14 +- lucet-runtime/src/c_api.rs | 147 +- lucet-runtime/src/lib.rs | 29 +- lucet-wasi/src/hostcalls.rs | 1697 ++++++++--------- 12 files changed, 1220 insertions(+), 1064 deletions(-) create mode 100644 lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs diff --git a/benchmarks/lucet-benchmarks/src/modules.rs b/benchmarks/lucet-benchmarks/src/modules.rs index 7e655a795..2972f0085 100644 --- a/benchmarks/lucet-benchmarks/src/modules.rs +++ b/benchmarks/lucet-benchmarks/src/modules.rs @@ -11,7 +11,7 @@ fn wasi_bindings() -> Bindings { pub fn compile_hello>(so_file: P) { let wasm_build = Lucetc::new(&["guests/hello.c"]) - .print_output(true) + .with_print_output(true) .with_cflag("-Wall") .with_cflag("-Werror") .with_bindings(wasi_bindings()); diff --git a/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs b/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs new file mode 100644 index 000000000..1c3ac37d1 --- /dev/null +++ b/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs @@ -0,0 +1,91 @@ +/// The macro that surrounds definitions of Lucet hostcalls in Rust. +/// +/// It is important to use this macro for hostcalls, rather than exporting them directly, as it +/// installs unwind protection that prevents panics from unwinding into the guest stack. +/// +/// Since this is not yet a proc macro, the syntax is unfortunately fairly brittle. The functions it +/// encloses must be of the form: +/// +/// ```ignore +/// #[$attr1] +/// #[$attr2] +/// ... // any number of attributes are supported; in most cases you will want `#[no_mangle]` +/// pub unsafe extern "C" fn $name( // must be `pub unsafe extern "C"` +/// &mut $vmctx, +/// $arg1: $arg1_ty, +/// $arg2: $arg2_ty, +/// ... , // trailing comma must always be present +/// ) -> $ret_ty { // return type must always be present even if it is `()` +/// // body +/// } +/// ``` +#[macro_export] +macro_rules! lucet_hostcalls { + { + $( + $(#[$attr:meta])* + pub unsafe extern "C" fn $name:ident( + &mut $vmctx:ident + $(, $arg:ident : $arg_ty:ty )*, + ) -> $ret_ty:ty { + $($body:tt)* + } + )* + } => { + $( + $(#[$attr])* + pub unsafe extern "C" fn $name( + vmctx_raw: *mut $crate::vmctx::lucet_vmctx, + $( $arg: $arg_ty ),* + ) -> $ret_ty { + unsafe fn hostcall_impl( + $vmctx: &mut $crate::vmctx::Vmctx, + $( $arg : $arg_ty ),* + ) -> $ret_ty { + $($body)* + } + let res = std::panic::catch_unwind(|| { + hostcall_impl(&mut $crate::vmctx::Vmctx::from_raw(vmctx_raw), $( $arg ),*) + }); + match res { + Ok(res) => res, + Err(e) => { + if let Some(details) = e.downcast_ref::<$crate::instance::TerminationDetails>() { + let mut vmctx = $crate::vmctx::Vmctx::from_raw(vmctx_raw); + vmctx.terminate_no_unwind(details.clone()); + } else { + std::panic::resume_unwind(e); + } + } + } + } + )* + } +} + +/// Terminate an instance from within a hostcall, returning an optional value as an error. +/// +/// Use this instead of `panic!` when you want the instance to terminate, but not the entire host +/// program. Like `panic!`, you can pass a format string with arguments, a value that implements +/// `Any`, or nothing to return a default message. +/// +/// Upon termination, the call to `Instance::run()` will return with an +/// `Err(Error::RuntimeTerminated)` value containing the value you pass to this macro. +/// +/// This macro safely unwinds the hostcall stack out to the entrypoint of the hostcall, so any +/// resources that may have been acquired will be properly dropped. +#[macro_export] +macro_rules! lucet_hostcall_terminate { + () => { + lucet_hostcall_terminate!("lucet_hostcall_terminate") + }; + ( $payload:expr ) => { + panic!($crate::instance::TerminationDetails::provide($payload)) + }; + ( $payload:expr, ) => { + lucet_hostcall_terminate!($payload) + }; + ( $fmt:expr, $($arg:tt)+ ) => { + lucet_hostcall_terminate!(format!($fmt, $($arg),+)) + }; +} diff --git a/lucet-runtime/lucet-runtime-internals/src/lib.rs b/lucet-runtime/lucet-runtime-internals/src/lib.rs index 40480ad58..7777b0e0c 100644 --- a/lucet-runtime/lucet-runtime-internals/src/lib.rs +++ b/lucet-runtime/lucet-runtime-internals/src/lib.rs @@ -6,6 +6,8 @@ #[macro_use] pub mod error; +#[macro_use] +pub mod hostcall_macros; #[macro_use] #[cfg(test)] diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index 1c25e8a91..b1c08f3a3 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -85,21 +85,34 @@ impl Vmctx { /// Get a reference to a context value of a particular type. If it does not exist, /// the context will terminate. pub fn get_embed_ctx(&self) -> &T { - unsafe { self.instance_mut().get_embed_ctx_or_term() } + match self.instance().embed_ctx.get::() { + Some(t) => t, + None => { + // this value will be caught by the wrapper in `lucet_hostcalls!` + panic!(TerminationDetails::GetEmbedCtx) + } + } } /// Get a mutable reference to a context value of a particular type> If it does not exist, /// the context will terminate. pub fn get_embed_ctx_mut(&mut self) -> &mut T { - unsafe { self.instance_mut().get_embed_ctx_mut_or_term() } + match unsafe { self.instance_mut().embed_ctx.get_mut::() } { + Some(t) => t, + None => { + // this value will be caught by the wrapper in `lucet_hostcalls!` + panic!(TerminationDetails::GetEmbedCtx) + } + } } - /// Terminate this guest and return to the host context. + /// Terminate this guest and return to the host context without unwinding. /// - /// This will return an `Error::RuntimeTerminated` value to the caller of `Instance::run()`. - pub fn terminate(&mut self, info: I) -> ! { - let details = TerminationDetails::provide(info); - unsafe { self.instance_mut().terminate(details) } + /// This is almost certainly not what you want to use to terminate an instance from a hostcall, + /// as any resources currently in scope will not be dropped. Instead, use + /// `lucet_hostcall_terminate!` which unwinds to the enclosing hostcall body. + pub unsafe fn terminate_no_unwind(&mut self, details: TerminationDetails) -> ! { + self.instance_mut().terminate(details) } /// Grow the guest memory by the given number of WebAssembly pages. @@ -130,21 +143,24 @@ impl Vmctx { /// from its own context. /// /// ```no_run + /// use lucet_runtime_internals::{lucet_hostcalls, lucet_hostcall_terminate}; /// use lucet_runtime_internals::vmctx::{lucet_vmctx, Vmctx}; - /// #[no_mangle] - /// extern "C" fn hostcall_call_binop( - /// vmctx: *mut lucet_vmctx, - /// binop_table_idx: u32, - /// binop_func_idx: u32, - /// operand1: u32, - /// operand2: u32, - /// ) -> u32 { - /// let mut ctx = unsafe { Vmctx::from_raw(vmctx) }; - /// if let Ok(binop) = ctx.get_func_from_idx(binop_table_idx, binop_func_idx) { - /// let typed_binop = binop as *const extern "C" fn(*mut lucet_vmctx, u32, u32) -> u32; - /// unsafe { (*typed_binop)(vmctx, operand1, operand2) } - /// } else { - /// ctx.terminate("invalid function index") + /// + /// lucet_hostcalls! { + /// #[no_mangle] + /// pub unsafe extern "C" fn hostcall_call_binop( + /// &mut vmctx, + /// binop_table_idx: u32, + /// binop_func_idx: u32, + /// operand1: u32, + /// operand2: u32, + /// ) -> u32 { + /// if let Ok(binop) = vmctx.get_func_from_idx(binop_table_idx, binop_func_idx) { + /// let typed_binop = binop as *const extern "C" fn(*mut lucet_vmctx, u32, u32) -> u32; + /// unsafe { (*typed_binop)(vmctx.as_raw(), operand1, operand2) } + /// } else { + /// lucet_hostcall_terminate!("invalid function index") + /// } /// } /// } pub fn get_func_from_idx( @@ -158,18 +174,6 @@ impl Vmctx { } } -/// Terminating an instance requires mutating the state field, and then jumping back to the -/// host context. The mutable borrow may conflict with a mutable borrow of the embed_ctx if -/// this is performed via a method call. We use a macro so we can convince the borrow checker that -/// this is safe at each use site. -macro_rules! inst_terminate { - ($self:ident, $details:expr) => {{ - $self.state = State::Terminated { details: $details }; - #[allow(unused_unsafe)] // The following unsafe will be incorrectly warned as unused - HOST_CTX.with(|host_ctx| unsafe { Context::set(&*host_ctx.get()) }) - }}; -} - /// Get an `Instance` from the `vmctx` pointer. /// /// Only safe to call from within the guest context. @@ -202,29 +206,14 @@ pub unsafe fn instance_from_vmctx<'a>(vmctx: *mut lucet_vmctx) -> &'a mut Instan } impl Instance { - /// Helper function specific to Vmctx::get_embed_ctx. From the vmctx interface, - /// there is no way to recover if the expected embedder ctx is not set, so we terminate - /// the instance. - fn get_embed_ctx_or_term(&mut self) -> &T { - match self.embed_ctx.get::() { - Some(t) => t, - None => inst_terminate!(self, TerminationDetails::GetEmbedCtx), - } - } - - /// Helper function specific to Vmctx::get_embed_ctx_mut. See above. - fn get_embed_ctx_mut_or_term(&mut self) -> &mut T { - match self.embed_ctx.get_mut::() { - Some(t) => t, - None => inst_terminate!(self, TerminationDetails::GetEmbedCtx), - } - } - - /// Terminate the guest and swap back to the host context. + /// Terminate the guest and swap back to the host context without unwinding. /// - /// Only safe to call from within the guest context. + /// This is almost certainly not what you want to use to terminate from a hostcall; use panics + /// with `TerminationDetails` instead. unsafe fn terminate(&mut self, details: TerminationDetails) -> ! { - inst_terminate!(self, details) + self.state = State::Terminated { details }; + #[allow(unused_unsafe)] // The following unsafe will be incorrectly warned as unused + HOST_CTX.with(|host_ctx| unsafe { Context::set(&*host_ctx.get()) }) } } diff --git a/lucet-runtime/lucet-runtime-tests/guests/host/bindings.json b/lucet-runtime/lucet-runtime-tests/guests/host/bindings.json index 26b5c8b44..383bcf316 100644 --- a/lucet-runtime/lucet-runtime-tests/guests/host/bindings.json +++ b/lucet-runtime/lucet-runtime-tests/guests/host/bindings.json @@ -1,6 +1,7 @@ { "env": { "hostcall_test_func_hello": "hostcall_test_func_hello", - "hostcall_test_func_hostcall_error": "hostcall_test_func_hostcall_error" + "hostcall_test_func_hostcall_error": "hostcall_test_func_hostcall_error", + "hostcall_test_func_hostcall_error_unwind": "hostcall_test_func_hostcall_error_unwind" } } diff --git a/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs b/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs index 3a1820513..480534329 100644 --- a/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs +++ b/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs @@ -135,13 +135,20 @@ macro_rules! entrypoint_tests { ( $TestRegion:path ) => { use libc::c_void; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; - use lucet_runtime::{DlModule, Error, Limits, Module, Region, Val, WASM_PAGE_SIZE}; + use lucet_runtime::{ + lucet_hostcalls, DlModule, Error, Limits, Module, Region, Val, WASM_PAGE_SIZE, + }; use std::sync::Arc; use $TestRegion as TestRegion; use $crate::entrypoint::{mock_calculator_module, wat_calculator_module}; - #[no_mangle] - extern "C" fn black_box(_vmctx: *mut lucet_vmctx, _val: *mut c_void) {} + lucet_hostcalls! { + #[no_mangle] + pub unsafe extern "C" fn black_box( + &mut _vmctx, + _val: *mut c_void, + ) -> () {} + } #[test] fn mock_calc_add_2() { @@ -711,14 +718,19 @@ macro_rules! entrypoint_tests { .expect("instance runs"); } - #[no_mangle] - extern "C" fn callback_hostcall(vmctx: *mut lucet_vmctx, cb_idx: u32, x: u64) -> u64 { - let vmctx = unsafe { Vmctx::from_raw(vmctx) }; - let func = vmctx - .get_func_from_idx(0, cb_idx) - .expect("can get function by index"); - let func = func as *const extern "C" fn(*mut lucet_vmctx, u64) -> u64; - unsafe { (*func)(vmctx.as_raw(), x) + 1 } + lucet_hostcalls! { + #[no_mangle] + pub unsafe extern "C" fn callback_hostcall( + &mut vmctx, + cb_idx: u32, + x: u64, + ) -> u64 { + let func = vmctx + .get_func_from_idx(0, cb_idx) + .expect("can get function by index"); + let func = func as *const extern "C" fn(*mut lucet_vmctx, u64) -> u64; + (*func)(vmctx.as_raw(), x) + 1 + } } #[test] diff --git a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs index 6e55084bc..3aacf3cfa 100644 --- a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs +++ b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs @@ -1,48 +1,54 @@ use crate::helpers::MockModuleBuilder; +use lucet_runtime_internals::lucet_hostcalls; use lucet_runtime_internals::module::{Module, TrapManifestRecord, TrapSite}; -use lucet_runtime_internals::vmctx::{lucet_vmctx, Vmctx}; +use lucet_runtime_internals::vmctx::lucet_vmctx; use std::sync::Arc; pub fn mock_traps_module() -> Arc { - extern "C" fn onetwothree(_vmctx: *mut lucet_vmctx) -> std::os::raw::c_int { - 123 - } - - extern "C" fn hostcall_main(vmctx: *mut lucet_vmctx) { - extern "C" { - // actually is defined in this file - fn hostcall_test(vmctx: *mut lucet_vmctx); + lucet_hostcalls! { + pub unsafe extern "C" fn onetwothree( + &mut _vmctx, + ) -> std::os::raw::c_int { + 123 } - unsafe { - hostcall_test(vmctx); + + pub unsafe extern "C" fn hostcall_main( + &mut vmctx, + ) -> () { + extern "C" { + // actually is defined in this file + fn hostcall_test(vmctx: *mut lucet_vmctx); + } + hostcall_test(vmctx.as_raw()); std::hint::unreachable_unchecked(); } - } - extern "C" fn infinite_loop(_vmctx: *mut lucet_vmctx) { - loop {} - } + pub unsafe extern "C" fn infinite_loop( + &mut _vmctx, + ) -> () { + loop {} + } - extern "C" fn fatal(vmctx: *mut lucet_vmctx) { - let mut vmctx = unsafe { Vmctx::from_raw(vmctx) }; - let heap_base = vmctx.heap_mut().as_mut_ptr(); + pub unsafe extern "C" fn fatal( + &mut vmctx, + ) -> () { + let heap_base = vmctx.heap_mut().as_mut_ptr(); - // Using the default limits, each instance as of this writing takes up 0x200026000 bytes - // worth of virtual address space. We want to access a point beyond all the instances, so - // that memory is unmapped. We assume no more than 16 instances are mapped - // concurrently. This may change as the library, test configuration, linker, phase of moon, - // etc change, but for now it works. - unsafe { + // Using the default limits, each instance as of this writing takes up 0x200026000 bytes + // worth of virtual address space. We want to access a point beyond all the instances, so + // that memory is unmapped. We assume no more than 16 instances are mapped + // concurrently. This may change as the library, test configuration, linker, phase of moon, + // etc change, but for now it works. *heap_base.offset(0x200026000 * 16) = 0; } - } - extern "C" fn recoverable_fatal(_vmctx: *mut lucet_vmctx) { - use std::os::raw::c_char; - extern "C" { - fn guest_recoverable_get_ptr() -> *mut c_char; - } - unsafe { + pub unsafe extern "C" fn recoverable_fatal( + &mut _vmctx, + ) -> () { + use std::os::raw::c_char; + extern "C" { + fn guest_recoverable_get_ptr() -> *mut c_char; + } *guest_recoverable_get_ptr() = '\0' as c_char; } } @@ -118,7 +124,8 @@ macro_rules! guest_fault_tests { use libc::{c_void, siginfo_t, SIGSEGV}; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime::{ - DlModule, Error, FaultDetails, Instance, Limits, Region, SignalBehavior, TrapCode, + lucet_hostcall_terminate, lucet_hostcalls, DlModule, Error, FaultDetails, Instance, + Limits, Region, SignalBehavior, TrapCode, }; use nix::sys::mman::{mmap, MapFlags, ProtFlags}; use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal}; @@ -173,9 +180,13 @@ macro_rules! guest_fault_tests { static HOSTCALL_TEST_ERROR: &'static str = "hostcall_test threw an error!"; - #[no_mangle] - unsafe extern "C" fn hostcall_test(vmctx: *mut lucet_vmctx) { - Vmctx::from_raw(vmctx).terminate(HOSTCALL_TEST_ERROR); + lucet_hostcalls! { + #[no_mangle] + pub unsafe extern "C" fn hostcall_test( + &mut _vmctx, + ) -> () { + lucet_hostcall_terminate!(HOSTCALL_TEST_ERROR); + } } fn run_onetwothree(inst: &mut Instance) { @@ -504,8 +515,12 @@ macro_rules! guest_fault_tests { *HOST_SIGSEGV_TRIGGERED.lock().unwrap() = true; } - extern "C" fn sleepy_guest(_vmctx: *const lucet_vmctx) { - std::thread::sleep(std::time::Duration::from_millis(20)); + lucet_hostcalls! { + pub unsafe extern "C" fn sleepy_guest( + &mut _vmctx, + ) -> () { + std::thread::sleep(std::time::Duration::from_millis(20)); + } } test_ex(|| { diff --git a/lucet-runtime/lucet-runtime-tests/src/host.rs b/lucet-runtime/lucet-runtime-tests/src/host.rs index 8f833b377..e99c66ec3 100644 --- a/lucet-runtime/lucet-runtime-tests/src/host.rs +++ b/lucet-runtime/lucet-runtime-tests/src/host.rs @@ -1,10 +1,13 @@ #[macro_export] macro_rules! host_tests { ( $TestRegion:path ) => { + use lazy_static::lazy_static; use libc::c_void; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; - use lucet_runtime::{DlModule, Error, Limits, Region, TrapCode}; - use std::sync::Arc; + use lucet_runtime::{ + lucet_hostcall_terminate, lucet_hostcalls, DlModule, Error, Limits, Region, TrapCode, + }; + use std::sync::{Arc, Mutex}; use $TestRegion as TestRegion; use $crate::build::test_module_c; #[test] @@ -18,30 +21,48 @@ macro_rules! host_tests { assert!(module.is_err()); } - #[no_mangle] - extern "C" fn hostcall_test_func_hello( - vmctx: *mut lucet_vmctx, - hello_ptr: u32, - hello_len: u32, - ) { - unsafe { - let mut vmctx = Vmctx::from_raw(vmctx); + const ERROR_MESSAGE: &'static str = "hostcall_test_func_hostcall_error"; + + lazy_static! { + static ref HOSTCALL_MUTEX: Mutex<()> = Mutex::new(()); + } + + lucet_hostcalls! { + #[no_mangle] + pub unsafe extern "C" fn hostcall_test_func_hello( + &mut vmctx, + hello_ptr: u32, + hello_len: u32, + ) -> () { let heap = vmctx.heap(); let hello = heap.as_ptr() as usize + hello_ptr as usize; if !vmctx.check_heap(hello as *const c_void, hello_len as usize) { - vmctx.terminate("heap access"); + lucet_hostcall_terminate!("heap access"); } let hello = std::slice::from_raw_parts(hello as *const u8, hello_len as usize); if hello.starts_with(b"hello") { *vmctx.get_embed_ctx_mut::() = true; } } - } - const ERROR_MESSAGE: &'static str = "hostcall_test_func_hostcall_error"; - #[no_mangle] - extern "C" fn hostcall_test_func_hostcall_error(vmctx: *mut lucet_vmctx) { - unsafe { Vmctx::from_raw(vmctx).terminate(ERROR_MESSAGE) } + #[no_mangle] + pub unsafe extern "C" fn hostcall_test_func_hostcall_error( + &mut _vmctx, + ) -> () { + lucet_hostcall_terminate!(ERROR_MESSAGE); + } + + #[allow(unreachable_code)] + #[no_mangle] + pub unsafe extern "C" fn hostcall_test_func_hostcall_error_unwind( + &mut vmctx, + ) -> () { + let lock = HOSTCALL_MUTEX.lock().unwrap(); + unsafe { + lucet_hostcall_terminate!(ERROR_MESSAGE); + } + drop(lock); + } } #[test] @@ -102,6 +123,32 @@ macro_rules! host_tests { } } + #[test] + fn run_hostcall_error_unwind() { + let module = + test_module_c("host", "hostcall_error_unwind.c").expect("build and load module"); + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + match inst.run(b"main", &[]) { + Err(Error::RuntimeTerminated(term)) => { + assert_eq!( + *term + .provided_details() + .expect("user provided termination reason") + .downcast_ref::<&'static str>() + .expect("error was static str"), + ERROR_MESSAGE + ); + } + res => panic!("unexpected result: {:?}", res), + } + + assert!(HOSTCALL_MUTEX.is_poisoned()); + } + #[test] fn run_fpe() { let module = test_module_c("host", "fpe.c").expect("build and load module"); diff --git a/lucet-runtime/lucet-runtime-tests/src/strcmp.rs b/lucet-runtime/lucet-runtime-tests/src/strcmp.rs index 2c6b9e260..80bbe415b 100644 --- a/lucet-runtime/lucet-runtime-tests/src/strcmp.rs +++ b/lucet-runtime/lucet-runtime-tests/src/strcmp.rs @@ -3,16 +3,20 @@ macro_rules! strcmp_tests { ( $TestRegion:path ) => { use libc::{c_char, c_int, c_void, strcmp, uint64_t}; use lucet_runtime::vmctx::lucet_vmctx; - use lucet_runtime::{Error, Limits, Region, Val, WASM_PAGE_SIZE}; + use lucet_runtime::{lucet_hostcalls, Error, Limits, Region, Val, WASM_PAGE_SIZE}; use std::ffi::CString; use std::sync::Arc; use $TestRegion as TestRegion; use $crate::build::test_module_c; - #[no_mangle] - unsafe extern "C" fn hostcall_host_fault(_vmctx: *const lucet_vmctx) { - let oob = (-1isize) as *mut c_char; - *oob = 'x' as c_char; + lucet_hostcalls! { + #[no_mangle] + pub unsafe extern "C" fn hostcall_host_fault( + &mut _vmctx, + ) -> () { + let oob = (-1isize) as *mut c_char; + *oob = 'x' as c_char; + } } fn strcmp_compare(s1: &str, s2: &str) { diff --git a/lucet-runtime/src/c_api.rs b/lucet-runtime/src/c_api.rs index 17e943943..e4bd29c3f 100644 --- a/lucet-runtime/src/c_api.rs +++ b/lucet-runtime/src/c_api.rs @@ -1,14 +1,14 @@ -extern crate lucet_runtime_internals; - use crate::{DlModule, Instance, Limits, MmapRegion, Module, Region, TrapCode}; use libc::{c_char, c_int, c_void}; use lucet_runtime_internals::c_api::*; use lucet_runtime_internals::instance::{ instance_handle_from_raw, instance_handle_to_raw, InstanceInternal, }; -use lucet_runtime_internals::vmctx::{instance_from_vmctx, lucet_vmctx, Vmctx, VmctxInternal}; +use lucet_runtime_internals::vmctx::VmctxInternal; use lucet_runtime_internals::WASM_PAGE_SIZE; -use lucet_runtime_internals::{assert_nonnull, with_ffi_arcs}; +use lucet_runtime_internals::{ + assert_nonnull, lucet_hostcall_terminate, lucet_hostcalls, with_ffi_arcs, +}; use num_traits::FromPrimitive; use std::ffi::CStr; use std::ptr; @@ -362,76 +362,87 @@ pub fn ensure_linked() { }); } -#[no_mangle] -pub unsafe extern "C" fn lucet_vmctx_get_heap(vmctx: *mut lucet_vmctx) -> *mut u8 { - Vmctx::from_raw(vmctx).instance().alloc().slot().heap as *mut u8 -} +lucet_hostcalls! { + #[no_mangle] + pub unsafe extern "C" fn lucet_vmctx_get_heap( + &mut vmctx, + ) -> *mut u8 { + vmctx.instance().alloc().slot().heap as *mut u8 + } -#[no_mangle] -pub unsafe extern "C" fn lucet_vmctx_get_globals(vmctx: *mut lucet_vmctx) -> *mut i64 { - Vmctx::from_raw(vmctx).instance().alloc().slot().globals as *mut i64 -} + #[no_mangle] + pub unsafe extern "C" fn lucet_vmctx_get_globals( + &mut vmctx, + ) -> *mut i64 { + vmctx.instance().alloc().slot().globals as *mut i64 + } -/// Get the number of WebAssembly pages currently in the heap. -#[no_mangle] -pub unsafe extern "C" fn lucet_vmctx_current_memory(vmctx: *mut lucet_vmctx) -> libc::uint32_t { - Vmctx::from_raw(vmctx).instance().alloc().heap_len() as u32 / WASM_PAGE_SIZE -} + #[no_mangle] + /// Get the number of WebAssembly pages currently in the heap. + pub unsafe extern "C" fn lucet_vmctx_current_memory( + &mut vmctx, + ) -> libc::uint32_t { + vmctx.instance().alloc().heap_len() as u32 / WASM_PAGE_SIZE + } -#[no_mangle] -/// Grows the guest heap by the given number of WebAssembly pages. -/// -/// On success, returns the number of pages that existed before the call. On failure, returns `-1`. -pub unsafe extern "C" fn lucet_vmctx_grow_memory( - vmctx: *mut lucet_vmctx, - additional_pages: libc::uint32_t, -) -> libc::int32_t { - let inst = instance_from_vmctx(vmctx); - if let Ok(old_pages) = inst.grow_memory(additional_pages) { - old_pages as libc::int32_t - } else { - -1 + #[no_mangle] + /// Grows the guest heap by the given number of WebAssembly pages. + /// + /// On success, returns the number of pages that existed before the call. On failure, returns `-1`. + pub unsafe extern "C" fn lucet_vmctx_grow_memory( + &mut vmctx, + additional_pages: libc::uint32_t, + ) -> libc::int32_t { + if let Ok(old_pages) = vmctx.instance_mut().grow_memory(additional_pages) { + old_pages as libc::int32_t + } else { + -1 + } } -} -#[no_mangle] -/// Check if a memory region is inside the instance heap. -pub unsafe extern "C" fn lucet_vmctx_check_heap( - vmctx: *mut lucet_vmctx, - ptr: *mut c_void, - len: libc::size_t, -) -> bool { - let inst = instance_from_vmctx(vmctx); - inst.check_heap(ptr, len) -} + #[no_mangle] + /// Check if a memory region is inside the instance heap. + pub unsafe extern "C" fn lucet_vmctx_check_heap( + &mut vmctx, + ptr: *mut c_void, + len: libc::size_t, + ) -> bool { + vmctx.instance().check_heap(ptr, len) + } -#[no_mangle] -pub unsafe extern "C" fn lucet_vmctx_get_func_from_idx( - vmctx: *mut lucet_vmctx, - table_idx: u32, - func_idx: u32, -) -> *const c_void { - let inst = instance_from_vmctx(vmctx); - inst.module() - .get_func_from_idx(table_idx, func_idx) - // the Rust API actually returns a pointer to a function pointer, so we want to dereference - // one layer of that to make it nicer in C - .map(|fptr| *(fptr as *const *const c_void)) - .unwrap_or(std::ptr::null()) -} + #[no_mangle] + pub unsafe extern "C" fn lucet_vmctx_get_func_from_idx( + &mut vmctx, + table_idx: u32, + func_idx: u32, + ) -> *const c_void { + vmctx.instance() + .module() + .get_func_from_idx(table_idx, func_idx) + // the Rust API actually returns a pointer to a function pointer, so we want to dereference + // one layer of that to make it nicer in C + .map(|fptr| *(fptr as *const *const c_void)) + .unwrap_or(std::ptr::null()) + } -#[no_mangle] -pub unsafe extern "C" fn lucet_vmctx_terminate(vmctx: *mut lucet_vmctx, info: *mut c_void) { - Vmctx::from_raw(vmctx).terminate(info); -} + #[no_mangle] + pub unsafe extern "C" fn lucet_vmctx_terminate( + &mut _vmctx, + info: *mut c_void, + ) -> () { + lucet_hostcall_terminate!(info); + } -#[no_mangle] -/// Get the delegate object for the current instance. -/// -/// TODO: rename -pub unsafe extern "C" fn lucet_vmctx_get_delegate(vmctx: *mut lucet_vmctx) -> *mut c_void { - let inst = instance_from_vmctx(vmctx); - inst.get_embed_ctx::<*mut c_void>() - .map(|p| *p) - .unwrap_or(std::ptr::null_mut()) + #[no_mangle] + /// Get the delegate object for the current instance. + /// + /// TODO: rename + pub unsafe extern "C" fn lucet_vmctx_get_delegate( + &mut vmctx, + ) -> *mut c_void { + vmctx.instance() + .get_embed_ctx::<*mut c_void>() + .map(|p| *p) + .unwrap_or(std::ptr::null_mut()) + } } diff --git a/lucet-runtime/src/lib.rs b/lucet-runtime/src/lib.rs index 4ffb79505..af85c489f 100644 --- a/lucet-runtime/src/lib.rs +++ b/lucet-runtime/src/lib.rs @@ -65,23 +65,26 @@ //! demo](https://wasm.fastly-labs.com/), hostcalls are provided for manipulating HTTP requests, //! accessing a key/value store, etc. //! -//! Some simple hostcalls can be implemented simply as an exported C function that takes an opaque -//! pointer argument (usually called `vmctx`). Hostcalls that require access to some underlying -//! state, such as the key/value store in Terrarium, can access a custom embedder context through -//! `vmctx`. For example, to make a `u32` available to hostcalls: +//! Some simple hostcalls can be implemented by wrapping an externed C function with the +//! [`lucet_hostcalls!`](macro.lucet_hostcalls.html] macro. The function must take a special `&mut +//! vmctx` argument for the guest context, similar to `&mut self` on methods. Hostcalls that require +//! access to some underlying state, such as the key/value store in Terrarium, can access a custom +//! embedder context through `vmctx`. For example, to make a `u32` available to hostcalls: //! //! ```no_run -//! use lucet_runtime::{DlModule, Limits, MmapRegion, Region}; +//! use lucet_runtime::{DlModule, Limits, MmapRegion, Region, lucet_hostcalls}; //! use lucet_runtime::vmctx::{Vmctx, lucet_vmctx}; //! //! struct MyContext { x: u32 } //! -//! #[no_mangle] -//! unsafe extern "C" fn foo(vmctx: *mut lucet_vmctx) { -//! let mut vmctx = Vmctx::from_raw(vmctx); -//! let hostcall_context = vmctx -//! .get_embed_ctx_mut::(); -//! hostcall_context.x = 42; +//! lucet_hostcalls! { +//! #[no_mangle] +//! pub unsafe extern "C" fn foo( +//! &mut vmctx, +//! ) -> () { +//! let hostcall_context = vmctx.get_embed_ctx_mut::(); +//! hostcall_context.x = 42; +//! } //! } //! //! let module = DlModule::load("/my/lucet/module.so").unwrap(); @@ -195,7 +198,7 @@ //! that, for example, a `SIGSEGV` on a non-Lucet thread of a host program will still likely abort //! the entire process. -mod c_api; +pub mod c_api; pub use lucet_runtime_internals::alloc::Limits; pub use lucet_runtime_internals::error::Error; @@ -207,7 +210,7 @@ pub use lucet_runtime_internals::region::mmap::MmapRegion; pub use lucet_runtime_internals::region::{InstanceBuilder, Region, RegionCreate}; pub use lucet_runtime_internals::trapcode::TrapCode; pub use lucet_runtime_internals::val::{UntypedRetVal, Val}; -pub use lucet_runtime_internals::WASM_PAGE_SIZE; +pub use lucet_runtime_internals::{lucet_hostcall_terminate, lucet_hostcalls, WASM_PAGE_SIZE}; pub mod vmctx { //! Functions for manipulating instances from hostcalls. diff --git a/lucet-wasi/src/hostcalls.rs b/lucet-wasi/src/hostcalls.rs index fab47b37c..9a6971f25 100644 --- a/lucet-wasi/src/hostcalls.rs +++ b/lucet-wasi/src/hostcalls.rs @@ -9,13 +9,15 @@ //! something nice. #![allow(non_camel_case_types)] +#![allow(unused_unsafe)] use crate::ctx::WasiCtx; use crate::fdentry::{determine_type_rights, FdEntry}; use crate::memory::*; use crate::{host, wasm32}; use cast::From as _0; -use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; +use lucet_runtime::vmctx::Vmctx; +use lucet_runtime::{lucet_hostcall_terminate, lucet_hostcalls}; use nix::convert_ioctl_res; use nix::libc::c_int; @@ -30,676 +32,913 @@ const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_RSYNC; #[cfg(not(target_os = "linux"))] const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_SYNC; -#[no_mangle] -pub extern "C" fn __wasi_proc_exit(vmctx: *mut lucet_vmctx, rval: wasm32::__wasi_exitcode_t) -> ! { - let mut vmctx = unsafe { Vmctx::from_raw(vmctx) }; - vmctx.terminate(dec_exitcode(rval)) -} +lucet_hostcalls! { + #[no_mangle] + pub unsafe extern "C" fn __wasi_proc_exit( + &mut _vmctx, + rval: wasm32::__wasi_exitcode_t, + ) -> ! { + lucet_hostcall_terminate!(dec_exitcode(rval)); + } -#[no_mangle] -pub extern "C" fn __wasi_args_get( - vmctx_raw: *mut lucet_vmctx, - argv_ptr: wasm32::uintptr_t, - argv_buf: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - let mut vmctx = unsafe { Vmctx::from_raw(vmctx_raw) }; - let ctx: &WasiCtx = vmctx.get_embed_ctx(); + #[no_mangle] + pub unsafe extern "C" fn __wasi_args_get( + &mut vmctx, + argv_ptr: wasm32::uintptr_t, + argv_buf: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + let ctx: &WasiCtx = vmctx.get_embed_ctx(); + + let mut argv_buf_offset = 0; + let mut argv = vec![]; + + for arg in ctx.args.iter() { + let arg_bytes = arg.as_bytes_with_nul(); + let arg_ptr = argv_buf + argv_buf_offset; + + // nasty aliasing here, but we aren't interfering with the borrow for `ctx` + // TODO: rework vmctx interface to avoid this + let mut vmctx = unsafe { Vmctx::from_raw(vmctx.as_raw()) }; + if let Err(e) = unsafe { enc_slice_of(&mut vmctx, arg_bytes, arg_ptr) } { + return enc_errno(e); + } - let mut argv_buf_offset = 0; - let mut argv = vec![]; + argv.push(arg_ptr); - for arg in ctx.args.iter() { - let arg_bytes = arg.as_bytes_with_nul(); - let arg_ptr = argv_buf + argv_buf_offset; + argv_buf_offset = if let Some(new_offset) = argv_buf_offset.checked_add( + wasm32::uintptr_t::cast(arg_bytes.len()) + .expect("cast overflow would have been caught by `enc_slice_of` above"), + ) { + new_offset + } else { + return wasm32::__WASI_EOVERFLOW; + } + } - // nasty aliasing here, but we aren't interfering with the borrow for `ctx` - // TODO: rework vmctx interface to avoid this - let mut vmctx = unsafe { Vmctx::from_raw(vmctx_raw) }; - if let Err(e) = unsafe { enc_slice_of(&mut vmctx, arg_bytes, arg_ptr) } { - return enc_errno(e); + unsafe { + enc_slice_of(vmctx, argv.as_slice(), argv_ptr) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) } + } - argv.push(arg_ptr); + #[no_mangle] + pub unsafe extern "C" fn __wasi_args_sizes_get( + &mut vmctx, + argc_ptr: wasm32::uintptr_t, + argv_buf_size_ptr: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + let ctx: &WasiCtx = vmctx.get_embed_ctx(); + + let argc = ctx.args.len(); + let argv_size = ctx + .args + .iter() + .map(|arg| arg.as_bytes_with_nul().len()) + .sum(); - argv_buf_offset = if let Some(new_offset) = argv_buf_offset.checked_add( - wasm32::uintptr_t::cast(arg_bytes.len()) - .expect("cast overflow would have been caught by `enc_slice_of` above"), - ) { - new_offset - } else { - return wasm32::__WASI_EOVERFLOW; + unsafe { + if let Err(e) = enc_usize_byref(vmctx, argc_ptr, argc) { + return enc_errno(e); + } + if let Err(e) = enc_usize_byref(vmctx, argv_buf_size_ptr, argv_size) { + return enc_errno(e); + } } + wasm32::__WASI_ESUCCESS } - unsafe { - enc_slice_of(&mut vmctx, argv.as_slice(), argv_ptr) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } -} + #[no_mangle] + pub unsafe extern "C" fn __wasi_clock_res_get( + &mut vmctx, + clock_id: wasm32::__wasi_clockid_t, + resolution_ptr: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + // convert the supported clocks to the libc types, or return EINVAL + let clock_id = match dec_clockid(clock_id) { + host::__WASI_CLOCK_REALTIME => libc::CLOCK_REALTIME, + host::__WASI_CLOCK_MONOTONIC => libc::CLOCK_MONOTONIC, + host::__WASI_CLOCK_PROCESS_CPUTIME_ID => libc::CLOCK_PROCESS_CPUTIME_ID, + host::__WASI_CLOCK_THREAD_CPUTIME_ID => libc::CLOCK_THREAD_CPUTIME_ID, + _ => return wasm32::__WASI_EINVAL, + }; -#[no_mangle] -pub extern "C" fn __wasi_args_sizes_get( - vmctx: *mut lucet_vmctx, - argc_ptr: wasm32::uintptr_t, - argv_buf_size_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - let mut vmctx = unsafe { Vmctx::from_raw(vmctx) }; + // no `nix` wrapper for clock_getres, so we do it ourselves + let mut timespec = unsafe { std::mem::uninitialized::() }; + let res = unsafe { libc::clock_getres(clock_id, &mut timespec as *mut libc::timespec) }; + if res != 0 { + return wasm32::errno_from_nix(nix::errno::Errno::last()); + } - let ctx: &WasiCtx = vmctx.get_embed_ctx(); + // convert to nanoseconds, returning EOVERFLOW in case of overflow; this is freelancing a bit + // from the spec but seems like it'll be an unusual situation to hit + (timespec.tv_sec as host::__wasi_timestamp_t) + .checked_mul(1_000_000_000) + .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t)) + .map(|resolution| { + // a supported clock can never return zero; this case will probably never get hit, but + // make sure we follow the spec + if resolution == 0 { + wasm32::__WASI_EINVAL + } else { + unsafe { + enc_timestamp_byref(vmctx, resolution_ptr, resolution) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) + } + } + }) + .unwrap_or(wasm32::__WASI_EOVERFLOW) + } - let argc = ctx.args.len(); - let argv_size = ctx - .args - .iter() - .map(|arg| arg.as_bytes_with_nul().len()) - .sum(); + #[no_mangle] + pub unsafe extern "C" fn __wasi_clock_time_get( + &mut vmctx, + clock_id: wasm32::__wasi_clockid_t, + // ignored for now, but will be useful once we put optional limits on precision to reduce side + // channels + _precision: wasm32::__wasi_timestamp_t, + time_ptr: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + // convert the supported clocks to the libc types, or return EINVAL + let clock_id = match dec_clockid(clock_id) { + host::__WASI_CLOCK_REALTIME => libc::CLOCK_REALTIME, + host::__WASI_CLOCK_MONOTONIC => libc::CLOCK_MONOTONIC, + host::__WASI_CLOCK_PROCESS_CPUTIME_ID => libc::CLOCK_PROCESS_CPUTIME_ID, + host::__WASI_CLOCK_THREAD_CPUTIME_ID => libc::CLOCK_THREAD_CPUTIME_ID, + _ => return wasm32::__WASI_EINVAL, + }; - unsafe { - if let Err(e) = enc_usize_byref(&mut vmctx, argc_ptr, argc) { - return enc_errno(e); + // no `nix` wrapper for clock_getres, so we do it ourselves + let mut timespec = unsafe { std::mem::uninitialized::() }; + let res = unsafe { libc::clock_gettime(clock_id, &mut timespec as *mut libc::timespec) }; + if res != 0 { + return wasm32::errno_from_nix(nix::errno::Errno::last()); } - if let Err(e) = enc_usize_byref(&mut vmctx, argv_buf_size_ptr, argv_size) { - return enc_errno(e); - } - } - wasm32::__WASI_ESUCCESS -} -#[no_mangle] -pub extern "C" fn __wasi_clock_res_get( - vmctx: *mut lucet_vmctx, - clock_id: wasm32::__wasi_clockid_t, - resolution_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - let mut vmctx = unsafe { Vmctx::from_raw(vmctx) }; - - // convert the supported clocks to the libc types, or return EINVAL - let clock_id = match dec_clockid(clock_id) { - host::__WASI_CLOCK_REALTIME => libc::CLOCK_REALTIME, - host::__WASI_CLOCK_MONOTONIC => libc::CLOCK_MONOTONIC, - host::__WASI_CLOCK_PROCESS_CPUTIME_ID => libc::CLOCK_PROCESS_CPUTIME_ID, - host::__WASI_CLOCK_THREAD_CPUTIME_ID => libc::CLOCK_THREAD_CPUTIME_ID, - _ => return wasm32::__WASI_EINVAL, - }; - - // no `nix` wrapper for clock_getres, so we do it ourselves - let mut timespec = unsafe { std::mem::uninitialized::() }; - let res = unsafe { libc::clock_getres(clock_id, &mut timespec as *mut libc::timespec) }; - if res != 0 { - return wasm32::errno_from_nix(nix::errno::Errno::last()); + // convert to nanoseconds, returning EOVERFLOW in case of overflow; this is freelancing a bit + // from the spec but seems like it'll be an unusual situation to hit + (timespec.tv_sec as host::__wasi_timestamp_t) + .checked_mul(1_000_000_000) + .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t)) + .map(|time| unsafe { + enc_timestamp_byref(vmctx, time_ptr, time) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) + }) + .unwrap_or(wasm32::__WASI_EOVERFLOW) } - // convert to nanoseconds, returning EOVERFLOW in case of overflow; this is freelancing a bit - // from the spec but seems like it'll be an unusual situation to hit - (timespec.tv_sec as host::__wasi_timestamp_t) - .checked_mul(1_000_000_000) - .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t)) - .map(|resolution| { - // a supported clock can never return zero; this case will probably never get hit, but - // make sure we follow the spec - if resolution == 0 { - wasm32::__WASI_EINVAL - } else { - unsafe { - enc_timestamp_byref(&mut vmctx, resolution_ptr, resolution) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } + #[no_mangle] + pub unsafe extern "C" fn __wasi_environ_get( + &mut vmctx, + environ_ptr: wasm32::uintptr_t, + environ_buf: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + let ctx: &WasiCtx = vmctx.get_embed_ctx(); + + let mut environ_buf_offset = 0; + let mut environ = vec![]; + + for pair in ctx.env.iter() { + let env_bytes = pair.as_bytes_with_nul(); + let env_ptr = environ_buf + environ_buf_offset; + + // nasty aliasing here, but we aren't interfering with the borrow for `ctx` + // TODO: rework vmctx interface to avoid this + let mut vmctx = unsafe { Vmctx::from_raw(vmctx.as_raw()) }; + if let Err(e) = unsafe { enc_slice_of(&mut vmctx, env_bytes, env_ptr) } { + return enc_errno(e); } - }) - .unwrap_or(wasm32::__WASI_EOVERFLOW) -} -#[no_mangle] -pub extern "C" fn __wasi_clock_time_get( - vmctx: *mut lucet_vmctx, - clock_id: wasm32::__wasi_clockid_t, - // ignored for now, but will be useful once we put optional limits on precision to reduce side - // channels - _precision: wasm32::__wasi_timestamp_t, - time_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - let mut vmctx = unsafe { Vmctx::from_raw(vmctx) }; - - // convert the supported clocks to the libc types, or return EINVAL - let clock_id = match dec_clockid(clock_id) { - host::__WASI_CLOCK_REALTIME => libc::CLOCK_REALTIME, - host::__WASI_CLOCK_MONOTONIC => libc::CLOCK_MONOTONIC, - host::__WASI_CLOCK_PROCESS_CPUTIME_ID => libc::CLOCK_PROCESS_CPUTIME_ID, - host::__WASI_CLOCK_THREAD_CPUTIME_ID => libc::CLOCK_THREAD_CPUTIME_ID, - _ => return wasm32::__WASI_EINVAL, - }; - - // no `nix` wrapper for clock_getres, so we do it ourselves - let mut timespec = unsafe { std::mem::uninitialized::() }; - let res = unsafe { libc::clock_gettime(clock_id, &mut timespec as *mut libc::timespec) }; - if res != 0 { - return wasm32::errno_from_nix(nix::errno::Errno::last()); - } + environ.push(env_ptr); - // convert to nanoseconds, returning EOVERFLOW in case of overflow; this is freelancing a bit - // from the spec but seems like it'll be an unusual situation to hit - (timespec.tv_sec as host::__wasi_timestamp_t) - .checked_mul(1_000_000_000) - .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t)) - .map(|time| unsafe { - enc_timestamp_byref(&mut vmctx, time_ptr, time) + environ_buf_offset = if let Some(new_offset) = environ_buf_offset.checked_add( + wasm32::uintptr_t::cast(env_bytes.len()) + .expect("cast overflow would have been caught by `enc_slice_of` above"), + ) { + new_offset + } else { + return wasm32::__WASI_EOVERFLOW; + } + } + + unsafe { + enc_slice_of(vmctx, environ.as_slice(), environ_ptr) .map(|_| wasm32::__WASI_ESUCCESS) .unwrap_or_else(|e| e) - }) - .unwrap_or(wasm32::__WASI_EOVERFLOW) -} - -#[no_mangle] -pub extern "C" fn __wasi_environ_get( - vmctx_raw: *mut lucet_vmctx, - environ_ptr: wasm32::uintptr_t, - environ_buf: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - let mut vmctx = unsafe { Vmctx::from_raw(vmctx_raw) }; - let ctx: &WasiCtx = vmctx.get_embed_ctx(); - - let mut environ_buf_offset = 0; - let mut environ = vec![]; + } + } - for pair in ctx.env.iter() { - let env_bytes = pair.as_bytes_with_nul(); - let env_ptr = environ_buf + environ_buf_offset; + #[no_mangle] + pub unsafe extern "C" fn __wasi_environ_sizes_get( + &mut vmctx, + environ_count_ptr: wasm32::uintptr_t, + environ_size_ptr: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + let ctx: &WasiCtx = vmctx.get_embed_ctx(); + + let environ_count = ctx.env.len(); + if let Some(environ_size) = ctx.env.iter().try_fold(0, |acc: u32, pair| { + acc.checked_add(pair.as_bytes_with_nul().len() as u32) + }) { + unsafe { + if let Err(e) = enc_usize_byref(vmctx, environ_count_ptr, environ_count) { + return enc_errno(e); + } + if let Err(e) = enc_usize_byref(vmctx, environ_size_ptr, environ_size as usize) { + return enc_errno(e); + } + } + wasm32::__WASI_ESUCCESS + } else { + wasm32::__WASI_EOVERFLOW + } + } - // nasty aliasing here, but we aren't interfering with the borrow for `ctx` - // TODO: rework vmctx interface to avoid this - let mut vmctx = unsafe { Vmctx::from_raw(vmctx_raw) }; - if let Err(e) = unsafe { enc_slice_of(&mut vmctx, env_bytes, env_ptr) } { - return enc_errno(e); + #[no_mangle] + pub unsafe extern "C" fn __wasi_fd_close( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + ) -> wasm32::__wasi_errno_t { + let ctx: &mut WasiCtx = vmctx.get_embed_ctx_mut(); + let fd = dec_fd(fd); + if let Some(fdent) = ctx.fds.get(&fd) { + // can't close preopened files + if fdent.preopen_path.is_some() { + return wasm32::__WASI_ENOTSUP; + } } + if let Some(mut fdent) = ctx.fds.remove(&fd) { + fdent.fd_object.needs_close = false; + match nix::unistd::close(fdent.fd_object.rawfd) { + Ok(_) => wasm32::__WASI_ESUCCESS, + Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()), + } + } else { + wasm32::__WASI_EBADF + } + } - environ.push(env_ptr); + #[no_mangle] + pub unsafe extern "C" fn __wasi_fd_fdstat_get( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + fdstat_ptr: wasm32::uintptr_t, // *mut wasm32::__wasi_fdstat_t + ) -> wasm32::__wasi_errno_t { + let host_fd = dec_fd(fd); + let mut host_fdstat = match unsafe { dec_fdstat_byref(vmctx, fdstat_ptr) } { + Ok(host_fdstat) => host_fdstat, + Err(e) => return enc_errno(e), + }; - environ_buf_offset = if let Some(new_offset) = environ_buf_offset.checked_add( - wasm32::uintptr_t::cast(env_bytes.len()) - .expect("cast overflow would have been caught by `enc_slice_of` above"), - ) { - new_offset + let ctx: &mut WasiCtx = vmctx.get_embed_ctx_mut(); + let errno = if let Some(fe) = ctx.fds.get(&host_fd) { + host_fdstat.fs_filetype = fe.fd_object.ty; + host_fdstat.fs_rights_base = fe.rights_base; + host_fdstat.fs_rights_inheriting = fe.rights_inheriting; + use nix::fcntl::{fcntl, OFlag, F_GETFL}; + match fcntl(fe.fd_object.rawfd, F_GETFL).map(OFlag::from_bits_truncate) { + Ok(flags) => { + host_fdstat.fs_flags = host::fdflags_from_nix(flags); + wasm32::__WASI_ESUCCESS + } + Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()), + } } else { - return wasm32::__WASI_EOVERFLOW; + wasm32::__WASI_EBADF + }; + + unsafe { + enc_fdstat_byref(vmctx, fdstat_ptr, host_fdstat) + .expect("can write back into the pointer we read from"); } + + errno } - unsafe { - enc_slice_of(&mut vmctx, environ.as_slice(), environ_ptr) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) + #[no_mangle] + pub unsafe extern "C" fn __wasi_fd_fdstat_set_flags( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + fdflags: wasm32::__wasi_fdflags_t, + ) -> wasm32::__wasi_errno_t { + let host_fd = dec_fd(fd); + let host_fdflags = dec_fdflags(fdflags); + let nix_flags = host::nix_from_fdflags(host_fdflags); + + let ctx: &mut WasiCtx = vmctx.get_embed_ctx_mut(); + + if let Some(fe) = ctx.fds.get(&host_fd) { + match nix::fcntl::fcntl(fe.fd_object.rawfd, nix::fcntl::F_SETFL(nix_flags)) { + Ok(_) => wasm32::__WASI_ESUCCESS, + Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()), + } + } else { + wasm32::__WASI_EBADF + } } -} -#[no_mangle] -pub extern "C" fn __wasi_environ_sizes_get( - vmctx: *mut lucet_vmctx, - environ_count_ptr: wasm32::uintptr_t, - environ_size_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - let mut vmctx = unsafe { Vmctx::from_raw(vmctx) }; + #[no_mangle] + pub unsafe extern "C" fn __wasi_fd_seek( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + offset: wasm32::__wasi_filedelta_t, + whence: wasm32::__wasi_whence_t, + newoffset: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + let ctx: &mut WasiCtx = vmctx.get_embed_ctx_mut(); + let fd = dec_fd(fd); + let offset = dec_filedelta(offset); + let whence = dec_whence(whence); + + let host_newoffset = { + use nix::unistd::{lseek, Whence}; + let nwhence = match whence as u32 { + host::__WASI_WHENCE_CUR => Whence::SeekCur, + host::__WASI_WHENCE_END => Whence::SeekEnd, + host::__WASI_WHENCE_SET => Whence::SeekSet, + _ => return wasm32::__WASI_EINVAL, + }; - let ctx: &WasiCtx = vmctx.get_embed_ctx(); + let rights = if offset == 0 && whence as u32 == host::__WASI_WHENCE_CUR { + host::__WASI_RIGHT_FD_TELL + } else { + host::__WASI_RIGHT_FD_SEEK | host::__WASI_RIGHT_FD_TELL + }; + match ctx.get_fd_entry(fd, rights.into(), 0) { + Ok(fe) => match lseek(fe.fd_object.rawfd, offset, nwhence) { + Ok(newoffset) => newoffset, + Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), + }, + Err(e) => return enc_errno(e), + } + }; - let environ_count = ctx.env.len(); - if let Some(environ_size) = ctx.env.iter().try_fold(0, |acc: u32, pair| { - acc.checked_add(pair.as_bytes_with_nul().len() as u32) - }) { unsafe { - if let Err(e) = enc_usize_byref(&mut vmctx, environ_count_ptr, environ_count) { - return enc_errno(e); - } - if let Err(e) = enc_usize_byref(&mut vmctx, environ_size_ptr, environ_size as usize) { - return enc_errno(e); - } + enc_filesize_byref(vmctx, newoffset, host_newoffset as u64) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) } - wasm32::__WASI_ESUCCESS - } else { - wasm32::__WASI_EOVERFLOW } -} -#[no_mangle] -pub extern "C" fn __wasi_fd_close( - vmctx: *mut lucet_vmctx, - fd: wasm32::__wasi_fd_t, -) -> wasm32::__wasi_errno_t { - let mut vmctx = unsafe { Vmctx::from_raw(vmctx) }; - let ctx: &mut WasiCtx = vmctx.get_embed_ctx_mut(); - let fd = dec_fd(fd); - if let Some(fdent) = ctx.fds.get(&fd) { - // can't close preopened files - if fdent.preopen_path.is_some() { - return wasm32::__WASI_ENOTSUP; + #[no_mangle] + pub unsafe extern "C" fn __wasi_fd_prestat_get( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + prestat_ptr: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + let ctx: &WasiCtx = vmctx.get_embed_ctx(); + let fd = dec_fd(fd); + // TODO: is this the correct right for this? + match ctx.get_fd_entry(fd, host::__WASI_RIGHT_PATH_OPEN.into(), 0) { + Ok(fe) => { + if let Some(po_path) = &fe.preopen_path { + if fe.fd_object.ty != host::__WASI_FILETYPE_DIRECTORY as host::__wasi_filetype_t { + return wasm32::__WASI_ENOTDIR; + } + // nasty aliasing here, but we aren't interfering with the borrow for `ctx` + // TODO: rework vmctx interface to avoid this + unsafe { + enc_prestat_byref( + &mut Vmctx::from_raw(vmctx.as_raw()), + prestat_ptr, + host::__wasi_prestat_t { + pr_type: host::__WASI_PREOPENTYPE_DIR as host::__wasi_preopentype_t, + u: host::__wasi_prestat_t___wasi_prestat_u { + dir: + host::__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t { + pr_name_len: po_path.as_os_str().as_bytes().len(), + }, + }, + }, + ) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) + } + } else { + wasm32::__WASI_ENOTSUP + } + } + Err(e) => enc_errno(e), } } - if let Some(mut fdent) = ctx.fds.remove(&fd) { - fdent.fd_object.needs_close = false; - match nix::unistd::close(fdent.fd_object.rawfd) { - Ok(_) => wasm32::__WASI_ESUCCESS, - Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()), + + #[no_mangle] + pub unsafe extern "C" fn __wasi_fd_prestat_dir_name( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, + ) -> wasm32::__wasi_errno_t { + let ctx: &WasiCtx = vmctx.get_embed_ctx(); + let fd = dec_fd(fd); + match ctx.get_fd_entry(fd, host::__WASI_RIGHT_PATH_OPEN.into(), 0) { + Ok(fe) => { + if let Some(po_path) = &fe.preopen_path { + if fe.fd_object.ty != host::__WASI_FILETYPE_DIRECTORY as host::__wasi_filetype_t { + return wasm32::__WASI_ENOTDIR; + } + let path_bytes = po_path.as_os_str().as_bytes(); + if path_bytes.len() > dec_usize(path_len) { + return wasm32::__WASI_ENAMETOOLONG; + } + // nasty aliasing here, but we aren't interfering with the borrow for `ctx` + // TODO: rework vmctx interface to avoid this + unsafe { + enc_slice_of(&mut Vmctx::from_raw(vmctx.as_raw()), path_bytes, path_ptr) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) + } + } else { + wasm32::__WASI_ENOTSUP + } + } + Err(e) => enc_errno(e), } - } else { - wasm32::__WASI_EBADF } -} -#[no_mangle] -pub extern "C" fn __wasi_fd_fdstat_get( - vmctx: *mut lucet_vmctx, - fd: wasm32::__wasi_fd_t, - fdstat_ptr: wasm32::uintptr_t, // *mut wasm32::__wasi_fdstat_t -) -> wasm32::__wasi_errno_t { - let mut vmctx = unsafe { Vmctx::from_raw(vmctx) }; - - let host_fd = dec_fd(fd); - let mut host_fdstat = match unsafe { dec_fdstat_byref(&mut vmctx, fdstat_ptr) } { - Ok(host_fdstat) => host_fdstat, - Err(e) => return enc_errno(e), - }; - - let ctx: &mut WasiCtx = vmctx.get_embed_ctx_mut(); - let errno = if let Some(fe) = ctx.fds.get(&host_fd) { - host_fdstat.fs_filetype = fe.fd_object.ty; - host_fdstat.fs_rights_base = fe.rights_base; - host_fdstat.fs_rights_inheriting = fe.rights_inheriting; - use nix::fcntl::{fcntl, OFlag, F_GETFL}; - match fcntl(fe.fd_object.rawfd, F_GETFL).map(OFlag::from_bits_truncate) { - Ok(flags) => { - host_fdstat.fs_flags = host::fdflags_from_nix(flags); - wasm32::__WASI_ESUCCESS - } - Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()), + #[no_mangle] + pub unsafe extern "C" fn __wasi_fd_read( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + iovs_ptr: wasm32::uintptr_t, + iovs_len: wasm32::size_t, + nread: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + use nix::sys::uio::{readv, IoVec}; + + let fd = dec_fd(fd); + let mut iovs = match unsafe { dec_ciovec_slice(vmctx, iovs_ptr, iovs_len) } { + Ok(iovs) => iovs, + Err(e) => return enc_errno(e), + }; + + let ctx: &mut WasiCtx = vmctx.get_embed_ctx_mut(); + let fe = match ctx.get_fd_entry(fd, host::__WASI_RIGHT_FD_READ.into(), 0) { + Ok(fe) => fe, + Err(e) => return enc_errno(e), + }; + + let mut iovs: Vec> = iovs + .iter_mut() + .map(|iov| unsafe { host::ciovec_to_nix_mut(iov) }) + .collect(); + + let full_nread = iovs.iter().map(|iov| iov.as_slice().len()).sum(); + + let host_nread = match readv(fe.fd_object.rawfd, &mut iovs) { + Ok(len) => len, + Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), + }; + + if host_nread < full_nread { + // we hit eof, so remove the fdentry from the context + let mut fe = ctx.fds.remove(&fd).expect("file entry is still there"); + fe.fd_object.needs_close = false; } - } else { - wasm32::__WASI_EBADF - }; - unsafe { - enc_fdstat_byref(&mut vmctx, fdstat_ptr, host_fdstat) - .expect("can write back into the pointer we read from"); + unsafe { + enc_usize_byref(vmctx, nread, host_nread) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) + } } - errno -} + #[no_mangle] + pub unsafe extern "C" fn __wasi_fd_write( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + iovs_ptr: wasm32::uintptr_t, + iovs_len: wasm32::size_t, + nwritten: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + use nix::sys::uio::{writev, IoVec}; + + let fd = dec_fd(fd); + let iovs = match unsafe { dec_ciovec_slice(vmctx, iovs_ptr, iovs_len) } { + Ok(iovs) => iovs, + Err(e) => return enc_errno(e), + }; -#[no_mangle] -pub extern "C" fn __wasi_fd_fdstat_set_flags( - vmctx: *mut lucet_vmctx, - fd: wasm32::__wasi_fd_t, - fdflags: wasm32::__wasi_fdflags_t, -) -> wasm32::__wasi_errno_t { - let mut vmctx = unsafe { Vmctx::from_raw(vmctx) }; + let ctx: &mut WasiCtx = vmctx.get_embed_ctx_mut(); + let fe = match ctx.get_fd_entry(fd, host::__WASI_RIGHT_FD_WRITE.into(), 0) { + Ok(fe) => fe, + Err(e) => return enc_errno(e), + }; - let host_fd = dec_fd(fd); - let host_fdflags = dec_fdflags(fdflags); - let nix_flags = host::nix_from_fdflags(host_fdflags); + let iovs: Vec> = iovs + .iter() + .map(|iov| unsafe { host::ciovec_to_nix(iov) }) + .collect(); - let ctx: &mut WasiCtx = vmctx.get_embed_ctx_mut(); + let host_nwritten = match writev(fe.fd_object.rawfd, &iovs) { + Ok(len) => len, + Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), + }; - if let Some(fe) = ctx.fds.get(&host_fd) { - match nix::fcntl::fcntl(fe.fd_object.rawfd, nix::fcntl::F_SETFL(nix_flags)) { - Ok(_) => wasm32::__WASI_ESUCCESS, - Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()), + unsafe { + enc_usize_byref(vmctx, nwritten, host_nwritten) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) } - } else { - wasm32::__WASI_EBADF } -} -#[no_mangle] -pub extern "C" fn __wasi_fd_seek( - vmctx: *mut lucet_vmctx, - fd: wasm32::__wasi_fd_t, - offset: wasm32::__wasi_filedelta_t, - whence: wasm32::__wasi_whence_t, - newoffset: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - let mut vmctx = unsafe { Vmctx::from_raw(vmctx) }; - let ctx: &mut WasiCtx = vmctx.get_embed_ctx_mut(); - let fd = dec_fd(fd); - let offset = dec_filedelta(offset); - let whence = dec_whence(whence); - - let host_newoffset = { - use nix::unistd::{lseek, Whence}; - let nwhence = match whence as u32 { - host::__WASI_WHENCE_CUR => Whence::SeekCur, - host::__WASI_WHENCE_END => Whence::SeekEnd, - host::__WASI_WHENCE_SET => Whence::SeekSet, - _ => return wasm32::__WASI_EINVAL, + #[no_mangle] + pub unsafe extern "C" fn __wasi_path_open( + &mut vmctx, + dirfd: wasm32::__wasi_fd_t, + dirflags: wasm32::__wasi_lookupflags_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, + oflags: wasm32::__wasi_oflags_t, + fs_rights_base: wasm32::__wasi_rights_t, + fs_rights_inheriting: wasm32::__wasi_rights_t, + fs_flags: wasm32::__wasi_fdflags_t, + fd_out_ptr: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + use nix::errno::Errno; + use nix::fcntl::{openat, AtFlags, OFlag}; + use nix::sys::stat::{fstatat, Mode, SFlag}; + + let dirfd = dec_fd(dirfd); + let dirflags = dec_lookupflags(dirflags); + let oflags = dec_oflags(oflags); + let fs_rights_base = dec_rights(fs_rights_base); + let fs_rights_inheriting = dec_rights(fs_rights_inheriting); + let fs_flags = dec_fdflags(fs_flags); + + // which open mode do we need? + let read = fs_rights_base + & ((host::__WASI_RIGHT_FD_READ | host::__WASI_RIGHT_FD_READDIR) as host::__wasi_rights_t) + != 0; + let write = fs_rights_base + & ((host::__WASI_RIGHT_FD_DATASYNC + | host::__WASI_RIGHT_FD_WRITE + | host::__WASI_RIGHT_FD_ALLOCATE + | host::__WASI_RIGHT_PATH_FILESTAT_SET_SIZE) as host::__wasi_rights_t) + != 0; + + let mut nix_all_oflags = if read && write { + OFlag::O_RDWR + } else if read { + OFlag::O_RDONLY + } else { + OFlag::O_WRONLY }; - let rights = if offset == 0 && whence as u32 == host::__WASI_WHENCE_CUR { - host::__WASI_RIGHT_FD_TELL - } else { - host::__WASI_RIGHT_FD_SEEK | host::__WASI_RIGHT_FD_TELL + // on non-Capsicum systems, we always want nofollow + nix_all_oflags.insert(OFlag::O_NOFOLLOW); + + // which rights are needed on the dirfd? + let mut needed_base = host::__WASI_RIGHT_PATH_OPEN as host::__wasi_rights_t; + let mut needed_inheriting = fs_rights_base | fs_rights_inheriting; + + // convert open flags + let nix_oflags = host::nix_from_oflags(oflags); + nix_all_oflags.insert(nix_oflags); + if nix_all_oflags.contains(OFlag::O_CREAT) { + needed_base |= host::__WASI_RIGHT_PATH_CREATE_FILE as host::__wasi_rights_t; + } + if nix_all_oflags.contains(OFlag::O_TRUNC) { + needed_inheriting |= host::__WASI_RIGHT_PATH_FILESTAT_SET_SIZE as host::__wasi_rights_t; + } + + // convert file descriptor flags + nix_all_oflags.insert(host::nix_from_fdflags(fs_flags)); + if nix_all_oflags.contains(OFlag::O_DSYNC) { + needed_inheriting |= host::__WASI_RIGHT_FD_DATASYNC as host::__wasi_rights_t; + } + if nix_all_oflags.intersects(O_RSYNC | OFlag::O_SYNC) { + needed_inheriting |= host::__WASI_RIGHT_FD_SYNC as host::__wasi_rights_t; + } + + let path = match unsafe { dec_slice_of::(vmctx, path_ptr, path_len) } { + Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + Err(e) => return enc_errno(e), }; - match ctx.get_fd_entry(fd, rights.into(), 0) { - Ok(fe) => match lseek(fe.fd_object.rawfd, offset, nwhence) { - Ok(newoffset) => newoffset, - Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), - }, + + let (dir, path) = match path_get( + &vmctx, + dirfd, + dirflags, + path, + needed_base, + needed_inheriting, + nix_oflags.contains(OFlag::O_CREAT), + ) { + Ok((dir, path)) => (dir, path), Err(e) => return enc_errno(e), + }; + + let new_fd = match openat( + dir, + path.as_os_str(), + nix_all_oflags, + Mode::from_bits_truncate(0o777), + ) { + Ok(fd) => fd, + Err(e) => { + match e.as_errno() { + // Linux returns ENXIO instead of EOPNOTSUPP when opening a socket + Some(Errno::ENXIO) => { + if let Ok(stat) = fstatat(dir, path.as_os_str(), AtFlags::AT_SYMLINK_NOFOLLOW) { + if SFlag::from_bits_truncate(stat.st_mode).contains(SFlag::S_IFSOCK) { + return wasm32::__WASI_ENOTSUP; + } else { + return wasm32::__WASI_ENXIO; + } + } else { + return wasm32::__WASI_ENXIO; + } + } + Some(e) => return wasm32::errno_from_nix(e), + None => return wasm32::__WASI_ENOSYS, + } + } + }; + + // Determine the type of the new file descriptor and which rights contradict with this type + let guest_fd = match unsafe { determine_type_rights(new_fd) } { + Err(e) => { + // if `close` fails, note it but do not override the underlying errno + nix::unistd::close(new_fd).unwrap_or_else(|e| { + dbg!(e); + }); + return enc_errno(e); + } + Ok((_ty, max_base, max_inheriting)) => { + let mut fe = unsafe { FdEntry::from_raw_fd(new_fd) }; + fe.rights_base &= max_base; + fe.rights_inheriting &= max_inheriting; + match vmctx.get_embed_ctx_mut::().insert_fd_entry(fe) { + Ok(fd) => fd, + Err(e) => return enc_errno(e), + } + } + }; + + unsafe { + enc_fd_byref(vmctx, fd_out_ptr, guest_fd) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) } - }; + } - unsafe { - enc_filesize_byref(&mut vmctx, newoffset, host_newoffset as u64) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) + #[no_mangle] + pub unsafe extern "C" fn __wasi_random_get( + &mut vmctx, + buf_ptr: wasm32::uintptr_t, + buf_len: wasm32::size_t, + ) -> wasm32::__wasi_errno_t { + use rand::{thread_rng, RngCore}; + + let buf_len = dec_usize(buf_len); + let buf_ptr = match unsafe { dec_ptr(vmctx, buf_ptr, buf_len) } { + Ok(ptr) => ptr, + Err(e) => return enc_errno(e), + }; + + let buf = unsafe { std::slice::from_raw_parts_mut(buf_ptr, buf_len) }; + + thread_rng().fill_bytes(buf); + + return wasm32::__WASI_ESUCCESS; + } + + #[no_mangle] + pub unsafe extern "C" fn __wasi_poll_oneoff( + &mut vmctx, + input: wasm32::uintptr_t, + output: wasm32::uintptr_t, + nsubscriptions: wasm32::size_t, + nevents: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + if nsubscriptions as u64 > wasm32::__wasi_filesize_t::max_value() { + return wasm32::__WASI_EINVAL; + } + unsafe { enc_pointee(vmctx, nevents, 0) }.unwrap(); + let input_slice_ = + unsafe { dec_slice_of::(vmctx, input, nsubscriptions) } + .unwrap(); + let input_slice = unsafe { slice::from_raw_parts(input_slice_.0, input_slice_.1) }; + + let output_slice_ = + unsafe { dec_slice_of::(vmctx, output, nsubscriptions) } + .unwrap(); + let output_slice = unsafe { slice::from_raw_parts_mut(output_slice_.0, output_slice_.1) }; + + let input: Vec<_> = input_slice.iter().map(|x| dec_subscription(x)).collect(); + + let timeout = input + .iter() + .filter_map(|event| match event { + Ok(event) if event.type_ == wasm32::__WASI_EVENTTYPE_CLOCK => Some(ClockEventData { + delay: wasi_clock_to_relative_ns_delay(unsafe { event.u.clock }) / 1_000_000, + userdata: event.userdata, + }), + _ => None, + }) + .min_by_key(|event| event.delay); + let fd_events: Vec<_> = input + .iter() + .filter_map(|event| match event { + Ok(event) + if event.type_ == wasm32::__WASI_EVENTTYPE_FD_READ + || event.type_ == wasm32::__WASI_EVENTTYPE_FD_WRITE => + { + Some(FdEventData { + fd: unsafe { event.u.fd_readwrite.fd } as c_int, + type_: event.type_, + userdata: event.userdata, + }) + } + _ => None, + }) + .collect(); + if fd_events.is_empty() && timeout.is_none() { + return wasm32::__WASI_ESUCCESS; + } + let mut poll_fds: Vec<_> = fd_events + .iter() + .map(|event| { + let mut flags = nix::poll::EventFlags::empty(); + match event.type_ { + wasm32::__WASI_EVENTTYPE_FD_READ => flags.insert(nix::poll::EventFlags::POLLIN), + wasm32::__WASI_EVENTTYPE_FD_WRITE => flags.insert(nix::poll::EventFlags::POLLOUT), + // An event on a file descriptor can currently only be of type FD_READ or FD_WRITE + // Nothing else has been defined in the specification, and these are also the only two + // events we filtered before. If we get something else here, the code has a serious bug. + _ => unreachable!(), + }; + nix::poll::PollFd::new(event.fd, flags) + }) + .collect(); + let timeout = timeout.map(|ClockEventData { delay, userdata }| ClockEventData { + delay: cmp::min(delay, c_int::max_value() as u128), + userdata, + }); + let poll_timeout = timeout.map(|timeout| timeout.delay as c_int).unwrap_or(-1); + let ready = loop { + match nix::poll::poll(&mut poll_fds, poll_timeout) { + Err(_) => { + if nix::errno::Errno::last() == nix::errno::Errno::EINTR { + continue; + } + return wasm32::errno_from_nix(nix::errno::Errno::last()); + } + Ok(ready) => break ready as usize, + } + }; + if ready == 0 { + return __wasi_poll_oneoff_handle_timeout_event(vmctx, output_slice, nevents, timeout); + } + let events = fd_events.iter().zip(poll_fds.iter()).take(ready); + __wasi_poll_oneoff_handle_fd_event(vmctx, output_slice, nevents, events) + } +} + +// define the `fionread()` function, equivalent to `ioctl(fd, FIONREAD, *bytes)` +nix::ioctl_read_bad!(fionread, nix::libc::FIONREAD, c_int); + +fn wasi_clock_to_relative_ns_delay( + wasi_clock: host::__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, +) -> u128 { + if wasi_clock.flags != wasm32::__WASI_SUBSCRIPTION_CLOCK_ABSTIME { + return wasi_clock.timeout as u128; + } + let now: u128 = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .expect("Current date is before the epoch") + .as_nanos(); + let deadline = wasi_clock.timeout as u128; + deadline.saturating_sub(now) +} + +#[derive(Debug, Copy, Clone)] +struct ClockEventData { + delay: u128, + userdata: host::__wasi_userdata_t, +} +#[derive(Debug, Copy, Clone)] +struct FdEventData { + fd: c_int, + type_: host::__wasi_eventtype_t, + userdata: host::__wasi_userdata_t, +} + +fn __wasi_poll_oneoff_handle_timeout_event( + vmctx: &mut Vmctx, + output_slice: &mut [wasm32::__wasi_event_t], + nevents: wasm32::uintptr_t, + timeout: Option, +) -> wasm32::__wasi_errno_t { + if let Some(ClockEventData { userdata, .. }) = timeout { + let output_event = host::__wasi_event_t { + userdata, + type_: wasm32::__WASI_EVENTTYPE_CLOCK, + error: wasm32::__WASI_ESUCCESS, + u: host::__wasi_event_t___wasi_event_u { + fd_readwrite: host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { + nbytes: 0, + flags: 0, + }, + }, + }; + output_slice[0] = enc_event(output_event); + if let Err(e) = unsafe { enc_pointee(vmctx, nevents, 1) } { + return enc_errno(e); + } + } else { + // shouldn't happen + if let Err(e) = unsafe { enc_pointee(vmctx, nevents, 0) } { + return enc_errno(e); + } } + wasm32::__WASI_ESUCCESS } -#[no_mangle] -pub extern "C" fn __wasi_fd_prestat_get( - vmctx_raw: *mut lucet_vmctx, - fd: wasm32::__wasi_fd_t, - prestat_ptr: wasm32::uintptr_t, +fn __wasi_poll_oneoff_handle_fd_event<'t>( + vmctx: &mut Vmctx, + output_slice: &mut [wasm32::__wasi_event_t], + nevents: wasm32::uintptr_t, + events: impl Iterator, ) -> wasm32::__wasi_errno_t { - let vmctx = unsafe { Vmctx::from_raw(vmctx_raw) }; - let ctx: &WasiCtx = vmctx.get_embed_ctx(); - let fd = dec_fd(fd); - // TODO: is this the correct right for this? - match ctx.get_fd_entry(fd, host::__WASI_RIGHT_PATH_OPEN.into(), 0) { - Ok(fe) => { - if let Some(po_path) = &fe.preopen_path { - if fe.fd_object.ty != host::__WASI_FILETYPE_DIRECTORY as host::__wasi_filetype_t { - return wasm32::__WASI_ENOTDIR; - } - // nasty aliasing here, but we aren't interfering with the borrow for `ctx` - // TODO: rework vmctx interface to avoid this - unsafe { - enc_prestat_byref( - &mut Vmctx::from_raw(vmctx_raw), - prestat_ptr, - host::__wasi_prestat_t { - pr_type: host::__WASI_PREOPENTYPE_DIR as host::__wasi_preopentype_t, - u: host::__wasi_prestat_t___wasi_prestat_u { - dir: - host::__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t { - pr_name_len: po_path.as_os_str().as_bytes().len(), - }, - }, + let mut output_slice_cur = output_slice.iter_mut(); + let mut revents_count = 0; + for (fd_event, poll_fd) in events { + let revents = match poll_fd.revents() { + Some(revents) => revents, + None => continue, + }; + let mut nbytes = 0; + if fd_event.type_ == wasm32::__WASI_EVENTTYPE_FD_READ { + let _ = unsafe { fionread(fd_event.fd, &mut nbytes) }; + } + let output_event = if revents.contains(nix::poll::EventFlags::POLLNVAL) { + host::__wasi_event_t { + userdata: fd_event.userdata, + type_: fd_event.type_, + error: wasm32::__WASI_EBADF, + u: host::__wasi_event_t___wasi_event_u { + fd_readwrite: + host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { + nbytes: 0, + flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP, + }, + }, + } + } else if revents.contains(nix::poll::EventFlags::POLLERR) { + host::__wasi_event_t { + userdata: fd_event.userdata, + type_: fd_event.type_, + error: wasm32::__WASI_EIO, + u: host::__wasi_event_t___wasi_event_u { + fd_readwrite: + host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { + nbytes: 0, + flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP, + }, + }, + } + } else if revents.contains(nix::poll::EventFlags::POLLHUP) { + host::__wasi_event_t { + userdata: fd_event.userdata, + type_: fd_event.type_, + error: wasm32::__WASI_ESUCCESS, + u: host::__wasi_event_t___wasi_event_u { + fd_readwrite: + host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { + nbytes: 0, + flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP, }, - ) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } - } else { - wasm32::__WASI_ENOTSUP + }, } - } - Err(e) => enc_errno(e), - } -} - -#[no_mangle] -pub extern "C" fn __wasi_fd_prestat_dir_name( - vmctx_raw: *mut lucet_vmctx, - fd: wasm32::__wasi_fd_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, -) -> wasm32::__wasi_errno_t { - let vmctx = unsafe { Vmctx::from_raw(vmctx_raw) }; - let ctx: &WasiCtx = vmctx.get_embed_ctx(); - let fd = dec_fd(fd); - match ctx.get_fd_entry(fd, host::__WASI_RIGHT_PATH_OPEN.into(), 0) { - Ok(fe) => { - if let Some(po_path) = &fe.preopen_path { - if fe.fd_object.ty != host::__WASI_FILETYPE_DIRECTORY as host::__wasi_filetype_t { - return wasm32::__WASI_ENOTDIR; - } - let path_bytes = po_path.as_os_str().as_bytes(); - if path_bytes.len() > dec_usize(path_len) { - return wasm32::__WASI_ENAMETOOLONG; - } - // nasty aliasing here, but we aren't interfering with the borrow for `ctx` - // TODO: rework vmctx interface to avoid this - unsafe { - enc_slice_of(&mut Vmctx::from_raw(vmctx_raw), path_bytes, path_ptr) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } - } else { - wasm32::__WASI_ENOTSUP + } else if revents.contains(nix::poll::EventFlags::POLLIN) + | revents.contains(nix::poll::EventFlags::POLLOUT) + { + host::__wasi_event_t { + userdata: fd_event.userdata, + type_: fd_event.type_, + error: wasm32::__WASI_ESUCCESS, + u: host::__wasi_event_t___wasi_event_u { + fd_readwrite: + host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { + nbytes: nbytes as host::__wasi_filesize_t, + flags: 0, + }, + }, } - } - Err(e) => enc_errno(e), - } -} - -#[no_mangle] -pub extern "C" fn __wasi_fd_read( - vmctx: *mut lucet_vmctx, - fd: wasm32::__wasi_fd_t, - iovs_ptr: wasm32::uintptr_t, - iovs_len: wasm32::size_t, - nread: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - use nix::sys::uio::{readv, IoVec}; - - let mut vmctx = unsafe { Vmctx::from_raw(vmctx) }; - let fd = dec_fd(fd); - let mut iovs = match unsafe { dec_ciovec_slice(&mut vmctx, iovs_ptr, iovs_len) } { - Ok(iovs) => iovs, - Err(e) => return enc_errno(e), - }; - - let ctx: &mut WasiCtx = vmctx.get_embed_ctx_mut(); - let fe = match ctx.get_fd_entry(fd, host::__WASI_RIGHT_FD_READ.into(), 0) { - Ok(fe) => fe, - Err(e) => return enc_errno(e), - }; - - let mut iovs: Vec> = iovs - .iter_mut() - .map(|iov| unsafe { host::ciovec_to_nix_mut(iov) }) - .collect(); - - let full_nread = iovs.iter().map(|iov| iov.as_slice().len()).sum(); - - let host_nread = match readv(fe.fd_object.rawfd, &mut iovs) { - Ok(len) => len, - Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), - }; - - if host_nread < full_nread { - // we hit eof, so remove the fdentry from the context - let mut fe = ctx.fds.remove(&fd).expect("file entry is still there"); - fe.fd_object.needs_close = false; - } - - unsafe { - enc_usize_byref(&mut vmctx, nread, host_nread) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } -} - -#[no_mangle] -pub extern "C" fn __wasi_fd_write( - vmctx: *mut lucet_vmctx, - fd: wasm32::__wasi_fd_t, - iovs_ptr: wasm32::uintptr_t, - iovs_len: wasm32::size_t, - nwritten: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - use nix::sys::uio::{writev, IoVec}; - - let mut vmctx = unsafe { Vmctx::from_raw(vmctx) }; - let fd = dec_fd(fd); - let iovs = match unsafe { dec_ciovec_slice(&mut vmctx, iovs_ptr, iovs_len) } { - Ok(iovs) => iovs, - Err(e) => return enc_errno(e), - }; - - let ctx: &mut WasiCtx = vmctx.get_embed_ctx_mut(); - let fe = match ctx.get_fd_entry(fd, host::__WASI_RIGHT_FD_WRITE.into(), 0) { - Ok(fe) => fe, - Err(e) => return enc_errno(e), - }; - - let iovs: Vec> = iovs - .iter() - .map(|iov| unsafe { host::ciovec_to_nix(iov) }) - .collect(); - - let host_nwritten = match writev(fe.fd_object.rawfd, &iovs) { - Ok(len) => len, - Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), - }; - - unsafe { - enc_usize_byref(&mut vmctx, nwritten, host_nwritten) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } -} - -#[no_mangle] -pub extern "C" fn __wasi_path_open( - vmctx: *mut lucet_vmctx, - dirfd: wasm32::__wasi_fd_t, - dirflags: wasm32::__wasi_lookupflags_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, - oflags: wasm32::__wasi_oflags_t, - fs_rights_base: wasm32::__wasi_rights_t, - fs_rights_inheriting: wasm32::__wasi_rights_t, - fs_flags: wasm32::__wasi_fdflags_t, - fd_out_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - use nix::errno::Errno; - use nix::fcntl::{openat, AtFlags, OFlag}; - use nix::sys::stat::{fstatat, Mode, SFlag}; - - let dirfd = dec_fd(dirfd); - let dirflags = dec_lookupflags(dirflags); - let oflags = dec_oflags(oflags); - let fs_rights_base = dec_rights(fs_rights_base); - let fs_rights_inheriting = dec_rights(fs_rights_inheriting); - let fs_flags = dec_fdflags(fs_flags); - - // which open mode do we need? - let read = fs_rights_base - & ((host::__WASI_RIGHT_FD_READ | host::__WASI_RIGHT_FD_READDIR) as host::__wasi_rights_t) - != 0; - let write = fs_rights_base - & ((host::__WASI_RIGHT_FD_DATASYNC - | host::__WASI_RIGHT_FD_WRITE - | host::__WASI_RIGHT_FD_ALLOCATE - | host::__WASI_RIGHT_PATH_FILESTAT_SET_SIZE) as host::__wasi_rights_t) - != 0; - - let mut nix_all_oflags = if read && write { - OFlag::O_RDWR - } else if read { - OFlag::O_RDONLY - } else { - OFlag::O_WRONLY - }; - - // on non-Capsicum systems, we always want nofollow - nix_all_oflags.insert(OFlag::O_NOFOLLOW); - - // which rights are needed on the dirfd? - let mut needed_base = host::__WASI_RIGHT_PATH_OPEN as host::__wasi_rights_t; - let mut needed_inheriting = fs_rights_base | fs_rights_inheriting; - - // convert open flags - let nix_oflags = host::nix_from_oflags(oflags); - nix_all_oflags.insert(nix_oflags); - if nix_all_oflags.contains(OFlag::O_CREAT) { - needed_base |= host::__WASI_RIGHT_PATH_CREATE_FILE as host::__wasi_rights_t; - } - if nix_all_oflags.contains(OFlag::O_TRUNC) { - needed_inheriting |= host::__WASI_RIGHT_PATH_FILESTAT_SET_SIZE as host::__wasi_rights_t; - } - - // convert file descriptor flags - nix_all_oflags.insert(host::nix_from_fdflags(fs_flags)); - if nix_all_oflags.contains(OFlag::O_DSYNC) { - needed_inheriting |= host::__WASI_RIGHT_FD_DATASYNC as host::__wasi_rights_t; - } - if nix_all_oflags.intersects(O_RSYNC | OFlag::O_SYNC) { - needed_inheriting |= host::__WASI_RIGHT_FD_SYNC as host::__wasi_rights_t; + } else { + continue; + }; + *output_slice_cur.next().unwrap() = enc_event(output_event); + revents_count += 1; } - - let mut vmctx = unsafe { Vmctx::from_raw(vmctx) }; - - let path = match unsafe { dec_slice_of::(&mut vmctx, path_ptr, path_len) } { - Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), - Err(e) => return enc_errno(e), - }; - - let (dir, path) = match path_get( - &vmctx, - dirfd, - dirflags, - path, - needed_base, - needed_inheriting, - nix_oflags.contains(OFlag::O_CREAT), - ) { - Ok((dir, path)) => (dir, path), - Err(e) => return enc_errno(e), - }; - - let new_fd = match openat( - dir, - path.as_os_str(), - nix_all_oflags, - Mode::from_bits_truncate(0o777), - ) { - Ok(fd) => fd, - Err(e) => { - match e.as_errno() { - // Linux returns ENXIO instead of EOPNOTSUPP when opening a socket - Some(Errno::ENXIO) => { - if let Ok(stat) = fstatat(dir, path.as_os_str(), AtFlags::AT_SYMLINK_NOFOLLOW) { - if SFlag::from_bits_truncate(stat.st_mode).contains(SFlag::S_IFSOCK) { - return wasm32::__WASI_ENOTSUP; - } else { - return wasm32::__WASI_ENXIO; - } - } else { - return wasm32::__WASI_ENXIO; - } - } - Some(e) => return wasm32::errno_from_nix(e), - None => return wasm32::__WASI_ENOSYS, - } - } - }; - - // Determine the type of the new file descriptor and which rights contradict with this type - let guest_fd = match unsafe { determine_type_rights(new_fd) } { - Err(e) => { - // if `close` fails, note it but do not override the underlying errno - nix::unistd::close(new_fd).unwrap_or_else(|e| { - dbg!(e); - }); - return enc_errno(e); - } - Ok((_ty, max_base, max_inheriting)) => { - let mut fe = unsafe { FdEntry::from_raw_fd(new_fd) }; - fe.rights_base &= max_base; - fe.rights_inheriting &= max_inheriting; - match vmctx.get_embed_ctx_mut::().insert_fd_entry(fe) { - Ok(fd) => fd, - Err(e) => return enc_errno(e), - } - } - }; - - unsafe { - enc_fd_byref(&mut vmctx, fd_out_ptr, guest_fd) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) + if let Err(e) = unsafe { enc_pointee(vmctx, nevents, revents_count) } { + return enc_errno(e); } + wasm32::__WASI_ESUCCESS } /// Normalizes a path to ensure that the target path is located under the directory provided. @@ -969,264 +1208,6 @@ pub fn path_get>( } } -#[no_mangle] -pub extern "C" fn __wasi_random_get( - vmctx: *mut lucet_vmctx, - buf_ptr: wasm32::uintptr_t, - buf_len: wasm32::size_t, -) -> wasm32::__wasi_errno_t { - use rand::{thread_rng, RngCore}; - - let mut vmctx = unsafe { Vmctx::from_raw(vmctx) }; - - let buf_len = dec_usize(buf_len); - let buf_ptr = match unsafe { dec_ptr(&mut vmctx, buf_ptr, buf_len) } { - Ok(ptr) => ptr, - Err(e) => return enc_errno(e), - }; - - let buf = unsafe { std::slice::from_raw_parts_mut(buf_ptr, buf_len) }; - - thread_rng().fill_bytes(buf); - - return wasm32::__WASI_ESUCCESS; -} - -// define the `fionread()` function, equivalent to `ioctl(fd, FIONREAD, *bytes)` -nix::ioctl_read_bad!(fionread, nix::libc::FIONREAD, c_int); - -fn wasi_clock_to_relative_ns_delay( - wasi_clock: host::__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, -) -> u128 { - if wasi_clock.flags != wasm32::__WASI_SUBSCRIPTION_CLOCK_ABSTIME { - return wasi_clock.timeout as u128; - } - let now: u128 = SystemTime::now() - .duration_since(SystemTime::UNIX_EPOCH) - .expect("Current date is before the epoch") - .as_nanos(); - let deadline = wasi_clock.timeout as u128; - deadline.saturating_sub(now) -} - -#[derive(Debug, Copy, Clone)] -struct ClockEventData { - delay: u128, - userdata: host::__wasi_userdata_t, -} -#[derive(Debug, Copy, Clone)] -struct FdEventData { - fd: c_int, - type_: host::__wasi_eventtype_t, - userdata: host::__wasi_userdata_t, -} - -fn __wasi_poll_oneoff_handle_timeout_event( - vmctx: &mut Vmctx, - output_slice: &mut [wasm32::__wasi_event_t], - nevents: wasm32::uintptr_t, - timeout: Option, -) -> wasm32::__wasi_errno_t { - if let Some(ClockEventData { userdata, .. }) = timeout { - let output_event = host::__wasi_event_t { - userdata, - type_: wasm32::__WASI_EVENTTYPE_CLOCK, - error: wasm32::__WASI_ESUCCESS, - u: host::__wasi_event_t___wasi_event_u { - fd_readwrite: host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { - nbytes: 0, - flags: 0, - }, - }, - }; - output_slice[0] = enc_event(output_event); - if let Err(e) = unsafe { enc_pointee(vmctx, nevents, 1) } { - return enc_errno(e); - } - } else { - // shouldn't happen - if let Err(e) = unsafe { enc_pointee(vmctx, nevents, 0) } { - return enc_errno(e); - } - } - wasm32::__WASI_ESUCCESS -} - -fn __wasi_poll_oneoff_handle_fd_event<'t>( - vmctx: &mut Vmctx, - output_slice: &mut [wasm32::__wasi_event_t], - nevents: wasm32::uintptr_t, - events: impl Iterator, -) -> wasm32::__wasi_errno_t { - let mut output_slice_cur = output_slice.iter_mut(); - let mut revents_count = 0; - for (fd_event, poll_fd) in events { - let revents = match poll_fd.revents() { - Some(revents) => revents, - None => continue, - }; - let mut nbytes = 0; - if fd_event.type_ == wasm32::__WASI_EVENTTYPE_FD_READ { - let _ = unsafe { fionread(fd_event.fd, &mut nbytes) }; - } - let output_event = if revents.contains(nix::poll::EventFlags::POLLNVAL) { - host::__wasi_event_t { - userdata: fd_event.userdata, - type_: fd_event.type_, - error: wasm32::__WASI_EBADF, - u: host::__wasi_event_t___wasi_event_u { - fd_readwrite: - host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { - nbytes: 0, - flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP, - }, - }, - } - } else if revents.contains(nix::poll::EventFlags::POLLERR) { - host::__wasi_event_t { - userdata: fd_event.userdata, - type_: fd_event.type_, - error: wasm32::__WASI_EIO, - u: host::__wasi_event_t___wasi_event_u { - fd_readwrite: - host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { - nbytes: 0, - flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP, - }, - }, - } - } else if revents.contains(nix::poll::EventFlags::POLLHUP) { - host::__wasi_event_t { - userdata: fd_event.userdata, - type_: fd_event.type_, - error: wasm32::__WASI_ESUCCESS, - u: host::__wasi_event_t___wasi_event_u { - fd_readwrite: - host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { - nbytes: 0, - flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP, - }, - }, - } - } else if revents.contains(nix::poll::EventFlags::POLLIN) - | revents.contains(nix::poll::EventFlags::POLLOUT) - { - host::__wasi_event_t { - userdata: fd_event.userdata, - type_: fd_event.type_, - error: wasm32::__WASI_ESUCCESS, - u: host::__wasi_event_t___wasi_event_u { - fd_readwrite: - host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { - nbytes: nbytes as host::__wasi_filesize_t, - flags: 0, - }, - }, - } - } else { - continue; - }; - *output_slice_cur.next().unwrap() = enc_event(output_event); - revents_count += 1; - } - if let Err(e) = unsafe { enc_pointee(vmctx, nevents, revents_count) } { - return enc_errno(e); - } - wasm32::__WASI_ESUCCESS -} - -#[no_mangle] -pub extern "C" fn __wasi_poll_oneoff( - vmctx: *mut lucet_vmctx, - input: wasm32::uintptr_t, - output: wasm32::uintptr_t, - nsubscriptions: wasm32::size_t, - nevents: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - if nsubscriptions as u64 > wasm32::__wasi_filesize_t::max_value() { - return wasm32::__WASI_EINVAL; - } - let mut vmctx = unsafe { Vmctx::from_raw(vmctx) }; - unsafe { enc_pointee(&mut vmctx, nevents, 0) }.unwrap(); - let input_slice_ = - unsafe { dec_slice_of::(&mut vmctx, input, nsubscriptions) } - .unwrap(); - let input_slice = unsafe { slice::from_raw_parts(input_slice_.0, input_slice_.1) }; - - let output_slice_ = - unsafe { dec_slice_of::(&mut vmctx, output, nsubscriptions) } - .unwrap(); - let output_slice = unsafe { slice::from_raw_parts_mut(output_slice_.0, output_slice_.1) }; - - let input: Vec<_> = input_slice.iter().map(|x| dec_subscription(x)).collect(); - - let timeout = input - .iter() - .filter_map(|event| match event { - Ok(event) if event.type_ == wasm32::__WASI_EVENTTYPE_CLOCK => Some(ClockEventData { - delay: wasi_clock_to_relative_ns_delay(unsafe { event.u.clock }) / 1_000_000, - userdata: event.userdata, - }), - _ => None, - }) - .min_by_key(|event| event.delay); - let fd_events: Vec<_> = input - .iter() - .filter_map(|event| match event { - Ok(event) - if event.type_ == wasm32::__WASI_EVENTTYPE_FD_READ - || event.type_ == wasm32::__WASI_EVENTTYPE_FD_WRITE => - { - Some(FdEventData { - fd: unsafe { event.u.fd_readwrite.fd } as c_int, - type_: event.type_, - userdata: event.userdata, - }) - } - _ => None, - }) - .collect(); - if fd_events.is_empty() && timeout.is_none() { - return wasm32::__WASI_ESUCCESS; - } - let mut poll_fds: Vec<_> = fd_events - .iter() - .map(|event| { - let mut flags = nix::poll::EventFlags::empty(); - match event.type_ { - wasm32::__WASI_EVENTTYPE_FD_READ => flags.insert(nix::poll::EventFlags::POLLIN), - wasm32::__WASI_EVENTTYPE_FD_WRITE => flags.insert(nix::poll::EventFlags::POLLOUT), - // An event on a file descriptor can currently only be of type FD_READ or FD_WRITE - // Nothing else has been defined in the specification, and these are also the only two - // events we filtered before. If we get something else here, the code has a serious bug. - _ => unreachable!(), - }; - nix::poll::PollFd::new(event.fd, flags) - }) - .collect(); - let timeout = timeout.map(|ClockEventData { delay, userdata }| ClockEventData { - delay: cmp::min(delay, c_int::max_value() as u128), - userdata, - }); - let poll_timeout = timeout.map(|timeout| timeout.delay as c_int).unwrap_or(-1); - let ready = loop { - match nix::poll::poll(&mut poll_fds, poll_timeout) { - Err(_) => { - if nix::errno::Errno::last() == nix::errno::Errno::EINTR { - continue; - } - return wasm32::errno_from_nix(nix::errno::Errno::last()); - } - Ok(ready) => break ready as usize, - } - }; - if ready == 0 { - return __wasi_poll_oneoff_handle_timeout_event(&mut vmctx, output_slice, nevents, timeout); - } - let events = fd_events.iter().zip(poll_fds.iter()).take(ready); - __wasi_poll_oneoff_handle_fd_event(&mut vmctx, output_slice, nevents, events) -} - #[doc(hidden)] pub fn ensure_linked() { unsafe { From 48f61c4046a156eda1bbf8530eaeed681bc60026 Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Tue, 16 Apr 2019 14:52:37 -0700 Subject: [PATCH 073/512] write a function manifest into lucetc artifacts this also adds Object as a representation of all information for a module, including function manifests, but is not yet used move trap information from lucet-runtime to module data have lucetc translate to lucet-module-data TrapCode and serialize those as well move function addresses out of TrapManifest and reference a FunctionSpec instead move trap information to CodeMetadata, and remove some more bit fiddling and unsafe serialization keep all the relocation-needing fields together on FunctionSpec describe the implicit relationship between FunctionSpec and write_function_manifest extract function manifest functions and clarify error modes if a module has no functions --- Cargo.lock | 6 + lucet-module-data/Cargo.toml | 2 + lucet-module-data/src/functions.rs | 62 ++++++++ lucet-module-data/src/lib.rs | 4 + lucet-module-data/src/module_data.rs | 2 +- lucet-module-data/src/traps.rs | 64 +++++++++ lucet-runtime/Cargo.toml | 2 +- .../lucet-runtime-internals/Cargo.toml | 1 + .../lucet-runtime-internals/src/c_api.rs | 2 +- .../lucet-runtime-internals/src/instance.rs | 2 +- .../src/instance/signals.rs | 2 +- .../lucet-runtime-internals/src/lib.rs | 1 - .../lucet-runtime-internals/src/module.rs | 72 ++-------- .../lucet-runtime-internals/src/module/dl.rs | 72 ++++++---- .../src/module/mock.rs | 20 ++- .../lucet-runtime-internals/src/trapcode.rs | 26 ---- lucet-runtime/lucet-runtime-tests/Cargo.toml | 1 + .../lucet-runtime-tests/src/guest_fault.rs | 38 ++--- lucet-runtime/lucet-runtime-tests/src/host.rs | 3 +- .../lucet-runtime-tests/src/stack.rs | 5 +- lucet-runtime/src/c_api.rs | 3 +- lucet-runtime/src/lib.rs | 4 +- lucet-spectest/Cargo.toml | 1 + lucet-spectest/src/lib.rs | 3 +- lucetc/Cargo.toml | 1 + lucetc/src/function_manifest.rs | 98 +++++++++++++ lucetc/src/lib.rs | 1 + lucetc/src/output.rs | 41 +++++- lucetc/src/stack_probe.rs | 2 +- lucetc/src/traps.rs | 132 +++++------------- 30 files changed, 418 insertions(+), 255 deletions(-) create mode 100644 lucet-module-data/src/functions.rs create mode 100644 lucet-module-data/src/traps.rs delete mode 100644 lucet-runtime/lucet-runtime-internals/src/trapcode.rs create mode 100644 lucetc/src/function_manifest.rs diff --git a/Cargo.lock b/Cargo.lock index 860848c33..86036818b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -621,6 +621,8 @@ version = "0.1.0" dependencies = [ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -644,6 +646,7 @@ dependencies = [ name = "lucet-runtime-internals" version = "0.1.0" dependencies = [ + "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", @@ -666,6 +669,7 @@ dependencies = [ "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lucet-module-data 0.1.0", "lucet-runtime-internals 0.1.0", "lucet-wasi-sdk 0.1.0", "lucetc 0.1.0", @@ -678,6 +682,7 @@ version = "0.1.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lucet-module-data 0.1.0", "lucet-runtime 0.1.0", "lucetc 0.1.0", "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", @@ -741,6 +746,7 @@ name = "lucetc" version = "0.1.0" dependencies = [ "bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-codegen 0.29.0", diff --git a/lucet-module-data/Cargo.toml b/lucet-module-data/Cargo.toml index dc8d813a1..297d7a6ed 100644 --- a/lucet-module-data/Cargo.toml +++ b/lucet-module-data/Cargo.toml @@ -9,3 +9,5 @@ edition = "2018" failure = "0.1" serde = { version = "1.0", features = ["derive"] } bincode = "~1.0.1" +num-derive = "0.2" +num-traits = "0.2" diff --git a/lucet-module-data/src/functions.rs b/lucet-module-data/src/functions.rs new file mode 100644 index 000000000..ddebb0751 --- /dev/null +++ b/lucet-module-data/src/functions.rs @@ -0,0 +1,62 @@ +use crate::traps::{TrapManifest, TrapSite}; + +use std::slice::from_raw_parts; + +// The layout of this struct is very tightly coupled to lucetc's `write_function_manifest`! +// +// Specifically, `write_function_manifest` sets up relocations on `code_addr` and `traps_addr`. +// It does not explicitly serialize a correctly formed `FunctionSpec`, because addresses +// for these fields do not exist until the object is loaded in the future. +// +// So `write_function_manifest` has implicit knowledge of the layout of this structure +// (including padding bytes between `code_len` and `traps_addr`) +#[repr(C)] +#[derive(Clone, Debug)] +pub struct FunctionSpec { + code_addr: u64, + code_len: u32, + traps_addr: u64, + traps_len: u64 +} + +impl FunctionSpec { + pub fn new(code_addr: u64, code_len: u32, traps_addr: u64, traps_len: u64) -> Self { + FunctionSpec { code_addr, code_len, traps_addr, traps_len } + } + pub fn code_len(&self) -> u32 { + self.code_len + } + pub fn traps_len(&self) -> u64 { + self.traps_len + } + pub fn contains(&self, addr: u64) -> bool { + // TODO This *may* be an off by one - replicating the check in + // looking up trap manifest addresses. Need to verify if the + // length produced by Cranelift is of an inclusive or exclusive range + addr >= self.code_addr && (addr - self.code_addr) <= (self.code_len as u64) + } + pub fn relative_addr(&self, addr: u64) -> Option { + if let Some(offset) = addr.checked_sub(self.code_addr) { + if offset < (self.code_len as u64) { + // self.code_len is u32, so if the above check succeeded + // offset must implicitly be <= u32::MAX - the following + // conversion will not truncate bits + return Some(offset as u32); + } + } + + None + } + pub fn traps(&self) -> Option { + let traps_ptr = self.traps_addr as *const TrapSite; + if !traps_ptr.is_null() { + let traps_slice = + unsafe { + from_raw_parts(traps_ptr, self.traps_len as usize) + }; + Some(TrapManifest::new(traps_slice)) + } else { + None + } + } +} diff --git a/lucet-module-data/src/lib.rs b/lucet-module-data/src/lib.rs index 949e7e6c1..deff08ddc 100644 --- a/lucet-module-data/src/lib.rs +++ b/lucet-module-data/src/lib.rs @@ -4,14 +4,18 @@ //! [`bincode`](https://github.com/TyOverby/bincode) format to the compiled Lucet modules. mod error; +mod functions; mod globals; mod linear_memory; mod module_data; +mod traps; pub use crate::error::Error; pub use crate::globals::{Global, GlobalDef, GlobalSpec}; pub use crate::linear_memory::{HeapSpec, SparseData, LinearMemorySpec}; pub use crate::module_data::ModuleData; +pub use crate::functions::FunctionSpec; +pub use crate::traps::{TrapManifest, TrapSite, TrapCode}; /// Owned variants of the module data types, useful for serialization and testing. pub mod owned { diff --git a/lucet-module-data/src/module_data.rs b/lucet-module-data/src/module_data.rs index 69cb9ce79..39b82bcaf 100644 --- a/lucet-module-data/src/module_data.rs +++ b/lucet-module-data/src/module_data.rs @@ -52,7 +52,7 @@ impl<'a> ModuleData<'a> { &self.globals_spec } - /// Serialize to (https://github.com/TyOverby/bincode). + /// Serialize to [`bincode`](https://github.com/TyOverby/bincode). pub fn serialize(&self) -> Result, Error> { bincode::serialize(self).map_err(Error::SerializationError) } diff --git a/lucet-module-data/src/traps.rs b/lucet-module-data/src/traps.rs new file mode 100644 index 000000000..63a4b5ca8 --- /dev/null +++ b/lucet-module-data/src/traps.rs @@ -0,0 +1,64 @@ +use num_derive::FromPrimitive; +use num_traits::FromPrimitive; + +/// The type of a WebAssembly +/// [trap](http://webassembly.github.io/spec/core/intro/overview.html#trap). +#[repr(u32)] +#[derive(Copy, Clone, Debug, FromPrimitive, PartialEq)] +pub enum TrapCode { + StackOverflow = 0, + HeapOutOfBounds = 1, + OutOfBounds = 2, + IndirectCallToNull = 3, + BadSignature = 4, + IntegerOverflow = 5, + IntegerDivByZero = 6, + BadConversionToInteger = 7, + Interrupt = 8, + TableOutOfBounds = 9, + Unreachable = 10, +} + +impl TrapCode { + pub fn try_from_u32(v: u32) -> Option { + Self::from_u32(v) + } +} + +/// Trap information for an address in a compiled function +/// +/// To support zero-copy deserialization of trap tables, this +/// must be repr(C) [to avoid cases where Rust may change the +/// layout in some future version, mangling the interpretation +/// of an old TrapSite struct] +#[repr(C)] +#[derive(Clone, Debug)] +pub struct TrapSite { + pub offset: u32, + pub code: TrapCode +} + +/// A collection of trap sites, typically obtained from a +/// single function (see [`FunctionSpec::traps`]) +#[repr(C)] +#[derive(Clone, Debug)] +pub struct TrapManifest<'a> { + pub traps: &'a [TrapSite] +} + +impl <'a> TrapManifest<'a> { + pub fn new(traps: &'a [TrapSite]) -> TrapManifest { + TrapManifest { traps } + } + pub fn lookup_addr(&self, addr: u32) -> Option { + // predicate to find the trapsite for the addr via binary search + let f = + |ts: &TrapSite| ts.offset.cmp(&addr); + + if let Ok(i) = self.traps.binary_search_by(f) { + Some(self.traps[i].code) + } else { + None + } + } +} diff --git a/lucet-runtime/Cargo.toml b/lucet-runtime/Cargo.toml index cd3baa7c2..272ac1200 100644 --- a/lucet-runtime/Cargo.toml +++ b/lucet-runtime/Cargo.toml @@ -10,6 +10,7 @@ edition = "2018" [dependencies] libc = "0.2.48" lucet-runtime-internals = { path = "lucet-runtime-internals" } +lucet-module-data = { path = "../lucet-module-data" } num-traits = "0.2" num-derive = "0.2" @@ -17,7 +18,6 @@ num-derive = "0.2" byteorder = "1.2" failure = "0.1" lazy_static = "1.1" -lucet-module-data = { path = "../lucet-module-data" } lucet-runtime-tests = { path = "lucet-runtime-tests" } nix = "0.13" diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index 8d0fa76d0..fc23c0592 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" lucet-module-data = { path = "../../lucet-module-data" } bitflags = "1.0" +bincode = "~1.0.1" failure = "0.1" lazy_static = "1.1" libc = "0.2.47" diff --git a/lucet-runtime/lucet-runtime-internals/src/c_api.rs b/lucet-runtime/lucet-runtime-internals/src/c_api.rs index 716ca8dfe..037f66141 100644 --- a/lucet-runtime/lucet-runtime-internals/src/c_api.rs +++ b/lucet-runtime/lucet-runtime-internals/src/c_api.rs @@ -199,8 +199,8 @@ pub mod lucet_state { use crate::instance::{State, TerminationDetails}; use crate::module::AddrDetails; use crate::sysdeps::UContext; - use crate::trapcode::TrapCode; use libc::{c_char, c_void}; + use lucet_module_data::TrapCode; use num_derive::FromPrimitive; use std::ffi::CString; use std::ptr; diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index b679ee17c..7f0ed8f09 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -10,10 +10,10 @@ use crate::error::Error; use crate::instance::siginfo_ext::SiginfoExt; use crate::module::{self, Global, Module}; use crate::sysdeps::UContext; -use crate::trapcode::TrapCode; use crate::val::{UntypedRetVal, Val}; use crate::WASM_PAGE_SIZE; use libc::{c_void, siginfo_t, uintptr_t, SIGBUS, SIGSEGV}; +use lucet_module_data::TrapCode; use memoffset::offset_of; use std::any::Any; use std::cell::{RefCell, UnsafeCell}; diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs index 98d540e40..c9f92b452 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs @@ -4,10 +4,10 @@ use crate::instance::{ HOST_CTX, }; use crate::sysdeps::UContextPtr; -use crate::trapcode::TrapCode; use failure::Error; use lazy_static::lazy_static; use libc::{c_int, c_void, siginfo_t, SIGBUS, SIGSEGV}; +use lucet_module_data::TrapCode; use nix::sys::signal::{ pthread_sigmask, raise, sigaction, SaFlags, SigAction, SigHandler, SigSet, SigmaskHow, Signal, }; diff --git a/lucet-runtime/lucet-runtime-internals/src/lib.rs b/lucet-runtime/lucet-runtime-internals/src/lib.rs index 40480ad58..821f916db 100644 --- a/lucet-runtime/lucet-runtime-internals/src/lib.rs +++ b/lucet-runtime/lucet-runtime-internals/src/lib.rs @@ -19,7 +19,6 @@ pub mod instance; pub mod module; pub mod region; pub mod sysdeps; -pub mod trapcode; pub mod val; pub mod vmctx; diff --git a/lucet-runtime/lucet-runtime-internals/src/module.rs b/lucet-runtime/lucet-runtime-internals/src/module.rs index 3d9251e25..7acf040e1 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module.rs @@ -5,62 +5,11 @@ mod sparse_page_data; pub use crate::module::dl::DlModule; pub use crate::module::mock::MockModuleBuilder; -pub use lucet_module_data::{Global, GlobalSpec, HeapSpec}; +pub use lucet_module_data::{FunctionSpec, Global, GlobalSpec, HeapSpec, TrapCode, TrapManifest}; use crate::alloc::Limits; use crate::error::Error; -use crate::trapcode::TrapCode; use libc::c_void; -use std::slice::from_raw_parts; - -#[repr(C)] -#[derive(Clone, Debug)] -pub struct TrapManifestRecord { - pub func_addr: u64, - pub func_len: u64, - pub table_addr: u64, - pub table_len: u64, -} - -impl TrapManifestRecord { - pub fn contains_addr(&self, addr: *const c_void) -> bool { - let addr = addr as u64; - // TODO: is this correct? off-by-one error? - addr >= self.func_addr && addr <= self.func_addr + self.func_len - } - - pub fn trapsites(&self) -> &[TrapSite] { - let table_addr = self.table_addr as *const TrapSite; - assert!(!table_addr.is_null()); - unsafe { from_raw_parts(table_addr, self.table_len as usize) } - } - - pub fn lookup_addr(&self, addr: *const c_void) -> Option { - if !self.contains_addr(addr) { - return None; - } - - // predicate to find the trapsite for the addr via binary search - let f = - |ts: &TrapSite| (self.func_addr as usize + ts.offset as usize).cmp(&(addr as usize)); - - let trapsites = self.trapsites(); - if let Ok(i) = trapsites.binary_search_by(f) { - let trapcode = - TrapCode::try_from_u32(trapsites[i].trapcode).expect("valid trapcode value"); - Some(trapcode) - } else { - None - } - } -} - -#[repr(C)] -#[derive(Copy, Clone, Debug)] -pub struct TrapSite { - pub offset: u32, - pub trapcode: u32, -} #[repr(C)] #[derive(Clone, Debug)] @@ -115,7 +64,7 @@ pub trait ModuleInternal: Send + Sync { fn get_start_func(&self) -> Result, Error>; - fn trap_manifest(&self) -> &[TrapManifestRecord]; + fn function_manifest(&self) -> &[FunctionSpec]; fn addr_details(&self, addr: *const c_void) -> Result, Error>; @@ -123,16 +72,13 @@ pub trait ModuleInternal: Send + Sync { /// /// This function must be signal-safe. fn lookup_trapcode(&self, rip: *const c_void) -> Option { - for record in self.trap_manifest() { - if record.contains_addr(rip) { - // the trap falls within a known function - if let Some(trapcode) = record.lookup_addr(rip) { - return Some(trapcode); - } else { - // stop looking through the rest of the trap manifests; only one function should - // ever match - break; - } + for fn_spec in self.function_manifest() { + if let Some(offset) = fn_spec.relative_addr(rip as u64) { + // the address falls in this trap manifest's function. + // `rip` can only lie in one function, so either + // there's a trap site in this manifest, and that's + // the one we want, or there's none + return fn_spec.traps().and_then(|traps| traps.lookup_addr(offset)); } } None diff --git a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs index 4ab668f41..9d3f4647b 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs @@ -1,10 +1,8 @@ use crate::error::Error; -use crate::module::{ - AddrDetails, GlobalSpec, HeapSpec, Module, ModuleInternal, TableElement, TrapManifestRecord, -}; +use crate::module::{AddrDetails, GlobalSpec, HeapSpec, Module, ModuleInternal, TableElement}; use libc::c_void; use libloading::{Library, Symbol}; -use lucet_module_data::ModuleData; +use lucet_module_data::{FunctionSpec, ModuleData}; use std::ffi::CStr; use std::mem; use std::path::Path; @@ -22,7 +20,7 @@ pub struct DlModule { /// Metadata decoded from inside the module module_data: ModuleData<'static>, - trap_manifest: &'static [TrapManifestRecord], + function_manifest: &'static [FunctionSpec], } // for the one raw pointer only @@ -71,23 +69,49 @@ impl DlModule { std::ptr::null() }; - let trap_manifest = unsafe { - if let Ok(len_ptr) = lib.get::<*const u32>(b"lucet_trap_manifest_len") { - let len = len_ptr.as_ref().ok_or(lucet_incorrect_module!( - "`lucet_trap_manifest_len` is defined but null" - ))?; - let records = lib - .get::<*const TrapManifestRecord>(b"lucet_trap_manifest") - .map_err(|e| { - lucet_incorrect_module!("error loading symbol `lucet_trap_manifest`: {}", e) - })? - .as_ref() - .ok_or(lucet_incorrect_module!( - "`lucet_trap_manifest` is defined but null" + let function_manifest = unsafe { + let manifest_len_ptr = lib.get::<*const u32>(b"lucet_function_manifest_len"); + let manifest_ptr = lib.get::<*const FunctionSpec>(b"lucet_function_manifest"); + + match (manifest_ptr, manifest_len_ptr) { + (Ok(ptr), Ok(len_ptr)) => { + let manifest_len = len_ptr.as_ref().ok_or(lucet_incorrect_module!( + "`lucet_function_manifest_len` is defined but null" ))?; - from_raw_parts(records, *len as usize) - } else { - &[] + let manifest = ptr.as_ref().ok_or(lucet_incorrect_module!( + "`lucet_function_manifest` is defined but null" + ))?; + + from_raw_parts(manifest, *manifest_len as usize) + } + (Err(ptr_err), Err(len_err)) => { + if is_undefined_symbol(&ptr_err) && is_undefined_symbol(&len_err) { + &[] + } else { + // This is an unfortunate situation. Both attempts to look up symbols + // failed, but at least one is not due to an undefined symbol. + if !is_undefined_symbol(&ptr_err) { + // This returns `ptr_err` (rather than `len_err` or some mix) because + // of the following hunch: if both failed, and neither are undefined + // symbols, they are probably the same error. + return Err(Error::DlError(ptr_err)); + } else { + return Err(Error::DlError(len_err)); + } + } + } + (Ok(_), Err(e)) => { + return Err(lucet_incorrect_module!( + "error loading symbol `lucet_function_manifest_len`: {}", + e + )); + } + (Err(e), Ok(_)) => { + return Err(lucet_incorrect_module!( + "error loading symbol `lucet_function_manifest`: {}", + e + )); + } } }; @@ -95,7 +119,7 @@ impl DlModule { lib, fbase, module_data, - trap_manifest, + function_manifest, })) } } @@ -186,8 +210,8 @@ impl ModuleInternal for DlModule { } } - fn trap_manifest(&self) -> &[TrapManifestRecord] { - self.trap_manifest + fn function_manifest(&self) -> &[FunctionSpec] { + self.function_manifest } fn addr_details(&self, addr: *const c_void) -> Result, Error> { diff --git a/lucet-runtime/lucet-runtime-internals/src/module/mock.rs b/lucet-runtime/lucet-runtime-internals/src/module/mock.rs index ed1034d77..b12f2ce02 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/mock.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/mock.rs @@ -1,12 +1,10 @@ use crate::error::Error; -use crate::module::{ - AddrDetails, GlobalSpec, HeapSpec, Module, ModuleInternal, TableElement, TrapManifestRecord, -}; +use crate::module::{AddrDetails, GlobalSpec, HeapSpec, Module, ModuleInternal, TableElement}; use libc::c_void; use lucet_module_data::owned::{ OwnedGlobalSpec, OwnedLinearMemorySpec, OwnedModuleData, OwnedSparseData, }; -use lucet_module_data::ModuleData; +use lucet_module_data::{FunctionSpec, ModuleData}; use std::collections::{BTreeMap, HashMap}; use std::sync::Arc; @@ -19,7 +17,7 @@ pub struct MockModuleBuilder { export_funcs: HashMap, *const extern "C" fn()>, func_table: HashMap<(u32, u32), *const extern "C" fn()>, start_func: Option, - trap_manifest: Vec, + function_manifest: Vec, } impl MockModuleBuilder { @@ -121,8 +119,8 @@ impl MockModuleBuilder { self } - pub fn with_trap_manifest(mut self, trap_manifest: &[TrapManifestRecord]) -> Self { - self.trap_manifest = trap_manifest.to_vec(); + pub fn with_function_manifest(mut self, function_manifest: &[FunctionSpec]) -> Self { + self.function_manifest = function_manifest.to_vec(); self } @@ -178,7 +176,7 @@ impl MockModuleBuilder { export_funcs: self.export_funcs, func_table: self.func_table, start_func: self.start_func, - trap_manifest: self.trap_manifest, + function_manifest: self.function_manifest, }; Arc::new(mock) } @@ -192,7 +190,7 @@ pub struct MockModule { pub export_funcs: HashMap, *const extern "C" fn()>, pub func_table: HashMap<(u32, u32), *const extern "C" fn()>, pub start_func: Option, - pub trap_manifest: Vec, + pub function_manifest: Vec, } unsafe impl Send for MockModule {} @@ -249,8 +247,8 @@ impl ModuleInternal for MockModule { Ok(self.start_func.map(|start| start as *const extern "C" fn())) } - fn trap_manifest(&self) -> &[TrapManifestRecord] { - &self.trap_manifest + fn function_manifest(&self) -> &[FunctionSpec] { + &self.function_manifest } fn addr_details(&self, _addr: *const c_void) -> Result, Error> { diff --git a/lucet-runtime/lucet-runtime-internals/src/trapcode.rs b/lucet-runtime/lucet-runtime-internals/src/trapcode.rs deleted file mode 100644 index 23cf5dd07..000000000 --- a/lucet-runtime/lucet-runtime-internals/src/trapcode.rs +++ /dev/null @@ -1,26 +0,0 @@ -use num_derive::FromPrimitive; -use num_traits::FromPrimitive; - -/// The type of a WebAssembly -/// [trap](http://webassembly.github.io/spec/core/intro/overview.html#trap). -#[repr(u32)] -#[derive(Copy, Clone, Debug, FromPrimitive, PartialEq)] -pub enum TrapCode { - StackOverflow = 0, - HeapOutOfBounds = 1, - OutOfBounds = 2, - IndirectCallToNull = 3, - BadSignature = 4, - IntegerOverflow = 5, - IntegerDivByZero = 6, - BadConversionToInteger = 7, - Interrupt = 8, - TableOutOfBounds = 9, - Unreachable = 10, -} - -impl TrapCode { - pub fn try_from_u32(v: u32) -> Option { - Self::from_u32(v) - } -} diff --git a/lucet-runtime/lucet-runtime-tests/Cargo.toml b/lucet-runtime/lucet-runtime-tests/Cargo.toml index ac72c9a07..a9806e7b0 100644 --- a/lucet-runtime/lucet-runtime-tests/Cargo.toml +++ b/lucet-runtime/lucet-runtime-tests/Cargo.toml @@ -13,6 +13,7 @@ test = false failure = "0.1" lazy_static = "1.1" tempfile = "3.0" +lucet-module-data = { path = "../../lucet-module-data" } lucet-runtime-internals = { path = "../lucet-runtime-internals" } lucet-wasi-sdk = { path = "../../lucet-wasi-sdk" } lucetc = { path = "../../lucetc" } diff --git a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs index 6e55084bc..708895d3c 100644 --- a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs +++ b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs @@ -1,5 +1,6 @@ use crate::helpers::MockModuleBuilder; -use lucet_runtime_internals::module::{Module, TrapManifestRecord, TrapSite}; +use lucet_module_data::{FunctionSpec, TrapCode, TrapSite}; +use lucet_runtime_internals::module::Module; use lucet_runtime_internals::vmctx::{lucet_vmctx, Vmctx}; use std::sync::Arc; @@ -70,27 +71,27 @@ pub fn mock_traps_module() -> Arc { static ILLEGAL_INSTR_TRAPS: &'static [TrapSite] = &[TrapSite { offset: 8, - trapcode: 4, /* BadSignature */ + code: TrapCode::BadSignature, }]; static OOB_TRAPS: &'static [TrapSite] = &[TrapSite { offset: 29, - trapcode: 1, /* HeapOutOfBounds */ + code: TrapCode::HeapOutOfBounds, }]; - let trap_manifest = &[ - TrapManifestRecord { - func_addr: guest_func_illegal_instr as *const extern "C" fn() as u64, - func_len: 11, - table_addr: ILLEGAL_INSTR_TRAPS.as_ptr() as u64, - table_len: 1, - }, - TrapManifestRecord { - func_addr: guest_func_oob as *const extern "C" fn() as u64, - func_len: 41, - table_addr: OOB_TRAPS.as_ptr() as u64, - table_len: 1, - }, + let function_manifest = &[ + FunctionSpec::new( + guest_func_illegal_instr as *const extern "C" fn() as u64, + 11, + ILLEGAL_INSTR_TRAPS.as_ptr() as u64, + ILLEGAL_INSTR_TRAPS.len() as u64, + ), + FunctionSpec::new( + guest_func_oob as *const extern "C" fn() as u64, + 41, + OOB_TRAPS.as_ptr() as u64, + OOB_TRAPS.len() as u64, + ), ]; MockModuleBuilder::new() @@ -107,7 +108,7 @@ pub fn mock_traps_module() -> Arc { b"recoverable_fatal", recoverable_fatal as *const extern "C" fn(), ) - .with_trap_manifest(trap_manifest) + .with_function_manifest(function_manifest) .build() } @@ -116,9 +117,10 @@ macro_rules! guest_fault_tests { ( $TestRegion:path ) => { use lazy_static::lazy_static; use libc::{c_void, siginfo_t, SIGSEGV}; + use lucet_module_data::TrapCode; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime::{ - DlModule, Error, FaultDetails, Instance, Limits, Region, SignalBehavior, TrapCode, + DlModule, Error, FaultDetails, Instance, Limits, Region, SignalBehavior, }; use nix::sys::mman::{mmap, MapFlags, ProtFlags}; use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal}; diff --git a/lucet-runtime/lucet-runtime-tests/src/host.rs b/lucet-runtime/lucet-runtime-tests/src/host.rs index 8f833b377..f46345133 100644 --- a/lucet-runtime/lucet-runtime-tests/src/host.rs +++ b/lucet-runtime/lucet-runtime-tests/src/host.rs @@ -2,8 +2,9 @@ macro_rules! host_tests { ( $TestRegion:path ) => { use libc::c_void; + use lucet_module_data::TrapCode; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; - use lucet_runtime::{DlModule, Error, Limits, Region, TrapCode}; + use lucet_runtime::{DlModule, Error, Limits, Region}; use std::sync::Arc; use $TestRegion as TestRegion; use $crate::build::test_module_c; diff --git a/lucet-runtime/lucet-runtime-tests/src/stack.rs b/lucet-runtime/lucet-runtime-tests/src/stack.rs index 3e448918a..791ab1713 100644 --- a/lucet-runtime/lucet-runtime-tests/src/stack.rs +++ b/lucet-runtime/lucet-runtime-tests/src/stack.rs @@ -83,9 +83,8 @@ fn generate_test_wat(num_locals: usize) -> String { #[macro_export] macro_rules! stack_tests { ( $TestRegion:path ) => { - use lucet_runtime::{ - DlModule, Error, InstanceHandle, Limits, Region, TrapCode, UntypedRetVal, Val, - }; + use lucet_module_data::TrapCode; + use lucet_runtime::{DlModule, Error, InstanceHandle, Limits, Region, UntypedRetVal, Val}; use std::sync::Arc; use $TestRegion as TestRegion; use $crate::stack::stack_testcase; diff --git a/lucet-runtime/src/c_api.rs b/lucet-runtime/src/c_api.rs index 17e943943..cd934ae8c 100644 --- a/lucet-runtime/src/c_api.rs +++ b/lucet-runtime/src/c_api.rs @@ -1,7 +1,8 @@ extern crate lucet_runtime_internals; -use crate::{DlModule, Instance, Limits, MmapRegion, Module, Region, TrapCode}; +use crate::{DlModule, Instance, Limits, MmapRegion, Module, Region}; use libc::{c_char, c_int, c_void}; +use lucet_module_data::TrapCode; use lucet_runtime_internals::c_api::*; use lucet_runtime_internals::instance::{ instance_handle_from_raw, instance_handle_to_raw, InstanceInternal, diff --git a/lucet-runtime/src/lib.rs b/lucet-runtime/src/lib.rs index 4ffb79505..9bedc2f2d 100644 --- a/lucet-runtime/src/lib.rs +++ b/lucet-runtime/src/lib.rs @@ -143,8 +143,9 @@ //! signal handler increments a counter of signals it has seen before setting the fault state: //! //! ```no_run +//! use lucet_module_data::TrapCode; //! use lucet_runtime::{ -//! DlModule, Error, Instance, Limits, MmapRegion, Region, SignalBehavior, TrapCode +//! DlModule, Error, Instance, Limits, MmapRegion, Region, SignalBehavior //! }; //! use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; //! @@ -205,7 +206,6 @@ pub use lucet_runtime_internals::instance::{ pub use lucet_runtime_internals::module::{DlModule, Module}; pub use lucet_runtime_internals::region::mmap::MmapRegion; pub use lucet_runtime_internals::region::{InstanceBuilder, Region, RegionCreate}; -pub use lucet_runtime_internals::trapcode::TrapCode; pub use lucet_runtime_internals::val::{UntypedRetVal, Val}; pub use lucet_runtime_internals::WASM_PAGE_SIZE; diff --git a/lucet-spectest/Cargo.toml b/lucet-spectest/Cargo.toml index c7c8f15c9..afd6a8fda 100644 --- a/lucet-spectest/Cargo.toml +++ b/lucet-spectest/Cargo.toml @@ -16,6 +16,7 @@ path = "src/main.rs" [dependencies] lucetc = { path = "../lucetc" } +lucet-module-data = { path = "../lucet-module-data" } lucet-runtime = { path = "../lucet-runtime" } wabt = "0.7" serde = "1.0" diff --git a/lucet-spectest/src/lib.rs b/lucet-spectest/src/lib.rs index f555349a9..e11c4e3ef 100644 --- a/lucet-spectest/src/lib.rs +++ b/lucet-spectest/src/lib.rs @@ -9,7 +9,8 @@ mod result; use crate::script::{ScriptEnv, ScriptError}; use failure::{format_err, Error, ResultExt}; -use lucet_runtime::{Error as RuntimeError, TrapCode, UntypedRetVal, Val}; +use lucet_module_data::TrapCode; +use lucet_runtime::{Error as RuntimeError, UntypedRetVal, Val}; use std::fs; use std::path::PathBuf; use wabt::script::{Action, CommandKind, ScriptParser, Value}; diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index c6f16a360..108e8543e 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -15,6 +15,7 @@ name = "lucetc" path = "src/main.rs" [dependencies] +bincode = "~1.0.1" cranelift-codegen = { path = "../cranelift/cranelift-codegen" } cranelift-native = { path = "../cranelift/cranelift-native" } cranelift-frontend = { path = "../cranelift/cranelift-frontend" } diff --git a/lucetc/src/function_manifest.rs b/lucetc/src/function_manifest.rs new file mode 100644 index 000000000..71471b2e8 --- /dev/null +++ b/lucetc/src/function_manifest.rs @@ -0,0 +1,98 @@ +use crate::traps::trap_sym_for_func; +use byteorder::{LittleEndian, WriteBytesExt}; +use faerie::{Artifact, Decl, Link}; +use failure::{Error, ResultExt}; +use lucet_module_data::FunctionSpec; +use std::io::Cursor; +use std::mem::size_of; + +fn write_relocated_slice( + obj: &mut Artifact, + buf: &mut Cursor>, + from: &str, + to: &str, + len: u64, +) -> Result<(), Error> { + obj.link(Link { + from, // the data at `from` + `at` (eg. manifest_sym) + to, // is a reference to `to` (eg. fn_name) + at: buf.position(), + }) + .context(format!("linking {} into function manifest", to))?; + + buf.write_u64::(0).unwrap(); + buf.write_u64::(len).unwrap(); + + Ok(()) +} + +/// +/// Writes a manifest of functions, with relocations, to the artifact. +/// +/// THIS IS NOT CURRENTLY A COMPLETE LIST OF FUNCTIONS. +/// +/// Currently the manifest returned here is the subset of functions +/// that happen to have traps. This manifest is only used, right now, +/// to look up trap manifest mappings, so this all lines up. +/// +/// The *order* of these functions are not (currently) guaranteed either! +/// Just that at the moment this order happens to be the same order as +/// `FaerieTrapManifest` lists. +/// +pub fn write_function_manifest( + functions: &[(&str, FunctionSpec)], + obj: &mut Artifact, +) -> Result<(), Error> { + let manifest_len_sym = "lucet_function_manifest_len"; + obj.declare(&manifest_len_sym, Decl::data().global()) + .context(format!("declaring {}", &manifest_len_sym))?; + + let manifest_sym = "lucet_function_manifest"; + obj.declare(&manifest_sym, Decl::data().global()) + .context(format!("declaring {}", &manifest_sym))?; + + let mut manifest_len_buf: Vec = Vec::new(); + manifest_len_buf + .write_u32::(functions.len() as u32) + .unwrap(); + obj.define(manifest_len_sym, manifest_len_buf) + .context(format!("defining {}", &manifest_len_sym))?; + + let mut manifest_buf: Cursor> = Cursor::new(Vec::with_capacity( + functions.len() * size_of::(), + )); + + for (fn_name, fn_spec) in functions.iter() { + /* + * This has implicit knowledge of the layout of `FunctionSpec`! + * + * Each iteraction writes out bytes with relocations that will + * result in data forming a valid FunctionSpec when this is loaded. + * + * Because the addresses don't exist until relocations are applied + * when the artifact is loaded, we can't just populate the fields + * and transmute, unfortunately. + */ + // Writes a (ptr, len) pair with relocation for code + write_relocated_slice( + obj, + &mut manifest_buf, + &manifest_sym, + fn_name, + fn_spec.code_len() as u64, + )?; + // Writes a (ptr, len) pair with relocation for this function's trap table + write_relocated_slice( + obj, + &mut manifest_buf, + &manifest_sym, + &trap_sym_for_func(fn_name), + fn_spec.traps_len() as u64, + )?; + } + + obj.define(&manifest_sym, manifest_buf.into_inner()) + .context(format!("defining {}", &manifest_sym))?; + + Ok(()) +} diff --git a/lucetc/src/lib.rs b/lucetc/src/lib.rs index 21ed7c59b..e00f2206f 100644 --- a/lucetc/src/lib.rs +++ b/lucetc/src/lib.rs @@ -3,6 +3,7 @@ mod compiler; mod decls; mod error; mod function; +mod function_manifest; mod heap; mod load; mod module; diff --git a/lucetc/src/output.rs b/lucetc/src/output.rs index 9ff984bc9..ecdaf5d6a 100644 --- a/lucetc/src/output.rs +++ b/lucetc/src/output.rs @@ -1,10 +1,12 @@ +use crate::function_manifest::write_function_manifest; use crate::name::Name; use crate::stack_probe; -use crate::traps::write_trap_manifest; +use crate::traps::write_trap_tables; use cranelift_codegen::{ir, isa}; use cranelift_faerie::FaerieProduct; use faerie::Artifact; use failure::{format_err, Error, ResultExt}; +use lucet_module_data::FunctionSpec; use std::collections::HashMap; use std::fs::File; use std::io::Write; @@ -43,7 +45,42 @@ impl ObjectFile { let trap_manifest = &product .trap_manifest .expect("trap manifest will be present"); - write_trap_manifest(trap_manifest, &mut product.artifact)?; + + // TODO: at this moment there is no way to get a full list of functions and sizes + // at this point in compilation. + // + // For now, we need the list of functions with traps, which we can get here. + let mut functions_and_names: Vec<(&str, FunctionSpec)> = vec![]; + + for sink in trap_manifest.sinks.iter() { + functions_and_names.push(( + &sink.name, + FunctionSpec::new(0, sink.code_size, 0, sink.sites.len() as u64), + )); + } + // + // stack_probe::declare_and_define adds a new function into `product`, but + // function_manifest was already constructed from all defined functions - + // so we have to add a new entry to `function_manifest` for the stack probe + functions_and_names.push(( + stack_probe::STACK_PROBE_SYM, + FunctionSpec::new( + 0, // there is no real address for the function until written to an object file + stack_probe::STACK_PROBE_BINARY.len() as u32, + 0, // there is no real address for its trap table until written, either + trap_manifest + .sinks + .iter() + .find(|sink| sink.name == stack_probe::STACK_PROBE_SYM) + .expect("Stack probe may trap and must have a trap manifest entry") + .sites + .len() as u64, + ), + )); + + write_trap_tables(trap_manifest, &mut product.artifact)?; + write_function_manifest(&functions_and_names[..], &mut product.artifact)?; + Ok(Self { artifact: product.artifact, }) diff --git a/lucetc/src/stack_probe.rs b/lucetc/src/stack_probe.rs index b7932fa8d..5f331cf78 100644 --- a/lucetc/src/stack_probe.rs +++ b/lucetc/src/stack_probe.rs @@ -19,7 +19,7 @@ use failure::Error; pub const STACK_PROBE_SYM: &'static str = "lucet_probestack"; /// The binary of the stack probe. -const STACK_PROBE_BINARY: &'static [u8] = &[ +pub const STACK_PROBE_BINARY: &'static [u8] = &[ // 49 89 c3 mov %rax,%r11 // 48 81 ec 00 10 00 00 sub $0x1000,%rsp // 48 85 64 24 08 test %rsp,0x8(%rsp) diff --git a/lucetc/src/traps.rs b/lucetc/src/traps.rs index f8c667a3d..3c60fbad0 100644 --- a/lucetc/src/traps.rs +++ b/lucetc/src/traps.rs @@ -1,104 +1,44 @@ use cranelift_codegen::ir; use cranelift_faerie::traps::FaerieTrapManifest; -use byteorder::{LittleEndian, WriteBytesExt}; -use faerie::{Artifact, Decl, Link}; +use faerie::{Artifact, Decl}; use failure::{Error, ResultExt}; -use std::io::Cursor; - -pub fn write_trap_manifest(manifest: &FaerieTrapManifest, obj: &mut Artifact) -> Result<(), Error> { - // declare traptable symbol - let manifest_len_sym = "lucet_trap_manifest_len"; - obj.declare(&manifest_len_sym, Decl::data().global()) - .context(format!("declaring {}", &manifest_len_sym))?; - - let manifest_sym = "lucet_trap_manifest"; - obj.declare(&manifest_sym, Decl::data().global()) - .context(format!("declaring {}", &manifest_sym))?; - - let manifest_len = manifest.sinks.len(); - let mut manifest_len_buf: Vec = Vec::new(); - manifest_len_buf - .write_u32::(manifest_len as u32) - .unwrap(); - obj.define(&manifest_len_sym, manifest_len_buf) - .context(format!("defining {}", &manifest_len_sym))?; - - // Manifests are serialized with the following struct elements in order: - // { func_start: ptr, func_len: u64, traps: ptr, traps_len: u64 } - let manifest_row_size = 8 * 4; - let mut manifest_buf: Cursor> = - Cursor::new(Vec::with_capacity(manifest_len * manifest_row_size)); +use lucet_module_data::TrapSite; +pub fn write_trap_tables(manifest: &FaerieTrapManifest, obj: &mut Artifact) -> Result<(), Error> { for sink in manifest.sinks.iter() { let func_sym = &sink.name; let trap_sym = trap_sym_for_func(func_sym); - // declare function-level trap table - obj.declare(&trap_sym, Decl::data().global()) + obj.declare(&trap_sym, Decl::data()) .context(format!("declaring {}", &trap_sym))?; - // function symbol is provided via a link (abs8 relocation) - obj.link(Link { - from: &manifest_sym, - to: func_sym, - at: manifest_buf.position(), - }) - .context("linking function sym into trap manifest")?; - manifest_buf.write_u64::(0).unwrap(); - - // write function length - manifest_buf - .write_u64::(sink.code_size as u64) - .unwrap(); - - // table for this function is provided via a link (abs8 relocation) - obj.link(Link { - from: &manifest_sym, - to: &trap_sym, - at: manifest_buf.position(), - }) - .context("linking trap table into trap manifest")?; - manifest_buf.write_u64::(0).unwrap(); - - // finally, write the length of the trap table - manifest_buf - .write_u64::(sink.sites.len() as u64) - .unwrap(); - - // ok, now write the actual function-level trap table - let mut traps: Vec = Vec::new(); - - for site in sink.sites.iter() { - // write offset into trap table - traps.write_u32::(site.offset as u32).unwrap(); - // write serialized trap code into trap table - traps - .write_u32::(serialize_trapcode(site.code)) - .unwrap(); - } - - // and finally write the function trap table into the object - obj.define(&trap_sym, traps) + // write the actual function-level trap table + let traps: Vec = sink + .sites + .iter() + .map(|site| TrapSite { + offset: site.offset, + code: translate_trapcode(site.code), + }) + .collect(); + + let trap_site_bytes = unsafe { + std::slice::from_raw_parts( + traps.as_ptr() as *const u8, + traps.len() * std::mem::size_of::(), + ) + }; + + // and write the function trap table into the object + obj.define(&trap_sym, trap_site_bytes.to_vec()) .context(format!("defining {}", &trap_sym))?; } - obj.define(&manifest_sym, manifest_buf.into_inner()) - .context(format!("defining {}", &manifest_sym))?; - - // iterate over tables: - // write empty relocation thunk - // link from traptable symbol + thunk offset to function symbol - // write trapsite count - // - // iterate over trapsites: - // write offset - // write trapcode - Ok(()) } -fn trap_sym_for_func(sym: &str) -> String { +pub(crate) fn trap_sym_for_func(sym: &str) -> String { return format!("lucet_trap_table_{}", sym); } @@ -109,19 +49,19 @@ fn trap_sym_for_func(sym: &str) -> String { // // Not all types have subtypes. Currently, only the user User type has a // subtype. -fn serialize_trapcode(code: ir::TrapCode) -> u32 { +fn translate_trapcode(code: ir::TrapCode) -> lucet_module_data::TrapCode { match code { - ir::TrapCode::StackOverflow => 0, - ir::TrapCode::HeapOutOfBounds => 1, - ir::TrapCode::OutOfBounds => 2, - ir::TrapCode::IndirectCallToNull => 3, - ir::TrapCode::BadSignature => 4, - ir::TrapCode::IntegerOverflow => 5, - ir::TrapCode::IntegerDivisionByZero => 6, - ir::TrapCode::BadConversionToInteger => 7, - ir::TrapCode::Interrupt => 8, - ir::TrapCode::TableOutOfBounds => 9, - ir::TrapCode::UnreachableCodeReached => 10 as u32, + ir::TrapCode::StackOverflow => lucet_module_data::TrapCode::StackOverflow, + ir::TrapCode::HeapOutOfBounds => lucet_module_data::TrapCode::HeapOutOfBounds, + ir::TrapCode::OutOfBounds => lucet_module_data::TrapCode::OutOfBounds, + ir::TrapCode::IndirectCallToNull => lucet_module_data::TrapCode::IndirectCallToNull, + ir::TrapCode::BadSignature => lucet_module_data::TrapCode::BadSignature, + ir::TrapCode::IntegerOverflow => lucet_module_data::TrapCode::IntegerOverflow, + ir::TrapCode::IntegerDivisionByZero => lucet_module_data::TrapCode::IntegerDivByZero, + ir::TrapCode::BadConversionToInteger => lucet_module_data::TrapCode::BadConversionToInteger, + ir::TrapCode::Interrupt => lucet_module_data::TrapCode::Interrupt, + ir::TrapCode::TableOutOfBounds => lucet_module_data::TrapCode::TableOutOfBounds, + ir::TrapCode::UnreachableCodeReached => lucet_module_data::TrapCode::Unreachable, ir::TrapCode::User(_) => panic!("we should never emit a user trapcode"), } } From 80f6fb94c0d1febc2292f23cf2e70210977f377e Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Thu, 25 Apr 2019 13:56:10 -0700 Subject: [PATCH 074/512] correct off by one in interpretation of function size --- lucet-module-data/src/functions.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lucet-module-data/src/functions.rs b/lucet-module-data/src/functions.rs index ddebb0751..c8b27aea5 100644 --- a/lucet-module-data/src/functions.rs +++ b/lucet-module-data/src/functions.rs @@ -30,10 +30,7 @@ impl FunctionSpec { self.traps_len } pub fn contains(&self, addr: u64) -> bool { - // TODO This *may* be an off by one - replicating the check in - // looking up trap manifest addresses. Need to verify if the - // length produced by Cranelift is of an inclusive or exclusive range - addr >= self.code_addr && (addr - self.code_addr) <= (self.code_len as u64) + addr >= self.code_addr && (addr - self.code_addr) < (self.code_len as u64) } pub fn relative_addr(&self, addr: u64) -> Option { if let Some(offset) = addr.checked_sub(self.code_addr) { From 694a8c8d3f65207900cf39b15a5dcd0f3149a2de Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 25 Apr 2019 23:28:56 +0200 Subject: [PATCH 075/512] Unfortunately, error strings are not very portable Here's another variant for an undefined symbol :( --- lucet-runtime/lucet-runtime-internals/src/module/dl.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs index 4ab668f41..ed349de22 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs @@ -216,7 +216,8 @@ impl ModuleInternal for DlModule { fn is_undefined_symbol(e: &std::io::Error) -> bool { // gross, but I'm not sure how else to differentiate this type of error from other // IO errors - format!("{}", e).contains("undefined symbol") + let msg = format!("{}", e); + msg.contains("undefined symbol") || msg.contains("symbol not found") } // TODO: PR to nix or libloading? From 11e7ab73c043170b798a48367bec0198c89b57cf Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 25 Apr 2019 19:22:08 +0200 Subject: [PATCH 076/512] Update to rust-1.34.1 --- Cargo.lock | 2 ++ Dockerfile | 8 ++++---- helpers/indent.sh | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 86036818b..a59350a30 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,3 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. [[package]] name = "aho-corasick" version = "0.7.3" diff --git a/Dockerfile b/Dockerfile index 9df79430e..14d9f31ea 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,12 +27,12 @@ RUN update-alternatives --install /usr/bin/clang clang /usr/bin/clang-6.0 100 # rebuilds. ENV LD_LIBRARY_PATH=/usr/local/lib -RUN curl -sS -L -O https://static.rust-lang.org/dist/rust-1.33.0-x86_64-unknown-linux-gnu.tar.gz \ - && tar xzf rust-1.33.0-x86_64-unknown-linux-gnu.tar.gz \ - && cd rust-1.33.0-x86_64-unknown-linux-gnu \ +RUN curl -sS -L -O https://static.rust-lang.org/dist/rust-1.34.1-x86_64-unknown-linux-gnu.tar.gz \ + && tar xzf rust-1.34.1-x86_64-unknown-linux-gnu.tar.gz \ + && cd rust-1.34.1-x86_64-unknown-linux-gnu \ && ./install.sh \ && cd .. \ - && rm -rf rust-1.33.0-x86_64-unknown-linux-gnu rust-1.33.0-x86_64-unknown-linux-gnu.tar.gz + && rm -rf rust-1.34.1-x86_64-unknown-linux-gnu rust-1.34.1-x86_64-unknown-linux-gnu.tar.gz ENV PATH=/usr/local/bin:$PATH RUN cargo install --root /usr/local cargo-audit cargo-watch diff --git a/helpers/indent.sh b/helpers/indent.sh index 642378999..b7c77c432 100755 --- a/helpers/indent.sh +++ b/helpers/indent.sh @@ -10,8 +10,8 @@ cleanup () { } trap cleanup 1 2 3 6 9 15 -if ! $(rustfmt --version | grep -q "rustfmt 1.0.1-stable"); then - echo "indent requires rustfmt 1.0.1-stable" +if ! $(rustfmt --version | grep -q "rustfmt 1.0.3-stable"); then + echo "indent requires rustfmt 1.0.3-stable" exit 1; fi From fd4f81ab5c21a6e9d2c029baa411a5656cb4eb62 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 26 Apr 2019 01:13:15 +0200 Subject: [PATCH 077/512] Resetting the heap did not zero it on non-Linux systems --- .../lucet-runtime-internals/src/region/mmap.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs index 7a39ba845..2deb87356 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs @@ -4,7 +4,7 @@ use crate::error::Error; use crate::instance::{new_instance_handle, Instance, InstanceHandle}; use crate::module::Module; use crate::region::{Region, RegionCreate, RegionInternal}; -use libc::{c_void, SIGSTKSZ}; +use libc::{c_void, memset, SIGSTKSZ}; use nix::sys::mman::{madvise, mmap, munmap, MapFlags, MmapAdvise, ProtFlags}; use std::ptr; use std::sync::{Arc, Mutex, Weak}; @@ -126,6 +126,17 @@ impl RegionInternal for MmapRegion { let heap_size = alloc.slot().limits.heap_address_space_size; unsafe { + // `mprotect()` and `madvise()` are sufficient to zero a page on Linux, + // but not necessarily on all POSIX operating systems, and on macOS in particular. + #[cfg(not(target_os = "linux"))] + { + mprotect( + heap, + alloc.heap_accessible_size, + ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, + )?; + memset(heap, 0, alloc.heap_accessible_size); + } mprotect(heap, heap_size, ProtFlags::PROT_NONE)?; madvise(heap, heap_size, MmapAdvise::MADV_DONTNEED)?; } From 2ae55a14b6f5f66f788a1adb8485d8367965e695 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Thu, 25 Apr 2019 17:59:26 -0700 Subject: [PATCH 078/512] [lucet-runtime] RefCell-based `Vmctx` interface This makes almost all of the `Vmctx` methods into `&self`, so hostcalls won't have to go through as many contortions when using multiple parts of the context. To report dynamic borrowing errors, there is a new `TerminationDetails` variant. --- .../lucet-runtime-internals/src/c_api.rs | 14 +- .../lucet-runtime-internals/src/embed_ctx.rs | 30 +++-- .../lucet-runtime-internals/src/instance.rs | 48 ++++--- .../lucet-runtime-internals/src/module.rs | 1 - .../src/module/globals.rs | 113 ---------------- .../lucet-runtime-internals/src/vmctx.rs | 114 +++++++++++----- .../lucet-runtime-tests/src/globals.rs | 111 +++++++++++++++- .../lucet-runtime-tests/src/guest_fault.rs | 66 +++++----- lucet-runtime/lucet-runtime-tests/src/host.rs | 122 +++++++++++++++++- lucet-runtime/src/c_api.rs | 4 +- lucet-runtime/src/lib.rs | 4 +- lucet-wasi/src/hostcalls.rs | 44 +++---- lucet-wasi/src/memory.rs | 32 ++--- 13 files changed, 441 insertions(+), 262 deletions(-) delete mode 100644 lucet-runtime/lucet-runtime-internals/src/module/globals.rs diff --git a/lucet-runtime/lucet-runtime-internals/src/c_api.rs b/lucet-runtime/lucet-runtime-internals/src/c_api.rs index 716ca8dfe..54d6c3050 100644 --- a/lucet-runtime/lucet-runtime-internals/src/c_api.rs +++ b/lucet-runtime/lucet-runtime-internals/src/c_api.rs @@ -55,7 +55,8 @@ macro_rules! with_ffi_arcs { /// Marker type for the `vmctx` pointer argument. /// -/// This type should only be used with [`Vmctx::from_raw()`](struct.Vmctx.html#method.from_raw). +/// This type should only be used with [`Vmctx::from_raw()`](struct.Vmctx.html#method.from_raw) or +/// the C API. #[repr(C)] pub struct lucet_vmctx { _unused: [u8; 0], @@ -243,8 +244,12 @@ pub mod lucet_state { reason: lucet_terminated_reason::Signal, provided: std::ptr::null_mut(), }, - TerminationDetails::GetEmbedCtx => lucet_terminated { - reason: lucet_terminated_reason::GetEmbedCtx, + TerminationDetails::CtxNotFound => lucet_terminated { + reason: lucet_terminated_reason::CtxNotFound, + provided: std::ptr::null_mut(), + }, + TerminationDetails::BorrowError(_) => lucet_terminated { + reason: lucet_terminated_reason::BorrowError, provided: std::ptr::null_mut(), }, TerminationDetails::Provided(p) => lucet_terminated { @@ -298,7 +303,8 @@ pub mod lucet_state { #[derive(Clone, Copy)] pub enum lucet_terminated_reason { Signal, - GetEmbedCtx, + CtxNotFound, + BorrowError, Provided, } diff --git a/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs b/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs index 7b9f98f0e..3affe2217 100644 --- a/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs @@ -1,4 +1,5 @@ use std::any::{Any, TypeId}; +use std::cell::{BorrowError, BorrowMutError, Ref, RefCell, RefMut}; use std::collections::HashMap; /// A map that holds at most one value of any type. @@ -6,7 +7,7 @@ use std::collections::HashMap; /// This is similar to the type provided by the `anymap` crate, but we can get away with simpler /// types on the methods due to our more specialized use case. pub struct CtxMap { - map: HashMap>, + map: HashMap>>, } impl CtxMap { @@ -18,25 +19,33 @@ impl CtxMap { self.map.contains_key(&TypeId::of::()) } - pub fn get(&self) -> Option<&T> { + pub fn try_get(&self) -> Option, BorrowError>> { self.map.get(&TypeId::of::()).map(|x| { - x.downcast_ref::() - .expect("value stored with TypeId::of:: is always type T") + x.try_borrow().map(|r| { + Ref::map(r, |b| { + b.downcast_ref::() + .expect("value stored with TypeId::of:: is always type T") + }) + }) }) } - pub fn get_mut(&mut self) -> Option<&mut T> { + pub fn try_get_mut(&mut self) -> Option, BorrowMutError>> { self.map.get_mut(&TypeId::of::()).map(|x| { - x.downcast_mut::() - .expect("value stored with TypeId::of:: is always type T") + x.try_borrow_mut().map(|r| { + RefMut::map(r, |b| { + b.downcast_mut::() + .expect("value stored with TypeId::of:: is always type T") + }) + }) }) } pub fn insert(&mut self, x: T) -> Option { self.map - .insert(TypeId::of::(), Box::new(x) as Box) + .insert(TypeId::of::(), RefCell::new(Box::new(x) as Box)) .map(|x_prev| { - *x_prev + *(x_prev.into_inner()) .downcast::() .expect("value stored with TypeId::of:: is always type T") }) @@ -50,7 +59,8 @@ impl CtxMap { pub fn remove(&mut self) -> Option { self.map.remove(&TypeId::of::()).map(|x| { - *x.downcast::() + *(x.into_inner()) + .downcast::() .expect("value stored with TypeId::of:: is always type T") }) } diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index b679ee17c..684278568 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -16,7 +16,7 @@ use crate::WASM_PAGE_SIZE; use libc::{c_void, siginfo_t, uintptr_t, SIGBUS, SIGSEGV}; use memoffset::offset_of; use std::any::Any; -use std::cell::{RefCell, UnsafeCell}; +use std::cell::{BorrowError, BorrowMutError, Ref, RefCell, RefMut, UnsafeCell}; use std::ffi::{CStr, CString}; use std::mem; use std::ops::{Deref, DerefMut}; @@ -387,13 +387,13 @@ impl Instance { } /// Get a reference to a context value of a particular type, if it exists. - pub fn get_embed_ctx(&self) -> Option<&T> { - self.embed_ctx.get::() + pub fn get_embed_ctx(&self) -> Option, BorrowError>> { + self.embed_ctx.try_get::() } /// Get a mutable reference to a context value of a particular type, if it exists. - pub fn get_embed_ctx_mut(&mut self) -> Option<&mut T> { - self.embed_ctx.get_mut::() + pub fn get_embed_ctx_mut(&mut self) -> Option, BorrowMutError>> { + self.embed_ctx.try_get_mut::() } /// Insert a context value. @@ -715,10 +715,13 @@ impl std::fmt::Display for FaultDetails { /// error has occurred in a hostcall, rather than in WebAssembly code. #[derive(Clone)] pub enum TerminationDetails { + /// Returned when a signal handler terminates the instance. Signal, - GetEmbedCtx, - /// Calls to `Vmctx::terminate()` may attach an arbitrary pointer for extra debugging - /// information. + /// Returned when `get_embed_ctx` or `get_embed_ctx_mut` are used with a type that is not present. + CtxNotFound, + /// Returned when dynamic borrowing rules of methods like `Vmctx::heap()` are violated. + BorrowError(&'static str), + /// Calls to `lucet_hostcall_terminate` provide a payload for use by the embedder. Provided(Arc), } @@ -747,17 +750,28 @@ fn termination_details_any_typing() { ); } +impl PartialEq for TerminationDetails { + fn eq(&self, rhs: &TerminationDetails) -> bool { + use TerminationDetails::*; + match (self, rhs) { + (Signal, Signal) => true, + (BorrowError(msg1), BorrowError(msg2)) => msg1 == msg2, + (CtxNotFound, CtxNotFound) => true, + // can't compare `Any` + _ => false, + } + } +} + impl std::fmt::Debug for TerminationDetails { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!( - f, - "TerminationDetails::{}", - match self { - TerminationDetails::Signal => "Signal", - TerminationDetails::GetEmbedCtx => "GetEmbedCtx", - TerminationDetails::Provided(_) => "Provided(Any)", - } - ) + write!(f, "TerminationDetails::")?; + match self { + TerminationDetails::Signal => write!(f, "Signal"), + TerminationDetails::BorrowError(msg) => write!(f, "BorrowError({})", msg), + TerminationDetails::CtxNotFound => write!(f, "CtxNotFound"), + TerminationDetails::Provided(_) => write!(f, "Provided(Any)"), + } } } diff --git a/lucet-runtime/lucet-runtime-internals/src/module.rs b/lucet-runtime/lucet-runtime-internals/src/module.rs index 3d9251e25..a99e76f34 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module.rs @@ -1,5 +1,4 @@ mod dl; -mod globals; mod mock; mod sparse_page_data; diff --git a/lucet-runtime/lucet-runtime-internals/src/module/globals.rs b/lucet-runtime/lucet-runtime-internals/src/module/globals.rs deleted file mode 100644 index 8616eb1bc..000000000 --- a/lucet-runtime/lucet-runtime-internals/src/module/globals.rs +++ /dev/null @@ -1,113 +0,0 @@ -#[macro_export] -macro_rules! globals_tests { - ( $TestRegion:path ) => { - use std::sync::Arc; - use $TestRegion as TestRegion; - use $crate::alloc::Limits; - use $crate::error::Error; - use $crate::module::{MockModuleBuilder, Module}; - use $crate::region::Region; - use $crate::vmctx::{lucet_vmctx, Vmctx}; - - fn mock_import_module() -> Arc { - MockModuleBuilder::new() - .with_import(0, "something", "else") - .build() - } - - #[test] - fn reject_import() { - let module = mock_import_module(); - let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); - match region.new_instance(module) { - Ok(_) => panic!("instance creation should not succeed"), - Err(Error::Unsupported(_)) => (), - Err(e) => panic!("unexpected error: {}", e), - } - } - - fn mock_globals_module() -> Arc { - extern "C" fn get_global0(vmctx: *mut lucet_vmctx) -> i64 { - unsafe { Vmctx::from_raw(vmctx) }.globals()[0] - } - - extern "C" fn set_global0(vmctx: *mut lucet_vmctx, val: i64) { - unsafe { Vmctx::from_raw(vmctx) }.globals_mut()[0] = val; - } - - extern "C" fn get_global1(vmctx: *mut lucet_vmctx) -> i64 { - unsafe { Vmctx::from_raw(vmctx) }.globals()[1] - } - - MockModuleBuilder::new() - .with_global(0, -1) - .with_global(1, 420) - .with_export_func(b"get_global0", get_global0 as *const extern "C" fn()) - .with_export_func(b"set_global0", set_global0 as *const extern "C" fn()) - .with_export_func(b"get_global1", get_global1 as *const extern "C" fn()) - .build() - } - - /* replace with use of instance public api to make sure defined globals are initialized - * correctly - */ - - #[test] - fn globals_initialized() { - let module = mock_globals_module(); - let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); - let inst = region - .new_instance(module) - .expect("instance can be created"); - assert_eq!(inst.globals()[0], -1); - assert_eq!(inst.globals()[1], 420); - } - - #[test] - fn get_global0() { - let module = mock_globals_module(); - let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); - let mut inst = region - .new_instance(module) - .expect("instance can be created"); - - let retval = inst.run(b"get_global0", &[]).expect("instance runs"); - assert_eq!(i64::from(retval), -1); - } - - #[test] - fn get_both_globals() { - let module = mock_globals_module(); - let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); - let mut inst = region - .new_instance(module) - .expect("instance can be created"); - - let retval = inst.run(b"get_global0", &[]).expect("instance runs"); - assert_eq!(i64::from(retval), -1); - - let retval = inst.run(b"get_global1", &[]).expect("instance runs"); - assert_eq!(i64::from(retval), 420); - } - - #[test] - fn mutate_global0() { - let module = mock_globals_module(); - let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); - let mut inst = region - .new_instance(module) - .expect("instance can be created"); - - inst.run(b"set_global0", &[666i64.into()]) - .expect("instance runs"); - - let retval = inst.run(b"get_global0", &[]).expect("instance runs"); - assert_eq!(i64::from(retval), 666); - } - }; -} - -#[cfg(test)] -mod tests { - globals_tests!(crate::region::mmap::MmapRegion); -} diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index b1c08f3a3..e3cde401c 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -13,11 +13,24 @@ use crate::instance::{ HOST_CTX, }; use std::any::Any; +use std::borrow::{Borrow, BorrowMut}; +use std::cell::{Ref, RefCell, RefMut}; /// An opaque handle to a running instance's context. #[derive(Debug)] pub struct Vmctx { vmctx: *mut lucet_vmctx, + heap: RefCell>, + globals: RefCell>, +} + +impl Drop for Vmctx { + fn drop(&mut self) { + let heap = self.heap.replace(Box::new([])); + let globals = self.globals.replace(Box::new([])); + Box::leak(heap); + Box::leak(globals); + } } pub trait VmctxInternal { @@ -48,11 +61,18 @@ impl VmctxInternal for Vmctx { impl Vmctx { /// Create a `Vmctx` from the compiler-inserted `vmctx` argument in a guest /// function. + /// + /// This is almost certainly not what you want to use to get a `Vmctx`; instead use the `&mut + /// Vmctx` argument to a `lucet_hostcalls!`-wrapped function. pub unsafe fn from_raw(vmctx: *mut lucet_vmctx) -> Vmctx { - let res = Vmctx { vmctx }; - // we don't actually need the instance for this call, but asking for it here causes an - // earlier failure if the pointer isn't valid - assert!(res.instance().valid_magic()); + let inst = instance_from_vmctx(vmctx); + assert!(inst.valid_magic()); + + let res = Vmctx { + vmctx, + heap: RefCell::new(Box::<[u8]>::from_raw(inst.heap_mut())), + globals: RefCell::new(Box::<[i64]>::from_raw(inst.globals_mut())), + }; res } @@ -62,13 +82,27 @@ impl Vmctx { } /// Return the WebAssembly heap as a slice of bytes. - pub fn heap(&self) -> &[u8] { - self.instance().heap() + /// + /// If the heap is already mutably borrowed by `heap_mut()`, the instance will + /// terminate with `TerminationDetails::BorrowError`. + pub fn heap(&self) -> Ref<[u8]> { + let r = self + .heap + .try_borrow() + .unwrap_or_else(|_| panic!(TerminationDetails::BorrowError("heap"))); + Ref::map(r, |b| b.borrow()) } /// Return the WebAssembly heap as a mutable slice of bytes. - pub fn heap_mut(&mut self) -> &mut [u8] { - unsafe { self.instance_mut().heap_mut() } + /// + /// If the heap is already borrowed by `heap()` or `heap_mut()`, the instance will terminate + /// with `TerminationDetails::BorrowError`. + pub fn heap_mut(&self) -> RefMut<[u8]> { + let r = self + .heap + .try_borrow_mut() + .unwrap_or_else(|_| panic!(TerminationDetails::BorrowError("heap_mut"))); + RefMut::map(r, |b| b.borrow_mut()) } /// Check whether a given range in the host address space overlaps with the memory that backs @@ -82,27 +116,33 @@ impl Vmctx { self.instance().contains_embed_ctx::() } - /// Get a reference to a context value of a particular type. If it does not exist, - /// the context will terminate. - pub fn get_embed_ctx(&self) -> &T { - match self.instance().embed_ctx.get::() { - Some(t) => t, - None => { - // this value will be caught by the wrapper in `lucet_hostcalls!` - panic!(TerminationDetails::GetEmbedCtx) - } + /// Get a reference to a context value of a particular type. + /// + /// If a context of that type does not exist, the instance will terminate with + /// `TerminationDetails::CtxNotFound`. + /// + /// If the context is already mutably borrowed by `get_embed_ctx_mut`, the instance will + /// terminate with `TerminationDetails::BorrowError`. + pub fn get_embed_ctx(&self) -> Ref { + match self.instance().embed_ctx.try_get::() { + Some(Ok(t)) => t, + Some(Err(_)) => panic!(TerminationDetails::BorrowError("get_embed_ctx")), + None => panic!(TerminationDetails::CtxNotFound), } } - /// Get a mutable reference to a context value of a particular type> If it does not exist, - /// the context will terminate. - pub fn get_embed_ctx_mut(&mut self) -> &mut T { - match unsafe { self.instance_mut().embed_ctx.get_mut::() } { - Some(t) => t, - None => { - // this value will be caught by the wrapper in `lucet_hostcalls!` - panic!(TerminationDetails::GetEmbedCtx) - } + /// Get a mutable reference to a context value of a particular type. + /// + /// If a context of that type does not exist, the instance will terminate with + /// `TerminationDetails::CtxNotFound`. + /// + /// If the context is already borrowed by some other use of `get_embed_ctx` or + /// `get_embed_ctx_mut`, the instance will terminate with `TerminationDetails::BorrowError`. + pub fn get_embed_ctx_mut(&self) -> RefMut { + match unsafe { self.instance_mut().embed_ctx.try_get_mut::() } { + Some(Ok(t)) => t, + Some(Err(_)) => panic!(TerminationDetails::BorrowError("get_embed_ctx_mut")), + None => panic!(TerminationDetails::CtxNotFound), } } @@ -123,13 +163,27 @@ impl Vmctx { } /// Return the WebAssembly globals as a slice of `i64`s. - pub fn globals(&self) -> &[i64] { - self.instance().globals() + /// + /// If the globals are already mutably borrowed by `globals_mut()`, the instance will terminate + /// with `TerminationDetails::BorrowError`. + pub fn globals(&self) -> Ref<[i64]> { + let r = self + .globals + .try_borrow() + .unwrap_or_else(|_| panic!(TerminationDetails::BorrowError("globals"))); + Ref::map(r, |b| b.borrow()) } /// Return the WebAssembly globals as a mutable slice of `i64`s. - pub fn globals_mut(&mut self) -> &mut [i64] { - unsafe { self.instance_mut().globals_mut() } + /// + /// If the globals are already borrowed by `globals()` or `globals_mut()`, the instance will + /// terminate with `TerminationDetails::BorrowError`. + pub fn globals_mut(&self) -> RefMut<[i64]> { + let r = self + .globals + .try_borrow_mut() + .unwrap_or_else(|_| panic!(TerminationDetails::BorrowError("globals_mut"))); + RefMut::map(r, |b| b.borrow_mut()) } /// Get a function pointer by WebAssembly table and function index. diff --git a/lucet-runtime/lucet-runtime-tests/src/globals.rs b/lucet-runtime/lucet-runtime-tests/src/globals.rs index c6da6d35b..74a7a1a54 100644 --- a/lucet-runtime/lucet-runtime-tests/src/globals.rs +++ b/lucet-runtime/lucet-runtime-tests/src/globals.rs @@ -2,11 +2,11 @@ macro_rules! globals_tests { ( $TestRegion:path ) => { use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; - use lucet_runtime::{Limits, Region}; - use lucet_runtime_internals::instance::InstanceInternal; + use lucet_runtime::{Error, Limits, Module, Region}; use std::sync::Arc; use $TestRegion as TestRegion; use $crate::build::test_module_wasm; + use $crate::helpers::MockModuleBuilder; #[test] fn defined_globals() { @@ -28,7 +28,7 @@ macro_rules! globals_tests { // [4] = 5 // [8] = 6 - let heap_u32 = unsafe { inst.alloc().heap_u32() }; + let heap_u32 = unsafe { inst.heap_u32() }; assert_eq!(heap_u32[0..=2], [4, 5, 6]); inst.run(b"main", &[]).expect("instance runs"); @@ -38,8 +38,111 @@ macro_rules! globals_tests { // [4] = 2 // [8] = 6 - let heap_u32 = unsafe { inst.alloc().heap_u32() }; + let heap_u32 = unsafe { inst.heap_u32() }; assert_eq!(heap_u32[0..=2], [3, 2, 6]); } + + fn mock_import_module() -> Arc { + MockModuleBuilder::new() + .with_import(0, "something", "else") + .build() + } + + #[test] + fn reject_import() { + let module = mock_import_module(); + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + match region.new_instance(module) { + Ok(_) => panic!("instance creation should not succeed"), + Err(Error::Unsupported(_)) => (), + Err(e) => panic!("unexpected error: {}", e), + } + } + + fn mock_globals_module() -> Arc { + extern "C" { + fn lucet_vmctx_get_globals(vmctx: *mut lucet_vmctx) -> *mut i64; + } + + unsafe extern "C" fn get_global0(vmctx: *mut lucet_vmctx) -> i64 { + let globals = std::slice::from_raw_parts(lucet_vmctx_get_globals(vmctx), 2); + globals[0] + } + + unsafe extern "C" fn set_global0(vmctx: *mut lucet_vmctx, val: i64) { + let globals = std::slice::from_raw_parts_mut(lucet_vmctx_get_globals(vmctx), 2); + globals[0] = val; + } + + unsafe extern "C" fn get_global1(vmctx: *mut lucet_vmctx) -> i64 { + let globals = std::slice::from_raw_parts(lucet_vmctx_get_globals(vmctx), 2); + globals[1] + } + + MockModuleBuilder::new() + .with_global(0, -1) + .with_global(1, 420) + .with_export_func(b"get_global0", get_global0 as *const extern "C" fn()) + .with_export_func(b"set_global0", set_global0 as *const extern "C" fn()) + .with_export_func(b"get_global1", get_global1 as *const extern "C" fn()) + .build() + } + + /* replace with use of instance public api to make sure defined globals are initialized + * correctly + */ + + #[test] + fn globals_initialized() { + let module = mock_globals_module(); + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let inst = region + .new_instance(module) + .expect("instance can be created"); + assert_eq!(inst.globals()[0], -1); + assert_eq!(inst.globals()[1], 420); + } + + #[test] + fn get_global0() { + let module = mock_globals_module(); + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + let retval = inst.run(b"get_global0", &[]).expect("instance runs"); + assert_eq!(i64::from(retval), -1); + } + + #[test] + fn get_both_globals() { + let module = mock_globals_module(); + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + let retval = inst.run(b"get_global0", &[]).expect("instance runs"); + assert_eq!(i64::from(retval), -1); + + let retval = inst.run(b"get_global1", &[]).expect("instance runs"); + assert_eq!(i64::from(retval), 420); + } + + #[test] + fn mutate_global0() { + let module = mock_globals_module(); + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + inst.run(b"set_global0", &[666i64.into()]) + .expect("instance runs"); + + let retval = inst.run(b"get_global0", &[]).expect("instance runs"); + assert_eq!(i64::from(retval), 666); + } }; } diff --git a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs index 3aacf3cfa..6f2667481 100644 --- a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs +++ b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs @@ -1,54 +1,52 @@ use crate::helpers::MockModuleBuilder; -use lucet_runtime_internals::lucet_hostcalls; use lucet_runtime_internals::module::{Module, TrapManifestRecord, TrapSite}; use lucet_runtime_internals::vmctx::lucet_vmctx; use std::sync::Arc; pub fn mock_traps_module() -> Arc { - lucet_hostcalls! { - pub unsafe extern "C" fn onetwothree( - &mut _vmctx, - ) -> std::os::raw::c_int { - 123 - } + extern "C" fn onetwothree(_vmctx: *mut lucet_vmctx) -> std::os::raw::c_int { + 123 + } - pub unsafe extern "C" fn hostcall_main( - &mut vmctx, - ) -> () { - extern "C" { - // actually is defined in this file - fn hostcall_test(vmctx: *mut lucet_vmctx); - } - hostcall_test(vmctx.as_raw()); + extern "C" fn hostcall_main(vmctx: *mut lucet_vmctx) -> () { + extern "C" { + // actually is defined in this file + fn hostcall_test(vmctx: *mut lucet_vmctx); + } + unsafe { + hostcall_test(vmctx); std::hint::unreachable_unchecked(); } + } - pub unsafe extern "C" fn infinite_loop( - &mut _vmctx, - ) -> () { - loop {} + extern "C" fn infinite_loop(_vmctx: *mut lucet_vmctx) -> () { + loop {} + } + + extern "C" fn fatal(vmctx: *mut lucet_vmctx) -> () { + extern "C" { + fn lucet_vmctx_get_heap(vmctx: *mut lucet_vmctx) -> *mut u8; } - pub unsafe extern "C" fn fatal( - &mut vmctx, - ) -> () { - let heap_base = vmctx.heap_mut().as_mut_ptr(); + unsafe { + let heap_base = lucet_vmctx_get_heap(vmctx); // Using the default limits, each instance as of this writing takes up 0x200026000 bytes - // worth of virtual address space. We want to access a point beyond all the instances, so - // that memory is unmapped. We assume no more than 16 instances are mapped - // concurrently. This may change as the library, test configuration, linker, phase of moon, - // etc change, but for now it works. + // worth of virtual address space. We want to access a point beyond all the instances, + // so that memory is unmapped. We assume no more than 16 instances are mapped + // concurrently. This may change as the library, test configuration, linker, phase of + // moon, etc change, but for now it works. *heap_base.offset(0x200026000 * 16) = 0; } + } - pub unsafe extern "C" fn recoverable_fatal( - &mut _vmctx, - ) -> () { - use std::os::raw::c_char; - extern "C" { - fn guest_recoverable_get_ptr() -> *mut c_char; - } + extern "C" fn recoverable_fatal(_vmctx: *mut lucet_vmctx) -> () { + use std::os::raw::c_char; + extern "C" { + fn guest_recoverable_get_ptr() -> *mut c_char; + } + + unsafe { *guest_recoverable_get_ptr() = '\0' as c_char; } } diff --git a/lucet-runtime/lucet-runtime-tests/src/host.rs b/lucet-runtime/lucet-runtime-tests/src/host.rs index e99c66ec3..e34a12aa6 100644 --- a/lucet-runtime/lucet-runtime-tests/src/host.rs +++ b/lucet-runtime/lucet-runtime-tests/src/host.rs @@ -5,11 +5,13 @@ macro_rules! host_tests { use libc::c_void; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime::{ - lucet_hostcall_terminate, lucet_hostcalls, DlModule, Error, Limits, Region, TrapCode, + lucet_hostcall_terminate, lucet_hostcalls, DlModule, Error, Limits, Region, + TerminationDetails, TrapCode, }; use std::sync::{Arc, Mutex}; use $TestRegion as TestRegion; use $crate::build::test_module_c; + use $crate::helpers::MockModuleBuilder; #[test] fn load_module() { let _module = test_module_c("host", "trivial.c").expect("build and load module"); @@ -63,6 +65,41 @@ macro_rules! host_tests { } drop(lock); } + + #[no_mangle] + pub unsafe extern "C" fn hostcall_bad_borrow( + &mut vmctx, + ) -> bool { + let heap = vmctx.heap(); + let mut other_heap = vmctx.heap_mut(); + heap[0] == other_heap[0] + } + + #[no_mangle] + pub unsafe extern "C" fn hostcall_missing_embed_ctx( + &mut vmctx, + ) -> bool { + struct S { + x: bool + } + let ctx = vmctx.get_embed_ctx::(); + ctx.x + } + + #[no_mangle] + pub unsafe extern "C" fn hostcall_multiple_vmctx( + &mut vmctx, + ) -> bool { + let mut vmctx1 = Vmctx::from_raw(vmctx.as_raw()); + vmctx1.heap_mut()[0] = 0xAF; + drop(vmctx1); + + let mut vmctx2 = Vmctx::from_raw(vmctx.as_raw()); + let res = vmctx2.heap()[0] == 0xAF; + drop(vmctx2); + + res + } } #[test] @@ -97,7 +134,7 @@ macro_rules! host_tests { inst.run(b"main", &[]).expect("instance runs"); - assert!(inst.get_embed_ctx::().unwrap()); + assert!(*inst.get_embed_ctx::().unwrap().unwrap()); } #[test] @@ -166,5 +203,86 @@ macro_rules! host_tests { } } } + + #[test] + fn run_hostcall_bad_borrow() { + extern "C" { + fn hostcall_bad_borrow(vmctx: *mut lucet_vmctx) -> bool; + } + + unsafe extern "C" fn f(vmctx: *mut lucet_vmctx) { + hostcall_bad_borrow(vmctx); + } + + let module = MockModuleBuilder::new() + .with_export_func(b"f", f as *const extern "C" fn()) + .build(); + + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + match inst.run(b"f", &[]) { + Err(Error::RuntimeTerminated(details)) => { + assert_eq!(details, TerminationDetails::BorrowError("heap_mut")); + } + res => { + panic!("unexpected result: {:?}", res); + } + } + } + + #[test] + fn run_hostcall_missing_embed_ctx() { + extern "C" { + fn hostcall_missing_embed_ctx(vmctx: *mut lucet_vmctx) -> bool; + } + + unsafe extern "C" fn f(vmctx: *mut lucet_vmctx) { + hostcall_missing_embed_ctx(vmctx); + } + + let module = MockModuleBuilder::new() + .with_export_func(b"f", f as *const extern "C" fn()) + .build(); + + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + match inst.run(b"f", &[]) { + Err(Error::RuntimeTerminated(details)) => { + assert_eq!(details, TerminationDetails::CtxNotFound); + } + res => { + panic!("unexpected result: {:?}", res); + } + } + } + + #[test] + fn run_hostcall_multiple_vmctx() { + extern "C" { + fn hostcall_multiple_vmctx(vmctx: *mut lucet_vmctx) -> bool; + } + + unsafe extern "C" fn f(vmctx: *mut lucet_vmctx) { + hostcall_multiple_vmctx(vmctx); + } + + let module = MockModuleBuilder::new() + .with_export_func(b"f", f as *const extern "C" fn()) + .build(); + + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + let retval = inst.run(b"f", &[]).expect("instance runs"); + assert_eq!(bool::from(retval), true); + } }; } diff --git a/lucet-runtime/src/c_api.rs b/lucet-runtime/src/c_api.rs index e4bd29c3f..51090bbdf 100644 --- a/lucet-runtime/src/c_api.rs +++ b/lucet-runtime/src/c_api.rs @@ -283,7 +283,7 @@ pub unsafe extern "C" fn lucet_instance_grow_heap( pub unsafe extern "C" fn lucet_instance_embed_ctx(inst: *mut lucet_instance) -> *mut c_void { with_instance_ptr_unchecked!(inst, { inst.get_embed_ctx::<*mut c_void>() - .map(|p| *p) + .map(|r| r.map(|p| *p).unwrap_or(ptr::null_mut())) .unwrap_or(ptr::null_mut()) }) } @@ -442,7 +442,7 @@ lucet_hostcalls! { ) -> *mut c_void { vmctx.instance() .get_embed_ctx::<*mut c_void>() - .map(|p| *p) + .map(|r| r.map(|p| *p).unwrap_or(ptr::null_mut())) .unwrap_or(std::ptr::null_mut()) } } diff --git a/lucet-runtime/src/lib.rs b/lucet-runtime/src/lib.rs index af85c489f..fdc22be94 100644 --- a/lucet-runtime/src/lib.rs +++ b/lucet-runtime/src/lib.rs @@ -82,7 +82,7 @@ //! pub unsafe extern "C" fn foo( //! &mut vmctx, //! ) -> () { -//! let hostcall_context = vmctx.get_embed_ctx_mut::(); +//! let mut hostcall_context = vmctx.get_embed_ctx_mut::(); //! hostcall_context.x = 42; //! } //! } @@ -97,7 +97,7 @@ //! //! inst.run(b"call_foo", &[]).unwrap(); //! -//! let context_after = inst.get_embed_ctx::().unwrap(); +//! let context_after = inst.get_embed_ctx::().unwrap().unwrap(); //! assert_eq!(context_after.x, 42); //! ``` //! diff --git a/lucet-wasi/src/hostcalls.rs b/lucet-wasi/src/hostcalls.rs index 9a6971f25..603c1364c 100644 --- a/lucet-wasi/src/hostcalls.rs +++ b/lucet-wasi/src/hostcalls.rs @@ -47,7 +47,7 @@ lucet_hostcalls! { argv_ptr: wasm32::uintptr_t, argv_buf: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - let ctx: &WasiCtx = vmctx.get_embed_ctx(); + let ctx = vmctx.get_embed_ctx::(); let mut argv_buf_offset = 0; let mut argv = vec![]; @@ -56,10 +56,7 @@ lucet_hostcalls! { let arg_bytes = arg.as_bytes_with_nul(); let arg_ptr = argv_buf + argv_buf_offset; - // nasty aliasing here, but we aren't interfering with the borrow for `ctx` - // TODO: rework vmctx interface to avoid this - let mut vmctx = unsafe { Vmctx::from_raw(vmctx.as_raw()) }; - if let Err(e) = unsafe { enc_slice_of(&mut vmctx, arg_bytes, arg_ptr) } { + if let Err(e) = unsafe { enc_slice_of(vmctx, arg_bytes, arg_ptr) } { return enc_errno(e); } @@ -88,7 +85,7 @@ lucet_hostcalls! { argc_ptr: wasm32::uintptr_t, argv_buf_size_ptr: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - let ctx: &WasiCtx = vmctx.get_embed_ctx(); + let ctx = vmctx.get_embed_ctx::(); let argc = ctx.args.len(); let argv_size = ctx @@ -195,7 +192,7 @@ lucet_hostcalls! { environ_ptr: wasm32::uintptr_t, environ_buf: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - let ctx: &WasiCtx = vmctx.get_embed_ctx(); + let ctx = vmctx.get_embed_ctx::(); let mut environ_buf_offset = 0; let mut environ = vec![]; @@ -204,10 +201,7 @@ lucet_hostcalls! { let env_bytes = pair.as_bytes_with_nul(); let env_ptr = environ_buf + environ_buf_offset; - // nasty aliasing here, but we aren't interfering with the borrow for `ctx` - // TODO: rework vmctx interface to avoid this - let mut vmctx = unsafe { Vmctx::from_raw(vmctx.as_raw()) }; - if let Err(e) = unsafe { enc_slice_of(&mut vmctx, env_bytes, env_ptr) } { + if let Err(e) = unsafe { enc_slice_of(vmctx, env_bytes, env_ptr) } { return enc_errno(e); } @@ -236,7 +230,7 @@ lucet_hostcalls! { environ_count_ptr: wasm32::uintptr_t, environ_size_ptr: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - let ctx: &WasiCtx = vmctx.get_embed_ctx(); + let ctx = vmctx.get_embed_ctx::(); let environ_count = ctx.env.len(); if let Some(environ_size) = ctx.env.iter().try_fold(0, |acc: u32, pair| { @@ -261,7 +255,7 @@ lucet_hostcalls! { &mut vmctx, fd: wasm32::__wasi_fd_t, ) -> wasm32::__wasi_errno_t { - let ctx: &mut WasiCtx = vmctx.get_embed_ctx_mut(); + let mut ctx = vmctx.get_embed_ctx_mut::(); let fd = dec_fd(fd); if let Some(fdent) = ctx.fds.get(&fd) { // can't close preopened files @@ -292,7 +286,7 @@ lucet_hostcalls! { Err(e) => return enc_errno(e), }; - let ctx: &mut WasiCtx = vmctx.get_embed_ctx_mut(); + let ctx = vmctx.get_embed_ctx_mut::(); let errno = if let Some(fe) = ctx.fds.get(&host_fd) { host_fdstat.fs_filetype = fe.fd_object.ty; host_fdstat.fs_rights_base = fe.rights_base; @@ -327,7 +321,7 @@ lucet_hostcalls! { let host_fdflags = dec_fdflags(fdflags); let nix_flags = host::nix_from_fdflags(host_fdflags); - let ctx: &mut WasiCtx = vmctx.get_embed_ctx_mut(); + let ctx = vmctx.get_embed_ctx_mut::(); if let Some(fe) = ctx.fds.get(&host_fd) { match nix::fcntl::fcntl(fe.fd_object.rawfd, nix::fcntl::F_SETFL(nix_flags)) { @@ -347,7 +341,7 @@ lucet_hostcalls! { whence: wasm32::__wasi_whence_t, newoffset: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - let ctx: &mut WasiCtx = vmctx.get_embed_ctx_mut(); + let ctx = vmctx.get_embed_ctx_mut::(); let fd = dec_fd(fd); let offset = dec_filedelta(offset); let whence = dec_whence(whence); @@ -388,7 +382,7 @@ lucet_hostcalls! { fd: wasm32::__wasi_fd_t, prestat_ptr: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - let ctx: &WasiCtx = vmctx.get_embed_ctx(); + let ctx = vmctx.get_embed_ctx::(); let fd = dec_fd(fd); // TODO: is this the correct right for this? match ctx.get_fd_entry(fd, host::__WASI_RIGHT_PATH_OPEN.into(), 0) { @@ -397,11 +391,9 @@ lucet_hostcalls! { if fe.fd_object.ty != host::__WASI_FILETYPE_DIRECTORY as host::__wasi_filetype_t { return wasm32::__WASI_ENOTDIR; } - // nasty aliasing here, but we aren't interfering with the borrow for `ctx` - // TODO: rework vmctx interface to avoid this unsafe { enc_prestat_byref( - &mut Vmctx::from_raw(vmctx.as_raw()), + vmctx, prestat_ptr, host::__wasi_prestat_t { pr_type: host::__WASI_PREOPENTYPE_DIR as host::__wasi_preopentype_t, @@ -431,7 +423,7 @@ lucet_hostcalls! { path_ptr: wasm32::uintptr_t, path_len: wasm32::size_t, ) -> wasm32::__wasi_errno_t { - let ctx: &WasiCtx = vmctx.get_embed_ctx(); + let ctx = vmctx.get_embed_ctx::(); let fd = dec_fd(fd); match ctx.get_fd_entry(fd, host::__WASI_RIGHT_PATH_OPEN.into(), 0) { Ok(fe) => { @@ -443,10 +435,8 @@ lucet_hostcalls! { if path_bytes.len() > dec_usize(path_len) { return wasm32::__WASI_ENAMETOOLONG; } - // nasty aliasing here, but we aren't interfering with the borrow for `ctx` - // TODO: rework vmctx interface to avoid this unsafe { - enc_slice_of(&mut Vmctx::from_raw(vmctx.as_raw()), path_bytes, path_ptr) + enc_slice_of(vmctx, path_bytes, path_ptr) .map(|_| wasm32::__WASI_ESUCCESS) .unwrap_or_else(|e| e) } @@ -474,7 +464,7 @@ lucet_hostcalls! { Err(e) => return enc_errno(e), }; - let ctx: &mut WasiCtx = vmctx.get_embed_ctx_mut(); + let mut ctx = vmctx.get_embed_ctx_mut::(); let fe = match ctx.get_fd_entry(fd, host::__WASI_RIGHT_FD_READ.into(), 0) { Ok(fe) => fe, Err(e) => return enc_errno(e), @@ -521,7 +511,7 @@ lucet_hostcalls! { Err(e) => return enc_errno(e), }; - let ctx: &mut WasiCtx = vmctx.get_embed_ctx_mut(); + let ctx = vmctx.get_embed_ctx_mut::(); let fe = match ctx.get_fd_entry(fd, host::__WASI_RIGHT_FD_WRITE.into(), 0) { Ok(fe) => fe, Err(e) => return enc_errno(e), @@ -989,7 +979,7 @@ pub fn path_get>( Err(errno) } - let ctx: &WasiCtx = vmctx.get_embed_ctx(); + let ctx = vmctx.get_embed_ctx::(); let dirfe = ctx.get_fd_entry(dirfd, needed_base, needed_inheriting)?; diff --git a/lucet-wasi/src/memory.rs b/lucet-wasi/src/memory.rs index 89cf9cfed..eb1da092f 100644 --- a/lucet-wasi/src/memory.rs +++ b/lucet-wasi/src/memory.rs @@ -23,11 +23,11 @@ macro_rules! bail_errno { } pub unsafe fn dec_ptr( - vmctx: &mut Vmctx, + vmctx: &Vmctx, ptr: wasm32::uintptr_t, len: usize, ) -> Result<*mut u8, host::__wasi_errno_t> { - let heap = vmctx.heap_mut(); + let mut heap = vmctx.heap_mut(); // check that `len` fits in the wasm32 address space if len > wasm32::UINTPTR_MAX as usize { @@ -44,7 +44,7 @@ pub unsafe fn dec_ptr( } pub unsafe fn dec_ptr_to( - vmctx: &mut Vmctx, + vmctx: &Vmctx, ptr: wasm32::uintptr_t, ) -> Result<*mut T, host::__wasi_errno_t> { // check that the ptr is aligned @@ -55,14 +55,14 @@ pub unsafe fn dec_ptr_to( } pub unsafe fn dec_pointee( - vmctx: &mut Vmctx, + vmctx: &Vmctx, ptr: wasm32::uintptr_t, ) -> Result { dec_ptr_to::(vmctx, ptr).map(|p| p.read()) } pub unsafe fn enc_pointee( - vmctx: &mut Vmctx, + vmctx: &Vmctx, ptr: wasm32::uintptr_t, t: T, ) -> Result<(), host::__wasi_errno_t> { @@ -70,7 +70,7 @@ pub unsafe fn enc_pointee( } pub unsafe fn dec_slice_of( - vmctx: &mut Vmctx, + vmctx: &Vmctx, ptr: wasm32::uintptr_t, len: wasm32::size_t, ) -> Result<(*mut T, usize), host::__wasi_errno_t> { @@ -91,7 +91,7 @@ pub unsafe fn dec_slice_of( } pub unsafe fn enc_slice_of( - vmctx: &mut Vmctx, + vmctx: &Vmctx, slice: &[T], ptr: wasm32::uintptr_t, ) -> Result<(), host::__wasi_errno_t> { @@ -120,7 +120,7 @@ macro_rules! dec_enc_scalar { } pub unsafe fn $dec_byref( - vmctx: &mut Vmctx, + vmctx: &Vmctx, ptr: wasm32::uintptr_t, ) -> Result { dec_pointee::(vmctx, ptr).map($dec) @@ -131,7 +131,7 @@ macro_rules! dec_enc_scalar { } pub unsafe fn $enc_byref( - vmctx: &mut Vmctx, + vmctx: &Vmctx, ptr: wasm32::uintptr_t, x: host::$ty, ) -> Result<(), host::__wasi_errno_t> { @@ -141,7 +141,7 @@ macro_rules! dec_enc_scalar { } pub unsafe fn dec_ciovec( - vmctx: &mut Vmctx, + vmctx: &Vmctx, ciovec: &wasm32::__wasi_ciovec_t, ) -> Result { let len = dec_usize(ciovec.buf_len); @@ -152,7 +152,7 @@ pub unsafe fn dec_ciovec( } pub unsafe fn dec_ciovec_slice( - vmctx: &mut Vmctx, + vmctx: &Vmctx, ptr: wasm32::uintptr_t, len: wasm32::size_t, ) -> Result, host::__wasi_errno_t> { @@ -201,7 +201,7 @@ pub fn dec_fdstat(fdstat: wasm32::__wasi_fdstat_t) -> host::__wasi_fdstat_t { } pub unsafe fn dec_fdstat_byref( - vmctx: &mut Vmctx, + vmctx: &Vmctx, fdstat_ptr: wasm32::uintptr_t, ) -> Result { dec_pointee::(vmctx, fdstat_ptr).map(dec_fdstat) @@ -218,7 +218,7 @@ pub fn enc_fdstat(fdstat: host::__wasi_fdstat_t) -> wasm32::__wasi_fdstat_t { } pub unsafe fn enc_fdstat_byref( - vmctx: &mut Vmctx, + vmctx: &Vmctx, fdstat_ptr: wasm32::uintptr_t, host_fdstat: host::__wasi_fdstat_t, ) -> Result<(), host::__wasi_errno_t> { @@ -285,7 +285,7 @@ pub fn dec_prestat( } pub unsafe fn dec_prestat_byref( - vmctx: &mut Vmctx, + vmctx: &Vmctx, prestat_ptr: wasm32::uintptr_t, ) -> Result { dec_pointee::(vmctx, prestat_ptr).and_then(dec_prestat) @@ -311,7 +311,7 @@ pub fn enc_prestat( } pub unsafe fn enc_prestat_byref( - vmctx: &mut Vmctx, + vmctx: &Vmctx, prestat_ptr: wasm32::uintptr_t, host_prestat: host::__wasi_prestat_t, ) -> Result<(), host::__wasi_errno_t> { @@ -343,7 +343,7 @@ pub fn enc_usize(size: usize) -> wasm32::size_t { } pub unsafe fn enc_usize_byref( - vmctx: &mut Vmctx, + vmctx: &Vmctx, usize_ptr: wasm32::uintptr_t, host_usize: usize, ) -> Result<(), host::__wasi_errno_t> { From d024c5bdc4a839a653b69b0513a84fe2e116340e Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 25 Apr 2019 03:33:35 +0200 Subject: [PATCH 079/512] Improve sigaltstack(2) usage in lucet-runtime Make the `sigaltstack(2)` wrapper more Rustic, and compatible with macOS, where providing the stack size is required, even with `SS_DISABLE`. --- .../src/instance/signals.rs | 62 ++++++++++++++++--- 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs index c9f92b452..10eb5fba9 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs @@ -59,9 +59,16 @@ impl Instance { SigStackFlags::empty(), libc::SIGSTKSZ, ); - let saved_sigstack = - unsafe { sigaltstack(&guest_sigstack).expect("saving sigaltstack succeeds") }; - + let previous_sigstack = unsafe { sigaltstack(Some(guest_sigstack)) } + .expect("enabling or changing the signal stack succeeds"); + if let Some(previous_sigstack) = previous_sigstack { + assert!( + !previous_sigstack + .flags() + .contains(SigStackFlags::SS_ONSTACK), + "an instance was created with a signal stack" + ); + } let mut ostate = LUCET_SIGNAL_STATE.lock().unwrap(); if let Some(ref mut state) = *ostate { state.counter += 1; @@ -81,7 +88,12 @@ impl Instance { if state.counter == 0 { unsafe { // restore the host signal stack - sigaltstack(&saved_sigstack).expect("sigaltstack restoration succeeds"); + if !altstack_flags() + .expect("the current stack flags could be retrieved") + .contains(SigStackFlags::SS_ONSTACK) + { + sigaltstack(previous_sigstack).expect("sigaltstack restoration succeeds"); + } restore_host_signal_state(state); } true @@ -333,6 +345,14 @@ impl SigStack { SigStack { stack } } + pub fn disabled() -> SigStack { + let mut stack = unsafe { std::mem::uninitialized::() }; + stack.ss_sp = std::ptr::null_mut(); + stack.ss_flags = SigStackFlags::SS_DISABLE.bits(); + stack.ss_size = libc::SIGSTKSZ; + SigStack { stack } + } + pub fn flags(&self) -> SigStackFlags { SigStackFlags::from_bits_truncate(self.stack.ss_flags) } @@ -357,13 +377,35 @@ bitflags! { } } -pub unsafe fn sigaltstack(ss: &SigStack) -> nix::Result { - let mut oldstack = std::mem::uninitialized::(); - +pub unsafe fn sigaltstack(new_sigstack: Option) -> nix::Result> { + let mut previous_stack = std::mem::uninitialized::(); + let disabled_sigstack = SigStack::disabled(); + let new_stack = match new_sigstack { + None => &disabled_sigstack.stack, + Some(ref new_stack) => &new_stack.stack, + }; let res = libc::sigaltstack( - &ss.stack as *const libc::stack_t, - &mut oldstack as *mut libc::stack_t, + new_stack as *const libc::stack_t, + &mut previous_stack as *mut libc::stack_t, ); + nix::errno::Errno::result(res).map(|_| { + let sigstack = SigStack { + stack: previous_stack, + }; + if sigstack.flags().contains(SigStackFlags::SS_DISABLE) { + None + } else { + Some(sigstack) + } + }) +} - nix::errno::Errno::result(res).map(|_| SigStack { stack: oldstack }) +pub unsafe fn altstack_flags() -> nix::Result { + let mut current_stack = std::mem::uninitialized::(); + let res = libc::sigaltstack( + std::ptr::null_mut(), + &mut current_stack as *mut libc::stack_t, + ); + nix::errno::Errno::result(res) + .map(|_| SigStackFlags::from_bits_truncate(current_stack.ss_flags)) } From eff817488f3344466e7aa136f38b5d4a49d28a16 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 26 Apr 2019 17:15:12 +0200 Subject: [PATCH 080/512] Just remove a warning about an unused use statement on linux --- lucet-runtime/lucet-runtime-internals/src/region/mmap.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs index 2deb87356..c97fd5e14 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs @@ -4,7 +4,9 @@ use crate::error::Error; use crate::instance::{new_instance_handle, Instance, InstanceHandle}; use crate::module::Module; use crate::region::{Region, RegionCreate, RegionInternal}; -use libc::{c_void, memset, SIGSTKSZ}; +#[cfg(not(target_os = "linux"))] +use libc::memset; +use libc::{c_void, SIGSTKSZ}; use nix::sys::mman::{madvise, mmap, munmap, MapFlags, MmapAdvise, ProtFlags}; use std::ptr; use std::sync::{Arc, Mutex, Weak}; From 153fe213edc80943cd81c91e694fc992c5e22bbe Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Fri, 26 Apr 2019 09:56:08 -0700 Subject: [PATCH 081/512] [lucet-runtime] silence panic output when terminating instances --- .../src/instance/signals.rs | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs index c9f92b452..a33cc813d 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs @@ -11,7 +11,8 @@ use lucet_module_data::TrapCode; use nix::sys::signal::{ pthread_sigmask, raise, sigaction, SaFlags, SigAction, SigHandler, SigSet, SigmaskHow, Signal, }; -use std::sync::Mutex; +use std::panic; +use std::sync::{Arc, Mutex}; lazy_static! { // TODO: work out an alternative to this that is signal-safe for `reraise_host_signal_in_handler` @@ -206,6 +207,7 @@ struct SignalState { saved_sigfpe: SigAction, saved_sigill: SigAction, saved_sigsegv: SigAction, + saved_panic_hook: Option>>, } // raw pointers in the saved types @@ -229,21 +231,50 @@ unsafe fn setup_guest_signal_state(ostate: &mut Option) { let saved_sigill = sigaction(Signal::SIGILL, &sa).expect("sigaction succeeds"); let saved_sigsegv = sigaction(Signal::SIGSEGV, &sa).expect("sigaction succeeds"); + let saved_panic_hook = Some(setup_guest_panic_hook()); + *ostate = Some(SignalState { counter: 1, saved_sigbus, saved_sigfpe, saved_sigill, saved_sigsegv, + saved_panic_hook, }); } +fn setup_guest_panic_hook() -> Arc> { + let saved_panic_hook = Arc::new(panic::take_hook()); + let closure_saved_panic_hook = saved_panic_hook.clone(); + std::panic::set_hook(Box::new(move |panic_info| { + if panic_info + .payload() + .downcast_ref::() + .is_none() + { + closure_saved_panic_hook(panic_info); + } else { + // this is a panic used to implement instance termination (such as + // `lucet_hostcall_terminate!`), so we don't want to print a backtrace; instead, we do + // nothing + } + })); + saved_panic_hook +} + unsafe fn restore_host_signal_state(state: &mut SignalState) { // restore signal handlers sigaction(Signal::SIGBUS, &state.saved_sigbus).expect("sigaction succeeds"); sigaction(Signal::SIGFPE, &state.saved_sigfpe).expect("sigaction succeeds"); sigaction(Signal::SIGILL, &state.saved_sigill).expect("sigaction succeeds"); sigaction(Signal::SIGSEGV, &state.saved_sigsegv).expect("sigaction succeeds"); + + // restore panic hook + drop(panic::take_hook()); + state + .saved_panic_hook + .take() + .map(|hook| Arc::try_unwrap(hook).map(|hook| panic::set_hook(hook))); } unsafe fn reraise_host_signal_in_handler( From d1ef54a4f4a4b8635ae6dc13a623bc8191cd751d Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Fri, 26 Apr 2019 11:12:27 -0700 Subject: [PATCH 082/512] [lucet-wasi] expose `inherit_stdio` C API --- lucet-wasi/include/lucet_wasi.h | 2 ++ lucet-wasi/src/c_api.rs | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/lucet-wasi/include/lucet_wasi.h b/lucet-wasi/include/lucet_wasi.h index 92d4d05d8..b0c5d6edc 100644 --- a/lucet-wasi/include/lucet_wasi.h +++ b/lucet-wasi/include/lucet_wasi.h @@ -11,6 +11,8 @@ enum lucet_error lucet_wasi_ctx_args(struct lucet_wasi_ctx *wasi_ctx, size_t arg enum lucet_error lucet_wasi_ctx_inherit_env(struct lucet_wasi_ctx *wasi_ctx); +enum lucet_error lucet_wasi_ctx_inherit_stdio(struct lucet_wasi_ctx *wasi_ctx); + void lucet_wasi_ctx_destroy(struct lucet_wasi_ctx *wasi_ctx); enum lucet_error lucet_region_new_instance_with_wasi_ctx(const struct lucet_region * region, diff --git a/lucet-wasi/src/c_api.rs b/lucet-wasi/src/c_api.rs index 484b6c090..be8dc9416 100644 --- a/lucet-wasi/src/c_api.rs +++ b/lucet-wasi/src/c_api.rs @@ -45,6 +45,17 @@ pub unsafe extern "C" fn lucet_wasi_ctx_inherit_env(wasi_ctx: *mut lucet_wasi_ct lucet_error::Ok } +#[no_mangle] +pub unsafe extern "C" fn lucet_wasi_ctx_inherit_stdio( + wasi_ctx: *mut lucet_wasi_ctx, +) -> lucet_error { + assert_nonnull!(wasi_ctx); + let mut b = Box::from_raw(wasi_ctx as *mut WasiCtxBuilder); + *b = b.inherit_stdio(); + Box::into_raw(b); + lucet_error::Ok +} + #[no_mangle] pub unsafe extern "C" fn lucet_wasi_ctx_destroy(wasi_ctx: *mut lucet_wasi_ctx) { Box::from_raw(wasi_ctx as *mut WasiCtxBuilder); From c9cfd141902842f2f4e2661000f492fbfde96b3b Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Fri, 26 Apr 2019 11:18:07 -0700 Subject: [PATCH 083/512] [lucet-runtime] avoid UB when destroying instances --- lucet-runtime/lucet-runtime-internals/src/instance.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index 7f0ed8f09..08719bd50 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -132,11 +132,12 @@ impl DerefMut for InstanceHandle { impl Drop for InstanceHandle { fn drop(&mut self) { - // eprintln!("InstanceHandle::drop()"); - // zero out magic, then run the destructor by taking and dropping the inner `Instance` - self.magic = 0; + // run the destructor by taking and dropping the inner `Instance` unsafe { mem::replace(self.inst.as_mut(), mem::uninitialized()); + // make sure magic is zeroed, as we can't depend on `uninitialized` throwing away the + // magic + self.inst.as_mut().magic = 0; } } } From 64f896428a9994cd4947da9f6a7ea066922914cc Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Fri, 26 Apr 2019 11:53:21 -0700 Subject: [PATCH 084/512] [lucet-benchmarks] add benchmarks for hostcall wrapper --- benchmarks/lucet-benchmarks/src/modules.rs | 35 ++++++++++++++++++++- benchmarks/lucet-benchmarks/src/seq.rs | 36 ++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/benchmarks/lucet-benchmarks/src/modules.rs b/benchmarks/lucet-benchmarks/src/modules.rs index 2972f0085..d08a5f662 100644 --- a/benchmarks/lucet-benchmarks/src/modules.rs +++ b/benchmarks/lucet-benchmarks/src/modules.rs @@ -1,4 +1,5 @@ -use lucet_runtime::vmctx::lucet_vmctx; +use lucet_runtime::vmctx::{Vmctx, lucet_vmctx}; +use lucet_runtime::lucet_hostcalls; use lucet_runtime_internals::module::{HeapSpec, MockModuleBuilder, Module}; use lucet_wasi_sdk::{CompileOpts, Lucetc}; use lucetc::{Bindings, LucetcOpts}; @@ -175,3 +176,35 @@ pub fn many_args_mock() -> Arc { .with_export_func(b"f", f as *const extern "C" fn()) .build() } + +pub fn hostcalls_mock() -> Arc { + lucet_hostcalls! { + pub unsafe extern "C" fn hostcall_wrapped( + &mut vmctx, + ) -> () { + assert_eq!(vmctx.heap()[0], 0); + } + } + + unsafe extern "C" fn hostcall_raw(vmctx: *mut lucet_vmctx) { + let vmctx = Vmctx::from_raw(vmctx); + assert_eq!(vmctx.heap()[0], 0); + } + + unsafe extern "C" fn wrapped(vmctx: *mut lucet_vmctx) { + for _ in 0..1000 { + hostcall_wrapped(vmctx); + } + } + + unsafe extern "C" fn raw(vmctx: *mut lucet_vmctx) { + for _ in 0..1000 { + hostcall_raw(vmctx); + } + } + + MockModuleBuilder::new() + .with_export_func(b"wrapped", wrapped as *const extern "C" fn()) + .with_export_func(b"raw", raw as *const extern "C" fn()) + .build() +} diff --git a/benchmarks/lucet-benchmarks/src/seq.rs b/benchmarks/lucet-benchmarks/src/seq.rs index baa3c484b..c090693b6 100644 --- a/benchmarks/lucet-benchmarks/src/seq.rs +++ b/benchmarks/lucet-benchmarks/src/seq.rs @@ -350,6 +350,40 @@ fn run_many_args(c: &mut Criterion) { }); } +fn run_hostcall_wrapped(c: &mut Criterion) { + fn body(inst: &mut InstanceHandle) { + inst.run(b"wrapped", &[]).unwrap(); + } + + let module = hostcalls_mock(); + let region = R::create(1, &Limits::default()).unwrap(); + + c.bench_function(&format!("run_hostcall_wrapped ({})", R::TYPE_NAME), move |b| { + b.iter_batched_ref( + || region.new_instance(module.clone()).unwrap(), + |inst| body(inst), + criterion::BatchSize::PerIteration, + ) + }); +} + +fn run_hostcall_raw(c: &mut Criterion) { + fn body(inst: &mut InstanceHandle) { + inst.run(b"raw", &[]).unwrap(); + } + + let module = hostcalls_mock(); + let region = R::create(1, &Limits::default()).unwrap(); + + c.bench_function(&format!("run_hostcall_raw ({})", R::TYPE_NAME), move |b| { + b.iter_batched_ref( + || region.new_instance(module.clone()).unwrap(), + |inst| body(inst), + criterion::BatchSize::PerIteration, + ) + }); +} + pub fn seq_benches(c: &mut Criterion) { load_mkregion_and_instantiate::(c); instantiate::(c); @@ -362,4 +396,6 @@ pub fn seq_benches(c: &mut Criterion) { run_fib::(c); run_hello::(c); run_many_args::(c); + run_hostcall_wrapped::(c); + run_hostcall_raw::(c); } From 7561b9897368d2fd993bde21b9b4e38fad5ff955 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Fri, 26 Apr 2019 12:02:45 -0700 Subject: [PATCH 085/512] make `/host` ignore more specific, and check in missing test --- .gitignore | 5 ++++- .../guests/host/hostcall_error_unwind.c | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 lucet-runtime/lucet-runtime-tests/guests/host/hostcall_error_unwind.c diff --git a/.gitignore b/.gitignore index 669bd5bf4..d0ba2d0ec 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ target/ *.rs.bk *.pyc -host + +# devenv-installed directory +/host + core.* diff --git a/lucet-runtime/lucet-runtime-tests/guests/host/hostcall_error_unwind.c b/lucet-runtime/lucet-runtime-tests/guests/host/hostcall_error_unwind.c new file mode 100644 index 000000000..6b48ce840 --- /dev/null +++ b/lucet-runtime/lucet-runtime-tests/guests/host/hostcall_error_unwind.c @@ -0,0 +1,9 @@ +#include + +extern void hostcall_test_func_hostcall_error_unwind(void); + +int main(void) +{ + hostcall_test_func_hostcall_error_unwind(); + return 0; +} From 13376da4d6a2b15cf58d5d1b103d292c59546b1e Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Fri, 26 Apr 2019 12:17:56 -0700 Subject: [PATCH 086/512] [lucet-runtime-tests] add test for sigaltstack preservation --- .../lucet-runtime-tests/src/guest_fault.rs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs index 708895d3c..b8bf1d372 100644 --- a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs +++ b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs @@ -677,6 +677,37 @@ macro_rules! guest_fault_tests { }) } + #[test] + fn sigaltstack_restores() { + use libc::*; + + test_nonex(|| { + // any alternate stack present before a thread runs an instance should be restored + // after the instance returns + let beforestack = unsafe { + let mut beforestack = std::mem::uninitialized::(); + sigaltstack(std::ptr::null(), &mut beforestack as *mut stack_t); + beforestack + }; + + let module = mock_traps_module(); + let region = + TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + run_onetwothree(&mut inst); + + let afterstack = unsafe { + let mut afterstack = std::mem::uninitialized::(); + sigaltstack(std::ptr::null(), &mut afterstack as *mut stack_t); + afterstack + }; + + assert_eq!(beforestack.ss_sp, afterstack.ss_sp); + }) + } + // TODO: remove this once `nix` PR https://github.com/nix-rust/nix/pull/991 is merged pub unsafe fn mprotect( addr: *mut c_void, From 0eb7b00f72c0593dcd8f241de6a4ce1f204f4ff5 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Fri, 26 Apr 2019 13:43:01 -0700 Subject: [PATCH 087/512] [lucet-benchmarks] hostcall overhead benches now take more arguments --- benchmarks/lucet-benchmarks/src/modules.rs | 56 +++++++++++++++++++--- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/benchmarks/lucet-benchmarks/src/modules.rs b/benchmarks/lucet-benchmarks/src/modules.rs index d08a5f662..426364bb4 100644 --- a/benchmarks/lucet-benchmarks/src/modules.rs +++ b/benchmarks/lucet-benchmarks/src/modules.rs @@ -1,5 +1,5 @@ -use lucet_runtime::vmctx::{Vmctx, lucet_vmctx}; use lucet_runtime::lucet_hostcalls; +use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime_internals::module::{HeapSpec, MockModuleBuilder, Module}; use lucet_wasi_sdk::{CompileOpts, Lucetc}; use lucetc::{Bindings, LucetcOpts}; @@ -179,27 +179,71 @@ pub fn many_args_mock() -> Arc { pub fn hostcalls_mock() -> Arc { lucet_hostcalls! { + #[inline(never)] + #[no_mangle] pub unsafe extern "C" fn hostcall_wrapped( &mut vmctx, + x1: u64, + x2: u64, + x3: u64, + x4: u64, + x5: u64, + x6: u64, + x7: u64, + x8: u64, + x9: u64, + x10: u64, + x11: u64, + x12: u64, + x13: u64, + x14: u64, + x15: u64, + x16: u64, ) -> () { - assert_eq!(vmctx.heap()[0], 0); + vmctx.heap_mut()[0] = + (x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16) + as u8; + assert_eq!(vmctx.heap()[0], 136); } } - unsafe extern "C" fn hostcall_raw(vmctx: *mut lucet_vmctx) { + #[inline(never)] + #[no_mangle] + pub unsafe extern "C" fn hostcall_raw( + vmctx: *mut lucet_vmctx, + x1: u64, + x2: u64, + x3: u64, + x4: u64, + x5: u64, + x6: u64, + x7: u64, + x8: u64, + x9: u64, + x10: u64, + x11: u64, + x12: u64, + x13: u64, + x14: u64, + x15: u64, + x16: u64, + ) { let vmctx = Vmctx::from_raw(vmctx); - assert_eq!(vmctx.heap()[0], 0); + vmctx.heap_mut()[0] = + (x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16) + as u8; + assert_eq!(vmctx.heap()[0], 136); } unsafe extern "C" fn wrapped(vmctx: *mut lucet_vmctx) { for _ in 0..1000 { - hostcall_wrapped(vmctx); + hostcall_wrapped(vmctx, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); } } unsafe extern "C" fn raw(vmctx: *mut lucet_vmctx) { for _ in 0..1000 { - hostcall_raw(vmctx); + hostcall_raw(vmctx, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); } } From c207a24dd887fd5f0518e99d0a17d5bb46ae0234 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Fri, 26 Apr 2019 14:11:08 -0700 Subject: [PATCH 088/512] [lucet-runtime] always inline hostcall implementation; use `move` This doesn't seem to make much of a dent in the benchmarking time, but it's the right thing to do --- lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs b/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs index 1c3ac37d1..1ff975fc4 100644 --- a/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs +++ b/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs @@ -38,13 +38,14 @@ macro_rules! lucet_hostcalls { vmctx_raw: *mut $crate::vmctx::lucet_vmctx, $( $arg: $arg_ty ),* ) -> $ret_ty { + #[inline(always)] unsafe fn hostcall_impl( $vmctx: &mut $crate::vmctx::Vmctx, $( $arg : $arg_ty ),* ) -> $ret_ty { $($body)* } - let res = std::panic::catch_unwind(|| { + let res = std::panic::catch_unwind(move || { hostcall_impl(&mut $crate::vmctx::Vmctx::from_raw(vmctx_raw), $( $arg ),*) }); match res { From e56975c18ff87c16640dfe3ead4a9bb8a4df291f Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Fri, 26 Apr 2019 15:59:35 -0700 Subject: [PATCH 089/512] [lucet-runtime] tweak the terrarium-only vmctx testing interface --- .../lucet-runtime-internals/src/vmctx.rs | 82 ++++++++++++------- 1 file changed, 51 insertions(+), 31 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index e3cde401c..883ecb6f5 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -22,6 +22,9 @@ pub struct Vmctx { vmctx: *mut lucet_vmctx, heap: RefCell>, globals: RefCell>, + + // only used for the `vmctx_from_mock_instance` fake vmctxs + check_instance: bool, } impl Drop for Vmctx { @@ -50,28 +53,28 @@ pub trait VmctxInternal { impl VmctxInternal for Vmctx { fn instance(&self) -> &Instance { - unsafe { instance_from_vmctx(self.vmctx) } + unsafe { instance_from_vmctx(self.vmctx, self.check_instance) } } unsafe fn instance_mut(&self) -> &mut Instance { - instance_from_vmctx(self.vmctx) + instance_from_vmctx(self.vmctx, self.check_instance) } } impl Vmctx { - /// Create a `Vmctx` from the compiler-inserted `vmctx` argument in a guest - /// function. + /// Create a `Vmctx` from the compiler-inserted `vmctx` argument in a guest function. /// /// This is almost certainly not what you want to use to get a `Vmctx`; instead use the `&mut /// Vmctx` argument to a `lucet_hostcalls!`-wrapped function. pub unsafe fn from_raw(vmctx: *mut lucet_vmctx) -> Vmctx { - let inst = instance_from_vmctx(vmctx); + let inst = instance_from_vmctx(vmctx, true); assert!(inst.valid_magic()); let res = Vmctx { vmctx, heap: RefCell::new(Box::<[u8]>::from_raw(inst.heap_mut())), globals: RefCell::new(Box::<[i64]>::from_raw(inst.globals_mut())), + check_instance: true, }; res } @@ -231,28 +234,33 @@ impl Vmctx { /// Get an `Instance` from the `vmctx` pointer. /// /// Only safe to call from within the guest context. -pub unsafe fn instance_from_vmctx<'a>(vmctx: *mut lucet_vmctx) -> &'a mut Instance { +pub unsafe fn instance_from_vmctx<'a>( + vmctx: *mut lucet_vmctx, + check_instance: bool, +) -> &'a mut Instance { assert!(!vmctx.is_null(), "vmctx is not null"); let inst_ptr = (vmctx as usize - instance_heap_offset()) as *mut Instance; - // We shouldn't actually need to access the thread local, only the exception handler should - // need to. But, as long as the thread local exists, we should make sure that the guest - // hasn't pulled any shenanigans and passed a bad vmctx. (Codegen should ensure the guest - // cant pull any shenanigans but there have been bugs before.) - CURRENT_INSTANCE.with(|current_instance| { - if let Some(current_inst_ptr) = current_instance.borrow().map(|nn| nn.as_ptr()) { - assert_eq!( - inst_ptr, current_inst_ptr, - "vmctx corresponds to current instance" - ); - } else { - panic!( - "current instance is not set; thread local storage failure can indicate \ - dynamic linking issues" - ); - } - }); + if check_instance { + // We shouldn't actually need to access the thread local, only the exception handler should + // need to. But, as long as the thread local exists, we should make sure that the guest + // hasn't pulled any shenanigans and passed a bad vmctx. (Codegen should ensure the guest + // cant pull any shenanigans but there have been bugs before.) + CURRENT_INSTANCE.with(|current_instance| { + if let Some(current_inst_ptr) = current_instance.borrow().map(|nn| nn.as_ptr()) { + assert_eq!( + inst_ptr, current_inst_ptr, + "vmctx corresponds to current instance" + ); + } else { + panic!( + "current instance is not set; thread local storage failure can indicate \ + dynamic linking issues" + ); + } + }); + } let inst = inst_ptr.as_mut().unwrap(); assert!(inst.valid_magic()); @@ -271,17 +279,29 @@ impl Instance { } } -/// Unsafely get a `Vmctx` from an `InstanceHandle`, and fake a current instance TLS variable. +/// Unsafely get a `Vmctx` from an `InstanceHandle` without checking the current instance TLS +/// variable. /// /// This is provided for compatibility with the Terrarium memory management test suite, but should /// absolutely not be used in newer code. #[deprecated] +#[allow(deprecated)] pub unsafe fn vmctx_from_mock_instance(inst: &InstanceHandle) -> Vmctx { - CURRENT_INSTANCE.with(|current_instance| { - let mut current_instance = current_instance.borrow_mut(); - *current_instance = Some(std::ptr::NonNull::new_unchecked( - inst.alloc().slot().start as *mut Instance, - )); - }); - Vmctx::from_raw(inst.alloc().slot().heap as *mut lucet_vmctx) + Vmctx::from_raw_unchecked(inst.alloc().slot().heap as *mut lucet_vmctx) +} + +impl Vmctx { + #[deprecated] + unsafe fn from_raw_unchecked(vmctx: *mut lucet_vmctx) -> Vmctx { + let inst = instance_from_vmctx(vmctx, false); + assert!(inst.valid_magic()); + + let res = Vmctx { + vmctx, + heap: RefCell::new(Box::<[u8]>::from_raw(inst.heap_mut())), + globals: RefCell::new(Box::<[i64]>::from_raw(inst.globals_mut())), + check_instance: false, + }; + res + } } From 959997b25b3a07ad77e3408efc86033f7a93d18d Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sat, 27 Apr 2019 00:15:08 +0200 Subject: [PATCH 090/512] Add another explicit page zeroing when MADV_DONTNEED is not enough --- lucet-runtime/lucet-runtime-internals/src/region/mmap.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs index c97fd5e14..cdaee6e04 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs @@ -100,6 +100,13 @@ impl RegionInternal for MmapRegion { { // eprintln!("setting none {:p}[{:x}]", *ptr, len); unsafe { + // MADV_DONTNEED is not guaranteed to clear pages on non-Linux systems + #[cfg(not(target_os = "linux"))] + { + mprotect(*ptr, *len, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE) + .expect("mprotect succeeds during drop"); + memset(*ptr, 0, *len); + } mprotect(*ptr, *len, ProtFlags::PROT_NONE).expect("mprotect succeeds during drop"); madvise(*ptr, *len, MmapAdvise::MADV_DONTNEED) .expect("madvise succeeds during drop"); From e0b58e0dabb0e75181ee05f099e5021a9fcbbc3a Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sat, 27 Apr 2019 01:10:19 +0200 Subject: [PATCH 091/512] Zero the heap only until the accessible size --- lucet-runtime/lucet-runtime-internals/src/region/mmap.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs index cdaee6e04..525364792 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs @@ -91,7 +91,8 @@ impl RegionInternal for MmapRegion { // clear and disable access to the heap, stack, globals, and sigstack for (ptr, len) in [ - (slot.heap, slot.limits.heap_address_space_size), + // We don't ever shrink the heap, so we only need to zero up until the accessible size + (slot.heap, alloc.heap_accessible_size), (slot.stack, slot.limits.stack_size), (slot.globals, slot.limits.globals_size), (slot.sigstack, SIGSTKSZ), From 394494c2ca3c803e654630eec9a60a66b691886f Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Fri, 26 Apr 2019 17:31:30 -0700 Subject: [PATCH 092/512] [lucet-runtime] remove obsolete testing functions --- .../lucet-runtime-internals/src/vmctx.rs | 81 +++++-------------- .../lucet-runtime-tests/src/helpers.rs | 2 - 2 files changed, 22 insertions(+), 61 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index 883ecb6f5..f35a9d4a8 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -9,8 +9,7 @@ use crate::alloc::instance_heap_offset; use crate::context::Context; use crate::error::Error; use crate::instance::{ - Instance, InstanceHandle, InstanceInternal, State, TerminationDetails, CURRENT_INSTANCE, - HOST_CTX, + Instance, InstanceInternal, State, TerminationDetails, CURRENT_INSTANCE, HOST_CTX, }; use std::any::Any; use std::borrow::{Borrow, BorrowMut}; @@ -22,9 +21,6 @@ pub struct Vmctx { vmctx: *mut lucet_vmctx, heap: RefCell>, globals: RefCell>, - - // only used for the `vmctx_from_mock_instance` fake vmctxs - check_instance: bool, } impl Drop for Vmctx { @@ -53,11 +49,11 @@ pub trait VmctxInternal { impl VmctxInternal for Vmctx { fn instance(&self) -> &Instance { - unsafe { instance_from_vmctx(self.vmctx, self.check_instance) } + unsafe { instance_from_vmctx(self.vmctx) } } unsafe fn instance_mut(&self) -> &mut Instance { - instance_from_vmctx(self.vmctx, self.check_instance) + instance_from_vmctx(self.vmctx) } } @@ -67,14 +63,13 @@ impl Vmctx { /// This is almost certainly not what you want to use to get a `Vmctx`; instead use the `&mut /// Vmctx` argument to a `lucet_hostcalls!`-wrapped function. pub unsafe fn from_raw(vmctx: *mut lucet_vmctx) -> Vmctx { - let inst = instance_from_vmctx(vmctx, true); + let inst = instance_from_vmctx(vmctx); assert!(inst.valid_magic()); let res = Vmctx { vmctx, heap: RefCell::new(Box::<[u8]>::from_raw(inst.heap_mut())), globals: RefCell::new(Box::<[i64]>::from_raw(inst.globals_mut())), - check_instance: true, }; res } @@ -234,33 +229,28 @@ impl Vmctx { /// Get an `Instance` from the `vmctx` pointer. /// /// Only safe to call from within the guest context. -pub unsafe fn instance_from_vmctx<'a>( - vmctx: *mut lucet_vmctx, - check_instance: bool, -) -> &'a mut Instance { +pub unsafe fn instance_from_vmctx<'a>(vmctx: *mut lucet_vmctx) -> &'a mut Instance { assert!(!vmctx.is_null(), "vmctx is not null"); let inst_ptr = (vmctx as usize - instance_heap_offset()) as *mut Instance; - if check_instance { - // We shouldn't actually need to access the thread local, only the exception handler should - // need to. But, as long as the thread local exists, we should make sure that the guest - // hasn't pulled any shenanigans and passed a bad vmctx. (Codegen should ensure the guest - // cant pull any shenanigans but there have been bugs before.) - CURRENT_INSTANCE.with(|current_instance| { - if let Some(current_inst_ptr) = current_instance.borrow().map(|nn| nn.as_ptr()) { - assert_eq!( - inst_ptr, current_inst_ptr, - "vmctx corresponds to current instance" - ); - } else { - panic!( - "current instance is not set; thread local storage failure can indicate \ - dynamic linking issues" - ); - } - }); - } + // We shouldn't actually need to access the thread local, only the exception handler should + // need to. But, as long as the thread local exists, we should make sure that the guest + // hasn't pulled any shenanigans and passed a bad vmctx. (Codegen should ensure the guest + // cant pull any shenanigans but there have been bugs before.) + CURRENT_INSTANCE.with(|current_instance| { + if let Some(current_inst_ptr) = current_instance.borrow().map(|nn| nn.as_ptr()) { + assert_eq!( + inst_ptr, current_inst_ptr, + "vmctx corresponds to current instance" + ); + } else { + panic!( + "current instance is not set; thread local storage failure can indicate \ + dynamic linking issues" + ); + } + }); let inst = inst_ptr.as_mut().unwrap(); assert!(inst.valid_magic()); @@ -278,30 +268,3 @@ impl Instance { HOST_CTX.with(|host_ctx| unsafe { Context::set(&*host_ctx.get()) }) } } - -/// Unsafely get a `Vmctx` from an `InstanceHandle` without checking the current instance TLS -/// variable. -/// -/// This is provided for compatibility with the Terrarium memory management test suite, but should -/// absolutely not be used in newer code. -#[deprecated] -#[allow(deprecated)] -pub unsafe fn vmctx_from_mock_instance(inst: &InstanceHandle) -> Vmctx { - Vmctx::from_raw_unchecked(inst.alloc().slot().heap as *mut lucet_vmctx) -} - -impl Vmctx { - #[deprecated] - unsafe fn from_raw_unchecked(vmctx: *mut lucet_vmctx) -> Vmctx { - let inst = instance_from_vmctx(vmctx, false); - assert!(inst.valid_magic()); - - let res = Vmctx { - vmctx, - heap: RefCell::new(Box::<[u8]>::from_raw(inst.heap_mut())), - globals: RefCell::new(Box::<[i64]>::from_raw(inst.globals_mut())), - check_instance: false, - }; - res - } -} diff --git a/lucet-runtime/lucet-runtime-tests/src/helpers.rs b/lucet-runtime/lucet-runtime-tests/src/helpers.rs index 967810c9c..f91f8fa79 100644 --- a/lucet-runtime/lucet-runtime-tests/src/helpers.rs +++ b/lucet-runtime/lucet-runtime-tests/src/helpers.rs @@ -1,7 +1,5 @@ // re-export types that should only be used for testing pub use lucet_runtime_internals::module::{HeapSpec, MockModuleBuilder}; -#[allow(deprecated)] -pub use lucet_runtime_internals::vmctx::vmctx_from_mock_instance; use lazy_static::lazy_static; use std::sync::RwLock; From 32918af1931828979954fcf323f24b6901edcb30 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Mon, 29 Apr 2019 15:07:03 +0200 Subject: [PATCH 093/512] Update faerie to version 0.10 + support for extended ELF section Also update cranelift, that already moved to faerie 0.10. --- Cargo.lock | 99 +++++++++++++++++++++++++++-------------------- Cargo.toml | 2 +- cranelift | 2 +- faerie | 2 +- lucetc/Cargo.toml | 2 +- 5 files changed, 62 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a59350a30..f728afede 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -203,87 +203,87 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.29.0" +version = "0.30.0" dependencies = [ - "cranelift-entity 0.29.0", + "cranelift-entity 0.30.0", ] [[package]] name = "cranelift-codegen" -version = "0.29.0" +version = "0.30.0" dependencies = [ - "cranelift-bforest 0.29.0", - "cranelift-codegen-meta 0.29.0", - "cranelift-entity 0.29.0", + "cranelift-bforest 0.30.0", + "cranelift-codegen-meta 0.30.0", + "cranelift-entity 0.30.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-codegen-meta" -version = "0.29.0" +version = "0.30.0" dependencies = [ - "cranelift-entity 0.29.0", + "cranelift-entity 0.30.0", ] [[package]] name = "cranelift-entity" -version = "0.29.0" +version = "0.30.0" [[package]] name = "cranelift-faerie" -version = "0.29.0" +version = "0.30.0" dependencies = [ - "cranelift-codegen 0.29.0", - "cranelift-module 0.29.0", - "faerie 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen 0.30.0", + "cranelift-module 0.30.0", + "faerie 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-frontend" -version = "0.29.0" +version = "0.30.0" dependencies = [ - "cranelift-codegen 0.29.0", + "cranelift-codegen 0.30.0", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-module" -version = "0.29.0" +version = "0.30.0" dependencies = [ - "cranelift-codegen 0.29.0", - "cranelift-entity 0.29.0", + "cranelift-codegen 0.30.0", + "cranelift-entity 0.30.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-native" -version = "0.29.0" +version = "0.30.0" dependencies = [ - "cranelift-codegen 0.29.0", + "cranelift-codegen 0.30.0", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-wasm" -version = "0.29.0" +version = "0.30.0" dependencies = [ "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.29.0", - "cranelift-entity 0.29.0", - "cranelift-frontend 0.29.0", + "cranelift-codegen 0.30.0", + "cranelift-entity 0.30.0", + "cranelift-frontend 0.30.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -410,7 +410,7 @@ dependencies = [ [[package]] name = "faerie" -version = "0.9.1" +version = "0.10.0" dependencies = [ "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -421,14 +421,14 @@ dependencies = [ "string-interner 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "structopt-derive 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "faerie" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -replace = "faerie 0.9.1" +replace = "faerie 0.10.0" [[package]] name = "failure" @@ -751,14 +751,14 @@ dependencies = [ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.29.0", - "cranelift-faerie 0.29.0", - "cranelift-frontend 0.29.0", - "cranelift-module 0.29.0", - "cranelift-native 0.29.0", - "cranelift-wasm 0.29.0", + "cranelift-codegen 0.30.0", + "cranelift-faerie 0.30.0", + "cranelift-frontend 0.30.0", + "cranelift-module 0.30.0", + "cranelift-native 0.30.0", + "cranelift-wasm 0.30.0", "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "faerie 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "faerie 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1296,6 +1296,16 @@ dependencies = [ "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "target-lexicon" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tempfile" version = "3.0.7" @@ -1469,6 +1479,11 @@ name = "wasmparser" version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "wasmparser" +version = "0.29.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "which" version = "2.0.1" @@ -1565,7 +1580,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a" "checksum errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2a071601ed01b988f896ab14b95e67335d1eeb50190932a1320f7fe3cadc84e" "checksum errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067" -"checksum faerie 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f48412f92b56015a240e249847295b38b0a731435806c21a199403b2c317272c" +"checksum faerie 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c6d75e6376216d6228fbab8025087523666623d9302ff17dd023d024bf98302" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" @@ -1647,6 +1662,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)" = "d2b4cfac95805274c6afdb12d8f770fa2d27c045953e7b630a81801953699a9a" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" "checksum target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6923974ce4eb5bd28814756256d8ab71c28dd6e7483313fe7ab6614306bf633" +"checksum target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b0ab4982b8945c35cc1c46a83a9094c414f6828a099ce5dcaa8ee2b04642dcb" "checksum tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b86c784c88d98c801132806dadd3819ed29d8600836c4088e855cdf3e178ed8a" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" "checksum terminal_size 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "023345d35850b69849741bd9a5432aa35290e3d8eb76af8717026f270d1cf133" @@ -1668,6 +1684,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" "checksum wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5e01c420bc7d36e778bd242e1167b079562ba8b34087122cc9057187026d060" +"checksum wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)" = "981a8797cf89762e0233ec45fae731cb79a4dfaee12d9f0fe6cee01e4ac58d00" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" diff --git a/Cargo.toml b/Cargo.toml index 34eed17b3..f1ff22eb8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,4 +20,4 @@ exclude = ["cranelift"] rpath = true [replace] -"faerie:0.9.1" = { path = "faerie" } +"faerie:0.10.0" = { path = "faerie" } diff --git a/cranelift b/cranelift index 894cecc78..c0ee30f9a 160000 --- a/cranelift +++ b/cranelift @@ -1 +1 @@ -Subproject commit 894cecc78fa3169c7efd74bafb5165315f0f7f36 +Subproject commit c0ee30f9a95bd80bd6485c21bad7e8e0b8c5caf0 diff --git a/faerie b/faerie index ebe9edff9..dcb671a99 160000 --- a/faerie +++ b/faerie @@ -1 +1 @@ -Subproject commit ebe9edff906749bd52718b8552d560b232a608ff +Subproject commit dcb671a99faa32b72fac88d2406e952a41844636 diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index 108e8543e..11e3fabda 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -28,7 +28,7 @@ wasmparser = "0.23" clap="2.32" log = "0.4" env_logger = "0.6" -faerie = "0.9.1" +faerie = "0.10.0" failure = "0.1" serde = "1.0" serde_json = "1.0" From b09d8301d568b63584a6441254f95c0f9e130b4c Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 25 Apr 2019 12:03:36 -0700 Subject: [PATCH 094/512] lucet-idl: separate command line opt parsing from library config --- lucet-idl/src/config.rs | 65 ++++--------------------------------- lucet-idl/src/main.rs | 71 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 61 deletions(-) diff --git a/lucet-idl/src/config.rs b/lucet-idl/src/config.rs index 2be0b54ea..f902257d7 100644 --- a/lucet-idl/src/config.rs +++ b/lucet-idl/src/config.rs @@ -1,78 +1,27 @@ -use super::backend::*; -use super::errors::*; -use super::target::*; -use clap::{App, Arg}; -use std::path::PathBuf; +use super::backend::{Backend, BackendConfig}; +use super::target::Target; #[derive(Default, Clone, Debug)] pub struct Config { - pub input_path: PathBuf, - pub output_path: Option, pub target: Target, pub backend: Backend, pub backend_config: BackendConfig, } impl Config { - pub fn parse() -> Result { - let matches = App::new("lucet-idl") - .version("1.0") - .about("lucet_idl code generator") - .arg( - Arg::with_name("input_file") - .short("i") - .long("input") - .takes_value(true) - .required(true) - .help("Path to the input file"), - ) - .arg( - Arg::with_name("target") - .short("t") - .long("target") - .default_value("Generic") - .takes_value(true) - .required(false) - .help("Target, one of: x86, x86_64, x86_64_32, generic"), - ) - .arg( - Arg::with_name("backend") - .short("b") - .long("backend") - .default_value("c") - .takes_value(true) - .required(false) - .help("Backend, one of: c, rust"), - ) - .arg( - Arg::with_name("zero-native-pointers") - .short("z") - .long("zero-native-pointers") - .takes_value(false) - .required(false) - .help("Do not serialize native pointers"), - ) - .get_matches(); - let input_path = PathBuf::from( - matches - .value_of("input_file") - .ok_or(IDLError::UsageError("Input file required"))?, - ); - let mut target = Target::from(matches.value_of("target").unwrap()); - let backend = Backend::from(matches.value_of("backend").unwrap()); - let zero_native_pointers = matches.is_present("zero-native-pointers"); + pub fn parse(target_opt: &str, backend_opt: &str, zero_native_pointers: bool) -> Self { + let mut target = Target::from(target_opt); + let backend = Backend::from(backend_opt); if zero_native_pointers { target = Target::Generic; } let backend_config = BackendConfig { zero_native_pointers, }; - Ok(Config { - input_path, - output_path: None, + Self { target, backend, backend_config, - }) + } } } diff --git a/lucet-idl/src/main.rs b/lucet-idl/src/main.rs index 170947390..68f142598 100644 --- a/lucet-idl/src/main.rs +++ b/lucet-idl/src/main.rs @@ -24,11 +24,76 @@ use lucet_idl::validate::*; use std::fs::File; use std::io; use std::io::prelude::*; +use clap::{App, Arg}; +use std::path::PathBuf; + +#[derive(Default, Clone, Debug)] +pub struct ExeConfig { + pub input_path: PathBuf, + pub output_path: Option, + pub config: Config, +} + +impl ExeConfig { + pub fn parse() -> Result { + let matches = App::new("lucet-idl") + .version("1.0") + .about("lucet_idl code generator") + .arg( + Arg::with_name("input_file") + .short("i") + .long("input") + .takes_value(true) + .required(true) + .help("Path to the input file"), + ) + .arg( + Arg::with_name("target") + .short("t") + .long("target") + .default_value("Generic") + .takes_value(true) + .required(false) + .help("Target, one of: x86, x86_64, x86_64_32, generic"), + ) + .arg( + Arg::with_name("backend") + .short("b") + .long("backend") + .default_value("c") + .takes_value(true) + .required(false) + .help("Backend, one of: c, rust"), + ) + .arg( + Arg::with_name("zero-native-pointers") + .short("z") + .long("zero-native-pointers") + .takes_value(false) + .required(false) + .help("Do not serialize native pointers"), + ) + .get_matches(); + let input_path = PathBuf::from( + matches + .value_of("input_file") + .ok_or(IDLError::UsageError("Input file required"))?, + ); + let config = Config::parse(matches.value_of("target").unwrap(), + matches.value_of("backend").unwrap(), + matches.is_present("zero-native-pointers")); + Ok(ExeConfig { + input_path, + output_path: None, + config, + }) + } +} fn doit() -> Result<(), IDLError> { - let config = Config::parse()?; + let exe_config = ExeConfig::parse()?; let mut source = String::new(); - File::open(&config.input_path)?.read_to_string(&mut source)?; + File::open(&exe_config.input_path)?.read_to_string(&mut source)?; let mut parser = Parser::new(&source); let decls = parser.match_decls()?; let data_description = DataDescription::validate(&decls)?; @@ -37,7 +102,7 @@ fn doit() -> Result<(), IDLError> { .map_err(|_| IDLError::InternalError("Unable to resolve dependencies"))?; let data_description_helper = DataDescriptionHelper { data_description }; let mut cache = Cache::default(); - let mut generator = Generators::c(&config); + let mut generator = Generators::c(&exe_config.config); let mut pretty_writer = PrettyWriter::new(io::stdout()); generator.gen_prelude(&mut pretty_writer)?; for id in deps { From feff1f47d746b6862a385506673e369c59fd854a Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 25 Apr 2019 12:09:12 -0700 Subject: [PATCH 095/512] lucet-idl: move bin-scoped modules to lib --- lucet-idl/src/cache.rs | 2 +- lucet-idl/src/cgenerator/catom.rs | 4 +-- lucet-idl/src/cgenerator/mod.rs | 18 +++++------ lucet-idl/src/data_description_helper.rs | 10 +++--- lucet-idl/src/errors.rs | 2 +- lucet-idl/src/lib.rs | 18 +++++++++++ lucet-idl/src/main.rs | 39 ++++++++---------------- lucet-idl/src/rustgenerator/mod.rs | 16 +++++----- lucet-idl/src/target.rs | 2 +- 9 files changed, 58 insertions(+), 53 deletions(-) diff --git a/lucet-idl/src/cache.rs b/lucet-idl/src/cache.rs index 7eacfe22d..16bd2abe9 100644 --- a/lucet-idl/src/cache.rs +++ b/lucet-idl/src/cache.rs @@ -1,4 +1,4 @@ -use lucet_idl::validate::*; +use crate::validate::*; use std::collections::HashMap; /// Cached information for a given structure member diff --git a/lucet-idl/src/cgenerator/catom.rs b/lucet-idl/src/cgenerator/catom.rs index 8c23e3168..5a46eafec 100644 --- a/lucet-idl/src/cgenerator/catom.rs +++ b/lucet-idl/src/cgenerator/catom.rs @@ -1,5 +1,5 @@ -use super::super::target::*; -use lucet_idl::types::*; +use crate::target::*; +use crate::types::*; /// Information about a C native type pub struct CAtom { diff --git a/lucet-idl/src/cgenerator/mod.rs b/lucet-idl/src/cgenerator/mod.rs index ee43a5c22..04cd9be2b 100644 --- a/lucet-idl/src/cgenerator/mod.rs +++ b/lucet-idl/src/cgenerator/mod.rs @@ -16,15 +16,15 @@ mod gen_tagged_union; mod macros; pub(crate) use self::catom::*; -use super::backend::*; -use super::cache::*; -use super::data_description_helper::*; -use super::errors::*; -use super::generators::*; -use super::pretty_writer::*; -use super::target::*; -use lucet_idl::types::*; -use lucet_idl::validate::*; +use crate::backend::*; +use crate::cache::*; +use crate::data_description_helper::*; +use crate::errors::*; +use crate::generators::*; +use crate::pretty_writer::*; +use crate::target::*; +use crate::types::*; +use crate::validate::*; use std::io::prelude::*; #[derive(Clone, Debug)] diff --git a/lucet-idl/src/data_description_helper.rs b/lucet-idl/src/data_description_helper.rs index fdec4ba48..5c83ddaeb 100644 --- a/lucet-idl/src/data_description_helper.rs +++ b/lucet-idl/src/data_description_helper.rs @@ -1,8 +1,8 @@ -use super::cache::*; -use super::errors::*; -use super::generators::*; -use super::pretty_writer::*; -use lucet_idl::validate::*; +use crate::cache::*; +use crate::errors::*; +use crate::generators::*; +use crate::pretty_writer::*; +use crate::validate::*; use std::io::prelude::*; /// A convenient structure holding a data type, its name and diff --git a/lucet-idl/src/errors.rs b/lucet-idl/src/errors.rs index 462f6b386..1a917017b 100644 --- a/lucet-idl/src/errors.rs +++ b/lucet-idl/src/errors.rs @@ -1,4 +1,4 @@ -use lucet_idl::{parser, validate}; +use crate::{parser, validate}; use std::io; #[allow(dead_code)] diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 69c4e1961..bbab1c565 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -1,4 +1,22 @@ +#[macro_use] +extern crate failure; + pub mod lexer; pub mod parser; pub mod types; pub mod validate; + +pub mod backend; +pub mod cache; +pub mod cgenerator; +pub mod config; +pub mod data_description_helper; +pub mod errors; +pub mod generators; +pub mod pretty_writer; +pub mod rustgenerator; +pub mod target; + +pub use crate::backend::{Backend, BackendConfig}; +pub use crate::config::Config; +pub use crate::target::Target; diff --git a/lucet-idl/src/main.rs b/lucet-idl/src/main.rs index 68f142598..0829c6c23 100644 --- a/lucet-idl/src/main.rs +++ b/lucet-idl/src/main.rs @@ -1,33 +1,18 @@ -#[macro_use] -extern crate failure; - -mod backend; -mod cache; -mod cgenerator; -mod config; -mod data_description_helper; -mod errors; -mod generators; -mod pretty_writer; -mod rustgenerator; -mod target; - -use self::cache::*; -use self::generators::*; - -use self::config::*; -use self::data_description_helper::*; -use self::errors::*; -use self::pretty_writer::*; +use lucet_idl::cache::*; +use lucet_idl::config::*; +use lucet_idl::data_description_helper::*; +use lucet_idl::errors::*; +use lucet_idl::generators::*; use lucet_idl::parser::*; +use lucet_idl::pretty_writer::*; use lucet_idl::validate::*; + +use clap::{App, Arg}; use std::fs::File; use std::io; use std::io::prelude::*; -use clap::{App, Arg}; use std::path::PathBuf; - #[derive(Default, Clone, Debug)] pub struct ExeConfig { pub input_path: PathBuf, @@ -80,9 +65,11 @@ impl ExeConfig { .value_of("input_file") .ok_or(IDLError::UsageError("Input file required"))?, ); - let config = Config::parse(matches.value_of("target").unwrap(), - matches.value_of("backend").unwrap(), - matches.is_present("zero-native-pointers")); + let config = Config::parse( + matches.value_of("target").unwrap(), + matches.value_of("backend").unwrap(), + matches.is_present("zero-native-pointers"), + ); Ok(ExeConfig { input_path, output_path: None, diff --git a/lucet-idl/src/rustgenerator/mod.rs b/lucet-idl/src/rustgenerator/mod.rs index 9972b9d19..ddc6242d5 100644 --- a/lucet-idl/src/rustgenerator/mod.rs +++ b/lucet-idl/src/rustgenerator/mod.rs @@ -1,14 +1,14 @@ #![allow(dead_code)] #![allow(unused_variables)] -use super::backend::*; -use super::cache::*; -use super::data_description_helper::*; -use super::errors::*; -use super::generators::*; -use super::pretty_writer::*; -use super::target::*; -use lucet_idl::validate::*; +use crate::backend::*; +use crate::cache::*; +use crate::data_description_helper::*; +use crate::errors::*; +use crate::generators::*; +use crate::pretty_writer::*; +use crate::target::*; +use crate::validate::*; use std::io::prelude::*; #[derive(Clone, Debug)] diff --git a/lucet-idl/src/target.rs b/lucet-idl/src/target.rs index 8a020079c..af5d6b79f 100644 --- a/lucet-idl/src/target.rs +++ b/lucet-idl/src/target.rs @@ -1,4 +1,4 @@ -use lucet_idl::types::*; +use crate::types::*; #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum Target { From 91c04066f0852722c69333d743ce186d185b0948 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 25 Apr 2019 14:58:59 -0700 Subject: [PATCH 096/512] lucet-idl: move the executable body into a func in lib --- lucet-idl/src/lib.rs | 59 ++++++++++++++++++++++++++++++++----------- lucet-idl/src/main.rs | 27 +++----------------- 2 files changed, 48 insertions(+), 38 deletions(-) diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index bbab1c565..27ae5ea99 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -1,22 +1,51 @@ #[macro_use] extern crate failure; -pub mod lexer; -pub mod parser; -pub mod types; -pub mod validate; - -pub mod backend; -pub mod cache; -pub mod cgenerator; -pub mod config; -pub mod data_description_helper; -pub mod errors; -pub mod generators; -pub mod pretty_writer; -pub mod rustgenerator; -pub mod target; +mod lexer; +mod parser; +mod types; +mod validate; +mod backend; +mod cache; +mod cgenerator; +mod config; +mod data_description_helper; +mod errors; +mod generators; +mod pretty_writer; +mod rustgenerator; +mod target; pub use crate::backend::{Backend, BackendConfig}; pub use crate::config::Config; pub use crate::target::Target; +pub use crate::errors::IDLError; + +use crate::parser::Parser; +use crate::data_description_helper::DataDescriptionHelper; +use crate::cache::Cache; +use crate::generators::{Generators, Generator}; +use crate::pretty_writer::PrettyWriter; +use crate::validate::DataDescription; +use std::io::Write; + +pub fn run(config: &Config, input: &str, output: W) -> Result<(), IDLError> { + let mut parser = Parser::new(&input); + let decls = parser.match_decls()?; + + let data_description = DataDescription::validate(&decls)?; + let deps = data_description + .ordered_dependencies() + .map_err(|_| IDLError::InternalError("Unable to resolve dependencies"))?; + let data_description_helper = DataDescriptionHelper { data_description }; + + let mut cache = Cache::default(); + let mut generator = Generators::c(config); + + let mut pretty_writer = PrettyWriter::new(output); + generator.gen_prelude(&mut pretty_writer)?; + for id in deps { + data_description_helper.gen_for_id(&mut generator, &mut cache, &mut pretty_writer, id)?; + } + Ok(()) +} diff --git a/lucet-idl/src/main.rs b/lucet-idl/src/main.rs index 0829c6c23..c544a6bbe 100644 --- a/lucet-idl/src/main.rs +++ b/lucet-idl/src/main.rs @@ -1,12 +1,4 @@ -use lucet_idl::cache::*; -use lucet_idl::config::*; -use lucet_idl::data_description_helper::*; -use lucet_idl::errors::*; -use lucet_idl::generators::*; -use lucet_idl::parser::*; -use lucet_idl::pretty_writer::*; -use lucet_idl::validate::*; - +use lucet_idl::{run, IDLError, Config}; use clap::{App, Arg}; use std::fs::File; use std::io; @@ -81,20 +73,9 @@ fn doit() -> Result<(), IDLError> { let exe_config = ExeConfig::parse()?; let mut source = String::new(); File::open(&exe_config.input_path)?.read_to_string(&mut source)?; - let mut parser = Parser::new(&source); - let decls = parser.match_decls()?; - let data_description = DataDescription::validate(&decls)?; - let deps = data_description - .ordered_dependencies() - .map_err(|_| IDLError::InternalError("Unable to resolve dependencies"))?; - let data_description_helper = DataDescriptionHelper { data_description }; - let mut cache = Cache::default(); - let mut generator = Generators::c(&exe_config.config); - let mut pretty_writer = PrettyWriter::new(io::stdout()); - generator.gen_prelude(&mut pretty_writer)?; - for id in deps { - data_description_helper.gen_for_id(&mut generator, &mut cache, &mut pretty_writer, id)?; - } + + run(&exe_config.config, &source, io::stdout())?; + Ok(()) } From c75fddf9d3d62fe5932e7c8b23df3ddda6318a50 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 25 Apr 2019 17:11:44 -0700 Subject: [PATCH 097/512] lucet-idl: tons of renaming and simplifying "DataDescription" is now "Module". "DataDescriptionHelper" methods folded into "Generator" --- lucet-idl/src/cache.rs | 2 +- .../src/cgenerator/gen_accessors_alias.rs | 6 +- .../src/cgenerator/gen_accessors_atom.rs | 2 +- .../src/cgenerator/gen_accessors_enum.rs | 2 +- lucet-idl/src/cgenerator/gen_accessors_ptr.rs | 6 +- .../src/cgenerator/gen_accessors_struct.rs | 6 +- .../cgenerator/gen_accessors_tagged_union.rs | 12 +- lucet-idl/src/cgenerator/gen_alias.rs | 6 +- lucet-idl/src/cgenerator/gen_enum.rs | 2 +- lucet-idl/src/cgenerator/gen_struct.rs | 4 +- lucet-idl/src/cgenerator/gen_tagged_union.rs | 6 +- lucet-idl/src/cgenerator/macros.rs | 4 +- lucet-idl/src/cgenerator/mod.rs | 77 ++++---- lucet-idl/src/data_description_helper.rs | 171 ------------------ lucet-idl/src/errors.rs | 8 +- lucet-idl/src/generators/generator.rs | 97 ++++++++-- lucet-idl/src/lib.rs | 13 +- lucet-idl/src/{validate.rs => module.rs} | 104 ++++++----- lucet-idl/src/rustgenerator/mod.rs | 21 +-- 19 files changed, 224 insertions(+), 325 deletions(-) delete mode 100644 lucet-idl/src/data_description_helper.rs rename lucet-idl/src/{validate.rs => module.rs} (86%) diff --git a/lucet-idl/src/cache.rs b/lucet-idl/src/cache.rs index 16bd2abe9..438c1daf5 100644 --- a/lucet-idl/src/cache.rs +++ b/lucet-idl/src/cache.rs @@ -1,4 +1,4 @@ -use crate::validate::*; +use crate::module::DataTypeId; use std::collections::HashMap; /// Cached information for a given structure member diff --git a/lucet-idl/src/cgenerator/gen_accessors_alias.rs b/lucet-idl/src/cgenerator/gen_accessors_alias.rs index 9898a8c96..5c585ec3f 100644 --- a/lucet-idl/src/cgenerator/gen_accessors_alias.rs +++ b/lucet-idl/src/cgenerator/gen_accessors_alias.rs @@ -2,7 +2,7 @@ use super::*; pub fn generate( cgenerator: &mut CGenerator, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -17,14 +17,14 @@ pub fn generate( } else { unreachable!() }; - let type_info = cgenerator.type_info(data_description_helper, cache, type_); + let type_info = cgenerator.type_info(module, cache, type_); pretty_writer.indent()?; pretty_writer .write(format!("// `{}` is an alias for `{}`", name, type_info.type_name).as_ref())?; if type_info.indirections == 0 { let leaf_type_info = - cgenerator.type_info(data_description_helper, cache, type_info.leaf_data_type_ref); + cgenerator.type_info(module, cache, type_info.leaf_data_type_ref); if leaf_type_info.type_name != type_info.type_name { pretty_writer .write(format!(", itself equivalent to `{}`", leaf_type_info.type_name).as_ref())?; diff --git a/lucet-idl/src/cgenerator/gen_accessors_atom.rs b/lucet-idl/src/cgenerator/gen_accessors_atom.rs index dff778842..4adb0f8ab 100644 --- a/lucet-idl/src/cgenerator/gen_accessors_atom.rs +++ b/lucet-idl/src/cgenerator/gen_accessors_atom.rs @@ -2,7 +2,7 @@ use super::*; pub fn generate( cgenerator: &mut CGenerator, - _data_description_helper: &DataDescriptionHelper, + _module: &Module, pretty_writer: &mut PrettyWriter, atom_type: AtomType, hierarchy: &Hierarchy, diff --git a/lucet-idl/src/cgenerator/gen_accessors_enum.rs b/lucet-idl/src/cgenerator/gen_accessors_enum.rs index 4512812c0..561c3cb4c 100644 --- a/lucet-idl/src/cgenerator/gen_accessors_enum.rs +++ b/lucet-idl/src/cgenerator/gen_accessors_enum.rs @@ -2,7 +2,7 @@ use super::*; pub fn generate( cgenerator: &mut CGenerator, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, diff --git a/lucet-idl/src/cgenerator/gen_accessors_ptr.rs b/lucet-idl/src/cgenerator/gen_accessors_ptr.rs index 5d89f22b4..f6f33acb5 100644 --- a/lucet-idl/src/cgenerator/gen_accessors_ptr.rs +++ b/lucet-idl/src/cgenerator/gen_accessors_ptr.rs @@ -2,15 +2,15 @@ use super::*; pub fn generate( cgenerator: &mut CGenerator, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &Cache, pretty_writer: &mut PrettyWriter, type_: &DataTypeRef, hierarchy: &Hierarchy, ) -> Result<(), IDLError> { - let type_info = cgenerator.type_info(data_description_helper, cache, type_); + let type_info = cgenerator.type_info(module, cache, type_); let leaf_type_info = - cgenerator.type_info(data_description_helper, cache, type_info.leaf_data_type_ref); + cgenerator.type_info(module, cache, type_info.leaf_data_type_ref); assert_eq!(leaf_type_info.indirections, 0); if type_info.indirections > 1 { pretty_writer.write_line( diff --git a/lucet-idl/src/cgenerator/gen_accessors_struct.rs b/lucet-idl/src/cgenerator/gen_accessors_struct.rs index 2f8cce95d..da5836556 100644 --- a/lucet-idl/src/cgenerator/gen_accessors_struct.rs +++ b/lucet-idl/src/cgenerator/gen_accessors_struct.rs @@ -2,7 +2,7 @@ use super::*; pub fn generate( cgenerator: &mut CGenerator, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -41,7 +41,7 @@ pub fn generate( let type_: &DataTypeRef = &named_member.type_; let hierarchy = hierarchy.push(named_member.name.to_string(), current_offset + offset); cgenerator.gen_accessors_for_data_type_ref( - data_description_helper, + module, cache, &mut pretty_writer.new_block(), type_, @@ -104,7 +104,7 @@ pub fn generate( let fn_name = hierarchy.fn_name(); let type_ = &named_member.type_; let is_eventually_an_atom_or_enum = - cgenerator.is_type_eventually_an_atom_or_enum(data_description_helper, type_); + cgenerator.is_type_eventually_an_atom_or_enum(module, type_); if let DataTypeRef::Ptr(_) = type_ { pretty_writer_preprocessor.write_line(b"# ifdef ZERO_NATIVE_POINTERS")?; pretty_writer_i1.write_line( diff --git a/lucet-idl/src/cgenerator/gen_accessors_tagged_union.rs b/lucet-idl/src/cgenerator/gen_accessors_tagged_union.rs index 3971aaa3d..39c28ba83 100644 --- a/lucet-idl/src/cgenerator/gen_accessors_tagged_union.rs +++ b/lucet-idl/src/cgenerator/gen_accessors_tagged_union.rs @@ -3,7 +3,7 @@ use super::*; pub fn generate( cgenerator: &mut CGenerator, data_type_entry: &DataTypeEntry<'_>, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &Cache, pretty_writer: &mut PrettyWriter, internal_union_type_id: usize, @@ -24,14 +24,14 @@ pub fn generate( .offset; let mut member_type_size = 0; if let Some(member_type) = member_type { - let type_info = cgenerator.type_info(data_description_helper, cache, member_type); + let type_info = cgenerator.type_info(module, cache, member_type); member_type_size = type_info.type_size; } let mut pretty_writer_i1 = pretty_writer.new_block(); let mut pretty_writer_preprocessor = pretty_writer.new_from_writer(); let member_macro_size_name = if let Some(member_type) = member_type { - let unaliased_member_type = cgenerator.unalias(data_description_helper, member_type); - macros::macro_for_data_type_ref(data_description_helper, "BYTES", unaliased_member_type) + let unaliased_member_type = cgenerator.unalias(module, member_type); + macros::macro_for_data_type_ref(module, "BYTES", unaliased_member_type) } else { CAtom::tagged_union_type().native_type_size.to_string() }; @@ -160,7 +160,7 @@ pub fn generate( let type_ = member_type.expect("Empty member"); let hierarchy1 = hierarchy.push(named_member.name.to_string(), first_member_offset); cgenerator.gen_accessors_for_data_type_ref( - data_description_helper, + module, cache, pretty_writer, type_, @@ -173,7 +173,7 @@ pub fn generate( let type_size = cached_type_entry.type_size; let union_macro_size_name = macros::macro_for("BYTES", &fn_name); let is_eventually_an_atom_or_enum = - cgenerator.is_type_eventually_an_atom_or_enum(data_description_helper, type_); + cgenerator.is_type_eventually_an_atom_or_enum(module, type_); pretty_writer .write_line( diff --git a/lucet-idl/src/cgenerator/gen_alias.rs b/lucet-idl/src/cgenerator/gen_alias.rs index 528749477..0cfd6fe35 100644 --- a/lucet-idl/src/cgenerator/gen_alias.rs +++ b/lucet-idl/src/cgenerator/gen_alias.rs @@ -4,7 +4,7 @@ use super::*; // and alignment rules of what it ultimately points to pub fn generate( cgenerator: &mut CGenerator, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -14,7 +14,7 @@ pub fn generate( } else { unreachable!() }; - let type_info = cgenerator.type_info(data_description_helper, cache, type_); + let type_info = cgenerator.type_info(module, cache, type_); pretty_writer.indent()?; pretty_writer.write(format!("typedef {}", type_info.type_name).as_bytes())?; pretty_writer.space()?; @@ -25,7 +25,7 @@ pub fn generate( pretty_writer.write(b";")?; if type_info.indirections == 0 { let leaf_type_info = - cgenerator.type_info(data_description_helper, cache, type_info.leaf_data_type_ref); + cgenerator.type_info(module, cache, type_info.leaf_data_type_ref); if leaf_type_info.type_name != type_info.type_name { pretty_writer.write(b" // equivalent to ")?; pretty_writer.write(leaf_type_info.type_name.as_bytes())?; diff --git a/lucet-idl/src/cgenerator/gen_enum.rs b/lucet-idl/src/cgenerator/gen_enum.rs index 5c763fa55..7fc78fd9c 100644 --- a/lucet-idl/src/cgenerator/gen_enum.rs +++ b/lucet-idl/src/cgenerator/gen_enum.rs @@ -4,7 +4,7 @@ use super::*; // The typedef is required to use a native type which is consistent across all architectures pub fn generate( cgenerator: &mut CGenerator, - _data_description_helper: &DataDescriptionHelper, + _module: &Module, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, diff --git a/lucet-idl/src/cgenerator/gen_struct.rs b/lucet-idl/src/cgenerator/gen_struct.rs index 9c876ab55..0f3a9b941 100644 --- a/lucet-idl/src/cgenerator/gen_struct.rs +++ b/lucet-idl/src/cgenerator/gen_struct.rs @@ -3,7 +3,7 @@ use std::cmp; pub fn generate( cgenerator: &mut CGenerator, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -23,7 +23,7 @@ pub fn generate( let mut first_member_align = 0; let mut members_offsets = vec![]; for named_member in named_members { - let type_info = cgenerator.type_info(data_description_helper, cache, &named_member.type_); + let type_info = cgenerator.type_info(module, cache, &named_member.type_); let type_align = type_info.type_align; let type_size = type_info.type_size; let padding = (type_align - 1) - ((offset + (type_align - 1)) % type_align); diff --git a/lucet-idl/src/cgenerator/gen_tagged_union.rs b/lucet-idl/src/cgenerator/gen_tagged_union.rs index 91cb40275..8a3f93c3c 100644 --- a/lucet-idl/src/cgenerator/gen_tagged_union.rs +++ b/lucet-idl/src/cgenerator/gen_tagged_union.rs @@ -2,7 +2,7 @@ use super::*; pub fn generate( cgenerator: &mut CGenerator, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -68,7 +68,7 @@ pub fn generate( let mut max_size = 0; for named_member in named_members { if let Some(type_) = named_member.type_.as_ref() { - let type_info = cgenerator.type_info(data_description_helper, cache, type_); + let type_info = cgenerator.type_info(module, cache, type_); if type_info.type_align > max_align { max_align = type_info.type_align; } @@ -108,7 +108,7 @@ pub fn generate( continue; } let type_ = named_member.type_.as_ref().unwrap(); - let type_info = cgenerator.type_info(data_description_helper, cache, type_); + let type_info = cgenerator.type_info(module, cache, type_); pretty_writer_i2.indent()?; pretty_writer_i2.write(type_info.type_name.as_bytes())?; pretty_writer_i2.space()?; diff --git a/lucet-idl/src/cgenerator/macros.rs b/lucet-idl/src/cgenerator/macros.rs index 151bba108..3d37b805d 100644 --- a/lucet-idl/src/cgenerator/macros.rs +++ b/lucet-idl/src/cgenerator/macros.rs @@ -39,7 +39,7 @@ pub fn define( // Return a macro name for a type reference pub fn macro_for_data_type_ref( - data_description_helper: &DataDescriptionHelper, + module: &Module, prefix: &str, data_type_ref: &DataTypeRef, ) -> String { @@ -50,7 +50,7 @@ pub fn macro_for_data_type_ref( } DataTypeRef::Ptr(_) => macro_for(prefix, "PTR"), DataTypeRef::Defined(data_type_id) => { - let data_type_entry = data_description_helper.get(*data_type_id); + let data_type_entry = module.get_datatype(*data_type_id); macro_for(prefix, &data_type_entry.name.name) } } diff --git a/lucet-idl/src/cgenerator/mod.rs b/lucet-idl/src/cgenerator/mod.rs index 04cd9be2b..d1ded8a35 100644 --- a/lucet-idl/src/cgenerator/mod.rs +++ b/lucet-idl/src/cgenerator/mod.rs @@ -18,13 +18,13 @@ mod macros; pub(crate) use self::catom::*; use crate::backend::*; use crate::cache::*; -use crate::data_description_helper::*; +use crate::module::*; use crate::errors::*; use crate::generators::*; use crate::pretty_writer::*; use crate::target::*; use crate::types::*; -use crate::validate::*; +use crate::module::{DataTypeRef, DataTypeEntry, Module}; use std::io::prelude::*; #[derive(Clone, Debug)] @@ -59,7 +59,7 @@ impl Generator for CGenerator { fn gen_type_header( &mut self, - _data_description_helper: &DataDescriptionHelper, + _module: &Module, _cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -77,14 +77,14 @@ impl Generator for CGenerator { // and alignment rules of what it ultimately points to fn gen_alias( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { gen_alias::generate( self, - data_description_helper, + module, cache, pretty_writer, data_type_entry, @@ -93,14 +93,14 @@ impl Generator for CGenerator { fn gen_struct( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { gen_struct::generate( self, - data_description_helper, + module, cache, pretty_writer, data_type_entry, @@ -111,14 +111,14 @@ impl Generator for CGenerator { // The typedef is required to use a native type which is consistent across all architectures fn gen_enum( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { gen_enum::generate( self, - data_description_helper, + module, cache, pretty_writer, data_type_entry, @@ -127,14 +127,14 @@ impl Generator for CGenerator { fn gen_tagged_union( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { gen_tagged_union::generate( self, - data_description_helper, + module, cache, pretty_writer, data_type_entry, @@ -143,7 +143,7 @@ impl Generator for CGenerator { fn gen_accessors_struct( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -151,7 +151,7 @@ impl Generator for CGenerator { ) -> Result<(), IDLError> { gen_accessors_struct::generate( self, - data_description_helper, + module, cache, pretty_writer, data_type_entry, @@ -161,7 +161,7 @@ impl Generator for CGenerator { fn gen_accessors_tagged_union( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -181,7 +181,7 @@ impl Generator for CGenerator { gen_accessors_tagged_union::generate( self, data_type_entry, - data_description_helper, + module, cache, pretty_writer, internal_union_type_id, @@ -194,7 +194,7 @@ impl Generator for CGenerator { fn gen_accessors_enum( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -202,7 +202,7 @@ impl Generator for CGenerator { ) -> Result<(), IDLError> { gen_accessors_enum::generate( self, - data_description_helper, + module, cache, pretty_writer, data_type_entry, @@ -212,7 +212,7 @@ impl Generator for CGenerator { fn gen_accessors_alias( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -220,7 +220,7 @@ impl Generator for CGenerator { ) -> Result<(), IDLError> { gen_accessors_alias::generate( self, - data_description_helper, + module, cache, pretty_writer, data_type_entry, @@ -235,7 +235,7 @@ impl CGenerator { /// for this data type fn type_info<'t>( &self, - data_description_helper: &'t DataDescriptionHelper, + module: &'t Module, cache: &Cache, mut type_: &'t DataTypeRef, ) -> CTypeInfo<'t> { @@ -265,7 +265,7 @@ impl CGenerator { type_align = type_align.or_else(|| Some(cached.type_align)); type_size = type_size.or_else(|| Some(cached.type_size)); } - let data_type_entry = data_description_helper.get(*data_type_id); + let data_type_entry = module.get_datatype(*data_type_id); match data_type_entry.data_type { DataType::Struct { .. } => { type_name = type_name @@ -286,7 +286,7 @@ impl CGenerator { DataType::Alias { to, .. } => { type_name = type_name.or_else(|| Some(data_type_entry.name.name.to_string())); - type_ = to; + type_ = &to; continue; } }; @@ -311,7 +311,7 @@ impl CGenerator { // Return `true` if the type is an atom, an emum, or an alias to one of these pub fn is_type_eventually_an_atom_or_enum( &self, - data_description_helper: &DataDescriptionHelper, + module: &Module, type_: &DataTypeRef, ) -> bool { let inner_type = match type_ { @@ -319,13 +319,13 @@ impl CGenerator { DataTypeRef::Ptr(_) => return false, DataTypeRef::Defined(inner_type) => inner_type, }; - let inner_data_type_entry = data_description_helper.get(*inner_type); + let inner_data_type_entry = module.get_datatype(*inner_type); let inner_data_type = inner_data_type_entry.data_type; match inner_data_type { DataType::Struct { .. } | DataType::TaggedUnion { .. } => false, DataType::Enum { .. } => true, DataType::Alias { to, .. } => { - self.is_type_eventually_an_atom_or_enum(data_description_helper, to) + self.is_type_eventually_an_atom_or_enum(module, to) } } } @@ -333,17 +333,17 @@ impl CGenerator { /// Return the type refererence, with aliases being resolved pub fn unalias<'t>( &self, - data_description_helper: &'t DataDescriptionHelper, + module: &'t Module, type_: &'t DataTypeRef, ) -> &'t DataTypeRef { let inner_type = match type_ { DataTypeRef::Atom(_) | DataTypeRef::Ptr(_) => return type_, DataTypeRef::Defined(inner_type) => inner_type, }; - let inner_data_type_entry = data_description_helper.get(*inner_type); + let inner_data_type_entry = module.get_datatype(*inner_type); let inner_data_type = inner_data_type_entry.data_type; if let DataType::Alias { to, .. } = inner_data_type { - self.unalias(data_description_helper, to) + self.unalias(module, to) } else { type_ } @@ -376,45 +376,34 @@ impl CGenerator { Ok(()) } - fn gen_accessors_for_id( - &mut self, - data_description_helper: &DataDescriptionHelper, - cache: &Cache, - pretty_writer: &mut PrettyWriter, - id: DataTypeId, - hierarchy: &Hierarchy, - ) -> Result<(), IDLError> { - data_description_helper.gen_accessors_for_id(self, cache, pretty_writer, id, hierarchy) - } - fn gen_accessors_for_data_type_ref( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &Cache, pretty_writer: &mut PrettyWriter, type_: &DataTypeRef, name: &str, hierarchy: &Hierarchy, ) -> Result<(), IDLError> { - let type_ = self.unalias(data_description_helper, type_); + let type_ = self.unalias(module, type_); match type_ { DataTypeRef::Atom(atom_type) => gen_accessors_atom::generate( self, - data_description_helper, + module, pretty_writer, *atom_type, &hierarchy, ), DataTypeRef::Ptr(type_) => gen_accessors_ptr::generate( self, - data_description_helper, + module, cache, pretty_writer, type_, &hierarchy, ), DataTypeRef::Defined(data_type_id) => self.gen_accessors_for_id( - data_description_helper, + module, cache, pretty_writer, *data_type_id, diff --git a/lucet-idl/src/data_description_helper.rs b/lucet-idl/src/data_description_helper.rs deleted file mode 100644 index 5c83ddaeb..000000000 --- a/lucet-idl/src/data_description_helper.rs +++ /dev/null @@ -1,171 +0,0 @@ -use crate::cache::*; -use crate::errors::*; -use crate::generators::*; -use crate::pretty_writer::*; -use crate::validate::*; -use std::io::prelude::*; - -/// A convenient structure holding a data type, its name and -/// its internal IDL representation -#[derive(Debug, Clone)] -pub struct DataTypeEntry<'t> { - pub id: DataTypeId, - pub name: &'t Name, - pub data_type: &'t DataType, -} - -/// Transforms a `DataDescription` -/// We definitely need a better name for it -#[derive(Debug, Clone)] -pub struct DataDescriptionHelper { - pub data_description: DataDescription, -} - -impl DataDescriptionHelper { - /// Retrieve information about a data type given its identifier - pub fn get(&self, id: DataTypeId) -> DataTypeEntry<'_> { - let name = &self.data_description.names[id.0]; - let data_type = &self.data_description.data_types[&id.0]; - DataTypeEntry { - id, - name, - data_type, - } - } - - /// Generate native code for a data type whose identifier is `id` - /// `Generator` is currently an alias for `CGenerator`, but will be turned into - /// a trait for dynamic dispatch when the first backend gets a reasonably stable API. - pub fn gen_for_id( - &self, - generator: &mut dyn Generator, - cache: &mut Cache, - pretty_writer: &mut PrettyWriter, - id: DataTypeId, - ) -> Result<(), IDLError> { - let data_type_entry = self.get(id); - self.gen_type_header(generator, cache, pretty_writer, &data_type_entry)?; - match &data_type_entry.data_type { - DataType::Struct { .. } => { - self.gen_struct(generator, cache, pretty_writer, &data_type_entry) - } - DataType::TaggedUnion { .. } => { - self.gen_tagged_union(generator, cache, pretty_writer, &data_type_entry) - } - DataType::Alias { .. } => { - self.gen_alias(generator, cache, pretty_writer, &data_type_entry) - } - DataType::Enum { .. } => { - self.gen_enum(generator, cache, pretty_writer, &data_type_entry) - } - }?; - self.gen_accessors_for_id( - generator, - cache, - pretty_writer, - id, - &Hierarchy::new(data_type_entry.name.name.to_string(), 0), - )?; - Ok(()) - } - - /// Generate a comment describing the type being defined right after - fn gen_type_header( - &self, - generator: &mut dyn Generator, - cache: &mut Cache, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - ) -> Result<(), IDLError> { - generator.gen_type_header(&self, cache, pretty_writer, data_type_entry)?; - Ok(()) - } - - fn gen_enum( - &self, - generator: &mut dyn Generator, - cache: &mut Cache, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - ) -> Result<(), IDLError> { - generator.gen_enum(&self, cache, pretty_writer, data_type_entry)?; - Ok(()) - } - - fn gen_struct( - &self, - generator: &mut dyn Generator, - cache: &mut Cache, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - ) -> Result<(), IDLError> { - generator.gen_struct(&self, cache, pretty_writer, data_type_entry)?; - Ok(()) - } - - fn gen_tagged_union( - &self, - generator: &mut dyn Generator, - cache: &mut Cache, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - ) -> Result<(), IDLError> { - generator.gen_tagged_union(&self, cache, pretty_writer, data_type_entry)?; - Ok(()) - } - - fn gen_alias( - &self, - generator: &mut dyn Generator, - cache: &mut Cache, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - ) -> Result<(), IDLError> { - generator.gen_alias(&self, cache, pretty_writer, data_type_entry)?; - Ok(()) - } - - /// Generate accessors for a data type whose identifier is `id` - /// `hierarchy` is used to derive function names from nested types - pub fn gen_accessors_for_id( - &self, - generator: &mut dyn Generator, - cache: &Cache, - pretty_writer: &mut PrettyWriter, - id: DataTypeId, - hierarchy: &Hierarchy, - ) -> Result<(), IDLError> { - let data_type_entry = self.get(id); - match &data_type_entry.data_type { - DataType::Struct { .. } => generator.gen_accessors_struct( - &self, - cache, - pretty_writer, - &data_type_entry, - hierarchy, - ), - DataType::TaggedUnion { .. } => generator.gen_accessors_tagged_union( - &self, - cache, - pretty_writer, - &data_type_entry, - hierarchy, - ), - DataType::Alias { .. } => generator.gen_accessors_alias( - &self, - cache, - pretty_writer, - &data_type_entry, - hierarchy, - ), - DataType::Enum { .. } => generator.gen_accessors_enum( - &self, - cache, - pretty_writer, - &data_type_entry, - hierarchy, - ), - }?; - Ok(()) - } -} diff --git a/lucet-idl/src/errors.rs b/lucet-idl/src/errors.rs index 1a917017b..a6475f940 100644 --- a/lucet-idl/src/errors.rs +++ b/lucet-idl/src/errors.rs @@ -1,4 +1,4 @@ -use crate::{parser, validate}; +use crate::{parser, module}; use std::io; #[allow(dead_code)] @@ -11,7 +11,7 @@ pub enum IDLError { #[fail(display = "{}", _0)] ParseError(#[cause] parser::ParseError), #[fail(display = "{}", _0)] - ValidationError(#[cause] validate::ValidationError), + ValidationError(#[cause] module::ValidationError), #[fail(display = "{}", _0)] Io(#[cause] io::Error), } @@ -28,8 +28,8 @@ impl From for IDLError { } } -impl From for IDLError { - fn from(e: validate::ValidationError) -> Self { +impl From for IDLError { + fn from(e: module::ValidationError) -> Self { IDLError::ValidationError(e) } } diff --git a/lucet-idl/src/generators/generator.rs b/lucet-idl/src/generators/generator.rs index bd21588fe..c2a2c8329 100644 --- a/lucet-idl/src/generators/generator.rs +++ b/lucet-idl/src/generators/generator.rs @@ -1,11 +1,11 @@ -use super::super::cache::*; -use super::super::cgenerator::*; -use super::super::config::*; -use super::super::data_description_helper::*; -use super::super::errors::*; -use super::super::pretty_writer::*; -use super::super::rustgenerator::*; -use super::hierarchy::*; +use crate::cache::Cache; +use crate::config::Config; +use crate::errors::IDLError; +use crate::pretty_writer::PrettyWriter; +use crate::rustgenerator::RustGenerator; +use crate::cgenerator::CGenerator; +use crate::module::{DataTypeEntry, DataType, DataTypeId, Module}; +use crate::generators::hierarchy::Hierarchy; use std::io::prelude::*; pub trait Generator { @@ -13,7 +13,7 @@ pub trait Generator { fn gen_type_header( &mut self, - _data_description_helper: &DataDescriptionHelper, + module: &Module, _cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -21,7 +21,7 @@ pub trait Generator { fn gen_alias( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -29,7 +29,7 @@ pub trait Generator { fn gen_struct( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -37,7 +37,7 @@ pub trait Generator { fn gen_enum( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -45,7 +45,7 @@ pub trait Generator { fn gen_tagged_union( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -53,7 +53,7 @@ pub trait Generator { fn gen_accessors_struct( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -62,7 +62,7 @@ pub trait Generator { fn gen_accessors_tagged_union( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -71,7 +71,7 @@ pub trait Generator { fn gen_accessors_enum( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -80,12 +80,75 @@ pub trait Generator { fn gen_accessors_alias( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, hierarchy: &Hierarchy, ) -> Result<(), IDLError>; + + fn gen_for_id( + &mut self, + module: &Module, + cache: &mut Cache, + pretty_writer: &mut PrettyWriter, + id: DataTypeId, + ) -> Result<(), IDLError> { + let data_type_entry = module.get_datatype(id); + self.gen_type_header(module, cache, pretty_writer, &data_type_entry)?; + match &data_type_entry.data_type { + DataType::Struct { .. } => { + self.gen_struct(module, cache, pretty_writer, &data_type_entry) + } + DataType::TaggedUnion { .. } => { + self.gen_tagged_union(module, cache, pretty_writer, &data_type_entry) + } + DataType::Alias { .. } => { + self.gen_alias(module, cache, pretty_writer, &data_type_entry) + } + DataType::Enum { .. } => self.gen_enum(module, cache, pretty_writer, &data_type_entry), + }?; + self.gen_accessors_for_id( + module, + cache, + pretty_writer, + id, + &Hierarchy::new(data_type_entry.name.name.to_string(), 0), + )?; + Ok(()) + } + + /// Generate accessors for a data type whose identifier is `id` + /// `hierarchy` is used to derive function names from nested types + fn gen_accessors_for_id( + &mut self, + module: &Module, + cache: &Cache, + pretty_writer: &mut PrettyWriter, + id: DataTypeId, + hierarchy: &Hierarchy, + ) -> Result<(), IDLError> { + let data_type_entry = module.get_datatype(id); + match &data_type_entry.data_type { + DataType::Struct { .. } => { + self.gen_accessors_struct(module, cache, pretty_writer, &data_type_entry, hierarchy) + } + DataType::TaggedUnion { .. } => self.gen_accessors_tagged_union( + module, + cache, + pretty_writer, + &data_type_entry, + hierarchy, + ), + DataType::Alias { .. } => { + self.gen_accessors_alias(module, cache, pretty_writer, &data_type_entry, hierarchy) + } + DataType::Enum { .. } => { + self.gen_accessors_enum(module, cache, pretty_writer, &data_type_entry, hierarchy) + } + }?; + Ok(()) + } } pub struct Generators; diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 27ae5ea99..a673895c2 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -4,12 +4,11 @@ extern crate failure; mod lexer; mod parser; mod types; -mod validate; +mod module; mod backend; mod cache; mod cgenerator; mod config; -mod data_description_helper; mod errors; mod generators; mod pretty_writer; @@ -22,22 +21,20 @@ pub use crate::target::Target; pub use crate::errors::IDLError; use crate::parser::Parser; -use crate::data_description_helper::DataDescriptionHelper; use crate::cache::Cache; use crate::generators::{Generators, Generator}; use crate::pretty_writer::PrettyWriter; -use crate::validate::DataDescription; +use crate::module::Module; use std::io::Write; pub fn run(config: &Config, input: &str, output: W) -> Result<(), IDLError> { let mut parser = Parser::new(&input); let decls = parser.match_decls()?; - let data_description = DataDescription::validate(&decls)?; - let deps = data_description + let module = Module::from_declarations(&decls)?; + let deps = module .ordered_dependencies() .map_err(|_| IDLError::InternalError("Unable to resolve dependencies"))?; - let data_description_helper = DataDescriptionHelper { data_description }; let mut cache = Cache::default(); let mut generator = Generators::c(config); @@ -45,7 +42,7 @@ pub fn run(config: &Config, input: &str, output: W) -> Result<(), IDLE let mut pretty_writer = PrettyWriter::new(output); generator.gen_prelude(&mut pretty_writer)?; for id in deps { - data_description_helper.gen_for_id(&mut generator, &mut cache, &mut pretty_writer, id)?; + generator.gen_for_id(&module, &mut cache, &mut pretty_writer, id)?; } Ok(()) } diff --git a/lucet-idl/src/validate.rs b/lucet-idl/src/module.rs similarity index 86% rename from lucet-idl/src/validate.rs rename to lucet-idl/src/module.rs index 3947175fd..6ceb5eaf4 100644 --- a/lucet-idl/src/validate.rs +++ b/lucet-idl/src/module.rs @@ -59,8 +59,9 @@ impl fmt::Display for Name { } } + #[derive(Debug, PartialEq, Eq, Clone)] -pub struct DataDescription { +pub struct Module { pub names: Vec, pub data_types: HashMap, } @@ -113,13 +114,22 @@ impl fmt::Display for ValidationError { } } +/// A convenient structure holding a data type, its name and +/// its internal IDL representation +#[derive(Debug, Clone)] +pub struct DataTypeEntry<'t> { + pub id: DataTypeId, + pub name: &'t Name, + pub data_type: &'t DataType, +} + impl Error for ValidationError { fn description(&self) -> &str { "Validation error" } } -impl DataDescription { +impl Module { fn new() -> Self { Self { names: Vec::new(), @@ -386,7 +396,7 @@ impl DataDescription { }) } - pub fn validate(decls: &[SyntaxDecl]) -> Result { + pub fn from_declarations(decls: &[SyntaxDecl]) -> Result { let mut desc = Self::new(); let mut idents: Vec = Vec::new(); for decl in decls { @@ -403,6 +413,18 @@ impl DataDescription { Ok(desc) } + + /// Retrieve information about a data type given its identifier + pub fn get_datatype(&self, id: DataTypeId) -> DataTypeEntry<'_> { + let name = &self.names[id.0]; + let data_type = &self.data_types[&id.0]; + DataTypeEntry { + id, + name, + data_type, + } + } + } #[cfg(test)] @@ -410,19 +432,19 @@ mod tests { use super::super::parser::Parser; use super::*; - fn data_description(syntax: &str) -> Result { + fn module(syntax: &str) -> Result { let mut parser = Parser::new(syntax); let decls = parser.match_decls().expect("parses"); - DataDescription::validate(&decls) + Module::from_declarations(&decls) } #[test] fn structs() { - assert!(data_description("struct foo { a: i32}").is_ok()); - assert!(data_description("struct foo { a: i32, b: f32 }").is_ok()); + assert!(module("struct foo { a: i32}").is_ok()); + assert!(module("struct foo { a: i32, b: f32 }").is_ok()); { - let d = data_description("struct foo { a: i32, b: f32 }").unwrap(); + let d = module("struct foo { a: i32, b: f32 }").unwrap(); let members = match &d.data_types[&0] { DataType::Struct { members, .. } => members, _ => panic!("Unexpected type"), @@ -440,16 +462,16 @@ mod tests { } // Refer to a struct defined previously: - assert!(data_description("struct foo { a: i32, b: f64 } struct bar { a: foo }").is_ok()); + assert!(module("struct foo { a: i32, b: f64 } struct bar { a: foo }").is_ok()); // Refer to a struct defined afterwards: - assert!(data_description("struct foo { a: i32, b: bar} struct bar { a: i32 }").is_ok()); + assert!(module("struct foo { a: i32, b: bar} struct bar { a: i32 }").is_ok()); // Refer to itself - assert!(data_description("struct list { next: *list, thing: i32 }").is_ok()); + assert!(module("struct list { next: *list, thing: i32 }").is_ok()); // No members assert_eq!( - data_description("struct foo {}").err().unwrap(), + module("struct foo {}").err().unwrap(), ValidationError::Empty { name: "foo".to_owned(), location: Location { line: 1, column: 0 }, @@ -458,7 +480,7 @@ mod tests { // Duplicate member in struct assert_eq!( - data_description("struct foo { \na: i32, \na: f64}") + module("struct foo { \na: i32, \na: f64}") .err() .unwrap(), ValidationError::NameAlreadyExists { @@ -470,7 +492,7 @@ mod tests { // Duplicate definition of struct assert_eq!( - data_description("struct foo { a: i32 }\nstruct foo { a: i32 } ") + module("struct foo { a: i32 }\nstruct foo { a: i32 } ") .err() .unwrap(), ValidationError::NameAlreadyExists { @@ -482,7 +504,7 @@ mod tests { // Refer to type that is not declared assert_eq!( - data_description("struct foo { \nb: bar }").err().unwrap(), + module("struct foo { \nb: bar }").err().unwrap(), ValidationError::NameNotFound { name: "bar".to_owned(), use_location: Location { line: 2, column: 3 }, @@ -492,13 +514,13 @@ mod tests { #[test] fn tagged_unions() { - assert!(data_description("taggedunion foo { a: () }").is_ok()); - assert!(data_description("taggedunion foo { a: i32 }").is_ok()); - assert!(data_description("taggedunion foo { a: i32, b: f32 }").is_ok()); - assert!(data_description("taggedunion foo { a: i32, b: () }").is_ok()); + assert!(module("taggedunion foo { a: () }").is_ok()); + assert!(module("taggedunion foo { a: i32 }").is_ok()); + assert!(module("taggedunion foo { a: i32, b: f32 }").is_ok()); + assert!(module("taggedunion foo { a: i32, b: () }").is_ok()); { - let d = data_description("taggedunion foo { a: i32, b: () }").unwrap(); + let d = module("taggedunion foo { a: i32, b: () }").unwrap(); let members = match &d.data_types[&0] { DataType::TaggedUnion { members, .. } => members, _ => panic!("Unexpected type"), @@ -516,22 +538,22 @@ mod tests { } // Recursive - assert!(data_description("taggedunion cons { succ: *cons, nil: () }").is_ok()); + assert!(module("taggedunion cons { succ: *cons, nil: () }").is_ok()); // Refer to a taggedunion defined previously: assert!( - data_description("taggedunion foo { a: i32, b: f64 } taggedunion bar { a: foo }") + module("taggedunion foo { a: i32, b: f64 } taggedunion bar { a: foo }") .is_ok() ); // Refer to a taggedunion defined afterwards: assert!( - data_description("taggedunion foo { a: i32, b: bar} taggedunion bar { a: i32 }") + module("taggedunion foo { a: i32, b: bar} taggedunion bar { a: i32 }") .is_ok() ); // No members assert_eq!( - data_description("taggedunion foo {}").err().unwrap(), + module("taggedunion foo {}").err().unwrap(), ValidationError::Empty { name: "foo".to_owned(), location: Location { line: 1, column: 0 }, @@ -540,7 +562,7 @@ mod tests { // Duplicate member in taggedunion assert_eq!( - data_description("taggedunion foo { \na: i32, \na: f64}") + module("taggedunion foo { \na: i32, \na: f64}") .err() .unwrap(), ValidationError::NameAlreadyExists { @@ -552,7 +574,7 @@ mod tests { // Duplicate definition of name "foo" assert_eq!( - data_description("taggedunion foo { a: i32 }\nstruct foo { a: i32 } ") + module("taggedunion foo { a: i32 }\nstruct foo { a: i32 } ") .err() .unwrap(), ValidationError::NameAlreadyExists { @@ -564,7 +586,7 @@ mod tests { // Refer to type that is not declared assert_eq!( - data_description("taggedunion foo { \nb: bar }") + module("taggedunion foo { \nb: bar }") .err() .unwrap(), ValidationError::NameNotFound { @@ -576,11 +598,11 @@ mod tests { #[test] fn enums() { - assert!(data_description("enum foo { a }").is_ok()); - assert!(data_description("enum foo { a, b }").is_ok()); + assert!(module("enum foo { a }").is_ok()); + assert!(module("enum foo { a, b }").is_ok()); { - let d = data_description("enum foo { a, b }").unwrap(); + let d = module("enum foo { a, b }").unwrap(); let members = match &d.data_types[&0] { DataType::Enum { members, .. } => members, _ => panic!("Unexpected type"), @@ -591,7 +613,7 @@ mod tests { // No members assert_eq!( - data_description("enum foo {}").err().unwrap(), + module("enum foo {}").err().unwrap(), ValidationError::Empty { name: "foo".to_owned(), location: Location { line: 1, column: 0 }, @@ -600,7 +622,7 @@ mod tests { // Duplicate member in enum assert_eq!( - data_description("enum foo { \na,\na }").err().unwrap(), + module("enum foo { \na,\na }").err().unwrap(), ValidationError::NameAlreadyExists { name: "a".to_owned(), at_location: Location { line: 3, column: 0 }, @@ -610,7 +632,7 @@ mod tests { // Duplicate definition of enum assert_eq!( - data_description("enum foo { a }\nenum foo { a } ") + module("enum foo { a }\nenum foo { a } ") .err() .unwrap(), ValidationError::NameAlreadyExists { @@ -623,21 +645,21 @@ mod tests { #[test] fn aliases() { - assert!(data_description("type foo = i32").is_ok()); - assert!(data_description("type foo = *f64").is_ok()); - assert!(data_description("type foo = ************f64").is_ok()); + assert!(module("type foo = i32").is_ok()); + assert!(module("type foo = *f64").is_ok()); + assert!(module("type foo = ************f64").is_ok()); - assert!(data_description("type foo = *bar\nenum bar { a }").is_ok()); + assert!(module("type foo = *bar\nenum bar { a }").is_ok()); assert!( - data_description("type link = *list\nstruct list { next: link, thing: i32 }").is_ok() + module("type link = *list\nstruct list { next: link, thing: i32 }").is_ok() ); } #[test] fn infinite() { assert_eq!( - data_description("type foo = bar\ntype bar = foo") + module("type foo = bar\ntype bar = foo") .err() .unwrap(), ValidationError::Infinite { @@ -647,7 +669,7 @@ mod tests { ); assert_eq!( - data_description("type foo = bar\nstruct bar { a: foo }") + module("type foo = bar\nstruct bar { a: foo }") .err() .unwrap(), ValidationError::Infinite { @@ -657,7 +679,7 @@ mod tests { ); assert_eq!( - data_description( + module( "type foo = bar\nstruct bar { a: baz }\ntaggedunion baz { c: i32, e: foo }" ) .err() diff --git a/lucet-idl/src/rustgenerator/mod.rs b/lucet-idl/src/rustgenerator/mod.rs index ddc6242d5..6409f14b2 100644 --- a/lucet-idl/src/rustgenerator/mod.rs +++ b/lucet-idl/src/rustgenerator/mod.rs @@ -3,12 +3,11 @@ use crate::backend::*; use crate::cache::*; -use crate::data_description_helper::*; use crate::errors::*; use crate::generators::*; use crate::pretty_writer::*; use crate::target::*; -use crate::validate::*; +use crate::module::{Module, DataTypeEntry, DataTypeRef}; use std::io::prelude::*; #[derive(Clone, Debug)] @@ -38,7 +37,7 @@ impl Generator for RustGenerator { fn gen_type_header( &mut self, - _data_description_helper: &DataDescriptionHelper, + _module: &Module, _cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -50,7 +49,7 @@ impl Generator for RustGenerator { // and alignment rules of what it ultimately points to fn gen_alias( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -60,7 +59,7 @@ impl Generator for RustGenerator { fn gen_struct( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -72,7 +71,7 @@ impl Generator for RustGenerator { // The typedef is required to use a native type which is consistent across all architectures fn gen_enum( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -82,7 +81,7 @@ impl Generator for RustGenerator { fn gen_tagged_union( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -92,7 +91,7 @@ impl Generator for RustGenerator { fn gen_accessors_struct( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -103,7 +102,7 @@ impl Generator for RustGenerator { fn gen_accessors_tagged_union( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -114,7 +113,7 @@ impl Generator for RustGenerator { fn gen_accessors_enum( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -125,7 +124,7 @@ impl Generator for RustGenerator { fn gen_accessors_alias( &mut self, - data_description_helper: &DataDescriptionHelper, + module: &Module, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, From e426024bee3d7720f0759f5a99867f5f44d2a7e4 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 25 Apr 2019 17:36:38 -0700 Subject: [PATCH 098/512] lucet-idl: simplify generators/backends module --- lucet-idl/src/backend.rs | 2 + lucet-idl/src/cgenerator/mod.rs | 2 +- lucet-idl/src/config.rs | 20 +++++ lucet-idl/src/{generators => }/generator.rs | 86 +++++++++++++++++---- lucet-idl/src/generators/hierarchy.rs | 76 ------------------ lucet-idl/src/generators/mod.rs | 5 -- lucet-idl/src/lib.rs | 5 +- lucet-idl/src/rustgenerator/mod.rs | 2 +- 8 files changed, 96 insertions(+), 102 deletions(-) rename lucet-idl/src/{generators => }/generator.rs (74%) delete mode 100644 lucet-idl/src/generators/hierarchy.rs delete mode 100644 lucet-idl/src/generators/mod.rs diff --git a/lucet-idl/src/backend.rs b/lucet-idl/src/backend.rs index 4313fb59a..e5b6fe214 100644 --- a/lucet-idl/src/backend.rs +++ b/lucet-idl/src/backend.rs @@ -1,6 +1,7 @@ #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum Backend { C, + Rust, } impl Default for Backend { @@ -13,6 +14,7 @@ impl> From for Backend { fn from(s: T) -> Self { match s.as_ref() { "c" => Backend::C, + "rust" => Backend::Rust, _ => Backend::default(), } } diff --git a/lucet-idl/src/cgenerator/mod.rs b/lucet-idl/src/cgenerator/mod.rs index d1ded8a35..5efc597fc 100644 --- a/lucet-idl/src/cgenerator/mod.rs +++ b/lucet-idl/src/cgenerator/mod.rs @@ -20,7 +20,7 @@ use crate::backend::*; use crate::cache::*; use crate::module::*; use crate::errors::*; -use crate::generators::*; +use crate::generator::{Generator, Hierarchy}; use crate::pretty_writer::*; use crate::target::*; use crate::types::*; diff --git a/lucet-idl/src/config.rs b/lucet-idl/src/config.rs index f902257d7..62e2ff019 100644 --- a/lucet-idl/src/config.rs +++ b/lucet-idl/src/config.rs @@ -1,5 +1,9 @@ use super::backend::{Backend, BackendConfig}; use super::target::Target; +use crate::generator::Generator; +use crate::rustgenerator::RustGenerator; +use crate::cgenerator::CGenerator; +use std::io::Write; #[derive(Default, Clone, Debug)] pub struct Config { @@ -24,4 +28,20 @@ impl Config { backend_config, } } + + pub fn generator(&self) -> Box> { + match self.backend { + Backend::C => Box::new(CGenerator { + target: self.target, + backend_config: self.backend_config, + }), + + Backend::Rust => Box::new(RustGenerator { + target: self.target, + backend_config: self.backend_config, + }) + } + } } + + diff --git a/lucet-idl/src/generators/generator.rs b/lucet-idl/src/generator.rs similarity index 74% rename from lucet-idl/src/generators/generator.rs rename to lucet-idl/src/generator.rs index c2a2c8329..683fe391f 100644 --- a/lucet-idl/src/generators/generator.rs +++ b/lucet-idl/src/generator.rs @@ -1,12 +1,9 @@ use crate::cache::Cache; -use crate::config::Config; use crate::errors::IDLError; use crate::pretty_writer::PrettyWriter; -use crate::rustgenerator::RustGenerator; -use crate::cgenerator::CGenerator; use crate::module::{DataTypeEntry, DataType, DataTypeId, Module}; -use crate::generators::hierarchy::Hierarchy; -use std::io::prelude::*; +use std::io::Write; +use std::rc::Rc; pub trait Generator { fn gen_prelude(&mut self, pretty_writer: &mut PrettyWriter) -> Result<(), IDLError>; @@ -151,21 +148,78 @@ pub trait Generator { } } -pub struct Generators; -impl Generators { - pub fn c(config: &Config) -> CGenerator { - CGenerator { - target: config.target, - backend_config: config.backend_config, +#[derive(Debug, Clone)] +pub struct HierarchyEntry { + name: Rc, + offset: usize, +} + +impl HierarchyEntry { + pub fn new(name: String, offset: usize) -> Self { + HierarchyEntry { + name: Rc::new(name), + offset, } } +} + +#[derive(Debug, Clone)] +pub struct Hierarchy(Vec); + +impl Hierarchy { + pub fn new(name: String, offset: usize) -> Self { + Hierarchy(vec![HierarchyEntry::new(name, offset)]) + } + + pub fn push(&self, name: String, offset: usize) -> Self { + let mut cloned = self.clone(); + cloned.0.push(HierarchyEntry::new(name, offset)); + cloned + } + + pub fn depth(&self) -> usize { + self.0.len() + } + + pub fn idl_name(&self) -> String { + self.0 + .iter() + .map(|x| x.name.as_str()) + .collect::>() + .join(".") + } + + pub fn fn_name(&self) -> String { + self.0 + .iter() + .map(|x| x.name.as_str()) + .collect::>() + .join("_") + } #[allow(dead_code)] - pub fn rust(config: &Config) -> RustGenerator { - RustGenerator { - target: config.target, - backend_config: config.backend_config, - } + pub fn parent_name(&self) -> String { + let len = self.0.len(); + assert!(len > 1); + self.0 + .iter() + .take(len - 1) + .map(|x| x.name.as_str()) + .collect::>() + .join("_") + } + + pub fn root_name(&self) -> String { + self.0 + .iter() + .take(1) + .map(|x| x.name.as_str()) + .collect::>() + .join("_") + } + + pub fn current_offset(&self) -> usize { + self.0.last().expect("Empty hierarchy").offset } } diff --git a/lucet-idl/src/generators/hierarchy.rs b/lucet-idl/src/generators/hierarchy.rs deleted file mode 100644 index e92b76369..000000000 --- a/lucet-idl/src/generators/hierarchy.rs +++ /dev/null @@ -1,76 +0,0 @@ -use std::rc::Rc; - -#[derive(Debug, Clone)] -pub struct HierarchyEntry { - name: Rc, - offset: usize, -} - -impl HierarchyEntry { - pub fn new(name: String, offset: usize) -> Self { - HierarchyEntry { - name: Rc::new(name), - offset, - } - } -} - -#[derive(Debug, Clone)] -pub struct Hierarchy(Vec); - -impl Hierarchy { - pub fn new(name: String, offset: usize) -> Self { - Hierarchy(vec![HierarchyEntry::new(name, offset)]) - } - - pub fn push(&self, name: String, offset: usize) -> Self { - let mut cloned = self.clone(); - cloned.0.push(HierarchyEntry::new(name, offset)); - cloned - } - - pub fn depth(&self) -> usize { - self.0.len() - } - - pub fn idl_name(&self) -> String { - self.0 - .iter() - .map(|x| x.name.as_str()) - .collect::>() - .join(".") - } - - pub fn fn_name(&self) -> String { - self.0 - .iter() - .map(|x| x.name.as_str()) - .collect::>() - .join("_") - } - - #[allow(dead_code)] - pub fn parent_name(&self) -> String { - let len = self.0.len(); - assert!(len > 1); - self.0 - .iter() - .take(len - 1) - .map(|x| x.name.as_str()) - .collect::>() - .join("_") - } - - pub fn root_name(&self) -> String { - self.0 - .iter() - .take(1) - .map(|x| x.name.as_str()) - .collect::>() - .join("_") - } - - pub fn current_offset(&self) -> usize { - self.0.last().expect("Empty hierarchy").offset - } -} diff --git a/lucet-idl/src/generators/mod.rs b/lucet-idl/src/generators/mod.rs deleted file mode 100644 index bfb9345ef..000000000 --- a/lucet-idl/src/generators/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod generator; -mod hierarchy; - -pub use generator::*; -pub use hierarchy::*; diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index a673895c2..11c62bc4a 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -10,7 +10,7 @@ mod cache; mod cgenerator; mod config; mod errors; -mod generators; +mod generator; mod pretty_writer; mod rustgenerator; mod target; @@ -22,7 +22,6 @@ pub use crate::errors::IDLError; use crate::parser::Parser; use crate::cache::Cache; -use crate::generators::{Generators, Generator}; use crate::pretty_writer::PrettyWriter; use crate::module::Module; use std::io::Write; @@ -37,7 +36,7 @@ pub fn run(config: &Config, input: &str, output: W) -> Result<(), IDLE .map_err(|_| IDLError::InternalError("Unable to resolve dependencies"))?; let mut cache = Cache::default(); - let mut generator = Generators::c(config); + let mut generator = config.generator(); let mut pretty_writer = PrettyWriter::new(output); generator.gen_prelude(&mut pretty_writer)?; diff --git a/lucet-idl/src/rustgenerator/mod.rs b/lucet-idl/src/rustgenerator/mod.rs index 6409f14b2..1c4b7aea1 100644 --- a/lucet-idl/src/rustgenerator/mod.rs +++ b/lucet-idl/src/rustgenerator/mod.rs @@ -4,7 +4,7 @@ use crate::backend::*; use crate::cache::*; use crate::errors::*; -use crate::generators::*; +use crate::generator::{Generator, Hierarchy}; use crate::pretty_writer::*; use crate::target::*; use crate::module::{Module, DataTypeEntry, DataTypeRef}; From 6ff8753ce2cd1c69057bbb245a9583814744728d Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 25 Apr 2019 17:53:35 -0700 Subject: [PATCH 099/512] c codegen: shorten names, reorganize, explicit imports --- .../accessors/alias.rs} | 8 +++- .../accessors/atom.rs} | 10 ++++- .../accessors/enum.rs} | 10 ++++- lucet-idl/src/c/accessors/mod.rs | 6 +++ .../accessors/ptr.rs} | 11 +++-- .../accessors/struct.rs} | 9 ++++- .../accessors/tagged_union.rs} | 10 ++++- .../{cgenerator/gen_alias.rs => c/alias.rs} | 0 lucet-idl/src/{cgenerator => c}/catom.rs | 0 .../src/{cgenerator/gen_enum.rs => c/enum.rs} | 0 lucet-idl/src/{cgenerator => c}/macros.rs | 0 lucet-idl/src/{cgenerator => c}/mod.rs | 40 ++++++++----------- .../gen_prelude.rs => c/prelude.rs} | 0 .../{cgenerator/gen_struct.rs => c/struct.rs} | 0 .../gen_tagged_union.rs => c/tagged_union.rs} | 0 lucet-idl/src/config.rs | 4 +- lucet-idl/src/lib.rs | 4 +- lucet-idl/src/{rustgenerator => rust}/mod.rs | 0 18 files changed, 77 insertions(+), 35 deletions(-) rename lucet-idl/src/{cgenerator/gen_accessors_alias.rs => c/accessors/alias.rs} (83%) rename lucet-idl/src/{cgenerator/gen_accessors_atom.rs => c/accessors/atom.rs} (93%) rename lucet-idl/src/{cgenerator/gen_accessors_enum.rs => c/accessors/enum.rs} (94%) create mode 100644 lucet-idl/src/c/accessors/mod.rs rename lucet-idl/src/{cgenerator/gen_accessors_ptr.rs => c/accessors/ptr.rs} (82%) rename lucet-idl/src/{cgenerator/gen_accessors_struct.rs => c/accessors/struct.rs} (96%) rename lucet-idl/src/{cgenerator/gen_accessors_tagged_union.rs => c/accessors/tagged_union.rs} (96%) rename lucet-idl/src/{cgenerator/gen_alias.rs => c/alias.rs} (100%) rename lucet-idl/src/{cgenerator => c}/catom.rs (100%) rename lucet-idl/src/{cgenerator/gen_enum.rs => c/enum.rs} (100%) rename lucet-idl/src/{cgenerator => c}/macros.rs (100%) rename lucet-idl/src/{cgenerator => c}/mod.rs (94%) rename lucet-idl/src/{cgenerator/gen_prelude.rs => c/prelude.rs} (100%) rename lucet-idl/src/{cgenerator/gen_struct.rs => c/struct.rs} (100%) rename lucet-idl/src/{cgenerator/gen_tagged_union.rs => c/tagged_union.rs} (100%) rename lucet-idl/src/{rustgenerator => rust}/mod.rs (100%) diff --git a/lucet-idl/src/cgenerator/gen_accessors_alias.rs b/lucet-idl/src/c/accessors/alias.rs similarity index 83% rename from lucet-idl/src/cgenerator/gen_accessors_alias.rs rename to lucet-idl/src/c/accessors/alias.rs index 5c585ec3f..9ce16d82a 100644 --- a/lucet-idl/src/cgenerator/gen_accessors_alias.rs +++ b/lucet-idl/src/c/accessors/alias.rs @@ -1,4 +1,10 @@ -use super::*; +use crate::c::CGenerator; +use crate::module::{Module, DataTypeEntry, DataType}; +use crate::cache::Cache; +use crate::pretty_writer::PrettyWriter; +use crate::generator::Hierarchy; +use crate::errors::IDLError; +use std::io::prelude::*; pub fn generate( cgenerator: &mut CGenerator, diff --git a/lucet-idl/src/cgenerator/gen_accessors_atom.rs b/lucet-idl/src/c/accessors/atom.rs similarity index 93% rename from lucet-idl/src/cgenerator/gen_accessors_atom.rs rename to lucet-idl/src/c/accessors/atom.rs index 4adb0f8ab..d6e53958d 100644 --- a/lucet-idl/src/cgenerator/gen_accessors_atom.rs +++ b/lucet-idl/src/c/accessors/atom.rs @@ -1,4 +1,12 @@ -use super::*; +use crate::c::catom::CAtom; +use crate::c::macros; +use crate::c::CGenerator; +use crate::errors::IDLError; +use crate::generator::Hierarchy; +use crate::module::Module; +use crate::pretty_writer::PrettyWriter; +use crate::types::AtomType; +use std::io::prelude::*; pub fn generate( cgenerator: &mut CGenerator, diff --git a/lucet-idl/src/cgenerator/gen_accessors_enum.rs b/lucet-idl/src/c/accessors/enum.rs similarity index 94% rename from lucet-idl/src/cgenerator/gen_accessors_enum.rs rename to lucet-idl/src/c/accessors/enum.rs index 561c3cb4c..fc6c8ab67 100644 --- a/lucet-idl/src/cgenerator/gen_accessors_enum.rs +++ b/lucet-idl/src/c/accessors/enum.rs @@ -1,4 +1,12 @@ -use super::*; +use crate::c::CGenerator; +use crate::c::catom::CAtom; +use crate::c::macros; +use crate::module::{Module, DataTypeEntry, DataType}; +use crate::cache::Cache; +use crate::pretty_writer::PrettyWriter; +use crate::generator::Hierarchy; +use crate::errors::IDLError; +use std::io::prelude::*; pub fn generate( cgenerator: &mut CGenerator, diff --git a/lucet-idl/src/c/accessors/mod.rs b/lucet-idl/src/c/accessors/mod.rs new file mode 100644 index 000000000..6c87bc922 --- /dev/null +++ b/lucet-idl/src/c/accessors/mod.rs @@ -0,0 +1,6 @@ +pub mod alias; +pub mod atom; +pub mod r#enum; +pub mod ptr; +pub mod r#struct; +pub mod tagged_union; diff --git a/lucet-idl/src/cgenerator/gen_accessors_ptr.rs b/lucet-idl/src/c/accessors/ptr.rs similarity index 82% rename from lucet-idl/src/cgenerator/gen_accessors_ptr.rs rename to lucet-idl/src/c/accessors/ptr.rs index f6f33acb5..f89caf2cf 100644 --- a/lucet-idl/src/cgenerator/gen_accessors_ptr.rs +++ b/lucet-idl/src/c/accessors/ptr.rs @@ -1,4 +1,10 @@ -use super::*; +use crate::c::CGenerator; +use crate::cache::Cache; +use crate::errors::IDLError; +use crate::generator::Hierarchy; +use crate::module::{Module, DataTypeRef}; +use crate::pretty_writer::PrettyWriter; +use std::io::prelude::*; pub fn generate( cgenerator: &mut CGenerator, @@ -9,8 +15,7 @@ pub fn generate( hierarchy: &Hierarchy, ) -> Result<(), IDLError> { let type_info = cgenerator.type_info(module, cache, type_); - let leaf_type_info = - cgenerator.type_info(module, cache, type_info.leaf_data_type_ref); + let leaf_type_info = cgenerator.type_info(module, cache, type_info.leaf_data_type_ref); assert_eq!(leaf_type_info.indirections, 0); if type_info.indirections > 1 { pretty_writer.write_line( diff --git a/lucet-idl/src/cgenerator/gen_accessors_struct.rs b/lucet-idl/src/c/accessors/struct.rs similarity index 96% rename from lucet-idl/src/cgenerator/gen_accessors_struct.rs rename to lucet-idl/src/c/accessors/struct.rs index da5836556..88d5798e9 100644 --- a/lucet-idl/src/cgenerator/gen_accessors_struct.rs +++ b/lucet-idl/src/c/accessors/struct.rs @@ -1,4 +1,11 @@ -use super::*; +use crate::c::CGenerator; +use crate::c::macros; +use crate::module::{Module, DataTypeEntry, DataTypeRef, DataType}; +use crate::cache::Cache; +use crate::pretty_writer::PrettyWriter; +use crate::generator::Hierarchy; +use crate::errors::IDLError; +use std::io::prelude::*; pub fn generate( cgenerator: &mut CGenerator, diff --git a/lucet-idl/src/cgenerator/gen_accessors_tagged_union.rs b/lucet-idl/src/c/accessors/tagged_union.rs similarity index 96% rename from lucet-idl/src/cgenerator/gen_accessors_tagged_union.rs rename to lucet-idl/src/c/accessors/tagged_union.rs index 39c28ba83..b8074b23f 100644 --- a/lucet-idl/src/cgenerator/gen_accessors_tagged_union.rs +++ b/lucet-idl/src/c/accessors/tagged_union.rs @@ -1,4 +1,12 @@ -use super::*; +use crate::c::CGenerator; +use crate::c::catom::CAtom; +use crate::c::macros; +use crate::module::{Module, DataTypeEntry, DataTypeRef, NamedMember}; +use crate::cache::Cache; +use crate::pretty_writer::PrettyWriter; +use crate::generator::Hierarchy; +use crate::errors::IDLError; +use std::io::prelude::*; pub fn generate( cgenerator: &mut CGenerator, diff --git a/lucet-idl/src/cgenerator/gen_alias.rs b/lucet-idl/src/c/alias.rs similarity index 100% rename from lucet-idl/src/cgenerator/gen_alias.rs rename to lucet-idl/src/c/alias.rs diff --git a/lucet-idl/src/cgenerator/catom.rs b/lucet-idl/src/c/catom.rs similarity index 100% rename from lucet-idl/src/cgenerator/catom.rs rename to lucet-idl/src/c/catom.rs diff --git a/lucet-idl/src/cgenerator/gen_enum.rs b/lucet-idl/src/c/enum.rs similarity index 100% rename from lucet-idl/src/cgenerator/gen_enum.rs rename to lucet-idl/src/c/enum.rs diff --git a/lucet-idl/src/cgenerator/macros.rs b/lucet-idl/src/c/macros.rs similarity index 100% rename from lucet-idl/src/cgenerator/macros.rs rename to lucet-idl/src/c/macros.rs diff --git a/lucet-idl/src/cgenerator/mod.rs b/lucet-idl/src/c/mod.rs similarity index 94% rename from lucet-idl/src/cgenerator/mod.rs rename to lucet-idl/src/c/mod.rs index 5efc597fc..e362cae6a 100644 --- a/lucet-idl/src/cgenerator/mod.rs +++ b/lucet-idl/src/c/mod.rs @@ -2,17 +2,12 @@ #![allow(unused_variables)] mod catom; -mod gen_accessors_alias; -mod gen_accessors_atom; -mod gen_accessors_enum; -mod gen_accessors_ptr; -mod gen_accessors_struct; -mod gen_accessors_tagged_union; -mod gen_alias; -mod gen_enum; -mod gen_prelude; -mod gen_struct; -mod gen_tagged_union; +mod accessors; +mod alias; +mod r#enum; +mod prelude; +mod r#struct; +mod tagged_union; mod macros; pub(crate) use self::catom::*; @@ -23,7 +18,6 @@ use crate::errors::*; use crate::generator::{Generator, Hierarchy}; use crate::pretty_writer::*; use crate::target::*; -use crate::types::*; use crate::module::{DataTypeRef, DataTypeEntry, Module}; use std::io::prelude::*; @@ -53,7 +47,7 @@ impl Generator for CGenerator { .eob()? .write_line(b"// ---------- Prelude ----------")? .eob()?; - gen_prelude::generate(pretty_writer, self.target, self.backend_config)?; + prelude::generate(pretty_writer, self.target, self.backend_config)?; Ok(()) } @@ -82,7 +76,7 @@ impl Generator for CGenerator { pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { - gen_alias::generate( + alias::generate( self, module, cache, @@ -98,7 +92,7 @@ impl Generator for CGenerator { pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { - gen_struct::generate( + r#struct::generate( self, module, cache, @@ -116,7 +110,7 @@ impl Generator for CGenerator { pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { - gen_enum::generate( + r#enum::generate( self, module, cache, @@ -132,7 +126,7 @@ impl Generator for CGenerator { pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { - gen_tagged_union::generate( + tagged_union::generate( self, module, cache, @@ -149,7 +143,7 @@ impl Generator for CGenerator { data_type_entry: &DataTypeEntry<'_>, hierarchy: &Hierarchy, ) -> Result<(), IDLError> { - gen_accessors_struct::generate( + accessors::r#struct::generate( self, module, cache, @@ -178,7 +172,7 @@ impl Generator for CGenerator { }; for (i, named_member) in named_members.iter().enumerate() { let internal_union_type_id = 1 + i; - gen_accessors_tagged_union::generate( + accessors::tagged_union::generate( self, data_type_entry, module, @@ -200,7 +194,7 @@ impl Generator for CGenerator { data_type_entry: &DataTypeEntry<'_>, hierarchy: &Hierarchy, ) -> Result<(), IDLError> { - gen_accessors_enum::generate( + accessors::r#enum::generate( self, module, cache, @@ -218,7 +212,7 @@ impl Generator for CGenerator { data_type_entry: &DataTypeEntry<'_>, hierarchy: &Hierarchy, ) -> Result<(), IDLError> { - gen_accessors_alias::generate( + accessors::alias::generate( self, module, cache, @@ -387,14 +381,14 @@ impl CGenerator { ) -> Result<(), IDLError> { let type_ = self.unalias(module, type_); match type_ { - DataTypeRef::Atom(atom_type) => gen_accessors_atom::generate( + DataTypeRef::Atom(atom_type) => accessors::atom::generate( self, module, pretty_writer, *atom_type, &hierarchy, ), - DataTypeRef::Ptr(type_) => gen_accessors_ptr::generate( + DataTypeRef::Ptr(type_) => accessors::ptr::generate( self, module, cache, diff --git a/lucet-idl/src/cgenerator/gen_prelude.rs b/lucet-idl/src/c/prelude.rs similarity index 100% rename from lucet-idl/src/cgenerator/gen_prelude.rs rename to lucet-idl/src/c/prelude.rs diff --git a/lucet-idl/src/cgenerator/gen_struct.rs b/lucet-idl/src/c/struct.rs similarity index 100% rename from lucet-idl/src/cgenerator/gen_struct.rs rename to lucet-idl/src/c/struct.rs diff --git a/lucet-idl/src/cgenerator/gen_tagged_union.rs b/lucet-idl/src/c/tagged_union.rs similarity index 100% rename from lucet-idl/src/cgenerator/gen_tagged_union.rs rename to lucet-idl/src/c/tagged_union.rs diff --git a/lucet-idl/src/config.rs b/lucet-idl/src/config.rs index 62e2ff019..bc1d39003 100644 --- a/lucet-idl/src/config.rs +++ b/lucet-idl/src/config.rs @@ -1,8 +1,8 @@ use super::backend::{Backend, BackendConfig}; use super::target::Target; use crate::generator::Generator; -use crate::rustgenerator::RustGenerator; -use crate::cgenerator::CGenerator; +use crate::rust::RustGenerator; +use crate::c::CGenerator; use std::io::Write; #[derive(Default, Clone, Debug)] diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 11c62bc4a..928f36167 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -7,12 +7,12 @@ mod types; mod module; mod backend; mod cache; -mod cgenerator; +mod c; mod config; mod errors; mod generator; mod pretty_writer; -mod rustgenerator; +mod rust; mod target; pub use crate::backend::{Backend, BackendConfig}; diff --git a/lucet-idl/src/rustgenerator/mod.rs b/lucet-idl/src/rust/mod.rs similarity index 100% rename from lucet-idl/src/rustgenerator/mod.rs rename to lucet-idl/src/rust/mod.rs From 7f41ef619a6e214455b7c8392e7bea5aa2b69b08 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Sat, 27 Apr 2019 16:46:33 -0700 Subject: [PATCH 100/512] pretty_writer: extract output writer after finished no way too pass it in as &mut with the current design of indentation in pretty_writer. nbd --- lucet-idl/src/lib.rs | 4 ++-- lucet-idl/src/pretty_writer.rs | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 928f36167..33809208a 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -26,7 +26,7 @@ use crate::pretty_writer::PrettyWriter; use crate::module::Module; use std::io::Write; -pub fn run(config: &Config, input: &str, output: W) -> Result<(), IDLError> { +pub fn run(config: &Config, input: &str, output: W) -> Result { let mut parser = Parser::new(&input); let decls = parser.match_decls()?; @@ -43,5 +43,5 @@ pub fn run(config: &Config, input: &str, output: W) -> Result<(), IDLE for id in deps { generator.gen_for_id(&module, &mut cache, &mut pretty_writer, id)?; } - Ok(()) + Ok(pretty_writer.into_inner().expect("outermost pretty_writer can unwrap")) } diff --git a/lucet-idl/src/pretty_writer.rs b/lucet-idl/src/pretty_writer.rs index 90123332b..bacb56ed7 100644 --- a/lucet-idl/src/pretty_writer.rs +++ b/lucet-idl/src/pretty_writer.rs @@ -102,4 +102,8 @@ impl PrettyWriter { pub fn write_line(&mut self, buf: &[u8]) -> Result<&mut Self, IDLError> { self.indent()?.write(buf)?.eol() } + + pub fn into_inner(self) -> Option { + Rc::try_unwrap(self.writer).ok().map(|w| w.into_inner()) + } } From 8eb6caf5174abe27969b63d1cabce9d0119bcb12 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Sat, 27 Apr 2019 16:47:27 -0700 Subject: [PATCH 101/512] lucetidl: generate code from example in readme, compile & run it --- Cargo.lock | 1 + lucet-idl/Cargo.toml | 3 +++ lucet-idl/tests/example.idl | 32 +++++++++++++++++++++++ lucet-idl/tests/example.rs | 45 ++++++++++++++++++++++++++++++++ lucet-idl/tests/example_driver.c | 34 ++++++++++++++++++++++++ 5 files changed, 115 insertions(+) create mode 100644 lucet-idl/tests/example.idl create mode 100644 lucet-idl/tests/example.rs create mode 100644 lucet-idl/tests/example_driver.c diff --git a/Cargo.lock b/Cargo.lock index f728afede..e61d2d718 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -614,6 +614,7 @@ version = "0.1.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/lucet-idl/Cargo.toml b/lucet-idl/Cargo.toml index e238f6a6e..e42dc2509 100644 --- a/lucet-idl/Cargo.toml +++ b/lucet-idl/Cargo.toml @@ -18,3 +18,6 @@ path = "src/main.rs" clap = "2" failure = "0.1" xfailure = "0.1" + +[dev-dependencies] +tempfile = "3.0" diff --git a/lucet-idl/tests/example.idl b/lucet-idl/tests/example.idl new file mode 100644 index 000000000..188b03876 --- /dev/null +++ b/lucet-idl/tests/example.idl @@ -0,0 +1,32 @@ + +// Primitive types: +// `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`, `f32`, `f64`. + +// Enumerations + +enum color { + red, blue, green +} + +// Aliases + +type colour = color +type col = colour + +// Structures + +struct st { + a: i8, + b: **i32, + c: color, + self: *st +} + +// Tagged unions + +taggedunion mixedbag { + a: col, + b: f64, + c: st, + d: () +} diff --git a/lucet-idl/tests/example.rs b/lucet-idl/tests/example.rs new file mode 100644 index 000000000..1e395b2c3 --- /dev/null +++ b/lucet-idl/tests/example.rs @@ -0,0 +1,45 @@ +use lucet_idl; +use std::fs::File; +use std::io::prelude::*; +use std::process::Command; +use tempfile::TempDir; + +#[test] +fn compile_and_run() { + let mut source = String::new(); + File::open("tests/example.idl") + .expect("open example.idl") + .read_to_string(&mut source) + .expect("read example.idl"); + + let config = lucet_idl::Config { + backend: lucet_idl::Backend::C, + backend_config: lucet_idl::BackendConfig::default(), + target: lucet_idl::Target::Generic, + }; + + let tempdir = TempDir::new().expect("create tempdir"); + + lucet_idl::run( + &config, + &source, + File::create(tempdir.path().join("example.h")).expect("create file"), + ) + .expect("run lucet_idl"); + + let cmd_cc = Command::new("cc") + .arg("--std=c99") + .arg("-I") + .arg(tempdir.path()) + .arg("tests/example_driver.c") + .arg("-o") + .arg(tempdir.path().join("example")) + .status() + .expect("run cc"); + assert!(cmd_cc.success(), "failure to compile generated code"); + + let cmd_run = Command::new(tempdir.path().join("example")) + .status() + .expect("run generated code"); + assert!(cmd_run.success(), "failure to run generated code"); +} diff --git a/lucet-idl/tests/example_driver.c b/lucet-idl/tests/example_driver.c new file mode 100644 index 000000000..6c75356aa --- /dev/null +++ b/lucet-idl/tests/example_driver.c @@ -0,0 +1,34 @@ +#include +#include +#include "example.h" + +int main (int argc, char *argv[]) { + + color c1 = COLOR_RED; + colour c2 = COLOR_BLUE; + col c3 = COLOR_GREEN; + + int32_t* b = malloc(sizeof(int32_t)); + struct st s = { + .a = 0, + .b = &b, + .c = COLOR_RED, + .self = &s, + }; + + char *mixedbag = malloc(BYTES_MIXEDBAG); + + store_mixedbag_a(mixedbag, c1); + assert(is_mixedbag_a(mixedbag)); + + store_mixedbag_b(mixedbag, 420.0); + assert(is_mixedbag_b(mixedbag)); + + store_mixedbag_c(mixedbag, &s); + assert(is_mixedbag_c(mixedbag)); + + set_mixedbag_d(mixedbag); + assert(is_mixedbag_d(mixedbag)); + + return 0; +} From d65d75a5d23f7b748ec77ffcd95c1030b21d558c Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 29 Apr 2019 10:46:44 -0700 Subject: [PATCH 102/512] =?UTF-8?q?[lucet-runtime]=20=F0=9F=90=9B=20fix=20?= =?UTF-8?q?soundness=20of=20vmctx=20heap=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also adds a privileged type for terminating from C --- lucet-runtime/lucet-runtime-internals/src/c_api.rs | 11 +++++++++-- .../lucet-runtime-internals/src/instance.rs | 4 ++-- lucet-runtime/lucet-runtime-internals/src/vmctx.rs | 14 ++++++++++++++ lucet-runtime/src/c_api.rs | 4 ++-- 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/c_api.rs b/lucet-runtime/lucet-runtime-internals/src/c_api.rs index be6a242b6..5ce4c6502 100644 --- a/lucet-runtime/lucet-runtime-internals/src/c_api.rs +++ b/lucet-runtime/lucet-runtime-internals/src/c_api.rs @@ -195,8 +195,15 @@ pub type lucet_signal_handler = unsafe extern "C" fn( pub type lucet_fatal_handler = unsafe extern "C" fn(inst: *mut lucet_instance); +pub struct CTerminationDetails { + pub details: *mut c_void, +} + +unsafe impl Send for CTerminationDetails {} +unsafe impl Sync for CTerminationDetails {} + pub mod lucet_state { - use crate::c_api::lucet_val; + use crate::c_api::{lucet_val, CTerminationDetails}; use crate::instance::{State, TerminationDetails}; use crate::module::AddrDetails; use crate::sysdeps::UContext; @@ -256,7 +263,7 @@ pub mod lucet_state { reason: lucet_terminated_reason::Provided, provided: p .downcast_ref() - .map(|v| *v) + .map(|CTerminationDetails { details }| *details) .unwrap_or(std::ptr::null_mut()), }, }, diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index 765c1e5e2..7eec7f57f 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -723,11 +723,11 @@ pub enum TerminationDetails { /// Returned when dynamic borrowing rules of methods like `Vmctx::heap()` are violated. BorrowError(&'static str), /// Calls to `lucet_hostcall_terminate` provide a payload for use by the embedder. - Provided(Arc), + Provided(Arc), } impl TerminationDetails { - pub fn provide(details: A) -> Self { + pub fn provide(details: A) -> Self { TerminationDetails::Provided(Arc::new(details)) } pub fn provided_details(&self) -> Option<&dyn Any> { diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index f35a9d4a8..802c8c9f0 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -84,6 +84,9 @@ impl Vmctx { /// If the heap is already mutably borrowed by `heap_mut()`, the instance will /// terminate with `TerminationDetails::BorrowError`. pub fn heap(&self) -> Ref<[u8]> { + unsafe { + self.reconstitute_heap_if_needed(); + } let r = self .heap .try_borrow() @@ -96,6 +99,9 @@ impl Vmctx { /// If the heap is already borrowed by `heap()` or `heap_mut()`, the instance will terminate /// with `TerminationDetails::BorrowError`. pub fn heap_mut(&self) -> RefMut<[u8]> { + unsafe { + self.reconstitute_heap_if_needed(); + } let r = self .heap .try_borrow_mut() @@ -103,6 +109,14 @@ impl Vmctx { RefMut::map(r, |b| b.borrow_mut()) } + unsafe fn reconstitute_heap_if_needed(&self) { + let inst = self.instance_mut(); + if inst.heap_mut().len() != self.heap.borrow().len() { + let old_heap = self.heap.replace(Box::<[u8]>::from_raw(inst.heap_mut())); + Box::leak(old_heap); + } + } + /// Check whether a given range in the host address space overlaps with the memory that backs /// the instance heap. pub fn check_heap(&self, ptr: *const T, len: usize) -> bool { diff --git a/lucet-runtime/src/c_api.rs b/lucet-runtime/src/c_api.rs index 39a306972..cb3bec40d 100644 --- a/lucet-runtime/src/c_api.rs +++ b/lucet-runtime/src/c_api.rs @@ -429,9 +429,9 @@ lucet_hostcalls! { #[no_mangle] pub unsafe extern "C" fn lucet_vmctx_terminate( &mut _vmctx, - info: *mut c_void, + details: *mut c_void, ) -> () { - lucet_hostcall_terminate!(info); + lucet_hostcall_terminate!(CTerminationDetails { details}); } #[no_mangle] From 0864270b492daf83f0e34dcda9bb5665e526ae0a Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 29 Apr 2019 10:54:55 -0700 Subject: [PATCH 103/512] lucet-idl: rustfmt 1.0.3 --- lucet-idl/src/c/accessors/alias.rs | 9 ++- lucet-idl/src/c/accessors/enum.rs | 8 +-- lucet-idl/src/c/accessors/ptr.rs | 2 +- lucet-idl/src/c/accessors/struct.rs | 8 +-- lucet-idl/src/c/accessors/tagged_union.rs | 8 +-- lucet-idl/src/c/alias.rs | 3 +- lucet-idl/src/c/mod.rs | 87 ++++++----------------- lucet-idl/src/config.rs | 6 +- lucet-idl/src/errors.rs | 2 +- lucet-idl/src/generator.rs | 3 +- lucet-idl/src/lib.rs | 20 +++--- lucet-idl/src/main.rs | 2 +- lucet-idl/src/module.rs | 40 +++-------- lucet-idl/src/rust/mod.rs | 2 +- 14 files changed, 65 insertions(+), 135 deletions(-) diff --git a/lucet-idl/src/c/accessors/alias.rs b/lucet-idl/src/c/accessors/alias.rs index 9ce16d82a..d55ccc876 100644 --- a/lucet-idl/src/c/accessors/alias.rs +++ b/lucet-idl/src/c/accessors/alias.rs @@ -1,9 +1,9 @@ use crate::c::CGenerator; -use crate::module::{Module, DataTypeEntry, DataType}; use crate::cache::Cache; -use crate::pretty_writer::PrettyWriter; -use crate::generator::Hierarchy; use crate::errors::IDLError; +use crate::generator::Hierarchy; +use crate::module::{DataType, DataTypeEntry, Module}; +use crate::pretty_writer::PrettyWriter; use std::io::prelude::*; pub fn generate( @@ -29,8 +29,7 @@ pub fn generate( pretty_writer .write(format!("// `{}` is an alias for `{}`", name, type_info.type_name).as_ref())?; if type_info.indirections == 0 { - let leaf_type_info = - cgenerator.type_info(module, cache, type_info.leaf_data_type_ref); + let leaf_type_info = cgenerator.type_info(module, cache, type_info.leaf_data_type_ref); if leaf_type_info.type_name != type_info.type_name { pretty_writer .write(format!(", itself equivalent to `{}`", leaf_type_info.type_name).as_ref())?; diff --git a/lucet-idl/src/c/accessors/enum.rs b/lucet-idl/src/c/accessors/enum.rs index fc6c8ab67..ea993cc3f 100644 --- a/lucet-idl/src/c/accessors/enum.rs +++ b/lucet-idl/src/c/accessors/enum.rs @@ -1,11 +1,11 @@ -use crate::c::CGenerator; use crate::c::catom::CAtom; use crate::c::macros; -use crate::module::{Module, DataTypeEntry, DataType}; +use crate::c::CGenerator; use crate::cache::Cache; -use crate::pretty_writer::PrettyWriter; -use crate::generator::Hierarchy; use crate::errors::IDLError; +use crate::generator::Hierarchy; +use crate::module::{DataType, DataTypeEntry, Module}; +use crate::pretty_writer::PrettyWriter; use std::io::prelude::*; pub fn generate( diff --git a/lucet-idl/src/c/accessors/ptr.rs b/lucet-idl/src/c/accessors/ptr.rs index f89caf2cf..eea3bc860 100644 --- a/lucet-idl/src/c/accessors/ptr.rs +++ b/lucet-idl/src/c/accessors/ptr.rs @@ -2,7 +2,7 @@ use crate::c::CGenerator; use crate::cache::Cache; use crate::errors::IDLError; use crate::generator::Hierarchy; -use crate::module::{Module, DataTypeRef}; +use crate::module::{DataTypeRef, Module}; use crate::pretty_writer::PrettyWriter; use std::io::prelude::*; diff --git a/lucet-idl/src/c/accessors/struct.rs b/lucet-idl/src/c/accessors/struct.rs index 88d5798e9..d1d602784 100644 --- a/lucet-idl/src/c/accessors/struct.rs +++ b/lucet-idl/src/c/accessors/struct.rs @@ -1,10 +1,10 @@ -use crate::c::CGenerator; use crate::c::macros; -use crate::module::{Module, DataTypeEntry, DataTypeRef, DataType}; +use crate::c::CGenerator; use crate::cache::Cache; -use crate::pretty_writer::PrettyWriter; -use crate::generator::Hierarchy; use crate::errors::IDLError; +use crate::generator::Hierarchy; +use crate::module::{DataType, DataTypeEntry, DataTypeRef, Module}; +use crate::pretty_writer::PrettyWriter; use std::io::prelude::*; pub fn generate( diff --git a/lucet-idl/src/c/accessors/tagged_union.rs b/lucet-idl/src/c/accessors/tagged_union.rs index b8074b23f..a855bbe3d 100644 --- a/lucet-idl/src/c/accessors/tagged_union.rs +++ b/lucet-idl/src/c/accessors/tagged_union.rs @@ -1,11 +1,11 @@ -use crate::c::CGenerator; use crate::c::catom::CAtom; use crate::c::macros; -use crate::module::{Module, DataTypeEntry, DataTypeRef, NamedMember}; +use crate::c::CGenerator; use crate::cache::Cache; -use crate::pretty_writer::PrettyWriter; -use crate::generator::Hierarchy; use crate::errors::IDLError; +use crate::generator::Hierarchy; +use crate::module::{DataTypeEntry, DataTypeRef, Module, NamedMember}; +use crate::pretty_writer::PrettyWriter; use std::io::prelude::*; pub fn generate( diff --git a/lucet-idl/src/c/alias.rs b/lucet-idl/src/c/alias.rs index 0cfd6fe35..6af89ccf3 100644 --- a/lucet-idl/src/c/alias.rs +++ b/lucet-idl/src/c/alias.rs @@ -24,8 +24,7 @@ pub fn generate( pretty_writer.write(data_type_entry.name.name.as_bytes())?; pretty_writer.write(b";")?; if type_info.indirections == 0 { - let leaf_type_info = - cgenerator.type_info(module, cache, type_info.leaf_data_type_ref); + let leaf_type_info = cgenerator.type_info(module, cache, type_info.leaf_data_type_ref); if leaf_type_info.type_name != type_info.type_name { pretty_writer.write(b" // equivalent to ")?; pretty_writer.write(leaf_type_info.type_name.as_bytes())?; diff --git a/lucet-idl/src/c/mod.rs b/lucet-idl/src/c/mod.rs index e362cae6a..591adf049 100644 --- a/lucet-idl/src/c/mod.rs +++ b/lucet-idl/src/c/mod.rs @@ -1,24 +1,24 @@ #![allow(dead_code)] #![allow(unused_variables)] -mod catom; mod accessors; mod alias; +mod catom; mod r#enum; +mod macros; mod prelude; mod r#struct; mod tagged_union; -mod macros; pub(crate) use self::catom::*; use crate::backend::*; use crate::cache::*; -use crate::module::*; use crate::errors::*; use crate::generator::{Generator, Hierarchy}; +use crate::module::*; +use crate::module::{DataTypeEntry, DataTypeRef, Module}; use crate::pretty_writer::*; use crate::target::*; -use crate::module::{DataTypeRef, DataTypeEntry, Module}; use std::io::prelude::*; #[derive(Clone, Debug)] @@ -76,13 +76,7 @@ impl Generator for CGenerator { pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { - alias::generate( - self, - module, - cache, - pretty_writer, - data_type_entry, - ) + alias::generate(self, module, cache, pretty_writer, data_type_entry) } fn gen_struct( @@ -92,13 +86,7 @@ impl Generator for CGenerator { pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { - r#struct::generate( - self, - module, - cache, - pretty_writer, - data_type_entry, - ) + r#struct::generate(self, module, cache, pretty_writer, data_type_entry) } // Enums generate both a specific typedef, and a traditional C-style enum @@ -110,13 +98,7 @@ impl Generator for CGenerator { pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { - r#enum::generate( - self, - module, - cache, - pretty_writer, - data_type_entry, - ) + r#enum::generate(self, module, cache, pretty_writer, data_type_entry) } fn gen_tagged_union( @@ -126,13 +108,7 @@ impl Generator for CGenerator { pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { - tagged_union::generate( - self, - module, - cache, - pretty_writer, - data_type_entry, - ) + tagged_union::generate(self, module, cache, pretty_writer, data_type_entry) } fn gen_accessors_struct( @@ -303,11 +279,7 @@ impl CGenerator { } // Return `true` if the type is an atom, an emum, or an alias to one of these - pub fn is_type_eventually_an_atom_or_enum( - &self, - module: &Module, - type_: &DataTypeRef, - ) -> bool { + pub fn is_type_eventually_an_atom_or_enum(&self, module: &Module, type_: &DataTypeRef) -> bool { let inner_type = match type_ { DataTypeRef::Atom(_) => return true, DataTypeRef::Ptr(_) => return false, @@ -318,18 +290,12 @@ impl CGenerator { match inner_data_type { DataType::Struct { .. } | DataType::TaggedUnion { .. } => false, DataType::Enum { .. } => true, - DataType::Alias { to, .. } => { - self.is_type_eventually_an_atom_or_enum(module, to) - } + DataType::Alias { to, .. } => self.is_type_eventually_an_atom_or_enum(module, to), } } /// Return the type refererence, with aliases being resolved - pub fn unalias<'t>( - &self, - module: &'t Module, - type_: &'t DataTypeRef, - ) -> &'t DataTypeRef { + pub fn unalias<'t>(&self, module: &'t Module, type_: &'t DataTypeRef) -> &'t DataTypeRef { let inner_type = match type_ { DataTypeRef::Atom(_) | DataTypeRef::Ptr(_) => return type_, DataTypeRef::Defined(inner_type) => inner_type, @@ -381,28 +347,15 @@ impl CGenerator { ) -> Result<(), IDLError> { let type_ = self.unalias(module, type_); match type_ { - DataTypeRef::Atom(atom_type) => accessors::atom::generate( - self, - module, - pretty_writer, - *atom_type, - &hierarchy, - ), - DataTypeRef::Ptr(type_) => accessors::ptr::generate( - self, - module, - cache, - pretty_writer, - type_, - &hierarchy, - ), - DataTypeRef::Defined(data_type_id) => self.gen_accessors_for_id( - module, - cache, - pretty_writer, - *data_type_id, - &hierarchy, - ), + DataTypeRef::Atom(atom_type) => { + accessors::atom::generate(self, module, pretty_writer, *atom_type, &hierarchy) + } + DataTypeRef::Ptr(type_) => { + accessors::ptr::generate(self, module, cache, pretty_writer, type_, &hierarchy) + } + DataTypeRef::Defined(data_type_id) => { + self.gen_accessors_for_id(module, cache, pretty_writer, *data_type_id, &hierarchy) + } } } } diff --git a/lucet-idl/src/config.rs b/lucet-idl/src/config.rs index bc1d39003..82871add8 100644 --- a/lucet-idl/src/config.rs +++ b/lucet-idl/src/config.rs @@ -1,8 +1,8 @@ use super::backend::{Backend, BackendConfig}; use super::target::Target; +use crate::c::CGenerator; use crate::generator::Generator; use crate::rust::RustGenerator; -use crate::c::CGenerator; use std::io::Write; #[derive(Default, Clone, Debug)] @@ -39,9 +39,7 @@ impl Config { Backend::Rust => Box::new(RustGenerator { target: self.target, backend_config: self.backend_config, - }) + }), } } } - - diff --git a/lucet-idl/src/errors.rs b/lucet-idl/src/errors.rs index a6475f940..0e1b1ac04 100644 --- a/lucet-idl/src/errors.rs +++ b/lucet-idl/src/errors.rs @@ -1,4 +1,4 @@ -use crate::{parser, module}; +use crate::{module, parser}; use std::io; #[allow(dead_code)] diff --git a/lucet-idl/src/generator.rs b/lucet-idl/src/generator.rs index 683fe391f..e825cab8e 100644 --- a/lucet-idl/src/generator.rs +++ b/lucet-idl/src/generator.rs @@ -1,7 +1,7 @@ use crate::cache::Cache; use crate::errors::IDLError; +use crate::module::{DataType, DataTypeEntry, DataTypeId, Module}; use crate::pretty_writer::PrettyWriter; -use crate::module::{DataTypeEntry, DataType, DataTypeId, Module}; use std::io::Write; use std::rc::Rc; @@ -148,7 +148,6 @@ pub trait Generator { } } - #[derive(Debug, Clone)] pub struct HierarchyEntry { name: Rc, diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 33809208a..fb5238b21 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -1,29 +1,29 @@ #[macro_use] extern crate failure; -mod lexer; -mod parser; -mod types; -mod module; mod backend; -mod cache; mod c; +mod cache; mod config; mod errors; mod generator; +mod lexer; +mod module; +mod parser; mod pretty_writer; mod rust; mod target; +mod types; pub use crate::backend::{Backend, BackendConfig}; pub use crate::config::Config; -pub use crate::target::Target; pub use crate::errors::IDLError; +pub use crate::target::Target; -use crate::parser::Parser; use crate::cache::Cache; -use crate::pretty_writer::PrettyWriter; use crate::module::Module; +use crate::parser::Parser; +use crate::pretty_writer::PrettyWriter; use std::io::Write; pub fn run(config: &Config, input: &str, output: W) -> Result { @@ -43,5 +43,7 @@ pub fn run(config: &Config, input: &str, output: W) -> Result, @@ -424,7 +423,6 @@ impl Module { data_type, } } - } #[cfg(test)] @@ -480,9 +478,7 @@ mod tests { // Duplicate member in struct assert_eq!( - module("struct foo { \na: i32, \na: f64}") - .err() - .unwrap(), + module("struct foo { \na: i32, \na: f64}").err().unwrap(), ValidationError::NameAlreadyExists { name: "a".to_owned(), at_location: Location { line: 3, column: 0 }, @@ -541,15 +537,9 @@ mod tests { assert!(module("taggedunion cons { succ: *cons, nil: () }").is_ok()); // Refer to a taggedunion defined previously: - assert!( - module("taggedunion foo { a: i32, b: f64 } taggedunion bar { a: foo }") - .is_ok() - ); + assert!(module("taggedunion foo { a: i32, b: f64 } taggedunion bar { a: foo }").is_ok()); // Refer to a taggedunion defined afterwards: - assert!( - module("taggedunion foo { a: i32, b: bar} taggedunion bar { a: i32 }") - .is_ok() - ); + assert!(module("taggedunion foo { a: i32, b: bar} taggedunion bar { a: i32 }").is_ok()); // No members assert_eq!( @@ -586,9 +576,7 @@ mod tests { // Refer to type that is not declared assert_eq!( - module("taggedunion foo { \nb: bar }") - .err() - .unwrap(), + module("taggedunion foo { \nb: bar }").err().unwrap(), ValidationError::NameNotFound { name: "bar".to_owned(), use_location: Location { line: 2, column: 3 }, @@ -632,9 +620,7 @@ mod tests { // Duplicate definition of enum assert_eq!( - module("enum foo { a }\nenum foo { a } ") - .err() - .unwrap(), + module("enum foo { a }\nenum foo { a } ").err().unwrap(), ValidationError::NameAlreadyExists { name: "foo".to_owned(), at_location: Location { line: 2, column: 0 }, @@ -651,17 +637,13 @@ mod tests { assert!(module("type foo = *bar\nenum bar { a }").is_ok()); - assert!( - module("type link = *list\nstruct list { next: link, thing: i32 }").is_ok() - ); + assert!(module("type link = *list\nstruct list { next: link, thing: i32 }").is_ok()); } #[test] fn infinite() { assert_eq!( - module("type foo = bar\ntype bar = foo") - .err() - .unwrap(), + module("type foo = bar\ntype bar = foo").err().unwrap(), ValidationError::Infinite { name: "foo".to_owned(), location: Location { line: 1, column: 0 }, @@ -679,11 +661,9 @@ mod tests { ); assert_eq!( - module( - "type foo = bar\nstruct bar { a: baz }\ntaggedunion baz { c: i32, e: foo }" - ) - .err() - .unwrap(), + module("type foo = bar\nstruct bar { a: baz }\ntaggedunion baz { c: i32, e: foo }") + .err() + .unwrap(), ValidationError::Infinite { name: "foo".to_owned(), location: Location { line: 1, column: 0 }, diff --git a/lucet-idl/src/rust/mod.rs b/lucet-idl/src/rust/mod.rs index 1c4b7aea1..bd63bc725 100644 --- a/lucet-idl/src/rust/mod.rs +++ b/lucet-idl/src/rust/mod.rs @@ -5,9 +5,9 @@ use crate::backend::*; use crate::cache::*; use crate::errors::*; use crate::generator::{Generator, Hierarchy}; +use crate::module::{DataTypeEntry, DataTypeRef, Module}; use crate::pretty_writer::*; use crate::target::*; -use crate::module::{Module, DataTypeEntry, DataTypeRef}; use std::io::prelude::*; #[derive(Clone, Debug)] From 031089ef439bbc555ef88d1e8422ccfa974687a7 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 29 Apr 2019 11:10:51 -0700 Subject: [PATCH 104/512] [lucet-runtime] document the assumptions around the Vmctx heap view --- lucet-runtime/lucet-runtime-internals/src/vmctx.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index 802c8c9f0..fcbc99e26 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -109,6 +109,16 @@ impl Vmctx { RefMut::map(r, |b| b.borrow_mut()) } + /// Check whether the heap has grown, and replace the heap view if it has. + /// + /// This handles the case where `Vmctx::grow_memory()` and `Vmctx::heap()` are called in + /// sequence. Since `Vmctx::grow_memory()` takes `&mut self`, heap references cannot live across + /// it. + /// + /// TODO: There is still an unsound case, though, when a heap reference is held across a call + /// back into the guest via `Vmctx::get_func_from_idx()`. That guest code may grow the heap as + /// well, causing any outstanding heap references to become invalid. We will address this when + /// we rework the interface for calling back into the guest. unsafe fn reconstitute_heap_if_needed(&self) { let inst = self.instance_mut(); if inst.heap_mut().len() != self.heap.borrow().len() { From 5eced44fff608e1f79d2e8d8ae17235bd4dcb796 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 29 Apr 2019 13:14:14 -0700 Subject: [PATCH 105/512] [lucet-runtime] zero out instance magic more safely This was previously segfaulting if the region got dropped after the `mem::replace` line. Our tests previously always had the Region remain in scope, which is why we didn't catch it till now --- .../lucet-runtime-internals/src/alloc/tests.rs | 10 ++++++++++ lucet-runtime/lucet-runtime-internals/src/instance.rs | 8 ++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs b/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs index eff5eb376..ec5ec766b 100644 --- a/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs +++ b/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs @@ -658,6 +658,16 @@ macro_rules! alloc_tests { } } } + + #[test] + fn drop_region_first() { + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let inst = region + .new_instance(MockModuleBuilder::new().build()) + .expect("new_instance succeeds"); + drop(region); + drop(inst); + } }; } diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index 08719bd50..2f38ec174 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -134,10 +134,10 @@ impl Drop for InstanceHandle { fn drop(&mut self) { // run the destructor by taking and dropping the inner `Instance` unsafe { - mem::replace(self.inst.as_mut(), mem::uninitialized()); - // make sure magic is zeroed, as we can't depend on `uninitialized` throwing away the - // magic - self.inst.as_mut().magic = 0; + // make sure magic is zeroed, but allow everything else to be uninitialized + let mut uninit: Instance = mem::uninitialized(); + uninit.magic = 0; + mem::replace(self.inst.as_mut(), uninit); } } } From 807a810fda372984ab0ad41ac48a41e33b7dd40e Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 29 Apr 2019 14:21:58 -0700 Subject: [PATCH 106/512] [lucet-runtime] be explicit about when an InstanceHandle should drop --- .../lucet-runtime-internals/src/instance.rs | 36 ++++++++++++------- lucet-runtime/src/c_api.rs | 2 +- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index 2f38ec174..714fb31dc 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -54,6 +54,7 @@ thread_local! { /// though it were a `&mut Instance`. pub struct InstanceHandle { inst: NonNull, + needs_inst_drop: bool, } // raw pointer lint @@ -77,13 +78,15 @@ pub fn new_instance_handle( let inst = NonNull::new(instance) .ok_or(lucet_format_err!("instance pointer is null; this is a bug"))?; - // do this check first so we don't run `InstanceHandle::drop()` for a failure lucet_ensure!( unsafe { inst.as_ref().magic } != LUCET_INSTANCE_MAGIC, "created a new instance handle in memory with existing instance magic; this is a bug" ); - let mut handle = InstanceHandle { inst }; + let mut handle = InstanceHandle { + inst, + needs_inst_drop: false, + }; let inst = Instance::new(alloc, module, embed_ctx); @@ -96,20 +99,25 @@ pub fn new_instance_handle( ptr::write(&mut *handle, inst); }; + handle.needs_inst_drop = true; + handle.reset()?; Ok(handle) } -pub fn instance_handle_to_raw(inst: InstanceHandle) -> *mut Instance { - let ptr = inst.inst.as_ptr(); - std::mem::forget(inst); - ptr +pub fn instance_handle_to_raw(mut inst: InstanceHandle) -> *mut Instance { + inst.needs_inst_drop = false; + inst.inst.as_ptr() } -pub unsafe fn instance_handle_from_raw(ptr: *mut Instance) -> InstanceHandle { +pub unsafe fn instance_handle_from_raw( + ptr: *mut Instance, + needs_inst_drop: bool, +) -> InstanceHandle { InstanceHandle { inst: NonNull::new_unchecked(ptr), + needs_inst_drop, } } @@ -132,12 +140,14 @@ impl DerefMut for InstanceHandle { impl Drop for InstanceHandle { fn drop(&mut self) { - // run the destructor by taking and dropping the inner `Instance` - unsafe { - // make sure magic is zeroed, but allow everything else to be uninitialized - let mut uninit: Instance = mem::uninitialized(); - uninit.magic = 0; - mem::replace(self.inst.as_mut(), uninit); + if self.needs_inst_drop { + // run the destructor by taking and dropping the inner `Instance` + unsafe { + // make sure magic is zeroed, but allow everything else to be uninitialized + let mut uninit: Instance = mem::uninitialized(); + uninit.magic = 0; + mem::replace(self.inst.as_mut(), uninit); + } } } } diff --git a/lucet-runtime/src/c_api.rs b/lucet-runtime/src/c_api.rs index cd934ae8c..84c65c382 100644 --- a/lucet-runtime/src/c_api.rs +++ b/lucet-runtime/src/c_api.rs @@ -239,7 +239,7 @@ pub unsafe extern "C" fn lucet_instance_reset(inst: *mut lucet_instance) -> luce #[no_mangle] pub unsafe extern "C" fn lucet_instance_release(inst: *mut lucet_instance) { - instance_handle_from_raw(inst as *mut Instance); + instance_handle_from_raw(inst as *mut Instance, true); } #[no_mangle] From a6c987ce9d85ecf95ded474977b427888c52288d Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 29 Apr 2019 16:52:30 -0700 Subject: [PATCH 107/512] lucet-idl: disable last part of test --- lucet-idl/tests/example.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lucet-idl/tests/example.rs b/lucet-idl/tests/example.rs index 1e395b2c3..4b4914a1f 100644 --- a/lucet-idl/tests/example.rs +++ b/lucet-idl/tests/example.rs @@ -38,8 +38,11 @@ fn compile_and_run() { .expect("run cc"); assert!(cmd_cc.success(), "failure to compile generated code"); + /* currently assertions in the example_driver fail. re-enable this when we figure out how to + * fix them: let cmd_run = Command::new(tempdir.path().join("example")) .status() .expect("run generated code"); assert!(cmd_run.success(), "failure to run generated code"); + */ } From 74d2808352f2b3ac07eb5f4e64dee874604ba465 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 30 Apr 2019 10:21:13 -0700 Subject: [PATCH 108/512] lucet-idl: delete tagged union from example tests we're going to drop support for these in the language for the time being --- lucet-idl/tests/example.idl | 8 -------- lucet-idl/tests/example_driver.c | 14 -------------- 2 files changed, 22 deletions(-) diff --git a/lucet-idl/tests/example.idl b/lucet-idl/tests/example.idl index 188b03876..a0abdb075 100644 --- a/lucet-idl/tests/example.idl +++ b/lucet-idl/tests/example.idl @@ -22,11 +22,3 @@ struct st { self: *st } -// Tagged unions - -taggedunion mixedbag { - a: col, - b: f64, - c: st, - d: () -} diff --git a/lucet-idl/tests/example_driver.c b/lucet-idl/tests/example_driver.c index 6c75356aa..02da1d00c 100644 --- a/lucet-idl/tests/example_driver.c +++ b/lucet-idl/tests/example_driver.c @@ -16,19 +16,5 @@ int main (int argc, char *argv[]) { .self = &s, }; - char *mixedbag = malloc(BYTES_MIXEDBAG); - - store_mixedbag_a(mixedbag, c1); - assert(is_mixedbag_a(mixedbag)); - - store_mixedbag_b(mixedbag, 420.0); - assert(is_mixedbag_b(mixedbag)); - - store_mixedbag_c(mixedbag, &s); - assert(is_mixedbag_c(mixedbag)); - - set_mixedbag_d(mixedbag); - assert(is_mixedbag_d(mixedbag)); - return 0; } From 27857a2ae6a36f96c5aba5383c93daeb38796e09 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 30 Apr 2019 10:22:14 -0700 Subject: [PATCH 109/512] Revert "lucet-idl: disable last part of test" This reverts commit a6c987ce9d85ecf95ded474977b427888c52288d. --- lucet-idl/tests/example.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/lucet-idl/tests/example.rs b/lucet-idl/tests/example.rs index 4b4914a1f..1e395b2c3 100644 --- a/lucet-idl/tests/example.rs +++ b/lucet-idl/tests/example.rs @@ -38,11 +38,8 @@ fn compile_and_run() { .expect("run cc"); assert!(cmd_cc.success(), "failure to compile generated code"); - /* currently assertions in the example_driver fail. re-enable this when we figure out how to - * fix them: let cmd_run = Command::new(tempdir.path().join("example")) .status() .expect("run generated code"); assert!(cmd_run.success(), "failure to run generated code"); - */ } From 4d6cf39a5716d30b41750944644060fedc8ee1b5 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 30 Apr 2019 10:32:40 -0700 Subject: [PATCH 110/512] lucet-idl: delete tagged unions from the language --- lucet-idl/README.md | 91 -------- lucet-idl/src/c/accessors/mod.rs | 1 - lucet-idl/src/c/accessors/tagged_union.rs | 264 ---------------------- lucet-idl/src/c/catom.rs | 5 - lucet-idl/src/c/mod.rs | 50 +--- lucet-idl/src/c/tagged_union.rs | 180 --------------- lucet-idl/src/generator.rs | 27 --- lucet-idl/src/lexer.rs | 8 +- lucet-idl/src/module.rs | 132 ----------- lucet-idl/src/parser.rs | 256 --------------------- lucet-idl/src/rust/mod.rs | 21 -- 11 files changed, 2 insertions(+), 1033 deletions(-) delete mode 100644 lucet-idl/src/c/accessors/tagged_union.rs delete mode 100644 lucet-idl/src/c/tagged_union.rs diff --git a/lucet-idl/README.md b/lucet-idl/README.md index 4cd1cb560..69817edb3 100644 --- a/lucet-idl/README.md +++ b/lucet-idl/README.md @@ -44,15 +44,6 @@ struct st { c: color, self: *st } - -// Tagged unions - -taggedunion mixedbag { - a: col, - b: f64, - c: st, - d: () -} ``` ## Sample output @@ -106,34 +97,6 @@ enum ___color { #define BYTES_COLOR 8 ``` -### Tagged unions - -Tagged unions allow different types to be stored in the same memory space. - -The `mixedbag` tagged union generates the following definition: - -```c -#define TYPE_MIXEDBAG_A 1 -#define TYPE_MIXEDBAG_B 2 -#define TYPE_MIXEDBAG_C 3 - -struct mixedbag { - uint32_t ___type; // tagged union type, should be in the [1...4] range - uint8_t ___pad8_4[4]; - union { - col a; // - type 1 - double b; // - type 2 - struct st c; // - type 3 - // void d; - type 4 - } variant; -}; - -#define BYTES_MIXEDBAG 40 -``` - -Like structures, explicit padding is added to try to match the alignment rules of the reference platform. - -`BYTES_MIXEDBAG` is the number of bytes required to store the whole tagged union. ## Accessors (C) @@ -156,62 +119,8 @@ On other platforms, individual values are re-aligned and byte-swapped accordingl Accessors for individual values are also generated. -The suffix of a function name represents the hierarchy of the value. For example, the -following functions can directly access the `a` value of the `st` structure `b` within -the `mixedbag` tagged union: - -```c -static inline void store_mixedbag_c_a(unsigned char buf[static BYTES_MIXEDBAG], const int8_t v); - -static inline void load_mixedbag_c_a(int8_t *v_p, const unsigned char buf[static BYTES_MIXEDBAG]); -``` - Subsets of types can thus be directly loaded and modified from a serialized representation. -Tagged unions generate different sets of functions: - -### Tagged unions: non-void members - -```c -static inline bool is_mixedbag_a(const unsigned char buf[static BYTES_COLOR]); -``` - -This returns `TRUE` if the current type is `a`. - -```c -static inline void ref_mixedbag_a( - const unsigned char **ibuf_p, - const unsigned char buf[static BYTES_MIXEDBAG]); - -static inline void mut_mixedbag_a( - unsigned char **ibuf_p, - unsigned char buf[static BYTES_MIXEDBAG]); -``` - -These functions return a pointer to a serialized representation of the tagged union, -assuming that it currently olds the `a` type. If this is not the case, an -`assert()`ion will be hit. - -```c -static inline void store_mixedbag_as_a( - unsigned char buf[static BYTES_MIXEDBAG], - const struct mixedbag *t); -``` - -This function serializes the tagged union into `buf`, possibly forcing the type to be `a`. - -### Tagged union: void members - -Member `d` of the `mixedbag` tagged union doesn't have any value. - -The following set of accessors are generated: - -```c -static inline bool is_mixedbag_d(const unsigned char buf[static 4]); - -static inline void set_mixedbag_d(unsigned char buf[static 4]); -``` - ## Pointers Pointers are not automatically dereferenced. Their value can be replaced with zeros in diff --git a/lucet-idl/src/c/accessors/mod.rs b/lucet-idl/src/c/accessors/mod.rs index 6c87bc922..fa1218590 100644 --- a/lucet-idl/src/c/accessors/mod.rs +++ b/lucet-idl/src/c/accessors/mod.rs @@ -3,4 +3,3 @@ pub mod atom; pub mod r#enum; pub mod ptr; pub mod r#struct; -pub mod tagged_union; diff --git a/lucet-idl/src/c/accessors/tagged_union.rs b/lucet-idl/src/c/accessors/tagged_union.rs deleted file mode 100644 index a855bbe3d..000000000 --- a/lucet-idl/src/c/accessors/tagged_union.rs +++ /dev/null @@ -1,264 +0,0 @@ -use crate::c::catom::CAtom; -use crate::c::macros; -use crate::c::CGenerator; -use crate::cache::Cache; -use crate::errors::IDLError; -use crate::generator::Hierarchy; -use crate::module::{DataTypeEntry, DataTypeRef, Module, NamedMember}; -use crate::pretty_writer::PrettyWriter; -use std::io::prelude::*; - -pub fn generate( - cgenerator: &mut CGenerator, - data_type_entry: &DataTypeEntry<'_>, - module: &Module, - cache: &Cache, - pretty_writer: &mut PrettyWriter, - internal_union_type_id: usize, - named_member: &NamedMember>, - hierarchy: &Hierarchy, -) -> Result<(), IDLError> { - let fn_name = hierarchy.fn_name(); - let root_name = hierarchy.root_name(); - let root_macro_size_name = macros::macro_for("BYTES", &root_name); - let name = &named_member.name; - let member_type = named_member.type_.as_ref(); - let cached_type_entry = cache - .load_type(data_type_entry.id) - .expect("Type not cached"); - let first_member_offset = cached_type_entry - .load_member(0) - .expect("No member entry") - .offset; - let mut member_type_size = 0; - if let Some(member_type) = member_type { - let type_info = cgenerator.type_info(module, cache, member_type); - member_type_size = type_info.type_size; - } - let mut pretty_writer_i1 = pretty_writer.new_block(); - let mut pretty_writer_preprocessor = pretty_writer.new_from_writer(); - let member_macro_size_name = if let Some(member_type) = member_type { - let unaliased_member_type = cgenerator.unalias(module, member_type); - macros::macro_for_data_type_ref(module, "BYTES", unaliased_member_type) - } else { - CAtom::tagged_union_type().native_type_size.to_string() - }; - pretty_writer.write_line( - format!( - "// The following set of functions accesses a tagged union `{}` as the internal type `{}`", - fn_name, name - ) - .as_ref(), - )?; - pretty_writer.eob()?; - - // --- is_*() - - pretty_writer.write_line( - format!( - "static inline bool is_{}_{}(const unsigned char buf[static {}])", - fn_name, name, member_macro_size_name - ) - .as_ref(), - )?; - pretty_writer.write_line(b"{")?; - pretty_writer_i1 - .write_line(format!("{} type;", CAtom::tagged_union_type().native_type_name).as_ref())? - .eob()?; - pretty_writer_i1.write_line( - format!( - "_Static_assert({} >= sizeof type, \"unexpected size\");", - member_macro_size_name - ) - .as_ref(), - )?; - pretty_writer_i1 - .write_line(b"memcpy(&type, &buf[0], sizeof type);")? - .eob()?; - pretty_writer_i1.write_line( - format!( - "return type == {};", - CAtom::tagged_union_type() - .little_endian(cgenerator.target, &format!("{}", internal_union_type_id)) - ) - .as_ref(), - )?; - pretty_writer.write_line(b"}")?.eob()?; - - // --- set_*() - - if member_type.is_none() { - pretty_writer.write_line( - format!( - "static inline void set_{}_{}(unsigned char buf[static {}])", - fn_name, name, member_macro_size_name - ) - .as_ref(), - )?; - pretty_writer.write_line(b"{")?; - pretty_writer_i1 - .write_line( - format!( - "const {} type = {};", - CAtom::tagged_union_type().native_type_name, - CAtom::tagged_union_type() - .little_endian(cgenerator.target, &format!("{}", internal_union_type_id)) - ) - .as_bytes(), - )? - .eob()?; - - pretty_writer_i1.write_line(b"memcpy(&buf[0], &type, sizeof type);")?; - pretty_writer.write_line(b"}")?.eob()?; - return Ok(()); - } - - // --- ref_*() - - pretty_writer.write_line(format!("static inline void ref_{}_{}(", fn_name, name).as_ref())?; - pretty_writer - .continuation()? - .write(b"const unsigned char **ibuf_p,")? - .eol()?; - pretty_writer - .continuation()? - .write(format!("const unsigned char buf[static {}])", root_macro_size_name).as_ref())? - .eol()?; - pretty_writer.write_line(b"{")?; - pretty_writer_i1.write_line(format!("assert(is_{}_{}(buf));", fn_name, name).as_ref())?; - pretty_writer_i1 - .write_line(format!("*ibuf_p = &buf[offsetof(struct {}, variant)];", fn_name).as_ref())?; - pretty_writer_i1.eob()?; - pretty_writer_i1.write_line( - format!( - "_Static_assert({} >= offsetof(struct {}, variant) + {}, \"unexpected size\");", - root_macro_size_name, fn_name, member_type_size - ) - .as_ref(), - )?; - pretty_writer.write_line(b"}")?.eob()?; - - // --- mut_*() - - pretty_writer.write_line(format!("static inline void mut_{}_{}(", fn_name, name).as_ref())?; - pretty_writer - .continuation()? - .write(b"unsigned char **ibuf_p,")? - .eol()?; - pretty_writer - .continuation()? - .write(format!("unsigned char buf[static {}])", root_macro_size_name).as_ref())? - .eol()?; - pretty_writer.write_line(b"{")?; - pretty_writer_i1.write_line(format!("assert(is_{}_{}(buf));", fn_name, name).as_ref())?; - pretty_writer_i1 - .write_line(format!("*ibuf_p = &buf[offsetof(struct {}, variant)];", fn_name).as_ref())?; - pretty_writer_i1.eob()?; - pretty_writer_i1.write_line( - format!( - "_Static_assert({} >= offsetof(struct {}, variant) + {}, \"unexpected size\");", - root_macro_size_name, fn_name, member_type_size - ) - .as_ref(), - )?; - pretty_writer.write_line(b"}")?.eob()?; - - // --- Accessors for inner members - - let type_ = member_type.expect("Empty member"); - let hierarchy1 = hierarchy.push(named_member.name.to_string(), first_member_offset); - cgenerator.gen_accessors_for_data_type_ref( - module, - cache, - pretty_writer, - type_, - &named_member.name, - &hierarchy1, - )?; - - // --- Accessors for the whole tagged union - - let type_size = cached_type_entry.type_size; - let union_macro_size_name = macros::macro_for("BYTES", &fn_name); - let is_eventually_an_atom_or_enum = - cgenerator.is_type_eventually_an_atom_or_enum(module, type_); - - pretty_writer - .write_line( - format!( - "// Store the whole `{}` tagged union, when used as type `{}`", - fn_name, name - ) - .as_ref(), - )? - .eob()?; - pretty_writer.write_line( - format!( - "static inline void store_{}_as_{}(unsigned char buf[static {}], const struct {} *t)", - fn_name, name, union_macro_size_name, fn_name - ) - .as_ref(), - )?; - pretty_writer.write_line(b"{")?; - pretty_writer_i1.write_line( - format!( - "_Static_assert({} == {}, \"unexpected size\");", - union_macro_size_name, type_size - ) - .as_ref(), - )?; - pretty_writer_i1 - .write_line(format!("assert(t->___type == {});", internal_union_type_id).as_ref())? - .eob()?; - pretty_writer_i1.write_line( - format!( - "const {} type = {}; // {}", - CAtom::tagged_union_type().native_type_name, - CAtom::tagged_union_type() - .little_endian(cgenerator.target, &format!("{}", internal_union_type_id)), - name - ) - .as_bytes(), - )?; - pretty_writer_i1 - .write_line(b"memcpy(&buf[0], &type, sizeof type);")? - .eob()?; - if let DataTypeRef::Ptr(_) = type_ { - pretty_writer_preprocessor.write_line(b"# ifdef ZERO_NATIVE_POINTERS")?; - pretty_writer_i1.write_line( - format!( - "memset(&buf[offsetof(struct {}, variant)], 0, sizeof *t);", - fn_name - ) - .as_ref(), - )?; - pretty_writer_preprocessor.write_line(b"# else")?; - pretty_writer_i1.write_line( - format!( - "memcpy(&buf[offsetof(struct {}, variant)], &t->variant.{}, sizeof *t);", - fn_name, name - ) - .as_ref(), - )?; - pretty_writer_preprocessor.write_line(b"# endif")?; - } else if is_eventually_an_atom_or_enum { - pretty_writer_i1.write_line( - format!( - "store_{}_{}(&buf[offsetof(struct {}, variant)], t->variant.{});", - fn_name, name, fn_name, name - ) - .as_ref(), - )?; - } else { - pretty_writer_i1.write_line( - format!( - "store_{}_{}(&buf[offsetof(struct {}, variant)], &t->variant.{});", - fn_name, name, fn_name, name - ) - .as_ref(), - )?; - } - pretty_writer.write_line(b"}")?; - - Ok(()) -} diff --git a/lucet-idl/src/c/catom.rs b/lucet-idl/src/c/catom.rs index 5a46eafec..4e535953d 100644 --- a/lucet-idl/src/c/catom.rs +++ b/lucet-idl/src/c/catom.rs @@ -75,11 +75,6 @@ impl CAtom { } } - /// Native type used for the type in tagged unions - pub fn tagged_union_type() -> Self { - CAtom::from(AtomType::U32) - } - /// Native type used for enums /// It can't be an `int` as it would not be portable across architectures pub fn enum_() -> Self { diff --git a/lucet-idl/src/c/mod.rs b/lucet-idl/src/c/mod.rs index 591adf049..49fb276bf 100644 --- a/lucet-idl/src/c/mod.rs +++ b/lucet-idl/src/c/mod.rs @@ -8,7 +8,6 @@ mod r#enum; mod macros; mod prelude; mod r#struct; -mod tagged_union; pub(crate) use self::catom::*; use crate::backend::*; @@ -101,16 +100,6 @@ impl Generator for CGenerator { r#enum::generate(self, module, cache, pretty_writer, data_type_entry) } - fn gen_tagged_union( - &mut self, - module: &Module, - cache: &mut Cache, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - ) -> Result<(), IDLError> { - tagged_union::generate(self, module, cache, pretty_writer, data_type_entry) - } - fn gen_accessors_struct( &mut self, module: &Module, @@ -129,39 +118,6 @@ impl Generator for CGenerator { ) } - fn gen_accessors_tagged_union( - &mut self, - module: &Module, - cache: &Cache, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - hierarchy: &Hierarchy, - ) -> Result<(), IDLError> { - let (named_members, _attrs) = if let DataType::TaggedUnion { - members: named_members, - attrs, - } = &data_type_entry.data_type - { - (named_members, attrs) - } else { - unreachable!() - }; - for (i, named_member) in named_members.iter().enumerate() { - let internal_union_type_id = 1 + i; - accessors::tagged_union::generate( - self, - data_type_entry, - module, - cache, - pretty_writer, - internal_union_type_id, - &named_member, - &hierarchy, - )?; - } - Ok(()) - } - fn gen_accessors_enum( &mut self, module: &Module, @@ -241,10 +197,6 @@ impl CGenerator { type_name = type_name .or_else(|| Some(format!("struct {}", data_type_entry.name.name))) } - DataType::TaggedUnion { .. } => { - type_name = type_name - .or_else(|| Some(format!("struct {}", data_type_entry.name.name))) - } DataType::Enum { .. } => { type_name = type_name.or_else(|| { Some(format!( @@ -288,7 +240,7 @@ impl CGenerator { let inner_data_type_entry = module.get_datatype(*inner_type); let inner_data_type = inner_data_type_entry.data_type; match inner_data_type { - DataType::Struct { .. } | DataType::TaggedUnion { .. } => false, + DataType::Struct { .. } => false, DataType::Enum { .. } => true, DataType::Alias { to, .. } => self.is_type_eventually_an_atom_or_enum(module, to), } diff --git a/lucet-idl/src/c/tagged_union.rs b/lucet-idl/src/c/tagged_union.rs deleted file mode 100644 index 8a3f93c3c..000000000 --- a/lucet-idl/src/c/tagged_union.rs +++ /dev/null @@ -1,180 +0,0 @@ -use super::*; - -pub fn generate( - cgenerator: &mut CGenerator, - module: &Module, - cache: &mut Cache, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, -) -> Result<(), IDLError> { - let (named_members, _attrs) = if let DataType::TaggedUnion { - members: named_members, - attrs, - } = &data_type_entry.data_type - { - (named_members, attrs) - } else { - unreachable!() - }; - - for (i, named_member) in named_members.iter().enumerate() { - let internal_union_type_id = i + 1; - macros::define( - cgenerator, - pretty_writer, - "TYPE", - format!("{}_{}", data_type_entry.name.name, named_member.name).as_str(), - internal_union_type_id, - )?; - } - pretty_writer.eob()?; - pretty_writer.write_line(format!("struct {} {{", data_type_entry.name.name).as_bytes())?; - let mut pretty_writer_i1 = pretty_writer.new_block(); - let mut offset: usize = 0; - - // The first member of the structure is the variant type - // This will also define the required alignment for the tagged union - // Variant types start at `1` and not `0` to help find possibly uninitialized variable - let tagged_union_type_native_type = CAtom::tagged_union_type(); - let (tagged_union_type_align, tagged_union_type_size, tagged_union_type_name) = ( - tagged_union_type_native_type.native_type_align, - tagged_union_type_native_type.native_type_size, - tagged_union_type_native_type.native_type_name, - ); - let first_member_align = Some(tagged_union_type_align); - pretty_writer_i1.indent()?; - pretty_writer_i1.write(tagged_union_type_name.as_bytes())?; - pretty_writer_i1.space()?; - pretty_writer_i1.write( - format!( - "___type; // tagged union type, should be in the [1...{}] range", - named_members.len() - ) - .as_bytes(), - )?; - pretty_writer_i1.eol()?; - offset += tagged_union_type_size; - - let mut includes_pointers = false; - - // The size of the union is the size of the largest member. - // Ditto for the alignment. - // In order to know how much padding is required between the variant type and the - // union, find these maximum values first. - // We also need to find if we have at least one pointer. In that case, additional - // padding at the end of the structure may be required for targets with 32-bit - // pointers. - let mut max_align = 0; - let mut max_size = 0; - for named_member in named_members { - if let Some(type_) = named_member.type_.as_ref() { - let type_info = cgenerator.type_info(module, cache, type_); - if type_info.type_align > max_align { - max_align = type_info.type_align; - } - if type_info.type_size > max_size { - max_size = type_info.type_size; - } - if type_info.indirections > 0 { - includes_pointers = true; - } - } - } - - // Add optional padding between the variant type and the union - let padding = (max_align - 1) - ((offset + (max_align - 1)) % max_align); - if padding > 0 { - pretty_writer_i1.write_line( - format!("uint8_t ___pad{}_{}[{}];", max_align, offset, padding).as_bytes(), - )?; - offset += padding; - } - - let variant_offset = offset; - - pretty_writer_i1.write_line(b"union {")?; - let mut pretty_writer_i2 = pretty_writer_i1.new_block(); - for (i, named_member) in named_members.iter().enumerate() { - let internal_union_type_id = i + 1; - if named_member.type_.is_none() { - // Untyped union member - pretty_writer_i2.write_line( - format!( - "// void {}; - type {}", - named_member.name, internal_union_type_id - ) - .as_bytes(), - )?; - continue; - } - let type_ = named_member.type_.as_ref().unwrap(); - let type_info = cgenerator.type_info(module, cache, type_); - pretty_writer_i2.indent()?; - pretty_writer_i2.write(type_info.type_name.as_bytes())?; - pretty_writer_i2.space()?; - for _ in 0..type_info.indirections { - pretty_writer_i2.write(b"*")?; - } - pretty_writer_i2.write(named_member.name.as_bytes())?; - pretty_writer_i2.write(b";")?; - pretty_writer_i2.space()?; - pretty_writer_i2.write(format!("// - type {}", internal_union_type_id).as_bytes())?; - pretty_writer_i2.eol()?; - } - - pretty_writer_i1.write_line(b"} variant;")?; - offset += max_size; - - // If the tagged enum includes pointers, we may have to extend its size - // to match what it would be on a target with 64-bit pointers - if includes_pointers { - cgenerator.pointer_pad(&mut pretty_writer_i1, 1, offset, "inside tagged union")?; - } - - pretty_writer.write_line(b"};")?; - pretty_writer.eob()?; - - let struct_align = first_member_align.unwrap(); - let struct_size = offset; - cache.store_type( - data_type_entry.id, - CachedTypeEntry { - type_size: struct_size, - type_align: struct_align, - members: vec![CachedStructMemberEntry { - offset: variant_offset, - }], - }, - ); - - // Add an assertion to check that the variant is properly aligned - pretty_writer.write_line( - format!( - "_Static_assert(offsetof(struct {}, variant) == {}, \"unexpected variant offset\");", - data_type_entry.name.name, variant_offset - ) - .as_bytes(), - )?; - - // Add an assertion to check that the structure size matches what we expect - pretty_writer.write_line( - format!( - "_Static_assert(sizeof(struct {}) == {}, \"unexpected tagged union structure size\");", - data_type_entry.name.name, struct_size - ) - .as_bytes(), - )?; - pretty_writer.eob()?; - - // Add a macro for the tagged union size - macros::define( - cgenerator, - pretty_writer, - "BYTES", - &data_type_entry.name.name, - struct_size, - )?; - pretty_writer.eob()?; - - Ok(()) -} diff --git a/lucet-idl/src/generator.rs b/lucet-idl/src/generator.rs index e825cab8e..ccc192546 100644 --- a/lucet-idl/src/generator.rs +++ b/lucet-idl/src/generator.rs @@ -40,14 +40,6 @@ pub trait Generator { data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError>; - fn gen_tagged_union( - &mut self, - module: &Module, - cache: &mut Cache, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - ) -> Result<(), IDLError>; - fn gen_accessors_struct( &mut self, module: &Module, @@ -57,15 +49,6 @@ pub trait Generator { hierarchy: &Hierarchy, ) -> Result<(), IDLError>; - fn gen_accessors_tagged_union( - &mut self, - module: &Module, - cache: &Cache, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - hierarchy: &Hierarchy, - ) -> Result<(), IDLError>; - fn gen_accessors_enum( &mut self, module: &Module, @@ -97,9 +80,6 @@ pub trait Generator { DataType::Struct { .. } => { self.gen_struct(module, cache, pretty_writer, &data_type_entry) } - DataType::TaggedUnion { .. } => { - self.gen_tagged_union(module, cache, pretty_writer, &data_type_entry) - } DataType::Alias { .. } => { self.gen_alias(module, cache, pretty_writer, &data_type_entry) } @@ -130,13 +110,6 @@ pub trait Generator { DataType::Struct { .. } => { self.gen_accessors_struct(module, cache, pretty_writer, &data_type_entry, hierarchy) } - DataType::TaggedUnion { .. } => self.gen_accessors_tagged_union( - module, - cache, - pretty_writer, - &data_type_entry, - hierarchy, - ), DataType::Alias { .. } => { self.gen_accessors_alias(module, cache, pretty_writer, &data_type_entry, hierarchy) } diff --git a/lucet-idl/src/lexer.rs b/lucet-idl/src/lexer.rs index 53057987b..8e242c70e 100644 --- a/lucet-idl/src/lexer.rs +++ b/lucet-idl/src/lexer.rs @@ -24,7 +24,6 @@ pub enum Token<'a> { #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Keyword { Struct, // 'struct' - TaggedUnion, // 'taggedunion' Enum, // 'enum' Type, // 'type' } @@ -145,7 +144,6 @@ impl<'a> Lexer<'a> { token( match text { "struct" => Token::Keyword(Keyword::Struct), - "taggedunion" => Token::Keyword(Keyword::TaggedUnion), "enum" => Token::Keyword(Keyword::Enum), "type" => Token::Keyword(Keyword::Type), "i8" => Token::Atom(AtomType::I8), @@ -294,12 +292,8 @@ mod tests { #[test] fn keywords() { - let mut lex = Lexer::new("struct\ntaggedunion\nenum type"); + let mut lex = Lexer::new("struct\n\nenum type"); assert_eq!(lex.next(), token(Token::Keyword(Keyword::Struct), 1, 0)); - assert_eq!( - lex.next(), - token(Token::Keyword(Keyword::TaggedUnion), 2, 0) - ); assert_eq!(lex.next(), token(Token::Keyword(Keyword::Enum), 3, 0)); assert_eq!(lex.next(), token(Token::Keyword(Keyword::Type), 3, 5)); assert_eq!(lex.next(), None); diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index a88eeff62..13f7eccca 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -33,10 +33,6 @@ pub enum DataType { members: Vec>, attrs: Vec, }, - TaggedUnion { - members: Vec>>, - attrs: Vec, - }, Enum { members: Vec>, attrs: Vec, @@ -233,51 +229,6 @@ impl Module { }, ) } - SyntaxDecl::TaggedUnion { - name, - variants, - attrs, - location, - } => { - let mut uniq_vars = HashMap::new(); - let mut dtype_members = Vec::new(); - if variants.is_empty() { - Err(ValidationError::Empty { - name: name.clone(), - location: *location, - })? - } - for var in variants { - // Ensure that each member name is unique: - if let Some(existing) = uniq_vars.insert(var.name.clone(), var) { - Err(ValidationError::NameAlreadyExists { - name: var.name.clone(), - at_location: var.location, - previous_location: existing.location, - })? - } - // Get the DataTypeRef for the member, which ensures that it refers only to - // defined types: - let type_ = if let Some(ref t) = var.type_ { - Some(self.get_ref(t)?) - } else { - None - }; - // build the struct with this as the member: - dtype_members.push(NamedMember { - type_, - name: var.name.clone(), - attrs: var.attrs.clone(), - }) - } - self.define_data_type( - id, - DataType::TaggedUnion { - members: dtype_members, - attrs: attrs.clone(), - }, - ) - } SyntaxDecl::Enum { name, variants, @@ -348,13 +299,6 @@ impl Module { } } } - DataType::TaggedUnion { members, .. } => { - for mem in members { - if let Some(DataTypeRef::Defined(id)) = mem.type_ { - self.dfs_walk(id, visited, ordered)? - } - } - } DataType::Alias { to, .. } => { if let DataTypeRef::Defined(id) = to { self.dfs_walk(*id, visited, ordered)? @@ -508,82 +452,6 @@ mod tests { ); } - #[test] - fn tagged_unions() { - assert!(module("taggedunion foo { a: () }").is_ok()); - assert!(module("taggedunion foo { a: i32 }").is_ok()); - assert!(module("taggedunion foo { a: i32, b: f32 }").is_ok()); - assert!(module("taggedunion foo { a: i32, b: () }").is_ok()); - - { - let d = module("taggedunion foo { a: i32, b: () }").unwrap(); - let members = match &d.data_types[&0] { - DataType::TaggedUnion { members, .. } => members, - _ => panic!("Unexpected type"), - }; - assert_eq!(members[0].name, "a"); - assert_eq!(members[1].name, "b"); - match &members[0].type_ { - Some(DataTypeRef::Atom(AtomType::I32)) => (), - _ => panic!("Unexpected type"), - }; - match &members[1].type_ { - None => (), - _ => panic!("Unexpected type"), - }; - } - - // Recursive - assert!(module("taggedunion cons { succ: *cons, nil: () }").is_ok()); - - // Refer to a taggedunion defined previously: - assert!(module("taggedunion foo { a: i32, b: f64 } taggedunion bar { a: foo }").is_ok()); - // Refer to a taggedunion defined afterwards: - assert!(module("taggedunion foo { a: i32, b: bar} taggedunion bar { a: i32 }").is_ok()); - - // No members - assert_eq!( - module("taggedunion foo {}").err().unwrap(), - ValidationError::Empty { - name: "foo".to_owned(), - location: Location { line: 1, column: 0 }, - } - ); - - // Duplicate member in taggedunion - assert_eq!( - module("taggedunion foo { \na: i32, \na: f64}") - .err() - .unwrap(), - ValidationError::NameAlreadyExists { - name: "a".to_owned(), - at_location: Location { line: 3, column: 0 }, - previous_location: Location { line: 2, column: 0 }, - } - ); - - // Duplicate definition of name "foo" - assert_eq!( - module("taggedunion foo { a: i32 }\nstruct foo { a: i32 } ") - .err() - .unwrap(), - ValidationError::NameAlreadyExists { - name: "foo".to_owned(), - at_location: Location { line: 2, column: 0 }, - previous_location: Location { line: 1, column: 0 }, - } - ); - - // Refer to type that is not declared - assert_eq!( - module("taggedunion foo { \nb: bar }").err().unwrap(), - ValidationError::NameNotFound { - name: "bar".to_owned(), - use_location: Location { line: 2, column: 3 }, - } - ); - } - #[test] fn enums() { assert!(module("enum foo { a }").is_ok()); diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index 17ff2ae7a..b0dbdab5a 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -11,12 +11,6 @@ pub enum SyntaxDecl { attrs: Vec, location: Location, }, - TaggedUnion { - name: String, - variants: Vec, - attrs: Vec, - location: Location, - }, Enum { name: String, variants: Vec, @@ -35,7 +29,6 @@ impl SyntaxDecl { pub fn name(&self) -> &str { match self { SyntaxDecl::Struct { name, .. } => &name, - SyntaxDecl::TaggedUnion { name, .. } => &name, SyntaxDecl::Enum { name, .. } => &name, SyntaxDecl::Alias { name, .. } => &name, } @@ -43,7 +36,6 @@ impl SyntaxDecl { pub fn location(&self) -> &Location { match self { SyntaxDecl::Struct { location, .. } => &location, - SyntaxDecl::TaggedUnion { location, .. } => &location, SyntaxDecl::Enum { location, .. } => &location, SyntaxDecl::Alias { location, .. } => &location, } @@ -251,58 +243,6 @@ impl<'a> Parser<'a> { Ok(members) } - fn match_tagged_union_body(&mut self) -> Result, ParseError> { - let mut variants = Vec::new(); - let mut attrs = Vec::new(); - loop { - match self.token() { - Some(Token::RBrace) => { - self.consume(); - break; - } - Some(Token::Hash) => { - self.consume(); - attrs.push(self.match_attr_body()?); - } - Some(Token::Word(variant_name)) => { - let location = self.location; - self.consume(); - self.match_token(Token::Colon, "expected :")?; - - let type_ = match self.token() { - Some(Token::LPar) => { - self.consume(); - self.match_token(Token::RPar, "expected )")?; - None - } - _ => Some(self.match_ref("expected member type or ()")?), - }; - - variants.push(UnionVariant { - name: variant_name.to_owned(), - type_, - attrs: attrs.clone(), - location, - }); - attrs.clear(); - match self.token() { - Some(Token::Comma) => { - self.consume(); - continue; - } - Some(Token::RBrace) => { - self.consume(); - break; - } - _ => parse_err!(self.location, "expected , or }}")?, - } - } - _ => parse_err!(self.location, "expected variant")?, - } - } - Ok(variants) - } - fn match_enum_body(&mut self) -> Result, ParseError> { let mut names = Vec::new(); let mut attrs = Vec::new(); @@ -360,19 +300,6 @@ impl<'a> Parser<'a> { location, })); } - Some(Token::Keyword(Keyword::TaggedUnion)) => { - let location = self.location; - self.consume(); - let name = err_ctx!(err_msg, self.match_a_word("expected tagged union name"))?; - err_ctx!(err_msg, self.match_token(Token::LBrace, "expected {"))?; - let variants = err_ctx!(err_msg, self.match_tagged_union_body())?; - return Ok(Some(SyntaxDecl::TaggedUnion { - name: name.to_owned(), - variants, - attrs, - location, - })); - } Some(Token::Keyword(Keyword::Enum)) => { let location = self.location; self.consume(); @@ -656,189 +583,6 @@ mod tests { ); } - #[test] - fn tagged_unions() { - let mut parser = Parser::new("taggedunion foo {}"); - assert_eq!( - parser - .match_decl("empty tagged union") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::TaggedUnion { - name: "foo".to_owned(), - variants: Vec::new(), - attrs: Vec::new(), - location: Location { line: 1, column: 0 }, - }, - ); - let mut parser = Parser::new("taggedunion bar {a: (), }"); - // 0 12 17 - assert_eq!( - parser - .match_decl("tagged union, trailing comma") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::TaggedUnion { - name: "bar".to_owned(), - variants: vec![UnionVariant { - name: "a".to_owned(), - type_: None, - attrs: Vec::new(), - location: Location { - line: 1, - column: 17, - }, - }], - attrs: Vec::new(), - location: Location { line: 1, column: 0 }, - }, - ); - let mut parser = Parser::new("taggedunion bat {a : ( ) }"); - // 0 12 17 - assert_eq!( - parser - .match_decl("tagged union, no trailing comma") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::TaggedUnion { - name: "bat".to_owned(), - variants: vec![UnionVariant { - name: "a".to_owned(), - type_: None, - attrs: Vec::new(), - location: Location { - line: 1, - column: 17, - }, - }], - attrs: Vec::new(), - location: Location { line: 1, column: 0 }, - }, - ); - let mut parser = Parser::new("taggedunion baz {a:(), b:f32, }"); - // 0 12 17 23 - assert_eq!( - parser - .match_decl("2 member tagged union, trailing comma") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::TaggedUnion { - name: "baz".to_owned(), - variants: vec![ - UnionVariant { - name: "a".to_owned(), - type_: None, - attrs: Vec::new(), - location: Location { - line: 1, - column: 17, - }, - }, - UnionVariant { - name: "b".to_owned(), - type_: Some(SyntaxRef::Atom { - atom: AtomType::F32, - location: Location { - line: 1, - column: 25, - }, - }), - attrs: Vec::new(), - location: Location { - line: 1, - column: 23, - }, - }, - ], - attrs: Vec::new(), - location: Location { line: 1, column: 0 }, - }, - ); - let mut parser = Parser::new("taggedunion acab {a:(), b: something_else }"); - // 0 12 18 24 27 - assert_eq!( - parser - .match_decl("2 member tagged union, no trailing comma") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::TaggedUnion { - name: "acab".to_owned(), - variants: vec![ - UnionVariant { - name: "a".to_owned(), - type_: None, - attrs: Vec::new(), - location: Location { - line: 1, - column: 18, - }, - }, - UnionVariant { - name: "b".to_owned(), - type_: Some(SyntaxRef::Name { - name: "something_else".to_owned(), - location: Location { - line: 1, - column: 27, - }, - }), - attrs: Vec::new(), - location: Location { - line: 1, - column: 24, - }, - }, - ], - attrs: Vec::new(), - location: Location { line: 1, column: 0 }, - }, - ); - - let mut parser = Parser::new("#[attr1=ftp]\ntaggedunion acab {\n#[yes=\"all of them\"] are_complicit: (),\n#[especially= PPB\n]and_always: lie}"); - assert_eq!( - parser - .match_decl("2 member tagged union, no trailing comma, with attributes") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::TaggedUnion { - name: "acab".to_owned(), - variants: vec![ - UnionVariant { - name: "are_complicit".to_owned(), - type_: None, - attrs: vec![Attr::new( - "yes", - "all of them", - Location { line: 3, column: 0 }, - )], - location: Location { - line: 3, - column: 21, - }, - }, - UnionVariant { - name: "and_always".to_owned(), - type_: Some(SyntaxRef::Name { - name: "lie".to_owned(), - location: Location { - line: 5, - column: 13, - }, - }), - attrs: vec![Attr::new( - "especially", - "PPB", - Location { line: 4, column: 0 }, - )], - location: Location { line: 5, column: 1 }, - }, - ], - attrs: vec![Attr::new("attr1", "ftp", Location { line: 1, column: 0 })], - location: Location { line: 2, column: 0 }, - }, - ); - } - #[test] fn enums() { let mut parser = Parser::new("enum foo {}"); diff --git a/lucet-idl/src/rust/mod.rs b/lucet-idl/src/rust/mod.rs index bd63bc725..7dbd8cb8a 100644 --- a/lucet-idl/src/rust/mod.rs +++ b/lucet-idl/src/rust/mod.rs @@ -79,16 +79,6 @@ impl Generator for RustGenerator { unimplemented!() } - fn gen_tagged_union( - &mut self, - module: &Module, - cache: &mut Cache, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - ) -> Result<(), IDLError> { - unimplemented!() - } - fn gen_accessors_struct( &mut self, module: &Module, @@ -100,17 +90,6 @@ impl Generator for RustGenerator { unimplemented!() } - fn gen_accessors_tagged_union( - &mut self, - module: &Module, - cache: &Cache, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - hierarchy: &Hierarchy, - ) -> Result<(), IDLError> { - unimplemented!() - } - fn gen_accessors_enum( &mut self, module: &Module, From b53346a286787e7fa2e5ae28e73258c9cb56c792 Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Tue, 30 Apr 2019 11:00:33 -0700 Subject: [PATCH 111/512] avoid swapping an entire Instance of memory during drop, note sharp edges of Instance drop --- .../lucet-runtime-internals/src/instance.rs | 37 ++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index 714fb31dc..bc3d9359c 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -9,6 +9,7 @@ use crate::embed_ctx::CtxMap; use crate::error::Error; use crate::instance::siginfo_ext::SiginfoExt; use crate::module::{self, Global, Module}; +use crate::region::RegionInternal; use crate::sysdeps::UContext; use crate::val::{UntypedRetVal, Val}; use crate::WASM_PAGE_SIZE; @@ -141,12 +142,23 @@ impl DerefMut for InstanceHandle { impl Drop for InstanceHandle { fn drop(&mut self) { if self.needs_inst_drop { - // run the destructor by taking and dropping the inner `Instance` unsafe { - // make sure magic is zeroed, but allow everything else to be uninitialized - let mut uninit: Instance = mem::uninitialized(); - uninit.magic = 0; - mem::replace(self.inst.as_mut(), uninit); + let inst = self.inst.as_mut(); + + // Grab a handle to the region to ensure it outlives `inst`. + // + // This ensures that the region won't be dropped by `inst` being + // dropped, which could result in `inst` being unmapped by the + // Region *during* drop of the Instance's fields. + let region: Arc = inst.alloc().region.clone(); + + // drop the actual instance + std::ptr::drop_in_place(inst); + + // and now we can drop what may be the last Arc. If it is + // it can safely do what it needs with memory; we're not running + // destructors on it anymore. + mem::drop(region); } } } @@ -211,6 +223,21 @@ pub struct Instance { _padding: (), } +/// Users of `Instance` must be very careful about when instances are dropped! +/// +/// Typically you will not have to worry about this, as InstanceHandle will robustly handle +/// Instance drop semantics. If an instance is dropped, and the Region it's in has already dropped, +/// it may contain the last reference counted pointer to its Region. If so, when Instance's +/// destructor runs, Region will be dropped, and may free or otherwise invalidate the memory that +/// this Instance exists in, *while* the Instance destructor is executing. +impl Drop for Instance { + fn drop(&mut self) { + // Reset magic to indicate this instance + // is no longer valid + self.magic = 0; + } +} + /// APIs that are internal, but useful to implementors of extension modules; you probably don't want /// this trait! /// From 52144c2e2568d81838cdf221ec33594e61ec1807 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 30 Apr 2019 11:05:27 -0700 Subject: [PATCH 112/512] [lucet-runtime] make sigaltstack restore on a per-thread basis This was previously causing the Lucet sigstack to stay installed after an instance returns, as long as another instance was running. --- .../src/instance/signals.rs | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs index 10eb5fba9..da5c1d2a7 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs @@ -53,7 +53,9 @@ impl Instance { where F: FnOnce(&mut Instance) -> Result, { - // setup signal stack for this thread + // Set up the signal stack for this thread. Note that because signal stacks are per-thread, + // rather than per-process, we do this for every run, while the signal handler is installed + // only once per process. let guest_sigstack = SigStack::new( self.alloc.slot().sigstack, SigStackFlags::empty(), @@ -87,13 +89,6 @@ impl Instance { state.counter -= 1; if state.counter == 0 { unsafe { - // restore the host signal stack - if !altstack_flags() - .expect("the current stack flags could be retrieved") - .contains(SigStackFlags::SS_ONSTACK) - { - sigaltstack(previous_sigstack).expect("sigaltstack restoration succeeds"); - } restore_host_signal_state(state); } true @@ -107,6 +102,16 @@ impl Instance { *ostate = None; } + unsafe { + // restore the host signal stack for this thread + if !altstack_flags() + .expect("the current stack flags could be retrieved") + .contains(SigStackFlags::SS_ONSTACK) + { + sigaltstack(previous_sigstack).expect("sigaltstack restoration succeeds"); + } + } + res } } From 476b4e24cf67eac9a944f1300945535b658469a5 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sat, 27 Apr 2019 00:15:08 +0200 Subject: [PATCH 113/512] Add another explicit page zeroing when MADV_DONTNEED is not enough --- lucet-runtime/lucet-runtime-internals/src/region/mmap.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs index c97fd5e14..cdaee6e04 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs @@ -100,6 +100,13 @@ impl RegionInternal for MmapRegion { { // eprintln!("setting none {:p}[{:x}]", *ptr, len); unsafe { + // MADV_DONTNEED is not guaranteed to clear pages on non-Linux systems + #[cfg(not(target_os = "linux"))] + { + mprotect(*ptr, *len, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE) + .expect("mprotect succeeds during drop"); + memset(*ptr, 0, *len); + } mprotect(*ptr, *len, ProtFlags::PROT_NONE).expect("mprotect succeeds during drop"); madvise(*ptr, *len, MmapAdvise::MADV_DONTNEED) .expect("madvise succeeds during drop"); From c20ca5b7c2fab345f615dca3595366c28d5cdaac Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sat, 27 Apr 2019 01:10:19 +0200 Subject: [PATCH 114/512] Zero the heap only until the accessible size --- lucet-runtime/lucet-runtime-internals/src/region/mmap.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs index cdaee6e04..525364792 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs @@ -91,7 +91,8 @@ impl RegionInternal for MmapRegion { // clear and disable access to the heap, stack, globals, and sigstack for (ptr, len) in [ - (slot.heap, slot.limits.heap_address_space_size), + // We don't ever shrink the heap, so we only need to zero up until the accessible size + (slot.heap, alloc.heap_accessible_size), (slot.stack, slot.limits.stack_size), (slot.globals, slot.limits.globals_size), (slot.sigstack, SIGSTKSZ), From 0ffcccb670de29131bd2d1b6bf24da703623e169 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Mon, 29 Apr 2019 15:07:03 +0200 Subject: [PATCH 115/512] Update faerie to version 0.10 + support for extended ELF section Also update cranelift, that already moved to faerie 0.10. --- Cargo.lock | 99 +++++++++++++++++++++++++++-------------------- Cargo.toml | 2 +- cranelift | 2 +- faerie | 2 +- lucetc/Cargo.toml | 2 +- 5 files changed, 62 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a59350a30..f728afede 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -203,87 +203,87 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.29.0" +version = "0.30.0" dependencies = [ - "cranelift-entity 0.29.0", + "cranelift-entity 0.30.0", ] [[package]] name = "cranelift-codegen" -version = "0.29.0" +version = "0.30.0" dependencies = [ - "cranelift-bforest 0.29.0", - "cranelift-codegen-meta 0.29.0", - "cranelift-entity 0.29.0", + "cranelift-bforest 0.30.0", + "cranelift-codegen-meta 0.30.0", + "cranelift-entity 0.30.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-codegen-meta" -version = "0.29.0" +version = "0.30.0" dependencies = [ - "cranelift-entity 0.29.0", + "cranelift-entity 0.30.0", ] [[package]] name = "cranelift-entity" -version = "0.29.0" +version = "0.30.0" [[package]] name = "cranelift-faerie" -version = "0.29.0" +version = "0.30.0" dependencies = [ - "cranelift-codegen 0.29.0", - "cranelift-module 0.29.0", - "faerie 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen 0.30.0", + "cranelift-module 0.30.0", + "faerie 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-frontend" -version = "0.29.0" +version = "0.30.0" dependencies = [ - "cranelift-codegen 0.29.0", + "cranelift-codegen 0.30.0", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-module" -version = "0.29.0" +version = "0.30.0" dependencies = [ - "cranelift-codegen 0.29.0", - "cranelift-entity 0.29.0", + "cranelift-codegen 0.30.0", + "cranelift-entity 0.30.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-native" -version = "0.29.0" +version = "0.30.0" dependencies = [ - "cranelift-codegen 0.29.0", + "cranelift-codegen 0.30.0", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-wasm" -version = "0.29.0" +version = "0.30.0" dependencies = [ "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.29.0", - "cranelift-entity 0.29.0", - "cranelift-frontend 0.29.0", + "cranelift-codegen 0.30.0", + "cranelift-entity 0.30.0", + "cranelift-frontend 0.30.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -410,7 +410,7 @@ dependencies = [ [[package]] name = "faerie" -version = "0.9.1" +version = "0.10.0" dependencies = [ "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -421,14 +421,14 @@ dependencies = [ "string-interner 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "structopt-derive 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "faerie" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -replace = "faerie 0.9.1" +replace = "faerie 0.10.0" [[package]] name = "failure" @@ -751,14 +751,14 @@ dependencies = [ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.29.0", - "cranelift-faerie 0.29.0", - "cranelift-frontend 0.29.0", - "cranelift-module 0.29.0", - "cranelift-native 0.29.0", - "cranelift-wasm 0.29.0", + "cranelift-codegen 0.30.0", + "cranelift-faerie 0.30.0", + "cranelift-frontend 0.30.0", + "cranelift-module 0.30.0", + "cranelift-native 0.30.0", + "cranelift-wasm 0.30.0", "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "faerie 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "faerie 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1296,6 +1296,16 @@ dependencies = [ "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "target-lexicon" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tempfile" version = "3.0.7" @@ -1469,6 +1479,11 @@ name = "wasmparser" version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "wasmparser" +version = "0.29.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "which" version = "2.0.1" @@ -1565,7 +1580,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a" "checksum errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2a071601ed01b988f896ab14b95e67335d1eeb50190932a1320f7fe3cadc84e" "checksum errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067" -"checksum faerie 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f48412f92b56015a240e249847295b38b0a731435806c21a199403b2c317272c" +"checksum faerie 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c6d75e6376216d6228fbab8025087523666623d9302ff17dd023d024bf98302" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" @@ -1647,6 +1662,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)" = "d2b4cfac95805274c6afdb12d8f770fa2d27c045953e7b630a81801953699a9a" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" "checksum target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6923974ce4eb5bd28814756256d8ab71c28dd6e7483313fe7ab6614306bf633" +"checksum target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b0ab4982b8945c35cc1c46a83a9094c414f6828a099ce5dcaa8ee2b04642dcb" "checksum tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b86c784c88d98c801132806dadd3819ed29d8600836c4088e855cdf3e178ed8a" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" "checksum terminal_size 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "023345d35850b69849741bd9a5432aa35290e3d8eb76af8717026f270d1cf133" @@ -1668,6 +1684,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" "checksum wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5e01c420bc7d36e778bd242e1167b079562ba8b34087122cc9057187026d060" +"checksum wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)" = "981a8797cf89762e0233ec45fae731cb79a4dfaee12d9f0fe6cee01e4ac58d00" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" diff --git a/Cargo.toml b/Cargo.toml index 34eed17b3..f1ff22eb8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,4 +20,4 @@ exclude = ["cranelift"] rpath = true [replace] -"faerie:0.9.1" = { path = "faerie" } +"faerie:0.10.0" = { path = "faerie" } diff --git a/cranelift b/cranelift index 894cecc78..c0ee30f9a 160000 --- a/cranelift +++ b/cranelift @@ -1 +1 @@ -Subproject commit 894cecc78fa3169c7efd74bafb5165315f0f7f36 +Subproject commit c0ee30f9a95bd80bd6485c21bad7e8e0b8c5caf0 diff --git a/faerie b/faerie index ebe9edff9..dcb671a99 160000 --- a/faerie +++ b/faerie @@ -1 +1 @@ -Subproject commit ebe9edff906749bd52718b8552d560b232a608ff +Subproject commit dcb671a99faa32b72fac88d2406e952a41844636 diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index 108e8543e..11e3fabda 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -28,7 +28,7 @@ wasmparser = "0.23" clap="2.32" log = "0.4" env_logger = "0.6" -faerie = "0.9.1" +faerie = "0.10.0" failure = "0.1" serde = "1.0" serde_json = "1.0" From 5ee39812417a47d795da6a9827f04b3e0d2c2e84 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 30 Apr 2019 11:05:27 -0700 Subject: [PATCH 116/512] [lucet-runtime] make sigaltstack restore on a per-thread basis This was previously causing the Lucet sigstack to stay installed after an instance returns, as long as another instance was running. --- .../src/instance/signals.rs | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs index 67581e2db..68dc76ca6 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs @@ -54,7 +54,9 @@ impl Instance { where F: FnOnce(&mut Instance) -> Result, { - // setup signal stack for this thread + // Set up the signal stack for this thread. Note that because signal stacks are per-thread, + // rather than per-process, we do this for every run, while the signal handler is installed + // only once per process. let guest_sigstack = SigStack::new( self.alloc.slot().sigstack, SigStackFlags::empty(), @@ -88,13 +90,6 @@ impl Instance { state.counter -= 1; if state.counter == 0 { unsafe { - // restore the host signal stack - if !altstack_flags() - .expect("the current stack flags could be retrieved") - .contains(SigStackFlags::SS_ONSTACK) - { - sigaltstack(previous_sigstack).expect("sigaltstack restoration succeeds"); - } restore_host_signal_state(state); } true @@ -108,6 +103,16 @@ impl Instance { *ostate = None; } + unsafe { + // restore the host signal stack for this thread + if !altstack_flags() + .expect("the current stack flags could be retrieved") + .contains(SigStackFlags::SS_ONSTACK) + { + sigaltstack(previous_sigstack).expect("sigaltstack restoration succeeds"); + } + } + res } } From f726c9a1071e9adad61780e52d4a0d437140bb5c Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Thu, 18 Apr 2019 16:39:55 -0700 Subject: [PATCH 117/512] construct a function manifest directly from the corresponding cranelift module this provides a complete list of functions in the artifact, rather than what we were using - the subset that happened to possibly trap --- lucetc/src/compiler.rs | 18 ++++++++- lucetc/src/function_manifest.rs | 12 +----- lucetc/src/output.rs | 67 ++++++++++++++++++--------------- lucetc/src/stack_probe.rs | 2 +- 4 files changed, 55 insertions(+), 44 deletions(-) diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index 87927a1ec..4c683c289 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -19,7 +19,7 @@ use cranelift_module::{Backend as ClifBackend, Module as ClifModule}; use cranelift_native; use cranelift_wasm::{translate_module, FuncTranslator, WasmError}; use failure::{format_err, Fail, ResultExt}; -use lucet_module_data::ModuleData; +use lucet_module_data::{FunctionSpec, ModuleData}; #[derive(Debug, Clone, Copy)] pub enum OptLevel { @@ -136,7 +136,21 @@ impl<'a> Compiler<'a> { write_startfunc_data(&mut self.clif_module, &self.decls)?; write_table_data(&mut self.clif_module, &self.decls)?; - let obj = ObjectFile::new(self.clif_module.finish()).context(LucetcErrorKind::Output)?; + let function_manifest: Vec<(String, FunctionSpec)> = self + .clif_module + .declared_functions() + .filter_map(|f| { + f.compiled.as_ref().map(|compiled| { + ( + f.decl.name.to_owned(), // this copy is only necessary because `clif_module` is moved in `finish, below` + FunctionSpec::new(0, compiled.code_length(), 0, 0), + ) + }) + }) + .collect(); + + let obj = ObjectFile::new(self.clif_module.finish(), function_manifest) + .context(LucetcErrorKind::Output)?; Ok(obj) } diff --git a/lucetc/src/function_manifest.rs b/lucetc/src/function_manifest.rs index 71471b2e8..7d5309271 100644 --- a/lucetc/src/function_manifest.rs +++ b/lucetc/src/function_manifest.rs @@ -29,18 +29,8 @@ fn write_relocated_slice( /// /// Writes a manifest of functions, with relocations, to the artifact. /// -/// THIS IS NOT CURRENTLY A COMPLETE LIST OF FUNCTIONS. -/// -/// Currently the manifest returned here is the subset of functions -/// that happen to have traps. This manifest is only used, right now, -/// to look up trap manifest mappings, so this all lines up. -/// -/// The *order* of these functions are not (currently) guaranteed either! -/// Just that at the moment this order happens to be the same order as -/// `FaerieTrapManifest` lists. -/// pub fn write_function_manifest( - functions: &[(&str, FunctionSpec)], + functions: &[(String, FunctionSpec)], obj: &mut Artifact, ) -> Result<(), Error> { let manifest_len_sym = "lucet_function_manifest_len"; diff --git a/lucetc/src/output.rs b/lucetc/src/output.rs index ecdaf5d6a..9728fae31 100644 --- a/lucetc/src/output.rs +++ b/lucetc/src/output.rs @@ -1,3 +1,4 @@ +use crate::error::LucetcErrorKind; use crate::function_manifest::write_function_manifest; use crate::name::Name; use crate::stack_probe; @@ -40,46 +41,52 @@ pub struct ObjectFile { artifact: Artifact, } impl ObjectFile { - pub fn new(mut product: FaerieProduct) -> Result { + pub fn new( + mut product: FaerieProduct, + mut function_manifest: Vec<(String, FunctionSpec)>, + ) -> Result { stack_probe::declare_and_define(&mut product)?; - let trap_manifest = &product - .trap_manifest - .expect("trap manifest will be present"); - - // TODO: at this moment there is no way to get a full list of functions and sizes - // at this point in compilation. - // - // For now, we need the list of functions with traps, which we can get here. - let mut functions_and_names: Vec<(&str, FunctionSpec)> = vec![]; - for sink in trap_manifest.sinks.iter() { - functions_and_names.push(( - &sink.name, - FunctionSpec::new(0, sink.code_size, 0, sink.sites.len() as u64), - )); - } - // // stack_probe::declare_and_define adds a new function into `product`, but - // function_manifest was already constructed from all defined functions - - // so we have to add a new entry to `function_manifest` for the stack probe - functions_and_names.push(( - stack_probe::STACK_PROBE_SYM, + // function_manifest was already constructed from all defined functions. + // So, we have to add a new entry to `function_manifest` for the stack probe + function_manifest.push(( + stack_probe::STACK_PROBE_SYM.to_string(), FunctionSpec::new( 0, // there is no real address for the function until written to an object file stack_probe::STACK_PROBE_BINARY.len() as u32, - 0, // there is no real address for its trap table until written, either - trap_manifest - .sinks - .iter() - .find(|sink| sink.name == stack_probe::STACK_PROBE_SYM) - .expect("Stack probe may trap and must have a trap manifest entry") - .sites - .len() as u64, + 0, + 0, // fix up this FunctionSpec with trap info like any other ), )); + let trap_manifest = &product + .trap_manifest + .expect("trap manifest will be present"); + + // Now that we have trap information, we can fix up FunctionSpec entries to have + // correct `trap_length` values + let mut function_map: HashMap = HashMap::new(); + for (name, fn_spec) in function_manifest.into_iter() { + function_map.insert(name, fn_spec); + } + + for sink in trap_manifest.sinks.iter() { + if let Some(ref mut fn_spec) = function_map.get_mut(&sink.name) { + std::mem::replace::( + fn_spec, + FunctionSpec::new(0, fn_spec.code_len(), 0, sink.sites.len() as u64), + ); + } else { + Err(format_err!("Inconsistent state: trap records present for function {} but the function does not exist?", sink.name)) + .context(LucetcErrorKind::TranslatingModule)?; + } + } + + let function_manifest: Vec<(String, FunctionSpec)> = function_map.into_iter().collect(); + write_trap_tables(trap_manifest, &mut product.artifact)?; - write_function_manifest(&functions_and_names[..], &mut product.artifact)?; + write_function_manifest(function_manifest.as_slice(), &mut product.artifact)?; Ok(Self { artifact: product.artifact, diff --git a/lucetc/src/stack_probe.rs b/lucetc/src/stack_probe.rs index 5f331cf78..265c83819 100644 --- a/lucetc/src/stack_probe.rs +++ b/lucetc/src/stack_probe.rs @@ -19,7 +19,7 @@ use failure::Error; pub const STACK_PROBE_SYM: &'static str = "lucet_probestack"; /// The binary of the stack probe. -pub const STACK_PROBE_BINARY: &'static [u8] = &[ +pub(crate) const STACK_PROBE_BINARY: &'static [u8] = &[ // 49 89 c3 mov %rax,%r11 // 48 81 ec 00 10 00 00 sub $0x1000,%rsp // 48 85 64 24 08 test %rsp,0x8(%rsp) From 1dd8b74b1a4e9468d9c48d370f01a90859d0d3a6 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 30 Apr 2019 12:07:04 -0700 Subject: [PATCH 118/512] rustfmt --- lucet-idl/src/lexer.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lucet-idl/src/lexer.rs b/lucet-idl/src/lexer.rs index 8e242c70e..925c6c001 100644 --- a/lucet-idl/src/lexer.rs +++ b/lucet-idl/src/lexer.rs @@ -23,9 +23,9 @@ pub enum Token<'a> { #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Keyword { - Struct, // 'struct' - Enum, // 'enum' - Type, // 'type' + Struct, // 'struct' + Enum, // 'enum' + Type, // 'type' } #[derive(Debug, PartialEq, Eq, Clone, Copy)] From 49c4ee43c581cc2a723fb1291bdd3ae76ed1c2c7 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 30 Apr 2019 12:51:04 -0700 Subject: [PATCH 119/512] lucet-idl: fixup tests --- lucet-idl/src/module.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index 13f7eccca..e2d2b7375 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -529,7 +529,7 @@ mod tests { ); assert_eq!( - module("type foo = bar\nstruct bar { a: baz }\ntaggedunion baz { c: i32, e: foo }") + module("type foo = bar\nstruct bar { a: baz }\nstruct baz { c: i32, e: foo }") .err() .unwrap(), ValidationError::Infinite { From 1f259308125b337a37043d532d55c94fccdeed4c Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 30 Apr 2019 13:41:07 -0700 Subject: [PATCH 120/512] [lucet-runtime] improve clarity of Vmctx heap/globals views This patch renames these fields to emphasize that they are views into memory managed elsewhere, rather than a normal Rust-allocated structure. Also adds comments whenever we use `Box::leak()` to avoid normal Rust deallocation. --- .../lucet-runtime-internals/src/vmctx.rs | 52 ++++++++++++------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index fcbc99e26..a1700b87f 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -19,16 +19,28 @@ use std::cell::{Ref, RefCell, RefMut}; #[derive(Debug)] pub struct Vmctx { vmctx: *mut lucet_vmctx, - heap: RefCell>, - globals: RefCell>, + /// A view of the underlying instance's heap. + /// + /// This must never be dropped automatically, as the view does not own the heap. Rather, this is + /// a value used to implement dynamic borrowing of the heap contents that are owned and managed + /// by the instance and its `Alloc`. + heap_view: RefCell>, + /// A view of the underlying instance's globals. + /// + /// This must never be dropped automatically, as the view does not own the globals. Rather, this + /// is a value used to implement dynamic borrowing of the globals that are owned and managed by + /// the instance and its `Alloc`. + globals_view: RefCell>, } impl Drop for Vmctx { fn drop(&mut self) { - let heap = self.heap.replace(Box::new([])); - let globals = self.globals.replace(Box::new([])); - Box::leak(heap); - Box::leak(globals); + let heap_view = self.heap_view.replace(Box::new([])); + let globals_view = self.globals_view.replace(Box::new([])); + // as described in the definition of `Vmctx`, we cannot allow the boxed views of the heap + // and globals to be dropped + Box::leak(heap_view); + Box::leak(globals_view); } } @@ -68,8 +80,8 @@ impl Vmctx { let res = Vmctx { vmctx, - heap: RefCell::new(Box::<[u8]>::from_raw(inst.heap_mut())), - globals: RefCell::new(Box::<[i64]>::from_raw(inst.globals_mut())), + heap_view: RefCell::new(Box::<[u8]>::from_raw(inst.heap_mut())), + globals_view: RefCell::new(Box::<[i64]>::from_raw(inst.globals_mut())), }; res } @@ -85,10 +97,10 @@ impl Vmctx { /// terminate with `TerminationDetails::BorrowError`. pub fn heap(&self) -> Ref<[u8]> { unsafe { - self.reconstitute_heap_if_needed(); + self.reconstitute_heap_view_if_needed(); } let r = self - .heap + .heap_view .try_borrow() .unwrap_or_else(|_| panic!(TerminationDetails::BorrowError("heap"))); Ref::map(r, |b| b.borrow()) @@ -100,10 +112,10 @@ impl Vmctx { /// with `TerminationDetails::BorrowError`. pub fn heap_mut(&self) -> RefMut<[u8]> { unsafe { - self.reconstitute_heap_if_needed(); + self.reconstitute_heap_view_if_needed(); } let r = self - .heap + .heap_view .try_borrow_mut() .unwrap_or_else(|_| panic!(TerminationDetails::BorrowError("heap_mut"))); RefMut::map(r, |b| b.borrow_mut()) @@ -119,11 +131,15 @@ impl Vmctx { /// back into the guest via `Vmctx::get_func_from_idx()`. That guest code may grow the heap as /// well, causing any outstanding heap references to become invalid. We will address this when /// we rework the interface for calling back into the guest. - unsafe fn reconstitute_heap_if_needed(&self) { + unsafe fn reconstitute_heap_view_if_needed(&self) { let inst = self.instance_mut(); - if inst.heap_mut().len() != self.heap.borrow().len() { - let old_heap = self.heap.replace(Box::<[u8]>::from_raw(inst.heap_mut())); - Box::leak(old_heap); + if inst.heap_mut().len() != self.heap_view.borrow().len() { + let old_heap_view = self + .heap_view + .replace(Box::<[u8]>::from_raw(inst.heap_mut())); + // as described in the definition of `Vmctx`, we cannot allow the boxed view of the heap + // to be dropped + Box::leak(old_heap_view); } } @@ -190,7 +206,7 @@ impl Vmctx { /// with `TerminationDetails::BorrowError`. pub fn globals(&self) -> Ref<[i64]> { let r = self - .globals + .globals_view .try_borrow() .unwrap_or_else(|_| panic!(TerminationDetails::BorrowError("globals"))); Ref::map(r, |b| b.borrow()) @@ -202,7 +218,7 @@ impl Vmctx { /// terminate with `TerminationDetails::BorrowError`. pub fn globals_mut(&self) -> RefMut<[i64]> { let r = self - .globals + .globals_view .try_borrow_mut() .unwrap_or_else(|_| panic!(TerminationDetails::BorrowError("globals_mut"))); RefMut::map(r, |b| b.borrow_mut()) From 838190af55c84719f04c7df9ece83ac5df32358a Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 1 May 2019 18:08:00 +0200 Subject: [PATCH 121/512] Implement more filesystem-related hostcalls __wasi_path_create_directory __wasi_path_filestat_get __wasi_path_unlink_file __wasi_fd_filestat_get --- lucet-wasi/bindings.json | 6 +- lucet-wasi/src/host.rs | 58 +++++++++++++ lucet-wasi/src/hostcalls.rs | 154 +++++++++++++++++++++++++++++++++ lucet-wasi/src/memory.rs | 63 ++++++++++++++ lucet-wasi/tests/guests/stat.c | 54 ++++++++++++ lucet-wasi/tests/tests.rs | 15 ++++ 6 files changed, 349 insertions(+), 1 deletion(-) create mode 100644 lucet-wasi/tests/guests/stat.c diff --git a/lucet-wasi/bindings.json b/lucet-wasi/bindings.json index d96e68ad8..edb2a947a 100644 --- a/lucet-wasi/bindings.json +++ b/lucet-wasi/bindings.json @@ -10,13 +10,17 @@ "fd_close": "__wasi_fd_close", "fd_fdstat_get": "__wasi_fd_fdstat_get", "fd_fdstat_set_flags": "__wasi_fd_fdstat_set_flags", + "fd_filestat_get": "__wasi_fd_filestat_get", "fd_prestat_get": "__wasi_fd_prestat_get", "fd_prestat_dir_name": "__wasi_fd_prestat_dir_name", "fd_read": "__wasi_fd_read", "fd_seek": "__wasi_fd_seek", "fd_write": "__wasi_fd_write", + "path_create_directory": "__wasi_path_create_directory", + "path_filestat_get": "__wasi_path_filestat_get", + "path_unlink_file": "__wasi_path_unlink_file", "path_open": "__wasi_path_open", "poll_oneoff": "__wasi_poll_oneoff", "random_get": "__wasi_random_get" } -} \ No newline at end of file +} diff --git a/lucet-wasi/src/host.rs b/lucet-wasi/src/host.rs index d7e085d14..b06b74574 100644 --- a/lucet-wasi/src/host.rs +++ b/lucet-wasi/src/host.rs @@ -164,6 +164,64 @@ pub fn nix_from_oflags(oflags: __wasi_oflags_t) -> nix::fcntl::OFlag { nix_flags } +pub fn filetype_from_nix(sflags: nix::sys::stat::SFlag) -> __wasi_filetype_t { + use nix::sys::stat::SFlag; + if sflags.contains(SFlag::S_IFCHR) { + __WASI_FILETYPE_CHARACTER_DEVICE as __wasi_filetype_t + } else if sflags.contains(SFlag::S_IFBLK) { + __WASI_FILETYPE_BLOCK_DEVICE as __wasi_filetype_t + } else if sflags.contains(SFlag::S_IFIFO) | sflags.contains(SFlag::S_IFSOCK) { + __WASI_FILETYPE_SOCKET_STREAM as __wasi_filetype_t + } else if sflags.contains(SFlag::S_IFDIR) { + __WASI_FILETYPE_DIRECTORY as __wasi_filetype_t + } else if sflags.contains(SFlag::S_IFREG) { + __WASI_FILETYPE_REGULAR_FILE as __wasi_filetype_t + } else if sflags.contains(SFlag::S_IFLNK) { + __WASI_FILETYPE_SYMBOLIC_LINK as __wasi_filetype_t + } else { + __WASI_FILETYPE_UNKNOWN as __wasi_filetype_t + } +} + +pub fn nix_from_filetype(sflags: __wasi_filetype_t) -> nix::sys::stat::SFlag { + use nix::sys::stat::SFlag; + let mut nix_sflags = SFlag::empty(); + if sflags & (__WASI_FILETYPE_CHARACTER_DEVICE as __wasi_filetype_t) != 0 { + nix_sflags.insert(SFlag::S_IFCHR); + } + if sflags & (__WASI_FILETYPE_BLOCK_DEVICE as __wasi_filetype_t) != 0 { + nix_sflags.insert(SFlag::S_IFBLK); + } + if sflags & (__WASI_FILETYPE_SOCKET_STREAM as __wasi_filetype_t) != 0 { + nix_sflags.insert(SFlag::S_IFIFO); + nix_sflags.insert(SFlag::S_IFSOCK); + } + if sflags & (__WASI_FILETYPE_DIRECTORY as __wasi_filetype_t) != 0 { + nix_sflags.insert(SFlag::S_IFDIR); + } + if sflags & (__WASI_FILETYPE_REGULAR_FILE as __wasi_filetype_t) != 0 { + nix_sflags.insert(SFlag::S_IFREG); + } + if sflags & (__WASI_FILETYPE_SYMBOLIC_LINK as __wasi_filetype_t) != 0 { + nix_sflags.insert(SFlag::S_IFLNK); + } + nix_sflags +} + +pub fn filestat_from_nix(filestat: nix::sys::stat::FileStat) -> __wasi_filestat_t { + let filetype = nix::sys::stat::SFlag::from_bits_truncate(filestat.st_mode); + __wasi_filestat_t { + st_dev: filestat.st_dev as __wasi_device_t, + st_ino: filestat.st_ino as __wasi_inode_t, + st_nlink: filestat.st_nlink as __wasi_linkcount_t, + st_size: filestat.st_size as __wasi_filesize_t, + st_atim: filestat.st_atime as __wasi_timestamp_t, + st_ctim: filestat.st_ctime as __wasi_timestamp_t, + st_mtim: filestat.st_mtime as __wasi_timestamp_t, + st_filetype: filetype_from_nix(filetype), + } +} + // Rights sets from wasmtime-wasi sandboxed system primitives. Transcribed because bindgen can't // parse the #defines. diff --git a/lucet-wasi/src/hostcalls.rs b/lucet-wasi/src/hostcalls.rs index 9d88ba458..e6e17660d 100644 --- a/lucet-wasi/src/hostcalls.rs +++ b/lucet-wasi/src/hostcalls.rs @@ -557,6 +557,160 @@ pub extern "C" fn __wasi_fd_write( } } +#[no_mangle] +pub extern "C" fn __wasi_fd_filestat_get( + vmctx: *mut lucet_vmctx, + fd: wasm32::__wasi_fd_t, + filestat_ptr: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + use nix::sys::stat::fstat; + + let mut vmctx = unsafe { Vmctx::from_raw(vmctx) }; + let host_fd = dec_fd(fd); + let ctx: &mut WasiCtx = vmctx.get_embed_ctx_mut(); + + let errno = if let Some(fe) = ctx.fds.get(&host_fd) { + match fstat(fe.fd_object.rawfd) { + Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()), + Ok(filestat) => { + let host_filestat = host::filestat_from_nix(filestat); + unsafe { + enc_filestat_byref(&mut vmctx, filestat_ptr, host_filestat) + .expect("can write into the pointer"); + } + wasm32::__WASI_ESUCCESS + } + } + } else { + wasm32::__WASI_EBADF + }; + errno +} + +#[no_mangle] +pub extern "C" fn __wasi_path_filestat_get( + vmctx: *mut lucet_vmctx, + dirfd: wasm32::__wasi_fd_t, + dirflags: wasm32::__wasi_lookupflags_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, + filestat_ptr: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + use nix::fcntl::AtFlags; + use nix::sys::stat::fstatat; + let mut vmctx = unsafe { Vmctx::from_raw(vmctx) }; + let dirfd = dec_fd(dirfd); + let dirflags = dec_lookupflags(dirflags); + let path = match unsafe { dec_slice_of::(&mut vmctx, path_ptr, path_len) } { + Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + Err(e) => return enc_errno(e), + }; + let (dir, path) = match path_get( + &vmctx, + dirfd, + dirflags, + path, + host::__WASI_RIGHT_PATH_FILESTAT_GET as host::__wasi_rights_t, + 0, + false, + ) { + Ok((dir, path)) => (dir, path), + Err(e) => return enc_errno(e), + }; + let atflags = match dirflags { + 0 => AtFlags::empty(), + _ => AtFlags::AT_SYMLINK_NOFOLLOW, + }; + match fstatat(dir, path.as_os_str(), atflags) { + Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()), + Ok(filestat) => { + let host_filestat = host::filestat_from_nix(filestat); + unsafe { + enc_filestat_byref(&mut vmctx, filestat_ptr, host_filestat) + .expect("can write into the pointer"); + } + wasm32::__WASI_ESUCCESS + } + } +} + +#[no_mangle] +pub extern "C" fn __wasi_path_create_directory( + vmctx: *mut lucet_vmctx, + dirfd: wasm32::__wasi_fd_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, +) -> wasm32::__wasi_errno_t { + use nix::errno; + use nix::libc::mkdirat; + let mut vmctx = unsafe { Vmctx::from_raw(vmctx) }; + let dirfd = dec_fd(dirfd); + let path = match unsafe { dec_slice_of::(&mut vmctx, path_ptr, path_len) } { + Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + Err(e) => return enc_errno(e), + }; + let (dir, path) = match path_get( + &vmctx, + dirfd, + 0, + path, + (host::__WASI_RIGHT_PATH_OPEN | host::__WASI_RIGHT_PATH_CREATE_DIRECTORY) + as host::__wasi_rights_t, + 0, + false, + ) { + Ok((dir, path)) => (dir, path), + Err(e) => return enc_errno(e), + }; + let path_cstr = match std::ffi::CString::new(path.as_os_str().as_bytes()) { + Ok(path_cstr) => path_cstr, + Err(_) => return wasm32::__WASI_EINVAL, + }; + // nix doesn't expose mkdirat() yet + match unsafe { mkdirat(dir, path_cstr.as_ptr(), 0o777) } { + 0 => wasm32::__WASI_ESUCCESS, + _ => wasm32::errno_from_nix(errno::Errno::last()), + } +} + +#[no_mangle] +pub extern "C" fn __wasi_path_unlink_file( + vmctx: *mut lucet_vmctx, + dirfd: wasm32::__wasi_fd_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, +) -> wasm32::__wasi_errno_t { + use nix::errno; + use nix::libc::unlinkat; + let mut vmctx = unsafe { Vmctx::from_raw(vmctx) }; + let dirfd = dec_fd(dirfd); + let path = match unsafe { dec_slice_of::(&mut vmctx, path_ptr, path_len) } { + Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + Err(e) => return enc_errno(e), + }; + let (dir, path) = match path_get( + &vmctx, + dirfd, + 0, + path, + host::__WASI_RIGHT_PATH_UNLINK_FILE as host::__wasi_rights_t, + 0, + false, + ) { + Ok((dir, path)) => (dir, path), + Err(e) => return enc_errno(e), + }; + let path_cstr = match std::ffi::CString::new(path.as_os_str().as_bytes()) { + Ok(path_cstr) => path_cstr, + Err(_) => return wasm32::__WASI_EINVAL, + }; + // nix doesn't expose unlinkat() yet + match unsafe { unlinkat(dir, path_cstr.as_ptr(), 0) } { + 0 => wasm32::__WASI_ESUCCESS, + _ => wasm32::errno_from_nix(errno::Errno::last()), + } +} + #[no_mangle] pub extern "C" fn __wasi_path_open( vmctx: *mut lucet_vmctx, diff --git a/lucet-wasi/src/memory.rs b/lucet-wasi/src/memory.rs index 89cf9cfed..57f81e17b 100644 --- a/lucet-wasi/src/memory.rs +++ b/lucet-wasi/src/memory.rs @@ -190,6 +190,69 @@ dec_enc_scalar!( enc_fdflags, enc_fdflags_byref ); +dec_enc_scalar!( + __wasi_device_t, + dec_device, + dev_device_byref, + enc_device, + enc_device_byref +); +dec_enc_scalar!( + __wasi_inode_t, + dec_inode, + dev_inode_byref, + enc_inode, + enc_inode_byref +); +dec_enc_scalar!( + __wasi_linkcount_t, + dec_linkcount, + dev_linkcount_byref, + enc_linkcount, + enc_linkcount_byref +); + +pub fn dec_filestat(filestat: wasm32::__wasi_filestat_t) -> host::__wasi_filestat_t { + host::__wasi_filestat_t { + st_dev: dec_device(filestat.st_dev), + st_ino: dec_inode(filestat.st_ino), + st_filetype: dec_filetype(filestat.st_filetype), + st_nlink: dec_linkcount(filestat.st_nlink), + st_size: dec_filesize(filestat.st_size), + st_atim: dec_timestamp(filestat.st_atim), + st_mtim: dec_timestamp(filestat.st_mtim), + st_ctim: dec_timestamp(filestat.st_ctim), + } +} + +pub unsafe fn dec_filestat_byref( + vmctx: &mut Vmctx, + filestat_ptr: wasm32::uintptr_t, +) -> Result { + dec_pointee::(vmctx, filestat_ptr).map(dec_filestat) +} + +pub fn enc_filestat(filestat: host::__wasi_filestat_t) -> wasm32::__wasi_filestat_t { + wasm32::__wasi_filestat_t { + st_dev: enc_device(filestat.st_dev), + st_ino: enc_inode(filestat.st_ino), + st_filetype: enc_filetype(filestat.st_filetype), + st_nlink: enc_linkcount(filestat.st_nlink), + st_size: enc_filesize(filestat.st_size), + st_atim: enc_timestamp(filestat.st_atim), + st_mtim: enc_timestamp(filestat.st_mtim), + st_ctim: enc_timestamp(filestat.st_ctim), + } +} + +pub unsafe fn enc_filestat_byref( + vmctx: &mut Vmctx, + filestat_ptr: wasm32::uintptr_t, + host_filestat: host::__wasi_filestat_t, +) -> Result<(), host::__wasi_errno_t> { + let filestat = enc_filestat(host_filestat); + enc_pointee::(vmctx, filestat_ptr, filestat) +} pub fn dec_fdstat(fdstat: wasm32::__wasi_fdstat_t) -> host::__wasi_fdstat_t { host::__wasi_fdstat_t { diff --git a/lucet-wasi/tests/guests/stat.c b/lucet-wasi/tests/guests/stat.c new file mode 100644 index 000000000..7974c31d8 --- /dev/null +++ b/lucet-wasi/tests/guests/stat.c @@ -0,0 +1,54 @@ +#include + +#include +#include +#include +#include + +#define BASE_DIR "/sandbox" +#define OUTPUT_DIR BASE_DIR "/testdir" +#define PATH OUTPUT_DIR "/output.txt" +#define SIZE 500 + +int main(void) +{ + struct stat st; + int fd; + int ret; + off_t pos; + + (void) st; + ret = mkdir(OUTPUT_DIR, 0755); + assert(ret == 0); + + fd = open(PATH, O_CREAT | O_WRONLY, 0666); + assert(fd != -1); + + pos = lseek(fd, SIZE - 1, SEEK_SET); + assert(pos == SIZE - 1); + + ret = (int) write(fd, "", 1); + assert(ret == 1); + + ret = fstat(fd, &st); + assert(ret == 0); + assert(st.st_size == SIZE); + + ret = close(fd); + assert(ret == 0); + + ret = access(PATH, R_OK); + assert(ret == 0); + + ret = stat(PATH, &st); + assert(ret == 0); + assert(st.st_size == SIZE); + + ret = unlink(PATH); + assert(ret == 0); + + ret = stat(PATH, &st); + assert(ret == -1); + + return 0; +} \ No newline at end of file diff --git a/lucet-wasi/tests/tests.rs b/lucet-wasi/tests/tests.rs index 7874088af..f46afe020 100644 --- a/lucet-wasi/tests/tests.rs +++ b/lucet-wasi/tests/tests.rs @@ -363,3 +363,18 @@ fn poll() { let exitcode = run("poll.c", ctx).unwrap(); assert_eq!(exitcode, 0); } + +#[test] +fn stat() { + let tmpdir = TempDir::new().unwrap(); + let preopen_host_path = tmpdir.path().join("preopen"); + std::fs::create_dir(&preopen_host_path).unwrap(); + let preopen_dir = File::open(&preopen_host_path).unwrap(); + let ctx = WasiCtxBuilder::new() + .args(&["stat"]) + .preopened_dir(preopen_dir, "/sandbox") + .build() + .expect("can build WasiCtx"); + let exitcode = run("stat.c", ctx).unwrap(); + assert_eq!(exitcode, 0); +} From 5d3efb6005391a7c71d585732a5507b00db6bb1e Mon Sep 17 00:00:00 2001 From: awortman-fastly <49215183+awortman-fastly@users.noreply.github.com> Date: Fri, 3 May 2019 15:37:37 -0700 Subject: [PATCH 122/512] Ensure indirect calls with duplicate types check correctly (#168) * typecheck indirect calls correctly --- Cargo.lock | 1 + lucetc/Cargo.toml | 1 + lucetc/src/decls.rs | 31 ++++++++++++++++++++++++++----- lucetc/src/function.rs | 11 +++++++++-- lucetc/src/module.rs | 21 +++++++++++++++++++-- 5 files changed, 56 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e61d2d718..5dbc3b316 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -753,6 +753,7 @@ dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-codegen 0.30.0", + "cranelift-entity 0.30.0", "cranelift-faerie 0.30.0", "cranelift-frontend 0.30.0", "cranelift-module 0.30.0", diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index 11e3fabda..eeb9ad95a 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -17,6 +17,7 @@ path = "src/main.rs" [dependencies] bincode = "~1.0.1" cranelift-codegen = { path = "../cranelift/cranelift-codegen" } +cranelift-entity = { path = "../cranelift/cranelift-entity" } cranelift-native = { path = "../cranelift/cranelift-native" } cranelift-frontend = { path = "../cranelift/cranelift-frontend" } cranelift-module = { path = "../cranelift/cranelift-module" } diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index 0fe2eafc4..b9fef33c6 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -5,7 +5,7 @@ use crate::module::ModuleInfo; pub use crate::module::{Exportable, TableElems}; use crate::name::Name; use crate::runtime::{Runtime, RuntimeFunc}; -use cranelift_codegen::entity::{EntityRef, PrimaryMap}; +use cranelift_codegen::entity::{entity_impl, EntityRef, PrimaryMap}; use cranelift_codegen::ir; use cranelift_codegen::isa::TargetFrontendConfig; use cranelift_module::{Backend as ClifBackend, Linkage, Module as ClifModule}; @@ -20,11 +20,18 @@ use lucet_module_data::{ }; use std::collections::HashMap; +/// UniqueSignatureIndex names a signature after collapsing duplicate signatures to a single +/// identifier, whereas SignatureIndex is directly what the original module specifies, and may +/// specify duplicates of types that are structurally equal. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] +pub struct UniqueSignatureIndex(u32); +entity_impl!(UniqueSignatureIndex); + #[derive(Debug)] pub struct FunctionDecl<'a> { pub import_name: Option<(&'a str, &'a str)>, pub export_names: Vec<&'a str>, - pub signature_index: SignatureIndex, + pub signature_index: UniqueSignatureIndex, pub signature: &'a ir::Signature, pub name: Name, } @@ -101,7 +108,8 @@ impl<'a> ModuleDecls<'a> { for ix in 0..info.functions.len() { let func_index = FuncIndex::new(ix); let exportable_sigix = info.functions.get(func_index).unwrap(); - let signature = info.signatures.get(exportable_sigix.entity).unwrap(); + let inner_sig_index = info.signature_mapping.get(exportable_sigix.entity).unwrap(); + let signature = info.signatures.get(*inner_sig_index).unwrap(); let name = if let Some((import_mod, import_field)) = info.imported_funcs.get(func_index) { let import_symbol = bindings @@ -278,7 +286,7 @@ impl<'a> ModuleDecls<'a> { .get(func_index) .ok_or_else(|| format_err!("func index out of bounds: {:?}", func_index))?; let exportable_sigix = self.info.functions.get(func_index).unwrap(); - let signature_index = exportable_sigix.entity; + let signature_index = self.get_signature_uid(exportable_sigix.entity).unwrap(); let signature = self.info.signatures.get(signature_index).unwrap(); let import_name = self.info.imported_funcs.get(func_index); Ok(FunctionDecl { @@ -326,9 +334,22 @@ impl<'a> ModuleDecls<'a> { } pub fn get_signature(&self, signature_index: SignatureIndex) -> Result<&ir::Signature, Error> { + self.get_signature_uid(signature_index).and_then(|uid| { + self.info + .signatures + .get(uid) + .ok_or_else(|| format_err!("signature out of bounds: {:?}", uid)) + }) + } + + pub fn get_signature_uid( + &self, + signature_index: SignatureIndex, + ) -> Result { self.info - .signatures + .signature_mapping .get(signature_index) + .map(|x| *x) .ok_or_else(|| format_err!("signature out of bounds: {:?}", signature_index)) } diff --git a/lucetc/src/function.rs b/lucetc/src/function.rs index 244472445..8892e8bd1 100644 --- a/lucetc/src/function.rs +++ b/lucetc/src/function.rs @@ -161,11 +161,18 @@ impl<'a> FuncEnvironment for FuncInfo<'a> { table_entry_addr, table_entry_sig_offset, ); - // Check it against sig_index, trap if wrong + + // Translate from the module's non-unique signature space to our internal unique space + let unique_sig_index = self + .module_decls + .get_signature_uid(sig_index) + .expect("signature index must be valid"); + + // Check it against the unique sig_index, trap if wrong let valid_type = pos.ins().icmp_imm( ir::condcodes::IntCC::Equal, table_entry_sig_ix, - sig_index.as_u32() as i64, + unique_sig_index.as_u32() as i64, ); pos.ins().trapz(valid_type, ir::TrapCode::BadSignature); diff --git a/lucetc/src/module.rs b/lucetc/src/module.rs index aeb734b83..61ae0f032 100644 --- a/lucetc/src/module.rs +++ b/lucetc/src/module.rs @@ -1,4 +1,5 @@ //! Implements ModuleEnvironment for cranelift-wasm. Code derived from cranelift-wasm/environ/dummy.rs +use crate::decls::UniqueSignatureIndex; use crate::pointer::NATIVE_POINTER; use cranelift_codegen::entity::{EntityRef, PrimaryMap}; use cranelift_codegen::ir; @@ -44,8 +45,11 @@ pub struct DataInitializer<'a> { pub struct ModuleInfo<'a> { /// Target description used for codegen pub target_config: TargetFrontendConfig, + /// This mapping lets us merge duplicate types (permitted by the wasm spec) as they're + /// declared. + pub signature_mapping: PrimaryMap, /// Provided by `declare_signature` - pub signatures: PrimaryMap, + pub signatures: PrimaryMap, /// Provided by `declare_func_import` pub imported_funcs: PrimaryMap, /// Provided by `declare_global_import` @@ -79,6 +83,7 @@ impl<'a> ModuleInfo<'a> { pub fn new(target_config: TargetFrontendConfig) -> Self { Self { target_config, + signature_mapping: PrimaryMap::new(), signatures: PrimaryMap::new(), imported_funcs: PrimaryMap::new(), imported_globals: PrimaryMap::new(), @@ -106,7 +111,19 @@ impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { 0, ir::AbiParam::special(NATIVE_POINTER, ir::ArgumentPurpose::VMContext), ); - self.signatures.push(sig); + + let match_key = self + .signatures + .iter() + .find(|(_, v)| *v == &sig) + .map(|(key, _)| key) + .unwrap_or_else(|| { + let lucet_sig_ix = UniqueSignatureIndex::from_u32(self.signatures.len() as u32); + self.signatures.push(sig); + lucet_sig_ix + }); + + self.signature_mapping.push(match_key); } fn declare_func_import(&mut self, sig_index: SignatureIndex, module: &'a str, field: &'a str) { From d3464b3379d93a3d3ca4048bb285e02992d1b04a Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 6 May 2019 11:12:26 -0700 Subject: [PATCH 123/512] [lucet-benchmarks] make paths for file relative to the crate root --- benchmarks/lucet-benchmarks/src/modules.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/benchmarks/lucet-benchmarks/src/modules.rs b/benchmarks/lucet-benchmarks/src/modules.rs index 426364bb4..83eb3f494 100644 --- a/benchmarks/lucet-benchmarks/src/modules.rs +++ b/benchmarks/lucet-benchmarks/src/modules.rs @@ -7,11 +7,13 @@ use std::path::Path; use std::sync::Arc; fn wasi_bindings() -> Bindings { - Bindings::from_file("../../lucet-wasi/bindings.json").unwrap() + let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../lucet-wasi/bindings.json"); + Bindings::from_file(&path).unwrap() } pub fn compile_hello>(so_file: P) { - let wasm_build = Lucetc::new(&["guests/hello.c"]) + let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("guests/hello.c"); + let wasm_build = Lucetc::new(&[&path]) .with_print_output(true) .with_cflag("-Wall") .with_cflag("-Werror") From a08e7e8691aaeb4f7cbaa7f1823971eb07054d79 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 6 May 2019 11:39:42 -0700 Subject: [PATCH 124/512] lucet-runtime: rename SiginfoExt::si_addr to si_addr_ext libc 0.2.54 introduces a Siginfo::si_addr method, which conflicts with our trait's method. Unfortunately the libc method only exists on Linux. until libc supports it on mac OS as well, we have to keep using our trait. --- lucet-runtime/lucet-runtime-internals/src/instance.rs | 2 +- .../lucet-runtime-internals/src/instance/siginfo_ext.rs | 4 ++-- lucet-runtime/lucet-runtime-internals/src/instance/signals.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index 566e2f2fe..bf51bff8d 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -839,7 +839,7 @@ impl std::fmt::Display for State { write!( f, " accessed memory at {:p} (inside heap guard)", - siginfo.si_addr() + siginfo.si_addr_ext() )?; } Ok(()) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/siginfo_ext.rs b/lucet-runtime/lucet-runtime-internals/src/instance/siginfo_ext.rs index 354a3711e..863d8a868 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/siginfo_ext.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/siginfo_ext.rs @@ -5,11 +5,11 @@ extern "C" { } pub trait SiginfoExt { - fn si_addr(&self) -> *const c_void; + fn si_addr_ext(&self) -> *const c_void; } impl SiginfoExt for siginfo_t { - fn si_addr(&self) -> *const c_void { + fn si_addr_ext(&self) -> *const c_void { unsafe { siginfo_si_addr(self as *const siginfo_t) } } } diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs index 68dc76ca6..db5c30f4e 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs @@ -189,7 +189,7 @@ extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext // If the trap was a segv or bus fault and the addressed memory was outside the // guard pages, it is also a fatal error let outside_guard = (siginfo.si_signo == SIGSEGV || siginfo.si_signo == SIGBUS) - && !inst.alloc.addr_in_heap_guard(siginfo.si_addr()); + && !inst.alloc.addr_in_heap_guard(siginfo.si_addr_ext()); // record the fault and jump back to the host context inst.state = State::Fault { From 49aea13555ba592e709232ebafb343a6c8e3499d Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 6 May 2019 17:05:15 -0700 Subject: [PATCH 125/512] [lucet-benchmarks] add compile benchmarks and parameterize heap size --- .../lucet-benchmarks/benches/benchmarks.rs | 3 +- benchmarks/lucet-benchmarks/src/compile.rs | 31 +++++ benchmarks/lucet-benchmarks/src/lib.rs | 2 + benchmarks/lucet-benchmarks/src/modules.rs | 46 ++++--- benchmarks/lucet-benchmarks/src/par.rs | 3 +- benchmarks/lucet-benchmarks/src/seq.rs | 127 ++++++++++-------- 6 files changed, 134 insertions(+), 78 deletions(-) create mode 100644 benchmarks/lucet-benchmarks/src/compile.rs diff --git a/benchmarks/lucet-benchmarks/benches/benchmarks.rs b/benchmarks/lucet-benchmarks/benches/benchmarks.rs index 3ff3f6f78..df0bc6877 100644 --- a/benchmarks/lucet-benchmarks/benches/benchmarks.rs +++ b/benchmarks/lucet-benchmarks/benches/benchmarks.rs @@ -1,10 +1,11 @@ use criterion::Criterion; -use lucet_benchmarks::{context_benches, par_benches, seq_benches}; +use lucet_benchmarks::*; use lucet_runtime::MmapRegion; fn main() { let mut c = Criterion::default().configure_from_args(); + compile_benches(&mut c); context_benches(&mut c); seq_benches::(&mut c); par_benches::(&mut c); diff --git a/benchmarks/lucet-benchmarks/src/compile.rs b/benchmarks/lucet-benchmarks/src/compile.rs new file mode 100644 index 000000000..ff351531a --- /dev/null +++ b/benchmarks/lucet-benchmarks/src/compile.rs @@ -0,0 +1,31 @@ +use crate::modules::*; +use criterion::Criterion; +use lucetc::OptLevel; +use tempfile::TempDir; + +/// Compile Hello World with default optimizations. +fn compile_hello_all(c: &mut Criterion) { + fn body(workdir: &TempDir, opt_level: OptLevel) { + let out = workdir.path().join("out.so"); + compile_hello(out, opt_level); + } + + let bench = criterion::ParameterizedBenchmark::new( + "compile_hello", + move |b, &&opt_level| { + b.iter_batched_ref( + || TempDir::new().expect("create per-run working directory"), + |workdir| body(workdir, opt_level), + criterion::BatchSize::SmallInput, + ) + }, + &[OptLevel::Fastest, OptLevel::Default, OptLevel::Best], + ) + .sample_size(10); + + c.bench("compile", bench); +} + +pub fn compile_benches(c: &mut Criterion) { + compile_hello_all(c); +} diff --git a/benchmarks/lucet-benchmarks/src/lib.rs b/benchmarks/lucet-benchmarks/src/lib.rs index 1943b08dc..e6f436bba 100644 --- a/benchmarks/lucet-benchmarks/src/lib.rs +++ b/benchmarks/lucet-benchmarks/src/lib.rs @@ -1,8 +1,10 @@ +mod compile; mod context; mod modules; mod par; mod seq; +pub use compile::compile_benches; pub use context::context_benches; pub use par::par_benches; pub use seq::seq_benches; diff --git a/benchmarks/lucet-benchmarks/src/modules.rs b/benchmarks/lucet-benchmarks/src/modules.rs index 83eb3f494..d19360a51 100644 --- a/benchmarks/lucet-benchmarks/src/modules.rs +++ b/benchmarks/lucet-benchmarks/src/modules.rs @@ -2,7 +2,7 @@ use lucet_runtime::lucet_hostcalls; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime_internals::module::{HeapSpec, MockModuleBuilder, Module}; use lucet_wasi_sdk::{CompileOpts, Lucetc}; -use lucetc::{Bindings, LucetcOpts}; +use lucetc::{Bindings, LucetcOpts, OptLevel}; use std::path::Path; use std::sync::Arc; @@ -11,13 +11,13 @@ fn wasi_bindings() -> Bindings { Bindings::from_file(&path).unwrap() } -pub fn compile_hello>(so_file: P) { +pub fn compile_hello>(so_file: P, opt_level: OptLevel) { let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("guests/hello.c"); let wasm_build = Lucetc::new(&[&path]) - .with_print_output(true) .with_cflag("-Wall") .with_cflag("-Werror") - .with_bindings(wasi_bindings()); + .with_bindings(wasi_bindings()) + .with_opt_level(opt_level); wasm_build.build(&so_file).unwrap(); } @@ -30,46 +30,48 @@ pub fn null_mock() -> Arc { .build() } -pub fn large_dense_heap_mock() -> Arc { +pub fn large_dense_heap_mock(heap_kb: usize) -> Arc { extern "C" fn f(_vmctx: *mut lucet_vmctx) {} - const HEAP_LEN: usize = 4 * 1024 * 1024; - const HEAP_SPEC: HeapSpec = HeapSpec { - reserved_size: HEAP_LEN as u64, + let heap_len = heap_kb * 1024; + + let heap_spec = HeapSpec { + reserved_size: heap_len as u64, guard_size: 4 * 1024 * 1024, - initial_size: HEAP_LEN as u64, + initial_size: heap_len as u64, max_size: None, }; - let mut heap = vec![0x00; HEAP_LEN]; - (0..HEAP_LEN).into_iter().for_each(|i| { + let mut heap = vec![0x00; heap_len]; + (0..heap_len).into_iter().for_each(|i| { heap[i] = (i % 256) as u8; }); MockModuleBuilder::new() .with_export_func(b"f", f as *const extern "C" fn()) .with_initial_heap(heap.as_slice()) - .with_heap_spec(HEAP_SPEC) + .with_heap_spec(heap_spec) .build() } -pub fn large_sparse_heap_mock() -> Arc { +pub fn large_sparse_heap_mock(heap_kb: usize, stride: usize) -> Arc { extern "C" fn f(_vmctx: *mut lucet_vmctx) {} - const HEAP_LEN: usize = 4 * 1024 * 1024; - const HEAP_SPEC: HeapSpec = HeapSpec { - reserved_size: HEAP_LEN as u64, + let heap_len = heap_kb * 1024; + + let heap_spec = HeapSpec { + reserved_size: heap_len as u64, guard_size: 4 * 1024 * 1024, - initial_size: HEAP_LEN as u64, + initial_size: heap_len as u64, max_size: None, }; - let mut heap = vec![0x00; HEAP_LEN]; + let mut heap = vec![0x00; heap_len]; - // fill every eighth page with data - (0..HEAP_LEN) + // fill every `stride`th page with data + (0..heap_len) .into_iter() - .step_by(4096 * 8) + .step_by(4096 * stride) .for_each(|base| { for i in base..base + 4096 { heap[i] = (i % 256) as u8; @@ -79,7 +81,7 @@ pub fn large_sparse_heap_mock() -> Arc { MockModuleBuilder::new() .with_export_func(b"f", f as *const extern "C" fn()) .with_initial_heap(heap.as_slice()) - .with_heap_spec(HEAP_SPEC) + .with_heap_spec(heap_spec) .build() } diff --git a/benchmarks/lucet-benchmarks/src/par.rs b/benchmarks/lucet-benchmarks/src/par.rs index 036a3c9c0..23542116a 100644 --- a/benchmarks/lucet-benchmarks/src/par.rs +++ b/benchmarks/lucet-benchmarks/src/par.rs @@ -1,6 +1,7 @@ use crate::modules::{compile_hello, fib_mock, null_mock}; use criterion::Criterion; use lucet_runtime::{DlModule, InstanceHandle, Limits, Module, Region, RegionCreate}; +use lucetc::OptLevel; use rayon::prelude::*; use std::sync::Arc; use tempfile::TempDir; @@ -41,7 +42,7 @@ fn par_instantiate(c: &mut Criterion) { let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); - compile_hello(&so_file); + compile_hello(&so_file, OptLevel::Best); let module = DlModule::load(&so_file).unwrap(); diff --git a/benchmarks/lucet-benchmarks/src/seq.rs b/benchmarks/lucet-benchmarks/src/seq.rs index c090693b6..c2855ce47 100644 --- a/benchmarks/lucet-benchmarks/src/seq.rs +++ b/benchmarks/lucet-benchmarks/src/seq.rs @@ -2,6 +2,7 @@ use crate::modules::*; use criterion::Criterion; use lucet_runtime::{DlModule, InstanceHandle, Limits, Module, Region, RegionCreate}; use lucet_wasi::WasiCtxBuilder; +use lucetc::OptLevel; use std::path::Path; use std::sync::Arc; use tempfile::TempDir; @@ -14,7 +15,7 @@ use tempfile::TempDir; /// /// To minimize the effects of filesystem cache on the `DlModule::load()`, this runs `sync` between /// each iteration. -fn load_mkregion_and_instantiate(c: &mut Criterion) { +fn hello_load_mkregion_and_instantiate(c: &mut Criterion) { fn body(so_file: &Path) -> InstanceHandle { let module = DlModule::load(so_file).unwrap(); let region = R::create(1, &Limits::default()).unwrap(); @@ -24,10 +25,10 @@ fn load_mkregion_and_instantiate(c: &mut Criterion) { let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); - compile_hello(&so_file); + compile_hello(&so_file, OptLevel::Best); c.bench_function( - &format!("load_mkregion_and_instantiate ({})", R::TYPE_NAME), + &format!("hello_load_mkregion_and_instantiate ({})", R::TYPE_NAME), move |b| { b.iter_batched( || unsafe { nix::libc::sync() }, @@ -44,7 +45,7 @@ fn load_mkregion_and_instantiate(c: &mut Criterion) { /// /// This simulates a typical case for a server process like Terrarium: the region and module stay /// initialized, but a new instance is created for each request. -fn instantiate(c: &mut Criterion) { +fn hello_instantiate(c: &mut Criterion) { fn body(module: Arc, region: Arc) -> InstanceHandle { region.new_instance(module).unwrap() } @@ -52,12 +53,12 @@ fn instantiate(c: &mut Criterion) { let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); - compile_hello(&so_file); + compile_hello(&so_file, OptLevel::Best); let module = DlModule::load(&so_file).unwrap(); let region = R::create(1, &Limits::default()).unwrap(); - c.bench_function(&format!("instantiate ({})", R::TYPE_NAME), move |b| { + c.bench_function(&format!("hello_instantiate ({})", R::TYPE_NAME), move |b| { b.iter(|| body(module.clone(), region.clone())) }); @@ -65,13 +66,11 @@ fn instantiate(c: &mut Criterion) { } /// Instance instantiation with a large, dense heap. -fn instantiate_large_dense(c: &mut Criterion) { +fn instantiate_with_dense_heap(c: &mut Criterion) { fn body(module: Arc, region: Arc) -> InstanceHandle { region.new_instance(module).unwrap() } - let module = large_dense_heap_mock(); - let limits = Limits { heap_memory_size: 1024 * 1024 * 1024, ..Limits::default() @@ -79,20 +78,23 @@ fn instantiate_large_dense(c: &mut Criterion) { let region = R::create(1, &limits).unwrap(); - c.bench_function( - &format!("instantiate_large_dense ({})", R::TYPE_NAME), - move |b| b.iter(|| body(module.clone(), region.clone())), + c.bench_function_over_inputs( + &format!("instantiate_with_dense_heap ({})", R::TYPE_NAME), + move |b, &&heap_kb| { + let module = large_dense_heap_mock(heap_kb); + b.iter(|| body(module.clone(), region.clone())) + }, + // heap sizes in KiB + &[512, 1024, 2 * 1024, 4 * 1024], ); } /// Instance instantiation with a large, sparse heap. -fn instantiate_large_sparse(c: &mut Criterion) { +fn instantiate_with_sparse_heap(c: &mut Criterion) { fn body(module: Arc, region: Arc) -> InstanceHandle { region.new_instance(module).unwrap() } - let module = large_sparse_heap_mock(); - let limits = Limits { heap_memory_size: 1024 * 1024 * 1024, ..Limits::default() @@ -100,39 +102,48 @@ fn instantiate_large_sparse(c: &mut Criterion) { let region = R::create(1, &limits).unwrap(); - c.bench_function( - &format!("instantiate_large_sparse ({})", R::TYPE_NAME), - move |b| b.iter(|| body(module.clone(), region.clone())), + c.bench_function_over_inputs( + &format!("instantiate_with_sparse_heap ({})", R::TYPE_NAME), + move |b, &&heap_kb| { + // 8 means that only every eighth page has non-zero data + let module = large_sparse_heap_mock(heap_kb, 8); + b.iter(|| body(module.clone(), region.clone())) + }, + // heap sizes in KiB + &[512, 1024, 2 * 1024, 4 * 1024], ); } /// Instance destruction. /// /// Instances have some cleanup to do with memory management and freeing their slot on their region. -fn drop_instance(c: &mut Criterion) { +fn hello_drop_instance(c: &mut Criterion) { fn body(_inst: InstanceHandle) {} let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); - compile_hello(&so_file); + compile_hello(&so_file, OptLevel::Best); let module = DlModule::load(&so_file).unwrap(); let region = R::create(1, &Limits::default()).unwrap(); - c.bench_function(&format!("drop_instance ({})", R::TYPE_NAME), move |b| { - b.iter_batched( - || region.new_instance(module.clone()).unwrap(), - |inst| body(inst), - criterion::BatchSize::PerIteration, - ) - }); + c.bench_function( + &format!("hello_drop_instance ({})", R::TYPE_NAME), + move |b| { + b.iter_batched( + || region.new_instance(module.clone()).unwrap(), + |inst| body(inst), + criterion::BatchSize::PerIteration, + ) + }, + ); workdir.close().unwrap(); } /// Instance destruction with a large, dense heap. -fn drop_instance_large_dense(c: &mut Criterion) { +fn drop_instance_with_dense_heap(c: &mut Criterion) { fn body(_inst: InstanceHandle) {} let limits = Limits { @@ -140,23 +151,25 @@ fn drop_instance_large_dense(c: &mut Criterion) { ..Limits::default() }; - let module = large_dense_heap_mock(); let region = R::create(1, &limits).unwrap(); - c.bench_function( - &format!("drop_instance_large_dense ({})", R::TYPE_NAME), - move |b| { + c.bench_function_over_inputs( + &format!("drop_instance_with_dense_heap ({})", R::TYPE_NAME), + move |b, &&heap_kb| { + let module = large_dense_heap_mock(heap_kb); b.iter_batched( - || region.new_instance(module.clone()).unwrap(), + || region.clone().new_instance(module.clone()).unwrap(), |inst| body(inst), criterion::BatchSize::PerIteration, ) }, + // heap sizes in KiB + &[512, 1024, 2 * 1024, 4 * 1024], ); } /// Instance destruction with a large, sparse heap. -fn drop_instance_large_sparse(c: &mut Criterion) { +fn drop_instance_with_sparse_heap(c: &mut Criterion) { fn body(_inst: InstanceHandle) {} let limits = Limits { @@ -164,18 +177,21 @@ fn drop_instance_large_sparse(c: &mut Criterion) { ..Limits::default() }; - let module = large_sparse_heap_mock(); let region = R::create(1, &limits).unwrap(); - c.bench_function( - &format!("drop_instance_large_sparse ({})", R::TYPE_NAME), - move |b| { + c.bench_function_over_inputs( + &format!("drop_instance_with_sparse_heap ({})", R::TYPE_NAME), + move |b, &&heap_kb| { + // 8 means that only every eighth page has non-zero data + let module = large_sparse_heap_mock(heap_kb, 8); b.iter_batched( - || region.new_instance(module.clone()).unwrap(), + || region.clone().new_instance(module.clone()).unwrap(), |inst| body(inst), criterion::BatchSize::PerIteration, ) }, + // heap sizes in KiB + &[512, 1024, 2 * 1024, 4 * 1024], ); } @@ -230,7 +246,7 @@ fn run_hello(c: &mut Criterion) { let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); - compile_hello(&so_file); + compile_hello(&so_file, OptLevel::Best); let module = DlModule::load(&so_file).unwrap(); let region = R::create(1, &Limits::default()).unwrap(); @@ -358,13 +374,16 @@ fn run_hostcall_wrapped(c: &mut Criterion) { let module = hostcalls_mock(); let region = R::create(1, &Limits::default()).unwrap(); - c.bench_function(&format!("run_hostcall_wrapped ({})", R::TYPE_NAME), move |b| { - b.iter_batched_ref( - || region.new_instance(module.clone()).unwrap(), - |inst| body(inst), - criterion::BatchSize::PerIteration, - ) - }); + c.bench_function( + &format!("run_hostcall_wrapped ({})", R::TYPE_NAME), + move |b| { + b.iter_batched_ref( + || region.new_instance(module.clone()).unwrap(), + |inst| body(inst), + criterion::BatchSize::PerIteration, + ) + }, + ); } fn run_hostcall_raw(c: &mut Criterion) { @@ -385,13 +404,13 @@ fn run_hostcall_raw(c: &mut Criterion) { } pub fn seq_benches(c: &mut Criterion) { - load_mkregion_and_instantiate::(c); - instantiate::(c); - instantiate_large_dense::(c); - instantiate_large_sparse::(c); - drop_instance::(c); - drop_instance_large_dense::(c); - drop_instance_large_sparse::(c); + hello_load_mkregion_and_instantiate::(c); + hello_instantiate::(c); + instantiate_with_dense_heap::(c); + instantiate_with_sparse_heap::(c); + hello_drop_instance::(c); + drop_instance_with_dense_heap::(c); + drop_instance_with_sparse_heap::(c); run_null::(c); run_fib::(c); run_hello::(c); From eff46aa8ad7a56823a103ea19a83dc58c992d547 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 6 May 2019 17:17:18 -0700 Subject: [PATCH 126/512] [lucet-benchmarks] run with zero-sized heaps as well --- benchmarks/lucet-benchmarks/src/seq.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/benchmarks/lucet-benchmarks/src/seq.rs b/benchmarks/lucet-benchmarks/src/seq.rs index c2855ce47..8da0ceeef 100644 --- a/benchmarks/lucet-benchmarks/src/seq.rs +++ b/benchmarks/lucet-benchmarks/src/seq.rs @@ -85,7 +85,7 @@ fn instantiate_with_dense_heap(c: &mut Criterion) { b.iter(|| body(module.clone(), region.clone())) }, // heap sizes in KiB - &[512, 1024, 2 * 1024, 4 * 1024], + &[0, 512, 1024, 2 * 1024, 4 * 1024], ); } @@ -110,7 +110,7 @@ fn instantiate_with_sparse_heap(c: &mut Criterion) { b.iter(|| body(module.clone(), region.clone())) }, // heap sizes in KiB - &[512, 1024, 2 * 1024, 4 * 1024], + &[0, 512, 1024, 2 * 1024, 4 * 1024], ); } @@ -164,7 +164,7 @@ fn drop_instance_with_dense_heap(c: &mut Criterion) { ) }, // heap sizes in KiB - &[512, 1024, 2 * 1024, 4 * 1024], + &[0, 512, 1024, 2 * 1024, 4 * 1024], ); } @@ -191,7 +191,7 @@ fn drop_instance_with_sparse_heap(c: &mut Criterion) ) }, // heap sizes in KiB - &[512, 1024, 2 * 1024, 4 * 1024], + &[0, 512, 1024, 2 * 1024, 4 * 1024], ); } From 3e53f68ed28e8d1f12743b6842a0e1eb142c0372 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 6 May 2019 18:00:35 -0700 Subject: [PATCH 127/512] [lucet-benchmarks] add many-arg context benchmark --- benchmarks/lucet-benchmarks/src/context.rs | 297 +++++++++++++++++++++ 1 file changed, 297 insertions(+) diff --git a/benchmarks/lucet-benchmarks/src/context.rs b/benchmarks/lucet-benchmarks/src/context.rs index 9e4116d11..a61be4f3f 100644 --- a/benchmarks/lucet-benchmarks/src/context.rs +++ b/benchmarks/lucet-benchmarks/src/context.rs @@ -48,6 +48,302 @@ fn context_swap_return(c: &mut Criterion) { }); } +/// Swap to a trivial guest function that takes a bunch of arguments. +fn context_swap_return_many_args(c: &mut Criterion) { + extern "C" fn f( + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + _: u8, + _: u16, + _: u32, + _: u64, + _: f32, + _: f64, + ) { + } + + let args = vec![ + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + 0xAFu8.into(), + 0xAFu16.into(), + 0xAFu32.into(), + 0xAFu64.into(), + 175.0f32.into(), + 175.0f64.into(), + ]; + + c.bench_function("context_swap_return_many_args", move |b| { + b.iter_batched( + || { + let mut stack = vec![0u64; 1024].into_boxed_slice(); + let mut parent = ContextHandle::new(); + let child = ContextHandle::create_and_init( + &mut *stack, + &mut parent, + f as *const extern "C" fn(), + &args, + ) + .unwrap(); + (stack, parent, child) + }, + |(stack, mut parent, child)| unsafe { + Context::swap(&mut parent, &child); + stack + }, + criterion::BatchSize::PerIteration, + ) + }); +} + /// Time the call to sigprocmask as used in `Context::init()`. fn context_sigprocmask(c: &mut Criterion) { use nix::sys::signal; @@ -66,5 +362,6 @@ fn context_sigprocmask(c: &mut Criterion) { pub fn context_benches(c: &mut Criterion) { context_init(c); context_swap_return(c); + context_swap_return_many_args(c); context_sigprocmask(c); } From d52560986dce99909b0434a66a3bee4528c53312 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 6 May 2019 18:07:50 -0700 Subject: [PATCH 128/512] [lucet-benchmarks] add cases that combine context init and swap --- benchmarks/lucet-benchmarks/src/context.rs | 40 +++++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/benchmarks/lucet-benchmarks/src/context.rs b/benchmarks/lucet-benchmarks/src/context.rs index a61be4f3f..06d2017e8 100644 --- a/benchmarks/lucet-benchmarks/src/context.rs +++ b/benchmarks/lucet-benchmarks/src/context.rs @@ -48,8 +48,32 @@ fn context_swap_return(c: &mut Criterion) { }); } +/// Time initialization plus swap and return. +fn context_init_swap_return(c: &mut Criterion) { + extern "C" fn f() {} + + c.bench_function("context_init_swap_return", move |b| { + b.iter_batched( + || vec![0u64; 1024].into_boxed_slice(), + |mut stack| { + let mut parent = ContextHandle::new(); + let child = ContextHandle::create_and_init( + &mut *stack, + &mut parent, + f as *const extern "C" fn(), + &[], + ) + .unwrap(); + unsafe { Context::swap(&mut parent, &child) }; + stack + }, + criterion::BatchSize::PerIteration, + ) + }); +} + /// Swap to a trivial guest function that takes a bunch of arguments. -fn context_swap_return_many_args(c: &mut Criterion) { +fn context_init_swap_return_many_args(c: &mut Criterion) { extern "C" fn f( _: u8, _: u16, @@ -321,10 +345,10 @@ fn context_swap_return_many_args(c: &mut Criterion) { 175.0f64.into(), ]; - c.bench_function("context_swap_return_many_args", move |b| { + c.bench_function("context_init_swap_return_many_args", move |b| { b.iter_batched( - || { - let mut stack = vec![0u64; 1024].into_boxed_slice(); + || vec![0u64; 1024].into_boxed_slice(), + |mut stack| { let mut parent = ContextHandle::new(); let child = ContextHandle::create_and_init( &mut *stack, @@ -333,10 +357,7 @@ fn context_swap_return_many_args(c: &mut Criterion) { &args, ) .unwrap(); - (stack, parent, child) - }, - |(stack, mut parent, child)| unsafe { - Context::swap(&mut parent, &child); + unsafe { Context::swap(&mut parent, &child) }; stack }, criterion::BatchSize::PerIteration, @@ -362,6 +383,7 @@ fn context_sigprocmask(c: &mut Criterion) { pub fn context_benches(c: &mut Criterion) { context_init(c); context_swap_return(c); - context_swap_return_many_args(c); + context_init_swap_return(c); + context_init_swap_return_many_args(c); context_sigprocmask(c); } From 32e7361b9cd95831ed82c1070fbcf6d0f88806ad Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 6 May 2019 18:50:33 -0700 Subject: [PATCH 129/512] [lucet-benchmarks] add more smaller heap sizes --- benchmarks/lucet-benchmarks/src/seq.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/benchmarks/lucet-benchmarks/src/seq.rs b/benchmarks/lucet-benchmarks/src/seq.rs index 8da0ceeef..f673efb85 100644 --- a/benchmarks/lucet-benchmarks/src/seq.rs +++ b/benchmarks/lucet-benchmarks/src/seq.rs @@ -7,6 +7,8 @@ use std::path::Path; use std::sync::Arc; use tempfile::TempDir; +const HEAP_SIZES_KB: &'static [usize] = &[0, 32, 128, 512, 1024, 2 * 1024, 4 * 1024]; + /// End-to-end instance instantiation. /// /// This is meant to simulate our startup time when we start from scratch, with no module loaded and @@ -84,8 +86,7 @@ fn instantiate_with_dense_heap(c: &mut Criterion) { let module = large_dense_heap_mock(heap_kb); b.iter(|| body(module.clone(), region.clone())) }, - // heap sizes in KiB - &[0, 512, 1024, 2 * 1024, 4 * 1024], + HEAP_SIZES_KB, ); } @@ -109,8 +110,7 @@ fn instantiate_with_sparse_heap(c: &mut Criterion) { let module = large_sparse_heap_mock(heap_kb, 8); b.iter(|| body(module.clone(), region.clone())) }, - // heap sizes in KiB - &[0, 512, 1024, 2 * 1024, 4 * 1024], + HEAP_SIZES_KB, ); } @@ -163,8 +163,7 @@ fn drop_instance_with_dense_heap(c: &mut Criterion) { criterion::BatchSize::PerIteration, ) }, - // heap sizes in KiB - &[0, 512, 1024, 2 * 1024, 4 * 1024], + HEAP_SIZES_KB, ); } @@ -190,8 +189,7 @@ fn drop_instance_with_sparse_heap(c: &mut Criterion) criterion::BatchSize::PerIteration, ) }, - // heap sizes in KiB - &[0, 512, 1024, 2 * 1024, 4 * 1024], + HEAP_SIZES_KB, ); } From 6c7ccacced412a42f07e53ec24018f44603f0d3a Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 7 May 2019 09:43:59 -0700 Subject: [PATCH 130/512] [lucet-benchmarks] use different heap sizes for dense and sparse Results are misleading when heap size is close to the stride of the sparse heap --- benchmarks/lucet-benchmarks/src/seq.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/benchmarks/lucet-benchmarks/src/seq.rs b/benchmarks/lucet-benchmarks/src/seq.rs index f673efb85..69784e5fc 100644 --- a/benchmarks/lucet-benchmarks/src/seq.rs +++ b/benchmarks/lucet-benchmarks/src/seq.rs @@ -7,7 +7,9 @@ use std::path::Path; use std::sync::Arc; use tempfile::TempDir; -const HEAP_SIZES_KB: &'static [usize] = &[0, 32, 128, 512, 1024, 2 * 1024, 4 * 1024]; +const DENSE_HEAP_SIZES_KB: &'static [usize] = &[0, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2 * 1024, 4 * 1024]; + +const SPARSE_HEAP_SIZES_KB: &'static [usize] = &[0, 256, 512, 1024, 2 * 1024, 4 * 1024]; /// End-to-end instance instantiation. /// @@ -86,7 +88,7 @@ fn instantiate_with_dense_heap(c: &mut Criterion) { let module = large_dense_heap_mock(heap_kb); b.iter(|| body(module.clone(), region.clone())) }, - HEAP_SIZES_KB, + DENSE_HEAP_SIZES_KB, ); } @@ -110,7 +112,7 @@ fn instantiate_with_sparse_heap(c: &mut Criterion) { let module = large_sparse_heap_mock(heap_kb, 8); b.iter(|| body(module.clone(), region.clone())) }, - HEAP_SIZES_KB, + SPARSE_HEAP_SIZES_KB, ); } @@ -163,7 +165,7 @@ fn drop_instance_with_dense_heap(c: &mut Criterion) { criterion::BatchSize::PerIteration, ) }, - HEAP_SIZES_KB, + DENSE_HEAP_SIZES_KB, ); } @@ -189,7 +191,7 @@ fn drop_instance_with_sparse_heap(c: &mut Criterion) criterion::BatchSize::PerIteration, ) }, - HEAP_SIZES_KB, + SPARSE_HEAP_SIZES_KB, ); } From 2ad80bbbd973342f18336c5da71164ed8f82c0f5 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 7 May 2019 11:25:47 -0700 Subject: [PATCH 131/512] [lucet-benchmarks] add readme --- benchmarks/lucet-benchmarks/README.md | 34 +++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 benchmarks/lucet-benchmarks/README.md diff --git a/benchmarks/lucet-benchmarks/README.md b/benchmarks/lucet-benchmarks/README.md new file mode 100644 index 000000000..58ddfe605 --- /dev/null +++ b/benchmarks/lucet-benchmarks/README.md @@ -0,0 +1,34 @@ +# lucet-benchmarks + +This crate defines a suite of microbenchmarks for the Lucet compiler and runtime. It is divided into +several suites to measure different categories of performance. + +To run the suite, run `cargo bench -p lucet-benchmarks`. Since some of the benchmarks measure +operations with extremely small runtimes, make sure to close as many competing background +applications as possible. For the most consistent results, disable simultaneous multithreading and +dynamic frequency scaling features such as Hyper-Threading or Turbo Boost before benchmarking. + +## Benchmark Suites + +### `src/compiler.rs` + +The compiler suite measures the performance of `lucetc` when compiling WebAssembly modules. This +suite is still fairly rudimentary; we need to add more example guests, split out the `clang` step, +and add a programmatic interface to `lucetc` that doesn't require an output file. + +### `src/context.rs` + +The context suite measures the performance of the low-level context switching code used by the +runtime to swap between host and guest execution. + +### `src/par.rs` + +The parallel execution suite measures the performance of running various runtime operations in +parallel. This suite is still fairly rudimentary. + +### `src/seq.rs` + +The sequential execution suite measures the performance of single-threaded Lucet runtime use. It +attempts to isolate the main phases of instantiation, running, and dropping a Lucet instance, as +well as some basic guest code benchmarking. The shootout benchmarks in `/benchmarks/shootout` are a +better means of analyzing the performance of guest code. From a9a1fc0cfeb26d1344fc9bc3ebf5b9e1e9c73850 Mon Sep 17 00:00:00 2001 From: awortman-fastly <49215183+awortman-fastly@users.noreply.github.com> Date: Fri, 10 May 2019 14:01:36 -0700 Subject: [PATCH 132/512] Add function signatures to module data (#174) * add function signatures to module data also typecheck entrypoint functions at Instance::run, then fix tests that had ill-typed run calls * replace use of `*const extern "C" fn()` with `FunctionPointer`, which wraps the underlying address in many places `*const extern "C" fn()` indicated a value was a pointer to a function pointer, the actual address was *just* a function pointer. replacement with `FunctionPointer` includes cleaning up a few sites where this becomes apparent (most notably in a `mem::transmute<*const fn, fn>`) --- Cargo.lock | 4 + benchmarks/lucet-benchmarks/Cargo.toml | 2 + benchmarks/lucet-benchmarks/src/context.rs | 9 +- benchmarks/lucet-benchmarks/src/modules.rs | 18 +- lucet-module-data/Cargo.toml | 1 + lucet-module-data/src/functions.rs | 62 +++++++ lucet-module-data/src/lib.rs | 5 +- lucet-module-data/src/module_data.rs | 44 ++++- lucet-module-data/src/types.rs | 146 ++++++++++++++++ .../lucet-runtime-internals/Cargo.toml | 1 + .../src/alloc/tests.rs | 5 +- .../src/context/mod.rs | 16 +- .../src/context/tests/c_child.rs | 3 +- .../src/context/tests/mod.rs | 3 +- .../src/context/tests/rust_child.rs | 3 +- .../lucet-runtime-internals/src/instance.rs | 38 +++-- .../lucet-runtime-internals/src/module.rs | 31 +++- .../lucet-runtime-internals/src/module/dl.rs | 47 +++--- .../src/module/mock.rs | 157 +++++++++++++----- .../lucet-runtime-internals/src/val.rs | 20 +++ .../lucet-runtime-internals/src/vmctx.rs | 10 +- .../lucet-runtime-tests/src/entrypoint.rs | 148 +++++++++++++++-- .../lucet-runtime-tests/src/globals.rs | 18 +- .../lucet-runtime-tests/src/guest_fault.rs | 66 ++++---- .../lucet-runtime-tests/src/helpers.rs | 2 +- lucet-runtime/lucet-runtime-tests/src/host.rs | 30 +++- .../lucet-runtime-tests/src/strcmp.rs | 12 +- lucet-runtime/src/c_api.rs | 4 +- lucetc/src/compiler.rs | 21 ++- lucetc/src/decls.rs | 53 ++++-- lucetc/src/function_manifest.rs | 14 +- lucetc/src/module.rs | 2 +- lucetc/src/output.rs | 14 +- lucetc/tests/wasi-sdk.rs | 8 +- lucetc/tests/wasm.rs | 18 +- 35 files changed, 814 insertions(+), 221 deletions(-) create mode 100644 lucet-module-data/src/types.rs diff --git a/Cargo.lock b/Cargo.lock index 5dbc3b316..04ff8bdcd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -597,8 +597,10 @@ name = "lucet-benchmarks" version = "0.1.0" dependencies = [ "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "lucet-module-data 0.1.0", "lucet-runtime 0.1.0", "lucet-runtime-internals 0.1.0", + "lucet-runtime-tests 0.1.0", "lucet-wasi 0.1.0", "lucet-wasi-sdk 0.1.0", "lucetc 0.1.0", @@ -623,6 +625,7 @@ name = "lucet-module-data" version = "0.1.0" dependencies = [ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen 0.30.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -653,6 +656,7 @@ dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen 0.30.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/benchmarks/lucet-benchmarks/Cargo.toml b/benchmarks/lucet-benchmarks/Cargo.toml index 5ec47f3c2..f3eb926bd 100644 --- a/benchmarks/lucet-benchmarks/Cargo.toml +++ b/benchmarks/lucet-benchmarks/Cargo.toml @@ -7,8 +7,10 @@ edition = "2018" [dependencies] criterion = "0.2" lucetc = { path = "../../lucetc" } +lucet-module-data = { path = "../../lucet-module-data" } lucet-runtime = { path = "../../lucet-runtime" } lucet-runtime-internals = { path = "../../lucet-runtime/lucet-runtime-internals" } +lucet-runtime-tests = { path = "../../lucet-runtime/lucet-runtime-tests" } lucet-wasi = { path = "../../lucet-wasi" } lucet-wasi-sdk = { path = "../../lucet-wasi-sdk" } nix = "0.13" diff --git a/benchmarks/lucet-benchmarks/src/context.rs b/benchmarks/lucet-benchmarks/src/context.rs index 06d2017e8..6c3d9e7bf 100644 --- a/benchmarks/lucet-benchmarks/src/context.rs +++ b/benchmarks/lucet-benchmarks/src/context.rs @@ -1,4 +1,5 @@ use criterion::Criterion; +use lucet_module_data::FunctionPointer; use lucet_runtime_internals::context::{Context, ContextHandle}; /// Time the initialization of a context. @@ -13,7 +14,7 @@ fn context_init(c: &mut Criterion) { ContextHandle::create_and_init( &mut *stack, &mut parent, - f as *const extern "C" fn(), + FunctionPointer::from_usize(f as usize), &[], ) .unwrap(); @@ -33,7 +34,7 @@ fn context_swap_return(c: &mut Criterion) { let child = ContextHandle::create_and_init( &mut *stack, &mut parent, - f as *const extern "C" fn(), + FunctionPointer::from_usize(f as usize), &[], ) .unwrap(); @@ -60,7 +61,7 @@ fn context_init_swap_return(c: &mut Criterion) { let child = ContextHandle::create_and_init( &mut *stack, &mut parent, - f as *const extern "C" fn(), + FunctionPointer::from_usize(f as usize), &[], ) .unwrap(); @@ -353,7 +354,7 @@ fn context_init_swap_return_many_args(c: &mut Criterion) { let child = ContextHandle::create_and_init( &mut *stack, &mut parent, - f as *const extern "C" fn(), + FunctionPointer::from_usize(f as usize), &args, ) .unwrap(); diff --git a/benchmarks/lucet-benchmarks/src/modules.rs b/benchmarks/lucet-benchmarks/src/modules.rs index d19360a51..2834fe617 100644 --- a/benchmarks/lucet-benchmarks/src/modules.rs +++ b/benchmarks/lucet-benchmarks/src/modules.rs @@ -1,6 +1,8 @@ +use lucet_module_data::FunctionPointer; use lucet_runtime::lucet_hostcalls; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime_internals::module::{HeapSpec, MockModuleBuilder, Module}; +use lucet_runtime_tests::helpers::MockExportBuilder; use lucet_wasi_sdk::{CompileOpts, Lucetc}; use lucetc::{Bindings, LucetcOpts, OptLevel}; use std::path::Path; @@ -26,7 +28,7 @@ pub fn null_mock() -> Arc { extern "C" fn f(_vmctx: *mut lucet_vmctx) {} MockModuleBuilder::new() - .with_export_func(b"f", f as *const extern "C" fn()) + .with_export_func(MockExportBuilder::new(b"f", FunctionPointer::from_usize(f as usize))) .build() } @@ -48,7 +50,7 @@ pub fn large_dense_heap_mock(heap_kb: usize) -> Arc { }); MockModuleBuilder::new() - .with_export_func(b"f", f as *const extern "C" fn()) + .with_export_func(MockExportBuilder::new(b"f", FunctionPointer::from_usize(f as usize))) .with_initial_heap(heap.as_slice()) .with_heap_spec(heap_spec) .build() @@ -79,7 +81,7 @@ pub fn large_sparse_heap_mock(heap_kb: usize, stride: usize) -> Arc }); MockModuleBuilder::new() - .with_export_func(b"f", f as *const extern "C" fn()) + .with_export_func(MockExportBuilder::new(b"f", FunctionPointer::from_usize(f as usize))) .with_initial_heap(heap.as_slice()) .with_heap_spec(heap_spec) .build() @@ -100,7 +102,7 @@ pub fn fib_mock() -> Arc { } MockModuleBuilder::new() - .with_export_func(b"f", f as *const extern "C" fn()) + .with_export_func(MockExportBuilder::new(b"f", FunctionPointer::from_usize(f as usize))) .build() } @@ -177,7 +179,7 @@ pub fn many_args_mock() -> Arc { } MockModuleBuilder::new() - .with_export_func(b"f", f as *const extern "C" fn()) + .with_export_func(MockExportBuilder::new(b"f", FunctionPointer::from_usize(f as usize))) .build() } @@ -252,7 +254,9 @@ pub fn hostcalls_mock() -> Arc { } MockModuleBuilder::new() - .with_export_func(b"wrapped", wrapped as *const extern "C" fn()) - .with_export_func(b"raw", raw as *const extern "C" fn()) + .with_export_func( + MockExportBuilder::new(b"wrapped", FunctionPointer::from_usize(wrapped as usize))) + .with_export_func( + MockExportBuilder::new(b"raw", FunctionPointer::from_usize(raw as usize))) .build() } diff --git a/lucet-module-data/Cargo.toml b/lucet-module-data/Cargo.toml index 297d7a6ed..e3276447b 100644 --- a/lucet-module-data/Cargo.toml +++ b/lucet-module-data/Cargo.toml @@ -6,6 +6,7 @@ repository = "https://github.com/fastly/lucet" edition = "2018" [dependencies] +cranelift-codegen = { path = "../cranelift/cranelift-codegen" } failure = "0.1" serde = { version = "1.0", features = ["derive"] } bincode = "~1.0.1" diff --git a/lucet-module-data/src/functions.rs b/lucet-module-data/src/functions.rs index c8b27aea5..5eeddee72 100644 --- a/lucet-module-data/src/functions.rs +++ b/lucet-module-data/src/functions.rs @@ -1,7 +1,66 @@ use crate::traps::{TrapManifest, TrapSite}; +use cranelift_codegen::entity::entity_impl; +use serde::{Deserialize, Serialize}; use std::slice::from_raw_parts; +/// UniqueSignatureIndex names a signature after collapsing duplicate signatures to a single +/// identifier, whereas SignatureIndex is directly what the original module specifies, and may +/// specify duplicates of types that are structurally equal. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)] +pub struct UniqueSignatureIndex(u32); +entity_impl!(UniqueSignatureIndex); + +/// FunctionPointer serves entirely as a safer way to work with function pointers than as raw u64 +/// or usize values. It also avoids the need to write them as `fn` types, which cannot be freely +/// cast from one to another with `as`. If you need to call a `FunctionPointer`, use `as_usize()` +/// and transmute the resulting usize to a `fn` type with appropriate signature. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)] +pub struct FunctionPointer(usize); + +impl FunctionPointer { + pub fn from_usize(ptr: usize) -> FunctionPointer { + FunctionPointer(ptr) + } + pub fn as_usize(&self) -> usize { + self.0 + } +} + +/// Information about the corresponding function. +/// +/// This is split from but closely related to a [`FunctionSpec`]. The distinction is largely for +/// serialization/deserialization simplicity, as [`FunctionSpec`] contains fields that need +/// cooperation from a loader, with manual layout and serialization as a result. +/// [`FunctionMetadata`] is the remainder of fields that can be automatically +/// serialized/deserialied and are small enough copying isn't a large concern. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct FunctionMetadata<'a> { + pub signature: UniqueSignatureIndex, + #[serde(borrow)] + pub sym: Option<&'a [u8]>, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct OwnedFunctionMetadata { + pub signature: UniqueSignatureIndex, + pub sym: Option>, +} + +impl OwnedFunctionMetadata { + pub fn to_ref<'a>(&'a self) -> FunctionMetadata<'a> { + FunctionMetadata { + signature: self.signature.clone(), + sym: self.sym.as_ref().map(|s| s.as_slice()).clone(), + } + } +} + +pub struct FunctionHandle { + pub ptr: FunctionPointer, + pub id: u32 +} + // The layout of this struct is very tightly coupled to lucetc's `write_function_manifest`! // // Specifically, `write_function_manifest` sets up relocations on `code_addr` and `traps_addr`. @@ -23,6 +82,9 @@ impl FunctionSpec { pub fn new(code_addr: u64, code_len: u32, traps_addr: u64, traps_len: u64) -> Self { FunctionSpec { code_addr, code_len, traps_addr, traps_len } } + pub fn ptr(&self) -> FunctionPointer { + FunctionPointer::from_usize(self.code_addr as usize) + } pub fn code_len(&self) -> u32 { self.code_len } diff --git a/lucet-module-data/src/lib.rs b/lucet-module-data/src/lib.rs index deff08ddc..a42013dc3 100644 --- a/lucet-module-data/src/lib.rs +++ b/lucet-module-data/src/lib.rs @@ -9,17 +9,20 @@ mod globals; mod linear_memory; mod module_data; mod traps; +mod types; pub use crate::error::Error; pub use crate::globals::{Global, GlobalDef, GlobalSpec}; pub use crate::linear_memory::{HeapSpec, SparseData, LinearMemorySpec}; pub use crate::module_data::ModuleData; -pub use crate::functions::FunctionSpec; +pub use crate::functions::{FunctionHandle, FunctionMetadata, FunctionPointer, FunctionSpec, UniqueSignatureIndex}; pub use crate::traps::{TrapManifest, TrapSite, TrapCode}; +pub use crate::types::{Signature, ValueType}; /// Owned variants of the module data types, useful for serialization and testing. pub mod owned { pub use crate::globals::OwnedGlobalSpec; pub use crate::linear_memory::{OwnedSparseData, OwnedLinearMemorySpec}; pub use crate::module_data::OwnedModuleData; + pub use crate::functions::OwnedFunctionMetadata; } diff --git a/lucet-module-data/src/module_data.rs b/lucet-module-data/src/module_data.rs index 39b82bcaf..e42a30c2b 100644 --- a/lucet-module-data/src/module_data.rs +++ b/lucet-module-data/src/module_data.rs @@ -1,6 +1,8 @@ use crate::{ + functions::{FunctionMetadata, OwnedFunctionMetadata}, globals::GlobalSpec, linear_memory::{HeapSpec, LinearMemorySpec, SparseData}, + types::Signature, Error, }; use serde::{Deserialize, Serialize}; @@ -19,16 +21,23 @@ pub struct ModuleData<'a> { linear_memory: Option>, #[serde(borrow)] globals_spec: Vec>, + #[serde(borrow)] + function_info: Vec>, + signatures: Vec, } impl<'a> ModuleData<'a> { pub fn new( linear_memory: Option>, globals_spec: Vec>, + function_info: Vec>, + signatures: Vec, ) -> Self { Self { linear_memory, globals_spec, + function_info, + signatures, } } @@ -52,6 +61,31 @@ impl<'a> ModuleData<'a> { &self.globals_spec } + // Function index here is a different index space than `get_func_from_idx`, which + // uses function index as an index into a table of function elements. + // + // This is an index of all functions in the module. + pub fn get_signature(&self, fn_id: u32) -> &Signature { + let sig_idx = self.function_info[fn_id as usize].signature; + &self.signatures[sig_idx.as_u32() as usize] + } + + pub fn function_id_by_name(&self, name: &[u8]) -> Option { + self.function_info + .iter() + .enumerate() + .find(|(_, fn_meta)| { fn_meta.sym == Some(name) }) + .map(|(i, _)| i as u32) + } + + pub fn sym_for(&self, fn_id: u32) -> Option<&[u8]> { + self.function_info.get(fn_id as usize).and_then(|func| func.sym) + } + + pub fn signatures(&self) -> &[Signature] { + &self.signatures + } + /// Serialize to [`bincode`](https://github.com/TyOverby/bincode). pub fn serialize(&self) -> Result, Error> { bincode::serialize(self).map_err(Error::SerializationError) @@ -76,16 +110,22 @@ use crate::{ pub struct OwnedModuleData { linear_memory: Option, globals_spec: Vec, + function_info: Vec, + signatures: Vec, } impl OwnedModuleData { pub fn new( linear_memory: Option, globals_spec: Vec, + function_info: Vec, + signatures: Vec, ) -> Self { Self { linear_memory, globals_spec, + function_info, + signatures, } } @@ -99,11 +139,13 @@ impl OwnedModuleData { None }, self.globals_spec.iter().map(|gs| gs.to_ref()).collect(), + self.function_info.iter().map(|info| info.to_ref()).collect(), + self.signatures.clone(), ) } pub fn empty() -> Self { - Self::new(None, vec![]) + Self::new(None, vec![], vec![], vec![]) } pub fn with_heap_spec(mut self, heap_spec: HeapSpec) -> Self { diff --git a/lucet-module-data/src/types.rs b/lucet-module-data/src/types.rs new file mode 100644 index 000000000..1d5ce4898 --- /dev/null +++ b/lucet-module-data/src/types.rs @@ -0,0 +1,146 @@ +use std::convert::TryFrom; +use cranelift_codegen::ir; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] +pub enum ValueType { + I32, + I64, + F32, + F64, +} + +#[derive(Debug)] +pub enum ValueError { + Unrepresentable, + InvalidVMContext +} + +impl TryFrom<&ir::AbiParam> for ValueType { + type Error = ValueError; + + fn try_from(value: &ir::AbiParam) -> Result { + match value { + ir::AbiParam { + value_type: cranelift_ty, + purpose: ir::ArgumentPurpose::Normal, + extension: ir::ArgumentExtension::None, + location: ir::ArgumentLoc::Unassigned + } => { + let size = cranelift_ty.bits(); + + if cranelift_ty.is_int() { + match size { + 32 => Ok(ValueType::I32), + 64 => Ok(ValueType::I64), + _ => Err(ValueError::Unrepresentable), + } + } else if cranelift_ty.is_float() { + match size { + 32 => Ok(ValueType::F32), + 64 => Ok(ValueType::F64), + _ => Err(ValueError::Unrepresentable), + } + } else { + Err(ValueError::Unrepresentable) + } + }, + _ => Err(ValueError::Unrepresentable) + } + } +} + +/// A signature for a function in a wasm module. +/// +/// Note that this does not explicitly name VMContext as a parameter! It is assumed that all wasm +/// functions take VMContext as their first parameter. +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct Signature { + pub params: Vec, + // In the future, wasm may permit this to be a Vec of ValueType + pub ret_ty: Option, +} + +#[macro_export] +macro_rules! lucet_signature { + ((() -> ())) => { + $crate::Signature { + params: vec![], + ret_ty: None + } + }; + (($($arg_ty:ident),*) -> ()) => { + $crate::Signature { + params: vec![$($crate::ValueType::$arg_ty),*], + ret_ty: None, + } + }; + (($($arg_ty:ident),*) -> $ret_ty:ident) => { + $crate::Signature { + params: vec![$($crate::ValueType::$arg_ty),*], + ret_ty: Some($crate::ValueType::$ret_ty), + } + }; +} + +#[derive(Debug)] +pub enum SignatureError { + BadElement(ir::AbiParam, ValueError), + BadSignature +} + +impl TryFrom<&ir::Signature> for Signature { + type Error = SignatureError; + + fn try_from(value: &ir::Signature) -> Result { + let mut params: Vec = Vec::new(); + + let mut param_iter = value.params.iter(); + + // Enforce that the first parameter is VMContext, as Signature assumes. + // Even functions declared no-arg take VMContext in reality. + if let Some(param) = param_iter.next() { + match ¶m { + ir::AbiParam { + value_type: value, + purpose: ir::ArgumentPurpose::VMContext, + extension: ir::ArgumentExtension::None, + location: ir::ArgumentLoc::Unassigned + } => { + if value.is_int() && value.bits() == 64 { + // this is VMContext, so we can move on. + } else { + return Err(SignatureError::BadElement(param.to_owned(), ValueError::InvalidVMContext)); + } + }, + _ => { + return Err(SignatureError::BadElement(param.to_owned(), ValueError::InvalidVMContext)); + } + } + } else { + return Err(SignatureError::BadSignature); + } + + for param in param_iter { + let value_ty = ValueType::try_from(param) + .map_err(|e| SignatureError::BadElement(param.clone(), e))?; + + params.push(value_ty); + } + + let ret_ty: Option = match value.returns.as_slice() { + &[] => None, + &[ref ret_ty] => { + let value_ty = ValueType::try_from(ret_ty) + .map_err(|e| SignatureError::BadElement(ret_ty.clone(), e))?; + + Some(value_ty) + }, + _ => { + return Err(SignatureError::BadSignature); + } + }; + + Ok(Signature { params, ret_ty }) + } +} diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index fc23c0592..f05fe5f8a 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -9,6 +9,7 @@ lucet-module-data = { path = "../../lucet-module-data" } bitflags = "1.0" bincode = "~1.0.1" +cranelift-codegen = { path = "../../cranelift/cranelift-codegen" } failure = "0.1" lazy_static = "1.1" libc = "0.2.47" diff --git a/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs b/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs index ec5ec766b..dbd20a904 100644 --- a/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs +++ b/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs @@ -2,6 +2,7 @@ macro_rules! alloc_tests { ( $TestRegion:path ) => { use libc::c_void; + use lucet_module_data::FunctionPointer; use std::sync::Arc; use $TestRegion as TestRegion; use $crate::alloc::Limits; @@ -598,7 +599,7 @@ macro_rules! alloc_tests { let child = ContextHandle::create_and_init( inst.alloc_mut().stack_u64_mut(), &mut parent, - heap_touching_child as *const extern "C" fn(), + FunctionPointer::from_usize(heap_touching_child as usize), &[Val::CPtr(heap_ptr)], ) .expect("context init succeeds"); @@ -640,7 +641,7 @@ macro_rules! alloc_tests { let child = ContextHandle::create_and_init( inst.alloc_mut().stack_u64_mut(), &mut parent, - stack_pattern_child as *const extern "C" fn(), + FunctionPointer::from_usize(stack_pattern_child as usize), &[Val::CPtr(heap_ptr)], ) .expect("context init succeeds"); diff --git a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs index 787208c9f..e493320d9 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs @@ -5,6 +5,7 @@ mod tests; use crate::val::{val_to_reg, val_to_stack, RegVal, UntypedRetVal, Val}; use failure::Fail; +use lucet_module_data::FunctionPointer; use nix; use nix::sys::signal; use std::arch::x86_64::{__m128, _mm_setzero_ps}; @@ -193,7 +194,7 @@ impl ContextHandle { pub fn create_and_init( stack: &mut [u64], parent: &mut ContextHandle, - fptr: *const extern "C" fn(), + fptr: FunctionPointer, args: &[Val], ) -> Result { let mut child = ContextHandle::new(); @@ -239,6 +240,7 @@ impl Context { /// ``` /// /// ```no_run + /// # use lucet_module_data::FunctionPointer; /// # use lucet_runtime_internals::context::Context; /// # use lucet_runtime_internals::val::Val; /// extern "C" { fn entrypoint(x: u64, y: f32); } @@ -251,7 +253,7 @@ impl Context { /// &mut *stack, /// &mut parent, /// &mut child, - /// entrypoint as *const extern "C" fn(), + /// FunctionPointer::from_usize(entrypoint as usize), /// &[Val::U64(120), Val::F32(3.14)], /// ); /// assert!(res.is_ok()); @@ -264,6 +266,7 @@ impl Context { /// with C calling conventions. /// /// ```no_run + /// # use lucet_module_data::FunctionPointer; /// # use lucet_runtime_internals::context::{Context, ContextHandle}; /// # use lucet_runtime_internals::val::Val; /// extern "C" fn entrypoint(x: u64, y: f32) { } @@ -276,7 +279,7 @@ impl Context { /// &mut *stack, /// &mut parent, /// &mut child, - /// entrypoint as *const extern "C" fn(), + /// FunctionPointer::from_usize(entrypoint as usize), /// &[Val::U64(120), Val::F32(3.14)], /// ); /// assert!(res.is_ok()); @@ -285,7 +288,7 @@ impl Context { stack: &mut [u64], parent: &mut Context, child: &mut Context, - fptr: *const extern "C" fn(), + fptr: FunctionPointer, args: &[Val], ) -> Result<(), Error> { if !stack_is_aligned(stack) { @@ -343,7 +346,7 @@ impl Context { stack[sp + 0 - stack_start] = lucet_context_bootstrap as u64; // The bootstrap function returns into the guest function, fptr - stack[sp + 1 - stack_start] = fptr as u64; + stack[sp + 1 - stack_start] = fptr.as_usize() as u64; // the guest function returns into lucet_context_backstop. stack[sp + 2 - stack_start] = lucet_context_backstop as u64; @@ -428,6 +431,7 @@ impl Context { /// parent context. /// /// ```no_run + /// # use lucet_module_data::FunctionPointer; /// # use lucet_runtime_internals::context::Context; /// # extern "C" fn entrypoint() {} /// # let mut stack = vec![0u64; 1024].into_boxed_slice(); @@ -437,7 +441,7 @@ impl Context { /// &mut stack, /// &mut parent, /// &mut child, - /// entrypoint as *const extern "C" fn(), + /// FunctionPointer::from_usize(entrypoint as usize), /// &[], /// ).unwrap(); /// diff --git a/lucet-runtime/lucet-runtime-internals/src/context/tests/c_child.rs b/lucet-runtime/lucet-runtime-internals/src/context/tests/c_child.rs index dd33f548d..4ec3d5cc3 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/tests/c_child.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/tests/c_child.rs @@ -8,6 +8,7 @@ use crate::context::{Context, ContextHandle}; use crate::val::Val; use lazy_static::lazy_static; +use lucet_module_data::FunctionPointer; use std::ffi::CStr; use std::os::raw::{c_char, c_int, c_void}; use std::sync::Mutex; @@ -54,7 +55,7 @@ macro_rules! init_and_swap { let child = Box::into_raw(Box::new(ContextHandle::create_and_init( &mut *$stack, parent_regs.as_mut().unwrap(), - $fn as *const extern "C" fn(), + FunctionPointer::from_usize($fn as usize), &[$( $args ),*], ).unwrap())); diff --git a/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs b/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs index b01edaf10..f2b034b89 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs @@ -1,6 +1,7 @@ mod c_child; mod rust_child; use crate::context::{Context, ContextHandle, Error}; +use lucet_module_data::FunctionPointer; use memoffset::offset_of; use std::slice; @@ -35,7 +36,7 @@ fn init_rejects_unaligned() { let res = ContextHandle::create_and_init( &mut stack_unaligned, &mut parent, - dummy as *const extern "C" fn(), + FunctionPointer::from_usize(dummy as usize), &[], ); diff --git a/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs b/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs index fc982d8f7..f044e39df 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs @@ -3,6 +3,7 @@ use crate::context::{Context, ContextHandle}; use crate::val::{Val, __m128_as_f32, __m128_as_f64}; use lazy_static::lazy_static; +use lucet_module_data::FunctionPointer; use std::cell::RefCell; use std::fmt::Write; use std::os::raw::{c_int, c_void}; @@ -50,7 +51,7 @@ macro_rules! init_and_swap { let child = ContextHandle::create_and_init( &mut *$stack, PARENT.as_mut().unwrap(), - $fn as *const extern "C" fn(), + FunctionPointer::from_usize($fn as usize), &[$( $args ),*], ).unwrap(); CHILD = Some(child); diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index bf51bff8d..08e1673b3 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -14,7 +14,7 @@ use crate::sysdeps::UContext; use crate::val::{UntypedRetVal, Val}; use crate::WASM_PAGE_SIZE; use libc::{c_void, siginfo_t, uintptr_t, SIGBUS, SIGSEGV}; -use lucet_module_data::TrapCode; +use lucet_module_data::{FunctionHandle, FunctionPointer, TrapCode}; use memoffset::offset_of; use std::any::Any; use std::cell::{BorrowError, BorrowMutError, Ref, RefCell, RefMut, UnsafeCell}; @@ -215,7 +215,7 @@ pub struct Instance { >, /// Pointer to the function used as the entrypoint (for use in backtraces) - entrypoint: *const extern "C" fn(), + entrypoint: Option, /// `_padding` must be the last member of the structure. /// This marks where the padding starts to make the structure exactly 4096 bytes long. @@ -517,7 +517,7 @@ impl Instance { fatal_handler: default_fatal_handler, c_fatal_handler: None, signal_handler: Box::new(signal_handler_none) as Box, - entrypoint: ptr::null(), + entrypoint: None, _padding: (), }; inst.set_globals_ptr(globals_ptr); @@ -551,21 +551,37 @@ impl Instance { } /// Run a function in guest context at the given entrypoint. - fn run_func( - &mut self, - func: *const extern "C" fn(), - args: &[Val], - ) -> Result { + fn run_func(&mut self, func: FunctionHandle, args: &[Val]) -> Result { lucet_ensure!( self.state.is_ready() || (self.state.is_fault() && !self.state.is_fatal()), "instance must be ready or non-fatally faulted" ); - if func.is_null() { + if func.ptr.as_usize() == 0 { return Err(Error::InvalidArgument( "entrypoint function cannot be null; this is probably a malformed module", )); } - self.entrypoint = func; + + let sig = self.module.get_signature(func.id); + + // in typechecking these values, we can only really check that arguments are correct. + // in the future we might want to make return value use more type safe as well. + + if sig.params.len() != args.len() { + return Err(Error::InvalidArgument( + "entrypoint function signature mismatch (number of arguments is incorrect)", + )); + } + + for (param_ty, arg) in sig.params.iter().zip(args.iter()) { + if param_ty != &arg.value_type() { + return Err(Error::InvalidArgument( + "entrypoint function signature mismatch", + )); + } + } + + self.entrypoint = Some(func.ptr); let mut args_with_vmctx = vec![Val::from(self.alloc.slot().heap)]; args_with_vmctx.extend_from_slice(args); @@ -575,7 +591,7 @@ impl Instance { unsafe { self.alloc.stack_u64_mut() }, unsafe { &mut *host_ctx.get() }, &mut self.ctx, - func, + func.ptr, &args_with_vmctx, ) })?; diff --git a/lucet-runtime/lucet-runtime-internals/src/module.rs b/lucet-runtime/lucet-runtime-internals/src/module.rs index 43672c5f5..4eecd5267 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module.rs @@ -3,8 +3,11 @@ mod mock; mod sparse_page_data; pub use crate::module::dl::DlModule; -pub use crate::module::mock::MockModuleBuilder; -pub use lucet_module_data::{FunctionSpec, Global, GlobalSpec, HeapSpec, TrapCode, TrapManifest}; +pub use crate::module::mock::{MockExportBuilder, MockModuleBuilder}; +pub use lucet_module_data::{ + FunctionHandle, FunctionPointer, FunctionSpec, Global, GlobalSpec, HeapSpec, Signature, + TrapCode, TrapManifest, ValueType, +}; use crate::alloc::Limits; use crate::error::Error; @@ -53,20 +56,30 @@ pub trait ModuleInternal: Send + Sync { /// Get the table elements from the module. fn table_elements(&self) -> Result<&[TableElement], Error>; - fn get_export_func(&self, sym: &[u8]) -> Result<*const extern "C" fn(), Error>; + fn get_export_func(&self, sym: &[u8]) -> Result; - fn get_func_from_idx( - &self, - table_id: u32, - func_id: u32, - ) -> Result<*const extern "C" fn(), Error>; + fn get_func_from_idx(&self, table_id: u32, func_id: u32) -> Result; - fn get_start_func(&self) -> Result, Error>; + fn get_start_func(&self) -> Result, Error>; fn function_manifest(&self) -> &[FunctionSpec]; fn addr_details(&self, addr: *const c_void) -> Result, Error>; + fn get_signature(&self, fn_id: u32) -> &Signature; + + fn function_handle_from_ptr(&self, ptr: FunctionPointer) -> FunctionHandle { + let id = self + .function_manifest() + .iter() + .enumerate() + .find(|(_, fn_spec)| fn_spec.ptr() == ptr) + .map(|(fn_id, _)| fn_id as u32) + .expect("valid function pointer"); + + FunctionHandle { ptr, id } + } + /// Look up an instruction pointer in the trap manifest. /// /// This function must be signal-safe. diff --git a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs index 35f911842..5411f7d8a 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs @@ -2,7 +2,7 @@ use crate::error::Error; use crate::module::{AddrDetails, GlobalSpec, HeapSpec, Module, ModuleInternal, TableElement}; use libc::c_void; use libloading::{Library, Symbol}; -use lucet_module_data::{FunctionSpec, ModuleData}; +use lucet_module_data::{FunctionHandle, FunctionPointer, FunctionSpec, ModuleData, Signature}; use std::ffi::CStr; use std::mem; use std::path::Path; @@ -165,46 +165,43 @@ impl ModuleInternal for DlModule { Ok(unsafe { from_raw_parts(*p_table_segment, **p_table_segment_len as usize) }) } - fn get_export_func(&self, sym: &[u8]) -> Result<*const extern "C" fn(), Error> { + fn get_export_func(&self, sym: &[u8]) -> Result { let mut guest_sym: Vec = b"guest_func_".to_vec(); guest_sym.extend_from_slice(sym); - match unsafe { self.lib.get::<*const extern "C" fn()>(&guest_sym) } { - Err(ref e) if is_undefined_symbol(e) => Err(Error::SymbolNotFound( - String::from_utf8_lossy(sym).into_owned(), - )), - Err(e) => Err(Error::DlError(e)), - Ok(f) => Ok(*f), - } + + self.module_data + .function_id_by_name(&guest_sym) + .ok_or_else(|| Error::SymbolNotFound(String::from_utf8_lossy(sym).into_owned())) + .map(|id| { + let ptr = self.function_manifest()[id as usize].ptr(); + FunctionHandle { ptr, id } + }) } - fn get_func_from_idx( - &self, - table_id: u32, - func_id: u32, - ) -> Result<*const extern "C" fn(), Error> { + fn get_func_from_idx(&self, table_id: u32, func_id: u32) -> Result { if table_id != 0 { return Err(Error::FuncNotFound(table_id, func_id)); } let table = self.table_elements()?; - let func: extern "C" fn() = table + let func: FunctionPointer = table .get(func_id as usize) - .map(|element| unsafe { std::mem::transmute(element.rf) }) + .map(|element| FunctionPointer::from_usize(element.rf as usize)) .ok_or(Error::FuncNotFound(table_id, func_id))?; - Ok(&func as *const extern "C" fn()) + + Ok(self.function_handle_from_ptr(func)) } - fn get_start_func(&self) -> Result, Error> { + fn get_start_func(&self) -> Result, Error> { // `guest_start` is a pointer to the function the module designates as the start function, // since we can't have multiple symbols pointing to the same function and guest code might // call it in the normal course of execution - if let Ok(start_func) = unsafe { - self.lib - .get::<*const *const extern "C" fn()>(b"guest_start") - } { + if let Ok(start_func) = unsafe { self.lib.get::<*const extern "C" fn()>(b"guest_start") } { if start_func.is_null() { lucet_incorrect_module!("`guest_start` is defined but null"); } - Ok(Some(unsafe { **start_func })) + Ok(Some(self.function_handle_from_ptr( + FunctionPointer::from_usize(unsafe { **start_func } as usize), + ))) } else { Ok(None) } @@ -235,6 +232,10 @@ impl ModuleInternal for DlModule { Ok(None) } } + + fn get_signature(&self, fn_id: u32) -> &Signature { + self.module_data.get_signature(fn_id) + } } fn is_undefined_symbol(e: &std::io::Error) -> bool { diff --git a/lucet-runtime/lucet-runtime-internals/src/module/mock.rs b/lucet-runtime/lucet-runtime-internals/src/module/mock.rs index b12f2ce02..1120b6bae 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/mock.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/mock.rs @@ -2,9 +2,12 @@ use crate::error::Error; use crate::module::{AddrDetails, GlobalSpec, HeapSpec, Module, ModuleInternal, TableElement}; use libc::c_void; use lucet_module_data::owned::{ - OwnedGlobalSpec, OwnedLinearMemorySpec, OwnedModuleData, OwnedSparseData, + OwnedFunctionMetadata, OwnedGlobalSpec, OwnedLinearMemorySpec, OwnedModuleData, OwnedSparseData, +}; +use lucet_module_data::{ + FunctionHandle, FunctionPointer, FunctionSpec, ModuleData, Signature, TrapSite, + UniqueSignatureIndex, }; -use lucet_module_data::{FunctionSpec, ModuleData}; use std::collections::{BTreeMap, HashMap}; use std::sync::Arc; @@ -14,10 +17,12 @@ pub struct MockModuleBuilder { sparse_page_data: Vec>>, globals: BTreeMap, table_elements: BTreeMap, - export_funcs: HashMap, *const extern "C" fn()>, - func_table: HashMap<(u32, u32), *const extern "C" fn()>, - start_func: Option, + export_funcs: HashMap, FunctionPointer>, + func_table: HashMap<(u32, u32), FunctionPointer>, + start_func: Option, function_manifest: Vec, + function_info: Vec, + signatures: Vec, } impl MockModuleBuilder { @@ -99,28 +104,44 @@ impl MockModuleBuilder { self } - pub fn with_export_func(mut self, sym: &[u8], func: *const extern "C" fn()) -> Self { - self.export_funcs.insert(sym.to_vec(), func); - self + fn record_sig(&mut self, sig: Signature) -> UniqueSignatureIndex { + let idx = self + .signatures + .iter() + .enumerate() + .find(|(_, v)| *v == &sig) + .map(|(key, _)| key) + .unwrap_or_else(|| { + self.signatures.push(sig); + self.signatures.len() - 1 + }); + UniqueSignatureIndex::from_u32(idx as u32) } - pub fn with_table_func( - mut self, - table_idx: u32, - func_idx: u32, - func: *const extern "C" fn(), - ) -> Self { - self.func_table.insert((table_idx, func_idx), func); + pub fn with_export_func(mut self, export: MockExportBuilder) -> Self { + self.export_funcs + .insert(export.sym().to_vec(), export.func()); + let sig_idx = self.record_sig(export.sig()); + self.function_info.push(OwnedFunctionMetadata { + signature: sig_idx, + sym: Some(export.sym().to_vec()), + }); + self.function_manifest.push(FunctionSpec::new( + export.func().as_usize() as u64, + export.func_len() as u32, + export.traps().as_ptr() as u64, + export.traps().len() as u64, + )); self } - pub fn with_start_func(mut self, func: extern "C" fn()) -> Self { - self.start_func = Some(func); + pub fn with_table_func(mut self, table_idx: u32, func_idx: u32, func: FunctionPointer) -> Self { + self.func_table.insert((table_idx, func_idx), func); self } - pub fn with_function_manifest(mut self, function_manifest: &[FunctionSpec]) -> Self { - self.function_manifest = function_manifest.to_vec(); + pub fn with_start_func(mut self, func: FunctionPointer) -> Self { + self.start_func = Some(func); self } @@ -161,6 +182,8 @@ impl MockModuleBuilder { .expect("sparse data pages are valid"), }), globals_spec, + self.function_info.clone(), + self.signatures, ); let serialized_module_data = owned_module_data .to_ref() @@ -187,9 +210,9 @@ pub struct MockModule { serialized_module_data: Vec, module_data: ModuleData<'static>, pub table_elements: Vec, - pub export_funcs: HashMap, *const extern "C" fn()>, - pub func_table: HashMap<(u32, u32), *const extern "C" fn()>, - pub start_func: Option, + pub export_funcs: HashMap, FunctionPointer>, + pub func_table: HashMap<(u32, u32), FunctionPointer>, + pub start_func: Option, pub function_manifest: Vec, } @@ -223,28 +246,28 @@ impl ModuleInternal for MockModule { Ok(&self.table_elements) } - fn get_export_func(&self, sym: &[u8]) -> Result<*const extern "C" fn(), Error> { - self.export_funcs - .get(sym) - .cloned() - .ok_or(Error::SymbolNotFound( - String::from_utf8_lossy(sym).into_owned(), - )) + fn get_export_func(&self, sym: &[u8]) -> Result { + let ptr = *self.export_funcs.get(sym).ok_or(Error::SymbolNotFound( + String::from_utf8_lossy(sym).into_owned(), + ))?; + + Ok(self.function_handle_from_ptr(ptr)) } - fn get_func_from_idx( - &self, - table_id: u32, - func_id: u32, - ) -> Result<*const extern "C" fn(), Error> { - self.func_table + fn get_func_from_idx(&self, table_id: u32, func_id: u32) -> Result { + let ptr = self + .func_table .get(&(table_id, func_id)) .cloned() - .ok_or(Error::FuncNotFound(table_id, func_id)) + .ok_or(Error::FuncNotFound(table_id, func_id))?; + + Ok(self.function_handle_from_ptr(ptr)) } - fn get_start_func(&self) -> Result, Error> { - Ok(self.start_func.map(|start| start as *const extern "C" fn())) + fn get_start_func(&self) -> Result, Error> { + Ok(self + .start_func + .map(|start| self.function_handle_from_ptr(start))) } fn function_manifest(&self) -> &[FunctionSpec] { @@ -256,4 +279,62 @@ impl ModuleInternal for MockModule { // a way to determine whether or not we're in "module" code; punt for now Ok(None) } + + fn get_signature(&self, fn_id: u32) -> &Signature { + self.module_data.get_signature(fn_id) + } +} + +pub struct MockExportBuilder { + sym: &'static [u8], + func: FunctionPointer, + func_len: Option, + traps: Option<&'static [TrapSite]>, + sig: Signature, +} + +impl MockExportBuilder { + pub fn new(name: &'static [u8], func: FunctionPointer) -> MockExportBuilder { + MockExportBuilder { + sym: name, + func: func, + func_len: None, + traps: None, + sig: Signature { + params: vec![], + ret_ty: None, + }, + } + } + + pub fn with_func_len(mut self, len: usize) -> MockExportBuilder { + self.func_len = Some(len); + self + } + + pub fn with_traps(mut self, traps: &'static [TrapSite]) -> MockExportBuilder { + self.traps = Some(traps); + self + } + + pub fn with_sig(mut self, sig: Signature) -> MockExportBuilder { + self.sig = sig; + self + } + + pub fn sym(&self) -> &'static [u8] { + self.sym + } + pub fn func(&self) -> FunctionPointer { + self.func + } + pub fn func_len(&self) -> usize { + self.func_len.unwrap_or(1) + } + pub fn traps(&self) -> &'static [TrapSite] { + self.traps.unwrap_or(&[]) + } + pub fn sig(&self) -> Signature { + self.sig.clone() + } } diff --git a/lucet-runtime/lucet-runtime-internals/src/val.rs b/lucet-runtime/lucet-runtime-internals/src/val.rs index 8b836ce39..a49c0540d 100644 --- a/lucet-runtime/lucet-runtime-internals/src/val.rs +++ b/lucet-runtime/lucet-runtime-internals/src/val.rs @@ -7,6 +7,26 @@ use std::arch::x86_64::{ _mm_storeu_pd, _mm_storeu_ps, }; +use lucet_module_data::ValueType; + +impl Val { + pub fn value_type(&self) -> ValueType { + match self { + // USize, ISize, and CPtr are all as fits for definitions on the target architecture + // (wasm) which is all 32-bit. + Val::USize(_) | Val::ISize(_) | Val::CPtr(_) => ValueType::I32, + Val::GuestPtr(_) => ValueType::I32, + Val::I8(_) | Val::U8(_) | Val::I16(_) | Val::U16(_) | Val::I32(_) | Val::U32(_) => { + ValueType::I32 + } + Val::I64(_) | Val::U64(_) => ValueType::I64, + Val::Bool(_) => ValueType::I32, + Val::F32(_) => ValueType::F32, + Val::F64(_) => ValueType::F64, + } + } +} + /// Typed values used for passing arguments into guest functions. #[derive(Clone, Copy, Debug)] pub enum Val { diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index a1700b87f..52e3ee9e9 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -11,6 +11,7 @@ use crate::error::Error; use crate::instance::{ Instance, InstanceInternal, State, TerminationDetails, CURRENT_INSTANCE, HOST_CTX, }; +use lucet_module_data::FunctionHandle; use std::any::Any; use std::borrow::{Borrow, BorrowMut}; use std::cell::{Ref, RefCell, RefMut}; @@ -248,8 +249,11 @@ impl Vmctx { /// operand2: u32, /// ) -> u32 { /// if let Ok(binop) = vmctx.get_func_from_idx(binop_table_idx, binop_func_idx) { - /// let typed_binop = binop as *const extern "C" fn(*mut lucet_vmctx, u32, u32) -> u32; - /// unsafe { (*typed_binop)(vmctx.as_raw(), operand1, operand2) } + /// let typed_binop = std::mem::transmute::< + /// usize, + /// extern "C" fn(*mut lucet_vmctx, u32, u32) -> u32 + /// >(binop.ptr.as_usize()); + /// unsafe { (typed_binop)(vmctx.as_raw(), operand1, operand2) } /// } else { /// lucet_hostcall_terminate!("invalid function index") /// } @@ -259,7 +263,7 @@ impl Vmctx { &self, table_idx: u32, func_idx: u32, - ) -> Result<*const extern "C" fn(), Error> { + ) -> Result { self.instance() .module() .get_func_from_idx(table_idx, func_idx) diff --git a/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs b/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs index 480534329..894362cff 100644 --- a/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs +++ b/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs @@ -1,5 +1,6 @@ use crate::build::test_module_wasm; -use crate::helpers::MockModuleBuilder; +use crate::helpers::{MockExportBuilder, MockModuleBuilder}; +use lucet_module_data::{lucet_signature, FunctionPointer}; use lucet_runtime_internals::module::Module; use lucet_runtime_internals::vmctx::lucet_vmctx; use std::sync::Arc; @@ -119,14 +120,62 @@ pub fn mock_calculator_module() -> Arc { } MockModuleBuilder::new() - .with_export_func(b"add_2", add_2 as *const extern "C" fn()) - .with_export_func(b"add_10", add_10 as *const extern "C" fn()) - .with_export_func(b"mul_2", mul_2 as *const extern "C" fn()) - .with_export_func(b"add_f32_2", add_f32_2 as *const extern "C" fn()) - .with_export_func(b"add_f64_2", add_f64_2 as *const extern "C" fn()) - .with_export_func(b"add_f32_10", add_f32_10 as *const extern "C" fn()) - .with_export_func(b"add_f64_10", add_f64_10 as *const extern "C" fn()) - .with_export_func(b"add_mixed_20", add_mixed_20 as *const extern "C" fn()) + .with_export_func( + MockExportBuilder::new(b"add_2", FunctionPointer::from_usize(add_2 as usize)) + .with_sig(lucet_signature!((I64, I64) -> I64)), + ) + .with_export_func( + MockExportBuilder::new(b"add_10", FunctionPointer::from_usize(add_10 as usize)) + .with_sig(lucet_signature!( + (I64, I64, I64, I64, I64, I64, I64, I64, I64, I64) -> I64)), + ) + .with_export_func( + MockExportBuilder::new(b"mul_2", FunctionPointer::from_usize(mul_2 as usize)) + .with_sig(lucet_signature!((I64, I64) -> I64)), + ) + .with_export_func( + MockExportBuilder::new( + b"add_f32_2", + FunctionPointer::from_usize(add_f32_2 as usize), + ) + .with_sig(lucet_signature!((F32, F32) -> F32)), + ) + .with_export_func( + MockExportBuilder::new( + b"add_f64_2", + FunctionPointer::from_usize(add_f64_2 as usize), + ) + .with_sig(lucet_signature!((F64, F64) -> F64)), + ) + .with_export_func( + MockExportBuilder::new( + b"add_f32_10", + FunctionPointer::from_usize(add_f32_10 as usize), + ) + .with_sig(lucet_signature!( + (F32, F32, F32, F32, F32, F32, F32, F32, F32, F32) -> F32)), + ) + .with_export_func( + MockExportBuilder::new( + b"add_f64_10", + FunctionPointer::from_usize(add_f64_10 as usize), + ) + .with_sig(lucet_signature!( + (F64, F64, F64, F64, F64, F64, F64, F64, F64, F64) -> F64)), + ) + .with_export_func( + MockExportBuilder::new( + b"add_mixed_20", + FunctionPointer::from_usize(add_mixed_20 as usize), + ) + .with_sig(lucet_signature!( + ( + F64, I32, F32, F64, I32, F32, + F64, I32, F32, F64, I32, F32, + F64, I32, F32, F64, I64, F32, + F64, I64 + ) -> F64)), + ) .build() } @@ -468,6 +517,80 @@ macro_rules! entrypoint_tests { ); } + #[test] + fn mock_typecheck_entrypoint_wrong_args() { + typecheck_entrypoint_wrong_args(mock_calculator_module()) + } + + #[test] + fn wat_typecheck_entrypoint_wrong_args() { + typecheck_entrypoint_wrong_args(wat_calculator_module()) + } + + fn typecheck_entrypoint_wrong_args(module: Arc) { + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + match inst.run(b"add_2", &[123.0f64.into(), 456.0f64.into()]) { + Err(Error::InvalidArgument(err)) => { + assert_eq!(err, "entrypoint function signature mismatch") + } + res => panic!("unexpected result: {:?}", res), + } + } + + #[test] + fn mock_typecheck_entrypoint_too_few_args() { + typecheck_entrypoint_too_few_args(mock_calculator_module()) + } + + #[test] + fn wat_typecheck_entrypoint_too_few_args() { + typecheck_entrypoint_too_few_args(wat_calculator_module()) + } + + fn typecheck_entrypoint_too_few_args(module: Arc) { + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + match inst.run(b"add_2", &[123u64.into()]) { + Err(Error::InvalidArgument(err)) => assert_eq!( + err, + "entrypoint function signature mismatch (number of arguments is incorrect)" + ), + res => panic!("unexpected result: {:?}", res), + } + } + + #[test] + fn mock_typecheck_entrypoint_too_many_args() { + typecheck_entrypoint_too_many_args(mock_calculator_module()) + } + + #[test] + fn wat_typecheck_entrypoint_too_many_args() { + typecheck_entrypoint_too_many_args(wat_calculator_module()) + } + + fn typecheck_entrypoint_too_many_args(module: Arc) { + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + match inst.run(b"add_2", &[123u64.into(), 456u64.into(), 789u64.into()]) { + Err(Error::InvalidArgument(err)) => assert_eq!( + err, + "entrypoint function signature mismatch (number of arguments is incorrect)" + ), + res => panic!("unexpected result: {:?}", res), + } + } + use $crate::build::test_module_c; const TEST_REGION_INIT_VAL: libc::c_int = 123; const TEST_REGION_SIZE: libc::size_t = 4; @@ -728,8 +851,11 @@ macro_rules! entrypoint_tests { let func = vmctx .get_func_from_idx(0, cb_idx) .expect("can get function by index"); - let func = func as *const extern "C" fn(*mut lucet_vmctx, u64) -> u64; - (*func)(vmctx.as_raw(), x) + 1 + let func = std::mem::transmute::< + usize, + extern "C" fn(*mut lucet_vmctx, u64) -> u64 + >(func.ptr.as_usize()); + (func)(vmctx.as_raw(), x) + 1 } } diff --git a/lucet-runtime/lucet-runtime-tests/src/globals.rs b/lucet-runtime/lucet-runtime-tests/src/globals.rs index 74a7a1a54..6beecdb5e 100644 --- a/lucet-runtime/lucet-runtime-tests/src/globals.rs +++ b/lucet-runtime/lucet-runtime-tests/src/globals.rs @@ -1,12 +1,13 @@ #[macro_export] macro_rules! globals_tests { ( $TestRegion:path ) => { + use lucet_module_data::{lucet_signature, FunctionPointer}; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime::{Error, Limits, Module, Region}; use std::sync::Arc; use $TestRegion as TestRegion; use $crate::build::test_module_wasm; - use $crate::helpers::MockModuleBuilder; + use $crate::helpers::{MockExportBuilder, MockModuleBuilder}; #[test] fn defined_globals() { @@ -82,9 +83,18 @@ macro_rules! globals_tests { MockModuleBuilder::new() .with_global(0, -1) .with_global(1, 420) - .with_export_func(b"get_global0", get_global0 as *const extern "C" fn()) - .with_export_func(b"set_global0", set_global0 as *const extern "C" fn()) - .with_export_func(b"get_global1", get_global1 as *const extern "C" fn()) + .with_export_func( + MockExportBuilder::new(b"get_global0", FunctionPointer::from_usize(get_global0 as usize)) + .with_sig(lucet_signature!(() -> I64)) + ) + .with_export_func( + MockExportBuilder::new(b"set_global0", FunctionPointer::from_usize(set_global0 as usize)) + .with_sig(lucet_signature!((I64) -> ())) + ) + .with_export_func( + MockExportBuilder::new(b"get_global1", FunctionPointer::from_usize(get_global1 as usize)) + .with_sig(lucet_signature!(() -> I64)) + ) .build() } diff --git a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs index 1a0303ad9..4c2314fee 100644 --- a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs +++ b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs @@ -1,5 +1,5 @@ -use crate::helpers::MockModuleBuilder; -use lucet_module_data::{FunctionSpec, TrapCode, TrapSite}; +use crate::helpers::{MockExportBuilder, MockModuleBuilder}; +use lucet_module_data::{FunctionPointer, TrapCode, TrapSite}; use lucet_runtime_internals::module::Module; use lucet_runtime_internals::vmctx::lucet_vmctx; use std::sync::Arc; @@ -83,36 +83,40 @@ pub fn mock_traps_module() -> Arc { code: TrapCode::HeapOutOfBounds, }]; - let function_manifest = &[ - FunctionSpec::new( - guest_func_illegal_instr as *const extern "C" fn() as u64, - 11, - ILLEGAL_INSTR_TRAPS.as_ptr() as u64, - ILLEGAL_INSTR_TRAPS.len() as u64, - ), - FunctionSpec::new( - guest_func_oob as *const extern "C" fn() as u64, - 41, - OOB_TRAPS.as_ptr() as u64, - OOB_TRAPS.len() as u64, - ), - ]; - MockModuleBuilder::new() - .with_export_func(b"onetwothree", onetwothree as *const extern "C" fn()) + .with_export_func(MockExportBuilder::new( + b"onetwothree", + FunctionPointer::from_usize(onetwothree as usize), + )) .with_export_func( - b"illegal_instr", - guest_func_illegal_instr as *const extern "C" fn(), + MockExportBuilder::new( + b"illegal_instr", + FunctionPointer::from_usize(guest_func_illegal_instr as usize), + ) + .with_func_len(11) + .with_traps(ILLEGAL_INSTR_TRAPS), ) - .with_export_func(b"oob", guest_func_oob as *const extern "C" fn()) - .with_export_func(b"hostcall_main", hostcall_main as *const extern "C" fn()) - .with_export_func(b"infinite_loop", infinite_loop as *const extern "C" fn()) - .with_export_func(b"fatal", fatal as *const extern "C" fn()) .with_export_func( - b"recoverable_fatal", - recoverable_fatal as *const extern "C" fn(), + MockExportBuilder::new(b"oob", FunctionPointer::from_usize(guest_func_oob as usize)) + .with_func_len(41) + .with_traps(OOB_TRAPS), ) - .with_function_manifest(function_manifest) + .with_export_func(MockExportBuilder::new( + b"hostcall_main", + FunctionPointer::from_usize(hostcall_main as usize), + )) + .with_export_func(MockExportBuilder::new( + b"infinite_loop", + FunctionPointer::from_usize(infinite_loop as usize), + )) + .with_export_func(MockExportBuilder::new( + b"fatal", + FunctionPointer::from_usize(fatal as usize), + )) + .with_export_func(MockExportBuilder::new( + b"recoverable_fatal", + FunctionPointer::from_usize(recoverable_fatal as usize), + )) .build() } @@ -121,6 +125,7 @@ macro_rules! guest_fault_tests { ( $TestRegion:path ) => { use lazy_static::lazy_static; use libc::{c_void, siginfo_t, SIGSEGV}; + use lucet_module_data::FunctionPointer; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime::{ lucet_hostcall_terminate, lucet_hostcalls, DlModule, Error, FaultDetails, Instance, @@ -134,7 +139,7 @@ macro_rules! guest_fault_tests { use std::sync::{Arc, Mutex}; use $TestRegion as TestRegion; use $crate::guest_fault::mock_traps_module; - use $crate::helpers::{test_ex, test_nonex, MockModuleBuilder}; + use $crate::helpers::{test_ex, test_nonex, MockExportBuilder, MockModuleBuilder}; lazy_static! { static ref RECOVERABLE_PTR_LOCK: Mutex<()> = Mutex::new(()); @@ -540,7 +545,10 @@ macro_rules! guest_fault_tests { // therefore testing that the host signal gets re-raised. let child = std::thread::spawn(|| { let module = MockModuleBuilder::new() - .with_export_func(b"sleepy_guest", sleepy_guest as *const extern "C" fn()) + .with_export_func(MockExportBuilder::new( + b"sleepy_guest", + FunctionPointer::from_usize(sleepy_guest as usize), + )) .build(); let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); diff --git a/lucet-runtime/lucet-runtime-tests/src/helpers.rs b/lucet-runtime/lucet-runtime-tests/src/helpers.rs index f91f8fa79..b1a9d8ebb 100644 --- a/lucet-runtime/lucet-runtime-tests/src/helpers.rs +++ b/lucet-runtime/lucet-runtime-tests/src/helpers.rs @@ -1,5 +1,5 @@ // re-export types that should only be used for testing -pub use lucet_runtime_internals::module::{HeapSpec, MockModuleBuilder}; +pub use lucet_runtime_internals::module::{HeapSpec, MockExportBuilder, MockModuleBuilder}; use lazy_static::lazy_static; use std::sync::RwLock; diff --git a/lucet-runtime/lucet-runtime-tests/src/host.rs b/lucet-runtime/lucet-runtime-tests/src/host.rs index e34a12aa6..5e8d10a54 100644 --- a/lucet-runtime/lucet-runtime-tests/src/host.rs +++ b/lucet-runtime/lucet-runtime-tests/src/host.rs @@ -3,6 +3,7 @@ macro_rules! host_tests { ( $TestRegion:path ) => { use lazy_static::lazy_static; use libc::c_void; + use lucet_module_data::FunctionPointer; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime::{ lucet_hostcall_terminate, lucet_hostcalls, DlModule, Error, Limits, Region, @@ -11,7 +12,7 @@ macro_rules! host_tests { use std::sync::{Arc, Mutex}; use $TestRegion as TestRegion; use $crate::build::test_module_c; - use $crate::helpers::MockModuleBuilder; + use $crate::helpers::{MockExportBuilder, MockModuleBuilder}; #[test] fn load_module() { let _module = test_module_c("host", "trivial.c").expect("build and load module"); @@ -118,7 +119,8 @@ macro_rules! host_tests { let mut inst = region .new_instance(module) .expect("instance can be created"); - inst.run(b"main", &[]).expect("instance runs"); + inst.run(b"main", &[0u32.into(), 0i32.into()]) + .expect("instance runs"); } #[test] @@ -132,7 +134,8 @@ macro_rules! host_tests { .build() .expect("instance can be created"); - inst.run(b"main", &[]).expect("instance runs"); + inst.run(b"main", &[0u32.into(), 0i32.into()]) + .expect("instance runs"); assert!(*inst.get_embed_ctx::().unwrap().unwrap()); } @@ -145,7 +148,7 @@ macro_rules! host_tests { .new_instance(module) .expect("instance can be created"); - match inst.run(b"main", &[]) { + match inst.run(b"main", &[0u32.into(), 0i32.into()]) { Err(Error::RuntimeTerminated(term)) => { assert_eq!( *term @@ -169,7 +172,7 @@ macro_rules! host_tests { .new_instance(module) .expect("instance can be created"); - match inst.run(b"main", &[]) { + match inst.run(b"main", &[0u32.into(), 0u32.into()]) { Err(Error::RuntimeTerminated(term)) => { assert_eq!( *term @@ -194,7 +197,7 @@ macro_rules! host_tests { .new_instance(module) .expect("instance can be created"); - match inst.run(b"trigger_div_error", &[0u64.into()]) { + match inst.run(b"trigger_div_error", &[0u32.into()]) { Err(Error::RuntimeFault(details)) => { assert_eq!(details.trapcode, Some(TrapCode::IntegerDivByZero)); } @@ -215,7 +218,10 @@ macro_rules! host_tests { } let module = MockModuleBuilder::new() - .with_export_func(b"f", f as *const extern "C" fn()) + .with_export_func(MockExportBuilder::new( + b"f", + FunctionPointer::from_usize(f as usize), + )) .build(); let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); @@ -244,7 +250,10 @@ macro_rules! host_tests { } let module = MockModuleBuilder::new() - .with_export_func(b"f", f as *const extern "C" fn()) + .with_export_func(MockExportBuilder::new( + b"f", + FunctionPointer::from_usize(f as usize), + )) .build(); let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); @@ -273,7 +282,10 @@ macro_rules! host_tests { } let module = MockModuleBuilder::new() - .with_export_func(b"f", f as *const extern "C" fn()) + .with_export_func(MockExportBuilder::new( + b"f", + FunctionPointer::from_usize(f as usize), + )) .build(); let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); diff --git a/lucet-runtime/lucet-runtime-tests/src/strcmp.rs b/lucet-runtime/lucet-runtime-tests/src/strcmp.rs index 80bbe415b..857b0b089 100644 --- a/lucet-runtime/lucet-runtime-tests/src/strcmp.rs +++ b/lucet-runtime/lucet-runtime-tests/src/strcmp.rs @@ -27,8 +27,7 @@ macro_rules! strcmp_tests { .expect("s2 is a valid CString") .into_bytes_with_nul(); - let res_size = std::mem::size_of::(); - assert!(res_size + s1.len() + s2.len() < WASM_PAGE_SIZE as usize); + assert!(s1.len() + s2.len() < WASM_PAGE_SIZE as usize); let module = test_module_c("strcmp", "guest.c").expect("compile module"); let region = TestRegion::create(10, &Limits::default()).expect("region can be created"); @@ -39,8 +38,7 @@ macro_rules! strcmp_tests { let newpage_start = inst.grow_memory(1).expect("grow_memory succeeds"); let heap = inst.heap_mut(); - let res_ptr = (newpage_start * WASM_PAGE_SIZE) as usize; - let s1_ptr = res_ptr + res_size; + let s1_ptr = (newpage_start * WASM_PAGE_SIZE) as usize; let s2_ptr = s1_ptr + s1.len(); heap[s1_ptr..s2_ptr].copy_from_slice(&s1); heap[s2_ptr..s2_ptr + s2.len()].copy_from_slice(&s2); @@ -48,11 +46,7 @@ macro_rules! strcmp_tests { let res = c_int::from( inst.run( b"run_strcmp", - &[ - Val::GuestPtr(s1_ptr as u32), - Val::GuestPtr(s2_ptr as u32), - Val::GuestPtr(res_ptr as u32), - ], + &[Val::GuestPtr(s1_ptr as u32), Val::GuestPtr(s2_ptr as u32)], ) .expect("instance runs"), ); diff --git a/lucet-runtime/src/c_api.rs b/lucet-runtime/src/c_api.rs index 6be2fe2c9..20c318b97 100644 --- a/lucet-runtime/src/c_api.rs +++ b/lucet-runtime/src/c_api.rs @@ -420,9 +420,7 @@ lucet_hostcalls! { vmctx.instance() .module() .get_func_from_idx(table_idx, func_idx) - // the Rust API actually returns a pointer to a function pointer, so we want to dereference - // one layer of that to make it nicer in C - .map(|fptr| *(fptr as *const *const c_void)) + .map(|fptr| fptr.ptr.as_usize() as *const c_void) .unwrap_or(std::ptr::null()) } diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index 4c683c289..eb5acec40 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -108,7 +108,7 @@ impl<'a> Compiler<'a> { }) } - pub fn module_data(&self) -> ModuleData { + pub fn module_data(&self) -> Result { self.decls.get_module_data() } @@ -139,13 +139,16 @@ impl<'a> Compiler<'a> { let function_manifest: Vec<(String, FunctionSpec)> = self .clif_module .declared_functions() - .filter_map(|f| { - f.compiled.as_ref().map(|compiled| { - ( - f.decl.name.to_owned(), // this copy is only necessary because `clif_module` is moved in `finish, below` - FunctionSpec::new(0, compiled.code_length(), 0, 0), - ) - }) + .map(|f| { + ( + f.decl.name.to_owned(), // this copy is only necessary because `clif_module` is moved in `finish, below` + FunctionSpec::new( + 0, + f.compiled.as_ref().map(|c| c.code_length()).unwrap_or(0), + 0, + 0, + ), + ) }) .collect(); @@ -195,7 +198,7 @@ fn write_module_data( use cranelift_module::{DataContext, Linkage}; let module_data_serialized: Vec = decls - .get_module_data() + .get_module_data()? .serialize() .context(LucetcErrorKind::ModuleData)?; { diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index b9fef33c6..edb76b91f 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -5,7 +5,7 @@ use crate::module::ModuleInfo; pub use crate::module::{Exportable, TableElems}; use crate::name::Name; use crate::runtime::{Runtime, RuntimeFunc}; -use cranelift_codegen::entity::{entity_impl, EntityRef, PrimaryMap}; +use cranelift_codegen::entity::{EntityRef, PrimaryMap}; use cranelift_codegen::ir; use cranelift_codegen::isa::TargetFrontendConfig; use cranelift_module::{Backend as ClifBackend, Linkage, Module as ClifModule}; @@ -15,17 +15,11 @@ use cranelift_wasm::{ }; use failure::{format_err, Error, ResultExt}; use lucet_module_data::{ - owned::OwnedLinearMemorySpec, Global as GlobalVariant, GlobalDef, GlobalSpec, HeapSpec, - ModuleData, + owned::OwnedLinearMemorySpec, FunctionMetadata, Global as GlobalVariant, GlobalDef, GlobalSpec, + HeapSpec, ModuleData, Signature as LucetSignature, UniqueSignatureIndex, }; use std::collections::HashMap; - -/// UniqueSignatureIndex names a signature after collapsing duplicate signatures to a single -/// identifier, whereas SignatureIndex is directly what the original module specifies, and may -/// specify duplicates of types that are structurally equal. -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] -pub struct UniqueSignatureIndex(u32); -entity_impl!(UniqueSignatureIndex); +use std::convert::TryFrom; #[derive(Debug)] pub struct FunctionDecl<'a> { @@ -368,12 +362,47 @@ impl<'a> ModuleDecls<'a> { } } - pub fn get_module_data(&self) -> ModuleData { + pub fn get_module_data(&self) -> Result { let linear_memory = if let Some(ref spec) = self.linear_memory_spec { Some(spec.to_ref()) } else { None }; - ModuleData::new(linear_memory, self.globals_spec.clone()) + + let mut functions: Vec = Vec::new(); + for fn_index in self.function_names.keys() { + let decl = self.get_func(fn_index).unwrap(); + + // can't use `decl.name` for `FunctionMetadata::name` as `decl` is dropped in the next + // iteration of this loop. + let name = self + .function_names + .get(fn_index) + .ok_or_else(|| format_err!("func index out of bounds: {:?}", fn_index)) + .unwrap(); + + functions.push(FunctionMetadata { + signature: decl.signature_index, + sym: Some(name.symbol().as_bytes()), // TODO: what about functions without names? currently internal functions are named like `guest_func_N`. + }); + } + + let signatures = self + .info + .signatures + .values() + .map(|sig| { + LucetSignature::try_from(sig) + .map_err(|e| format_err!("error converting cranelift sig to wasm sig: {:?}", e)) + .context(LucetcErrorKind::TranslatingModule) + }) + .collect::, failure::Context>>()?; + + Ok(ModuleData::new( + linear_memory, + self.globals_spec.clone(), + functions, + signatures, + )) } } diff --git a/lucetc/src/function_manifest.rs b/lucetc/src/function_manifest.rs index 7d5309271..b7f2105a3 100644 --- a/lucetc/src/function_manifest.rs +++ b/lucetc/src/function_manifest.rs @@ -13,12 +13,14 @@ fn write_relocated_slice( to: &str, len: u64, ) -> Result<(), Error> { - obj.link(Link { - from, // the data at `from` + `at` (eg. manifest_sym) - to, // is a reference to `to` (eg. fn_name) - at: buf.position(), - }) - .context(format!("linking {} into function manifest", to))?; + if len > 0 { + obj.link(Link { + from, // the data at `from` + `at` (eg. manifest_sym) + to, // is a reference to `to` (eg. fn_name) + at: buf.position(), + }) + .context(format!("linking {} into function manifest", to))?; + } buf.write_u64::(0).unwrap(); buf.write_u64::(len).unwrap(); diff --git a/lucetc/src/module.rs b/lucetc/src/module.rs index 61ae0f032..4975a3276 100644 --- a/lucetc/src/module.rs +++ b/lucetc/src/module.rs @@ -1,5 +1,4 @@ //! Implements ModuleEnvironment for cranelift-wasm. Code derived from cranelift-wasm/environ/dummy.rs -use crate::decls::UniqueSignatureIndex; use crate::pointer::NATIVE_POINTER; use cranelift_codegen::entity::{EntityRef, PrimaryMap}; use cranelift_codegen::ir; @@ -8,6 +7,7 @@ use cranelift_wasm::{ FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, ModuleEnvironment, SignatureIndex, Table, TableElementType, TableIndex, WasmResult, }; +use lucet_module_data::UniqueSignatureIndex; use std::collections::{hash_map::Entry, HashMap}; #[derive(Debug, Clone)] diff --git a/lucetc/src/output.rs b/lucetc/src/output.rs index 9728fae31..f354b3db1 100644 --- a/lucetc/src/output.rs +++ b/lucetc/src/output.rs @@ -66,13 +66,17 @@ impl ObjectFile { // Now that we have trap information, we can fix up FunctionSpec entries to have // correct `trap_length` values - let mut function_map: HashMap = HashMap::new(); - for (name, fn_spec) in function_manifest.into_iter() { - function_map.insert(name, fn_spec); + let mut function_map: HashMap = HashMap::new(); + for (i, (name, _)) in function_manifest.iter().enumerate() { + function_map.insert(name.clone(), i as u32); } for sink in trap_manifest.sinks.iter() { - if let Some(ref mut fn_spec) = function_map.get_mut(&sink.name) { + if let Some(idx) = function_map.get(&sink.name) { + let (_, fn_spec) = &mut function_manifest + .get_mut(*idx as usize) + .expect("index is valid"); + std::mem::replace::( fn_spec, FunctionSpec::new(0, fn_spec.code_len(), 0, sink.sites.len() as u64), @@ -83,8 +87,6 @@ impl ObjectFile { } } - let function_manifest: Vec<(String, FunctionSpec)> = function_map.into_iter().collect(); - write_trap_tables(trap_manifest, &mut product.artifact)?; write_function_manifest(function_manifest.as_slice(), &mut product.artifact)?; diff --git a/lucetc/tests/wasi-sdk.rs b/lucetc/tests/wasi-sdk.rs index ba1b72ce3..270bf682e 100644 --- a/lucetc/tests/wasi-sdk.rs +++ b/lucetc/tests/wasi-sdk.rs @@ -57,7 +57,7 @@ mod programs { let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile empty"); - let mdata = c.module_data(); + let mdata = c.module_data().unwrap(); assert!(mdata.heap_spec().is_some()); // clang creates 3 globals, all internal: assert_eq!(mdata.globals_spec().len(), 3); @@ -87,7 +87,7 @@ mod programs { let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile a"); - let _mdata = c.module_data(); + let _mdata = c.module_data().unwrap(); /* FIXME: module data doesn't contain the information to check these properties: assert_eq!(p.import_functions().len(), 0, "import functions"); @@ -104,7 +104,7 @@ mod programs { let b = b_only_test_bindings(); let h = HeapSettings::default(); let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile b"); - let _mdata = c.module_data(); + let _mdata = c.module_data().unwrap(); /* FIXME: module data doesn't contain the information to check these properties: assert_eq!(p.import_functions().len(), 1, "import functions"); assert_eq!(num_import_globals(&p), 0, "import globals"); @@ -119,7 +119,7 @@ mod programs { let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile a & b"); - let _mdata = c.module_data(); + let _mdata = c.module_data().unwrap(); /* FIXME: module data doesn't contain the information to check these properties: assert_eq!(p.import_functions().len(), 0, "import functions"); assert_eq!(num_import_globals(&p), 0, "import globals"); diff --git a/lucetc/tests/wasm.rs b/lucetc/tests/wasm.rs index f92a91d04..8213e163c 100644 --- a/lucetc/tests/wasm.rs +++ b/lucetc/tests/wasm.rs @@ -41,7 +41,7 @@ mod module_data { let b = super::test_bindings(); let h = HeapSettings::default(); let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compiling fibonacci"); - assert_eq!(c.module_data().globals_spec().len(), 0); + assert_eq!(c.module_data().unwrap().globals_spec().len(), 0); /* TODO can't express these with module data assert_eq!(p.import_functions().len(), 0); @@ -59,7 +59,7 @@ mod module_data { let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compiling arith"); - assert_eq!(c.module_data().globals_spec().len(), 0); + assert_eq!(c.module_data().unwrap().globals_spec().len(), 0); /* TODO can't express these with module data assert_eq!(p.import_functions().len(), 0); @@ -79,7 +79,7 @@ mod module_data { .unwrap(); let h = HeapSettings::default(); let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile icall"); - let _module_data = c.module_data(); + let _module_data = c.module_data().unwrap(); /* TODO can't express these with module data assert_eq!(p.import_functions().len(), 1); @@ -117,7 +117,7 @@ mod module_data { let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile icall"); - let _module_data = c.module_data(); + let _module_data = c.module_data().unwrap(); /* TODO can't express these with module data assert_eq!( @@ -142,7 +142,7 @@ mod module_data { let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile icall_sparse"); - let _module_data = c.module_data(); + let _module_data = c.module_data().unwrap(); /* TODO can't express these with module data assert_eq!( @@ -181,7 +181,7 @@ mod module_data { let h = HeapSettings::default(); let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile globals_import"); - let module_data = c.module_data(); + let module_data = c.module_data().unwrap(); let gspec = module_data.globals_spec(); assert_eq!(gspec.len(), 1); @@ -205,7 +205,7 @@ mod module_data { Compiler::new(&m, OptLevel::Best, &b, h.clone()).expect("compiling heap_spec_import"); assert_eq!( - c.module_data().heap_spec(), + c.module_data().unwrap().heap_spec(), Some(&HeapSpec { // reserved and guard are given by HeapSettings reserved_size: h.min_reserved_size, @@ -228,7 +228,7 @@ mod module_data { .expect("compiling heap_spec_definition"); assert_eq!( - c.module_data().heap_spec(), + c.module_data().unwrap().heap_spec(), Some(&HeapSpec { // reserved and guard are given by HeapSettings reserved_size: h.min_reserved_size, @@ -247,7 +247,7 @@ mod module_data { let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compiling heap_spec_none"); - assert_eq!(c.module_data().heap_spec(), None,); + assert_eq!(c.module_data().unwrap().heap_spec(), None,); } #[test] From fa676739ea677340b17d0ae6e2005eea4f8262e3 Mon Sep 17 00:00:00 2001 From: awortman-fastly <49215183+awortman-fastly@users.noreply.github.com> Date: Tue, 14 May 2019 13:18:27 -0700 Subject: [PATCH 133/512] bump rust version (#178) --- Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 14d9f31ea..294b4a433 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,12 +27,12 @@ RUN update-alternatives --install /usr/bin/clang clang /usr/bin/clang-6.0 100 # rebuilds. ENV LD_LIBRARY_PATH=/usr/local/lib -RUN curl -sS -L -O https://static.rust-lang.org/dist/rust-1.34.1-x86_64-unknown-linux-gnu.tar.gz \ - && tar xzf rust-1.34.1-x86_64-unknown-linux-gnu.tar.gz \ - && cd rust-1.34.1-x86_64-unknown-linux-gnu \ +RUN curl -sS -L -O https://static.rust-lang.org/dist/rust-1.34.2-x86_64-unknown-linux-gnu.tar.gz \ + && tar xzf rust-1.34.2-x86_64-unknown-linux-gnu.tar.gz \ + && cd rust-1.34.2-x86_64-unknown-linux-gnu \ && ./install.sh \ && cd .. \ - && rm -rf rust-1.34.1-x86_64-unknown-linux-gnu rust-1.34.1-x86_64-unknown-linux-gnu.tar.gz + && rm -rf rust-1.34.2-x86_64-unknown-linux-gnu rust-1.34.2-x86_64-unknown-linux-gnu.tar.gz ENV PATH=/usr/local/bin:$PATH RUN cargo install --root /usr/local cargo-audit cargo-watch From 68068137e9a5ee26c9c49dedd2f0f4d7a06fdc98 Mon Sep 17 00:00:00 2001 From: awortman-fastly <49215183+awortman-fastly@users.noreply.github.com> Date: Thu, 16 May 2019 12:23:48 -0700 Subject: [PATCH 134/512] Add function import/export information to module data (#177) * add function import/export information to module data * run (and other functions operating on function names) take &str now, rather than byte slices * uncomment parts of lucetc tests that are now expressible * add FunctionIndex newtype instead of passing around raw u32, as well also note that FunctionMetadata's sym is possibly related to, but not an indicator of, exported- or imported-ness. --- benchmarks/lucet-benchmarks/src/modules.rs | 14 +-- benchmarks/lucet-benchmarks/src/par.rs | 2 +- benchmarks/lucet-benchmarks/src/seq.rs | 12 +-- lucet-module-data/src/functions.rs | 79 ++++++++++++++-- lucet-module-data/src/lib.rs | 4 +- lucet-module-data/src/module_data.rs | 50 ++++++++--- .../lucet-runtime-internals/src/instance.rs | 6 +- .../lucet-runtime-internals/src/module.rs | 10 +-- .../lucet-runtime-internals/src/module/dl.rs | 17 ++-- .../src/module/mock.rs | 39 ++++---- .../lucet-runtime-tests/src/entrypoint.rs | 70 +++++++-------- .../lucet-runtime-tests/src/globals.rs | 20 ++--- .../lucet-runtime-tests/src/guest_fault.rs | 40 ++++----- lucet-runtime/lucet-runtime-tests/src/host.rs | 22 ++--- .../lucet-runtime-tests/src/memory.rs | 4 +- .../lucet-runtime-tests/src/stack.rs | 2 +- .../lucet-runtime-tests/src/start.rs | 6 +- .../lucet-runtime-tests/src/strcmp.rs | 4 +- lucet-runtime/src/c_api.rs | 10 ++- lucet-runtime/src/lib.rs | 8 +- lucet-spectest/src/script.rs | 2 +- lucet-wasi-fuzz/src/main.rs | 2 +- lucet-wasi/src/main.rs | 2 +- lucet-wasi/tests/test_helpers/mod.rs | 2 +- lucetc/src/decls.rs | 90 +++++++++++++------ lucetc/tests/wasi-sdk.rs | 26 +++--- lucetc/tests/wasm.rs | 46 ++++------ 27 files changed, 359 insertions(+), 230 deletions(-) diff --git a/benchmarks/lucet-benchmarks/src/modules.rs b/benchmarks/lucet-benchmarks/src/modules.rs index 2834fe617..77e892711 100644 --- a/benchmarks/lucet-benchmarks/src/modules.rs +++ b/benchmarks/lucet-benchmarks/src/modules.rs @@ -28,7 +28,7 @@ pub fn null_mock() -> Arc { extern "C" fn f(_vmctx: *mut lucet_vmctx) {} MockModuleBuilder::new() - .with_export_func(MockExportBuilder::new(b"f", FunctionPointer::from_usize(f as usize))) + .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize))) .build() } @@ -50,7 +50,7 @@ pub fn large_dense_heap_mock(heap_kb: usize) -> Arc { }); MockModuleBuilder::new() - .with_export_func(MockExportBuilder::new(b"f", FunctionPointer::from_usize(f as usize))) + .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize))) .with_initial_heap(heap.as_slice()) .with_heap_spec(heap_spec) .build() @@ -81,7 +81,7 @@ pub fn large_sparse_heap_mock(heap_kb: usize, stride: usize) -> Arc }); MockModuleBuilder::new() - .with_export_func(MockExportBuilder::new(b"f", FunctionPointer::from_usize(f as usize))) + .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize))) .with_initial_heap(heap.as_slice()) .with_heap_spec(heap_spec) .build() @@ -102,7 +102,7 @@ pub fn fib_mock() -> Arc { } MockModuleBuilder::new() - .with_export_func(MockExportBuilder::new(b"f", FunctionPointer::from_usize(f as usize))) + .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize))) .build() } @@ -179,7 +179,7 @@ pub fn many_args_mock() -> Arc { } MockModuleBuilder::new() - .with_export_func(MockExportBuilder::new(b"f", FunctionPointer::from_usize(f as usize))) + .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize))) .build() } @@ -255,8 +255,8 @@ pub fn hostcalls_mock() -> Arc { MockModuleBuilder::new() .with_export_func( - MockExportBuilder::new(b"wrapped", FunctionPointer::from_usize(wrapped as usize))) + MockExportBuilder::new("wrapped", FunctionPointer::from_usize(wrapped as usize))) .with_export_func( - MockExportBuilder::new(b"raw", FunctionPointer::from_usize(raw as usize))) + MockExportBuilder::new("raw", FunctionPointer::from_usize(raw as usize))) .build() } diff --git a/benchmarks/lucet-benchmarks/src/par.rs b/benchmarks/lucet-benchmarks/src/par.rs index 23542116a..ac535aa7f 100644 --- a/benchmarks/lucet-benchmarks/src/par.rs +++ b/benchmarks/lucet-benchmarks/src/par.rs @@ -89,7 +89,7 @@ fn par_run( .unwrap() .install(|| { handles.par_iter_mut().for_each(|handle| { - handle.run(b"f", &[]).unwrap(); + handle.run("f", &[]).unwrap(); }) }) } diff --git a/benchmarks/lucet-benchmarks/src/seq.rs b/benchmarks/lucet-benchmarks/src/seq.rs index 69784e5fc..b8360dbbf 100644 --- a/benchmarks/lucet-benchmarks/src/seq.rs +++ b/benchmarks/lucet-benchmarks/src/seq.rs @@ -201,7 +201,7 @@ fn drop_instance_with_sparse_heap(c: &mut Criterion) /// switching overhead. fn run_null(c: &mut Criterion) { fn body(inst: &mut InstanceHandle) { - inst.run(b"f", &[]).unwrap(); + inst.run("f", &[]).unwrap(); } let module = null_mock(); @@ -222,7 +222,7 @@ fn run_null(c: &mut Criterion) { /// cost of the Lucet runtime. fn run_fib(c: &mut Criterion) { fn body(inst: &mut InstanceHandle) { - inst.run(b"f", &[]).unwrap(); + inst.run("f", &[]).unwrap(); } let module = fib_mock(); @@ -240,7 +240,7 @@ fn run_fib(c: &mut Criterion) { /// Run a trivial WASI program. fn run_hello(c: &mut Criterion) { fn body(inst: &mut InstanceHandle) { - inst.run(b"_start", &[]).unwrap(); + inst.run("_start", &[]).unwrap(); } let workdir = TempDir::new().expect("create working directory"); @@ -281,7 +281,7 @@ fn run_hello(c: &mut Criterion) { fn run_many_args(c: &mut Criterion) { fn body(inst: &mut InstanceHandle) { inst.run( - b"f", + "f", &[ 0xAFu8.into(), 0xAFu16.into(), @@ -368,7 +368,7 @@ fn run_many_args(c: &mut Criterion) { fn run_hostcall_wrapped(c: &mut Criterion) { fn body(inst: &mut InstanceHandle) { - inst.run(b"wrapped", &[]).unwrap(); + inst.run("wrapped", &[]).unwrap(); } let module = hostcalls_mock(); @@ -388,7 +388,7 @@ fn run_hostcall_wrapped(c: &mut Criterion) { fn run_hostcall_raw(c: &mut Criterion) { fn body(inst: &mut InstanceHandle) { - inst.run(b"raw", &[]).unwrap(); + inst.run("raw", &[]).unwrap(); } let module = hostcalls_mock(); diff --git a/lucet-module-data/src/functions.rs b/lucet-module-data/src/functions.rs index 5eeddee72..cc4e4cc4e 100644 --- a/lucet-module-data/src/functions.rs +++ b/lucet-module-data/src/functions.rs @@ -4,6 +4,70 @@ use serde::{Deserialize, Serialize}; use std::slice::from_raw_parts; +/// FunctionIndex is an identifier for a function, imported, exported, or external. The space of +/// FunctionIndex is shared for all of these, so `FunctionIndex(N)` may identify exported function +/// #2, `FunctionIndex(N + 1)` may identify an internal function, and `FunctionIndex(N + 2)` may +/// identify an imported function. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] +pub struct FunctionIndex(u32); + +impl FunctionIndex { + pub fn from_u32(idx: u32) -> FunctionIndex { + FunctionIndex(idx) + } + pub fn as_u32(&self) -> u32 { + self.0 + } +} + +/// ImportFunction describes an internal function - its internal function index and the name/module +/// pair that function should be found in. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] +pub struct ImportFunction<'a> { + pub fn_idx: FunctionIndex, + pub module: &'a str, + pub name: &'a str +} + +/// ExportFunction describes an exported function - its internal function index and a name that +/// function has been exported under. +#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] +pub struct ExportFunction<'a> { + pub fn_idx: FunctionIndex, + #[serde(borrow)] + pub names: Vec<&'a str> +} + +pub struct OwnedExportFunction { + pub fn_idx: FunctionIndex, + pub names: Vec +} + +impl OwnedExportFunction { + pub fn to_ref<'a>(&'a self) -> ExportFunction<'a> { + ExportFunction { + fn_idx: self.fn_idx.clone(), + names: self.names.iter().map(|x| x.as_str()).collect() + } + } +} + +pub struct OwnedImportFunction { + pub fn_idx: FunctionIndex, + pub module: String, + pub name: String +} + +impl OwnedImportFunction { + pub fn to_ref<'a>(&'a self) -> ImportFunction<'a> { + ImportFunction { + fn_idx: self.fn_idx.clone(), + module: self.module.as_str(), + name: self.name.as_str(), + } + } +} + /// UniqueSignatureIndex names a signature after collapsing duplicate signatures to a single /// identifier, whereas SignatureIndex is directly what the original module specifies, and may /// specify duplicates of types that are structurally equal. @@ -37,28 +101,33 @@ impl FunctionPointer { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct FunctionMetadata<'a> { pub signature: UniqueSignatureIndex, + /// the "name" field is some human-friendly name, not necessarily the same as used to reach + /// this function (through an export, for example), and may not even indicate that a function + /// is exported at all. + /// TODO: at some point when possible, this field ought to be set from the names section of a + /// wasm module. At the moment that information is lost at parse time. #[serde(borrow)] - pub sym: Option<&'a [u8]>, + pub name: Option<&'a str>, } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct OwnedFunctionMetadata { pub signature: UniqueSignatureIndex, - pub sym: Option>, + pub name: Option, } impl OwnedFunctionMetadata { - pub fn to_ref<'a>(&'a self) -> FunctionMetadata<'a> { + pub fn to_ref(&self) -> FunctionMetadata { FunctionMetadata { signature: self.signature.clone(), - sym: self.sym.as_ref().map(|s| s.as_slice()).clone(), + name: self.name.as_ref().map(|n| n.as_str()), } } } pub struct FunctionHandle { pub ptr: FunctionPointer, - pub id: u32 + pub id: FunctionIndex } // The layout of this struct is very tightly coupled to lucetc's `write_function_manifest`! diff --git a/lucet-module-data/src/lib.rs b/lucet-module-data/src/lib.rs index a42013dc3..4836c58f1 100644 --- a/lucet-module-data/src/lib.rs +++ b/lucet-module-data/src/lib.rs @@ -15,7 +15,7 @@ pub use crate::error::Error; pub use crate::globals::{Global, GlobalDef, GlobalSpec}; pub use crate::linear_memory::{HeapSpec, SparseData, LinearMemorySpec}; pub use crate::module_data::ModuleData; -pub use crate::functions::{FunctionHandle, FunctionMetadata, FunctionPointer, FunctionSpec, UniqueSignatureIndex}; +pub use crate::functions::{ExportFunction, FunctionHandle, FunctionIndex, FunctionMetadata, FunctionPointer, FunctionSpec, ImportFunction, UniqueSignatureIndex}; pub use crate::traps::{TrapManifest, TrapSite, TrapCode}; pub use crate::types::{Signature, ValueType}; @@ -24,5 +24,5 @@ pub mod owned { pub use crate::globals::OwnedGlobalSpec; pub use crate::linear_memory::{OwnedSparseData, OwnedLinearMemorySpec}; pub use crate::module_data::OwnedModuleData; - pub use crate::functions::OwnedFunctionMetadata; + pub use crate::functions::{OwnedFunctionMetadata, OwnedExportFunction, OwnedImportFunction}; } diff --git a/lucet-module-data/src/module_data.rs b/lucet-module-data/src/module_data.rs index e42a30c2b..fd87e6121 100644 --- a/lucet-module-data/src/module_data.rs +++ b/lucet-module-data/src/module_data.rs @@ -1,5 +1,5 @@ use crate::{ - functions::{FunctionMetadata, OwnedFunctionMetadata}, + functions::{ExportFunction, FunctionIndex, FunctionMetadata, ImportFunction, OwnedFunctionMetadata}, globals::GlobalSpec, linear_memory::{HeapSpec, LinearMemorySpec, SparseData}, types::Signature, @@ -23,6 +23,10 @@ pub struct ModuleData<'a> { globals_spec: Vec>, #[serde(borrow)] function_info: Vec>, + #[serde(borrow)] + import_functions: Vec>, + #[serde(borrow)] + export_functions: Vec>, signatures: Vec, } @@ -31,12 +35,16 @@ impl<'a> ModuleData<'a> { linear_memory: Option>, globals_spec: Vec>, function_info: Vec>, + import_functions: Vec>, + export_functions: Vec>, signatures: Vec, ) -> Self { Self { linear_memory, globals_spec, function_info, + import_functions, + export_functions, signatures, } } @@ -61,25 +69,32 @@ impl<'a> ModuleData<'a> { &self.globals_spec } + pub fn function_info(&self) -> &[FunctionMetadata<'a>] { + &self.function_info + } + + pub fn import_functions(&self) -> &[ImportFunction] { + &self.import_functions + } + + pub fn export_functions(&self) -> &[ExportFunction] { + &self.export_functions + } + // Function index here is a different index space than `get_func_from_idx`, which // uses function index as an index into a table of function elements. // // This is an index of all functions in the module. - pub fn get_signature(&self, fn_id: u32) -> &Signature { - let sig_idx = self.function_info[fn_id as usize].signature; + pub fn get_signature(&self, fn_id: FunctionIndex) -> &Signature { + let sig_idx = self.function_info[fn_id.as_u32() as usize].signature; &self.signatures[sig_idx.as_u32() as usize] } - pub fn function_id_by_name(&self, name: &[u8]) -> Option { - self.function_info + pub fn get_export_func_id(&self, name: &str) -> Option { + self.export_functions .iter() - .enumerate() - .find(|(_, fn_meta)| { fn_meta.sym == Some(name) }) - .map(|(i, _)| i as u32) - } - - pub fn sym_for(&self, fn_id: u32) -> Option<&[u8]> { - self.function_info.get(fn_id as usize).and_then(|func| func.sym) + .find(|export| export.names.contains(&name)) + .map(|export| export.fn_idx) } pub fn signatures(&self) -> &[Signature] { @@ -100,6 +115,7 @@ impl<'a> ModuleData<'a> { use crate::{ globals::OwnedGlobalSpec, linear_memory::{OwnedLinearMemorySpec, OwnedSparseData}, + functions::{OwnedExportFunction, OwnedImportFunction}, }; /// The metadata (and some data) for a Lucet module. @@ -111,6 +127,8 @@ pub struct OwnedModuleData { linear_memory: Option, globals_spec: Vec, function_info: Vec, + imports: Vec, + exports: Vec, signatures: Vec, } @@ -119,12 +137,16 @@ impl OwnedModuleData { linear_memory: Option, globals_spec: Vec, function_info: Vec, + imports: Vec, + exports: Vec, signatures: Vec, ) -> Self { Self { linear_memory, globals_spec, function_info, + imports, + exports, signatures, } } @@ -140,12 +162,14 @@ impl OwnedModuleData { }, self.globals_spec.iter().map(|gs| gs.to_ref()).collect(), self.function_info.iter().map(|info| info.to_ref()).collect(), + self.imports.iter().map(|imp| imp.to_ref()).collect(), + self.exports.iter().map(|exp| exp.to_ref()).collect(), self.signatures.clone(), ) } pub fn empty() -> Self { - Self::new(None, vec![], vec![], vec![]) + Self::new(None, vec![], vec![], vec![], vec![], vec![]) } pub fn with_heap_spec(mut self, heap_spec: HeapSpec) -> Self { diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index 08e1673b3..d590f45e2 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -286,11 +286,11 @@ impl Instance { /// # use lucet_runtime_internals::instance::InstanceHandle; /// # let instance: InstanceHandle = unimplemented!(); /// // regular execution yields `Ok(UntypedRetVal)` - /// let retval = instance.run(b"factorial", &[5u64.into()]).unwrap(); + /// let retval = instance.run("factorial", &[5u64.into()]).unwrap(); /// assert_eq!(u64::from(retval), 120u64); /// /// // runtime faults yield `Err(Error)` - /// let result = instance.run(b"faulting_function", &[]); + /// let result = instance.run("faulting_function", &[]); /// assert!(result.is_err()); /// ``` /// @@ -310,7 +310,7 @@ impl Instance { /// /// For the moment, we do not mark this as `unsafe` in the Rust type system, but that may change /// in the future. - pub fn run(&mut self, entrypoint: &[u8], args: &[Val]) -> Result { + pub fn run(&mut self, entrypoint: &str, args: &[Val]) -> Result { let func = self.module.get_export_func(entrypoint)?; self.run_func(func, &args) } diff --git a/lucet-runtime/lucet-runtime-internals/src/module.rs b/lucet-runtime/lucet-runtime-internals/src/module.rs index 4eecd5267..c94c3af8a 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module.rs @@ -5,8 +5,8 @@ mod sparse_page_data; pub use crate::module::dl::DlModule; pub use crate::module::mock::{MockExportBuilder, MockModuleBuilder}; pub use lucet_module_data::{ - FunctionHandle, FunctionPointer, FunctionSpec, Global, GlobalSpec, HeapSpec, Signature, - TrapCode, TrapManifest, ValueType, + FunctionHandle, FunctionIndex, FunctionPointer, FunctionSpec, Global, GlobalSpec, HeapSpec, + Signature, TrapCode, TrapManifest, ValueType, }; use crate::alloc::Limits; @@ -56,7 +56,7 @@ pub trait ModuleInternal: Send + Sync { /// Get the table elements from the module. fn table_elements(&self) -> Result<&[TableElement], Error>; - fn get_export_func(&self, sym: &[u8]) -> Result; + fn get_export_func(&self, sym: &str) -> Result; fn get_func_from_idx(&self, table_id: u32, func_id: u32) -> Result; @@ -66,7 +66,7 @@ pub trait ModuleInternal: Send + Sync { fn addr_details(&self, addr: *const c_void) -> Result, Error>; - fn get_signature(&self, fn_id: u32) -> &Signature; + fn get_signature(&self, fn_id: FunctionIndex) -> &Signature; fn function_handle_from_ptr(&self, ptr: FunctionPointer) -> FunctionHandle { let id = self @@ -74,7 +74,7 @@ pub trait ModuleInternal: Send + Sync { .iter() .enumerate() .find(|(_, fn_spec)| fn_spec.ptr() == ptr) - .map(|(fn_id, _)| fn_id as u32) + .map(|(fn_id, _)| FunctionIndex::from_u32(fn_id as u32)) .expect("valid function pointer"); FunctionHandle { ptr, id } diff --git a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs index 5411f7d8a..232e3f052 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs @@ -2,7 +2,9 @@ use crate::error::Error; use crate::module::{AddrDetails, GlobalSpec, HeapSpec, Module, ModuleInternal, TableElement}; use libc::c_void; use libloading::{Library, Symbol}; -use lucet_module_data::{FunctionHandle, FunctionPointer, FunctionSpec, ModuleData, Signature}; +use lucet_module_data::{ + FunctionHandle, FunctionIndex, FunctionPointer, FunctionSpec, ModuleData, Signature, +}; use std::ffi::CStr; use std::mem; use std::path::Path; @@ -165,15 +167,12 @@ impl ModuleInternal for DlModule { Ok(unsafe { from_raw_parts(*p_table_segment, **p_table_segment_len as usize) }) } - fn get_export_func(&self, sym: &[u8]) -> Result { - let mut guest_sym: Vec = b"guest_func_".to_vec(); - guest_sym.extend_from_slice(sym); - + fn get_export_func(&self, sym: &str) -> Result { self.module_data - .function_id_by_name(&guest_sym) - .ok_or_else(|| Error::SymbolNotFound(String::from_utf8_lossy(sym).into_owned())) + .get_export_func_id(sym) + .ok_or_else(|| Error::SymbolNotFound(sym.to_string())) .map(|id| { - let ptr = self.function_manifest()[id as usize].ptr(); + let ptr = self.function_manifest()[id.as_u32() as usize].ptr(); FunctionHandle { ptr, id } }) } @@ -233,7 +232,7 @@ impl ModuleInternal for DlModule { } } - fn get_signature(&self, fn_id: u32) -> &Signature { + fn get_signature(&self, fn_id: FunctionIndex) -> &Signature { self.module_data.get_signature(fn_id) } } diff --git a/lucet-runtime/lucet-runtime-internals/src/module/mock.rs b/lucet-runtime/lucet-runtime-internals/src/module/mock.rs index 1120b6bae..ca1aa1bd7 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/mock.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/mock.rs @@ -2,10 +2,11 @@ use crate::error::Error; use crate::module::{AddrDetails, GlobalSpec, HeapSpec, Module, ModuleInternal, TableElement}; use libc::c_void; use lucet_module_data::owned::{ - OwnedFunctionMetadata, OwnedGlobalSpec, OwnedLinearMemorySpec, OwnedModuleData, OwnedSparseData, + OwnedExportFunction, OwnedFunctionMetadata, OwnedGlobalSpec, OwnedImportFunction, + OwnedLinearMemorySpec, OwnedModuleData, OwnedSparseData, }; use lucet_module_data::{ - FunctionHandle, FunctionPointer, FunctionSpec, ModuleData, Signature, TrapSite, + FunctionHandle, FunctionIndex, FunctionPointer, FunctionSpec, ModuleData, Signature, TrapSite, UniqueSignatureIndex, }; use std::collections::{BTreeMap, HashMap}; @@ -17,11 +18,13 @@ pub struct MockModuleBuilder { sparse_page_data: Vec>>, globals: BTreeMap, table_elements: BTreeMap, - export_funcs: HashMap, FunctionPointer>, + export_funcs: HashMap<&'static str, FunctionPointer>, func_table: HashMap<(u32, u32), FunctionPointer>, start_func: Option, function_manifest: Vec, function_info: Vec, + imports: Vec, + exports: Vec, signatures: Vec, } @@ -119,12 +122,15 @@ impl MockModuleBuilder { } pub fn with_export_func(mut self, export: MockExportBuilder) -> Self { - self.export_funcs - .insert(export.sym().to_vec(), export.func()); + self.export_funcs.insert(export.sym(), export.func()); let sig_idx = self.record_sig(export.sig()); self.function_info.push(OwnedFunctionMetadata { signature: sig_idx, - sym: Some(export.sym().to_vec()), + name: Some(export.sym().to_string()), + }); + self.exports.push(OwnedExportFunction { + fn_idx: FunctionIndex::from_u32(self.function_manifest.len() as u32), + names: vec![export.sym().to_string()], }); self.function_manifest.push(FunctionSpec::new( export.func().as_usize() as u64, @@ -183,6 +189,8 @@ impl MockModuleBuilder { }), globals_spec, self.function_info.clone(), + self.imports, + self.exports, self.signatures, ); let serialized_module_data = owned_module_data @@ -210,7 +218,7 @@ pub struct MockModule { serialized_module_data: Vec, module_data: ModuleData<'static>, pub table_elements: Vec, - pub export_funcs: HashMap, FunctionPointer>, + pub export_funcs: HashMap<&'static str, FunctionPointer>, pub func_table: HashMap<(u32, u32), FunctionPointer>, pub start_func: Option, pub function_manifest: Vec, @@ -246,10 +254,11 @@ impl ModuleInternal for MockModule { Ok(&self.table_elements) } - fn get_export_func(&self, sym: &[u8]) -> Result { - let ptr = *self.export_funcs.get(sym).ok_or(Error::SymbolNotFound( - String::from_utf8_lossy(sym).into_owned(), - ))?; + fn get_export_func(&self, sym: &str) -> Result { + let ptr = *self + .export_funcs + .get(sym) + .ok_or(Error::SymbolNotFound(sym.to_string()))?; Ok(self.function_handle_from_ptr(ptr)) } @@ -280,13 +289,13 @@ impl ModuleInternal for MockModule { Ok(None) } - fn get_signature(&self, fn_id: u32) -> &Signature { + fn get_signature(&self, fn_id: FunctionIndex) -> &Signature { self.module_data.get_signature(fn_id) } } pub struct MockExportBuilder { - sym: &'static [u8], + sym: &'static str, func: FunctionPointer, func_len: Option, traps: Option<&'static [TrapSite]>, @@ -294,7 +303,7 @@ pub struct MockExportBuilder { } impl MockExportBuilder { - pub fn new(name: &'static [u8], func: FunctionPointer) -> MockExportBuilder { + pub fn new(name: &'static str, func: FunctionPointer) -> MockExportBuilder { MockExportBuilder { sym: name, func: func, @@ -322,7 +331,7 @@ impl MockExportBuilder { self } - pub fn sym(&self) -> &'static [u8] { + pub fn sym(&self) -> &'static str { self.sym } pub fn func(&self) -> FunctionPointer { diff --git a/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs b/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs index 894362cff..66421f815 100644 --- a/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs +++ b/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs @@ -121,35 +121,29 @@ pub fn mock_calculator_module() -> Arc { MockModuleBuilder::new() .with_export_func( - MockExportBuilder::new(b"add_2", FunctionPointer::from_usize(add_2 as usize)) + MockExportBuilder::new("add_2", FunctionPointer::from_usize(add_2 as usize)) .with_sig(lucet_signature!((I64, I64) -> I64)), ) .with_export_func( - MockExportBuilder::new(b"add_10", FunctionPointer::from_usize(add_10 as usize)) + MockExportBuilder::new("add_10", FunctionPointer::from_usize(add_10 as usize)) .with_sig(lucet_signature!( (I64, I64, I64, I64, I64, I64, I64, I64, I64, I64) -> I64)), ) .with_export_func( - MockExportBuilder::new(b"mul_2", FunctionPointer::from_usize(mul_2 as usize)) + MockExportBuilder::new("mul_2", FunctionPointer::from_usize(mul_2 as usize)) .with_sig(lucet_signature!((I64, I64) -> I64)), ) .with_export_func( - MockExportBuilder::new( - b"add_f32_2", - FunctionPointer::from_usize(add_f32_2 as usize), - ) - .with_sig(lucet_signature!((F32, F32) -> F32)), + MockExportBuilder::new("add_f32_2", FunctionPointer::from_usize(add_f32_2 as usize)) + .with_sig(lucet_signature!((F32, F32) -> F32)), ) .with_export_func( - MockExportBuilder::new( - b"add_f64_2", - FunctionPointer::from_usize(add_f64_2 as usize), - ) - .with_sig(lucet_signature!((F64, F64) -> F64)), + MockExportBuilder::new("add_f64_2", FunctionPointer::from_usize(add_f64_2 as usize)) + .with_sig(lucet_signature!((F64, F64) -> F64)), ) .with_export_func( MockExportBuilder::new( - b"add_f32_10", + "add_f32_10", FunctionPointer::from_usize(add_f32_10 as usize), ) .with_sig(lucet_signature!( @@ -157,7 +151,7 @@ pub fn mock_calculator_module() -> Arc { ) .with_export_func( MockExportBuilder::new( - b"add_f64_10", + "add_f64_10", FunctionPointer::from_usize(add_f64_10 as usize), ) .with_sig(lucet_signature!( @@ -165,7 +159,7 @@ pub fn mock_calculator_module() -> Arc { ) .with_export_func( MockExportBuilder::new( - b"add_mixed_20", + "add_mixed_20", FunctionPointer::from_usize(add_mixed_20 as usize), ) .with_sig(lucet_signature!( @@ -216,7 +210,7 @@ macro_rules! entrypoint_tests { .expect("instance can be created"); let retval = inst - .run(b"add_2", &[123u64.into(), 456u64.into()]) + .run("add_2", &[123u64.into(), 456u64.into()]) .expect("instance runs"); assert_eq!(u64::from(retval), 123u64 + 456); @@ -246,7 +240,7 @@ macro_rules! entrypoint_tests { // order is correct. let retval = inst .run( - b"add_10", + "add_10", &[ 1u64.into(), 2u64.into(), @@ -282,7 +276,7 @@ macro_rules! entrypoint_tests { .expect("instance can be created"); let retval = inst - .run(b"mul_2", &[123u64.into(), 456u64.into()]) + .run("mul_2", &[123u64.into(), 456u64.into()]) .expect("instance runs"); assert_eq!(u64::from(retval), 123 * 456); @@ -300,13 +294,13 @@ macro_rules! entrypoint_tests { .expect("instance can be created"); let retval = inst - .run(b"add_2", &[111u64.into(), 222u64.into()]) + .run("add_2", &[111u64.into(), 222u64.into()]) .expect("instance runs"); assert_eq!(u64::from(retval), 111 + 222); let retval = inst - .run(b"mul_2", &[333u64.into(), 444u64.into()]) + .run("mul_2", &[333u64.into(), 444u64.into()]) .expect("instance runs"); assert_eq!(u64::from(retval), 333 * 444); @@ -328,7 +322,7 @@ macro_rules! entrypoint_tests { .new_instance(module) .expect("instance can be created"); - match inst.run(b"invalid", &[123u64.into(), 456u64.into()]) { + match inst.run("invalid", &[123u64.into(), 456u64.into()]) { Err(Error::SymbolNotFound(sym)) => assert_eq!(sym, "invalid"), res => panic!("unexpected result: {:?}", res), } @@ -350,7 +344,7 @@ macro_rules! entrypoint_tests { .expect("instance can be created"); let retval = inst - .run(b"add_f32_2", &[(-6.9f32).into(), 4.2f32.into()]) + .run("add_f32_2", &[(-6.9f32).into(), 4.2f32.into()]) .expect("instance runs"); assert_eq!(f32::from(retval), -6.9 + 4.2); @@ -371,7 +365,7 @@ macro_rules! entrypoint_tests { .expect("instance can be created"); let retval = inst - .run(b"add_f64_2", &[(-6.9f64).into(), 4.2f64.into()]) + .run("add_f64_2", &[(-6.9f64).into(), 4.2f64.into()]) .expect("instance runs"); assert_eq!(f64::from(retval), -6.9 + 4.2); @@ -393,7 +387,7 @@ macro_rules! entrypoint_tests { let retval = inst .run( - b"add_f32_10", + "add_f32_10", &[ 0.1f32.into(), 0.2f32.into(), @@ -431,7 +425,7 @@ macro_rules! entrypoint_tests { let retval = inst .run( - b"add_f64_10", + "add_f64_10", &[ 0.1f64.into(), 0.2f64.into(), @@ -466,7 +460,7 @@ macro_rules! entrypoint_tests { let retval = inst .run( - b"add_mixed_20", + "add_mixed_20", &[ (-1.1f64).into(), 1u8.into(), @@ -533,7 +527,7 @@ macro_rules! entrypoint_tests { .new_instance(module) .expect("instance can be created"); - match inst.run(b"add_2", &[123.0f64.into(), 456.0f64.into()]) { + match inst.run("add_2", &[123.0f64.into(), 456.0f64.into()]) { Err(Error::InvalidArgument(err)) => { assert_eq!(err, "entrypoint function signature mismatch") } @@ -557,7 +551,7 @@ macro_rules! entrypoint_tests { .new_instance(module) .expect("instance can be created"); - match inst.run(b"add_2", &[123u64.into()]) { + match inst.run("add_2", &[123u64.into()]) { Err(Error::InvalidArgument(err)) => assert_eq!( err, "entrypoint function signature mismatch (number of arguments is incorrect)" @@ -582,7 +576,7 @@ macro_rules! entrypoint_tests { .new_instance(module) .expect("instance can be created"); - match inst.run(b"add_2", &[123u64.into(), 456u64.into(), 789u64.into()]) { + match inst.run("add_2", &[123u64.into(), 456u64.into(), 789u64.into()]) { Err(Error::InvalidArgument(err)) => assert_eq!( err, "entrypoint function signature mismatch (number of arguments is incorrect)" @@ -617,7 +611,7 @@ macro_rules! entrypoint_tests { // This function will call `malloc` for the given size, then `memset` the entire region to the // init_as argument. The pointer to the allocated region gets stored in loc_outval. inst.run( - b"create_and_memset", + "create_and_memset", &[ // int init_as TEST_REGION_INIT_VAL.into(), @@ -668,7 +662,7 @@ macro_rules! entrypoint_tests { // Create a region and initialize it, just like above inst.run( - b"create_and_memset", + "create_and_memset", &[ // int init_as TEST_REGION_INIT_VAL.into(), @@ -698,7 +692,7 @@ macro_rules! entrypoint_tests { } // Then increment the first location in the region - inst.run(b"increment_ptr", &[Val::GuestPtr(loc_region_1)]) + inst.run("increment_ptr", &[Val::GuestPtr(loc_region_1)]) .expect("instance runs"); let heap = inst.heap(); @@ -743,7 +737,7 @@ macro_rules! entrypoint_tests { // same as above inst.run( - b"create_and_memset", + "create_and_memset", &[ // int init_as TEST_REGION_INIT_VAL.into(), @@ -763,7 +757,7 @@ macro_rules! entrypoint_tests { // Create a second region inst.run( - b"create_and_memset", + "create_and_memset", &[ // int init_as TEST_REGION2_INIT_VAL.into(), @@ -821,7 +815,7 @@ macro_rules! entrypoint_tests { // Run the setup routine inst.run( - b"ctype_setup", + "ctype_setup", &[ std::ptr::null::().into(), Val::GuestPtr(loc_ctxstar), @@ -837,7 +831,7 @@ macro_rules! entrypoint_tests { assert!(ctxstar > 0); // Run the body routine - inst.run(b"ctype_body", &[Val::GuestPtr(ctxstar)]) + inst.run("ctype_body", &[Val::GuestPtr(ctxstar)]) .expect("instance runs"); } @@ -870,7 +864,7 @@ macro_rules! entrypoint_tests { .expect("instance can be created"); let retval = inst - .run(b"callback_entrypoint", &[0u64.into()]) + .run("callback_entrypoint", &[0u64.into()]) .expect("instance runs"); assert_eq!(u64::from(retval), 3); } diff --git a/lucet-runtime/lucet-runtime-tests/src/globals.rs b/lucet-runtime/lucet-runtime-tests/src/globals.rs index 6beecdb5e..de3eca6ec 100644 --- a/lucet-runtime/lucet-runtime-tests/src/globals.rs +++ b/lucet-runtime/lucet-runtime-tests/src/globals.rs @@ -18,7 +18,7 @@ macro_rules! globals_tests { .new_instance(module) .expect("instance can be created"); - inst.run(b"main", &[]).expect("instance runs"); + inst.run("main", &[]).expect("instance runs"); // Now the globals should be: // $x = 3 @@ -32,7 +32,7 @@ macro_rules! globals_tests { let heap_u32 = unsafe { inst.heap_u32() }; assert_eq!(heap_u32[0..=2], [4, 5, 6]); - inst.run(b"main", &[]).expect("instance runs"); + inst.run("main", &[]).expect("instance runs"); // now heap should be: // [0] = 3 @@ -84,15 +84,15 @@ macro_rules! globals_tests { .with_global(0, -1) .with_global(1, 420) .with_export_func( - MockExportBuilder::new(b"get_global0", FunctionPointer::from_usize(get_global0 as usize)) + MockExportBuilder::new("get_global0", FunctionPointer::from_usize(get_global0 as usize)) .with_sig(lucet_signature!(() -> I64)) ) .with_export_func( - MockExportBuilder::new(b"set_global0", FunctionPointer::from_usize(set_global0 as usize)) + MockExportBuilder::new("set_global0", FunctionPointer::from_usize(set_global0 as usize)) .with_sig(lucet_signature!((I64) -> ())) ) .with_export_func( - MockExportBuilder::new(b"get_global1", FunctionPointer::from_usize(get_global1 as usize)) + MockExportBuilder::new("get_global1", FunctionPointer::from_usize(get_global1 as usize)) .with_sig(lucet_signature!(() -> I64)) ) .build() @@ -121,7 +121,7 @@ macro_rules! globals_tests { .new_instance(module) .expect("instance can be created"); - let retval = inst.run(b"get_global0", &[]).expect("instance runs"); + let retval = inst.run("get_global0", &[]).expect("instance runs"); assert_eq!(i64::from(retval), -1); } @@ -133,10 +133,10 @@ macro_rules! globals_tests { .new_instance(module) .expect("instance can be created"); - let retval = inst.run(b"get_global0", &[]).expect("instance runs"); + let retval = inst.run("get_global0", &[]).expect("instance runs"); assert_eq!(i64::from(retval), -1); - let retval = inst.run(b"get_global1", &[]).expect("instance runs"); + let retval = inst.run("get_global1", &[]).expect("instance runs"); assert_eq!(i64::from(retval), 420); } @@ -148,10 +148,10 @@ macro_rules! globals_tests { .new_instance(module) .expect("instance can be created"); - inst.run(b"set_global0", &[666i64.into()]) + inst.run("set_global0", &[666i64.into()]) .expect("instance runs"); - let retval = inst.run(b"get_global0", &[]).expect("instance runs"); + let retval = inst.run("get_global0", &[]).expect("instance runs"); assert_eq!(i64::from(retval), 666); } }; diff --git a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs index 4c2314fee..a99df235e 100644 --- a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs +++ b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs @@ -85,36 +85,36 @@ pub fn mock_traps_module() -> Arc { MockModuleBuilder::new() .with_export_func(MockExportBuilder::new( - b"onetwothree", + "onetwothree", FunctionPointer::from_usize(onetwothree as usize), )) .with_export_func( MockExportBuilder::new( - b"illegal_instr", + "illegal_instr", FunctionPointer::from_usize(guest_func_illegal_instr as usize), ) .with_func_len(11) .with_traps(ILLEGAL_INSTR_TRAPS), ) .with_export_func( - MockExportBuilder::new(b"oob", FunctionPointer::from_usize(guest_func_oob as usize)) + MockExportBuilder::new("oob", FunctionPointer::from_usize(guest_func_oob as usize)) .with_func_len(41) .with_traps(OOB_TRAPS), ) .with_export_func(MockExportBuilder::new( - b"hostcall_main", + "hostcall_main", FunctionPointer::from_usize(hostcall_main as usize), )) .with_export_func(MockExportBuilder::new( - b"infinite_loop", + "infinite_loop", FunctionPointer::from_usize(infinite_loop as usize), )) .with_export_func(MockExportBuilder::new( - b"fatal", + "fatal", FunctionPointer::from_usize(fatal as usize), )) .with_export_func(MockExportBuilder::new( - b"recoverable_fatal", + "recoverable_fatal", FunctionPointer::from_usize(recoverable_fatal as usize), )) .build() @@ -194,7 +194,7 @@ macro_rules! guest_fault_tests { } fn run_onetwothree(inst: &mut Instance) { - let retval = inst.run(b"onetwothree", &[]).expect("instance runs"); + let retval = inst.run("onetwothree", &[]).expect("instance runs"); assert_eq!(libc::c_int::from(retval), 123); } @@ -208,7 +208,7 @@ macro_rules! guest_fault_tests { .new_instance(module) .expect("instance can be created"); - match inst.run(b"illegal_instr", &[]) { + match inst.run("illegal_instr", &[]) { Err(Error::RuntimeFault(details)) => { assert_eq!(details.trapcode, Some(TrapCode::BadSignature)); } @@ -232,7 +232,7 @@ macro_rules! guest_fault_tests { .new_instance(module) .expect("instance can be created"); - match inst.run(b"oob", &[]) { + match inst.run("oob", &[]) { Err(Error::RuntimeFault(details)) => { assert_eq!(details.trapcode, Some(TrapCode::HeapOutOfBounds)); } @@ -256,7 +256,7 @@ macro_rules! guest_fault_tests { .new_instance(module) .expect("instance can be created"); - match inst.run(b"hostcall_main", &[]) { + match inst.run("hostcall_main", &[]) { Err(Error::RuntimeTerminated(term)) => { assert_eq!( *term @@ -317,7 +317,7 @@ macro_rules! guest_fault_tests { // returns. This will initially cause a segfault. The signal handler will recover // from the segfault, map the page to read/write, and then return to the child // code. The child code will then succeed, and the instance will exit successfully. - inst.run(b"recoverable_fatal", &[]).expect("instance runs"); + inst.run("recoverable_fatal", &[]).expect("instance runs"); unsafe { recoverable_ptr_teardown() }; drop(lock); @@ -362,7 +362,7 @@ macro_rules! guest_fault_tests { // returns. This will initially cause a segfault. The signal handler will recover // from the segfault, map the page to read/write, and then return to the child // code. The child code will then succeed, and the instance will exit successfully. - match inst.run(b"recoverable_fatal", &[]) { + match inst.run("recoverable_fatal", &[]) { Err(Error::RuntimeTerminated(_)) => (), res => panic!("unexpected result: {:?}", res), } @@ -417,7 +417,7 @@ macro_rules! guest_fault_tests { ); unsafe { sigaction(Signal::SIGSEGV, &sa).expect("sigaction succeeds") }; - match inst.run(b"illegal_instr", &[]) { + match inst.run("illegal_instr", &[]) { Err(Error::RuntimeFault(details)) => { assert_eq!(details.trapcode, Some(TrapCode::BadSignature)); } @@ -486,7 +486,7 @@ macro_rules! guest_fault_tests { nix::unistd::alarm::set(1); // run guest code that loops forever - inst.run(b"infinite_loop", &[]).expect("instance runs"); + inst.run("infinite_loop", &[]).expect("instance runs"); // show that we never get here std::process::exit(1); } @@ -546,7 +546,7 @@ macro_rules! guest_fault_tests { let child = std::thread::spawn(|| { let module = MockModuleBuilder::new() .with_export_func(MockExportBuilder::new( - b"sleepy_guest", + "sleepy_guest", FunctionPointer::from_usize(sleepy_guest as usize), )) .build(); @@ -556,7 +556,7 @@ macro_rules! guest_fault_tests { .new_instance(module) .expect("instance can be created"); - inst.run(b"sleepy_guest", &[]).expect("instance runs"); + inst.run("sleepy_guest", &[]).expect("instance runs"); }); // now trigger a segfault in the middle of running the guest @@ -606,7 +606,7 @@ macro_rules! guest_fault_tests { .new_instance(module) .expect("instance can be created"); - inst.run(b"infinite_loop", &[]).expect("instance runs"); + inst.run("infinite_loop", &[]).expect("instance runs"); unreachable!() }); @@ -646,7 +646,7 @@ macro_rules! guest_fault_tests { // Child code should run code that will make an OOB beyond the guard page. This will // cause the entire process to abort before returning from `run` inst.set_fatal_handler(handler); - inst.run(b"fatal", &[]).expect("instance runs"); + inst.run("fatal", &[]).expect("instance runs"); // Show that we never get here: std::process::exit(1); } @@ -681,7 +681,7 @@ macro_rules! guest_fault_tests { // Child code should run code that will make an OOB beyond the guard page. This will // cause the entire process to abort before returning from `run` inst.set_fatal_handler(fatal_handler_exit); - inst.run(b"fatal", &[]).expect("instance runs"); + inst.run("fatal", &[]).expect("instance runs"); // Show that we never get here: std::process::exit(1); } diff --git a/lucet-runtime/lucet-runtime-tests/src/host.rs b/lucet-runtime/lucet-runtime-tests/src/host.rs index 5e8d10a54..91c40a346 100644 --- a/lucet-runtime/lucet-runtime-tests/src/host.rs +++ b/lucet-runtime/lucet-runtime-tests/src/host.rs @@ -119,7 +119,7 @@ macro_rules! host_tests { let mut inst = region .new_instance(module) .expect("instance can be created"); - inst.run(b"main", &[0u32.into(), 0i32.into()]) + inst.run("main", &[0u32.into(), 0i32.into()]) .expect("instance runs"); } @@ -134,7 +134,7 @@ macro_rules! host_tests { .build() .expect("instance can be created"); - inst.run(b"main", &[0u32.into(), 0i32.into()]) + inst.run("main", &[0u32.into(), 0i32.into()]) .expect("instance runs"); assert!(*inst.get_embed_ctx::().unwrap().unwrap()); @@ -148,7 +148,7 @@ macro_rules! host_tests { .new_instance(module) .expect("instance can be created"); - match inst.run(b"main", &[0u32.into(), 0i32.into()]) { + match inst.run("main", &[0u32.into(), 0i32.into()]) { Err(Error::RuntimeTerminated(term)) => { assert_eq!( *term @@ -172,7 +172,7 @@ macro_rules! host_tests { .new_instance(module) .expect("instance can be created"); - match inst.run(b"main", &[0u32.into(), 0u32.into()]) { + match inst.run("main", &[0u32.into(), 0u32.into()]) { Err(Error::RuntimeTerminated(term)) => { assert_eq!( *term @@ -197,7 +197,7 @@ macro_rules! host_tests { .new_instance(module) .expect("instance can be created"); - match inst.run(b"trigger_div_error", &[0u32.into()]) { + match inst.run("trigger_div_error", &[0u32.into()]) { Err(Error::RuntimeFault(details)) => { assert_eq!(details.trapcode, Some(TrapCode::IntegerDivByZero)); } @@ -219,7 +219,7 @@ macro_rules! host_tests { let module = MockModuleBuilder::new() .with_export_func(MockExportBuilder::new( - b"f", + "f", FunctionPointer::from_usize(f as usize), )) .build(); @@ -229,7 +229,7 @@ macro_rules! host_tests { .new_instance(module) .expect("instance can be created"); - match inst.run(b"f", &[]) { + match inst.run("f", &[]) { Err(Error::RuntimeTerminated(details)) => { assert_eq!(details, TerminationDetails::BorrowError("heap_mut")); } @@ -251,7 +251,7 @@ macro_rules! host_tests { let module = MockModuleBuilder::new() .with_export_func(MockExportBuilder::new( - b"f", + "f", FunctionPointer::from_usize(f as usize), )) .build(); @@ -261,7 +261,7 @@ macro_rules! host_tests { .new_instance(module) .expect("instance can be created"); - match inst.run(b"f", &[]) { + match inst.run("f", &[]) { Err(Error::RuntimeTerminated(details)) => { assert_eq!(details, TerminationDetails::CtxNotFound); } @@ -283,7 +283,7 @@ macro_rules! host_tests { let module = MockModuleBuilder::new() .with_export_func(MockExportBuilder::new( - b"f", + "f", FunctionPointer::from_usize(f as usize), )) .build(); @@ -293,7 +293,7 @@ macro_rules! host_tests { .new_instance(module) .expect("instance can be created"); - let retval = inst.run(b"f", &[]).expect("instance runs"); + let retval = inst.run("f", &[]).expect("instance runs"); assert_eq!(bool::from(retval), true); } }; diff --git a/lucet-runtime/lucet-runtime-tests/src/memory.rs b/lucet-runtime/lucet-runtime-tests/src/memory.rs index ad3cc458a..b24cab9cb 100644 --- a/lucet-runtime/lucet-runtime-tests/src/memory.rs +++ b/lucet-runtime/lucet-runtime-tests/src/memory.rs @@ -16,7 +16,7 @@ macro_rules! memory_tests { .new_instance(module) .expect("instance can be created"); - let retval = inst.run(b"main", &[]).expect("instance runs"); + let retval = inst.run("main", &[]).expect("instance runs"); assert_eq!(u32::from(retval), 4); } @@ -29,7 +29,7 @@ macro_rules! memory_tests { .new_instance(module) .expect("instance can be created"); - inst.run(b"main", &[]).expect("instance runs"); + inst.run("main", &[]).expect("instance runs"); let heap = inst.heap_u32(); // guest puts the result of the grow_memory(1) call in heap[0]; based on the current settings, diff --git a/lucet-runtime/lucet-runtime-tests/src/stack.rs b/lucet-runtime/lucet-runtime-tests/src/stack.rs index 3e448918a..126716dec 100644 --- a/lucet-runtime/lucet-runtime-tests/src/stack.rs +++ b/lucet-runtime/lucet-runtime-tests/src/stack.rs @@ -96,7 +96,7 @@ macro_rules! stack_tests { .new_instance(module) .expect("instance can be created"); - inst.run(b"localpalooza", &[recursion_depth.into()]) + inst.run("localpalooza", &[recursion_depth.into()]) } fn expect_ok(module: Arc, recursion_depth: i32) { diff --git a/lucet-runtime/lucet-runtime-tests/src/start.rs b/lucet-runtime/lucet-runtime-tests/src/start.rs index 91418163b..2daab564b 100644 --- a/lucet-runtime/lucet-runtime-tests/src/start.rs +++ b/lucet-runtime/lucet-runtime-tests/src/start.rs @@ -15,7 +15,7 @@ macro_rules! start_tests { .new_instance(module) .expect("instance can be created"); - inst.run(b"main", &[]).expect("instance runs"); + inst.run("main", &[]).expect("instance runs"); // Now the globals should be: // $flossie = 17 @@ -35,7 +35,7 @@ macro_rules! start_tests { .new_instance(module) .expect("instance can be created"); - inst.run(b"main", &[]).expect("instance runs"); + inst.run("main", &[]).expect("instance runs"); // Now the globals should be: // $flossie = 17 @@ -55,7 +55,7 @@ macro_rules! start_tests { .new_instance(module) .expect("instance can be created"); - inst.run(b"main", &[]).expect("instance runs"); + inst.run("main", &[]).expect("instance runs"); // Now the globals should be: // $flossie = 17 diff --git a/lucet-runtime/lucet-runtime-tests/src/strcmp.rs b/lucet-runtime/lucet-runtime-tests/src/strcmp.rs index 857b0b089..991f7833b 100644 --- a/lucet-runtime/lucet-runtime-tests/src/strcmp.rs +++ b/lucet-runtime/lucet-runtime-tests/src/strcmp.rs @@ -45,7 +45,7 @@ macro_rules! strcmp_tests { let res = c_int::from( inst.run( - b"run_strcmp", + "run_strcmp", &[Val::GuestPtr(s1_ptr as u32), Val::GuestPtr(s2_ptr as u32)], ) .expect("instance runs"), @@ -84,7 +84,7 @@ macro_rules! strcmp_tests { .new_instance(module) .expect("instance can be created"); - match inst.run(b"wasm_fault", &[]) { + match inst.run("wasm_fault", &[]) { Err(Error::RuntimeFault { .. }) => (), res => panic!("unexpected result: {:?}", res), } diff --git a/lucet-runtime/src/c_api.rs b/lucet-runtime/src/c_api.rs index 20c318b97..b41f0f475 100644 --- a/lucet-runtime/src/c_api.rs +++ b/lucet-runtime/src/c_api.rs @@ -165,9 +165,15 @@ pub unsafe extern "C" fn lucet_instance_run( .map(|v| v.into()) .collect() }; + let entrypoint = match CStr::from_ptr(entrypoint).to_str() { + Ok(entrypoint_str) => entrypoint_str, + Err(_) => { + return lucet_error::SymbolNotFound; + } + }; + with_instance_ptr!(inst, { - let entrypoint = CStr::from_ptr(entrypoint); - inst.run(entrypoint.to_bytes(), args.as_slice()) + inst.run(entrypoint, args.as_slice()) .map(|_| lucet_error::Ok) .unwrap_or_else(|e| { eprintln!("{}", e); diff --git a/lucet-runtime/src/lib.rs b/lucet-runtime/src/lib.rs index aeb91b0a3..a4583d1e3 100644 --- a/lucet-runtime/src/lib.rs +++ b/lucet-runtime/src/lib.rs @@ -53,7 +53,7 @@ //! let region = MmapRegion::create(1, &Limits::default()).unwrap(); //! let mut inst = region.new_instance(module).unwrap(); //! -//! let retval = inst.run(b"factorial", &[5u64.into()]).unwrap(); +//! let retval = inst.run("factorial", &[5u64.into()]).unwrap(); //! assert_eq!(u64::from(retval), 120u64); //! ``` //! @@ -95,7 +95,7 @@ //! .build() //! .unwrap(); //! -//! inst.run(b"call_foo", &[]).unwrap(); +//! inst.run("call_foo", &[]).unwrap(); //! //! let context_after = inst.get_embed_ctx::().unwrap().unwrap(); //! assert_eq!(context_after.x, 42); @@ -124,7 +124,7 @@ //! .build() //! .unwrap(); //! -//! inst.run(b"main", &[]).unwrap(); +//! inst.run("main", &[]).unwrap(); //! //! // clean up embedder context //! drop(inst); @@ -171,7 +171,7 @@ //! // install the handler //! inst.set_signal_handler(signal_handler_count); //! -//! match inst.run(b"raise_a_signal", &[]) { +//! match inst.run("raise_a_signal", &[]) { //! Err(Error::RuntimeFault(_)) => { //! println!("I've now handled {} signals!", SIGNAL_COUNT.load(Ordering::SeqCst)); //! } diff --git a/lucet-spectest/src/script.rs b/lucet-spectest/src/script.rs index 3fea710f0..db0269d13 100644 --- a/lucet-spectest/src/script.rs +++ b/lucet-spectest/src/script.rs @@ -159,7 +159,7 @@ impl ScriptEnv { args: Vec, ) -> Result { let (_, ref mut inst) = self.instance_named_mut(name)?; - inst.run(field.as_bytes(), &args) + inst.run(field, &args) .map_err(|e| ScriptError::RuntimeError(e)) } diff --git a/lucet-wasi-fuzz/src/main.rs b/lucet-wasi-fuzz/src/main.rs index 740bb7e09..1757838df 100644 --- a/lucet-wasi-fuzz/src/main.rs +++ b/lucet-wasi-fuzz/src/main.rs @@ -382,7 +382,7 @@ fn run>( .with_embed_ctx(ctx) .build()?; - match inst.run(b"_start", &[]) { + match inst.run("_start", &[]) { // normal termination implies 0 exit code Ok(_) => Ok(0), Err(lucet_runtime::Error::RuntimeTerminated( diff --git a/lucet-wasi/src/main.rs b/lucet-wasi/src/main.rs index 67ee5b90c..9ce31ad28 100644 --- a/lucet-wasi/src/main.rs +++ b/lucet-wasi/src/main.rs @@ -188,7 +188,7 @@ fn run(config: Config) { .build() .expect("instance can be created"); - match inst.run(config.entrypoint.as_bytes(), &[]) { + match inst.run(config.entrypoint, &[]) { // normal termination implies 0 exit code Ok(_) => 0, Err(lucet_runtime::Error::RuntimeTerminated( diff --git a/lucet-wasi/tests/test_helpers/mod.rs b/lucet-wasi/tests/test_helpers/mod.rs index 5c32b9c28..4fc9e34bb 100644 --- a/lucet-wasi/tests/test_helpers/mod.rs +++ b/lucet-wasi/tests/test_helpers/mod.rs @@ -65,7 +65,7 @@ pub fn run>(path: P, ctx: WasiCtx) -> Result<__wasi_exitcode_t, E .with_embed_ctx(ctx) .build()?; - match inst.run(b"_start", &[]) { + match inst.run("_start", &[]) { // normal termination implies 0 exit code Ok(_) => Ok(0), Err(lucet_runtime::Error::RuntimeTerminated( diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index edb76b91f..d494c5f98 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -15,8 +15,9 @@ use cranelift_wasm::{ }; use failure::{format_err, Error, ResultExt}; use lucet_module_data::{ - owned::OwnedLinearMemorySpec, FunctionMetadata, Global as GlobalVariant, GlobalDef, GlobalSpec, - HeapSpec, ModuleData, Signature as LucetSignature, UniqueSignatureIndex, + owned::OwnedLinearMemorySpec, ExportFunction, FunctionIndex as LucetFunctionIndex, + FunctionMetadata, Global as GlobalVariant, GlobalDef, GlobalSpec, HeapSpec, ImportFunction, + ModuleData, Signature as LucetSignature, UniqueSignatureIndex, }; use std::collections::HashMap; use std::convert::TryFrom; @@ -61,6 +62,8 @@ pub struct ModuleDecls<'a> { info: ModuleInfo<'a>, runtime: Runtime, function_names: PrimaryMap, + imports: Vec>, + exports: Vec>, table_names: PrimaryMap, runtime_names: HashMap, globals_spec: Vec>, @@ -75,7 +78,7 @@ impl<'a> ModuleDecls<'a> { runtime: Runtime, heap_settings: HeapSettings, ) -> Result { - let function_names = Self::declare_funcs(&info, clif_module, bindings)?; + let (function_names, imports, exports) = Self::declare_funcs(&info, clif_module, bindings)?; let table_names = Self::declare_tables(&info, clif_module)?; let runtime_names = Self::declare_runtime(&runtime, clif_module)?; let globals_spec = Self::declare_globals_spec(&info)?; @@ -83,6 +86,8 @@ impl<'a> ModuleDecls<'a> { Ok(Self { info, function_names, + imports, + exports, table_names, runtime_names, runtime, @@ -97,40 +102,64 @@ impl<'a> ModuleDecls<'a> { info: &ModuleInfo<'a>, clif_module: &mut ClifModule, bindings: &Bindings, - ) -> Result, LucetcError> { + ) -> Result< + ( + PrimaryMap, + Vec>, + Vec>, + ), + LucetcError, + > { let mut function_names = PrimaryMap::new(); + let mut exports: Vec> = Vec::new(); + let mut imports: Vec> = Vec::with_capacity(info.imported_funcs.len()); + for ix in 0..info.functions.len() { let func_index = FuncIndex::new(ix); let exportable_sigix = info.functions.get(func_index).unwrap(); let inner_sig_index = info.signature_mapping.get(exportable_sigix.entity).unwrap(); let signature = info.signatures.get(*inner_sig_index).unwrap(); - let name = if let Some((import_mod, import_field)) = info.imported_funcs.get(func_index) - { - let import_symbol = bindings - .translate(import_mod, import_field) - .context(LucetcErrorKind::TranslatingModule)?; - let funcid = clif_module - .declare_function(&import_symbol, Linkage::Import, signature) - .context(LucetcErrorKind::TranslatingModule)?; - Name::new_func(import_symbol, funcid) + + let exported_name = if !exportable_sigix.export_names.is_empty() { + exports.push(ExportFunction { + fn_idx: LucetFunctionIndex::from_u32(function_names.len() as u32), + names: exportable_sigix.export_names.clone(), + }); + + Some(( + format!("guest_func_{}", exportable_sigix.export_names[0]), + Linkage::Export, + )) } else { - if exportable_sigix.export_names.is_empty() { - let def_symbol = format!("guest_func_{}", ix); - let funcid = clif_module - .declare_function(&def_symbol, Linkage::Local, signature) + None + }; + + let imported_name = + if let Some((import_mod, import_field)) = info.imported_funcs.get(func_index) { + imports.push(ImportFunction { + fn_idx: LucetFunctionIndex::from_u32(function_names.len() as u32), + module: import_mod, + name: import_field, + }); + let import_symbol = bindings + .translate(import_mod, import_field) .context(LucetcErrorKind::TranslatingModule)?; - Name::new_func(def_symbol, funcid) + Some((import_symbol, Linkage::Import)) } else { - let export_symbol = format!("guest_func_{}", exportable_sigix.export_names[0]); - let funcid = clif_module - .declare_function(&export_symbol, Linkage::Export, signature) - .context(LucetcErrorKind::TranslatingModule)?; - Name::new_func(export_symbol, funcid) - } - }; - function_names.push(name); + None + }; + + let (decl_sym, decl_linkage) = imported_name + .or(exported_name) + .unwrap_or_else(|| (format!("guest_func_{}", ix), Linkage::Local)); + + let funcid = clif_module + .declare_function(&decl_sym, decl_linkage, signature) + .context(LucetcErrorKind::TranslatingModule)?; + + function_names.push(Name::new_func(decl_sym, funcid)); } - Ok(function_names) + Ok((function_names, imports, exports)) } fn declare_tables( @@ -383,7 +412,10 @@ impl<'a> ModuleDecls<'a> { functions.push(FunctionMetadata { signature: decl.signature_index, - sym: Some(name.symbol().as_bytes()), // TODO: what about functions without names? currently internal functions are named like `guest_func_N`. + // TODO: this is a best-effort attempt to figure out a useful name. + // in the future, we should use names from the module names section + // and maybe use export names as a fallback. + name: Some(name.symbol()), }); } @@ -402,6 +434,8 @@ impl<'a> ModuleDecls<'a> { linear_memory, self.globals_spec.clone(), functions, + self.imports.clone(), + self.exports.clone(), signatures, )) } diff --git a/lucetc/tests/wasi-sdk.rs b/lucetc/tests/wasi-sdk.rs index 270bf682e..48fb51f62 100644 --- a/lucetc/tests/wasi-sdk.rs +++ b/lucetc/tests/wasi-sdk.rs @@ -71,10 +71,11 @@ mod programs { 0 ); + assert_eq!(mdata.import_functions().len(), 0, "import functions"); + assert_eq!(mdata.export_functions().len(), 0, "export functions"); + /* FIXME: module data doesn't contain the information to check these properties: - assert_eq!(p.import_functions().len(), 0, "import functions"); assert_eq!(num_import_globals(&p), 0, "import globals"); - assert_eq!(num_export_functions(&p), 0, "export functions"); */ let _obj = c.object_file().expect("generate code from empty"); @@ -87,12 +88,13 @@ mod programs { let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile a"); - let _mdata = c.module_data().unwrap(); + let mdata = c.module_data().unwrap(); + + assert_eq!(mdata.import_functions().len(), 0, "import functions"); + assert_eq!(mdata.export_functions().len(), 1, "export functions"); /* FIXME: module data doesn't contain the information to check these properties: - assert_eq!(p.import_functions().len(), 0, "import functions"); assert_eq!(num_import_globals(&p), 0, "import globals"); - assert_eq!(num_export_functions(&p), 1, "export functions"); */ let _obj = c.object_file().expect("generate code from a"); @@ -104,11 +106,12 @@ mod programs { let b = b_only_test_bindings(); let h = HeapSettings::default(); let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile b"); - let _mdata = c.module_data().unwrap(); + let mdata = c.module_data().unwrap(); + assert_eq!(mdata.import_functions().len(), 1, "import functions"); + assert_eq!(mdata.export_functions().len(), 1, "export functions"); + /* FIXME: module data doesn't contain the information to check these properties: - assert_eq!(p.import_functions().len(), 1, "import functions"); assert_eq!(num_import_globals(&p), 0, "import globals"); - assert_eq!(num_export_functions(&p), 1, "export functions"); */ let _obj = c.object_file().expect("generate code from b"); } @@ -119,11 +122,12 @@ mod programs { let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile a & b"); - let _mdata = c.module_data().unwrap(); + let mdata = c.module_data().unwrap(); + assert_eq!(mdata.import_functions().len(), 0, "import functions"); + assert_eq!(mdata.export_functions().len(), 2, "export functions"); + /* FIXME: module data doesn't contain the information to check these properties: - assert_eq!(p.import_functions().len(), 0, "import functions"); assert_eq!(num_import_globals(&p), 0, "import globals"); - assert_eq!(num_export_functions(&p), 2, "export functions"); */ let _obj = c.object_file().expect("generate code from a & b"); } diff --git a/lucetc/tests/wasm.rs b/lucetc/tests/wasm.rs index 8213e163c..2c9cfe133 100644 --- a/lucetc/tests/wasm.rs +++ b/lucetc/tests/wasm.rs @@ -41,16 +41,12 @@ mod module_data { let b = super::test_bindings(); let h = HeapSettings::default(); let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compiling fibonacci"); - assert_eq!(c.module_data().unwrap().globals_spec().len(), 0); + let mdata = c.module_data().unwrap(); + assert_eq!(mdata.globals_spec().len(), 0); - /* TODO can't express these with module data - assert_eq!(p.import_functions().len(), 0); - assert_eq!(p.defined_functions().len(), 1); - assert_eq!( - p.defined_functions().get(0).unwrap().symbol(), - "guest_func_main" - ); - */ + assert_eq!(mdata.import_functions().len(), 0); + assert_eq!(mdata.function_info().len(), 1); + assert_eq!(mdata.export_functions()[0].names, vec!["main"]); } #[test] @@ -59,16 +55,12 @@ mod module_data { let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compiling arith"); - assert_eq!(c.module_data().unwrap().globals_spec().len(), 0); + let mdata = c.module_data().unwrap(); + assert_eq!(mdata.globals_spec().len(), 0); - /* TODO can't express these with module data - assert_eq!(p.import_functions().len(), 0); - assert_eq!(p.defined_functions().len(), 1); - assert_eq!( - p.defined_functions().get(0).unwrap().symbol(), - "guest_func_main" - ); - */ + assert_eq!(mdata.import_functions().len(), 0); + assert_eq!(mdata.function_info().len(), 1); + assert_eq!(mdata.export_functions()[0].names, vec!["main"]); } #[test] fn icall_import() { @@ -79,18 +71,16 @@ mod module_data { .unwrap(); let h = HeapSettings::default(); let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile icall"); - let _module_data = c.module_data().unwrap(); + let mdata = c.module_data().unwrap(); + + assert_eq!(mdata.import_functions().len(), 1); + assert_eq!(mdata.import_functions()[0].module, "env"); + assert_eq!(mdata.import_functions()[0].name, "icalltarget"); + assert_eq!(mdata.function_info().len(), 5); + assert_eq!(mdata.export_functions()[0].names, vec!["launchpad"]); + assert_eq!(mdata.globals_spec().len(), 0); /* TODO can't express these with module data - assert_eq!(p.import_functions().len(), 1); - assert_eq!(p.import_functions()[0].module(), "env"); - assert_eq!(p.import_functions()[0].field(), "icalltarget"); - assert_eq!(p.globals().len(), 0); - assert_eq!(p.defined_functions().len(), 4); - assert_eq!( - p.defined_functions().get(0).unwrap().symbol(), - "guest_func_launchpad" - ); assert_eq!( p.get_table(0).unwrap().elements().get(0), Some(&TableElem::FunctionIx(2)) From 40ae1df64536250a2b6ab67e7f167d22f4aa7f94 Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Fri, 17 May 2019 02:23:17 +0200 Subject: [PATCH 135/512] Implement the remaining hostcalls (#176) * Implement the remaining hostcalls * host->wasm32 encoding: convert to little-endian if required * Add an errno test --- lucet-wasi/bindings.json | 27 +- lucet-wasi/src/host.rs | 12 + lucet-wasi/src/hostcalls.rs | 1357 ------------------------ lucet-wasi/src/hostcalls/fs.rs | 1338 +++++++++++++++++++++++ lucet-wasi/src/hostcalls/fs_helpers.rs | 303 ++++++ lucet-wasi/src/hostcalls/misc.rs | 479 +++++++++ lucet-wasi/src/hostcalls/mod.rs | 447 ++++++++ lucet-wasi/src/memory.rs | 86 +- lucet-wasi/tests/guests/fs.c | 149 +++ lucet-wasi/tests/tests.rs | 15 + 10 files changed, 2851 insertions(+), 1362 deletions(-) delete mode 100644 lucet-wasi/src/hostcalls.rs create mode 100644 lucet-wasi/src/hostcalls/fs.rs create mode 100644 lucet-wasi/src/hostcalls/fs_helpers.rs create mode 100644 lucet-wasi/src/hostcalls/misc.rs create mode 100644 lucet-wasi/src/hostcalls/mod.rs create mode 100644 lucet-wasi/tests/guests/fs.c diff --git a/lucet-wasi/bindings.json b/lucet-wasi/bindings.json index edb2a947a..568ad7eb6 100644 --- a/lucet-wasi/bindings.json +++ b/lucet-wasi/bindings.json @@ -6,21 +6,40 @@ "clock_time_get": "__wasi_clock_time_get", "environ_get": "__wasi_environ_get", "environ_sizes_get": "__wasi_environ_sizes_get", - "proc_exit": "__wasi_proc_exit", + "fd_advise": "__wasi_fd_advise", + "fd_allocate": "__wasi_fd_allocate", "fd_close": "__wasi_fd_close", + "fd_datasync": "__wasi_fd_datasync", "fd_fdstat_get": "__wasi_fd_fdstat_get", "fd_fdstat_set_flags": "__wasi_fd_fdstat_set_flags", + "fd_fdstat_set_rights": "__wasi_fd_fdstat_set_rights", "fd_filestat_get": "__wasi_fd_filestat_get", - "fd_prestat_get": "__wasi_fd_prestat_get", + "fd_filestat_set_size": "__wasi_fd_filestat_set_size", + "fd_filestat_set_times": "__wasi_fd_filestat_set_times", + "fd_pread": "__wasi_fd_pread", "fd_prestat_dir_name": "__wasi_fd_prestat_dir_name", + "fd_prestat_get": "__wasi_fd_prestat_get", + "fd_pwrite": "__wasi_fd_pwrite", "fd_read": "__wasi_fd_read", + "fd_readdir": "__wasi_fd_readdir", + "fd_renumber": "__wasi_fd_renumber", "fd_seek": "__wasi_fd_seek", + "fd_sync": "__wasi_fd_sync", + "fd_tell": "__wasi_fd_tell", "fd_write": "__wasi_fd_write", "path_create_directory": "__wasi_path_create_directory", "path_filestat_get": "__wasi_path_filestat_get", - "path_unlink_file": "__wasi_path_unlink_file", + "path_filestat_set_times": "__wasi_path_filestat_set_times", + "path_link": "__wasi_path_link", "path_open": "__wasi_path_open", + "path_readlink": "__wasi_path_readlink", + "path_remove_directory": "__wasi_path_remove_directory", + "path_rename": "__wasi_path_rename", + "path_symlink": "__wasi_path_symlink", + "path_unlink_file": "__wasi_path_unlink_file", "poll_oneoff": "__wasi_poll_oneoff", - "random_get": "__wasi_random_get" + "proc_exit": "__wasi_proc_exit", + "random_get": "__wasi_random_get", + "sched_yield": "__wasi_sched_yield" } } diff --git a/lucet-wasi/src/host.rs b/lucet-wasi/src/host.rs index b06b74574..b1ce783ef 100644 --- a/lucet-wasi/src/host.rs +++ b/lucet-wasi/src/host.rs @@ -17,6 +17,18 @@ pub unsafe fn ciovec_to_nix_mut<'a>( nix::sys::uio::IoVec::from_mut_slice(slice) } +pub unsafe fn iovec_to_nix<'a>(iovec: &'a __wasi_iovec_t) -> nix::sys::uio::IoVec<&'a [u8]> { + let slice = std::slice::from_raw_parts(iovec.buf as *const u8, iovec.buf_len); + nix::sys::uio::IoVec::from_slice(slice) +} + +pub unsafe fn iovec_to_nix_mut<'a>( + iovec: &'a mut __wasi_iovec_t, +) -> nix::sys::uio::IoVec<&'a mut [u8]> { + let slice = std::slice::from_raw_parts_mut(iovec.buf as *mut u8, iovec.buf_len); + nix::sys::uio::IoVec::from_mut_slice(slice) +} + pub fn errno_from_nix(errno: nix::errno::Errno) -> __wasi_errno_t { let e = match errno { nix::errno::Errno::EPERM => __WASI_EPERM, diff --git a/lucet-wasi/src/hostcalls.rs b/lucet-wasi/src/hostcalls.rs deleted file mode 100644 index ce88e81d7..000000000 --- a/lucet-wasi/src/hostcalls.rs +++ /dev/null @@ -1,1357 +0,0 @@ -//! Hostcalls that implement -//! [WASI](https://github.com/CraneStation/wasmtime-wasi/blob/wasi/docs/WASI-overview.md). -//! -//! This code borrows heavily from [wasmtime-wasi](https://github.com/CraneStation/wasmtime-wasi), -//! which in turn borrows from cloudabi-utils. See `LICENSE.wasmtime-wasi` for license information. -//! -//! This is currently a very incomplete prototype, only supporting the hostcalls required to run -//! `/examples/hello.c`, and using a bare-bones translation of the capabilities system rather than -//! something nice. - -#![allow(non_camel_case_types)] -#![allow(unused_unsafe)] -use crate::ctx::WasiCtx; -use crate::fdentry::{determine_type_rights, FdEntry}; -use crate::memory::*; -use crate::{host, wasm32}; - -use cast::From as _0; -use lucet_runtime::vmctx::Vmctx; -use lucet_runtime::{lucet_hostcall_terminate, lucet_hostcalls}; - -use nix::convert_ioctl_res; -use nix::libc::c_int; -use std::ffi::{OsStr, OsString}; -use std::os::unix::prelude::{FromRawFd, OsStrExt, OsStringExt, RawFd}; -use std::time::SystemTime; -use std::{cmp, slice}; - -#[cfg(target_os = "linux")] -const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_RSYNC; - -#[cfg(not(target_os = "linux"))] -const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_SYNC; - -lucet_hostcalls! { - #[no_mangle] - pub unsafe extern "C" fn __wasi_proc_exit( - &mut _vmctx, - rval: wasm32::__wasi_exitcode_t, - ) -> ! { - lucet_hostcall_terminate!(dec_exitcode(rval)); - } - - #[no_mangle] - pub unsafe extern "C" fn __wasi_args_get( - &mut vmctx, - argv_ptr: wasm32::uintptr_t, - argv_buf: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - let ctx = vmctx.get_embed_ctx::(); - - let mut argv_buf_offset = 0; - let mut argv = vec![]; - - for arg in ctx.args.iter() { - let arg_bytes = arg.as_bytes_with_nul(); - let arg_ptr = argv_buf + argv_buf_offset; - - if let Err(e) = unsafe { enc_slice_of(vmctx, arg_bytes, arg_ptr) } { - return enc_errno(e); - } - - argv.push(arg_ptr); - - argv_buf_offset = if let Some(new_offset) = argv_buf_offset.checked_add( - wasm32::uintptr_t::cast(arg_bytes.len()) - .expect("cast overflow would have been caught by `enc_slice_of` above"), - ) { - new_offset - } else { - return wasm32::__WASI_EOVERFLOW; - } - } - - unsafe { - enc_slice_of(vmctx, argv.as_slice(), argv_ptr) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } - } - - #[no_mangle] - pub unsafe extern "C" fn __wasi_args_sizes_get( - &mut vmctx, - argc_ptr: wasm32::uintptr_t, - argv_buf_size_ptr: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - let ctx = vmctx.get_embed_ctx::(); - - let argc = ctx.args.len(); - let argv_size = ctx - .args - .iter() - .map(|arg| arg.as_bytes_with_nul().len()) - .sum(); - - unsafe { - if let Err(e) = enc_usize_byref(vmctx, argc_ptr, argc) { - return enc_errno(e); - } - if let Err(e) = enc_usize_byref(vmctx, argv_buf_size_ptr, argv_size) { - return enc_errno(e); - } - } - wasm32::__WASI_ESUCCESS - } - - #[no_mangle] - pub unsafe extern "C" fn __wasi_clock_res_get( - &mut vmctx, - clock_id: wasm32::__wasi_clockid_t, - resolution_ptr: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - // convert the supported clocks to the libc types, or return EINVAL - let clock_id = match dec_clockid(clock_id) { - host::__WASI_CLOCK_REALTIME => libc::CLOCK_REALTIME, - host::__WASI_CLOCK_MONOTONIC => libc::CLOCK_MONOTONIC, - host::__WASI_CLOCK_PROCESS_CPUTIME_ID => libc::CLOCK_PROCESS_CPUTIME_ID, - host::__WASI_CLOCK_THREAD_CPUTIME_ID => libc::CLOCK_THREAD_CPUTIME_ID, - _ => return wasm32::__WASI_EINVAL, - }; - - // no `nix` wrapper for clock_getres, so we do it ourselves - let mut timespec = unsafe { std::mem::uninitialized::() }; - let res = unsafe { libc::clock_getres(clock_id, &mut timespec as *mut libc::timespec) }; - if res != 0 { - return wasm32::errno_from_nix(nix::errno::Errno::last()); - } - - // convert to nanoseconds, returning EOVERFLOW in case of overflow; this is freelancing a bit - // from the spec but seems like it'll be an unusual situation to hit - (timespec.tv_sec as host::__wasi_timestamp_t) - .checked_mul(1_000_000_000) - .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t)) - .map(|resolution| { - // a supported clock can never return zero; this case will probably never get hit, but - // make sure we follow the spec - if resolution == 0 { - wasm32::__WASI_EINVAL - } else { - unsafe { - enc_timestamp_byref(vmctx, resolution_ptr, resolution) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } - } - }) - .unwrap_or(wasm32::__WASI_EOVERFLOW) - } - - #[no_mangle] - pub unsafe extern "C" fn __wasi_clock_time_get( - &mut vmctx, - clock_id: wasm32::__wasi_clockid_t, - // ignored for now, but will be useful once we put optional limits on precision to reduce side - // channels - _precision: wasm32::__wasi_timestamp_t, - time_ptr: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - // convert the supported clocks to the libc types, or return EINVAL - let clock_id = match dec_clockid(clock_id) { - host::__WASI_CLOCK_REALTIME => libc::CLOCK_REALTIME, - host::__WASI_CLOCK_MONOTONIC => libc::CLOCK_MONOTONIC, - host::__WASI_CLOCK_PROCESS_CPUTIME_ID => libc::CLOCK_PROCESS_CPUTIME_ID, - host::__WASI_CLOCK_THREAD_CPUTIME_ID => libc::CLOCK_THREAD_CPUTIME_ID, - _ => return wasm32::__WASI_EINVAL, - }; - - // no `nix` wrapper for clock_getres, so we do it ourselves - let mut timespec = unsafe { std::mem::uninitialized::() }; - let res = unsafe { libc::clock_gettime(clock_id, &mut timespec as *mut libc::timespec) }; - if res != 0 { - return wasm32::errno_from_nix(nix::errno::Errno::last()); - } - - // convert to nanoseconds, returning EOVERFLOW in case of overflow; this is freelancing a bit - // from the spec but seems like it'll be an unusual situation to hit - (timespec.tv_sec as host::__wasi_timestamp_t) - .checked_mul(1_000_000_000) - .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t)) - .map(|time| unsafe { - enc_timestamp_byref(vmctx, time_ptr, time) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - }) - .unwrap_or(wasm32::__WASI_EOVERFLOW) - } - - #[no_mangle] - pub unsafe extern "C" fn __wasi_environ_get( - &mut vmctx, - environ_ptr: wasm32::uintptr_t, - environ_buf: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - let ctx = vmctx.get_embed_ctx::(); - - let mut environ_buf_offset = 0; - let mut environ = vec![]; - - for pair in ctx.env.iter() { - let env_bytes = pair.as_bytes_with_nul(); - let env_ptr = environ_buf + environ_buf_offset; - - if let Err(e) = unsafe { enc_slice_of(vmctx, env_bytes, env_ptr) } { - return enc_errno(e); - } - - environ.push(env_ptr); - - environ_buf_offset = if let Some(new_offset) = environ_buf_offset.checked_add( - wasm32::uintptr_t::cast(env_bytes.len()) - .expect("cast overflow would have been caught by `enc_slice_of` above"), - ) { - new_offset - } else { - return wasm32::__WASI_EOVERFLOW; - } - } - - unsafe { - enc_slice_of(vmctx, environ.as_slice(), environ_ptr) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } - } - - #[no_mangle] - pub unsafe extern "C" fn __wasi_environ_sizes_get( - &mut vmctx, - environ_count_ptr: wasm32::uintptr_t, - environ_size_ptr: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - let ctx = vmctx.get_embed_ctx::(); - - let environ_count = ctx.env.len(); - if let Some(environ_size) = ctx.env.iter().try_fold(0, |acc: u32, pair| { - acc.checked_add(pair.as_bytes_with_nul().len() as u32) - }) { - unsafe { - if let Err(e) = enc_usize_byref(vmctx, environ_count_ptr, environ_count) { - return enc_errno(e); - } - if let Err(e) = enc_usize_byref(vmctx, environ_size_ptr, environ_size as usize) { - return enc_errno(e); - } - } - wasm32::__WASI_ESUCCESS - } else { - wasm32::__WASI_EOVERFLOW - } - } - - #[no_mangle] - pub unsafe extern "C" fn __wasi_fd_close( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - ) -> wasm32::__wasi_errno_t { - let mut ctx = vmctx.get_embed_ctx_mut::(); - let fd = dec_fd(fd); - if let Some(fdent) = ctx.fds.get(&fd) { - // can't close preopened files - if fdent.preopen_path.is_some() { - return wasm32::__WASI_ENOTSUP; - } - } - if let Some(mut fdent) = ctx.fds.remove(&fd) { - fdent.fd_object.needs_close = false; - match nix::unistd::close(fdent.fd_object.rawfd) { - Ok(_) => wasm32::__WASI_ESUCCESS, - Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()), - } - } else { - wasm32::__WASI_EBADF - } - } - - #[no_mangle] - pub unsafe extern "C" fn __wasi_fd_fdstat_get( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - fdstat_ptr: wasm32::uintptr_t, // *mut wasm32::__wasi_fdstat_t - ) -> wasm32::__wasi_errno_t { - let host_fd = dec_fd(fd); - let mut host_fdstat = match unsafe { dec_fdstat_byref(vmctx, fdstat_ptr) } { - Ok(host_fdstat) => host_fdstat, - Err(e) => return enc_errno(e), - }; - - let ctx = vmctx.get_embed_ctx_mut::(); - let errno = if let Some(fe) = ctx.fds.get(&host_fd) { - host_fdstat.fs_filetype = fe.fd_object.ty; - host_fdstat.fs_rights_base = fe.rights_base; - host_fdstat.fs_rights_inheriting = fe.rights_inheriting; - use nix::fcntl::{fcntl, OFlag, F_GETFL}; - match fcntl(fe.fd_object.rawfd, F_GETFL).map(OFlag::from_bits_truncate) { - Ok(flags) => { - host_fdstat.fs_flags = host::fdflags_from_nix(flags); - wasm32::__WASI_ESUCCESS - } - Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()), - } - } else { - wasm32::__WASI_EBADF - }; - - unsafe { - enc_fdstat_byref(vmctx, fdstat_ptr, host_fdstat) - .expect("can write back into the pointer we read from"); - } - - errno - } - - #[no_mangle] - pub unsafe extern "C" fn __wasi_fd_fdstat_set_flags( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - fdflags: wasm32::__wasi_fdflags_t, - ) -> wasm32::__wasi_errno_t { - let host_fd = dec_fd(fd); - let host_fdflags = dec_fdflags(fdflags); - let nix_flags = host::nix_from_fdflags(host_fdflags); - - let ctx = vmctx.get_embed_ctx_mut::(); - - if let Some(fe) = ctx.fds.get(&host_fd) { - match nix::fcntl::fcntl(fe.fd_object.rawfd, nix::fcntl::F_SETFL(nix_flags)) { - Ok(_) => wasm32::__WASI_ESUCCESS, - Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()), - } - } else { - wasm32::__WASI_EBADF - } - } - - #[no_mangle] - pub unsafe extern "C" fn __wasi_fd_seek( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - offset: wasm32::__wasi_filedelta_t, - whence: wasm32::__wasi_whence_t, - newoffset: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - let ctx = vmctx.get_embed_ctx_mut::(); - let fd = dec_fd(fd); - let offset = dec_filedelta(offset); - let whence = dec_whence(whence); - - let host_newoffset = { - use nix::unistd::{lseek, Whence}; - let nwhence = match whence as u32 { - host::__WASI_WHENCE_CUR => Whence::SeekCur, - host::__WASI_WHENCE_END => Whence::SeekEnd, - host::__WASI_WHENCE_SET => Whence::SeekSet, - _ => return wasm32::__WASI_EINVAL, - }; - - let rights = if offset == 0 && whence as u32 == host::__WASI_WHENCE_CUR { - host::__WASI_RIGHT_FD_TELL - } else { - host::__WASI_RIGHT_FD_SEEK | host::__WASI_RIGHT_FD_TELL - }; - match ctx.get_fd_entry(fd, rights.into(), 0) { - Ok(fe) => match lseek(fe.fd_object.rawfd, offset, nwhence) { - Ok(newoffset) => newoffset, - Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), - }, - Err(e) => return enc_errno(e), - } - }; - - unsafe { - enc_filesize_byref(vmctx, newoffset, host_newoffset as u64) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } - } - - #[no_mangle] - pub unsafe extern "C" fn __wasi_fd_prestat_get( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - prestat_ptr: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - let ctx = vmctx.get_embed_ctx::(); - let fd = dec_fd(fd); - // TODO: is this the correct right for this? - match ctx.get_fd_entry(fd, host::__WASI_RIGHT_PATH_OPEN.into(), 0) { - Ok(fe) => { - if let Some(po_path) = &fe.preopen_path { - if fe.fd_object.ty != host::__WASI_FILETYPE_DIRECTORY as host::__wasi_filetype_t { - return wasm32::__WASI_ENOTDIR; - } - unsafe { - enc_prestat_byref( - vmctx, - prestat_ptr, - host::__wasi_prestat_t { - pr_type: host::__WASI_PREOPENTYPE_DIR as host::__wasi_preopentype_t, - u: host::__wasi_prestat_t___wasi_prestat_u { - dir: - host::__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t { - pr_name_len: po_path.as_os_str().as_bytes().len(), - }, - }, - }, - ) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } - } else { - wasm32::__WASI_ENOTSUP - } - } - Err(e) => enc_errno(e), - } - } - - #[no_mangle] - pub unsafe extern "C" fn __wasi_fd_prestat_dir_name( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, - ) -> wasm32::__wasi_errno_t { - let ctx = vmctx.get_embed_ctx::(); - let fd = dec_fd(fd); - match ctx.get_fd_entry(fd, host::__WASI_RIGHT_PATH_OPEN.into(), 0) { - Ok(fe) => { - if let Some(po_path) = &fe.preopen_path { - if fe.fd_object.ty != host::__WASI_FILETYPE_DIRECTORY as host::__wasi_filetype_t { - return wasm32::__WASI_ENOTDIR; - } - let path_bytes = po_path.as_os_str().as_bytes(); - if path_bytes.len() > dec_usize(path_len) { - return wasm32::__WASI_ENAMETOOLONG; - } - unsafe { - enc_slice_of(vmctx, path_bytes, path_ptr) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } - } else { - wasm32::__WASI_ENOTSUP - } - } - Err(e) => enc_errno(e), - } - } - - #[no_mangle] - pub unsafe extern "C" fn __wasi_fd_read( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - iovs_ptr: wasm32::uintptr_t, - iovs_len: wasm32::size_t, - nread: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - use nix::sys::uio::{readv, IoVec}; - - let fd = dec_fd(fd); - let mut iovs = match unsafe { dec_ciovec_slice(vmctx, iovs_ptr, iovs_len) } { - Ok(iovs) => iovs, - Err(e) => return enc_errno(e), - }; - - let mut ctx = vmctx.get_embed_ctx_mut::(); - let fe = match ctx.get_fd_entry(fd, host::__WASI_RIGHT_FD_READ.into(), 0) { - Ok(fe) => fe, - Err(e) => return enc_errno(e), - }; - - let mut iovs: Vec> = iovs - .iter_mut() - .map(|iov| unsafe { host::ciovec_to_nix_mut(iov) }) - .collect(); - - let host_nread = match readv(fe.fd_object.rawfd, &mut iovs) { - Ok(len) => len, - Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), - }; - - if host_nread == 0 { - // we hit eof, so remove the fdentry from the context - let mut fe = ctx.fds.remove(&fd).expect("file entry is still there"); - fe.fd_object.needs_close = false; - } - - unsafe { - enc_usize_byref(vmctx, nread, host_nread) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } - } - - #[no_mangle] - pub unsafe extern "C" fn __wasi_fd_write( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - iovs_ptr: wasm32::uintptr_t, - iovs_len: wasm32::size_t, - nwritten: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - use nix::sys::uio::{writev, IoVec}; - - let fd = dec_fd(fd); - let iovs = match unsafe { dec_ciovec_slice(vmctx, iovs_ptr, iovs_len) } { - Ok(iovs) => iovs, - Err(e) => return enc_errno(e), - }; - - let ctx = vmctx.get_embed_ctx::(); - let fe = match ctx.get_fd_entry(fd, host::__WASI_RIGHT_FD_WRITE.into(), 0) { - Ok(fe) => fe, - Err(e) => return enc_errno(e), - }; - - let iovs: Vec> = iovs - .iter() - .map(|iov| unsafe { host::ciovec_to_nix(iov) }) - .collect(); - - let host_nwritten = match writev(fe.fd_object.rawfd, &iovs) { - Ok(len) => len, - Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), - }; - - unsafe { - enc_usize_byref(vmctx, nwritten, host_nwritten) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } - } - - #[no_mangle] - pub unsafe extern "C" fn __wasi_path_open( - &mut vmctx, - dirfd: wasm32::__wasi_fd_t, - dirflags: wasm32::__wasi_lookupflags_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, - oflags: wasm32::__wasi_oflags_t, - fs_rights_base: wasm32::__wasi_rights_t, - fs_rights_inheriting: wasm32::__wasi_rights_t, - fs_flags: wasm32::__wasi_fdflags_t, - fd_out_ptr: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - use nix::errno::Errno; - use nix::fcntl::{openat, AtFlags, OFlag}; - use nix::sys::stat::{fstatat, Mode, SFlag}; - - let dirfd = dec_fd(dirfd); - let dirflags = dec_lookupflags(dirflags); - let oflags = dec_oflags(oflags); - let fs_rights_base = dec_rights(fs_rights_base); - let fs_rights_inheriting = dec_rights(fs_rights_inheriting); - let fs_flags = dec_fdflags(fs_flags); - - // which open mode do we need? - let read = fs_rights_base - & ((host::__WASI_RIGHT_FD_READ | host::__WASI_RIGHT_FD_READDIR) as host::__wasi_rights_t) - != 0; - let write = fs_rights_base - & ((host::__WASI_RIGHT_FD_DATASYNC - | host::__WASI_RIGHT_FD_WRITE - | host::__WASI_RIGHT_FD_ALLOCATE - | host::__WASI_RIGHT_PATH_FILESTAT_SET_SIZE) as host::__wasi_rights_t) - != 0; - - let mut nix_all_oflags = if read && write { - OFlag::O_RDWR - } else if read { - OFlag::O_RDONLY - } else { - OFlag::O_WRONLY - }; - - // on non-Capsicum systems, we always want nofollow - nix_all_oflags.insert(OFlag::O_NOFOLLOW); - - // which rights are needed on the dirfd? - let mut needed_base = host::__WASI_RIGHT_PATH_OPEN as host::__wasi_rights_t; - let mut needed_inheriting = fs_rights_base | fs_rights_inheriting; - - // convert open flags - let nix_oflags = host::nix_from_oflags(oflags); - nix_all_oflags.insert(nix_oflags); - if nix_all_oflags.contains(OFlag::O_CREAT) { - needed_base |= host::__WASI_RIGHT_PATH_CREATE_FILE as host::__wasi_rights_t; - } - if nix_all_oflags.contains(OFlag::O_TRUNC) { - needed_inheriting |= host::__WASI_RIGHT_PATH_FILESTAT_SET_SIZE as host::__wasi_rights_t; - } - - // convert file descriptor flags - nix_all_oflags.insert(host::nix_from_fdflags(fs_flags)); - if nix_all_oflags.contains(OFlag::O_DSYNC) { - needed_inheriting |= host::__WASI_RIGHT_FD_DATASYNC as host::__wasi_rights_t; - } - if nix_all_oflags.intersects(O_RSYNC | OFlag::O_SYNC) { - needed_inheriting |= host::__WASI_RIGHT_FD_SYNC as host::__wasi_rights_t; - } - - let path = match unsafe { dec_slice_of::(vmctx, path_ptr, path_len) } { - Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), - Err(e) => return enc_errno(e), - }; - - let (dir, path) = match path_get( - &vmctx, - dirfd, - dirflags, - path, - needed_base, - needed_inheriting, - nix_oflags.contains(OFlag::O_CREAT), - ) { - Ok((dir, path)) => (dir, path), - Err(e) => return enc_errno(e), - }; - - let new_fd = match openat( - dir, - path.as_os_str(), - nix_all_oflags, - Mode::from_bits_truncate(0o777), - ) { - Ok(fd) => fd, - Err(e) => { - match e.as_errno() { - // Linux returns ENXIO instead of EOPNOTSUPP when opening a socket - Some(Errno::ENXIO) => { - if let Ok(stat) = fstatat(dir, path.as_os_str(), AtFlags::AT_SYMLINK_NOFOLLOW) { - if SFlag::from_bits_truncate(stat.st_mode).contains(SFlag::S_IFSOCK) { - return wasm32::__WASI_ENOTSUP; - } else { - return wasm32::__WASI_ENXIO; - } - } else { - return wasm32::__WASI_ENXIO; - } - } - Some(e) => return wasm32::errno_from_nix(e), - None => return wasm32::__WASI_ENOSYS, - } - } - }; - - // Determine the type of the new file descriptor and which rights contradict with this type - let guest_fd = match unsafe { determine_type_rights(new_fd) } { - Err(e) => { - // if `close` fails, note it but do not override the underlying errno - nix::unistd::close(new_fd).unwrap_or_else(|e| { - dbg!(e); - }); - return enc_errno(e); - } - Ok((_ty, max_base, max_inheriting)) => { - let mut fe = unsafe { FdEntry::from_raw_fd(new_fd) }; - fe.rights_base &= max_base; - fe.rights_inheriting &= max_inheriting; - match vmctx.get_embed_ctx_mut::().insert_fd_entry(fe) { - Ok(fd) => fd, - Err(e) => return enc_errno(e), - } - } - }; - - unsafe { - enc_fd_byref(vmctx, fd_out_ptr, guest_fd) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } - } - - #[no_mangle] - pub unsafe extern "C" fn __wasi_random_get( - &mut vmctx, - buf_ptr: wasm32::uintptr_t, - buf_len: wasm32::size_t, - ) -> wasm32::__wasi_errno_t { - use rand::{thread_rng, RngCore}; - - let buf_len = dec_usize(buf_len); - let buf_ptr = match unsafe { dec_ptr(vmctx, buf_ptr, buf_len) } { - Ok(ptr) => ptr, - Err(e) => return enc_errno(e), - }; - - let buf = unsafe { std::slice::from_raw_parts_mut(buf_ptr, buf_len) }; - - thread_rng().fill_bytes(buf); - - return wasm32::__WASI_ESUCCESS; - } - - #[no_mangle] - pub unsafe extern "C" fn __wasi_poll_oneoff( - &mut vmctx, - input: wasm32::uintptr_t, - output: wasm32::uintptr_t, - nsubscriptions: wasm32::size_t, - nevents: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - if nsubscriptions as u64 > wasm32::__wasi_filesize_t::max_value() { - return wasm32::__WASI_EINVAL; - } - unsafe { enc_pointee(vmctx, nevents, 0) }.unwrap(); - let input_slice_ = - unsafe { dec_slice_of::(vmctx, input, nsubscriptions) } - .unwrap(); - let input_slice = unsafe { slice::from_raw_parts(input_slice_.0, input_slice_.1) }; - - let output_slice_ = - unsafe { dec_slice_of::(vmctx, output, nsubscriptions) } - .unwrap(); - let output_slice = unsafe { slice::from_raw_parts_mut(output_slice_.0, output_slice_.1) }; - - let input: Vec<_> = input_slice.iter().map(|x| dec_subscription(x)).collect(); - - let timeout = input - .iter() - .filter_map(|event| match event { - Ok(event) if event.type_ == wasm32::__WASI_EVENTTYPE_CLOCK => Some(ClockEventData { - delay: wasi_clock_to_relative_ns_delay(unsafe { event.u.clock }) / 1_000_000, - userdata: event.userdata, - }), - _ => None, - }) - .min_by_key(|event| event.delay); - let fd_events: Vec<_> = input - .iter() - .filter_map(|event| match event { - Ok(event) - if event.type_ == wasm32::__WASI_EVENTTYPE_FD_READ - || event.type_ == wasm32::__WASI_EVENTTYPE_FD_WRITE => - { - Some(FdEventData { - fd: unsafe { event.u.fd_readwrite.fd } as c_int, - type_: event.type_, - userdata: event.userdata, - }) - } - _ => None, - }) - .collect(); - if fd_events.is_empty() && timeout.is_none() { - return wasm32::__WASI_ESUCCESS; - } - let mut poll_fds: Vec<_> = fd_events - .iter() - .map(|event| { - let mut flags = nix::poll::EventFlags::empty(); - match event.type_ { - wasm32::__WASI_EVENTTYPE_FD_READ => flags.insert(nix::poll::EventFlags::POLLIN), - wasm32::__WASI_EVENTTYPE_FD_WRITE => flags.insert(nix::poll::EventFlags::POLLOUT), - // An event on a file descriptor can currently only be of type FD_READ or FD_WRITE - // Nothing else has been defined in the specification, and these are also the only two - // events we filtered before. If we get something else here, the code has a serious bug. - _ => unreachable!(), - }; - nix::poll::PollFd::new(event.fd, flags) - }) - .collect(); - let timeout = timeout.map(|ClockEventData { delay, userdata }| ClockEventData { - delay: cmp::min(delay, c_int::max_value() as u128), - userdata, - }); - let poll_timeout = timeout.map(|timeout| timeout.delay as c_int).unwrap_or(-1); - let ready = loop { - match nix::poll::poll(&mut poll_fds, poll_timeout) { - Err(_) => { - if nix::errno::Errno::last() == nix::errno::Errno::EINTR { - continue; - } - return wasm32::errno_from_nix(nix::errno::Errno::last()); - } - Ok(ready) => break ready as usize, - } - }; - if ready == 0 { - return __wasi_poll_oneoff_handle_timeout_event(vmctx, output_slice, nevents, timeout); - } - let events = fd_events.iter().zip(poll_fds.iter()).take(ready); - __wasi_poll_oneoff_handle_fd_event(vmctx, output_slice, nevents, events) - } - - #[no_mangle] - pub unsafe extern "C" fn __wasi_fd_filestat_get( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - filestat_ptr: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - use nix::sys::stat::fstat; - - let host_fd = dec_fd(fd); - let ctx = vmctx.get_embed_ctx_mut::(); - - let errno = if let Some(fe) = ctx.fds.get(&host_fd) { - match fstat(fe.fd_object.rawfd) { - Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()), - Ok(filestat) => { - let host_filestat = host::filestat_from_nix(filestat); - unsafe { - enc_filestat_byref(vmctx, filestat_ptr, host_filestat) - .expect("can write into the pointer"); - } - wasm32::__WASI_ESUCCESS - } - } - } else { - wasm32::__WASI_EBADF - }; - errno - } - - #[no_mangle] - pub unsafe extern "C" fn __wasi_path_filestat_get( - &mut vmctx, - dirfd: wasm32::__wasi_fd_t, - dirflags: wasm32::__wasi_lookupflags_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, - filestat_ptr: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - use nix::fcntl::AtFlags; - use nix::sys::stat::fstatat; - - let dirfd = dec_fd(dirfd); - let dirflags = dec_lookupflags(dirflags); - let path = match unsafe { dec_slice_of::(vmctx, path_ptr, path_len) } { - Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), - Err(e) => return enc_errno(e), - }; - let (dir, path) = match path_get( - &vmctx, - dirfd, - dirflags, - path, - host::__WASI_RIGHT_PATH_FILESTAT_GET as host::__wasi_rights_t, - 0, - false, - ) { - Ok((dir, path)) => (dir, path), - Err(e) => return enc_errno(e), - }; - let atflags = match dirflags { - 0 => AtFlags::empty(), - _ => AtFlags::AT_SYMLINK_NOFOLLOW, - }; - match fstatat(dir, path.as_os_str(), atflags) { - Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()), - Ok(filestat) => { - let host_filestat = host::filestat_from_nix(filestat); - unsafe { - enc_filestat_byref(vmctx, filestat_ptr, host_filestat) - .expect("can write into the pointer"); - } - wasm32::__WASI_ESUCCESS - } - } - } - - #[no_mangle] - pub unsafe extern "C" fn __wasi_path_create_directory( - &mut vmctx, - dirfd: wasm32::__wasi_fd_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, - ) -> wasm32::__wasi_errno_t { - use nix::errno; - use nix::libc::mkdirat; - - let dirfd = dec_fd(dirfd); - let path = match unsafe { dec_slice_of::(vmctx, path_ptr, path_len) } { - Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), - Err(e) => return enc_errno(e), - }; - let (dir, path) = match path_get( - &vmctx, - dirfd, - 0, - path, - (host::__WASI_RIGHT_PATH_OPEN | host::__WASI_RIGHT_PATH_CREATE_DIRECTORY) - as host::__wasi_rights_t, - 0, - false, - ) { - Ok((dir, path)) => (dir, path), - Err(e) => return enc_errno(e), - }; - let path_cstr = match std::ffi::CString::new(path.as_os_str().as_bytes()) { - Ok(path_cstr) => path_cstr, - Err(_) => return wasm32::__WASI_EINVAL, - }; - // nix doesn't expose mkdirat() yet - match unsafe { mkdirat(dir, path_cstr.as_ptr(), 0o777) } { - 0 => wasm32::__WASI_ESUCCESS, - _ => wasm32::errno_from_nix(errno::Errno::last()), - } - } - - #[no_mangle] - pub unsafe extern "C" fn __wasi_path_unlink_file( - &mut vmctx, - dirfd: wasm32::__wasi_fd_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, - ) -> wasm32::__wasi_errno_t { - use nix::errno; - use nix::libc::unlinkat; - - let dirfd = dec_fd(dirfd); - let path = match unsafe { dec_slice_of::(vmctx, path_ptr, path_len) } { - Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), - Err(e) => return enc_errno(e), - }; - let (dir, path) = match path_get( - &vmctx, - dirfd, - 0, - path, - host::__WASI_RIGHT_PATH_UNLINK_FILE as host::__wasi_rights_t, - 0, - false, - ) { - Ok((dir, path)) => (dir, path), - Err(e) => return enc_errno(e), - }; - let path_cstr = match std::ffi::CString::new(path.as_os_str().as_bytes()) { - Ok(path_cstr) => path_cstr, - Err(_) => return wasm32::__WASI_EINVAL, - }; - // nix doesn't expose unlinkat() yet - match unsafe { unlinkat(dir, path_cstr.as_ptr(), 0) } { - 0 => wasm32::__WASI_ESUCCESS, - _ => wasm32::errno_from_nix(errno::Errno::last()), - } - } -} - -// define the `fionread()` function, equivalent to `ioctl(fd, FIONREAD, *bytes)` -nix::ioctl_read_bad!(fionread, nix::libc::FIONREAD, c_int); - -fn wasi_clock_to_relative_ns_delay( - wasi_clock: host::__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, -) -> u128 { - if wasi_clock.flags != wasm32::__WASI_SUBSCRIPTION_CLOCK_ABSTIME { - return wasi_clock.timeout as u128; - } - let now: u128 = SystemTime::now() - .duration_since(SystemTime::UNIX_EPOCH) - .expect("Current date is before the epoch") - .as_nanos(); - let deadline = wasi_clock.timeout as u128; - deadline.saturating_sub(now) -} - -#[derive(Debug, Copy, Clone)] -struct ClockEventData { - delay: u128, - userdata: host::__wasi_userdata_t, -} -#[derive(Debug, Copy, Clone)] -struct FdEventData { - fd: c_int, - type_: host::__wasi_eventtype_t, - userdata: host::__wasi_userdata_t, -} - -fn __wasi_poll_oneoff_handle_timeout_event( - vmctx: &mut Vmctx, - output_slice: &mut [wasm32::__wasi_event_t], - nevents: wasm32::uintptr_t, - timeout: Option, -) -> wasm32::__wasi_errno_t { - if let Some(ClockEventData { userdata, .. }) = timeout { - let output_event = host::__wasi_event_t { - userdata, - type_: wasm32::__WASI_EVENTTYPE_CLOCK, - error: wasm32::__WASI_ESUCCESS, - u: host::__wasi_event_t___wasi_event_u { - fd_readwrite: host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { - nbytes: 0, - flags: 0, - }, - }, - }; - output_slice[0] = enc_event(output_event); - if let Err(e) = unsafe { enc_pointee(vmctx, nevents, 1) } { - return enc_errno(e); - } - } else { - // shouldn't happen - if let Err(e) = unsafe { enc_pointee(vmctx, nevents, 0) } { - return enc_errno(e); - } - } - wasm32::__WASI_ESUCCESS -} - -fn __wasi_poll_oneoff_handle_fd_event<'t>( - vmctx: &mut Vmctx, - output_slice: &mut [wasm32::__wasi_event_t], - nevents: wasm32::uintptr_t, - events: impl Iterator, -) -> wasm32::__wasi_errno_t { - let mut output_slice_cur = output_slice.iter_mut(); - let mut revents_count = 0; - for (fd_event, poll_fd) in events { - let revents = match poll_fd.revents() { - Some(revents) => revents, - None => continue, - }; - let mut nbytes = 0; - if fd_event.type_ == wasm32::__WASI_EVENTTYPE_FD_READ { - let _ = unsafe { fionread(fd_event.fd, &mut nbytes) }; - } - let output_event = if revents.contains(nix::poll::EventFlags::POLLNVAL) { - host::__wasi_event_t { - userdata: fd_event.userdata, - type_: fd_event.type_, - error: wasm32::__WASI_EBADF, - u: host::__wasi_event_t___wasi_event_u { - fd_readwrite: - host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { - nbytes: 0, - flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP, - }, - }, - } - } else if revents.contains(nix::poll::EventFlags::POLLERR) { - host::__wasi_event_t { - userdata: fd_event.userdata, - type_: fd_event.type_, - error: wasm32::__WASI_EIO, - u: host::__wasi_event_t___wasi_event_u { - fd_readwrite: - host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { - nbytes: 0, - flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP, - }, - }, - } - } else if revents.contains(nix::poll::EventFlags::POLLHUP) { - host::__wasi_event_t { - userdata: fd_event.userdata, - type_: fd_event.type_, - error: wasm32::__WASI_ESUCCESS, - u: host::__wasi_event_t___wasi_event_u { - fd_readwrite: - host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { - nbytes: 0, - flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP, - }, - }, - } - } else if revents.contains(nix::poll::EventFlags::POLLIN) - | revents.contains(nix::poll::EventFlags::POLLOUT) - { - host::__wasi_event_t { - userdata: fd_event.userdata, - type_: fd_event.type_, - error: wasm32::__WASI_ESUCCESS, - u: host::__wasi_event_t___wasi_event_u { - fd_readwrite: - host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { - nbytes: nbytes as host::__wasi_filesize_t, - flags: 0, - }, - }, - } - } else { - continue; - }; - *output_slice_cur.next().unwrap() = enc_event(output_event); - revents_count += 1; - } - if let Err(e) = unsafe { enc_pointee(vmctx, nevents, revents_count) } { - return enc_errno(e); - } - wasm32::__WASI_ESUCCESS -} - -/// Normalizes a path to ensure that the target path is located under the directory provided. -/// -/// This is a workaround for not having Capsicum support in the OS. -pub fn path_get>( - vmctx: &Vmctx, - dirfd: host::__wasi_fd_t, - dirflags: host::__wasi_lookupflags_t, - path: P, - needed_base: host::__wasi_rights_t, - needed_inheriting: host::__wasi_rights_t, - needs_final_component: bool, -) -> Result<(RawFd, OsString), host::__wasi_errno_t> { - use nix::errno::Errno; - use nix::fcntl::{openat, readlinkat, OFlag}; - use nix::sys::stat::Mode; - - const MAX_SYMLINK_EXPANSIONS: usize = 128; - - /// close all the intermediate file descriptors, but make sure not to drop either the original - /// dirfd or the one we return (which may be the same dirfd) - fn ret_dir_success(dir_stack: &mut Vec) -> RawFd { - let ret_dir = dir_stack.pop().expect("there is always a dirfd to return"); - if let Some(dirfds) = dir_stack.get(1..) { - for dirfd in dirfds { - nix::unistd::close(*dirfd).unwrap_or_else(|e| { - dbg!(e); - }); - } - } - ret_dir - } - - /// close all file descriptors other than the base directory, and return the errno for - /// convenience with `return` - fn ret_error( - dir_stack: &mut Vec, - errno: host::__wasi_errno_t, - ) -> Result<(RawFd, OsString), host::__wasi_errno_t> { - if let Some(dirfds) = dir_stack.get(1..) { - for dirfd in dirfds { - nix::unistd::close(*dirfd).unwrap_or_else(|e| { - dbg!(e); - }); - } - } - Err(errno) - } - - let ctx = vmctx.get_embed_ctx::(); - - let dirfe = ctx.get_fd_entry(dirfd, needed_base, needed_inheriting)?; - - // Stack of directory file descriptors. Index 0 always corresponds with the directory provided - // to this function. Entering a directory causes a file descriptor to be pushed, while handling - // ".." entries causes an entry to be popped. Index 0 cannot be popped, as this would imply - // escaping the base directory. - let mut dir_stack = vec![dirfe.fd_object.rawfd]; - - // Stack of paths left to process. This is initially the `path` argument to this function, but - // any symlinks we encounter are processed by pushing them on the stack. - let mut path_stack = vec![path.as_ref().to_owned().into_vec()]; - - // Track the number of symlinks we've expanded, so we can return `ELOOP` after too many. - let mut symlink_expansions = 0; - - // Buffer to read links into; defined outside of the loop so we don't reallocate it constantly. - let mut readlink_buf = vec![0u8; libc::PATH_MAX as usize + 1]; - - // TODO: rewrite this using a custom posix path type, with a component iterator that respects - // trailing slashes. This version does way too much allocation, and is way too fiddly. - loop { - let component = if let Some(cur_path) = path_stack.pop() { - // eprintln!( - // "cur_path = {:?}", - // std::str::from_utf8(cur_path.as_slice()).unwrap() - // ); - let mut split = cur_path.splitn(2, |&c| c == '/' as u8); - let head = split.next(); - let tail = split.next(); - match (head, tail) { - (None, _) => { - // split always returns at least a singleton iterator with an empty slice - panic!("unreachable"); - } - // path is empty - (Some([]), None) => { - return ret_error(&mut dir_stack, host::__WASI_ENOENT as host::__wasi_errno_t); - } - // path starts with `/`, is absolute - (Some([]), Some(_)) => { - return ret_error( - &mut dir_stack, - host::__WASI_ENOTCAPABLE as host::__wasi_errno_t, - ); - } - // the final component of the path with no trailing slash - (Some(component), None) => component.to_vec(), - (Some(component), Some(rest)) => { - if rest.iter().all(|&c| c == '/' as u8) { - // the final component of the path with trailing slashes; put one trailing - // slash back on - let mut component = component.to_vec(); - component.push('/' as u8); - component - } else { - // non-final component; push the rest back on the stack - path_stack.push(rest.to_vec()); - component.to_vec() - } - } - } - } else { - // if the path stack is ever empty, we return rather than going through the loop again - panic!("unreachable"); - }; - - // eprintln!( - // "component = {:?}", - // std::str::from_utf8(component.as_slice()).unwrap() - // ); - - match component.as_slice() { - b"." => { - // skip component - } - b".." => { - // pop a directory - let dirfd = dir_stack.pop().expect("dir_stack is never empty"); - - // we're not allowed to pop past the original directory - if dir_stack.is_empty() { - return ret_error( - &mut dir_stack, - host::__WASI_ENOTCAPABLE as host::__wasi_errno_t, - ); - } else { - nix::unistd::close(dirfd).unwrap_or_else(|e| { - dbg!(e); - }); - } - } - // should the component be a directory? it should if there is more path left to process, or - // if it has a trailing slash and `needs_final_component` is not set - component - if !path_stack.is_empty() - || (component.ends_with(b"/") && !needs_final_component) => - { - match openat( - *dir_stack.first().expect("dir_stack is never empty"), - component, - OFlag::O_RDONLY | OFlag::O_DIRECTORY | OFlag::O_NOFOLLOW, - Mode::empty(), - ) { - Ok(new_dir) => { - dir_stack.push(new_dir); - continue; - } - Err(e) - if e.as_errno() == Some(Errno::ELOOP) - || e.as_errno() == Some(Errno::EMLINK) => - { - // attempt symlink expansion - match readlinkat( - *dir_stack.last().expect("dir_stack is never empty"), - component, - readlink_buf.as_mut_slice(), - ) { - Ok(link_path) => { - symlink_expansions += 1; - if symlink_expansions > MAX_SYMLINK_EXPANSIONS { - return ret_error( - &mut dir_stack, - host::__WASI_ELOOP as host::__wasi_errno_t, - ); - } - - let mut link_path = link_path.as_bytes().to_vec(); - - // append a trailing slash if the component leading to it has one, so - // that we preserve any ENOTDIR that might come from trying to open a - // non-directory - if component.ends_with(b"/") { - link_path.push('/' as u8); - } - - path_stack.push(link_path); - continue; - } - Err(e) => { - return ret_error( - &mut dir_stack, - host::errno_from_nix(e.as_errno().unwrap()), - ); - } - } - } - Err(e) => { - return ret_error( - &mut dir_stack, - host::errno_from_nix(e.as_errno().unwrap()), - ); - } - } - } - // the final component - component => { - // if there's a trailing slash, or if `LOOKUP_SYMLINK_FOLLOW` is set, attempt - // symlink expansion - if component.ends_with(b"/") || (dirflags & host::__WASI_LOOKUP_SYMLINK_FOLLOW) != 0 - { - match readlinkat( - *dir_stack.last().expect("dir_stack is never empty"), - component, - readlink_buf.as_mut_slice(), - ) { - Ok(link_path) => { - symlink_expansions += 1; - if symlink_expansions > MAX_SYMLINK_EXPANSIONS { - return ret_error( - &mut dir_stack, - host::__WASI_ELOOP as host::__wasi_errno_t, - ); - } - - let mut link_path = link_path.as_bytes().to_vec(); - - // append a trailing slash if the component leading to it has one, so - // that we preserve any ENOTDIR that might come from trying to open a - // non-directory - if component.ends_with(b"/") { - link_path.push('/' as u8); - } - - path_stack.push(link_path); - continue; - } - Err(e) => { - let errno = e.as_errno().unwrap(); - if errno != Errno::EINVAL && errno != Errno::ENOENT { - // only return an error if this path is not actually a symlink - return ret_error(&mut dir_stack, host::errno_from_nix(errno)); - } - } - } - } - - // not a symlink, so we're done; - return Ok(( - ret_dir_success(&mut dir_stack), - OsStr::from_bytes(component).to_os_string(), - )); - } - } - - if path_stack.is_empty() { - // no further components to process. means we've hit a case like "." or "a/..", or if the - // input path has trailing slashes and `needs_final_component` is not set - return Ok(( - ret_dir_success(&mut dir_stack), - OsStr::new(".").to_os_string(), - )); - } else { - continue; - } - } -} - -#[doc(hidden)] -pub fn ensure_linked() { - unsafe { - std::ptr::read_volatile(__wasi_proc_exit as *const extern "C" fn()); - } -} diff --git a/lucet-wasi/src/hostcalls/fs.rs b/lucet-wasi/src/hostcalls/fs.rs new file mode 100644 index 000000000..65b60fd90 --- /dev/null +++ b/lucet-wasi/src/hostcalls/fs.rs @@ -0,0 +1,1338 @@ +#![allow(non_camel_case_types)] +#![allow(unused_unsafe)] + +use crate::ctx::WasiCtx; +use crate::fdentry::{determine_type_rights, FdEntry}; +use crate::memory::*; +use crate::{host, wasm32}; + +use super::fs_helpers::*; +use lucet_runtime::vmctx::Vmctx; + +use nix::libc::{self, c_long, c_void, off_t}; +use std::ffi::OsStr; +use std::os::unix::prelude::{FromRawFd, OsStrExt}; + +pub fn wasi_fd_close(vmctx: &mut Vmctx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t { + let mut ctx = vmctx.get_embed_ctx_mut::(); + let fd = dec_fd(fd); + if let Some(fdent) = ctx.fds.get(&fd) { + // can't close preopened files + if fdent.preopen_path.is_some() { + return wasm32::__WASI_ENOTSUP; + } + } + if let Some(mut fdent) = ctx.fds.remove(&fd) { + fdent.fd_object.needs_close = false; + match nix::unistd::close(fdent.fd_object.rawfd) { + Ok(_) => wasm32::__WASI_ESUCCESS, + Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()), + } + } else { + wasm32::__WASI_EBADF + } +} + +pub fn wasi_fd_fdstat_get( + vmctx: &mut Vmctx, + fd: wasm32::__wasi_fd_t, + fdstat_ptr: wasm32::uintptr_t, // *mut wasm32::__wasi_fdstat_t +) -> wasm32::__wasi_errno_t { + let host_fd = dec_fd(fd); + let mut host_fdstat = match unsafe { dec_fdstat_byref(vmctx, fdstat_ptr) } { + Ok(host_fdstat) => host_fdstat, + Err(e) => return enc_errno(e), + }; + + let ctx = vmctx.get_embed_ctx_mut::(); + let errno = if let Some(fe) = ctx.fds.get(&host_fd) { + host_fdstat.fs_filetype = fe.fd_object.ty; + host_fdstat.fs_rights_base = fe.rights_base; + host_fdstat.fs_rights_inheriting = fe.rights_inheriting; + use nix::fcntl::{fcntl, OFlag, F_GETFL}; + match fcntl(fe.fd_object.rawfd, F_GETFL).map(OFlag::from_bits_truncate) { + Ok(flags) => { + host_fdstat.fs_flags = host::fdflags_from_nix(flags); + wasm32::__WASI_ESUCCESS + } + Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()), + } + } else { + wasm32::__WASI_EBADF + }; + + unsafe { + enc_fdstat_byref(vmctx, fdstat_ptr, host_fdstat) + .expect("can write back into the pointer we read from"); + } + + errno +} + +pub fn wasi_fd_fdstat_set_flags( + vmctx: &mut Vmctx, + fd: wasm32::__wasi_fd_t, + fdflags: wasm32::__wasi_fdflags_t, +) -> wasm32::__wasi_errno_t { + let host_fd = dec_fd(fd); + let host_fdflags = dec_fdflags(fdflags); + let nix_flags = host::nix_from_fdflags(host_fdflags); + + let ctx = vmctx.get_embed_ctx_mut::(); + + if let Some(fe) = ctx.fds.get(&host_fd) { + match nix::fcntl::fcntl(fe.fd_object.rawfd, nix::fcntl::F_SETFL(nix_flags)) { + Ok(_) => wasm32::__WASI_ESUCCESS, + Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()), + } + } else { + wasm32::__WASI_EBADF + } +} + +pub fn wasi_fd_tell( + vmctx: &mut Vmctx, + fd: wasm32::__wasi_fd_t, + offset: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let ctx = vmctx.get_embed_ctx_mut::(); + let fd = dec_fd(fd); + + let host_offset = { + use nix::unistd::{lseek, Whence}; + + let rights = host::__WASI_RIGHT_FD_TELL; + match ctx.get_fd_entry(fd, rights.into(), 0) { + Ok(fe) => match lseek(fe.fd_object.rawfd, 0, Whence::SeekCur) { + Ok(newoffset) => newoffset, + Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), + }, + Err(e) => return enc_errno(e), + } + }; + + unsafe { + enc_filesize_byref(vmctx, offset, host_offset as u64) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) + } +} + +pub fn wasi_fd_seek( + vmctx: &mut Vmctx, + fd: wasm32::__wasi_fd_t, + offset: wasm32::__wasi_filedelta_t, + whence: wasm32::__wasi_whence_t, + newoffset: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let ctx = vmctx.get_embed_ctx_mut::(); + let fd = dec_fd(fd); + let offset = dec_filedelta(offset); + let whence = dec_whence(whence); + + let host_newoffset = { + use nix::unistd::{lseek, Whence}; + let nwhence = match u32::from(whence) { + host::__WASI_WHENCE_CUR => Whence::SeekCur, + host::__WASI_WHENCE_END => Whence::SeekEnd, + host::__WASI_WHENCE_SET => Whence::SeekSet, + _ => return wasm32::__WASI_EINVAL, + }; + + let rights = if offset == 0 && whence as u32 == host::__WASI_WHENCE_CUR { + host::__WASI_RIGHT_FD_TELL + } else { + host::__WASI_RIGHT_FD_SEEK | host::__WASI_RIGHT_FD_TELL + }; + match ctx.get_fd_entry(fd, rights.into(), 0) { + Ok(fe) => match lseek(fe.fd_object.rawfd, offset, nwhence) { + Ok(newoffset) => newoffset, + Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), + }, + Err(e) => return enc_errno(e), + } + }; + + unsafe { + enc_filesize_byref(vmctx, newoffset, host_newoffset as u64) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) + } +} + +pub fn wasi_fd_prestat_get( + vmctx: &mut Vmctx, + fd: wasm32::__wasi_fd_t, + prestat_ptr: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let ctx = vmctx.get_embed_ctx::(); + let fd = dec_fd(fd); + + let rights = host::__WASI_RIGHT_PATH_OPEN; + match ctx.get_fd_entry(fd, rights.into(), 0) { + Ok(fe) => { + if let Some(po_path) = &fe.preopen_path { + if fe.fd_object.ty != host::__WASI_FILETYPE_DIRECTORY as host::__wasi_filetype_t { + return wasm32::__WASI_ENOTDIR; + } + unsafe { + enc_prestat_byref( + vmctx, + prestat_ptr, + host::__wasi_prestat_t { + pr_type: host::__WASI_PREOPENTYPE_DIR as host::__wasi_preopentype_t, + u: host::__wasi_prestat_t___wasi_prestat_u { + dir: + host::__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t { + pr_name_len: po_path.as_os_str().as_bytes().len(), + }, + }, + }, + ) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) + } + } else { + wasm32::__WASI_ENOTSUP + } + } + Err(e) => enc_errno(e), + } +} + +pub fn wasi_fd_prestat_dir_name( + vmctx: &mut Vmctx, + fd: wasm32::__wasi_fd_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, +) -> wasm32::__wasi_errno_t { + let ctx = vmctx.get_embed_ctx::(); + let fd = dec_fd(fd); + let rights = host::__WASI_RIGHT_PATH_OPEN; + match ctx.get_fd_entry(fd, rights.into(), 0) { + Ok(fe) => { + if let Some(po_path) = &fe.preopen_path { + if fe.fd_object.ty != host::__WASI_FILETYPE_DIRECTORY as host::__wasi_filetype_t { + return wasm32::__WASI_ENOTDIR; + } + let path_bytes = po_path.as_os_str().as_bytes(); + if path_bytes.len() > dec_usize(path_len) { + return wasm32::__WASI_ENAMETOOLONG; + } + unsafe { + enc_slice_of(vmctx, path_bytes, path_ptr) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) + } + } else { + wasm32::__WASI_ENOTSUP + } + } + Err(e) => enc_errno(e), + } +} + +pub fn wasi_fd_read( + vmctx: &mut Vmctx, + fd: wasm32::__wasi_fd_t, + iovs_ptr: wasm32::uintptr_t, + iovs_len: wasm32::size_t, + nread: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + use nix::sys::uio::{readv, IoVec}; + + let fd = dec_fd(fd); + let mut iovs = match unsafe { dec_iovec_slice(vmctx, iovs_ptr, iovs_len) } { + Ok(iovs) => iovs, + Err(e) => return enc_errno(e), + }; + + let mut ctx = vmctx.get_embed_ctx_mut::(); + let rights = host::__WASI_RIGHT_FD_READ; + let fe = match ctx.get_fd_entry(fd, rights.into(), 0) { + Ok(fe) => fe, + Err(e) => return enc_errno(e), + }; + + let mut iovs: Vec> = iovs + .iter_mut() + .map(|iov| unsafe { host::iovec_to_nix_mut(iov) }) + .collect(); + + let host_nread = match readv(fe.fd_object.rawfd, &mut iovs) { + Ok(len) => len, + Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), + }; + + if host_nread == 0 { + // we hit eof, so remove the fdentry from the context + let mut fe = ctx.fds.remove(&fd).expect("file entry is still there"); + fe.fd_object.needs_close = false; + } + + unsafe { + enc_usize_byref(vmctx, nread, host_nread) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) + } +} + +pub fn wasi_fd_write( + vmctx: &mut Vmctx, + fd: wasm32::__wasi_fd_t, + iovs_ptr: wasm32::uintptr_t, + iovs_len: wasm32::size_t, + nwritten: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + use nix::sys::uio::{writev, IoVec}; + + let fd = dec_fd(fd); + let iovs = match unsafe { dec_ciovec_slice(vmctx, iovs_ptr, iovs_len) } { + Ok(iovs) => iovs, + Err(e) => return enc_errno(e), + }; + + let ctx = vmctx.get_embed_ctx::(); + let rights = host::__WASI_RIGHT_FD_WRITE; + let fe = match ctx.get_fd_entry(fd, rights.into(), 0) { + Ok(fe) => fe, + Err(e) => return enc_errno(e), + }; + + let iovs: Vec> = iovs + .iter() + .map(|iov| unsafe { host::ciovec_to_nix(iov) }) + .collect(); + + let host_nwritten = match writev(fe.fd_object.rawfd, &iovs) { + Ok(len) => len, + Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), + }; + + unsafe { + enc_usize_byref(vmctx, nwritten, host_nwritten) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) + } +} + +pub fn wasi_path_open( + vmctx: &mut Vmctx, + dirfd: wasm32::__wasi_fd_t, + dirflags: wasm32::__wasi_lookupflags_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, + oflags: wasm32::__wasi_oflags_t, + fs_rights_base: wasm32::__wasi_rights_t, + fs_rights_inheriting: wasm32::__wasi_rights_t, + fs_flags: wasm32::__wasi_fdflags_t, + fd_out_ptr: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + use nix::errno::Errno; + use nix::fcntl::{openat, AtFlags, OFlag}; + use nix::sys::stat::{fstatat, Mode, SFlag}; + + let dirfd = dec_fd(dirfd); + let dirflags = dec_lookupflags(dirflags); + let oflags = dec_oflags(oflags); + let fs_rights_base = dec_rights(fs_rights_base); + let fs_rights_inheriting = dec_rights(fs_rights_inheriting); + let fs_flags = dec_fdflags(fs_flags); + + // which open mode do we need? + let read = fs_rights_base + & ((host::__WASI_RIGHT_FD_READ | host::__WASI_RIGHT_FD_READDIR) as host::__wasi_rights_t) + != 0; + let write = fs_rights_base + & ((host::__WASI_RIGHT_FD_DATASYNC + | host::__WASI_RIGHT_FD_WRITE + | host::__WASI_RIGHT_FD_ALLOCATE + | host::__WASI_RIGHT_PATH_FILESTAT_SET_SIZE) as host::__wasi_rights_t) + != 0; + + let mut nix_all_oflags = if read && write { + OFlag::O_RDWR + } else if read { + OFlag::O_RDONLY + } else { + OFlag::O_WRONLY + }; + + // on non-Capsicum systems, we always want nofollow + nix_all_oflags.insert(OFlag::O_NOFOLLOW); + + // which rights are needed on the dirfd? + let mut needed_base = host::__WASI_RIGHT_PATH_OPEN as host::__wasi_rights_t; + let mut needed_inheriting = fs_rights_base | fs_rights_inheriting; + + // convert open flags + let nix_oflags = host::nix_from_oflags(oflags); + nix_all_oflags.insert(nix_oflags); + if nix_all_oflags.contains(OFlag::O_CREAT) { + needed_base |= host::__WASI_RIGHT_PATH_CREATE_FILE as host::__wasi_rights_t; + } + if nix_all_oflags.contains(OFlag::O_TRUNC) { + needed_inheriting |= host::__WASI_RIGHT_PATH_FILESTAT_SET_SIZE as host::__wasi_rights_t; + } + + // convert file descriptor flags + nix_all_oflags.insert(host::nix_from_fdflags(fs_flags)); + if nix_all_oflags.contains(OFlag::O_DSYNC) { + needed_inheriting |= host::__WASI_RIGHT_FD_DATASYNC as host::__wasi_rights_t; + } + if nix_all_oflags.intersects(O_RSYNC | OFlag::O_SYNC) { + needed_inheriting |= host::__WASI_RIGHT_FD_SYNC as host::__wasi_rights_t; + } + if nix_all_oflags.contains(OFlag::O_DIRECTORY) { + nix_all_oflags.remove(OFlag::O_RDWR); + nix_all_oflags.remove(OFlag::O_WRONLY); + nix_all_oflags.insert(OFlag::O_RDONLY); + } + let path = match unsafe { dec_slice_of::(vmctx, path_ptr, path_len) } { + Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + Err(e) => return enc_errno(e), + }; + + let (dir, path) = match path_get( + &vmctx, + dirfd, + dirflags, + path, + needed_base, + needed_inheriting, + nix_oflags.contains(OFlag::O_CREAT), + ) { + Ok((dir, path)) => (dir, path), + Err(e) => return enc_errno(e), + }; + + let new_fd = match openat( + dir, + path.as_os_str(), + nix_all_oflags, + Mode::from_bits_truncate(0o777), + ) { + Ok(fd) => fd, + Err(e) => { + match e.as_errno() { + // Linux returns ENXIO instead of EOPNOTSUPP when opening a socket + Some(Errno::ENXIO) => { + if let Ok(stat) = fstatat(dir, path.as_os_str(), AtFlags::AT_SYMLINK_NOFOLLOW) { + if SFlag::from_bits_truncate(stat.st_mode).contains(SFlag::S_IFSOCK) { + return wasm32::__WASI_ENOTSUP; + } else { + return wasm32::__WASI_ENXIO; + } + } else { + return wasm32::__WASI_ENXIO; + } + } + Some(e) => return wasm32::errno_from_nix(e), + None => return wasm32::__WASI_ENOSYS, + } + } + }; + + // Determine the type of the new file descriptor and which rights contradict with this type + let guest_fd = match unsafe { determine_type_rights(new_fd) } { + Err(e) => { + // if `close` fails, note it but do not override the underlying errno + nix::unistd::close(new_fd).unwrap_or_else(|e| { + dbg!(e); + }); + return enc_errno(e); + } + Ok((_ty, max_base, max_inheriting)) => { + let mut fe = unsafe { FdEntry::from_raw_fd(new_fd) }; + fe.rights_base &= max_base; + fe.rights_inheriting &= max_inheriting; + match vmctx.get_embed_ctx_mut::().insert_fd_entry(fe) { + Ok(fd) => fd, + Err(e) => return enc_errno(e), + } + } + }; + + unsafe { + enc_fd_byref(vmctx, fd_out_ptr, guest_fd) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) + } +} + +pub fn wasi_fd_filestat_get( + vmctx: &mut Vmctx, + fd: wasm32::__wasi_fd_t, + filestat_ptr: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + use nix::sys::stat::fstat; + + let host_fd = dec_fd(fd); + let ctx = vmctx.get_embed_ctx_mut::(); + + let rights = host::__WASI_RIGHT_FD_FILESTAT_GET; + match ctx.get_fd_entry(host_fd, rights.into(), 0) { + Ok(fe) => match fstat(fe.fd_object.rawfd) { + Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), + Ok(filestat) => { + let host_filestat = host::filestat_from_nix(filestat); + unsafe { + enc_filestat_byref(vmctx, filestat_ptr, host_filestat) + .expect("can write into the pointer"); + } + } + }, + Err(e) => return enc_errno(e), + } + wasm32::__WASI_ESUCCESS +} + +pub fn wasi_path_filestat_get( + vmctx: &mut Vmctx, + dirfd: wasm32::__wasi_fd_t, + dirflags: wasm32::__wasi_lookupflags_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, + filestat_ptr: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + use nix::fcntl::AtFlags; + use nix::sys::stat::fstatat; + + let dirfd = dec_fd(dirfd); + let dirflags = dec_lookupflags(dirflags); + let path = match unsafe { dec_slice_of::(vmctx, path_ptr, path_len) } { + Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + Err(e) => return enc_errno(e), + }; + let rights = host::__WASI_RIGHT_PATH_FILESTAT_GET; + let (dir, path) = match path_get(&vmctx, dirfd, dirflags, path, rights.into(), 0, false) { + Ok((dir, path)) => (dir, path), + Err(e) => return enc_errno(e), + }; + let atflags = match dirflags { + wasm32::__WASI_LOOKUP_SYMLINK_FOLLOW => AtFlags::empty(), + _ => AtFlags::AT_SYMLINK_NOFOLLOW, + }; + match fstatat(dir, path.as_os_str(), atflags) { + Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()), + Ok(filestat) => { + let host_filestat = host::filestat_from_nix(filestat); + unsafe { + enc_filestat_byref(vmctx, filestat_ptr, host_filestat) + .expect("can write into the pointer"); + } + wasm32::__WASI_ESUCCESS + } + } +} + +pub fn wasi_path_create_directory( + vmctx: &mut Vmctx, + dirfd: wasm32::__wasi_fd_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, +) -> wasm32::__wasi_errno_t { + use nix::errno; + use nix::libc::mkdirat; + + let dirfd = dec_fd(dirfd); + let path = match unsafe { dec_slice_of::(vmctx, path_ptr, path_len) } { + Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + Err(e) => return enc_errno(e), + }; + let rights = host::__WASI_RIGHT_PATH_CREATE_DIRECTORY; + let (dir, path) = match path_get(&vmctx, dirfd, 0, path, rights.into(), 0, false) { + Ok((dir, path)) => (dir, path), + Err(e) => return enc_errno(e), + }; + let path_cstr = match std::ffi::CString::new(path.as_os_str().as_bytes()) { + Ok(path_cstr) => path_cstr, + Err(_) => return wasm32::__WASI_EINVAL, + }; + // nix doesn't expose mkdirat() yet + match unsafe { mkdirat(dir, path_cstr.as_ptr(), 0o777) } { + 0 => wasm32::__WASI_ESUCCESS, + _ => wasm32::errno_from_nix(errno::Errno::last()), + } +} + +pub fn wasi_path_unlink_file( + vmctx: &mut Vmctx, + dirfd: wasm32::__wasi_fd_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, +) -> wasm32::__wasi_errno_t { + use nix::errno; + use nix::libc::unlinkat; + + let dirfd = dec_fd(dirfd); + let path = match unsafe { dec_slice_of::(vmctx, path_ptr, path_len) } { + Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + Err(e) => return enc_errno(e), + }; + let rights = host::__WASI_RIGHT_PATH_UNLINK_FILE; + let (dir, path) = match path_get(&vmctx, dirfd, 0, path, rights.into(), 0, false) { + Ok((dir, path)) => (dir, path), + Err(e) => return enc_errno(e), + }; + let path_cstr = match std::ffi::CString::new(path.as_os_str().as_bytes()) { + Ok(path_cstr) => path_cstr, + Err(_) => return wasm32::__WASI_EINVAL, + }; + // nix doesn't expose unlinkat() yet + match unsafe { unlinkat(dir, path_cstr.as_ptr(), 0) } { + 0 => wasm32::__WASI_ESUCCESS, + _ => wasm32::errno_from_nix(errno::Errno::last()), + } +} + +pub fn wasi_fd_allocate( + vmctx: &mut Vmctx, + fd: wasm32::__wasi_fd_t, + offset: wasm32::__wasi_filesize_t, + len: wasm32::__wasi_filesize_t, +) -> wasm32::__wasi_errno_t { + let host_fd = dec_fd(fd); + let ctx = vmctx.get_embed_ctx_mut::(); + let rights = host::__WASI_RIGHT_FD_ALLOCATE; + let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) { + Ok(fe) => fe, + Err(e) => return enc_errno(e), + }; + let offset = dec_filesize(offset); + let len = dec_filesize(len); + + #[cfg(target_os = "linux")] + { + let res = + unsafe { libc::posix_fallocate(fe.fd_object.rawfd, offset as off_t, len as off_t) }; + if res != 0 { + return wasm32::errno_from_nix(nix::errno::Errno::last()); + } + } + + #[cfg(not(target_os = "linux"))] + { + use nix::sys::stat::fstat; + use nix::unistd::ftruncate; + + match fstat(fe.fd_object.rawfd) { + Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), + Ok(st) => { + let current_size = st.st_size as u64; + let wanted_size = match offset.checked_add(len) { + Some(wanted_size) => wanted_size, + None => return wasm32::__WASI_E2BIG, + }; + if wanted_size > i64::max_value() as u64 { + return wasm32::__WASI_E2BIG; + } + if wanted_size > current_size { + if let Err(e) = ftruncate(fe.fd_object.rawfd, wanted_size as off_t) { + return wasm32::errno_from_nix(e.as_errno().unwrap()); + } + } + } + } + } + + wasm32::__WASI_ESUCCESS +} + +pub fn wasi_fd_advise( + vmctx: &mut Vmctx, + fd: wasm32::__wasi_fd_t, + offset: wasm32::__wasi_filesize_t, + len: wasm32::__wasi_filesize_t, + advice: wasm32::__wasi_advice_t, +) -> wasm32::__wasi_errno_t { + let host_fd = dec_fd(fd); + let ctx = vmctx.get_embed_ctx_mut::(); + let rights = host::__WASI_RIGHT_FD_ADVISE; + let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) { + Ok(fe) => fe, + Err(e) => return enc_errno(e), + }; + let advice = dec_advice(advice); + + #[cfg(target_os = "linux")] + { + let host_advice = match advice as u32 { + host::__WASI_ADVICE_DONTNEED => libc::POSIX_FADV_DONTNEED, + host::__WASI_ADVICE_SEQUENTIAL => libc::POSIX_FADV_SEQUENTIAL, + host::__WASI_ADVICE_WILLNEED => libc::POSIX_FADV_DONTNEED, + host::__WASI_ADVICE_NOREUSE => libc::POSIX_FADV_NOREUSE, + host::__WASI_ADVICE_RANDOM => libc::POSIX_FADV_RANDOM, + host::__WASI_ADVICE_NORMAL => libc::POSIX_FADV_NORMAL, + _ => return wasm32::__WASI_EINVAL, + }; + let offset = dec_filesize(offset); + let len = dec_filesize(len); + let res = unsafe { + libc::posix_fadvise( + fe.fd_object.rawfd, + offset as off_t, + len as off_t, + host_advice, + ) + }; + if res != 0 { + return wasm32::errno_from_nix(nix::errno::Errno::last()); + } + } + + #[cfg(not(target_os = "linux"))] + { + let _ = (fe, offset, len); + match advice as u32 { + host::__WASI_ADVICE_DONTNEED + | host::__WASI_ADVICE_SEQUENTIAL + | host::__WASI_ADVICE_WILLNEED + | host::__WASI_ADVICE_NOREUSE + | host::__WASI_ADVICE_RANDOM + | host::__WASI_ADVICE_NORMAL => {} + _ => return wasm32::__WASI_EINVAL, + } + } + + wasm32::__WASI_ESUCCESS +} + +pub fn wasi_fd_datasync(vmctx: &mut Vmctx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t { + let host_fd = dec_fd(fd); + let ctx = vmctx.get_embed_ctx_mut::(); + let rights = host::__WASI_RIGHT_FD_DATASYNC; + let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) { + Ok(fe) => fe, + Err(e) => return enc_errno(e), + }; + let res; + + #[cfg(target_os = "linux")] + { + res = nix::unistd::fdatasync(fe.fd_object.rawfd); + } + + #[cfg(not(target_os = "linux"))] + { + res = nix::unistd::fsync(fe.fd_object.rawfd); + } + + if let Err(e) = res { + return wasm32::errno_from_nix(e.as_errno().unwrap()); + } + wasm32::__WASI_ESUCCESS +} + +pub fn wasi_fd_sync(vmctx: &mut Vmctx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t { + let host_fd = dec_fd(fd); + let ctx = vmctx.get_embed_ctx_mut::(); + let rights = host::__WASI_RIGHT_FD_SYNC; + let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) { + Ok(fe) => fe, + Err(e) => return enc_errno(e), + }; + let res = nix::unistd::fsync(fe.fd_object.rawfd); + if let Err(e) = res { + return wasm32::errno_from_nix(e.as_errno().unwrap()); + } + wasm32::__WASI_ESUCCESS +} + +pub fn wasi_fd_fdstat_set_rights( + vmctx: &mut Vmctx, + fd: wasm32::__wasi_fd_t, + fs_rights_base: wasm32::__wasi_rights_t, + fs_rights_inheriting: wasm32::__wasi_rights_t, +) -> wasm32::__wasi_errno_t { + let host_fd = dec_fd(fd); + let ctx = vmctx.get_embed_ctx_mut::(); + let fe = match ctx.fds.get(&host_fd) { + Some(fe) => fe, + None => return wasm32::__WASI_EBADF, + }; + if fe.rights_base & fs_rights_base != fs_rights_base + || fe.rights_inheriting & fs_rights_inheriting != fs_rights_inheriting + { + return wasm32::__WASI_ENOTCAPABLE; + } + wasm32::__WASI_ESUCCESS +} + +pub fn wasi_fd_filestat_set_size( + vmctx: &mut Vmctx, + fd: wasm32::__wasi_fd_t, + st_size: wasm32::__wasi_filesize_t, +) -> wasm32::__wasi_errno_t { + use nix::unistd::ftruncate; + + let host_fd = dec_fd(fd); + let ctx = vmctx.get_embed_ctx_mut::(); + let rights = host::__WASI_RIGHT_FD_FILESTAT_SET_SIZE; + let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) { + Ok(fe) => fe, + Err(e) => return enc_errno(e), + }; + let st_size = dec_filesize(st_size); + if st_size > i64::max_value() as u64 { + return wasm32::__WASI_E2BIG; + } + if let Err(e) = ftruncate(fe.fd_object.rawfd, st_size as off_t) { + return wasm32::errno_from_nix(e.as_errno().unwrap()); + } + wasm32::__WASI_ESUCCESS +} + +pub fn wasi_fd_filestat_set_times( + vmctx: &mut Vmctx, + fd: wasm32::__wasi_fd_t, + st_atim: wasm32::__wasi_timestamp_t, + st_mtim: wasm32::__wasi_timestamp_t, + fst_flags: wasm32::__wasi_fstflags_t, +) -> wasm32::__wasi_errno_t { + use nix::sys::time::{TimeSpec, TimeValLike}; + + let host_fd = dec_fd(fd); + let ctx = vmctx.get_embed_ctx_mut::(); + let rights = host::__WASI_RIGHT_FD_FILESTAT_SET_TIMES; + let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) { + Ok(fe) => fe, + Err(e) => return enc_errno(e), + }; + let st_atim = dec_timestamp(st_atim); + let mut st_mtim = dec_timestamp(st_mtim); + let fst_flags = dec_fstflags(fst_flags); + if fst_flags & (host::__WASI_FILESTAT_SET_MTIM_NOW as host::__wasi_fstflags_t) != 0 { + let clock_id = libc::CLOCK_REALTIME; + let mut timespec = unsafe { std::mem::uninitialized::() }; + let res = unsafe { libc::clock_gettime(clock_id, &mut timespec as *mut libc::timespec) }; + if res != 0 { + return wasm32::errno_from_nix(nix::errno::Errno::last()); + } + let time_ns = match (timespec.tv_sec as host::__wasi_timestamp_t) + .checked_mul(1_000_000_000) + .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t)) + { + Some(time_ns) => time_ns, + None => return wasm32::__WASI_EOVERFLOW, + }; + st_mtim = time_ns; + } + let ts_atime = match fst_flags as u32 { + f if f & host::__WASI_FILESTAT_SET_ATIM_NOW != 0 => libc::timespec { + tv_sec: 0, + tv_nsec: utime_now(), + }, + f if f & host::__WASI_FILESTAT_SET_ATIM != 0 => { + *TimeSpec::nanoseconds(st_atim as i64).as_ref() + } + _ => libc::timespec { + tv_sec: 0, + tv_nsec: utime_omit(), + }, + }; + let ts_mtime = *TimeSpec::nanoseconds(st_mtim as i64).as_ref(); + let times = [ts_atime, ts_mtime]; + let res = unsafe { libc::futimens(fe.fd_object.rawfd, times.as_ptr()) }; + if res != 0 { + return wasm32::errno_from_nix(nix::errno::Errno::last()); + } + wasm32::__WASI_ESUCCESS +} + +pub fn wasi_path_filestat_set_times( + vmctx: &mut Vmctx, + dirfd: wasm32::__wasi_fd_t, + dirflags: wasm32::__wasi_lookupflags_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, + st_atim: wasm32::__wasi_timestamp_t, + st_mtim: wasm32::__wasi_timestamp_t, + fst_flags: wasm32::__wasi_fstflags_t, +) -> wasm32::__wasi_errno_t { + use nix::sys::time::{TimeSpec, TimeValLike}; + + let dirfd = dec_fd(dirfd); + let dirflags = dec_lookupflags(dirflags); + let path = match unsafe { dec_slice_of::(vmctx, path_ptr, path_len) } { + Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + Err(e) => return enc_errno(e), + }; + let rights = host::__WASI_RIGHT_PATH_FILESTAT_SET_TIMES; + let (dir, path) = match path_get(&vmctx, dirfd, dirflags, path, rights.into(), 0, false) { + Ok((dir, path)) => (dir, path), + Err(e) => return enc_errno(e), + }; + let atflags = match dirflags { + wasm32::__WASI_LOOKUP_SYMLINK_FOLLOW => 0, + _ => libc::AT_SYMLINK_NOFOLLOW, + }; + let st_atim = dec_timestamp(st_atim); + let mut st_mtim = dec_timestamp(st_mtim); + let fst_flags = dec_fstflags(fst_flags); + if fst_flags & (host::__WASI_FILESTAT_SET_MTIM_NOW as host::__wasi_fstflags_t) != 0 { + let clock_id = libc::CLOCK_REALTIME; + let mut timespec = unsafe { std::mem::uninitialized::() }; + let res = unsafe { libc::clock_gettime(clock_id, &mut timespec as *mut libc::timespec) }; + if res != 0 { + return wasm32::errno_from_nix(nix::errno::Errno::last()); + } + let time_ns = match (timespec.tv_sec as host::__wasi_timestamp_t) + .checked_mul(1_000_000_000) + .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t)) + { + Some(time_ns) => time_ns, + None => return wasm32::__WASI_EOVERFLOW, + }; + st_mtim = time_ns; + } + let ts_atime = match fst_flags as u32 { + f if f & host::__WASI_FILESTAT_SET_ATIM_NOW != 0 => libc::timespec { + tv_sec: 0, + tv_nsec: utime_now(), + }, + f if f & host::__WASI_FILESTAT_SET_ATIM != 0 => { + *TimeSpec::nanoseconds(st_atim as i64).as_ref() + } + _ => libc::timespec { + tv_sec: 0, + tv_nsec: utime_omit(), + }, + }; + let ts_mtime = *TimeSpec::nanoseconds(st_mtim as i64).as_ref(); + let times = [ts_atime, ts_mtime]; + let path_cstr = match std::ffi::CString::new(path.as_os_str().as_bytes()) { + Ok(path_cstr) => path_cstr, + Err(_) => return wasm32::__WASI_EINVAL, + }; + let res = unsafe { libc::utimensat(dir, path_cstr.as_ptr(), times.as_ptr(), atflags) }; + if res != 0 { + return wasm32::errno_from_nix(nix::errno::Errno::last()); + } + wasm32::__WASI_ESUCCESS +} + +pub fn wasi_fd_pread( + vmctx: &mut Vmctx, + fd: wasm32::__wasi_fd_t, + iovs_ptr: wasm32::uintptr_t, + iovs_len: wasm32::size_t, + offset: wasm32::__wasi_filesize_t, + nread: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + use nix::sys::uio::pread; + use std::cmp; + + let fd = dec_fd(fd); + let iovs = match unsafe { dec_iovec_slice(vmctx, iovs_ptr, iovs_len) } { + Ok(iovs) => iovs, + Err(e) => return enc_errno(e), + }; + let ctx = vmctx.get_embed_ctx_mut::(); + let rights = host::__WASI_RIGHT_FD_READ; + let fe = match ctx.get_fd_entry(fd, rights.into(), 0) { + Ok(fe) => fe, + Err(e) => return enc_errno(e), + }; + let offset = dec_filesize(offset); + if offset > i64::max_value() as u64 { + return wasm32::__WASI_EIO; + } + let buf_size = iovs.iter().map(|v| v.buf_len).sum(); + let mut buf = vec![0; buf_size]; + let host_nread = match pread(fe.fd_object.rawfd, &mut buf, offset as off_t) { + Ok(len) => len, + Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), + }; + let mut buf_offset = 0; + let mut left = host_nread; + for iov in &iovs { + if left == 0 { + break; + } + let vec_len = cmp::min(iov.buf_len, left); + unsafe { std::slice::from_raw_parts_mut(iov.buf as *mut u8, vec_len) } + .copy_from_slice(&buf[buf_offset..buf_offset + vec_len]); + buf_offset += vec_len; + left -= vec_len; + } + unsafe { + enc_usize_byref(vmctx, nread, host_nread) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) + } +} + +pub fn wasi_fd_pwrite( + vmctx: &mut Vmctx, + fd: wasm32::__wasi_fd_t, + iovs_ptr: wasm32::uintptr_t, + iovs_len: wasm32::size_t, + offset: wasm32::__wasi_filesize_t, + nwritten: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + use nix::sys::uio::pwrite; + + let fd = dec_fd(fd); + let iovs = match unsafe { dec_iovec_slice(vmctx, iovs_ptr, iovs_len) } { + Ok(iovs) => iovs, + Err(e) => return enc_errno(e), + }; + let ctx = vmctx.get_embed_ctx_mut::(); + let rights = host::__WASI_RIGHT_FD_READ; + let fe = match ctx.get_fd_entry(fd, rights.into(), 0) { + Ok(fe) => fe, + Err(e) => return enc_errno(e), + }; + let offset = dec_filesize(offset); + if offset > i64::max_value() as u64 { + return wasm32::__WASI_EIO; + } + let buf_size = iovs.iter().map(|v| v.buf_len).sum(); + let mut buf = Vec::with_capacity(buf_size); + for iov in &iovs { + buf.extend_from_slice(unsafe { + std::slice::from_raw_parts(iov.buf as *const u8, iov.buf_len) + }); + } + let host_nwritten = match pwrite(fe.fd_object.rawfd, &buf, offset as off_t) { + Ok(len) => len, + Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), + }; + unsafe { + enc_usize_byref(vmctx, nwritten, host_nwritten) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) + } +} + +pub fn wasi_fd_readdir( + vmctx: &mut Vmctx, + fd: wasm32::__wasi_fd_t, + buf: wasm32::uintptr_t, + buf_len: wasm32::size_t, + cookie: wasm32::__wasi_dircookie_t, + bufused: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + use libc::{dirent, fdopendir, memcpy, readdir_r, seekdir}; + + match unsafe { enc_usize_byref(vmctx, bufused, 0) } { + Ok(_) => {} + Err(e) => return enc_errno(e), + }; + let fd = dec_fd(fd); + let ctx = vmctx.get_embed_ctx_mut::(); + let rights = host::__WASI_RIGHT_FD_READDIR; + let fe = match ctx.get_fd_entry(fd, rights.into(), 0) { + Ok(fe) => fe, + Err(e) => return enc_errno(e), + }; + let host_buf = match unsafe { dec_slice_of::(vmctx, buf, buf_len) } { + Ok(host_buf) => host_buf, + Err(e) => return enc_errno(e), + }; + let host_buf_ptr = host_buf.0; + let host_buf_len = host_buf.1; + let dir = unsafe { fdopendir(fe.fd_object.rawfd) }; + if dir.is_null() { + return wasm32::errno_from_nix(nix::errno::Errno::last()); + } + let cookie = dec_dircookie(cookie); + if cookie != wasm32::__WASI_DIRCOOKIE_START { + unsafe { seekdir(dir, cookie as c_long) }; + } + let mut entry_buf = unsafe { std::mem::uninitialized::() }; + let mut left = host_buf_len; + let mut host_buf_offset: usize = 0; + while left > 0 { + let mut host_entry: *mut dirent = std::ptr::null_mut(); + let res = unsafe { readdir_r(dir, &mut entry_buf, &mut host_entry) }; + if res == -1 { + return wasm32::errno_from_nix(nix::errno::Errno::last()); + } + if host_entry.is_null() { + break; + } + let entry: wasm32::__wasi_dirent_t = match dirent_from_host(&unsafe { *host_entry }) { + Ok(entry) => entry, + Err(e) => return enc_errno(e), + }; + let name_len = entry.d_namlen as usize; + let required_space = std::mem::size_of_val(&entry) + name_len; + if required_space > left { + break; + } + unsafe { + let ptr = host_buf_ptr.offset(host_buf_offset as isize) as *mut c_void + as *mut wasm32::__wasi_dirent_t; + *ptr = entry; + } + host_buf_offset += std::mem::size_of_val(&entry); + let name_ptr = unsafe { *host_entry }.d_name.as_ptr(); + unsafe { + memcpy( + host_buf_ptr.offset(host_buf_offset as isize) as *mut _, + name_ptr as *const _, + name_len, + ) + }; + host_buf_offset += name_len; + left -= required_space; + } + let host_bufused = host_buf_len - left; + unsafe { + enc_usize_byref(vmctx, bufused, host_bufused) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) + } +} + +pub fn wasi_fd_renumber( + vmctx: &mut Vmctx, + from: wasm32::__wasi_fd_t, + to: wasm32::__wasi_fd_t, +) -> wasm32::__wasi_errno_t { + let from = dec_fd(from); + let to = dec_fd(to); + let mut ctx = vmctx.get_embed_ctx_mut::(); + let fe_from = match ctx.fds.get(&from) { + Some(fe_from) => fe_from, + None => return wasm32::__WASI_EBADF, + }; + let fe_to = match ctx.fds.get(&to) { + Some(fe_to) => fe_to, + None => return wasm32::__WASI_EBADF, + }; + if let Err(e) = nix::unistd::dup2(fe_from.fd_object.rawfd, fe_to.fd_object.rawfd) { + return wasm32::errno_from_nix(e.as_errno().unwrap()); + } + let fe_from_rawfd = fe_from.fd_object.rawfd; + ctx.fds.remove(&(fe_from_rawfd as host::__wasi_fd_t)); + + wasm32::__WASI_ESUCCESS +} + +pub fn wasi_path_link( + vmctx: &mut Vmctx, + old_dirfd: wasm32::__wasi_fd_t, + _old_flags: wasm32::__wasi_lookupflags_t, + old_path_ptr: wasm32::uintptr_t, + old_path_len: wasm32::size_t, + new_dirfd: wasm32::__wasi_fd_t, + new_path_ptr: wasm32::uintptr_t, + new_path_len: wasm32::size_t, +) -> wasm32::__wasi_errno_t { + use nix::libc::linkat; + + let old_dirfd = dec_fd(old_dirfd); + let new_dirfd = dec_fd(new_dirfd); + let old_path = match unsafe { dec_slice_of::(vmctx, old_path_ptr, old_path_len) } { + Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + Err(e) => return enc_errno(e), + }; + let new_path = match unsafe { dec_slice_of::(vmctx, new_path_ptr, new_path_len) } { + Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + Err(e) => return enc_errno(e), + }; + let rights = host::__WASI_RIGHT_PATH_LINK_SOURCE; + let (old_dir, old_path) = + match path_get(&vmctx, old_dirfd, 0, old_path, rights.into(), 0, false) { + Ok((dir, path)) => (dir, path), + Err(e) => return enc_errno(e), + }; + let rights = host::__WASI_RIGHT_PATH_LINK_TARGET; + let (new_dir, new_path) = + match path_get(&vmctx, new_dirfd, 0, new_path, rights.into(), 0, false) { + Ok((dir, path)) => (dir, path), + Err(e) => return enc_errno(e), + }; + let old_path_cstr = match std::ffi::CString::new(old_path.as_bytes()) { + Ok(old_path_cstr) => old_path_cstr, + Err(_) => return wasm32::__WASI_EINVAL, + }; + let new_path_cstr = match std::ffi::CString::new(new_path.as_bytes()) { + Ok(new_path_cstr) => new_path_cstr, + Err(_) => return wasm32::__WASI_EINVAL, + }; + + // Not setting AT_SYMLINK_FOLLOW fails on most filesystems + let atflags = libc::AT_SYMLINK_FOLLOW; + let res = unsafe { + linkat( + old_dir, + old_path_cstr.as_ptr(), + new_dir, + new_path_cstr.as_ptr(), + atflags, + ) + }; + if res != 0 { + return wasm32::errno_from_nix(nix::errno::Errno::last()); + } + wasm32::__WASI_ESUCCESS +} + +pub fn wasi_path_readlink( + vmctx: &mut Vmctx, + dirfd: wasm32::__wasi_fd_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, + buf_ptr: wasm32::uintptr_t, + buf_len: wasm32::size_t, + bufused: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + use nix::fcntl::readlinkat; + + match unsafe { enc_usize_byref(vmctx, bufused, 0) } { + Ok(_) => {} + Err(e) => return enc_errno(e), + }; + let dirfd = dec_fd(dirfd); + let path = match unsafe { dec_slice_of::(vmctx, path_ptr, path_len) } { + Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + Err(e) => return enc_errno(e), + }; + let rights = host::__WASI_RIGHT_PATH_READLINK; + let (dir, path) = match path_get(&vmctx, dirfd, 0, path, rights.into(), 0, false) { + Ok((dir, path)) => (dir, path), + Err(e) => return enc_errno(e), + }; + let mut buf = match unsafe { dec_slice_of::(vmctx, buf_ptr, buf_len) } { + Ok((ptr, len)) => unsafe { std::slice::from_raw_parts_mut(ptr, len) }, + Err(e) => return enc_errno(e), + }; + let target_path = match readlinkat(dir, path.as_os_str(), &mut buf) { + Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), + Ok(target_path) => target_path, + }; + let host_bufused = target_path.len(); + match unsafe { enc_usize_byref(vmctx, bufused, host_bufused) } { + Ok(_) => {} + Err(e) => return enc_errno(e), + }; + wasm32::__WASI_ESUCCESS +} + +pub fn wasi_path_remove_directory( + vmctx: &mut Vmctx, + dirfd: wasm32::__wasi_fd_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, +) -> wasm32::__wasi_errno_t { + use nix::errno; + use nix::libc::{unlinkat, AT_REMOVEDIR}; + + let dirfd = dec_fd(dirfd); + let path = match unsafe { dec_slice_of::(vmctx, path_ptr, path_len) } { + Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + Err(e) => return enc_errno(e), + }; + let rights = host::__WASI_RIGHT_PATH_REMOVE_DIRECTORY; + let (dir, path) = match path_get(&vmctx, dirfd, 0, path, rights.into(), 0, false) { + Ok((dir, path)) => (dir, path), + Err(e) => return enc_errno(e), + }; + let path_cstr = match std::ffi::CString::new(path.as_os_str().as_bytes()) { + Ok(path_cstr) => path_cstr, + Err(_) => return wasm32::__WASI_EINVAL, + }; + // nix doesn't expose unlinkat() yet + match unsafe { unlinkat(dir, path_cstr.as_ptr(), AT_REMOVEDIR) } { + 0 => wasm32::__WASI_ESUCCESS, + _ => wasm32::errno_from_nix(errno::Errno::last()), + } +} + +pub fn wasi_path_rename( + vmctx: &mut Vmctx, + old_dirfd: wasm32::__wasi_fd_t, + old_path_ptr: wasm32::uintptr_t, + old_path_len: wasm32::size_t, + new_dirfd: wasm32::__wasi_fd_t, + new_path_ptr: wasm32::uintptr_t, + new_path_len: wasm32::size_t, +) -> wasm32::__wasi_errno_t { + use nix::libc::renameat; + + let old_dirfd = dec_fd(old_dirfd); + let new_dirfd = dec_fd(new_dirfd); + let old_path = match unsafe { dec_slice_of::(vmctx, old_path_ptr, old_path_len) } { + Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + Err(e) => return enc_errno(e), + }; + let new_path = match unsafe { dec_slice_of::(vmctx, new_path_ptr, new_path_len) } { + Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + Err(e) => return enc_errno(e), + }; + let rights = host::__WASI_RIGHT_PATH_RENAME_SOURCE; + let (old_dir, old_path) = + match path_get(&vmctx, old_dirfd, 0, old_path, rights.into(), 0, false) { + Ok((dir, path)) => (dir, path), + Err(e) => return enc_errno(e), + }; + let rights = host::__WASI_RIGHT_PATH_RENAME_TARGET; + let (new_dir, new_path) = + match path_get(&vmctx, new_dirfd, 0, new_path, rights.into(), 0, false) { + Ok((dir, path)) => (dir, path), + Err(e) => return enc_errno(e), + }; + let old_path_cstr = match std::ffi::CString::new(old_path.as_bytes()) { + Ok(old_path_cstr) => old_path_cstr, + Err(_) => return wasm32::__WASI_EINVAL, + }; + let new_path_cstr = match std::ffi::CString::new(new_path.as_bytes()) { + Ok(new_path_cstr) => new_path_cstr, + Err(_) => return wasm32::__WASI_EINVAL, + }; + let res = unsafe { + renameat( + old_dir, + old_path_cstr.as_ptr(), + new_dir, + new_path_cstr.as_ptr(), + ) + }; + if res != 0 { + return wasm32::errno_from_nix(nix::errno::Errno::last()); + } + wasm32::__WASI_ESUCCESS +} + +pub fn wasi_path_symlink( + vmctx: &mut Vmctx, + old_path_ptr: wasm32::uintptr_t, + old_path_len: wasm32::size_t, + dirfd: wasm32::__wasi_fd_t, + new_path_ptr: wasm32::uintptr_t, + new_path_len: wasm32::size_t, +) -> wasm32::__wasi_errno_t { + use nix::libc::symlinkat; + + let dirfd = dec_fd(dirfd); + let old_path = match unsafe { dec_slice_of::(vmctx, old_path_ptr, old_path_len) } { + Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + Err(e) => return enc_errno(e), + }; + let new_path = match unsafe { dec_slice_of::(vmctx, new_path_ptr, new_path_len) } { + Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + Err(e) => return enc_errno(e), + }; + let rights = host::__WASI_RIGHT_PATH_SYMLINK; + let (dir, new_path) = match path_get(&vmctx, dirfd, 0, new_path, rights.into(), 0, false) { + Ok((dir, path)) => (dir, path), + Err(e) => return enc_errno(e), + }; + let old_path_cstr = match std::ffi::CString::new(old_path.as_bytes()) { + Ok(old_path_cstr) => old_path_cstr, + Err(_) => return wasm32::__WASI_EINVAL, + }; + let new_path_cstr = match std::ffi::CString::new(new_path.as_bytes()) { + Ok(new_path_cstr) => new_path_cstr, + Err(_) => return wasm32::__WASI_EINVAL, + }; + let res = unsafe { symlinkat(old_path_cstr.as_ptr(), dir, new_path_cstr.as_ptr()) }; + if res != 0 { + return wasm32::errno_from_nix(nix::errno::Errno::last()); + } + wasm32::__WASI_ESUCCESS +} diff --git a/lucet-wasi/src/hostcalls/fs_helpers.rs b/lucet-wasi/src/hostcalls/fs_helpers.rs new file mode 100644 index 000000000..c949a1d67 --- /dev/null +++ b/lucet-wasi/src/hostcalls/fs_helpers.rs @@ -0,0 +1,303 @@ +#![allow(non_camel_case_types)] +#![allow(unused_unsafe)] +use crate::ctx::WasiCtx; +use crate::host; + +use lucet_runtime::vmctx::Vmctx; + +use nix::libc::{self, c_long}; +use std::ffi::{OsStr, OsString}; +use std::os::unix::prelude::{OsStrExt, OsStringExt, RawFd}; + +#[cfg(target_os = "linux")] +pub const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_RSYNC; + +#[cfg(not(target_os = "linux"))] +pub const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_SYNC; + +/// Normalizes a path to ensure that the target path is located under the directory provided. +/// +/// This is a workaround for not having Capsicum support in the OS. +pub fn path_get>( + vmctx: &Vmctx, + dirfd: host::__wasi_fd_t, + dirflags: host::__wasi_lookupflags_t, + path: P, + needed_base: host::__wasi_rights_t, + needed_inheriting: host::__wasi_rights_t, + needs_final_component: bool, +) -> Result<(RawFd, OsString), host::__wasi_errno_t> { + use nix::errno::Errno; + use nix::fcntl::{openat, readlinkat, OFlag}; + use nix::sys::stat::Mode; + + const MAX_SYMLINK_EXPANSIONS: usize = 128; + + /// close all the intermediate file descriptors, but make sure not to drop either the original + /// dirfd or the one we return (which may be the same dirfd) + fn ret_dir_success(dir_stack: &mut Vec) -> RawFd { + let ret_dir = dir_stack.pop().expect("there is always a dirfd to return"); + if let Some(dirfds) = dir_stack.get(1..) { + for dirfd in dirfds { + nix::unistd::close(*dirfd).unwrap_or_else(|e| { + dbg!(e); + }); + } + } + ret_dir + } + + /// close all file descriptors other than the base directory, and return the errno for + /// convenience with `return` + fn ret_error( + dir_stack: &mut Vec, + errno: host::__wasi_errno_t, + ) -> Result<(RawFd, OsString), host::__wasi_errno_t> { + if let Some(dirfds) = dir_stack.get(1..) { + for dirfd in dirfds { + nix::unistd::close(*dirfd).unwrap_or_else(|e| { + dbg!(e); + }); + } + } + Err(errno) + } + + let ctx = vmctx.get_embed_ctx::(); + + let dirfe = ctx.get_fd_entry(dirfd, needed_base, needed_inheriting)?; + + // Stack of directory file descriptors. Index 0 always corresponds with the directory provided + // to this function. Entering a directory causes a file descriptor to be pushed, while handling + // ".." entries causes an entry to be popped. Index 0 cannot be popped, as this would imply + // escaping the base directory. + let mut dir_stack = vec![dirfe.fd_object.rawfd]; + + // Stack of paths left to process. This is initially the `path` argument to this function, but + // any symlinks we encounter are processed by pushing them on the stack. + let mut path_stack = vec![path.as_ref().to_owned().into_vec()]; + + // Track the number of symlinks we've expanded, so we can return `ELOOP` after too many. + let mut symlink_expansions = 0; + + // Buffer to read links into; defined outside of the loop so we don't reallocate it constantly. + let mut readlink_buf = vec![0u8; libc::PATH_MAX as usize + 1]; + + // TODO: rewrite this using a custom posix path type, with a component iterator that respects + // trailing slashes. This version does way too much allocation, and is way too fiddly. + loop { + let component = if let Some(cur_path) = path_stack.pop() { + // eprintln!( + // "cur_path = {:?}", + // std::str::from_utf8(cur_path.as_slice()).unwrap() + // ); + let mut split = cur_path.splitn(2, |&c| c == b'/'); + let head = split.next(); + let tail = split.next(); + match (head, tail) { + (None, _) => { + // split always returns at least a singleton iterator with an empty slice + panic!("unreachable"); + } + // path is empty + (Some([]), None) => { + return ret_error(&mut dir_stack, host::__WASI_ENOENT as host::__wasi_errno_t); + } + // path starts with `/`, is absolute + (Some([]), Some(_)) => { + return ret_error( + &mut dir_stack, + host::__WASI_ENOTCAPABLE as host::__wasi_errno_t, + ); + } + // the final component of the path with no trailing slash + (Some(component), None) => component.to_vec(), + (Some(component), Some(rest)) => { + if rest.iter().all(|&c| c == b'/') { + // the final component of the path with trailing slashes; put one trailing + // slash back on + let mut component = component.to_vec(); + component.push('/' as u8); + component + } else { + // non-final component; push the rest back on the stack + path_stack.push(rest.to_vec()); + component.to_vec() + } + } + } + } else { + // if the path stack is ever empty, we return rather than going through the loop again + panic!("unreachable"); + }; + + // eprintln!( + // "component = {:?}", + // std::str::from_utf8(component.as_slice()).unwrap() + // ); + + match component.as_slice() { + b"." => { + // skip component + } + b".." => { + // pop a directory + let dirfd = dir_stack.pop().expect("dir_stack is never empty"); + + // we're not allowed to pop past the original directory + if dir_stack.is_empty() { + return ret_error( + &mut dir_stack, + host::__WASI_ENOTCAPABLE as host::__wasi_errno_t, + ); + } else { + nix::unistd::close(dirfd).unwrap_or_else(|e| { + dbg!(e); + }); + } + } + // should the component be a directory? it should if there is more path left to process, or + // if it has a trailing slash and `needs_final_component` is not set + component + if !path_stack.is_empty() + || (component.ends_with(b"/") && !needs_final_component) => + { + match openat( + *dir_stack.first().expect("dir_stack is never empty"), + component, + OFlag::O_RDONLY | OFlag::O_DIRECTORY | OFlag::O_NOFOLLOW, + Mode::empty(), + ) { + Ok(new_dir) => { + dir_stack.push(new_dir); + continue; + } + Err(e) + if e.as_errno() == Some(Errno::ELOOP) + || e.as_errno() == Some(Errno::EMLINK) => + { + // attempt symlink expansion + match readlinkat( + *dir_stack.last().expect("dir_stack is never empty"), + component, + readlink_buf.as_mut_slice(), + ) { + Ok(link_path) => { + symlink_expansions += 1; + if symlink_expansions > MAX_SYMLINK_EXPANSIONS { + return ret_error( + &mut dir_stack, + host::__WASI_ELOOP as host::__wasi_errno_t, + ); + } + + let mut link_path = link_path.as_bytes().to_vec(); + + // append a trailing slash if the component leading to it has one, so + // that we preserve any ENOTDIR that might come from trying to open a + // non-directory + if component.ends_with(b"/") { + link_path.push(b'/'); + } + + path_stack.push(link_path); + continue; + } + Err(e) => { + return ret_error( + &mut dir_stack, + host::errno_from_nix(e.as_errno().unwrap()), + ); + } + } + } + Err(e) => { + return ret_error( + &mut dir_stack, + host::errno_from_nix(e.as_errno().unwrap()), + ); + } + } + } + // the final component + component => { + // if there's a trailing slash, or if `LOOKUP_SYMLINK_FOLLOW` is set, attempt + // symlink expansion + if component.ends_with(b"/") || (dirflags & host::__WASI_LOOKUP_SYMLINK_FOLLOW) != 0 + { + match readlinkat( + *dir_stack.last().expect("dir_stack is never empty"), + component, + readlink_buf.as_mut_slice(), + ) { + Ok(link_path) => { + symlink_expansions += 1; + if symlink_expansions > MAX_SYMLINK_EXPANSIONS { + return ret_error( + &mut dir_stack, + host::__WASI_ELOOP as host::__wasi_errno_t, + ); + } + + let mut link_path = link_path.as_bytes().to_vec(); + + // append a trailing slash if the component leading to it has one, so + // that we preserve any ENOTDIR that might come from trying to open a + // non-directory + if component.ends_with(b"/") { + link_path.push(b'/'); + } + + path_stack.push(link_path); + continue; + } + Err(e) => { + let errno = e.as_errno().unwrap(); + if errno != Errno::EINVAL && errno != Errno::ENOENT { + // only return an error if this path is not actually a symlink + return ret_error(&mut dir_stack, host::errno_from_nix(errno)); + } + } + } + } + + // not a symlink, so we're done; + return Ok(( + ret_dir_success(&mut dir_stack), + OsStr::from_bytes(component).to_os_string(), + )); + } + } + + if path_stack.is_empty() { + // no further components to process. means we've hit a case like "." or "a/..", or if the + // input path has trailing slashes and `needs_final_component` is not set + return Ok(( + ret_dir_success(&mut dir_stack), + OsStr::new(".").to_os_string(), + )); + } else { + continue; + } + } +} + +#[cfg(not(target_os = "macos"))] +pub fn utime_now() -> c_long { + libc::UTIME_NOW +} + +#[cfg(target_os = "macos")] +pub fn utime_now() -> c_long { + -1 +} + +#[cfg(not(target_os = "macos"))] +pub fn utime_omit() -> c_long { + libc::UTIME_OMIT +} + +#[cfg(target_os = "macos")] +pub fn utime_omit() -> c_long { + -2 +} diff --git a/lucet-wasi/src/hostcalls/misc.rs b/lucet-wasi/src/hostcalls/misc.rs new file mode 100644 index 000000000..05c57ee27 --- /dev/null +++ b/lucet-wasi/src/hostcalls/misc.rs @@ -0,0 +1,479 @@ +#![allow(non_camel_case_types)] +#![allow(unused_unsafe)] + +use crate::ctx::WasiCtx; +use crate::memory::*; +use crate::{host, wasm32}; + +use cast::From as _0; +use lucet_runtime::lucet_hostcall_terminate; +use lucet_runtime::vmctx::Vmctx; + +use nix::convert_ioctl_res; +use nix::libc::{self, c_int}; +use std::time::SystemTime; +use std::{cmp, slice}; + +// define the `fionread()` function, equivalent to `ioctl(fd, FIONREAD, *bytes)` +nix::ioctl_read_bad!(fionread, nix::libc::FIONREAD, c_int); + +fn wasi_clock_to_relative_ns_delay( + wasi_clock: host::__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, +) -> u128 { + if wasi_clock.flags != wasm32::__WASI_SUBSCRIPTION_CLOCK_ABSTIME { + return wasi_clock.timeout as u128; + } + let now: u128 = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .expect("Current date is before the epoch") + .as_nanos(); + let deadline = wasi_clock.timeout as u128; + deadline.saturating_sub(now) +} + +#[derive(Debug, Copy, Clone)] +struct ClockEventData { + delay: u128, + userdata: host::__wasi_userdata_t, +} +#[derive(Debug, Copy, Clone)] +struct FdEventData { + fd: c_int, + type_: host::__wasi_eventtype_t, + userdata: host::__wasi_userdata_t, +} + +pub fn wasi_proc_exit(_vmctx: &mut Vmctx, rval: wasm32::__wasi_exitcode_t) -> ! { + lucet_hostcall_terminate!(dec_exitcode(rval)); +} + +pub fn wasi_args_get( + vmctx: &mut Vmctx, + argv_ptr: wasm32::uintptr_t, + argv_buf: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let ctx = vmctx.get_embed_ctx::(); + + let mut argv_buf_offset = 0; + let mut argv = vec![]; + + for arg in ctx.args.iter() { + let arg_bytes = arg.as_bytes_with_nul(); + let arg_ptr = argv_buf + argv_buf_offset; + + if let Err(e) = unsafe { enc_slice_of(vmctx, arg_bytes, arg_ptr) } { + return enc_errno(e); + } + + argv.push(arg_ptr); + + argv_buf_offset = if let Some(new_offset) = argv_buf_offset.checked_add( + wasm32::uintptr_t::cast(arg_bytes.len()) + .expect("cast overflow would have been caught by `enc_slice_of` above"), + ) { + new_offset + } else { + return wasm32::__WASI_EOVERFLOW; + } + } + + unsafe { + enc_slice_of(vmctx, argv.as_slice(), argv_ptr) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) + } +} + +pub fn wasi_args_sizes_get( + vmctx: &mut Vmctx, + argc_ptr: wasm32::uintptr_t, + argv_buf_size_ptr: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let ctx = vmctx.get_embed_ctx::(); + + let argc = ctx.args.len(); + let argv_size = ctx + .args + .iter() + .map(|arg| arg.as_bytes_with_nul().len()) + .sum(); + + unsafe { + if let Err(e) = enc_usize_byref(vmctx, argc_ptr, argc) { + return enc_errno(e); + } + if let Err(e) = enc_usize_byref(vmctx, argv_buf_size_ptr, argv_size) { + return enc_errno(e); + } + } + wasm32::__WASI_ESUCCESS +} + +pub fn wasi_sched_yield(_vmctx: &mut Vmctx) -> wasm32::__wasi_errno_t { + unsafe { libc::sched_yield() }; + wasm32::__WASI_ESUCCESS +} + +pub fn wasi_clock_res_get( + vmctx: &mut Vmctx, + clock_id: wasm32::__wasi_clockid_t, + resolution_ptr: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + // convert the supported clocks to the libc types, or return EINVAL + let clock_id = match dec_clockid(clock_id) { + host::__WASI_CLOCK_REALTIME => libc::CLOCK_REALTIME, + host::__WASI_CLOCK_MONOTONIC => libc::CLOCK_MONOTONIC, + host::__WASI_CLOCK_PROCESS_CPUTIME_ID => libc::CLOCK_PROCESS_CPUTIME_ID, + host::__WASI_CLOCK_THREAD_CPUTIME_ID => libc::CLOCK_THREAD_CPUTIME_ID, + _ => return wasm32::__WASI_EINVAL, + }; + + // no `nix` wrapper for clock_getres, so we do it ourselves + let mut timespec = unsafe { std::mem::uninitialized::() }; + let res = unsafe { libc::clock_getres(clock_id, &mut timespec as *mut libc::timespec) }; + if res != 0 { + return wasm32::errno_from_nix(nix::errno::Errno::last()); + } + + // convert to nanoseconds, returning EOVERFLOW in case of overflow; this is freelancing a bit + // from the spec but seems like it'll be an unusual situation to hit + (timespec.tv_sec as host::__wasi_timestamp_t) + .checked_mul(1_000_000_000) + .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t)) + .map(|resolution| { + // a supported clock can never return zero; this case will probably never get hit, but + // make sure we follow the spec + if resolution == 0 { + wasm32::__WASI_EINVAL + } else { + unsafe { + enc_timestamp_byref(vmctx, resolution_ptr, resolution) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) + } + } + }) + .unwrap_or(wasm32::__WASI_EOVERFLOW) +} + +pub fn wasi_clock_time_get( + vmctx: &mut Vmctx, + clock_id: wasm32::__wasi_clockid_t, + // ignored for now, but will be useful once we put optional limits on precision to reduce side + // channels + _precision: wasm32::__wasi_timestamp_t, + time_ptr: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + // convert the supported clocks to the libc types, or return EINVAL + let clock_id = match dec_clockid(clock_id) { + host::__WASI_CLOCK_REALTIME => libc::CLOCK_REALTIME, + host::__WASI_CLOCK_MONOTONIC => libc::CLOCK_MONOTONIC, + host::__WASI_CLOCK_PROCESS_CPUTIME_ID => libc::CLOCK_PROCESS_CPUTIME_ID, + host::__WASI_CLOCK_THREAD_CPUTIME_ID => libc::CLOCK_THREAD_CPUTIME_ID, + _ => return wasm32::__WASI_EINVAL, + }; + + // no `nix` wrapper for clock_getres, so we do it ourselves + let mut timespec = unsafe { std::mem::uninitialized::() }; + let res = unsafe { libc::clock_gettime(clock_id, &mut timespec as *mut libc::timespec) }; + if res != 0 { + return wasm32::errno_from_nix(nix::errno::Errno::last()); + } + + // convert to nanoseconds, returning EOVERFLOW in case of overflow; this is freelancing a bit + // from the spec but seems like it'll be an unusual situation to hit + (timespec.tv_sec as host::__wasi_timestamp_t) + .checked_mul(1_000_000_000) + .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t)) + .map(|time| unsafe { + enc_timestamp_byref(vmctx, time_ptr, time) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) + }) + .unwrap_or(wasm32::__WASI_EOVERFLOW) +} + +pub fn wasi_environ_get( + vmctx: &mut Vmctx, + environ_ptr: wasm32::uintptr_t, + environ_buf: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let ctx = vmctx.get_embed_ctx::(); + + let mut environ_buf_offset = 0; + let mut environ = vec![]; + + for pair in ctx.env.iter() { + let env_bytes = pair.as_bytes_with_nul(); + let env_ptr = environ_buf + environ_buf_offset; + + if let Err(e) = unsafe { enc_slice_of(vmctx, env_bytes, env_ptr) } { + return enc_errno(e); + } + + environ.push(env_ptr); + + environ_buf_offset = if let Some(new_offset) = environ_buf_offset.checked_add( + wasm32::uintptr_t::cast(env_bytes.len()) + .expect("cast overflow would have been caught by `enc_slice_of` above"), + ) { + new_offset + } else { + return wasm32::__WASI_EOVERFLOW; + } + } + + unsafe { + enc_slice_of(vmctx, environ.as_slice(), environ_ptr) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) + } +} + +pub fn wasi_environ_sizes_get( + vmctx: &mut Vmctx, + environ_count_ptr: wasm32::uintptr_t, + environ_size_ptr: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let ctx = vmctx.get_embed_ctx::(); + + let environ_count = ctx.env.len(); + if let Some(environ_size) = ctx.env.iter().try_fold(0, |acc: u32, pair| { + acc.checked_add(pair.as_bytes_with_nul().len() as u32) + }) { + unsafe { + if let Err(e) = enc_usize_byref(vmctx, environ_count_ptr, environ_count) { + return enc_errno(e); + } + if let Err(e) = enc_usize_byref(vmctx, environ_size_ptr, environ_size as usize) { + return enc_errno(e); + } + } + wasm32::__WASI_ESUCCESS + } else { + wasm32::__WASI_EOVERFLOW + } +} + +pub fn wasi_random_get( + vmctx: &mut Vmctx, + buf_ptr: wasm32::uintptr_t, + buf_len: wasm32::size_t, +) -> wasm32::__wasi_errno_t { + use rand::{thread_rng, RngCore}; + + let buf_len = dec_usize(buf_len); + let buf_ptr = match unsafe { dec_ptr(vmctx, buf_ptr, buf_len) } { + Ok(ptr) => ptr, + Err(e) => return enc_errno(e), + }; + + let buf = unsafe { std::slice::from_raw_parts_mut(buf_ptr, buf_len) }; + + thread_rng().fill_bytes(buf); + + return wasm32::__WASI_ESUCCESS; +} + +fn __wasi_poll_oneoff_handle_timeout_event( + vmctx: &mut Vmctx, + output_slice: &mut [wasm32::__wasi_event_t], + nevents: wasm32::uintptr_t, + timeout: Option, +) -> wasm32::__wasi_errno_t { + if let Some(ClockEventData { userdata, .. }) = timeout { + let output_event = host::__wasi_event_t { + userdata, + type_: wasm32::__WASI_EVENTTYPE_CLOCK, + error: wasm32::__WASI_ESUCCESS, + u: host::__wasi_event_t___wasi_event_u { + fd_readwrite: host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { + nbytes: 0, + flags: 0, + }, + }, + }; + output_slice[0] = enc_event(output_event); + if let Err(e) = unsafe { enc_pointee(vmctx, nevents, 1) } { + return enc_errno(e); + } + } else { + // shouldn't happen + if let Err(e) = unsafe { enc_pointee(vmctx, nevents, 0) } { + return enc_errno(e); + } + } + wasm32::__WASI_ESUCCESS +} + +fn __wasi_poll_oneoff_handle_fd_event<'t>( + vmctx: &mut Vmctx, + output_slice: &mut [wasm32::__wasi_event_t], + nevents: wasm32::uintptr_t, + events: impl Iterator, +) -> wasm32::__wasi_errno_t { + let mut output_slice_cur = output_slice.iter_mut(); + let mut revents_count = 0; + for (fd_event, poll_fd) in events { + let revents = match poll_fd.revents() { + Some(revents) => revents, + None => continue, + }; + let mut nbytes = 0; + if fd_event.type_ == wasm32::__WASI_EVENTTYPE_FD_READ { + let _ = unsafe { fionread(fd_event.fd, &mut nbytes) }; + } + let output_event = if revents.contains(nix::poll::EventFlags::POLLNVAL) { + host::__wasi_event_t { + userdata: fd_event.userdata, + type_: fd_event.type_, + error: wasm32::__WASI_EBADF, + u: host::__wasi_event_t___wasi_event_u { + fd_readwrite: + host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { + nbytes: 0, + flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP, + }, + }, + } + } else if revents.contains(nix::poll::EventFlags::POLLERR) { + host::__wasi_event_t { + userdata: fd_event.userdata, + type_: fd_event.type_, + error: wasm32::__WASI_EIO, + u: host::__wasi_event_t___wasi_event_u { + fd_readwrite: + host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { + nbytes: 0, + flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP, + }, + }, + } + } else if revents.contains(nix::poll::EventFlags::POLLHUP) { + host::__wasi_event_t { + userdata: fd_event.userdata, + type_: fd_event.type_, + error: wasm32::__WASI_ESUCCESS, + u: host::__wasi_event_t___wasi_event_u { + fd_readwrite: + host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { + nbytes: 0, + flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP, + }, + }, + } + } else if revents.contains(nix::poll::EventFlags::POLLIN) + | revents.contains(nix::poll::EventFlags::POLLOUT) + { + host::__wasi_event_t { + userdata: fd_event.userdata, + type_: fd_event.type_, + error: wasm32::__WASI_ESUCCESS, + u: host::__wasi_event_t___wasi_event_u { + fd_readwrite: + host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { + nbytes: nbytes as host::__wasi_filesize_t, + flags: 0, + }, + }, + } + } else { + continue; + }; + *output_slice_cur.next().unwrap() = enc_event(output_event); + revents_count += 1; + } + if let Err(e) = unsafe { enc_pointee(vmctx, nevents, revents_count) } { + return enc_errno(e); + } + wasm32::__WASI_ESUCCESS +} + +pub fn wasi_poll_oneoff( + vmctx: &mut Vmctx, + input: wasm32::uintptr_t, + output: wasm32::uintptr_t, + nsubscriptions: wasm32::size_t, + nevents: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + if nsubscriptions as u64 > wasm32::__wasi_filesize_t::max_value() { + return wasm32::__WASI_EINVAL; + } + unsafe { enc_pointee(vmctx, nevents, 0) }.unwrap(); + let input_slice_ = + unsafe { dec_slice_of::(vmctx, input, nsubscriptions) } + .unwrap(); + let input_slice = unsafe { slice::from_raw_parts(input_slice_.0, input_slice_.1) }; + + let output_slice_ = + unsafe { dec_slice_of::(vmctx, output, nsubscriptions) }.unwrap(); + let output_slice = unsafe { slice::from_raw_parts_mut(output_slice_.0, output_slice_.1) }; + + let input: Vec<_> = input_slice.iter().map(|x| dec_subscription(x)).collect(); + + let timeout = input + .iter() + .filter_map(|event| match event { + Ok(event) if event.type_ == wasm32::__WASI_EVENTTYPE_CLOCK => Some(ClockEventData { + delay: wasi_clock_to_relative_ns_delay(unsafe { event.u.clock }) / 1_000_000, + userdata: event.userdata, + }), + _ => None, + }) + .min_by_key(|event| event.delay); + let fd_events: Vec<_> = input + .iter() + .filter_map(|event| match event { + Ok(event) + if event.type_ == wasm32::__WASI_EVENTTYPE_FD_READ + || event.type_ == wasm32::__WASI_EVENTTYPE_FD_WRITE => + { + Some(FdEventData { + fd: unsafe { event.u.fd_readwrite.fd } as c_int, + type_: event.type_, + userdata: event.userdata, + }) + } + _ => None, + }) + .collect(); + if fd_events.is_empty() && timeout.is_none() { + return wasm32::__WASI_ESUCCESS; + } + let mut poll_fds: Vec<_> = fd_events + .iter() + .map(|event| { + let mut flags = nix::poll::EventFlags::empty(); + match event.type_ { + wasm32::__WASI_EVENTTYPE_FD_READ => flags.insert(nix::poll::EventFlags::POLLIN), + wasm32::__WASI_EVENTTYPE_FD_WRITE => flags.insert(nix::poll::EventFlags::POLLOUT), + // An event on a file descriptor can currently only be of type FD_READ or FD_WRITE + // Nothing else has been defined in the specification, and these are also the only two + // events we filtered before. If we get something else here, the code has a serious bug. + _ => unreachable!(), + }; + nix::poll::PollFd::new(event.fd, flags) + }) + .collect(); + let timeout = timeout.map(|ClockEventData { delay, userdata }| ClockEventData { + delay: cmp::min(delay, c_int::max_value() as u128), + userdata, + }); + let poll_timeout = timeout.map(|timeout| timeout.delay as c_int).unwrap_or(-1); + let ready = loop { + match nix::poll::poll(&mut poll_fds, poll_timeout) { + Err(_) => { + if nix::errno::Errno::last() == nix::errno::Errno::EINTR { + continue; + } + return wasm32::errno_from_nix(nix::errno::Errno::last()); + } + Ok(ready) => break ready as usize, + } + }; + if ready == 0 { + return __wasi_poll_oneoff_handle_timeout_event(vmctx, output_slice, nevents, timeout); + } + let events = fd_events.iter().zip(poll_fds.iter()).take(ready); + __wasi_poll_oneoff_handle_fd_event(vmctx, output_slice, nevents, events) +} diff --git a/lucet-wasi/src/hostcalls/mod.rs b/lucet-wasi/src/hostcalls/mod.rs new file mode 100644 index 000000000..450468176 --- /dev/null +++ b/lucet-wasi/src/hostcalls/mod.rs @@ -0,0 +1,447 @@ +//! Hostcalls that implement +//! [WASI](https://github.com/CraneStation/wasmtime-wasi/blob/wasi/docs/WASI-overview.md). +//! +//! This code borrows heavily from [wasmtime-wasi](https://github.com/CraneStation/wasmtime-wasi), +//! which in turn borrows from cloudabi-utils. See `LICENSE.wasmtime-wasi` for license information. + +#![allow(non_camel_case_types)] +#![allow(unused_unsafe)] + +mod fs; +mod fs_helpers; +mod misc; + +use crate::wasm32; + +use fs::*; +use lucet_runtime::lucet_hostcalls; +use misc::*; + +lucet_hostcalls! { + #[no_mangle] pub unsafe extern "C" + fn __wasi_proc_exit(&mut vmctx, rval: wasm32::__wasi_exitcode_t,) -> ! { + wasi_proc_exit(vmctx, rval) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_args_get( + &mut vmctx, + argv_ptr: wasm32::uintptr_t, + argv_buf: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + wasi_args_get(vmctx, argv_ptr, argv_buf) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_args_sizes_get(&mut vmctx, + argc_ptr: wasm32::uintptr_t, + argv_buf_size_ptr: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + wasi_args_sizes_get(vmctx, argc_ptr, argv_buf_size_ptr) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_sched_yield(&mut vmctx,) -> wasm32::__wasi_errno_t { + wasi_sched_yield(vmctx) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_clock_res_get( + &mut vmctx, + clock_id: wasm32::__wasi_clockid_t, + resolution_ptr: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + wasi_clock_res_get(vmctx, clock_id, resolution_ptr) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_clock_time_get( + &mut vmctx, + clock_id: wasm32::__wasi_clockid_t, + precision: wasm32::__wasi_timestamp_t, + time_ptr: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + wasi_clock_time_get(vmctx, clock_id, precision, time_ptr) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_environ_get( + &mut vmctx, + environ_ptr: wasm32::uintptr_t, + environ_buf: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + wasi_environ_get(vmctx, environ_ptr, environ_buf) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_environ_sizes_get( + &mut vmctx, + environ_count_ptr: wasm32::uintptr_t, + environ_size_ptr: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + wasi_environ_sizes_get(vmctx, environ_count_ptr, environ_size_ptr) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_fd_close( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + ) -> wasm32::__wasi_errno_t { + wasi_fd_close(vmctx, fd) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_fd_fdstat_get( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + fdstat_ptr: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + wasi_fd_fdstat_get(vmctx, fd, fdstat_ptr) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_fd_fdstat_set_flags( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + fdflags: wasm32::__wasi_fdflags_t, + ) -> wasm32::__wasi_errno_t { + wasi_fd_fdstat_set_flags(vmctx, fd, fdflags) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_fd_tell(&mut vmctx, + fd: wasm32::__wasi_fd_t, + offset: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + wasi_fd_tell(vmctx, fd, offset) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_fd_seek(&mut vmctx, + fd: wasm32::__wasi_fd_t, + offset: wasm32::__wasi_filedelta_t, + whence: wasm32::__wasi_whence_t, + newoffset: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + wasi_fd_seek(vmctx, fd, offset, whence, newoffset) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_fd_prestat_get( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + prestat_ptr: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + wasi_fd_prestat_get(vmctx, fd, prestat_ptr) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_fd_prestat_dir_name( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, + ) -> wasm32::__wasi_errno_t { + wasi_fd_prestat_dir_name(vmctx, fd, path_ptr, path_len) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_fd_read( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + iovs_ptr: wasm32::uintptr_t, + iovs_len: wasm32::size_t, + nread: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + wasi_fd_read(vmctx, fd, iovs_ptr, iovs_len, nread) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_fd_write( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + iovs_ptr: wasm32::uintptr_t, + iovs_len: wasm32::size_t, + nwritten: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + wasi_fd_write(vmctx, fd, iovs_ptr, iovs_len, nwritten) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_path_open( + &mut vmctx, + dirfd: wasm32::__wasi_fd_t, + dirflags: wasm32::__wasi_lookupflags_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, + oflags: wasm32::__wasi_oflags_t, + fs_rights_base: wasm32::__wasi_rights_t, + fs_rights_inheriting: wasm32::__wasi_rights_t, + fs_flags: wasm32::__wasi_fdflags_t, + fd_out_ptr: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + wasi_path_open(vmctx, dirfd, dirflags, path_ptr, path_len, + oflags, fs_rights_base, fs_rights_inheriting, fs_flags, + fd_out_ptr) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_random_get( + &mut vmctx, + buf_ptr: wasm32::uintptr_t, + buf_len: wasm32::size_t, + ) -> wasm32::__wasi_errno_t { + wasi_random_get(vmctx, buf_ptr, buf_len) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_poll_oneoff( + &mut vmctx, + input: wasm32::uintptr_t, + output: wasm32::uintptr_t, + nsubscriptions: wasm32::size_t, + nevents: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + wasi_poll_oneoff(vmctx, input, output, nsubscriptions, nevents) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_fd_filestat_get( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + filestat_ptr: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + wasi_fd_filestat_get(vmctx, fd, filestat_ptr) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_path_filestat_get( + &mut vmctx, + dirfd: wasm32::__wasi_fd_t, + dirflags: wasm32::__wasi_lookupflags_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, + filestat_ptr: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + wasi_path_filestat_get(vmctx, dirfd, dirflags, path_ptr, + path_len, filestat_ptr) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_path_create_directory( + &mut vmctx, + dirfd: wasm32::__wasi_fd_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, + ) -> wasm32::__wasi_errno_t { + wasi_path_create_directory(vmctx, dirfd, path_ptr, path_len) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_path_unlink_file( + &mut vmctx, + dirfd: wasm32::__wasi_fd_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, + ) -> wasm32::__wasi_errno_t { + wasi_path_unlink_file(vmctx, dirfd, path_ptr, path_len) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_fd_allocate( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + offset: wasm32::__wasi_filesize_t, + len: wasm32::__wasi_filesize_t, + ) -> wasm32::__wasi_errno_t { + wasi_fd_allocate(vmctx, fd, offset, len) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_fd_advise( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + offset: wasm32::__wasi_filesize_t, + len: wasm32::__wasi_filesize_t, + advice: wasm32::__wasi_advice_t, + ) -> wasm32::__wasi_errno_t { + wasi_fd_advise(vmctx, fd, offset, len, advice) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_fd_datasync( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + ) -> wasm32::__wasi_errno_t { + wasi_fd_datasync(vmctx, fd) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_fd_sync( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + ) -> wasm32::__wasi_errno_t { + wasi_fd_sync(vmctx, fd) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_fd_fdstat_set_rights( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + fs_rights_base: wasm32::__wasi_rights_t, + fs_rights_inheriting: wasm32::__wasi_rights_t, + ) -> wasm32::__wasi_errno_t { + wasi_fd_fdstat_set_rights(vmctx, fd, fs_rights_base, fs_rights_inheriting) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_fd_filestat_set_size( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + st_size: wasm32::__wasi_filesize_t, + ) -> wasm32::__wasi_errno_t { + wasi_fd_filestat_set_size(vmctx, fd, st_size) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_fd_filestat_set_times( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + st_atim: wasm32::__wasi_timestamp_t, + st_mtim: wasm32::__wasi_timestamp_t, + fst_flags: wasm32::__wasi_fstflags_t, + ) -> wasm32::__wasi_errno_t { + wasi_fd_filestat_set_times(vmctx, fd, st_atim, st_mtim, fst_flags) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_fd_pread( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + iovs_ptr: wasm32::uintptr_t, + iovs_len: wasm32::size_t, + offset: wasm32::__wasi_filesize_t, + nread: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + wasi_fd_pread(vmctx, fd, iovs_ptr, iovs_len, offset, nread) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_fd_pwrite( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + iovs_ptr: wasm32::uintptr_t, + iovs_len: wasm32::size_t, + offset: wasm32::__wasi_filesize_t, + nwritten: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + wasi_fd_pwrite(vmctx, fd, iovs_ptr, iovs_len, offset, nwritten) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_fd_readdir( + &mut vmctx, + fd: wasm32::__wasi_fd_t, + buf: wasm32::uintptr_t, + buf_len: wasm32::size_t, + cookie: wasm32::__wasi_dircookie_t, + bufused: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + wasi_fd_readdir(vmctx, fd, buf, buf_len, cookie, bufused) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_fd_renumber( + &mut vmctx, + from: wasm32::__wasi_fd_t, + to: wasm32::__wasi_fd_t, + ) -> wasm32::__wasi_errno_t { + wasi_fd_renumber(vmctx, from, to) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_path_filestat_set_times( + &mut vmctx, + dirfd: wasm32::__wasi_fd_t, + dirflags: wasm32::__wasi_lookupflags_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, + st_atim: wasm32::__wasi_timestamp_t, + st_mtim: wasm32::__wasi_timestamp_t, + fst_flags: wasm32::__wasi_fstflags_t, + ) -> wasm32::__wasi_errno_t { + wasi_path_filestat_set_times(vmctx, dirfd, dirflags, path_ptr, path_len, st_atim, st_mtim, fst_flags) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_path_link( + &mut vmctx, + old_fd: wasm32::__wasi_fd_t, + old_flags: wasm32::__wasi_lookupflags_t, + old_path_ptr: wasm32::uintptr_t, + old_path_len: wasm32::size_t, + new_fd: wasm32::__wasi_fd_t, + new_path_ptr: wasm32::uintptr_t, + new_path_len: wasm32::size_t, + ) -> wasm32::__wasi_errno_t { + wasi_path_link(vmctx, old_fd, old_flags, old_path_ptr, old_path_len, + new_fd, new_path_ptr, new_path_len) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_path_readlink( + &mut vmctx, + dirfd: wasm32::__wasi_fd_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, + buf_ptr: wasm32::uintptr_t, + buf_len: wasm32::size_t, + bufused: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + wasi_path_readlink(vmctx, dirfd, path_ptr, path_len, buf_ptr, buf_len, bufused) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_path_remove_directory( + &mut vmctx, + dirfd: wasm32::__wasi_fd_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, + ) -> wasm32::__wasi_errno_t { + wasi_path_remove_directory(vmctx, dirfd, path_ptr, path_len) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_path_rename( + &mut vmctx, + old_dirfd: wasm32::__wasi_fd_t, + old_path_ptr: wasm32::uintptr_t, + old_path_len: wasm32::size_t, + new_dirfd: wasm32::__wasi_fd_t, + new_path_ptr: wasm32::uintptr_t, + new_path_len: wasm32::size_t, + ) -> wasm32::__wasi_errno_t { + wasi_path_rename(vmctx, old_dirfd, old_path_ptr, old_path_len, + new_dirfd, new_path_ptr, new_path_len) + } + + #[no_mangle] pub unsafe extern "C" + fn __wasi_path_symlink( + &mut vmctx, + old_path_ptr: wasm32::uintptr_t, + old_path_len: wasm32::size_t, + dir_fd: wasm32::__wasi_fd_t, + new_path_ptr: wasm32::uintptr_t, + new_path_len: wasm32::size_t, + ) -> wasm32::__wasi_errno_t { + wasi_path_symlink(vmctx, old_path_ptr, old_path_len, + dir_fd, new_path_ptr, new_path_len) + } +} + +#[doc(hidden)] +pub fn ensure_linked() { + unsafe { + std::ptr::read_volatile(__wasi_proc_exit as *const extern "C" fn()); + } +} diff --git a/lucet-wasi/src/memory.rs b/lucet-wasi/src/memory.rs index 2ae54ac59..e231f64dc 100644 --- a/lucet-wasi/src/memory.rs +++ b/lucet-wasi/src/memory.rs @@ -161,6 +161,27 @@ pub unsafe fn dec_ciovec_slice( slice.iter().map(|iov| dec_ciovec(vmctx, iov)).collect() } +pub unsafe fn dec_iovec( + vmctx: &Vmctx, + iovec: &wasm32::__wasi_iovec_t, +) -> Result { + let len = dec_usize(iovec.buf_len); + Ok(host::__wasi_iovec_t { + buf: dec_ptr(vmctx, iovec.buf, len)? as *mut host::void, + buf_len: len, + }) +} + +pub unsafe fn dec_iovec_slice( + vmctx: &Vmctx, + ptr: wasm32::uintptr_t, + len: wasm32::size_t, +) -> Result, host::__wasi_errno_t> { + let slice = dec_slice_of::(vmctx, ptr, len)?; + let slice = slice::from_raw_parts(slice.0, slice.1); + slice.iter().map(|iov| dec_iovec(vmctx, iov)).collect() +} + dec_enc_scalar!( __wasi_clockid_t, dec_clockid, @@ -357,7 +378,7 @@ pub unsafe fn dec_prestat_byref( pub fn enc_prestat( prestat: host::__wasi_prestat_t, ) -> Result { - match prestat.pr_type as u32 { + match u32::from(prestat.pr_type) { host::__WASI_PREOPENTYPE_DIR => { let u = wasm32::__wasi_prestat_t___wasi_prestat_u { dir: wasm32::__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t { @@ -389,6 +410,7 @@ dec_enc_scalar!( enc_rights, enc_rights_byref ); + dec_enc_scalar!( __wasi_timestamp_t, dec_timestamp, @@ -397,6 +419,14 @@ dec_enc_scalar!( enc_timestamp_byref ); +pub fn dec_u32(x: u32) -> u32 { + u32::from_le(x) +} + +pub fn enc_u32(x: u32) -> u32 { + x.to_le() +} + pub fn dec_usize(size: wasm32::size_t) -> usize { cast::usize(u32::from_le(size)) } @@ -497,3 +527,57 @@ pub fn enc_event(event: host::__wasi_event_t) -> wasm32::__wasi_event_t { __bindgen_padding_0: 0, } } + +dec_enc_scalar!( + __wasi_advice_t, + dec_advice, + dec_advice_byref, + enc_advice, + enc_advice_byref +); + +dec_enc_scalar!( + __wasi_fstflags_t, + dec_fstflags, + dec_fstflags_byref, + enc_fstflags, + enc_fstflags_byref +); + +dec_enc_scalar!( + __wasi_dircookie_t, + dec_dircookie, + dec_dircookie_byref, + enc_dircookie, + enc_dircookie_byref +); + +#[cfg(target_os = "linux")] +pub fn dirent_from_host( + host_entry: &nix::libc::dirent, +) -> Result { + let mut entry = unsafe { std::mem::zeroed::() }; + let d_namlen = unsafe { std::ffi::CStr::from_ptr(host_entry.d_name.as_ptr()) } + .to_bytes() + .len(); + if d_namlen > u32::max_value() as usize { + return Err(host::__WASI_EIO as host::__wasi_errno_t); + } + entry.d_ino = enc_inode(host_entry.d_ino); + entry.d_next = enc_dircookie(host_entry.d_off as u64); + entry.d_namlen = enc_u32(d_namlen as u32); + entry.d_type = enc_filetype(host_entry.d_type); + Ok(entry) +} + +#[cfg(not(target_os = "linux"))] +pub fn dirent_from_host( + host_entry: &nix::libc::dirent, +) -> Result { + let mut entry = unsafe { std::mem::zeroed::() }; + entry.d_ino = enc_inode(host_entry.d_ino); + entry.d_next = enc_dircookie(host_entry.d_seekoff); + entry.d_namlen = enc_u32(u32::from(host_entry.d_namlen)); + entry.d_type = enc_filetype(host_entry.d_type); + Ok(entry) +} diff --git a/lucet-wasi/tests/guests/fs.c b/lucet-wasi/tests/guests/fs.c new file mode 100644 index 000000000..3d30ae0f0 --- /dev/null +++ b/lucet-wasi/tests/guests/fs.c @@ -0,0 +1,149 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(void) +{ + struct timespec times[2]; + struct dirent * entry; + char buf[4]; + DIR * dir; + FILE * fp; + struct stat st; + off_t offset; + int fd; + int res; + + fd = open("/sandbox/testfile", O_CREAT | O_RDWR, 0644); + assert(fd != -1); + + res = posix_fallocate(fd, 0, 10000); + assert(res == 0); + + res = fstat(fd, &st); + assert(res == 0); + assert(st.st_size == 10000); + + res = ftruncate(fd, 1000); + res = fstat(fd, &st); + assert(res == 0); + assert(st.st_size == 1000); + assert(st.st_nlink == 1); + res = posix_fadvise(fd, 0, 1000, POSIX_FADV_RANDOM); + assert(res == 0); + + res = (int) write(fd, "test", 4); + assert(res == 4); + + offset = lseek(fd, 0, SEEK_CUR); + assert(offset == 4); + offset = lseek(fd, 0, SEEK_END); + assert(offset == 1000); + offset = lseek(fd, 0, SEEK_SET); + assert(offset == 0); + + res = fdatasync(fd); + assert(res == 0); + + res = fsync(fd); + assert(res == 0); + + times[0] = (struct timespec){ .tv_sec = 1557403800, .tv_nsec = 0 }; + times[1] = (struct timespec){ .tv_sec = 1557403800, .tv_nsec = 0 }; + + res = futimens(fd, times); + assert(res == 0); + + res = pread(fd, buf, sizeof buf, 2); + assert(res == 4); + assert(buf[1] == 't'); + + res = pwrite(fd, "T", 1, 3); + assert(res == 1); + + res = pread(fd, buf, sizeof buf, 2); + assert(res == 4); + assert(buf[1] == 'T'); + + res = close(fd); + assert(res == 0); + + dir = opendir("/nonexistent"); + assert(dir == NULL); + + res = mkdir("/sandbox/test", 0755); + assert(res == 0); + + res = mkdir("/sandbox/test", 0755); + assert(res == -1); + assert(errno == EEXIST); + + res = rmdir("/sandbox/test"); + assert(res == 0); + + res = rmdir("/sandbox/test"); + assert(res == -1); + + res = rename("/sandbox/testfile", "/sandbox/testfile2"); + assert(res == 0); + + res = unlink("/sandbox/testfile"); + assert(res == -1); + + res = access("/sandbox/testfile2", R_OK); + assert(res == 0); + + res = link("/sandbox/testfile2", "/sandbox/testfile-link"); + assert(res == 0); + + res = access("/sandbox/testfile-link", R_OK); + assert(res == 0); + + res = symlink("/sandbox/testfile-link", "/sandbox/testfile-symlink"); + assert(res == 0); + + res = symlink("/sandbox/testfile2", "/sandbox/testfile-symlink"); + assert(res == -1); + + res = sched_yield(); + assert(res == 0); + + fd = open("/sandbox/testfile2", O_RDONLY); + assert(fd != -1); + + fp = fdopen(fd, "r"); + assert(fp != NULL); + + res = fgetc(fp); + assert(res == 't'); + + res = fclose(fp); + assert(res == 0); + + dir = opendir("/sandbox"); + assert(dir != NULL); + + res = 0; + while ((entry = readdir(dir)) != NULL) { + if (entry->d_name[0] == '.') { + res += 1000; + } else { + res++; + } + } + assert(res == 2003); + + res = closedir(dir); + assert(res == 0); + + return 0; +} diff --git a/lucet-wasi/tests/tests.rs b/lucet-wasi/tests/tests.rs index f46afe020..f5176cf27 100644 --- a/lucet-wasi/tests/tests.rs +++ b/lucet-wasi/tests/tests.rs @@ -378,3 +378,18 @@ fn stat() { let exitcode = run("stat.c", ctx).unwrap(); assert_eq!(exitcode, 0); } + +#[test] +fn fs() { + let tmpdir = TempDir::new().unwrap(); + let preopen_host_path = tmpdir.path().join("preopen"); + std::fs::create_dir(&preopen_host_path).unwrap(); + let preopen_dir = File::open(&preopen_host_path).unwrap(); + let ctx = WasiCtxBuilder::new() + .args(&["stat"]) + .preopened_dir(preopen_dir, "/sandbox") + .build() + .expect("can build WasiCtx"); + let exitcode = run("fs.c", ctx).unwrap(); + assert_eq!(exitcode, 0); +} From a68377f9b2c886bc727488afc3f3e14ebd5bc9fc Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 22 May 2019 17:06:20 +0200 Subject: [PATCH 136/512] WASI: Don't grant __WASI_RIGHT_FD_FILESTAT_SET_SIZE for directories RIGHTS_DIRECTORY_BASE should not include __WASI_RIGHT_FD_FILESTAT_SET_SIZE, because that would imply the ability to set the size of a directory. Via @sunfishcode --- lucet-wasi/src/host.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/lucet-wasi/src/host.rs b/lucet-wasi/src/host.rs index b1ce783ef..e74227373 100644 --- a/lucet-wasi/src/host.rs +++ b/lucet-wasi/src/host.rs @@ -292,7 +292,6 @@ pub const RIGHTS_DIRECTORY_BASE: __wasi_rights_t = (__WASI_RIGHT_FD_FDSTAT_SET_F | __WASI_RIGHT_PATH_FILESTAT_SET_SIZE | __WASI_RIGHT_PATH_FILESTAT_SET_TIMES | __WASI_RIGHT_FD_FILESTAT_GET - | __WASI_RIGHT_FD_FILESTAT_SET_SIZE | __WASI_RIGHT_FD_FILESTAT_SET_TIMES | __WASI_RIGHT_PATH_SYMLINK | __WASI_RIGHT_PATH_UNLINK_FILE From ee96fe16b46cea826b3719671008c9ad2264441c Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 22 May 2019 17:10:18 +0200 Subject: [PATCH 137/512] WASI: Handle set-size rights correctly when truncating a file. If a path_open call is requesting __WASI_RIGHT_FD_FILESTAT_SET_SIZE, interpret that as a request for write privleges. If it is requesting O_TRUNC, require __WASI_RIGHT_PATH_FILESTAT_SET_SIZE, since this is a path operation rather than a FD operation. via @sunfishcode --- lucet-wasi/src/hostcalls/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lucet-wasi/src/hostcalls/fs.rs b/lucet-wasi/src/hostcalls/fs.rs index 65b60fd90..d17180360 100644 --- a/lucet-wasi/src/hostcalls/fs.rs +++ b/lucet-wasi/src/hostcalls/fs.rs @@ -347,7 +347,7 @@ pub fn wasi_path_open( & ((host::__WASI_RIGHT_FD_DATASYNC | host::__WASI_RIGHT_FD_WRITE | host::__WASI_RIGHT_FD_ALLOCATE - | host::__WASI_RIGHT_PATH_FILESTAT_SET_SIZE) as host::__wasi_rights_t) + | host::__WASI_RIGHT_FD_FILESTAT_SET_SIZE) as host::__wasi_rights_t) != 0; let mut nix_all_oflags = if read && write { @@ -372,7 +372,7 @@ pub fn wasi_path_open( needed_base |= host::__WASI_RIGHT_PATH_CREATE_FILE as host::__wasi_rights_t; } if nix_all_oflags.contains(OFlag::O_TRUNC) { - needed_inheriting |= host::__WASI_RIGHT_PATH_FILESTAT_SET_SIZE as host::__wasi_rights_t; + needed_base |= host::__WASI_RIGHT_PATH_FILESTAT_SET_SIZE as host::__wasi_rights_t; } // convert file descriptor flags From fc76ca0b9f8c051448a588035642fe005746bf07 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 22 May 2019 17:11:57 +0200 Subject: [PATCH 138/512] WASI: Change path_open to not create files with execute privleges. WASI currently lacks the ability to specify the full UNIX access control information when creating files and directories, so for now just avoid creating executable files and rely on the umask. via @sunfishcode --- lucet-wasi/src/hostcalls/fs.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lucet-wasi/src/hostcalls/fs.rs b/lucet-wasi/src/hostcalls/fs.rs index d17180360..04e4d4d70 100644 --- a/lucet-wasi/src/hostcalls/fs.rs +++ b/lucet-wasi/src/hostcalls/fs.rs @@ -406,11 +406,14 @@ pub fn wasi_path_open( Err(e) => return enc_errno(e), }; + // Call openat. Use mode 0o666 so that we follow whatever the user's + // umask is, but don't set the executable flag, because it isn't yet + // meaningful for WASI programs to create executable files. let new_fd = match openat( dir, path.as_os_str(), nix_all_oflags, - Mode::from_bits_truncate(0o777), + Mode::from_bits_truncate(0o666), ) { Ok(fd) => fd, Err(e) => { From 91f1fd04a6aeecdd9f5c8dec006dfac21bb15f39 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 22 May 2019 17:21:26 +0200 Subject: [PATCH 139/512] WASI: Fix symlink resolution on Linux and FreeBSD. Linux's open returns ENOTDIR when used with O_DIRECTORY|O_NOFOLLOW and the path is a symlink. Update the code to expect this. FreeBSD's open returns EMLINK instead of ELOOP when using O_NOFOLLOW on symlink. Update the code to expect this. via @sunfishcode --- lucet-wasi/src/hostcalls/fs.rs | 17 +++++++++++++++++ lucet-wasi/src/hostcalls/fs_helpers.rs | 5 ++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lucet-wasi/src/hostcalls/fs.rs b/lucet-wasi/src/hostcalls/fs.rs index 04e4d4d70..5bc133cbb 100644 --- a/lucet-wasi/src/hostcalls/fs.rs +++ b/lucet-wasi/src/hostcalls/fs.rs @@ -430,6 +430,23 @@ pub fn wasi_path_open( return wasm32::__WASI_ENXIO; } } + // Linux returns ENOTDIR instead of ELOOP when using O_NOFOLLOW|O_DIRECTORY + // on a symlink. + Some(Errno::ENOTDIR) + if !(nix_all_oflags & (OFlag::O_NOFOLLOW | OFlag::O_DIRECTORY)).is_empty() => + { + if let Ok(stat) = fstatat(dir, path.as_os_str(), AtFlags::AT_SYMLINK_NOFOLLOW) { + if SFlag::from_bits_truncate(stat.st_mode).contains(SFlag::S_IFLNK) { + return wasm32::__WASI_ELOOP; + } + } + return wasm32::__WASI_ENOTDIR; + } + // FreeBSD returns EMLINK instead of ELOOP when using O_NOFOLLOW on + // a symlink. + Some(Errno::EMLINK) if !(nix_all_oflags & OFlag::O_NOFOLLOW).is_empty() => { + return wasm32::__WASI_ELOOP; + } Some(e) => return wasm32::errno_from_nix(e), None => return wasm32::__WASI_ENOSYS, } diff --git a/lucet-wasi/src/hostcalls/fs_helpers.rs b/lucet-wasi/src/hostcalls/fs_helpers.rs index c949a1d67..3c6756013 100644 --- a/lucet-wasi/src/hostcalls/fs_helpers.rs +++ b/lucet-wasi/src/hostcalls/fs_helpers.rs @@ -173,8 +173,11 @@ pub fn path_get>( continue; } Err(e) + // Check to see if it was a symlink. Linux indicates + // this with ENOTDIR because of the O_DIRECTORY flag. if e.as_errno() == Some(Errno::ELOOP) - || e.as_errno() == Some(Errno::EMLINK) => + || e.as_errno() == Some(Errno::EMLINK) + || e.as_errno() == Some(Errno::ENOTDIR) => { // attempt symlink expansion match readlinkat( From e41a4c3deb73242b927a8a5660e28f5fc8d2dcd9 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 22 May 2019 17:25:00 +0200 Subject: [PATCH 140/512] WASI: Fix fd_fdstat_set_rights to set the rights. After checking that no new rights are being added, actually set the rights, which may be a subset of the original rights. via @sunfishcode --- lucet-wasi/src/hostcalls/fs.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lucet-wasi/src/hostcalls/fs.rs b/lucet-wasi/src/hostcalls/fs.rs index 5bc133cbb..af7e78042 100644 --- a/lucet-wasi/src/hostcalls/fs.rs +++ b/lucet-wasi/src/hostcalls/fs.rs @@ -766,8 +766,8 @@ pub fn wasi_fd_fdstat_set_rights( fs_rights_inheriting: wasm32::__wasi_rights_t, ) -> wasm32::__wasi_errno_t { let host_fd = dec_fd(fd); - let ctx = vmctx.get_embed_ctx_mut::(); - let fe = match ctx.fds.get(&host_fd) { + let mut ctx = vmctx.get_embed_ctx_mut::(); + let fe = match ctx.fds.get_mut(&host_fd) { Some(fe) => fe, None => return wasm32::__WASI_EBADF, }; @@ -776,6 +776,8 @@ pub fn wasi_fd_fdstat_set_rights( { return wasm32::__WASI_ENOTCAPABLE; } + fe.rights_base = fs_rights_base; + fe.rights_inheriting = fs_rights_inheriting; wasm32::__WASI_ESUCCESS } From 54baa4c38c2a0a17d91039dbd30c1eed6bab81f7 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 22 May 2019 17:27:36 +0200 Subject: [PATCH 141/512] WASI: don't call get_embed_ctx_mut() if we don't need a mutable ref --- lucet-wasi/src/hostcalls/fs.rs | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/lucet-wasi/src/hostcalls/fs.rs b/lucet-wasi/src/hostcalls/fs.rs index af7e78042..1c0cefb11 100644 --- a/lucet-wasi/src/hostcalls/fs.rs +++ b/lucet-wasi/src/hostcalls/fs.rs @@ -44,7 +44,7 @@ pub fn wasi_fd_fdstat_get( Err(e) => return enc_errno(e), }; - let ctx = vmctx.get_embed_ctx_mut::(); + let ctx = vmctx.get_embed_ctx::(); let errno = if let Some(fe) = ctx.fds.get(&host_fd) { host_fdstat.fs_filetype = fe.fd_object.ty; host_fdstat.fs_rights_base = fe.rights_base; @@ -78,8 +78,7 @@ pub fn wasi_fd_fdstat_set_flags( let host_fdflags = dec_fdflags(fdflags); let nix_flags = host::nix_from_fdflags(host_fdflags); - let ctx = vmctx.get_embed_ctx_mut::(); - + let ctx = vmctx.get_embed_ctx::(); if let Some(fe) = ctx.fds.get(&host_fd) { match nix::fcntl::fcntl(fe.fd_object.rawfd, nix::fcntl::F_SETFL(nix_flags)) { Ok(_) => wasm32::__WASI_ESUCCESS, @@ -95,7 +94,7 @@ pub fn wasi_fd_tell( fd: wasm32::__wasi_fd_t, offset: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - let ctx = vmctx.get_embed_ctx_mut::(); + let ctx = vmctx.get_embed_ctx::(); let fd = dec_fd(fd); let host_offset = { @@ -125,7 +124,7 @@ pub fn wasi_fd_seek( whence: wasm32::__wasi_whence_t, newoffset: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - let ctx = vmctx.get_embed_ctx_mut::(); + let ctx = vmctx.get_embed_ctx::(); let fd = dec_fd(fd); let offset = dec_filedelta(offset); let whence = dec_whence(whence); @@ -488,7 +487,7 @@ pub fn wasi_fd_filestat_get( use nix::sys::stat::fstat; let host_fd = dec_fd(fd); - let ctx = vmctx.get_embed_ctx_mut::(); + let ctx = vmctx.get_embed_ctx::(); let rights = host::__WASI_RIGHT_FD_FILESTAT_GET; match ctx.get_fd_entry(host_fd, rights.into(), 0) { @@ -613,7 +612,7 @@ pub fn wasi_fd_allocate( len: wasm32::__wasi_filesize_t, ) -> wasm32::__wasi_errno_t { let host_fd = dec_fd(fd); - let ctx = vmctx.get_embed_ctx_mut::(); + let ctx = vmctx.get_embed_ctx::(); let rights = host::__WASI_RIGHT_FD_ALLOCATE; let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) { Ok(fe) => fe, @@ -667,7 +666,7 @@ pub fn wasi_fd_advise( advice: wasm32::__wasi_advice_t, ) -> wasm32::__wasi_errno_t { let host_fd = dec_fd(fd); - let ctx = vmctx.get_embed_ctx_mut::(); + let ctx = vmctx.get_embed_ctx::(); let rights = host::__WASI_RIGHT_FD_ADVISE; let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) { Ok(fe) => fe, @@ -720,7 +719,7 @@ pub fn wasi_fd_advise( pub fn wasi_fd_datasync(vmctx: &mut Vmctx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t { let host_fd = dec_fd(fd); - let ctx = vmctx.get_embed_ctx_mut::(); + let ctx = vmctx.get_embed_ctx::(); let rights = host::__WASI_RIGHT_FD_DATASYNC; let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) { Ok(fe) => fe, @@ -746,7 +745,7 @@ pub fn wasi_fd_datasync(vmctx: &mut Vmctx, fd: wasm32::__wasi_fd_t) -> wasm32::_ pub fn wasi_fd_sync(vmctx: &mut Vmctx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t { let host_fd = dec_fd(fd); - let ctx = vmctx.get_embed_ctx_mut::(); + let ctx = vmctx.get_embed_ctx::(); let rights = host::__WASI_RIGHT_FD_SYNC; let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) { Ok(fe) => fe, @@ -789,7 +788,7 @@ pub fn wasi_fd_filestat_set_size( use nix::unistd::ftruncate; let host_fd = dec_fd(fd); - let ctx = vmctx.get_embed_ctx_mut::(); + let ctx = vmctx.get_embed_ctx::(); let rights = host::__WASI_RIGHT_FD_FILESTAT_SET_SIZE; let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) { Ok(fe) => fe, @@ -815,7 +814,7 @@ pub fn wasi_fd_filestat_set_times( use nix::sys::time::{TimeSpec, TimeValLike}; let host_fd = dec_fd(fd); - let ctx = vmctx.get_embed_ctx_mut::(); + let ctx = vmctx.get_embed_ctx::(); let rights = host::__WASI_RIGHT_FD_FILESTAT_SET_TIMES; let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) { Ok(fe) => fe, @@ -950,7 +949,7 @@ pub fn wasi_fd_pread( Ok(iovs) => iovs, Err(e) => return enc_errno(e), }; - let ctx = vmctx.get_embed_ctx_mut::(); + let ctx = vmctx.get_embed_ctx::(); let rights = host::__WASI_RIGHT_FD_READ; let fe = match ctx.get_fd_entry(fd, rights.into(), 0) { Ok(fe) => fe, @@ -1000,7 +999,7 @@ pub fn wasi_fd_pwrite( Ok(iovs) => iovs, Err(e) => return enc_errno(e), }; - let ctx = vmctx.get_embed_ctx_mut::(); + let ctx = vmctx.get_embed_ctx::(); let rights = host::__WASI_RIGHT_FD_READ; let fe = match ctx.get_fd_entry(fd, rights.into(), 0) { Ok(fe) => fe, @@ -1043,7 +1042,7 @@ pub fn wasi_fd_readdir( Err(e) => return enc_errno(e), }; let fd = dec_fd(fd); - let ctx = vmctx.get_embed_ctx_mut::(); + let ctx = vmctx.get_embed_ctx::(); let rights = host::__WASI_RIGHT_FD_READDIR; let fe = match ctx.get_fd_entry(fd, rights.into(), 0) { Ok(fe) => fe, From ad4c93f1c45cda0d751ce59193a4049a78423aa2 Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Thu, 23 May 2019 19:30:31 +0200 Subject: [PATCH 142/512] Update lucet-wasi documentation, and the main documentation (#182) * Update lucet-wasi documentation * Add instructions for compiling Lucet without Docker * Remove the reference to IRC/Discord until we have a definitive place * standardised -> standardized --- README.md | 132 +++++++++++++++++++++++++++++++++++++++++-- lucet-wasi/README.md | 73 +++++++----------------- 2 files changed, 148 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 80ce48dea..1a143dc27 100644 --- a/README.md +++ b/README.md @@ -189,19 +189,19 @@ used to manage the container. #### Setting up the environment -0) The Lucet repository uses git submodules. Make sure they are checked out +1) The Lucet repository uses git submodules. Make sure they are checked out by running `git submodule init && git submodule update`. -1) Install and run the `docker` service. We do not support `podman` at this +2) Install and run the `docker` service. We do not support `podman` at this time. On MacOS, [Docker for Mac](https://docs.docker.com/docker-for-mac/install/) is an option. -2) Once Docker is running, in a terminal, and at the root of the cloned +3) Once Docker is running, in a terminal, and at the root of the cloned repository, run: `source devenv_setenv.sh`. (This command requires the current shell to be `zsh`, `ksh` or `bash`). After a couple minutes, the Docker image is built and a new container is run. -3) Check that new commands are now available: +4) Check that new commands are now available: ```sh lucetc --help @@ -274,11 +274,133 @@ lucet-wasi hello.so environment. * `./devenv_start.sh` and `./devenv_stop.sh` start and stop the container. +### Compiling the toolchain without Docker + +Support for WebAssembly was introduced in LLVM 8, released in March 2019. + +As a result, Lucet can be compiled with an existing LLVM installation, provided +that it is up to date. + +We successfully compiled it on macOS, Arch Linux and Ubuntu 19.04 using standard +system packages. + +#### Compilation on Ubuntu 19.04 + +On recent Ubuntu versions, the `cmake`, `clang` and `lld` packages must be +installed: + +```sh +apt install curl ca-certificates clang lld + +update-alternatives --install /usr/bin/wasm-ld wasm-ld /usr/bin/wasm-ld-8 100 +``` + +In order to compile applications to WebAssembly, builtins need to be installed +as well: + +```sh +curl -sL https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-5/libclang_rt.builtins-wasm32-wasi-5.0.tar.gz | \ +sudo tar x -zf - -C /usr/lib/llvm-8/lib/clang/8.0.0 +``` + +Install the latest stable version of the Rust compiler: + +```sh +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +source $HOME/.cargo/env +``` + +Fetch, compile and install the WASI sysroot: + +```sh +git clone --recursive https://github.com/CraneStation/wasi-sysroot + +cd wasi-sysroot + +sudo make WASM_CC=clang-8 WASM_NM=llvm-nm-8 WASM_AR=llvm-ar-8 \ + INSTALL_DIR=/opt/wasi-sysroot install + +cd - && sudo rm -fr wasi-sysroot +``` + +Enter the Lucet git repository clone, and fetch/update the submodules: + +```sh +cd lucet + +git submodule update --init +``` + +Set relevant environment variables: + +```sh +export WASI_SYSROOT=/opt/wasi-sysroot +export CLANG_ROOT=/usr/lib/llvm-8/lib/clang/8.0.0 +export CLANG=clang-8 +``` + +Finally, compile the toolchain: + +```sh +cargo build --release +``` + +### Compilation on macOS + +Install `llvm`, `rust` and `cmake` using [Homebrew](https://brew.sh): + +```sh +brew install llvm rust cmake +``` + +In order to compile applications to WebAssembly, builtins need to be installed +as well: + +```sh +curl -sL https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-5/libclang_rt.builtins-wasm32-wasi-5.0.tar.gz | \ +sudo tar x -zf - -C /usr/local/opt/llvm/lib/clang/8* +``` + +Fetch, compile and install the WASI sysroot: + +```sh +git clone --recursive https://github.com/CraneStation/wasi-sysroot + +cd wasi-sysroot + +sudo env PATH=/usr/local/opt/llvm/bin:$PATH \ + make INSTALL_DIR=/opt/wasi-sysroot install + +cd - && sudo rm -fr wasi-sysroot +``` + +Enter the Lucet git repository clone, and fetch/update the submodules: + +```sh +cd lucet + +git submodule update --init +``` + +Set relevant environment variables: + +```sh +export WASI_SYSROOT=/opt/wasi-sysroot +export CLANG_ROOT="$(echo /usr/local/opt/llvm/lib/clang/8*)" +export CLANG=/usr/local/opt/llvm/bin/clang +``` + +Finally, compile the toolchain: + +```sh +cargo build --release +``` + ## Security The lucet project aims to provide support for secure execution of untrusted code. Security is achieved through a combination of lucet-supplied security controls and user-supplied security controls. See [SECURITY.md](SECURITY.md) for more information on the lucet security model. -### Reporting Security Issues +### Reporting Security Issues The Lucet project team welcomes security reports and is committed to providing prompt attention to security issues. Security issues should be reported diff --git a/lucet-wasi/README.md b/lucet-wasi/README.md index 0584db24a..a6f31894c 100644 --- a/lucet-wasi/README.md +++ b/lucet-wasi/README.md @@ -2,78 +2,47 @@ Experimental WASI embedding for the Lucet runtime. -Much of this code is a direct port of the `cloudabi-utils`-based syscall emulation layer via -[`wasmtime`](https://github.com/CraneStation/wasmtime/tree/master/wasmtime-wasi/sandboxed-system-primitives). It -is currently suitable for demonstration purposes, but needs to be rewritten in a more Rust-native -style to reduce the code complexity and the number of potential panics. - -If you have questions or suggestions, the authors of `lucet-wasi` and others in the WASI community -can be found in [`#wasi` on Mozilla IRC](https://wiki.mozilla.org/IRC). - ## Examples Example WASI programs are in the [`examples`](examples) directory. ## Supported syscalls -We support a subset of the [WASI -API](https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-api.md), though we are adding -new syscalls on a regular basis. We currently implement: - -- `__wasi_args_get` -- `__wasi_args_sizes_get` -- `__wasi_clock_res_get` -- `__wasi_clock_time_get` -- `__wasi_environ_get` -- `__wasi_environ_sizes_get` -- `__wasi_fd_close` -- `__wasi_fd_fdstat_get` -- `__wasi_fd_fdstat_set_flags` -- `__wasi_fd_prestat_dir_name` -- `__wasi_fd_prestat_get` -- `__wasi_fd_read` -- `__wasi_fd_seek` -- `__wasi_fd_write` -- `__wasi_path_open` -- `__wasi_proc_exit` -- `__wasi_random_get` - -This is enough to run basic C and Rust programs, including those that use command-line arguments, -environment variables, stdio, and basic file operations. +We support the entire [WASI API](https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-api.md), +with the exception of socket-related syscalls. These will be added when +network access is standardized. ## Thread safety -Lucet guests are currently single-threaded only. The WASI embedding assumes this, and so the syscall -implementations are not thread-safe. This is not a fundamental limitation, should Lucet support -multi-threaded guests in the future. +Lucet guests are currently single-threaded only. The WASI embedding assumes +this, and so the syscall implementations are not thread-safe. This is not a +fundamental limitation, should Lucet support multi-threaded guests in the +future. ## TODOs -### Complete the WASI API syscalls - -We are missing support for advanced filesystem operations, sockets, and polling, among others. - ### Introduce optional abstraction between system clocks and WASI clocks -The current implementations of `__wasi_clock_*` delegate to the host system's `clock_getres` and -`clock_gettime`. For untrusted code, it would be useful to limit the precision of these clocks to -reduce the potential impact of side channels. Furthermore, the `CLOCK_*_CPUTIME_ID` clocks currently -give timings for the host process, but a measure of the guest instance runtime would be more -accurate. +The current implementations of `__wasi_clock_*` delegate to the host system's +`clock_getres` and `clock_gettime`. For untrusted code, it would be useful to +limit the precision of these clocks to reduce the potential impact of side +channels. Furthermore, the `CLOCK_*_CPUTIME_ID` clocks currently give timings +for the host process, but a measure of the guest instance runtime would be +more accurate. ### Rewrite the code that implements capability checking -Much of this code is a direct port of the [`wasmtime` C -implementation](https://github.com/CraneStation/wasmtime/tree/master/wasmtime-wasi/sandboxed-system-primitives), -and as such contains a fair amount of unsafety and low-level operations on bytestrings and -bitfields. Since this code is critical to the integrity of the sandboxing model, we intend to -rewrite this code in higher-level Rust that is easier to test and verify. +Much of this code is a direct port of the [`wasmtime` C implementation](https://github.com/CraneStation/wasmtime/tree/master/wasmtime-wasi/sandboxed-system-primitives), +and as such contains a fair amount of unsafety and low-level operations on +bytestrings and bitfields. Since this code is critical to the integrity of the +sandboxing model, we intend to rewrite this code in higher-level Rust that is +easier to test and verify. ## Third-Party Code `src/wasm32.rs` is copied from -[wasmtime](https://github.com/CraneStation/wasmtime/blob/master/wasmtime-wasi/src/wasm32.rs), along -with the associated `LICENSE.wasmtime` file. +[wasmtime](https://github.com/CraneStation/wasmtime/blob/master/wasmtime-wasi/src/wasm32.rs), +along with the associated `LICENSE.wasmtime` file. -Significant parts of our syscall implementations are derived from the C implementations in +Parts of our syscall implementations are derived from the C implementations in `cloudabi-utils`. See `LICENSE.cloudabi-utils` for license information. From e6dc0617c4c6acd5181f2cdfb2c0a5ec2b38bdcd Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Thu, 23 May 2019 19:40:22 +0200 Subject: [PATCH 143/512] Make users of `dec_slice_of` safe, make codecs safe (#180) Similar to what was done in wasi-common, make `dec_slice_of` return a slice rather than a pionter-length pair. Add a mutable version, and use immutable slices as much as possible. Mark codec functions safe. --- lucet-wasi/src/hostcalls/fs.rs | 78 ++++++++++---------- lucet-wasi/src/hostcalls/misc.rs | 63 +++++++--------- lucet-wasi/src/memory.rs | 121 ++++++++++++++++++++----------- 3 files changed, 143 insertions(+), 119 deletions(-) diff --git a/lucet-wasi/src/hostcalls/fs.rs b/lucet-wasi/src/hostcalls/fs.rs index 65b60fd90..9d29eb62b 100644 --- a/lucet-wasi/src/hostcalls/fs.rs +++ b/lucet-wasi/src/hostcalls/fs.rs @@ -39,7 +39,7 @@ pub fn wasi_fd_fdstat_get( fdstat_ptr: wasm32::uintptr_t, // *mut wasm32::__wasi_fdstat_t ) -> wasm32::__wasi_errno_t { let host_fd = dec_fd(fd); - let mut host_fdstat = match unsafe { dec_fdstat_byref(vmctx, fdstat_ptr) } { + let mut host_fdstat = match dec_fdstat_byref(vmctx, fdstat_ptr) { Ok(host_fdstat) => host_fdstat, Err(e) => return enc_errno(e), }; @@ -242,7 +242,7 @@ pub fn wasi_fd_read( use nix::sys::uio::{readv, IoVec}; let fd = dec_fd(fd); - let mut iovs = match unsafe { dec_iovec_slice(vmctx, iovs_ptr, iovs_len) } { + let mut iovs = match dec_iovec_slice(vmctx, iovs_ptr, iovs_len) { Ok(iovs) => iovs, Err(e) => return enc_errno(e), }; @@ -287,7 +287,7 @@ pub fn wasi_fd_write( use nix::sys::uio::{writev, IoVec}; let fd = dec_fd(fd); - let iovs = match unsafe { dec_ciovec_slice(vmctx, iovs_ptr, iovs_len) } { + let iovs = match dec_ciovec_slice(vmctx, iovs_ptr, iovs_len) { Ok(iovs) => iovs, Err(e) => return enc_errno(e), }; @@ -388,8 +388,8 @@ pub fn wasi_path_open( nix_all_oflags.remove(OFlag::O_WRONLY); nix_all_oflags.insert(OFlag::O_RDONLY); } - let path = match unsafe { dec_slice_of::(vmctx, path_ptr, path_len) } { - Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + let path = match dec_slice_of::(vmctx, path_ptr, path_len) { + Ok(path_bytes) => OsStr::from_bytes(path_bytes), Err(e) => return enc_errno(e), }; @@ -500,8 +500,8 @@ pub fn wasi_path_filestat_get( let dirfd = dec_fd(dirfd); let dirflags = dec_lookupflags(dirflags); - let path = match unsafe { dec_slice_of::(vmctx, path_ptr, path_len) } { - Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + let path = match dec_slice_of::(vmctx, path_ptr, path_len) { + Ok(path_bytes) => OsStr::from_bytes(path_bytes), Err(e) => return enc_errno(e), }; let rights = host::__WASI_RIGHT_PATH_FILESTAT_GET; @@ -536,8 +536,8 @@ pub fn wasi_path_create_directory( use nix::libc::mkdirat; let dirfd = dec_fd(dirfd); - let path = match unsafe { dec_slice_of::(vmctx, path_ptr, path_len) } { - Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + let path = match dec_slice_of::(vmctx, path_ptr, path_len) { + Ok(path_bytes) => OsStr::from_bytes(path_bytes), Err(e) => return enc_errno(e), }; let rights = host::__WASI_RIGHT_PATH_CREATE_DIRECTORY; @@ -566,8 +566,8 @@ pub fn wasi_path_unlink_file( use nix::libc::unlinkat; let dirfd = dec_fd(dirfd); - let path = match unsafe { dec_slice_of::(vmctx, path_ptr, path_len) } { - Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + let path = match dec_slice_of::(vmctx, path_ptr, path_len) { + Ok(path_bytes) => OsStr::from_bytes(path_bytes), Err(e) => return enc_errno(e), }; let rights = host::__WASI_RIGHT_PATH_UNLINK_FILE; @@ -854,8 +854,8 @@ pub fn wasi_path_filestat_set_times( let dirfd = dec_fd(dirfd); let dirflags = dec_lookupflags(dirflags); - let path = match unsafe { dec_slice_of::(vmctx, path_ptr, path_len) } { - Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + let path = match dec_slice_of::(vmctx, path_ptr, path_len) { + Ok(path_bytes) => OsStr::from_bytes(path_bytes), Err(e) => return enc_errno(e), }; let rights = host::__WASI_RIGHT_PATH_FILESTAT_SET_TIMES; @@ -924,7 +924,7 @@ pub fn wasi_fd_pread( use std::cmp; let fd = dec_fd(fd); - let iovs = match unsafe { dec_iovec_slice(vmctx, iovs_ptr, iovs_len) } { + let iovs = match dec_iovec_slice(vmctx, iovs_ptr, iovs_len) { Ok(iovs) => iovs, Err(e) => return enc_errno(e), }; @@ -974,7 +974,7 @@ pub fn wasi_fd_pwrite( use nix::sys::uio::pwrite; let fd = dec_fd(fd); - let iovs = match unsafe { dec_iovec_slice(vmctx, iovs_ptr, iovs_len) } { + let iovs = match dec_iovec_slice(vmctx, iovs_ptr, iovs_len) { Ok(iovs) => iovs, Err(e) => return enc_errno(e), }; @@ -1016,7 +1016,7 @@ pub fn wasi_fd_readdir( ) -> wasm32::__wasi_errno_t { use libc::{dirent, fdopendir, memcpy, readdir_r, seekdir}; - match unsafe { enc_usize_byref(vmctx, bufused, 0) } { + match enc_usize_byref(vmctx, bufused, 0) { Ok(_) => {} Err(e) => return enc_errno(e), }; @@ -1027,12 +1027,12 @@ pub fn wasi_fd_readdir( Ok(fe) => fe, Err(e) => return enc_errno(e), }; - let host_buf = match unsafe { dec_slice_of::(vmctx, buf, buf_len) } { + let host_buf = match dec_slice_of::(vmctx, buf, buf_len) { Ok(host_buf) => host_buf, Err(e) => return enc_errno(e), }; - let host_buf_ptr = host_buf.0; - let host_buf_len = host_buf.1; + let host_buf_ptr = host_buf.as_ptr(); + let host_buf_len = host_buf.len(); let dir = unsafe { fdopendir(fe.fd_object.rawfd) }; if dir.is_null() { return wasm32::errno_from_nix(nix::errno::Errno::last()); @@ -1126,12 +1126,12 @@ pub fn wasi_path_link( let old_dirfd = dec_fd(old_dirfd); let new_dirfd = dec_fd(new_dirfd); - let old_path = match unsafe { dec_slice_of::(vmctx, old_path_ptr, old_path_len) } { - Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + let old_path = match dec_slice_of::(vmctx, old_path_ptr, old_path_len) { + Ok(old_path_bytes) => OsStr::from_bytes(old_path_bytes), Err(e) => return enc_errno(e), }; - let new_path = match unsafe { dec_slice_of::(vmctx, new_path_ptr, new_path_len) } { - Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + let new_path = match dec_slice_of::(vmctx, new_path_ptr, new_path_len) { + Ok(new_path_bytes) => OsStr::from_bytes(new_path_bytes), Err(e) => return enc_errno(e), }; let rights = host::__WASI_RIGHT_PATH_LINK_SOURCE; @@ -1183,13 +1183,13 @@ pub fn wasi_path_readlink( ) -> wasm32::__wasi_errno_t { use nix::fcntl::readlinkat; - match unsafe { enc_usize_byref(vmctx, bufused, 0) } { + match enc_usize_byref(vmctx, bufused, 0) { Ok(_) => {} Err(e) => return enc_errno(e), }; let dirfd = dec_fd(dirfd); - let path = match unsafe { dec_slice_of::(vmctx, path_ptr, path_len) } { - Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + let path = match dec_slice_of::(vmctx, path_ptr, path_len) { + Ok(path_bytes) => OsStr::from_bytes(path_bytes), Err(e) => return enc_errno(e), }; let rights = host::__WASI_RIGHT_PATH_READLINK; @@ -1197,8 +1197,8 @@ pub fn wasi_path_readlink( Ok((dir, path)) => (dir, path), Err(e) => return enc_errno(e), }; - let mut buf = match unsafe { dec_slice_of::(vmctx, buf_ptr, buf_len) } { - Ok((ptr, len)) => unsafe { std::slice::from_raw_parts_mut(ptr, len) }, + let mut buf = match dec_slice_of_mut::(vmctx, buf_ptr, buf_len) { + Ok(buf) => buf, Err(e) => return enc_errno(e), }; let target_path = match readlinkat(dir, path.as_os_str(), &mut buf) { @@ -1206,7 +1206,7 @@ pub fn wasi_path_readlink( Ok(target_path) => target_path, }; let host_bufused = target_path.len(); - match unsafe { enc_usize_byref(vmctx, bufused, host_bufused) } { + match enc_usize_byref(vmctx, bufused, host_bufused) { Ok(_) => {} Err(e) => return enc_errno(e), }; @@ -1223,8 +1223,8 @@ pub fn wasi_path_remove_directory( use nix::libc::{unlinkat, AT_REMOVEDIR}; let dirfd = dec_fd(dirfd); - let path = match unsafe { dec_slice_of::(vmctx, path_ptr, path_len) } { - Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + let path = match dec_slice_of::(vmctx, path_ptr, path_len) { + Ok(path_bytes) => OsStr::from_bytes(path_bytes), Err(e) => return enc_errno(e), }; let rights = host::__WASI_RIGHT_PATH_REMOVE_DIRECTORY; @@ -1256,12 +1256,12 @@ pub fn wasi_path_rename( let old_dirfd = dec_fd(old_dirfd); let new_dirfd = dec_fd(new_dirfd); - let old_path = match unsafe { dec_slice_of::(vmctx, old_path_ptr, old_path_len) } { - Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + let old_path = match dec_slice_of::(vmctx, old_path_ptr, old_path_len) { + Ok(old_path_bytes) => OsStr::from_bytes(old_path_bytes), Err(e) => return enc_errno(e), }; - let new_path = match unsafe { dec_slice_of::(vmctx, new_path_ptr, new_path_len) } { - Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + let new_path = match dec_slice_of::(vmctx, new_path_ptr, new_path_len) { + Ok(new_path_bytes) => OsStr::from_bytes(new_path_bytes), Err(e) => return enc_errno(e), }; let rights = host::__WASI_RIGHT_PATH_RENAME_SOURCE; @@ -1309,12 +1309,12 @@ pub fn wasi_path_symlink( use nix::libc::symlinkat; let dirfd = dec_fd(dirfd); - let old_path = match unsafe { dec_slice_of::(vmctx, old_path_ptr, old_path_len) } { - Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + let old_path = match dec_slice_of::(vmctx, old_path_ptr, old_path_len) { + Ok(old_path_bytes) => OsStr::from_bytes(old_path_bytes), Err(e) => return enc_errno(e), }; - let new_path = match unsafe { dec_slice_of::(vmctx, new_path_ptr, new_path_len) } { - Ok((ptr, len)) => OsStr::from_bytes(unsafe { std::slice::from_raw_parts(ptr, len) }), + let new_path = match dec_slice_of::(vmctx, new_path_ptr, new_path_len) { + Ok(new_path_bytes) => OsStr::from_bytes(new_path_bytes), Err(e) => return enc_errno(e), }; let rights = host::__WASI_RIGHT_PATH_SYMLINK; diff --git a/lucet-wasi/src/hostcalls/misc.rs b/lucet-wasi/src/hostcalls/misc.rs index 05c57ee27..d592427cb 100644 --- a/lucet-wasi/src/hostcalls/misc.rs +++ b/lucet-wasi/src/hostcalls/misc.rs @@ -11,8 +11,8 @@ use lucet_runtime::vmctx::Vmctx; use nix::convert_ioctl_res; use nix::libc::{self, c_int}; +use std::cmp; use std::time::SystemTime; -use std::{cmp, slice}; // define the `fionread()` function, equivalent to `ioctl(fd, FIONREAD, *bytes)` nix::ioctl_read_bad!(fionread, nix::libc::FIONREAD, c_int); @@ -262,25 +262,19 @@ pub fn wasi_random_get( ) -> wasm32::__wasi_errno_t { use rand::{thread_rng, RngCore}; - let buf_len = dec_usize(buf_len); - let buf_ptr = match unsafe { dec_ptr(vmctx, buf_ptr, buf_len) } { - Ok(ptr) => ptr, + let buf = match dec_slice_of_mut::(vmctx, buf_ptr, buf_len) { + Ok(buf) => buf, Err(e) => return enc_errno(e), }; - - let buf = unsafe { std::slice::from_raw_parts_mut(buf_ptr, buf_len) }; - thread_rng().fill_bytes(buf); return wasm32::__WASI_ESUCCESS; } -fn __wasi_poll_oneoff_handle_timeout_event( - vmctx: &mut Vmctx, +fn _wasi_poll_oneoff_handle_timeout_event( output_slice: &mut [wasm32::__wasi_event_t], - nevents: wasm32::uintptr_t, timeout: Option, -) -> wasm32::__wasi_errno_t { +) -> wasm32::size_t { if let Some(ClockEventData { userdata, .. }) = timeout { let output_event = host::__wasi_event_t { userdata, @@ -294,24 +288,17 @@ fn __wasi_poll_oneoff_handle_timeout_event( }, }; output_slice[0] = enc_event(output_event); - if let Err(e) = unsafe { enc_pointee(vmctx, nevents, 1) } { - return enc_errno(e); - } + 1 } else { // shouldn't happen - if let Err(e) = unsafe { enc_pointee(vmctx, nevents, 0) } { - return enc_errno(e); - } + 0 } - wasm32::__WASI_ESUCCESS } -fn __wasi_poll_oneoff_handle_fd_event<'t>( - vmctx: &mut Vmctx, +fn _wasi_poll_oneoff_handle_fd_event<'t>( output_slice: &mut [wasm32::__wasi_event_t], - nevents: wasm32::uintptr_t, events: impl Iterator, -) -> wasm32::__wasi_errno_t { +) -> wasm32::size_t { let mut output_slice_cur = output_slice.iter_mut(); let mut revents_count = 0; for (fd_event, poll_fd) in events { @@ -383,10 +370,7 @@ fn __wasi_poll_oneoff_handle_fd_event<'t>( *output_slice_cur.next().unwrap() = enc_event(output_event); revents_count += 1; } - if let Err(e) = unsafe { enc_pointee(vmctx, nevents, revents_count) } { - return enc_errno(e); - } - wasm32::__WASI_ESUCCESS + revents_count } pub fn wasi_poll_oneoff( @@ -399,15 +383,13 @@ pub fn wasi_poll_oneoff( if nsubscriptions as u64 > wasm32::__wasi_filesize_t::max_value() { return wasm32::__WASI_EINVAL; } - unsafe { enc_pointee(vmctx, nevents, 0) }.unwrap(); - let input_slice_ = - unsafe { dec_slice_of::(vmctx, input, nsubscriptions) } - .unwrap(); - let input_slice = unsafe { slice::from_raw_parts(input_slice_.0, input_slice_.1) }; + enc_pointee(vmctx, nevents, 0).unwrap(); - let output_slice_ = - unsafe { dec_slice_of::(vmctx, output, nsubscriptions) }.unwrap(); - let output_slice = unsafe { slice::from_raw_parts_mut(output_slice_.0, output_slice_.1) }; + let input_slice = + dec_slice_of::(vmctx, input, nsubscriptions).unwrap(); + + let output_slice = + dec_slice_of_mut::(vmctx, output, nsubscriptions).unwrap(); let input: Vec<_> = input_slice.iter().map(|x| dec_subscription(x)).collect(); @@ -471,9 +453,14 @@ pub fn wasi_poll_oneoff( Ok(ready) => break ready as usize, } }; - if ready == 0 { - return __wasi_poll_oneoff_handle_timeout_event(vmctx, output_slice, nevents, timeout); + let events_count = if ready == 0 { + _wasi_poll_oneoff_handle_timeout_event(output_slice, timeout) + } else { + let events = fd_events.iter().zip(poll_fds.iter()).take(ready); + _wasi_poll_oneoff_handle_fd_event(output_slice, events) + }; + if let Err(e) = enc_pointee(vmctx, nevents, events_count) { + return enc_errno(e); } - let events = fd_events.iter().zip(poll_fds.iter()).take(ready); - __wasi_poll_oneoff_handle_fd_event(vmctx, output_slice, nevents, events) + wasm32::__WASI_ESUCCESS } diff --git a/lucet-wasi/src/memory.rs b/lucet-wasi/src/memory.rs index e231f64dc..b94aac3b2 100644 --- a/lucet-wasi/src/memory.rs +++ b/lucet-wasi/src/memory.rs @@ -22,75 +22,114 @@ macro_rules! bail_errno { }; } -pub unsafe fn dec_ptr( +pub fn dec_ptr( + vmctx: &Vmctx, + ptr: wasm32::uintptr_t, + len: usize, +) -> Result<*const u8, host::__wasi_errno_t> { + let heap = vmctx.heap(); + + // check for overflow + let checked_len = (ptr as usize) + .checked_add(len) + .ok_or(host::__WASI_EFAULT as host::__wasi_errno_t)?; + if checked_len > heap.len() { + bail_errno!(__WASI_EFAULT); + } + // translate the pointer + Ok(unsafe { heap.as_ptr().offset(ptr as isize) }) +} + +pub fn dec_ptr_mut( vmctx: &Vmctx, ptr: wasm32::uintptr_t, len: usize, ) -> Result<*mut u8, host::__wasi_errno_t> { let mut heap = vmctx.heap_mut(); - // check that `len` fits in the wasm32 address space - if len > wasm32::UINTPTR_MAX as usize { - bail_errno!(__WASI_EOVERFLOW); - } - - // check that `ptr` and `ptr + len` are both within the guest heap - if ptr as usize > heap.len() || ptr as usize + len > heap.len() { + // check for overflow + let checked_len = (ptr as usize) + .checked_add(len) + .ok_or(host::__WASI_EFAULT as host::__wasi_errno_t)?; + if checked_len > heap.len() { bail_errno!(__WASI_EFAULT); } - // translate the pointer - Ok(heap.as_mut_ptr().offset(ptr as isize)) + Ok(unsafe { heap.as_mut_ptr().offset(ptr as isize) }) } -pub unsafe fn dec_ptr_to( +pub fn dec_ptr_to( vmctx: &Vmctx, ptr: wasm32::uintptr_t, -) -> Result<*mut T, host::__wasi_errno_t> { +) -> Result<*const T, host::__wasi_errno_t> { // check that the ptr is aligned if ptr as usize % align_of::() != 0 { bail_errno!(__WASI_EINVAL); } - dec_ptr(vmctx, ptr, size_of::()).map(|p| p as *mut T) + dec_ptr(vmctx, ptr, size_of::()).map(|p| p as *const T) } -pub unsafe fn dec_pointee( +pub fn dec_ptr_to_mut( vmctx: &Vmctx, ptr: wasm32::uintptr_t, -) -> Result { - dec_ptr_to::(vmctx, ptr).map(|p| p.read()) +) -> Result<*mut T, host::__wasi_errno_t> { + // check that the ptr is aligned + if ptr as usize % align_of::() != 0 { + bail_errno!(__WASI_EINVAL); + } + dec_ptr_mut(vmctx, ptr, size_of::()).map(|p| p as *mut T) +} + +pub fn dec_pointee(vmctx: &Vmctx, ptr: wasm32::uintptr_t) -> Result { + dec_ptr_to::(vmctx, ptr).map(|p| unsafe { p.read() }) } -pub unsafe fn enc_pointee( +pub fn enc_pointee( vmctx: &Vmctx, ptr: wasm32::uintptr_t, t: T, ) -> Result<(), host::__wasi_errno_t> { - dec_ptr_to::(vmctx, ptr).map(|p| p.write(t)) + dec_ptr_to_mut::(vmctx, ptr).map(|p| unsafe { p.write(t) }) } -pub unsafe fn dec_slice_of( - vmctx: &Vmctx, +fn check_slice_of( ptr: wasm32::uintptr_t, len: wasm32::size_t, -) -> Result<(*mut T, usize), host::__wasi_errno_t> { +) -> Result<(usize, usize), host::__wasi_errno_t> { // check alignment, and that length doesn't overflow if ptr as usize % align_of::() != 0 { - return Err(host::__WASI_EINVAL as host::__wasi_errno_t); + bail_errno!(__WASI_EINVAL); } let len = dec_usize(len); let len_bytes = if let Some(len) = size_of::().checked_mul(len) { len } else { - return Err(host::__WASI_EOVERFLOW as host::__wasi_errno_t); + bail_errno!(__WASI_EOVERFLOW); }; + Ok((len, len_bytes)) +} - let ptr = dec_ptr(vmctx, ptr, len_bytes)? as *mut T; +pub fn dec_slice_of<'vmctx, T>( + vmctx: &'vmctx Vmctx, + ptr: wasm32::uintptr_t, + len: wasm32::size_t, +) -> Result<&'vmctx [T], host::__wasi_errno_t> { + let (len, len_bytes) = check_slice_of::(ptr, len)?; + let ptr = dec_ptr(vmctx, ptr, len_bytes)? as *const T; + Ok(unsafe { slice::from_raw_parts(ptr, len) }) +} - Ok((ptr, len)) +pub fn dec_slice_of_mut<'vmctx, T>( + vmctx: &'vmctx Vmctx, + ptr: wasm32::uintptr_t, + len: wasm32::size_t, +) -> Result<&'vmctx mut [T], host::__wasi_errno_t> { + let (len, len_bytes) = check_slice_of::(ptr, len)?; + let ptr = dec_ptr_mut(vmctx, ptr, len_bytes)? as *mut T; + Ok(unsafe { slice::from_raw_parts_mut(ptr, len) }) } -pub unsafe fn enc_slice_of( +pub fn enc_slice_of( vmctx: &Vmctx, slice: &[T], ptr: wasm32::uintptr_t, @@ -108,7 +147,7 @@ pub unsafe fn enc_slice_of( // get the pointer into guest memory, and copy the bytes let ptr = dec_ptr(vmctx, ptr, len_bytes)? as *mut libc::c_void; - libc::memcpy(ptr, slice.as_ptr() as *const libc::c_void, len_bytes); + unsafe { libc::memcpy(ptr, slice.as_ptr() as *const libc::c_void, len_bytes) }; Ok(()) } @@ -119,7 +158,7 @@ macro_rules! dec_enc_scalar { host::$ty::from_le(x) } - pub unsafe fn $dec_byref( + pub fn $dec_byref( vmctx: &Vmctx, ptr: wasm32::uintptr_t, ) -> Result { @@ -130,7 +169,7 @@ macro_rules! dec_enc_scalar { x.to_le() } - pub unsafe fn $enc_byref( + pub fn $enc_byref( vmctx: &Vmctx, ptr: wasm32::uintptr_t, x: host::$ty, @@ -140,7 +179,7 @@ macro_rules! dec_enc_scalar { }; } -pub unsafe fn dec_ciovec( +pub fn dec_ciovec( vmctx: &Vmctx, ciovec: &wasm32::__wasi_ciovec_t, ) -> Result { @@ -151,17 +190,16 @@ pub unsafe fn dec_ciovec( }) } -pub unsafe fn dec_ciovec_slice( +pub fn dec_ciovec_slice( vmctx: &Vmctx, ptr: wasm32::uintptr_t, len: wasm32::size_t, ) -> Result, host::__wasi_errno_t> { let slice = dec_slice_of::(vmctx, ptr, len)?; - let slice = slice::from_raw_parts(slice.0, slice.1); slice.iter().map(|iov| dec_ciovec(vmctx, iov)).collect() } -pub unsafe fn dec_iovec( +pub fn dec_iovec( vmctx: &Vmctx, iovec: &wasm32::__wasi_iovec_t, ) -> Result { @@ -172,13 +210,12 @@ pub unsafe fn dec_iovec( }) } -pub unsafe fn dec_iovec_slice( +pub fn dec_iovec_slice( vmctx: &Vmctx, ptr: wasm32::uintptr_t, len: wasm32::size_t, ) -> Result, host::__wasi_errno_t> { let slice = dec_slice_of::(vmctx, ptr, len)?; - let slice = slice::from_raw_parts(slice.0, slice.1); slice.iter().map(|iov| dec_iovec(vmctx, iov)).collect() } @@ -246,7 +283,7 @@ pub fn dec_filestat(filestat: wasm32::__wasi_filestat_t) -> host::__wasi_filesta } } -pub unsafe fn dec_filestat_byref( +pub fn dec_filestat_byref( vmctx: &Vmctx, filestat_ptr: wasm32::uintptr_t, ) -> Result { @@ -266,7 +303,7 @@ pub fn enc_filestat(filestat: host::__wasi_filestat_t) -> wasm32::__wasi_filesta } } -pub unsafe fn enc_filestat_byref( +pub fn enc_filestat_byref( vmctx: &Vmctx, filestat_ptr: wasm32::uintptr_t, host_filestat: host::__wasi_filestat_t, @@ -284,7 +321,7 @@ pub fn dec_fdstat(fdstat: wasm32::__wasi_fdstat_t) -> host::__wasi_fdstat_t { } } -pub unsafe fn dec_fdstat_byref( +pub fn dec_fdstat_byref( vmctx: &Vmctx, fdstat_ptr: wasm32::uintptr_t, ) -> Result { @@ -301,7 +338,7 @@ pub fn enc_fdstat(fdstat: host::__wasi_fdstat_t) -> wasm32::__wasi_fdstat_t { } } -pub unsafe fn enc_fdstat_byref( +pub fn enc_fdstat_byref( vmctx: &Vmctx, fdstat_ptr: wasm32::uintptr_t, host_fdstat: host::__wasi_fdstat_t, @@ -368,7 +405,7 @@ pub fn dec_prestat( } } -pub unsafe fn dec_prestat_byref( +pub fn dec_prestat_byref( vmctx: &Vmctx, prestat_ptr: wasm32::uintptr_t, ) -> Result { @@ -394,7 +431,7 @@ pub fn enc_prestat( } } -pub unsafe fn enc_prestat_byref( +pub fn enc_prestat_byref( vmctx: &Vmctx, prestat_ptr: wasm32::uintptr_t, host_prestat: host::__wasi_prestat_t, @@ -435,7 +472,7 @@ pub fn enc_usize(size: usize) -> wasm32::size_t { wasm32::size_t::cast(size).unwrap() } -pub unsafe fn enc_usize_byref( +pub fn enc_usize_byref( vmctx: &Vmctx, usize_ptr: wasm32::uintptr_t, host_usize: usize, From 3f19a91c0c7d3f69a644636b121eb1c6ce83bf8a Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Fri, 24 May 2019 09:05:34 +0900 Subject: [PATCH 144/512] add some temporary debugging statements --- lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs | 6 ++++-- lucet-runtime/lucet-runtime-internals/src/instance.rs | 4 ++-- lucet-runtime/lucet-runtime-internals/src/region/mmap.rs | 2 +- lucet-runtime/lucet-runtime-internals/src/region/mod.rs | 4 +++- lucet-runtime/src/c_api.rs | 2 +- lucet-wasi/src/c_api.rs | 1 + 6 files changed, 12 insertions(+), 7 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs b/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs index f2a24bad1..c66ba09c8 100644 --- a/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs @@ -106,7 +106,7 @@ pub struct Alloc { impl Drop for Alloc { fn drop(&mut self) { - // eprintln!("Alloc::drop()"); + eprintln!("Alloc::drop()"); self.region.clone().drop_alloc(self); } } @@ -133,7 +133,8 @@ impl Alloc { let host_page_size = host_page_size() as u32; - if self.heap_accessible_size as u32 % host_page_size != 0 { + dbg!(self.heap_accessible_size); + if dbg!(self.heap_accessible_size as u32) % dbg!(host_page_size) != 0 { lucet_bail!("heap is not page-aligned; this is a bug"); } @@ -191,6 +192,7 @@ impl Alloc { .expand_heap(slot, newly_accessible as u32, expand_pagealigned)?; self.heap_accessible_size += expand_pagealigned as usize; + dbg!(self.heap_accessible_size); self.heap_inaccessible_size -= expand_pagealigned as usize; Ok(newly_accessible as u32) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index d590f45e2..68c23f0e8 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -141,7 +141,7 @@ impl DerefMut for InstanceHandle { impl Drop for InstanceHandle { fn drop(&mut self) { - if self.needs_inst_drop { + if dbg!(self.needs_inst_drop) { unsafe { let inst = self.inst.as_mut(); @@ -669,7 +669,7 @@ impl Instance { fn run_start(&mut self) -> Result<(), Error> { if let Some(start) = self.module.get_start_func()? { - self.run_func(start, &[])?; + dbg!(self.run_func(start, &[])?); } Ok(()) } diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs index 525364792..0240d9191 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs @@ -167,7 +167,7 @@ impl RegionInternal for MmapRegion { )? }; } - alloc.heap_accessible_size = initial_size; + alloc.heap_accessible_size = dbg!(initial_size); alloc.heap_inaccessible_size = alloc.slot().limits.heap_address_space_size - initial_size; // Initialize the heap using the module sparse page data. There cannot be more pages in the diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mod.rs b/lucet-runtime/lucet-runtime-internals/src/region/mod.rs index 7099ed639..5339e6b2e 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mod.rs @@ -100,6 +100,8 @@ impl<'a> InstanceBuilder<'a> { /// This function runs the guest code for the WebAssembly `start` section, and running any guest /// code is potentially unsafe; see [`Instance::run()`](struct.Instance.html#method.run). pub fn build(self) -> Result { - self.region.new_instance_with(self.module, self.embed_ctx) + let inst = self.region.new_instance_with(self.module, self.embed_ctx)?; + dbg!(inst.heap().len()); + Ok(inst) } } diff --git a/lucet-runtime/src/c_api.rs b/lucet-runtime/src/c_api.rs index b41f0f475..c3f5764a0 100644 --- a/lucet-runtime/src/c_api.rs +++ b/lucet-runtime/src/c_api.rs @@ -281,7 +281,7 @@ pub unsafe extern "C" fn lucet_instance_grow_heap( } lucet_error::Ok } - Err(e) => e.into(), + Err(e) => dbg!(e).into(), } }) } diff --git a/lucet-wasi/src/c_api.rs b/lucet-wasi/src/c_api.rs index be8dc9416..7d64e8ba8 100644 --- a/lucet-wasi/src/c_api.rs +++ b/lucet-wasi/src/c_api.rs @@ -80,6 +80,7 @@ pub unsafe extern "C" fn lucet_region_new_instance_with_wasi_ctx( .with_embed_ctx(wasi_ctx.build()) .build() .map(|i| { + dbg!(i.heap().len()); inst_out.write(instance_handle_to_raw(i) as _); lucet_error::Ok }) From 6c95d108ca7f90a7c68e61520407e76c6e48ade3 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Fri, 24 May 2019 19:43:35 +0900 Subject: [PATCH 145/512] [lucet-runtime] start C API test suite and rearrange modules --- Cargo.lock | 4 ++ lucet-runtime/Cargo.toml | 7 +++ lucet-runtime/build.rs | 12 +++++ .../src/alloc/tests.rs | 5 +- .../lucet-runtime-internals/src/c_api.rs | 3 +- .../src/context/mod.rs | 16 +++--- .../src/context/tests/c_child.rs | 3 +- .../src/context/tests/mod.rs | 3 +- .../src/context/tests/rust_child.rs | 3 +- .../lucet-runtime-internals/src/instance.rs | 5 +- .../lucet-runtime-tests/src/guest_fault.rs | 5 +- lucet-runtime/lucet-runtime-tests/src/host.rs | 5 +- lucet-runtime/src/c_api.rs | 34 +++++++++++++ lucet-runtime/src/lib.rs | 2 +- lucet-runtime/tests/c_api.c | 50 +++++++++++++++++++ lucet-runtime/tests/guests/null.c | 3 ++ 16 files changed, 129 insertions(+), 31 deletions(-) create mode 100644 lucet-runtime/build.rs create mode 100644 lucet-runtime/tests/c_api.c create mode 100644 lucet-runtime/tests/guests/null.c diff --git a/Cargo.lock b/Cargo.lock index 04ff8bdcd..2a70b7c1e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -637,15 +637,19 @@ name = "lucet-runtime" version = "0.1.0" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module-data 0.1.0", "lucet-runtime-internals 0.1.0", "lucet-runtime-tests 0.1.0", + "lucet-wasi-sdk 0.1.0", + "lucetc 0.1.0", "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/lucet-runtime/Cargo.toml b/lucet-runtime/Cargo.toml index 33dfb8084..4b660c678 100644 --- a/lucet-runtime/Cargo.toml +++ b/lucet-runtime/Cargo.toml @@ -18,8 +18,15 @@ num-derive = "0.2" byteorder = "1.2" failure = "0.1" lazy_static = "1.1" +lucetc = { path = "../lucetc" } lucet-runtime-tests = { path = "lucet-runtime-tests" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk" } nix = "0.13" +tempfile = "3.0" + +[build-dependencies] +# only used for tests +cc = "1.0" [lib] name = "lucet_runtime" diff --git a/lucet-runtime/build.rs b/lucet-runtime/build.rs new file mode 100644 index 000000000..8abc728f8 --- /dev/null +++ b/lucet-runtime/build.rs @@ -0,0 +1,12 @@ +use cc; + +fn main() { + build_c_api_tests(); +} + +fn build_c_api_tests() { + cc::Build::new() + .file("tests/c_api.c") + .include("include") + .compile("lucet_runtime_c_api_tests"); +} diff --git a/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs b/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs index dbd20a904..74a45a681 100644 --- a/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs +++ b/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs @@ -2,7 +2,6 @@ macro_rules! alloc_tests { ( $TestRegion:path ) => { use libc::c_void; - use lucet_module_data::FunctionPointer; use std::sync::Arc; use $TestRegion as TestRegion; use $crate::alloc::Limits; @@ -599,7 +598,7 @@ macro_rules! alloc_tests { let child = ContextHandle::create_and_init( inst.alloc_mut().stack_u64_mut(), &mut parent, - FunctionPointer::from_usize(heap_touching_child as usize), + heap_touching_child as usize, &[Val::CPtr(heap_ptr)], ) .expect("context init succeeds"); @@ -641,7 +640,7 @@ macro_rules! alloc_tests { let child = ContextHandle::create_and_init( inst.alloc_mut().stack_u64_mut(), &mut parent, - FunctionPointer::from_usize(stack_pattern_child as usize), + stack_pattern_child as usize, &[Val::CPtr(heap_ptr)], ) .expect("context init succeeds"); diff --git a/lucet-runtime/lucet-runtime-internals/src/c_api.rs b/lucet-runtime/lucet-runtime-internals/src/c_api.rs index 5ce4c6502..9878ee1b0 100644 --- a/lucet-runtime/lucet-runtime-internals/src/c_api.rs +++ b/lucet-runtime/lucet-runtime-internals/src/c_api.rs @@ -205,10 +205,9 @@ unsafe impl Sync for CTerminationDetails {} pub mod lucet_state { use crate::c_api::{lucet_val, CTerminationDetails}; use crate::instance::{State, TerminationDetails}; - use crate::module::AddrDetails; + use crate::module::{AddrDetails, TrapCode}; use crate::sysdeps::UContext; use libc::{c_char, c_void}; - use lucet_module_data::TrapCode; use num_derive::FromPrimitive; use std::ffi::CString; use std::ptr; diff --git a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs index e493320d9..da957d636 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs @@ -5,7 +5,6 @@ mod tests; use crate::val::{val_to_reg, val_to_stack, RegVal, UntypedRetVal, Val}; use failure::Fail; -use lucet_module_data::FunctionPointer; use nix; use nix::sys::signal; use std::arch::x86_64::{__m128, _mm_setzero_ps}; @@ -194,7 +193,7 @@ impl ContextHandle { pub fn create_and_init( stack: &mut [u64], parent: &mut ContextHandle, - fptr: FunctionPointer, + fptr: usize, args: &[Val], ) -> Result { let mut child = ContextHandle::new(); @@ -240,7 +239,6 @@ impl Context { /// ``` /// /// ```no_run - /// # use lucet_module_data::FunctionPointer; /// # use lucet_runtime_internals::context::Context; /// # use lucet_runtime_internals::val::Val; /// extern "C" { fn entrypoint(x: u64, y: f32); } @@ -253,7 +251,7 @@ impl Context { /// &mut *stack, /// &mut parent, /// &mut child, - /// FunctionPointer::from_usize(entrypoint as usize), + /// entrypoint as usize, /// &[Val::U64(120), Val::F32(3.14)], /// ); /// assert!(res.is_ok()); @@ -266,7 +264,6 @@ impl Context { /// with C calling conventions. /// /// ```no_run - /// # use lucet_module_data::FunctionPointer; /// # use lucet_runtime_internals::context::{Context, ContextHandle}; /// # use lucet_runtime_internals::val::Val; /// extern "C" fn entrypoint(x: u64, y: f32) { } @@ -279,7 +276,7 @@ impl Context { /// &mut *stack, /// &mut parent, /// &mut child, - /// FunctionPointer::from_usize(entrypoint as usize), + /// entrypoint as usize, /// &[Val::U64(120), Val::F32(3.14)], /// ); /// assert!(res.is_ok()); @@ -288,7 +285,7 @@ impl Context { stack: &mut [u64], parent: &mut Context, child: &mut Context, - fptr: FunctionPointer, + fptr: usize, args: &[Val], ) -> Result<(), Error> { if !stack_is_aligned(stack) { @@ -346,7 +343,7 @@ impl Context { stack[sp + 0 - stack_start] = lucet_context_bootstrap as u64; // The bootstrap function returns into the guest function, fptr - stack[sp + 1 - stack_start] = fptr.as_usize() as u64; + stack[sp + 1 - stack_start] = fptr as u64; // the guest function returns into lucet_context_backstop. stack[sp + 2 - stack_start] = lucet_context_backstop as u64; @@ -431,7 +428,6 @@ impl Context { /// parent context. /// /// ```no_run - /// # use lucet_module_data::FunctionPointer; /// # use lucet_runtime_internals::context::Context; /// # extern "C" fn entrypoint() {} /// # let mut stack = vec![0u64; 1024].into_boxed_slice(); @@ -441,7 +437,7 @@ impl Context { /// &mut stack, /// &mut parent, /// &mut child, - /// FunctionPointer::from_usize(entrypoint as usize), + /// entrypoint as usize, /// &[], /// ).unwrap(); /// diff --git a/lucet-runtime/lucet-runtime-internals/src/context/tests/c_child.rs b/lucet-runtime/lucet-runtime-internals/src/context/tests/c_child.rs index 4ec3d5cc3..4bdb3bd14 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/tests/c_child.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/tests/c_child.rs @@ -8,7 +8,6 @@ use crate::context::{Context, ContextHandle}; use crate::val::Val; use lazy_static::lazy_static; -use lucet_module_data::FunctionPointer; use std::ffi::CStr; use std::os::raw::{c_char, c_int, c_void}; use std::sync::Mutex; @@ -55,7 +54,7 @@ macro_rules! init_and_swap { let child = Box::into_raw(Box::new(ContextHandle::create_and_init( &mut *$stack, parent_regs.as_mut().unwrap(), - FunctionPointer::from_usize($fn as usize), + $fn as usize, &[$( $args ),*], ).unwrap())); diff --git a/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs b/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs index f2b034b89..4ef68993a 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs @@ -1,7 +1,6 @@ mod c_child; mod rust_child; use crate::context::{Context, ContextHandle, Error}; -use lucet_module_data::FunctionPointer; use memoffset::offset_of; use std::slice; @@ -36,7 +35,7 @@ fn init_rejects_unaligned() { let res = ContextHandle::create_and_init( &mut stack_unaligned, &mut parent, - FunctionPointer::from_usize(dummy as usize), + dummy as usize, &[], ); diff --git a/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs b/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs index f044e39df..7292114b9 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs @@ -3,7 +3,6 @@ use crate::context::{Context, ContextHandle}; use crate::val::{Val, __m128_as_f32, __m128_as_f64}; use lazy_static::lazy_static; -use lucet_module_data::FunctionPointer; use std::cell::RefCell; use std::fmt::Write; use std::os::raw::{c_int, c_void}; @@ -51,7 +50,7 @@ macro_rules! init_and_swap { let child = ContextHandle::create_and_init( &mut *$stack, PARENT.as_mut().unwrap(), - FunctionPointer::from_usize($fn as usize), + $fn as usize, &[$( $args ),*], ).unwrap(); CHILD = Some(child); diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index 68c23f0e8..5a49d1487 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -8,13 +8,12 @@ use crate::context::Context; use crate::embed_ctx::CtxMap; use crate::error::Error; use crate::instance::siginfo_ext::SiginfoExt; -use crate::module::{self, Global, Module}; +use crate::module::{self, FunctionHandle, FunctionPointer, Global, Module, TrapCode}; use crate::region::RegionInternal; use crate::sysdeps::UContext; use crate::val::{UntypedRetVal, Val}; use crate::WASM_PAGE_SIZE; use libc::{c_void, siginfo_t, uintptr_t, SIGBUS, SIGSEGV}; -use lucet_module_data::{FunctionHandle, FunctionPointer, TrapCode}; use memoffset::offset_of; use std::any::Any; use std::cell::{BorrowError, BorrowMutError, Ref, RefCell, RefMut, UnsafeCell}; @@ -591,7 +590,7 @@ impl Instance { unsafe { self.alloc.stack_u64_mut() }, unsafe { &mut *host_ctx.get() }, &mut self.ctx, - func.ptr, + func.ptr.as_usize(), &args_with_vmctx, ) })?; diff --git a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs index a99df235e..350e66d8f 100644 --- a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs +++ b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs @@ -125,11 +125,10 @@ macro_rules! guest_fault_tests { ( $TestRegion:path ) => { use lazy_static::lazy_static; use libc::{c_void, siginfo_t, SIGSEGV}; - use lucet_module_data::FunctionPointer; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime::{ - lucet_hostcall_terminate, lucet_hostcalls, DlModule, Error, FaultDetails, Instance, - Limits, Region, SignalBehavior, TrapCode, + lucet_hostcall_terminate, lucet_hostcalls, DlModule, Error, FaultDetails, + FunctionPointer, Instance, Limits, Region, SignalBehavior, TrapCode, }; use nix::sys::mman::{mmap, MapFlags, ProtFlags}; use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal}; diff --git a/lucet-runtime/lucet-runtime-tests/src/host.rs b/lucet-runtime/lucet-runtime-tests/src/host.rs index 91c40a346..4dc2ef048 100644 --- a/lucet-runtime/lucet-runtime-tests/src/host.rs +++ b/lucet-runtime/lucet-runtime-tests/src/host.rs @@ -3,11 +3,10 @@ macro_rules! host_tests { ( $TestRegion:path ) => { use lazy_static::lazy_static; use libc::c_void; - use lucet_module_data::FunctionPointer; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime::{ - lucet_hostcall_terminate, lucet_hostcalls, DlModule, Error, Limits, Region, - TerminationDetails, TrapCode, + lucet_hostcall_terminate, lucet_hostcalls, DlModule, Error, FunctionPointer, Limits, + Region, TerminationDetails, TrapCode, }; use std::sync::{Arc, Mutex}; use $TestRegion as TestRegion; diff --git a/lucet-runtime/src/c_api.rs b/lucet-runtime/src/c_api.rs index c3f5764a0..b4a5fc2ab 100644 --- a/lucet-runtime/src/c_api.rs +++ b/lucet-runtime/src/c_api.rs @@ -451,3 +451,37 @@ lucet_hostcalls! { .unwrap_or(std::ptr::null_mut()) } } + +#[cfg(test)] +mod tests { + use super::lucet_dl_module; + use crate::DlModule; + use lucet_wasi_sdk::{LinkOpt, LinkOpts, Lucetc}; + use std::sync::Arc; + use tempfile::TempDir; + + extern "C" { + fn lucet_runtime_test_expand_heap(module: *mut lucet_dl_module) -> bool; + } + + #[test] + fn expand_heap() { + let workdir = TempDir::new().expect("create working directory"); + + let native_build = Lucetc::new(&["tests/guests/null.c"]) + .with_link_opt(LinkOpt::NoDefaultEntryPoint) + .with_link_opt(LinkOpt::AllowUndefinedAll); + + let so_file = workdir.path().join("null.so"); + + native_build.build(so_file.clone()).unwrap(); + + let dlmodule = DlModule::load(so_file).unwrap(); + + unsafe { + assert!(lucet_runtime_test_expand_heap( + Arc::into_raw(dlmodule) as *mut lucet_dl_module + )); + } + } +} diff --git a/lucet-runtime/src/lib.rs b/lucet-runtime/src/lib.rs index a4583d1e3..6542120e2 100644 --- a/lucet-runtime/src/lib.rs +++ b/lucet-runtime/src/lib.rs @@ -200,7 +200,7 @@ pub mod c_api; -pub use lucet_module_data::TrapCode; +pub use lucet_module_data::{FunctionPointer, TrapCode}; pub use lucet_runtime_internals::alloc::Limits; pub use lucet_runtime_internals::error::Error; pub use lucet_runtime_internals::instance::{ diff --git a/lucet-runtime/tests/c_api.c b/lucet-runtime/tests/c_api.c new file mode 100644 index 000000000..ae5bb5d51 --- /dev/null +++ b/lucet-runtime/tests/c_api.c @@ -0,0 +1,50 @@ +#include +#include + +#include "lucet.h" + +bool lucet_runtime_test_expand_heap(struct lucet_dl_module *mod) +{ + struct lucet_region * region; + struct lucet_alloc_limits limits = { + .heap_memory_size = 4 * 1024 * 1024, + .heap_address_space_size = 8 * 1024 * 1024, + .stack_size = 64 * 1024, + .globals_size = 4096, + }; + + enum lucet_error err; + + err = lucet_mmap_region_create(1, &limits, ®ion); + if (err != lucet_error_ok) { + fprintf(stderr, "failed to create region\n"); + goto fail1; + } + + struct lucet_instance *inst; + err = lucet_region_new_instance(region, mod, &inst); + if (err != lucet_error_ok) { + fprintf(stderr, "failed to create instance\n"); + goto fail2; + } + + uint32_t newpage_start; + err = lucet_instance_grow_heap(inst, 1, &newpage_start); + if (err != lucet_error_ok) { + fprintf(stderr, "failed to grow memory\n"); + goto fail3; + } + + lucet_region_release(region); + lucet_dl_module_release(mod); + + return true; + +fail3: + lucet_instance_release(inst); +fail2: + lucet_region_release(region); +fail1: + lucet_dl_module_release(mod); + return false; +} diff --git a/lucet-runtime/tests/guests/null.c b/lucet-runtime/tests/guests/null.c new file mode 100644 index 000000000..dbec2355b --- /dev/null +++ b/lucet-runtime/tests/guests/null.c @@ -0,0 +1,3 @@ +void f() { + return; +} From 0a4753b060feabb6c141a676e25e2baa28c829d9 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Fri, 24 May 2019 20:04:21 +0900 Subject: [PATCH 146/512] remove temp debugging, fix benchmark compile --- Cargo.lock | 2 - benchmarks/lucet-benchmarks/Cargo.toml | 2 - benchmarks/lucet-benchmarks/src/context.rs | 9 ++-- benchmarks/lucet-benchmarks/src/modules.rs | 43 +++++++++++++------ .../lucet-runtime-internals/src/alloc/mod.rs | 6 +-- .../src/context/tests/mod.rs | 8 +--- .../lucet-runtime-internals/src/instance.rs | 4 +- .../src/region/mmap.rs | 2 +- .../lucet-runtime-internals/src/region/mod.rs | 4 +- lucet-runtime/src/c_api.rs | 2 +- lucet-wasi/src/c_api.rs | 1 - 11 files changed, 44 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2a70b7c1e..4f531dfb7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -597,10 +597,8 @@ name = "lucet-benchmarks" version = "0.1.0" dependencies = [ "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", "lucet-runtime 0.1.0", "lucet-runtime-internals 0.1.0", - "lucet-runtime-tests 0.1.0", "lucet-wasi 0.1.0", "lucet-wasi-sdk 0.1.0", "lucetc 0.1.0", diff --git a/benchmarks/lucet-benchmarks/Cargo.toml b/benchmarks/lucet-benchmarks/Cargo.toml index f3eb926bd..5ec47f3c2 100644 --- a/benchmarks/lucet-benchmarks/Cargo.toml +++ b/benchmarks/lucet-benchmarks/Cargo.toml @@ -7,10 +7,8 @@ edition = "2018" [dependencies] criterion = "0.2" lucetc = { path = "../../lucetc" } -lucet-module-data = { path = "../../lucet-module-data" } lucet-runtime = { path = "../../lucet-runtime" } lucet-runtime-internals = { path = "../../lucet-runtime/lucet-runtime-internals" } -lucet-runtime-tests = { path = "../../lucet-runtime/lucet-runtime-tests" } lucet-wasi = { path = "../../lucet-wasi" } lucet-wasi-sdk = { path = "../../lucet-wasi-sdk" } nix = "0.13" diff --git a/benchmarks/lucet-benchmarks/src/context.rs b/benchmarks/lucet-benchmarks/src/context.rs index 6c3d9e7bf..5b10be803 100644 --- a/benchmarks/lucet-benchmarks/src/context.rs +++ b/benchmarks/lucet-benchmarks/src/context.rs @@ -1,5 +1,4 @@ use criterion::Criterion; -use lucet_module_data::FunctionPointer; use lucet_runtime_internals::context::{Context, ContextHandle}; /// Time the initialization of a context. @@ -14,7 +13,7 @@ fn context_init(c: &mut Criterion) { ContextHandle::create_and_init( &mut *stack, &mut parent, - FunctionPointer::from_usize(f as usize), + f as usize, &[], ) .unwrap(); @@ -34,7 +33,7 @@ fn context_swap_return(c: &mut Criterion) { let child = ContextHandle::create_and_init( &mut *stack, &mut parent, - FunctionPointer::from_usize(f as usize), + f as usize, &[], ) .unwrap(); @@ -61,7 +60,7 @@ fn context_init_swap_return(c: &mut Criterion) { let child = ContextHandle::create_and_init( &mut *stack, &mut parent, - FunctionPointer::from_usize(f as usize), + f as usize, &[], ) .unwrap(); @@ -354,7 +353,7 @@ fn context_init_swap_return_many_args(c: &mut Criterion) { let child = ContextHandle::create_and_init( &mut *stack, &mut parent, - FunctionPointer::from_usize(f as usize), + f as usize, &args, ) .unwrap(); diff --git a/benchmarks/lucet-benchmarks/src/modules.rs b/benchmarks/lucet-benchmarks/src/modules.rs index 77e892711..fc49dc09a 100644 --- a/benchmarks/lucet-benchmarks/src/modules.rs +++ b/benchmarks/lucet-benchmarks/src/modules.rs @@ -1,8 +1,8 @@ -use lucet_module_data::FunctionPointer; use lucet_runtime::lucet_hostcalls; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; -use lucet_runtime_internals::module::{HeapSpec, MockModuleBuilder, Module}; -use lucet_runtime_tests::helpers::MockExportBuilder; +use lucet_runtime_internals::module::{ + FunctionPointer, HeapSpec, MockExportBuilder, MockModuleBuilder, Module, +}; use lucet_wasi_sdk::{CompileOpts, Lucetc}; use lucetc::{Bindings, LucetcOpts, OptLevel}; use std::path::Path; @@ -28,7 +28,10 @@ pub fn null_mock() -> Arc { extern "C" fn f(_vmctx: *mut lucet_vmctx) {} MockModuleBuilder::new() - .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize))) + .with_export_func(MockExportBuilder::new( + "f", + FunctionPointer::from_usize(f as usize), + )) .build() } @@ -50,7 +53,10 @@ pub fn large_dense_heap_mock(heap_kb: usize) -> Arc { }); MockModuleBuilder::new() - .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize))) + .with_export_func(MockExportBuilder::new( + "f", + FunctionPointer::from_usize(f as usize), + )) .with_initial_heap(heap.as_slice()) .with_heap_spec(heap_spec) .build() @@ -81,7 +87,10 @@ pub fn large_sparse_heap_mock(heap_kb: usize, stride: usize) -> Arc }); MockModuleBuilder::new() - .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize))) + .with_export_func(MockExportBuilder::new( + "f", + FunctionPointer::from_usize(f as usize), + )) .with_initial_heap(heap.as_slice()) .with_heap_spec(heap_spec) .build() @@ -102,7 +111,10 @@ pub fn fib_mock() -> Arc { } MockModuleBuilder::new() - .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize))) + .with_export_func(MockExportBuilder::new( + "f", + FunctionPointer::from_usize(f as usize), + )) .build() } @@ -179,7 +191,10 @@ pub fn many_args_mock() -> Arc { } MockModuleBuilder::new() - .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize))) + .with_export_func(MockExportBuilder::new( + "f", + FunctionPointer::from_usize(f as usize), + )) .build() } @@ -254,9 +269,13 @@ pub fn hostcalls_mock() -> Arc { } MockModuleBuilder::new() - .with_export_func( - MockExportBuilder::new("wrapped", FunctionPointer::from_usize(wrapped as usize))) - .with_export_func( - MockExportBuilder::new("raw", FunctionPointer::from_usize(raw as usize))) + .with_export_func(MockExportBuilder::new( + "wrapped", + FunctionPointer::from_usize(wrapped as usize), + )) + .with_export_func(MockExportBuilder::new( + "raw", + FunctionPointer::from_usize(raw as usize), + )) .build() } diff --git a/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs b/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs index c66ba09c8..f2a24bad1 100644 --- a/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs @@ -106,7 +106,7 @@ pub struct Alloc { impl Drop for Alloc { fn drop(&mut self) { - eprintln!("Alloc::drop()"); + // eprintln!("Alloc::drop()"); self.region.clone().drop_alloc(self); } } @@ -133,8 +133,7 @@ impl Alloc { let host_page_size = host_page_size() as u32; - dbg!(self.heap_accessible_size); - if dbg!(self.heap_accessible_size as u32) % dbg!(host_page_size) != 0 { + if self.heap_accessible_size as u32 % host_page_size != 0 { lucet_bail!("heap is not page-aligned; this is a bug"); } @@ -192,7 +191,6 @@ impl Alloc { .expand_heap(slot, newly_accessible as u32, expand_pagealigned)?; self.heap_accessible_size += expand_pagealigned as usize; - dbg!(self.heap_accessible_size); self.heap_inaccessible_size -= expand_pagealigned as usize; Ok(newly_accessible as u32) diff --git a/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs b/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs index 4ef68993a..14bc5312c 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs @@ -32,12 +32,8 @@ fn init_rejects_unaligned() { // now we have the unaligned stack, let's make sure it blows up right let mut parent = ContextHandle::new(); - let res = ContextHandle::create_and_init( - &mut stack_unaligned, - &mut parent, - dummy as usize, - &[], - ); + let res = + ContextHandle::create_and_init(&mut stack_unaligned, &mut parent, dummy as usize, &[]); if let Err(Error::UnalignedStack) = res { assert!(true); diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index 5a49d1487..47c54fb70 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -140,7 +140,7 @@ impl DerefMut for InstanceHandle { impl Drop for InstanceHandle { fn drop(&mut self) { - if dbg!(self.needs_inst_drop) { + if self.needs_inst_drop { unsafe { let inst = self.inst.as_mut(); @@ -668,7 +668,7 @@ impl Instance { fn run_start(&mut self) -> Result<(), Error> { if let Some(start) = self.module.get_start_func()? { - dbg!(self.run_func(start, &[])?); + self.run_func(start, &[])?; } Ok(()) } diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs index 0240d9191..525364792 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs @@ -167,7 +167,7 @@ impl RegionInternal for MmapRegion { )? }; } - alloc.heap_accessible_size = dbg!(initial_size); + alloc.heap_accessible_size = initial_size; alloc.heap_inaccessible_size = alloc.slot().limits.heap_address_space_size - initial_size; // Initialize the heap using the module sparse page data. There cannot be more pages in the diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mod.rs b/lucet-runtime/lucet-runtime-internals/src/region/mod.rs index 5339e6b2e..7099ed639 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mod.rs @@ -100,8 +100,6 @@ impl<'a> InstanceBuilder<'a> { /// This function runs the guest code for the WebAssembly `start` section, and running any guest /// code is potentially unsafe; see [`Instance::run()`](struct.Instance.html#method.run). pub fn build(self) -> Result { - let inst = self.region.new_instance_with(self.module, self.embed_ctx)?; - dbg!(inst.heap().len()); - Ok(inst) + self.region.new_instance_with(self.module, self.embed_ctx) } } diff --git a/lucet-runtime/src/c_api.rs b/lucet-runtime/src/c_api.rs index b4a5fc2ab..700599e09 100644 --- a/lucet-runtime/src/c_api.rs +++ b/lucet-runtime/src/c_api.rs @@ -281,7 +281,7 @@ pub unsafe extern "C" fn lucet_instance_grow_heap( } lucet_error::Ok } - Err(e) => dbg!(e).into(), + Err(e) => e.into(), } }) } diff --git a/lucet-wasi/src/c_api.rs b/lucet-wasi/src/c_api.rs index 7d64e8ba8..be8dc9416 100644 --- a/lucet-wasi/src/c_api.rs +++ b/lucet-wasi/src/c_api.rs @@ -80,7 +80,6 @@ pub unsafe extern "C" fn lucet_region_new_instance_with_wasi_ctx( .with_embed_ctx(wasi_ctx.build()) .build() .map(|i| { - dbg!(i.heap().len()); inst_out.write(instance_handle_to_raw(i) as _); lucet_error::Ok }) From de6a4a01b1d14a5e8128c152bd403494562c1ee0 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Fri, 24 May 2019 20:21:32 +0900 Subject: [PATCH 147/512] [lucet-runtime] add repr(C) to all C API opaque structs --- lucet-runtime/lucet-runtime-internals/src/c_api.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lucet-runtime/lucet-runtime-internals/src/c_api.rs b/lucet-runtime/lucet-runtime-internals/src/c_api.rs index 9878ee1b0..4c74a1de9 100644 --- a/lucet-runtime/lucet-runtime-internals/src/c_api.rs +++ b/lucet-runtime/lucet-runtime-internals/src/c_api.rs @@ -99,14 +99,17 @@ impl From for lucet_error { } } +#[repr(C)] pub struct lucet_instance { _unused: [u8; 0], } +#[repr(C)] pub struct lucet_region { _unused: [u8; 0], } +#[repr(C)] pub struct lucet_dl_module { _unused: [u8; 0], } From 826cc7a01fa8ee700c25079369424a2b790d7e6b Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 30 May 2019 20:48:20 +0200 Subject: [PATCH 148/512] Replace the wasm32-unknown-wasi prefix with wasm32-wasi --- README.md | 4 ++-- helpers/install.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1a143dc27..a7c559494 100644 --- a/README.md +++ b/README.md @@ -239,12 +239,12 @@ int main(void) Time to compile to WebAssembly! The development environment includes a version of the Clang toolchain that is built to generate WebAssembly by default. The related commands are accessible from your current shell, and are prefixed by -`wasm32-unknown-wasi-`. +`wasm32-wasi-`. For example, to create a WebAssembly module `hello.wasm` from `hello.c`: ```sh -wasm32-unknown-wasi-clang -Ofast -o hello.wasm hello.c +wasm32-wasi-clang -Ofast -o hello.wasm hello.c ``` The next step is to use Lucet to build native `x86_64` code from that diff --git a/helpers/install.sh b/helpers/install.sh index ff6c61e1a..1f104e24a 100755 --- a/helpers/install.sh +++ b/helpers/install.sh @@ -25,7 +25,7 @@ LUCET_BUNDLE_DOC_DIR=${LUCET_BUNDLE_DOC_DIR:-"${LUCET_DOC_DIR}/lucet"} WASI_PREFIX=${WASI_PREFIX:-${WASI_SDK:-"/opt/wasi-sdk"}} WASI_BIN=${WASI_BIN:-"${WASI_PREFIX}/bin"} WASI_SYSROOT=${WASI_SYSROOT:-"${WASI_PREFIX}/share/sysroot"} -WASI_TARGET=${WASI_TARGET:-"wasm32-unknown-wasi"} +WASI_TARGET=${WASI_TARGET:-"wasm32-wasi"} WASI_BIN_PREFIX=${WASI_BIN_PREFIX:-"$WASI_TARGET"} BINS="lucet-analyze lucet-wasi lucetc sightglass spec-test wasmonkey" From c376ec9162547e02cc33fb889f2f4503d318a44d Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 31 May 2019 11:49:24 +0200 Subject: [PATCH 149/512] Fix a path_get() bug with nested directories When traversing directories, we should keep the most recent file descriptor. Add a test case originally triggering that bug. Spotted by @kubkon -- thanks! --- lucet-wasi/src/hostcalls/fs_helpers.rs | 2 +- lucet-wasi/tests/guests/fs.c | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lucet-wasi/src/hostcalls/fs_helpers.rs b/lucet-wasi/src/hostcalls/fs_helpers.rs index 3c6756013..a82924e48 100644 --- a/lucet-wasi/src/hostcalls/fs_helpers.rs +++ b/lucet-wasi/src/hostcalls/fs_helpers.rs @@ -163,7 +163,7 @@ pub fn path_get>( || (component.ends_with(b"/") && !needs_final_component) => { match openat( - *dir_stack.first().expect("dir_stack is never empty"), + *dir_stack.last().expect("dir_stack is never empty"), component, OFlag::O_RDONLY | OFlag::O_DIRECTORY | OFlag::O_NOFOLLOW, Mode::empty(), diff --git a/lucet-wasi/tests/guests/fs.c b/lucet-wasi/tests/guests/fs.c index 3d30ae0f0..6f4bfa78e 100644 --- a/lucet-wasi/tests/guests/fs.c +++ b/lucet-wasi/tests/guests/fs.c @@ -145,5 +145,14 @@ int main(void) res = closedir(dir); assert(res == 0); + res = mkdir("/sandbox/a", 0755); + assert(res == 0); + res = mkdir("/sandbox/a/b", 0755); + assert(res == 0); + res = mkdir("/sandbox/a/b/c", 0755); + assert(res == 0); + res = access("/sandbox/a/b/c", R_OK); + assert(res == 0); + return 0; } From c181c7bfdc5dbc7f59aecfd3996975c614e59e2b Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 30 May 2019 23:42:40 +0200 Subject: [PATCH 150/512] Rename lucetc optimization levels --- benchmarks/lucet-benchmarks/src/compile.rs | 2 +- benchmarks/lucet-benchmarks/src/par.rs | 2 +- benchmarks/lucet-benchmarks/src/seq.rs | 8 +++---- lucet-spectest/src/script.rs | 2 +- lucetc/src/compiler.rs | 14 ++++++------ lucetc/src/options.rs | 12 +++++----- lucetc/tests/wasi-sdk.rs | 8 +++---- lucetc/tests/wasm.rs | 26 +++++++++++----------- 8 files changed, 37 insertions(+), 37 deletions(-) diff --git a/benchmarks/lucet-benchmarks/src/compile.rs b/benchmarks/lucet-benchmarks/src/compile.rs index ff351531a..85fd65920 100644 --- a/benchmarks/lucet-benchmarks/src/compile.rs +++ b/benchmarks/lucet-benchmarks/src/compile.rs @@ -19,7 +19,7 @@ fn compile_hello_all(c: &mut Criterion) { criterion::BatchSize::SmallInput, ) }, - &[OptLevel::Fastest, OptLevel::Default, OptLevel::Best], + &[OptLevel::None, OptLevel::Standard, OptLevel::Fast], ) .sample_size(10); diff --git a/benchmarks/lucet-benchmarks/src/par.rs b/benchmarks/lucet-benchmarks/src/par.rs index ac535aa7f..ac595f3d5 100644 --- a/benchmarks/lucet-benchmarks/src/par.rs +++ b/benchmarks/lucet-benchmarks/src/par.rs @@ -42,7 +42,7 @@ fn par_instantiate(c: &mut Criterion) { let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); - compile_hello(&so_file, OptLevel::Best); + compile_hello(&so_file, OptLevel::Fast); let module = DlModule::load(&so_file).unwrap(); diff --git a/benchmarks/lucet-benchmarks/src/seq.rs b/benchmarks/lucet-benchmarks/src/seq.rs index b8360dbbf..4e8462e4c 100644 --- a/benchmarks/lucet-benchmarks/src/seq.rs +++ b/benchmarks/lucet-benchmarks/src/seq.rs @@ -29,7 +29,7 @@ fn hello_load_mkregion_and_instantiate(c: &mut Criter let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); - compile_hello(&so_file, OptLevel::Best); + compile_hello(&so_file, OptLevel::Fast); c.bench_function( &format!("hello_load_mkregion_and_instantiate ({})", R::TYPE_NAME), @@ -57,7 +57,7 @@ fn hello_instantiate(c: &mut Criterion) { let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); - compile_hello(&so_file, OptLevel::Best); + compile_hello(&so_file, OptLevel::Fast); let module = DlModule::load(&so_file).unwrap(); let region = R::create(1, &Limits::default()).unwrap(); @@ -125,7 +125,7 @@ fn hello_drop_instance(c: &mut Criterion) { let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); - compile_hello(&so_file, OptLevel::Best); + compile_hello(&so_file, OptLevel::Fast); let module = DlModule::load(&so_file).unwrap(); let region = R::create(1, &Limits::default()).unwrap(); @@ -246,7 +246,7 @@ fn run_hello(c: &mut Criterion) { let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); - compile_hello(&so_file, OptLevel::Best); + compile_hello(&so_file, OptLevel::Fast); let module = DlModule::load(&so_file).unwrap(); let region = R::create(1, &Limits::default()).unwrap(); diff --git a/lucet-spectest/src/script.rs b/lucet-spectest/src/script.rs index db0269d13..b6e5f58ae 100644 --- a/lucet-spectest/src/script.rs +++ b/lucet-spectest/src/script.rs @@ -67,7 +67,7 @@ impl ScriptEnv { } pub fn instantiate(&mut self, module: &[u8], name: &Option) -> Result<(), ScriptError> { let bindings = bindings::spec_test_bindings(); - let compiler = Compiler::new(module, OptLevel::Best, &bindings, HeapSettings::default()) + let compiler = Compiler::new(module, OptLevel::Fast, &bindings, HeapSettings::default()) .map_err(program_error)?; let dir = tempfile::Builder::new().prefix("codegen").tempdir()?; diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index eb5acec40..e40624884 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -23,23 +23,23 @@ use lucet_module_data::{FunctionSpec, ModuleData}; #[derive(Debug, Clone, Copy)] pub enum OptLevel { - Default, - Best, - Fastest, + None, + Standard, + Fast, } impl Default for OptLevel { fn default() -> OptLevel { - OptLevel::Default + OptLevel::Standard } } impl OptLevel { pub fn to_flag(&self) -> &str { match self { - OptLevel::Default => "default", - OptLevel::Best => "best", - OptLevel::Fastest => "fastest", + OptLevel::None => "fast", + OptLevel::Standard => "default", + OptLevel::Fast => "best", } } } diff --git a/lucetc/src/options.rs b/lucetc/src/options.rs index 427b0a45b..96caabdb5 100644 --- a/lucetc/src/options.rs +++ b/lucetc/src/options.rs @@ -94,10 +94,10 @@ impl Options { }; let opt_level = match m.value_of("opt_level") { - None => OptLevel::Default, - Some("default") => OptLevel::Default, - Some("best") => OptLevel::Best, - Some("fastest") => OptLevel::Fastest, + None => OptLevel::default(), + Some("0") => OptLevel::None, + Some("1") => OptLevel::Standard, + Some("2") => OptLevel::Fast, Some(_) => panic!("unknown value for opt-level"), }; @@ -195,8 +195,8 @@ impl Options { Arg::with_name("opt_level") .long("--opt-level") .takes_value(true) - .possible_values(&["default", "fastest", "best"]) - .help("optimization level (default: 'default')"), + .possible_values(&["0", "1", "2"]) + .help("optimization level (default: '1')"), ) .get_matches(); diff --git a/lucetc/tests/wasi-sdk.rs b/lucetc/tests/wasi-sdk.rs index 48fb51f62..4ced38eb4 100644 --- a/lucetc/tests/wasi-sdk.rs +++ b/lucetc/tests/wasi-sdk.rs @@ -56,7 +56,7 @@ mod programs { let m = module_from_c(&["empty"], &[]).expect("build module for empty"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile empty"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile empty"); let mdata = c.module_data().unwrap(); assert!(mdata.heap_spec().is_some()); // clang creates 3 globals, all internal: @@ -87,7 +87,7 @@ mod programs { let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile a"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile a"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 0, "import functions"); @@ -105,7 +105,7 @@ mod programs { let m = module_from_c(&["b"], &["b"]).expect("build module for b"); let b = b_only_test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile b"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile b"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 1, "import functions"); assert_eq!(mdata.export_functions().len(), 1, "export functions"); @@ -121,7 +121,7 @@ mod programs { let m = module_from_c(&["a", "b"], &["a", "b"]).expect("build module for a & b"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile a & b"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile a & b"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 0, "import functions"); assert_eq!(mdata.export_functions().len(), 2, "export functions"); diff --git a/lucetc/tests/wasm.rs b/lucetc/tests/wasm.rs index 2c9cfe133..dd09e30a2 100644 --- a/lucetc/tests/wasm.rs +++ b/lucetc/tests/wasm.rs @@ -40,7 +40,7 @@ mod module_data { let m = load_wat_module("fibonacci"); let b = super::test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compiling fibonacci"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compiling fibonacci"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.globals_spec().len(), 0); @@ -54,7 +54,7 @@ mod module_data { let m = load_wat_module("arith"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compiling arith"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compiling arith"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.globals_spec().len(), 0); @@ -70,7 +70,7 @@ mod module_data { )) .unwrap(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile icall"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile icall"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 1); @@ -106,7 +106,7 @@ mod module_data { let m = load_wat_module("icall"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile icall"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile icall"); let _module_data = c.module_data().unwrap(); /* TODO can't express these with module data @@ -131,7 +131,7 @@ mod module_data { let m = load_wat_module("icall_sparse"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile icall_sparse"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile icall_sparse"); let _module_data = c.module_data().unwrap(); /* TODO can't express these with module data @@ -170,7 +170,7 @@ mod module_data { let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile globals_import"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile globals_import"); let module_data = c.module_data().unwrap(); let gspec = module_data.globals_spec(); @@ -192,7 +192,7 @@ mod module_data { let b = Bindings::empty(); let h = HeapSettings::default(); let c = - Compiler::new(&m, OptLevel::Best, &b, h.clone()).expect("compiling heap_spec_import"); + Compiler::new(&m, OptLevel::Fast, &b, h.clone()).expect("compiling heap_spec_import"); assert_eq!( c.module_data().unwrap().heap_spec(), @@ -214,7 +214,7 @@ mod module_data { let m = load_wat_module("heap_spec_definition"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Best, &b, h.clone()) + let c = Compiler::new(&m, OptLevel::Fast, &b, h.clone()) .expect("compiling heap_spec_definition"); assert_eq!( @@ -236,7 +236,7 @@ mod module_data { let m = load_wat_module("heap_spec_none"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compiling heap_spec_none"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compiling heap_spec_none"); assert_eq!(c.module_data().unwrap().heap_spec(), None,); } @@ -245,7 +245,7 @@ mod module_data { let m = load_wat_module("oversize_data_segment"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Best, &b, h); + let c = Compiler::new(&m, OptLevel::Fast, &b, h); assert!( c.is_err(), "compilation error because data initializers are oversized" @@ -268,7 +268,7 @@ mod module_data { let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Best, &b, h); + let c = Compiler::new(&m, OptLevel::Fast, &b, h); assert!( c.is_err(), "compilation error because wasm module is invalid" @@ -281,7 +281,7 @@ mod module_data { let m = load_wat_module("start_section"); let b = Bindings::empty(); let h = HeapSettings::default(); - let _c = Compiler::new(&m, OptLevel::Best, &b, h).expect("compile start_section"); + let _c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile start_section"); /* assert!( p.module().start_section().is_some(), @@ -299,7 +299,7 @@ mod compile { let m = load_wat_module(file); let b = super::test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Best, &b, h).expect(&format!("compile {}", file)); + let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect(&format!("compile {}", file)); let _obj = c.object_file().expect(&format!("codegen {}", file)); } macro_rules! compile_test { From c8bea80c56b4e88b9869d341dfba429a226c4580 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 31 May 2019 11:59:56 +0200 Subject: [PATCH 151/512] Add the "fast" optimization level Currently equivalent to "2", but if costly optimizations are introduced later (e.g. a superoptimizer), "fast" will target the new optimization level. --- lucetc/src/options.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lucetc/src/options.rs b/lucetc/src/options.rs index 96caabdb5..8adcd2c9d 100644 --- a/lucetc/src/options.rs +++ b/lucetc/src/options.rs @@ -97,7 +97,7 @@ impl Options { None => OptLevel::default(), Some("0") => OptLevel::None, Some("1") => OptLevel::Standard, - Some("2") => OptLevel::Fast, + Some("2") | Some("fast") => OptLevel::Fast, Some(_) => panic!("unknown value for opt-level"), }; @@ -195,7 +195,7 @@ impl Options { Arg::with_name("opt_level") .long("--opt-level") .takes_value(true) - .possible_values(&["0", "1", "2"]) + .possible_values(&["0", "1", "2", "fast"]) .help("optimization level (default: '1')"), ) .get_matches(); From d3674f97eab38eda46a539f71fa80634a7a4f05a Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Fri, 31 May 2019 19:31:18 +0200 Subject: [PATCH 152/512] Update Rust to 1.35.0 and WASI-SDK (#187) * Update Rust to 1.35.0, wasi-sdk to 5.0 * Use consistent indentation for the Dockerfile --- Dockerfile | 28 ++++++++++++++-------------- helpers/indent.sh | 4 ++-- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Dockerfile b/Dockerfile index 294b4a433..8b76ea092 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ FROM ubuntu:xenial RUN apt-get update \ - && apt-get install -y --no-install-recommends \ + && apt-get install -y --no-install-recommends \ build-essential \ curl \ git \ @@ -13,13 +13,13 @@ RUN apt-get update \ ca-certificates \ software-properties-common \ libssl-dev \ - pkg-config \ - csmith \ - libcsmith-dev \ - creduce \ - gcc-multilib \ - clang-6.0 \ - && rm -rf /var/lib/apt/lists/* + pkg-config \ + csmith \ + libcsmith-dev \ + creduce \ + gcc-multilib \ + clang-6.0 \ + && rm -rf /var/lib/apt/lists/* RUN update-alternatives --install /usr/bin/clang clang /usr/bin/clang-6.0 100 @@ -27,16 +27,16 @@ RUN update-alternatives --install /usr/bin/clang clang /usr/bin/clang-6.0 100 # rebuilds. ENV LD_LIBRARY_PATH=/usr/local/lib -RUN curl -sS -L -O https://static.rust-lang.org/dist/rust-1.34.2-x86_64-unknown-linux-gnu.tar.gz \ - && tar xzf rust-1.34.2-x86_64-unknown-linux-gnu.tar.gz \ - && cd rust-1.34.2-x86_64-unknown-linux-gnu \ +RUN curl -sS -L -O https://static.rust-lang.org/dist/rust-1.35.0-x86_64-unknown-linux-gnu.tar.gz \ + && tar xzf rust-1.35.0-x86_64-unknown-linux-gnu.tar.gz \ + && cd rust-1.35.0-x86_64-unknown-linux-gnu \ && ./install.sh \ && cd .. \ - && rm -rf rust-1.34.2-x86_64-unknown-linux-gnu rust-1.34.2-x86_64-unknown-linux-gnu.tar.gz + && rm -rf rust-1.35.0-x86_64-unknown-linux-gnu rust-1.35.0-x86_64-unknown-linux-gnu.tar.gz ENV PATH=/usr/local/bin:$PATH RUN cargo install --root /usr/local cargo-audit cargo-watch -RUN curl -sS -L -O https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-4/wasi-sdk_4.0_amd64.deb \ - && dpkg -i wasi-sdk_4.0_amd64.deb && rm -f wasi-sdk_4.0_amd64.deb +RUN curl -sS -L -O https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-5/wasi-sdk_5.0_amd64.deb \ + && dpkg -i wasi-sdk_5.0_amd64.deb && rm -f wasi-sdk_5.0_amd64.deb ENV WASI_SDK=/opt/wasi-sdk diff --git a/helpers/indent.sh b/helpers/indent.sh index b7c77c432..76b652819 100755 --- a/helpers/indent.sh +++ b/helpers/indent.sh @@ -10,8 +10,8 @@ cleanup () { } trap cleanup 1 2 3 6 9 15 -if ! $(rustfmt --version | grep -q "rustfmt 1.0.3-stable"); then - echo "indent requires rustfmt 1.0.3-stable" +if ! $(rustfmt --version | grep -q "rustfmt 1.2.0-stable"); then + echo "indent requires rustfmt 1.2.0-stable" exit 1; fi From a9b409dd56ca746cd1db4d27ceb55182f50429c5 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Fri, 31 May 2019 12:31:57 -0700 Subject: [PATCH 153/512] [lucet-wasi] include bindings.json in deb package --- lucet-wasi/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index 8d9ba2025..f12b5da80 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -42,4 +42,5 @@ assets = [ ["LICENSE", "/opt/fst-lucet-wasi/share/doc/lucet-wasi/", "644"], ["LICENSE.wasmtime", "/opt/fst-lucet-wasi/share/doc/lucet-wasi/", "644"], ["LICENSE.cloudabi-utils", "/opt/fst-lucet-wasi/share/doc/lucet-wasi/", "644"], + ["bindings.json", "/opt/fst-lucet-wasi/share/", "644"], ] From 88819b1431cbc1920232c6ed5be517b2455b5a48 Mon Sep 17 00:00:00 2001 From: awortman-fastly <49215183+awortman-fastly@users.noreply.github.com> Date: Mon, 3 Jun 2019 10:39:09 -0700 Subject: [PATCH 154/512] Emit function information for lucetc-provided functions (#190) * emit function information for lucetc-provided functions (runtime funcs and stack probe) * refactor function declaration to hide away internal bookkeeping --- lucetc/src/compiler.rs | 2 + lucetc/src/decls.rs | 194 ++++++++++++++++++++++---------------- lucetc/src/function.rs | 2 +- lucetc/src/module.rs | 22 +++++ lucetc/src/output.rs | 22 +++-- lucetc/src/runtime.rs | 8 +- lucetc/src/stack_probe.rs | 23 +++++ lucetc/tests/wasm.rs | 6 +- 8 files changed, 183 insertions(+), 96 deletions(-) diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index e40624884..9cc82d858 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -132,6 +132,8 @@ impl<'a> Compiler<'a> { .context(LucetcErrorKind::FunctionDefinition)?; } + stack_probe::declare_metadata(&mut self.decls, &mut self.clif_module).unwrap(); + write_module_data(&mut self.clif_module, &self.decls)?; write_startfunc_data(&mut self.clif_module, &self.decls)?; write_table_data(&mut self.clif_module, &self.decls)?; diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index d494c5f98..de146b664 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -44,10 +44,16 @@ impl<'a> FunctionDecl<'a> { /// Function provided by lucet-runtime to be called from generated code, e.g. memory size & grow /// functions. pub struct RuntimeDecl<'a> { - pub signature: &'a ir::Signature, + signature: &'a ir::Signature, pub name: Name, } +impl<'a> RuntimeDecl<'a> { + pub fn signature(&self) -> &'a ir::Signature { + self.signature + } +} + #[derive(Debug)] pub struct TableDecl<'a> { pub import_name: Option<(&'a str, &'a str)>, @@ -60,12 +66,11 @@ pub struct TableDecl<'a> { pub struct ModuleDecls<'a> { info: ModuleInfo<'a>, - runtime: Runtime, function_names: PrimaryMap, imports: Vec>, exports: Vec>, table_names: PrimaryMap, - runtime_names: HashMap, + runtime_names: HashMap, globals_spec: Vec>, linear_memory_spec: Option, } @@ -78,88 +83,121 @@ impl<'a> ModuleDecls<'a> { runtime: Runtime, heap_settings: HeapSettings, ) -> Result { - let (function_names, imports, exports) = Self::declare_funcs(&info, clif_module, bindings)?; + let imports: Vec> = Vec::with_capacity(info.imported_funcs.len()); let table_names = Self::declare_tables(&info, clif_module)?; - let runtime_names = Self::declare_runtime(&runtime, clif_module)?; - let globals_spec = Self::declare_globals_spec(&info)?; - let linear_memory_spec = Self::declare_linear_memory_spec(&info, heap_settings)?; - Ok(Self { + let globals_spec = Self::build_globals_spec(&info)?; + let linear_memory_spec = Self::build_linear_memory_spec(&info, heap_settings)?; + let mut decls = Self { info, - function_names, + function_names: PrimaryMap::new(), imports, - exports, + exports: vec![], table_names, - runtime_names, - runtime, + runtime_names: HashMap::new(), globals_spec, linear_memory_spec, - }) + }; + + Self::declare_funcs(&mut decls, clif_module, bindings)?; + Self::declare_runtime(&mut decls, clif_module, runtime)?; + + Ok(decls) } // ********************* Constructor auxillary functions *********************** fn declare_funcs( - info: &ModuleInfo<'a>, + decls: &mut ModuleDecls<'a>, clif_module: &mut ClifModule, bindings: &Bindings, - ) -> Result< - ( - PrimaryMap, - Vec>, - Vec>, - ), - LucetcError, - > { - let mut function_names = PrimaryMap::new(); - let mut exports: Vec> = Vec::new(); - let mut imports: Vec> = Vec::with_capacity(info.imported_funcs.len()); - - for ix in 0..info.functions.len() { + ) -> Result<(), LucetcError> { + for ix in 0..decls.info.functions.len() { let func_index = FuncIndex::new(ix); - let exportable_sigix = info.functions.get(func_index).unwrap(); - let inner_sig_index = info.signature_mapping.get(exportable_sigix.entity).unwrap(); - let signature = info.signatures.get(*inner_sig_index).unwrap(); - - let exported_name = if !exportable_sigix.export_names.is_empty() { - exports.push(ExportFunction { - fn_idx: LucetFunctionIndex::from_u32(function_names.len() as u32), - names: exportable_sigix.export_names.clone(), - }); - - Some(( - format!("guest_func_{}", exportable_sigix.export_names[0]), - Linkage::Export, - )) - } else { - None + + fn export_name_for<'a>( + func_ix: FuncIndex, + decls: &mut ModuleDecls<'a>, + ) -> Option<(String, Linkage)> { + let export = decls.info.functions.get(func_ix).unwrap(); + + if !export.export_names.is_empty() { + decls.exports.push(ExportFunction { + fn_idx: LucetFunctionIndex::from_u32(decls.function_names.len() as u32), + names: export.export_names.clone(), + }); + + Some(( + format!("guest_func_{}", export.export_names[0]), + Linkage::Export, + )) + } else { + None + } }; - let imported_name = - if let Some((import_mod, import_field)) = info.imported_funcs.get(func_index) { - imports.push(ImportFunction { - fn_idx: LucetFunctionIndex::from_u32(function_names.len() as u32), + fn import_name_for<'a>( + func_ix: FuncIndex, + decls: &mut ModuleDecls<'a>, + bindings: &Bindings, + ) -> Result, failure::Context> { + if let Some((import_mod, import_field)) = decls.info.imported_funcs.get(func_ix) { + decls.imports.push(ImportFunction { + fn_idx: LucetFunctionIndex::from_u32(decls.function_names.len() as u32), module: import_mod, name: import_field, }); let import_symbol = bindings .translate(import_mod, import_field) .context(LucetcErrorKind::TranslatingModule)?; - Some((import_symbol, Linkage::Import)) + Ok(Some((import_symbol, Linkage::Import))) } else { - None - }; + Ok(None) + } + }; - let (decl_sym, decl_linkage) = imported_name - .or(exported_name) + let (decl_sym, decl_linkage) = import_name_for(func_index, decls, bindings)? + .or_else(|| export_name_for(func_index, decls)) .unwrap_or_else(|| (format!("guest_func_{}", ix), Linkage::Local)); - let funcid = clif_module - .declare_function(&decl_sym, decl_linkage, signature) - .context(LucetcErrorKind::TranslatingModule)?; - - function_names.push(Name::new_func(decl_sym, funcid)); + decls.declare_function(clif_module, decl_sym, decl_linkage, func_index)?; } - Ok((function_names, imports, exports)) + Ok(()) + } + + /// Insert a new function into this set of decls and declare it appropriately to `clif_module`. + /// This is intended for cases where `lucetc` adds a new function that was not present in the + /// original wasm - in these cases, Cranelift has not already declared the signature or + /// function type, let alone name, linkage, etc. So we must do that ourselves! + pub fn declare_new_function( + &mut self, + clif_module: &mut ClifModule, + decl_sym: String, + decl_linkage: Linkage, + signature: ir::Signature, + ) -> Result { + let (new_funcidx, _) = self.info.declare_func_with_sig(signature); + + self.declare_function(clif_module, decl_sym, decl_linkage, new_funcidx) + } + + /// The internal side of fixing up a new function declaration. This is also the work that must + /// be done when building a ModuleDecls record of functions that were described by ModuleInfo. + fn declare_function( + &mut self, + clif_module: &mut ClifModule, + decl_sym: String, + decl_linkage: Linkage, + func_ix: FuncIndex, + ) -> Result { + let funcid = clif_module + .declare_function( + &decl_sym, + decl_linkage, + self.info.signature_for_function(func_ix), + ) + .context(LucetcErrorKind::TranslatingModule)?; + self.function_names.push(Name::new_func(decl_sym, funcid)); + Ok(FuncIndex::new(self.function_names.len() - 1)) } fn declare_tables( @@ -186,27 +224,29 @@ impl<'a> ModuleDecls<'a> { } fn declare_runtime( - runtime: &Runtime, + decls: &mut ModuleDecls<'a>, clif_module: &mut ClifModule, - ) -> Result, LucetcError> { - let mut runtime_names: HashMap = HashMap::new(); + runtime: Runtime, + ) -> Result<(), LucetcError> { for (func, (symbol, signature)) in runtime.functions.iter() { - let funcid = clif_module - .declare_function(&symbol, Linkage::Import, signature) - .context(LucetcErrorKind::TranslatingModule)?; - let name = Name::new_func(symbol.clone(), funcid); - - runtime_names.insert(*func, name); + let func_id = decls.declare_new_function( + clif_module, + symbol.clone(), + Linkage::Import, + signature.clone(), + )?; + + decls.runtime_names.insert(*func, func_id); } - Ok(runtime_names) + Ok(()) } - fn declare_linear_memory_spec( + fn build_linear_memory_spec( info: &ModuleInfo<'a>, heap_settings: HeapSettings, ) -> Result, LucetcError> { use crate::sparsedata::owned_sparse_data_from_initializers; - if let Some(heap_spec) = Self::declare_heap_spec(info, heap_settings)? { + if let Some(heap_spec) = Self::build_heap_spec(info, heap_settings)? { let data_initializers = info .data_initializers .get(&MemoryIndex::new(0)) @@ -222,7 +262,7 @@ impl<'a> ModuleDecls<'a> { } } - fn declare_globals_spec(info: &ModuleInfo<'a>) -> Result>, LucetcError> { + fn build_globals_spec(info: &ModuleInfo<'a>) -> Result>, LucetcError> { let mut globals = Vec::new(); for ix in 0..info.globals.len() { let ix = GlobalIndex::new(ix); @@ -250,7 +290,7 @@ impl<'a> ModuleDecls<'a> { Ok(globals) } - fn declare_heap_spec( + fn build_heap_spec( info: &ModuleInfo<'a>, heap_settings: HeapSettings, ) -> Result, LucetcError> { @@ -326,14 +366,10 @@ impl<'a> ModuleDecls<'a> { } pub fn get_runtime(&self, runtime_func: RuntimeFunc) -> Result { - let (_, signature) = self - .runtime - .functions - .get(&runtime_func) - .ok_or_else(|| format_err!("runtime func not supported: {:?}", runtime_func))?; - let name = self.runtime_names.get(&runtime_func).unwrap(); + let func_id = *self.runtime_names.get(&runtime_func).unwrap(); + let name = self.function_names.get(func_id).unwrap(); Ok(RuntimeDecl { - signature, + signature: self.info.signature_for_function(func_id), name: name.clone(), }) } diff --git a/lucetc/src/function.rs b/lucetc/src/function.rs index 8892e8bd1..6c59bd43f 100644 --- a/lucetc/src/function.rs +++ b/lucetc/src/function.rs @@ -67,7 +67,7 @@ impl<'a> FuncInfo<'a> { .module_decls .get_runtime(runtime_func) .expect("runtime function not available"); - let signature = func.import_signature(decl.signature.clone()); + let signature = func.import_signature(decl.signature().to_owned()); let fref = func.import_function(ir::ExtFuncData { name: decl.name.into(), signature, diff --git a/lucetc/src/module.rs b/lucetc/src/module.rs index 4975a3276..e90c35ed7 100644 --- a/lucetc/src/module.rs +++ b/lucetc/src/module.rs @@ -99,6 +99,28 @@ impl<'a> ModuleInfo<'a> { data_initializers: HashMap::new(), } } + + pub fn signature_for_function(&self, func_index: FuncIndex) -> &ir::Signature { + // FuncIndex are valid (or the caller has very bad data) + let sigidx = self.functions.get(func_index).unwrap().entity; + + self.signature_by_id(sigidx) + } + + pub fn signature_by_id(&self, sig_idx: SignatureIndex) -> &ir::Signature { + // All signatures map to some unique signature index + let unique_sig_idx = self.signature_mapping.get(sig_idx).unwrap(); + // Unique signature indices are valid (or we're in some deeply bad state) + self.signatures.get(*unique_sig_idx).unwrap() + } + + pub fn declare_func_with_sig(&mut self, sig: ir::Signature) -> (FuncIndex, SignatureIndex) { + let new_sigidx = SignatureIndex::from_u32(self.signature_mapping.len() as u32); + self.declare_signature(sig); + let new_funcidx = FuncIndex::from_u32(self.functions.len() as u32); + self.declare_func_type(new_sigidx); + (new_funcidx, new_sigidx) + } } impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { diff --git a/lucetc/src/output.rs b/lucetc/src/output.rs index f354b3db1..36b4303bb 100644 --- a/lucetc/src/output.rs +++ b/lucetc/src/output.rs @@ -47,18 +47,26 @@ impl ObjectFile { ) -> Result { stack_probe::declare_and_define(&mut product)?; - // stack_probe::declare_and_define adds a new function into `product`, but - // function_manifest was already constructed from all defined functions. - // So, we have to add a new entry to `function_manifest` for the stack probe - function_manifest.push(( - stack_probe::STACK_PROBE_SYM.to_string(), - FunctionSpec::new( + // stack_probe::declare_and_define never exists as clif, and as a result never exist as + // compiled code. This means the declared length of the stack probe's code is 0. This is + // incorrect, and must be fixed up before writing out the function manifest. + + // because the stack probe is the last declared function... + let last_idx = function_manifest.len() - 1; + let stack_probe_entry = function_manifest + .get_mut(last_idx) + .expect("function manifest has entries"); + debug_assert!(stack_probe_entry.0 == stack_probe::STACK_PROBE_SYM); + debug_assert!(stack_probe_entry.1.code_len() == 0); + std::mem::swap( + &mut stack_probe_entry.1, + &mut FunctionSpec::new( 0, // there is no real address for the function until written to an object file stack_probe::STACK_PROBE_BINARY.len() as u32, 0, 0, // fix up this FunctionSpec with trap info like any other ), - )); + ); let trap_manifest = &product .trap_manifest diff --git a/lucetc/src/runtime.rs b/lucetc/src/runtime.rs index 7f2a2aba5..1b14e7d72 100644 --- a/lucetc/src/runtime.rs +++ b/lucetc/src/runtime.rs @@ -1,4 +1,4 @@ -use cranelift_codegen::ir::{types, AbiParam, ArgumentPurpose, Signature}; +use cranelift_codegen::ir::{types, AbiParam, Signature}; use cranelift_codegen::isa::TargetFrontendConfig; use std::collections::HashMap; @@ -20,10 +20,7 @@ impl Runtime { ( "lucet_vmctx_current_memory".to_owned(), Signature { - params: vec![AbiParam::special( - target.pointer_type(), - ArgumentPurpose::VMContext, - )], + params: vec![], returns: vec![AbiParam::new(types::I32)], call_conv: target.default_call_conv, }, @@ -35,7 +32,6 @@ impl Runtime { "lucet_vmctx_grow_memory".to_owned(), Signature { params: vec![ - AbiParam::special(target.pointer_type(), ArgumentPurpose::VMContext), AbiParam::new(types::I32), // wasm pages to grow ], returns: vec![AbiParam::new(types::I32)], diff --git a/lucetc/src/stack_probe.rs b/lucetc/src/stack_probe.rs index 265c83819..97b72b548 100644 --- a/lucetc/src/stack_probe.rs +++ b/lucetc/src/stack_probe.rs @@ -8,10 +8,15 @@ //! adding custom entries for it into the trap table, so that stack overflows in the probe will be //! treated like any other guest trap. +use crate::decls::ModuleDecls; use cranelift_codegen::binemit::TrapSink; use cranelift_codegen::ir; +use cranelift_codegen::ir::{types, AbiParam, Signature}; +use cranelift_codegen::isa::CallConv; use cranelift_faerie::traps::{FaerieTrapManifest, FaerieTrapSink}; use cranelift_faerie::FaerieProduct; +use cranelift_module::{Backend as ClifBackend, Linkage, Module as ClifModule}; +use cranelift_wasm::FuncIndex; use faerie::Decl; use failure::Error; @@ -35,6 +40,24 @@ pub(crate) const STACK_PROBE_BINARY: &'static [u8] = &[ 0x29, 0xdc, 0x48, 0x85, 0x64, 0x24, 0x08, 0x48, 0x01, 0xc4, 0xc3, ]; +pub fn declare_metadata<'a, B: ClifBackend>( + decls: &mut ModuleDecls<'a>, + clif_module: &mut ClifModule, +) -> Result { + Ok(decls + .declare_new_function( + clif_module, + STACK_PROBE_SYM.to_string(), + Linkage::Local, + Signature { + params: vec![], + returns: vec![AbiParam::new(types::I32)], + call_conv: CallConv::SystemV, // the stack probe function is very specific to x86_64, and possibly to SystemV ABI platforms? + }, + ) + .unwrap()) +} + pub fn declare_and_define(product: &mut FaerieProduct) -> Result<(), Error> { product.artifact.declare_with( STACK_PROBE_SYM, diff --git a/lucetc/tests/wasm.rs b/lucetc/tests/wasm.rs index dd09e30a2..07f358859 100644 --- a/lucetc/tests/wasm.rs +++ b/lucetc/tests/wasm.rs @@ -45,7 +45,7 @@ mod module_data { assert_eq!(mdata.globals_spec().len(), 0); assert_eq!(mdata.import_functions().len(), 0); - assert_eq!(mdata.function_info().len(), 1); + assert_eq!(mdata.function_info().len(), 3); assert_eq!(mdata.export_functions()[0].names, vec!["main"]); } @@ -59,7 +59,7 @@ mod module_data { assert_eq!(mdata.globals_spec().len(), 0); assert_eq!(mdata.import_functions().len(), 0); - assert_eq!(mdata.function_info().len(), 1); + assert_eq!(mdata.function_info().len(), 3); assert_eq!(mdata.export_functions()[0].names, vec!["main"]); } #[test] @@ -76,7 +76,7 @@ mod module_data { assert_eq!(mdata.import_functions().len(), 1); assert_eq!(mdata.import_functions()[0].module, "env"); assert_eq!(mdata.import_functions()[0].name, "icalltarget"); - assert_eq!(mdata.function_info().len(), 5); + assert_eq!(mdata.function_info().len(), 7); assert_eq!(mdata.export_functions()[0].names, vec!["launchpad"]); assert_eq!(mdata.globals_spec().len(), 0); From b3fc0e78d369ee6ecbafde4064ba6c3e3dd26072 Mon Sep 17 00:00:00 2001 From: awortman-fastly <49215183+awortman-fastly@users.noreply.github.com> Date: Mon, 3 Jun 2019 10:40:09 -0700 Subject: [PATCH 155/512] Update lucet-analyze (#189) * fix off by one in lucet-analyze read_memory * teach lucet-analyze about module data and friends also adjust read_memory to not clone for all module reads this covers showing: * function manifests * function signatures * function import/export information try to be careful about instances where a module's information may be malformed as well --- Cargo.lock | 1 + lucet-analyze/Cargo.toml | 1 + lucet-analyze/src/main.rs | 650 ++++++++++++++++++--------------- lucet-module-data/src/types.rs | 30 ++ 4 files changed, 391 insertions(+), 291 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 04ff8bdcd..eece2d2bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -590,6 +590,7 @@ dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "lucet-module-data 0.1.0", ] [[package]] diff --git a/lucet-analyze/Cargo.toml b/lucet-analyze/Cargo.toml index 64e400480..117e72d7e 100644 --- a/lucet-analyze/Cargo.toml +++ b/lucet-analyze/Cargo.toml @@ -11,3 +11,4 @@ edition = "2018" goblin="0.0.21" byteorder="1.2.1" colored="1.6.1" +lucet-module-data = { path = "../lucet-module-data" } diff --git a/lucet-analyze/src/main.rs b/lucet-analyze/src/main.rs index 51026bd55..8949af139 100644 --- a/lucet-analyze/src/main.rs +++ b/lucet-analyze/src/main.rs @@ -1,3 +1,5 @@ +use lucet_module_data::{Error, FunctionSpec, ModuleData, TrapManifest, TrapSite}; + use byteorder::{LittleEndian, ReadBytesExt}; use colored::Colorize; use goblin::{elf, Object}; @@ -5,51 +7,27 @@ use std::env; use std::fs::File; use std::io::Cursor; use std::io::Read; -use std::mem::size_of; #[derive(Debug)] struct ArtifactSummary<'a> { buffer: &'a Vec, elf: &'a elf::Elf<'a>, symbols: StandardSymbols, - heap_spec: Option, - globals_spec: Option, data_segments: Option, - sparse_page_data: Option, - trap_manifest: Option, + module_data_bytes: Vec, + module_data: Option, Error>>, exported_functions: Vec<&'a str>, imported_symbols: Vec<&'a str>, } #[derive(Debug)] struct StandardSymbols { - lucet_trap_manifest: Option, - lucet_trap_manifest_len: Option, wasm_data_segments: Option, wasm_data_segments_len: Option, - lucet_heap_spec: Option, - lucet_globals_spec: Option, - guest_sparse_page_data: Option, -} - -#[derive(Debug)] -struct TrapManifest { - records: Vec, -} - -#[derive(Debug)] -struct TrapManifestRow { - func_name: String, - func_addr: u64, - func_len: u64, - trap_count: u64, - sites: Vec, -} - -#[derive(Debug)] -struct TrapSite { - offset: u32, - trapcode: u32, + lucet_module_data: Option, + lucet_module_data_len: Option, + lucet_function_manifest: Option, + lucet_function_manifest_len: Option, } #[derive(Debug)] @@ -64,57 +42,36 @@ struct DataSegment { data: Vec, } -#[derive(Debug)] -struct SparsePageData { - pages: Vec<*const u8>, -} - -#[derive(Debug)] -struct HeapSpec { - reserved_size: u64, - guard_size: u64, - initial_size: u64, - max_size: Option, -} - -#[derive(Debug)] -struct GlobalsSpec { - count: u64, -} - impl<'a> ArtifactSummary<'a> { fn new(buffer: &'a Vec, elf: &'a elf::Elf) -> Self { Self { buffer: buffer, elf: elf, symbols: StandardSymbols { - lucet_trap_manifest: None, - lucet_trap_manifest_len: None, wasm_data_segments: None, wasm_data_segments_len: None, - lucet_heap_spec: None, - lucet_globals_spec: None, - guest_sparse_page_data: None, + lucet_module_data: None, + lucet_module_data_len: None, + lucet_function_manifest: None, + lucet_function_manifest_len: None, }, - heap_spec: None, - globals_spec: None, data_segments: None, - sparse_page_data: None, - trap_manifest: None, + module_data_bytes: vec![], + module_data: None, exported_functions: Vec::new(), imported_symbols: Vec::new(), } } - fn read_memory(&self, addr: u64, size: u64) -> Option> { + fn read_memory(&self, addr: u64, size: u64) -> Option<&'a [u8]> { for header in &self.elf.program_headers { if header.p_type == elf::program_header::PT_LOAD { // Bounds check the entry - if addr >= header.p_vaddr && (addr + size) < (header.p_vaddr + header.p_memsz) { + if addr >= header.p_vaddr && (addr + size) <= (header.p_vaddr + header.p_memsz) { let start = (addr - header.p_vaddr + header.p_offset) as usize; let end = start + size as usize; - return Some(self.buffer[start..end].to_vec()); + return Some(&self.buffer[start..end]); } } } @@ -123,18 +80,6 @@ impl<'a> ArtifactSummary<'a> { } fn gather(&mut self) { - // println!("Syms"); - // for sym in eo.syms.iter() { - // let name = eo.strtab - // .get(sym.st_name) - // .unwrap_or(Ok("(no name)")) - // .expect("strtab entry"); - - // println!("Sym: name={} {:?}", name, sym); - // } - - // println!("Dyn syms"); - for ref sym in self.elf.syms.iter() { let name = self .elf @@ -143,17 +88,17 @@ impl<'a> ArtifactSummary<'a> { .unwrap_or(Ok("(no name)")) .expect("strtab entry"); - //println!("sym: name={} {:?}", name, sym); match name { - "lucet_trap_manifest" => self.symbols.lucet_trap_manifest = Some(sym.clone()), - "lucet_trap_manifest_len" => { - self.symbols.lucet_trap_manifest_len = Some(sym.clone()) + "lucet_module_data" => self.symbols.lucet_module_data = Some(sym.clone()), + "lucet_module_data_len" => self.symbols.lucet_module_data_len = Some(sym.clone()), + "lucet_function_manifest" => { + self.symbols.lucet_function_manifest = Some(sym.clone()) + } + "lucet_function_manifest_len" => { + self.symbols.lucet_function_manifest_len = Some(sym.clone()) } "wasm_data_segments" => self.symbols.wasm_data_segments = Some(sym.clone()), "wasm_data_segments_len" => self.symbols.wasm_data_segments_len = Some(sym.clone()), - "lucet_heap_spec" => self.symbols.lucet_heap_spec = Some(sym.clone()), - "lucet_globals_spec" => self.symbols.lucet_globals_spec = Some(sym.clone()), - "guest_sparse_page_data" => self.symbols.guest_sparse_page_data = Some(sym.clone()), _ => { if sym.st_bind() == elf::sym::STB_GLOBAL { if sym.is_function() { @@ -165,53 +110,75 @@ impl<'a> ArtifactSummary<'a> { } } } - - self.heap_spec = self.parse_heap_spec(); - self.globals_spec = self.parse_globals_spec(); - self.data_segments = self.parse_data_segments(); - self.trap_manifest = self.parse_trap_manifest(); - self.sparse_page_data = self.parse_sparse_page_data(); } - fn parse_heap_spec(&self) -> Option { - if let Some(ref sym) = self.symbols.lucet_heap_spec { - let mut spec = HeapSpec { - reserved_size: 0, - guard_size: 0, - initial_size: 0, - max_size: None, - }; - - let serialized = self.read_memory(sym.st_value, sym.st_size).unwrap(); - let mut rdr = Cursor::new(serialized); - spec.reserved_size = rdr.read_u64::().unwrap(); - spec.guard_size = rdr.read_u64::().unwrap(); - spec.initial_size = rdr.read_u64::().unwrap(); - - let max_size = rdr.read_u64::().unwrap(); - let max_size_valid = rdr.read_u64::().unwrap(); - - if max_size_valid == 1 { - spec.max_size = Some(max_size); - } else { - spec.max_size = None; + fn load_module_data(&self) -> Option, Error>> { + if let (Some(ref data_sym), Some(ref data_len_sym)) = ( + &self.symbols.lucet_module_data, + &self.symbols.lucet_module_data_len, + ) { + // TODO: validate that sym.st_size == 4 + let buffer = self + .read_memory(data_len_sym.st_value, data_len_sym.st_size) + .unwrap(); + let mut rdr = Cursor::new(buffer); + let data_len = rdr.read_u32::().unwrap(); + + if data_len as u64 != data_sym.st_size { + print!("{}", + format!( + "Module data reported size ({} bytes) does not match size declared for symbol ({} bytes).", + data_len, + data_sym.st_size + ).red().bold() + ); + println!(" Assuming the symbol is correct, wish me luck!"); } - Some(spec) + let module_data_bytes = self + .read_memory(data_sym.st_value, data_sym.st_size) + .unwrap(); + Some(ModuleData::deserialize(module_data_bytes)) } else { None } } - fn parse_globals_spec(&self) -> Option { - if let Some(ref sym) = self.symbols.lucet_globals_spec { - let mut spec = GlobalsSpec { count: 0 }; - - let serialized = self.read_memory(sym.st_value, sym.st_size).unwrap(); - let mut rdr = Cursor::new(serialized); - spec.count = rdr.read_u64::().unwrap(); + fn load_function_manifest(&self) -> Option<&'a [FunctionSpec]> { + if let (Some(ref data_sym), Some(ref data_len_sym)) = ( + &self.symbols.lucet_function_manifest, + &self.symbols.lucet_function_manifest_len, + ) { + // TODO: validate that sym.st_size == 4 + let buffer = self + .read_memory(data_len_sym.st_value, data_len_sym.st_size) + .unwrap(); + let mut rdr = Cursor::new(buffer); + let data_len = rdr.read_u32::().unwrap(); + + // cast up to u64 here to not overflow if data_len were an order of magnitude or so + // from u32::MAX + let expected_data_size = data_len as u64 * std::mem::size_of::() as u64; + if expected_data_size != data_sym.st_size { + println!("{}", + format!( + "Function manifest expected size ({} bytes) does not match size declared for symbol ({} bytes).", + expected_data_size, + data_sym.st_size + ).red().bold() + ); + println!(" Assuming the symbol is correct, wish me luck!"); + } - Some(spec) + let module_data_bytes = self + .read_memory(data_sym.st_value, data_sym.st_size) + .unwrap(); + Some(unsafe { + std::slice::from_raw_parts( + module_data_bytes.as_ptr() as *const FunctionSpec, + data_len as usize, + ) + }) } else { None } @@ -269,101 +236,6 @@ impl<'a> ArtifactSummary<'a> { } } - fn parse_sparse_page_data(&self) -> Option { - if let Some(ref sparse_sym) = self.symbols.guest_sparse_page_data { - let mut sparse_page_data = SparsePageData { pages: Vec::new() }; - let buffer = self - .read_memory(sparse_sym.st_value, sparse_sym.st_size) - .unwrap(); - let buffer_len = buffer.len(); - let mut rdr = Cursor::new(buffer); - let num_pages = rdr.read_u64::().unwrap(); - if buffer_len != size_of::() + num_pages as usize * size_of::() { - eprintln!("size of sparse page data doesn't match the number of pages specified"); - None - } else { - for _ in 0..num_pages { - let ptr = rdr.read_u64::().unwrap() as *const u8; - sparse_page_data.pages.push(ptr); - } - Some(sparse_page_data) - } - } else { - None - } - } - - fn parse_trap_manifest(&self) -> Option { - let trap_manifest: elf::sym::Sym; - let trap_manifest_len: elf::sym::Sym; - - // Make sure we have the necessary symbols first - if let Some(ref tm) = self.symbols.lucet_trap_manifest { - trap_manifest = tm.clone(); - } else { - return None; - } - - if let Some(ref tml) = self.symbols.lucet_trap_manifest_len { - trap_manifest_len = tml.clone(); - } else { - return None; - } - - let mut manifest = TrapManifest { - records: Vec::new(), - }; - - // Get the length of the manifest - // TODO: return error if st_size != 4 - let serialized = self - .read_memory(trap_manifest_len.st_value, trap_manifest_len.st_size) - .unwrap(); - let mut rdr = Cursor::new(serialized); - let trap_manifest_len = rdr.read_u32::().unwrap(); - - // Find the manifest itself - let serialized = self - .read_memory(trap_manifest.st_value, trap_manifest.st_size) - .unwrap(); - let mut rdr = Cursor::new(serialized); - - // Iterate through each row - for _ in 0..trap_manifest_len { - let func_start = rdr.read_u64::().unwrap(); - let func_len = rdr.read_u64::().unwrap(); - let traps = rdr.read_u64::().unwrap(); - let traps_len = rdr.read_u64::().unwrap(); - let func_name = self - .get_func_name_for_addr(func_start) - .unwrap_or("(not found)"); - - let mut sites = Vec::new(); - - // Find the table - let serialized_table = self.read_memory(traps, 8 * traps_len).unwrap(); - let mut table_rdr = Cursor::new(serialized_table); - - // Iterate through each site - for _ in 0..traps_len { - let offset = table_rdr.read_u32::().unwrap(); - let trapcode = table_rdr.read_u32::().unwrap(); - - sites.push(TrapSite { offset, trapcode }); - } - - manifest.records.push(TrapManifestRow { - func_name: func_name.to_string(), - func_addr: func_start, - func_len: func_len, - trap_count: traps_len, - sites: sites, - }); - } - - Some(manifest) - } - fn get_func_name_for_addr(&self, addr: u64) -> Option<&str> { for ref sym in self.elf.syms.iter() { if sym.is_function() && sym.st_value == addr { @@ -397,59 +269,49 @@ fn main() { } } -fn print_summary(summary: ArtifactSummary) { - println!("Required Symbols:"); - println!( - " {:25}: {}", - "lucet_trap_manifest", - exists_to_str(&summary.symbols.lucet_trap_manifest) - ); - println!( - " {:25}: {}", - "lucet_trap_manifest_len", - exists_to_str(&summary.symbols.lucet_trap_manifest_len) - ); - println!( - " {:25}: {}", - "wasm_data_segments", - exists_to_str(&summary.symbols.wasm_data_segments) - ); - println!( - " {:25}: {}", - "wasm_data_segments_len", - exists_to_str(&summary.symbols.wasm_data_segments_len) - ); - println!( - " {:25}: {}", - "guest_sparse_page_data", - exists_to_str(&summary.symbols.guest_sparse_page_data) - ); - println!( - " {:25}: {}", - "lucet_heap_spec", - exists_to_str(&summary.symbols.lucet_heap_spec) - ); - println!( - " {:25}: {}", - "lucet_globals_spec", - exists_to_str(&summary.symbols.lucet_globals_spec) - ); - - println!(""); - println!("Exported Functions/Symbols:"); - for function_name in summary.exported_functions { - println!(" {}", function_name); - } - - println!(""); - println!("Imported Functions/Symbols:"); - for function_name in summary.imported_symbols { - println!(" {}", function_name); +/// Parse a trap manifest for function `f`, if it has one. +/// +/// `parse_trap_manifest` may very understandably be confusing. Why not use `f.traps()`? In +/// `lucet-analyze` the module has been accessed by reading the file and following structures as +/// they exist at rest. This means pointers are not relocated, so slices that would be valid when +/// loaded through the platform's loader currently have pointers that are not valid for memory +/// access. +/// +/// In particular, trap pointers are correct with respect to 0 being the start of the file (or, +/// buffer, after reading), which means we can (and must) rebuild a correct slice from the buffer. +fn parse_trap_manifest<'a>( + summary: &'a ArtifactSummary<'a>, + f: &FunctionSpec, +) -> Option> { + if let Some(faulty_trap_manifest) = f.traps() { + let trap_ptr = faulty_trap_manifest.traps.as_ptr(); + let traps_count = faulty_trap_manifest.traps.len(); + let traps_byte_count = traps_count * std::mem::size_of::(); + if let Some(traps_byte_slice) = + summary.read_memory(trap_ptr as u64, traps_byte_count as u64) + { + let real_trap_ptr = traps_byte_slice.as_ptr() as *const TrapSite; + Some(TrapManifest { + traps: unsafe { std::slice::from_raw_parts(real_trap_ptr, traps_count) }, + }) + } else { + println!( + "Failed to read trap bytes for function {:?}, at {:p}", + f, trap_ptr + ); + None + } + } else { + None } +} - println!(""); - println!("Heap Specification:"); - if let Some(heap_spec) = summary.heap_spec { +fn summarize_module_data<'a, 'b: 'a>( + summary: &'a ArtifactSummary<'a>, + module_data: ModuleData<'b>, +) { + println!(" Heap Specification:"); + if let Some(heap_spec) = module_data.heap_spec() { println!(" {:9}: {} bytes", "Reserved", heap_spec.reserved_size); println!(" {:9}: {} bytes", "Guard", heap_spec.guard_size); println!(" {:9}: {} bytes", "Initial", heap_spec.initial_size); @@ -459,57 +321,263 @@ fn print_summary(summary: ArtifactSummary) { println!(" {:9}: None", "Maximum"); } } else { - println!(" {}", "MISSING!".red().bold()); + println!(" {}", "MISSING".red().bold()); } println!(""); - println!("Globals Specification:"); - if let Some(globals_spec) = summary.globals_spec { - println!(" {:6}: {}", "Count", globals_spec.count); + println!(" Sparse Page Data:"); + if let Some(sparse_page_data) = module_data.sparse_data() { + println!(" {:6}: {}", "Count", sparse_page_data.pages().len()); + let mut allempty = true; + let mut anyempty = false; + for (i, page) in sparse_page_data.pages().iter().enumerate() { + match page { + Some(page) => { + allempty = false; + println!( + " Page[{}]: {:p}, size: {}", + i, + page.as_ptr(), + if page.len() != 4096 { + format!( + "{} (page size, expected 4096)", + format!("{}", page.len()).bold().red() + ) + .red() + } else { + format!("{}", page.len()).green() + } + ); + } + None => { + anyempty = true; + } + }; + } + if allempty && sparse_page_data.pages().len() > 0 { + println!(" (all pages empty)"); + } else if anyempty { + println!(" (empty pages omitted)"); + } } else { println!(" {}", "MISSING!".red().bold()); } println!(""); - println!("Data Segments:"); - if let Some(data_segments) = summary.data_segments { - println!(" {:6}: {}", "Count", data_segments.segments.len()); - for segment in &data_segments.segments { + println!("Signatures:"); + for (i, s) in module_data.signatures().iter().enumerate() { + println!(" Signature {}: {}", i, s); + } + + println!(""); + println!("Functions:"); + if let Some(function_manifest) = summary.load_function_manifest() { + if function_manifest.len() != module_data.function_info().len() { println!( - " {:7}: {:6} {:6}: {:6}", - "Offset", segment.offset, "Length", segment.len, + " {} function manifest and function info have diverging function counts", + "lucetc bug:".red().bold() + ); + println!( + " function_manifest length : {}", + function_manifest.len() + ); + println!( + " module data function count : {}", + module_data.function_info().len() + ); + println!(" Will attempt to display information about functions anyway, but trap/code information may be misaligned with symbols and signatures."); + } + + for (i, f) in function_manifest.iter().enumerate() { + let header_name = summary.get_func_name_for_addr(f.ptr().as_usize() as u64); + + if i >= module_data.function_info().len() { + // This is one form of the above-mentioned bug case + // Half the function information is missing, so just report the issue and continue. + println!( + " Function {} {}", + i, + "is missing the module data part of its declaration".red() + ); + match header_name { + Some(name) => { + println!(" ELF header name: {}", name); + } + None => { + println!(" No corresponding ELF symbol."); + } + }; + break; + } + + let colorize_name = |x: Option<&str>| match x { + Some(name) => name.green(), + None => "None".red().bold(), + }; + + let fn_meta = &module_data.function_info()[i]; + println!(" Function {} (name: {}):", i, colorize_name(fn_meta.name)); + if fn_meta.name != header_name { + println!( + " Name {} with name declared in ELF headers: {}", + "DISAGREES".red().bold(), + colorize_name(header_name) + ); + } + + println!( + " Signature (index {}): {}", + fn_meta.signature.as_u32() as usize, + module_data.signatures()[fn_meta.signature.as_u32() as usize] ); + + println!(" Start: {:#010x}", f.ptr().as_usize()); + println!(" Code length: {} bytes", f.code_len()); + if let Some(trap_manifest) = parse_trap_manifest(&summary, f) { + let trap_count = trap_manifest.traps.len(); + + println!(" Trap information:"); + if trap_count > 0 { + println!( + " {} {} ...", + trap_manifest.traps.len(), + if trap_count == 1 { "trap" } else { "traps" }, + ); + for trap in trap_manifest.traps { + println!(" $+{:#06x}: {:?}", trap.offset, trap.code); + } + } else { + println!(" No traps for this function"); + } + } } } else { println!(" {}", "MISSING!".red().bold()); } println!(""); - println!("Sparse page data:"); - if let Some(sparse_page_data) = summary.sparse_page_data { - println!(" {:6}: {}", "Count", sparse_page_data.pages.len()); - let mut allempty = true; - for (i, page) in sparse_page_data.pages.iter().enumerate() { - if !page.is_null() { - allempty = false; - println!(" Page[{}]: {:p}", i, *page); + println!("Exported Functions/Symbols:"); + let mut exported_symbols = summary.exported_functions.clone(); + for export in module_data.export_functions() { + match module_data.function_info()[export.fn_idx.as_u32() as usize].name { + Some(name) => { + println!(" Internal name: {}", name); + + // The "internal name" is probably the first exported name for this function. + // Remove it from the exported_symbols list to not double-count + if let Some(idx) = exported_symbols.iter().position(|x| *x == name) { + exported_symbols.remove(idx); + } + } + None => { + println!(" No internal name"); } } - if allempty { - println!(" (all pages empty)"); - } else { - println!(" (empty pages omitted)"); + + // Export names do not have the guest_func_ prefix that symbol names get, and as such do + // not need to be removed from `exported_symbols` (which is built entirely from + // ELF-declared exports, with namespaced names) + println!(" Exported as: {}", export.names.join(", ")); + } + + if exported_symbols.len() > 0 { + println!(""); + println!(" Other exported symbols (from ELF headers):"); + for export in exported_symbols { + println!(" {}", export); + } + } + + println!(""); + println!("Imported Functions/Symbols:"); + let mut imported_symbols = summary.imported_symbols.clone(); + for import in module_data.import_functions() { + match module_data.function_info()[import.fn_idx.as_u32() as usize].name { + Some(name) => { + println!(" Internal name: {}", name); + } + None => { + println!(" No internal name"); + } + } + println!(" Imported as: {}/{}", import.module, import.name); + + // Remove from the imported_symbols list to not double-count imported functions + if let Some(idx) = imported_symbols.iter().position(|x| x == &import.name) { + imported_symbols.remove(idx); + } + } + + if imported_symbols.len() > 0 { + println!(""); + println!(" Other imported symbols (from ELF headers):"); + for import in &imported_symbols { + println!(" {}", import); + } + } +} + +fn print_summary(summary: ArtifactSummary) { + println!("Required Symbols:"); + println!( + " {:30}: {}", + "lucet_module_data", + exists_to_str(&summary.symbols.lucet_module_data) + ); + println!( + " {:30}: {}", + "lucet_module_data_len", + exists_to_str(&summary.symbols.lucet_module_data_len) + ); + println!( + " {:30}: {}", + "lucet_function_manifest", + exists_to_str(&summary.symbols.lucet_function_manifest) + ); + println!( + " {:30}: {}", + "lucet_function_manifest_len", + exists_to_str(&summary.symbols.lucet_function_manifest_len) + ); + println!( + " {:30}: {}", + "wasm_data_segments", + exists_to_str(&summary.symbols.wasm_data_segments) + ); + println!( + " {:30}: {}", + "wasm_data_segments_len", + exists_to_str(&summary.symbols.wasm_data_segments_len) + ); + + println!("\nModule data:"); + match summary.load_module_data() { + Some(Ok(module_data)) => { + summarize_module_data(&summary, module_data); + } + Some(Err(e)) => { + println!(" ERROR: {}", e.to_string().red().bold()); + } + None => { + println!(" MISSING SYMBOL:"); + if summary.symbols.lucet_module_data.is_none() { + println!(" - {}", "lucet_module_data".red().bold()); + } + if summary.symbols.lucet_module_data_len.is_none() { + println!(" - {}", "lucet_module_data_len".red().bold()); + } } - } else { - println!(" {}", "MISSING!".red().bold()); } println!(""); - println!("Trap Manifest:"); - if let Some(trap_manifest) = summary.trap_manifest { - for row in trap_manifest.records { - println!(" {:25} {} traps", row.func_name, row.trap_count); - println!(" {:?}", row.sites); + println!("Data Segments:"); + if let Some(data_segments) = summary.data_segments { + println!(" {:6}: {}", "Count", data_segments.segments.len()); + for segment in &data_segments.segments { + println!( + " {:7}: {:6} {:6}: {:6}", + "Offset", segment.offset, "Length", segment.len, + ); } } else { println!(" {}", "MISSING!".red().bold()); diff --git a/lucet-module-data/src/types.rs b/lucet-module-data/src/types.rs index 1d5ce4898..2157ae109 100644 --- a/lucet-module-data/src/types.rs +++ b/lucet-module-data/src/types.rs @@ -1,6 +1,7 @@ use std::convert::TryFrom; use cranelift_codegen::ir; use serde::{Deserialize, Serialize}; +use std::fmt::{Display, Formatter}; #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub enum ValueType { @@ -10,6 +11,17 @@ pub enum ValueType { F64, } +impl Display for ValueType { + fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { + match self { + ValueType::I32 => write!(f, "I32"), + ValueType::I64 => write!(f, "I64"), + ValueType::F32 => write!(f, "F32"), + ValueType::F64 => write!(f, "F64"), + } + } +} + #[derive(Debug)] pub enum ValueError { Unrepresentable, @@ -61,6 +73,24 @@ pub struct Signature { pub ret_ty: Option, } +impl Display for Signature { + fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { + write!(f, "(")?; + for (i, p) in self.params.iter().enumerate() { + if i == 0 { + write!(f, "{}", p)?; + } else { + write!(f, ", {}", p)?; + } + } + write!(f, ") -> ")?; + match self.ret_ty { + Some(ty) => write!(f, "{}", ty), + None => write!(f, "()") + } + } +} + #[macro_export] macro_rules! lucet_signature { ((() -> ())) => { From bfb549423da0bee0e330e41d486104f99f60a991 Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Fri, 7 Jun 2019 20:42:10 +0200 Subject: [PATCH 156/512] Improve the install target (#200) * Improve the install target - When used interactively, give a chance to the user to change the destination directory, and provide feedback after installation - Add support for macOS - Exit early if directories cannot be created - Suggest adding ${LUCET_BIN_DIR}/devenv_setenv.sh to the shell configuration, with different instructions for the fish shell * Escape PATH and (DY)LD_LIBRARY_PATH --- helpers/install.sh | 66 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/helpers/install.sh b/helpers/install.sh index 1f104e24a..f887aeeaf 100755 --- a/helpers/install.sh +++ b/helpers/install.sh @@ -1,11 +1,9 @@ #! /bin/sh -if [ "$(uname -s)" != "Linux" ]; then - echo "Installation on this operating system cannot be done using that script yet." >&2 - exit 1 -fi - -LUCET_SRC_PREFIX=${LUCET_SRC_PREFIX:-"$(readlink -e $(dirname $(dirname ${0})))"} +LUCET_SRC_PREFIX=${LUCET_SRC_PREFIX:-"$( + cd $(dirname $(dirname ${0})) + pwd -P +)"} if [ ! -x "${LUCET_SRC_PREFIX}/helpers/install.sh" ]; then echo "Unable to find the current script base directory" >&2 exit 1 @@ -28,31 +26,47 @@ WASI_SYSROOT=${WASI_SYSROOT:-"${WASI_PREFIX}/share/sysroot"} WASI_TARGET=${WASI_TARGET:-"wasm32-wasi"} WASI_BIN_PREFIX=${WASI_BIN_PREFIX:-"$WASI_TARGET"} +if [ "$(uname -s)" = "Darwin" ]; then + DYLIB_SUFFIX="dylib" +else + DYLIB_SUFFIX="so" +fi + BINS="lucet-analyze lucet-wasi lucetc sightglass spec-test wasmonkey" -LIBS="liblucet_runtime.so" +LIBS="liblucet_runtime.${DYLIB_SUFFIX}" DOCS="lucet-wasi/README.md sightglass/README.md" BUNDLE_DOCS="README.md" -install -d -v "$LUCET_BIN_DIR" +if test -t 0; then + echo + echo "The Lucet toolchain is going to be installed in [${LUCET_PREFIX}]." + echo "The installation prefix can be changed by defining a LUCET_PREFIX environment variable." + echo "Hit Ctrl-C right now to abort before the installation begins." + echo + sleep 10 +fi + +install -d -v "$LUCET_BIN_DIR" || exit 1 for bin in $BINS; do install -p -v "${LUCET_SRC_RELEASE_DIR}/${bin}" "${LUCET_BIN_DIR}/${bin}" done -install -d -v "$LUCET_LIB_DIR" +install -d -v "$LUCET_LIB_DIR" || exit 1 for lib in $LIBS; do install -p -v "${LUCET_SRC_RELEASE_DIR}/${lib}" "${LUCET_LIB_DIR}/${lib}" done -install -d -v "$LUCET_LIBEXEC_DIR" +install -d -v "$LUCET_LIBEXEC_DIR" || exit 1 install -p -v "${LUCET_SRC_PREFIX}/lucet-builtins/build/libbuiltins.so" \ - "${LUCET_LIBEXEC_DIR}/libbuiltins.so" + "${LUCET_LIBEXEC_DIR}/libbuiltins.${DYLIB_SUFFIX}" devenv_setenv_file="$(mktemp)" -cat > "$devenv_setenv_file" << EOT +cat >"$devenv_setenv_file" < "$wrapper_file" << EOT + cat >"$wrapper_file" < "$wrapper_file" << EOT +cat >"$wrapper_file" < Date: Mon, 10 Jun 2019 11:06:10 +0200 Subject: [PATCH 157/512] Find how a wasm32-wasi compatible LLVM and Clang were installed (#206) The installation script now tries to compile a minimal program to verify that a a compatible compilation toolchain exists. We also try to deal with the fact that some environments require a version suffix on clang and/or llvm tools (ex: Ubuntu 19.10), but some don't (ex: macOS). The script produces more verbose output about what it is doing and what may be missing for a successful installation. --- helpers/install.sh | 97 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 90 insertions(+), 7 deletions(-) diff --git a/helpers/install.sh b/helpers/install.sh index f887aeeaf..92b70ad8f 100755 --- a/helpers/install.sh +++ b/helpers/install.sh @@ -20,9 +20,7 @@ LUCET_SHARE_DIR=${LUCET_SHARE_DIR:-"${LUCET_PREFIX}/share"} LUCET_EXAMPLES_DIR=${LUCET_EXAMPLES_DIR:-"${LUCET_SHARE_DIR}/examples"} LUCET_DOC_DIR=${LUCET_DOC_DIR:-"${LUCET_SHARE_DIR}/doc"} LUCET_BUNDLE_DOC_DIR=${LUCET_BUNDLE_DOC_DIR:-"${LUCET_DOC_DIR}/lucet"} -WASI_PREFIX=${WASI_PREFIX:-${WASI_SDK:-"/opt/wasi-sdk"}} -WASI_BIN=${WASI_BIN:-"${WASI_PREFIX}/bin"} -WASI_SYSROOT=${WASI_SYSROOT:-"${WASI_PREFIX}/share/sysroot"} +WASI_SDK_PREFIX=${WASI_SDK_PREFIX:-${WASI_SDK:-"/opt/wasi-sdk"}} WASI_TARGET=${WASI_TARGET:-"wasm32-wasi"} WASI_BIN_PREFIX=${WASI_BIN_PREFIX:-"$WASI_TARGET"} @@ -46,6 +44,91 @@ if test -t 0; then sleep 10 fi +if ! install -d "$LUCET_PREFIX" 2>/dev/null; then + SUDO="" + if command -v doas >/dev/null; then + SUDO="doas" + elif command -v sudo >/dev/null; then + SUDO="sudo" + else + echo "[${LUCET_PREFIX}] doesn't exist and cannot be created" >&2 + exit 1 + fi + echo "[${LUCET_PREFIX}] doesn't exist and the $SUDO command is required to create it" + if ! "$SUDO" install -o "$(id -u)" -d "$LUCET_PREFIX"; then + echo "[${LUCET_PREFIX}] doesn't exist and cannot be created even with additional privileges" >&2 + exit 1 + fi +fi + +# Find a WASI sysroot +for wasi_sysroot in $WASI_SYSROOT ${WASI_SDK_PREFIX}/share/sysroot /opt/wasi-sysroot; do + if [ -e "${wasi_sysroot}/include/wasi/core.h" ]; then + WASI_SYSROOT="$wasi_sysroot" + fi +done +if [ -z "$WASI_SYSROOT" ]; then + echo "The WASI sysroot was not found." >&2 + echo "You may have to define a WASI_SYSROOT environment variable set to its base directory." + exit 1 +fi +echo "* WASI sysroot: [$WASI_SYSROOT]" + +# Find: +# - A clang/llvm installation able to compile to WebAssmbly/WASI +# - The base path to this installation +# - The optional suffix added to clang (e.g. clang-8) +# - The optional suffix added to LLVM tools (e.g. ar-8) that differs from the clang one on some Linux distributions + +TMP_OBJ=$(mktemp) +for llvm_bin_path_candidate in "$LLVM_BIN" "${WASI_SDK_PREFIX}/bin" /usr/local/opt/llvm/bin $(echo "$PATH" | sed s/:/\ /g); do + [ -d "$llvm_bin_path_candidate" ] || continue + clang_candidate=$(find "$llvm_bin_path_candidate" -maxdepth 1 \( -type f -o -type l \) \( -name "clang" -o -name "clang-[0-9]*" \) -print | + sort | while read -r clang_candidate; do + echo "int main(void){return 0;}" | "$clang_candidate" --target=wasm32-wasi -o "$TMP_OBJ" -c -x c - 2>/dev/null || continue + echo "$clang_candidate" + break + done) + [ -z "$clang_candidate" ] && continue + llvm_bin=$(dirname "$clang_candidate") + clang_candidate_bn=$(basename "$clang_candidate") + case "$clang_candidate_bn" in + clang) clang_bin_suffix="none" ;; + clang-[0-9]*) clang_bin_suffix=$(echo "$clang_candidate_bn" | sed "s/^clang//") ;; + *) continue ;; + esac + CLANG_BIN_SUFFIX="$clang_bin_suffix" + LLVM_BIN="$llvm_bin" + if [ -z "$CLANG_BIN_SUFFIX" ] || [ -z "$LLVM_BIN" ]; then + continue + fi + if [ "$CLANG_BIN_SUFFIX" = "none" ]; then + CLANG_BIN_SUFFIX="" + fi + break +done +rm -f "$TMP_OBJ" + +if [ -z "$LLVM_BIN" ]; then + echo "No clang/LLVM installation able to compile to WebAssembly/WASI was found." >&2 + echo "The builtins might be missing -- See the Lucet documentation." >&2 + exit 1 +fi +echo "* LLVM installation directory: [$LLVM_BIN]" +echo "* Suitable clang executable: [clang${CLANG_BIN_SUFFIX}]" + +LLVM_BIN_SUFFIX="$CLANG_BIN_SUFFIX" +if ! command -v "${LLVM_BIN}/llvm-ar${LLVM_BIN_SUFFIX}" >/dev/null; then + LLVM_BIN_SUFFIX="" + if ! command -v "${LLVM_BIN}/llvm-ar${LLVM_BIN_SUFFIX}" >/dev/null; then + echo "LLVM not found" >&2 + exit 1 + fi + echo test +fi +echo "* LLVM tools suffix: [${LLVM_BIN_SUFFIX}] (ex: [llvm-ar${LLVM_BIN_SUFFIX}])" +echo + install -d -v "$LUCET_BIN_DIR" || exit 1 for bin in $BINS; do install -p -v "${LUCET_SRC_RELEASE_DIR}/${bin}" "${LUCET_BIN_DIR}/${bin}" @@ -97,18 +180,18 @@ for file in clang clang++; do cat >"$wrapper_file" < Date: Mon, 10 Jun 2019 09:44:52 -0700 Subject: [PATCH 158/512] Float global support (#204) * support float globals, lucetc-side support for import globals * record names of exported globals, fix corresponding tests * add test around multiple exports of a global --- lucet-analyze/src/main.rs | 13 ++ lucet-module-data/src/globals.rs | 125 ++++++++++-------- lucet-module-data/src/lib.rs | 2 +- .../lucet-runtime-internals/src/alloc/mod.rs | 13 +- .../src/alloc/tests.rs | 23 ++-- .../lucet-runtime-internals/src/instance.rs | 8 +- .../src/module/mock.rs | 12 +- .../lucet-runtime-internals/src/vmctx.rs | 10 +- .../lucet-runtime-tests/src/globals.rs | 14 +- lucetc/src/decls.rs | 53 +++++--- lucetc/tests/wasi-sdk.rs | 14 +- lucetc/tests/wasm.rs | 16 +++ lucetc/tests/wasm/globals_export.wat | 5 + 13 files changed, 193 insertions(+), 115 deletions(-) create mode 100644 lucetc/tests/wasm/globals_export.wat diff --git a/lucet-analyze/src/main.rs b/lucet-analyze/src/main.rs index 8949af139..2b8127a88 100644 --- a/lucet-analyze/src/main.rs +++ b/lucet-analyze/src/main.rs @@ -455,6 +455,19 @@ fn summarize_module_data<'a, 'b: 'a>( println!(" {}", "MISSING!".red().bold()); } + println!(""); + println!("Globals:"); + if module_data.globals_spec().len() > 0 { + for global_spec in module_data.globals_spec().iter() { + println!(" {:?}", global_spec.global()); + for name in global_spec.export_names() { + println!(" Exported as: {}", name); + } + } + } else { + println!(" None"); + } + println!(""); println!("Exported Functions/Symbols:"); let mut exported_symbols = summary.exported_functions.clone(); diff --git a/lucet-module-data/src/globals.rs b/lucet-module-data/src/globals.rs index 590c0d947..af870d260 100644 --- a/lucet-module-data/src/globals.rs +++ b/lucet-module-data/src/globals.rs @@ -5,74 +5,102 @@ use serde::{Deserialize, Serialize}; /// The lifetime parameter exists to support zero-copy deserialization for the `&str` fields at the /// leaves of the structure. For a variant with owned types at the leaves, see /// [`OwnedGlobalSpec`](owned/struct.OwnedGlobalSpec.html). -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct GlobalSpec<'a> { #[serde(borrow)] global: Global<'a>, - export: Option<&'a str>, + export_names: Vec<&'a str>, } impl<'a> GlobalSpec<'a> { - pub fn new(global: Global<'a>, export: Option<&'a str>) -> Self { - Self { global, export } + pub fn new(global: Global<'a>, export_names: Vec<&'a str>) -> Self { + Self { global, export_names } } - /// Create a new global definition with an initial value and an optional export name. - pub fn new_def(init_val: i64, export: Option<&'a str>) -> Self { + /// Create a new global definition with an initial value and export names. + pub fn new_def(init_val: i64, export_names: Vec<&'a str>) -> Self { Self::new( - Global::Def { - def: GlobalDef::new(init_val), - }, - export, + Global::Def(GlobalDef::I64(init_val)), + export_names, ) } - /// Create a new global import definition with a module and field name, and an optional export - /// name. - pub fn new_import(module: &'a str, field: &'a str, export: Option<&'a str>) -> Self { - Self::new(Global::Import { module, field }, export) + /// Create a new global import definition with a module and field name, and export names. + pub fn new_import(module: &'a str, field: &'a str, export_names: Vec<&'a str>) -> Self { + Self::new(Global::Import { module, field }, export_names) } pub fn global(&self) -> &Global { &self.global } - pub fn export(&self) -> Option<&str> { - self.export + pub fn export_names(&self) -> &[&str] { + &self.export_names + } + + pub fn is_internal(&self) -> bool { + self.export_names.len() == 0 } } /// A WebAssembly global is either defined locally, or is defined in relation to a field of another /// WebAssembly module. /// -/// Lucet currently does not support import globals, but we support the metadata for future -/// compatibility. -/// /// The lifetime parameter exists to support zero-copy deserialization for the `&str` fields at the /// leaves of the structure. For a variant with owned types at the leaves, see /// [`OwnedGlobal`](owned/struct.OwnedGlobal.html). -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum Global<'a> { - Def { def: GlobalDef }, + Def(GlobalDef), Import { module: &'a str, field: &'a str }, } -/// A global definition. -/// -/// Currently we cast everything to an `i64`, but in the future this may have explicit variants for -/// the different WebAssembly scalar types. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct GlobalDef { - init_val: i64, +/// Definition for a global in this module (not imported). +#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] +pub enum GlobalDef { + I32(i32), + I64(i64), + F32(f32), + F64(f64) } impl GlobalDef { - pub fn new(init_val: i64) -> Self { - Self { init_val } + pub fn init_val(&self) -> GlobalValue { + match self { + GlobalDef::I32(i) => GlobalValue { i_32: *i }, + GlobalDef::I64(i) => GlobalValue { i_64: *i }, + GlobalDef::F32(f) => GlobalValue { f_32: *f }, + GlobalDef::F64(f) => GlobalValue { f_64: *f }, + } } +} + +#[derive(Copy, Clone)] +pub union GlobalValue { + pub i_32: i32, + pub i_64: i64, + pub f_32: f32, + pub f_64: f64, +} - pub fn init_val(&self) -> i64 { - self.init_val +impl std::fmt::Debug for GlobalValue { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + // Because GlobalValue is a union of primitives, there won't be anything wrong, + // representation-wise, with printing the underlying data as an i64, f64, or + // another primitive. This still may incur UB by doing something like trying to + // read data from an uninitialized memory, if the union is initialized with a + // 32-bit value, and then read as a 64-bit value (as this code is about to do). + // + // In short, avoid using ``::fmt, please. + + writeln!(f, "GlobalValue {{")?; + unsafe { + writeln!(f, " i_32: {},", self.i_32)?; + writeln!(f, " i_64: {},", self.i_64)?; + writeln!(f, " f_32: {},", self.f_32)?; + writeln!(f, " f_64: {},", self.f_64)?; + } + writeln!(f, "}}") } } @@ -83,38 +111,31 @@ impl GlobalDef { /// This type is useful when directly building up a value to be serialized. pub struct OwnedGlobalSpec { global: OwnedGlobal, - export: Option, + export_names: Vec, } impl OwnedGlobalSpec { - pub fn new(global: OwnedGlobal, export: Option) -> Self { - Self { global, export } + pub fn new(global: OwnedGlobal, export_names: Vec) -> Self { + Self { global, export_names } } - /// Create a new global definition with an initial value and an optional export name. - pub fn new_def(init_val: i64, export: Option) -> Self { + /// Create a new global definition with an initial value and export names. + pub fn new_def(init_val: i64, export_names: Vec) -> Self { Self::new( - OwnedGlobal::Def { - def: GlobalDef::new(init_val), - }, - export, + OwnedGlobal::Def(GlobalDef::I64(init_val)), + export_names, ) } - /// Create a new global import definition with a module and field name, and an optional export - /// name. - pub fn new_import(module: String, field: String, export: Option) -> Self { - Self::new(OwnedGlobal::Import { module, field }, export) + /// Create a new global import definition with a module and field name, and export names. + pub fn new_import(module: String, field: String, export_names: Vec) -> Self { + Self::new(OwnedGlobal::Import { module, field }, export_names) } /// Create a [`GlobalSpec`](../struct.GlobalSpec.html) backed by the values in this /// `OwnedGlobalSpec`. pub fn to_ref<'a>(&'a self) -> GlobalSpec<'a> { - let export = match &self.export { - Some(e) => Some(e.as_str()), - None => None, - }; - GlobalSpec::new(self.global.to_ref(), export) + GlobalSpec::new(self.global.to_ref(), self.export_names.iter().map(|x| x.as_str()).collect()) } } @@ -122,7 +143,7 @@ impl OwnedGlobalSpec { /// /// This type is useful when directly building up a value to be serialized. pub enum OwnedGlobal { - Def { def: GlobalDef }, + Def(GlobalDef), Import { module: String, field: String }, } @@ -130,7 +151,7 @@ impl OwnedGlobal { /// Create a [`Global`](../struct.Global.html) backed by the values in this `OwnedGlobal`. pub fn to_ref<'a>(&'a self) -> Global<'a> { match self { - OwnedGlobal::Def { def } => Global::Def { def: def.clone() }, + OwnedGlobal::Def(def) => Global::Def(def.clone()), OwnedGlobal::Import { module, field } => Global::Import { module: module.as_str(), field: field.as_str(), diff --git a/lucet-module-data/src/lib.rs b/lucet-module-data/src/lib.rs index 4836c58f1..8f5696fd0 100644 --- a/lucet-module-data/src/lib.rs +++ b/lucet-module-data/src/lib.rs @@ -12,7 +12,7 @@ mod traps; mod types; pub use crate::error::Error; -pub use crate::globals::{Global, GlobalDef, GlobalSpec}; +pub use crate::globals::{Global, GlobalDef, GlobalSpec, GlobalValue}; pub use crate::linear_memory::{HeapSpec, SparseData, LinearMemorySpec}; pub use crate::module_data::ModuleData; pub use crate::functions::{ExportFunction, FunctionHandle, FunctionIndex, FunctionMetadata, FunctionPointer, FunctionSpec, ImportFunction, UniqueSignatureIndex}; diff --git a/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs b/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs index f2a24bad1..5d5105aab 100644 --- a/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs @@ -2,6 +2,7 @@ use crate::error::Error; use crate::module::Module; use crate::region::RegionInternal; use libc::{c_void, SIGSTKSZ}; +use lucet_module_data::GlobalValue; use nix::unistd::{sysconf, SysconfVar}; use std::sync::{Arc, Once, Weak}; @@ -290,18 +291,18 @@ impl Alloc { } /// Return the globals as a slice. - pub unsafe fn globals(&self) -> &[i64] { + pub unsafe fn globals(&self) -> &[GlobalValue] { std::slice::from_raw_parts( - self.slot().globals as *const i64, - self.slot().limits.globals_size / 8, + self.slot().globals as *const GlobalValue, + self.slot().limits.globals_size / std::mem::size_of::(), ) } /// Return the globals as a mutable slice. - pub unsafe fn globals_mut(&mut self) -> &mut [i64] { + pub unsafe fn globals_mut(&mut self) -> &mut [GlobalValue] { std::slice::from_raw_parts_mut( - self.slot().globals as *mut i64, - self.slot().limits.globals_size / 8, + self.slot().globals as *mut GlobalValue, + self.slot().limits.globals_size / std::mem::size_of::(), ) } diff --git a/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs b/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs index dbd20a904..ebf3ad190 100644 --- a/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs +++ b/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs @@ -2,7 +2,7 @@ macro_rules! alloc_tests { ( $TestRegion:path ) => { use libc::c_void; - use lucet_module_data::FunctionPointer; + use lucet_module_data::{FunctionPointer, GlobalValue}; use std::sync::Arc; use $TestRegion as TestRegion; use $crate::alloc::Limits; @@ -349,15 +349,22 @@ macro_rules! alloc_tests { assert_eq!(stack[LIMITS_STACK_SIZE - 1], 0xFF); let globals = unsafe { inst.alloc_mut().globals_mut() }; - assert_eq!(globals.len(), LIMITS_GLOBALS_SIZE / 8); + assert_eq!( + globals.len(), + LIMITS_GLOBALS_SIZE / std::mem::size_of::() + ); - assert_eq!(globals[0], 0); - globals[0] = 0xFF; - assert_eq!(globals[0], 0xFF); + unsafe { + assert_eq!(globals[0].i_64, 0); + globals[0].i_64 = 0xFF; + assert_eq!(globals[0].i_64, 0xFF); + } - assert_eq!(globals[globals.len() - 1], 0); - globals[globals.len() - 1] = 0xFF; - assert_eq!(globals[globals.len() - 1], 0xFF); + unsafe { + assert_eq!(globals[globals.len() - 1].i_64, 0); + globals[globals.len() - 1].i_64 = 0xFF; + assert_eq!(globals[globals.len() - 1].i_64, 0xFF); + } let sigstack = unsafe { inst.alloc_mut().sigstack_mut() }; assert_eq!(sigstack.len(), libc::SIGSTKSZ); diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index d590f45e2..f84a762cc 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -14,7 +14,7 @@ use crate::sysdeps::UContext; use crate::val::{UntypedRetVal, Val}; use crate::WASM_PAGE_SIZE; use libc::{c_void, siginfo_t, uintptr_t, SIGBUS, SIGSEGV}; -use lucet_module_data::{FunctionHandle, FunctionPointer, TrapCode}; +use lucet_module_data::{FunctionHandle, FunctionPointer, GlobalValue, TrapCode}; use memoffset::offset_of; use std::any::Any; use std::cell::{BorrowError, BorrowMutError, Ref, RefCell, RefMut, UnsafeCell}; @@ -354,7 +354,7 @@ impl Instance { i ))); } - Global::Def { def } => def.init_val(), + Global::Def(def) => def.init_val(), }; } @@ -404,12 +404,12 @@ impl Instance { } /// Return the WebAssembly globals as a slice of `i64`s. - pub fn globals(&self) -> &[i64] { + pub fn globals(&self) -> &[GlobalValue] { unsafe { self.alloc.globals() } } /// Return the WebAssembly globals as a mutable slice of `i64`s. - pub fn globals_mut(&mut self) -> &mut [i64] { + pub fn globals_mut(&mut self) -> &mut [GlobalValue] { unsafe { self.alloc.globals_mut() } } diff --git a/lucet-runtime/lucet-runtime-internals/src/module/mock.rs b/lucet-runtime/lucet-runtime-internals/src/module/mock.rs index ca1aa1bd7..a79a14b3f 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/mock.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/mock.rs @@ -64,14 +64,14 @@ impl MockModuleBuilder { pub fn with_global(mut self, idx: u32, init_val: i64) -> Self { self.globals - .insert(idx as usize, OwnedGlobalSpec::new_def(init_val, None)); + .insert(idx as usize, OwnedGlobalSpec::new_def(init_val, vec![])); self } pub fn with_exported_global(mut self, idx: u32, init_val: i64, export_name: &str) -> Self { self.globals.insert( idx as usize, - OwnedGlobalSpec::new_def(init_val, Some(export_name.to_string())), + OwnedGlobalSpec::new_def(init_val, vec![export_name.to_string()]), ); self } @@ -79,7 +79,11 @@ impl MockModuleBuilder { pub fn with_import(mut self, idx: u32, import_module: &str, import_field: &str) -> Self { self.globals.insert( idx as usize, - OwnedGlobalSpec::new_import(import_module.to_string(), import_field.to_string(), None), + OwnedGlobalSpec::new_import( + import_module.to_string(), + import_field.to_string(), + vec![], + ), ); self } @@ -96,7 +100,7 @@ impl MockModuleBuilder { OwnedGlobalSpec::new_import( import_module.to_string(), import_field.to_string(), - Some(export_name.to_string()), + vec![export_name.to_string()], ), ); self diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index 52e3ee9e9..e2ecfd1d3 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -11,7 +11,7 @@ use crate::error::Error; use crate::instance::{ Instance, InstanceInternal, State, TerminationDetails, CURRENT_INSTANCE, HOST_CTX, }; -use lucet_module_data::FunctionHandle; +use lucet_module_data::{FunctionHandle, GlobalValue}; use std::any::Any; use std::borrow::{Borrow, BorrowMut}; use std::cell::{Ref, RefCell, RefMut}; @@ -31,7 +31,7 @@ pub struct Vmctx { /// This must never be dropped automatically, as the view does not own the globals. Rather, this /// is a value used to implement dynamic borrowing of the globals that are owned and managed by /// the instance and its `Alloc`. - globals_view: RefCell>, + globals_view: RefCell>, } impl Drop for Vmctx { @@ -82,7 +82,7 @@ impl Vmctx { let res = Vmctx { vmctx, heap_view: RefCell::new(Box::<[u8]>::from_raw(inst.heap_mut())), - globals_view: RefCell::new(Box::<[i64]>::from_raw(inst.globals_mut())), + globals_view: RefCell::new(Box::<[GlobalValue]>::from_raw(inst.globals_mut())), }; res } @@ -205,7 +205,7 @@ impl Vmctx { /// /// If the globals are already mutably borrowed by `globals_mut()`, the instance will terminate /// with `TerminationDetails::BorrowError`. - pub fn globals(&self) -> Ref<[i64]> { + pub fn globals(&self) -> Ref<[GlobalValue]> { let r = self .globals_view .try_borrow() @@ -217,7 +217,7 @@ impl Vmctx { /// /// If the globals are already borrowed by `globals()` or `globals_mut()`, the instance will /// terminate with `TerminationDetails::BorrowError`. - pub fn globals_mut(&self) -> RefMut<[i64]> { + pub fn globals_mut(&self) -> RefMut<[GlobalValue]> { let r = self .globals_view .try_borrow_mut() diff --git a/lucet-runtime/lucet-runtime-tests/src/globals.rs b/lucet-runtime/lucet-runtime-tests/src/globals.rs index de3eca6ec..ce78d968e 100644 --- a/lucet-runtime/lucet-runtime-tests/src/globals.rs +++ b/lucet-runtime/lucet-runtime-tests/src/globals.rs @@ -1,7 +1,7 @@ #[macro_export] macro_rules! globals_tests { ( $TestRegion:path ) => { - use lucet_module_data::{lucet_signature, FunctionPointer}; + use lucet_module_data::{lucet_signature, FunctionPointer, GlobalValue}; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime::{Error, Limits, Module, Region}; use std::sync::Arc; @@ -62,22 +62,22 @@ macro_rules! globals_tests { fn mock_globals_module() -> Arc { extern "C" { - fn lucet_vmctx_get_globals(vmctx: *mut lucet_vmctx) -> *mut i64; + fn lucet_vmctx_get_globals(vmctx: *mut lucet_vmctx) -> *mut GlobalValue; } unsafe extern "C" fn get_global0(vmctx: *mut lucet_vmctx) -> i64 { let globals = std::slice::from_raw_parts(lucet_vmctx_get_globals(vmctx), 2); - globals[0] + globals[0].i_64 } unsafe extern "C" fn set_global0(vmctx: *mut lucet_vmctx, val: i64) { let globals = std::slice::from_raw_parts_mut(lucet_vmctx_get_globals(vmctx), 2); - globals[0] = val; + globals[0].i_64 = val; } unsafe extern "C" fn get_global1(vmctx: *mut lucet_vmctx) -> i64 { let globals = std::slice::from_raw_parts(lucet_vmctx_get_globals(vmctx), 2); - globals[1] + globals[1].i_64 } MockModuleBuilder::new() @@ -109,8 +109,8 @@ macro_rules! globals_tests { let inst = region .new_instance(module) .expect("instance can be created"); - assert_eq!(inst.globals()[0], -1); - assert_eq!(inst.globals()[1], 420); + assert_eq!(unsafe { inst.globals()[0].i_64 }, -1); + assert_eq!(unsafe { inst.globals()[1].i_64 }, 420); } #[test] diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index de146b664..85d4cd019 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -267,25 +267,42 @@ impl<'a> ModuleDecls<'a> { for ix in 0..info.globals.len() { let ix = GlobalIndex::new(ix); let g_decl = info.globals.get(ix).unwrap(); - let g_import = info.imported_globals.get(ix); - let g_variant = if let Some((module, field)) = g_import { - GlobalVariant::Import { module, field } - } else { - let init_val = match g_decl.entity.initializer { - // Need to fix global spec in ModuleData and the runtime to support more: - GlobalInit::I32Const(i) => i as i64, - GlobalInit::I64Const(i) => i, - _ => Err(format_err!( - "non-integer global initializer: {:?}", - g_decl.entity - )) - .context(LucetcErrorKind::Unsupported)?, - }; - GlobalVariant::Def { - def: GlobalDef::new(init_val), + + let global = match g_decl.entity.initializer { + GlobalInit::I32Const(i) => Ok(GlobalVariant::Def(GlobalDef::I32(i))), + GlobalInit::I64Const(i) => Ok(GlobalVariant::Def(GlobalDef::I64(i))), + GlobalInit::F32Const(f) => { + Ok(GlobalVariant::Def(GlobalDef::F32(f32::from_bits(f)))) } - }; - globals.push(GlobalSpec::new(g_variant, None)); + GlobalInit::F64Const(f) => { + Ok(GlobalVariant::Def(GlobalDef::F64(f64::from_bits(f)))) + } + GlobalInit::GetGlobal(ref_ix) => { + let ref_decl = info.globals.get(ref_ix).unwrap(); + if let GlobalInit::Import = ref_decl.entity.initializer { + if let Some((module, field)) = info.imported_globals.get(ref_ix) { + Ok(GlobalVariant::Import { module, field }) + } else { + Err(format_err!("inconsistent state: global {} is declared as an import but has no entry in imported_globals", ref_ix.as_u32())) + .context(LucetcErrorKind::TranslatingModule) + } + } else { + // This WASM restriction may be loosened in the future: + Err(format_err!("invalid global declarations: global {} is initialized by referencing another global value, but the referenced global is not an import", ix.as_u32())) + .context(LucetcErrorKind::TranslatingModule) + } + } + GlobalInit::Import => { + if let Some((module, field)) = info.imported_globals.get(ix) { + Ok(GlobalVariant::Import { module, field }) + } else { + Err(format_err!("inconsistent state: global {} is declared as an import but has no entry in imported_globals", ix.as_u32())) + .context(LucetcErrorKind::TranslatingModule) + } + } + }?; + + globals.push(GlobalSpec::new(global, g_decl.export_names.clone())); } Ok(globals) } diff --git a/lucetc/tests/wasi-sdk.rs b/lucetc/tests/wasi-sdk.rs index 4ced38eb4..72f5172f2 100644 --- a/lucetc/tests/wasi-sdk.rs +++ b/lucetc/tests/wasi-sdk.rs @@ -59,17 +59,11 @@ mod programs { let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile empty"); let mdata = c.module_data().unwrap(); assert!(mdata.heap_spec().is_some()); - // clang creates 3 globals, all internal: + // clang creates 3 globals: assert_eq!(mdata.globals_spec().len(), 3); - assert_eq!( - mdata - .globals_spec() - .iter() - .filter(|g| g.export().is_some()) - .collect::>() - .len(), - 0 - ); + assert!(mdata.globals_spec()[0].is_internal()); + assert_eq!(mdata.globals_spec()[1].export_names(), &["__heap_base"]); + assert_eq!(mdata.globals_spec()[2].export_names(), &["__data_end"]); assert_eq!(mdata.import_functions().len(), 0, "import functions"); assert_eq!(mdata.export_functions().len(), 0, "export functions"); diff --git a/lucetc/tests/wasm.rs b/lucetc/tests/wasm.rs index 07f358859..702f80521 100644 --- a/lucetc/tests/wasm.rs +++ b/lucetc/tests/wasm.rs @@ -35,6 +35,22 @@ mod module_data { use lucetc::{Bindings, Compiler, HeapSettings, LucetcErrorKind, OptLevel}; use std::path::PathBuf; + #[test] + fn globals_export() { + let m = load_wat_module("globals_export"); + let b = super::test_bindings(); + let h = HeapSettings::default(); + let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compiling globals_export"); + let mdata = c.module_data().unwrap(); + + assert_eq!(mdata.globals_spec().len(), 1); + assert_eq!(mdata.globals_spec()[0].export_names(), &["start", "dupe"]); + + assert_eq!(mdata.import_functions().len(), 0); + assert_eq!(mdata.export_functions().len(), 0); + assert_eq!(mdata.function_info().len(), 2); + } + #[test] fn fibonacci() { let m = load_wat_module("fibonacci"); diff --git a/lucetc/tests/wasm/globals_export.wat b/lucetc/tests/wasm/globals_export.wat new file mode 100644 index 000000000..a17adbecb --- /dev/null +++ b/lucetc/tests/wasm/globals_export.wat @@ -0,0 +1,5 @@ +(module + (global (;0;) i32 (i32.const 0x1234)) + (export "start" (global 0)) + (export "dupe" (global 0)) +) From 3951892858b897d9eeae47dd7b346a76768bcc29 Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Wed, 12 Jun 2019 10:55:51 +0200 Subject: [PATCH 159/512] lucetc: do not print the error returned by wat2wasm (#207) When the input is neither valid WASM nor WAT, only print that rather than the wat2wasm error. This prevents the terminal from exploding after pages of garbage (from a WAT parser perspective) are printed whenever one inadvertently types "lucetc-wasi" instead of "lucet-wasi". --- lucetc/src/load.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lucetc/src/load.rs b/lucetc/src/load.rs index 5b6140078..b6c7bcf5c 100644 --- a/lucetc/src/load.rs +++ b/lucetc/src/load.rs @@ -1,3 +1,4 @@ +use crate::error::LucetcErrorKind; use failure::*; use std::fs::File; use std::io::Read; @@ -9,7 +10,9 @@ pub fn read_module>(path: P) -> Result, Error> { let converted = if wasm_preamble(&contents) { contents } else { - wat2wasm(contents)? + wat2wasm(contents).map_err(|_| { + format_err!("Input is neither valid WASM nor WAT").context(LucetcErrorKind::Input) + })? }; Ok(converted) } From 3f04ef0e85fae4a925a208be353d0f93da671c9e Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Wed, 12 Jun 2019 10:56:40 +0200 Subject: [PATCH 160/512] Add support for small(er) Docker images to use (not work on) Lucet (#201) * Add support for small(er) Docker images to use (not work on) Lucet * Indent .travis.yml * Let Travis build the lucet-toolchain container Building the toolchain in release mode is too slow for CI. So, introduce an `install-dev` target, that reuses the debug build. The overhead is reasonable. --- .travis.yml | 12 ++++---- Dockerfile.toolchain | 14 +++++++++ Makefile | 4 +++ devenv_build_container.sh | 13 ++++---- devenv_build_toolchain_only.sh | 55 ++++++++++++++++++++++++++++++++++ helpers/install.sh | 8 ++++- 6 files changed, 94 insertions(+), 12 deletions(-) create mode 100644 Dockerfile.toolchain create mode 100755 devenv_build_toolchain_only.sh diff --git a/.travis.yml b/.travis.yml index 7955ca525..d8a5a0a85 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,16 @@ dist: xenial env: - - DEVENV_NO_INSTALL=1 + - UNOPTIMIZED_BUILD=true services: - - docker + - docker script: - - ./devenv_run.sh make indent-check test audit - - git diff --exit-code + - ./devenv_run.sh make indent-check test audit + - ./devenv_stop.sh + - git diff --exit-code + - ./devenv_build_toolchain_only.sh notifications: - email: false + email: false diff --git a/Dockerfile.toolchain b/Dockerfile.toolchain new file mode 100644 index 000000000..a034d5b69 --- /dev/null +++ b/Dockerfile.toolchain @@ -0,0 +1,14 @@ +FROM ubuntu:disco + +ENV WASI_SDK=/opt/wasi-sdk +ENV LD_LIBRARY_PATH=/opt/lucet/lib:$LD_LIBRARY_PATH +ENV PATH=/opt/lucet/bin:$PATH + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + ca-certificates clang curl lld && \ + rm -rf /var/lib/apt/lists/* && \ + update-alternatives --install /usr/bin/wasm-ld wasm-ld /usr/bin/wasm-ld-8 100 + +RUN curl -sL https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-5/libclang_rt.builtins-wasm32-wasi-5.0.tar.gz | tar x -zf - -C /usr/lib/llvm-8/lib/clang/8.0.0 + diff --git a/Makefile b/Makefile index ce0fbb17a..71fe46a10 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,10 @@ build: install: build @helpers/install.sh +.PHONY: install-dev +install-dev: build-dev + @helpers/install.sh --unoptimized + .PHONY: test test: indent-check cargo test --no-fail-fast \ diff --git a/devenv_build_container.sh b/devenv_build_container.sh index f2299c24c..196cc3064 100755 --- a/devenv_build_container.sh +++ b/devenv_build_container.sh @@ -16,10 +16,7 @@ fi echo "Building lucet-dev:latest" docker build -t lucet-dev:latest . -if [ -n "$DEVENV_NO_INSTALL" ]; then - docker tag lucet-dev:latest lucet:latest - exit -fi +docker tag lucet-dev:latest lucet:latest if docker image inspect lucet:latest > /dev/null; then if [ -z "$DEVENV_FORCE_REBUILD" ]; then @@ -31,11 +28,15 @@ if docker image inspect lucet:latest > /dev/null; then fi echo "Now creating lucet:latest on top of lucet-dev:latest" -docker run --name=lucet-dev --detach --mount type=bind,src="$(cd $(dirname ${0}); pwd -P),target=/lucet" \ +docker run --name=lucet-dev --detach --mount type=bind,src="$(cd $(dirname ${0}); pwd),target=/lucet" \ lucet-dev:latest /bin/sleep 99999999 > /dev/null echo "Building and installing optimized files in [$HOST_LUCET_MOUNT_POINT]" -docker exec -t -w "$HOST_LUCET_MOUNT_POINT" lucet-dev make install +if [ -z "$UNOPTIMIZED_BUILD" ]; then + docker exec -t -w "$HOST_LUCET_MOUNT_POINT" lucet-dev make install +else + docker exec -t -w "$HOST_LUCET_MOUNT_POINT" lucet-dev make install-dev +fi echo "Cleaning" docker exec -t -w "$HOST_LUCET_MOUNT_POINT" lucet-dev make clean diff --git a/devenv_build_toolchain_only.sh b/devenv_build_toolchain_only.sh new file mode 100755 index 000000000..516075409 --- /dev/null +++ b/devenv_build_toolchain_only.sh @@ -0,0 +1,55 @@ +#!/bin/sh + +. "$(dirname ${BASH_SOURCE:-$0})/config.inc" + +git submodule update --init 2>/dev/null || : + +if ! docker image inspect lucet:latest >/dev/null; then + echo "A lucet image is not present" + exit 1 +fi + +echo "Building lucet-toolchain:latest" +docker build -t lucet-toolchain:latest -f Dockerfile.toolchain . + +echo "Starting the lucet container" +docker run --name=lucet --detach --mount type=bind,src="$(cd $(dirname ${0}); pwd),target=/lucet" \ + lucet:latest /bin/sleep 99999999 > /dev/null + +echo "Creating a container from the lucet-toolchain:latest image" +docker run --name=lucet-toolchain --detach --mount type=bind,src="$( + cd $(dirname ${0}) || exit 1 + pwd -P +),target=/lucet" \ + lucet-toolchain:latest /bin/sleep 99999999 >/dev/null + +docker exec lucet tar c -pf - -C /opt lucet | + docker exec -i lucet-toolchain tar x -pf - -C /opt + +docker exec lucet-toolchain mkdir /opt/wasi-sysroot + +docker exec lucet tar c -pf - -C /opt/wasi-sdk/share/sysroot . | + docker exec -i lucet-toolchain tar x -pf - -C /opt/wasi-sysroot + +docker exec lucet-toolchain sh -c 'rm -f /opt/lucet/bin/wasm32-*' + +docker exec -i lucet-toolchain sh -c 'cat > /opt/lucet/bin/wasm32-wasi-clang; chmod 755 /opt/lucet/bin/wasm32-wasi-clang' < /opt/lucet/bin/wasm32-wasi-clang++; chmod 755 /opt/lucet/bin/wasm32-wasi-clang++' < Date: Wed, 12 Jun 2019 19:08:03 +0200 Subject: [PATCH 161/512] WASI fixes (#209) - Remove unneeded `unsafe` blocks; codecs don't need these any longer. - Removing a directory without `REMOVEDIR` may return `EPERM` instead of `EISDIR`. Adjust accordingly. (thanks, @kubkon) - If a path cannot be opened, set the file descriptor to `wasi_fd_t::max_value()` --- lucet-wasi/src/hostcalls/fs.rs | 148 ++++++++++++++----------------- lucet-wasi/src/hostcalls/misc.rs | 57 +++++------- 2 files changed, 90 insertions(+), 115 deletions(-) diff --git a/lucet-wasi/src/hostcalls/fs.rs b/lucet-wasi/src/hostcalls/fs.rs index ffedd7c75..77f854910 100644 --- a/lucet-wasi/src/hostcalls/fs.rs +++ b/lucet-wasi/src/hostcalls/fs.rs @@ -60,12 +60,8 @@ pub fn wasi_fd_fdstat_get( } else { wasm32::__WASI_EBADF }; - - unsafe { - enc_fdstat_byref(vmctx, fdstat_ptr, host_fdstat) - .expect("can write back into the pointer we read from"); - } - + enc_fdstat_byref(vmctx, fdstat_ptr, host_fdstat) + .expect("can write back into the pointer we read from"); errno } @@ -109,12 +105,9 @@ pub fn wasi_fd_tell( Err(e) => return enc_errno(e), } }; - - unsafe { - enc_filesize_byref(vmctx, offset, host_offset as u64) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } + enc_filesize_byref(vmctx, offset, host_offset as u64) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) } pub fn wasi_fd_seek( @@ -151,12 +144,9 @@ pub fn wasi_fd_seek( Err(e) => return enc_errno(e), } }; - - unsafe { - enc_filesize_byref(vmctx, newoffset, host_newoffset as u64) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } + enc_filesize_byref(vmctx, newoffset, host_newoffset as u64) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) } pub fn wasi_fd_prestat_get( @@ -174,23 +164,20 @@ pub fn wasi_fd_prestat_get( if fe.fd_object.ty != host::__WASI_FILETYPE_DIRECTORY as host::__wasi_filetype_t { return wasm32::__WASI_ENOTDIR; } - unsafe { - enc_prestat_byref( - vmctx, - prestat_ptr, - host::__wasi_prestat_t { - pr_type: host::__WASI_PREOPENTYPE_DIR as host::__wasi_preopentype_t, - u: host::__wasi_prestat_t___wasi_prestat_u { - dir: - host::__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t { - pr_name_len: po_path.as_os_str().as_bytes().len(), - }, + enc_prestat_byref( + vmctx, + prestat_ptr, + host::__wasi_prestat_t { + pr_type: host::__WASI_PREOPENTYPE_DIR as host::__wasi_preopentype_t, + u: host::__wasi_prestat_t___wasi_prestat_u { + dir: host::__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t { + pr_name_len: po_path.as_os_str().as_bytes().len(), }, }, - ) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } + }, + ) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) } else { wasm32::__WASI_ENOTSUP } @@ -218,11 +205,9 @@ pub fn wasi_fd_prestat_dir_name( if path_bytes.len() > dec_usize(path_len) { return wasm32::__WASI_ENAMETOOLONG; } - unsafe { - enc_slice_of(vmctx, path_bytes, path_ptr) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } + enc_slice_of(vmctx, path_bytes, path_ptr) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) } else { wasm32::__WASI_ENOTSUP } @@ -268,12 +253,9 @@ pub fn wasi_fd_read( let mut fe = ctx.fds.remove(&fd).expect("file entry is still there"); fe.fd_object.needs_close = false; } - - unsafe { - enc_usize_byref(vmctx, nread, host_nread) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } + enc_usize_byref(vmctx, nread, host_nread) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) } pub fn wasi_fd_write( @@ -307,12 +289,9 @@ pub fn wasi_fd_write( Ok(len) => len, Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), }; - - unsafe { - enc_usize_byref(vmctx, nwritten, host_nwritten) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } + enc_usize_byref(vmctx, nwritten, host_nwritten) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) } pub fn wasi_path_open( @@ -459,6 +438,9 @@ pub fn wasi_path_open( nix::unistd::close(new_fd).unwrap_or_else(|e| { dbg!(e); }); + if let Err(e) = enc_fd_byref(vmctx, fd_out_ptr, wasm32::__wasi_fd_t::max_value()) { + return enc_errno(e); + } return enc_errno(e); } Ok((_ty, max_base, max_inheriting)) => { @@ -471,12 +453,9 @@ pub fn wasi_path_open( } } }; - - unsafe { - enc_fd_byref(vmctx, fd_out_ptr, guest_fd) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } + enc_fd_byref(vmctx, fd_out_ptr, guest_fd) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) } pub fn wasi_fd_filestat_get( @@ -495,10 +474,8 @@ pub fn wasi_fd_filestat_get( Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), Ok(filestat) => { let host_filestat = host::filestat_from_nix(filestat); - unsafe { - enc_filestat_byref(vmctx, filestat_ptr, host_filestat) - .expect("can write into the pointer"); - } + enc_filestat_byref(vmctx, filestat_ptr, host_filestat) + .expect("can write into the pointer"); } }, Err(e) => return enc_errno(e), @@ -536,10 +513,8 @@ pub fn wasi_path_filestat_get( Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()), Ok(filestat) => { let host_filestat = host::filestat_from_nix(filestat); - unsafe { - enc_filestat_byref(vmctx, filestat_ptr, host_filestat) - .expect("can write into the pointer"); - } + enc_filestat_byref(vmctx, filestat_ptr, host_filestat) + .expect("can write into the pointer"); wasm32::__WASI_ESUCCESS } } @@ -601,7 +576,26 @@ pub fn wasi_path_unlink_file( // nix doesn't expose unlinkat() yet match unsafe { unlinkat(dir, path_cstr.as_ptr(), 0) } { 0 => wasm32::__WASI_ESUCCESS, - _ => wasm32::errno_from_nix(errno::Errno::last()), + _ => { + let mut e = errno::Errno::last(); + // Non-Linux implementations may return EPERM when attempting to remove a + // directory without `REMOVEDIR`. For WASI, adjust this to `EISDIR`. + #[cfg(not(linux))] + { + use nix::fcntl::AtFlags; + use nix::sys::stat::{fstatat, SFlag}; + if e == errno::Errno::EPERM { + if let Ok(stat) = fstatat(dir, path.as_os_str(), AtFlags::AT_SYMLINK_NOFOLLOW) { + if SFlag::from_bits_truncate(stat.st_mode).contains(SFlag::S_IFDIR) { + e = errno::Errno::EISDIR; + } + } else { + e = errno::Errno::last(); + } + } + } + wasm32::errno_from_nix(e) + } } } @@ -977,11 +971,9 @@ pub fn wasi_fd_pread( buf_offset += vec_len; left -= vec_len; } - unsafe { - enc_usize_byref(vmctx, nread, host_nread) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } + enc_usize_byref(vmctx, nread, host_nread) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) } pub fn wasi_fd_pwrite( @@ -1020,11 +1012,9 @@ pub fn wasi_fd_pwrite( Ok(len) => len, Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), }; - unsafe { - enc_usize_byref(vmctx, nwritten, host_nwritten) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } + enc_usize_byref(vmctx, nwritten, host_nwritten) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) } pub fn wasi_fd_readdir( @@ -1101,11 +1091,9 @@ pub fn wasi_fd_readdir( left -= required_space; } let host_bufused = host_buf_len - left; - unsafe { - enc_usize_byref(vmctx, bufused, host_bufused) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } + enc_usize_byref(vmctx, bufused, host_bufused) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) } pub fn wasi_fd_renumber( diff --git a/lucet-wasi/src/hostcalls/misc.rs b/lucet-wasi/src/hostcalls/misc.rs index d592427cb..a96161ebc 100644 --- a/lucet-wasi/src/hostcalls/misc.rs +++ b/lucet-wasi/src/hostcalls/misc.rs @@ -61,7 +61,7 @@ pub fn wasi_args_get( let arg_bytes = arg.as_bytes_with_nul(); let arg_ptr = argv_buf + argv_buf_offset; - if let Err(e) = unsafe { enc_slice_of(vmctx, arg_bytes, arg_ptr) } { + if let Err(e) = enc_slice_of(vmctx, arg_bytes, arg_ptr) { return enc_errno(e); } @@ -76,12 +76,9 @@ pub fn wasi_args_get( return wasm32::__WASI_EOVERFLOW; } } - - unsafe { - enc_slice_of(vmctx, argv.as_slice(), argv_ptr) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } + enc_slice_of(vmctx, argv.as_slice(), argv_ptr) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) } pub fn wasi_args_sizes_get( @@ -97,14 +94,11 @@ pub fn wasi_args_sizes_get( .iter() .map(|arg| arg.as_bytes_with_nul().len()) .sum(); - - unsafe { - if let Err(e) = enc_usize_byref(vmctx, argc_ptr, argc) { - return enc_errno(e); - } - if let Err(e) = enc_usize_byref(vmctx, argv_buf_size_ptr, argv_size) { - return enc_errno(e); - } + if let Err(e) = enc_usize_byref(vmctx, argc_ptr, argc) { + return enc_errno(e); + } + if let Err(e) = enc_usize_byref(vmctx, argv_buf_size_ptr, argv_size) { + return enc_errno(e); } wasm32::__WASI_ESUCCESS } @@ -146,11 +140,9 @@ pub fn wasi_clock_res_get( if resolution == 0 { wasm32::__WASI_EINVAL } else { - unsafe { - enc_timestamp_byref(vmctx, resolution_ptr, resolution) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } + enc_timestamp_byref(vmctx, resolution_ptr, resolution) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) } }) .unwrap_or(wasm32::__WASI_EOVERFLOW) @@ -185,7 +177,7 @@ pub fn wasi_clock_time_get( (timespec.tv_sec as host::__wasi_timestamp_t) .checked_mul(1_000_000_000) .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t)) - .map(|time| unsafe { + .map(|time| { enc_timestamp_byref(vmctx, time_ptr, time) .map(|_| wasm32::__WASI_ESUCCESS) .unwrap_or_else(|e| e) @@ -207,7 +199,7 @@ pub fn wasi_environ_get( let env_bytes = pair.as_bytes_with_nul(); let env_ptr = environ_buf + environ_buf_offset; - if let Err(e) = unsafe { enc_slice_of(vmctx, env_bytes, env_ptr) } { + if let Err(e) = enc_slice_of(vmctx, env_bytes, env_ptr) { return enc_errno(e); } @@ -222,12 +214,9 @@ pub fn wasi_environ_get( return wasm32::__WASI_EOVERFLOW; } } - - unsafe { - enc_slice_of(vmctx, environ.as_slice(), environ_ptr) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } + enc_slice_of(vmctx, environ.as_slice(), environ_ptr) + .map(|_| wasm32::__WASI_ESUCCESS) + .unwrap_or_else(|e| e) } pub fn wasi_environ_sizes_get( @@ -241,13 +230,11 @@ pub fn wasi_environ_sizes_get( if let Some(environ_size) = ctx.env.iter().try_fold(0, |acc: u32, pair| { acc.checked_add(pair.as_bytes_with_nul().len() as u32) }) { - unsafe { - if let Err(e) = enc_usize_byref(vmctx, environ_count_ptr, environ_count) { - return enc_errno(e); - } - if let Err(e) = enc_usize_byref(vmctx, environ_size_ptr, environ_size as usize) { - return enc_errno(e); - } + if let Err(e) = enc_usize_byref(vmctx, environ_count_ptr, environ_count) { + return enc_errno(e); + } + if let Err(e) = enc_usize_byref(vmctx, environ_size_ptr, environ_size as usize) { + return enc_errno(e); } wasm32::__WASI_ESUCCESS } else { From d0ca8ad6f8a21b4c9dac94658c5a5e6ffb3ed0c5 Mon Sep 17 00:00:00 2001 From: Zheng Luo Date: Wed, 12 Jun 2019 13:20:51 -0700 Subject: [PATCH 162/512] lucet-runtime: add missing lucet_error_no_linear_memory (#210) Error::NoLinearMemory was added in d03aaad7b198ab4e4eff442e213871801df5c36f, but it didn't update the C header, causing GDB to display lucet_error incorrectly --- lucet-runtime/include/lucet_types.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lucet-runtime/include/lucet_types.h b/lucet-runtime/include/lucet_types.h index 7d032339a..01a69beaf 100644 --- a/lucet-runtime/include/lucet_types.h +++ b/lucet-runtime/include/lucet_types.h @@ -22,6 +22,7 @@ enum lucet_error { lucet_error_region_full, lucet_error_module, lucet_error_limits_exceeded, + lucet_error_no_linear_memory, lucet_error_symbol_not_found, lucet_error_func_not_found, lucet_error_runtime_fault, From 52f27b7b6e962c540edaeb4a06d38d3476980a0f Mon Sep 17 00:00:00 2001 From: data-pup <16364986+data-pup@users.noreply.github.com> Date: Fri, 14 Jun 2019 20:37:40 +0000 Subject: [PATCH 163/512] lucetc::Lucetc::from_bytes (#215) * lucetc::Lucetc::from_bytes * address pr review * fixup --- lucet-runtime/lucet-runtime-tests/Cargo.toml | 1 - .../lucet-runtime-tests/src/stack.rs | 11 ++------ lucetc/src/lib.rs | 26 ++++++++++++++++--- lucetc/src/load.rs | 10 ++++--- 4 files changed, 32 insertions(+), 16 deletions(-) diff --git a/lucet-runtime/lucet-runtime-tests/Cargo.toml b/lucet-runtime/lucet-runtime-tests/Cargo.toml index a9806e7b0..dcf514ad4 100644 --- a/lucet-runtime/lucet-runtime-tests/Cargo.toml +++ b/lucet-runtime/lucet-runtime-tests/Cargo.toml @@ -18,6 +18,5 @@ lucet-runtime-internals = { path = "../lucet-runtime-internals" } lucet-wasi-sdk = { path = "../../lucet-wasi-sdk" } lucetc = { path = "../../lucetc" } - [build-dependencies] cc = "1.0" diff --git a/lucet-runtime/lucet-runtime-tests/src/stack.rs b/lucet-runtime/lucet-runtime-tests/src/stack.rs index 126716dec..76ec20df5 100644 --- a/lucet-runtime/lucet-runtime-tests/src/stack.rs +++ b/lucet-runtime/lucet-runtime-tests/src/stack.rs @@ -1,20 +1,13 @@ use failure::Error; use lucet_runtime_internals::module::DlModule; use lucetc::Lucetc; -use std::fs::File; -use std::io::prelude::*; use std::sync::Arc; use tempfile::TempDir; pub fn stack_testcase(num_locals: usize) -> Result, Error> { - let workdir = TempDir::new().expect("create working directory"); - - let wasm_path = workdir.path().join("out.wasm"); + let native_build = Lucetc::try_from_bytes(generate_test_wat(num_locals))?; - let mut wasm_file = File::create(&wasm_path)?; - wasm_file.write_all(generate_test_wat(num_locals).as_bytes())?; - - let native_build = Lucetc::new(wasm_path); + let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); diff --git a/lucetc/src/lib.rs b/lucetc/src/lib.rs index f2035f6bf..ab1134b05 100644 --- a/lucetc/src/lib.rs +++ b/lucetc/src/lib.rs @@ -26,13 +26,19 @@ pub use crate::{ load::read_module, patch::patch_module, }; +use crate::load::read_bytes; use failure::{format_err, Error, ResultExt}; use std::env; use std::path::{Path, PathBuf}; use tempfile; +enum LucetcInput { + Bytes(Vec), + Path(PathBuf), +} + pub struct Lucetc { - input: PathBuf, + input: LucetcInput, bindings: Vec, opt_level: OptLevel, heap: HeapSettings, @@ -150,7 +156,7 @@ impl Lucetc { pub fn new>(input: P) -> Self { let input = input.as_ref(); Self { - input: input.to_owned(), + input: LucetcInput::Path(input.to_owned()), bindings: vec![], opt_level: OptLevel::default(), heap: HeapSettings::default(), @@ -158,11 +164,25 @@ impl Lucetc { } } + pub fn try_from_bytes>(bytes: B) -> Result { + let input = read_bytes(bytes.as_ref().to_vec())?; + Ok(Self { + input: LucetcInput::Bytes(input), + bindings: vec![], + opt_level: OptLevel::default(), + heap: HeapSettings::default(), + builtins_paths: vec![], + }) + } + fn build(&self) -> Result<(Vec, Bindings), Error> { use parity_wasm::elements::{deserialize_buffer, serialize}; let mut builtins_bindings = vec![]; - let mut module_binary = read_module(&self.input)?; + let mut module_binary = match &self.input { + LucetcInput::Bytes(bytes) => bytes.clone(), + LucetcInput::Path(path) => read_module(&path)?, + }; if !self.builtins_paths.is_empty() { let mut module = deserialize_buffer(&module_binary)?; diff --git a/lucetc/src/load.rs b/lucetc/src/load.rs index b6c7bcf5c..8a69b2ff3 100644 --- a/lucetc/src/load.rs +++ b/lucetc/src/load.rs @@ -7,10 +7,14 @@ use wabt::wat2wasm; pub fn read_module>(path: P) -> Result, Error> { let contents = read_to_u8s(path)?; - let converted = if wasm_preamble(&contents) { - contents + read_bytes(contents) +} + +pub fn read_bytes(bytes: Vec) -> Result, Error> { + let converted = if wasm_preamble(&bytes) { + bytes } else { - wat2wasm(contents).map_err(|_| { + wat2wasm(bytes).map_err(|_| { format_err!("Input is neither valid WASM nor WAT").context(LucetcErrorKind::Input) })? }; From 0c609c19292e2b2f83b2c96e25db0ede87352450 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 14 Jun 2019 22:38:17 +0200 Subject: [PATCH 164/512] Indent --- lucetc/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lucetc/src/lib.rs b/lucetc/src/lib.rs index ab1134b05..2300539e2 100644 --- a/lucetc/src/lib.rs +++ b/lucetc/src/lib.rs @@ -17,6 +17,7 @@ mod stack_probe; mod table; mod traps; +use crate::load::read_bytes; pub use crate::{ bindings::Bindings, compiler::Compiler, @@ -26,7 +27,6 @@ pub use crate::{ load::read_module, patch::patch_module, }; -use crate::load::read_bytes; use failure::{format_err, Error, ResultExt}; use std::env; use std::path::{Path, PathBuf}; From d45a2aa7eb3eef03af1dac265ce6cef88cefda51 Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Mon, 17 Jun 2019 13:02:48 +0200 Subject: [PATCH 165/512] Update the shootout makefile to use the `fast` optimization level (#217) `best` doesn't exist any more. And the cranelift option for no optimization is "fastest" not "fast" --- benchmarks/shootout/Makefile | 2 +- lucetc/src/compiler.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmarks/shootout/Makefile b/benchmarks/shootout/Makefile index 22a2fcbdd..ac5607998 100644 --- a/benchmarks/shootout/Makefile +++ b/benchmarks/shootout/Makefile @@ -16,7 +16,7 @@ SHOOTOUT_SRCS:=$(shell ls $(SHOOTOUT)/*.c) SHOOTOUT_NATIVE_OBJS:= SHOOTOUT_LUCET_OBJS:= -LUCETC_FLAGS:=--opt-level best --min-reserved-size 4294967296 +LUCETC_FLAGS:=--opt-level fast --min-reserved-size 4294967296 COMMON_CFLAGS:=--std=c99 -Ofast -Wall -W -I$(SIGHTGLASS)/include SHOOTOUT_NATIVE_CFLAGS:=-march=native -fPIC \ diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index 9cc82d858..dfc49255a 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -37,7 +37,7 @@ impl Default for OptLevel { impl OptLevel { pub fn to_flag(&self) -> &str { match self { - OptLevel::None => "fast", + OptLevel::None => "fastest", OptLevel::Standard => "default", OptLevel::Fast => "best", } From 8b20e9527aabd27e8360bd2aac763cedf4a96a8b Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Mon, 17 Jun 2019 13:04:22 +0200 Subject: [PATCH 166/512] wasi_path_readlink: do not return EINVAL if an empty buffer is supplied (#213) POSIX mentions that readlink(2) and readlinkat(2) can accept an empty buffer. As usual, Linux doesn't follow the specification, and returns EINVAL if the buffer length is zero. Work around this by allocating a dummy buffer if the length is zero. Bug spotted in wasi-common, but different fix. --- lucet-wasi/src/hostcalls/fs.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lucet-wasi/src/hostcalls/fs.rs b/lucet-wasi/src/hostcalls/fs.rs index 77f854910..a7255fce4 100644 --- a/lucet-wasi/src/hostcalls/fs.rs +++ b/lucet-wasi/src/hostcalls/fs.rs @@ -1191,6 +1191,7 @@ pub fn wasi_path_readlink( bufused: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { use nix::fcntl::readlinkat; + use std::cmp; match enc_usize_byref(vmctx, bufused, 0) { Ok(_) => {} @@ -1206,15 +1207,20 @@ pub fn wasi_path_readlink( Ok((dir, path)) => (dir, path), Err(e) => return enc_errno(e), }; - let mut buf = match dec_slice_of_mut::(vmctx, buf_ptr, buf_len) { - Ok(buf) => buf, - Err(e) => return enc_errno(e), + let dummy_buf = &mut [0u8]; + let mut buf = if buf_len > 0 { + match dec_slice_of_mut::(vmctx, buf_ptr, buf_len) { + Ok(buf) => buf, + Err(e) => return enc_errno(e), + } + } else { + dummy_buf }; let target_path = match readlinkat(dir, path.as_os_str(), &mut buf) { Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), Ok(target_path) => target_path, }; - let host_bufused = target_path.len(); + let host_bufused = cmp::min(buf_len as usize, target_path.len()); match enc_usize_byref(vmctx, bufused, host_bufused) { Ok(_) => {} Err(e) => return enc_errno(e), From 23eaca6ce96bff1ea3611fa123f5febe76877d75 Mon Sep 17 00:00:00 2001 From: awortman-fastly <49215183+awortman-fastly@users.noreply.github.com> Date: Tue, 18 Jun 2019 13:19:11 -0700 Subject: [PATCH 167/512] add a non-default signature so benchmark functions typecheck (#191) --- benchmarks/lucet-benchmarks/src/modules.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/benchmarks/lucet-benchmarks/src/modules.rs b/benchmarks/lucet-benchmarks/src/modules.rs index 77e892711..c510fa132 100644 --- a/benchmarks/lucet-benchmarks/src/modules.rs +++ b/benchmarks/lucet-benchmarks/src/modules.rs @@ -1,4 +1,4 @@ -use lucet_module_data::FunctionPointer; +use lucet_module_data::{lucet_signature, FunctionPointer}; use lucet_runtime::lucet_hostcalls; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime_internals::module::{HeapSpec, MockModuleBuilder, Module}; @@ -179,7 +179,24 @@ pub fn many_args_mock() -> Arc { } MockModuleBuilder::new() - .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize))) + .with_export_func( + MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize)) + .with_sig(lucet_signature!( + ( + I32, I32, I32, I64, F32, F64, + I32, I32, I32, I64, F32, F64, + I32, I32, I32, I64, F32, F64, + I32, I32, I32, I64, F32, F64, + I32, I32, I32, I64, F32, F64, + I32, I32, I32, I64, F32, F64, + I32, I32, I32, I64, F32, F64, + I32, I32, I32, I64, F32, F64, + I32, I32, I32, I64, F32, F64, + I32, I32, I32, I64, F32, F64, + I32, I32, I32, I64, F32, F64 + ) -> () + )) + ) .build() } From b0cc5e47ad2aee9b9a94b5292b0d89522111bcf2 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Wed, 19 Jun 2019 13:14:45 -0400 Subject: [PATCH 168/512] Allow creating UntypedRetVal This allows only creating it from values that can be fully safely represented. The reason to do this is for writing tests in downstream crates that want to test what is done with the result of a guest run. Closes #211 --- .../lucet-runtime-internals/src/val.rs | 15 +++++ lucet-runtime/tests/val.rs | 61 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 lucet-runtime/tests/val.rs diff --git a/lucet-runtime/lucet-runtime-internals/src/val.rs b/lucet-runtime/lucet-runtime-internals/src/val.rs index a49c0540d..77cd05dcb 100644 --- a/lucet-runtime/lucet-runtime-internals/src/val.rs +++ b/lucet-runtime/lucet-runtime-internals/src/val.rs @@ -176,6 +176,21 @@ impl UntypedRetVal { } } +impl From for UntypedRetVal { + fn from(reg: RegVal) -> UntypedRetVal { + match reg { + RegVal::GpReg(r) => UntypedRetVal::new(r, unsafe { _mm_setzero_ps() }), + RegVal::FpReg(r) => UntypedRetVal::new(0, r), + } + } +} + +impl> From for UntypedRetVal { + fn from(v: T) -> UntypedRetVal { + val_to_reg(&v.into()).into() + } +} + macro_rules! impl_from_fp { ( $ty:ty, $f:ident, $as:ident ) => { impl From for $ty { diff --git a/lucet-runtime/tests/val.rs b/lucet-runtime/tests/val.rs new file mode 100644 index 000000000..7fe78e3e2 --- /dev/null +++ b/lucet-runtime/tests/val.rs @@ -0,0 +1,61 @@ +use lucet_runtime_internals::val::UntypedRetVal; + +#[test] +fn untyped_ret_val_from_f32() { + assert_eq!(1.2, f32::from(UntypedRetVal::from(1.2f32))); +} + +#[test] +fn untyped_ret_val_from_f64() { + assert_eq!(1.2, f64::from(UntypedRetVal::from(1.2f64))); +} + +#[test] +fn untyped_ret_val_from_u8() { + assert_eq!(5, u8::from(UntypedRetVal::from(5u8))); +} + +#[test] +fn untyped_ret_val_from_u16() { + assert_eq!(5, u16::from(UntypedRetVal::from(5u16))); +} + +#[test] +fn untyped_ret_val_from_u32() { + assert_eq!(5, u32::from(UntypedRetVal::from(5u32))); +} + +#[test] +fn untyped_ret_val_from_u64() { + assert_eq!(5, u64::from(UntypedRetVal::from(5u64))); +} + +#[test] +fn untyped_ret_val_from_i8() { + assert_eq!(5, i8::from(UntypedRetVal::from(5i8))); +} + +#[test] +fn untyped_ret_val_from_i16() { + assert_eq!(5, i16::from(UntypedRetVal::from(5i16))); +} + +#[test] +fn untyped_ret_val_from_i32() { + assert_eq!(5, i32::from(UntypedRetVal::from(5i32))); +} + +#[test] +fn untyped_ret_val_from_i64() { + assert_eq!(5, i64::from(UntypedRetVal::from(5i64))); +} + +#[test] +fn untyped_ret_val_from_bool_true() { + assert_eq!(true, bool::from(UntypedRetVal::from(true))); +} + +#[test] +fn untyped_ret_val_from_bool_false() { + assert_eq!(false, bool::from(UntypedRetVal::from(false))); +} From 37fd519df95ea831408f39e9b50e9cdfa49cb29a Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Fri, 21 Jun 2019 18:06:57 +0200 Subject: [PATCH 169/512] Update sightglass (updates the axios dependency to fix CVE-2019-10742) (#188) --- sightglass | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sightglass b/sightglass index 4999f901b..b409ba75a 160000 --- a/sightglass +++ b/sightglass @@ -1 +1 @@ -Subproject commit 4999f901b3d686a911dfe24b588d6397ca2b193a +Subproject commit b409ba75a7a89cbf4cbf9ec44880e4ae6509a85c From ca21c6720eeec54fe6e64006bdba722d717f16eb Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Sat, 22 Jun 2019 17:41:37 +0200 Subject: [PATCH 170/512] Fixed-width ints have been deprecated by the libc crate (#223) --- lucet-runtime/src/c_api.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lucet-runtime/src/c_api.rs b/lucet-runtime/src/c_api.rs index b41f0f475..a1d42b637 100644 --- a/lucet-runtime/src/c_api.rs +++ b/lucet-runtime/src/c_api.rs @@ -388,7 +388,7 @@ lucet_hostcalls! { /// Get the number of WebAssembly pages currently in the heap. pub unsafe extern "C" fn lucet_vmctx_current_memory( &mut vmctx, - ) -> libc::uint32_t { + ) -> u32 { vmctx.instance().alloc().heap_len() as u32 / WASM_PAGE_SIZE } @@ -398,10 +398,10 @@ lucet_hostcalls! { /// On success, returns the number of pages that existed before the call. On failure, returns `-1`. pub unsafe extern "C" fn lucet_vmctx_grow_memory( &mut vmctx, - additional_pages: libc::uint32_t, - ) -> libc::int32_t { + additional_pages: u32, + ) -> i32 { if let Ok(old_pages) = vmctx.instance_mut().grow_memory(additional_pages) { - old_pages as libc::int32_t + old_pages as i32 } else { -1 } From 4f2d2a591abe5293945bf267fdb38697a13a8b8b Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Sat, 22 Jun 2019 17:42:44 +0200 Subject: [PATCH 171/512] Dynamic traits without "dyn" will not be supported any more (#222) * Dynamic traits without "dyn" will not be supported any more Also add explicit lifetimes, because implicit ones is so 2015. * Deny bare trait objects --- lucet-analyze/src/main.rs | 8 +++++--- lucet-idl/src/lib.rs | 2 ++ lucet-module-data/src/functions.rs | 4 ++-- lucet-module-data/src/globals.rs | 4 ++-- lucet-module-data/src/lib.rs | 2 ++ lucet-module-data/src/module_data.rs | 4 ++-- lucet-module-data/src/traps.rs | 2 +- lucet-module-data/src/types.rs | 4 ++-- .../lucet-runtime-internals/src/embed_ctx.rs | 4 ++-- .../lucet-runtime-internals/src/instance.rs | 10 +++++----- .../src/instance/signals.rs | 4 ++-- .../lucet-runtime-internals/src/module.rs | 2 +- .../lucet-runtime-internals/src/module/dl.rs | 6 +++--- .../lucet-runtime-internals/src/module/mock.rs | 2 +- lucet-runtime/lucet-runtime-internals/src/val.rs | 2 +- lucet-runtime/lucet-runtime-internals/src/vmctx.rs | 12 ++++++------ lucet-runtime/src/lib.rs | 2 ++ lucet-spectest/src/error.rs | 4 ++-- lucet-spectest/src/lib.rs | 2 ++ lucet-wasi-fuzz/src/main.rs | 2 ++ lucet-wasi-sdk/src/lib.rs | 10 ++++++---- lucet-wasi/src/lib.rs | 2 ++ lucet-wasi/src/main.rs | 4 +++- lucetc/src/compiler.rs | 6 +++--- lucetc/src/decls.rs | 14 +++++++------- lucetc/src/error.rs | 4 ++-- lucetc/src/function.rs | 6 +++--- lucetc/src/lib.rs | 2 ++ lucetc/src/options.rs | 2 +- lucetc/src/output.rs | 2 +- lucetc/src/table.rs | 4 ++-- 31 files changed, 79 insertions(+), 59 deletions(-) diff --git a/lucet-analyze/src/main.rs b/lucet-analyze/src/main.rs index 2b8127a88..15ac64c1e 100644 --- a/lucet-analyze/src/main.rs +++ b/lucet-analyze/src/main.rs @@ -1,3 +1,5 @@ +#![deny(bare_trait_objects)] + use lucet_module_data::{Error, FunctionSpec, ModuleData, TrapManifest, TrapSite}; use byteorder::{LittleEndian, ReadBytesExt}; @@ -43,7 +45,7 @@ struct DataSegment { } impl<'a> ArtifactSummary<'a> { - fn new(buffer: &'a Vec, elf: &'a elf::Elf) -> Self { + fn new(buffer: &'a Vec, elf: &'a elf::Elf<'_>) -> Self { Self { buffer: buffer, elf: elf, @@ -286,7 +288,7 @@ fn parse_trap_manifest<'a>( if let Some(faulty_trap_manifest) = f.traps() { let trap_ptr = faulty_trap_manifest.traps.as_ptr(); let traps_count = faulty_trap_manifest.traps.len(); - let traps_byte_count = traps_count * std::mem::size_of::(); + let traps_byte_count = traps_count * std::mem::size_of::>(); if let Some(traps_byte_slice) = summary.read_memory(trap_ptr as u64, traps_byte_count as u64) { @@ -530,7 +532,7 @@ fn summarize_module_data<'a, 'b: 'a>( } } -fn print_summary(summary: ArtifactSummary) { +fn print_summary(summary: ArtifactSummary<'_>) { println!("Required Symbols:"); println!( " {:30}: {}", diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index fb5238b21..111c54791 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(bare_trait_objects)] + #[macro_use] extern crate failure; diff --git a/lucet-module-data/src/functions.rs b/lucet-module-data/src/functions.rs index cc4e4cc4e..c37bbb158 100644 --- a/lucet-module-data/src/functions.rs +++ b/lucet-module-data/src/functions.rs @@ -117,7 +117,7 @@ pub struct OwnedFunctionMetadata { } impl OwnedFunctionMetadata { - pub fn to_ref(&self) -> FunctionMetadata { + pub fn to_ref(&self) -> FunctionMetadata<'_> { FunctionMetadata { signature: self.signature.clone(), name: self.name.as_ref().map(|n| n.as_str()), @@ -175,7 +175,7 @@ impl FunctionSpec { None } - pub fn traps(&self) -> Option { + pub fn traps(&self) -> Option> { let traps_ptr = self.traps_addr as *const TrapSite; if !traps_ptr.is_null() { let traps_slice = diff --git a/lucet-module-data/src/globals.rs b/lucet-module-data/src/globals.rs index af870d260..cbbfe448e 100644 --- a/lucet-module-data/src/globals.rs +++ b/lucet-module-data/src/globals.rs @@ -30,7 +30,7 @@ impl<'a> GlobalSpec<'a> { Self::new(Global::Import { module, field }, export_names) } - pub fn global(&self) -> &Global { + pub fn global(&self) -> &Global<'_> { &self.global } @@ -84,7 +84,7 @@ pub union GlobalValue { } impl std::fmt::Debug for GlobalValue { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // Because GlobalValue is a union of primitives, there won't be anything wrong, // representation-wise, with printing the underlying data as an i64, f64, or // another primitive. This still may incur UB by doing something like trying to diff --git a/lucet-module-data/src/lib.rs b/lucet-module-data/src/lib.rs index 8f5696fd0..994a41da0 100644 --- a/lucet-module-data/src/lib.rs +++ b/lucet-module-data/src/lib.rs @@ -3,6 +3,8 @@ //! These types are used both in `lucetc` and `lucet-runtime`, with values serialized in //! [`bincode`](https://github.com/TyOverby/bincode) format to the compiled Lucet modules. +#![deny(bare_trait_objects)] + mod error; mod functions; mod globals; diff --git a/lucet-module-data/src/module_data.rs b/lucet-module-data/src/module_data.rs index fd87e6121..7d0acba15 100644 --- a/lucet-module-data/src/module_data.rs +++ b/lucet-module-data/src/module_data.rs @@ -73,11 +73,11 @@ impl<'a> ModuleData<'a> { &self.function_info } - pub fn import_functions(&self) -> &[ImportFunction] { + pub fn import_functions(&self) -> &[ImportFunction<'_>] { &self.import_functions } - pub fn export_functions(&self) -> &[ExportFunction] { + pub fn export_functions(&self) -> &[ExportFunction<'_>] { &self.export_functions } diff --git a/lucet-module-data/src/traps.rs b/lucet-module-data/src/traps.rs index 63a4b5ca8..a87b69a00 100644 --- a/lucet-module-data/src/traps.rs +++ b/lucet-module-data/src/traps.rs @@ -47,7 +47,7 @@ pub struct TrapManifest<'a> { } impl <'a> TrapManifest<'a> { - pub fn new(traps: &'a [TrapSite]) -> TrapManifest { + pub fn new(traps: &'a [TrapSite]) -> TrapManifest<'_> { TrapManifest { traps } } pub fn lookup_addr(&self, addr: u32) -> Option { diff --git a/lucet-module-data/src/types.rs b/lucet-module-data/src/types.rs index 2157ae109..fa7eaba6d 100644 --- a/lucet-module-data/src/types.rs +++ b/lucet-module-data/src/types.rs @@ -12,7 +12,7 @@ pub enum ValueType { } impl Display for ValueType { - fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { ValueType::I32 => write!(f, "I32"), ValueType::I64 => write!(f, "I64"), @@ -74,7 +74,7 @@ pub struct Signature { } impl Display for Signature { - fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "(")?; for (i, p) in self.params.iter().enumerate() { if i == 0 { diff --git a/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs b/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs index 3affe2217..808390545 100644 --- a/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs @@ -19,7 +19,7 @@ impl CtxMap { self.map.contains_key(&TypeId::of::()) } - pub fn try_get(&self) -> Option, BorrowError>> { + pub fn try_get(&self) -> Option, BorrowError>> { self.map.get(&TypeId::of::()).map(|x| { x.try_borrow().map(|r| { Ref::map(r, |b| { @@ -30,7 +30,7 @@ impl CtxMap { }) } - pub fn try_get_mut(&mut self) -> Option, BorrowMutError>> { + pub fn try_get_mut(&mut self) -> Option, BorrowMutError>> { self.map.get_mut(&TypeId::of::()).map(|x| { x.try_borrow_mut().map(|r| { RefMut::map(r, |b| { diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index f84a762cc..c970726d6 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -425,12 +425,12 @@ impl Instance { } /// Get a reference to a context value of a particular type, if it exists. - pub fn get_embed_ctx(&self) -> Option, BorrowError>> { + pub fn get_embed_ctx(&self) -> Option, BorrowError>> { self.embed_ctx.try_get::() } /// Get a mutable reference to a context value of a particular type, if it exists. - pub fn get_embed_ctx_mut(&mut self) -> Option, BorrowMutError>> { + pub fn get_embed_ctx_mut(&mut self) -> Option, BorrowMutError>> { self.embed_ctx.try_get_mut::() } @@ -727,7 +727,7 @@ pub struct FaultDetails { } impl std::fmt::Display for FaultDetails { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if self.fatal { write!(f, "fault FATAL ")?; } else { @@ -818,7 +818,7 @@ impl PartialEq for TerminationDetails { } impl std::fmt::Debug for TerminationDetails { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "TerminationDetails::")?; match self { TerminationDetails::Signal => write!(f, "Signal"), @@ -833,7 +833,7 @@ unsafe impl Send for TerminationDetails {} unsafe impl Sync for TerminationDetails {} impl std::fmt::Display for State { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { State::Ready { .. } => write!(f, "ready"), State::Running => write!(f, "running"), diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs index db5c30f4e..5b367bbe0 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs @@ -224,7 +224,7 @@ struct SignalState { saved_sigfpe: SigAction, saved_sigill: SigAction, saved_sigsegv: SigAction, - saved_panic_hook: Option>>, + saved_panic_hook: Option) + Sync + Send + 'static>>>, } // raw pointers in the saved types @@ -260,7 +260,7 @@ unsafe fn setup_guest_signal_state(ostate: &mut Option) { }); } -fn setup_guest_panic_hook() -> Arc> { +fn setup_guest_panic_hook() -> Arc) + Sync + Send + 'static>> { let saved_panic_hook = Arc::new(panic::take_hook()); let closure_saved_panic_hook = saved_panic_hook.clone(); std::panic::set_hook(Box::new(move |panic_info| { diff --git a/lucet-runtime/lucet-runtime-internals/src/module.rs b/lucet-runtime/lucet-runtime-internals/src/module.rs index c94c3af8a..cbcd99c32 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module.rs @@ -46,7 +46,7 @@ pub trait ModuleInternal: Send + Sync { /// /// The indices into the returned slice correspond to the WebAssembly indices of the globals /// () - fn globals(&self) -> &[GlobalSpec]; + fn globals(&self) -> &[GlobalSpec<'_>]; fn get_sparse_page_data(&self, page: usize) -> Option<&[u8]>; diff --git a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs index 232e3f052..780a02340 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs @@ -133,7 +133,7 @@ impl ModuleInternal for DlModule { self.module_data.heap_spec() } - fn globals(&self) -> &[GlobalSpec] { + fn globals(&self) -> &[GlobalSpec<'_>] { self.module_data.globals_spec() } @@ -150,12 +150,12 @@ impl ModuleInternal for DlModule { } fn table_elements(&self) -> Result<&[TableElement], Error> { - let p_table_segment: Symbol<*const TableElement> = unsafe { + let p_table_segment: Symbol<'_, *const TableElement> = unsafe { self.lib.get(b"guest_table_0").map_err(|e| { lucet_incorrect_module!("error loading required symbol `guest_table_0`: {}", e) })? }; - let p_table_segment_len: Symbol<*const usize> = unsafe { + let p_table_segment_len: Symbol<'_, *const usize> = unsafe { self.lib.get(b"guest_table_0_len").map_err(|e| { lucet_incorrect_module!("error loading required symbol `guest_table_0_len`: {}", e) })? diff --git a/lucet-runtime/lucet-runtime-internals/src/module/mock.rs b/lucet-runtime/lucet-runtime-internals/src/module/mock.rs index a79a14b3f..a1c215060 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/mock.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/mock.rs @@ -238,7 +238,7 @@ impl ModuleInternal for MockModule { self.module_data.heap_spec() } - fn globals(&self) -> &[GlobalSpec] { + fn globals(&self) -> &[GlobalSpec<'_>] { self.module_data.globals_spec() } diff --git a/lucet-runtime/lucet-runtime-internals/src/val.rs b/lucet-runtime/lucet-runtime-internals/src/val.rs index a49c0540d..3bbafd367 100644 --- a/lucet-runtime/lucet-runtime-internals/src/val.rs +++ b/lucet-runtime/lucet-runtime-internals/src/val.rs @@ -165,7 +165,7 @@ pub struct UntypedRetVal { } impl std::fmt::Display for UntypedRetVal { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "") } } diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index e2ecfd1d3..f95c3a603 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -96,7 +96,7 @@ impl Vmctx { /// /// If the heap is already mutably borrowed by `heap_mut()`, the instance will /// terminate with `TerminationDetails::BorrowError`. - pub fn heap(&self) -> Ref<[u8]> { + pub fn heap(&self) -> Ref<'_, [u8]> { unsafe { self.reconstitute_heap_view_if_needed(); } @@ -111,7 +111,7 @@ impl Vmctx { /// /// If the heap is already borrowed by `heap()` or `heap_mut()`, the instance will terminate /// with `TerminationDetails::BorrowError`. - pub fn heap_mut(&self) -> RefMut<[u8]> { + pub fn heap_mut(&self) -> RefMut<'_, [u8]> { unsafe { self.reconstitute_heap_view_if_needed(); } @@ -162,7 +162,7 @@ impl Vmctx { /// /// If the context is already mutably borrowed by `get_embed_ctx_mut`, the instance will /// terminate with `TerminationDetails::BorrowError`. - pub fn get_embed_ctx(&self) -> Ref { + pub fn get_embed_ctx(&self) -> Ref<'_, T> { match self.instance().embed_ctx.try_get::() { Some(Ok(t)) => t, Some(Err(_)) => panic!(TerminationDetails::BorrowError("get_embed_ctx")), @@ -177,7 +177,7 @@ impl Vmctx { /// /// If the context is already borrowed by some other use of `get_embed_ctx` or /// `get_embed_ctx_mut`, the instance will terminate with `TerminationDetails::BorrowError`. - pub fn get_embed_ctx_mut(&self) -> RefMut { + pub fn get_embed_ctx_mut(&self) -> RefMut<'_, T> { match unsafe { self.instance_mut().embed_ctx.try_get_mut::() } { Some(Ok(t)) => t, Some(Err(_)) => panic!(TerminationDetails::BorrowError("get_embed_ctx_mut")), @@ -205,7 +205,7 @@ impl Vmctx { /// /// If the globals are already mutably borrowed by `globals_mut()`, the instance will terminate /// with `TerminationDetails::BorrowError`. - pub fn globals(&self) -> Ref<[GlobalValue]> { + pub fn globals(&self) -> Ref<'_, [GlobalValue]> { let r = self .globals_view .try_borrow() @@ -217,7 +217,7 @@ impl Vmctx { /// /// If the globals are already borrowed by `globals()` or `globals_mut()`, the instance will /// terminate with `TerminationDetails::BorrowError`. - pub fn globals_mut(&self) -> RefMut<[GlobalValue]> { + pub fn globals_mut(&self) -> RefMut<'_, [GlobalValue]> { let r = self .globals_view .try_borrow_mut() diff --git a/lucet-runtime/src/lib.rs b/lucet-runtime/src/lib.rs index a4583d1e3..ea2631b6e 100644 --- a/lucet-runtime/src/lib.rs +++ b/lucet-runtime/src/lib.rs @@ -198,6 +198,8 @@ //! that, for example, a `SIGSEGV` on a non-Lucet thread of a host program will still likely abort //! the entire process. +#![deny(bare_trait_objects)] + pub mod c_api; pub use lucet_module_data::TrapCode; diff --git a/lucet-spectest/src/error.rs b/lucet-spectest/src/error.rs index ea49ae1ca..e9ced68c5 100644 --- a/lucet-spectest/src/error.rs +++ b/lucet-spectest/src/error.rs @@ -27,7 +27,7 @@ impl SpecTestError { } impl Fail for SpecTestError { - fn cause(&self) -> Option<&Fail> { + fn cause(&self) -> Option<&dyn Fail> { self.inner.cause() } fn backtrace(&self) -> Option<&Backtrace> { @@ -36,7 +36,7 @@ impl Fail for SpecTestError { } impl Display for SpecTestError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Display::fmt(&self.inner, f) } } diff --git a/lucet-spectest/src/lib.rs b/lucet-spectest/src/lib.rs index f555349a9..15fbbd4d2 100644 --- a/lucet-spectest/src/lib.rs +++ b/lucet-spectest/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(bare_trait_objects)] + pub mod error; pub mod script; diff --git a/lucet-wasi-fuzz/src/main.rs b/lucet-wasi-fuzz/src/main.rs index 1757838df..f8662ab1f 100644 --- a/lucet-wasi-fuzz/src/main.rs +++ b/lucet-wasi-fuzz/src/main.rs @@ -1,3 +1,5 @@ +#![deny(bare_trait_objects)] + use failure::{bail, ensure, format_err, Error}; use libc::c_ulong; use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region}; diff --git a/lucet-wasi-sdk/src/lib.rs b/lucet-wasi-sdk/src/lib.rs index 99fa9eada..4791b33d2 100644 --- a/lucet-wasi-sdk/src/lib.rs +++ b/lucet-wasi-sdk/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(bare_trait_objects)] + use failure::{Error, Fail}; use std::env; use std::io::Write; @@ -273,19 +275,19 @@ impl<'t> LinkOpt<'t> { } pub trait LinkOpts { - fn link_opt(&mut self, link_opt: LinkOpt); - fn with_link_opt(self, link_opt: LinkOpt) -> Self; + fn link_opt(&mut self, link_opt: LinkOpt<'_>); + fn with_link_opt(self, link_opt: LinkOpt<'_>) -> Self; fn export>(&mut self, export: S); fn with_export>(self, export: S) -> Self; } impl LinkOpts for T { - fn link_opt(&mut self, link_opt: LinkOpt) { + fn link_opt(&mut self, link_opt: LinkOpt<'_>) { self.as_link().ldflags.extend(link_opt.as_ldflags()); } - fn with_link_opt(mut self, link_opt: LinkOpt) -> Self { + fn with_link_opt(mut self, link_opt: LinkOpt<'_>) -> Self { self.link_opt(link_opt); self } diff --git a/lucet-wasi/src/lib.rs b/lucet-wasi/src/lib.rs index de17160fe..77dbf654b 100644 --- a/lucet-wasi/src/lib.rs +++ b/lucet-wasi/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(bare_trait_objects)] + pub mod c_api; pub mod ctx; pub mod fdentry; diff --git a/lucet-wasi/src/main.rs b/lucet-wasi/src/main.rs index 9ce31ad28..003d7174e 100644 --- a/lucet-wasi/src/main.rs +++ b/lucet-wasi/src/main.rs @@ -1,3 +1,5 @@ +#![deny(bare_trait_objects)] + #[macro_use] extern crate clap; @@ -154,7 +156,7 @@ fn main() { run(config) } -fn run(config: Config) { +fn run(config: Config<'_>) { lucet_wasi::hostcalls::ensure_linked(); let exitcode = { // doing all of this in a block makes sure everything gets dropped before exiting diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index dfc49255a..5fc96999d 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -108,7 +108,7 @@ impl<'a> Compiler<'a> { }) } - pub fn module_data(&self) -> Result { + pub fn module_data(&self) -> Result, LucetcError> { self.decls.get_module_data() } @@ -194,7 +194,7 @@ impl<'a> Compiler<'a> { fn write_module_data( clif_module: &mut ClifModule, - decls: &ModuleDecls, + decls: &ModuleDecls<'_>, ) -> Result<(), LucetcError> { use byteorder::{LittleEndian, WriteBytesExt}; use cranelift_module::{DataContext, Linkage}; @@ -235,7 +235,7 @@ fn write_module_data( fn write_startfunc_data( clif_module: &mut ClifModule, - decls: &ModuleDecls, + decls: &ModuleDecls<'_>, ) -> Result<(), LucetcError> { use cranelift_module::{DataContext, Linkage}; diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index 85d4cd019..bbbd82c89 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -351,7 +351,7 @@ impl<'a> ModuleDecls<'a> { self.info.target_config() } - pub fn function_bodies(&self) -> impl Iterator { + pub fn function_bodies(&self) -> impl Iterator, &(&'a [u8], usize))> { Box::new( self.info .function_bodies @@ -360,7 +360,7 @@ impl<'a> ModuleDecls<'a> { ) } - pub fn get_func(&self, func_index: FuncIndex) -> Result { + pub fn get_func(&self, func_index: FuncIndex) -> Result, Error> { let name = self .function_names .get(func_index) @@ -382,7 +382,7 @@ impl<'a> ModuleDecls<'a> { self.info.start_func.clone() } - pub fn get_runtime(&self, runtime_func: RuntimeFunc) -> Result { + pub fn get_runtime(&self, runtime_func: RuntimeFunc) -> Result, Error> { let func_id = *self.runtime_names.get(&runtime_func).unwrap(); let name = self.function_names.get(func_id).unwrap(); Ok(RuntimeDecl { @@ -391,7 +391,7 @@ impl<'a> ModuleDecls<'a> { }) } - pub fn get_table(&self, table_index: TableIndex) -> Result { + pub fn get_table(&self, table_index: TableIndex) -> Result, Error> { let (contents_name, len_name) = self .table_names .get(table_index) @@ -429,7 +429,7 @@ impl<'a> ModuleDecls<'a> { .ok_or_else(|| format_err!("signature out of bounds: {:?}", signature_index)) } - pub fn get_global(&self, global_index: GlobalIndex) -> Result<&Exportable, Error> { + pub fn get_global(&self, global_index: GlobalIndex) -> Result<&Exportable<'_, Global>, Error> { self.info .globals .get(global_index) @@ -444,14 +444,14 @@ impl<'a> ModuleDecls<'a> { } } - pub fn get_module_data(&self) -> Result { + pub fn get_module_data(&self) -> Result, LucetcError> { let linear_memory = if let Some(ref spec) = self.linear_memory_spec { Some(spec.to_ref()) } else { None }; - let mut functions: Vec = Vec::new(); + let mut functions: Vec> = Vec::new(); for fn_index in self.function_names.keys() { let decl = self.get_func(fn_index).unwrap(); diff --git a/lucetc/src/error.rs b/lucetc/src/error.rs index 788be41f3..539d7b702 100644 --- a/lucetc/src/error.rs +++ b/lucetc/src/error.rs @@ -27,7 +27,7 @@ impl LucetcError { } impl Fail for LucetcError { - fn cause(&self) -> Option<&Fail> { + fn cause(&self) -> Option<&dyn Fail> { self.inner.cause() } fn backtrace(&self) -> Option<&Backtrace> { @@ -36,7 +36,7 @@ impl Fail for LucetcError { } impl Display for LucetcError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Display::fmt(&self.inner, f) } } diff --git a/lucetc/src/function.rs b/lucetc/src/function.rs index 6c59bd43f..d551a02ad 100644 --- a/lucetc/src/function.rs +++ b/lucetc/src/function.rs @@ -143,7 +143,7 @@ impl<'a> FuncEnvironment for FuncInfo<'a> { fn translate_call_indirect( &mut self, - mut pos: FuncCursor, + mut pos: FuncCursor<'_>, _table_index: TableIndex, table: ir::Table, sig_index: SignatureIndex, @@ -215,7 +215,7 @@ impl<'a> FuncEnvironment for FuncInfo<'a> { fn translate_call( &mut self, - mut pos: FuncCursor, + mut pos: FuncCursor<'_>, _callee_index: FuncIndex, callee: ir::FuncRef, call_args: &[ir::Value], @@ -251,7 +251,7 @@ impl<'a> FuncEnvironment for FuncInfo<'a> { fn translate_memory_size( &mut self, - mut pos: FuncCursor, + mut pos: FuncCursor<'_>, index: MemoryIndex, _heap: ir::Heap, ) -> WasmResult { diff --git a/lucetc/src/lib.rs b/lucetc/src/lib.rs index 2300539e2..b1aaeebeb 100644 --- a/lucetc/src/lib.rs +++ b/lucetc/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(bare_trait_objects)] + mod bindings; mod compiler; mod decls; diff --git a/lucetc/src/options.rs b/lucetc/src/options.rs index 8adcd2c9d..1970259e2 100644 --- a/lucetc/src/options.rs +++ b/lucetc/src/options.rs @@ -44,7 +44,7 @@ pub struct Options { } impl Options { - pub fn from_args(m: &ArgMatches) -> Result { + pub fn from_args(m: &ArgMatches<'_>) -> Result { let input: Vec = m .values_of("input") .unwrap_or_default() diff --git a/lucetc/src/output.rs b/lucetc/src/output.rs index 36b4303bb..167672986 100644 --- a/lucetc/src/output.rs +++ b/lucetc/src/output.rs @@ -19,7 +19,7 @@ pub struct CraneliftFuncs { } impl CraneliftFuncs { - pub fn new(funcs: HashMap, isa: Box) -> Self { + pub fn new(funcs: HashMap, isa: Box) -> Self { Self { funcs, isa } } /// This outputs a .clif file diff --git a/lucetc/src/table.rs b/lucetc/src/table.rs index 8ae16b595..c382dc78b 100644 --- a/lucetc/src/table.rs +++ b/lucetc/src/table.rs @@ -14,7 +14,7 @@ enum Elem { Empty, } -fn table_elements(decl: &TableDecl) -> Result, LucetcError> { +fn table_elements(decl: &TableDecl<'_>) -> Result, LucetcError> { match decl.table.ty { TableElementType::Func => Ok(()), _ => Err(format_err!("table with non-function elements: {:?}", decl)) @@ -45,7 +45,7 @@ fn table_elements(decl: &TableDecl) -> Result, LucetcError> { pub fn write_table_data( clif_module: &mut ClifModule, - decls: &ModuleDecls, + decls: &ModuleDecls<'_>, ) -> Result<(), LucetcError> { if let Ok(table_decl) = decls.get_table(TableIndex::new(0)) { // Indirect calls are performed by looking up the callee function and type in a table that From a3f3a33e9b36b6ea6334c04c85225384ea507741 Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Mon, 24 Jun 2019 18:31:25 +0200 Subject: [PATCH 172/512] Replace libc::memcpy() calls with std::ptr::copy_nonoverlapping() (#227) --- lucet-wasi/src/hostcalls/fs.rs | 6 +++--- lucet-wasi/src/memory.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lucet-wasi/src/hostcalls/fs.rs b/lucet-wasi/src/hostcalls/fs.rs index a7255fce4..01bd835e6 100644 --- a/lucet-wasi/src/hostcalls/fs.rs +++ b/lucet-wasi/src/hostcalls/fs.rs @@ -1025,7 +1025,7 @@ pub fn wasi_fd_readdir( cookie: wasm32::__wasi_dircookie_t, bufused: wasm32::uintptr_t, ) -> wasm32::__wasi_errno_t { - use libc::{dirent, fdopendir, memcpy, readdir_r, seekdir}; + use libc::{dirent, fdopendir, readdir_r, seekdir}; match enc_usize_byref(vmctx, bufused, 0) { Ok(_) => {} @@ -1081,9 +1081,9 @@ pub fn wasi_fd_readdir( host_buf_offset += std::mem::size_of_val(&entry); let name_ptr = unsafe { *host_entry }.d_name.as_ptr(); unsafe { - memcpy( - host_buf_ptr.offset(host_buf_offset as isize) as *mut _, + std::ptr::copy_nonoverlapping( name_ptr as *const _, + host_buf_ptr.offset(host_buf_offset as isize) as *mut _, name_len, ) }; diff --git a/lucet-wasi/src/memory.rs b/lucet-wasi/src/memory.rs index b94aac3b2..3ecfd51b1 100644 --- a/lucet-wasi/src/memory.rs +++ b/lucet-wasi/src/memory.rs @@ -147,7 +147,7 @@ pub fn enc_slice_of( // get the pointer into guest memory, and copy the bytes let ptr = dec_ptr(vmctx, ptr, len_bytes)? as *mut libc::c_void; - unsafe { libc::memcpy(ptr, slice.as_ptr() as *const libc::c_void, len_bytes) }; + unsafe { std::ptr::copy_nonoverlapping(slice.as_ptr() as *const libc::c_void, ptr, len_bytes) }; Ok(()) } From 8f7a54d8c1d56a777819ed1d3d4d4cfb43a433ef Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Mon, 24 Jun 2019 18:34:34 +0200 Subject: [PATCH 173/512] Fix nix->wasi file timestamp conversion (#224) st_*tim value are in seconds, not nanoseconds --- lucet-wasi/src/host.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lucet-wasi/src/host.rs b/lucet-wasi/src/host.rs index e74227373..fb2c35b6a 100644 --- a/lucet-wasi/src/host.rs +++ b/lucet-wasi/src/host.rs @@ -227,9 +227,9 @@ pub fn filestat_from_nix(filestat: nix::sys::stat::FileStat) -> __wasi_filestat_ st_ino: filestat.st_ino as __wasi_inode_t, st_nlink: filestat.st_nlink as __wasi_linkcount_t, st_size: filestat.st_size as __wasi_filesize_t, - st_atim: filestat.st_atime as __wasi_timestamp_t, - st_ctim: filestat.st_ctime as __wasi_timestamp_t, - st_mtim: filestat.st_mtime as __wasi_timestamp_t, + st_atim: filestat.st_atime as __wasi_timestamp_t * 1_000_000_000, + st_ctim: filestat.st_ctime as __wasi_timestamp_t * 1_000_000_000, + st_mtim: filestat.st_mtime as __wasi_timestamp_t * 1_000_000_000, st_filetype: filetype_from_nix(filetype), } } From 0c15f420a4d0a09da0918bd561676f3c85a68566 Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Mon, 24 Jun 2019 23:07:44 +0200 Subject: [PATCH 174/512] Remove README.md, direct users to the Wiki (#199) --- README.md | 402 +------------------------------------------ lucet-idl/README.md | 129 -------------- lucet-wasi/README.md | 48 ------ 3 files changed, 5 insertions(+), 574 deletions(-) delete mode 100644 lucet-idl/README.md delete mode 100644 lucet-wasi/README.md diff --git a/README.md b/README.md index a7c559494..db9fa0fda 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ [Build Status]: https://travis-ci.org/fastly/lucet.svg?branch=master [travis]: https://travis-ci.org/fastly/lucet -**Lucet is a native WebAssembly compiler and runtime. It is designed to safely -execute untrusted WebAssembly programs inside your application.** +**Lucet is a native WebAssembly compiler and runtime. It is designed +to safely execute untrusted WebAssembly programs inside your application.** Check out our [announcement post on the Fastly blog](https://www.fastly.com/blog/announcing-lucet-fastly-native-webassembly-compiler-runtime). @@ -12,400 +12,8 @@ blog](https://www.fastly.com/blog/announcing-lucet-fastly-native-webassembly-com Lucet uses, and is developed in collaboration with, Mozilla's [Cranelift](http://github.com/cranestation/cranelift) code generator. -Lucet powers Fastly's [Terrarium](https://wasm.fastlylabs.com) platform. +It powers Fastly's [Terrarium](https://wasm.fastlylabs.com) platform. ---- +Lucet's documentation is available in the Wiki: -## Status - -Lucet supports running WebAssembly programs written in C (via `clang`), Rust, -and AssemblyScript. It does not yet support the entire WebAssembly spec, but -full support is [coming in the near future](#lucet-spectest). - -Lucet's runtime currently only supports x86-64 based Linux systems, with -experimental support for macOS. - -## Contents - -### `lucetc` - -`lucetc` is the Lucet Compiler. - -The Rust crate `lucetc` provides an executable `lucetc`. It compiles -WebAssembly modules (`.wasm` or `.wat` files) into native code (`.o` or `.so` -files). - -### `lucet-runtime` - -`lucet-runtime` is the runtime for WebAssembly modules compiled through -`lucetc`. It is a Rust crate that provides the functionality to load modules -from shared object files, instantiate them, and call exported WebAssembly -functions. `lucet-runtime` manages the resources used by each WebAssembly -instance (linear memory & globals), and the exception mechanisms that detect -and recover from illegal operations. - -The bulk of the library is defined in the child crate -`lucet-runtime-internals`. The public API is exposed in `lucet-runtime`. Test -suites are defined in the child crate `lucet-runtime-tests`. Many of these -tests invoke `lucetc` and the `wasi-sdk` tools. - -`lucet-runtime` is usable as a Rust crate or as a C library. The C language -interface is found at `lucet-runtime/include/lucet.h`. - -### `lucet-wasi` - -`lucet-wasi` is a crate providing runtime support for the [WebAssembly System -Interface (WASI)](https://wasi.dev). It can be used as a library to support -WASI in another application, or as an executable, `lucet-wasi`, to execute WASI -programs compiled through `lucetc`. - -See ["Your first Lucet application"](#your-first-lucet-application) for an -example that builds a C program and executes it with `lucet-wasi`. - -For details on WASI's implementation, see -[`lucet-wasi/README.md`](lucet-wasi/README.md). - -### `lucet-wasi-sdk` - -[`wasi-sdk`](https://github.com/cranestation/wasi-sdk) is a Cranelift project -that packages a build of the Clang toolchain, the WASI reference sysroot, and a -libc based on WASI syscalls. `lucet-wasi-sdk` is a Rust crate that provides -wrappers around these tools for building C programs into Lucet modules. We use -this crate to build test cases in `lucet-runtime-tests` and `lucet-wasi`. - -### `lucet-module-data` - -`lucet-module-data` is a crate with data structure definitions and serialization -functions that we emit into shared objects with `lucetc`, and read with -`lucet-runtime`. - -### `lucet-analyze` - -`lucet-analyze` is a Rust executable for inspecting the contents of a shared -object generated by `lucetc`. - -### `lucet-idl` - -`lucet-idl` is a Rust executable that implements code generation via an -Interface Description Language (IDL). The generated code provides zero-copy -accessor and constructor functions for datatypes that have the same -representation in both the WebAssembly guest program and the host program. - -Functionality is incomplete at the time of writing, and not yet integrated with -other parts of the project. Rust code generator, definition of import and -export function interfaces, and opaque type definitions are planned for the -near future. - -### `lucet-spectest` - -`lucet-spectest` is a Rust crate that uses `lucetc` and `lucet-runtime`, as well -as the (external) `wabt` crate, to run the official WebAssembly spec test suite, -which is provided as a submodule in this directory. Lucet is not yet fully spec -compliant, and the implementation of `lucet-spectest` has not been maintained -very well during recent codebase evolutions. We expect to fix this up and reach -spec compliance in the near future. - -### `lucet-builtins` - -`lucet-builtins` is a C library that provides optimized native versions of libc -primitives. `lucetc` can substitute the implementations defined in this library -for the WebAssembly implementations. - -`lucet-builtins/wasmonkey` is the Rust crate that `lucetc` uses to transform -function definitions in a WebAssembly module into uses of an import function. - -### Vendor libraries - -Lucet is tightly coupled to several upstream dependencies, and Lucet -development often requires making changes to these dependencies which are -submitted upstream once fully baked. To reduce friction in this development -cycle, we use git submodules to vendor these modules into the Lucet source -tree. - -#### Cranelift - -We keep the primary Cranelift project repository as a submodule at -`/cranelift`. - -Cranelift provides the native code generator used by `lucetc`, and a ton of -supporting infrastructure. - -Cranelift was previously known as Cretonne. Project developers hang out in the -`#cranelift` channel on [`irc.mozilla.org:6697`](https://wiki.mozilla.org/IRC). - -#### Faerie - -`faerie` is a Rust crate for producing ELF files. Faerie is used by Cranelift -(through the module system's `cranelift-faerie` backend) and also directly by -`lucetc`, for places where the `cranelift-module` API can't do everything we -need. - -### Tests - -Most of the crates in this repository have some form of unit tests. In addition, -`lucet-runtime/lucet-runtime-tests` defines a number of integration tests for -the runtime, and `lucet-wasi` has a number of integration tests using WASI C -programs. - -### Benchmarks - -We created the `sightglass` benchmarking tool to measure the runtime of C code -compiled through a standard native toolchain against the Lucet toolchain. It -is provided as a submodule at `/sightglass`. - -Sightglass ships with a set of microbenchmarks called `shootout`. The scripts -to build the shootout tests with native and various versions of the Lucet -toolchain are in `/benchmarks/shootout`. - -Furthermore, there is a suite of benchmarks of various Lucet runtime functions, -such as instance creation and teardown, in `/benchmarks/lucet-benchmarks`. - -## Development Environment - -### Operating System - -Lucet is developed and tested on Linux and macOS. We expect it to work on any -POSIX system which supports shared libraries. - -### Dependencies - -Lucet requires: - -* Stable Rust, and `rustfmt`. We typically track the latest stable release. -* [`wasi-sdk`](https://github.com/CraneStation/wasi-sdk), providing a Clang - toolchain with wasm-ld, the WASI reference sysroot, and a libc based on WASI - syscalls. -* GNU Make, CMake, & various standard Unix utilities for the build system. - -### Getting started - -The easiest way to get started with the Lucet toolchain is by using the provided -Docker-based development environment. - -This repository includes a `Dockerfile` to build a complete environment for -compiling and running WebAssembly code with Lucet, but you shouldn't have to use -Docker commands directly. A set of shell scripts with the `devenv_` prefix are -used to manage the container. - -#### Setting up the environment - -1) The Lucet repository uses git submodules. Make sure they are checked out - by running `git submodule init && git submodule update`. - -2) Install and run the `docker` service. We do not support `podman` at this - time. On MacOS, [Docker for - Mac](https://docs.docker.com/docker-for-mac/install/) is an option. - -3) Once Docker is running, in a terminal, and at the root of the cloned - repository, run: `source devenv_setenv.sh`. (This command requires the - current shell to be `zsh`, `ksh` or `bash`). After a couple minutes, the - Docker image is built and a new container is run. - -4) Check that new commands are now available: - -```sh -lucetc --help -``` - -You're now all set! - -#### Your first Lucet application - -The `devenv_setenv.sh` shell script ensures the Lucet executables are available -in your shell. Under the hood, these commands are executed in the Docker -container. The container has limited visibility into the host's filesystem - it -can only see files under the `lucet` repository. - -Create a new work directory in the `lucet` directory: - -```sh -mkdir -p src/hello - -cd src/hello -``` - -Save the following C source code as `hello.c`: - -```c -#include - -int main(void) -{ - puts("Hello world"); - return 0; -} -``` - -Time to compile to WebAssembly! The development environment includes a version -of the Clang toolchain that is built to generate WebAssembly by default. The -related commands are accessible from your current shell, and are prefixed by -`wasm32-wasi-`. - -For example, to create a WebAssembly module `hello.wasm` from `hello.c`: - -```sh -wasm32-wasi-clang -Ofast -o hello.wasm hello.c -``` - -The next step is to use Lucet to build native `x86_64` code from that -WebAssembly file: - -```sh -lucetc-wasi -o hello.so hello.wasm -``` - -`lucetc` is the WebAssembly to native code compiler. The `lucetc-wasi` command -runs the same compiler, but automatically configures it to target WASI. - -`hello.so` is created and ready to be run: - -```sh -lucet-wasi hello.so -``` - -#### Additional shell commands - -* `./devenv_build_container.sh` rebuilds the container image. This is never - required unless you edit the `Dockerfile`. -* `./devenv_run.sh [] [...]` runs a command in the container. If - a command is not provided, an interactive shell is spawned. In this - container, Lucet tools are installed in `/opt/lucet` by default. The command - `source /opt/lucet/bin/devenv_setenv.sh` can be used to initialize the - environment. -* `./devenv_start.sh` and `./devenv_stop.sh` start and stop the container. - -### Compiling the toolchain without Docker - -Support for WebAssembly was introduced in LLVM 8, released in March 2019. - -As a result, Lucet can be compiled with an existing LLVM installation, provided -that it is up to date. - -We successfully compiled it on macOS, Arch Linux and Ubuntu 19.04 using standard -system packages. - -#### Compilation on Ubuntu 19.04 - -On recent Ubuntu versions, the `cmake`, `clang` and `lld` packages must be -installed: - -```sh -apt install curl ca-certificates clang lld - -update-alternatives --install /usr/bin/wasm-ld wasm-ld /usr/bin/wasm-ld-8 100 -``` - -In order to compile applications to WebAssembly, builtins need to be installed -as well: - -```sh -curl -sL https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-5/libclang_rt.builtins-wasm32-wasi-5.0.tar.gz | \ -sudo tar x -zf - -C /usr/lib/llvm-8/lib/clang/8.0.0 -``` - -Install the latest stable version of the Rust compiler: - -```sh -curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -source $HOME/.cargo/env -``` - -Fetch, compile and install the WASI sysroot: - -```sh -git clone --recursive https://github.com/CraneStation/wasi-sysroot - -cd wasi-sysroot - -sudo make WASM_CC=clang-8 WASM_NM=llvm-nm-8 WASM_AR=llvm-ar-8 \ - INSTALL_DIR=/opt/wasi-sysroot install - -cd - && sudo rm -fr wasi-sysroot -``` - -Enter the Lucet git repository clone, and fetch/update the submodules: - -```sh -cd lucet - -git submodule update --init -``` - -Set relevant environment variables: - -```sh -export WASI_SYSROOT=/opt/wasi-sysroot -export CLANG_ROOT=/usr/lib/llvm-8/lib/clang/8.0.0 -export CLANG=clang-8 -``` - -Finally, compile the toolchain: - -```sh -cargo build --release -``` - -### Compilation on macOS - -Install `llvm`, `rust` and `cmake` using [Homebrew](https://brew.sh): - -```sh -brew install llvm rust cmake -``` - -In order to compile applications to WebAssembly, builtins need to be installed -as well: - -```sh -curl -sL https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-5/libclang_rt.builtins-wasm32-wasi-5.0.tar.gz | \ -sudo tar x -zf - -C /usr/local/opt/llvm/lib/clang/8* -``` - -Fetch, compile and install the WASI sysroot: - -```sh -git clone --recursive https://github.com/CraneStation/wasi-sysroot - -cd wasi-sysroot - -sudo env PATH=/usr/local/opt/llvm/bin:$PATH \ - make INSTALL_DIR=/opt/wasi-sysroot install - -cd - && sudo rm -fr wasi-sysroot -``` - -Enter the Lucet git repository clone, and fetch/update the submodules: - -```sh -cd lucet - -git submodule update --init -``` - -Set relevant environment variables: - -```sh -export WASI_SYSROOT=/opt/wasi-sysroot -export CLANG_ROOT="$(echo /usr/local/opt/llvm/lib/clang/8*)" -export CLANG=/usr/local/opt/llvm/bin/clang -``` - -Finally, compile the toolchain: - -```sh -cargo build --release -``` - -## Security - -The lucet project aims to provide support for secure execution of untrusted code. Security is achieved through a combination of lucet-supplied security controls and user-supplied security controls. See [SECURITY.md](SECURITY.md) for more information on the lucet security model. - -### Reporting Security Issues - -The Lucet project team welcomes security reports and is committed to providing -prompt attention to security issues. Security issues should be reported -privately via [Fastly’s security issue reporting -process](https://www.fastly.com/security/report-security-issue). Remediation of -security vulnerabilities is prioritized. The project teams endeavors to -coordinate remediation with third-party stakeholders, and is committed to -transparency in the disclosure process. +# [Lucet documentation](https://github.com/fastly/lucet/wiki) diff --git a/lucet-idl/README.md b/lucet-idl/README.md deleted file mode 100644 index 69817edb3..000000000 --- a/lucet-idl/README.md +++ /dev/null @@ -1,129 +0,0 @@ -# Lucet-IDL - -This is an IDL. A tool that reads descriptions of data types, and spits out these types' definitions, plus a bunch of functions to represent them as a serialized, platform-independent way. - -## Usage - -```text -USAGE: - lucet-idl [FLAGS] [OPTIONS] --input - -FLAGS: - -h, --help Prints help information - -V, --version Prints version information - -z, --zero-native-pointers Do not serialize native pointers - -OPTIONS: - -b, --backend Backend, one of: c [default: c] - -i, --input Path to the input file - -t, --target Target, one of: x86, x86_64, x86_64_32, generic [default: Generic] -``` - -## The description language in one example - -```text -// Primitive types: -// `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`, `f32`, `f64`. - -// Enumerations - -enum color { - red, blue, green -} - -// Aliases - -type colour = color -type col = colour - -// Structures - -struct st { - a: i8, - b: **i32, - c: color, - self: *st -} -``` - -## Sample output - -[Output (C backend) for the example above](https://gist.github.com/jedisct1/db5f81aa5e21b280d6f0f0350215889e). - -## Generated type definitions (C) - -### Structures - -No matter what the target and backend are, the generator will attempt to align data the same way as the reference target (C on x86_64). - -Using the example above, the `st` structure above gets defined as: - -```c -struct st { - int8_t a; - uint8_t ___pad8_1[7]; - int32_t **b; - ___POINTER_PAD(8) // pad pointer `b` at offset 8 to match alignment of the reference target (8 bytes) - color /* (enum ___color) */ c; - struct st *self; - ___POINTER_PAD(24) // pad pointer `self` at offset 24 to match alignment of the reference target (8 bytes) -}; - -#define BYTES_ST 32 -``` - -Explicit padding has been added after the first element `a` so that `b` is 64-bit aligned. - -However, native pointers can be 32-bit even though we require them to be 64-bit aligned. - -The `___POINTER_PAD` macro adds extra padding after a pointer on platforms where pointers are not 64-bit long. - -The `self` pointer will always be 64-bit aligned, as the previous member `c` is 64-bit aligned, and 64-bit long. Therefore, no extra padding is added before, but optional padding is added after the pointer itself. - -For every structure, a macro representing the number of bytes required to store it is defined as `BYTES_`, such as `BYTES_ST` in the example above. - -### Enumerations - -Enumerations are stored as a signed 64-bit integer: - -```c -typedef int64_t color; // enum, should be in the [0...2] range -enum ___color { - COLOR_RED, // 0 - COLOR_BLUE, // 1 - COLOR_GREEN, // 2 -}; - -#define BYTES_COLOR 8 -``` - - -## Accessors (C) - -The generated types are designed to be directly used by applications. - -However, they can also be represented as platform-independent serialized data. - -In particular, the `st` structure above generates the following accessors: - -```c -static inline void store_st(unsigned char buf[static BYTES_ST], const struct st *v); - -static inline void load_st(struct st *v_p, const unsigned char buf[static BYTES_ST]); -``` - -On platforms that can share the same endianness and alignment rules as the target platform, -these operations translate into a single `memcpy()` call. - -On other platforms, individual values are re-aligned and byte-swapped accordingly. - -Accessors for individual values are also generated. - -Subsets of types can thus be directly loaded and modified from a serialized representation. - -## Pointers - -Pointers are not automatically dereferenced. Their value can be replaced with zeros in -serialized representations. - -The `--zero-native-pointers` command-line option enables it. diff --git a/lucet-wasi/README.md b/lucet-wasi/README.md deleted file mode 100644 index a6f31894c..000000000 --- a/lucet-wasi/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# lucet-wasi - -Experimental WASI embedding for the Lucet runtime. - -## Examples - -Example WASI programs are in the [`examples`](examples) directory. - -## Supported syscalls - -We support the entire [WASI API](https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-api.md), -with the exception of socket-related syscalls. These will be added when -network access is standardized. - -## Thread safety - -Lucet guests are currently single-threaded only. The WASI embedding assumes -this, and so the syscall implementations are not thread-safe. This is not a -fundamental limitation, should Lucet support multi-threaded guests in the -future. - -## TODOs - -### Introduce optional abstraction between system clocks and WASI clocks - -The current implementations of `__wasi_clock_*` delegate to the host system's -`clock_getres` and `clock_gettime`. For untrusted code, it would be useful to -limit the precision of these clocks to reduce the potential impact of side -channels. Furthermore, the `CLOCK_*_CPUTIME_ID` clocks currently give timings -for the host process, but a measure of the guest instance runtime would be -more accurate. - -### Rewrite the code that implements capability checking - -Much of this code is a direct port of the [`wasmtime` C implementation](https://github.com/CraneStation/wasmtime/tree/master/wasmtime-wasi/sandboxed-system-primitives), -and as such contains a fair amount of unsafety and low-level operations on -bytestrings and bitfields. Since this code is critical to the integrity of the -sandboxing model, we intend to rewrite this code in higher-level Rust that is -easier to test and verify. - -## Third-Party Code - -`src/wasm32.rs` is copied from -[wasmtime](https://github.com/CraneStation/wasmtime/blob/master/wasmtime-wasi/src/wasm32.rs), -along with the associated `LICENSE.wasmtime` file. - -Parts of our syscall implementations are derived from the C implementations in -`cloudabi-utils`. See `LICENSE.cloudabi-utils` for license information. From f4dc37112ae7869138d72fa8a6501c5bb0875f0f Mon Sep 17 00:00:00 2001 From: awortman-fastly <49215183+awortman-fastly@users.noreply.github.com> Date: Mon, 24 Jun 2019 18:04:16 -0700 Subject: [PATCH 175/512] Fix duplicate imports causing broken module data (#219) * fix duplicate imports causing broken module data * add runtime test that modules with repeat imports function correctly --- lucet-wasi/tests/guests/duplicate_import.wat | 38 +++++++++ lucet-wasi/tests/test_helpers/mod.rs | 36 +++++++-- lucet-wasi/tests/tests.rs | 10 +++ lucetc/src/decls.rs | 30 +++---- lucetc/src/function.rs | 8 +- lucetc/src/module.rs | 78 +++++++++++++++---- lucetc/src/stack_probe.rs | 4 +- lucetc/src/table.rs | 5 +- .../bindings/duplicate_imports_bindings.json | 6 ++ lucetc/tests/wasm.rs | 26 +++++++ lucetc/tests/wasm/duplicate_imports.wat | 34 ++++++++ 11 files changed, 231 insertions(+), 44 deletions(-) create mode 100644 lucet-wasi/tests/guests/duplicate_import.wat create mode 100644 lucetc/tests/bindings/duplicate_imports_bindings.json create mode 100644 lucetc/tests/wasm/duplicate_imports.wat diff --git a/lucet-wasi/tests/guests/duplicate_import.wat b/lucet-wasi/tests/guests/duplicate_import.wat new file mode 100644 index 000000000..6bd7c1eec --- /dev/null +++ b/lucet-wasi/tests/guests/duplicate_import.wat @@ -0,0 +1,38 @@ +(module + (type (func (param i32 i32 i32 i32) (result i32))) + (type (func (result i32))) + + ;; import fd_read, this is fine. + (func $read (import "wasi_unstable" "fd_read") (type 0)) + + ;; import fd_write, this is also fine. + (func $write (import "wasi_unstable" "fd_write") (type 0)) + + ;; import fd_read, again, under a different name! + ;; this is to test that we join together the imports. + ;; the .wat would be invalid if their types disagree, so there + ;; is no observable difference between $read and $read_2 + (func $read_2 (import "wasi_unstable" "fd_read") (type 0)) + + ;; import fd_write again for grins. + (import "wasi_unstable" "fd_write" (func (type 0))) + (memory 1) + (data (i32.const 0) "duplicate import works!\0a") + (data (i32.const 64) "\00\00\00\00\18\00\00\00") + + (func $_setup (type 1) + (call $write (i32.const 1) (i32.const 64) (i32.const 1) (i32.const 0))) + + ;; declare that, actually, one of the imported functions is exported + (export "read_2" (func $read_2)) + ;; and delcare that the *other* read function is also exported, by a + ;; different name. This lets us check that when we merge the functions, + ;; we also merge their export names properly. + (export "read" (func $read)) + + ;; and check that other exported functions still work, and are not affected + (export "write" (func $write)) + + ;; and that we can export local functions without issue + (export "_start" (func $_setup)) +) diff --git a/lucet-wasi/tests/test_helpers/mod.rs b/lucet-wasi/tests/test_helpers/mod.rs index 4fc9e34bb..1b29f62d8 100644 --- a/lucet-wasi/tests/test_helpers/mod.rs +++ b/lucet-wasi/tests/test_helpers/mod.rs @@ -31,18 +31,38 @@ pub fn guest_file>(path: P) -> PathBuf { p } -pub fn wasi_test>(c_file: P) -> Result, Error> { +pub fn wasi_test>(file: P) -> Result, Error> { let workdir = TempDir::new().expect("create working directory"); - let wasm_build = Link::new(&[c_file]) - .with_cflag("-Wall") - .with_cflag("-Werror") - .with_print_output(true); - - let wasm_file = workdir.path().join("out.wasm"); + let wasm_path = match file.as_ref().extension().and_then(|x| x.to_str()) { + Some("c") => { + // some tests are .c, and must be compiled/linked to .wasm we can run + let wasm_build = Link::new(&[file]) + .with_cflag("-Wall") + .with_cflag("-Werror") + .with_print_output(true); + + let wasm_file = workdir.path().join("out.wasm"); + wasm_build.link(wasm_file.clone())?; + + wasm_file + }, + Some("wasm") | Some("wat") => { + // others are just wasm we can run directly + file.as_ref().to_owned() + } + Some(ext) => { + panic!("unknown test file extension: .{}", ext); + } + None => { + panic!("unknown test file, has no extension"); + } + }; - wasm_build.link(wasm_file.clone())?; + wasi_load(&workdir, wasm_path) +} +pub fn wasi_load>(workdir: &TempDir, wasm_file: P) -> Result, Error> { let bindings = Bindings::from_file(Path::new(LUCET_WASI_ROOT).join("bindings.json"))?; let native_build = Lucetc::new(wasm_file).with_bindings(bindings); diff --git a/lucet-wasi/tests/tests.rs b/lucet-wasi/tests/tests.rs index f5176cf27..18cdf386d 100644 --- a/lucet-wasi/tests/tests.rs +++ b/lucet-wasi/tests/tests.rs @@ -6,6 +6,16 @@ use std::fs::File; use std::path::Path; use tempfile::TempDir; +#[test] +fn double_import() { + let ctx = WasiCtxBuilder::new(); + + let (exitcode, stdout) = run_with_stdout("duplicate_import.wat", ctx).unwrap(); + + assert_eq!(stdout, "duplicate import works!\n"); + assert_eq!(exitcode, 0); +} + #[test] fn hello() { let ctx = WasiCtxBuilder::new().args(&["hello"]); diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index bbbd82c89..2137a23c2 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -1,8 +1,8 @@ use crate::bindings::Bindings; use crate::error::{LucetcError, LucetcErrorKind}; use crate::heap::HeapSettings; -use crate::module::ModuleInfo; pub use crate::module::{Exportable, TableElems}; +use crate::module::{ModuleInfo, UniqueFuncIndex}; use crate::name::Name; use crate::runtime::{Runtime, RuntimeFunc}; use cranelift_codegen::entity::{EntityRef, PrimaryMap}; @@ -10,8 +10,8 @@ use cranelift_codegen::ir; use cranelift_codegen::isa::TargetFrontendConfig; use cranelift_module::{Backend as ClifBackend, Linkage, Module as ClifModule}; use cranelift_wasm::{ - FuncIndex, Global, GlobalIndex, GlobalInit, MemoryIndex, ModuleEnvironment, SignatureIndex, - Table, TableIndex, + Global, GlobalIndex, GlobalInit, MemoryIndex, ModuleEnvironment, SignatureIndex, Table, + TableIndex, }; use failure::{format_err, Error, ResultExt}; use lucet_module_data::{ @@ -65,12 +65,12 @@ pub struct TableDecl<'a> { } pub struct ModuleDecls<'a> { - info: ModuleInfo<'a>, - function_names: PrimaryMap, + pub info: ModuleInfo<'a>, + function_names: PrimaryMap, imports: Vec>, exports: Vec>, table_names: PrimaryMap, - runtime_names: HashMap, + runtime_names: HashMap, globals_spec: Vec>, linear_memory_spec: Option, } @@ -112,10 +112,10 @@ impl<'a> ModuleDecls<'a> { bindings: &Bindings, ) -> Result<(), LucetcError> { for ix in 0..decls.info.functions.len() { - let func_index = FuncIndex::new(ix); + let func_index = UniqueFuncIndex::new(ix); fn export_name_for<'a>( - func_ix: FuncIndex, + func_ix: UniqueFuncIndex, decls: &mut ModuleDecls<'a>, ) -> Option<(String, Linkage)> { let export = decls.info.functions.get(func_ix).unwrap(); @@ -136,7 +136,7 @@ impl<'a> ModuleDecls<'a> { }; fn import_name_for<'a>( - func_ix: FuncIndex, + func_ix: UniqueFuncIndex, decls: &mut ModuleDecls<'a>, bindings: &Bindings, ) -> Result, failure::Context> { @@ -174,7 +174,7 @@ impl<'a> ModuleDecls<'a> { decl_sym: String, decl_linkage: Linkage, signature: ir::Signature, - ) -> Result { + ) -> Result { let (new_funcidx, _) = self.info.declare_func_with_sig(signature); self.declare_function(clif_module, decl_sym, decl_linkage, new_funcidx) @@ -187,8 +187,8 @@ impl<'a> ModuleDecls<'a> { clif_module: &mut ClifModule, decl_sym: String, decl_linkage: Linkage, - func_ix: FuncIndex, - ) -> Result { + func_ix: UniqueFuncIndex, + ) -> Result { let funcid = clif_module .declare_function( &decl_sym, @@ -197,7 +197,7 @@ impl<'a> ModuleDecls<'a> { ) .context(LucetcErrorKind::TranslatingModule)?; self.function_names.push(Name::new_func(decl_sym, funcid)); - Ok(FuncIndex::new(self.function_names.len() - 1)) + Ok(UniqueFuncIndex::new(self.function_names.len() - 1)) } fn declare_tables( @@ -360,7 +360,7 @@ impl<'a> ModuleDecls<'a> { ) } - pub fn get_func(&self, func_index: FuncIndex) -> Result, Error> { + pub fn get_func(&self, func_index: UniqueFuncIndex) -> Result, Error> { let name = self .function_names .get(func_index) @@ -378,7 +378,7 @@ impl<'a> ModuleDecls<'a> { }) } - pub fn get_start_func(&self) -> Option { + pub fn get_start_func(&self) -> Option { self.info.start_func.clone() } diff --git a/lucetc/src/function.rs b/lucetc/src/function.rs index d551a02ad..2cb4b9533 100644 --- a/lucetc/src/function.rs +++ b/lucetc/src/function.rs @@ -203,7 +203,13 @@ impl<'a> FuncEnvironment for FuncInfo<'a> { } fn make_direct_func(&mut self, func: &mut ir::Function, index: FuncIndex) -> ir::FuncRef { - let func_decl = self.module_decls.get_func(index).unwrap(); + let unique_index = *self + .module_decls + .info + .function_mapping + .get(index) + .expect("function indices are valid"); + let func_decl = self.module_decls.get_func(unique_index).unwrap(); let signature = func.import_signature(func_decl.signature.clone()); let colocated = !func_decl.imported(); func.import_function(ir::ExtFuncData { diff --git a/lucetc/src/module.rs b/lucetc/src/module.rs index e90c35ed7..a1bb7bb0f 100644 --- a/lucetc/src/module.rs +++ b/lucetc/src/module.rs @@ -1,6 +1,6 @@ //! Implements ModuleEnvironment for cranelift-wasm. Code derived from cranelift-wasm/environ/dummy.rs use crate::pointer::NATIVE_POINTER; -use cranelift_codegen::entity::{EntityRef, PrimaryMap}; +use cranelift_codegen::entity::{entity_impl, EntityRef, PrimaryMap}; use cranelift_codegen::ir; use cranelift_codegen::isa::TargetFrontendConfig; use cranelift_wasm::{ @@ -10,6 +10,13 @@ use cranelift_wasm::{ use lucet_module_data::UniqueSignatureIndex; use std::collections::{hash_map::Entry, HashMap}; +/// UniqueFuncIndex names a function after merging duplicate function declarations to a single +/// identifier, whereas FuncIndex is maintained by Cranelift and may have multiple indices referring +/// to a single function in the resulting artifact. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] +pub struct UniqueFuncIndex(u32); +entity_impl!(UniqueFuncIndex); + #[derive(Debug, Clone)] pub struct Exportable<'a, T> { pub entity: T, @@ -32,7 +39,7 @@ impl<'a, T> Exportable<'a, T> { pub struct TableElems { pub base: Option, pub offset: usize, - pub elements: Box<[FuncIndex]>, + pub elements: Box<[UniqueFuncIndex]>, } #[derive(Debug, Clone)] @@ -51,15 +58,18 @@ pub struct ModuleInfo<'a> { /// Provided by `declare_signature` pub signatures: PrimaryMap, /// Provided by `declare_func_import` - pub imported_funcs: PrimaryMap, + pub imported_funcs: PrimaryMap, /// Provided by `declare_global_import` pub imported_globals: PrimaryMap, /// Provided by `declare_table_import` pub imported_tables: PrimaryMap, /// Provided by `declare_memory_import` pub imported_memories: PrimaryMap, + /// This mapping lets us merge duplicate functions (for example, multiple import declarations) + /// as they're declared. + pub function_mapping: PrimaryMap, /// Function signatures: imported and local - pub functions: PrimaryMap>, + pub functions: PrimaryMap>, /// Provided by `declare_table` pub tables: PrimaryMap>, /// Provided by `declare_memory` @@ -67,10 +77,10 @@ pub struct ModuleInfo<'a> { /// Provided by `declare_global` pub globals: PrimaryMap>, /// Provided by `declare_start_func` - pub start_func: Option, + pub start_func: Option, /// Function bodies: local only - pub function_bodies: HashMap, + pub function_bodies: HashMap, /// Table elements: local only pub table_elems: HashMap>, @@ -89,6 +99,7 @@ impl<'a> ModuleInfo<'a> { imported_globals: PrimaryMap::new(), imported_tables: PrimaryMap::new(), imported_memories: PrimaryMap::new(), + function_mapping: PrimaryMap::new(), functions: PrimaryMap::new(), tables: PrimaryMap::new(), memories: PrimaryMap::new(), @@ -100,8 +111,8 @@ impl<'a> ModuleInfo<'a> { } } - pub fn signature_for_function(&self, func_index: FuncIndex) -> &ir::Signature { - // FuncIndex are valid (or the caller has very bad data) + pub fn signature_for_function(&self, func_index: UniqueFuncIndex) -> &ir::Signature { + // UniqueFuncIndex are valid (or the caller has very bad data) let sigidx = self.functions.get(func_index).unwrap().entity; self.signature_by_id(sigidx) @@ -114,10 +125,13 @@ impl<'a> ModuleInfo<'a> { self.signatures.get(*unique_sig_idx).unwrap() } - pub fn declare_func_with_sig(&mut self, sig: ir::Signature) -> (FuncIndex, SignatureIndex) { + pub fn declare_func_with_sig( + &mut self, + sig: ir::Signature, + ) -> (UniqueFuncIndex, SignatureIndex) { let new_sigidx = SignatureIndex::from_u32(self.signature_mapping.len() as u32); self.declare_signature(sig); - let new_funcidx = FuncIndex::from_u32(self.functions.len() as u32); + let new_funcidx = UniqueFuncIndex::from_u32(self.functions.len() as u32); self.declare_func_type(new_sigidx); (new_funcidx, new_sigidx) } @@ -154,8 +168,19 @@ impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { self.imported_funcs.len(), "import functions are declared first" ); - self.functions.push(Exportable::new(sig_index)); - self.imported_funcs.push((module, field)); + + let unique_fn_index = self + .imported_funcs + .iter() + .find(|(_, v)| *v == &(module, field)) + .map(|(key, _)| key) + .unwrap_or_else(|| { + self.functions.push(Exportable::new(sig_index)); + self.imported_funcs.push((module, field)); + UniqueFuncIndex::from_u32(self.functions.len() as u32 - 1) + }); + + self.function_mapping.push(unique_fn_index); } fn declare_global_import(&mut self, global: Global, module: &'a str, field: &'a str) { @@ -192,6 +217,8 @@ impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { fn declare_func_type(&mut self, sig_index: SignatureIndex) { self.functions.push(Exportable::new(sig_index)); + self.function_mapping + .push(UniqueFuncIndex::from_u32(self.functions.len() as u32 - 1)); } fn declare_table(&mut self, table: Table) { @@ -211,8 +238,12 @@ impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { } fn declare_func_export(&mut self, func_index: FuncIndex, name: &'a str) { + let unique_func_index = *self + .function_mapping + .get(func_index) + .expect("function indices are valid"); self.functions - .get_mut(func_index) + .get_mut(unique_func_index) .expect("export of declared function") .push_export(name); } @@ -239,15 +270,20 @@ impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { } fn declare_start_func(&mut self, func_index: FuncIndex) { + let unique_func_index = *self + .function_mapping + .get(func_index) + .expect("function indices are valid"); debug_assert!( self.start_func.is_none(), "start func can only be defined once" ); - self.start_func = Some(func_index); + self.start_func = Some(unique_func_index); } fn define_function_body(&mut self, body_bytes: &'a [u8], body_offset: usize) -> WasmResult<()> { - let func_index = FuncIndex::new(self.imported_funcs.len() + self.function_bodies.len()); + let func_index = + UniqueFuncIndex::new(self.imported_funcs.len() + self.function_bodies.len()); self.function_bodies .insert(func_index, (body_bytes, body_offset)); Ok(()) @@ -260,10 +296,20 @@ impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { offset: usize, elements: Box<[FuncIndex]>, ) { + let elements_vec: Vec = elements.into(); + let uniquified_elements = elements_vec + .into_iter() + .map(|fn_idx| { + *self + .function_mapping + .get(fn_idx) + .expect("function indices are valid") + }) + .collect(); let table_elems = TableElems { base, offset, - elements, + elements: uniquified_elements, }; match self.table_elems.entry(table_index) { Entry::Occupied(mut occ) => occ.get_mut().push(table_elems), diff --git a/lucetc/src/stack_probe.rs b/lucetc/src/stack_probe.rs index 97b72b548..da6c3f645 100644 --- a/lucetc/src/stack_probe.rs +++ b/lucetc/src/stack_probe.rs @@ -9,6 +9,7 @@ //! treated like any other guest trap. use crate::decls::ModuleDecls; +use crate::module::UniqueFuncIndex; use cranelift_codegen::binemit::TrapSink; use cranelift_codegen::ir; use cranelift_codegen::ir::{types, AbiParam, Signature}; @@ -16,7 +17,6 @@ use cranelift_codegen::isa::CallConv; use cranelift_faerie::traps::{FaerieTrapManifest, FaerieTrapSink}; use cranelift_faerie::FaerieProduct; use cranelift_module::{Backend as ClifBackend, Linkage, Module as ClifModule}; -use cranelift_wasm::FuncIndex; use faerie::Decl; use failure::Error; @@ -43,7 +43,7 @@ pub(crate) const STACK_PROBE_BINARY: &'static [u8] = &[ pub fn declare_metadata<'a, B: ClifBackend>( decls: &mut ModuleDecls<'a>, clif_module: &mut ClifModule, -) -> Result { +) -> Result { Ok(decls .declare_new_function( clif_module, diff --git a/lucetc/src/table.rs b/lucetc/src/table.rs index c382dc78b..8663afaa8 100644 --- a/lucetc/src/table.rs +++ b/lucetc/src/table.rs @@ -1,16 +1,17 @@ use crate::decls::{ModuleDecls, TableDecl}; use crate::error::{LucetcError, LucetcErrorKind}; +use crate::module::UniqueFuncIndex; use crate::pointer::NATIVE_POINTER_SIZE; use byteorder::{LittleEndian, WriteBytesExt}; use cranelift_codegen::entity::EntityRef; use cranelift_module::{Backend as ClifBackend, DataContext, Module as ClifModule}; -use cranelift_wasm::{FuncIndex, TableElementType, TableIndex}; +use cranelift_wasm::{TableElementType, TableIndex}; use failure::{format_err, ResultExt}; use std::io::Cursor; #[derive(Debug, Clone)] enum Elem { - Func(FuncIndex), + Func(UniqueFuncIndex), Empty, } diff --git a/lucetc/tests/bindings/duplicate_imports_bindings.json b/lucetc/tests/bindings/duplicate_imports_bindings.json new file mode 100644 index 000000000..207089019 --- /dev/null +++ b/lucetc/tests/bindings/duplicate_imports_bindings.json @@ -0,0 +1,6 @@ +{ + "env": { + "read": "host_read", + "write": "host_write" + } +} diff --git a/lucetc/tests/wasm.rs b/lucetc/tests/wasm.rs index 702f80521..6e5d23dad 100644 --- a/lucetc/tests/wasm.rs +++ b/lucetc/tests/wasm.rs @@ -78,6 +78,32 @@ mod module_data { assert_eq!(mdata.function_info().len(), 3); assert_eq!(mdata.export_functions()[0].names, vec!["main"]); } + + #[test] + fn duplicate_imports() { + let m = load_wat_module("duplicate_imports"); + let b = Bindings::from_file(&PathBuf::from( + "tests/bindings/duplicate_imports_bindings.json", + )) + .unwrap(); + let h = HeapSettings::default(); + let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile duplicate_imports"); + let mdata = c.module_data().unwrap(); + + assert_eq!(mdata.import_functions().len(), 2); + assert_eq!(mdata.import_functions()[0].module, "env"); + assert_eq!(mdata.import_functions()[0].name, "read"); + assert_eq!(mdata.import_functions()[1].module, "env"); + assert_eq!(mdata.import_functions()[1].name, "write"); + assert_eq!(mdata.function_info().len(), 5); + assert_eq!(mdata.function_info()[0].name, Some("host_read")); + assert_eq!(mdata.function_info()[1].name, Some("host_write")); + assert_eq!(mdata.function_info()[2].name, Some("guest_func__start")); + assert_eq!(mdata.export_functions().len(), 1); + assert_eq!(mdata.export_functions()[0].names, ["_start"]); + assert_eq!(mdata.globals_spec().len(), 0); + } + #[test] fn icall_import() { let m = load_wat_module("icall_import"); diff --git a/lucetc/tests/wasm/duplicate_imports.wat b/lucetc/tests/wasm/duplicate_imports.wat new file mode 100644 index 000000000..b85726bfa --- /dev/null +++ b/lucetc/tests/wasm/duplicate_imports.wat @@ -0,0 +1,34 @@ +(module + (type (func (param i32 i32 i32 i32) (result i32))) + (type (func)) + + ;; import fd_read, this is fine. + (func $read (import "env" "read") (type 0)) + + ;; import fd_write, this is also fine. + (func $write (import "env" "write") (type 0)) + + ;; import fd_read, again, under a different name! + ;; this is to test that we join together the imports. + ;; the .wat would be invalid if their types disagree, so there + ;; is no observable difference between $read and $read_2 + (func $read_2 (import "env" "read") (type 0)) + + ;; import fd_write again for grins. + (import "env" "write" (func (type 0))) + + (func $_setup (type 1) return) + + ;; declare that, actually, one of the imported functions is exported + (export "read_2" (func $read_2)) + ;; and delcare that the *other* read function is also exported, by a + ;; different name. This lets us check that when we merge the functions, + ;; we also merge their export names properly. + (export "read" (func $read)) + + ;; and check that other exported functions still work, and are not affected + (export "write" (func $write)) + + ;; and that we can export local functions without issue + (export "_start" (func $_setup)) +) From 28a4f70782c547847aa863ca763019eeac7b43c6 Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Tue, 25 Jun 2019 18:49:27 +0200 Subject: [PATCH 176/512] End-to-end authentication and integrity verification of Lucet assets (#221) Lucetc can now verify the signature of a source file before compiling it. The object resulting from the compilation of that source file can itself embed a signature, possibly created using a different key. Lucetc can also create key pairs. These can be either password protected for interactive use, or passwordless, for automated deployment. And the Lucet runtime gets new options to verify the embedded signature before loading a module. Add rsign2 to the Docker image --- Cargo.lock | 855 ++++++++++++------ Dockerfile | 2 +- Makefile | 1 + benchmarks/lucet-benchmarks/src/modules.rs | 39 +- benchmarks/lucet-benchmarks/src/seq.rs | 3 +- helpers/lucet-toolchain-tests/signature.sh | 91 ++ .../wasmonkey/src/bin/config/mod.rs | 16 +- lucet-builtins/wasmonkey/src/patcher.rs | 3 +- lucet-builtins/wasmonkey/src/symbols.rs | 12 +- lucet-module-data/Cargo.toml | 3 + lucet-module-data/src/error.rs | 4 + lucet-module-data/src/functions.rs | 26 +- lucet-module-data/src/globals.rs | 29 +- lucet-module-data/src/lib.rs | 15 +- lucet-module-data/src/linear_memory.rs | 1 - lucet-module-data/src/module_data.rs | 38 +- lucet-module-data/src/signature.rs | 194 ++++ lucet-module-data/src/traps.rs | 7 +- lucet-module-data/src/types.rs | 30 +- .../lucet-runtime-internals/Cargo.toml | 1 + .../lucet-runtime-internals/src/module/dl.rs | 22 +- lucet-runtime/src/lib.rs | 2 +- lucet-wasi/src/main.rs | 36 +- lucetc/Cargo.toml | 1 + lucetc/src/error.rs | 2 + lucetc/src/lib.rs | 69 +- lucetc/src/load.rs | 20 +- lucetc/src/main.rs | 37 +- lucetc/src/options.rs | 48 +- lucetc/src/signature.rs | 79 ++ 30 files changed, 1348 insertions(+), 338 deletions(-) create mode 100755 helpers/lucet-toolchain-tests/signature.sh create mode 100644 lucet-module-data/src/signature.rs create mode 100644 lucetc/src/signature.rs diff --git a/Cargo.lock b/Cargo.lock index eece2d2bc..465c6fe91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,10 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "adler32" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "aho-corasick" version = "0.7.3" @@ -16,6 +21,11 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "approx" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "arrayvec" version = "0.4.10" @@ -29,27 +39,26 @@ name = "atty" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "autocfg" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.15" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -57,8 +66,16 @@ name = "backtrace-sys" version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "base64" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -71,7 +88,7 @@ name = "bimap" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -79,8 +96,8 @@ name = "bincode" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -88,9 +105,9 @@ name = "bindgen" version = "0.47.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "clang-sys 0.26.4 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -98,9 +115,9 @@ dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -111,12 +128,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "1.0.4" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "block-padding" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "build_const" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "byte-tools" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "byteorder" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -126,7 +172,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cc" -version = "1.0.35" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -139,17 +185,27 @@ dependencies = [ [[package]] name = "cfg-if" -version = "0.1.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cgmath" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "clang-sys" version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libloading 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -159,7 +215,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -171,23 +227,24 @@ name = "cloudabi" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cmake" -version = "0.1.38" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "colored" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -196,8 +253,8 @@ version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -286,6 +343,22 @@ dependencies = [ "wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crc" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crc32fast" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "criterion" version = "0.2.11" @@ -298,18 +371,18 @@ dependencies = [ "csv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", - "tinytemplate 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -317,40 +390,57 @@ name = "criterion-plot" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-deque" -version = "0.2.0" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-epoch" -version = "0.3.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-queue" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-utils" -version = "0.2.2" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crypto-mac" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -359,9 +449,9 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -372,6 +462,14 @@ dependencies = [ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "digest" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "either" version = "1.5.2" @@ -385,8 +483,8 @@ dependencies = [ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -395,7 +493,7 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -405,7 +503,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -419,8 +517,8 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "string-interner 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt-derive 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -435,7 +533,7 @@ name = "failure" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.30 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -444,10 +542,26 @@ name = "failure_derive" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "flate2" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -460,6 +574,25 @@ name = "gcc" version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "generic-array" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "getrandom" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "glob" version = "0.2.11" @@ -490,7 +623,7 @@ name = "hashbrown" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -499,7 +632,16 @@ name = "heck" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hmac" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -523,7 +665,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -544,7 +686,7 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -563,15 +705,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.51" +version = "0.2.58" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libloading" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -580,15 +722,15 @@ name = "log" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucet-analyze" version = "0.1.0" dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "colored 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module-data 0.1.0", ] @@ -605,10 +747,10 @@ dependencies = [ "lucet-wasi 0.1.0", "lucet-wasi-sdk 0.1.0", "lucetc 0.1.0", - "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -617,7 +759,7 @@ version = "0.1.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -626,27 +768,30 @@ name = "lucet-module-data" version = "0.1.0" dependencies = [ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-codegen 0.30.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", + "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "object 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucet-runtime" version = "0.1.0" dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module-data 0.1.0", "lucet-runtime-internals 0.1.0", "lucet-runtime-tests 0.1.0", - "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -654,19 +799,19 @@ name = "lucet-runtime-internals" version = "0.1.0" dependencies = [ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-codegen 0.30.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libloading 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module-data 0.1.0", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -674,14 +819,14 @@ dependencies = [ name = "lucet-runtime-tests" version = "0.1.0" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module-data 0.1.0", "lucet-runtime-internals 0.1.0", "lucet-wasi-sdk 0.1.0", "lucetc 0.1.0", - "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -693,9 +838,9 @@ dependencies = [ "lucet-module-data 0.1.0", "lucet-runtime 0.1.0", "lucetc 0.1.0", - "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -708,14 +853,14 @@ dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-runtime 0.1.0", "lucet-runtime-internals 0.1.0", "lucet-wasi-sdk 0.1.0", "lucetc 0.1.0", - "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -724,19 +869,19 @@ version = "0.1.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-runtime 0.1.0", "lucet-wasi 0.1.0", "lucet-wasi-sdk 0.1.0", "lucetc 0.1.0", - "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -746,7 +891,7 @@ version = "0.1.0" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lucetc 0.1.0", - "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -755,7 +900,7 @@ version = "0.1.0" dependencies = [ "bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-codegen 0.30.0", "cranelift-entity 0.30.0", @@ -771,11 +916,12 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module-data 0.1.0", "lucet-wasi-sdk 0.1.0", + "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.35.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "wasmonkey 0.1.4", "wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -786,7 +932,7 @@ name = "memchr" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -794,15 +940,54 @@ name = "memoffset" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "minisign" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rpassword 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "scrypt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miniz-sys" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miniz_oxide" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miniz_oxide_c_api" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "nix" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -825,57 +1010,106 @@ name = "num" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-derive" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-integer" -version = "0.1.39" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-iter" -version = "0.1.37" +version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.2.6" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "num_cpus" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "numtoa" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "object" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "flate2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "opaque-debug" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "parity-wasm" version = "0.35.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parity-wasm" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pbkdf2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -898,8 +1132,8 @@ name = "precision" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -910,7 +1144,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "0.4.27" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -934,7 +1168,19 @@ name = "quote" version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -942,13 +1188,13 @@ name = "rand" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -960,7 +1206,7 @@ name = "rand_chacha" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -995,10 +1241,10 @@ dependencies = [ [[package]] name = "rand_jitter" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1010,7 +1256,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1021,7 +1267,7 @@ name = "rand_pcg" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1038,7 +1284,7 @@ name = "rand_xoshiro" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1047,30 +1293,31 @@ name = "raw-cpuid" version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon-core" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1096,19 +1343,19 @@ dependencies = [ [[package]] name = "regex" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1116,15 +1363,30 @@ dependencies = [ [[package]] name = "remove_dir_all" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rgb" +version = "0.8.13" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rpassword" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc-demangle" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1137,7 +1399,7 @@ dependencies = [ [[package]] name = "ryu" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1167,9 +1429,21 @@ name = "scroll_derive" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "scrypt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1187,20 +1461,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.90" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.90" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1208,9 +1482,20 @@ name = "serde_json" version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sha2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1223,14 +1508,14 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)", "hwloc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libloading 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "precision 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "printtable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1244,7 +1529,7 @@ name = "string-interner" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1254,42 +1539,47 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "structopt" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt-derive 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "structopt-derive" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "subtle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "syn" -version = "0.15.31" +version = "0.15.36" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "synstructure" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1315,20 +1605,20 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.0.7" +version = "3.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "termcolor" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1339,16 +1629,17 @@ name = "terminal_size" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "termion" -version = "1.5.1" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1371,21 +1662,26 @@ dependencies = [ [[package]] name = "tinytemplate" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "toml" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "typenum" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ucd-util" version = "0.1.3" @@ -1393,7 +1689,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-segmentation" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1408,7 +1704,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "utf8-ranges" -version = "1.0.2" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "uuid" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1431,8 +1732,8 @@ name = "wabt" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1442,8 +1743,8 @@ name = "wabt-sys" version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1452,12 +1753,12 @@ name = "wait-timeout" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "walkdir" -version = "2.2.7" +version = "2.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1474,8 +1775,8 @@ dependencies = [ "goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.35.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1497,7 +1798,7 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1546,43 +1847,67 @@ dependencies = [ "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "winconsole" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rgb 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "xfailure" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] +"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" "checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +"checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94" "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" -"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" -"checksum backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f106c02a3604afcdc0df5d36cc47b44b55917dbaf3d808f71c163a0ddba64637" +"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" +"checksum backtrace 0.3.30 (registry+https://github.com/rust-lang/crates.io-index)" = "ada4c783bb7e7443c14e0480f429ae2cc99da95065aeab7ee1b81ada0419404f" "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" +"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum bencher 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdb4953a096c551ce9ace855a604d702e6e62d77fac690575ae347571717f5" "checksum bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "505e45beaf0a1462f5548fe885edf2d83e62022b2ce8b10fef0f7686b48c9266" "checksum bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f2fb9e29e72fd6bc12071533d5dc7664cb01480c59406f656d7ac25c7bd8ff7" "checksum bindgen 0.47.3 (registry+https://github.com/rust-lang/crates.io-index)" = "df683a55b54b41d5ea8ebfaebb5aa7e6b84e3f3006a78f010dadc9ca88469260" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" -"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" +"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" +"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +"checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" +"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" +"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" -"checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83" +"checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d" "checksum cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7fa24eb00d5ffab90eaeaf1092ac85c04c64aaf358ea6f84505b8116d24c6af" -"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" +"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" +"checksum cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c" "checksum clang-sys 0.26.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ef0c1bcf2e99c649104bd7a7012d8f8802684400e03db0ec0af48583c6fa0e4" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "96210eec534fc3fbfc0452a63769424eaa80205fda6cea98e5b61cb3d97bcec8" -"checksum colored 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e9a455e156a4271e12fd0246238c380b1e223e3736663c7a18ed8b6362028a9" +"checksum cmake 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "2ca4386c8954b76a8415b63959337d940d724b336cabd3afe189c2b51a7e1ff0" +"checksum colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cdb90b60f2927f8d76139c72dbde7e10c3a2bc47c8594c9c7a66529f2687c03" "checksum core_affinity 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6d162c6e463c31dbf78fefa99d042156c1c74d404e299cfe3df2923cb857595b" +"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" +"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0363053954f3e679645fc443321ca128b7b950a6fe288cf5f9335cc22ee58394" "checksum criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76f9212ddf2f4a9eb2d401635190600656a1f88a932ef53d06e7fa4c7e02fb8e" -"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" -"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" -"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" +"checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" +"checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" +"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" +"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" +"checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" "checksum csv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9044e25afb0924b5a5fc5511689b0918629e85d68ea591e5e87fbf1e85ea1b3b" "checksum csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5cdef62f37e6ffe7d1f07a381bc0db32b7a3ff1cac0de56cb0d81e71f53d65" +"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" "checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" "checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a" "checksum errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2a071601ed01b988f896ab14b95e67335d1eeb50190932a1320f7fe3cadc84e" @@ -1590,106 +1915,129 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum faerie 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c6d75e6376216d6228fbab8025087523666623d9302ff17dd023d024bf98302" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" +"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +"checksum flate2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "246b6f24d8e616b0c176a8143486ddc8bb0bac2f30f0a0d3efbcf1e0d47cb7e5" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" +"checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" +"checksum getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8d1dffef07351aafe6ef177e4dd2b8dcf503e6bc765dea3b0de9ed149a3db1ec" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6a4013e9182f2345c6b7829b9ef6e670bce0dfca12c6f974457ed2160c2c7fe9" "checksum goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "7f55d53401eb2fd30afd025c570b1946b6966344acf21b42e31286f3bf89e6a8" "checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +"checksum hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f127a908633569f208325f86f71255d3363c79721d7f9fe31cd5569908819771" "checksum human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bec6e801ef7367625bd94ad7e2965e6027189f3e9deef422388d993af2814a0" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" "checksum hwloc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2934f84993b8b4bcae9b6a4e5f0aca638462dda9c7b4f26a570241494f21e0f4" "checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" -"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" +"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" -"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917" -"checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2" +"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" +"checksum libloading 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5692f82b51823e27c4118b3e5c0d98aee9be90633ebc71ad12afef380b50219" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" -"checksum nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46f0f3210768d796e8fa79ec70ee6af172dacbe7147f5e69be5240a47778302b" +"checksum minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "185d3531e38475163c1652a0915ac612be3f2655756af43f10789d6145f527c2" +"checksum miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9e3ae51cea1576ceba0dde3d484d30e6e5b86dee0b2d412fe3a16a15c98202" +"checksum miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c468f2369f07d651a5d0bb2c9079f8488a66d5466efe42d0c5c6466edcb7f71e" +"checksum miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7fe927a42e3807ef71defb191dc87d4e24479b221e67015fe38ae2b7b447bab" +"checksum nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4dbdc256eaac2e3bd236d93ad999d3479ef775c863dbda3068c4006a92eec51b" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" -"checksum num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d9fe8fcafd1b86a37ce8a1cfa15ae504817e0c8c2e7ad42767371461ac1d316d" -"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" -"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" -"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" -"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba" +"checksum num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2" +"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" +"checksum num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e" +"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" +"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" +"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" +"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" +"checksum object 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df4af347f5ac3d0e83e78c26be33cd10e8e874dcb68517a909ad802ba50a90b5" +"checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" "checksum parity-wasm 0.35.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3e1e076c4e01399b6cd0793a8df42f90bba3ae424671ef421d1608a943155d93" +"checksum parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)" = "20d7e522a7f994cc4ae32970b1ce0d99ecf91b8e1df080517a26faa6d2e2ee62" +"checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" "checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" "checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" "checksum precision 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "83f0b3de90e9edd6382604f4f28509ce25272deb065b94045fc47abcde567d55" "checksum printtable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "69967dae4cac71681361899d9905d3d2985fc989d7afb32a8dff3aed5461ecdf" -"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" +"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b820305721858696053a7fd0215cfeeee16ecaaf96b7a209945428e02f1c44" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" +"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -"checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832" +"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03b418169fb9c46533f326efd6eed2576699c44ca92d3052a066214a8d828929" "checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d" -"checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473" -"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" +"checksum rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4b0186e22767d5b9738a05eab7c6ac90b15db17e5b5f9bd87976dd7d89a10a4" +"checksum rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe0df8435ac0c397d467b6cad6d25543d06e8a019ef3f6af3c384597515bd2" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58" -"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" -"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" -"checksum rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc78bfd5acd7bf3e89cffcf899e5cb1a52d6fafa8dec2739ad70c9577a57288" +"checksum regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0b2f0808e7d7e4fb1cb07feb6ff2f4bc827938f24f8c2e6a3beb7370af544bdd" +"checksum regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d76410686f9e3a17f06128962e0ecc5755870bb890c34820c7af7f1db2e1d48" +"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" +"checksum rgb 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)" = "4f089652ca87f5a82a62935ec6172a534066c7b97be003cc8f702ee9a7a59c92" +"checksum rpassword 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34fa7bcae7fca3c8471e8417088bbc3ad9af8066b0ecf4f3c0d98a0d772716e" +"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" +"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f" "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f84d114ef17fd144153d608fba7c446b0145d038985e7a8cc5d08bb0ce20383" "checksum scroll_derive 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1aa96c45e7f5a91cb7fabe7b279f02fea7126239fc40b732316e8b6a2d0fcb" +"checksum scrypt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "656c79d0e90d0ab28ac86bf3c3d10bfbbac91450d3f190113b4e76d9fec3cfdd" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "aa5f7c20820475babd2c077c3ab5f8c77a31c15e16ea38687b4c02d3e48680f4" -"checksum serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "58fc82bec244f168b23d1963b45c8bf5726e9a15a9d146a067f9081aeed2de79" +"checksum serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "32746bf0f26eab52f06af0d0aa1984f641341d06d8d673c693871da2d188c9be" +"checksum serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "46a3223d0c9ba936b61c0d2e3e559e3217dbfb8d65d06d26e8b3c25de38bae3e" "checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" +"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" "checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" "checksum string-interner 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "abb38a0d8fe673c40b10b6b75abcb076a958cc10fb894f14993d9737c4c87000" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3d0760c312538987d363c36c42339b55f5ee176ea8808bbe4543d484a291c8d1" -"checksum structopt-derive 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "528aeb7351d042e6ffbc2a6fb76a86f9b622fdf7c25932798e7a82cb03bc94c6" -"checksum syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)" = "d2b4cfac95805274c6afdb12d8f770fa2d27c045953e7b630a81801953699a9a" -"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" +"checksum structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fa19a5a708e22bb5be31c1b6108a2a902f909c4b9ba85cba44c06632386bc0ff" +"checksum structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "c6d59d0ae8ef8de16e49e3ca7afa16024a3e0dfd974a75ef93fdc5464e34523f" +"checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" +"checksum syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)" = "8b4f551a91e2e3848aeef8751d0d4eec9489b6474c720fd4c55958d8d31a430c" +"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" "checksum target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6923974ce4eb5bd28814756256d8ab71c28dd6e7483313fe7ab6614306bf633" "checksum target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b0ab4982b8945c35cc1c46a83a9094c414f6828a099ce5dcaa8ee2b04642dcb" -"checksum tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b86c784c88d98c801132806dadd3819ed29d8600836c4088e855cdf3e178ed8a" -"checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" +"checksum tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dc4738f2e68ed2855de5ac9cdbe05c9216773ecde4739b2f095002ab03a13ef" +"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" "checksum terminal_size 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "023345d35850b69849741bd9a5432aa35290e3d8eb76af8717026f270d1cf133" -"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" +"checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" -"checksum tinytemplate 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7655088894274afb52b807bd3c87072daa1fedd155068b8705cabfd628956115" -"checksum toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87c5890a989fa47ecdc7bcb4c63a77a82c18f306714104b1decfd722db17b39e" +"checksum tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4574b75faccaacddb9b284faecdf0b544b80b6b294f3d062d325c5726a209c20" +"checksum toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8c96d7873fa7ef8bdeb3a9cda3ac48389b4154f32b9803b4bc26220b677b039" +"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" -"checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" +"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" +"checksum utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9d50aa7650df78abf942826607c62468ce18d9019673d4a2ebe1865dbb96ffde" +"checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "74e463a508e390cc7447e70f640fbf44ad52e1bd095314ace1fdf99516d32add" "checksum wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a6265b25719e82598d104b3717375e37661d41753e2c84cde3f51050c7ed7e3c" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" -"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" +"checksum walkdir 2.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c7904a7e2bb3cdf0cf5e783f44204a85a37a93151738fa349f06680f59a98b45" "checksum wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5e01c420bc7d36e778bd242e1167b079562ba8b34087122cc9057187026d060" "checksum wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)" = "981a8797cf89762e0233ec45fae731cb79a4dfaee12d9f0fe6cee01e4ac58d00" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" @@ -1700,4 +2048,5 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" +"checksum winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef84b96d10db72dd980056666d7f1e7663ce93d82fa33b63e71c966f4cf5032" "checksum xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da90eac47bf1d7871b75004b9b631d107df15f37669383b23f0b5297bc7516b6" diff --git a/Dockerfile b/Dockerfile index 8b76ea092..ca3a75762 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,7 +34,7 @@ RUN curl -sS -L -O https://static.rust-lang.org/dist/rust-1.35.0-x86_64-unknown- && cd .. \ && rm -rf rust-1.35.0-x86_64-unknown-linux-gnu rust-1.35.0-x86_64-unknown-linux-gnu.tar.gz ENV PATH=/usr/local/bin:$PATH -RUN cargo install --root /usr/local cargo-audit cargo-watch +RUN cargo install --root /usr/local cargo-audit cargo-watch rsign2 RUN curl -sS -L -O https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-5/wasi-sdk_5.0_amd64.deb \ && dpkg -i wasi-sdk_5.0_amd64.deb && rm -f wasi-sdk_5.0_amd64.deb diff --git a/Makefile b/Makefile index 71fe46a10..b844264b5 100644 --- a/Makefile +++ b/Makefile @@ -33,6 +33,7 @@ test: indent-check -p lucet-benchmarks # run a single seed through the fuzzer to stave off bitrot cargo run -p lucet-wasi-fuzz -- test-seed 410757864950 + helpers/lucet-toolchain-tests/signature.sh .PHONY: fuzz fuzz: diff --git a/benchmarks/lucet-benchmarks/src/modules.rs b/benchmarks/lucet-benchmarks/src/modules.rs index c510fa132..7a6b51d50 100644 --- a/benchmarks/lucet-benchmarks/src/modules.rs +++ b/benchmarks/lucet-benchmarks/src/modules.rs @@ -28,7 +28,10 @@ pub fn null_mock() -> Arc { extern "C" fn f(_vmctx: *mut lucet_vmctx) {} MockModuleBuilder::new() - .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize))) + .with_export_func(MockExportBuilder::new( + "f", + FunctionPointer::from_usize(f as usize), + )) .build() } @@ -50,7 +53,10 @@ pub fn large_dense_heap_mock(heap_kb: usize) -> Arc { }); MockModuleBuilder::new() - .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize))) + .with_export_func(MockExportBuilder::new( + "f", + FunctionPointer::from_usize(f as usize), + )) .with_initial_heap(heap.as_slice()) .with_heap_spec(heap_spec) .build() @@ -81,7 +87,10 @@ pub fn large_sparse_heap_mock(heap_kb: usize, stride: usize) -> Arc }); MockModuleBuilder::new() - .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize))) + .with_export_func(MockExportBuilder::new( + "f", + FunctionPointer::from_usize(f as usize), + )) .with_initial_heap(heap.as_slice()) .with_heap_spec(heap_spec) .build() @@ -102,7 +111,10 @@ pub fn fib_mock() -> Arc { } MockModuleBuilder::new() - .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize))) + .with_export_func(MockExportBuilder::new( + "f", + FunctionPointer::from_usize(f as usize), + )) .build() } @@ -180,8 +192,8 @@ pub fn many_args_mock() -> Arc { MockModuleBuilder::new() .with_export_func( - MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize)) - .with_sig(lucet_signature!( + MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize)).with_sig( + lucet_signature!( ( I32, I32, I32, I64, F32, F64, I32, I32, I32, I64, F32, F64, @@ -195,7 +207,8 @@ pub fn many_args_mock() -> Arc { I32, I32, I32, I64, F32, F64, I32, I32, I32, I64, F32, F64 ) -> () - )) + ), + ), ) .build() } @@ -271,9 +284,13 @@ pub fn hostcalls_mock() -> Arc { } MockModuleBuilder::new() - .with_export_func( - MockExportBuilder::new("wrapped", FunctionPointer::from_usize(wrapped as usize))) - .with_export_func( - MockExportBuilder::new("raw", FunctionPointer::from_usize(raw as usize))) + .with_export_func(MockExportBuilder::new( + "wrapped", + FunctionPointer::from_usize(wrapped as usize), + )) + .with_export_func(MockExportBuilder::new( + "raw", + FunctionPointer::from_usize(raw as usize), + )) .build() } diff --git a/benchmarks/lucet-benchmarks/src/seq.rs b/benchmarks/lucet-benchmarks/src/seq.rs index 4e8462e4c..77651de5f 100644 --- a/benchmarks/lucet-benchmarks/src/seq.rs +++ b/benchmarks/lucet-benchmarks/src/seq.rs @@ -7,7 +7,8 @@ use std::path::Path; use std::sync::Arc; use tempfile::TempDir; -const DENSE_HEAP_SIZES_KB: &'static [usize] = &[0, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2 * 1024, 4 * 1024]; +const DENSE_HEAP_SIZES_KB: &'static [usize] = + &[0, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2 * 1024, 4 * 1024]; const SPARSE_HEAP_SIZES_KB: &'static [usize] = &[0, 256, 512, 1024, 2 * 1024, 4 * 1024]; diff --git a/helpers/lucet-toolchain-tests/signature.sh b/helpers/lucet-toolchain-tests/signature.sh new file mode 100755 index 000000000..73343a8a4 --- /dev/null +++ b/helpers/lucet-toolchain-tests/signature.sh @@ -0,0 +1,91 @@ +#! /bin/sh + +LUCET_DIR="." +LUCET_TARGET_DIR="${LUCET_DIR}/target/debug" +TMPDIR="$(mktemp -d)" + +if [ -d "${LUCET_DIR}/target/release" ]; then + LUCET_TARGET_DIR="${LUCET_DIR}/target/release" +fi + +if ! command -v rsign >/dev/null; then + cargo install rsign2 + export PATH="${HOME}/.cargo/bin:${PATH}" +fi + +echo "Creating a key pair to sign the WebAssembly code" +( + echo x + echo x +) | rsign generate -p "${TMPDIR}/src_public.key" -s "${TMPDIR}/src_secret.key" -f >/dev/null + +echo "Signing the WebAssembly code" +cp "${LUCET_DIR}/lucetc/tests/wasm/call.wat" "${TMPDIR}/test.wat" +echo x | rsign sign -p "${TMPDIR}/src_public.key" -s "${TMPDIR}/src_secret.key" "${TMPDIR}/test.wat" >/dev/null + +echo "Creating a key pair using lucetc for the compiled code" +if ! "${LUCET_TARGET_DIR}/lucetc" \ + --signature-keygen \ + --signature-pk="${TMPDIR}/public.key" \ + --signature-sk="raw:${TMPDIR}/secret.key"; then + echo "Keypair generation failed" >&2 + exit 1 +fi + +echo "Trying to compile source code whose signature is invalid" +if "${LUCET_TARGET_DIR}/lucetc" \ + "${TMPDIR}/test.wat" \ + -o "${TMPDIR}/test.so" \ + --signature-verify \ + --signature-pk="${TMPDIR}/public.key" 2>/dev/null; then + echo "Source signature verification with the wrong public key shouldn't have passed" >&2 + exit 1 +fi + +echo "Compiling the verified source code" +if ! "${LUCET_TARGET_DIR}/lucetc" \ + "${TMPDIR}/test.wat" \ + -o "${TMPDIR}/test.so" \ + --signature-verify \ + --signature-pk="${TMPDIR}/src_public.key" 2>/dev/null; then + echo "Source signature verification with the correct public key didn't pass" >&2 + exit 1 +fi + +echo "Compiling the verified source code and embedding a signature into the resulting object" +if ! "${LUCET_TARGET_DIR}/lucetc" \ + "${TMPDIR}/test.wat" \ + -o "${TMPDIR}/test.so" \ + --signature-create \ + --signature-verify \ + --signature-pk="${TMPDIR}/src_public.key" \ + --signature-sk=raw:"${TMPDIR}/secret.key" 2>/dev/null; then + echo "Compilation failed" >&2 + exit 1 +fi + +echo "Running the resulting object" +if ! "${LUCET_TARGET_DIR}/lucet-wasi" \ + "${TMPDIR}/test.so" \ + --signature-verify \ + --signature-pk="${TMPDIR}/public.key" \ + --entrypoint main; then + echo "Runtime failed" >&2 + exit 1 +fi + +echo >>"${TMPDIR}/test.so" + +echo "Trying to run a tampered version of the object" +if "${LUCET_TARGET_DIR}/lucet-wasi" \ + "${TMPDIR}/test.so" \ + --signature-verify \ + --signature-pk="${TMPDIR}/public.key" \ + --entrypoint main 2>/dev/null; then + echo "Signature verification of tampered module shouldn't have passed" >&2 + exit 1 +fi + +rm -fr "$TMPDIR" + +echo "Done." diff --git a/lucet-builtins/wasmonkey/src/bin/config/mod.rs b/lucet-builtins/wasmonkey/src/bin/config/mod.rs index f3cf30bc3..87c7f8b02 100644 --- a/lucet-builtins/wasmonkey/src/bin/config/mod.rs +++ b/lucet-builtins/wasmonkey/src/bin/config/mod.rs @@ -64,12 +64,16 @@ impl Config { .help("Use the original name as a key in the builtins map"), ) .get_matches(); - let input_path = PathBuf::from(matches - .value_of("input_file") - .ok_or(WError::UsageError("Input file required"))?); - let output_path = PathBuf::from(matches - .value_of("output_file") - .ok_or(WError::UsageError("Output file required"))?); + let input_path = PathBuf::from( + matches + .value_of("input_file") + .ok_or(WError::UsageError("Input file required"))?, + ); + let output_path = PathBuf::from( + matches + .value_of("output_file") + .ok_or(WError::UsageError("Output file required"))?, + ); let builtins_path = matches.value_of("builtins_file").map(PathBuf::from); let builtins_map_path = matches.value_of("builtins_map_file").map(PathBuf::from); let builtins_map_original_names = matches.is_present("builtins_map_original_names"); diff --git a/lucet-builtins/wasmonkey/src/patcher.rs b/lucet-builtins/wasmonkey/src/patcher.rs index bb39a0a79..8514a0929 100644 --- a/lucet-builtins/wasmonkey/src/patcher.rs +++ b/lucet-builtins/wasmonkey/src/patcher.rs @@ -32,7 +32,8 @@ impl Patcher { let symbols = match &config.builtins_path { None => ExtractedSymbols::from(vec![]), Some(builtins_path) => symbols::extract_symbols(&builtins_path)?, - }.merge_additional(&config.builtins_additional); + } + .merge_additional(&config.builtins_additional); let builtins_names = symbols.builtins_names(); let (patched_module, patched_builtins_map) = patch_module(module, &builtins_names)?; let patcher = Patcher { diff --git a/lucet-builtins/wasmonkey/src/symbols.rs b/lucet-builtins/wasmonkey/src/symbols.rs index 5bbd46c58..411c6645d 100644 --- a/lucet-builtins/wasmonkey/src/symbols.rs +++ b/lucet-builtins/wasmonkey/src/symbols.rs @@ -25,7 +25,8 @@ impl From> for ExtractedSymbols { impl ExtractedSymbols { pub fn builtins_names(&self) -> Vec<&str> { - let builtins_names: Vec<&str> = self.symbols + let builtins_names: Vec<&str> = self + .symbols .iter() .filter(|symbol| symbol.name.starts_with(BUILTIN_PREFIX)) .map(|symbol| &symbol.name[BUILTIN_PREFIX.len()..]) @@ -49,11 +50,13 @@ impl ExtractedSymbols { fn parse_elf(elf: &Elf) -> Result { let mut symbols = vec![]; - for symbol in elf.dynsyms + for symbol in elf + .dynsyms .iter() .filter(|symbol| symbol.st_info == 0x12 || symbol.st_info == 0x22) { - let name = elf.dynstrtab + let name = elf + .dynstrtab .get(symbol.st_name) .ok_or(WError::ParseError)? .map_err(|_| WError::ParseError)? @@ -102,8 +105,7 @@ fn parse_macho(macho: &MachO) -> Result { n_value, .. }, - )) if name.len() > 1 && name.starts_with('_') => - { + )) if name.len() > 1 && name.starts_with('_') => { let extracted_symbol = ExtractedSymbol { name: name[1..].to_string(), }; diff --git a/lucet-module-data/Cargo.toml b/lucet-module-data/Cargo.toml index e3276447b..2767f934c 100644 --- a/lucet-module-data/Cargo.toml +++ b/lucet-module-data/Cargo.toml @@ -12,3 +12,6 @@ serde = { version = "1.0", features = ["derive"] } bincode = "~1.0.1" num-derive = "0.2" num-traits = "0.2" +minisign = "0.5.11" +object = "0.12" +byteorder = "1.3" \ No newline at end of file diff --git a/lucet-module-data/src/error.rs b/lucet-module-data/src/error.rs index f20757a72..311459392 100644 --- a/lucet-module-data/src/error.rs +++ b/lucet-module-data/src/error.rs @@ -9,4 +9,8 @@ pub enum Error { DeserializationError(#[cause] bincode::Error), #[fail(display = "Serialization error: {}", _0)] SerializationError(#[cause] bincode::Error), + #[fail(display = "Module signature error: {}", _0)] + ModuleSignatureError(#[cause] minisign::PError), + #[fail(display = "I/O error: {}", _0)] + IOError(#[cause] std::io::Error), } diff --git a/lucet-module-data/src/functions.rs b/lucet-module-data/src/functions.rs index c37bbb158..a703e8d10 100644 --- a/lucet-module-data/src/functions.rs +++ b/lucet-module-data/src/functions.rs @@ -26,7 +26,7 @@ impl FunctionIndex { pub struct ImportFunction<'a> { pub fn_idx: FunctionIndex, pub module: &'a str, - pub name: &'a str + pub name: &'a str, } /// ExportFunction describes an exported function - its internal function index and a name that @@ -35,19 +35,19 @@ pub struct ImportFunction<'a> { pub struct ExportFunction<'a> { pub fn_idx: FunctionIndex, #[serde(borrow)] - pub names: Vec<&'a str> + pub names: Vec<&'a str>, } pub struct OwnedExportFunction { pub fn_idx: FunctionIndex, - pub names: Vec + pub names: Vec, } impl OwnedExportFunction { pub fn to_ref<'a>(&'a self) -> ExportFunction<'a> { ExportFunction { fn_idx: self.fn_idx.clone(), - names: self.names.iter().map(|x| x.as_str()).collect() + names: self.names.iter().map(|x| x.as_str()).collect(), } } } @@ -55,7 +55,7 @@ impl OwnedExportFunction { pub struct OwnedImportFunction { pub fn_idx: FunctionIndex, pub module: String, - pub name: String + pub name: String, } impl OwnedImportFunction { @@ -127,7 +127,7 @@ impl OwnedFunctionMetadata { pub struct FunctionHandle { pub ptr: FunctionPointer, - pub id: FunctionIndex + pub id: FunctionIndex, } // The layout of this struct is very tightly coupled to lucetc's `write_function_manifest`! @@ -144,12 +144,17 @@ pub struct FunctionSpec { code_addr: u64, code_len: u32, traps_addr: u64, - traps_len: u64 + traps_len: u64, } impl FunctionSpec { pub fn new(code_addr: u64, code_len: u32, traps_addr: u64, traps_len: u64) -> Self { - FunctionSpec { code_addr, code_len, traps_addr, traps_len } + FunctionSpec { + code_addr, + code_len, + traps_addr, + traps_len, + } } pub fn ptr(&self) -> FunctionPointer { FunctionPointer::from_usize(self.code_addr as usize) @@ -178,10 +183,7 @@ impl FunctionSpec { pub fn traps(&self) -> Option> { let traps_ptr = self.traps_addr as *const TrapSite; if !traps_ptr.is_null() { - let traps_slice = - unsafe { - from_raw_parts(traps_ptr, self.traps_len as usize) - }; + let traps_slice = unsafe { from_raw_parts(traps_ptr, self.traps_len as usize) }; Some(TrapManifest::new(traps_slice)) } else { None diff --git a/lucet-module-data/src/globals.rs b/lucet-module-data/src/globals.rs index cbbfe448e..801d0c9d8 100644 --- a/lucet-module-data/src/globals.rs +++ b/lucet-module-data/src/globals.rs @@ -14,15 +14,15 @@ pub struct GlobalSpec<'a> { impl<'a> GlobalSpec<'a> { pub fn new(global: Global<'a>, export_names: Vec<&'a str>) -> Self { - Self { global, export_names } + Self { + global, + export_names, + } } /// Create a new global definition with an initial value and export names. pub fn new_def(init_val: i64, export_names: Vec<&'a str>) -> Self { - Self::new( - Global::Def(GlobalDef::I64(init_val)), - export_names, - ) + Self::new(Global::Def(GlobalDef::I64(init_val)), export_names) } /// Create a new global import definition with a module and field name, and export names. @@ -61,7 +61,7 @@ pub enum GlobalDef { I32(i32), I64(i64), F32(f32), - F64(f64) + F64(f64), } impl GlobalDef { @@ -87,7 +87,7 @@ impl std::fmt::Debug for GlobalValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // Because GlobalValue is a union of primitives, there won't be anything wrong, // representation-wise, with printing the underlying data as an i64, f64, or - // another primitive. This still may incur UB by doing something like trying to + // another primitive. This still may incur UB by doing something like trying to // read data from an uninitialized memory, if the union is initialized with a // 32-bit value, and then read as a 64-bit value (as this code is about to do). // @@ -116,15 +116,15 @@ pub struct OwnedGlobalSpec { impl OwnedGlobalSpec { pub fn new(global: OwnedGlobal, export_names: Vec) -> Self { - Self { global, export_names } + Self { + global, + export_names, + } } /// Create a new global definition with an initial value and export names. pub fn new_def(init_val: i64, export_names: Vec) -> Self { - Self::new( - OwnedGlobal::Def(GlobalDef::I64(init_val)), - export_names, - ) + Self::new(OwnedGlobal::Def(GlobalDef::I64(init_val)), export_names) } /// Create a new global import definition with a module and field name, and export names. @@ -135,7 +135,10 @@ impl OwnedGlobalSpec { /// Create a [`GlobalSpec`](../struct.GlobalSpec.html) backed by the values in this /// `OwnedGlobalSpec`. pub fn to_ref<'a>(&'a self) -> GlobalSpec<'a> { - GlobalSpec::new(self.global.to_ref(), self.export_names.iter().map(|x| x.as_str()).collect()) + GlobalSpec::new( + self.global.to_ref(), + self.export_names.iter().map(|x| x.as_str()).collect(), + ) } } diff --git a/lucet-module-data/src/lib.rs b/lucet-module-data/src/lib.rs index 994a41da0..1f852f3c8 100644 --- a/lucet-module-data/src/lib.rs +++ b/lucet-module-data/src/lib.rs @@ -10,21 +10,26 @@ mod functions; mod globals; mod linear_memory; mod module_data; +mod signature; mod traps; mod types; pub use crate::error::Error; +pub use crate::functions::{ + ExportFunction, FunctionHandle, FunctionIndex, FunctionMetadata, FunctionPointer, FunctionSpec, + ImportFunction, UniqueSignatureIndex, +}; pub use crate::globals::{Global, GlobalDef, GlobalSpec, GlobalValue}; -pub use crate::linear_memory::{HeapSpec, SparseData, LinearMemorySpec}; +pub use crate::linear_memory::{HeapSpec, LinearMemorySpec, SparseData}; pub use crate::module_data::ModuleData; -pub use crate::functions::{ExportFunction, FunctionHandle, FunctionIndex, FunctionMetadata, FunctionPointer, FunctionSpec, ImportFunction, UniqueSignatureIndex}; -pub use crate::traps::{TrapManifest, TrapSite, TrapCode}; +pub use crate::signature::{ModuleSignature, PublicKey}; +pub use crate::traps::{TrapCode, TrapManifest, TrapSite}; pub use crate::types::{Signature, ValueType}; /// Owned variants of the module data types, useful for serialization and testing. pub mod owned { + pub use crate::functions::{OwnedExportFunction, OwnedFunctionMetadata, OwnedImportFunction}; pub use crate::globals::OwnedGlobalSpec; - pub use crate::linear_memory::{OwnedSparseData, OwnedLinearMemorySpec}; + pub use crate::linear_memory::{OwnedLinearMemorySpec, OwnedSparseData}; pub use crate::module_data::OwnedModuleData; - pub use crate::functions::{OwnedFunctionMetadata, OwnedExportFunction, OwnedImportFunction}; } diff --git a/lucet-module-data/src/linear_memory.rs b/lucet-module-data/src/linear_memory.rs index 1bc3e44d5..d2107c421 100644 --- a/lucet-module-data/src/linear_memory.rs +++ b/lucet-module-data/src/linear_memory.rs @@ -23,7 +23,6 @@ pub struct OwnedLinearMemorySpec { pub initializer: OwnedSparseData, } - impl OwnedLinearMemorySpec { pub fn to_ref<'a>(&'a self) -> LinearMemorySpec<'a> { LinearMemorySpec { diff --git a/lucet-module-data/src/module_data.rs b/lucet-module-data/src/module_data.rs index 7d0acba15..9ec2b8317 100644 --- a/lucet-module-data/src/module_data.rs +++ b/lucet-module-data/src/module_data.rs @@ -1,10 +1,13 @@ use crate::{ - functions::{ExportFunction, FunctionIndex, FunctionMetadata, ImportFunction, OwnedFunctionMetadata}, + functions::{ + ExportFunction, FunctionIndex, FunctionMetadata, ImportFunction, OwnedFunctionMetadata, + }, globals::GlobalSpec, linear_memory::{HeapSpec, LinearMemorySpec, SparseData}, types::Signature, Error, }; +use minisign::SignatureBones; use serde::{Deserialize, Serialize}; /// The metadata (and some data) for a Lucet module. @@ -28,6 +31,7 @@ pub struct ModuleData<'a> { #[serde(borrow)] export_functions: Vec>, signatures: Vec, + module_signature: Vec, } impl<'a> ModuleData<'a> { @@ -39,6 +43,7 @@ impl<'a> ModuleData<'a> { export_functions: Vec>, signatures: Vec, ) -> Self { + let module_signature = vec![0u8; SignatureBones::BYTES]; Self { linear_memory, globals_spec, @@ -46,6 +51,7 @@ impl<'a> ModuleData<'a> { import_functions, export_functions, signatures, + module_signature, } } @@ -101,6 +107,29 @@ impl<'a> ModuleData<'a> { &self.signatures } + pub fn get_module_signature(&self) -> &[u8] { + &self.module_signature + } + + pub fn patch_module_signature( + module_data_bin: &'a [u8], + module_signature: &[u8], + ) -> Result, Error> { + assert_eq!(module_signature.len(), SignatureBones::BYTES); + let mut module_data = Self::deserialize(module_data_bin)?; + module_data + .module_signature + .copy_from_slice(module_signature); + let patched_module_data_bin = module_data.serialize()?; + assert_eq!(patched_module_data_bin.len(), module_data_bin.len()); + Ok(patched_module_data_bin) + } + + pub fn clear_module_signature(module_data_bin: &'a [u8]) -> Result, Error> { + let module_signature = vec![0u8; SignatureBones::BYTES]; + Self::patch_module_signature(module_data_bin, &module_signature) + } + /// Serialize to [`bincode`](https://github.com/TyOverby/bincode). pub fn serialize(&self) -> Result, Error> { bincode::serialize(self).map_err(Error::SerializationError) @@ -113,9 +142,9 @@ impl<'a> ModuleData<'a> { } use crate::{ + functions::{OwnedExportFunction, OwnedImportFunction}, globals::OwnedGlobalSpec, linear_memory::{OwnedLinearMemorySpec, OwnedSparseData}, - functions::{OwnedExportFunction, OwnedImportFunction}, }; /// The metadata (and some data) for a Lucet module. @@ -161,7 +190,10 @@ impl OwnedModuleData { None }, self.globals_spec.iter().map(|gs| gs.to_ref()).collect(), - self.function_info.iter().map(|info| info.to_ref()).collect(), + self.function_info + .iter() + .map(|info| info.to_ref()) + .collect(), self.imports.iter().map(|imp| imp.to_ref()).collect(), self.exports.iter().map(|exp| exp.to_ref()).collect(), self.signatures.clone(), diff --git a/lucet-module-data/src/signature.rs b/lucet-module-data/src/signature.rs new file mode 100644 index 000000000..99a1e6df9 --- /dev/null +++ b/lucet-module-data/src/signature.rs @@ -0,0 +1,194 @@ +use crate::error::Error::{self, IOError, ModuleSignatureError}; +use crate::ModuleData; +use byteorder::{ByteOrder, LittleEndian}; +pub use minisign::{PublicKey, SecretKey}; +use minisign::{SignatureBones, SignatureBox}; +use object::*; +use std::fs::{File, OpenOptions}; +use std::io::{self, Cursor, Read, Seek, SeekFrom, Write}; +use std::path::Path; + +pub struct ModuleSignature; + +impl ModuleSignature { + pub fn verify>( + so_path: P, + pk: &PublicKey, + module_data: &ModuleData, + ) -> Result<(), Error> { + let signature_box: SignatureBox = + SignatureBones::from_bytes(&module_data.get_module_signature()) + .map_err(|e| ModuleSignatureError(e))? + .into(); + + let mut raw_module_and_data = + RawModuleAndData::from_file(&so_path).map_err(|e| IOError(e))?; + let cleared_module_data_bin = + ModuleData::clear_module_signature(raw_module_and_data.module_data_bin())?; + raw_module_and_data.patch_module_data(&cleared_module_data_bin); + + minisign::verify( + &pk, + &signature_box, + Cursor::new(&raw_module_and_data.obj_bin), + true, + false, + ) + .map_err(|e| ModuleSignatureError(e)) + } + + pub fn sign>(path: P, sk: &SecretKey) -> Result<(), Error> { + let raw_module_and_data = RawModuleAndData::from_file(&path).map_err(|e| IOError(e))?; + let signature_box = minisign::sign( + None, + sk, + Cursor::new(&raw_module_and_data.obj_bin), + true, + None, + None, + ) + .map_err(|e| ModuleSignatureError(e))?; + let signature_bones: SignatureBones = signature_box.into(); + let patched_module_data_bin = ModuleData::patch_module_signature( + raw_module_and_data.module_data_bin(), + &signature_bones.to_bytes(), + )?; + raw_module_and_data + .write_patched_module_data(&path, &patched_module_data_bin) + .map_err(|e| IOError(e))?; + Ok(()) + } +} + +struct SymbolData { + offset: usize, + len: usize, +} + +struct RawModuleAndData { + pub obj_bin: Vec, + pub module_data_offset: usize, + pub module_data_len: usize, +} + +impl RawModuleAndData { + pub fn from_file>(path: P) -> Result { + let mut obj_bin: Vec = Vec::new(); + File::open(&path)?.read_to_end(&mut obj_bin)?; + + let module_data_symbol_data = Self::symbol_data(&obj_bin, "lucet_module_data", true)? + .ok_or(io::Error::new( + io::ErrorKind::InvalidInput, + "module data not found", + ))?; + let module_data_len_symbol_data = + Self::symbol_data(&obj_bin, "lucet_module_data_len", true)?.ok_or(io::Error::new( + io::ErrorKind::InvalidInput, + "module length not found", + ))?; + assert_eq!(module_data_len_symbol_data.len, 4); + assert_eq!( + LittleEndian::read_u32(&obj_bin[module_data_len_symbol_data.offset..]) as usize, + module_data_symbol_data.len + ); + Ok(RawModuleAndData { + obj_bin, + module_data_offset: module_data_symbol_data.offset, + module_data_len: module_data_symbol_data.len, + }) + } + + pub fn module_data_bin(&self) -> &[u8] { + &self.obj_bin[self.module_data_offset as usize + ..self.module_data_offset as usize + self.module_data_len] + } + + pub fn module_data_bin_mut(&mut self) -> &mut [u8] { + &mut self.obj_bin[self.module_data_offset as usize + ..self.module_data_offset as usize + self.module_data_len] + } + + pub fn patch_module_data(&mut self, module_data_bin: &[u8]) { + self.module_data_bin_mut().copy_from_slice(&module_data_bin); + } + + pub fn write_patched_module_data>( + &self, + path: P, + patched_module_data_bin: &[u8], + ) -> Result<(), io::Error> { + let mut fp = OpenOptions::new() + .write(true) + .create_new(false) + .open(&path)?; + fp.seek(SeekFrom::Start(self.module_data_offset as u64))?; + fp.write_all(&patched_module_data_bin)?; + Ok(()) + } + + // Retrieving the offset of a symbol is not supported by the object crate. + // In Mach-O, actual file offsets are encoded, whereas Elf encodes virtual + // addresses, requiring extra steps to retrieve the section, its base + // address as well as the section offset. + + // Elf + #[cfg(all(target_family = "unix", not(target_os = "macos")))] + fn symbol_data( + obj_bin: &[u8], + symbol_name: &str, + _mangle: bool, + ) -> Result, io::Error> { + let obj = object::ElfFile::parse(obj_bin) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?; + let symbol_map = obj.symbol_map(); + for symbol in symbol_map.symbols() { + let kind = symbol.kind(); + if kind != SymbolKind::Data { + continue; + } + if symbol.name() != Some(symbol_name) { + continue; + } + let section_index = match symbol.section_index() { + Some(section_index) => section_index, + None => continue, + }; + let section = &obj.elf().section_headers[section_index.0]; + let offset = (symbol.address() - section.sh_addr + section.sh_offset) as usize; + let len = symbol.size() as usize; + return Ok(Some(SymbolData { offset, len })); + } + Ok(None) + } + + // Mach-O + #[cfg(target_os = "macos")] + fn symbol_data( + obj_bin: &[u8], + symbol_name: &str, + mangle: bool, + ) -> Result, io::Error> { + let obj = object::File::parse(obj_bin) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?; + let symbol_map = obj.symbol_map(); + let mangled_symbol_name = format!("_{}", symbol_name); + let symbol_name = if mangle { + &mangled_symbol_name + } else { + symbol_name + }; + for symbol in symbol_map.symbols() { + let kind = symbol.kind(); + if kind != SymbolKind::Data && kind != SymbolKind::Unknown { + continue; + } + if symbol.name() != Some(symbol_name) { + continue; + } + let offset = symbol.address() as usize; + let len = symbol.size() as usize; + return Ok(Some(SymbolData { offset, len })); + } + Ok(None) + } +} diff --git a/lucet-module-data/src/traps.rs b/lucet-module-data/src/traps.rs index a87b69a00..26b7a8c6e 100644 --- a/lucet-module-data/src/traps.rs +++ b/lucet-module-data/src/traps.rs @@ -35,7 +35,7 @@ impl TrapCode { #[derive(Clone, Debug)] pub struct TrapSite { pub offset: u32, - pub code: TrapCode + pub code: TrapCode, } /// A collection of trap sites, typically obtained from a @@ -43,7 +43,7 @@ pub struct TrapSite { #[repr(C)] #[derive(Clone, Debug)] pub struct TrapManifest<'a> { - pub traps: &'a [TrapSite] + pub traps: &'a [TrapSite], } impl <'a> TrapManifest<'a> { @@ -52,8 +52,7 @@ impl <'a> TrapManifest<'a> { } pub fn lookup_addr(&self, addr: u32) -> Option { // predicate to find the trapsite for the addr via binary search - let f = - |ts: &TrapSite| ts.offset.cmp(&addr); + let f = |ts: &TrapSite| ts.offset.cmp(&addr); if let Ok(i) = self.traps.binary_search_by(f) { Some(self.traps[i].code) diff --git a/lucet-module-data/src/types.rs b/lucet-module-data/src/types.rs index fa7eaba6d..2b5c02e51 100644 --- a/lucet-module-data/src/types.rs +++ b/lucet-module-data/src/types.rs @@ -1,6 +1,6 @@ -use std::convert::TryFrom; use cranelift_codegen::ir; use serde::{Deserialize, Serialize}; +use std::convert::TryFrom; use std::fmt::{Display, Formatter}; #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] @@ -25,7 +25,7 @@ impl Display for ValueType { #[derive(Debug)] pub enum ValueError { Unrepresentable, - InvalidVMContext + InvalidVMContext, } impl TryFrom<&ir::AbiParam> for ValueType { @@ -37,7 +37,7 @@ impl TryFrom<&ir::AbiParam> for ValueType { value_type: cranelift_ty, purpose: ir::ArgumentPurpose::Normal, extension: ir::ArgumentExtension::None, - location: ir::ArgumentLoc::Unassigned + location: ir::ArgumentLoc::Unassigned, } => { let size = cranelift_ty.bits(); @@ -56,8 +56,8 @@ impl TryFrom<&ir::AbiParam> for ValueType { } else { Err(ValueError::Unrepresentable) } - }, - _ => Err(ValueError::Unrepresentable) + } + _ => Err(ValueError::Unrepresentable), } } } @@ -86,7 +86,7 @@ impl Display for Signature { write!(f, ") -> ")?; match self.ret_ty { Some(ty) => write!(f, "{}", ty), - None => write!(f, "()") + None => write!(f, "()"), } } } @@ -116,7 +116,7 @@ macro_rules! lucet_signature { #[derive(Debug)] pub enum SignatureError { BadElement(ir::AbiParam, ValueError), - BadSignature + BadSignature, } impl TryFrom<&ir::Signature> for Signature { @@ -135,16 +135,22 @@ impl TryFrom<&ir::Signature> for Signature { value_type: value, purpose: ir::ArgumentPurpose::VMContext, extension: ir::ArgumentExtension::None, - location: ir::ArgumentLoc::Unassigned + location: ir::ArgumentLoc::Unassigned, } => { if value.is_int() && value.bits() == 64 { // this is VMContext, so we can move on. } else { - return Err(SignatureError::BadElement(param.to_owned(), ValueError::InvalidVMContext)); + return Err(SignatureError::BadElement( + param.to_owned(), + ValueError::InvalidVMContext, + )); } - }, + } _ => { - return Err(SignatureError::BadElement(param.to_owned(), ValueError::InvalidVMContext)); + return Err(SignatureError::BadElement( + param.to_owned(), + ValueError::InvalidVMContext, + )); } } } else { @@ -165,7 +171,7 @@ impl TryFrom<&ir::Signature> for Signature { .map_err(|e| SignatureError::BadElement(ret_ty.clone(), e))?; Some(value_ty) - }, + } _ => { return Err(SignatureError::BadSignature); } diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index f05fe5f8a..a9a388825 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -9,6 +9,7 @@ lucet-module-data = { path = "../../lucet-module-data" } bitflags = "1.0" bincode = "~1.0.1" +byteorder = "1.3" cranelift-codegen = { path = "../../cranelift/cranelift-codegen" } failure = "0.1" lazy_static = "1.1" diff --git a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs index 780a02340..b9ef9cbc8 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs @@ -3,7 +3,8 @@ use crate::module::{AddrDetails, GlobalSpec, HeapSpec, Module, ModuleInternal, T use libc::c_void; use libloading::{Library, Symbol}; use lucet_module_data::{ - FunctionHandle, FunctionIndex, FunctionPointer, FunctionSpec, ModuleData, Signature, + FunctionHandle, FunctionIndex, FunctionPointer, FunctionSpec, ModuleData, ModuleSignature, + PublicKey, Signature, }; use std::ffi::CStr; use std::mem; @@ -32,6 +33,19 @@ unsafe impl Sync for DlModule {} impl DlModule { /// Create a module, loading code from a shared object on the filesystem. pub fn load>(so_path: P) -> Result, Error> { + Self::load_and_maybe_verify(so_path, None) + } + + /// Create a module, loading code from a shared object on the filesystem + /// and verifying it using a public key if one has been supplied. + pub fn load_and_verify>(so_path: P, pk: PublicKey) -> Result, Error> { + Self::load_and_maybe_verify(so_path, Some(pk)) + } + + fn load_and_maybe_verify>( + so_path: P, + pk: Option, + ) -> Result, Error> { // Load the dynamic library. The undefined symbols corresponding to the lucet_syscall_ // functions will be provided by the current executable. We trust our wasm->dylib compiler // to make sure these function calls are the way the dylib can touch memory outside of its @@ -65,6 +79,12 @@ impl DlModule { unsafe { slice::from_raw_parts(*module_data_ptr, *module_data_len) }; let module_data = ModuleData::deserialize(module_data_slice)?; + // If a public key has been provided, verify the module signature + // The TOCTOU issue is unavoidable without reimplenting `dlopen(3)` + if let Some(pk) = pk { + ModuleSignature::verify(so_path, &pk, &module_data)?; + } + let fbase = if let Some(dli) = dladdr(*module_data_ptr as *const c_void) { dli.dli_fbase } else { diff --git a/lucet-runtime/src/lib.rs b/lucet-runtime/src/lib.rs index ea2631b6e..e7a781853 100644 --- a/lucet-runtime/src/lib.rs +++ b/lucet-runtime/src/lib.rs @@ -202,7 +202,7 @@ pub mod c_api; -pub use lucet_module_data::TrapCode; +pub use lucet_module_data::{PublicKey, TrapCode}; pub use lucet_runtime_internals::alloc::Limits; pub use lucet_runtime_internals::error::Error; pub use lucet_runtime_internals::instance::{ diff --git a/lucet-wasi/src/main.rs b/lucet-wasi/src/main.rs index 003d7174e..c4bc36a47 100644 --- a/lucet-wasi/src/main.rs +++ b/lucet-wasi/src/main.rs @@ -5,10 +5,11 @@ extern crate clap; use clap::Arg; use human_size::{Byte, Size}; -use lucet_runtime::{self, DlModule, Limits, MmapRegion, Module, Region}; +use lucet_runtime::{self, DlModule, Limits, MmapRegion, Module, PublicKey, Region}; use lucet_runtime_internals::module::ModuleInternal; use lucet_wasi::{hostcalls, WasiCtxBuilder}; use std::fs::File; +use std::path::PathBuf; use std::sync::Arc; struct Config<'a> { @@ -17,6 +18,8 @@ struct Config<'a> { entrypoint: &'a str, preopen_dirs: Vec<(File, &'a str)>, limits: Limits, + verify: bool, + pk_path: Option, } fn main() { @@ -88,6 +91,18 @@ fn main() { .multiple(true) .help("Arguments to the WASI `main` function"), ) + .arg( + Arg::with_name("verify") + .long("--signature-verify") + .takes_value(false) + .help("Verify the signature of the source file") + ) + .arg( + Arg::with_name("pk_path") + .long("--signature-pk") + .takes_value(true) + .help("Path to the public key to verify the source code signature") + ) .get_matches(); let entrypoint = matches.value_of("entrypoint").unwrap(); @@ -145,12 +160,17 @@ fn main() { .map(|vals| vals.collect()) .unwrap_or(vec![]); + let verify = matches.is_present("verify"); + let pk_path = matches.value_of("pk_path").map(PathBuf::from); + let config = Config { lucet_module, guest_args, entrypoint, preopen_dirs, limits, + verify, + pk_path, }; run(config) @@ -160,7 +180,19 @@ fn run(config: Config<'_>) { lucet_wasi::hostcalls::ensure_linked(); let exitcode = { // doing all of this in a block makes sure everything gets dropped before exiting - let module = DlModule::load(&config.lucet_module).expect("module can be loaded"); + let pk = match (config.verify, config.pk_path) { + (false, _) => None, + (true, Some(pk_path)) => { + Some(PublicKey::from_file(pk_path).expect("public key can be loaded")) + } + (true, None) => panic!("signature verification requires a public key"), + }; + let module = if let Some(pk) = pk { + DlModule::load_and_verify(&config.lucet_module, pk) + .expect("signed module can be loaded") + } else { + DlModule::load(&config.lucet_module).expect("module can be loaded") + }; let min_globals_size = module.globals().len() * std::mem::size_of::(); let globals_size = ((min_globals_size + 4096 - 1) / 4096) * 4096; diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index eeb9ad95a..9d7e25926 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -40,6 +40,7 @@ tempfile = "3.0" bimap = "0.2" human-size = "0.4" parity-wasm = "0.35" +minisign = "0.5.11" [dev-dependencies] lucet-wasi-sdk = { path = "../lucet-wasi-sdk" } diff --git a/lucetc/src/error.rs b/lucetc/src/error.rs index 539d7b702..7ac842842 100644 --- a/lucetc/src/error.rs +++ b/lucetc/src/error.rs @@ -63,6 +63,8 @@ pub enum LucetcErrorKind { MemorySpecs, #[fail(display = "Output")] Output, + #[fail(display = "Signature")] + Signature, #[fail(display = "Unsupported")] Unsupported, } diff --git a/lucetc/src/lib.rs b/lucetc/src/lib.rs index b1aaeebeb..bc78e5eac 100644 --- a/lucetc/src/lib.rs +++ b/lucetc/src/lib.rs @@ -14,6 +14,7 @@ mod output; mod patch; mod pointer; mod runtime; +pub mod signature; mod sparsedata; mod stack_probe; mod table; @@ -30,6 +31,7 @@ pub use crate::{ patch::patch_module, }; use failure::{format_err, Error, ResultExt}; +use signature::{PublicKey, SecretKey}; use std::env; use std::path::{Path, PathBuf}; use tempfile; @@ -45,6 +47,10 @@ pub struct Lucetc { opt_level: OptLevel, heap: HeapSettings, builtins_paths: Vec, + sk: Option, + pk: Option, + sign: bool, + verify: bool, } pub trait AsLucetc { @@ -84,6 +90,15 @@ pub trait LucetcOpts { fn guard_size(&mut self, guard_size: u64); fn with_guard_size(self, guard_size: u64) -> Self; + + fn pk(&mut self, pk: PublicKey); + fn with_pk(self, pk: PublicKey) -> Self; + fn sk(&mut self, sk: SecretKey); + fn with_sk(self, sk: SecretKey) -> Self; + fn verify(&mut self); + fn with_verify(self) -> Self; + fn sign(&mut self); + fn with_sign(self) -> Self; } impl LucetcOpts for T { @@ -152,6 +167,42 @@ impl LucetcOpts for T { self.guard_size(guard_size); self } + + fn pk(&mut self, pk: PublicKey) { + self.as_lucetc().pk = Some(pk); + } + + fn with_pk(mut self, pk: PublicKey) -> Self { + self.pk(pk); + self + } + + fn sk(&mut self, sk: SecretKey) { + self.as_lucetc().sk = Some(sk); + } + + fn with_sk(mut self, sk: SecretKey) -> Self { + self.sk(sk); + self + } + + fn verify(&mut self) { + self.as_lucetc().verify = true; + } + + fn with_verify(mut self) -> Self { + self.verify(); + self + } + + fn sign(&mut self) { + self.as_lucetc().sign = true; + } + + fn with_sign(mut self) -> Self { + self.sign(); + self + } } impl Lucetc { @@ -163,6 +214,10 @@ impl Lucetc { opt_level: OptLevel::default(), heap: HeapSettings::default(), builtins_paths: vec![], + pk: None, + sk: None, + sign: false, + verify: false, } } @@ -174,6 +229,10 @@ impl Lucetc { opt_level: OptLevel::default(), heap: HeapSettings::default(), builtins_paths: vec![], + pk: None, + sk: None, + sign: false, + verify: false, }) } @@ -183,7 +242,7 @@ impl Lucetc { let mut builtins_bindings = vec![]; let mut module_binary = match &self.input { LucetcInput::Bytes(bytes) => bytes.clone(), - LucetcInput::Path(path) => read_module(&path)?, + LucetcInput::Path(path) => read_module(&path, &self.pk, self.verify)?, }; if !self.builtins_paths.is_empty() { @@ -242,7 +301,13 @@ impl Lucetc { let dir = tempfile::Builder::new().prefix("lucetc").tempdir()?; let objpath = dir.path().join("tmp.o"); self.object_file(objpath.clone())?; - link_so(objpath, output)?; + link_so(objpath, &output)?; + if self.sign { + let sk = self.sk.as_ref().ok_or( + format_err!("signing requires a secret key").context(LucetcErrorKind::Signature), + )?; + signature::sign_module(&output, sk)?; + } Ok(()) } } diff --git a/lucetc/src/load.rs b/lucetc/src/load.rs index 8a69b2ff3..97b449ed4 100644 --- a/lucetc/src/load.rs +++ b/lucetc/src/load.rs @@ -1,12 +1,30 @@ use crate::error::LucetcErrorKind; +use crate::signature::{self, PublicKey}; use failure::*; use std::fs::File; use std::io::Read; use std::path::Path; use wabt::wat2wasm; -pub fn read_module>(path: P) -> Result, Error> { +pub fn read_module>( + path: P, + pk: &Option, + verify: bool, +) -> Result, Error> { + let signature_box = if verify { + Some(signature::signature_box_for_module_path(&path)?) + } else { + None + }; let contents = read_to_u8s(path)?; + if let Some(signature_box) = signature_box { + signature::verify_source_code( + &contents, + &signature_box, + pk.as_ref() + .ok_or(format_err!("public key is missing").context(LucetcErrorKind::Signature))?, + )?; + } read_bytes(contents) } diff --git a/lucetc/src/main.rs b/lucetc/src/main.rs index c8f0fe82d..c27766966 100644 --- a/lucetc/src/main.rs +++ b/lucetc/src/main.rs @@ -3,7 +3,10 @@ mod options; use crate::options::{CodegenOutput, Options}; use failure::{format_err, Error, ResultExt}; use log::info; -use lucetc::{Bindings, Lucetc, LucetcOpts}; +use lucetc::{ + signature::{self, PublicKey}, + Bindings, Lucetc, LucetcOpts, +}; use std::io::{self, Write}; use std::path::PathBuf; @@ -19,7 +22,7 @@ fn main() { if !msg.ends_with('\n') { msg.push('\n'); } - io::stderr().write(msg.as_bytes()).unwrap(); + io::stderr().write_all(msg.as_bytes()).unwrap(); process::exit(1); } } @@ -27,6 +30,11 @@ fn main() { pub fn run(opts: &Options) -> Result<(), Error> { info!("lucetc {:?}", opts); + if opts.keygen { + keygen(opts)?; + return Ok(()); + } + let input = &match opts.input.len() { 0 => Err(format_err!("must provide at least one input")), 1 => Ok(opts.input[0].clone()), @@ -67,6 +75,22 @@ pub fn run(opts: &Options) -> Result<(), Error> { c.guard_size(guard_size); } + if let Some(pk_path) = &opts.pk_path { + c.pk(PublicKey::from_file(pk_path)?); + } + + if let Some(sk_path) = &opts.sk_path { + c.sk(signature::sk_from_file(sk_path)?); + } + + if opts.verify { + c.verify(); + } + + if opts.sign { + c.sign(); + } + match opts.codegen { CodegenOutput::Obj => c.object_file(&opts.output)?, CodegenOutput::SharedObj => c.shared_object_file(&opts.output)?, @@ -74,3 +98,12 @@ pub fn run(opts: &Options) -> Result<(), Error> { } Ok(()) } + +fn keygen(opts: &Options) -> Result<(), Error> { + let (pk_path, sk_path) = match (&opts.pk_path, &opts.sk_path) { + (Some(pk_path), Some(sk_path)) => (pk_path, sk_path), + _ => Err(format_err!("Keypair generation requires --signature-pk and --signature-sk to specify where the keys should be stored to"))? + }; + signature::keygen(pk_path, sk_path)?; + Ok(()) +} diff --git a/lucetc/src/options.rs b/lucetc/src/options.rs index 1970259e2..8e3c42a6c 100644 --- a/lucetc/src/options.rs +++ b/lucetc/src/options.rs @@ -41,6 +41,11 @@ pub struct Options { pub reserved_size: Option, pub guard_size: Option, pub opt_level: OptLevel, + pub keygen: bool, + pub sign: bool, + pub verify: bool, + pub pk_path: Option, + pub sk_path: Option, } impl Options { @@ -101,6 +106,12 @@ impl Options { Some(_) => panic!("unknown value for opt-level"), }; + let keygen = m.is_present("keygen"); + let sign = m.is_present("sign"); + let verify = m.is_present("verify"); + let sk_path = m.value_of("sk_path").map(PathBuf::from); + let pk_path = m.value_of("pk_path").map(PathBuf::from); + Ok(Options { output, input, @@ -112,6 +123,11 @@ impl Options { reserved_size, guard_size, opt_level, + keygen, + sign, + verify, + sk_path, + pk_path, }) } pub fn get() -> Result { @@ -188,7 +204,7 @@ impl Options { .arg( Arg::with_name("input") .multiple(false) - .required(true) + .required(false) .help("input file"), ) .arg( @@ -198,6 +214,36 @@ impl Options { .possible_values(&["0", "1", "2", "fast"]) .help("optimization level (default: '1')"), ) + .arg( + Arg::with_name("keygen") + .long("--signature-keygen") + .takes_value(false) + .help("Create a new key pair") + ) + .arg( + Arg::with_name("verify") + .long("--signature-verify") + .takes_value(false) + .help("Verify the signature of the source file") + ) + .arg( + Arg::with_name("sign") + .long("--signature-create") + .takes_value(false) + .help("Sign the object file") + ) + .arg( + Arg::with_name("pk_path") + .long("--signature-pk") + .takes_value(true) + .help("Path to the public key to verify the source code signature") + ) + .arg( + Arg::with_name("sk_path") + .long("--signature-sk") + .takes_value(true) + .help("Path to the secret key to sign the object file. The file can be prefixed with \"raw:\" in order to store a raw, unencrypted secret key") + ) .get_matches(); Self::from_args(&m) diff --git a/lucetc/src/signature.rs b/lucetc/src/signature.rs new file mode 100644 index 000000000..ad2e18385 --- /dev/null +++ b/lucetc/src/signature.rs @@ -0,0 +1,79 @@ +use failure::*; +use lucet_module_data::ModuleSignature; +pub use minisign::{KeyPair, PublicKey, SecretKey, SignatureBones, SignatureBox}; +use std::fs::File; +use std::io::{Cursor, Read, Write}; +use std::path::{Path, PathBuf}; + +pub const RAW_KEY_PREFIX: &str = "raw:"; + +fn raw_key_path>(path: P) -> Option { + let path = path.as_ref(); + if let Some(path) = path.to_str() { + if path.starts_with(RAW_KEY_PREFIX) { + return Some(PathBuf::from(&path[RAW_KEY_PREFIX.len()..])); + } + } + None +} + +pub fn sk_from_file>(sk_path: P) -> Result { + match raw_key_path(sk_path.as_ref()) { + None => SecretKey::from_file(sk_path, None) + .map_err(|e| format_err!("Unable to read the secret key: {}", e)), + Some(sk_path) => { + let mut sk_bin: Vec = Vec::new(); + File::open(sk_path)?.read_to_end(&mut sk_bin)?; + SecretKey::from_bytes(&sk_bin) + .map_err(|e| format_err!("Unable to read the secret key: {}", e)) + } + } +} + +fn signature_path>(path: P) -> Result { + let path = path + .as_ref() + .to_str() + .ok_or_else(|| format_err!("Invalid path"))?; + Ok(PathBuf::from(format!("{}.minisig", path))) +} + +pub fn signature_box_for_module_path>(path: P) -> Result { + let signature_path = signature_path(path)?; + SignatureBox::from_file(&signature_path) + .map_err(|e| format_err!("Unable to load the signature file: {}", e)) +} + +pub fn keygen, Q: AsRef>(pk_path: P, sk_path: Q) -> Result { + match raw_key_path(&sk_path) { + None => { + let pk_writer = File::create(pk_path)?; + let sk_writer = File::create(sk_path)?; + KeyPair::generate_and_write_encrypted_keypair(pk_writer, sk_writer, None, None) + .map_err(|e| format_err!("Unable to generate the key pair: {}", e)) + } + Some(sk_path_raw) => { + let kp = KeyPair::generate_unencrypted_keypair() + .map_err(|e| format_err!("Unable to generate the key pair: {}", e))?; + let mut pk_writer = File::create(pk_path)?; + let mut sk_writer = File::create(sk_path_raw)?; + pk_writer.write_all(&kp.pk.to_box()?.to_bytes())?; + sk_writer.write_all(&kp.sk.to_bytes())?; + Ok(kp) + } + } +} + +// Verify the source code (WASM / WAT) +pub fn verify_source_code( + buf: &[u8], + signature_box: &SignatureBox, + pk: &PublicKey, +) -> Result<(), Error> { + minisign::verify(pk, signature_box, Cursor::new(buf), false, false).map_err(|e| e.into()) +} + +// Sign the compiled code +pub fn sign_module>(path: P, sk: &SecretKey) -> Result<(), Error> { + ModuleSignature::sign(path, sk).map_err(|e| e.into()) +} From 630ee4ad89888f7eb6dbefe8aa7d99e7969b8187 Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Tue, 25 Jun 2019 19:36:49 +0200 Subject: [PATCH 177/512] Indent all the lucet subprojects (#229) --- helpers/indent.sh | 19 +++++++++---------- lucet-module-data/src/traps.rs | 2 +- lucet-wasi/tests/test_helpers/mod.rs | 7 +++++-- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/helpers/indent.sh b/helpers/indent.sh index 76b652819..664b7fcc5 100755 --- a/helpers/indent.sh +++ b/helpers/indent.sh @@ -1,36 +1,35 @@ #!/bin/bash set -e ARG=$1 -cleanup () { +cleanup() { if [[ $ARG == "check" ]]; then echo "" echo "Formatting diffs detected! run \"./indent\" to correct." fi rm -f .formatted } -trap cleanup 1 2 3 6 9 15 +trap cleanup 1 2 3 6 15 -if ! $(rustfmt --version | grep -q "rustfmt 1.2.0-stable"); then +if ! rustfmt --version | grep -q "rustfmt 1.2.0-stable"; then echo "indent requires rustfmt 1.2.0-stable" - exit 1; + exit 1 fi -RUST_DIRS=$(find lucet-analyze lucet-idl lucet-spectest lucetc lucet-runtime lucet-wasi-sdk -type f -name 'Cargo.toml' -print) +RUST_DIRS=$(find lucetc lucet-* benchmarks/lucet-* -type f -name 'Cargo.toml' -print) if [[ $ARG == "check" ]]; then for RUST_DIR in ${RUST_DIRS}; do - pushd $(dirname ${RUST_DIR}) > /dev/null + pushd "$(dirname ${RUST_DIR})" >/dev/null cargo fmt -- --check - popd > /dev/null + popd >/dev/null done elif [[ $ARG == "" ]]; then for RUST_DIR in ${RUST_DIRS}; do - pushd $(dirname ${RUST_DIR}) > /dev/null + pushd "$(dirname ${RUST_DIR})" >/dev/null cargo fmt - popd > /dev/null + popd >/dev/null done else echo "unsupported argument: $1" exit 1 fi - diff --git a/lucet-module-data/src/traps.rs b/lucet-module-data/src/traps.rs index 26b7a8c6e..28f01c60e 100644 --- a/lucet-module-data/src/traps.rs +++ b/lucet-module-data/src/traps.rs @@ -46,7 +46,7 @@ pub struct TrapManifest<'a> { pub traps: &'a [TrapSite], } -impl <'a> TrapManifest<'a> { +impl<'a> TrapManifest<'a> { pub fn new(traps: &'a [TrapSite]) -> TrapManifest<'_> { TrapManifest { traps } } diff --git a/lucet-wasi/tests/test_helpers/mod.rs b/lucet-wasi/tests/test_helpers/mod.rs index 1b29f62d8..6ed75e9da 100644 --- a/lucet-wasi/tests/test_helpers/mod.rs +++ b/lucet-wasi/tests/test_helpers/mod.rs @@ -46,7 +46,7 @@ pub fn wasi_test>(file: P) -> Result, Error> { wasm_build.link(wasm_file.clone())?; wasm_file - }, + } Some("wasm") | Some("wat") => { // others are just wasm we can run directly file.as_ref().to_owned() @@ -62,7 +62,10 @@ pub fn wasi_test>(file: P) -> Result, Error> { wasi_load(&workdir, wasm_path) } -pub fn wasi_load>(workdir: &TempDir, wasm_file: P) -> Result, Error> { +pub fn wasi_load>( + workdir: &TempDir, + wasm_file: P, +) -> Result, Error> { let bindings = Bindings::from_file(Path::new(LUCET_WASI_ROOT).join("bindings.json"))?; let native_build = Lucetc::new(wasm_file).with_bindings(bindings); From 70b4bea65160f72be102f166e664c3054ab81714 Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Tue, 25 Jun 2019 20:28:00 +0200 Subject: [PATCH 178/512] Add a helper script to set the global package version (#230) Check that in their current state, subpackages can be published. Only then, set the global version number to the same as the main Cargo.toml file Try one last dry run with the new version number. --- Cargo.toml | 2 ++ helpers/bump-global-version.sh | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100755 helpers/bump-global-version.sh diff --git a/Cargo.toml b/Cargo.toml index f1ff22eb8..775e33972 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,5 @@ +# Lucet version 0.1.0 + [workspace] members = [ "lucet-analyze", diff --git a/helpers/bump-global-version.sh b/helpers/bump-global-version.sh new file mode 100755 index 000000000..05f275170 --- /dev/null +++ b/helpers/bump-global-version.sh @@ -0,0 +1,27 @@ +#! /bin/sh + +VERSION=$(grep '#*Lucet version ' Cargo.toml | sed 's/^ *# Lucet version *//') +[ -z "$VERSION" ] && echo "Version header not found in the top Cargo.toml file" >&2 && exit 1 + +dry_run() { + echo "Checking if the package can be published (dry run)..." + echo + find lucetc lucet-* benchmarks/lucet-* -type f -maxdepth 1 -name 'Cargo.toml' -print | while read -r file; do + dir="$(dirname $file)" + echo "* Checking [$dir]" + (cd "$dir" && cargo publish --allow-dirty --dry-run >/dev/null) || exit 1 + done || exit 1 + echo + echo "Done." +} + +version_bump() { + echo + echo "Setting the global Lucet version number to: [$VERSION]" + find lucetc lucet-* benchmarks/lucet-* -type f -maxdepth 1 -name 'Cargo.toml' -print | while read -r file; do + sed -i '.previous' "s/^ *version *=.*/version = \"${VERSION}\"/" "$file" && rm -f "${file}.previous" + done + echo "Done." +} + +dry_run && version_bump && dry_run From 4f4b451be0d30c89bd5593ed442c825ec168bd3a Mon Sep 17 00:00:00 2001 From: awortman-fastly <49215183+awortman-fastly@users.noreply.github.com> Date: Tue, 25 Jun 2019 11:34:49 -0700 Subject: [PATCH 179/512] Update lucetc to match cranelift upstream changes (#228) * update lucetc to match cranelift upstream changes --- cranelift | 2 +- lucetc/src/compiler.rs | 9 ++++---- lucetc/src/decls.rs | 4 ++-- lucetc/src/function.rs | 50 +++++++++++++++++++++++++++++------------- lucetc/src/output.rs | 2 +- 5 files changed, 44 insertions(+), 23 deletions(-) diff --git a/cranelift b/cranelift index c0ee30f9a..42bd100d9 160000 --- a/cranelift +++ b/cranelift @@ -1 +1 @@ -Subproject commit c0ee30f9a95bd80bd6485c21bad7e8e0b8c5caf0 +Subproject commit 42bd100d9d12e12cea029ba4213c4c154ea0adcb diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index 5fc96999d..bb06fa811 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -72,6 +72,7 @@ impl<'a> Compiler<'a> { } translate_module(wasm_binary, &mut module_info).map_err(|e| match e { + WasmError::User(_) => e.context(LucetcErrorKind::Input), WasmError::InvalidWebAssembly { .. } => e.context(LucetcErrorKind::Validation), // This will trigger once cranelift-wasm upgrades to a validating wasm parser. WasmError::Unsupported { .. } => e.context(LucetcErrorKind::Unsupported), WasmError::ImplLimitExceeded { .. } => e.context(LucetcErrorKind::TranslatingModule), @@ -79,7 +80,7 @@ impl<'a> Compiler<'a> { let libcalls = Box::new(move |libcall| match libcall { ir::LibCall::Probestack => stack_probe::STACK_PROBE_SYM.to_owned(), - _ => (FaerieBuilder::default_libcall_names())(libcall), + _ => (cranelift_module::default_libcall_names())(libcall), }); let mut clif_module: ClifModule = ClifModule::new( @@ -212,7 +213,7 @@ fn write_module_data( data_len_ctx.define(serialized_len.into_boxed_slice()); let data_len_decl = clif_module - .declare_data("lucet_module_data_len", Linkage::Export, false) + .declare_data("lucet_module_data_len", Linkage::Export, false, None) .context(LucetcErrorKind::ModuleData)?; clif_module .define_data(data_len_decl, &data_len_ctx) @@ -224,7 +225,7 @@ fn write_module_data( module_data_ctx.define(module_data_serialized.into_boxed_slice()); let module_data_decl = clif_module - .declare_data("lucet_module_data", Linkage::Export, true) + .declare_data("lucet_module_data", Linkage::Export, true, None) .context(LucetcErrorKind::ModuleData)?; clif_module .define_data(module_data_decl, &module_data_ctx) @@ -243,7 +244,7 @@ fn write_startfunc_data( if let Some(func_ix) = decls.get_start_func() { let name = clif_module - .declare_data("guest_start", Linkage::Export, false) + .declare_data("guest_start", Linkage::Export, false, None) .context(error_kind.clone())?; let mut ctx = DataContext::new(); ctx.define_zeroinit(8); diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index 2137a23c2..66f1d937a 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -208,13 +208,13 @@ impl<'a> ModuleDecls<'a> { for ix in 0..info.tables.len() { let def_symbol = format!("guest_table_{}", ix); let def_data_id = clif_module - .declare_data(&def_symbol, Linkage::Export, false) + .declare_data(&def_symbol, Linkage::Export, false, None) .context(LucetcErrorKind::TranslatingModule)?; let def_name = Name::new_data(def_symbol, def_data_id); let len_symbol = format!("guest_table_{}_len", ix); let len_data_id = clif_module - .declare_data(&len_symbol, Linkage::Export, false) + .declare_data(&len_symbol, Linkage::Export, false, None) .context(LucetcErrorKind::TranslatingModule)?; let len_name = Name::new_data(len_symbol, len_data_id); diff --git a/lucetc/src/function.rs b/lucetc/src/function.rs index 2cb4b9533..6090bfc19 100644 --- a/lucetc/src/function.rs +++ b/lucetc/src/function.rs @@ -7,7 +7,7 @@ use cranelift_codegen::ir::{self, InstBuilder}; use cranelift_codegen::isa::TargetFrontendConfig; use cranelift_wasm::{ FuncEnvironment, FuncIndex, GlobalIndex, GlobalVariable, MemoryIndex, SignatureIndex, - TableIndex, WasmResult, + TableIndex, WasmError, WasmResult, }; use std::collections::HashMap; @@ -84,23 +84,31 @@ impl<'a> FuncEnvironment for FuncInfo<'a> { self.module_decls.target_config() } - fn make_global(&mut self, func: &mut ir::Function, index: GlobalIndex) -> GlobalVariable { + fn make_global( + &mut self, + func: &mut ir::Function, + index: GlobalIndex, + ) -> Result { let global_base = self.get_global_base(func); let global = self.module_decls.get_global(index).expect("valid global"); let index = index.as_u32() as i32; let offset = (index * NATIVE_POINTER_SIZE as i32).into(); - GlobalVariable::Memory { + Ok(GlobalVariable::Memory { gv: global_base, offset, ty: global.entity.ty, - } + }) } - fn make_heap(&mut self, func: &mut ir::Function, index: MemoryIndex) -> ir::Heap { + fn make_heap( + &mut self, + func: &mut ir::Function, + index: MemoryIndex, + ) -> Result { assert_eq!(index, MemoryIndex::new(0), "only memory 0 is supported"); let heap_spec = self.module_decls.get_heap().expect("valid heap"); let vmctx = self.get_vmctx(func); - func.create_heap(ir::HeapData { + Ok(func.create_heap(ir::HeapData { base: vmctx, min_size: heap_spec.initial_size.into(), offset_guard_size: heap_spec.guard_size.into(), @@ -108,10 +116,14 @@ impl<'a> FuncEnvironment for FuncInfo<'a> { bound: heap_spec.reserved_size.into(), }, index_type: ir::types::I32, - }) + })) } - fn make_table(&mut self, func: &mut ir::Function, index: TableIndex) -> ir::Table { + fn make_table( + &mut self, + func: &mut ir::Function, + index: TableIndex, + ) -> Result { let index_type = ir::types::I64; let table_decl = self.module_decls.get_table(index).expect("valid table"); let base_gv = func.create_global_value(ir::GlobalValueData::Symbol { @@ -132,13 +144,13 @@ impl<'a> FuncEnvironment for FuncInfo<'a> { }); let element_size = ((NATIVE_POINTER_SIZE * 2) as u64).into(); let min_size = (table_decl.table.minimum as u64).into(); - func.create_table(ir::TableData { + Ok(func.create_table(ir::TableData { base_gv, bound_gv, element_size, index_type, min_size, - }) + })) } fn translate_call_indirect( @@ -197,12 +209,20 @@ impl<'a> FuncEnvironment for FuncInfo<'a> { Ok(pos.ins().call_indirect(sig_ref, table_entry_fptr, &args)) } - fn make_indirect_sig(&mut self, func: &mut ir::Function, index: SignatureIndex) -> ir::SigRef { + fn make_indirect_sig( + &mut self, + func: &mut ir::Function, + index: SignatureIndex, + ) -> Result { let sig = self.module_decls.get_signature(index).unwrap().clone(); - func.import_signature(sig) + Ok(func.import_signature(sig)) } - fn make_direct_func(&mut self, func: &mut ir::Function, index: FuncIndex) -> ir::FuncRef { + fn make_direct_func( + &mut self, + func: &mut ir::Function, + index: FuncIndex, + ) -> Result { let unique_index = *self .module_decls .info @@ -212,11 +232,11 @@ impl<'a> FuncEnvironment for FuncInfo<'a> { let func_decl = self.module_decls.get_func(unique_index).unwrap(); let signature = func.import_signature(func_decl.signature.clone()); let colocated = !func_decl.imported(); - func.import_function(ir::ExtFuncData { + Ok(func.import_function(ir::ExtFuncData { name: func_decl.name.into(), signature, colocated, - }) + })) } fn translate_call( diff --git a/lucetc/src/output.rs b/lucetc/src/output.rs index 167672986..a0d6d578e 100644 --- a/lucetc/src/output.rs +++ b/lucetc/src/output.rs @@ -28,7 +28,7 @@ impl CraneliftFuncs { let mut buffer = String::new(); for (n, func) in self.funcs.iter() { buffer.push_str(&format!("; {}\n", n.symbol())); - write_function(&mut buffer, func, Some(self.isa.as_ref())) + write_function(&mut buffer, func, &Some(self.isa.as_ref()).into()) .context(format_err!("writing func {:?}", n))? } let mut file = File::create(path)?; From 4166def13b9f273c5da89bb1c4859541c3fde566 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 30 Apr 2019 11:41:36 -0700 Subject: [PATCH 180/512] lucet-idl: start stubbing out rust backend --- Cargo.lock | 5 ++ lucet-idl/Cargo.toml | 1 + lucet-idl/src/rust/mod.rs | 120 ++++++++++++++++++++++++++++---------- 3 files changed, 95 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 465c6fe91..03ab5f8b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -759,7 +759,12 @@ version = "0.1.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +<<<<<<< 415d8fff3d93c96d4e5208f33d82ca2cf947c5bb "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", +======= + "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", +>>>>>>> lucet-idl: start stubbing out rust backend "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/lucet-idl/Cargo.toml b/lucet-idl/Cargo.toml index e42dc2509..cabe34cd6 100644 --- a/lucet-idl/Cargo.toml +++ b/lucet-idl/Cargo.toml @@ -18,6 +18,7 @@ path = "src/main.rs" clap = "2" failure = "0.1" xfailure = "0.1" +heck = "0.3" [dev-dependencies] tempfile = "3.0" diff --git a/lucet-idl/src/rust/mod.rs b/lucet-idl/src/rust/mod.rs index 7dbd8cb8a..0f6d68dab 100644 --- a/lucet-idl/src/rust/mod.rs +++ b/lucet-idl/src/rust/mod.rs @@ -1,14 +1,15 @@ #![allow(dead_code)] #![allow(unused_variables)] -use crate::backend::*; -use crate::cache::*; -use crate::errors::*; +use crate::backend::BackendConfig; +use crate::cache::Cache; +use crate::errors::IDLError; use crate::generator::{Generator, Hierarchy}; -use crate::module::{DataTypeEntry, DataTypeRef, Module}; -use crate::pretty_writer::*; -use crate::target::*; -use std::io::prelude::*; +use crate::module::{DataTypeEntry, DataTypeRef, DataType, Module}; +use crate::pretty_writer::PrettyWriter; +use crate::target::Target; +use std::io::Write; +use heck::CamelCase; #[derive(Clone, Debug)] struct CTypeInfo<'t> { @@ -31,8 +32,8 @@ pub struct RustGenerator { } impl Generator for RustGenerator { - fn gen_prelude(&mut self, pretty_writer: &mut PrettyWriter) -> Result<(), IDLError> { - unimplemented!() + fn gen_prelude(&mut self, _pretty_writer: &mut PrettyWriter) -> Result<(), IDLError> { + Ok(()) } fn gen_type_header( @@ -42,7 +43,12 @@ impl Generator for RustGenerator { pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { - unimplemented!() + pretty_writer + .eob()? + .write_line( + format!("/// {}: {:?}", data_type_entry.name.name, data_type_entry).as_bytes(), + )?; + Ok(()) } // The most important thing in alias generation is to cache the size @@ -54,7 +60,17 @@ impl Generator for RustGenerator { pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { - unimplemented!() + let (pointee, _attrs) = if let DataType::Alias { to: pointee, attrs } = &data_type_entry.data_type { + (pointee, attrs) + } else { + unreachable!() + }; + pretty_writer + .write_line( + format!("type {} = {:?};", data_type_entry.name.name.to_camel_case(), pointee).as_bytes(), + )? + .eob()?; + Ok(()) } fn gen_struct( @@ -64,7 +80,18 @@ impl Generator for RustGenerator { pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { - unimplemented!() + pretty_writer + .write_line( + "#[repr(C)]".as_bytes() + )? + .write_line( + format!("struct {} {{", data_type_entry.name.name.to_camel_case()).as_bytes(), + )? + .write_line( + "}".as_bytes(), + )? + .eob()?; + Ok(()) } // Enums generate both a specific typedef, and a traditional C-style enum @@ -76,39 +103,70 @@ impl Generator for RustGenerator { pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { - unimplemented!() + let (named_members, _attrs) = if let DataType::Enum { + members: named_members, + attrs, + } = &data_type_entry.data_type + { + (named_members, attrs) + } else { + unreachable!() + }; + + + pretty_writer + .write_line( + "#[repr(C)]".as_bytes() + )? + .write_line( + "#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]".as_bytes() + )? + .write_line( + format!("enum {} {{", data_type_entry.name.name.to_camel_case()).as_bytes(), + )?; + + for m in named_members { + pretty_writer.write_line(format!(" {},", m.name.to_camel_case()).as_bytes())?; + } + + pretty_writer + .write_line( + "}".as_bytes(), + )? + .eob()?; + Ok(()) } fn gen_accessors_struct( &mut self, - module: &Module, - cache: &Cache, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - hierarchy: &Hierarchy, + _module: &Module, + _cache: &Cache, + _pretty_writer: &mut PrettyWriter, + _data_type_entry: &DataTypeEntry<'_>, + _hierarchy: &Hierarchy, ) -> Result<(), IDLError> { - unimplemented!() + Ok(()) } fn gen_accessors_enum( &mut self, - module: &Module, - cache: &Cache, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - hierarchy: &Hierarchy, + _module: &Module, + _cache: &Cache, + _pretty_writer: &mut PrettyWriter, + _data_type_entry: &DataTypeEntry<'_>, + _hierarchy: &Hierarchy, ) -> Result<(), IDLError> { - unimplemented!() + Ok(()) } fn gen_accessors_alias( &mut self, - module: &Module, - cache: &Cache, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - hierarchy: &Hierarchy, + _module: &Module, + _cache: &Cache, + _pretty_writer: &mut PrettyWriter, + _data_type_entry: &DataTypeEntry<'_>, + _hierarchy: &Hierarchy, ) -> Result<(), IDLError> { - unimplemented!() + Ok(()) } } From 36bc0b45ce36965f2285410cd4ea6939d3c15ac6 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 1 May 2019 15:32:22 -0700 Subject: [PATCH 181/512] lucet-idl: eliminate pointers, disable C accessors, improve test granularity --- lucet-idl/src/c/accessors/mod.rs | 1 - lucet-idl/src/c/alias.rs | 31 +++---- lucet-idl/src/c/catom.rs | 13 +-- lucet-idl/src/c/macros.rs | 1 - lucet-idl/src/c/mod.rs | 65 +++------------ lucet-idl/src/c/struct.rs | 10 --- lucet-idl/src/config.rs | 8 +- lucet-idl/src/module.rs | 50 +++++++++--- lucet-idl/src/parser.rs | 60 +++++++------- lucet-idl/src/rust/mod.rs | 133 +++++++++++++++++++++---------- lucet-idl/tests/example.idl | 3 +- lucet-idl/tests/example.rs | 43 +++++++++- lucet-idl/tests/example_driver.c | 4 +- 13 files changed, 235 insertions(+), 187 deletions(-) diff --git a/lucet-idl/src/c/accessors/mod.rs b/lucet-idl/src/c/accessors/mod.rs index fa1218590..c053bab6c 100644 --- a/lucet-idl/src/c/accessors/mod.rs +++ b/lucet-idl/src/c/accessors/mod.rs @@ -1,5 +1,4 @@ pub mod alias; pub mod atom; pub mod r#enum; -pub mod ptr; pub mod r#struct; diff --git a/lucet-idl/src/c/alias.rs b/lucet-idl/src/c/alias.rs index 6af89ccf3..486de2317 100644 --- a/lucet-idl/src/c/alias.rs +++ b/lucet-idl/src/c/alias.rs @@ -18,17 +18,12 @@ pub fn generate( pretty_writer.indent()?; pretty_writer.write(format!("typedef {}", type_info.type_name).as_bytes())?; pretty_writer.space()?; - for _ in 0..type_info.indirections { - pretty_writer.write(b"*")?; - } pretty_writer.write(data_type_entry.name.name.as_bytes())?; pretty_writer.write(b";")?; - if type_info.indirections == 0 { - let leaf_type_info = cgenerator.type_info(module, cache, type_info.leaf_data_type_ref); - if leaf_type_info.type_name != type_info.type_name { - pretty_writer.write(b" // equivalent to ")?; - pretty_writer.write(leaf_type_info.type_name.as_bytes())?; - } + let leaf_type_info = cgenerator.type_info(module, cache, type_info.leaf_data_type_ref); + if leaf_type_info.type_name != type_info.type_name { + pretty_writer.write(b" // equivalent to ")?; + pretty_writer.write(leaf_type_info.type_name.as_bytes())?; } pretty_writer.eol()?; pretty_writer.eob()?; @@ -42,16 +37,14 @@ pub fn generate( ); // Add an assertion to check that resolved size is the one we computed - if type_info.indirections == 0 { - pretty_writer.write_line( - format!( - "_Static_assert(sizeof({}) == {}, \"unexpected alias size\");", - data_type_entry.name.name, type_info.type_size - ) - .as_bytes(), - )?; - pretty_writer.eob()?; - } + pretty_writer.write_line( + format!( + "_Static_assert(sizeof({}) == {}, \"unexpected alias size\");", + data_type_entry.name.name, type_info.type_size + ) + .as_bytes(), + )?; + pretty_writer.eob()?; Ok(()) } diff --git a/lucet-idl/src/c/catom.rs b/lucet-idl/src/c/catom.rs index 4e535953d..224ede2dd 100644 --- a/lucet-idl/src/c/catom.rs +++ b/lucet-idl/src/c/catom.rs @@ -66,19 +66,10 @@ impl From for CAtom { } impl CAtom { - /// Native type used for pointers - pub fn ptr() -> Self { - CAtom { - native_type_name: "void *", - native_type_size: 8, - native_type_align: 8, // x86_64 alignment rule - } - } - /// Native type used for enums - /// It can't be an `int` as it would not be portable across architectures + /// X86_64 ABI says its an U32, wasm32 seems to agree pub fn enum_() -> Self { - CAtom::from(AtomType::I64) + CAtom::from(AtomType::U32) } /// C atom type to generic atom type diff --git a/lucet-idl/src/c/macros.rs b/lucet-idl/src/c/macros.rs index 3d37b805d..74ec5c0d0 100644 --- a/lucet-idl/src/c/macros.rs +++ b/lucet-idl/src/c/macros.rs @@ -48,7 +48,6 @@ pub fn macro_for_data_type_ref( let native_type_size = CAtom::from(*atom_type).native_type_size; format!("{}", native_type_size) } - DataTypeRef::Ptr(_) => macro_for(prefix, "PTR"), DataTypeRef::Defined(data_type_id) => { let data_type_entry = module.get_datatype(*data_type_id); macro_for(prefix, &data_type_entry.name.name) diff --git a/lucet-idl/src/c/mod.rs b/lucet-idl/src/c/mod.rs index 49fb276bf..995e32d86 100644 --- a/lucet-idl/src/c/mod.rs +++ b/lucet-idl/src/c/mod.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] #![allow(unused_variables)] -mod accessors; +// mod accessors; mod alias; mod catom; mod r#enum; @@ -28,8 +28,6 @@ struct CTypeInfo<'t> { type_align: usize, /// The native type size type_size: usize, - /// How many pointer indirections are required to get to the atomic type - indirections: usize, /// The leaf type node leaf_data_type_ref: &'t DataTypeRef, } @@ -108,6 +106,7 @@ impl Generator for CGenerator { data_type_entry: &DataTypeEntry<'_>, hierarchy: &Hierarchy, ) -> Result<(), IDLError> { + /* accessors::r#struct::generate( self, module, @@ -116,6 +115,8 @@ impl Generator for CGenerator { data_type_entry, hierarchy, ) + */ + Ok(()) } fn gen_accessors_enum( @@ -126,6 +127,7 @@ impl Generator for CGenerator { data_type_entry: &DataTypeEntry<'_>, hierarchy: &Hierarchy, ) -> Result<(), IDLError> { + /* accessors::r#enum::generate( self, module, @@ -134,6 +136,8 @@ impl Generator for CGenerator { data_type_entry, hierarchy, ) + */ + Ok(()) } fn gen_accessors_alias( @@ -144,6 +148,7 @@ impl Generator for CGenerator { data_type_entry: &DataTypeEntry<'_>, hierarchy: &Hierarchy, ) -> Result<(), IDLError> { + /* accessors::alias::generate( self, module, @@ -152,6 +157,8 @@ impl Generator for CGenerator { data_type_entry, hierarchy, ) + */ + Ok(()) } } @@ -165,19 +172,10 @@ impl CGenerator { cache: &Cache, mut type_: &'t DataTypeRef, ) -> CTypeInfo<'t> { - let mut indirections = 0; let (mut type_align, mut type_size) = (None, None); let mut type_name = None; loop { match &type_ { - DataTypeRef::Ptr(to) => { - type_ = to.as_ref(); - // Only keep counting indirections if we are not resolving an alias - if type_name.is_none() { - indirections += 1; - } - continue; - } DataTypeRef::Atom(atom_type) => { let native_atom = CAtom::from(*atom_type); type_align = type_align.or_else(|| Some(native_atom.native_type_align)); @@ -186,11 +184,9 @@ impl CGenerator { type_name.or_else(|| Some(native_atom.native_type_name.to_string())); } DataTypeRef::Defined(data_type_id) => { - if indirections == 0 { let cached = cache.load_type(*data_type_id).unwrap(); type_align = type_align.or_else(|| Some(cached.type_align)); type_size = type_size.or_else(|| Some(cached.type_size)); - } let data_type_entry = module.get_datatype(*data_type_id); match data_type_entry.data_type { DataType::Struct { .. } => { @@ -216,16 +212,10 @@ impl CGenerator { } break; } - // No matter what the base type is, pointers always have the same size - if indirections > 0 { - type_align = Some(CAtom::ptr().native_type_align); - type_size = Some(CAtom::ptr().native_type_size); - } CTypeInfo { type_name: type_name.unwrap(), type_align: type_align.unwrap(), type_size: type_size.unwrap(), - indirections, leaf_data_type_ref: type_, } } @@ -234,7 +224,6 @@ impl CGenerator { pub fn is_type_eventually_an_atom_or_enum(&self, module: &Module, type_: &DataTypeRef) -> bool { let inner_type = match type_ { DataTypeRef::Atom(_) => return true, - DataTypeRef::Ptr(_) => return false, DataTypeRef::Defined(inner_type) => inner_type, }; let inner_data_type_entry = module.get_datatype(*inner_type); @@ -249,7 +238,7 @@ impl CGenerator { /// Return the type refererence, with aliases being resolved pub fn unalias<'t>(&self, module: &'t Module, type_: &'t DataTypeRef) -> &'t DataTypeRef { let inner_type = match type_ { - DataTypeRef::Atom(_) | DataTypeRef::Ptr(_) => return type_, + DataTypeRef::Atom(_) => return type_, DataTypeRef::Defined(inner_type) => inner_type, }; let inner_data_type_entry = module.get_datatype(*inner_type); @@ -261,33 +250,7 @@ impl CGenerator { } } - /// Possibly add some padding so that pointers are aligned like the reference platform - pub fn pointer_pad( - &mut self, - pretty_writer: &mut PrettyWriter, - indirections: usize, - offset: usize, - name: &str, - ) -> Result<(), IDLError> { - if indirections == 0 { - return Ok(()); - } - if self.target.is_reference_target() { - return Ok(()); - } - pretty_writer.write_line( - format!( - "___POINTER_PAD({}) // pad pointer `{}` at offset {} to match alignment of the reference target ({} bytes)", - offset, - name, - offset, - CAtom::ptr().native_type_align - ) - .as_bytes(), - )?; - Ok(()) - } - + /* fn gen_accessors_for_data_type_ref( &mut self, module: &Module, @@ -302,12 +265,10 @@ impl CGenerator { DataTypeRef::Atom(atom_type) => { accessors::atom::generate(self, module, pretty_writer, *atom_type, &hierarchy) } - DataTypeRef::Ptr(type_) => { - accessors::ptr::generate(self, module, cache, pretty_writer, type_, &hierarchy) - } DataTypeRef::Defined(data_type_id) => { self.gen_accessors_for_id(module, cache, pretty_writer, *data_type_id, &hierarchy) } } } + */ } diff --git a/lucet-idl/src/c/struct.rs b/lucet-idl/src/c/struct.rs index 0f3a9b941..01cd25348 100644 --- a/lucet-idl/src/c/struct.rs +++ b/lucet-idl/src/c/struct.rs @@ -37,20 +37,10 @@ pub fn generate( pretty_writer_i1.indent()?; pretty_writer_i1.write(type_info.type_name.as_bytes())?; pretty_writer_i1.space()?; - for _ in 0..type_info.indirections { - pretty_writer_i1.write(b"*")?; - } pretty_writer_i1.write(named_member.name.as_bytes())?; pretty_writer_i1.write(b";")?; pretty_writer_i1.eol()?; - cgenerator.pointer_pad( - &mut pretty_writer_i1, - type_info.indirections, - offset, - &named_member.name, - )?; - offset += type_size; first_member_align = cmp::max(first_member_align, type_align); } diff --git a/lucet-idl/src/config.rs b/lucet-idl/src/config.rs index 82871add8..bc30d7aac 100644 --- a/lucet-idl/src/config.rs +++ b/lucet-idl/src/config.rs @@ -36,10 +36,10 @@ impl Config { backend_config: self.backend_config, }), - Backend::Rust => Box::new(RustGenerator { - target: self.target, - backend_config: self.backend_config, - }), + Backend::Rust => Box::new(RustGenerator::new( + self.target, + self.backend_config, + )), } } } diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index e2d2b7375..897b6bbb6 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -1,5 +1,5 @@ -use super::parser::{SyntaxDecl, SyntaxRef}; -use super::types::{AtomType, Attr, Location}; +use crate::parser::{SyntaxDecl, SyntaxRef}; +use crate::types::{AtomType, Attr, Location}; use std::collections::HashMap; use std::error::Error; use std::fmt; @@ -17,7 +17,6 @@ impl fmt::Display for DataTypeId { pub enum DataTypeRef { Defined(DataTypeId), Atom(AtomType), - Ptr(Box), } #[derive(Debug, PartialEq, Eq, Clone)] @@ -169,7 +168,6 @@ impl Module { fn get_ref(&self, syntax_ref: &SyntaxRef) -> Result { match syntax_ref { SyntaxRef::Atom { atom, .. } => Ok(DataTypeRef::Atom(*atom)), - SyntaxRef::Ptr { to, .. } => Ok(DataTypeRef::Ptr(Box::new(self.get_ref(&to)?))), SyntaxRef::Name { name, location } => match self.id_for_name(name) { Some(id) => Ok(DataTypeRef::Defined(id)), None => Err(ValidationError::NameNotFound { @@ -381,10 +379,14 @@ mod tests { } #[test] - fn structs() { + fn structs_basic() { assert!(module("struct foo { a: i32}").is_ok()); assert!(module("struct foo { a: i32, b: f32 }").is_ok()); + } + + #[test] + fn struct_two_atoms() { { let d = module("struct foo { a: i32, b: f32 }").unwrap(); let members = match &d.data_types[&0] { @@ -403,14 +405,30 @@ mod tests { }; } + } + + #[test] + fn struct_prev_definition() { // Refer to a struct defined previously: assert!(module("struct foo { a: i32, b: f64 } struct bar { a: foo }").is_ok()); + } + + #[test] + fn struct_next_definition() { // Refer to a struct defined afterwards: assert!(module("struct foo { a: i32, b: bar} struct bar { a: i32 }").is_ok()); + } + + #[test] + fn struct_self_referential() { // Refer to itself - assert!(module("struct list { next: *list, thing: i32 }").is_ok()); + assert!(module("struct list { next: list, thing: i32 }").is_err()); + } + + #[test] + fn struct_empty() { // No members assert_eq!( module("struct foo {}").err().unwrap(), @@ -420,6 +438,10 @@ mod tests { } ); + } + + #[test] + fn struct_duplicate_member() { // Duplicate member in struct assert_eq!( module("struct foo { \na: i32, \na: f64}").err().unwrap(), @@ -430,6 +452,10 @@ mod tests { } ); + } + + #[test] + fn struct_duplicate_definition() { // Duplicate definition of struct assert_eq!( module("struct foo { a: i32 }\nstruct foo { a: i32 } ") @@ -442,6 +468,10 @@ mod tests { } ); + } + + #[test] + fn struct_undeclared_member() { // Refer to type that is not declared assert_eq!( module("struct foo { \nb: bar }").err().unwrap(), @@ -500,12 +530,12 @@ mod tests { #[test] fn aliases() { assert!(module("type foo = i32").is_ok()); - assert!(module("type foo = *f64").is_ok()); - assert!(module("type foo = ************f64").is_ok()); + assert!(module("type foo = f64").is_ok()); + assert!(module("type foo = u8").is_ok()); - assert!(module("type foo = *bar\nenum bar { a }").is_ok()); + assert!(module("type foo = bar\nenum bar { a }").is_ok()); - assert!(module("type link = *list\nstruct list { next: link, thing: i32 }").is_ok()); + assert!(module("type link = u32\nstruct list { next: link, thing: i32 }").is_ok()); } #[test] diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index b0dbdab5a..c65b49926 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -44,18 +44,8 @@ impl SyntaxDecl { #[derive(Debug, PartialEq, Eq, Clone)] pub enum SyntaxRef { - Atom { - atom: AtomType, - location: Location, - }, - Ptr { - to: Box, - location: Location, - }, - Name { - name: String, - location: Location, - }, + Atom { atom: AtomType, location: Location }, + Name { name: String, location: Location }, } #[derive(Debug, PartialEq, Eq, Clone)] @@ -364,18 +354,9 @@ impl<'a> Parser<'a> { location, }) } - Some(Token::Star) => { - let location = self.location; - self.consume(); - let ref_of = self.match_ref(err_msg)?; - Ok(SyntaxRef::Ptr { - to: Box::new(ref_of), - location, - }) - } _ => err_ctx!( err_msg, - parse_err!(self.location, "expected atom, ref, or type name") + parse_err!(self.location, "expected atom, or type name") ), } } @@ -385,7 +366,7 @@ impl<'a> Parser<'a> { mod tests { use super::*; #[test] - fn structs() { + fn struct_empty() { let mut parser = Parser::new("struct foo {}"); assert_eq!( parser @@ -399,6 +380,9 @@ mod tests { location: Location { line: 1, column: 0 }, } ); + } + #[test] + fn struct_one_int_member() { let mut parser = Parser::new("struct foo {a: i32 }"); // column ruler: 0 7 12 15 assert_eq!( @@ -427,6 +411,9 @@ mod tests { location: Location { line: 1, column: 0 }, } ); + } + #[test] + fn struct_one_int_member_trailing_comma() { let mut parser = Parser::new("struct foo {b: i32, }"); // 0 7 12 15 assert_eq!( @@ -455,7 +442,10 @@ mod tests { location: Location { line: 1, column: 0 }, } ); - let mut parser = Parser::new("struct c { d: f64, e: *u8 }"); + } + #[test] + fn struct_two_int_members() { + let mut parser = Parser::new("struct c { d: f64, e: u8 }"); // 0 7 11 14 19 22 assert_eq!( parser @@ -482,14 +472,8 @@ mod tests { }, StructMember { name: "e".to_owned(), - type_: SyntaxRef::Ptr { - to: Box::new(SyntaxRef::Atom { - atom: AtomType::U8, - location: Location { - line: 1, - column: 23, - }, - }), + type_: SyntaxRef::Atom { + atom: AtomType::U8, location: Location { line: 1, column: 22, @@ -507,6 +491,9 @@ mod tests { } ); + } + #[test] + fn struct_empty_one_attribute() { // Test out attributes: let mut parser = Parser::new("#[key1=val1] struct foo {}"); assert_eq!( @@ -524,6 +511,9 @@ mod tests { }, } ); + } + #[test] + fn struct_empty_one_attribute_with_spaces() { let mut parser = Parser::new("#[key2=\"1 value with spaces!\"]\nstruct foo {}"); assert_eq!( parser @@ -541,6 +531,9 @@ mod tests { location: Location { line: 2, column: 0 }, } ); + } + #[test] + fn struct_empty_multiple_attributes() { let mut parser = Parser::new("#[key1=val1]\n\t#[key2 = \"val2\" ]\nstruct foo {}"); assert_eq!( parser @@ -557,6 +550,9 @@ mod tests { location: Location { line: 3, column: 0 }, } ); + } + #[test] + fn struct_member_attribute() { let mut parser = Parser::new("struct foo {\n\t#[key=val]\n\tmem: f32,\n}"); assert_eq!( parser diff --git a/lucet-idl/src/rust/mod.rs b/lucet-idl/src/rust/mod.rs index 0f6d68dab..8e12d8507 100644 --- a/lucet-idl/src/rust/mod.rs +++ b/lucet-idl/src/rust/mod.rs @@ -5,11 +5,13 @@ use crate::backend::BackendConfig; use crate::cache::Cache; use crate::errors::IDLError; use crate::generator::{Generator, Hierarchy}; -use crate::module::{DataTypeEntry, DataTypeRef, DataType, Module}; +use crate::module::{DataType, DataTypeEntry, DataTypeId, DataTypeRef, Module}; use crate::pretty_writer::PrettyWriter; use crate::target::Target; +use crate::types::AtomType; +use heck::{CamelCase, SnakeCase}; +use std::collections::HashMap; use std::io::Write; -use heck::CamelCase; #[derive(Clone, Debug)] struct CTypeInfo<'t> { @@ -19,8 +21,6 @@ struct CTypeInfo<'t> { type_align: usize, /// The native type size type_size: usize, - /// How many pointer indirections are required to get to the atomic type - indirections: usize, /// The leaf type node leaf_data_type_ref: &'t DataTypeRef, } @@ -29,6 +29,46 @@ struct CTypeInfo<'t> { pub struct RustGenerator { pub target: Target, pub backend_config: BackendConfig, + pub defined: HashMap, +} + +impl RustGenerator { + pub fn new(target: Target, backend_config: BackendConfig) -> Self { + Self { + target, + backend_config, + defined: HashMap::new(), + } + } + + fn define_name(&mut self, data_type_entry: &DataTypeEntry) -> String { + let typename = data_type_entry.name.name.to_camel_case(); + self.defined.insert(data_type_entry.id, typename.clone()); + typename + } + + fn get_defined_name(&self, data_type_ref: &DataTypeRef) -> &str { + match data_type_ref { + DataTypeRef::Defined(id) => self.defined.get(id).expect("definition exists"), + DataTypeRef::Atom(a) => Self::atom_name(a), + } + } + + fn atom_name(atom_type: &AtomType) -> &'static str { + use AtomType::*; + match atom_type { + U8 => "u8", + U16 => "u16", + U32 => "u32", + U64 => "u64", + I8 => "i32", + I16 => "i16", + I32 => "i32", + I64 => "i64", + F32 => "f32", + F64 => "f64", + } + } } impl Generator for RustGenerator { @@ -43,11 +83,9 @@ impl Generator for RustGenerator { pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { - pretty_writer - .eob()? - .write_line( - format!("/// {}: {:?}", data_type_entry.name.name, data_type_entry).as_bytes(), - )?; + pretty_writer.eob()?.write_line( + format!("/// {}: {:?}", data_type_entry.name.name, data_type_entry).as_bytes(), + )?; Ok(()) } @@ -60,15 +98,18 @@ impl Generator for RustGenerator { pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { - let (pointee, _attrs) = if let DataType::Alias { to: pointee, attrs } = &data_type_entry.data_type { - (pointee, attrs) - } else { - unreachable!() - }; + let (pointee, _attrs) = + if let DataType::Alias { to: pointee, attrs } = &data_type_entry.data_type { + (pointee, attrs) + } else { + unreachable!() + }; + + let typename = self.define_name(data_type_entry); + let pointee_name = self.get_defined_name(pointee); + pretty_writer - .write_line( - format!("type {} = {:?};", data_type_entry.name.name.to_camel_case(), pointee).as_bytes(), - )? + .write_line(format!("type {} = {};", typename, pointee_name).as_bytes())? .eob()?; Ok(()) } @@ -80,17 +121,35 @@ impl Generator for RustGenerator { pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { + let (named_members, _attrs) = if let DataType::Struct { + members: named_members, + attrs, + } = &data_type_entry.data_type + { + (named_members, attrs) + } else { + unreachable!() + }; + + let typename = data_type_entry.name.name.to_camel_case(); + self.defined.insert(data_type_entry.id, typename.clone()); + pretty_writer - .write_line( - "#[repr(C)]".as_bytes() - )? - .write_line( - format!("struct {} {{", data_type_entry.name.name.to_camel_case()).as_bytes(), - )? - .write_line( - "}".as_bytes(), - )? - .eob()?; + .write_line("#[repr(C)]".as_bytes())? + .write_line(format!("struct {} {{", typename).as_bytes())?; + + for m in named_members { + pretty_writer.write_line( + format!( + " {}: {},", + m.name.to_snake_case(), + self.get_defined_name(&m.type_) + ) + .as_bytes(), + )?; + } + + pretty_writer.write_line("}".as_bytes())?.eob()?; Ok(()) } @@ -113,27 +172,19 @@ impl Generator for RustGenerator { unreachable!() }; + let typename = data_type_entry.name.name.to_camel_case(); + self.defined.insert(data_type_entry.id, typename.clone()); pretty_writer - .write_line( - "#[repr(C)]".as_bytes() - )? - .write_line( - "#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]".as_bytes() - )? - .write_line( - format!("enum {} {{", data_type_entry.name.name.to_camel_case()).as_bytes(), - )?; + .write_line("#[repr(C)]".as_bytes())? + .write_line("#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]".as_bytes())? + .write_line(format!("enum {} {{", typename).as_bytes())?; for m in named_members { pretty_writer.write_line(format!(" {},", m.name.to_camel_case()).as_bytes())?; } - pretty_writer - .write_line( - "}".as_bytes(), - )? - .eob()?; + pretty_writer.write_line("}".as_bytes())?.eob()?; Ok(()) } diff --git a/lucet-idl/tests/example.idl b/lucet-idl/tests/example.idl index a0abdb075..3a52d0fa2 100644 --- a/lucet-idl/tests/example.idl +++ b/lucet-idl/tests/example.idl @@ -17,8 +17,7 @@ type col = colour struct st { a: i8, - b: **i32, + b: i32, c: color, - self: *st } diff --git a/lucet-idl/tests/example.rs b/lucet-idl/tests/example.rs index 1e395b2c3..a5de8dbe9 100644 --- a/lucet-idl/tests/example.rs +++ b/lucet-idl/tests/example.rs @@ -5,7 +5,7 @@ use std::process::Command; use tempfile::TempDir; #[test] -fn compile_and_run() { +fn compile_and_run_c() { let mut source = String::new(); File::open("tests/example.idl") .expect("open example.idl") @@ -43,3 +43,44 @@ fn compile_and_run() { .expect("run generated code"); assert!(cmd_run.success(), "failure to run generated code"); } + +#[test] +fn compile_and_run_rust() { + let mut source = String::new(); + File::open("tests/example.idl") + .expect("open example.idl") + .read_to_string(&mut source) + .expect("read example.idl"); + + let config = lucet_idl::Config { + backend: lucet_idl::Backend::Rust, + backend_config: lucet_idl::BackendConfig::default(), + target: lucet_idl::Target::Generic, + }; + + let tempdir = TempDir::new().expect("create tempdir"); + + let gen_file = tempdir.path().join("out.rs"); + + lucet_idl::run( + &config, + &source, + File::create(gen_file.clone()).expect("create file"), + ) + .expect("run lucet_idl"); + + let cmd_rustc = Command::new("rustc") + .arg(gen_file.clone()) + .arg("--test") + .arg("--allow=dead_code") + .arg("-o") + .arg(tempdir.path().join("example")) + .status() + .expect("run rustcc"); + assert!(cmd_rustc.success(), "failure to compile generated code"); + + let cmd_run = Command::new(tempdir.path().join("example")) + .status() + .expect("run generated code"); + assert!(cmd_run.success(), "failure to run generated code"); +} diff --git a/lucet-idl/tests/example_driver.c b/lucet-idl/tests/example_driver.c index 02da1d00c..36376ff63 100644 --- a/lucet-idl/tests/example_driver.c +++ b/lucet-idl/tests/example_driver.c @@ -8,12 +8,10 @@ int main (int argc, char *argv[]) { colour c2 = COLOR_BLUE; col c3 = COLOR_GREEN; - int32_t* b = malloc(sizeof(int32_t)); struct st s = { .a = 0, - .b = &b, + .b = 123, .c = COLOR_RED, - .self = &s, }; return 0; From 10af48573cbd2be132cb50872305c3728c24e9c0 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 1 May 2019 17:16:47 -0700 Subject: [PATCH 182/512] lucet-idl: make keywords accepted as regular idents, start adding modules --- lucet-idl/src/lexer.rs | 25 ++++++-------- lucet-idl/src/module.rs | 3 ++ lucet-idl/src/parser.rs | 74 +++++++++++++++++++++++++++++++++++------ 3 files changed, 77 insertions(+), 25 deletions(-) diff --git a/lucet-idl/src/lexer.rs b/lucet-idl/src/lexer.rs index 925c6c001..7146b4b12 100644 --- a/lucet-idl/src/lexer.rs +++ b/lucet-idl/src/lexer.rs @@ -15,19 +15,12 @@ pub enum Token<'a> { Comma, // , Hash, // # Equals, // = - Keyword(Keyword), + Keyword(&'a str), Atom(AtomType), Word(&'a str), Quote(&'a str), // Found between balanced "". No escaping. } -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum Keyword { - Struct, // 'struct' - Enum, // 'enum' - Type, // 'type' -} - #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct LocatedToken<'a> { pub token: Token<'a>, @@ -143,9 +136,10 @@ impl<'a> Lexer<'a> { let text = &self.source[begin..self.pos]; token( match text { - "struct" => Token::Keyword(Keyword::Struct), - "enum" => Token::Keyword(Keyword::Enum), - "type" => Token::Keyword(Keyword::Type), + "struct" => Token::Keyword(text), + "enum" => Token::Keyword(text), + "type" => Token::Keyword(text), + "mod" => Token::Keyword(text), "i8" => Token::Atom(AtomType::I8), "i16" => Token::Atom(AtomType::I16), "i32" => Token::Atom(AtomType::I32), @@ -292,10 +286,11 @@ mod tests { #[test] fn keywords() { - let mut lex = Lexer::new("struct\n\nenum type"); - assert_eq!(lex.next(), token(Token::Keyword(Keyword::Struct), 1, 0)); - assert_eq!(lex.next(), token(Token::Keyword(Keyword::Enum), 3, 0)); - assert_eq!(lex.next(), token(Token::Keyword(Keyword::Type), 3, 5)); + let mut lex = Lexer::new("struct\n\nenum type mod"); + assert_eq!(lex.next(), token(Token::Keyword("struct"), 1, 0)); + assert_eq!(lex.next(), token(Token::Keyword("enum"), 3, 0)); + assert_eq!(lex.next(), token(Token::Keyword("type"), 3, 5)); + assert_eq!(lex.next(), token(Token::Keyword("mod"), 3, 10)); assert_eq!(lex.next(), None); } diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index 897b6bbb6..c39e0bd92 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -275,6 +275,9 @@ impl Module { }, ); } + SyntaxDecl::Module { .. } => { + unreachable!() + } } Ok(()) } diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index c65b49926..cf1420afd 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -1,4 +1,4 @@ -use super::lexer::{Keyword, LexError, Lexer, LocatedError, LocatedToken, Token}; +use super::lexer::{LexError, Lexer, LocatedError, LocatedToken, Token}; use super::types::{AtomType, Attr, Location}; use std::error::Error; use std::fmt; @@ -23,6 +23,12 @@ pub enum SyntaxDecl { attrs: Vec, location: Location, }, + Module { + name: String, + decls: Vec>, + attrs: Vec, + location: Location, + } } impl SyntaxDecl { @@ -31,6 +37,7 @@ impl SyntaxDecl { SyntaxDecl::Struct { name, .. } => &name, SyntaxDecl::Enum { name, .. } => &name, SyntaxDecl::Alias { name, .. } => &name, + SyntaxDecl::Module { name, .. } => &name, } } pub fn location(&self) -> &Location { @@ -38,6 +45,7 @@ impl SyntaxDecl { SyntaxDecl::Struct { location, .. } => &location, SyntaxDecl::Enum { location, .. } => &location, SyntaxDecl::Alias { location, .. } => &location, + SyntaxDecl::Module { location, .. } => &location, } } } @@ -167,7 +175,7 @@ impl<'a> Parser<'a> { fn match_a_word(&mut self, err_msg: &str) -> Result<&'a str, ParseError> { match self.token() { - Some(Token::Word(text)) => { + Some(Token::Word(text)) | Some(Token::Keyword(text)) => { self.consume(); Ok(text) } @@ -203,7 +211,7 @@ impl<'a> Parser<'a> { self.consume(); attrs.push(self.match_attr_body()?); } - Some(Token::Word(member_name)) => { + Some(Token::Word(member_name)) | Some(Token::Keyword(member_name)) => { let location = self.location; self.consume(); self.match_token(Token::Colon, "expected :")?; @@ -224,10 +232,10 @@ impl<'a> Parser<'a> { self.consume(); break; } - _ => parse_err!(self.location, "in struct body:\nexpected , or }}")?, + _ => parse_err!(self.location, "in struct body:\nexpected , or '}'")?, } } - _ => parse_err!(self.location, "in struct body:\nexpected member name or }}")?, + _ => parse_err!(self.location, "in struct body:\nexpected member name or '}'")?, } } Ok(members) @@ -277,7 +285,7 @@ impl<'a> Parser<'a> { let mut attrs = Vec::new(); loop { match self.token() { - Some(Token::Keyword(Keyword::Struct)) => { + Some(Token::Keyword("struct")) => { let location = self.location; self.consume(); let name = err_ctx!(err_msg, self.match_a_word("expected struct name"))?; @@ -290,7 +298,7 @@ impl<'a> Parser<'a> { location, })); } - Some(Token::Keyword(Keyword::Enum)) => { + Some(Token::Keyword("enum")) => { let location = self.location; self.consume(); let name = err_ctx!(err_msg, self.match_a_word("expected enum name"))?; @@ -303,7 +311,7 @@ impl<'a> Parser<'a> { location, })); } - Some(Token::Keyword(Keyword::Type)) => { + Some(Token::Keyword("type")) => { let location = self.location; self.consume(); let name = err_ctx!(err_msg, self.match_a_word("expected type name"))?; @@ -346,11 +354,11 @@ impl<'a> Parser<'a> { self.consume(); Ok(SyntaxRef::Atom { atom, location }) } - Some(Token::Word(name)) => { + Some(Token::Word(name)) | Some(Token::Keyword(name)) => { let location = self.location; self.consume(); Ok(SyntaxRef::Name { - name: name.to_owned(), + name: name.to_string(), location, }) } @@ -579,6 +587,52 @@ mod tests { ); } + #[test] + fn struct_reserved_members() { + let mut parser = Parser::new("struct foo {a: mod, struct: enum }"); + // column ruler: 0 7 12 15 21 30 + assert_eq!( + parser + .match_decl("foo a i32") + .expect("valid parse") + .expect("valid decl"), + SyntaxDecl::Struct { + name: "foo".to_string(), + members: vec![StructMember { + name: "a".to_owned(), + type_: SyntaxRef::Name { + name: "mod".to_owned(), + location: Location { + line: 1, + column: 15, + }, + }, + attrs: Vec::new(), + location: Location { + line: 1, + column: 12, + }, + }, + StructMember { + name: "struct".to_owned(), + type_: SyntaxRef::Name { + name: "enum".to_owned(), + location: Location { + line: 1, + column: 28, + }, + }, + attrs: Vec::new(), + location: Location { + line: 1, + column: 20, + }, + }], + attrs: Vec::new(), + location: Location { line: 1, column: 0 }, + } + ); + } #[test] fn enums() { let mut parser = Parser::new("enum foo {}"); From 1f8a6cf317f025ebe47dd33c0beba3e711396e8f Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 2 May 2019 11:20:16 -0700 Subject: [PATCH 183/512] lucet-idl: parser supports modules --- lucet-idl/src/parser.rs | 183 ++++++++++++++++++++++++++++++++++------ 1 file changed, 156 insertions(+), 27 deletions(-) diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index cf1420afd..80bb8fdf1 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -28,7 +28,7 @@ pub enum SyntaxDecl { decls: Vec>, attrs: Vec, location: Location, - } + }, } impl SyntaxDecl { @@ -235,7 +235,10 @@ impl<'a> Parser<'a> { _ => parse_err!(self.location, "in struct body:\nexpected , or '}'")?, } } - _ => parse_err!(self.location, "in struct body:\nexpected member name or '}'")?, + _ => parse_err!( + self.location, + "in struct body:\nexpected member name or '}'" + )?, } } Ok(members) @@ -324,6 +327,33 @@ impl<'a> Parser<'a> { location, })); } + Some(Token::Keyword("mod")) => { + let location = self.location; + self.consume(); + let name = err_ctx!(err_msg, self.match_a_word("expected module name"))?; + err_ctx!(err_msg, self.match_token(Token::LBrace, "expected {"))?; + + let mut decls = Vec::new(); + loop { + if let Some(Token::RBrace) = self.token() { + self.consume(); + break; + } else { + match self.match_decl("declaration") { + Ok(Some(decl)) => decls.push(Box::new(decl)), + Ok(None) => parse_err!(self.location, "missing close brace '}'")?, + Err(e) => Err(e)?, + } + } + } + + return Ok(Some(SyntaxDecl::Module { + name: name.to_owned(), + decls, + attrs, + location, + })); + } Some(Token::Hash) => { self.consume(); attrs.push(self.match_attr_body()?); @@ -498,7 +528,6 @@ mod tests { location: Location { line: 1, column: 0 }, } ); - } #[test] fn struct_empty_one_attribute() { @@ -598,43 +627,45 @@ mod tests { .expect("valid decl"), SyntaxDecl::Struct { name: "foo".to_string(), - members: vec![StructMember { - name: "a".to_owned(), - type_: SyntaxRef::Name { - name: "mod".to_owned(), + members: vec![ + StructMember { + name: "a".to_owned(), + type_: SyntaxRef::Name { + name: "mod".to_owned(), + location: Location { + line: 1, + column: 15, + }, + }, + attrs: Vec::new(), location: Location { line: 1, - column: 15, + column: 12, }, }, - attrs: Vec::new(), - location: Location { - line: 1, - column: 12, - }, - }, - StructMember { - name: "struct".to_owned(), - type_: SyntaxRef::Name { - name: "enum".to_owned(), + StructMember { + name: "struct".to_owned(), + type_: SyntaxRef::Name { + name: "enum".to_owned(), + location: Location { + line: 1, + column: 28, + }, + }, + attrs: Vec::new(), location: Location { line: 1, - column: 28, + column: 20, }, - }, - attrs: Vec::new(), - location: Location { - line: 1, - column: 20, - }, - }], + } + ], attrs: Vec::new(), location: Location { line: 1, column: 0 }, } ); } #[test] - fn enums() { + fn enum_empty() { let mut parser = Parser::new("enum foo {}"); // 0 5 assert_eq!( @@ -649,6 +680,9 @@ mod tests { location: Location { line: 1, column: 0 }, }, ); + } + #[test] + fn enum_one_entry_trailing_comma() { let mut parser = Parser::new("enum foo {first,}"); // 0 5 10 assert_eq!( @@ -670,6 +704,9 @@ mod tests { location: Location { line: 1, column: 0 }, }, ); + } + #[test] + fn enum_one_entry() { let mut parser = Parser::new("enum bar {first}"); // 0 5 10 assert_eq!( @@ -691,6 +728,9 @@ mod tests { location: Location { line: 1, column: 0 }, }, ); + } + #[test] + fn enum_four_entry() { let mut parser = Parser::new("enum baz { one, two, three\n, four, }"); // 0 5 11 16 21 0 2 assert_eq!( @@ -736,4 +776,93 @@ mod tests { }, ); } + + #[test] + fn mod_empty() { + let mut parser = Parser::new("mod empty {}"); + // 0 5 10 + assert_eq!( + parser + .match_decl("empty module") + .expect("valid parse") + .expect("valid decl"), + SyntaxDecl::Module { + name: "empty".to_owned(), + decls: Vec::new(), + attrs: Vec::new(), + location: Location { line: 1, column: 0 }, + } + ); + } + + #[test] + fn mod_nesting() { + let mut parser = Parser::new("mod one { mod two { mod three { } } }"); + // 0 5 10 15 20 + assert_eq!( + parser + .match_decl("nested modules") + .expect("valid parse") + .expect("valid decl"), + SyntaxDecl::Module { + name: "one".to_owned(), + decls: vec![Box::new(SyntaxDecl::Module { + name: "two".to_owned(), + decls: vec![Box::new(SyntaxDecl::Module { + name: "three".to_owned(), + decls: Vec::new(), + attrs: Vec::new(), + location: Location { + line: 1, + column: 20 + }, + })], + attrs: Vec::new(), + location: Location { + line: 1, + column: 10 + }, + })], + attrs: Vec::new(), + location: Location { line: 1, column: 0 }, + } + ); + } + + #[test] + fn mod_types() { + let mut parser = Parser::new("mod one { enum foo {} struct bar {} }"); + // 0 5 10 15 20 + assert_eq!( + parser + .match_decl("module with types") + .expect("valid parse") + .expect("valid decl"), + SyntaxDecl::Module { + name: "one".to_owned(), + decls: vec![ + Box::new(SyntaxDecl::Enum { + name: "foo".to_owned(), + variants: Vec::new(), + attrs: Vec::new(), + location: Location { + line: 1, + column: 10 + }, + }), + Box::new(SyntaxDecl::Struct { + name: "bar".to_owned(), + members: Vec::new(), + attrs: Vec::new(), + location: Location { + line: 1, + column: 22 + }, + }) + ], + attrs: Vec::new(), + location: Location { line: 1, column: 0 }, + } + ); + } } From c38e27d36dc7a58d5c91d25776fb2e2f9f6e35f6 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 2 May 2019 11:38:09 -0700 Subject: [PATCH 184/512] lucet-idl: rename top level set of defs to package --- lucet-idl/src/c/alias.rs | 6 +-- lucet-idl/src/c/enum.rs | 2 +- lucet-idl/src/c/macros.rs | 4 +- lucet-idl/src/c/mod.rs | 51 ++++++++++---------- lucet-idl/src/c/struct.rs | 4 +- lucet-idl/src/cache.rs | 2 +- lucet-idl/src/errors.rs | 8 ++-- lucet-idl/src/generator.rs | 40 ++++++++-------- lucet-idl/src/lib.rs | 10 ++-- lucet-idl/src/{module.rs => package.rs} | 62 ++++++++++++------------- lucet-idl/src/rust/mod.rs | 16 +++---- 11 files changed, 104 insertions(+), 101 deletions(-) rename lucet-idl/src/{module.rs => package.rs} (89%) diff --git a/lucet-idl/src/c/alias.rs b/lucet-idl/src/c/alias.rs index 486de2317..10c79c98c 100644 --- a/lucet-idl/src/c/alias.rs +++ b/lucet-idl/src/c/alias.rs @@ -4,7 +4,7 @@ use super::*; // and alignment rules of what it ultimately points to pub fn generate( cgenerator: &mut CGenerator, - module: &Module, + package: &Package, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -14,13 +14,13 @@ pub fn generate( } else { unreachable!() }; - let type_info = cgenerator.type_info(module, cache, type_); + let type_info = cgenerator.type_info(package, cache, type_); pretty_writer.indent()?; pretty_writer.write(format!("typedef {}", type_info.type_name).as_bytes())?; pretty_writer.space()?; pretty_writer.write(data_type_entry.name.name.as_bytes())?; pretty_writer.write(b";")?; - let leaf_type_info = cgenerator.type_info(module, cache, type_info.leaf_data_type_ref); + let leaf_type_info = cgenerator.type_info(package, cache, type_info.leaf_data_type_ref); if leaf_type_info.type_name != type_info.type_name { pretty_writer.write(b" // equivalent to ")?; pretty_writer.write(leaf_type_info.type_name.as_bytes())?; diff --git a/lucet-idl/src/c/enum.rs b/lucet-idl/src/c/enum.rs index 7fc78fd9c..0425d90d5 100644 --- a/lucet-idl/src/c/enum.rs +++ b/lucet-idl/src/c/enum.rs @@ -4,7 +4,7 @@ use super::*; // The typedef is required to use a native type which is consistent across all architectures pub fn generate( cgenerator: &mut CGenerator, - _module: &Module, + _package: &Package, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, diff --git a/lucet-idl/src/c/macros.rs b/lucet-idl/src/c/macros.rs index 74ec5c0d0..67a8168ac 100644 --- a/lucet-idl/src/c/macros.rs +++ b/lucet-idl/src/c/macros.rs @@ -39,7 +39,7 @@ pub fn define( // Return a macro name for a type reference pub fn macro_for_data_type_ref( - module: &Module, + package: &Package, prefix: &str, data_type_ref: &DataTypeRef, ) -> String { @@ -49,7 +49,7 @@ pub fn macro_for_data_type_ref( format!("{}", native_type_size) } DataTypeRef::Defined(data_type_id) => { - let data_type_entry = module.get_datatype(*data_type_id); + let data_type_entry = package.get_datatype(*data_type_id); macro_for(prefix, &data_type_entry.name.name) } } diff --git a/lucet-idl/src/c/mod.rs b/lucet-idl/src/c/mod.rs index 995e32d86..879722fd3 100644 --- a/lucet-idl/src/c/mod.rs +++ b/lucet-idl/src/c/mod.rs @@ -14,8 +14,7 @@ use crate::backend::*; use crate::cache::*; use crate::errors::*; use crate::generator::{Generator, Hierarchy}; -use crate::module::*; -use crate::module::{DataTypeEntry, DataTypeRef, Module}; +use crate::package::{DataType, DataTypeEntry, DataTypeRef, Package}; use crate::pretty_writer::*; use crate::target::*; use std::io::prelude::*; @@ -50,7 +49,7 @@ impl Generator for CGenerator { fn gen_type_header( &mut self, - _module: &Module, + _package: &Package, _cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -68,39 +67,39 @@ impl Generator for CGenerator { // and alignment rules of what it ultimately points to fn gen_alias( &mut self, - module: &Module, + package: &Package, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { - alias::generate(self, module, cache, pretty_writer, data_type_entry) + alias::generate(self, package, cache, pretty_writer, data_type_entry) } fn gen_struct( &mut self, - module: &Module, + package: &Package, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { - r#struct::generate(self, module, cache, pretty_writer, data_type_entry) + r#struct::generate(self, package, cache, pretty_writer, data_type_entry) } // Enums generate both a specific typedef, and a traditional C-style enum // The typedef is required to use a native type which is consistent across all architectures fn gen_enum( &mut self, - module: &Module, + package: &Package, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { - r#enum::generate(self, module, cache, pretty_writer, data_type_entry) + r#enum::generate(self, package, cache, pretty_writer, data_type_entry) } fn gen_accessors_struct( &mut self, - module: &Module, + package: &Package, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -121,7 +120,7 @@ impl Generator for CGenerator { fn gen_accessors_enum( &mut self, - module: &Module, + package: &Package, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -130,7 +129,7 @@ impl Generator for CGenerator { /* accessors::r#enum::generate( self, - module, + package, cache, pretty_writer, data_type_entry, @@ -142,7 +141,7 @@ impl Generator for CGenerator { fn gen_accessors_alias( &mut self, - module: &Module, + package: &Package, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -168,7 +167,7 @@ impl CGenerator { /// for this data type fn type_info<'t>( &self, - module: &'t Module, + package: &'t Package, cache: &Cache, mut type_: &'t DataTypeRef, ) -> CTypeInfo<'t> { @@ -184,10 +183,10 @@ impl CGenerator { type_name.or_else(|| Some(native_atom.native_type_name.to_string())); } DataTypeRef::Defined(data_type_id) => { - let cached = cache.load_type(*data_type_id).unwrap(); - type_align = type_align.or_else(|| Some(cached.type_align)); - type_size = type_size.or_else(|| Some(cached.type_size)); - let data_type_entry = module.get_datatype(*data_type_id); + let cached = cache.load_type(*data_type_id).unwrap(); + type_align = type_align.or_else(|| Some(cached.type_align)); + type_size = type_size.or_else(|| Some(cached.type_size)); + let data_type_entry = package.get_datatype(*data_type_id); match data_type_entry.data_type { DataType::Struct { .. } => { type_name = type_name @@ -221,30 +220,34 @@ impl CGenerator { } // Return `true` if the type is an atom, an emum, or an alias to one of these - pub fn is_type_eventually_an_atom_or_enum(&self, module: &Module, type_: &DataTypeRef) -> bool { + pub fn is_type_eventually_an_atom_or_enum( + &self, + package: &Package, + type_: &DataTypeRef, + ) -> bool { let inner_type = match type_ { DataTypeRef::Atom(_) => return true, DataTypeRef::Defined(inner_type) => inner_type, }; - let inner_data_type_entry = module.get_datatype(*inner_type); + let inner_data_type_entry = package.get_datatype(*inner_type); let inner_data_type = inner_data_type_entry.data_type; match inner_data_type { DataType::Struct { .. } => false, DataType::Enum { .. } => true, - DataType::Alias { to, .. } => self.is_type_eventually_an_atom_or_enum(module, to), + DataType::Alias { to, .. } => self.is_type_eventually_an_atom_or_enum(package, to), } } /// Return the type refererence, with aliases being resolved - pub fn unalias<'t>(&self, module: &'t Module, type_: &'t DataTypeRef) -> &'t DataTypeRef { + pub fn unalias<'t>(&self, package: &'t Package, type_: &'t DataTypeRef) -> &'t DataTypeRef { let inner_type = match type_ { DataTypeRef::Atom(_) => return type_, DataTypeRef::Defined(inner_type) => inner_type, }; - let inner_data_type_entry = module.get_datatype(*inner_type); + let inner_data_type_entry = package.get_datatype(*inner_type); let inner_data_type = inner_data_type_entry.data_type; if let DataType::Alias { to, .. } = inner_data_type { - self.unalias(module, to) + self.unalias(package, to) } else { type_ } diff --git a/lucet-idl/src/c/struct.rs b/lucet-idl/src/c/struct.rs index 01cd25348..820780d4b 100644 --- a/lucet-idl/src/c/struct.rs +++ b/lucet-idl/src/c/struct.rs @@ -3,7 +3,7 @@ use std::cmp; pub fn generate( cgenerator: &mut CGenerator, - module: &Module, + package: &Package, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -23,7 +23,7 @@ pub fn generate( let mut first_member_align = 0; let mut members_offsets = vec![]; for named_member in named_members { - let type_info = cgenerator.type_info(module, cache, &named_member.type_); + let type_info = cgenerator.type_info(package, cache, &named_member.type_); let type_align = type_info.type_align; let type_size = type_info.type_size; let padding = (type_align - 1) - ((offset + (type_align - 1)) % type_align); diff --git a/lucet-idl/src/cache.rs b/lucet-idl/src/cache.rs index 438c1daf5..ef50acb25 100644 --- a/lucet-idl/src/cache.rs +++ b/lucet-idl/src/cache.rs @@ -1,4 +1,4 @@ -use crate::module::DataTypeId; +use crate::package::DataTypeId; use std::collections::HashMap; /// Cached information for a given structure member diff --git a/lucet-idl/src/errors.rs b/lucet-idl/src/errors.rs index 0e1b1ac04..a0221a79b 100644 --- a/lucet-idl/src/errors.rs +++ b/lucet-idl/src/errors.rs @@ -1,4 +1,4 @@ -use crate::{module, parser}; +use crate::{package, parser}; use std::io; #[allow(dead_code)] @@ -11,7 +11,7 @@ pub enum IDLError { #[fail(display = "{}", _0)] ParseError(#[cause] parser::ParseError), #[fail(display = "{}", _0)] - ValidationError(#[cause] module::ValidationError), + ValidationError(#[cause] package::ValidationError), #[fail(display = "{}", _0)] Io(#[cause] io::Error), } @@ -28,8 +28,8 @@ impl From for IDLError { } } -impl From for IDLError { - fn from(e: module::ValidationError) -> Self { +impl From for IDLError { + fn from(e: package::ValidationError) -> Self { IDLError::ValidationError(e) } } diff --git a/lucet-idl/src/generator.rs b/lucet-idl/src/generator.rs index ccc192546..51201c59c 100644 --- a/lucet-idl/src/generator.rs +++ b/lucet-idl/src/generator.rs @@ -1,6 +1,6 @@ use crate::cache::Cache; use crate::errors::IDLError; -use crate::module::{DataType, DataTypeEntry, DataTypeId, Module}; +use crate::package::{DataType, DataTypeEntry, DataTypeId, Package}; use crate::pretty_writer::PrettyWriter; use std::io::Write; use std::rc::Rc; @@ -10,7 +10,7 @@ pub trait Generator { fn gen_type_header( &mut self, - module: &Module, + package: &Package, _cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -18,7 +18,7 @@ pub trait Generator { fn gen_alias( &mut self, - module: &Module, + package: &Package, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -26,7 +26,7 @@ pub trait Generator { fn gen_struct( &mut self, - module: &Module, + package: &Package, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -34,7 +34,7 @@ pub trait Generator { fn gen_enum( &mut self, - module: &Module, + package: &Package, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -42,7 +42,7 @@ pub trait Generator { fn gen_accessors_struct( &mut self, - module: &Module, + package: &Package, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -51,7 +51,7 @@ pub trait Generator { fn gen_accessors_enum( &mut self, - module: &Module, + package: &Package, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -60,7 +60,7 @@ pub trait Generator { fn gen_accessors_alias( &mut self, - module: &Module, + package: &Package, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -69,24 +69,24 @@ pub trait Generator { fn gen_for_id( &mut self, - module: &Module, + package: &Package, cache: &mut Cache, pretty_writer: &mut PrettyWriter, id: DataTypeId, ) -> Result<(), IDLError> { - let data_type_entry = module.get_datatype(id); - self.gen_type_header(module, cache, pretty_writer, &data_type_entry)?; + let data_type_entry = package.get_datatype(id); + self.gen_type_header(package, cache, pretty_writer, &data_type_entry)?; match &data_type_entry.data_type { DataType::Struct { .. } => { - self.gen_struct(module, cache, pretty_writer, &data_type_entry) + self.gen_struct(package, cache, pretty_writer, &data_type_entry) } DataType::Alias { .. } => { - self.gen_alias(module, cache, pretty_writer, &data_type_entry) + self.gen_alias(package, cache, pretty_writer, &data_type_entry) } - DataType::Enum { .. } => self.gen_enum(module, cache, pretty_writer, &data_type_entry), + DataType::Enum { .. } => self.gen_enum(package, cache, pretty_writer, &data_type_entry), }?; self.gen_accessors_for_id( - module, + package, cache, pretty_writer, id, @@ -99,22 +99,22 @@ pub trait Generator { /// `hierarchy` is used to derive function names from nested types fn gen_accessors_for_id( &mut self, - module: &Module, + package: &Package, cache: &Cache, pretty_writer: &mut PrettyWriter, id: DataTypeId, hierarchy: &Hierarchy, ) -> Result<(), IDLError> { - let data_type_entry = module.get_datatype(id); + let data_type_entry = package.get_datatype(id); match &data_type_entry.data_type { DataType::Struct { .. } => { - self.gen_accessors_struct(module, cache, pretty_writer, &data_type_entry, hierarchy) + self.gen_accessors_struct(package, cache, pretty_writer, &data_type_entry, hierarchy) } DataType::Alias { .. } => { - self.gen_accessors_alias(module, cache, pretty_writer, &data_type_entry, hierarchy) + self.gen_accessors_alias(package, cache, pretty_writer, &data_type_entry, hierarchy) } DataType::Enum { .. } => { - self.gen_accessors_enum(module, cache, pretty_writer, &data_type_entry, hierarchy) + self.gen_accessors_enum(package, cache, pretty_writer, &data_type_entry, hierarchy) } }?; Ok(()) diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 111c54791..6c0035cec 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -10,7 +10,7 @@ mod config; mod errors; mod generator; mod lexer; -mod module; +mod package; mod parser; mod pretty_writer; mod rust; @@ -23,7 +23,7 @@ pub use crate::errors::IDLError; pub use crate::target::Target; use crate::cache::Cache; -use crate::module::Module; +use crate::package::Package; use crate::parser::Parser; use crate::pretty_writer::PrettyWriter; use std::io::Write; @@ -32,8 +32,8 @@ pub fn run(config: &Config, input: &str, output: W) -> Result(config: &Config, input: &str, output: W) -> Result, pub data_types: HashMap, } @@ -123,7 +123,7 @@ impl Error for ValidationError { } } -impl Module { +impl Package { fn new() -> Self { Self { names: Vec::new(), @@ -275,8 +275,8 @@ impl Module { }, ); } - SyntaxDecl::Module { .. } => { - unreachable!() + SyntaxDecl::Module{ .. } => { + unimplemented!() } } Ok(()) @@ -340,7 +340,7 @@ impl Module { }) } - pub fn from_declarations(decls: &[SyntaxDecl]) -> Result { + pub fn from_declarations(decls: &[SyntaxDecl]) -> Result { let mut desc = Self::new(); let mut idents: Vec = Vec::new(); for decl in decls { @@ -375,23 +375,23 @@ mod tests { use super::super::parser::Parser; use super::*; - fn module(syntax: &str) -> Result { + fn pkg(syntax: &str) -> Result { let mut parser = Parser::new(syntax); let decls = parser.match_decls().expect("parses"); - Module::from_declarations(&decls) + Package::from_declarations(&decls) } #[test] fn structs_basic() { - assert!(module("struct foo { a: i32}").is_ok()); - assert!(module("struct foo { a: i32, b: f32 }").is_ok()); + assert!(pkg("struct foo { a: i32}").is_ok()); + assert!(pkg("struct foo { a: i32, b: f32 }").is_ok()); } #[test] fn struct_two_atoms() { { - let d = module("struct foo { a: i32, b: f32 }").unwrap(); + let d = pkg("struct foo { a: i32, b: f32 }").unwrap(); let members = match &d.data_types[&0] { DataType::Struct { members, .. } => members, _ => panic!("Unexpected type"), @@ -413,20 +413,20 @@ mod tests { #[test] fn struct_prev_definition() { // Refer to a struct defined previously: - assert!(module("struct foo { a: i32, b: f64 } struct bar { a: foo }").is_ok()); + assert!(pkg("struct foo { a: i32, b: f64 } struct bar { a: foo }").is_ok()); } #[test] fn struct_next_definition() { // Refer to a struct defined afterwards: - assert!(module("struct foo { a: i32, b: bar} struct bar { a: i32 }").is_ok()); + assert!(pkg("struct foo { a: i32, b: bar} struct bar { a: i32 }").is_ok()); } #[test] fn struct_self_referential() { // Refer to itself - assert!(module("struct list { next: list, thing: i32 }").is_err()); + assert!(pkg("struct list { next: list, thing: i32 }").is_err()); } @@ -434,7 +434,7 @@ mod tests { fn struct_empty() { // No members assert_eq!( - module("struct foo {}").err().unwrap(), + pkg("struct foo {}").err().unwrap(), ValidationError::Empty { name: "foo".to_owned(), location: Location { line: 1, column: 0 }, @@ -447,7 +447,7 @@ mod tests { fn struct_duplicate_member() { // Duplicate member in struct assert_eq!( - module("struct foo { \na: i32, \na: f64}").err().unwrap(), + pkg("struct foo { \na: i32, \na: f64}").err().unwrap(), ValidationError::NameAlreadyExists { name: "a".to_owned(), at_location: Location { line: 3, column: 0 }, @@ -461,7 +461,7 @@ mod tests { fn struct_duplicate_definition() { // Duplicate definition of struct assert_eq!( - module("struct foo { a: i32 }\nstruct foo { a: i32 } ") + pkg("struct foo { a: i32 }\nstruct foo { a: i32 } ") .err() .unwrap(), ValidationError::NameAlreadyExists { @@ -477,7 +477,7 @@ mod tests { fn struct_undeclared_member() { // Refer to type that is not declared assert_eq!( - module("struct foo { \nb: bar }").err().unwrap(), + pkg("struct foo { \nb: bar }").err().unwrap(), ValidationError::NameNotFound { name: "bar".to_owned(), use_location: Location { line: 2, column: 3 }, @@ -487,11 +487,11 @@ mod tests { #[test] fn enums() { - assert!(module("enum foo { a }").is_ok()); - assert!(module("enum foo { a, b }").is_ok()); + assert!(pkg("enum foo { a }").is_ok()); + assert!(pkg("enum foo { a, b }").is_ok()); { - let d = module("enum foo { a, b }").unwrap(); + let d = pkg("enum foo { a, b }").unwrap(); let members = match &d.data_types[&0] { DataType::Enum { members, .. } => members, _ => panic!("Unexpected type"), @@ -502,7 +502,7 @@ mod tests { // No members assert_eq!( - module("enum foo {}").err().unwrap(), + pkg("enum foo {}").err().unwrap(), ValidationError::Empty { name: "foo".to_owned(), location: Location { line: 1, column: 0 }, @@ -511,7 +511,7 @@ mod tests { // Duplicate member in enum assert_eq!( - module("enum foo { \na,\na }").err().unwrap(), + pkg("enum foo { \na,\na }").err().unwrap(), ValidationError::NameAlreadyExists { name: "a".to_owned(), at_location: Location { line: 3, column: 0 }, @@ -521,7 +521,7 @@ mod tests { // Duplicate definition of enum assert_eq!( - module("enum foo { a }\nenum foo { a } ").err().unwrap(), + pkg("enum foo { a }\nenum foo { a } ").err().unwrap(), ValidationError::NameAlreadyExists { name: "foo".to_owned(), at_location: Location { line: 2, column: 0 }, @@ -532,19 +532,19 @@ mod tests { #[test] fn aliases() { - assert!(module("type foo = i32").is_ok()); - assert!(module("type foo = f64").is_ok()); - assert!(module("type foo = u8").is_ok()); + assert!(pkg("type foo = i32").is_ok()); + assert!(pkg("type foo = f64").is_ok()); + assert!(pkg("type foo = u8").is_ok()); - assert!(module("type foo = bar\nenum bar { a }").is_ok()); + assert!(pkg("type foo = bar\nenum bar { a }").is_ok()); - assert!(module("type link = u32\nstruct list { next: link, thing: i32 }").is_ok()); + assert!(pkg("type link = u32\nstruct list { next: link, thing: i32 }").is_ok()); } #[test] fn infinite() { assert_eq!( - module("type foo = bar\ntype bar = foo").err().unwrap(), + pkg("type foo = bar\ntype bar = foo").err().unwrap(), ValidationError::Infinite { name: "foo".to_owned(), location: Location { line: 1, column: 0 }, @@ -552,7 +552,7 @@ mod tests { ); assert_eq!( - module("type foo = bar\nstruct bar { a: foo }") + pkg("type foo = bar\nstruct bar { a: foo }") .err() .unwrap(), ValidationError::Infinite { @@ -562,7 +562,7 @@ mod tests { ); assert_eq!( - module("type foo = bar\nstruct bar { a: baz }\nstruct baz { c: i32, e: foo }") + pkg("type foo = bar\nstruct bar { a: baz }\nstruct baz { c: i32, e: foo }") .err() .unwrap(), ValidationError::Infinite { diff --git a/lucet-idl/src/rust/mod.rs b/lucet-idl/src/rust/mod.rs index 8e12d8507..40a8ed0da 100644 --- a/lucet-idl/src/rust/mod.rs +++ b/lucet-idl/src/rust/mod.rs @@ -5,7 +5,7 @@ use crate::backend::BackendConfig; use crate::cache::Cache; use crate::errors::IDLError; use crate::generator::{Generator, Hierarchy}; -use crate::module::{DataType, DataTypeEntry, DataTypeId, DataTypeRef, Module}; +use crate::package::{DataType, DataTypeEntry, DataTypeId, DataTypeRef, Package}; use crate::pretty_writer::PrettyWriter; use crate::target::Target; use crate::types::AtomType; @@ -78,7 +78,7 @@ impl Generator for RustGenerator { fn gen_type_header( &mut self, - _module: &Module, + _package: &Package, _cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -93,7 +93,7 @@ impl Generator for RustGenerator { // and alignment rules of what it ultimately points to fn gen_alias( &mut self, - module: &Module, + package: &Package, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -116,7 +116,7 @@ impl Generator for RustGenerator { fn gen_struct( &mut self, - module: &Module, + package: &Package, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -157,7 +157,7 @@ impl Generator for RustGenerator { // The typedef is required to use a native type which is consistent across all architectures fn gen_enum( &mut self, - module: &Module, + package: &Package, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -190,7 +190,7 @@ impl Generator for RustGenerator { fn gen_accessors_struct( &mut self, - _module: &Module, + _package: &Package, _cache: &Cache, _pretty_writer: &mut PrettyWriter, _data_type_entry: &DataTypeEntry<'_>, @@ -201,7 +201,7 @@ impl Generator for RustGenerator { fn gen_accessors_enum( &mut self, - _module: &Module, + _package: &Package, _cache: &Cache, _pretty_writer: &mut PrettyWriter, _data_type_entry: &DataTypeEntry<'_>, @@ -212,7 +212,7 @@ impl Generator for RustGenerator { fn gen_accessors_alias( &mut self, - _module: &Module, + _package: &Package, _cache: &Cache, _pretty_writer: &mut PrettyWriter, _data_type_entry: &DataTypeEntry<'_>, From 935f13e8e19a128553e272e64b236815ca64c576 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 3 May 2019 16:45:29 -0700 Subject: [PATCH 185/512] lucet-idl: add functions to syntax also get rid of keywords since theyre fake --- lucet-idl/src/lexer.rs | 26 +- lucet-idl/src/package.rs | 3 + lucet-idl/src/parser.rs | 586 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 588 insertions(+), 27 deletions(-) diff --git a/lucet-idl/src/lexer.rs b/lucet-idl/src/lexer.rs index 7146b4b12..421c40dda 100644 --- a/lucet-idl/src/lexer.rs +++ b/lucet-idl/src/lexer.rs @@ -15,7 +15,7 @@ pub enum Token<'a> { Comma, // , Hash, // # Equals, // = - Keyword(&'a str), + Arrow, // -> Atom(AtomType), Word(&'a str), Quote(&'a str), // Found between balanced "". No escaping. @@ -136,10 +136,6 @@ impl<'a> Lexer<'a> { let text = &self.source[begin..self.pos]; token( match text { - "struct" => Token::Keyword(text), - "enum" => Token::Keyword(text), - "type" => Token::Keyword(text), - "mod" => Token::Keyword(text), "i8" => Token::Atom(AtomType::I8), "i16" => Token::Atom(AtomType::I16), "i32" => Token::Atom(AtomType::I32), @@ -218,6 +214,16 @@ impl<'a> Lexer<'a> { ',' => self.scan_char(Token::Comma), '#' => self.scan_char(Token::Hash), '=' => self.scan_char(Token::Equals), + '-' => { + if self.looking_at("->") { + self.next_ch(); // Consume - + self.next_ch(); // Consume > + token(Token::Arrow, loc) + } else { + self.next_ch(); + error(LexError::InvalidChar('/'), loc) + } + } '/' => { if self.looking_at("//") { self.rest_of_line(); @@ -284,16 +290,6 @@ mod tests { assert_eq!(lex.next(), None); } - #[test] - fn keywords() { - let mut lex = Lexer::new("struct\n\nenum type mod"); - assert_eq!(lex.next(), token(Token::Keyword("struct"), 1, 0)); - assert_eq!(lex.next(), token(Token::Keyword("enum"), 3, 0)); - assert_eq!(lex.next(), token(Token::Keyword("type"), 3, 5)); - assert_eq!(lex.next(), token(Token::Keyword("mod"), 3, 10)); - assert_eq!(lex.next(), None); - } - #[test] fn comments() { let mut lex = Lexer::new("the quick // brown fox\njumped\n//over the three\nlazy//dogs"); diff --git a/lucet-idl/src/package.rs b/lucet-idl/src/package.rs index 5e6c1b7d1..b2533747a 100644 --- a/lucet-idl/src/package.rs +++ b/lucet-idl/src/package.rs @@ -278,6 +278,9 @@ impl Package { SyntaxDecl::Module{ .. } => { unimplemented!() } + SyntaxDecl::Function{ .. } => { + unimplemented!() + } } Ok(()) } diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index 80bb8fdf1..5e698e183 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -29,6 +29,13 @@ pub enum SyntaxDecl { attrs: Vec, location: Location, }, + Function { + name: String, + args: Vec, + rets: Vec, + attrs: Vec, + location: Location, + }, } impl SyntaxDecl { @@ -38,6 +45,7 @@ impl SyntaxDecl { SyntaxDecl::Enum { name, .. } => &name, SyntaxDecl::Alias { name, .. } => &name, SyntaxDecl::Module { name, .. } => &name, + SyntaxDecl::Function { name, .. } => &name, } } pub fn location(&self) -> &Location { @@ -46,6 +54,7 @@ impl SyntaxDecl { SyntaxDecl::Enum { location, .. } => &location, SyntaxDecl::Alias { location, .. } => &location, SyntaxDecl::Module { location, .. } => &location, + SyntaxDecl::Function { location, .. } => &location, } } } @@ -65,16 +74,23 @@ pub struct StructMember { } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct UnionVariant { +pub struct EnumVariant { pub name: String, - pub type_: Option, pub attrs: Vec, pub location: Location, } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct EnumVariant { +pub struct FuncArg { pub name: String, + pub type_: SyntaxRef, + pub attrs: Vec, + pub location: Location, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct FuncRet { + pub type_: SyntaxRef, pub attrs: Vec, pub location: Location, } @@ -175,7 +191,7 @@ impl<'a> Parser<'a> { fn match_a_word(&mut self, err_msg: &str) -> Result<&'a str, ParseError> { match self.token() { - Some(Token::Word(text)) | Some(Token::Keyword(text)) => { + Some(Token::Word(text)) => { self.consume(); Ok(text) } @@ -211,7 +227,7 @@ impl<'a> Parser<'a> { self.consume(); attrs.push(self.match_attr_body()?); } - Some(Token::Word(member_name)) | Some(Token::Keyword(member_name)) => { + Some(Token::Word(member_name)) => { let location = self.location; self.consume(); self.match_token(Token::Colon, "expected :")?; @@ -281,14 +297,112 @@ impl<'a> Parser<'a> { _ => parse_err!(self.location, "expected variant")?, } } + if !attrs.is_empty() { + parse_err!(self.location, "attributes unattached to an enum variant")? + } Ok(names) } + fn match_func_args(&mut self) -> Result, ParseError> { + let mut args = Vec::new(); + let mut attrs = Vec::new(); + loop { + match self.token() { + Some(Token::RPar) => { + self.consume(); + break; + } + Some(Token::Hash) => { + self.consume(); + attrs.push(self.match_attr_body()?); + } + Some(Token::Word(name)) => { + let location = self.location; + self.consume(); + self.match_token(Token::Colon, "expected :")?; + let type_ref = self.match_ref("expected type")?; + + args.push(FuncArg { + name: name.to_string(), + type_: type_ref, + attrs: attrs.clone(), + location, + }); + attrs.clear(); + match self.token() { + Some(Token::Comma) => { + self.consume(); + continue; + } + Some(Token::RPar) => { + self.consume(); + break; + } + _ => parse_err!(self.location, "expected , or )")?, + } + } + _ => parse_err!(self.location, "expected argument, or )")?, + } + } + if !attrs.is_empty() { + parse_err!( + self.location, + "attributes unattached to a function argument" + )? + } + Ok(args) + } + + fn match_func_rets(&mut self) -> Result, ParseError> { + let mut args = Vec::new(); + let mut attrs = Vec::new(); + loop { + match self.token() { + Some(Token::Semi) => { + self.consume(); + break; + } + Some(Token::Hash) => { + self.consume(); + attrs.push(self.match_attr_body()?); + } + _ => { + let location = self.location; + let type_ref = self.match_ref("expected type, attribute, or ;")?; + args.push(FuncRet { + type_: type_ref, + attrs: attrs.clone(), + location, + }); + attrs.clear(); + match self.token() { + Some(Token::Comma) => { + self.consume(); + continue; + } + Some(Token::Semi) => { + self.consume(); + break; + } + _ => parse_err!(self.location, "expected , or ;")?, + } + } + } + } + if !attrs.is_empty() { + parse_err!( + self.location, + "attributes unattached to a function return type" + )? + } + Ok(args) + } + pub fn match_decl(&mut self, err_msg: &str) -> Result, ParseError> { let mut attrs = Vec::new(); loop { match self.token() { - Some(Token::Keyword("struct")) => { + Some(Token::Word("struct")) => { let location = self.location; self.consume(); let name = err_ctx!(err_msg, self.match_a_word("expected struct name"))?; @@ -301,7 +415,7 @@ impl<'a> Parser<'a> { location, })); } - Some(Token::Keyword("enum")) => { + Some(Token::Word("enum")) => { let location = self.location; self.consume(); let name = err_ctx!(err_msg, self.match_a_word("expected enum name"))?; @@ -314,7 +428,7 @@ impl<'a> Parser<'a> { location, })); } - Some(Token::Keyword("type")) => { + Some(Token::Word("type")) => { let location = self.location; self.consume(); let name = err_ctx!(err_msg, self.match_a_word("expected type name"))?; @@ -327,7 +441,7 @@ impl<'a> Parser<'a> { location, })); } - Some(Token::Keyword("mod")) => { + Some(Token::Word("mod")) => { let location = self.location; self.consume(); let name = err_ctx!(err_msg, self.match_a_word("expected module name"))?; @@ -354,13 +468,52 @@ impl<'a> Parser<'a> { location, })); } + Some(Token::Word("fn")) => { + let location = self.location; + self.consume(); + let name = err_ctx!(err_msg, self.match_a_word("expected function name"))?; + + err_ctx!(err_msg, self.match_token(Token::LPar, "expected ("))?; + let args = err_ctx!(err_msg, self.match_func_args())?; + + let rets = match self.token() { + Some(Token::Arrow) => { + self.consume(); + err_ctx!(err_msg, self.match_func_rets())? + } + Some(Token::Semi) => Vec::new(), + t => err_ctx!( + err_msg, + parse_err!(self.location, "expected -> or ;, got {:?}", t) + )?, + }; + + return Ok(Some(SyntaxDecl::Function { + name: name.to_owned(), + args, + rets, + attrs, + location, + })); + } Some(Token::Hash) => { self.consume(); attrs.push(self.match_attr_body()?); continue; } - Some(_) => return parse_err!(self.location, "expected keyword or attribute"), - None => return Ok(None), + Some(_) => { + return parse_err!( + self.location, + "in {}\nexpected keyword or attribute", + err_msg + ) + } + None => { + if !attrs.is_empty() { + parse_err!(self.location, "attributes unattached to a declaration")? + } + return Ok(None); + } } } } @@ -384,7 +537,7 @@ impl<'a> Parser<'a> { self.consume(); Ok(SyntaxRef::Atom { atom, location }) } - Some(Token::Word(name)) | Some(Token::Keyword(name)) => { + Some(Token::Word(name)) => { let location = self.location; self.consume(); Ok(SyntaxRef::Name { @@ -730,6 +883,49 @@ mod tests { ); } #[test] + fn enum_one_entry_with_attr() { + let mut parser = Parser::new("enum bar { #[a=b] first}"); + // 0 5 10 + assert_eq!( + parser + .match_decl("one entry enum, no trailing comma") + .expect("valid parse") + .expect("valid decl"), + SyntaxDecl::Enum { + name: "bar".to_owned(), + variants: vec![EnumVariant { + name: "first".to_owned(), + attrs: vec![Attr::new( + "a", + "b", + Location { + line: 1, + column: 11 + } + ),], + location: Location { + line: 1, + column: 18, + }, + }], + attrs: Vec::new(), + location: Location { line: 1, column: 0 }, + }, + ); + } + #[test] + fn enum_one_entry_trailing_attr() { + assert!(Parser::new("enum bar { #[a=b] first, #[c=d] }") + .match_decl("one entry enum") + .is_err()); + } + #[test] + fn enum_no_entry_attr() { + assert!(Parser::new("enum bar { #[c=d] }") + .match_decl("zero entry enum") + .is_err()); + } + #[test] fn enum_four_entry() { let mut parser = Parser::new("enum baz { one, two, three\n, four, }"); // 0 5 11 16 21 0 2 @@ -865,4 +1061,370 @@ mod tests { } ); } + + #[test] + fn mod_attrs() { + let mut parser = Parser::new("#[a=b]\nmod one { #[c=d] enum foo {} struct bar {} }"); + // 0 5 10 15 20 25 30 + assert_eq!( + parser + .match_decl("module with types") + .expect("valid parse") + .expect("valid decl"), + SyntaxDecl::Module { + name: "one".to_owned(), + decls: vec![ + Box::new(SyntaxDecl::Enum { + name: "foo".to_owned(), + variants: Vec::new(), + attrs: vec![Attr::new( + "c", + "d", + Location { + line: 2, + column: 10 + } + ),], + location: Location { + line: 2, + column: 17 + }, + }), + Box::new(SyntaxDecl::Struct { + name: "bar".to_owned(), + members: Vec::new(), + attrs: Vec::new(), + location: Location { + line: 2, + column: 29 + }, + }) + ], + attrs: vec![Attr::new("a", "b", Location { line: 1, column: 0 }),], + location: Location { line: 2, column: 0 }, + } + ); + } + + #[test] + fn fn_trivial() { + let canonical = SyntaxDecl::Function { + name: "trivial".to_owned(), + args: Vec::new(), + rets: Vec::new(), + attrs: Vec::new(), + location: Location { line: 1, column: 0 }, + }; + assert_eq!( + Parser::new("fn trivial();") + // 0 5 10 + .match_decl("trivial func") + .expect("valid parse") + .expect("valid decl"), + canonical, + ); + assert_eq!( + Parser::new("fn trivial ( ) ;") + // 0 5 10 + .match_decl("trivial func") + .expect("valid parse") + .expect("valid decl"), + canonical, + ); + assert_eq!( + Parser::new("fn trivial()->;") + // 0 5 10 + .match_decl("trivial func") + .expect("valid parse") + .expect("valid decl"), + canonical, + ); + } + + #[test] + fn fn_return_u8() { + let canonical = SyntaxDecl::Function { + name: "getch".to_owned(), + args: Vec::new(), + rets: vec![FuncRet { + type_: SyntaxRef::Atom { + atom: AtomType::U8, + location: Location { + line: 1, + column: 14, + }, + }, + attrs: vec![], + location: Location { + line: 1, + column: 14, + }, + }], + attrs: Vec::new(), + location: Location { line: 1, column: 0 }, + }; + assert_eq!( + Parser::new("fn getch() -> u8;") + // 0 5 10 + .match_decl("returns u8") + .expect("valid parse") + .expect("valid decl"), + canonical + ); + assert_eq!( + Parser::new("fn getch() -> u8,;") + // 0 5 10 + .match_decl("returns u8") + .expect("valid parse") + .expect("valid decl"), + canonical + ); + assert_eq!( + Parser::new("fn getch() -> u8 , ;") + // 0 5 10 + .match_decl("returns u8") + .expect("valid parse") + .expect("valid decl"), + canonical + ); + } + + #[test] + fn fn_one_arg() { + let canonical = SyntaxDecl::Function { + name: "foo".to_owned(), + args: vec![FuncArg { + type_: SyntaxRef::Atom { + atom: AtomType::U8, + location: Location { + line: 1, + column: 10, + }, + }, + name: "a".to_owned(), + attrs: Vec::new(), + location: Location { line: 1, column: 7 }, + }], + rets: Vec::new(), + attrs: Vec::new(), + location: Location { line: 1, column: 0 }, + }; + assert_eq!( + Parser::new("fn foo(a: u8);") + // 0 5 10 15 20 25 + .match_decl("returns u8") + .expect("valid parse") + .expect("valid decl"), + canonical + ); + assert_eq!( + Parser::new("fn foo(a: u8,);") + // 0 5 10 15 20 25 + .match_decl("returns u8") + .expect("valid parse") + .expect("valid decl"), + canonical + ); + } + + #[test] + fn fn_multi_arg() { + let canonical = SyntaxDecl::Function { + name: "foo".to_owned(), + args: vec![ + FuncArg { + type_: SyntaxRef::Atom { + atom: AtomType::U8, + location: Location { + line: 1, + column: 10, + }, + }, + name: "a".to_owned(), + attrs: Vec::new(), + location: Location { line: 1, column: 7 }, + }, + FuncArg { + type_: SyntaxRef::Atom { + atom: AtomType::F64, + location: Location { + line: 1, + column: 17, + }, + }, + name: "b".to_owned(), + attrs: Vec::new(), + location: Location { + line: 1, + column: 14, + }, + }, + ], + rets: Vec::new(), + attrs: Vec::new(), + location: Location { line: 1, column: 0 }, + }; + assert_eq!( + Parser::new("fn foo(a: u8, b: f64);") + // 0 5 10 15 20 25 + .match_decl("returns u8") + .expect("valid parse") + .expect("valid decl"), + canonical + ); + assert_eq!( + Parser::new("fn foo(a: u8, b: f64, );") + // 0 5 10 15 20 25 + .match_decl("returns u8") + .expect("valid parse") + .expect("valid decl"), + canonical + ); + } + + #[test] + fn fn_many_returns() { + assert_eq!( + Parser::new("fn getch() -> u8, u16, u32;") + // 0 5 10 15 20 25 + .match_decl("returns u8") + .expect("valid parse") + .expect("valid decl"), + SyntaxDecl::Function { + name: "getch".to_owned(), + args: Vec::new(), + rets: vec![ + FuncRet { + type_: SyntaxRef::Atom { + atom: AtomType::U8, + location: Location { + line: 1, + column: 14, + }, + }, + attrs: vec![], + location: Location { + line: 1, + column: 14, + }, + }, + FuncRet { + type_: SyntaxRef::Atom { + atom: AtomType::U16, + location: Location { + line: 1, + column: 18, + }, + }, + attrs: vec![], + location: Location { + line: 1, + column: 18, + }, + }, + FuncRet { + type_: SyntaxRef::Atom { + atom: AtomType::U32, + location: Location { + line: 1, + column: 23, + }, + }, + attrs: vec![], + location: Location { + line: 1, + column: 23, + }, + }, + ], + attrs: Vec::new(), + location: Location { line: 1, column: 0 }, + } + ); + } + + #[test] + fn fn_many_returns_with_attrs() { + assert_eq!( + Parser::new("fn getch() -> #[a=b] u8, #[c=d] #[e=f] u16, u32;") + // 0 5 10 15 20 25 30 35 40 45 + .match_decl("returns u8") + .expect("valid parse") + .expect("valid decl"), + SyntaxDecl::Function { + name: "getch".to_owned(), + args: Vec::new(), + rets: vec![ + FuncRet { + type_: SyntaxRef::Atom { + atom: AtomType::U8, + location: Location { + line: 1, + column: 21, + }, + }, + attrs: vec![Attr::new( + "a", + "b", + Location { + line: 1, + column: 14 + } + )], + location: Location { + line: 1, + column: 21, + }, + }, + FuncRet { + type_: SyntaxRef::Atom { + atom: AtomType::U16, + location: Location { + line: 1, + column: 39, + }, + }, + attrs: vec![ + Attr::new( + "c", + "d", + Location { + line: 1, + column: 25 + } + ), + Attr::new( + "e", + "f", + Location { + line: 1, + column: 32 + } + ), + ], + location: Location { + line: 1, + column: 39, + }, + }, + FuncRet { + type_: SyntaxRef::Atom { + atom: AtomType::U32, + location: Location { + line: 1, + column: 44, + }, + }, + attrs: vec![], + location: Location { + line: 1, + column: 44, + }, + }, + ], + attrs: Vec::new(), + location: Location { line: 1, column: 0 }, + } + ); + } } From 215a9c3b7913e346dbeb605fee581af50a3da11c Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 3 May 2019 17:01:14 -0700 Subject: [PATCH 186/512] lucet-idl: reorganize some definitions --- lucet-idl/src/c/mod.rs | 11 +-- lucet-idl/src/cache.rs | 2 +- lucet-idl/src/config.rs | 5 +- lucet-idl/src/error.rs | 92 ++++++++++++++++++++++ lucet-idl/src/errors.rs | 35 --------- lucet-idl/src/generator.rs | 15 ++-- lucet-idl/src/lib.rs | 4 +- lucet-idl/src/package.rs | 138 ++------------------------------- lucet-idl/src/pretty_writer.rs | 2 +- lucet-idl/src/rust/mod.rs | 5 +- lucet-idl/src/types.rs | 61 +++++++++++++++ 11 files changed, 183 insertions(+), 187 deletions(-) create mode 100644 lucet-idl/src/error.rs delete mode 100644 lucet-idl/src/errors.rs diff --git a/lucet-idl/src/c/mod.rs b/lucet-idl/src/c/mod.rs index 879722fd3..471cf10a6 100644 --- a/lucet-idl/src/c/mod.rs +++ b/lucet-idl/src/c/mod.rs @@ -11,12 +11,13 @@ mod r#struct; pub(crate) use self::catom::*; use crate::backend::*; -use crate::cache::*; -use crate::errors::*; +use crate::cache::{Cache, CachedStructMemberEntry, CachedTypeEntry}; +use crate::error::IDLError; use crate::generator::{Generator, Hierarchy}; -use crate::package::{DataType, DataTypeEntry, DataTypeRef, Package}; -use crate::pretty_writer::*; -use crate::target::*; +use crate::package::Package; +use crate::pretty_writer::PrettyWriter; +use crate::target::Target; +use crate::types::{DataType, DataTypeEntry, DataTypeRef}; use std::io::prelude::*; #[derive(Clone, Debug)] diff --git a/lucet-idl/src/cache.rs b/lucet-idl/src/cache.rs index ef50acb25..50ff2f625 100644 --- a/lucet-idl/src/cache.rs +++ b/lucet-idl/src/cache.rs @@ -1,4 +1,4 @@ -use crate::package::DataTypeId; +use crate::types::DataTypeId; use std::collections::HashMap; /// Cached information for a given structure member diff --git a/lucet-idl/src/config.rs b/lucet-idl/src/config.rs index bc30d7aac..b7ffb1bca 100644 --- a/lucet-idl/src/config.rs +++ b/lucet-idl/src/config.rs @@ -36,10 +36,7 @@ impl Config { backend_config: self.backend_config, }), - Backend::Rust => Box::new(RustGenerator::new( - self.target, - self.backend_config, - )), + Backend::Rust => Box::new(RustGenerator::new(self.target, self.backend_config)), } } } diff --git a/lucet-idl/src/error.rs b/lucet-idl/src/error.rs new file mode 100644 index 000000000..740c4c647 --- /dev/null +++ b/lucet-idl/src/error.rs @@ -0,0 +1,92 @@ +use crate::parser; +use crate::types::Location; +use std::error::Error; +use std::fmt; +use std::io; + +#[allow(dead_code)] +#[derive(Debug, Fail)] +pub enum IDLError { + #[fail(display = "Internal error: {}", _0)] + InternalError(&'static str), + #[fail(display = "Incorrect usage: {}", _0)] + UsageError(&'static str), + #[fail(display = "{}", _0)] + ParseError(#[cause] parser::ParseError), + #[fail(display = "{}", _0)] + ValidationError(#[cause] ValidationError), + #[fail(display = "{}", _0)] + Io(#[cause] io::Error), +} + +impl From for IDLError { + fn from(e: io::Error) -> Self { + IDLError::Io(e) + } +} + +impl From for IDLError { + fn from(e: parser::ParseError) -> Self { + IDLError::ParseError(e) + } +} + +impl From for IDLError { + fn from(e: ValidationError) -> Self { + IDLError::ValidationError(e) + } +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum ValidationError { + NameAlreadyExists { + name: String, + at_location: Location, + previous_location: Location, + }, + NameNotFound { + name: String, + use_location: Location, + }, + Empty { + name: String, + location: Location, + }, + Infinite { + name: String, + location: Location, + }, +} + +impl fmt::Display for ValidationError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ValidationError::NameAlreadyExists { + name, + at_location, + previous_location, + } => write!( + f, + "Redefinition of name {} at line {} - previous definition was at line {}", + name, at_location.line, previous_location.line + ), + ValidationError::NameNotFound { name, use_location } => { + write!(f, "Name {} not found at line {}", name, use_location.line) + } + ValidationError::Empty { name, location } => { + write!(f, "Empty definition for {} at line {}", name, location.line) + } + ValidationError::Infinite { name, location } => write!( + f, + "Circular reference for {} at line {}", + name, location.line + ), + } + } +} + +impl Error for ValidationError { + fn description(&self) -> &str { + "Validation error" + } +} diff --git a/lucet-idl/src/errors.rs b/lucet-idl/src/errors.rs deleted file mode 100644 index a0221a79b..000000000 --- a/lucet-idl/src/errors.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::{package, parser}; -use std::io; - -#[allow(dead_code)] -#[derive(Debug, Fail)] -pub enum IDLError { - #[fail(display = "Internal error: {}", _0)] - InternalError(&'static str), - #[fail(display = "Incorrect usage: {}", _0)] - UsageError(&'static str), - #[fail(display = "{}", _0)] - ParseError(#[cause] parser::ParseError), - #[fail(display = "{}", _0)] - ValidationError(#[cause] package::ValidationError), - #[fail(display = "{}", _0)] - Io(#[cause] io::Error), -} - -impl From for IDLError { - fn from(e: io::Error) -> Self { - IDLError::Io(e) - } -} - -impl From for IDLError { - fn from(e: parser::ParseError) -> Self { - IDLError::ParseError(e) - } -} - -impl From for IDLError { - fn from(e: package::ValidationError) -> Self { - IDLError::ValidationError(e) - } -} diff --git a/lucet-idl/src/generator.rs b/lucet-idl/src/generator.rs index 51201c59c..528e57dd0 100644 --- a/lucet-idl/src/generator.rs +++ b/lucet-idl/src/generator.rs @@ -1,7 +1,8 @@ use crate::cache::Cache; -use crate::errors::IDLError; -use crate::package::{DataType, DataTypeEntry, DataTypeId, Package}; +use crate::error::IDLError; +use crate::package::Package; use crate::pretty_writer::PrettyWriter; +use crate::types::{DataType, DataTypeEntry, DataTypeId}; use std::io::Write; use std::rc::Rc; @@ -107,9 +108,13 @@ pub trait Generator { ) -> Result<(), IDLError> { let data_type_entry = package.get_datatype(id); match &data_type_entry.data_type { - DataType::Struct { .. } => { - self.gen_accessors_struct(package, cache, pretty_writer, &data_type_entry, hierarchy) - } + DataType::Struct { .. } => self.gen_accessors_struct( + package, + cache, + pretty_writer, + &data_type_entry, + hierarchy, + ), DataType::Alias { .. } => { self.gen_accessors_alias(package, cache, pretty_writer, &data_type_entry, hierarchy) } diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 6c0035cec..b9437c29f 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -7,7 +7,7 @@ mod backend; mod c; mod cache; mod config; -mod errors; +mod error; mod generator; mod lexer; mod package; @@ -19,7 +19,7 @@ mod types; pub use crate::backend::{Backend, BackendConfig}; pub use crate::config::Config; -pub use crate::errors::IDLError; +pub use crate::error::IDLError; pub use crate::target::Target; use crate::cache::Cache; diff --git a/lucet-idl/src/package.rs b/lucet-idl/src/package.rs index b2533747a..2759a38f0 100644 --- a/lucet-idl/src/package.rs +++ b/lucet-idl/src/package.rs @@ -1,58 +1,7 @@ +use crate::error::ValidationError; use crate::parser::{SyntaxDecl, SyntaxRef}; -use crate::types::{AtomType, Attr, Location}; +use crate::types::{DataType, DataTypeEntry, DataTypeId, DataTypeRef, Location, Name, NamedMember}; use std::collections::HashMap; -use std::error::Error; -use std::fmt; - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] -pub struct DataTypeId(pub usize); - -impl fmt::Display for DataTypeId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum DataTypeRef { - Defined(DataTypeId), - Atom(AtomType), -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct NamedMember { - pub type_: R, - pub name: String, - pub attrs: Vec, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum DataType { - Struct { - members: Vec>, - attrs: Vec, - }, - Enum { - members: Vec>, - attrs: Vec, - }, - Alias { - to: DataTypeRef, - attrs: Vec, - }, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Name { - pub name: String, - pub location: Location, -} - -impl fmt::Display for Name { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.name) - } -} #[derive(Debug, PartialEq, Eq, Clone)] pub struct Package { @@ -60,69 +9,6 @@ pub struct Package { pub data_types: HashMap, } -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum ValidationError { - NameAlreadyExists { - name: String, - at_location: Location, - previous_location: Location, - }, - NameNotFound { - name: String, - use_location: Location, - }, - Empty { - name: String, - location: Location, - }, - Infinite { - name: String, - location: Location, - }, -} - -impl fmt::Display for ValidationError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ValidationError::NameAlreadyExists { - name, - at_location, - previous_location, - } => write!( - f, - "Redefinition of name {} at line {} - previous definition was at line {}", - name, at_location.line, previous_location.line - ), - ValidationError::NameNotFound { name, use_location } => { - write!(f, "Name {} not found at line {}", name, use_location.line) - } - ValidationError::Empty { name, location } => { - write!(f, "Empty definition for {} at line {}", name, location.line) - } - ValidationError::Infinite { name, location } => write!( - f, - "Circular reference for {} at line {}", - name, location.line - ), - } - } -} - -/// A convenient structure holding a data type, its name and -/// its internal IDL representation -#[derive(Debug, Clone)] -pub struct DataTypeEntry<'t> { - pub id: DataTypeId, - pub name: &'t Name, - pub data_type: &'t DataType, -} - -impl Error for ValidationError { - fn description(&self) -> &str { - "Validation error" - } -} - impl Package { fn new() -> Self { Self { @@ -275,12 +161,8 @@ impl Package { }, ); } - SyntaxDecl::Module{ .. } => { - unimplemented!() - } - SyntaxDecl::Function{ .. } => { - unimplemented!() - } + SyntaxDecl::Module { .. } => unimplemented!(), + SyntaxDecl::Function { .. } => unimplemented!(), } Ok(()) } @@ -377,6 +259,7 @@ impl Package { mod tests { use super::super::parser::Parser; use super::*; + use crate::types::AtomType; fn pkg(syntax: &str) -> Result { let mut parser = Parser::new(syntax); @@ -388,7 +271,6 @@ mod tests { fn structs_basic() { assert!(pkg("struct foo { a: i32}").is_ok()); assert!(pkg("struct foo { a: i32, b: f32 }").is_ok()); - } #[test] @@ -410,7 +292,6 @@ mod tests { _ => panic!("Unexpected type"), }; } - } #[test] @@ -423,14 +304,12 @@ mod tests { fn struct_next_definition() { // Refer to a struct defined afterwards: assert!(pkg("struct foo { a: i32, b: bar} struct bar { a: i32 }").is_ok()); - } #[test] fn struct_self_referential() { // Refer to itself assert!(pkg("struct list { next: list, thing: i32 }").is_err()); - } #[test] @@ -443,7 +322,6 @@ mod tests { location: Location { line: 1, column: 0 }, } ); - } #[test] @@ -457,7 +335,6 @@ mod tests { previous_location: Location { line: 2, column: 0 }, } ); - } #[test] @@ -473,7 +350,6 @@ mod tests { previous_location: Location { line: 1, column: 0 }, } ); - } #[test] @@ -555,9 +431,7 @@ mod tests { ); assert_eq!( - pkg("type foo = bar\nstruct bar { a: foo }") - .err() - .unwrap(), + pkg("type foo = bar\nstruct bar { a: foo }").err().unwrap(), ValidationError::Infinite { name: "foo".to_owned(), location: Location { line: 1, column: 0 }, diff --git a/lucet-idl/src/pretty_writer.rs b/lucet-idl/src/pretty_writer.rs index bacb56ed7..aea75d064 100644 --- a/lucet-idl/src/pretty_writer.rs +++ b/lucet-idl/src/pretty_writer.rs @@ -1,4 +1,4 @@ -use super::errors::*; +use super::error::IDLError; use std::cell::RefCell; use std::convert::Into; use std::io::prelude::*; diff --git a/lucet-idl/src/rust/mod.rs b/lucet-idl/src/rust/mod.rs index 40a8ed0da..aa7b87d8e 100644 --- a/lucet-idl/src/rust/mod.rs +++ b/lucet-idl/src/rust/mod.rs @@ -3,12 +3,13 @@ use crate::backend::BackendConfig; use crate::cache::Cache; -use crate::errors::IDLError; +use crate::error::IDLError; use crate::generator::{Generator, Hierarchy}; -use crate::package::{DataType, DataTypeEntry, DataTypeId, DataTypeRef, Package}; +use crate::package::Package; use crate::pretty_writer::PrettyWriter; use crate::target::Target; use crate::types::AtomType; +use crate::types::{DataType, DataTypeEntry, DataTypeId, DataTypeRef}; use heck::{CamelCase, SnakeCase}; use std::collections::HashMap; use std::io::Write; diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index 7c747a4c3..6a11713c8 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -1,3 +1,5 @@ +use std::fmt; + #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum AtomType { U8, @@ -34,3 +36,62 @@ impl Attr { } } } + +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] +pub struct DataTypeId(pub usize); + +impl fmt::Display for DataTypeId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum DataTypeRef { + Defined(DataTypeId), + Atom(AtomType), +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct NamedMember { + pub type_: R, + pub name: String, + pub attrs: Vec, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum DataType { + Struct { + members: Vec>, + attrs: Vec, + }, + Enum { + members: Vec>, + attrs: Vec, + }, + Alias { + to: DataTypeRef, + attrs: Vec, + }, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct Name { + pub name: String, + pub location: Location, +} + +impl fmt::Display for Name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.name) + } +} + +/// A convenient structure holding a data type, its name and +/// its internal IDL representation +#[derive(Debug, Clone)] +pub struct DataTypeEntry<'t> { + pub id: DataTypeId, + pub name: &'t Name, + pub data_type: &'t DataType, +} From 2430ba0095d27f64f1f0dfdd96aa2609a1cadf8a Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 6 May 2019 16:34:07 -0700 Subject: [PATCH 187/512] lucet-idl: split hierarchy into packages and modules --- lucet-idl/src/cache.rs | 8 +- lucet-idl/src/config.rs | 7 +- lucet-idl/src/error.rs | 7 + lucet-idl/src/generator.rs | 46 ++-- lucet-idl/src/lib.rs | 26 +- lucet-idl/src/module.rs | 466 +++++++++++++++++++++++++++++++++ lucet-idl/src/package.rs | 500 +++++++++++------------------------- lucet-idl/src/parser.rs | 29 ++- lucet-idl/src/rust/mod.rs | 4 +- lucet-idl/src/types.rs | 8 +- lucet-idl/tests/example.idl | 33 +-- 11 files changed, 705 insertions(+), 429 deletions(-) create mode 100644 lucet-idl/src/module.rs diff --git a/lucet-idl/src/cache.rs b/lucet-idl/src/cache.rs index 50ff2f625..51814cb83 100644 --- a/lucet-idl/src/cache.rs +++ b/lucet-idl/src/cache.rs @@ -1,4 +1,4 @@ -use crate::types::DataTypeId; +use crate::types::Ident; use std::collections::HashMap; /// Cached information for a given structure member @@ -28,18 +28,18 @@ impl CachedTypeEntry { /// Cache information about a type given its id #[derive(Clone, Debug, Default)] pub struct Cache { - type_map: HashMap, + type_map: HashMap, } impl Cache { - pub fn store_type(&mut self, id: DataTypeId, entry: CachedTypeEntry) -> &mut CachedTypeEntry { + pub fn store_type(&mut self, id: Ident, entry: CachedTypeEntry) -> &mut CachedTypeEntry { if self.type_map.insert(id, entry).is_some() { panic!("Type {:?} had already been cached", id) } self.type_map.get_mut(&id).unwrap() } - pub fn load_type(&self, id: DataTypeId) -> Option<&CachedTypeEntry> { + pub fn load_type(&self, id: Ident) -> Option<&CachedTypeEntry> { self.type_map.get(&id) } } diff --git a/lucet-idl/src/config.rs b/lucet-idl/src/config.rs index b7ffb1bca..fb91a7366 100644 --- a/lucet-idl/src/config.rs +++ b/lucet-idl/src/config.rs @@ -1,8 +1,8 @@ use super::backend::{Backend, BackendConfig}; use super::target::Target; -use crate::c::CGenerator; +//use crate::c::CGenerator; use crate::generator::Generator; -use crate::rust::RustGenerator; +//use crate::rust::RustGenerator; use std::io::Write; #[derive(Default, Clone, Debug)] @@ -30,6 +30,8 @@ impl Config { } pub fn generator(&self) -> Box> { + unimplemented!() + /* disabled while module / pkg representation in flux match self.backend { Backend::C => Box::new(CGenerator { target: self.target, @@ -38,5 +40,6 @@ impl Config { Backend::Rust => Box::new(RustGenerator::new(self.target, self.backend_config)), } + */ } } diff --git a/lucet-idl/src/error.rs b/lucet-idl/src/error.rs index 740c4c647..ce06013fe 100644 --- a/lucet-idl/src/error.rs +++ b/lucet-idl/src/error.rs @@ -56,6 +56,10 @@ pub enum ValidationError { name: String, location: Location, }, + Syntax { + expected: &'static str, + location: Location, + } } impl fmt::Display for ValidationError { @@ -81,6 +85,9 @@ impl fmt::Display for ValidationError { "Circular reference for {} at line {}", name, location.line ), + ValidationError::Syntax { expected, location } => { + write!(f, "Invalid syntax: expected {} at line {}", expected, location.line) + } } } } diff --git a/lucet-idl/src/generator.rs b/lucet-idl/src/generator.rs index 528e57dd0..c0475c114 100644 --- a/lucet-idl/src/generator.rs +++ b/lucet-idl/src/generator.rs @@ -1,8 +1,8 @@ use crate::cache::Cache; use crate::error::IDLError; -use crate::package::Package; +use crate::module::Module; use crate::pretty_writer::PrettyWriter; -use crate::types::{DataType, DataTypeEntry, DataTypeId}; +use crate::types::{DataType, DataTypeEntry, Ident}; use std::io::Write; use std::rc::Rc; @@ -11,7 +11,7 @@ pub trait Generator { fn gen_type_header( &mut self, - package: &Package, + module: &Module, _cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -19,7 +19,7 @@ pub trait Generator { fn gen_alias( &mut self, - package: &Package, + module: &Module, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -27,7 +27,7 @@ pub trait Generator { fn gen_struct( &mut self, - package: &Package, + module: &Module, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -35,7 +35,7 @@ pub trait Generator { fn gen_enum( &mut self, - package: &Package, + module: &Module, cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -43,7 +43,7 @@ pub trait Generator { fn gen_accessors_struct( &mut self, - package: &Package, + module: &Module, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -52,7 +52,7 @@ pub trait Generator { fn gen_accessors_enum( &mut self, - package: &Package, + module: &Module, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -61,7 +61,7 @@ pub trait Generator { fn gen_accessors_alias( &mut self, - package: &Package, + module: &Module, cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, @@ -70,24 +70,24 @@ pub trait Generator { fn gen_for_id( &mut self, - package: &Package, + module: &Module, cache: &mut Cache, pretty_writer: &mut PrettyWriter, - id: DataTypeId, + id: Ident, ) -> Result<(), IDLError> { - let data_type_entry = package.get_datatype(id); - self.gen_type_header(package, cache, pretty_writer, &data_type_entry)?; + let data_type_entry = module.get_datatype(id); + self.gen_type_header(module, cache, pretty_writer, &data_type_entry)?; match &data_type_entry.data_type { DataType::Struct { .. } => { - self.gen_struct(package, cache, pretty_writer, &data_type_entry) + self.gen_struct(module, cache, pretty_writer, &data_type_entry) } DataType::Alias { .. } => { - self.gen_alias(package, cache, pretty_writer, &data_type_entry) + self.gen_alias(module, cache, pretty_writer, &data_type_entry) } - DataType::Enum { .. } => self.gen_enum(package, cache, pretty_writer, &data_type_entry), + DataType::Enum { .. } => self.gen_enum(module, cache, pretty_writer, &data_type_entry), }?; self.gen_accessors_for_id( - package, + module, cache, pretty_writer, id, @@ -100,26 +100,26 @@ pub trait Generator { /// `hierarchy` is used to derive function names from nested types fn gen_accessors_for_id( &mut self, - package: &Package, + module: &Module, cache: &Cache, pretty_writer: &mut PrettyWriter, - id: DataTypeId, + id: Ident, hierarchy: &Hierarchy, ) -> Result<(), IDLError> { - let data_type_entry = package.get_datatype(id); + let data_type_entry = module.get_datatype(id); match &data_type_entry.data_type { DataType::Struct { .. } => self.gen_accessors_struct( - package, + module, cache, pretty_writer, &data_type_entry, hierarchy, ), DataType::Alias { .. } => { - self.gen_accessors_alias(package, cache, pretty_writer, &data_type_entry, hierarchy) + self.gen_accessors_alias(module, cache, pretty_writer, &data_type_entry, hierarchy) } DataType::Enum { .. } => { - self.gen_accessors_enum(package, cache, pretty_writer, &data_type_entry, hierarchy) + self.gen_accessors_enum(module, cache, pretty_writer, &data_type_entry, hierarchy) } }?; Ok(()) diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index b9437c29f..d97307ef2 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -4,16 +4,17 @@ extern crate failure; mod backend; -mod c; +//mod c; mod cache; mod config; mod error; mod generator; mod lexer; +mod module; mod package; mod parser; mod pretty_writer; -mod rust; +//mod rust; mod target; mod types; @@ -32,18 +33,21 @@ pub fn run(config: &Config, input: &str, output: W) -> Result, + pub attrs: Vec, + pub data_types: HashMap, +} + +impl Module { + fn new(attrs: &[Attr]) -> Self { + Self { + names: Vec::new(), + attrs: attrs.to_vec(), + data_types: HashMap::new(), + } + } + + fn introduce_name( + &mut self, + name: &str, + location: &Location, + ) -> Result { + if let Some(existing) = self.id_for_name(&name) { + let prev = self + .names + .get(existing.0) + .expect("lookup told us name exists"); + Err(ValidationError::NameAlreadyExists { + name: name.to_owned(), + at_location: *location, + previous_location: prev.location, + }) + } else { + let id = self.names.len(); + self.names.push(Name { + name: name.to_owned(), + location: *location, + }); + Ok(Ident(id)) + } + } + + fn id_for_name(&self, name: &str) -> Option { + for (id, n) in self.names.iter().enumerate() { + if n.name == name { + return Some(Ident(id)); + } + } + None + } + + fn get_ref(&self, syntax_ref: &SyntaxRef) -> Result { + match syntax_ref { + SyntaxRef::Atom { atom, .. } => Ok(DataTypeRef::Atom(*atom)), + SyntaxRef::Name { name, location } => match self.id_for_name(name) { + Some(id) => Ok(DataTypeRef::Defined(id)), + None => Err(ValidationError::NameNotFound { + name: name.clone(), + use_location: *location, + }), + }, + } + } + + fn define_data_type(&mut self, id: Ident, dt: DataType) { + if let Some(prev_def) = self.data_types.insert(id, dt) { + panic!("id {} already defined: {:?}", id, prev_def) + } + } + + fn define_decl(&mut self, id: Ident, decl: &SyntaxDecl) -> Result<(), ValidationError> { + match decl { + SyntaxDecl::Struct { + name, + members, + attrs, + location, + } => { + let mut uniq_membs = HashMap::new(); + let mut dtype_members = Vec::new(); + if members.is_empty() { + Err(ValidationError::Empty { + name: name.clone(), + location: *location, + })? + } + for mem in members { + // Ensure that each member name is unique: + if let Some(existing) = uniq_membs.insert(mem.name.clone(), mem) { + Err(ValidationError::NameAlreadyExists { + name: mem.name.clone(), + at_location: mem.location, + previous_location: existing.location, + })? + } + // Get the DataTypeRef for the member, which ensures that it refers only to + // defined types: + let type_ = self.get_ref(&mem.type_)?; + // build the struct with this as the member: + dtype_members.push(NamedMember { + type_, + name: mem.name.clone(), + attrs: mem.attrs.clone(), + }) + } + self.define_data_type( + id, + DataType::Struct { + members: dtype_members, + attrs: attrs.clone(), + }, + ) + } + SyntaxDecl::Enum { + name, + variants, + attrs, + location, + } => { + let mut uniq_vars = HashMap::new(); + let mut dtype_members = Vec::new(); + if variants.is_empty() { + Err(ValidationError::Empty { + name: name.clone(), + location: *location, + })? + } + for var in variants { + // Ensure that each member name is unique: + if let Some(existing) = uniq_vars.insert(var.name.clone(), var) { + Err(ValidationError::NameAlreadyExists { + name: var.name.clone(), + at_location: var.location, + previous_location: existing.location, + })? + } + // build the struct with this as the member: + dtype_members.push(NamedMember { + type_: (), + name: var.name.clone(), + attrs: var.attrs.clone(), + }) + } + self.define_data_type( + id, + DataType::Enum { + members: dtype_members, + attrs: attrs.clone(), + }, + ) + } + SyntaxDecl::Alias { what, attrs, .. } => { + let to = self.get_ref(what)?; + self.define_data_type( + id, + DataType::Alias { + to, + attrs: attrs.clone(), + }, + ); + } + SyntaxDecl::Module { .. } => unimplemented!(), + SyntaxDecl::Function { .. } => unimplemented!(), + } + Ok(()) + } + + fn dfs_walk( + &self, + id: Ident, + visited: &mut [bool], + ordered: &mut Option<&mut Vec>, + ) -> Result<(), ()> { + if visited[id.0] { + Err(())? + } + visited[id.0] = true; + match self.data_types.get(&id).expect("data_type is defined") { + DataType::Struct { members, .. } => { + for mem in members { + if let DataTypeRef::Defined(id) = mem.type_ { + self.dfs_walk(id, visited, ordered)? + } + } + } + DataType::Alias { to, .. } => { + if let DataTypeRef::Defined(id) = to { + self.dfs_walk(*id, visited, ordered)? + } + } + DataType::Enum { .. } => {} + } + if let Some(ordered) = ordered.as_mut() { + if !ordered.contains(&id) { + ordered.push(id) + } + } + visited[id.0] = false; + Ok(()) + } + + pub fn ordered_dependencies(&self) -> Result, ()> { + let mut visited = Vec::new(); + visited.resize(self.names.len(), false); + let mut ordered = Vec::with_capacity(visited.capacity()); + for id in self.data_types.keys() { + let _ = self.dfs_walk(*id, &mut visited, &mut Some(&mut ordered)); + } + Ok(ordered) + } + + fn dfs_find_cycle(&self, id: Ident) -> Result<(), ()> { + let mut visited = Vec::new(); + visited.resize(self.names.len(), false); + self.dfs_walk(id, &mut visited, &mut None) + } + + fn ensure_finite(&self, id: Ident, decl: &SyntaxDecl) -> Result<(), ValidationError> { + self.dfs_find_cycle(id) + .map_err(|_| ValidationError::Infinite { + name: decl.name().to_owned(), + location: *decl.location(), + }) + } + + pub fn from_declarations( + decls: &[SyntaxDecl], + attrs: &[Attr], + ) -> Result { + let mut mod_ = Self::new(attrs); + let mut idents: Vec = Vec::new(); + for decl in decls { + match decl { + SyntaxDecl::Module { .. } => Err(ValidationError::Syntax { + expected: "type or function declaration", + location: *decl.location(), + })?, + _ => idents.push(mod_.introduce_name(decl.name(), decl.location())?), + } + } + + for (decl, id) in decls.iter().zip(&idents) { + mod_.define_decl(id.clone(), decl)? + } + + for (decl, id) in decls.iter().zip(idents) { + mod_.ensure_finite(id, decl)? + } + + Ok(mod_) + } + + /// Retrieve information about a data type given its identifier + pub fn get_datatype(&self, id: Ident) -> DataTypeEntry<'_> { + let name = &self.names[id.0]; + let data_type = &self.data_types[&id]; + DataTypeEntry { + id, + name, + data_type, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::parser::Parser; + use crate::types::AtomType; + + fn mod_(syntax: &str) -> Result { + let mut parser = Parser::new(syntax); + let decls = parser.match_decls().expect("parses"); + Module::from_declarations(&decls, &[]) + } + + #[test] + fn structs_basic() { + assert!(mod_("struct foo { a: i32}").is_ok()); + assert!(mod_("struct foo { a: i32, b: f32 }").is_ok()); + } + + #[test] + fn struct_two_atoms() { + { + let d = mod_("struct foo { a: i32, b: f32 }").unwrap(); + let members = match &d.data_types[&Ident(0)] { + DataType::Struct { members, .. } => members, + _ => panic!("Unexpected type"), + }; + assert_eq!(members[0].name, "a"); + assert_eq!(members[1].name, "b"); + match &members[0].type_ { + DataTypeRef::Atom(AtomType::I32) => (), + _ => panic!("Unexpected type"), + }; + match &members[1].type_ { + DataTypeRef::Atom(AtomType::F32) => (), + _ => panic!("Unexpected type"), + }; + } + } + + #[test] + fn struct_prev_definition() { + // Refer to a struct defined previously: + assert!(mod_("struct foo { a: i32, b: f64 } struct bar { a: foo }").is_ok()); + } + + #[test] + fn struct_next_definition() { + // Refer to a struct defined afterwards: + assert!(mod_("struct foo { a: i32, b: bar} struct bar { a: i32 }").is_ok()); + } + + #[test] + fn struct_self_referential() { + // Refer to itself + assert!(mod_("struct list { next: list, thing: i32 }").is_err()); + } + + #[test] + fn struct_empty() { + // No members + assert_eq!( + mod_("struct foo {}").err().unwrap(), + ValidationError::Empty { + name: "foo".to_owned(), + location: Location { line: 1, column: 0 }, + } + ); + } + + #[test] + fn struct_duplicate_member() { + // Duplicate member in struct + assert_eq!( + mod_("struct foo { \na: i32, \na: f64}").err().unwrap(), + ValidationError::NameAlreadyExists { + name: "a".to_owned(), + at_location: Location { line: 3, column: 0 }, + previous_location: Location { line: 2, column: 0 }, + } + ); + } + + #[test] + fn struct_duplicate_definition() { + // Duplicate definition of struct + assert_eq!( + mod_("struct foo { a: i32 }\nstruct foo { a: i32 } ") + .err() + .unwrap(), + ValidationError::NameAlreadyExists { + name: "foo".to_owned(), + at_location: Location { line: 2, column: 0 }, + previous_location: Location { line: 1, column: 0 }, + } + ); + } + + #[test] + fn struct_undeclared_member() { + // Refer to type that is not declared + assert_eq!( + mod_("struct foo { \nb: bar }").err().unwrap(), + ValidationError::NameNotFound { + name: "bar".to_owned(), + use_location: Location { line: 2, column: 3 }, + } + ); + } + + #[test] + fn enums() { + assert!(mod_("enum foo { a }").is_ok()); + assert!(mod_("enum foo { a, b }").is_ok()); + + { + let d = mod_("enum foo { a, b }").unwrap(); + let members = match &d.data_types[&Ident(0)] { + DataType::Enum { members, .. } => members, + _ => panic!("Unexpected type"), + }; + assert_eq!(members[0].name, "a"); + assert_eq!(members[1].name, "b"); + } + + // No members + assert_eq!( + mod_("enum foo {}").err().unwrap(), + ValidationError::Empty { + name: "foo".to_owned(), + location: Location { line: 1, column: 0 }, + } + ); + + // Duplicate member in enum + assert_eq!( + mod_("enum foo { \na,\na }").err().unwrap(), + ValidationError::NameAlreadyExists { + name: "a".to_owned(), + at_location: Location { line: 3, column: 0 }, + previous_location: Location { line: 2, column: 0 }, + } + ); + + // Duplicate definition of enum + assert_eq!( + mod_("enum foo { a }\nenum foo { a } ").err().unwrap(), + ValidationError::NameAlreadyExists { + name: "foo".to_owned(), + at_location: Location { line: 2, column: 0 }, + previous_location: Location { line: 1, column: 0 }, + } + ); + } + + #[test] + fn aliases() { + assert!(mod_("type foo = i32;").is_ok()); + assert!(mod_("type foo = f64;").is_ok()); + assert!(mod_("type foo = u8;").is_ok()); + + assert!(mod_("type foo = bar;\nenum bar { a }").is_ok()); + + assert!(mod_("type link = u32;\nstruct list { next: link, thing: i32 }").is_ok()); + } + + #[test] + fn infinite() { + assert_eq!( + mod_("type foo = bar;\ntype bar = foo;").err().unwrap(), + ValidationError::Infinite { + name: "foo".to_owned(), + location: Location { line: 1, column: 0 }, + } + ); + + assert_eq!( + mod_("type foo = bar;\nstruct bar { a: foo }") + .err() + .unwrap(), + ValidationError::Infinite { + name: "foo".to_owned(), + location: Location { line: 1, column: 0 }, + } + ); + + assert_eq!( + mod_("type foo = bar;\nstruct bar { a: baz }\nstruct baz { c: i32, e: foo }") + .err() + .unwrap(), + ValidationError::Infinite { + name: "foo".to_owned(), + location: Location { line: 1, column: 0 }, + } + ); + } + +} diff --git a/lucet-idl/src/package.rs b/lucet-idl/src/package.rs index 2759a38f0..6fbfccf53 100644 --- a/lucet-idl/src/package.rs +++ b/lucet-idl/src/package.rs @@ -1,19 +1,20 @@ use crate::error::ValidationError; -use crate::parser::{SyntaxDecl, SyntaxRef}; -use crate::types::{DataType, DataTypeEntry, DataTypeId, DataTypeRef, Location, Name, NamedMember}; +use crate::module::Module; +use crate::parser::SyntaxDecl; +use crate::types::{Ident, Location, Name}; use std::collections::HashMap; #[derive(Debug, PartialEq, Eq, Clone)] pub struct Package { pub names: Vec, - pub data_types: HashMap, + pub modules: HashMap, } impl Package { fn new() -> Self { Self { names: Vec::new(), - data_types: HashMap::new(), + modules: HashMap::new(), } } @@ -21,7 +22,7 @@ impl Package { &mut self, name: &str, location: &Location, - ) -> Result { + ) -> Result { if let Some(existing) = self.id_for_name(&name) { let prev = self .names @@ -38,414 +39,205 @@ impl Package { name: name.to_owned(), location: *location, }); - Ok(DataTypeId(id)) + Ok(Ident(id)) } } - fn id_for_name(&self, name: &str) -> Option { + fn id_for_name(&self, name: &str) -> Option { for (id, n) in self.names.iter().enumerate() { if n.name == name { - return Some(DataTypeId(id)); + return Some(Ident(id)); } } None } - fn get_ref(&self, syntax_ref: &SyntaxRef) -> Result { - match syntax_ref { - SyntaxRef::Atom { atom, .. } => Ok(DataTypeRef::Atom(*atom)), - SyntaxRef::Name { name, location } => match self.id_for_name(name) { - Some(id) => Ok(DataTypeRef::Defined(id)), - None => Err(ValidationError::NameNotFound { - name: name.clone(), - use_location: *location, - }), - }, - } - } - - fn define_data_type(&mut self, id: DataTypeId, dt: DataType) { - if let Some(prev_def) = self.data_types.insert(id.0, dt) { + fn define_module(&mut self, id: Ident, mod_: Module) { + if let Some(prev_def) = self.modules.insert(id, mod_) { panic!("id {} already defined: {:?}", id, prev_def) } } - fn define_decl(&mut self, id: DataTypeId, decl: &SyntaxDecl) -> Result<(), ValidationError> { - match decl { - SyntaxDecl::Struct { - name, - members, - attrs, - location, - } => { - let mut uniq_membs = HashMap::new(); - let mut dtype_members = Vec::new(); - if members.is_empty() { - Err(ValidationError::Empty { - name: name.clone(), - location: *location, - })? - } - for mem in members { - // Ensure that each member name is unique: - if let Some(existing) = uniq_membs.insert(mem.name.clone(), mem) { - Err(ValidationError::NameAlreadyExists { - name: mem.name.clone(), - at_location: mem.location, - previous_location: existing.location, - })? - } - // Get the DataTypeRef for the member, which ensures that it refers only to - // defined types: - let type_ = self.get_ref(&mem.type_)?; - // build the struct with this as the member: - dtype_members.push(NamedMember { - type_, - name: mem.name.clone(), - attrs: mem.attrs.clone(), - }) - } - self.define_data_type( - id, - DataType::Struct { - members: dtype_members, - attrs: attrs.clone(), - }, - ) - } - SyntaxDecl::Enum { - name, - variants, - attrs, - location, - } => { - let mut uniq_vars = HashMap::new(); - let mut dtype_members = Vec::new(); - if variants.is_empty() { - Err(ValidationError::Empty { - name: name.clone(), - location: *location, - })? - } - for var in variants { - // Ensure that each member name is unique: - if let Some(existing) = uniq_vars.insert(var.name.clone(), var) { - Err(ValidationError::NameAlreadyExists { - name: var.name.clone(), - at_location: var.location, - previous_location: existing.location, - })? - } - // build the struct with this as the member: - dtype_members.push(NamedMember { - type_: (), - name: var.name.clone(), - attrs: var.attrs.clone(), - }) + pub fn from_declarations(decls: &[SyntaxDecl]) -> Result { + let mut pkg = Self::new(); + let mut idents: Vec = Vec::new(); + for decl in decls { + match decl { + SyntaxDecl::Module { name, location, .. } => { + idents.push(pkg.introduce_name(name, location)?); } - self.define_data_type( - id, - DataType::Enum { - members: dtype_members, - attrs: attrs.clone(), - }, - ) - } - SyntaxDecl::Alias { what, attrs, .. } => { - let to = self.get_ref(what)?; - self.define_data_type( - id, - DataType::Alias { - to, - attrs: attrs.clone(), - }, - ); + _ => Err(ValidationError::Syntax { + expected: "module", + location: *decl.location(), + })?, } - SyntaxDecl::Module { .. } => unimplemented!(), - SyntaxDecl::Function { .. } => unimplemented!(), } - Ok(()) - } - fn dfs_walk( - &self, - id: DataTypeId, - visited: &mut [bool], - ordered: &mut Option<&mut Vec>, - ) -> Result<(), ()> { - if visited[id.0] { - Err(())? - } - visited[id.0] = true; - match self.data_types.get(&id.0).expect("data_type is defined") { - DataType::Struct { members, .. } => { - for mem in members { - if let DataTypeRef::Defined(id) = mem.type_ { - self.dfs_walk(id, visited, ordered)? - } - } - } - DataType::Alias { to, .. } => { - if let DataTypeRef::Defined(id) = to { - self.dfs_walk(*id, visited, ordered)? + for (decl, id) in decls.iter().zip(&idents) { + match decl { + SyntaxDecl::Module { decls, attrs, .. } => { + pkg.define_module(*id, Module::from_declarations(decls, attrs)?); } + _ => unreachable!(), } - DataType::Enum { .. } => {} - } - if let Some(ordered) = ordered.as_mut() { - if !ordered.contains(&id) { - ordered.push(id) - } - } - visited[id.0] = false; - Ok(()) - } - - pub fn ordered_dependencies(&self) -> Result, ()> { - let mut visited = Vec::new(); - visited.resize(self.names.len(), false); - let mut ordered = Vec::with_capacity(visited.capacity()); - for id in self.data_types.keys() { - let _ = self.dfs_walk(DataTypeId(*id), &mut visited, &mut Some(&mut ordered)); - } - Ok(ordered) - } - - fn dfs_find_cycle(&self, id: DataTypeId) -> Result<(), ()> { - let mut visited = Vec::new(); - visited.resize(self.names.len(), false); - self.dfs_walk(id, &mut visited, &mut None) - } - - fn ensure_finite(&self, id: DataTypeId, decl: &SyntaxDecl) -> Result<(), ValidationError> { - self.dfs_find_cycle(id) - .map_err(|_| ValidationError::Infinite { - name: decl.name().to_owned(), - location: *decl.location(), - }) - } - - pub fn from_declarations(decls: &[SyntaxDecl]) -> Result { - let mut desc = Self::new(); - let mut idents: Vec = Vec::new(); - for decl in decls { - idents.push(desc.introduce_name(decl.name(), decl.location())?) - } - - for (decl, id) in decls.iter().zip(&idents) { - desc.define_decl(id.clone(), decl)? } - for (decl, id) in decls.iter().zip(idents) { - desc.ensure_finite(id, decl)? - } - - Ok(desc) - } - - /// Retrieve information about a data type given its identifier - pub fn get_datatype(&self, id: DataTypeId) -> DataTypeEntry<'_> { - let name = &self.names[id.0]; - let data_type = &self.data_types[&id.0]; - DataTypeEntry { - id, - name, - data_type, - } + Ok(pkg) } } #[cfg(test)] -mod tests { - use super::super::parser::Parser; +mod test { use super::*; - use crate::types::AtomType; + use crate::parser::Parser; + use crate::types::{AtomType, DataType, DataTypeRef}; - fn pkg(syntax: &str) -> Result { + fn pkg_(syntax: &str) -> Result { let mut parser = Parser::new(syntax); let decls = parser.match_decls().expect("parses"); Package::from_declarations(&decls) } #[test] - fn structs_basic() { - assert!(pkg("struct foo { a: i32}").is_ok()); - assert!(pkg("struct foo { a: i32, b: f32 }").is_ok()); - } - - #[test] - fn struct_two_atoms() { - { - let d = pkg("struct foo { a: i32, b: f32 }").unwrap(); - let members = match &d.data_types[&0] { - DataType::Struct { members, .. } => members, - _ => panic!("Unexpected type"), - }; - assert_eq!(members[0].name, "a"); - assert_eq!(members[1].name, "b"); - match &members[0].type_ { - DataTypeRef::Atom(AtomType::I32) => (), - _ => panic!("Unexpected type"), - }; - match &members[1].type_ { - DataTypeRef::Atom(AtomType::F32) => (), - _ => panic!("Unexpected type"), - }; - } - } - - #[test] - fn struct_prev_definition() { - // Refer to a struct defined previously: - assert!(pkg("struct foo { a: i32, b: f64 } struct bar { a: foo }").is_ok()); - } - - #[test] - fn struct_next_definition() { - // Refer to a struct defined afterwards: - assert!(pkg("struct foo { a: i32, b: bar} struct bar { a: i32 }").is_ok()); - } - - #[test] - fn struct_self_referential() { - // Refer to itself - assert!(pkg("struct list { next: list, thing: i32 }").is_err()); - } - - #[test] - fn struct_empty() { - // No members + fn trivial() { + let pkg = pkg_("mod empty {}").expect("valid package"); assert_eq!( - pkg("struct foo {}").err().unwrap(), - ValidationError::Empty { - name: "foo".to_owned(), - location: Location { line: 1, column: 0 }, - } + pkg.names, + vec![Name { + name: "empty".to_owned(), + location: Location { line: 1, column: 0 } + }] ); - } - - #[test] - fn struct_duplicate_member() { - // Duplicate member in struct assert_eq!( - pkg("struct foo { \na: i32, \na: f64}").err().unwrap(), - ValidationError::NameAlreadyExists { - name: "a".to_owned(), - at_location: Location { line: 3, column: 0 }, - previous_location: Location { line: 2, column: 0 }, - } + pkg.modules, + vec![( + Ident(0), + Module { + names: Vec::new(), + attrs: Vec::new(), + data_types: HashMap::new(), + } + )] + .into_iter() + .collect::>() ); } #[test] - fn struct_duplicate_definition() { - // Duplicate definition of struct + fn multiple_empty_mods() { + let pkg = pkg_("mod empty1 {} mod empty2{}mod\nempty3{//\n}").expect("valid package"); assert_eq!( - pkg("struct foo { a: i32 }\nstruct foo { a: i32 } ") - .err() - .unwrap(), - ValidationError::NameAlreadyExists { - name: "foo".to_owned(), - at_location: Location { line: 2, column: 0 }, - previous_location: Location { line: 1, column: 0 }, - } + pkg.names, + vec![ + Name { + name: "empty1".to_owned(), + location: Location { line: 1, column: 0 } + }, + Name { + name: "empty2".to_owned(), + location: Location { + line: 1, + column: 14 + } + }, + Name { + name: "empty3".to_owned(), + location: Location { + line: 1, + column: 26 + } + } + ] ); - } - - #[test] - fn struct_undeclared_member() { - // Refer to type that is not declared assert_eq!( - pkg("struct foo { \nb: bar }").err().unwrap(), - ValidationError::NameNotFound { - name: "bar".to_owned(), - use_location: Location { line: 2, column: 3 }, - } + pkg.modules, + vec![ + ( + Ident(0), + Module { + names: Vec::new(), + attrs: Vec::new(), + data_types: HashMap::new(), + } + ), + ( + Ident(1), + Module { + names: Vec::new(), + attrs: Vec::new(), + data_types: HashMap::new(), + } + ), + ( + Ident(2), + Module { + names: Vec::new(), + attrs: Vec::new(), + data_types: HashMap::new(), + } + ) + ] + .into_iter() + .collect::>() ); } #[test] - fn enums() { - assert!(pkg("enum foo { a }").is_ok()); - assert!(pkg("enum foo { a, b }").is_ok()); - - { - let d = pkg("enum foo { a, b }").unwrap(); - let members = match &d.data_types[&0] { - DataType::Enum { members, .. } => members, - _ => panic!("Unexpected type"), - }; - assert_eq!(members[0].name, "a"); - assert_eq!(members[1].name, "b"); - } - - // No members + fn mod_with_a_type() { + let pkg = pkg_("mod foo { type bar = u8; }").expect("valid package"); assert_eq!( - pkg("enum foo {}").err().unwrap(), - ValidationError::Empty { + pkg.names, + vec![Name { name: "foo".to_owned(), - location: Location { line: 1, column: 0 }, - } + location: Location { line: 1, column: 0 } + }] ); - - // Duplicate member in enum - assert_eq!( - pkg("enum foo { \na,\na }").err().unwrap(), - ValidationError::NameAlreadyExists { - name: "a".to_owned(), - at_location: Location { line: 3, column: 0 }, - previous_location: Location { line: 2, column: 0 }, - } - ); - - // Duplicate definition of enum assert_eq!( - pkg("enum foo { a }\nenum foo { a } ").err().unwrap(), - ValidationError::NameAlreadyExists { - name: "foo".to_owned(), - at_location: Location { line: 2, column: 0 }, - previous_location: Location { line: 1, column: 0 }, - } + pkg.modules, + vec![( + Ident(0), + Module { + names: vec![Name { + name: "bar".to_owned(), + location: Location { + line: 1, + column: 10 + } + }], + attrs: Vec::new(), + data_types: vec![( + Ident(0), + DataType::Alias { + to: DataTypeRef::Atom(AtomType::U8), + attrs: Vec::new() + } + )] + .into_iter() + .collect::>(), + } + )] + .into_iter() + .collect::>() ); } #[test] - fn aliases() { - assert!(pkg("type foo = i32").is_ok()); - assert!(pkg("type foo = f64").is_ok()); - assert!(pkg("type foo = u8").is_ok()); - - assert!(pkg("type foo = bar\nenum bar { a }").is_ok()); - - assert!(pkg("type link = u32\nstruct list { next: link, thing: i32 }").is_ok()); + fn no_mod_duplicate_name() { + pkg_("mod foo {} mod foo {}").err().expect("error package"); } #[test] - fn infinite() { - assert_eq!( - pkg("type foo = bar\ntype bar = foo").err().unwrap(), - ValidationError::Infinite { - name: "foo".to_owned(), - location: Location { line: 1, column: 0 }, - } - ); - - assert_eq!( - pkg("type foo = bar\nstruct bar { a: foo }").err().unwrap(), - ValidationError::Infinite { - name: "foo".to_owned(), - location: Location { line: 1, column: 0 }, - } - ); + fn no_mod_in_mod() { + pkg_("mod foo { mod bar { }}").err().expect("error package"); + pkg_("mod foo { enum whatever {} mod bar { }}") + .err() + .expect("error package"); + } - assert_eq!( - pkg("type foo = bar\nstruct bar { a: baz }\nstruct baz { c: i32, e: foo }") - .err() - .unwrap(), - ValidationError::Infinite { - name: "foo".to_owned(), - location: Location { line: 1, column: 0 }, - } - ); + #[test] + fn no_top_level_types() { + pkg_("mod foo { } enum bar {}") + .err() + .expect("error package"); } } diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index 5e698e183..f5a766e44 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -25,7 +25,7 @@ pub enum SyntaxDecl { }, Module { name: String, - decls: Vec>, + decls: Vec, attrs: Vec, location: Location, }, @@ -434,6 +434,7 @@ impl<'a> Parser<'a> { let name = err_ctx!(err_msg, self.match_a_word("expected type name"))?; err_ctx!(err_msg, self.match_token(Token::Equals, "expected ="))?; let what = self.match_ref("type value")?; + err_ctx!(err_msg, self.match_token(Token::Semi, "expected ;"))?; return Ok(Some(SyntaxDecl::Alias { name: name.to_owned(), what, @@ -454,7 +455,7 @@ impl<'a> Parser<'a> { break; } else { match self.match_decl("declaration") { - Ok(Some(decl)) => decls.push(Box::new(decl)), + Ok(Some(decl)) => decls.push(decl), Ok(None) => parse_err!(self.location, "missing close brace '}'")?, Err(e) => Err(e)?, } @@ -1002,9 +1003,9 @@ mod tests { .expect("valid decl"), SyntaxDecl::Module { name: "one".to_owned(), - decls: vec![Box::new(SyntaxDecl::Module { + decls: vec![SyntaxDecl::Module { name: "two".to_owned(), - decls: vec![Box::new(SyntaxDecl::Module { + decls: vec![SyntaxDecl::Module { name: "three".to_owned(), decls: Vec::new(), attrs: Vec::new(), @@ -1012,13 +1013,13 @@ mod tests { line: 1, column: 20 }, - })], + }], attrs: Vec::new(), location: Location { line: 1, column: 10 }, - })], + }], attrs: Vec::new(), location: Location { line: 1, column: 0 }, } @@ -1037,7 +1038,7 @@ mod tests { SyntaxDecl::Module { name: "one".to_owned(), decls: vec![ - Box::new(SyntaxDecl::Enum { + SyntaxDecl::Enum { name: "foo".to_owned(), variants: Vec::new(), attrs: Vec::new(), @@ -1045,8 +1046,8 @@ mod tests { line: 1, column: 10 }, - }), - Box::new(SyntaxDecl::Struct { + }, + SyntaxDecl::Struct { name: "bar".to_owned(), members: Vec::new(), attrs: Vec::new(), @@ -1054,7 +1055,7 @@ mod tests { line: 1, column: 22 }, - }) + } ], attrs: Vec::new(), location: Location { line: 1, column: 0 }, @@ -1074,7 +1075,7 @@ mod tests { SyntaxDecl::Module { name: "one".to_owned(), decls: vec![ - Box::new(SyntaxDecl::Enum { + SyntaxDecl::Enum { name: "foo".to_owned(), variants: Vec::new(), attrs: vec![Attr::new( @@ -1089,8 +1090,8 @@ mod tests { line: 2, column: 17 }, - }), - Box::new(SyntaxDecl::Struct { + }, + SyntaxDecl::Struct { name: "bar".to_owned(), members: Vec::new(), attrs: Vec::new(), @@ -1098,7 +1099,7 @@ mod tests { line: 2, column: 29 }, - }) + } ], attrs: vec![Attr::new("a", "b", Location { line: 1, column: 0 }),], location: Location { line: 2, column: 0 }, diff --git a/lucet-idl/src/rust/mod.rs b/lucet-idl/src/rust/mod.rs index aa7b87d8e..29780437d 100644 --- a/lucet-idl/src/rust/mod.rs +++ b/lucet-idl/src/rust/mod.rs @@ -9,7 +9,7 @@ use crate::package::Package; use crate::pretty_writer::PrettyWriter; use crate::target::Target; use crate::types::AtomType; -use crate::types::{DataType, DataTypeEntry, DataTypeId, DataTypeRef}; +use crate::types::{DataType, DataTypeEntry, DataTypeRef, Ident}; use heck::{CamelCase, SnakeCase}; use std::collections::HashMap; use std::io::Write; @@ -30,7 +30,7 @@ struct CTypeInfo<'t> { pub struct RustGenerator { pub target: Target, pub backend_config: BackendConfig, - pub defined: HashMap, + pub defined: HashMap, } impl RustGenerator { diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index 6a11713c8..21a90d343 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -38,9 +38,9 @@ impl Attr { } #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] -pub struct DataTypeId(pub usize); +pub struct Ident(pub usize); -impl fmt::Display for DataTypeId { +impl fmt::Display for Ident { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) } @@ -48,7 +48,7 @@ impl fmt::Display for DataTypeId { #[derive(Debug, PartialEq, Eq, Clone)] pub enum DataTypeRef { - Defined(DataTypeId), + Defined(Ident), Atom(AtomType), } @@ -91,7 +91,7 @@ impl fmt::Display for Name { /// its internal IDL representation #[derive(Debug, Clone)] pub struct DataTypeEntry<'t> { - pub id: DataTypeId, + pub id: Ident, pub name: &'t Name, pub data_type: &'t DataType, } diff --git a/lucet-idl/tests/example.idl b/lucet-idl/tests/example.idl index 3a52d0fa2..1776f245f 100644 --- a/lucet-idl/tests/example.idl +++ b/lucet-idl/tests/example.idl @@ -1,23 +1,26 @@ +mod example { + // Primitive types: + // `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`, `f32`, `f64`. -// Primitive types: -// `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`, `f32`, `f64`. + // Enumerations -// Enumerations + enum color { + red, + blue, + green, + } -enum color { - red, blue, green -} + // Aliases -// Aliases + type colour = color; + type col = colour; -type colour = color -type col = colour + // Structures -// Structures + struct st { + a: i8, + b: i32, + c: color, + } -struct st { - a: i8, - b: i32, - c: color, } - From 4fdd39052bd547f3bc0e5e00b78ff8463c3825ea Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 6 May 2019 20:02:58 -0700 Subject: [PATCH 188/512] lucet-idl: modules can have functions --- lucet-idl/src/module.rs | 233 ++++++++++++++++++++++++++++++++++++++- lucet-idl/src/package.rs | 5 + lucet-idl/src/parser.rs | 85 +++++++------- lucet-idl/src/types.rs | 14 +++ 4 files changed, 291 insertions(+), 46 deletions(-) diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index 87f0b3659..978d4cf93 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -1,7 +1,8 @@ use crate::error::ValidationError; use crate::parser::{SyntaxDecl, SyntaxRef}; use crate::types::{ - Attr, DataType, DataTypeEntry, DataTypeRef, Ident, Location, Name, NamedMember, + Attr, DataType, DataTypeEntry, DataTypeRef, FuncDecl, FuncRet, Ident, Location, Name, + NamedMember, }; use std::collections::HashMap; #[derive(Debug, PartialEq, Eq, Clone)] @@ -9,6 +10,7 @@ pub struct Module { pub names: Vec, pub attrs: Vec, pub data_types: HashMap, + pub funcs: HashMap, } impl Module { @@ -17,6 +19,7 @@ impl Module { names: Vec::new(), attrs: attrs.to_vec(), data_types: HashMap::new(), + funcs: HashMap::new(), } } @@ -73,6 +76,12 @@ impl Module { } } + fn define_function(&mut self, id: Ident, decl: FuncDecl) { + if let Some(prev_def) = self.funcs.insert(id, decl) { + panic!("id {} already defined: {:?}", id, prev_def) + } + } + fn define_decl(&mut self, id: Ident, decl: &SyntaxDecl) -> Result<(), ValidationError> { match decl { SyntaxDecl::Struct { @@ -164,8 +173,52 @@ impl Module { }, ); } - SyntaxDecl::Module { .. } => unimplemented!(), - SyntaxDecl::Function { .. } => unimplemented!(), + SyntaxDecl::Function { + args, rets, attrs, .. + } => { + let mut arg_names: HashMap = HashMap::new(); + let args = args + .iter() + .map(|arg_syntax| { + let type_ = self.get_ref(&arg_syntax.type_)?; + if let Some(previous_location) = arg_names.get(&arg_syntax.name) { + Err(ValidationError::NameAlreadyExists { + name: arg_syntax.name.clone(), + at_location: arg_syntax.location, + previous_location: previous_location.clone(), + })?; + } else { + arg_names.insert(arg_syntax.name.clone(), arg_syntax.location.clone()); + } + Ok(NamedMember { + name: arg_syntax.name.clone(), + type_, + attrs: arg_syntax.attrs.clone(), + }) + }) + .collect::>, _>>()?; + + let rets = rets + .iter() + .map(|ret_syntax| { + let type_ = self.get_ref(&ret_syntax.type_)?; + Ok(FuncRet { + type_, + attrs: ret_syntax.attrs.clone(), + }) + }) + .collect::, _>>()?; + + self.define_function( + id, + FuncDecl { + args, + rets, + attrs: attrs.clone(), + }, + ); + } + SyntaxDecl::Module { .. } => unreachable!(), // Should be excluded by from_declarations constructor } Ok(()) } @@ -220,7 +273,7 @@ impl Module { self.dfs_walk(id, &mut visited, &mut None) } - fn ensure_finite(&self, id: Ident, decl: &SyntaxDecl) -> Result<(), ValidationError> { + fn ensure_finite_datatype(&self, id: Ident, decl: &SyntaxDecl) -> Result<(), ValidationError> { self.dfs_find_cycle(id) .map_err(|_| ValidationError::Infinite { name: decl.name().to_owned(), @@ -249,7 +302,9 @@ impl Module { } for (decl, id) in decls.iter().zip(idents) { - mod_.ensure_finite(id, decl)? + if decl.is_datatype() { + mod_.ensure_finite_datatype(id, decl)? + } } Ok(mod_) @@ -463,4 +518,172 @@ mod tests { ); } + #[test] + fn func_trivial() { + assert_eq!( + mod_("fn trivial();").ok().unwrap(), + Module { + names: vec![Name { + name: "trivial".to_owned(), + location: Location { line: 1, column: 0 } + }], + funcs: vec![( + Ident(0), + FuncDecl { + args: Vec::new(), + rets: Vec::new(), + attrs: Vec::new(), + } + )] + .into_iter() + .collect::>(), + data_types: HashMap::new(), + attrs: Vec::new(), + } + ); + } + #[test] + fn func_one_arg() { + assert_eq!( + mod_("fn trivial(a: u8);").ok().unwrap(), + Module { + names: vec![Name { + name: "trivial".to_owned(), + location: Location { line: 1, column: 0 } + }], + funcs: vec![( + Ident(0), + FuncDecl { + args: vec![NamedMember { + type_: DataTypeRef::Atom(AtomType::U8), + name: "a".to_owned(), + attrs: Vec::new(), + }], + rets: Vec::new(), + attrs: Vec::new(), + } + )] + .into_iter() + .collect::>(), + data_types: HashMap::new(), + attrs: Vec::new(), + } + ); + } + + #[test] + fn func_one_ret() { + assert_eq!( + mod_("fn trivial() -> u8;").ok().unwrap(), + Module { + names: vec![Name { + name: "trivial".to_owned(), + location: Location { line: 1, column: 0 } + }], + funcs: vec![( + Ident(0), + FuncDecl { + args: Vec::new(), + rets: vec![FuncRet { + type_: DataTypeRef::Atom(AtomType::U8), + attrs: Vec::new(), + }], + attrs: Vec::new(), + } + )] + .into_iter() + .collect::>(), + data_types: HashMap::new(), + attrs: Vec::new(), + } + ); + } + + #[test] + fn func_one_ret_defined_type() { + assert_eq!( + mod_("fn trivial() -> foo;\ntype foo = u8;").ok().unwrap(), + Module { + names: vec![ + Name { + name: "trivial".to_owned(), + location: Location { line: 1, column: 0 } + }, + Name { + name: "foo".to_owned(), + location: Location { line: 2, column: 0 } + } + ], + funcs: vec![( + Ident(0), + FuncDecl { + args: Vec::new(), + rets: vec![FuncRet { + type_: DataTypeRef::Defined(Ident(1)), + attrs: Vec::new(), + }], + attrs: Vec::new(), + } + )] + .into_iter() + .collect::>(), + data_types: vec![( + Ident(1), + DataType::Alias { + to: DataTypeRef::Atom(AtomType::U8), + attrs: Vec::new() + } + )] + .into_iter() + .collect::>(), + attrs: Vec::new(), + } + ); + } + + #[test] + fn func_unknown_arg_type() { + assert_eq!( + mod_("fn trivial(a: foo);").err().unwrap(), + ValidationError::NameNotFound { + name: "foo".to_owned(), + use_location: Location { + line: 1, + column: 14 + }, + } + ); + } + + #[test] + fn func_unknown_ret_type() { + assert_eq!( + mod_("fn trivial(a: u8) -> foo;").err().unwrap(), + ValidationError::NameNotFound { + name: "foo".to_owned(), + use_location: Location { + line: 1, + column: 21 + }, + } + ); + } + + #[test] + fn func_duplicate_arg() { + assert_eq!( + mod_("fn trivial(a: u8, a: u8);").err().unwrap(), + ValidationError::NameAlreadyExists { + name: "a".to_owned(), + at_location: Location { + line: 1, + column: 18 + }, + previous_location: Location { + line: 1, + column: 11 + }, + } + ); + } } diff --git a/lucet-idl/src/package.rs b/lucet-idl/src/package.rs index 6fbfccf53..67fb3f780 100644 --- a/lucet-idl/src/package.rs +++ b/lucet-idl/src/package.rs @@ -116,6 +116,7 @@ mod test { names: Vec::new(), attrs: Vec::new(), data_types: HashMap::new(), + funcs: HashMap::new(), } )] .into_iter() @@ -158,6 +159,7 @@ mod test { names: Vec::new(), attrs: Vec::new(), data_types: HashMap::new(), + funcs: HashMap::new(), } ), ( @@ -166,6 +168,7 @@ mod test { names: Vec::new(), attrs: Vec::new(), data_types: HashMap::new(), + funcs: HashMap::new(), } ), ( @@ -174,6 +177,7 @@ mod test { names: Vec::new(), attrs: Vec::new(), data_types: HashMap::new(), + funcs: HashMap::new(), } ) ] @@ -205,6 +209,7 @@ mod test { } }], attrs: Vec::new(), + funcs: HashMap::new(), data_types: vec![( Ident(0), DataType::Alias { diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index f5a766e44..ccbdbc9b7 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -31,8 +31,8 @@ pub enum SyntaxDecl { }, Function { name: String, - args: Vec, - rets: Vec, + args: Vec, + rets: Vec, attrs: Vec, location: Location, }, @@ -57,6 +57,12 @@ impl SyntaxDecl { SyntaxDecl::Function { location, .. } => &location, } } + pub fn is_datatype(&self) -> bool { + match self { + SyntaxDecl::Struct { .. } | SyntaxDecl::Enum { .. } | SyntaxDecl::Alias { .. } => true, + _ => false, + } + } } #[derive(Debug, PartialEq, Eq, Clone)] @@ -81,7 +87,7 @@ pub struct EnumVariant { } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct FuncArg { +pub struct FuncArgSyntax { pub name: String, pub type_: SyntaxRef, pub attrs: Vec, @@ -89,7 +95,7 @@ pub struct FuncArg { } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct FuncRet { +pub struct FuncRetSyntax { pub type_: SyntaxRef, pub attrs: Vec, pub location: Location, @@ -303,7 +309,7 @@ impl<'a> Parser<'a> { Ok(names) } - fn match_func_args(&mut self) -> Result, ParseError> { + fn match_func_args(&mut self) -> Result, ParseError> { let mut args = Vec::new(); let mut attrs = Vec::new(); loop { @@ -322,7 +328,7 @@ impl<'a> Parser<'a> { self.match_token(Token::Colon, "expected :")?; let type_ref = self.match_ref("expected type")?; - args.push(FuncArg { + args.push(FuncArgSyntax { name: name.to_string(), type_: type_ref, attrs: attrs.clone(), @@ -353,7 +359,7 @@ impl<'a> Parser<'a> { Ok(args) } - fn match_func_rets(&mut self) -> Result, ParseError> { + fn match_func_rets(&mut self) -> Result, ParseError> { let mut args = Vec::new(); let mut attrs = Vec::new(); loop { @@ -369,7 +375,7 @@ impl<'a> Parser<'a> { _ => { let location = self.location; let type_ref = self.match_ref("expected type, attribute, or ;")?; - args.push(FuncRet { + args.push(FuncRetSyntax { type_: type_ref, attrs: attrs.clone(), location, @@ -482,7 +488,10 @@ impl<'a> Parser<'a> { self.consume(); err_ctx!(err_msg, self.match_func_rets())? } - Some(Token::Semi) => Vec::new(), + Some(Token::Semi) => { + self.consume(); + Vec::new() + } t => err_ctx!( err_msg, parse_err!(self.location, "expected -> or ;, got {:?}", t) @@ -1109,45 +1118,42 @@ mod tests { #[test] fn fn_trivial() { - let canonical = SyntaxDecl::Function { + let canonical = vec![SyntaxDecl::Function { name: "trivial".to_owned(), args: Vec::new(), rets: Vec::new(), attrs: Vec::new(), location: Location { line: 1, column: 0 }, - }; + }]; assert_eq!( Parser::new("fn trivial();") // 0 5 10 - .match_decl("trivial func") - .expect("valid parse") - .expect("valid decl"), + .match_decls() + .expect("valid parse"), canonical, ); assert_eq!( Parser::new("fn trivial ( ) ;") // 0 5 10 - .match_decl("trivial func") - .expect("valid parse") - .expect("valid decl"), + .match_decls() + .expect("valid parse"), canonical, ); assert_eq!( Parser::new("fn trivial()->;") // 0 5 10 - .match_decl("trivial func") - .expect("valid parse") - .expect("valid decl"), + .match_decls() + .expect("valid parse"), canonical, ); } #[test] fn fn_return_u8() { - let canonical = SyntaxDecl::Function { + let canonical = vec![SyntaxDecl::Function { name: "getch".to_owned(), args: Vec::new(), - rets: vec![FuncRet { + rets: vec![FuncRetSyntax { type_: SyntaxRef::Atom { atom: AtomType::U8, location: Location { @@ -1163,29 +1169,26 @@ mod tests { }], attrs: Vec::new(), location: Location { line: 1, column: 0 }, - }; + }]; assert_eq!( Parser::new("fn getch() -> u8;") // 0 5 10 - .match_decl("returns u8") - .expect("valid parse") - .expect("valid decl"), + .match_decls() + .expect("valid decls"), canonical ); assert_eq!( Parser::new("fn getch() -> u8,;") // 0 5 10 - .match_decl("returns u8") - .expect("valid parse") - .expect("valid decl"), + .match_decls() + .expect("valid decls"), canonical ); assert_eq!( Parser::new("fn getch() -> u8 , ;") // 0 5 10 - .match_decl("returns u8") - .expect("valid parse") - .expect("valid decl"), + .match_decls() + .expect("valid decls"), canonical ); } @@ -1194,7 +1197,7 @@ mod tests { fn fn_one_arg() { let canonical = SyntaxDecl::Function { name: "foo".to_owned(), - args: vec![FuncArg { + args: vec![FuncArgSyntax { type_: SyntaxRef::Atom { atom: AtomType::U8, location: Location { @@ -1233,7 +1236,7 @@ mod tests { let canonical = SyntaxDecl::Function { name: "foo".to_owned(), args: vec![ - FuncArg { + FuncArgSyntax { type_: SyntaxRef::Atom { atom: AtomType::U8, location: Location { @@ -1245,7 +1248,7 @@ mod tests { attrs: Vec::new(), location: Location { line: 1, column: 7 }, }, - FuncArg { + FuncArgSyntax { type_: SyntaxRef::Atom { atom: AtomType::F64, location: Location { @@ -1295,7 +1298,7 @@ mod tests { name: "getch".to_owned(), args: Vec::new(), rets: vec![ - FuncRet { + FuncRetSyntax { type_: SyntaxRef::Atom { atom: AtomType::U8, location: Location { @@ -1309,7 +1312,7 @@ mod tests { column: 14, }, }, - FuncRet { + FuncRetSyntax { type_: SyntaxRef::Atom { atom: AtomType::U16, location: Location { @@ -1323,7 +1326,7 @@ mod tests { column: 18, }, }, - FuncRet { + FuncRetSyntax { type_: SyntaxRef::Atom { atom: AtomType::U32, location: Location { @@ -1356,7 +1359,7 @@ mod tests { name: "getch".to_owned(), args: Vec::new(), rets: vec![ - FuncRet { + FuncRetSyntax { type_: SyntaxRef::Atom { atom: AtomType::U8, location: Location { @@ -1377,7 +1380,7 @@ mod tests { column: 21, }, }, - FuncRet { + FuncRetSyntax { type_: SyntaxRef::Atom { atom: AtomType::U16, location: Location { @@ -1408,7 +1411,7 @@ mod tests { column: 39, }, }, - FuncRet { + FuncRetSyntax { type_: SyntaxRef::Atom { atom: AtomType::U32, location: Location { diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index 21a90d343..bc3e6aeea 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -75,6 +75,20 @@ pub enum DataType { }, } +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct FuncDecl { + pub args: Vec>, + pub rets: Vec, + pub attrs: Vec, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct FuncRet { + pub type_: DataTypeRef, + pub attrs: Vec, +} + + #[derive(Debug, PartialEq, Eq, Clone)] pub struct Name { pub name: String, From 91b0e9eb5a14b3e0111f56a5d63186a0ab9423cf Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 6 May 2019 20:04:03 -0700 Subject: [PATCH 189/512] rustfmt --- lucet-idl/src/config.rs | 2 +- lucet-idl/src/error.rs | 10 ++++++---- lucet-idl/src/generator.rs | 10 +++------- lucet-idl/src/types.rs | 1 - 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/lucet-idl/src/config.rs b/lucet-idl/src/config.rs index fb91a7366..2434e6384 100644 --- a/lucet-idl/src/config.rs +++ b/lucet-idl/src/config.rs @@ -31,7 +31,7 @@ impl Config { pub fn generator(&self) -> Box> { unimplemented!() - /* disabled while module / pkg representation in flux + /* disabled while module / pkg representation in flux match self.backend { Backend::C => Box::new(CGenerator { target: self.target, diff --git a/lucet-idl/src/error.rs b/lucet-idl/src/error.rs index ce06013fe..7626e577d 100644 --- a/lucet-idl/src/error.rs +++ b/lucet-idl/src/error.rs @@ -59,7 +59,7 @@ pub enum ValidationError { Syntax { expected: &'static str, location: Location, - } + }, } impl fmt::Display for ValidationError { @@ -85,9 +85,11 @@ impl fmt::Display for ValidationError { "Circular reference for {} at line {}", name, location.line ), - ValidationError::Syntax { expected, location } => { - write!(f, "Invalid syntax: expected {} at line {}", expected, location.line) - } + ValidationError::Syntax { expected, location } => write!( + f, + "Invalid syntax: expected {} at line {}", + expected, location.line + ), } } } diff --git a/lucet-idl/src/generator.rs b/lucet-idl/src/generator.rs index c0475c114..4e4e50318 100644 --- a/lucet-idl/src/generator.rs +++ b/lucet-idl/src/generator.rs @@ -108,13 +108,9 @@ pub trait Generator { ) -> Result<(), IDLError> { let data_type_entry = module.get_datatype(id); match &data_type_entry.data_type { - DataType::Struct { .. } => self.gen_accessors_struct( - module, - cache, - pretty_writer, - &data_type_entry, - hierarchy, - ), + DataType::Struct { .. } => { + self.gen_accessors_struct(module, cache, pretty_writer, &data_type_entry, hierarchy) + } DataType::Alias { .. } => { self.gen_accessors_alias(module, cache, pretty_writer, &data_type_entry, hierarchy) } diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index bc3e6aeea..56aaffa19 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -88,7 +88,6 @@ pub struct FuncRet { pub attrs: Vec, } - #[derive(Debug, PartialEq, Eq, Clone)] pub struct Name { pub name: String, From 88d7dd00d29c771e17cc86afb6a663ca741aacc8 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 7 May 2019 15:17:21 -0700 Subject: [PATCH 190/512] lucet-idl: make c backend work again, make cache internal to it --- lucet-idl/src/c/alias.rs | 9 ++--- lucet-idl/src/{ => c}/cache.rs | 0 lucet-idl/src/c/enum.rs | 5 +-- lucet-idl/src/c/macros.rs | 4 +- lucet-idl/src/c/mod.rs | 69 +++++++++++++++++----------------- lucet-idl/src/c/struct.rs | 7 ++-- lucet-idl/src/config.rs | 16 +++----- lucet-idl/src/generator.rs | 25 ++++-------- lucet-idl/src/lib.rs | 7 +--- 9 files changed, 60 insertions(+), 82 deletions(-) rename lucet-idl/src/{ => c}/cache.rs (100%) diff --git a/lucet-idl/src/c/alias.rs b/lucet-idl/src/c/alias.rs index 10c79c98c..0a67d26e3 100644 --- a/lucet-idl/src/c/alias.rs +++ b/lucet-idl/src/c/alias.rs @@ -4,8 +4,7 @@ use super::*; // and alignment rules of what it ultimately points to pub fn generate( cgenerator: &mut CGenerator, - package: &Package, - cache: &mut Cache, + module: &Module, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { @@ -14,20 +13,20 @@ pub fn generate( } else { unreachable!() }; - let type_info = cgenerator.type_info(package, cache, type_); + let type_info = cgenerator.type_info(module, type_); pretty_writer.indent()?; pretty_writer.write(format!("typedef {}", type_info.type_name).as_bytes())?; pretty_writer.space()?; pretty_writer.write(data_type_entry.name.name.as_bytes())?; pretty_writer.write(b";")?; - let leaf_type_info = cgenerator.type_info(package, cache, type_info.leaf_data_type_ref); + let leaf_type_info = cgenerator.type_info(module, type_info.leaf_data_type_ref); if leaf_type_info.type_name != type_info.type_name { pretty_writer.write(b" // equivalent to ")?; pretty_writer.write(leaf_type_info.type_name.as_bytes())?; } pretty_writer.eol()?; pretty_writer.eob()?; - cache.store_type( + cgenerator.cache.store_type( data_type_entry.id, CachedTypeEntry { type_size: type_info.type_size, diff --git a/lucet-idl/src/cache.rs b/lucet-idl/src/c/cache.rs similarity index 100% rename from lucet-idl/src/cache.rs rename to lucet-idl/src/c/cache.rs diff --git a/lucet-idl/src/c/enum.rs b/lucet-idl/src/c/enum.rs index 0425d90d5..5fff7c4f5 100644 --- a/lucet-idl/src/c/enum.rs +++ b/lucet-idl/src/c/enum.rs @@ -4,8 +4,7 @@ use super::*; // The typedef is required to use a native type which is consistent across all architectures pub fn generate( cgenerator: &mut CGenerator, - _package: &Package, - cache: &mut Cache, + _module: &Module, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { @@ -66,7 +65,7 @@ pub fn generate( )?; pretty_writer.eob()?; - cache.store_type( + cgenerator.cache.store_type( data_type_entry.id, CachedTypeEntry { type_size, diff --git a/lucet-idl/src/c/macros.rs b/lucet-idl/src/c/macros.rs index 67a8168ac..74ec5c0d0 100644 --- a/lucet-idl/src/c/macros.rs +++ b/lucet-idl/src/c/macros.rs @@ -39,7 +39,7 @@ pub fn define( // Return a macro name for a type reference pub fn macro_for_data_type_ref( - package: &Package, + module: &Module, prefix: &str, data_type_ref: &DataTypeRef, ) -> String { @@ -49,7 +49,7 @@ pub fn macro_for_data_type_ref( format!("{}", native_type_size) } DataTypeRef::Defined(data_type_id) => { - let data_type_entry = package.get_datatype(*data_type_id); + let data_type_entry = module.get_datatype(*data_type_id); macro_for(prefix, &data_type_entry.name.name) } } diff --git a/lucet-idl/src/c/mod.rs b/lucet-idl/src/c/mod.rs index 471cf10a6..dba1948cc 100644 --- a/lucet-idl/src/c/mod.rs +++ b/lucet-idl/src/c/mod.rs @@ -3,6 +3,7 @@ // mod accessors; mod alias; +mod cache; mod catom; mod r#enum; mod macros; @@ -11,10 +12,10 @@ mod r#struct; pub(crate) use self::catom::*; use crate::backend::*; -use crate::cache::{Cache, CachedStructMemberEntry, CachedTypeEntry}; +use self::cache::{Cache, CachedStructMemberEntry, CachedTypeEntry}; use crate::error::IDLError; use crate::generator::{Generator, Hierarchy}; -use crate::package::Package; +use crate::module::Module; use crate::pretty_writer::PrettyWriter; use crate::target::Target; use crate::types::{DataType, DataTypeEntry, DataTypeRef}; @@ -36,6 +37,7 @@ struct CTypeInfo<'t> { pub struct CGenerator { pub target: Target, pub backend_config: BackendConfig, + pub cache: Cache, } impl Generator for CGenerator { @@ -50,8 +52,7 @@ impl Generator for CGenerator { fn gen_type_header( &mut self, - _package: &Package, - _cache: &mut Cache, + _module: &Module, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { @@ -68,40 +69,36 @@ impl Generator for CGenerator { // and alignment rules of what it ultimately points to fn gen_alias( &mut self, - package: &Package, - cache: &mut Cache, + module: &Module, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { - alias::generate(self, package, cache, pretty_writer, data_type_entry) + alias::generate(self, module, pretty_writer, data_type_entry) } fn gen_struct( &mut self, - package: &Package, - cache: &mut Cache, + module: &Module, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { - r#struct::generate(self, package, cache, pretty_writer, data_type_entry) + r#struct::generate(self, module, pretty_writer, data_type_entry) } // Enums generate both a specific typedef, and a traditional C-style enum // The typedef is required to use a native type which is consistent across all architectures fn gen_enum( &mut self, - package: &Package, - cache: &mut Cache, + module: &Module, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { - r#enum::generate(self, package, cache, pretty_writer, data_type_entry) + r#enum::generate(self, module, pretty_writer, data_type_entry) } fn gen_accessors_struct( &mut self, - package: &Package, - cache: &Cache, + module: &Module, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, hierarchy: &Hierarchy, @@ -110,7 +107,6 @@ impl Generator for CGenerator { accessors::r#struct::generate( self, module, - cache, pretty_writer, data_type_entry, hierarchy, @@ -121,8 +117,7 @@ impl Generator for CGenerator { fn gen_accessors_enum( &mut self, - package: &Package, - cache: &Cache, + module: &Module, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, hierarchy: &Hierarchy, @@ -130,8 +125,7 @@ impl Generator for CGenerator { /* accessors::r#enum::generate( self, - package, - cache, + module, pretty_writer, data_type_entry, hierarchy, @@ -142,8 +136,7 @@ impl Generator for CGenerator { fn gen_accessors_alias( &mut self, - package: &Package, - cache: &Cache, + module: &Module, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, hierarchy: &Hierarchy, @@ -152,7 +145,6 @@ impl Generator for CGenerator { accessors::alias::generate( self, module, - cache, pretty_writer, data_type_entry, hierarchy, @@ -163,13 +155,21 @@ impl Generator for CGenerator { } impl CGenerator { + pub fn new( + target: Target, + backend_config: BackendConfig) -> Self { + Self { + target, + backend_config, + cache: Cache::default(), + } + } /// Traverse a `DataTypeRef` chain, and return information /// about the leaf node as well as the native type to use /// for this data type fn type_info<'t>( &self, - package: &'t Package, - cache: &Cache, + module: &'t Module, mut type_: &'t DataTypeRef, ) -> CTypeInfo<'t> { let (mut type_align, mut type_size) = (None, None); @@ -184,10 +184,10 @@ impl CGenerator { type_name.or_else(|| Some(native_atom.native_type_name.to_string())); } DataTypeRef::Defined(data_type_id) => { - let cached = cache.load_type(*data_type_id).unwrap(); + let cached = self.cache.load_type(*data_type_id).unwrap(); type_align = type_align.or_else(|| Some(cached.type_align)); type_size = type_size.or_else(|| Some(cached.type_size)); - let data_type_entry = package.get_datatype(*data_type_id); + let data_type_entry = module.get_datatype(*data_type_id); match data_type_entry.data_type { DataType::Struct { .. } => { type_name = type_name @@ -223,32 +223,32 @@ impl CGenerator { // Return `true` if the type is an atom, an emum, or an alias to one of these pub fn is_type_eventually_an_atom_or_enum( &self, - package: &Package, + module: &Module, type_: &DataTypeRef, ) -> bool { let inner_type = match type_ { DataTypeRef::Atom(_) => return true, DataTypeRef::Defined(inner_type) => inner_type, }; - let inner_data_type_entry = package.get_datatype(*inner_type); + let inner_data_type_entry = module.get_datatype(*inner_type); let inner_data_type = inner_data_type_entry.data_type; match inner_data_type { DataType::Struct { .. } => false, DataType::Enum { .. } => true, - DataType::Alias { to, .. } => self.is_type_eventually_an_atom_or_enum(package, to), + DataType::Alias { to, .. } => self.is_type_eventually_an_atom_or_enum(module, to), } } /// Return the type refererence, with aliases being resolved - pub fn unalias<'t>(&self, package: &'t Package, type_: &'t DataTypeRef) -> &'t DataTypeRef { + pub fn unalias<'t>(&self, module: &'t Module, type_: &'t DataTypeRef) -> &'t DataTypeRef { let inner_type = match type_ { DataTypeRef::Atom(_) => return type_, DataTypeRef::Defined(inner_type) => inner_type, }; - let inner_data_type_entry = package.get_datatype(*inner_type); + let inner_data_type_entry = module.get_datatype(*inner_type); let inner_data_type = inner_data_type_entry.data_type; if let DataType::Alias { to, .. } = inner_data_type { - self.unalias(package, to) + self.unalias(module, to) } else { type_ } @@ -258,7 +258,6 @@ impl CGenerator { fn gen_accessors_for_data_type_ref( &mut self, module: &Module, - cache: &Cache, pretty_writer: &mut PrettyWriter, type_: &DataTypeRef, name: &str, @@ -270,7 +269,7 @@ impl CGenerator { accessors::atom::generate(self, module, pretty_writer, *atom_type, &hierarchy) } DataTypeRef::Defined(data_type_id) => { - self.gen_accessors_for_id(module, cache, pretty_writer, *data_type_id, &hierarchy) + self.gen_accessors_for_id(module, pretty_writer, *data_type_id, &hierarchy) } } } diff --git a/lucet-idl/src/c/struct.rs b/lucet-idl/src/c/struct.rs index 820780d4b..da195a21a 100644 --- a/lucet-idl/src/c/struct.rs +++ b/lucet-idl/src/c/struct.rs @@ -3,8 +3,7 @@ use std::cmp; pub fn generate( cgenerator: &mut CGenerator, - package: &Package, - cache: &mut Cache, + module: &Module, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { @@ -23,7 +22,7 @@ pub fn generate( let mut first_member_align = 0; let mut members_offsets = vec![]; for named_member in named_members { - let type_info = cgenerator.type_info(package, cache, &named_member.type_); + let type_info = cgenerator.type_info(module, &named_member.type_); let type_align = type_info.type_align; let type_size = type_info.type_size; let padding = (type_align - 1) - ((offset + (type_align - 1)) % type_align); @@ -51,7 +50,7 @@ pub fn generate( // to the alignment of the first member of that structure let struct_align = first_member_align; let struct_size = offset; - let cached = cache.store_type( + let cached = cgenerator.cache.store_type( data_type_entry.id, CachedTypeEntry { type_size: struct_size, diff --git a/lucet-idl/src/config.rs b/lucet-idl/src/config.rs index 2434e6384..a68147963 100644 --- a/lucet-idl/src/config.rs +++ b/lucet-idl/src/config.rs @@ -1,6 +1,6 @@ use super::backend::{Backend, BackendConfig}; use super::target::Target; -//use crate::c::CGenerator; +use crate::c::CGenerator; use crate::generator::Generator; //use crate::rust::RustGenerator; use std::io::Write; @@ -30,16 +30,12 @@ impl Config { } pub fn generator(&self) -> Box> { - unimplemented!() - /* disabled while module / pkg representation in flux match self.backend { - Backend::C => Box::new(CGenerator { - target: self.target, - backend_config: self.backend_config, - }), - - Backend::Rust => Box::new(RustGenerator::new(self.target, self.backend_config)), + Backend::C => Box::new(CGenerator::new( + self.target, + self.backend_config, + )), + Backend::Rust => unimplemented!(), //Box::new(RustGenerator::new(self.target, self.backend_config)), } - */ } } diff --git a/lucet-idl/src/generator.rs b/lucet-idl/src/generator.rs index 4e4e50318..6c7c60b62 100644 --- a/lucet-idl/src/generator.rs +++ b/lucet-idl/src/generator.rs @@ -1,4 +1,3 @@ -use crate::cache::Cache; use crate::error::IDLError; use crate::module::Module; use crate::pretty_writer::PrettyWriter; @@ -12,7 +11,6 @@ pub trait Generator { fn gen_type_header( &mut self, module: &Module, - _cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError>; @@ -20,7 +18,6 @@ pub trait Generator { fn gen_alias( &mut self, module: &Module, - cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError>; @@ -28,7 +25,6 @@ pub trait Generator { fn gen_struct( &mut self, module: &Module, - cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError>; @@ -36,7 +32,6 @@ pub trait Generator { fn gen_enum( &mut self, module: &Module, - cache: &mut Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError>; @@ -44,7 +39,6 @@ pub trait Generator { fn gen_accessors_struct( &mut self, module: &Module, - cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, hierarchy: &Hierarchy, @@ -53,7 +47,6 @@ pub trait Generator { fn gen_accessors_enum( &mut self, module: &Module, - cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, hierarchy: &Hierarchy, @@ -62,7 +55,6 @@ pub trait Generator { fn gen_accessors_alias( &mut self, module: &Module, - cache: &Cache, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, hierarchy: &Hierarchy, @@ -71,24 +63,22 @@ pub trait Generator { fn gen_for_id( &mut self, module: &Module, - cache: &mut Cache, pretty_writer: &mut PrettyWriter, id: Ident, ) -> Result<(), IDLError> { let data_type_entry = module.get_datatype(id); - self.gen_type_header(module, cache, pretty_writer, &data_type_entry)?; + self.gen_type_header(module, pretty_writer, &data_type_entry)?; match &data_type_entry.data_type { DataType::Struct { .. } => { - self.gen_struct(module, cache, pretty_writer, &data_type_entry) + self.gen_struct(module, pretty_writer, &data_type_entry) } DataType::Alias { .. } => { - self.gen_alias(module, cache, pretty_writer, &data_type_entry) + self.gen_alias(module, pretty_writer, &data_type_entry) } - DataType::Enum { .. } => self.gen_enum(module, cache, pretty_writer, &data_type_entry), + DataType::Enum { .. } => self.gen_enum(module, pretty_writer, &data_type_entry), }?; self.gen_accessors_for_id( module, - cache, pretty_writer, id, &Hierarchy::new(data_type_entry.name.name.to_string(), 0), @@ -101,7 +91,6 @@ pub trait Generator { fn gen_accessors_for_id( &mut self, module: &Module, - cache: &Cache, pretty_writer: &mut PrettyWriter, id: Ident, hierarchy: &Hierarchy, @@ -109,13 +98,13 @@ pub trait Generator { let data_type_entry = module.get_datatype(id); match &data_type_entry.data_type { DataType::Struct { .. } => { - self.gen_accessors_struct(module, cache, pretty_writer, &data_type_entry, hierarchy) + self.gen_accessors_struct(module, pretty_writer, &data_type_entry, hierarchy) } DataType::Alias { .. } => { - self.gen_accessors_alias(module, cache, pretty_writer, &data_type_entry, hierarchy) + self.gen_accessors_alias(module, pretty_writer, &data_type_entry, hierarchy) } DataType::Enum { .. } => { - self.gen_accessors_enum(module, cache, pretty_writer, &data_type_entry, hierarchy) + self.gen_accessors_enum(module, pretty_writer, &data_type_entry, hierarchy) } }?; Ok(()) diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index d97307ef2..8d70dbff2 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -4,8 +4,7 @@ extern crate failure; mod backend; -//mod c; -mod cache; +mod c; mod config; mod error; mod generator; @@ -23,7 +22,6 @@ pub use crate::config::Config; pub use crate::error::IDLError; pub use crate::target::Target; -use crate::cache::Cache; use crate::package::Package; use crate::parser::Parser; use crate::pretty_writer::PrettyWriter; @@ -41,12 +39,11 @@ pub fn run(config: &Config, input: &str, output: W) -> Result Date: Tue, 7 May 2019 15:20:38 -0700 Subject: [PATCH 191/512] lucet-idl: get rust backend working again as well --- lucet-idl/src/config.rs | 9 +++------ lucet-idl/src/lib.rs | 2 +- lucet-idl/src/rust/mod.rs | 26 ++++++++------------------ 3 files changed, 12 insertions(+), 25 deletions(-) diff --git a/lucet-idl/src/config.rs b/lucet-idl/src/config.rs index a68147963..1b7956e2e 100644 --- a/lucet-idl/src/config.rs +++ b/lucet-idl/src/config.rs @@ -2,7 +2,7 @@ use super::backend::{Backend, BackendConfig}; use super::target::Target; use crate::c::CGenerator; use crate::generator::Generator; -//use crate::rust::RustGenerator; +use crate::rust::RustGenerator; use std::io::Write; #[derive(Default, Clone, Debug)] @@ -31,11 +31,8 @@ impl Config { pub fn generator(&self) -> Box> { match self.backend { - Backend::C => Box::new(CGenerator::new( - self.target, - self.backend_config, - )), - Backend::Rust => unimplemented!(), //Box::new(RustGenerator::new(self.target, self.backend_config)), + Backend::C => Box::new(CGenerator::new(self.target, self.backend_config)), + Backend::Rust => Box::new(RustGenerator::new(self.target, self.backend_config)), } } } diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 8d70dbff2..3176e0666 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -13,7 +13,7 @@ mod module; mod package; mod parser; mod pretty_writer; -//mod rust; +mod rust; mod target; mod types; diff --git a/lucet-idl/src/rust/mod.rs b/lucet-idl/src/rust/mod.rs index 29780437d..611bfe039 100644 --- a/lucet-idl/src/rust/mod.rs +++ b/lucet-idl/src/rust/mod.rs @@ -2,10 +2,9 @@ #![allow(unused_variables)] use crate::backend::BackendConfig; -use crate::cache::Cache; use crate::error::IDLError; use crate::generator::{Generator, Hierarchy}; -use crate::package::Package; +use crate::module::Module; use crate::pretty_writer::PrettyWriter; use crate::target::Target; use crate::types::AtomType; @@ -79,8 +78,7 @@ impl Generator for RustGenerator { fn gen_type_header( &mut self, - _package: &Package, - _cache: &mut Cache, + _module: &Module, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { @@ -90,12 +88,9 @@ impl Generator for RustGenerator { Ok(()) } - // The most important thing in alias generation is to cache the size - // and alignment rules of what it ultimately points to fn gen_alias( &mut self, - package: &Package, - cache: &mut Cache, + module: &Module, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { @@ -117,8 +112,7 @@ impl Generator for RustGenerator { fn gen_struct( &mut self, - package: &Package, - cache: &mut Cache, + module: &Module, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { @@ -158,8 +152,7 @@ impl Generator for RustGenerator { // The typedef is required to use a native type which is consistent across all architectures fn gen_enum( &mut self, - package: &Package, - cache: &mut Cache, + module: &Module, pretty_writer: &mut PrettyWriter, data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError> { @@ -191,8 +184,7 @@ impl Generator for RustGenerator { fn gen_accessors_struct( &mut self, - _package: &Package, - _cache: &Cache, + _module: &Module, _pretty_writer: &mut PrettyWriter, _data_type_entry: &DataTypeEntry<'_>, _hierarchy: &Hierarchy, @@ -202,8 +194,7 @@ impl Generator for RustGenerator { fn gen_accessors_enum( &mut self, - _package: &Package, - _cache: &Cache, + _module: &Module, _pretty_writer: &mut PrettyWriter, _data_type_entry: &DataTypeEntry<'_>, _hierarchy: &Hierarchy, @@ -213,8 +204,7 @@ impl Generator for RustGenerator { fn gen_accessors_alias( &mut self, - _package: &Package, - _cache: &Cache, + _module: &Module, _pretty_writer: &mut PrettyWriter, _data_type_entry: &DataTypeEntry<'_>, _hierarchy: &Hierarchy, From 6a35266124f8c5da8513e42fc62247e6a61e4824 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 7 May 2019 15:40:23 -0700 Subject: [PATCH 192/512] lucet-idl: Module::get_datatype is partial --- lucet-idl/src/c/macros.rs | 2 +- lucet-idl/src/c/mod.rs | 6 ++-- lucet-idl/src/generator.rs | 60 ++++++++++++++++++++------------------ lucet-idl/src/module.rs | 15 ++++++---- 4 files changed, 44 insertions(+), 39 deletions(-) diff --git a/lucet-idl/src/c/macros.rs b/lucet-idl/src/c/macros.rs index 74ec5c0d0..d10d88012 100644 --- a/lucet-idl/src/c/macros.rs +++ b/lucet-idl/src/c/macros.rs @@ -49,7 +49,7 @@ pub fn macro_for_data_type_ref( format!("{}", native_type_size) } DataTypeRef::Defined(data_type_id) => { - let data_type_entry = module.get_datatype(*data_type_id); + let data_type_entry = module.get_datatype(*data_type_id).expect("defined datatype"); macro_for(prefix, &data_type_entry.name.name) } } diff --git a/lucet-idl/src/c/mod.rs b/lucet-idl/src/c/mod.rs index dba1948cc..9a7984f8a 100644 --- a/lucet-idl/src/c/mod.rs +++ b/lucet-idl/src/c/mod.rs @@ -187,7 +187,7 @@ impl CGenerator { let cached = self.cache.load_type(*data_type_id).unwrap(); type_align = type_align.or_else(|| Some(cached.type_align)); type_size = type_size.or_else(|| Some(cached.type_size)); - let data_type_entry = module.get_datatype(*data_type_id); + let data_type_entry = module.get_datatype(*data_type_id).expect("defined datatype"); match data_type_entry.data_type { DataType::Struct { .. } => { type_name = type_name @@ -230,7 +230,7 @@ impl CGenerator { DataTypeRef::Atom(_) => return true, DataTypeRef::Defined(inner_type) => inner_type, }; - let inner_data_type_entry = module.get_datatype(*inner_type); + let inner_data_type_entry = module.get_datatype(*inner_type).expect("defined datatype"); let inner_data_type = inner_data_type_entry.data_type; match inner_data_type { DataType::Struct { .. } => false, @@ -245,7 +245,7 @@ impl CGenerator { DataTypeRef::Atom(_) => return type_, DataTypeRef::Defined(inner_type) => inner_type, }; - let inner_data_type_entry = module.get_datatype(*inner_type); + let inner_data_type_entry = module.get_datatype(*inner_type).expect("defined datatype"); let inner_data_type = inner_data_type_entry.data_type; if let DataType::Alias { to, .. } = inner_data_type { self.unalias(module, to) diff --git a/lucet-idl/src/generator.rs b/lucet-idl/src/generator.rs index 6c7c60b62..4a7016a3f 100644 --- a/lucet-idl/src/generator.rs +++ b/lucet-idl/src/generator.rs @@ -66,23 +66,24 @@ pub trait Generator { pretty_writer: &mut PrettyWriter, id: Ident, ) -> Result<(), IDLError> { - let data_type_entry = module.get_datatype(id); - self.gen_type_header(module, pretty_writer, &data_type_entry)?; - match &data_type_entry.data_type { - DataType::Struct { .. } => { - self.gen_struct(module, pretty_writer, &data_type_entry) - } - DataType::Alias { .. } => { - self.gen_alias(module, pretty_writer, &data_type_entry) - } - DataType::Enum { .. } => self.gen_enum(module, pretty_writer, &data_type_entry), - }?; - self.gen_accessors_for_id( - module, - pretty_writer, - id, - &Hierarchy::new(data_type_entry.name.name.to_string(), 0), - )?; + if let Some(data_type_entry) = module.get_datatype(id) { + self.gen_type_header(module, pretty_writer, &data_type_entry)?; + match &data_type_entry.data_type { + DataType::Struct { .. } => { + self.gen_struct(module, pretty_writer, &data_type_entry) + } + DataType::Alias { .. } => { + self.gen_alias(module, pretty_writer, &data_type_entry) + } + DataType::Enum { .. } => self.gen_enum(module, pretty_writer, &data_type_entry), + }?; + self.gen_accessors_for_id( + module, + pretty_writer, + id, + &Hierarchy::new(data_type_entry.name.name.to_string(), 0), + )?; + } Ok(()) } @@ -95,18 +96,19 @@ pub trait Generator { id: Ident, hierarchy: &Hierarchy, ) -> Result<(), IDLError> { - let data_type_entry = module.get_datatype(id); - match &data_type_entry.data_type { - DataType::Struct { .. } => { - self.gen_accessors_struct(module, pretty_writer, &data_type_entry, hierarchy) - } - DataType::Alias { .. } => { - self.gen_accessors_alias(module, pretty_writer, &data_type_entry, hierarchy) - } - DataType::Enum { .. } => { - self.gen_accessors_enum(module, pretty_writer, &data_type_entry, hierarchy) - } - }?; + if let Some(data_type_entry) = module.get_datatype(id) { + match &data_type_entry.data_type { + DataType::Struct { .. } => { + self.gen_accessors_struct(module, pretty_writer, &data_type_entry, hierarchy) + } + DataType::Alias { .. } => { + self.gen_accessors_alias(module, pretty_writer, &data_type_entry, hierarchy) + } + DataType::Enum { .. } => { + self.gen_accessors_enum(module, pretty_writer, &data_type_entry, hierarchy) + } + }?; + } Ok(()) } } diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index 978d4cf93..c11973755 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -311,13 +311,16 @@ impl Module { } /// Retrieve information about a data type given its identifier - pub fn get_datatype(&self, id: Ident) -> DataTypeEntry<'_> { + pub fn get_datatype(&self, id: Ident) -> Option> { let name = &self.names[id.0]; - let data_type = &self.data_types[&id]; - DataTypeEntry { - id, - name, - data_type, + if let Some(data_type) = &self.data_types.get(&id) { + Some(DataTypeEntry { + id, + name, + data_type, + }) + } else { + None } } } From 73c9b03505329ef779de15e59d0ddfa84df9d996 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 8 May 2019 10:32:44 -0700 Subject: [PATCH 193/512] lucet-idl: add bool as an atom type, rustfmt --- lucet-idl/src/c/catom.rs | 5 +++++ lucet-idl/src/c/macros.rs | 4 +++- lucet-idl/src/c/mod.rs | 22 +++++++--------------- lucet-idl/src/generator.rs | 8 ++------ lucet-idl/src/lexer.rs | 1 + lucet-idl/src/rust/mod.rs | 1 + lucet-idl/src/types.rs | 1 + lucet-idl/tests/example.idl | 5 +++++ 8 files changed, 25 insertions(+), 22 deletions(-) diff --git a/lucet-idl/src/c/catom.rs b/lucet-idl/src/c/catom.rs index 224ede2dd..4ecaea8cf 100644 --- a/lucet-idl/src/c/catom.rs +++ b/lucet-idl/src/c/catom.rs @@ -11,6 +11,11 @@ pub struct CAtom { impl From for CAtom { fn from(atom_type: AtomType) -> Self { match atom_type { + AtomType::Bool => CAtom { + native_type_name: "bool", + native_type_size: 1, + native_type_align: 1, + }, AtomType::U8 => CAtom { native_type_name: "uint8_t", native_type_size: 1, diff --git a/lucet-idl/src/c/macros.rs b/lucet-idl/src/c/macros.rs index d10d88012..906405b88 100644 --- a/lucet-idl/src/c/macros.rs +++ b/lucet-idl/src/c/macros.rs @@ -49,7 +49,9 @@ pub fn macro_for_data_type_ref( format!("{}", native_type_size) } DataTypeRef::Defined(data_type_id) => { - let data_type_entry = module.get_datatype(*data_type_id).expect("defined datatype"); + let data_type_entry = module + .get_datatype(*data_type_id) + .expect("defined datatype"); macro_for(prefix, &data_type_entry.name.name) } } diff --git a/lucet-idl/src/c/mod.rs b/lucet-idl/src/c/mod.rs index 9a7984f8a..ec73bd9e5 100644 --- a/lucet-idl/src/c/mod.rs +++ b/lucet-idl/src/c/mod.rs @@ -10,9 +10,9 @@ mod macros; mod prelude; mod r#struct; +use self::cache::{Cache, CachedStructMemberEntry, CachedTypeEntry}; pub(crate) use self::catom::*; use crate::backend::*; -use self::cache::{Cache, CachedStructMemberEntry, CachedTypeEntry}; use crate::error::IDLError; use crate::generator::{Generator, Hierarchy}; use crate::module::Module; @@ -155,9 +155,7 @@ impl Generator for CGenerator { } impl CGenerator { - pub fn new( - target: Target, - backend_config: BackendConfig) -> Self { + pub fn new(target: Target, backend_config: BackendConfig) -> Self { Self { target, backend_config, @@ -167,11 +165,7 @@ impl CGenerator { /// Traverse a `DataTypeRef` chain, and return information /// about the leaf node as well as the native type to use /// for this data type - fn type_info<'t>( - &self, - module: &'t Module, - mut type_: &'t DataTypeRef, - ) -> CTypeInfo<'t> { + fn type_info<'t>(&self, module: &'t Module, mut type_: &'t DataTypeRef) -> CTypeInfo<'t> { let (mut type_align, mut type_size) = (None, None); let mut type_name = None; loop { @@ -187,7 +181,9 @@ impl CGenerator { let cached = self.cache.load_type(*data_type_id).unwrap(); type_align = type_align.or_else(|| Some(cached.type_align)); type_size = type_size.or_else(|| Some(cached.type_size)); - let data_type_entry = module.get_datatype(*data_type_id).expect("defined datatype"); + let data_type_entry = module + .get_datatype(*data_type_id) + .expect("defined datatype"); match data_type_entry.data_type { DataType::Struct { .. } => { type_name = type_name @@ -221,11 +217,7 @@ impl CGenerator { } // Return `true` if the type is an atom, an emum, or an alias to one of these - pub fn is_type_eventually_an_atom_or_enum( - &self, - module: &Module, - type_: &DataTypeRef, - ) -> bool { + pub fn is_type_eventually_an_atom_or_enum(&self, module: &Module, type_: &DataTypeRef) -> bool { let inner_type = match type_ { DataTypeRef::Atom(_) => return true, DataTypeRef::Defined(inner_type) => inner_type, diff --git a/lucet-idl/src/generator.rs b/lucet-idl/src/generator.rs index 4a7016a3f..ae60a466f 100644 --- a/lucet-idl/src/generator.rs +++ b/lucet-idl/src/generator.rs @@ -69,12 +69,8 @@ pub trait Generator { if let Some(data_type_entry) = module.get_datatype(id) { self.gen_type_header(module, pretty_writer, &data_type_entry)?; match &data_type_entry.data_type { - DataType::Struct { .. } => { - self.gen_struct(module, pretty_writer, &data_type_entry) - } - DataType::Alias { .. } => { - self.gen_alias(module, pretty_writer, &data_type_entry) - } + DataType::Struct { .. } => self.gen_struct(module, pretty_writer, &data_type_entry), + DataType::Alias { .. } => self.gen_alias(module, pretty_writer, &data_type_entry), DataType::Enum { .. } => self.gen_enum(module, pretty_writer, &data_type_entry), }?; self.gen_accessors_for_id( diff --git a/lucet-idl/src/lexer.rs b/lucet-idl/src/lexer.rs index 421c40dda..33516a0a4 100644 --- a/lucet-idl/src/lexer.rs +++ b/lucet-idl/src/lexer.rs @@ -136,6 +136,7 @@ impl<'a> Lexer<'a> { let text = &self.source[begin..self.pos]; token( match text { + "bool" => Token::Atom(AtomType::Bool), "i8" => Token::Atom(AtomType::I8), "i16" => Token::Atom(AtomType::I16), "i32" => Token::Atom(AtomType::I32), diff --git a/lucet-idl/src/rust/mod.rs b/lucet-idl/src/rust/mod.rs index 611bfe039..2b9a6fe87 100644 --- a/lucet-idl/src/rust/mod.rs +++ b/lucet-idl/src/rust/mod.rs @@ -57,6 +57,7 @@ impl RustGenerator { fn atom_name(atom_type: &AtomType) -> &'static str { use AtomType::*; match atom_type { + Bool => "bool", U8 => "u8", U16 => "u16", U32 => "u32", diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index 56aaffa19..51c4e24ba 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -2,6 +2,7 @@ use std::fmt; #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum AtomType { + Bool, U8, U16, U32, diff --git a/lucet-idl/tests/example.idl b/lucet-idl/tests/example.idl index 1776f245f..161abab38 100644 --- a/lucet-idl/tests/example.idl +++ b/lucet-idl/tests/example.idl @@ -23,4 +23,9 @@ mod example { c: color, } + // functions + + fn set_color(to: color) -> bool; + + fn get_structure(for: color) -> st; } From d4878af858da0906644e4346da2186c3762e124b Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 8 May 2019 10:36:40 -0700 Subject: [PATCH 194/512] lucet-idl: delete accessors code generators they've been disabled for a little bit; now that structs dont have pointers in them there is no longer a need. --- lucet-idl/src/c/accessors/alias.rs | 42 ------ lucet-idl/src/c/accessors/atom.rs | 128 ----------------- lucet-idl/src/c/accessors/enum.rs | 166 ---------------------- lucet-idl/src/c/accessors/mod.rs | 4 - lucet-idl/src/c/accessors/ptr.rs | 57 -------- lucet-idl/src/c/accessors/struct.rs | 209 ---------------------------- lucet-idl/src/c/mod.rs | 81 +---------- lucet-idl/src/generator.rs | 131 ----------------- lucet-idl/src/rust/mod.rs | 32 +---- 9 files changed, 2 insertions(+), 848 deletions(-) delete mode 100644 lucet-idl/src/c/accessors/alias.rs delete mode 100644 lucet-idl/src/c/accessors/atom.rs delete mode 100644 lucet-idl/src/c/accessors/enum.rs delete mode 100644 lucet-idl/src/c/accessors/mod.rs delete mode 100644 lucet-idl/src/c/accessors/ptr.rs delete mode 100644 lucet-idl/src/c/accessors/struct.rs diff --git a/lucet-idl/src/c/accessors/alias.rs b/lucet-idl/src/c/accessors/alias.rs deleted file mode 100644 index d55ccc876..000000000 --- a/lucet-idl/src/c/accessors/alias.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::c::CGenerator; -use crate::cache::Cache; -use crate::errors::IDLError; -use crate::generator::Hierarchy; -use crate::module::{DataType, DataTypeEntry, Module}; -use crate::pretty_writer::PrettyWriter; -use std::io::prelude::*; - -pub fn generate( - cgenerator: &mut CGenerator, - module: &Module, - cache: &Cache, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - hierarchy: &Hierarchy, -) -> Result<(), IDLError> { - if hierarchy.depth() > 1 { - return Ok(()); - } - let name = &data_type_entry.name; - let (type_, _attrs) = if let DataType::Alias { to: type_, attrs } = &data_type_entry.data_type { - (type_, attrs) - } else { - unreachable!() - }; - let type_info = cgenerator.type_info(module, cache, type_); - - pretty_writer.indent()?; - pretty_writer - .write(format!("// `{}` is an alias for `{}`", name, type_info.type_name).as_ref())?; - if type_info.indirections == 0 { - let leaf_type_info = cgenerator.type_info(module, cache, type_info.leaf_data_type_ref); - if leaf_type_info.type_name != type_info.type_name { - pretty_writer - .write(format!(", itself equivalent to `{}`", leaf_type_info.type_name).as_ref())?; - } - } - pretty_writer.write(b".")?.eol()?; - pretty_writer.write_line(b"// No dedicated accessors have been generated.")?; - pretty_writer.eob()?; - Ok(()) -} diff --git a/lucet-idl/src/c/accessors/atom.rs b/lucet-idl/src/c/accessors/atom.rs deleted file mode 100644 index d6e53958d..000000000 --- a/lucet-idl/src/c/accessors/atom.rs +++ /dev/null @@ -1,128 +0,0 @@ -use crate::c::catom::CAtom; -use crate::c::macros; -use crate::c::CGenerator; -use crate::errors::IDLError; -use crate::generator::Hierarchy; -use crate::module::Module; -use crate::pretty_writer::PrettyWriter; -use crate::types::AtomType; -use std::io::prelude::*; - -pub fn generate( - cgenerator: &mut CGenerator, - _module: &Module, - pretty_writer: &mut PrettyWriter, - atom_type: AtomType, - hierarchy: &Hierarchy, -) -> Result<(), IDLError> { - let fn_name = hierarchy.fn_name(); - let root_name = hierarchy.root_name(); - let root_macro_size_name = macros::macro_for("BYTES", &root_name); - let current_offset = hierarchy.current_offset(); - let catom = CAtom::from(atom_type); - let mut pretty_writer_i1 = pretty_writer.new_block(); - let mut preprocessor_writer = PrettyWriter::new_from_writer(pretty_writer); - let uses_reference_target_endianness = cgenerator - .target - .uses_reference_target_endianness_for_atom_type(atom_type); - - // --- store_*() - - pretty_writer - .write_line( - format!( - "static inline void store_{}(unsigned char buf[static {}], const {} v)", - fn_name, root_macro_size_name, catom.native_type_name - ) - .as_bytes(), - )? - .write_line(b"{")?; - pretty_writer_i1.write_line( - format!( - "_Static_assert({} >= {} + {}, \"unexpected size\");", - root_macro_size_name, current_offset, catom.native_type_size - ) - .as_bytes(), - )?; - if !uses_reference_target_endianness { - preprocessor_writer.write_line(b"#ifdef ___REFERENCE_COMPATIBLE_ENCODING")?; - } - pretty_writer_i1.write_line( - format!( - "memcpy(&buf[{}], &v, {});", - current_offset, catom.native_type_size - ) - .as_bytes(), - )?; - - if !uses_reference_target_endianness { - preprocessor_writer.write_line(b"#else")?; - pretty_writer_i1 - .write_line( - format!( - "{} t = {};", - catom.native_type_name, - catom.little_endian(cgenerator.target, "v") - ) - .as_bytes(), - )? - .write_line( - format!( - "memcpy(&buf[{}], &t, {});", - current_offset, catom.native_type_size - ) - .as_bytes(), - )?; - preprocessor_writer.write_line(b"#endif")?; - } - - pretty_writer.write_line(b"}")?.eob()?; - - // --- load_*() - - pretty_writer - .write_line( - format!( - "static inline void load_{}({} *v_p, const unsigned char buf[static {}])", - fn_name, catom.native_type_name, root_macro_size_name - ) - .as_bytes(), - )? - .write_line(b"{")?; - pretty_writer_i1.write_line( - format!( - "_Static_assert({} >= {} + {}, \"unexpected size\");", - root_macro_size_name, current_offset, catom.native_type_size - ) - .as_bytes(), - )?; - if !uses_reference_target_endianness { - preprocessor_writer.write_line(b"#ifdef ___REFERENCE_COMPATIBLE_ENCODING")?; - } - pretty_writer_i1.write_line( - format!( - "memcpy(v_p, &buf[{}], {});", - current_offset, catom.native_type_size - ) - .as_bytes(), - )?; - if !uses_reference_target_endianness { - preprocessor_writer.write_line(b"#else")?; - pretty_writer_i1 - .write_line(format!("{} t = 0;", catom.native_type_name).as_bytes())? - .write_line( - format!( - "memcpy(&t, &buf[{}], {});", - current_offset, catom.native_type_size - ) - .as_bytes(), - )? - .write_line( - format!("*v_p = {};", catom.little_endian(cgenerator.target, "t")).as_bytes(), - )?; - preprocessor_writer.write_line(b"#endif")?; - } - pretty_writer.write_line(b"}")?.eob()?; - - Ok(()) -} diff --git a/lucet-idl/src/c/accessors/enum.rs b/lucet-idl/src/c/accessors/enum.rs deleted file mode 100644 index ea993cc3f..000000000 --- a/lucet-idl/src/c/accessors/enum.rs +++ /dev/null @@ -1,166 +0,0 @@ -use crate::c::catom::CAtom; -use crate::c::macros; -use crate::c::CGenerator; -use crate::cache::Cache; -use crate::errors::IDLError; -use crate::generator::Hierarchy; -use crate::module::{DataType, DataTypeEntry, Module}; -use crate::pretty_writer::PrettyWriter; -use std::io::prelude::*; - -pub fn generate( - cgenerator: &mut CGenerator, - module: &Module, - cache: &Cache, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - hierarchy: &Hierarchy, -) -> Result<(), IDLError> { - let (named_members, _attrs) = if let DataType::Enum { - members: named_members, - attrs, - } = &data_type_entry.data_type - { - (named_members, attrs) - } else { - unreachable!() - }; - let root_name = hierarchy.root_name(); - let fn_name = hierarchy.fn_name(); - let root_macro_size_name = macros::macro_for("BYTES", &root_name); - let current_offset = hierarchy.current_offset(); - - let catom = CAtom::enum_(); - let mut preprocessor_writer = PrettyWriter::new_from_writer(pretty_writer); - let uses_reference_target_endianness = cgenerator - .target - .uses_reference_target_endianness_for_atom_type(catom.as_atom_type().unwrap()); - - pretty_writer.eob()?; - - if hierarchy.depth() > 1 { - pretty_writer.write_line( - format!( - "// Accessors for the `{}` enumeration in `{}`", - data_type_entry.name, - hierarchy.idl_name() - ) - .as_bytes(), - )?; - } else { - pretty_writer.write_line( - format!( - "// Platform-independent accessors for the `{}` enumeration", - data_type_entry.name - ) - .as_bytes(), - )?; - } - pretty_writer.eob()?; - - let mut pretty_writer_i1 = pretty_writer.new_block(); - - // --- store_*() - - pretty_writer - .write_line( - format!( - "static inline void store_{}(unsigned char buf[static {}], const {} v)", - fn_name, root_macro_size_name, catom.native_type_name - ) - .as_bytes(), - )? - .write_line(b"{")?; - pretty_writer_i1.write_line( - format!( - "_Static_assert({} >= {} + {}, \"unexpected size\");", - root_macro_size_name, current_offset, catom.native_type_size - ) - .as_bytes(), - )?; - pretty_writer_i1 - .write_line(format!("assert(v >= 0 && v < {});", named_members.len()).as_ref())? - .eob()?; - if !uses_reference_target_endianness { - preprocessor_writer.write_line(b"#ifdef ___REFERENCE_COMPATIBLE_ENCODING")?; - } - pretty_writer_i1.write_line( - format!( - "memcpy(&buf[{}], &v, {});", - current_offset, catom.native_type_size - ) - .as_bytes(), - )?; - - if !uses_reference_target_endianness { - preprocessor_writer.write_line(b"#else")?; - pretty_writer_i1 - .write_line( - format!( - "{} t = {};", - catom.native_type_name, - catom.little_endian(cgenerator.target, "v") - ) - .as_bytes(), - )? - .write_line( - format!( - "memcpy(&buf[{}], &t, {});", - current_offset, catom.native_type_size - ) - .as_bytes(), - )?; - preprocessor_writer.write_line(b"#endif")?; - } - pretty_writer.write_line(b"}")?.eob()?; - - // --- load_*() - - pretty_writer - .write_line( - format!( - "static inline void load_{}({} *v_p, const unsigned char buf[static {}])", - fn_name, catom.native_type_name, root_macro_size_name - ) - .as_bytes(), - )? - .write_line(b"{")?; - pretty_writer_i1.write_line( - format!( - "_Static_assert({} >= {} + {}, \"unexpected size\");", - root_macro_size_name, current_offset, catom.native_type_size - ) - .as_bytes(), - )?; - if !uses_reference_target_endianness { - preprocessor_writer.write_line(b"#ifdef ___REFERENCE_COMPATIBLE_ENCODING")?; - } - pretty_writer_i1.write_line( - format!( - "memcpy(v_p, &buf[{}], {});", - current_offset, catom.native_type_size - ) - .as_bytes(), - )?; - if !uses_reference_target_endianness { - preprocessor_writer.write_line(b"#else")?; - pretty_writer_i1 - .write_line(format!("{} t = 0;", catom.native_type_name).as_bytes())? - .write_line( - format!( - "memcpy(&t, &buf[{}], {});", - current_offset, catom.native_type_size - ) - .as_bytes(), - )? - .write_line( - format!("*v_p = {};", catom.little_endian(cgenerator.target, "t")).as_bytes(), - )?; - preprocessor_writer.write_line(b"#endif")?; - } - pretty_writer_i1 - .write_line(format!("assert(*v_p >= 0 && *v_p < {});", named_members.len()).as_ref())?; - pretty_writer.write_line(b"}")?.eob()?; - - Ok(()) -} diff --git a/lucet-idl/src/c/accessors/mod.rs b/lucet-idl/src/c/accessors/mod.rs deleted file mode 100644 index c053bab6c..000000000 --- a/lucet-idl/src/c/accessors/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod alias; -pub mod atom; -pub mod r#enum; -pub mod r#struct; diff --git a/lucet-idl/src/c/accessors/ptr.rs b/lucet-idl/src/c/accessors/ptr.rs deleted file mode 100644 index eea3bc860..000000000 --- a/lucet-idl/src/c/accessors/ptr.rs +++ /dev/null @@ -1,57 +0,0 @@ -use crate::c::CGenerator; -use crate::cache::Cache; -use crate::errors::IDLError; -use crate::generator::Hierarchy; -use crate::module::{DataTypeRef, Module}; -use crate::pretty_writer::PrettyWriter; -use std::io::prelude::*; - -pub fn generate( - cgenerator: &mut CGenerator, - module: &Module, - cache: &Cache, - pretty_writer: &mut PrettyWriter, - type_: &DataTypeRef, - hierarchy: &Hierarchy, -) -> Result<(), IDLError> { - let type_info = cgenerator.type_info(module, cache, type_); - let leaf_type_info = cgenerator.type_info(module, cache, type_info.leaf_data_type_ref); - assert_eq!(leaf_type_info.indirections, 0); - if type_info.indirections > 1 { - pretty_writer.write_line( - format!( - "// `{}` is a sequence of {} pointers to `{}`.", - hierarchy.idl_name(), - type_info.indirections, - leaf_type_info.type_name - ) - .as_ref(), - )?; - } else if type_info.indirections == 1 { - pretty_writer.write_line( - format!( - "// `{}` is a native pointer to a pointer to `{}`.", - hierarchy.idl_name(), - leaf_type_info.type_name - ) - .as_ref(), - )?; - } else { - pretty_writer.write_line( - format!( - "// `{}` is a native pointer to `{}`.", - hierarchy.idl_name(), - leaf_type_info.type_name - ) - .as_ref(), - )?; - } - pretty_writer.write_line(b"// Accessors are intentionally not defined for it: ")?; - pretty_writer - .write_line( - b"// it is only designed to be used internally, and its value will not be serialized.", - )? - .eob()?; - - Ok(()) -} diff --git a/lucet-idl/src/c/accessors/struct.rs b/lucet-idl/src/c/accessors/struct.rs deleted file mode 100644 index d1d602784..000000000 --- a/lucet-idl/src/c/accessors/struct.rs +++ /dev/null @@ -1,209 +0,0 @@ -use crate::c::macros; -use crate::c::CGenerator; -use crate::cache::Cache; -use crate::errors::IDLError; -use crate::generator::Hierarchy; -use crate::module::{DataType, DataTypeEntry, DataTypeRef, Module}; -use crate::pretty_writer::PrettyWriter; -use std::io::prelude::*; - -pub fn generate( - cgenerator: &mut CGenerator, - module: &Module, - cache: &Cache, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - hierarchy: &Hierarchy, -) -> Result<(), IDLError> { - let root_name = hierarchy.root_name(); - let root_macro_size_name = macros::macro_for("BYTES", &root_name); - let current_offset = hierarchy.current_offset(); - - let (named_members, _attrs) = if let DataType::Struct { - members: named_members, - attrs, - } = &data_type_entry.data_type - { - (named_members, attrs) - } else { - unreachable!() - }; - pretty_writer - .eob()? - .write_line( - format!( - "// Platform-independent accessors for the members of the `{}` structure", - data_type_entry.name - ) - .as_bytes(), - )? - .eob()?; - for (i, named_member) in named_members.iter().enumerate() { - let offset = cache - .load_type(data_type_entry.id) - .unwrap() - .load_member(i) - .unwrap() - .offset; - let type_: &DataTypeRef = &named_member.type_; - let hierarchy = hierarchy.push(named_member.name.to_string(), current_offset + offset); - cgenerator.gen_accessors_for_data_type_ref( - module, - cache, - &mut pretty_writer.new_block(), - type_, - &named_member.name, - &hierarchy, - )?; - } - - pretty_writer - .eob()? - .write_line( - format!( - "// Platform-independent accessors for the whole `{}` structure", - data_type_entry.name - ) - .as_bytes(), - )? - .eob()?; - let cached = cache.load_type(data_type_entry.id).unwrap(); - let fn_name = hierarchy.fn_name(); - let mut pretty_writer_i1 = pretty_writer.new_block(); - let mut pretty_writer_preprocessor = pretty_writer.new_from_writer(); - let is_reference_alignment_compatible = cgenerator.target.is_reference_alignment_compatible(); - let struct_macro_size_name = macros::macro_for("BYTES", &data_type_entry.name.name); - - // --- store_*() - - pretty_writer - .write_line( - format!( - "static inline void store_{}(unsigned char buf[static {}], const struct {} *v)", - fn_name, root_macro_size_name, data_type_entry.name - ) - .as_bytes(), - )? - .write_line(b"{")?; - pretty_writer_i1.write_line( - format!( - "_Static_assert({} == {}, \"unexpected size\");", - struct_macro_size_name, cached.type_size - ) - .as_bytes(), - )?; - if !is_reference_alignment_compatible { - pretty_writer_preprocessor.write_line(b"#ifdef ___REFERENCE_COMPATIBLE_ENCODING")?; - } - pretty_writer_i1.write_line( - format!("memcpy(&buf[{}], v, {});", current_offset, cached.type_size).as_bytes(), - )?; - if !is_reference_alignment_compatible { - pretty_writer_preprocessor.write_line(b"#else")?; - for (i, named_member) in named_members.iter().enumerate() { - let offset = cache - .load_type(data_type_entry.id) - .unwrap() - .load_member(i) - .unwrap() - .offset; - let hierarchy = hierarchy.push(named_member.name.to_string(), offset); - let fn_name = hierarchy.fn_name(); - let type_ = &named_member.type_; - let is_eventually_an_atom_or_enum = - cgenerator.is_type_eventually_an_atom_or_enum(module, type_); - if let DataTypeRef::Ptr(_) = type_ { - pretty_writer_preprocessor.write_line(b"# ifdef ZERO_NATIVE_POINTERS")?; - pretty_writer_i1.write_line( - format!( - "memset(&buf[{} + {}], 0, sizeof v->{});", - current_offset, offset, named_member.name - ) - .as_bytes(), - )?; - pretty_writer_preprocessor.write_line(b"# else")?; - pretty_writer_i1.write_line( - format!( - "memcpy(&buf[{} + {}], &v->{}, sizeof v->{});", - current_offset, offset, named_member.name, named_member.name - ) - .as_bytes(), - )?; - pretty_writer_preprocessor.write_line(b"# endif")?; - } else if is_eventually_an_atom_or_enum { - pretty_writer_i1.write_line( - format!("store_{}(buf, v->{});", fn_name, named_member.name).as_bytes(), - )?; - } else { - pretty_writer_i1.write_line( - format!("store_{}(buf, &v->{});", fn_name, named_member.name).as_bytes(), - )?; - } - } - pretty_writer_preprocessor.write_line(b"#endif")?; - } - pretty_writer.write_line(b"}")?.eob()?; - - // --- load_*() - - pretty_writer - .write_line( - format!( - "static inline void load_{}(struct {} *v_p, const unsigned char buf[static {}])", - fn_name, data_type_entry.name, root_macro_size_name - ) - .as_bytes(), - )? - .write_line(b"{")?; - pretty_writer_i1.write_line( - format!( - "_Static_assert({} == {}, \"unexpected size\");", - struct_macro_size_name, cached.type_size - ) - .as_bytes(), - )?; - if !is_reference_alignment_compatible { - pretty_writer_preprocessor.write_line(b"#ifdef ___REFERENCE_COMPATIBLE_ENCODING")?; - } - pretty_writer_i1.write_line( - format!( - "memcpy(v_p, &buf[{}], {});", - current_offset, cached.type_size - ) - .as_bytes(), - )?; - if !is_reference_alignment_compatible { - pretty_writer_preprocessor.write_line(b"#else")?; - for (i, named_member) in named_members.iter().enumerate() { - let offset = cache - .load_type(data_type_entry.id) - .unwrap() - .load_member(i) - .unwrap() - .offset; - let hierarchy = hierarchy.push(named_member.name.to_string(), offset); - let fn_name = hierarchy.fn_name(); - let type_ = &named_member.type_; - match type_ { - DataTypeRef::Atom(_) | DataTypeRef::Defined(_) => { - pretty_writer_i1.write_line( - format!("load_{}(&v_p->{}, buf);", fn_name, named_member.name).as_bytes(), - )?; - } - DataTypeRef::Ptr(_) => { - pretty_writer_i1.write_line( - format!( - "memcpy(&v_p->{}, &buf[{} + {}], sizeof v_p->{});", - named_member.name, current_offset, offset, named_member.name - ) - .as_bytes(), - )?; - } - } - } - pretty_writer_preprocessor.write_line(b"#endif")?; - } - pretty_writer.write_line(b"}")?.eob()?; - - Ok(()) -} diff --git a/lucet-idl/src/c/mod.rs b/lucet-idl/src/c/mod.rs index ec73bd9e5..8042a0ba7 100644 --- a/lucet-idl/src/c/mod.rs +++ b/lucet-idl/src/c/mod.rs @@ -1,7 +1,6 @@ #![allow(dead_code)] #![allow(unused_variables)] -// mod accessors; mod alias; mod cache; mod catom; @@ -14,7 +13,7 @@ use self::cache::{Cache, CachedStructMemberEntry, CachedTypeEntry}; pub(crate) use self::catom::*; use crate::backend::*; use crate::error::IDLError; -use crate::generator::{Generator, Hierarchy}; +use crate::generator::Generator; use crate::module::Module; use crate::pretty_writer::PrettyWriter; use crate::target::Target; @@ -95,63 +94,6 @@ impl Generator for CGenerator { ) -> Result<(), IDLError> { r#enum::generate(self, module, pretty_writer, data_type_entry) } - - fn gen_accessors_struct( - &mut self, - module: &Module, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - hierarchy: &Hierarchy, - ) -> Result<(), IDLError> { - /* - accessors::r#struct::generate( - self, - module, - pretty_writer, - data_type_entry, - hierarchy, - ) - */ - Ok(()) - } - - fn gen_accessors_enum( - &mut self, - module: &Module, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - hierarchy: &Hierarchy, - ) -> Result<(), IDLError> { - /* - accessors::r#enum::generate( - self, - module, - pretty_writer, - data_type_entry, - hierarchy, - ) - */ - Ok(()) - } - - fn gen_accessors_alias( - &mut self, - module: &Module, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - hierarchy: &Hierarchy, - ) -> Result<(), IDLError> { - /* - accessors::alias::generate( - self, - module, - pretty_writer, - data_type_entry, - hierarchy, - ) - */ - Ok(()) - } } impl CGenerator { @@ -245,25 +187,4 @@ impl CGenerator { type_ } } - - /* - fn gen_accessors_for_data_type_ref( - &mut self, - module: &Module, - pretty_writer: &mut PrettyWriter, - type_: &DataTypeRef, - name: &str, - hierarchy: &Hierarchy, - ) -> Result<(), IDLError> { - let type_ = self.unalias(module, type_); - match type_ { - DataTypeRef::Atom(atom_type) => { - accessors::atom::generate(self, module, pretty_writer, *atom_type, &hierarchy) - } - DataTypeRef::Defined(data_type_id) => { - self.gen_accessors_for_id(module, pretty_writer, *data_type_id, &hierarchy) - } - } - } - */ } diff --git a/lucet-idl/src/generator.rs b/lucet-idl/src/generator.rs index ae60a466f..e58170476 100644 --- a/lucet-idl/src/generator.rs +++ b/lucet-idl/src/generator.rs @@ -3,7 +3,6 @@ use crate::module::Module; use crate::pretty_writer::PrettyWriter; use crate::types::{DataType, DataTypeEntry, Ident}; use std::io::Write; -use std::rc::Rc; pub trait Generator { fn gen_prelude(&mut self, pretty_writer: &mut PrettyWriter) -> Result<(), IDLError>; @@ -36,30 +35,6 @@ pub trait Generator { data_type_entry: &DataTypeEntry<'_>, ) -> Result<(), IDLError>; - fn gen_accessors_struct( - &mut self, - module: &Module, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - hierarchy: &Hierarchy, - ) -> Result<(), IDLError>; - - fn gen_accessors_enum( - &mut self, - module: &Module, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - hierarchy: &Hierarchy, - ) -> Result<(), IDLError>; - - fn gen_accessors_alias( - &mut self, - module: &Module, - pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, - hierarchy: &Hierarchy, - ) -> Result<(), IDLError>; - fn gen_for_id( &mut self, module: &Module, @@ -73,113 +48,7 @@ pub trait Generator { DataType::Alias { .. } => self.gen_alias(module, pretty_writer, &data_type_entry), DataType::Enum { .. } => self.gen_enum(module, pretty_writer, &data_type_entry), }?; - self.gen_accessors_for_id( - module, - pretty_writer, - id, - &Hierarchy::new(data_type_entry.name.name.to_string(), 0), - )?; - } - Ok(()) - } - - /// Generate accessors for a data type whose identifier is `id` - /// `hierarchy` is used to derive function names from nested types - fn gen_accessors_for_id( - &mut self, - module: &Module, - pretty_writer: &mut PrettyWriter, - id: Ident, - hierarchy: &Hierarchy, - ) -> Result<(), IDLError> { - if let Some(data_type_entry) = module.get_datatype(id) { - match &data_type_entry.data_type { - DataType::Struct { .. } => { - self.gen_accessors_struct(module, pretty_writer, &data_type_entry, hierarchy) - } - DataType::Alias { .. } => { - self.gen_accessors_alias(module, pretty_writer, &data_type_entry, hierarchy) - } - DataType::Enum { .. } => { - self.gen_accessors_enum(module, pretty_writer, &data_type_entry, hierarchy) - } - }?; } Ok(()) } } - -#[derive(Debug, Clone)] -pub struct HierarchyEntry { - name: Rc, - offset: usize, -} - -impl HierarchyEntry { - pub fn new(name: String, offset: usize) -> Self { - HierarchyEntry { - name: Rc::new(name), - offset, - } - } -} - -#[derive(Debug, Clone)] -pub struct Hierarchy(Vec); - -impl Hierarchy { - pub fn new(name: String, offset: usize) -> Self { - Hierarchy(vec![HierarchyEntry::new(name, offset)]) - } - - pub fn push(&self, name: String, offset: usize) -> Self { - let mut cloned = self.clone(); - cloned.0.push(HierarchyEntry::new(name, offset)); - cloned - } - - pub fn depth(&self) -> usize { - self.0.len() - } - - pub fn idl_name(&self) -> String { - self.0 - .iter() - .map(|x| x.name.as_str()) - .collect::>() - .join(".") - } - - pub fn fn_name(&self) -> String { - self.0 - .iter() - .map(|x| x.name.as_str()) - .collect::>() - .join("_") - } - - #[allow(dead_code)] - pub fn parent_name(&self) -> String { - let len = self.0.len(); - assert!(len > 1); - self.0 - .iter() - .take(len - 1) - .map(|x| x.name.as_str()) - .collect::>() - .join("_") - } - - pub fn root_name(&self) -> String { - self.0 - .iter() - .take(1) - .map(|x| x.name.as_str()) - .collect::>() - .join("_") - } - - pub fn current_offset(&self) -> usize { - self.0.last().expect("Empty hierarchy").offset - } -} diff --git a/lucet-idl/src/rust/mod.rs b/lucet-idl/src/rust/mod.rs index 2b9a6fe87..9b48919c6 100644 --- a/lucet-idl/src/rust/mod.rs +++ b/lucet-idl/src/rust/mod.rs @@ -3,7 +3,7 @@ use crate::backend::BackendConfig; use crate::error::IDLError; -use crate::generator::{Generator, Hierarchy}; +use crate::generator::Generator; use crate::module::Module; use crate::pretty_writer::PrettyWriter; use crate::target::Target; @@ -182,34 +182,4 @@ impl Generator for RustGenerator { pretty_writer.write_line("}".as_bytes())?.eob()?; Ok(()) } - - fn gen_accessors_struct( - &mut self, - _module: &Module, - _pretty_writer: &mut PrettyWriter, - _data_type_entry: &DataTypeEntry<'_>, - _hierarchy: &Hierarchy, - ) -> Result<(), IDLError> { - Ok(()) - } - - fn gen_accessors_enum( - &mut self, - _module: &Module, - _pretty_writer: &mut PrettyWriter, - _data_type_entry: &DataTypeEntry<'_>, - _hierarchy: &Hierarchy, - ) -> Result<(), IDLError> { - Ok(()) - } - - fn gen_accessors_alias( - &mut self, - _module: &Module, - _pretty_writer: &mut PrettyWriter, - _data_type_entry: &DataTypeEntry<'_>, - _hierarchy: &Hierarchy, - ) -> Result<(), IDLError> { - Ok(()) - } } From 9dff8ff435ab6f2ceb1952cbfe01ed3c0f131fb2 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 8 May 2019 10:50:42 -0700 Subject: [PATCH 195/512] lucet-idl: refactor DataTypeEntry into a generic name wrapper --- lucet-idl/src/c/alias.rs | 4 ++-- lucet-idl/src/c/enum.rs | 4 ++-- lucet-idl/src/c/mod.rs | 16 ++++++++-------- lucet-idl/src/c/struct.rs | 4 ++-- lucet-idl/src/generator.rs | 20 +++++++++++++------- lucet-idl/src/module.rs | 9 ++++----- lucet-idl/src/rust/mod.rs | 18 +++++++++--------- lucet-idl/src/types.rs | 4 ++-- 8 files changed, 42 insertions(+), 37 deletions(-) diff --git a/lucet-idl/src/c/alias.rs b/lucet-idl/src/c/alias.rs index 0a67d26e3..beda94324 100644 --- a/lucet-idl/src/c/alias.rs +++ b/lucet-idl/src/c/alias.rs @@ -6,9 +6,9 @@ pub fn generate( cgenerator: &mut CGenerator, module: &Module, pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, + data_type_entry: &Named, ) -> Result<(), IDLError> { - let (type_, _attrs) = if let DataType::Alias { to: type_, attrs } = &data_type_entry.data_type { + let (type_, _attrs) = if let DataType::Alias { to: type_, attrs } = &data_type_entry.entity { (type_, attrs) } else { unreachable!() diff --git a/lucet-idl/src/c/enum.rs b/lucet-idl/src/c/enum.rs index 5fff7c4f5..ee7d30452 100644 --- a/lucet-idl/src/c/enum.rs +++ b/lucet-idl/src/c/enum.rs @@ -6,12 +6,12 @@ pub fn generate( cgenerator: &mut CGenerator, _module: &Module, pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, + data_type_entry: &Named, ) -> Result<(), IDLError> { let (named_members, _attrs) = if let DataType::Enum { members: named_members, attrs, - } = &data_type_entry.data_type + } = &data_type_entry.entity { (named_members, attrs) } else { diff --git a/lucet-idl/src/c/mod.rs b/lucet-idl/src/c/mod.rs index 8042a0ba7..98d3e4930 100644 --- a/lucet-idl/src/c/mod.rs +++ b/lucet-idl/src/c/mod.rs @@ -17,7 +17,7 @@ use crate::generator::Generator; use crate::module::Module; use crate::pretty_writer::PrettyWriter; use crate::target::Target; -use crate::types::{DataType, DataTypeEntry, DataTypeRef}; +use crate::types::{DataType, DataTypeRef, Named}; use std::io::prelude::*; #[derive(Clone, Debug)] @@ -53,7 +53,7 @@ impl Generator for CGenerator { &mut self, _module: &Module, pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, + data_type_entry: &Named, ) -> Result<(), IDLError> { pretty_writer .eob()? @@ -70,7 +70,7 @@ impl Generator for CGenerator { &mut self, module: &Module, pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, + data_type_entry: &Named, ) -> Result<(), IDLError> { alias::generate(self, module, pretty_writer, data_type_entry) } @@ -79,7 +79,7 @@ impl Generator for CGenerator { &mut self, module: &Module, pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, + data_type_entry: &Named, ) -> Result<(), IDLError> { r#struct::generate(self, module, pretty_writer, data_type_entry) } @@ -90,7 +90,7 @@ impl Generator for CGenerator { &mut self, module: &Module, pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, + data_type_entry: &Named, ) -> Result<(), IDLError> { r#enum::generate(self, module, pretty_writer, data_type_entry) } @@ -126,7 +126,7 @@ impl CGenerator { let data_type_entry = module .get_datatype(*data_type_id) .expect("defined datatype"); - match data_type_entry.data_type { + match data_type_entry.entity { DataType::Struct { .. } => { type_name = type_name .or_else(|| Some(format!("struct {}", data_type_entry.name.name))) @@ -165,7 +165,7 @@ impl CGenerator { DataTypeRef::Defined(inner_type) => inner_type, }; let inner_data_type_entry = module.get_datatype(*inner_type).expect("defined datatype"); - let inner_data_type = inner_data_type_entry.data_type; + let inner_data_type = inner_data_type_entry.entity; match inner_data_type { DataType::Struct { .. } => false, DataType::Enum { .. } => true, @@ -180,7 +180,7 @@ impl CGenerator { DataTypeRef::Defined(inner_type) => inner_type, }; let inner_data_type_entry = module.get_datatype(*inner_type).expect("defined datatype"); - let inner_data_type = inner_data_type_entry.data_type; + let inner_data_type = inner_data_type_entry.entity; if let DataType::Alias { to, .. } = inner_data_type { self.unalias(module, to) } else { diff --git a/lucet-idl/src/c/struct.rs b/lucet-idl/src/c/struct.rs index da195a21a..7e932b65e 100644 --- a/lucet-idl/src/c/struct.rs +++ b/lucet-idl/src/c/struct.rs @@ -5,12 +5,12 @@ pub fn generate( cgenerator: &mut CGenerator, module: &Module, pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, + data_type_entry: &Named, ) -> Result<(), IDLError> { let (named_members, _attrs) = if let DataType::Struct { members: named_members, attrs, - } = &data_type_entry.data_type + } = &data_type_entry.entity { (named_members, attrs) } else { diff --git a/lucet-idl/src/generator.rs b/lucet-idl/src/generator.rs index e58170476..f5f838665 100644 --- a/lucet-idl/src/generator.rs +++ b/lucet-idl/src/generator.rs @@ -1,7 +1,7 @@ use crate::error::IDLError; use crate::module::Module; use crate::pretty_writer::PrettyWriter; -use crate::types::{DataType, DataTypeEntry, Ident}; +use crate::types::{DataType, Ident, Named}; use std::io::Write; pub trait Generator { @@ -11,30 +11,36 @@ pub trait Generator { &mut self, module: &Module, pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, + data_type_entry: &Named, ) -> Result<(), IDLError>; fn gen_alias( &mut self, module: &Module, pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, + data_type_entry: &Named, ) -> Result<(), IDLError>; fn gen_struct( &mut self, module: &Module, pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, + data_type_entry: &Named, ) -> Result<(), IDLError>; fn gen_enum( &mut self, module: &Module, pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, + data_type_entry: &Named, ) -> Result<(), IDLError>; - + /* + fn gen_function( + &mut self, + module: &Module, + pretty_writer: &mut PrettyWriter, + func_decl: &Named, + */ fn gen_for_id( &mut self, module: &Module, @@ -43,7 +49,7 @@ pub trait Generator { ) -> Result<(), IDLError> { if let Some(data_type_entry) = module.get_datatype(id) { self.gen_type_header(module, pretty_writer, &data_type_entry)?; - match &data_type_entry.data_type { + match &data_type_entry.entity { DataType::Struct { .. } => self.gen_struct(module, pretty_writer, &data_type_entry), DataType::Alias { .. } => self.gen_alias(module, pretty_writer, &data_type_entry), DataType::Enum { .. } => self.gen_enum(module, pretty_writer, &data_type_entry), diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index c11973755..bca813f58 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -1,8 +1,7 @@ use crate::error::ValidationError; use crate::parser::{SyntaxDecl, SyntaxRef}; use crate::types::{ - Attr, DataType, DataTypeEntry, DataTypeRef, FuncDecl, FuncRet, Ident, Location, Name, - NamedMember, + Attr, DataType, DataTypeRef, FuncDecl, FuncRet, Ident, Location, Name, Named, NamedMember, }; use std::collections::HashMap; #[derive(Debug, PartialEq, Eq, Clone)] @@ -311,13 +310,13 @@ impl Module { } /// Retrieve information about a data type given its identifier - pub fn get_datatype(&self, id: Ident) -> Option> { + pub fn get_datatype(&self, id: Ident) -> Option> { let name = &self.names[id.0]; if let Some(data_type) = &self.data_types.get(&id) { - Some(DataTypeEntry { + Some(Named { id, name, - data_type, + entity: data_type, }) } else { None diff --git a/lucet-idl/src/rust/mod.rs b/lucet-idl/src/rust/mod.rs index 9b48919c6..07bacb279 100644 --- a/lucet-idl/src/rust/mod.rs +++ b/lucet-idl/src/rust/mod.rs @@ -8,7 +8,7 @@ use crate::module::Module; use crate::pretty_writer::PrettyWriter; use crate::target::Target; use crate::types::AtomType; -use crate::types::{DataType, DataTypeEntry, DataTypeRef, Ident}; +use crate::types::{DataType, DataTypeRef, Ident, Named}; use heck::{CamelCase, SnakeCase}; use std::collections::HashMap; use std::io::Write; @@ -41,7 +41,7 @@ impl RustGenerator { } } - fn define_name(&mut self, data_type_entry: &DataTypeEntry) -> String { + fn define_name(&mut self, data_type_entry: &Named) -> String { let typename = data_type_entry.name.name.to_camel_case(); self.defined.insert(data_type_entry.id, typename.clone()); typename @@ -81,7 +81,7 @@ impl Generator for RustGenerator { &mut self, _module: &Module, pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, + data_type_entry: &Named, ) -> Result<(), IDLError> { pretty_writer.eob()?.write_line( format!("/// {}: {:?}", data_type_entry.name.name, data_type_entry).as_bytes(), @@ -93,10 +93,10 @@ impl Generator for RustGenerator { &mut self, module: &Module, pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, + data_type_entry: &Named, ) -> Result<(), IDLError> { let (pointee, _attrs) = - if let DataType::Alias { to: pointee, attrs } = &data_type_entry.data_type { + if let DataType::Alias { to: pointee, attrs } = &data_type_entry.entity { (pointee, attrs) } else { unreachable!() @@ -115,12 +115,12 @@ impl Generator for RustGenerator { &mut self, module: &Module, pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, + data_type_entry: &Named, ) -> Result<(), IDLError> { let (named_members, _attrs) = if let DataType::Struct { members: named_members, attrs, - } = &data_type_entry.data_type + } = &data_type_entry.entity { (named_members, attrs) } else { @@ -155,12 +155,12 @@ impl Generator for RustGenerator { &mut self, module: &Module, pretty_writer: &mut PrettyWriter, - data_type_entry: &DataTypeEntry<'_>, + data_type_entry: &Named, ) -> Result<(), IDLError> { let (named_members, _attrs) = if let DataType::Enum { members: named_members, attrs, - } = &data_type_entry.data_type + } = &data_type_entry.entity { (named_members, attrs) } else { diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index 51c4e24ba..0f17beebc 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -104,8 +104,8 @@ impl fmt::Display for Name { /// A convenient structure holding a data type, its name and /// its internal IDL representation #[derive(Debug, Clone)] -pub struct DataTypeEntry<'t> { +pub struct Named<'t, E> { pub id: Ident, pub name: &'t Name, - pub data_type: &'t DataType, + pub entity: &'t E, } From a0df27faa6de54b23bed3394d4d50c9efa50e964 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 8 May 2019 15:01:53 -0700 Subject: [PATCH 196/512] lucet-idl: rather than pass pretty_writer along, make it part of the generator --- lucet-idl/src/c/alias.rs | 34 ++++++++++++------------ lucet-idl/src/c/enum.rs | 32 +++++++++-------------- lucet-idl/src/c/macros.rs | 8 +++--- lucet-idl/src/c/mod.rs | 37 ++++++++++++-------------- lucet-idl/src/c/prelude.rs | 4 +-- lucet-idl/src/c/struct.rs | 48 +++++++++++++++------------------- lucet-idl/src/config.rs | 6 ++--- lucet-idl/src/generator.rs | 43 +++++++++++++----------------- lucet-idl/src/lib.rs | 17 +++++------- lucet-idl/src/main.rs | 2 +- lucet-idl/src/module.rs | 16 +++++++++++- lucet-idl/src/pretty_writer.rs | 44 ++++++++----------------------- lucet-idl/src/rust/mod.rs | 44 +++++++++++++++++-------------- 13 files changed, 151 insertions(+), 184 deletions(-) diff --git a/lucet-idl/src/c/alias.rs b/lucet-idl/src/c/alias.rs index beda94324..388ad7b93 100644 --- a/lucet-idl/src/c/alias.rs +++ b/lucet-idl/src/c/alias.rs @@ -2,10 +2,9 @@ use super::*; // The most important thing in alias generation is to cache the size // and alignment rules of what it ultimately points to -pub fn generate( - cgenerator: &mut CGenerator, +pub fn generate( + gen: &mut CGenerator, module: &Module, - pretty_writer: &mut PrettyWriter, data_type_entry: &Named, ) -> Result<(), IDLError> { let (type_, _attrs) = if let DataType::Alias { to: type_, attrs } = &data_type_entry.entity { @@ -13,20 +12,21 @@ pub fn generate( } else { unreachable!() }; - let type_info = cgenerator.type_info(module, type_); - pretty_writer.indent()?; - pretty_writer.write(format!("typedef {}", type_info.type_name).as_bytes())?; - pretty_writer.space()?; - pretty_writer.write(data_type_entry.name.name.as_bytes())?; - pretty_writer.write(b";")?; - let leaf_type_info = cgenerator.type_info(module, type_info.leaf_data_type_ref); + let type_info = gen.type_info(module, type_); + gen.w.indent()?; + gen.w + .write(format!("typedef {}", type_info.type_name).as_bytes())?; + gen.w.space()?; + gen.w.write(data_type_entry.name.name.as_bytes())?; + gen.w.write(b";")?; + let leaf_type_info = gen.type_info(module, type_info.leaf_data_type_ref); if leaf_type_info.type_name != type_info.type_name { - pretty_writer.write(b" // equivalent to ")?; - pretty_writer.write(leaf_type_info.type_name.as_bytes())?; + gen.w.write(b" // equivalent to ")?; + gen.w.write(leaf_type_info.type_name.as_bytes())?; } - pretty_writer.eol()?; - pretty_writer.eob()?; - cgenerator.cache.store_type( + gen.w.eol()?; + gen.w.eob()?; + gen.cache.store_type( data_type_entry.id, CachedTypeEntry { type_size: type_info.type_size, @@ -36,14 +36,14 @@ pub fn generate( ); // Add an assertion to check that resolved size is the one we computed - pretty_writer.write_line( + gen.w.write_line( format!( "_Static_assert(sizeof({}) == {}, \"unexpected alias size\");", data_type_entry.name.name, type_info.type_size ) .as_bytes(), )?; - pretty_writer.eob()?; + gen.w.eob()?; Ok(()) } diff --git a/lucet-idl/src/c/enum.rs b/lucet-idl/src/c/enum.rs index ee7d30452..488648b81 100644 --- a/lucet-idl/src/c/enum.rs +++ b/lucet-idl/src/c/enum.rs @@ -2,10 +2,9 @@ use super::*; // Enums generate both a specific typedef, and a traditional C-style enum // The typedef is required to use a native type which is consistent across all architectures -pub fn generate( - cgenerator: &mut CGenerator, +pub fn generate( + gen: &mut CGenerator, _module: &Module, - pretty_writer: &mut PrettyWriter, data_type_entry: &Named, ) -> Result<(), IDLError> { let (named_members, _attrs) = if let DataType::Enum { @@ -25,7 +24,7 @@ pub fn generate( enum_native_type.native_type_name, ); - pretty_writer.write_line( + gen.w.write_line( format!( "typedef {} {}; // enum, should be in the [0...{}] range", type_name, @@ -34,8 +33,9 @@ pub fn generate( ) .as_bytes(), )?; - pretty_writer.write_line(format!("enum ___{} {{", data_type_entry.name.name).as_bytes())?; - let mut pretty_writer_i1 = pretty_writer.new_block(); + gen.w + .write_line(format!("enum ___{} {{", data_type_entry.name.name).as_bytes())?; + let mut pretty_writer_i1 = gen.w.new_block(); for (i, named_member) in named_members.iter().enumerate() { pretty_writer_i1.write_line( format!( @@ -46,26 +46,20 @@ pub fn generate( .as_bytes(), )?; } - pretty_writer.write_line(b"};")?; - pretty_writer.eob()?; - pretty_writer.write_line( + gen.w.write_line(b"};")?; + gen.w.eob()?; + gen.w.write_line( format!( "_Static_assert(sizeof({}) == {}, \"unexpected enumeration size\");", data_type_entry.name.name, type_size ) .as_bytes(), )?; - pretty_writer.eob()?; - macros::define( - cgenerator, - pretty_writer, - "BYTES", - &data_type_entry.name.name, - type_size, - )?; - pretty_writer.eob()?; + gen.w.eob()?; + macros::define(gen, "BYTES", &data_type_entry.name.name, type_size)?; + gen.w.eob()?; - cgenerator.cache.store_type( + gen.cache.store_type( data_type_entry.id, CachedTypeEntry { type_size, diff --git a/lucet-idl/src/c/macros.rs b/lucet-idl/src/c/macros.rs index 906405b88..38f3a9ba5 100644 --- a/lucet-idl/src/c/macros.rs +++ b/lucet-idl/src/c/macros.rs @@ -22,16 +22,14 @@ pub fn macro_for(prefix: &str, name: &str) -> String { // Generate a macro definition -pub fn define( - _cgenerator: &mut CGenerator, - pretty_writer: &mut PrettyWriter, +pub fn define( + gen: &mut CGenerator, prefix: &str, name: &str, value: V, ) -> Result<(), IDLError> { let macro_name = macro_for(prefix, name); - let mut pretty_writer_preprocessor = pretty_writer.new_from_writer(); - pretty_writer_preprocessor + gen.w .write_line(format!("#define {} {}", macro_name, value.to_string()).as_ref())?; Ok(()) } diff --git a/lucet-idl/src/c/mod.rs b/lucet-idl/src/c/mod.rs index 98d3e4930..eb7ad88ae 100644 --- a/lucet-idl/src/c/mod.rs +++ b/lucet-idl/src/c/mod.rs @@ -17,7 +17,7 @@ use crate::generator::Generator; use crate::module::Module; use crate::pretty_writer::PrettyWriter; use crate::target::Target; -use crate::types::{DataType, DataTypeRef, Named}; +use crate::types::{DataType, DataTypeRef, FuncDecl, Named}; use std::io::prelude::*; #[derive(Clone, Debug)] @@ -37,25 +37,16 @@ pub struct CGenerator { pub target: Target, pub backend_config: BackendConfig, pub cache: Cache, + pub w: PrettyWriter, } -impl Generator for CGenerator { - fn gen_prelude(&mut self, pretty_writer: &mut PrettyWriter) -> Result<(), IDLError> { - pretty_writer - .eob()? - .write_line(b"// ---------- Prelude ----------")? - .eob()?; - prelude::generate(pretty_writer, self.target, self.backend_config)?; - Ok(()) - } - +impl Generator for CGenerator { fn gen_type_header( &mut self, _module: &Module, - pretty_writer: &mut PrettyWriter, data_type_entry: &Named, ) -> Result<(), IDLError> { - pretty_writer + self.w .eob()? .write_line( format!("// ---------- {} ----------", data_type_entry.name.name).as_bytes(), @@ -69,19 +60,17 @@ impl Generator for CGenerator { fn gen_alias( &mut self, module: &Module, - pretty_writer: &mut PrettyWriter, data_type_entry: &Named, ) -> Result<(), IDLError> { - alias::generate(self, module, pretty_writer, data_type_entry) + alias::generate(self, module, data_type_entry) } fn gen_struct( &mut self, module: &Module, - pretty_writer: &mut PrettyWriter, data_type_entry: &Named, ) -> Result<(), IDLError> { - r#struct::generate(self, module, pretty_writer, data_type_entry) + r#struct::generate(self, module, data_type_entry) } // Enums generate both a specific typedef, and a traditional C-style enum @@ -89,19 +78,27 @@ impl Generator for CGenerator { fn gen_enum( &mut self, module: &Module, - pretty_writer: &mut PrettyWriter, data_type_entry: &Named, ) -> Result<(), IDLError> { - r#enum::generate(self, module, pretty_writer, data_type_entry) + r#enum::generate(self, module, data_type_entry) + } + + fn gen_function( + &mut self, + module: &Module, + func_decl_entry: &Named, + ) -> Result<(), IDLError> { + unimplemented!(); } } impl CGenerator { - pub fn new(target: Target, backend_config: BackendConfig) -> Self { + pub fn new(target: Target, backend_config: BackendConfig, w: Box) -> Self { Self { target, backend_config, cache: Cache::default(), + w: PrettyWriter::new(w), } } /// Traverse a `DataTypeRef` chain, and return information diff --git a/lucet-idl/src/c/prelude.rs b/lucet-idl/src/c/prelude.rs index 3edddd76c..96f561905 100644 --- a/lucet-idl/src/c/prelude.rs +++ b/lucet-idl/src/c/prelude.rs @@ -1,7 +1,7 @@ use super::*; -pub fn generate( - pretty_writer: &mut PrettyWriter, +pub fn generate( + pretty_writer: &mut PrettyWriter, target: Target, backend_config: BackendConfig, ) -> Result<(), IDLError> { diff --git a/lucet-idl/src/c/struct.rs b/lucet-idl/src/c/struct.rs index 7e932b65e..2f6156087 100644 --- a/lucet-idl/src/c/struct.rs +++ b/lucet-idl/src/c/struct.rs @@ -1,10 +1,9 @@ use super::*; use std::cmp; -pub fn generate( - cgenerator: &mut CGenerator, +pub fn generate( + gen: &mut CGenerator, module: &Module, - pretty_writer: &mut PrettyWriter, data_type_entry: &Named, ) -> Result<(), IDLError> { let (named_members, _attrs) = if let DataType::Struct { @@ -16,41 +15,42 @@ pub fn generate( } else { unreachable!() }; - pretty_writer.write_line(format!("struct {} {{", data_type_entry.name.name).as_bytes())?; - let mut pretty_writer_i1 = pretty_writer.new_block(); + gen.w + .write_line(format!("struct {} {{", data_type_entry.name.name).as_bytes())?; + let mut w_block = gen.w.new_block(); let mut offset: usize = 0; let mut first_member_align = 0; let mut members_offsets = vec![]; for named_member in named_members { - let type_info = cgenerator.type_info(module, &named_member.type_); + let type_info = gen.type_info(module, &named_member.type_); let type_align = type_info.type_align; let type_size = type_info.type_size; let padding = (type_align - 1) - ((offset + (type_align - 1)) % type_align); if padding > 0 { - pretty_writer_i1.write_line( + w_block.write_line( format!("uint8_t ___pad{}_{}[{}];", type_align, offset, padding).as_bytes(), )?; offset += padding; } members_offsets.push(offset); - pretty_writer_i1.indent()?; - pretty_writer_i1.write(type_info.type_name.as_bytes())?; - pretty_writer_i1.space()?; - pretty_writer_i1.write(named_member.name.as_bytes())?; - pretty_writer_i1.write(b";")?; - pretty_writer_i1.eol()?; + w_block.indent()?; + w_block.write(type_info.type_name.as_bytes())?; + w_block.space()?; + w_block.write(named_member.name.as_bytes())?; + w_block.write(b";")?; + w_block.eol()?; offset += type_size; first_member_align = cmp::max(first_member_align, type_align); } - pretty_writer.write_line(b"};")?; - pretty_writer.eob()?; + gen.w.write_line(b"};")?; + gen.w.eob()?; // cache the total structure size, as well as its alignment, which is equal // to the alignment of the first member of that structure let struct_align = first_member_align; let struct_size = offset; - let cached = cgenerator.cache.store_type( + let cached = gen.cache.store_type( data_type_entry.id, CachedTypeEntry { type_size: struct_size, @@ -71,7 +71,7 @@ pub fn generate( // Also add a macro definition for the structure size // Skip the first member, as it will always be at the beginning of the structure for (i, named_member) in named_members.iter().enumerate().skip(1) { - pretty_writer.write_line( + gen.w.write_line( format!( "_Static_assert(offsetof(struct {}, {}) == {}, \"unexpected offset\");", data_type_entry.name.name, named_member.name, members_offsets[i] @@ -79,22 +79,16 @@ pub fn generate( .as_bytes(), )?; } - pretty_writer.write_line( + gen.w.write_line( format!( "_Static_assert(sizeof(struct {}) == {}, \"unexpected structure size\");", data_type_entry.name.name, struct_size ) .as_bytes(), )?; - pretty_writer.eob()?; - macros::define( - cgenerator, - pretty_writer, - "BYTES", - &data_type_entry.name.name, - struct_size, - )?; - pretty_writer.eob()?; + gen.w.eob()?; + macros::define(gen, "BYTES", &data_type_entry.name.name, struct_size)?; + gen.w.eob()?; Ok(()) } diff --git a/lucet-idl/src/config.rs b/lucet-idl/src/config.rs index 1b7956e2e..b200effb4 100644 --- a/lucet-idl/src/config.rs +++ b/lucet-idl/src/config.rs @@ -29,10 +29,10 @@ impl Config { } } - pub fn generator(&self) -> Box> { + pub fn generator(&self, w: Box) -> Box { match self.backend { - Backend::C => Box::new(CGenerator::new(self.target, self.backend_config)), - Backend::Rust => Box::new(RustGenerator::new(self.target, self.backend_config)), + Backend::C => Box::new(CGenerator::new(self.target, self.backend_config, w)), + Backend::Rust => Box::new(RustGenerator::new(self.target, self.backend_config, w)), } } } diff --git a/lucet-idl/src/generator.rs b/lucet-idl/src/generator.rs index f5f838665..af2732a98 100644 --- a/lucet-idl/src/generator.rs +++ b/lucet-idl/src/generator.rs @@ -1,59 +1,52 @@ use crate::error::IDLError; use crate::module::Module; -use crate::pretty_writer::PrettyWriter; -use crate::types::{DataType, Ident, Named}; -use std::io::Write; - -pub trait Generator { - fn gen_prelude(&mut self, pretty_writer: &mut PrettyWriter) -> Result<(), IDLError>; +use crate::types::{DataType, FuncDecl, Ident, Named}; +pub trait Generator { fn gen_type_header( &mut self, module: &Module, - pretty_writer: &mut PrettyWriter, data_type_entry: &Named, ) -> Result<(), IDLError>; fn gen_alias( &mut self, module: &Module, - pretty_writer: &mut PrettyWriter, data_type_entry: &Named, ) -> Result<(), IDLError>; fn gen_struct( &mut self, module: &Module, - pretty_writer: &mut PrettyWriter, data_type_entry: &Named, ) -> Result<(), IDLError>; fn gen_enum( &mut self, module: &Module, - pretty_writer: &mut PrettyWriter, data_type_entry: &Named, ) -> Result<(), IDLError>; - /* - fn gen_function( - &mut self, - module: &Module, - pretty_writer: &mut PrettyWriter, - func_decl: &Named, - */ - fn gen_for_id( + + fn gen_function( &mut self, module: &Module, - pretty_writer: &mut PrettyWriter, - id: Ident, - ) -> Result<(), IDLError> { + func_decl_entry: &Named, + ) -> Result<(), IDLError>; + + fn gen_for_id(&mut self, module: &Module, id: Ident) -> Result<(), IDLError> { if let Some(data_type_entry) = module.get_datatype(id) { - self.gen_type_header(module, pretty_writer, &data_type_entry)?; + self.gen_type_header(module, &data_type_entry)?; match &data_type_entry.entity { - DataType::Struct { .. } => self.gen_struct(module, pretty_writer, &data_type_entry), - DataType::Alias { .. } => self.gen_alias(module, pretty_writer, &data_type_entry), - DataType::Enum { .. } => self.gen_enum(module, pretty_writer, &data_type_entry), + DataType::Struct { .. } => self.gen_struct(module, &data_type_entry), + DataType::Alias { .. } => self.gen_alias(module, &data_type_entry), + DataType::Enum { .. } => self.gen_enum(module, &data_type_entry), }?; + } else { + if let Some(func_decl_entry) = module.get_func_decl(id) { + self.gen_function(module, &func_decl_entry)?; + } else { + unreachable!("identifier must be for a datatype or function declration") + } } Ok(()) } diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 3176e0666..3bef09d5d 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -24,29 +24,24 @@ pub use crate::target::Target; use crate::package::Package; use crate::parser::Parser; -use crate::pretty_writer::PrettyWriter; use std::io::Write; -pub fn run(config: &Config, input: &str, output: W) -> Result { +pub fn run(config: &Config, input: &str, output: Box) -> Result<(), IDLError> { let mut parser = Parser::new(&input); let decls = parser.match_decls()?; - let mut pretty_writer = PrettyWriter::new(output); let pkg = Package::from_declarations(&decls)?; + let mut generator = config.generator(output); + for (_ident, mod_) in pkg.modules { let deps = mod_ - .ordered_dependencies() + .ordered_datatype_idents() .map_err(|_| IDLError::InternalError("Unable to resolve dependencies"))?; - let mut generator = config.generator(); - - generator.gen_prelude(&mut pretty_writer)?; for id in deps { - generator.gen_for_id(&mod_, &mut pretty_writer, id)?; + generator.gen_for_id(&mod_, id)?; } } - Ok(pretty_writer - .into_inner() - .expect("outermost pretty_writer can unwrap")) + Ok(()) } diff --git a/lucet-idl/src/main.rs b/lucet-idl/src/main.rs index a49b40fa7..34ff25da3 100644 --- a/lucet-idl/src/main.rs +++ b/lucet-idl/src/main.rs @@ -74,7 +74,7 @@ fn doit() -> Result<(), IDLError> { let mut source = String::new(); File::open(&exe_config.input_path)?.read_to_string(&mut source)?; - run(&exe_config.config, &source, io::stdout())?; + run(&exe_config.config, &source, Box::new(io::stdout()))?; Ok(()) } diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index bca813f58..06e85d52a 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -256,7 +256,7 @@ impl Module { Ok(()) } - pub fn ordered_dependencies(&self) -> Result, ()> { + pub fn ordered_datatype_idents(&self) -> Result, ()> { let mut visited = Vec::new(); visited.resize(self.names.len(), false); let mut ordered = Vec::with_capacity(visited.capacity()); @@ -322,6 +322,20 @@ impl Module { None } } + + /// Retrieve information about a function declaration given its identifier + pub fn get_func_decl(&self, id: Ident) -> Option> { + let name = &self.names[id.0]; + if let Some(func_decl) = &self.funcs.get(&id) { + Some(Named { + id, + name, + entity: func_decl, + }) + } else { + None + } + } } #[cfg(test)] diff --git a/lucet-idl/src/pretty_writer.rs b/lucet-idl/src/pretty_writer.rs index aea75d064..b24fbe750 100644 --- a/lucet-idl/src/pretty_writer.rs +++ b/lucet-idl/src/pretty_writer.rs @@ -6,15 +6,15 @@ use std::rc::Rc; /// Write indented code /// #[derive(Clone)] -pub struct PrettyWriter { - writer: Rc>, +pub struct PrettyWriter { + writer: Rc>>, indent: u32, indent_bytes: Vec, } -impl PrettyWriter { +impl PrettyWriter { /// Create a new `PrettyWriter` with `indent` initial units of indentation - pub fn new_with_indent(writer: W, indent: u32) -> Self { + pub fn new_with_indent(writer: Box, indent: u32) -> Self { PrettyWriter { writer: Rc::new(RefCell::new(writer)), indent, @@ -23,19 +23,10 @@ impl PrettyWriter { } /// Create a new `PrettyWriter` with no initial indentation - pub fn new(writer: W) -> Self { + pub fn new(writer: Box) -> Self { PrettyWriter::new_with_indent(writer, 0) } - /// Create a writer based on a existing writer, but with no indentation` - pub fn new_from_writer(&mut self) -> Self { - PrettyWriter { - writer: self.writer.clone(), - indent: 0, - indent_bytes: self.indent_bytes.clone(), - } - } - /// Create an indented block within the current `PrettyWriter` pub fn new_block(&mut self) -> Self { PrettyWriter { @@ -45,8 +36,8 @@ impl PrettyWriter { } } - fn _write_all(writer: &mut W, buf: &[u8]) -> Result<(), IDLError> { - writer.write_all(buf).map_err(Into::into) + fn _write_all(&mut self, buf: &[u8]) -> Result<(), IDLError> { + self.writer.borrow_mut().write_all(buf).map_err(Into::into) } /// Return the current indentation level @@ -59,9 +50,8 @@ impl PrettyWriter { pub fn indent(&mut self) -> Result<&mut Self, IDLError> { let indent_bytes = &self.indent_bytes.clone(); { - let mut writer = self.writer.borrow_mut(); for _ in 0..self.indent { - Self::_write_all(&mut writer, indent_bytes)? + self._write_all(indent_bytes)? } } Ok(self) @@ -69,13 +59,13 @@ impl PrettyWriter { /// Output a space pub fn space(&mut self) -> Result<&mut Self, IDLError> { - Self::_write_all(&mut self.writer.borrow_mut(), b" ")?; + self._write_all(b" ")?; Ok(self) } /// Output an end of line pub fn eol(&mut self) -> Result<&mut Self, IDLError> { - Self::_write_all(&mut self.writer.borrow_mut(), b"\n")?; + self._write_all(b"\n")?; Ok(self) } @@ -84,17 +74,9 @@ impl PrettyWriter { self.eol() } - /// Continuation - pub fn continuation(&mut self) -> Result<&mut Self, IDLError> { - self.indent()?; - let indent_bytes = &self.indent_bytes.clone(); - Self::_write_all(&mut self.writer.borrow_mut(), indent_bytes)?; - Ok(self) - } - /// Write raw data pub fn write(&mut self, buf: &[u8]) -> Result<&mut Self, IDLError> { - Self::_write_all(&mut self.writer.borrow_mut(), buf)?; + self._write_all(buf)?; Ok(self) } @@ -102,8 +84,4 @@ impl PrettyWriter { pub fn write_line(&mut self, buf: &[u8]) -> Result<&mut Self, IDLError> { self.indent()?.write(buf)?.eol() } - - pub fn into_inner(self) -> Option { - Rc::try_unwrap(self.writer).ok().map(|w| w.into_inner()) - } } diff --git a/lucet-idl/src/rust/mod.rs b/lucet-idl/src/rust/mod.rs index 07bacb279..d4d715924 100644 --- a/lucet-idl/src/rust/mod.rs +++ b/lucet-idl/src/rust/mod.rs @@ -8,7 +8,7 @@ use crate::module::Module; use crate::pretty_writer::PrettyWriter; use crate::target::Target; use crate::types::AtomType; -use crate::types::{DataType, DataTypeRef, Ident, Named}; +use crate::types::{DataType, DataTypeRef, FuncDecl, Ident, Named}; use heck::{CamelCase, SnakeCase}; use std::collections::HashMap; use std::io::Write; @@ -30,14 +30,16 @@ pub struct RustGenerator { pub target: Target, pub backend_config: BackendConfig, pub defined: HashMap, + pub w: PrettyWriter, } impl RustGenerator { - pub fn new(target: Target, backend_config: BackendConfig) -> Self { + pub fn new(target: Target, backend_config: BackendConfig, w: Box) -> Self { Self { target, backend_config, defined: HashMap::new(), + w: PrettyWriter::new(w), } } @@ -72,18 +74,13 @@ impl RustGenerator { } } -impl Generator for RustGenerator { - fn gen_prelude(&mut self, _pretty_writer: &mut PrettyWriter) -> Result<(), IDLError> { - Ok(()) - } - +impl Generator for RustGenerator { fn gen_type_header( &mut self, _module: &Module, - pretty_writer: &mut PrettyWriter, data_type_entry: &Named, ) -> Result<(), IDLError> { - pretty_writer.eob()?.write_line( + self.w.eob()?.write_line( format!("/// {}: {:?}", data_type_entry.name.name, data_type_entry).as_bytes(), )?; Ok(()) @@ -92,7 +89,6 @@ impl Generator for RustGenerator { fn gen_alias( &mut self, module: &Module, - pretty_writer: &mut PrettyWriter, data_type_entry: &Named, ) -> Result<(), IDLError> { let (pointee, _attrs) = @@ -105,7 +101,7 @@ impl Generator for RustGenerator { let typename = self.define_name(data_type_entry); let pointee_name = self.get_defined_name(pointee); - pretty_writer + self.w .write_line(format!("type {} = {};", typename, pointee_name).as_bytes())? .eob()?; Ok(()) @@ -114,7 +110,6 @@ impl Generator for RustGenerator { fn gen_struct( &mut self, module: &Module, - pretty_writer: &mut PrettyWriter, data_type_entry: &Named, ) -> Result<(), IDLError> { let (named_members, _attrs) = if let DataType::Struct { @@ -130,14 +125,15 @@ impl Generator for RustGenerator { let typename = data_type_entry.name.name.to_camel_case(); self.defined.insert(data_type_entry.id, typename.clone()); - pretty_writer + self.w .write_line("#[repr(C)]".as_bytes())? .write_line(format!("struct {} {{", typename).as_bytes())?; + let mut w = self.w.new_block(); for m in named_members { - pretty_writer.write_line( + w.write_line( format!( - " {}: {},", + "{}: {},", m.name.to_snake_case(), self.get_defined_name(&m.type_) ) @@ -145,7 +141,7 @@ impl Generator for RustGenerator { )?; } - pretty_writer.write_line("}".as_bytes())?.eob()?; + self.w.write_line("}".as_bytes())?.eob()?; Ok(()) } @@ -154,7 +150,6 @@ impl Generator for RustGenerator { fn gen_enum( &mut self, module: &Module, - pretty_writer: &mut PrettyWriter, data_type_entry: &Named, ) -> Result<(), IDLError> { let (named_members, _attrs) = if let DataType::Enum { @@ -170,16 +165,25 @@ impl Generator for RustGenerator { let typename = data_type_entry.name.name.to_camel_case(); self.defined.insert(data_type_entry.id, typename.clone()); - pretty_writer + self.w .write_line("#[repr(C)]".as_bytes())? .write_line("#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]".as_bytes())? .write_line(format!("enum {} {{", typename).as_bytes())?; + let mut w = self.w.new_block(); for m in named_members { - pretty_writer.write_line(format!(" {},", m.name.to_camel_case()).as_bytes())?; + w.write_line(format!("{},", m.name.to_camel_case()).as_bytes())?; } - pretty_writer.write_line("}".as_bytes())?.eob()?; + self.w.write_line("}".as_bytes())?.eob()?; Ok(()) } + + fn gen_function( + &mut self, + module: &Module, + func_decl_entry: &Named, + ) -> Result<(), IDLError> { + unimplemented!(); + } } From edc616a34b942a342023f2d5e82e564605498e48 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 8 May 2019 16:12:46 -0700 Subject: [PATCH 197/512] lucet-idl: module iterators for datatypes and funcs. simplify calls to write_line --- lucet-idl/src/generator.rs | 22 ++++++------------ lucet-idl/src/lib.rs | 11 ++++----- lucet-idl/src/module.rs | 33 ++++++++++++++++++-------- lucet-idl/src/pretty_writer.rs | 5 ++++ lucet-idl/src/rust/mod.rs | 42 +++++++++++++++++----------------- 5 files changed, 61 insertions(+), 52 deletions(-) diff --git a/lucet-idl/src/generator.rs b/lucet-idl/src/generator.rs index af2732a98..335f42301 100644 --- a/lucet-idl/src/generator.rs +++ b/lucet-idl/src/generator.rs @@ -1,6 +1,6 @@ use crate::error::IDLError; use crate::module::Module; -use crate::types::{DataType, FuncDecl, Ident, Named}; +use crate::types::{DataType, FuncDecl, Named}; pub trait Generator { fn gen_type_header( @@ -33,20 +33,12 @@ pub trait Generator { func_decl_entry: &Named, ) -> Result<(), IDLError>; - fn gen_for_id(&mut self, module: &Module, id: Ident) -> Result<(), IDLError> { - if let Some(data_type_entry) = module.get_datatype(id) { - self.gen_type_header(module, &data_type_entry)?; - match &data_type_entry.entity { - DataType::Struct { .. } => self.gen_struct(module, &data_type_entry), - DataType::Alias { .. } => self.gen_alias(module, &data_type_entry), - DataType::Enum { .. } => self.gen_enum(module, &data_type_entry), - }?; - } else { - if let Some(func_decl_entry) = module.get_func_decl(id) { - self.gen_function(module, &func_decl_entry)?; - } else { - unreachable!("identifier must be for a datatype or function declration") - } + fn gen_datatype(&mut self, module: &Module, dt: &Named) -> Result<(), IDLError> { + self.gen_type_header(module, dt)?; + match &dt.entity { + DataType::Struct { .. } => self.gen_struct(module, dt)?, + DataType::Alias { .. } => self.gen_alias(module, dt)?, + DataType::Enum { .. } => self.gen_enum(module, dt)?, } Ok(()) } diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 3bef09d5d..c87a367a8 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -35,12 +35,11 @@ pub fn run(config: &Config, input: &str, output: Box) -> Result<(), I let mut generator = config.generator(output); for (_ident, mod_) in pkg.modules { - let deps = mod_ - .ordered_datatype_idents() - .map_err(|_| IDLError::InternalError("Unable to resolve dependencies"))?; - - for id in deps { - generator.gen_for_id(&mod_, id)?; + for dt in mod_.datatypes() { + generator.gen_datatype(&mod_, &dt)?; + } + for fdecl in mod_.func_decls() { + generator.gen_function(&mod_, &fdecl)?; } } Ok(()) diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index 06e85d52a..8e138332d 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -256,16 +256,6 @@ impl Module { Ok(()) } - pub fn ordered_datatype_idents(&self) -> Result, ()> { - let mut visited = Vec::new(); - visited.resize(self.names.len(), false); - let mut ordered = Vec::with_capacity(visited.capacity()); - for id in self.data_types.keys() { - let _ = self.dfs_walk(*id, &mut visited, &mut Some(&mut ordered)); - } - Ok(ordered) - } - fn dfs_find_cycle(&self, id: Ident) -> Result<(), ()> { let mut visited = Vec::new(); visited.resize(self.names.len(), false); @@ -336,6 +326,29 @@ impl Module { None } } + + fn ordered_datatype_idents(&self) -> Vec { + let mut visited = Vec::new(); + visited.resize(self.names.len(), false); + let mut ordered = Vec::with_capacity(visited.capacity()); + for id in self.data_types.keys() { + let _ = self.dfs_walk(*id, &mut visited, &mut Some(&mut ordered)); + } + ordered + } + + pub fn datatypes(&self) -> impl Iterator> { + let idents = self.ordered_datatype_idents(); + idents + .into_iter() + .map(move |i| self.get_datatype(i).unwrap()) + } + + pub fn func_decls(&self) -> impl Iterator> { + self.funcs + .iter() + .map(move |(i, _)| self.get_func_decl(*i).unwrap()) + } } #[cfg(test)] diff --git a/lucet-idl/src/pretty_writer.rs b/lucet-idl/src/pretty_writer.rs index b24fbe750..45b5708f0 100644 --- a/lucet-idl/src/pretty_writer.rs +++ b/lucet-idl/src/pretty_writer.rs @@ -84,4 +84,9 @@ impl PrettyWriter { pub fn write_line(&mut self, buf: &[u8]) -> Result<&mut Self, IDLError> { self.indent()?.write(buf)?.eol() } + + /// Indent, write raw data and terminate with an end of line + pub fn writeln>(&mut self, buf: S) -> Result<&mut Self, IDLError> { + self.write_line(buf.as_ref().as_bytes()) + } } diff --git a/lucet-idl/src/rust/mod.rs b/lucet-idl/src/rust/mod.rs index d4d715924..fb8125a10 100644 --- a/lucet-idl/src/rust/mod.rs +++ b/lucet-idl/src/rust/mod.rs @@ -80,9 +80,10 @@ impl Generator for RustGenerator { _module: &Module, data_type_entry: &Named, ) -> Result<(), IDLError> { - self.w.eob()?.write_line( - format!("/// {}: {:?}", data_type_entry.name.name, data_type_entry).as_bytes(), - )?; + self.w.eob()?.writeln(format!( + "/// {}: {:?}", + data_type_entry.name.name, data_type_entry + ))?; Ok(()) } @@ -102,7 +103,7 @@ impl Generator for RustGenerator { let pointee_name = self.get_defined_name(pointee); self.w - .write_line(format!("type {} = {};", typename, pointee_name).as_bytes())? + .writeln(format!("type {} = {};", typename, pointee_name))? .eob()?; Ok(()) } @@ -126,22 +127,19 @@ impl Generator for RustGenerator { self.defined.insert(data_type_entry.id, typename.clone()); self.w - .write_line("#[repr(C)]".as_bytes())? - .write_line(format!("struct {} {{", typename).as_bytes())?; + .writeln("#[repr(C)]")? + .writeln(format!("struct {} {{", typename))?; let mut w = self.w.new_block(); for m in named_members { - w.write_line( - format!( - "{}: {},", - m.name.to_snake_case(), - self.get_defined_name(&m.type_) - ) - .as_bytes(), - )?; + w.writeln(format!( + "{}: {},", + m.name.to_snake_case(), + self.get_defined_name(&m.type_) + ))?; } - self.w.write_line("}".as_bytes())?.eob()?; + self.w.writeln("}")?.eob()?; Ok(()) } @@ -166,16 +164,16 @@ impl Generator for RustGenerator { self.defined.insert(data_type_entry.id, typename.clone()); self.w - .write_line("#[repr(C)]".as_bytes())? - .write_line("#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]".as_bytes())? - .write_line(format!("enum {} {{", typename).as_bytes())?; + .writeln("#[repr(C)]")? + .writeln("#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]")? + .writeln(format!("enum {} {{", typename))?; let mut w = self.w.new_block(); for m in named_members { - w.write_line(format!("{},", m.name.to_camel_case()).as_bytes())?; + w.writeln(format!("{},", m.name.to_camel_case()))?; } - self.w.write_line("}".as_bytes())?.eob()?; + self.w.writeln("}")?.eob()?; Ok(()) } @@ -184,6 +182,8 @@ impl Generator for RustGenerator { module: &Module, func_decl_entry: &Named, ) -> Result<(), IDLError> { - unimplemented!(); + self.w + .write_line(format!("// {:?}", func_decl_entry).as_bytes())?; + Ok(()) } } From 57c8bd5752be4be94b224f46e617041df3b7edc2 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 8 May 2019 16:44:13 -0700 Subject: [PATCH 198/512] lucet-idl: limit return values to 0 or 1. output rust function signature. --- lucet-idl/src/module.rs | 24 ++++++++++++++++++++-- lucet-idl/src/rust/mod.rs | 40 +++++++++++++++++++++++++++++++------ lucet-idl/tests/example.idl | 2 +- lucet-idl/tests/example.rs | 4 ++-- 4 files changed, 59 insertions(+), 11 deletions(-) diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index 8e138332d..8f6ca3bbf 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -173,7 +173,11 @@ impl Module { ); } SyntaxDecl::Function { - args, rets, attrs, .. + args, + rets, + attrs, + location, + .. } => { let mut arg_names: HashMap = HashMap::new(); let args = args @@ -207,7 +211,12 @@ impl Module { }) }) .collect::, _>>()?; - + if rets.len() > 1 { + Err(ValidationError::Syntax { + expected: "at most one return value", + location: location.clone(), + })? + } self.define_function( id, FuncDecl { @@ -698,6 +707,17 @@ mod tests { ); } + #[test] + fn func_multiple_returns() { + assert_eq!( + mod_("fn trivial(a: u8) -> bool, bool;").err().unwrap(), + ValidationError::Syntax { + expected: "at most one return value", + location: Location { line: 1, column: 0 }, + } + ); + } + #[test] fn func_duplicate_arg() { assert_eq!( diff --git a/lucet-idl/src/rust/mod.rs b/lucet-idl/src/rust/mod.rs index fb8125a10..b167bc6eb 100644 --- a/lucet-idl/src/rust/mod.rs +++ b/lucet-idl/src/rust/mod.rs @@ -49,7 +49,7 @@ impl RustGenerator { typename } - fn get_defined_name(&self, data_type_ref: &DataTypeRef) -> &str { + fn get_defined_typename(&self, data_type_ref: &DataTypeRef) -> &str { match data_type_ref { DataTypeRef::Defined(id) => self.defined.get(id).expect("definition exists"), DataTypeRef::Atom(a) => Self::atom_name(a), @@ -100,10 +100,10 @@ impl Generator for RustGenerator { }; let typename = self.define_name(data_type_entry); - let pointee_name = self.get_defined_name(pointee); + let pointee_name = self.get_defined_typename(pointee); self.w - .writeln(format!("type {} = {};", typename, pointee_name))? + .writeln(format!("pub type {} = {};", typename, pointee_name))? .eob()?; Ok(()) } @@ -128,14 +128,14 @@ impl Generator for RustGenerator { self.w .writeln("#[repr(C)]")? - .writeln(format!("struct {} {{", typename))?; + .writeln(format!("pub struct {} {{", typename))?; let mut w = self.w.new_block(); for m in named_members { w.writeln(format!( "{}: {},", m.name.to_snake_case(), - self.get_defined_name(&m.type_) + self.get_defined_typename(&m.type_) ))?; } @@ -166,7 +166,7 @@ impl Generator for RustGenerator { self.w .writeln("#[repr(C)]")? .writeln("#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]")? - .writeln(format!("enum {} {{", typename))?; + .writeln(format!("pub enum {} {{", typename))?; let mut w = self.w.new_block(); for m in named_members { @@ -184,6 +184,34 @@ impl Generator for RustGenerator { ) -> Result<(), IDLError> { self.w .write_line(format!("// {:?}", func_decl_entry).as_bytes())?; + + let name = func_decl_entry.name.name.to_snake_case(); + let mut args = String::new(); + for a in func_decl_entry.entity.args.iter() { + args += &format!( + "{}: {},", + a.name.to_snake_case(), + self.get_defined_typename(&a.type_) + ); + } + + let func_rets = &func_decl_entry.entity.rets; + let rets = if func_rets.len() == 0 { + "()".to_owned() + } else { + assert_eq!(func_rets.len(), 1); + self.get_defined_typename(&func_rets[0].type_).to_owned() + }; + + self.w + .writeln("#[no_mangle]")? + .writeln(format!("pub fn {}({}) -> {} {{", name, args, rets))?; + + let mut w = self.w.new_block(); + w.writeln("unimplemented!()")?; + + self.w.writeln("}")?.eob()?; + Ok(()) } } diff --git a/lucet-idl/tests/example.idl b/lucet-idl/tests/example.idl index 161abab38..0b9256ce0 100644 --- a/lucet-idl/tests/example.idl +++ b/lucet-idl/tests/example.idl @@ -27,5 +27,5 @@ mod example { fn set_color(to: color) -> bool; - fn get_structure(for: color) -> st; + fn get_structure(of: color) -> st; } diff --git a/lucet-idl/tests/example.rs b/lucet-idl/tests/example.rs index a5de8dbe9..d0bfea0c9 100644 --- a/lucet-idl/tests/example.rs +++ b/lucet-idl/tests/example.rs @@ -23,7 +23,7 @@ fn compile_and_run_c() { lucet_idl::run( &config, &source, - File::create(tempdir.path().join("example.h")).expect("create file"), + Box::new(File::create(tempdir.path().join("example.h")).expect("create file")), ) .expect("run lucet_idl"); @@ -65,7 +65,7 @@ fn compile_and_run_rust() { lucet_idl::run( &config, &source, - File::create(gen_file.clone()).expect("create file"), + Box::new(File::create(gen_file.clone()).expect("create file")), ) .expect("run lucet_idl"); From 2b3454686ddaaf447d223ef216480e77ba7e2809 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 9 May 2019 12:42:29 -0700 Subject: [PATCH 199/512] dockerfile: switch to install rust via rustup we need this to install --target wasm32-wasi via nightly. --- Dockerfile | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index ca3a75762..40d96c0b2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,12 +27,14 @@ RUN update-alternatives --install /usr/bin/clang clang /usr/bin/clang-6.0 100 # rebuilds. ENV LD_LIBRARY_PATH=/usr/local/lib -RUN curl -sS -L -O https://static.rust-lang.org/dist/rust-1.35.0-x86_64-unknown-linux-gnu.tar.gz \ - && tar xzf rust-1.35.0-x86_64-unknown-linux-gnu.tar.gz \ - && cd rust-1.35.0-x86_64-unknown-linux-gnu \ - && ./install.sh \ - && cd .. \ - && rm -rf rust-1.35.0-x86_64-unknown-linux-gnu rust-1.35.0-x86_64-unknown-linux-gnu.tar.gz +RUN curl https://sh.rustup.rs -sSf | \ + sh -s -- --default-toolchain 1.35.0 -y && \ + /root/.cargo/bin/rustup update nightly +ENV PATH=/root/.cargo/bin:$PATH + +RUN rustup target add wasm32-unknown-wasi \ + --toolchain nightly + ENV PATH=/usr/local/bin:$PATH RUN cargo install --root /usr/local cargo-audit cargo-watch rsign2 From ad8b9bba3526e03dcf87d8f1a14fd1bd7143d450 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 9 May 2019 12:43:18 -0700 Subject: [PATCH 200/512] lucet-idl-test: initial commit --- Cargo.lock | 10 ++++++++++ Cargo.toml | 1 + lucet-idl/lucet-idl-test/Cargo.toml | 11 +++++++++++ lucet-idl/lucet-idl-test/src/main.rs | 3 +++ 4 files changed, 25 insertions(+) create mode 100644 lucet-idl/lucet-idl-test/Cargo.toml create mode 100644 lucet-idl/lucet-idl-test/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 03ab5f8b2..61510c6fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -768,6 +768,16 @@ dependencies = [ "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lucet-idl-test" +version = "0.1.0" +dependencies = [ + "lucet-idl 0.1.0", + "lucet-runtime 0.1.0", + "lucet-wasi-sdk 0.1.0", + "lucetc 0.1.0", +] + [[package]] name = "lucet-module-data" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 775e33972..19f5085c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "lucet-analyze", "lucet-idl", + "lucet-idl/lucet-idl-test", "lucet-module-data", "lucet-runtime", "lucet-runtime/lucet-runtime-internals", diff --git a/lucet-idl/lucet-idl-test/Cargo.toml b/lucet-idl/lucet-idl-test/Cargo.toml new file mode 100644 index 000000000..6248a94e4 --- /dev/null +++ b/lucet-idl/lucet-idl-test/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "lucet-idl-test" +version = "0.1.0" +authors = ["Pat Hickey "] +edition = "2018" + +[dependencies] +lucet-idl = { path = "../" } +lucet-wasi-sdk = { path = "../../lucet-wasi-sdk" } +lucetc = { path = "../../lucetc" } +lucet-runtime = { path = "../../lucet-runtime" } diff --git a/lucet-idl/lucet-idl-test/src/main.rs b/lucet-idl/lucet-idl-test/src/main.rs new file mode 100644 index 000000000..e7a11a969 --- /dev/null +++ b/lucet-idl/lucet-idl-test/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} From a7baa0036e696d87ec14db572b6086c95bcf68d1 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 9 May 2019 13:12:46 -0700 Subject: [PATCH 201/512] lucet-idl: delete BackendConfig which is no longer meaningful --- lucet-idl/src/backend.rs | 5 ----- lucet-idl/src/c/mod.rs | 7 ++----- lucet-idl/src/c/prelude.rs | 19 +------------------ lucet-idl/src/config.rs | 16 ++++------------ lucet-idl/src/lib.rs | 25 ++++++++++++++++++------- lucet-idl/src/rust/mod.rs | 5 +---- 6 files changed, 26 insertions(+), 51 deletions(-) diff --git a/lucet-idl/src/backend.rs b/lucet-idl/src/backend.rs index e5b6fe214..5af0d5208 100644 --- a/lucet-idl/src/backend.rs +++ b/lucet-idl/src/backend.rs @@ -19,8 +19,3 @@ impl> From for Backend { } } } - -#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)] -pub struct BackendConfig { - pub zero_native_pointers: bool, -} diff --git a/lucet-idl/src/c/mod.rs b/lucet-idl/src/c/mod.rs index eb7ad88ae..56906baa4 100644 --- a/lucet-idl/src/c/mod.rs +++ b/lucet-idl/src/c/mod.rs @@ -10,8 +10,7 @@ mod prelude; mod r#struct; use self::cache::{Cache, CachedStructMemberEntry, CachedTypeEntry}; -pub(crate) use self::catom::*; -use crate::backend::*; +pub(crate) use self::catom::CAtom; use crate::error::IDLError; use crate::generator::Generator; use crate::module::Module; @@ -35,7 +34,6 @@ struct CTypeInfo<'t> { /// Generator for the C backend pub struct CGenerator { pub target: Target, - pub backend_config: BackendConfig, pub cache: Cache, pub w: PrettyWriter, } @@ -93,10 +91,9 @@ impl Generator for CGenerator { } impl CGenerator { - pub fn new(target: Target, backend_config: BackendConfig, w: Box) -> Self { + pub fn new(target: Target, w: Box) -> Self { Self { target, - backend_config, cache: Cache::default(), w: PrettyWriter::new(w), } diff --git a/lucet-idl/src/c/prelude.rs b/lucet-idl/src/c/prelude.rs index 96f561905..b1bcd3306 100644 --- a/lucet-idl/src/c/prelude.rs +++ b/lucet-idl/src/c/prelude.rs @@ -1,10 +1,6 @@ use super::*; -pub fn generate( - pretty_writer: &mut PrettyWriter, - target: Target, - backend_config: BackendConfig, -) -> Result<(), IDLError> { +pub fn generate(pretty_writer: &mut PrettyWriter, target: Target) -> Result<(), IDLError> { let prelude = r" #include #include @@ -18,19 +14,6 @@ pub fn generate( } pretty_writer.eob()?; - if backend_config.zero_native_pointers { - pretty_writer.write_line( - r"#define ZERO_NATIVE_POINTERS // Avoid serializing native pointers".as_ref(), - )?; - } else if !(target.is_reference_alignment_compatible() - && target.uses_reference_target_endianness()) - { - pretty_writer.write_line( - r"// #define ZERO_NATIVE_POINTERS // Define to avoid serializing native pointers" - .as_ref(), - )?; - } - let prelude = r" #ifndef ___REFERENCE_COMPATIBLE_ALIGNMENT # if defined(__amd64) || defined(__amd64__) || defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) || \ diff --git a/lucet-idl/src/config.rs b/lucet-idl/src/config.rs index b200effb4..556a00762 100644 --- a/lucet-idl/src/config.rs +++ b/lucet-idl/src/config.rs @@ -1,4 +1,4 @@ -use super::backend::{Backend, BackendConfig}; +use super::backend::Backend; use super::target::Target; use crate::c::CGenerator; use crate::generator::Generator; @@ -9,7 +9,6 @@ use std::io::Write; pub struct Config { pub target: Target, pub backend: Backend, - pub backend_config: BackendConfig, } impl Config { @@ -19,20 +18,13 @@ impl Config { if zero_native_pointers { target = Target::Generic; } - let backend_config = BackendConfig { - zero_native_pointers, - }; - Self { - target, - backend, - backend_config, - } + Self { target, backend } } pub fn generator(&self, w: Box) -> Box { match self.backend { - Backend::C => Box::new(CGenerator::new(self.target, self.backend_config, w)), - Backend::Rust => Box::new(RustGenerator::new(self.target, self.backend_config, w)), + Backend::C => Box::new(CGenerator::new(self.target, w)), + Backend::Rust => Box::new(RustGenerator::new(self.target, w)), } } } diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index c87a367a8..5a03fe993 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -17,30 +17,41 @@ mod rust; mod target; mod types; -pub use crate::backend::{Backend, BackendConfig}; +pub use crate::backend::Backend; pub use crate::config::Config; pub use crate::error::IDLError; +pub use crate::module::Module; +pub use crate::package::Package; pub use crate::target::Target; +pub use crate::types::{ + Attr, DataType, DataTypeRef, FuncDecl, FuncRet, Ident, Location, Name, Named, NamedMember, +}; -use crate::package::Package; use crate::parser::Parser; use std::io::Write; -pub fn run(config: &Config, input: &str, output: Box) -> Result<(), IDLError> { +pub fn parse_package(input: &str) -> Result { let mut parser = Parser::new(&input); let decls = parser.match_decls()?; - let pkg = Package::from_declarations(&decls)?; + Ok(pkg) +} +pub fn codegen(package: &Package, config: &Config, output: Box) -> Result<(), IDLError> { let mut generator = config.generator(output); - for (_ident, mod_) in pkg.modules { + for (_ident, mod_) in package.modules.iter() { for dt in mod_.datatypes() { - generator.gen_datatype(&mod_, &dt)?; + generator.gen_datatype(mod_, &dt)?; } for fdecl in mod_.func_decls() { - generator.gen_function(&mod_, &fdecl)?; + generator.gen_function(mod_, &fdecl)?; } } Ok(()) } + +pub fn run(config: &Config, input: &str, output: Box) -> Result<(), IDLError> { + let pkg = parse_package(input)?; + codegen(&pkg, config, output) +} diff --git a/lucet-idl/src/rust/mod.rs b/lucet-idl/src/rust/mod.rs index b167bc6eb..1f6d18a2c 100644 --- a/lucet-idl/src/rust/mod.rs +++ b/lucet-idl/src/rust/mod.rs @@ -1,7 +1,6 @@ #![allow(dead_code)] #![allow(unused_variables)] -use crate::backend::BackendConfig; use crate::error::IDLError; use crate::generator::Generator; use crate::module::Module; @@ -28,16 +27,14 @@ struct CTypeInfo<'t> { /// Generator for the C backend pub struct RustGenerator { pub target: Target, - pub backend_config: BackendConfig, pub defined: HashMap, pub w: PrettyWriter, } impl RustGenerator { - pub fn new(target: Target, backend_config: BackendConfig, w: Box) -> Self { + pub fn new(target: Target, w: Box) -> Self { Self { target, - backend_config, defined: HashMap::new(), w: PrettyWriter::new(w), } From 6e586727f851b348c03014bd15bae334d5898112 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 9 May 2019 13:14:21 -0700 Subject: [PATCH 202/512] lucet-idl: fix rust backend --- lucet-idl/src/rust/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lucet-idl/src/rust/mod.rs b/lucet-idl/src/rust/mod.rs index 1f6d18a2c..981a342ac 100644 --- a/lucet-idl/src/rust/mod.rs +++ b/lucet-idl/src/rust/mod.rs @@ -61,7 +61,7 @@ impl RustGenerator { U16 => "u16", U32 => "u32", U64 => "u64", - I8 => "i32", + I8 => "i8", I16 => "i16", I32 => "i32", I64 => "i64", From 84f050b6702c8e478a056be5622527662dd6fd2f Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 9 May 2019 13:19:08 -0700 Subject: [PATCH 203/512] lucet-idl: input file isnt a named argument --- lucet-idl/src/main.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lucet-idl/src/main.rs b/lucet-idl/src/main.rs index 34ff25da3..dd43ff30c 100644 --- a/lucet-idl/src/main.rs +++ b/lucet-idl/src/main.rs @@ -18,10 +18,7 @@ impl ExeConfig { .version("1.0") .about("lucet_idl code generator") .arg( - Arg::with_name("input_file") - .short("i") - .long("input") - .takes_value(true) + Arg::with_name("input") .required(true) .help("Path to the input file"), ) @@ -54,7 +51,7 @@ impl ExeConfig { .get_matches(); let input_path = PathBuf::from( matches - .value_of("input_file") + .value_of("input") .ok_or(IDLError::UsageError("Input file required"))?, ); let config = Config::parse( From fd2f9fc48aa0eae70273ba9a49ddd16302f6915d Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 10 May 2019 16:55:27 -0700 Subject: [PATCH 204/512] lucet-idl-test: property-based testing of rust, c backends c has a bug rn, will fix on monday --- Cargo.lock | 59 ++++++ lucet-idl/lucet-idl-test/.gitignore | 1 + lucet-idl/lucet-idl-test/Cargo.toml | 9 + lucet-idl/lucet-idl-test/src/compile.rs | 71 ++++++++ lucet-idl/lucet-idl-test/src/lib.rs | 26 +++ lucet-idl/lucet-idl-test/src/main.rs | 17 +- lucet-idl/lucet-idl-test/src/syntax.rs | 227 ++++++++++++++++++++++++ lucet-idl/src/c/mod.rs | 4 +- lucet-idl/src/lib.rs | 3 +- 9 files changed, 414 insertions(+), 3 deletions(-) create mode 100644 lucet-idl/lucet-idl-test/.gitignore create mode 100644 lucet-idl/lucet-idl-test/src/compile.rs create mode 100644 lucet-idl/lucet-idl-test/src/lib.rs create mode 100644 lucet-idl/lucet-idl-test/src/syntax.rs diff --git a/Cargo.lock b/Cargo.lock index 61510c6fa..ed6352253 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -121,6 +121,19 @@ dependencies = [ "which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "bit-set" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bit-vec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bitflags" version = "0.7.0" @@ -564,6 +577,11 @@ dependencies = [ "miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fnv" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -776,6 +794,8 @@ dependencies = [ "lucet-runtime 0.1.0", "lucet-wasi-sdk 0.1.0", "lucetc 0.1.0", + "proptest 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1173,6 +1193,25 @@ dependencies = [ "terminal_size 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "proptest" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rusty-fork 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quick-error" version = "1.2.2" @@ -1412,6 +1451,17 @@ dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rusty-fork" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ryu" version = "0.2.8" @@ -1893,6 +1943,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "505e45beaf0a1462f5548fe885edf2d83e62022b2ce8b10fef0f7686b48c9266" "checksum bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f2fb9e29e72fd6bc12071533d5dc7664cb01480c59406f656d7ac25c7bd8ff7" "checksum bindgen 0.47.3 (registry+https://github.com/rust-lang/crates.io-index)" = "df683a55b54b41d5ea8ebfaebb5aa7e6b84e3f3006a78f010dadc9ca88469260" +"checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80" +"checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" @@ -1932,6 +1984,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum flate2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "246b6f24d8e616b0c176a8143486ddc8bb0bac2f30f0a0d3efbcf1e0d47cb7e5" +"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" @@ -1982,6 +2035,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum printtable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "69967dae4cac71681361899d9905d3d2985fc989d7afb32a8dff3aed5461ecdf" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b820305721858696053a7fd0215cfeeee16ecaaf96b7a209945428e02f1c44" +"checksum proptest 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2afed8cbdc8a64b58a5c021757a782351ec1afee85be374872721c84d5da5d80" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" @@ -2009,7 +2063,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rpassword 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34fa7bcae7fca3c8471e8417088bbc3ad9af8066b0ecf4f3c0d98a0d772716e" "checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +<<<<<<< 84f050b6702c8e478a056be5622527662dd6fd2f "checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f" +======= +"checksum rusty-fork 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd93264e10c577503e926bd1430193eeb5d21b059148910082245309b424fae" +"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" +>>>>>>> lucet-idl-test: property-based testing of rust, c backends "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f84d114ef17fd144153d608fba7c446b0145d038985e7a8cc5d08bb0ce20383" diff --git a/lucet-idl/lucet-idl-test/.gitignore b/lucet-idl/lucet-idl-test/.gitignore new file mode 100644 index 000000000..402fd5d87 --- /dev/null +++ b/lucet-idl/lucet-idl-test/.gitignore @@ -0,0 +1 @@ +proptest-regressions diff --git a/lucet-idl/lucet-idl-test/Cargo.toml b/lucet-idl/lucet-idl-test/Cargo.toml index 6248a94e4..aa4be074d 100644 --- a/lucet-idl/lucet-idl-test/Cargo.toml +++ b/lucet-idl/lucet-idl-test/Cargo.toml @@ -4,8 +4,17 @@ version = "0.1.0" authors = ["Pat Hickey "] edition = "2018" +[lib] +crate-type=["rlib"] + +[[bin]] +name = "lucet-idl-test" +path = "src/main.rs" + [dependencies] lucet-idl = { path = "../" } lucet-wasi-sdk = { path = "../../lucet-wasi-sdk" } lucetc = { path = "../../lucetc" } lucet-runtime = { path = "../../lucet-runtime" } +proptest = "0.9.3" +tempfile = "3.0" diff --git a/lucet-idl/lucet-idl-test/src/compile.rs b/lucet-idl/lucet-idl-test/src/compile.rs new file mode 100644 index 000000000..378b6f15f --- /dev/null +++ b/lucet-idl/lucet-idl-test/src/compile.rs @@ -0,0 +1,71 @@ +use lucet_idl::{codegen, Backend, Config, Package, Target}; +use std::fs::File; +use std::process::Command; +use tempfile::TempDir; + +pub fn rust_codegen(package: &Package) { + let config = Config { + backend: Backend::Rust, + target: Target::Generic, + }; + + let tempdir = TempDir::new().expect("create tempdir"); + + let gen_file = tempdir.path().join("out.rs"); + + codegen( + package, + &config, + Box::new(File::create(gen_file.clone()).expect("create file")), + ) + .expect("lucet_idl codegen"); + + let cmd_rustc = Command::new("rustc") + .arg(gen_file.clone()) + .arg("--test") + .arg("--allow=dead_code") + .arg("-o") + .arg(tempdir.path().join("example")) + .status() + .expect("run rustcc"); + assert!(cmd_rustc.success(), "failure to compile generated code"); + /* + let cmd_run = Command::new(tempdir.path().join("example")) + .status() + .expect("run generated code"); + assert!(cmd_run.success(), "failure to run generated code"); + */ +} + +pub fn c_codegen(package: &Package) { + let config = lucet_idl::Config { + backend: lucet_idl::Backend::C, + target: lucet_idl::Target::Generic, + }; + + let tempdir = TempDir::new().expect("create tempdir"); + + codegen( + package, + &config, + Box::new(File::create(tempdir.path().join("example.c")).expect("create file")), + ) + .expect("lucet_idl codegen"); + + let cmd_cc = Command::new("cc") + .arg("--std=c99") + .arg("-c") + .arg(tempdir.path().join("example.c")) + .arg("-o") + .arg(tempdir.path().join("example.o")) + .status() + .expect("run cc"); + assert!(cmd_cc.success(), "failure to compile generated code"); + + /* + let cmd_run = Command::new(tempdir.path().join("example")) + .status() + .expect("run generated code"); + assert!(cmd_run.success(), "failure to run generated code"); + */ +} diff --git a/lucet-idl/lucet-idl-test/src/lib.rs b/lucet-idl/lucet-idl-test/src/lib.rs new file mode 100644 index 000000000..3f065c72d --- /dev/null +++ b/lucet-idl/lucet-idl-test/src/lib.rs @@ -0,0 +1,26 @@ +pub mod compile; +pub mod syntax; + +#[cfg(test)] +mod tests { + use crate::compile; + use crate::syntax::Spec; + use lucet_idl::parse_package; + use proptest::prelude::*; + + proptest! { + #[test] + fn generate_and_rust(spec in Spec::strat(20)) { + let rendered = spec.render_idl(); + let pkg = parse_package(&rendered).unwrap(); + compile::rust_codegen(&pkg); + } + + //#[test] + fn generate_and_c(spec in Spec::strat(20)) { + let rendered = spec.render_idl(); + let pkg = parse_package(&rendered).unwrap(); + compile::c_codegen(&pkg); + } + } +} diff --git a/lucet-idl/lucet-idl-test/src/main.rs b/lucet-idl/lucet-idl-test/src/main.rs index e7a11a969..332d72dae 100644 --- a/lucet-idl/lucet-idl-test/src/main.rs +++ b/lucet-idl/lucet-idl-test/src/main.rs @@ -1,3 +1,18 @@ +use lucet_idl::parse_package; +use lucet_idl_test::syntax::{DatatypeSyntax, Spec}; +use proptest::prelude::*; +use proptest::strategy::ValueTree; +use proptest::test_runner::TestRunner; + fn main() { - println!("Hello, world!"); + let mut runner = TestRunner::default(); + let dts = prop::collection::vec(DatatypeSyntax::strat(), 0..20) + .new_tree(&mut runner) + .unwrap() + .current(); + let spec = Spec::from_decls(dts); + let rendered = spec.render_idl(); + println!("{}", rendered); + + let _pkg = parse_package(&rendered).expect("parse generated package"); } diff --git a/lucet-idl/lucet-idl-test/src/syntax.rs b/lucet-idl/lucet-idl-test/src/syntax.rs new file mode 100644 index 000000000..c20ab2dc3 --- /dev/null +++ b/lucet-idl/lucet-idl-test/src/syntax.rs @@ -0,0 +1,227 @@ +use lucet_idl::AtomType; +use proptest::prelude::*; + +pub trait AtomTypeExt +where + Self: Sized, +{ + fn strat() -> BoxedStrategy; + fn render_idl(&self) -> String; +} + +impl AtomTypeExt for AtomType { + fn strat() -> BoxedStrategy { + prop_oneof![ + Just(AtomType::Bool), + Just(AtomType::U8), + Just(AtomType::U16), + Just(AtomType::U32), + Just(AtomType::U64), + Just(AtomType::I8), + Just(AtomType::I16), + Just(AtomType::I32), + Just(AtomType::I64), + Just(AtomType::F32), + Just(AtomType::F64), + ] + .boxed() + } + fn render_idl(&self) -> String { + use AtomType::*; + match self { + Bool => "bool", + U8 => "u8", + U16 => "u16", + U32 => "u32", + U64 => "u64", + I8 => "i8", + I16 => "i16", + I32 => "i32", + I64 => "i64", + F32 => "f32", + F64 => "f64", + } + .to_owned() + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct DatatypeRef(usize); + +impl DatatypeRef { + pub fn strat() -> impl Strategy { + any::().prop_map(DatatypeRef) + } + + pub fn normalize(&self, highest_definition: usize) -> Self { + assert!(highest_definition != 0); + DatatypeRef(self.0 % highest_definition) + } + + pub fn render_idl(&self) -> String { + format!("dt_{}", self.0) + } +} + +#[derive(Debug, Clone)] +pub enum DatatypeName { + Atom(AtomType), + Defined(DatatypeRef), +} + +impl DatatypeName { + pub fn normalize(&self, highest_definition: usize) -> Self { + match self { + DatatypeName::Defined(def) => { + if highest_definition == 0 { + DatatypeName::Atom(AtomType::I64) + } else { + DatatypeName::Defined(def.normalize(highest_definition)) + } + } + DatatypeName::Atom(a) => DatatypeName::Atom(a.clone()), + } + } + + pub fn strat() -> impl Strategy { + prop_oneof![ + DatatypeRef::strat().prop_map(DatatypeName::Defined), + AtomType::strat().prop_map(DatatypeName::Atom) + ] + } + + pub fn render_idl(&self) -> String { + match self { + DatatypeName::Atom(a) => a.render_idl(), + DatatypeName::Defined(d) => d.render_idl(), + } + } +} + +#[derive(Debug, Clone)] +pub struct EnumSyntax { + pub variants: usize, +} + +impl EnumSyntax { + pub fn strat() -> impl Strategy { + (1..20usize).prop_map(|variants| EnumSyntax { variants }) + } + + pub fn render_idl(&self, name: usize) -> String { + let mut s = String::new(); + for v in 0..self.variants { + s += &format!("v_{}, ", v); + } + format!("enum dt_{} {{ {} }} ", name, s) + } +} + +#[derive(Debug, Clone)] +pub struct StructSyntax { + pub members: Vec, +} + +impl StructSyntax { + pub fn strat() -> impl Strategy { + prop::collection::vec(DatatypeName::strat(), 1..10) + .prop_map(|members| StructSyntax { members }) + } + + pub fn normalize(&self, highest_definition: usize) -> Self { + let members = self + .members + .iter() + .map(|m| m.normalize(highest_definition)) + .collect(); + Self { members } + } + + pub fn render_idl(&self, name: usize) -> String { + let mut s = String::new(); + for (ix, m) in self.members.iter().enumerate() { + s += &format!("m_{}: {}, ", ix, m.render_idl()); + } + format!("struct dt_{} {{ {} }} ", name, s) + } +} + +#[derive(Debug, Clone)] +pub struct AliasSyntax { + pub target: DatatypeName, +} + +impl AliasSyntax { + pub fn strat() -> impl Strategy { + DatatypeName::strat().prop_map(|target| AliasSyntax { target }) + } + pub fn normalize(&self, highest_definition: usize) -> Self { + Self { + target: self.target.normalize(highest_definition), + } + } + pub fn render_idl(&self, name: usize) -> String { + format!("type dt_{} = {};", name, self.target.render_idl()) + } +} + +#[derive(Debug, Clone)] +pub enum DatatypeSyntax { + Enum(EnumSyntax), + Struct(StructSyntax), + Alias(AliasSyntax), +} + +impl DatatypeSyntax { + pub fn strat() -> impl Strategy { + prop_oneof![ + EnumSyntax::strat().prop_map(DatatypeSyntax::Enum), + StructSyntax::strat().prop_map(DatatypeSyntax::Struct), + AliasSyntax::strat().prop_map(DatatypeSyntax::Alias), + ] + } + + pub fn normalize(&self, highest_definition: usize) -> Self { + match self { + DatatypeSyntax::Enum(e) => DatatypeSyntax::Enum(e.clone()), + DatatypeSyntax::Struct(s) => DatatypeSyntax::Struct(s.normalize(highest_definition)), + DatatypeSyntax::Alias(a) => DatatypeSyntax::Alias(a.normalize(highest_definition)), + } + } + + pub fn render_idl(&self, name: usize) -> String { + match self { + DatatypeSyntax::Enum(e) => e.render_idl(name), + DatatypeSyntax::Struct(s) => s.render_idl(name), + DatatypeSyntax::Alias(a) => a.render_idl(name), + } + } +} + +#[derive(Debug, Clone)] +pub struct Spec { + pub decls: Vec, +} + +impl Spec { + pub fn strat(max_size: usize) -> impl Strategy { + prop::collection::vec(DatatypeSyntax::strat(), 1..max_size).prop_map(Self::from_decls) + } + + pub fn from_decls(decls: Vec) -> Self { + let decls = decls + .iter() + .enumerate() + .map(|(ix, decl)| decl.normalize(ix)) + .collect(); + Spec { decls } + } + + pub fn render_idl(&self) -> String { + let mut s = String::new(); + for (ix, d) in self.decls.iter().enumerate() { + s += &format!(" {}\n", d.render_idl(ix)); + } + format!("mod spec {{\n{}\n}}", s) + } +} diff --git a/lucet-idl/src/c/mod.rs b/lucet-idl/src/c/mod.rs index 56906baa4..73bf632a2 100644 --- a/lucet-idl/src/c/mod.rs +++ b/lucet-idl/src/c/mod.rs @@ -92,10 +92,12 @@ impl Generator for CGenerator { impl CGenerator { pub fn new(target: Target, w: Box) -> Self { + let mut w = PrettyWriter::new(w); + prelude::generate(&mut w, target.clone()).expect("write prelude"); Self { target, cache: Cache::default(), - w: PrettyWriter::new(w), + w, } } /// Traverse a `DataTypeRef` chain, and return information diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 5a03fe993..a9f2cf9a0 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -24,7 +24,8 @@ pub use crate::module::Module; pub use crate::package::Package; pub use crate::target::Target; pub use crate::types::{ - Attr, DataType, DataTypeRef, FuncDecl, FuncRet, Ident, Location, Name, Named, NamedMember, + AtomType, Attr, DataType, DataTypeRef, FuncDecl, FuncRet, Ident, Location, Name, Named, + NamedMember, }; use crate::parser::Parser; From 766ccab64fe7695c68ec7c45ab4fc3837e4aac5a Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 13 May 2019 11:16:19 -0700 Subject: [PATCH 205/512] lucet-idl: debug compilation failures --- lucet-idl/lucet-idl-test/src/compile.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lucet-idl/lucet-idl-test/src/compile.rs b/lucet-idl/lucet-idl-test/src/compile.rs index 378b6f15f..ebadafc40 100644 --- a/lucet-idl/lucet-idl-test/src/compile.rs +++ b/lucet-idl/lucet-idl-test/src/compile.rs @@ -27,8 +27,16 @@ pub fn rust_codegen(package: &Package) { .arg("-o") .arg(tempdir.path().join("example")) .status() - .expect("run rustcc"); + .expect("run rustc"); + + if !cmd_rustc.success() { + Command::new("cat") + .arg(gen_file.clone()) + .status() + .expect("debug output"); + } assert!(cmd_rustc.success(), "failure to compile generated code"); + /* let cmd_run = Command::new(tempdir.path().join("example")) .status() @@ -60,6 +68,13 @@ pub fn c_codegen(package: &Package) { .arg(tempdir.path().join("example.o")) .status() .expect("run cc"); + + if !cmd_cc.success() { + Command::new("cat") + .arg(tempdir.path().join("example.c")) + .status() + .expect("debug output"); + } assert!(cmd_cc.success(), "failure to compile generated code"); /* From 37dc6c0201c23964e651bd32db00a9b105d23fea Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 13 May 2019 15:50:31 -0700 Subject: [PATCH 206/512] lucet-idl: refactor datatype repr --- lucet-idl/src/c/alias.rs | 8 ++--- lucet-idl/src/c/enum.rs | 15 ++------ lucet-idl/src/c/mod.rs | 38 +++++++++++--------- lucet-idl/src/c/struct.rs | 14 ++------ lucet-idl/src/generator.rs | 15 +++++--- lucet-idl/src/lib.rs | 1 - lucet-idl/src/module.rs | 71 ++++++++++++++++++++------------------ lucet-idl/src/package.rs | 9 ++--- lucet-idl/src/rust/mod.rs | 40 +++++---------------- lucet-idl/src/types.rs | 57 +++++++++++++++++++++--------- lucet-idl/tests/example.rs | 2 -- 11 files changed, 132 insertions(+), 138 deletions(-) diff --git a/lucet-idl/src/c/alias.rs b/lucet-idl/src/c/alias.rs index 388ad7b93..eea008bc5 100644 --- a/lucet-idl/src/c/alias.rs +++ b/lucet-idl/src/c/alias.rs @@ -6,13 +6,9 @@ pub fn generate( gen: &mut CGenerator, module: &Module, data_type_entry: &Named, + alias: &AliasDataType, ) -> Result<(), IDLError> { - let (type_, _attrs) = if let DataType::Alias { to: type_, attrs } = &data_type_entry.entity { - (type_, attrs) - } else { - unreachable!() - }; - let type_info = gen.type_info(module, type_); + let type_info = gen.type_info(module, &alias.to); gen.w.indent()?; gen.w .write(format!("typedef {}", type_info.type_name).as_bytes())?; diff --git a/lucet-idl/src/c/enum.rs b/lucet-idl/src/c/enum.rs index 488648b81..18b7c3750 100644 --- a/lucet-idl/src/c/enum.rs +++ b/lucet-idl/src/c/enum.rs @@ -6,17 +6,8 @@ pub fn generate( gen: &mut CGenerator, _module: &Module, data_type_entry: &Named, + enum_: &EnumDataType, ) -> Result<(), IDLError> { - let (named_members, _attrs) = if let DataType::Enum { - members: named_members, - attrs, - } = &data_type_entry.entity - { - (named_members, attrs) - } else { - unreachable!() - }; - let enum_native_type = CAtom::enum_(); let (type_align, type_size, type_name) = ( enum_native_type.native_type_align, @@ -29,14 +20,14 @@ pub fn generate( "typedef {} {}; // enum, should be in the [0...{}] range", type_name, data_type_entry.name.name, - named_members.len() - 1 + enum_.members.len() - 1 ) .as_bytes(), )?; gen.w .write_line(format!("enum ___{} {{", data_type_entry.name.name).as_bytes())?; let mut pretty_writer_i1 = gen.w.new_block(); - for (i, named_member) in named_members.iter().enumerate() { + for (i, named_member) in enum_.members.iter().enumerate() { pretty_writer_i1.write_line( format!( "{}, // {}", diff --git a/lucet-idl/src/c/mod.rs b/lucet-idl/src/c/mod.rs index 73bf632a2..17b92e90d 100644 --- a/lucet-idl/src/c/mod.rs +++ b/lucet-idl/src/c/mod.rs @@ -16,7 +16,10 @@ use crate::generator::Generator; use crate::module::Module; use crate::pretty_writer::PrettyWriter; use crate::target::Target; -use crate::types::{DataType, DataTypeRef, FuncDecl, Named}; +use crate::types::{ + AliasDataType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, FuncDecl, Named, + StructDataType, +}; use std::io::prelude::*; #[derive(Clone, Debug)] @@ -59,16 +62,18 @@ impl Generator for CGenerator { &mut self, module: &Module, data_type_entry: &Named, + alias: &AliasDataType, ) -> Result<(), IDLError> { - alias::generate(self, module, data_type_entry) + alias::generate(self, module, data_type_entry, alias) } fn gen_struct( &mut self, module: &Module, data_type_entry: &Named, + struct_: &StructDataType, ) -> Result<(), IDLError> { - r#struct::generate(self, module, data_type_entry) + r#struct::generate(self, module, data_type_entry, struct_) } // Enums generate both a specific typedef, and a traditional C-style enum @@ -77,8 +82,9 @@ impl Generator for CGenerator { &mut self, module: &Module, data_type_entry: &Named, + enum_: &EnumDataType, ) -> Result<(), IDLError> { - r#enum::generate(self, module, data_type_entry) + r#enum::generate(self, module, data_type_entry, enum_) } fn gen_function( @@ -122,12 +128,12 @@ impl CGenerator { let data_type_entry = module .get_datatype(*data_type_id) .expect("defined datatype"); - match data_type_entry.entity { - DataType::Struct { .. } => { + match data_type_entry.entity.variant { + DataTypeVariant::Struct { .. } => { type_name = type_name .or_else(|| Some(format!("struct {}", data_type_entry.name.name))) } - DataType::Enum { .. } => { + DataTypeVariant::Enum { .. } => { type_name = type_name.or_else(|| { Some(format!( "{} /* (enum ___{}) */", @@ -135,10 +141,10 @@ impl CGenerator { )) }) } - DataType::Alias { to, .. } => { + DataTypeVariant::Alias(ref a) => { type_name = type_name.or_else(|| Some(data_type_entry.name.name.to_string())); - type_ = &to; + type_ = &a.to; continue; } }; @@ -161,11 +167,10 @@ impl CGenerator { DataTypeRef::Defined(inner_type) => inner_type, }; let inner_data_type_entry = module.get_datatype(*inner_type).expect("defined datatype"); - let inner_data_type = inner_data_type_entry.entity; - match inner_data_type { - DataType::Struct { .. } => false, - DataType::Enum { .. } => true, - DataType::Alias { to, .. } => self.is_type_eventually_an_atom_or_enum(module, to), + match inner_data_type_entry.entity.variant { + DataTypeVariant::Struct { .. } => false, + DataTypeVariant::Enum { .. } => true, + DataTypeVariant::Alias(ref a) => self.is_type_eventually_an_atom_or_enum(module, &a.to), } } @@ -176,9 +181,8 @@ impl CGenerator { DataTypeRef::Defined(inner_type) => inner_type, }; let inner_data_type_entry = module.get_datatype(*inner_type).expect("defined datatype"); - let inner_data_type = inner_data_type_entry.entity; - if let DataType::Alias { to, .. } = inner_data_type { - self.unalias(module, to) + if let DataTypeVariant::Alias(ref a) = inner_data_type_entry.entity.variant { + self.unalias(module, &a.to) } else { type_ } diff --git a/lucet-idl/src/c/struct.rs b/lucet-idl/src/c/struct.rs index 2f6156087..be7da9eb7 100644 --- a/lucet-idl/src/c/struct.rs +++ b/lucet-idl/src/c/struct.rs @@ -5,23 +5,15 @@ pub fn generate( gen: &mut CGenerator, module: &Module, data_type_entry: &Named, + struct_: &StructDataType, ) -> Result<(), IDLError> { - let (named_members, _attrs) = if let DataType::Struct { - members: named_members, - attrs, - } = &data_type_entry.entity - { - (named_members, attrs) - } else { - unreachable!() - }; gen.w .write_line(format!("struct {} {{", data_type_entry.name.name).as_bytes())?; let mut w_block = gen.w.new_block(); let mut offset: usize = 0; let mut first_member_align = 0; let mut members_offsets = vec![]; - for named_member in named_members { + for named_member in struct_.members.iter() { let type_info = gen.type_info(module, &named_member.type_); let type_align = type_info.type_align; let type_size = type_info.type_size; @@ -70,7 +62,7 @@ pub fn generate( // Add assertions to check that the target platform matches the expected alignment // Also add a macro definition for the structure size // Skip the first member, as it will always be at the beginning of the structure - for (i, named_member) in named_members.iter().enumerate().skip(1) { + for (i, named_member) in struct_.members.iter().enumerate().skip(1) { gen.w.write_line( format!( "_Static_assert(offsetof(struct {}, {}) == {}, \"unexpected offset\");", diff --git a/lucet-idl/src/generator.rs b/lucet-idl/src/generator.rs index 335f42301..bd67532b2 100644 --- a/lucet-idl/src/generator.rs +++ b/lucet-idl/src/generator.rs @@ -1,6 +1,8 @@ use crate::error::IDLError; use crate::module::Module; -use crate::types::{DataType, FuncDecl, Named}; +use crate::types::{ + AliasDataType, DataType, DataTypeVariant, EnumDataType, FuncDecl, Named, StructDataType, +}; pub trait Generator { fn gen_type_header( @@ -13,18 +15,21 @@ pub trait Generator { &mut self, module: &Module, data_type_entry: &Named, + alias_: &AliasDataType, ) -> Result<(), IDLError>; fn gen_struct( &mut self, module: &Module, data_type_entry: &Named, + struct_: &StructDataType, ) -> Result<(), IDLError>; fn gen_enum( &mut self, module: &Module, data_type_entry: &Named, + enum_: &EnumDataType, ) -> Result<(), IDLError>; fn gen_function( @@ -35,10 +40,10 @@ pub trait Generator { fn gen_datatype(&mut self, module: &Module, dt: &Named) -> Result<(), IDLError> { self.gen_type_header(module, dt)?; - match &dt.entity { - DataType::Struct { .. } => self.gen_struct(module, dt)?, - DataType::Alias { .. } => self.gen_alias(module, dt)?, - DataType::Enum { .. } => self.gen_enum(module, dt)?, + match &dt.entity.variant { + DataTypeVariant::Struct(s) => self.gen_struct(module, dt, s)?, + DataTypeVariant::Alias(a) => self.gen_alias(module, dt, a)?, + DataTypeVariant::Enum(e) => self.gen_enum(module, dt, e)?, } Ok(()) } diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index a9f2cf9a0..fa50ef875 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -25,7 +25,6 @@ pub use crate::package::Package; pub use crate::target::Target; pub use crate::types::{ AtomType, Attr, DataType, DataTypeRef, FuncDecl, FuncRet, Ident, Location, Name, Named, - NamedMember, }; use crate::parser::Parser; diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index 8f6ca3bbf..b710d8c7e 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -1,7 +1,8 @@ use crate::error::ValidationError; use crate::parser::{SyntaxDecl, SyntaxRef}; use crate::types::{ - Attr, DataType, DataTypeRef, FuncDecl, FuncRet, Ident, Location, Name, Named, NamedMember, + AliasDataType, Attr, DataType, DataTypeRef, DataTypeVariant, EnumDataType, EnumMember, FuncArg, + FuncDecl, FuncRet, Ident, Location, Name, Named, StructDataType, StructMember, }; use std::collections::HashMap; #[derive(Debug, PartialEq, Eq, Clone)] @@ -69,8 +70,8 @@ impl Module { } } - fn define_data_type(&mut self, id: Ident, dt: DataType) { - if let Some(prev_def) = self.data_types.insert(id, dt) { + fn define_data_type(&mut self, id: Ident, variant: DataTypeVariant, attrs: Vec) { + if let Some(prev_def) = self.data_types.insert(id, DataType { variant, attrs }) { panic!("id {} already defined: {:?}", id, prev_def) } } @@ -110,7 +111,7 @@ impl Module { // defined types: let type_ = self.get_ref(&mem.type_)?; // build the struct with this as the member: - dtype_members.push(NamedMember { + dtype_members.push(StructMember { type_, name: mem.name.clone(), attrs: mem.attrs.clone(), @@ -118,10 +119,10 @@ impl Module { } self.define_data_type( id, - DataType::Struct { + DataTypeVariant::Struct(StructDataType { members: dtype_members, - attrs: attrs.clone(), - }, + }), + attrs.clone(), ) } SyntaxDecl::Enum { @@ -148,28 +149,25 @@ impl Module { })? } // build the struct with this as the member: - dtype_members.push(NamedMember { - type_: (), + dtype_members.push(EnumMember { name: var.name.clone(), attrs: var.attrs.clone(), }) } self.define_data_type( id, - DataType::Enum { + DataTypeVariant::Enum(EnumDataType { members: dtype_members, - attrs: attrs.clone(), - }, + }), + attrs.clone(), ) } SyntaxDecl::Alias { what, attrs, .. } => { let to = self.get_ref(what)?; self.define_data_type( id, - DataType::Alias { - to, - attrs: attrs.clone(), - }, + DataTypeVariant::Alias(AliasDataType { to }), + attrs.clone(), ); } SyntaxDecl::Function { @@ -193,13 +191,13 @@ impl Module { } else { arg_names.insert(arg_syntax.name.clone(), arg_syntax.location.clone()); } - Ok(NamedMember { + Ok(FuncArg { name: arg_syntax.name.clone(), type_, attrs: arg_syntax.attrs.clone(), }) }) - .collect::>, _>>()?; + .collect::, _>>()?; let rets = rets .iter() @@ -241,20 +239,25 @@ impl Module { Err(())? } visited[id.0] = true; - match self.data_types.get(&id).expect("data_type is defined") { - DataType::Struct { members, .. } => { - for mem in members { + match self + .data_types + .get(&id) + .expect("data_type is defined") + .variant + { + DataTypeVariant::Struct(ref s) => { + for mem in s.members.iter() { if let DataTypeRef::Defined(id) = mem.type_ { self.dfs_walk(id, visited, ordered)? } } } - DataType::Alias { to, .. } => { - if let DataTypeRef::Defined(id) = to { - self.dfs_walk(*id, visited, ordered)? + DataTypeVariant::Alias(ref a) => { + if let DataTypeRef::Defined(id) = a.to { + self.dfs_walk(id, visited, ordered)? } } - DataType::Enum { .. } => {} + DataTypeVariant::Enum(_) => {} } if let Some(ordered) = ordered.as_mut() { if !ordered.contains(&id) { @@ -382,8 +385,8 @@ mod tests { fn struct_two_atoms() { { let d = mod_("struct foo { a: i32, b: f32 }").unwrap(); - let members = match &d.data_types[&Ident(0)] { - DataType::Struct { members, .. } => members, + let members = match &d.data_types[&Ident(0)].variant { + DataTypeVariant::Struct(s) => &s.members, _ => panic!("Unexpected type"), }; assert_eq!(members[0].name, "a"); @@ -476,8 +479,8 @@ mod tests { { let d = mod_("enum foo { a, b }").unwrap(); - let members = match &d.data_types[&Ident(0)] { - DataType::Enum { members, .. } => members, + let members = match &d.data_types[&Ident(0)].variant { + DataTypeVariant::Enum(e) => &e.members, _ => panic!("Unexpected type"), }; assert_eq!(members[0].name, "a"); @@ -592,7 +595,7 @@ mod tests { funcs: vec![( Ident(0), FuncDecl { - args: vec![NamedMember { + args: vec![FuncArg { type_: DataTypeRef::Atom(AtomType::U8), name: "a".to_owned(), attrs: Vec::new(), @@ -667,9 +670,11 @@ mod tests { .collect::>(), data_types: vec![( Ident(1), - DataType::Alias { - to: DataTypeRef::Atom(AtomType::U8), - attrs: Vec::new() + DataType { + variant: DataTypeVariant::Alias(AliasDataType { + to: DataTypeRef::Atom(AtomType::U8), + }), + attrs: Vec::new(), } )] .into_iter() diff --git a/lucet-idl/src/package.rs b/lucet-idl/src/package.rs index 67fb3f780..733a2593a 100644 --- a/lucet-idl/src/package.rs +++ b/lucet-idl/src/package.rs @@ -90,8 +90,7 @@ impl Package { mod test { use super::*; use crate::parser::Parser; - use crate::types::{AtomType, DataType, DataTypeRef}; - + use crate::types::{AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant}; fn pkg_(syntax: &str) -> Result { let mut parser = Parser::new(syntax); let decls = parser.match_decls().expect("parses"); @@ -212,8 +211,10 @@ mod test { funcs: HashMap::new(), data_types: vec![( Ident(0), - DataType::Alias { - to: DataTypeRef::Atom(AtomType::U8), + DataType { + variant: DataTypeVariant::Alias(AliasDataType { + to: DataTypeRef::Atom(AtomType::U8) + }), attrs: Vec::new() } )] diff --git a/lucet-idl/src/rust/mod.rs b/lucet-idl/src/rust/mod.rs index 981a342ac..6fce29f94 100644 --- a/lucet-idl/src/rust/mod.rs +++ b/lucet-idl/src/rust/mod.rs @@ -7,7 +7,9 @@ use crate::module::Module; use crate::pretty_writer::PrettyWriter; use crate::target::Target; use crate::types::AtomType; -use crate::types::{DataType, DataTypeRef, FuncDecl, Ident, Named}; +use crate::types::{ + AliasDataType, DataType, DataTypeRef, EnumDataType, FuncDecl, Ident, Named, StructDataType, +}; use heck::{CamelCase, SnakeCase}; use std::collections::HashMap; use std::io::Write; @@ -88,16 +90,10 @@ impl Generator for RustGenerator { &mut self, module: &Module, data_type_entry: &Named, + alias: &AliasDataType, ) -> Result<(), IDLError> { - let (pointee, _attrs) = - if let DataType::Alias { to: pointee, attrs } = &data_type_entry.entity { - (pointee, attrs) - } else { - unreachable!() - }; - let typename = self.define_name(data_type_entry); - let pointee_name = self.get_defined_typename(pointee); + let pointee_name = self.get_defined_typename(&alias.to); self.w .writeln(format!("pub type {} = {};", typename, pointee_name))? @@ -109,17 +105,8 @@ impl Generator for RustGenerator { &mut self, module: &Module, data_type_entry: &Named, + struct_: &StructDataType, ) -> Result<(), IDLError> { - let (named_members, _attrs) = if let DataType::Struct { - members: named_members, - attrs, - } = &data_type_entry.entity - { - (named_members, attrs) - } else { - unreachable!() - }; - let typename = data_type_entry.name.name.to_camel_case(); self.defined.insert(data_type_entry.id, typename.clone()); @@ -128,7 +115,7 @@ impl Generator for RustGenerator { .writeln(format!("pub struct {} {{", typename))?; let mut w = self.w.new_block(); - for m in named_members { + for m in struct_.members.iter() { w.writeln(format!( "{}: {},", m.name.to_snake_case(), @@ -146,17 +133,8 @@ impl Generator for RustGenerator { &mut self, module: &Module, data_type_entry: &Named, + enum_: &EnumDataType, ) -> Result<(), IDLError> { - let (named_members, _attrs) = if let DataType::Enum { - members: named_members, - attrs, - } = &data_type_entry.entity - { - (named_members, attrs) - } else { - unreachable!() - }; - let typename = data_type_entry.name.name.to_camel_case(); self.defined.insert(data_type_entry.id, typename.clone()); @@ -166,7 +144,7 @@ impl Generator for RustGenerator { .writeln(format!("pub enum {} {{", typename))?; let mut w = self.w.new_block(); - for m in named_members { + for m in enum_.members.iter() { w.writeln(format!("{},", m.name.to_camel_case()))?; } diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index 0f17beebc..d0c04ee10 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -54,31 +54,56 @@ pub enum DataTypeRef { } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct NamedMember { - pub type_: R, +pub struct StructMember { + pub type_: DataTypeRef, pub name: String, pub attrs: Vec, } #[derive(Debug, PartialEq, Eq, Clone)] -pub enum DataType { - Struct { - members: Vec>, - attrs: Vec, - }, - Enum { - members: Vec>, - attrs: Vec, - }, - Alias { - to: DataTypeRef, - attrs: Vec, - }, +pub struct StructDataType { + pub members: Vec, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct EnumMember { + pub name: String, + pub attrs: Vec, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct EnumDataType { + pub members: Vec, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct AliasDataType { + pub to: DataTypeRef, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum DataTypeVariant { + Struct(StructDataType), + Enum(EnumDataType), + Alias(AliasDataType), +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct DataType { + pub variant: DataTypeVariant, + pub attrs: Vec, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct FuncArg { + pub type_: DataTypeRef, + pub name: String, + pub attrs: Vec, } #[derive(Debug, PartialEq, Eq, Clone)] pub struct FuncDecl { - pub args: Vec>, + pub args: Vec, pub rets: Vec, pub attrs: Vec, } diff --git a/lucet-idl/tests/example.rs b/lucet-idl/tests/example.rs index d0bfea0c9..16fd69e7c 100644 --- a/lucet-idl/tests/example.rs +++ b/lucet-idl/tests/example.rs @@ -14,7 +14,6 @@ fn compile_and_run_c() { let config = lucet_idl::Config { backend: lucet_idl::Backend::C, - backend_config: lucet_idl::BackendConfig::default(), target: lucet_idl::Target::Generic, }; @@ -54,7 +53,6 @@ fn compile_and_run_rust() { let config = lucet_idl::Config { backend: lucet_idl::Backend::Rust, - backend_config: lucet_idl::BackendConfig::default(), target: lucet_idl::Target::Generic, }; From 174778a2aafebdcf8df5e8c24fa9420b234476f3 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 13 May 2019 18:07:19 -0700 Subject: [PATCH 207/512] lucet-idl: add intermediate stage between datatype syntax and canonical repr going to add richer info to the canonical repr next --- lucet-idl/src/module.rs | 151 +++++++++++--------------------- lucet-idl/src/module/builder.rs | 111 +++++++++++++++++++++++ lucet-idl/src/package.rs | 5 ++ 3 files changed, 167 insertions(+), 100 deletions(-) create mode 100644 lucet-idl/src/module/builder.rs diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index b710d8c7e..21ba67b7b 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -1,15 +1,20 @@ +mod builder; + use crate::error::ValidationError; use crate::parser::{SyntaxDecl, SyntaxRef}; use crate::types::{ AliasDataType, Attr, DataType, DataTypeRef, DataTypeVariant, EnumDataType, EnumMember, FuncArg, FuncDecl, FuncRet, Ident, Location, Name, Named, StructDataType, StructMember, }; +use builder::DataTypeModuleBuilder; use std::collections::HashMap; + #[derive(Debug, PartialEq, Eq, Clone)] pub struct Module { pub names: Vec, pub attrs: Vec, pub data_types: HashMap, + pub data_type_ordering: Vec, pub funcs: HashMap, } @@ -19,6 +24,7 @@ impl Module { names: Vec::new(), attrs: attrs.to_vec(), data_types: HashMap::new(), + data_type_ordering: Vec::new(), funcs: HashMap::new(), } } @@ -70,19 +76,13 @@ impl Module { } } - fn define_data_type(&mut self, id: Ident, variant: DataTypeVariant, attrs: Vec) { - if let Some(prev_def) = self.data_types.insert(id, DataType { variant, attrs }) { - panic!("id {} already defined: {:?}", id, prev_def) - } - } - - fn define_function(&mut self, id: Ident, decl: FuncDecl) { - if let Some(prev_def) = self.funcs.insert(id, decl) { - panic!("id {} already defined: {:?}", id, prev_def) - } - } - - fn define_decl(&mut self, id: Ident, decl: &SyntaxDecl) -> Result<(), ValidationError> { + fn decl_to_ir( + &self, + id: Ident, + decl: &SyntaxDecl, + data_types_ir: &mut DataTypeModuleBuilder, + funcs_ir: &mut HashMap, + ) -> Result<(), ValidationError> { match decl { SyntaxDecl::Struct { name, @@ -117,13 +117,15 @@ impl Module { attrs: mem.attrs.clone(), }) } - self.define_data_type( + + data_types_ir.define( id, DataTypeVariant::Struct(StructDataType { members: dtype_members, }), attrs.clone(), - ) + location.clone(), + ); } SyntaxDecl::Enum { name, @@ -154,20 +156,27 @@ impl Module { attrs: var.attrs.clone(), }) } - self.define_data_type( + data_types_ir.define( id, DataTypeVariant::Enum(EnumDataType { members: dtype_members, }), attrs.clone(), - ) + location.clone(), + ); } - SyntaxDecl::Alias { what, attrs, .. } => { + SyntaxDecl::Alias { + what, + attrs, + location, + .. + } => { let to = self.get_ref(what)?; - self.define_data_type( + data_types_ir.define( id, DataTypeVariant::Alias(AliasDataType { to }), attrs.clone(), + location.clone(), ); } SyntaxDecl::Function { @@ -215,73 +224,21 @@ impl Module { location: location.clone(), })? } - self.define_function( - id, - FuncDecl { - args, - rets, - attrs: attrs.clone(), - }, - ); - } - SyntaxDecl::Module { .. } => unreachable!(), // Should be excluded by from_declarations constructor - } - Ok(()) - } - fn dfs_walk( - &self, - id: Ident, - visited: &mut [bool], - ordered: &mut Option<&mut Vec>, - ) -> Result<(), ()> { - if visited[id.0] { - Err(())? - } - visited[id.0] = true; - match self - .data_types - .get(&id) - .expect("data_type is defined") - .variant - { - DataTypeVariant::Struct(ref s) => { - for mem in s.members.iter() { - if let DataTypeRef::Defined(id) = mem.type_ { - self.dfs_walk(id, visited, ordered)? - } + let decl = FuncDecl { + args, + rets, + attrs: attrs.clone(), + }; + if let Some(prev_def) = funcs_ir.insert(id, decl) { + panic!("id {} already defined: {:?}", id, prev_def) } } - DataTypeVariant::Alias(ref a) => { - if let DataTypeRef::Defined(id) = a.to { - self.dfs_walk(id, visited, ordered)? - } - } - DataTypeVariant::Enum(_) => {} - } - if let Some(ordered) = ordered.as_mut() { - if !ordered.contains(&id) { - ordered.push(id) - } + SyntaxDecl::Module { .. } => unreachable!(), // Should be excluded by from_declarations constructor } - visited[id.0] = false; Ok(()) } - fn dfs_find_cycle(&self, id: Ident) -> Result<(), ()> { - let mut visited = Vec::new(); - visited.resize(self.names.len(), false); - self.dfs_walk(id, &mut visited, &mut None) - } - - fn ensure_finite_datatype(&self, id: Ident, decl: &SyntaxDecl) -> Result<(), ValidationError> { - self.dfs_find_cycle(id) - .map_err(|_| ValidationError::Infinite { - name: decl.name().to_owned(), - location: *decl.location(), - }) - } - pub fn from_declarations( decls: &[SyntaxDecl], attrs: &[Attr], @@ -298,15 +255,17 @@ impl Module { } } + let mut data_types_ir = DataTypeModuleBuilder::new(); + let mut funcs_ir = HashMap::new(); for (decl, id) in decls.iter().zip(&idents) { - mod_.define_decl(id.clone(), decl)? + mod_.decl_to_ir(id.clone(), decl, &mut data_types_ir, &mut funcs_ir)? } - for (decl, id) in decls.iter().zip(idents) { - if decl.is_datatype() { - mod_.ensure_finite_datatype(id, decl)? - } - } + let (data_types, ordering) = data_types_ir.validate_datatypes(&mod_.names)?; + mod_.data_types = data_types; + mod_.data_type_ordering = ordering; + + mod_.funcs = funcs_ir; Ok(mod_) } @@ -338,22 +297,10 @@ impl Module { None } } - - fn ordered_datatype_idents(&self) -> Vec { - let mut visited = Vec::new(); - visited.resize(self.names.len(), false); - let mut ordered = Vec::with_capacity(visited.capacity()); - for id in self.data_types.keys() { - let _ = self.dfs_walk(*id, &mut visited, &mut Some(&mut ordered)); - } - ordered - } - pub fn datatypes(&self) -> impl Iterator> { - let idents = self.ordered_datatype_idents(); - idents - .into_iter() - .map(move |i| self.get_datatype(i).unwrap()) + self.data_type_ordering + .iter() + .map(move |i| self.get_datatype(*i).unwrap()) } pub fn func_decls(&self) -> impl Iterator> { @@ -579,6 +526,7 @@ mod tests { .into_iter() .collect::>(), data_types: HashMap::new(), + data_type_ordering: Vec::new(), attrs: Vec::new(), } ); @@ -607,6 +555,7 @@ mod tests { .into_iter() .collect::>(), data_types: HashMap::new(), + data_type_ordering: Vec::new(), attrs: Vec::new(), } ); @@ -635,6 +584,7 @@ mod tests { .into_iter() .collect::>(), data_types: HashMap::new(), + data_type_ordering: Vec::new(), attrs: Vec::new(), } ); @@ -679,6 +629,7 @@ mod tests { )] .into_iter() .collect::>(), + data_type_ordering: vec![Ident(1)], attrs: Vec::new(), } ); diff --git a/lucet-idl/src/module/builder.rs b/lucet-idl/src/module/builder.rs new file mode 100644 index 000000000..564ddfefd --- /dev/null +++ b/lucet-idl/src/module/builder.rs @@ -0,0 +1,111 @@ +use crate::error::ValidationError; +use crate::types::{Attr, DataType, DataTypeRef, DataTypeVariant, Ident, Location, Name}; +use std::collections::HashMap; + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct DataTypeModuleBuilder { + data_types: HashMap, +} + +impl DataTypeModuleBuilder { + pub fn new() -> Self { + Self { + data_types: HashMap::new(), + } + } + + pub fn define( + &mut self, + id: Ident, + variant: DataTypeVariant, + attrs: Vec, + location: Location, + ) { + if let Some(prev_def) = self.data_types.insert( + id, + DataTypeIR { + variant, + attrs: attrs.clone(), + location: location.clone(), + }, + ) { + panic!("id {} already defined: {:?}", id, prev_def) + } + } + + fn dfs_walk( + &self, + id: Ident, + visited: &mut [bool], + ordered: &mut Option<&mut Vec>, + ) -> Result<(), ()> { + if visited[id.0] { + Err(())? + } + visited[id.0] = true; + match self + .data_types + .get(&id) + .expect("data_type is defined") + .variant + { + DataTypeVariant::Struct(ref s) => { + for mem in s.members.iter() { + if let DataTypeRef::Defined(id) = mem.type_ { + self.dfs_walk(id, visited, ordered)? + } + } + } + DataTypeVariant::Alias(ref a) => { + if let DataTypeRef::Defined(id) = a.to { + self.dfs_walk(id, visited, ordered)? + } + } + DataTypeVariant::Enum(_) => {} + } + if let Some(ordered) = ordered.as_mut() { + if !ordered.contains(&id) { + ordered.push(id) + } + } + visited[id.0] = false; + Ok(()) + } + + pub fn validate_datatypes( + &self, + names: &[Name], + ) -> Result<(HashMap, Vec), ValidationError> { + let mut finalized = HashMap::new(); + let mut ordered = Vec::new(); + // Important to iterate in name order, so error messages are consistient. + // HashMap iteration order is not stable. + for (ix, name) in names.iter().enumerate() { + let id = Ident(ix); + if let Some(decl) = self.data_types.get(&id) { + let mut visited = Vec::new(); + visited.resize(names.len(), false); + self.dfs_walk(id, &mut visited, &mut Some(&mut ordered)) + .map_err(|_| ValidationError::Infinite { + name: name.name.clone(), + location: decl.location.clone(), + })?; + finalized.insert( + id, + DataType { + variant: decl.variant.clone(), + attrs: decl.attrs.clone(), + }, + ); + } + } + Ok((finalized, ordered)) + } +} + +#[derive(Debug, PartialEq, Eq, Clone)] +struct DataTypeIR { + pub variant: DataTypeVariant, + pub attrs: Vec, + pub location: Location, +} diff --git a/lucet-idl/src/package.rs b/lucet-idl/src/package.rs index 733a2593a..b7a36e1da 100644 --- a/lucet-idl/src/package.rs +++ b/lucet-idl/src/package.rs @@ -115,6 +115,7 @@ mod test { names: Vec::new(), attrs: Vec::new(), data_types: HashMap::new(), + data_type_ordering: Vec::new(), funcs: HashMap::new(), } )] @@ -158,6 +159,7 @@ mod test { names: Vec::new(), attrs: Vec::new(), data_types: HashMap::new(), + data_type_ordering: Vec::new(), funcs: HashMap::new(), } ), @@ -167,6 +169,7 @@ mod test { names: Vec::new(), attrs: Vec::new(), data_types: HashMap::new(), + data_type_ordering: Vec::new(), funcs: HashMap::new(), } ), @@ -176,6 +179,7 @@ mod test { names: Vec::new(), attrs: Vec::new(), data_types: HashMap::new(), + data_type_ordering: Vec::new(), funcs: HashMap::new(), } ) @@ -220,6 +224,7 @@ mod test { )] .into_iter() .collect::>(), + data_type_ordering: vec![Ident(0)], } )] .into_iter() From 86c681d8efc66917e46a8d24c9ab2592f915a546 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 14 May 2019 18:05:28 -0700 Subject: [PATCH 208/512] lucet-idl: compute struct layout in module::builder --- lucet-idl/src/module.rs | 56 ++++++---- lucet-idl/src/module/builder.rs | 182 +++++++++++++++++++++++++------- lucet-idl/src/package.rs | 3 +- lucet-idl/src/types.rs | 3 + 4 files changed, 183 insertions(+), 61 deletions(-) diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index 21ba67b7b..fee51cf09 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -3,10 +3,10 @@ mod builder; use crate::error::ValidationError; use crate::parser::{SyntaxDecl, SyntaxRef}; use crate::types::{ - AliasDataType, Attr, DataType, DataTypeRef, DataTypeVariant, EnumDataType, EnumMember, FuncArg, - FuncDecl, FuncRet, Ident, Location, Name, Named, StructDataType, StructMember, + Attr, DataType, DataTypeRef, EnumMember, FuncArg, FuncDecl, FuncRet, Ident, Location, Name, + Named, }; -use builder::DataTypeModuleBuilder; +use builder::{AliasIR, DataTypeModuleBuilder, EnumIR, StructIR, StructMemberIR, VariantIR}; use std::collections::HashMap; #[derive(Debug, PartialEq, Eq, Clone)] @@ -111,7 +111,7 @@ impl Module { // defined types: let type_ = self.get_ref(&mem.type_)?; // build the struct with this as the member: - dtype_members.push(StructMember { + dtype_members.push(StructMemberIR { type_, name: mem.name.clone(), attrs: mem.attrs.clone(), @@ -120,7 +120,7 @@ impl Module { data_types_ir.define( id, - DataTypeVariant::Struct(StructDataType { + VariantIR::Struct(StructIR { members: dtype_members, }), attrs.clone(), @@ -158,7 +158,7 @@ impl Module { } data_types_ir.define( id, - DataTypeVariant::Enum(EnumDataType { + VariantIR::Enum(EnumIR { members: dtype_members, }), attrs.clone(), @@ -174,7 +174,7 @@ impl Module { let to = self.get_ref(what)?; data_types_ir.define( id, - DataTypeVariant::Alias(AliasDataType { to }), + VariantIR::Alias(AliasIR { to }), attrs.clone(), location.clone(), ); @@ -314,7 +314,7 @@ impl Module { mod tests { use super::*; use crate::parser::Parser; - use crate::types::AtomType; + use crate::types::{AliasDataType, AtomType, DataTypeVariant, StructDataType, StructMember}; fn mod_(syntax: &str) -> Result { let mut parser = Parser::new(syntax); @@ -332,20 +332,31 @@ mod tests { fn struct_two_atoms() { { let d = mod_("struct foo { a: i32, b: f32 }").unwrap(); - let members = match &d.data_types[&Ident(0)].variant { - DataTypeVariant::Struct(s) => &s.members, - _ => panic!("Unexpected type"), - }; - assert_eq!(members[0].name, "a"); - assert_eq!(members[1].name, "b"); - match &members[0].type_ { - DataTypeRef::Atom(AtomType::I32) => (), - _ => panic!("Unexpected type"), - }; - match &members[1].type_ { - DataTypeRef::Atom(AtomType::F32) => (), - _ => panic!("Unexpected type"), - }; + assert_eq!( + d.data_types[&Ident(0)], + DataType { + variant: DataTypeVariant::Struct(StructDataType { + members: vec![ + StructMember { + name: "a".to_owned(), + type_: DataTypeRef::Atom(AtomType::I32), + attrs: Vec::new(), + repr_size: 4, + offset: 0, + }, + StructMember { + name: "b".to_owned(), + type_: DataTypeRef::Atom(AtomType::F32), + attrs: Vec::new(), + repr_size: 4, + offset: 4, + }, + ] + }), + attrs: Vec::new(), + repr_size: 8, + } + ); } } @@ -625,6 +636,7 @@ mod tests { to: DataTypeRef::Atom(AtomType::U8), }), attrs: Vec::new(), + repr_size: 1, } )] .into_iter() diff --git a/lucet-idl/src/module/builder.rs b/lucet-idl/src/module/builder.rs index 564ddfefd..d7e66ba05 100644 --- a/lucet-idl/src/module/builder.rs +++ b/lucet-idl/src/module/builder.rs @@ -1,7 +1,46 @@ use crate::error::ValidationError; -use crate::types::{Attr, DataType, DataTypeRef, DataTypeVariant, Ident, Location, Name}; +use crate::types::{ + AliasDataType, AtomType, Attr, DataType, DataTypeRef, DataTypeVariant, EnumDataType, + EnumMember, Ident, Location, Name, StructDataType, StructMember, +}; use std::collections::HashMap; +#[derive(Debug, PartialEq, Eq, Clone)] +struct DataTypeIR { + pub variant: VariantIR, + pub attrs: Vec, + pub location: Location, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct StructMemberIR { + pub type_: DataTypeRef, + pub name: String, + pub attrs: Vec, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct StructIR { + pub members: Vec, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct EnumIR { + pub members: Vec, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct AliasIR { + pub to: DataTypeRef, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum VariantIR { + Struct(StructIR), + Enum(EnumIR), + Alias(AliasIR), +} + #[derive(Debug, PartialEq, Eq, Clone)] pub struct DataTypeModuleBuilder { data_types: HashMap, @@ -14,13 +53,7 @@ impl DataTypeModuleBuilder { } } - pub fn define( - &mut self, - id: Ident, - variant: DataTypeVariant, - attrs: Vec, - location: Location, - ) { + pub fn define(&mut self, id: Ident, variant: VariantIR, attrs: Vec, location: Location) { if let Some(prev_def) = self.data_types.insert( id, DataTypeIR { @@ -37,37 +70,102 @@ impl DataTypeModuleBuilder { &self, id: Ident, visited: &mut [bool], - ordered: &mut Option<&mut Vec>, + ordered: &mut Vec, + finalized_types: &mut HashMap, ) -> Result<(), ()> { if visited[id.0] { Err(())? } visited[id.0] = true; - match self - .data_types - .get(&id) - .expect("data_type is defined") - .variant - { - DataTypeVariant::Struct(ref s) => { + let dt = self.data_types.get(&id).expect("data type IR is defined"); + match &dt.variant { + VariantIR::Struct(ref s) => { + // First, iterate down the member to ensure this is finite, and fill in type + // info for leaves first for mem in s.members.iter() { if let DataTypeRef::Defined(id) = mem.type_ { - self.dfs_walk(id, visited, ordered)? + self.dfs_walk(id, visited, ordered, finalized_types)?; + }; + } + // If finalized type information has not yet been computed, we can now compute it: + if !finalized_types.contains_key(&id) { + let mut offset = 0; + let mut members: Vec = Vec::new(); + for mem in s.members.iter() { + let repr_size = datatype_repr_size(&mem.type_, finalized_types) + .expect("datatype is defined by prior dfs_walk"); + + if let Some(prev_elem) = members.last() { + let prev_elem_size = prev_elem.repr_size; + let padding = (prev_elem_size - 1) + - ((offset + (prev_elem_size - 1)) % prev_elem_size); + offset += padding; + } + + members.push(StructMember { + type_: mem.type_.clone(), + name: mem.name.clone(), + attrs: mem.attrs.clone(), + repr_size, + offset, + }); + offset += repr_size; } + + // Struct will be aligned to the size of the first element. Structs always have + // at least one element. + let first_elem_size = members[0].repr_size; + let end_padding = (first_elem_size - 1) + - ((offset + (first_elem_size - 1)) % first_elem_size); + + finalized_types.insert( + id, + DataType { + variant: DataTypeVariant::Struct(StructDataType { members }), + attrs: dt.attrs.clone(), + repr_size: offset + end_padding, + }, + ); } } - DataTypeVariant::Alias(ref a) => { - if let DataTypeRef::Defined(id) = a.to { - self.dfs_walk(id, visited, ordered)? + VariantIR::Alias(ref a) => { + if let DataTypeRef::Defined(pointee_id) = a.to { + self.dfs_walk(pointee_id, visited, ordered, finalized_types)?; + }; + if !finalized_types.contains_key(&id) { + let repr_size = datatype_repr_size(&a.to, finalized_types) + .expect("datatype is defined by prior dfs_walk"); + finalized_types.insert( + id, + DataType { + variant: DataTypeVariant::Alias(AliasDataType { to: a.to.clone() }), + attrs: dt.attrs.clone(), + repr_size, + }, + ); } } - DataTypeVariant::Enum(_) => {} - } - if let Some(ordered) = ordered.as_mut() { - if !ordered.contains(&id) { - ordered.push(id) + VariantIR::Enum(ref e) => { + // No recursion to do on the dfs. + if !finalized_types.contains_key(&id) { + // x86_64 ABI says enum is 32 bits wide + let repr_size = atom_repr_size(&AtomType::U32); + finalized_types.insert( + id, + DataType { + variant: DataTypeVariant::Enum(EnumDataType { + members: e.members.clone(), + }), + attrs: dt.attrs.clone(), + repr_size, + }, + ); + } } } + if !ordered.contains(&id) { + ordered.push(id) + } visited[id.0] = false; Ok(()) } @@ -83,29 +181,37 @@ impl DataTypeModuleBuilder { for (ix, name) in names.iter().enumerate() { let id = Ident(ix); if let Some(decl) = self.data_types.get(&id) { + // First, make sure datatypes are finite let mut visited = Vec::new(); visited.resize(names.len(), false); - self.dfs_walk(id, &mut visited, &mut Some(&mut ordered)) + + self.dfs_walk(id, &mut visited, &mut ordered, &mut finalized) .map_err(|_| ValidationError::Infinite { name: name.name.clone(), location: decl.location.clone(), })?; - finalized.insert( - id, - DataType { - variant: decl.variant.clone(), - attrs: decl.attrs.clone(), - }, - ); } } Ok((finalized, ordered)) } } -#[derive(Debug, PartialEq, Eq, Clone)] -struct DataTypeIR { - pub variant: DataTypeVariant, - pub attrs: Vec, - pub location: Location, +fn datatype_repr_size( + datatype_ref: &DataTypeRef, + finalized_types: &HashMap, +) -> Option { + Some(match datatype_ref { + DataTypeRef::Atom(a) => atom_repr_size(a), + DataTypeRef::Defined(ref member_ident) => finalized_types.get(member_ident)?.repr_size, + }) +} + +fn atom_repr_size(atom_type: &AtomType) -> usize { + match atom_type { + AtomType::Bool => 1, + AtomType::U8 | AtomType::I8 => 1, + AtomType::U16 | AtomType::I16 => 2, + AtomType::U32 | AtomType::I32 | AtomType::F32 => 4, + AtomType::U64 | AtomType::I64 | AtomType::F64 => 8, + } } diff --git a/lucet-idl/src/package.rs b/lucet-idl/src/package.rs index b7a36e1da..ff07a4e34 100644 --- a/lucet-idl/src/package.rs +++ b/lucet-idl/src/package.rs @@ -219,7 +219,8 @@ mod test { variant: DataTypeVariant::Alias(AliasDataType { to: DataTypeRef::Atom(AtomType::U8) }), - attrs: Vec::new() + attrs: Vec::new(), + repr_size: 1, } )] .into_iter() diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index d0c04ee10..6525a0f95 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -58,6 +58,8 @@ pub struct StructMember { pub type_: DataTypeRef, pub name: String, pub attrs: Vec, + pub repr_size: usize, + pub offset: usize, } #[derive(Debug, PartialEq, Eq, Clone)] @@ -92,6 +94,7 @@ pub enum DataTypeVariant { pub struct DataType { pub variant: DataTypeVariant, pub attrs: Vec, + pub repr_size: usize, } #[derive(Debug, PartialEq, Eq, Clone)] From 555fc66941baadfb14c63522f1af557b11d566cb Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 14 May 2019 18:58:04 -0700 Subject: [PATCH 209/512] lucet-idl: convert c backend to use centralized type info --- lucet-idl/src/c/alias.rs | 41 ++++---------- lucet-idl/src/c/catom.rs | 60 +++++---------------- lucet-idl/src/c/enum.rs | 31 ++++------- lucet-idl/src/c/macros.rs | 5 +- lucet-idl/src/c/mod.rs | 94 +++++++-------------------------- lucet-idl/src/c/struct.rs | 54 ++++--------------- lucet-idl/src/module/builder.rs | 14 +---- lucet-idl/src/types.rs | 12 +++++ 8 files changed, 78 insertions(+), 233 deletions(-) diff --git a/lucet-idl/src/c/alias.rs b/lucet-idl/src/c/alias.rs index eea008bc5..0b70efe85 100644 --- a/lucet-idl/src/c/alias.rs +++ b/lucet-idl/src/c/alias.rs @@ -1,44 +1,25 @@ use super::*; -// The most important thing in alias generation is to cache the size -// and alignment rules of what it ultimately points to pub fn generate( gen: &mut CGenerator, module: &Module, - data_type_entry: &Named, + dt: &Named, alias: &AliasDataType, ) -> Result<(), IDLError> { - let type_info = gen.type_info(module, &alias.to); + let dtname = &dt.name.name; gen.w.indent()?; - gen.w - .write(format!("typedef {}", type_info.type_name).as_bytes())?; - gen.w.space()?; - gen.w.write(data_type_entry.name.name.as_bytes())?; - gen.w.write(b";")?; - let leaf_type_info = gen.type_info(module, type_info.leaf_data_type_ref); - if leaf_type_info.type_name != type_info.type_name { - gen.w.write(b" // equivalent to ")?; - gen.w.write(leaf_type_info.type_name.as_bytes())?; - } - gen.w.eol()?; + gen.w.writeln(format!( + "typedef {} {};", + gen.type_name(module, &alias.to), + dtname + ))?; gen.w.eob()?; - gen.cache.store_type( - data_type_entry.id, - CachedTypeEntry { - type_size: type_info.type_size, - type_align: type_info.type_align, - members: vec![], - }, - ); // Add an assertion to check that resolved size is the one we computed - gen.w.write_line( - format!( - "_Static_assert(sizeof({}) == {}, \"unexpected alias size\");", - data_type_entry.name.name, type_info.type_size - ) - .as_bytes(), - )?; + gen.w.writeln(format!( + "_Static_assert(sizeof({}) == {}, \"unexpected alias size\");", + dtname, dt.entity.repr_size + ))?; gen.w.eob()?; Ok(()) diff --git a/lucet-idl/src/c/catom.rs b/lucet-idl/src/c/catom.rs index 4ecaea8cf..1b906945f 100644 --- a/lucet-idl/src/c/catom.rs +++ b/lucet-idl/src/c/catom.rs @@ -3,68 +3,56 @@ use crate::types::*; /// Information about a C native type pub struct CAtom { + pub atom_type: AtomType, pub native_type_name: &'static str, - pub native_type_size: usize, - pub native_type_align: usize, } impl From for CAtom { fn from(atom_type: AtomType) -> Self { match atom_type { AtomType::Bool => CAtom { + atom_type, native_type_name: "bool", - native_type_size: 1, - native_type_align: 1, }, AtomType::U8 => CAtom { + atom_type, native_type_name: "uint8_t", - native_type_size: 1, - native_type_align: 1, }, AtomType::U16 => CAtom { + atom_type, native_type_name: "uint16_t", - native_type_size: 2, - native_type_align: 2, }, AtomType::U32 => CAtom { + atom_type, native_type_name: "uint32_t", - native_type_size: 4, - native_type_align: 4, }, AtomType::U64 => CAtom { + atom_type, native_type_name: "uint64_t", - native_type_size: 8, - native_type_align: 8, // x86_64 alignment rule }, AtomType::I8 => CAtom { + atom_type, native_type_name: "int8_t", - native_type_size: 1, - native_type_align: 1, }, AtomType::I16 => CAtom { + atom_type, native_type_name: "int16_t", - native_type_size: 2, - native_type_align: 2, }, AtomType::I32 => CAtom { + atom_type, native_type_name: "int32_t", - native_type_size: 4, - native_type_align: 4, }, AtomType::I64 => CAtom { + atom_type, native_type_name: "int64_t", - native_type_size: 8, - native_type_align: 8, // x86_64 alignment rule }, AtomType::F32 => CAtom { + atom_type, native_type_name: "float", - native_type_size: 4, - native_type_align: 4, }, AtomType::F64 => CAtom { + atom_type, native_type_name: "double", - native_type_size: 8, - native_type_align: 8, // x86_64 alignment rule }, } } @@ -77,28 +65,11 @@ impl CAtom { CAtom::from(AtomType::U32) } - /// C atom type to generic atom type - pub fn as_atom_type(&self) -> Option { - match self.native_type_name { - "uint8_t" => Some(AtomType::U8), - "uint16_t" => Some(AtomType::U16), - "uint32_t" => Some(AtomType::U32), - "uint64_t" => Some(AtomType::U64), - "int8_t" => Some(AtomType::I8), - "int16_t" => Some(AtomType::I16), - "int32_t" => Some(AtomType::I32), - "int64_t" => Some(AtomType::I64), - "float" => Some(AtomType::F32), - "double" => Some(AtomType::F64), - _ => None, - } - } - /// Return an expression to swap byte order /// No need to swap anything if we have a single byte or if we explicitly /// target an architecture that matches the reference target for the type pub fn bswap(&self, _target: Target, vstr: &str) -> String { - if self.native_type_size < 2 { + if self.atom_type.repr_size() < 2 { vstr.to_string() } else { format!("___bswap_{}({})", self.native_type_name, vstr) @@ -107,10 +78,7 @@ impl CAtom { /// Return an expression to force little-endian order pub fn little_endian(&self, target: Target, vstr: &str) -> String { - let atom_type = self.as_atom_type(); - if self.native_type_size < 2 - || (atom_type.is_some() && target.uses_reference_target_endianness()) - { + if self.atom_type.repr_size() < 2 || target.uses_reference_target_endianness() { vstr.to_string() } else { format!("___le_{}({})", self.native_type_name, vstr) diff --git a/lucet-idl/src/c/enum.rs b/lucet-idl/src/c/enum.rs index 18b7c3750..2ee335f41 100644 --- a/lucet-idl/src/c/enum.rs +++ b/lucet-idl/src/c/enum.rs @@ -1,37 +1,32 @@ use super::*; +use crate::types::AtomType; // Enums generate both a specific typedef, and a traditional C-style enum // The typedef is required to use a native type which is consistent across all architectures pub fn generate( gen: &mut CGenerator, _module: &Module, - data_type_entry: &Named, + dt: &Named, enum_: &EnumDataType, ) -> Result<(), IDLError> { - let enum_native_type = CAtom::enum_(); - let (type_align, type_size, type_name) = ( - enum_native_type.native_type_align, - enum_native_type.native_type_size, - enum_native_type.native_type_name, - ); - + let type_size = dt.entity.repr_size; gen.w.write_line( format!( "typedef {} {}; // enum, should be in the [0...{}] range", - type_name, - data_type_entry.name.name, + CAtom::from(AtomType::U32).native_type_name, + dt.name.name, enum_.members.len() - 1 ) .as_bytes(), )?; gen.w - .write_line(format!("enum ___{} {{", data_type_entry.name.name).as_bytes())?; + .write_line(format!("enum ___{} {{", dt.name.name).as_bytes())?; let mut pretty_writer_i1 = gen.w.new_block(); for (i, named_member) in enum_.members.iter().enumerate() { pretty_writer_i1.write_line( format!( "{}, // {}", - macros::macro_for(&data_type_entry.name.name, &named_member.name), + macros::macro_for(&dt.name.name, &named_member.name), i ) .as_bytes(), @@ -42,21 +37,13 @@ pub fn generate( gen.w.write_line( format!( "_Static_assert(sizeof({}) == {}, \"unexpected enumeration size\");", - data_type_entry.name.name, type_size + dt.name.name, type_size ) .as_bytes(), )?; gen.w.eob()?; - macros::define(gen, "BYTES", &data_type_entry.name.name, type_size)?; + macros::define(gen, "BYTES", &dt.name.name, type_size)?; gen.w.eob()?; - gen.cache.store_type( - data_type_entry.id, - CachedTypeEntry { - type_size, - type_align, - members: vec![], - }, - ); Ok(()) } diff --git a/lucet-idl/src/c/macros.rs b/lucet-idl/src/c/macros.rs index 38f3a9ba5..194a9bba8 100644 --- a/lucet-idl/src/c/macros.rs +++ b/lucet-idl/src/c/macros.rs @@ -42,10 +42,7 @@ pub fn macro_for_data_type_ref( data_type_ref: &DataTypeRef, ) -> String { match data_type_ref { - DataTypeRef::Atom(atom_type) => { - let native_type_size = CAtom::from(*atom_type).native_type_size; - format!("{}", native_type_size) - } + DataTypeRef::Atom(atom_type) => format!("{}", atom_type.repr_size()), DataTypeRef::Defined(data_type_id) => { let data_type_entry = module .get_datatype(*data_type_id) diff --git a/lucet-idl/src/c/mod.rs b/lucet-idl/src/c/mod.rs index 17b92e90d..fb4c63c0f 100644 --- a/lucet-idl/src/c/mod.rs +++ b/lucet-idl/src/c/mod.rs @@ -2,14 +2,12 @@ #![allow(unused_variables)] mod alias; -mod cache; mod catom; mod r#enum; mod macros; mod prelude; mod r#struct; -use self::cache::{Cache, CachedStructMemberEntry, CachedTypeEntry}; pub(crate) use self::catom::CAtom; use crate::error::IDLError; use crate::generator::Generator; @@ -22,22 +20,9 @@ use crate::types::{ }; use std::io::prelude::*; -#[derive(Clone, Debug)] -struct CTypeInfo<'t> { - /// The native type name - type_name: String, - /// Alignment rules for that type - type_align: usize, - /// The native type size - type_size: usize, - /// The leaf type node - leaf_data_type_ref: &'t DataTypeRef, -} - /// Generator for the C backend pub struct CGenerator { pub target: Target, - pub cache: Cache, pub w: PrettyWriter, } @@ -89,10 +74,11 @@ impl Generator for CGenerator { fn gen_function( &mut self, - module: &Module, - func_decl_entry: &Named, + _module: &Module, + _func_decl_entry: &Named, ) -> Result<(), IDLError> { - unimplemented!(); + // UNIMPLEMENTED!! + Ok(()) } } @@ -100,64 +86,7 @@ impl CGenerator { pub fn new(target: Target, w: Box) -> Self { let mut w = PrettyWriter::new(w); prelude::generate(&mut w, target.clone()).expect("write prelude"); - Self { - target, - cache: Cache::default(), - w, - } - } - /// Traverse a `DataTypeRef` chain, and return information - /// about the leaf node as well as the native type to use - /// for this data type - fn type_info<'t>(&self, module: &'t Module, mut type_: &'t DataTypeRef) -> CTypeInfo<'t> { - let (mut type_align, mut type_size) = (None, None); - let mut type_name = None; - loop { - match &type_ { - DataTypeRef::Atom(atom_type) => { - let native_atom = CAtom::from(*atom_type); - type_align = type_align.or_else(|| Some(native_atom.native_type_align)); - type_size = type_size.or_else(|| Some(native_atom.native_type_size)); - type_name = - type_name.or_else(|| Some(native_atom.native_type_name.to_string())); - } - DataTypeRef::Defined(data_type_id) => { - let cached = self.cache.load_type(*data_type_id).unwrap(); - type_align = type_align.or_else(|| Some(cached.type_align)); - type_size = type_size.or_else(|| Some(cached.type_size)); - let data_type_entry = module - .get_datatype(*data_type_id) - .expect("defined datatype"); - match data_type_entry.entity.variant { - DataTypeVariant::Struct { .. } => { - type_name = type_name - .or_else(|| Some(format!("struct {}", data_type_entry.name.name))) - } - DataTypeVariant::Enum { .. } => { - type_name = type_name.or_else(|| { - Some(format!( - "{} /* (enum ___{}) */", - data_type_entry.name.name, data_type_entry.name.name - )) - }) - } - DataTypeVariant::Alias(ref a) => { - type_name = - type_name.or_else(|| Some(data_type_entry.name.name.to_string())); - type_ = &a.to; - continue; - } - }; - } - } - break; - } - CTypeInfo { - type_name: type_name.unwrap(), - type_align: type_align.unwrap(), - type_size: type_size.unwrap(), - leaf_data_type_ref: type_, - } + Self { target, w } } // Return `true` if the type is an atom, an emum, or an alias to one of these @@ -187,4 +116,17 @@ impl CGenerator { type_ } } + + pub fn type_name<'t>(&self, module: &'t Module, type_: &'t DataTypeRef) -> &'t str { + match type_ { + DataTypeRef::Atom(a) => CAtom::from(*a).native_type_name, + DataTypeRef::Defined(id) => { + &module + .get_datatype(*id) + .expect("alias has valid pointee") + .name + .name + } + } + } } diff --git a/lucet-idl/src/c/struct.rs b/lucet-idl/src/c/struct.rs index be7da9eb7..6eaff7592 100644 --- a/lucet-idl/src/c/struct.rs +++ b/lucet-idl/src/c/struct.rs @@ -4,69 +4,37 @@ use std::cmp; pub fn generate( gen: &mut CGenerator, module: &Module, - data_type_entry: &Named, + dt: &Named, struct_: &StructDataType, ) -> Result<(), IDLError> { + let dtname = &dt.name.name; gen.w - .write_line(format!("struct {} {{", data_type_entry.name.name).as_bytes())?; + .write_line(format!("struct {} {{", dtname).as_bytes())?; let mut w_block = gen.w.new_block(); let mut offset: usize = 0; - let mut first_member_align = 0; - let mut members_offsets = vec![]; - for named_member in struct_.members.iter() { - let type_info = gen.type_info(module, &named_member.type_); - let type_align = type_info.type_align; - let type_size = type_info.type_size; - let padding = (type_align - 1) - ((offset + (type_align - 1)) % type_align); - if padding > 0 { - w_block.write_line( - format!("uint8_t ___pad{}_{}[{}];", type_align, offset, padding).as_bytes(), - )?; - offset += padding; - } - members_offsets.push(offset); + for member in struct_.members.iter() { w_block.indent()?; - w_block.write(type_info.type_name.as_bytes())?; + w_block.write(gen.type_name(module, &member.type_).as_bytes())?; w_block.space()?; - w_block.write(named_member.name.as_bytes())?; + w_block.write(member.name.as_bytes())?; w_block.write(b";")?; w_block.eol()?; - offset += type_size; - first_member_align = cmp::max(first_member_align, type_align); + offset += member.repr_size; } gen.w.write_line(b"};")?; gen.w.eob()?; - // cache the total structure size, as well as its alignment, which is equal - // to the alignment of the first member of that structure - let struct_align = first_member_align; let struct_size = offset; - let cached = gen.cache.store_type( - data_type_entry.id, - CachedTypeEntry { - type_size: struct_size, - type_align: struct_align, - members: vec![], - }, - ); - - // Cache members offsets - cached.store_members( - members_offsets - .iter() - .map(|&offset| CachedStructMemberEntry { offset }) - .collect::>(), - ); // Add assertions to check that the target platform matches the expected alignment // Also add a macro definition for the structure size // Skip the first member, as it will always be at the beginning of the structure - for (i, named_member) in struct_.members.iter().enumerate().skip(1) { + for (i, member) in struct_.members.iter().enumerate().skip(1) { gen.w.write_line( format!( "_Static_assert(offsetof(struct {}, {}) == {}, \"unexpected offset\");", - data_type_entry.name.name, named_member.name, members_offsets[i] + dtname, member.name, member.offset ) .as_bytes(), )?; @@ -74,12 +42,12 @@ pub fn generate( gen.w.write_line( format!( "_Static_assert(sizeof(struct {}) == {}, \"unexpected structure size\");", - data_type_entry.name.name, struct_size + dtname, struct_size ) .as_bytes(), )?; gen.w.eob()?; - macros::define(gen, "BYTES", &data_type_entry.name.name, struct_size)?; + macros::define(gen, "BYTES", dtname, struct_size)?; gen.w.eob()?; Ok(()) diff --git a/lucet-idl/src/module/builder.rs b/lucet-idl/src/module/builder.rs index d7e66ba05..f7ccc2e44 100644 --- a/lucet-idl/src/module/builder.rs +++ b/lucet-idl/src/module/builder.rs @@ -149,7 +149,7 @@ impl DataTypeModuleBuilder { // No recursion to do on the dfs. if !finalized_types.contains_key(&id) { // x86_64 ABI says enum is 32 bits wide - let repr_size = atom_repr_size(&AtomType::U32); + let repr_size = AtomType::U32.repr_size(); finalized_types.insert( id, DataType { @@ -201,17 +201,7 @@ fn datatype_repr_size( finalized_types: &HashMap, ) -> Option { Some(match datatype_ref { - DataTypeRef::Atom(a) => atom_repr_size(a), + DataTypeRef::Atom(a) => a.repr_size(), DataTypeRef::Defined(ref member_ident) => finalized_types.get(member_ident)?.repr_size, }) } - -fn atom_repr_size(atom_type: &AtomType) -> usize { - match atom_type { - AtomType::Bool => 1, - AtomType::U8 | AtomType::I8 => 1, - AtomType::U16 | AtomType::I16 => 2, - AtomType::U32 | AtomType::I32 | AtomType::F32 => 4, - AtomType::U64 | AtomType::I64 | AtomType::F64 => 8, - } -} diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index 6525a0f95..6e17eedc6 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -15,6 +15,18 @@ pub enum AtomType { F64, } +impl AtomType { + pub fn repr_size(&self) -> usize { + match self { + AtomType::Bool => 1, + AtomType::U8 | AtomType::I8 => 1, + AtomType::U16 | AtomType::I16 => 2, + AtomType::U32 | AtomType::I32 | AtomType::F32 => 4, + AtomType::U64 | AtomType::I64 | AtomType::F64 => 8, + } + } +} + #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] pub struct Location { pub line: usize, From b6c69be8e410639d9dcedef4b8476e88c95557bd Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 15 May 2019 13:51:52 -0700 Subject: [PATCH 210/512] lucet-idl: fix alignment calcs, generate rust tests that check alignment unfortunately i used a crate to test alignment, and therefore lucet-idl-test downloads and compiles it in the tight loop! ill fix that next --- lucet-idl/lucet-idl-test/src/compile.rs | 41 +++++++----- lucet-idl/lucet-idl-test/src/lib.rs | 4 +- lucet-idl/src/c/struct.rs | 10 +-- lucet-idl/src/module/builder.rs | 49 ++++++++++---- lucet-idl/src/rust/mod.rs | 88 +++++++++++++++++++------ lucet-idl/tests/example.rs | 37 +++++++---- 6 files changed, 160 insertions(+), 69 deletions(-) diff --git a/lucet-idl/lucet-idl-test/src/compile.rs b/lucet-idl/lucet-idl-test/src/compile.rs index ebadafc40..065023a3e 100644 --- a/lucet-idl/lucet-idl-test/src/compile.rs +++ b/lucet-idl/lucet-idl-test/src/compile.rs @@ -1,5 +1,6 @@ use lucet_idl::{codegen, Backend, Config, Package, Target}; -use std::fs::File; +use std::fs::{create_dir, File}; +use std::io::Write; use std::process::Command; use tempfile::TempDir; @@ -11,8 +12,26 @@ pub fn rust_codegen(package: &Package) { let tempdir = TempDir::new().expect("create tempdir"); - let gen_file = tempdir.path().join("out.rs"); + create_dir(tempdir.path().join("src")).expect("create src"); + let gen_file = tempdir.path().join("src").join("lib.rs"); + let mut cargo_toml = + File::create(tempdir.path().join("Cargo.toml")).expect("create cargo.toml"); + cargo_toml + .write_all( + " +[package] +name = \"test\" +version = \"0.1.0\" +edition = \"2018\" +[lib] +crate-type=[\"rlib\"] +[dependencies] +memoffset=\"*\"" + .as_bytes(), + ) + .unwrap(); + drop(cargo_toml); codegen( package, &config, @@ -20,14 +39,11 @@ pub fn rust_codegen(package: &Package) { ) .expect("lucet_idl codegen"); - let cmd_rustc = Command::new("rustc") - .arg(gen_file.clone()) - .arg("--test") - .arg("--allow=dead_code") - .arg("-o") - .arg(tempdir.path().join("example")) + let cmd_rustc = Command::new("cargo") + .arg("test") + .current_dir(tempdir.path()) .status() - .expect("run rustc"); + .expect("run cargo test"); if !cmd_rustc.success() { Command::new("cat") @@ -36,13 +52,6 @@ pub fn rust_codegen(package: &Package) { .expect("debug output"); } assert!(cmd_rustc.success(), "failure to compile generated code"); - - /* - let cmd_run = Command::new(tempdir.path().join("example")) - .status() - .expect("run generated code"); - assert!(cmd_run.success(), "failure to run generated code"); - */ } pub fn c_codegen(package: &Package) { diff --git a/lucet-idl/lucet-idl-test/src/lib.rs b/lucet-idl/lucet-idl-test/src/lib.rs index 3f065c72d..cf4903580 100644 --- a/lucet-idl/lucet-idl-test/src/lib.rs +++ b/lucet-idl/lucet-idl-test/src/lib.rs @@ -9,14 +9,14 @@ mod tests { use proptest::prelude::*; proptest! { - #[test] + //#[test] fn generate_and_rust(spec in Spec::strat(20)) { let rendered = spec.render_idl(); let pkg = parse_package(&rendered).unwrap(); compile::rust_codegen(&pkg); } - //#[test] + #[test] fn generate_and_c(spec in Spec::strat(20)) { let rendered = spec.render_idl(); let pkg = parse_package(&rendered).unwrap(); diff --git a/lucet-idl/src/c/struct.rs b/lucet-idl/src/c/struct.rs index 6eaff7592..42e1fc343 100644 --- a/lucet-idl/src/c/struct.rs +++ b/lucet-idl/src/c/struct.rs @@ -1,5 +1,4 @@ use super::*; -use std::cmp; pub fn generate( gen: &mut CGenerator, @@ -11,7 +10,6 @@ pub fn generate( gen.w .write_line(format!("struct {} {{", dtname).as_bytes())?; let mut w_block = gen.w.new_block(); - let mut offset: usize = 0; for member in struct_.members.iter() { w_block.indent()?; w_block.write(gen.type_name(module, &member.type_).as_bytes())?; @@ -19,14 +17,10 @@ pub fn generate( w_block.write(member.name.as_bytes())?; w_block.write(b";")?; w_block.eol()?; - - offset += member.repr_size; } gen.w.write_line(b"};")?; gen.w.eob()?; - let struct_size = offset; - // Add assertions to check that the target platform matches the expected alignment // Also add a macro definition for the structure size // Skip the first member, as it will always be at the beginning of the structure @@ -39,10 +33,12 @@ pub fn generate( .as_bytes(), )?; } + + let struct_size = dt.entity.repr_size; gen.w.write_line( format!( "_Static_assert(sizeof(struct {}) == {}, \"unexpected structure size\");", - dtname, struct_size + dtname, struct_size, ) .as_bytes(), )?; diff --git a/lucet-idl/src/module/builder.rs b/lucet-idl/src/module/builder.rs index f7ccc2e44..44b5208fd 100644 --- a/lucet-idl/src/module/builder.rs +++ b/lucet-idl/src/module/builder.rs @@ -78,6 +78,7 @@ impl DataTypeModuleBuilder { } visited[id.0] = true; let dt = self.data_types.get(&id).expect("data type IR is defined"); + match &dt.variant { VariantIR::Struct(ref s) => { // First, iterate down the member to ensure this is finite, and fill in type @@ -95,12 +96,7 @@ impl DataTypeModuleBuilder { let repr_size = datatype_repr_size(&mem.type_, finalized_types) .expect("datatype is defined by prior dfs_walk"); - if let Some(prev_elem) = members.last() { - let prev_elem_size = prev_elem.repr_size; - let padding = (prev_elem_size - 1) - - ((offset + (prev_elem_size - 1)) % prev_elem_size); - offset += padding; - } + offset = align_to(offset, repr_size); members.push(StructMember { type_: mem.type_.clone(), @@ -115,15 +111,14 @@ impl DataTypeModuleBuilder { // Struct will be aligned to the size of the first element. Structs always have // at least one element. let first_elem_size = members[0].repr_size; - let end_padding = (first_elem_size - 1) - - ((offset + (first_elem_size - 1)) % first_elem_size); + let repr_size = align_to(offset, first_elem_size); finalized_types.insert( id, DataType { variant: DataTypeVariant::Struct(StructDataType { members }), attrs: dt.attrs.clone(), - repr_size: offset + end_padding, + repr_size, }, ); } @@ -200,8 +195,40 @@ fn datatype_repr_size( datatype_ref: &DataTypeRef, finalized_types: &HashMap, ) -> Option { - Some(match datatype_ref { + let r = match datatype_ref { DataTypeRef::Atom(a) => a.repr_size(), DataTypeRef::Defined(ref member_ident) => finalized_types.get(member_ident)?.repr_size, - }) + }; + assert!(r > 0); + Some(r) +} +fn align_to(offs: usize, alignment: usize) -> usize { + offs + alignment - 1 - ((offs + alignment - 1) % alignment) +} + +#[cfg(test)] +mod align_test { + use super::align_to; + #[test] + fn align_test() { + assert_eq!(0, align_to(0, 1)); + assert_eq!(0, align_to(0, 2)); + assert_eq!(0, align_to(0, 4)); + assert_eq!(0, align_to(0, 8)); + + assert_eq!(1, align_to(1, 1)); + assert_eq!(2, align_to(1, 2)); + assert_eq!(4, align_to(1, 4)); + assert_eq!(8, align_to(1, 8)); + + assert_eq!(2, align_to(2, 1)); + assert_eq!(2, align_to(2, 2)); + assert_eq!(4, align_to(2, 4)); + assert_eq!(8, align_to(2, 8)); + + assert_eq!(5, align_to(5, 1)); + assert_eq!(6, align_to(5, 2)); + assert_eq!(8, align_to(5, 4)); + assert_eq!(8, align_to(5, 8)); + } } diff --git a/lucet-idl/src/rust/mod.rs b/lucet-idl/src/rust/mod.rs index 6fce29f94..0389b3125 100644 --- a/lucet-idl/src/rust/mod.rs +++ b/lucet-idl/src/rust/mod.rs @@ -42,9 +42,9 @@ impl RustGenerator { } } - fn define_name(&mut self, data_type_entry: &Named) -> String { - let typename = data_type_entry.name.name.to_camel_case(); - self.defined.insert(data_type_entry.id, typename.clone()); + fn define_name(&mut self, dt: &Named) -> String { + let typename = dt.name.name.to_camel_case(); + self.defined.insert(dt.id, typename.clone()); typename } @@ -74,41 +74,44 @@ impl RustGenerator { } impl Generator for RustGenerator { - fn gen_type_header( - &mut self, - _module: &Module, - data_type_entry: &Named, - ) -> Result<(), IDLError> { - self.w.eob()?.writeln(format!( - "/// {}: {:?}", - data_type_entry.name.name, data_type_entry - ))?; + fn gen_type_header(&mut self, _module: &Module, dt: &Named) -> Result<(), IDLError> { + self.w + .eob()? + .writeln(format!("/// {}: {:?}", dt.name.name, dt))?; Ok(()) } fn gen_alias( &mut self, module: &Module, - data_type_entry: &Named, + dt: &Named, alias: &AliasDataType, ) -> Result<(), IDLError> { - let typename = self.define_name(data_type_entry); + let typename = self.define_name(dt); let pointee_name = self.get_defined_typename(&alias.to); self.w .writeln(format!("pub type {} = {};", typename, pointee_name))? .eob()?; + + gen_testcase(&mut self.w, &dt.name.name.to_snake_case(), |w| { + w.writeln(format!( + "assert_eq!({}, ::std::mem::size_of::());", + dt.entity.repr_size, typename + ))?; + Ok(()) + })?; + Ok(()) } fn gen_struct( &mut self, module: &Module, - data_type_entry: &Named, + dt: &Named, struct_: &StructDataType, ) -> Result<(), IDLError> { - let typename = data_type_entry.name.name.to_camel_case(); - self.defined.insert(data_type_entry.id, typename.clone()); + let typename = self.define_name(dt); self.w .writeln("#[repr(C)]")? @@ -124,6 +127,22 @@ impl Generator for RustGenerator { } self.w.writeln("}")?.eob()?; + + gen_testcase(&mut self.w, &dt.name.name.to_snake_case(), |w| { + w.writeln(format!( + "assert_eq!({}, ::std::mem::size_of::());", + dt.entity.repr_size, typename + ))?; + + for m in struct_.members.iter() { + w.writeln(format!( + "assert_eq!({}, offset_of!(super::{}, {}));", + m.offset, typename, m.name, + ))?; + } + Ok(()) + })?; + Ok(()) } @@ -132,11 +151,10 @@ impl Generator for RustGenerator { fn gen_enum( &mut self, module: &Module, - data_type_entry: &Named, + dt: &Named, enum_: &EnumDataType, ) -> Result<(), IDLError> { - let typename = data_type_entry.name.name.to_camel_case(); - self.defined.insert(data_type_entry.id, typename.clone()); + let typename = self.define_name(dt); self.w .writeln("#[repr(C)]")? @@ -149,6 +167,15 @@ impl Generator for RustGenerator { } self.w.writeln("}")?.eob()?; + + gen_testcase(&mut self.w, &dt.name.name.to_snake_case(), |w| { + w.writeln(format!( + "assert_eq!({}, ::std::mem::size_of::());", + dt.entity.repr_size, typename + ))?; + Ok(()) + })?; + Ok(()) } @@ -180,6 +207,7 @@ impl Generator for RustGenerator { self.w .writeln("#[no_mangle]")? + .writeln("#[allow(unused_variables)]")? .writeln(format!("pub fn {}({}) -> {} {{", name, args, rets))?; let mut w = self.w.new_block(); @@ -190,3 +218,23 @@ impl Generator for RustGenerator { Ok(()) } } + +fn gen_testcase(w: &mut PrettyWriter, name: &str, f: F) -> Result<(), IDLError> +where + F: FnOnce(&mut PrettyWriter) -> Result<(), IDLError>, +{ + w.writeln("#[cfg(test)]")?; + w.writeln(format!("mod {} {{", name))?; + let mut ww = w.new_block(); + ww.writeln("#[allow(unused_imports)]")?; + ww.writeln("use ::memoffset::offset_of;")?; + ww.writeln("#[test]")?; + ww.writeln("fn test() {")?; + let mut www = ww.new_block(); + f(&mut www)?; + ww.writeln("}")?; + ww.eob()?; + w.writeln("}")?; + w.eob()?; + Ok(()) +} diff --git a/lucet-idl/tests/example.rs b/lucet-idl/tests/example.rs index 16fd69e7c..534582e1c 100644 --- a/lucet-idl/tests/example.rs +++ b/lucet-idl/tests/example.rs @@ -1,5 +1,5 @@ use lucet_idl; -use std::fs::File; +use std::fs::{create_dir, File}; use std::io::prelude::*; use std::process::Command; use tempfile::TempDir; @@ -58,7 +58,26 @@ fn compile_and_run_rust() { let tempdir = TempDir::new().expect("create tempdir"); - let gen_file = tempdir.path().join("out.rs"); + create_dir(tempdir.path().join("src")).expect("create src"); + let gen_file = tempdir.path().join("src").join("lib.rs"); + + let mut cargo_toml = + File::create(tempdir.path().join("Cargo.toml")).expect("create cargo.toml"); + cargo_toml + .write_all( + " +[package] +name = \"test\" +version = \"0.1.0\" +edition = \"2018\" +[lib] +crate-type=[\"rlib\"] +[dependencies] +memoffset=\"*\"" + .as_bytes(), + ) + .unwrap(); + drop(cargo_toml); lucet_idl::run( &config, @@ -67,18 +86,10 @@ fn compile_and_run_rust() { ) .expect("run lucet_idl"); - let cmd_rustc = Command::new("rustc") - .arg(gen_file.clone()) - .arg("--test") - .arg("--allow=dead_code") - .arg("-o") - .arg(tempdir.path().join("example")) + let cmd_rustc = Command::new("cargo") + .arg("test") + .current_dir(tempdir.path()) .status() .expect("run rustcc"); assert!(cmd_rustc.success(), "failure to compile generated code"); - - let cmd_run = Command::new(tempdir.path().join("example")) - .status() - .expect("run generated code"); - assert!(cmd_run.success(), "failure to run generated code"); } From f412becc183baafa4fd3d2a5ef87d07f2bfe2232 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 15 May 2019 15:20:10 -0700 Subject: [PATCH 211/512] lucet-idl: don't need the majority of this prelude --- lucet-idl/src/c/prelude.rs | 67 +------------------------------------- 1 file changed, 1 insertion(+), 66 deletions(-) diff --git a/lucet-idl/src/c/prelude.rs b/lucet-idl/src/c/prelude.rs index b1bcd3306..b2a923ff7 100644 --- a/lucet-idl/src/c/prelude.rs +++ b/lucet-idl/src/c/prelude.rs @@ -3,74 +3,9 @@ use super::*; pub fn generate(pretty_writer: &mut PrettyWriter, target: Target) -> Result<(), IDLError> { let prelude = r" #include -#include #include -#include #include -#include "; - - for line in prelude.lines() { - pretty_writer.write_line(line.as_ref())?; - } - pretty_writer.eob()?; - - let prelude = r" -#ifndef ___REFERENCE_COMPATIBLE_ALIGNMENT -# if defined(__amd64) || defined(__amd64__) || defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) || \ - defined(__EMSCRIPTEN__) -# define ___REFERENCE_COMPATIBLE_ALIGNMENT -# endif -#endif - -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -# define ___le_uint16_t(X) (X) -# define ___le_uint32_t(X) (X) -# define ___le_uint64_t(X) (X) -# define ___le_int16_t(X) (X) -# define ___le_int32_t(X) (X) -# define ___le_int64_t(X) (X) -# define ___le_float(X) (X) -# define ___le_double(X) (X) -#else -# define ___bswap16(X) __builtin_bswap16(X) -# define ___bswap32(X) __builtin_bswap32(X) -# define ___bswap64(X) __builtin_bswap64(X) - -# define ___le_uint16_t(X) ___bswap16(X) -# define ___le_uint32_t(X) ___bswap32(X) -# define ___le_uint64_t(X) ___bswap64(X) -# define ___le_int16_t(X) ((int16_t) ___bswap16((uint16_t) (X))) -# define ___le_int32_t(X) ((int32_t) ___bswap32((uint32_t) (X))) -# define ___le_int64_t(X) ((int64_t) ___bswap64((uint64_t) (X))) - -static inline float ___le_float(float X) { - uint32_t X_; float Xf; memcpy(&X_, &X, sizeof X_); - X_ = ___le_uint32_t(X_); memcpy(&Xf, &X_, sizeof Xf); - return Xf; -} - -static inline double ___le_double(double X) { - uint64_t X_; double Xd; memcpy(&X_, &X, sizeof X_); - X_ = ___le_uint64_t(X_); memcpy(&Xd, &X_, sizeof Xd); - return Xd; -} -#endif - -#if !defined(ZERO_NATIVE_POINTERS) && defined(___REFERENCE_COMPATIBLE_ALIGNMENT) && \ - __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -# define ___REFERENCE_COMPATIBLE_ENCODING -#endif - -#define BYTES_PTR 8 - -#if UINTPTR_MAX > 0xFFFFFFFFULL -# define ___POINTER_PAD(O) -#elif UINTPTR_MAX > 0xFFFFUL -# define ___POINTER_PAD(O) uint8_t ___ptrpad_ ## O ## _[4]; -#else -# define ___POINTER_PAD(O) uint8_t ___ptrpad_ ## O ## _[6]; -#endif -"; +#include "; for line in prelude.lines() { pretty_writer.write_line(line.as_ref())?; } From 8096e7f1e7ba0039cc84ad6d50d420278b49ae91 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 15 May 2019 15:34:27 -0700 Subject: [PATCH 212/512] lucet-idl: move C generator to be all one file --- lucet-idl/src/c.rs | 230 +++++++++++++++++++++++++ lucet-idl/src/c/alias.rs | 26 --- lucet-idl/src/c/cache.rs | 45 ----- lucet-idl/src/c/catom.rs | 87 ---------- lucet-idl/src/c/enum.rs | 49 ------ lucet-idl/src/c/macros.rs | 53 ------ lucet-idl/src/c/mod.rs | 132 -------------- lucet-idl/src/c/prelude.rs | 14 -- lucet-idl/src/c/struct.rs | 50 ------ lucet-idl/src/{rust/mod.rs => rust.rs} | 0 10 files changed, 230 insertions(+), 456 deletions(-) create mode 100644 lucet-idl/src/c.rs delete mode 100644 lucet-idl/src/c/alias.rs delete mode 100644 lucet-idl/src/c/cache.rs delete mode 100644 lucet-idl/src/c/catom.rs delete mode 100644 lucet-idl/src/c/enum.rs delete mode 100644 lucet-idl/src/c/macros.rs delete mode 100644 lucet-idl/src/c/mod.rs delete mode 100644 lucet-idl/src/c/prelude.rs delete mode 100644 lucet-idl/src/c/struct.rs rename lucet-idl/src/{rust/mod.rs => rust.rs} (100%) diff --git a/lucet-idl/src/c.rs b/lucet-idl/src/c.rs new file mode 100644 index 000000000..8a0bc98eb --- /dev/null +++ b/lucet-idl/src/c.rs @@ -0,0 +1,230 @@ +#![allow(dead_code)] +#![allow(unused_variables)] + +use crate::error::IDLError; +use crate::generator::Generator; +use crate::module::Module; +use crate::pretty_writer::PrettyWriter; +use crate::target::Target; +use crate::types::{ + AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, FuncDecl, Named, + StructDataType, +}; +use std::io::prelude::*; + +/// Generator for the C backend +pub struct CGenerator { + pub target: Target, + pub w: PrettyWriter, +} + +impl Generator for CGenerator { + fn gen_type_header(&mut self, _module: &Module, dt: &Named) -> Result<(), IDLError> { + self.w + .eob()? + .writeln(format!("// ---------- {} ----------", dt.name.name))? + .eob()?; + Ok(()) + } + + // The most important thing in alias generation is to cache the size + // and alignment rules of what it ultimately points to + fn gen_alias( + &mut self, + module: &Module, + dt: &Named, + alias: &AliasDataType, + ) -> Result<(), IDLError> { + let dtname = &dt.name.name; + self.w.indent()?; + self.w.writeln(format!( + "typedef {} {};", + self.type_name(module, &alias.to), + dtname + ))?; + self.w.eob()?; + + // Add an assertion to check that resolved size is the one we computed + self.w.writeln(format!( + "_Static_assert(sizeof({}) == {}, \"unexpected alias size\");", + dtname, dt.entity.repr_size + ))?; + self.w.eob()?; + + Ok(()) + } + + fn gen_struct( + &mut self, + module: &Module, + dt: &Named, + struct_: &StructDataType, + ) -> Result<(), IDLError> { + let dtname = &dt.name.name; + self.w.writeln(format!("struct {} {{", dtname))?; + let mut w_block = self.w.new_block(); + for member in struct_.members.iter() { + w_block.indent()?; + w_block.write(self.type_name(module, &member.type_).as_bytes())?; + w_block.space()?; + w_block.write(member.name.as_bytes())?; + w_block.write(b";")?; + w_block.eol()?; + } + self.w.writeln("};")?; + self.w.eob()?; + + // Add assertions to check that the target platform matches the expected alignment + // Also add a macro definition for the structure size + // Skip the first member, as it will always be at the beginning of the structure + for (i, member) in struct_.members.iter().enumerate().skip(1) { + self.w.writeln(format!( + "_Static_assert(offsetof(struct {}, {}) == {}, \"unexpected offset\");", + dtname, member.name, member.offset + ))?; + } + + let struct_size = dt.entity.repr_size; + self.w.writeln(format!( + "_Static_assert(sizeof(struct {}) == {}, \"unexpected structure size\");", + dtname, struct_size, + ))?; + self.w.eob()?; + + Ok(()) + } + + // Enums generate both a specific typedef, and a traditional C-style enum + // The typedef is required to use a native type which is consistent across all architectures + fn gen_enum( + &mut self, + module: &Module, + dt: &Named, + enum_: &EnumDataType, + ) -> Result<(), IDLError> { + let type_size = dt.entity.repr_size; + self.w.writeln(format!( + "typedef {} {}; // enum, should be in the [0...{}] range", + atom_type_name(&AtomType::U32), + dt.name.name, + enum_.members.len() - 1 + ))?; + self.w.writeln(format!("enum ___{} {{", dt.name.name))?; + let mut pretty_writer_i1 = self.w.new_block(); + for (i, named_member) in enum_.members.iter().enumerate() { + pretty_writer_i1.writeln(format!( + "{}, // {}", + macro_for(&dt.name.name, &named_member.name), + i + ))?; + } + self.w.writeln("};")?; + self.w.eob()?; + self.w.writeln(format!( + "_Static_assert(sizeof({}) == {}, \"unexpected enumeration size\");", + dt.name.name, type_size + ))?; + self.w.eob()?; + Ok(()) + } + + fn gen_function( + &mut self, + _module: &Module, + _func_decl_entry: &Named, + ) -> Result<(), IDLError> { + // UNIMPLEMENTED!! + Ok(()) + } +} + +impl CGenerator { + pub fn new(target: Target, w: Box) -> Self { + let mut w = PrettyWriter::new(w); + let prelude = r" +#include +#include +#include +#include "; + for line in prelude.lines() { + w.write_line(line.as_ref()).unwrap(); + } + w.eob().unwrap(); + Self { target, w } + } + + // Return `true` if the type is an atom, an emum, or an alias to one of these + pub fn is_type_eventually_an_atom_or_enum(&self, module: &Module, type_: &DataTypeRef) -> bool { + let inner_type = match type_ { + DataTypeRef::Atom(_) => return true, + DataTypeRef::Defined(inner_type) => inner_type, + }; + let inner_data_type_entry = module.get_datatype(*inner_type).expect("defined datatype"); + match inner_data_type_entry.entity.variant { + DataTypeVariant::Struct { .. } => false, + DataTypeVariant::Enum { .. } => true, + DataTypeVariant::Alias(ref a) => self.is_type_eventually_an_atom_or_enum(module, &a.to), + } + } + + /// Return the type refererence, with aliases being resolved + pub fn unalias<'t>(&self, module: &'t Module, type_: &'t DataTypeRef) -> &'t DataTypeRef { + let inner_type = match type_ { + DataTypeRef::Atom(_) => return type_, + DataTypeRef::Defined(inner_type) => inner_type, + }; + let inner_data_type_entry = module.get_datatype(*inner_type).expect("defined datatype"); + if let DataTypeVariant::Alias(ref a) = inner_data_type_entry.entity.variant { + self.unalias(module, &a.to) + } else { + type_ + } + } + + pub fn type_name<'t>(&self, module: &'t Module, type_: &'t DataTypeRef) -> &'t str { + match type_ { + DataTypeRef::Atom(a) => atom_type_name(a), + DataTypeRef::Defined(id) => { + &module + .get_datatype(*id) + .expect("alias has valid pointee") + .name + .name + } + } + } +} + +fn atom_type_name(atom_type: &AtomType) -> &'static str { + match atom_type { + AtomType::Bool => "bool", + AtomType::U8 => "uint8_t", + AtomType::U16 => "uint16_t", + AtomType::U32 => "uint32_t", + AtomType::U64 => "uint64_t", + AtomType::I8 => "int8_t", + AtomType::I16 => "int16_t", + AtomType::I32 => "int32_t", + AtomType::I64 => "int64_t", + AtomType::F32 => "float", + AtomType::F64 => "double", + } +} + +fn macro_for(prefix: &str, name: &str) -> String { + let mut macro_name = String::new(); + macro_name.push_str(&prefix.to_uppercase()); + macro_name.push('_'); + let mut previous_was_uppercase = name.chars().nth(0).expect("Empty name").is_uppercase(); + for c in name.chars() { + let is_uppercase = c.is_uppercase(); + if is_uppercase != previous_was_uppercase { + macro_name.push('_'); + } + for uc in c.to_uppercase() { + macro_name.push(uc); + } + previous_was_uppercase = is_uppercase; + } + macro_name +} diff --git a/lucet-idl/src/c/alias.rs b/lucet-idl/src/c/alias.rs deleted file mode 100644 index 0b70efe85..000000000 --- a/lucet-idl/src/c/alias.rs +++ /dev/null @@ -1,26 +0,0 @@ -use super::*; - -pub fn generate( - gen: &mut CGenerator, - module: &Module, - dt: &Named, - alias: &AliasDataType, -) -> Result<(), IDLError> { - let dtname = &dt.name.name; - gen.w.indent()?; - gen.w.writeln(format!( - "typedef {} {};", - gen.type_name(module, &alias.to), - dtname - ))?; - gen.w.eob()?; - - // Add an assertion to check that resolved size is the one we computed - gen.w.writeln(format!( - "_Static_assert(sizeof({}) == {}, \"unexpected alias size\");", - dtname, dt.entity.repr_size - ))?; - gen.w.eob()?; - - Ok(()) -} diff --git a/lucet-idl/src/c/cache.rs b/lucet-idl/src/c/cache.rs deleted file mode 100644 index 51814cb83..000000000 --- a/lucet-idl/src/c/cache.rs +++ /dev/null @@ -1,45 +0,0 @@ -use crate::types::Ident; -use std::collections::HashMap; - -/// Cached information for a given structure member -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct CachedStructMemberEntry { - pub offset: usize, -} - -/// Cached information for a given type -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct CachedTypeEntry { - pub type_size: usize, - pub type_align: usize, - pub members: Vec, -} - -impl CachedTypeEntry { - pub fn store_members(&mut self, entries: Vec) { - self.members = entries; - } - - pub fn load_member(&self, member_id: usize) -> Option<&CachedStructMemberEntry> { - self.members.get(member_id) - } -} - -/// Cache information about a type given its id -#[derive(Clone, Debug, Default)] -pub struct Cache { - type_map: HashMap, -} - -impl Cache { - pub fn store_type(&mut self, id: Ident, entry: CachedTypeEntry) -> &mut CachedTypeEntry { - if self.type_map.insert(id, entry).is_some() { - panic!("Type {:?} had already been cached", id) - } - self.type_map.get_mut(&id).unwrap() - } - - pub fn load_type(&self, id: Ident) -> Option<&CachedTypeEntry> { - self.type_map.get(&id) - } -} diff --git a/lucet-idl/src/c/catom.rs b/lucet-idl/src/c/catom.rs deleted file mode 100644 index 1b906945f..000000000 --- a/lucet-idl/src/c/catom.rs +++ /dev/null @@ -1,87 +0,0 @@ -use crate::target::*; -use crate::types::*; - -/// Information about a C native type -pub struct CAtom { - pub atom_type: AtomType, - pub native_type_name: &'static str, -} - -impl From for CAtom { - fn from(atom_type: AtomType) -> Self { - match atom_type { - AtomType::Bool => CAtom { - atom_type, - native_type_name: "bool", - }, - AtomType::U8 => CAtom { - atom_type, - native_type_name: "uint8_t", - }, - AtomType::U16 => CAtom { - atom_type, - native_type_name: "uint16_t", - }, - AtomType::U32 => CAtom { - atom_type, - native_type_name: "uint32_t", - }, - AtomType::U64 => CAtom { - atom_type, - native_type_name: "uint64_t", - }, - AtomType::I8 => CAtom { - atom_type, - native_type_name: "int8_t", - }, - AtomType::I16 => CAtom { - atom_type, - native_type_name: "int16_t", - }, - AtomType::I32 => CAtom { - atom_type, - native_type_name: "int32_t", - }, - AtomType::I64 => CAtom { - atom_type, - native_type_name: "int64_t", - }, - AtomType::F32 => CAtom { - atom_type, - native_type_name: "float", - }, - AtomType::F64 => CAtom { - atom_type, - native_type_name: "double", - }, - } - } -} - -impl CAtom { - /// Native type used for enums - /// X86_64 ABI says its an U32, wasm32 seems to agree - pub fn enum_() -> Self { - CAtom::from(AtomType::U32) - } - - /// Return an expression to swap byte order - /// No need to swap anything if we have a single byte or if we explicitly - /// target an architecture that matches the reference target for the type - pub fn bswap(&self, _target: Target, vstr: &str) -> String { - if self.atom_type.repr_size() < 2 { - vstr.to_string() - } else { - format!("___bswap_{}({})", self.native_type_name, vstr) - } - } - - /// Return an expression to force little-endian order - pub fn little_endian(&self, target: Target, vstr: &str) -> String { - if self.atom_type.repr_size() < 2 || target.uses_reference_target_endianness() { - vstr.to_string() - } else { - format!("___le_{}({})", self.native_type_name, vstr) - } - } -} diff --git a/lucet-idl/src/c/enum.rs b/lucet-idl/src/c/enum.rs deleted file mode 100644 index 2ee335f41..000000000 --- a/lucet-idl/src/c/enum.rs +++ /dev/null @@ -1,49 +0,0 @@ -use super::*; -use crate::types::AtomType; - -// Enums generate both a specific typedef, and a traditional C-style enum -// The typedef is required to use a native type which is consistent across all architectures -pub fn generate( - gen: &mut CGenerator, - _module: &Module, - dt: &Named, - enum_: &EnumDataType, -) -> Result<(), IDLError> { - let type_size = dt.entity.repr_size; - gen.w.write_line( - format!( - "typedef {} {}; // enum, should be in the [0...{}] range", - CAtom::from(AtomType::U32).native_type_name, - dt.name.name, - enum_.members.len() - 1 - ) - .as_bytes(), - )?; - gen.w - .write_line(format!("enum ___{} {{", dt.name.name).as_bytes())?; - let mut pretty_writer_i1 = gen.w.new_block(); - for (i, named_member) in enum_.members.iter().enumerate() { - pretty_writer_i1.write_line( - format!( - "{}, // {}", - macros::macro_for(&dt.name.name, &named_member.name), - i - ) - .as_bytes(), - )?; - } - gen.w.write_line(b"};")?; - gen.w.eob()?; - gen.w.write_line( - format!( - "_Static_assert(sizeof({}) == {}, \"unexpected enumeration size\");", - dt.name.name, type_size - ) - .as_bytes(), - )?; - gen.w.eob()?; - macros::define(gen, "BYTES", &dt.name.name, type_size)?; - gen.w.eob()?; - - Ok(()) -} diff --git a/lucet-idl/src/c/macros.rs b/lucet-idl/src/c/macros.rs deleted file mode 100644 index 194a9bba8..000000000 --- a/lucet-idl/src/c/macros.rs +++ /dev/null @@ -1,53 +0,0 @@ -use super::*; - -// Return the name of a macro according to a name and a prefix - -pub fn macro_for(prefix: &str, name: &str) -> String { - let mut macro_name = String::new(); - macro_name.push_str(&prefix.to_uppercase()); - macro_name.push('_'); - let mut previous_was_uppercase = name.chars().nth(0).expect("Empty name").is_uppercase(); - for c in name.chars() { - let is_uppercase = c.is_uppercase(); - if is_uppercase != previous_was_uppercase { - macro_name.push('_'); - } - for uc in c.to_uppercase() { - macro_name.push(uc); - } - previous_was_uppercase = is_uppercase; - } - macro_name -} - -// Generate a macro definition - -pub fn define( - gen: &mut CGenerator, - prefix: &str, - name: &str, - value: V, -) -> Result<(), IDLError> { - let macro_name = macro_for(prefix, name); - gen.w - .write_line(format!("#define {} {}", macro_name, value.to_string()).as_ref())?; - Ok(()) -} - -// Return a macro name for a type reference - -pub fn macro_for_data_type_ref( - module: &Module, - prefix: &str, - data_type_ref: &DataTypeRef, -) -> String { - match data_type_ref { - DataTypeRef::Atom(atom_type) => format!("{}", atom_type.repr_size()), - DataTypeRef::Defined(data_type_id) => { - let data_type_entry = module - .get_datatype(*data_type_id) - .expect("defined datatype"); - macro_for(prefix, &data_type_entry.name.name) - } - } -} diff --git a/lucet-idl/src/c/mod.rs b/lucet-idl/src/c/mod.rs deleted file mode 100644 index fb4c63c0f..000000000 --- a/lucet-idl/src/c/mod.rs +++ /dev/null @@ -1,132 +0,0 @@ -#![allow(dead_code)] -#![allow(unused_variables)] - -mod alias; -mod catom; -mod r#enum; -mod macros; -mod prelude; -mod r#struct; - -pub(crate) use self::catom::CAtom; -use crate::error::IDLError; -use crate::generator::Generator; -use crate::module::Module; -use crate::pretty_writer::PrettyWriter; -use crate::target::Target; -use crate::types::{ - AliasDataType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, FuncDecl, Named, - StructDataType, -}; -use std::io::prelude::*; - -/// Generator for the C backend -pub struct CGenerator { - pub target: Target, - pub w: PrettyWriter, -} - -impl Generator for CGenerator { - fn gen_type_header( - &mut self, - _module: &Module, - data_type_entry: &Named, - ) -> Result<(), IDLError> { - self.w - .eob()? - .write_line( - format!("// ---------- {} ----------", data_type_entry.name.name).as_bytes(), - )? - .eob()?; - Ok(()) - } - - // The most important thing in alias generation is to cache the size - // and alignment rules of what it ultimately points to - fn gen_alias( - &mut self, - module: &Module, - data_type_entry: &Named, - alias: &AliasDataType, - ) -> Result<(), IDLError> { - alias::generate(self, module, data_type_entry, alias) - } - - fn gen_struct( - &mut self, - module: &Module, - data_type_entry: &Named, - struct_: &StructDataType, - ) -> Result<(), IDLError> { - r#struct::generate(self, module, data_type_entry, struct_) - } - - // Enums generate both a specific typedef, and a traditional C-style enum - // The typedef is required to use a native type which is consistent across all architectures - fn gen_enum( - &mut self, - module: &Module, - data_type_entry: &Named, - enum_: &EnumDataType, - ) -> Result<(), IDLError> { - r#enum::generate(self, module, data_type_entry, enum_) - } - - fn gen_function( - &mut self, - _module: &Module, - _func_decl_entry: &Named, - ) -> Result<(), IDLError> { - // UNIMPLEMENTED!! - Ok(()) - } -} - -impl CGenerator { - pub fn new(target: Target, w: Box) -> Self { - let mut w = PrettyWriter::new(w); - prelude::generate(&mut w, target.clone()).expect("write prelude"); - Self { target, w } - } - - // Return `true` if the type is an atom, an emum, or an alias to one of these - pub fn is_type_eventually_an_atom_or_enum(&self, module: &Module, type_: &DataTypeRef) -> bool { - let inner_type = match type_ { - DataTypeRef::Atom(_) => return true, - DataTypeRef::Defined(inner_type) => inner_type, - }; - let inner_data_type_entry = module.get_datatype(*inner_type).expect("defined datatype"); - match inner_data_type_entry.entity.variant { - DataTypeVariant::Struct { .. } => false, - DataTypeVariant::Enum { .. } => true, - DataTypeVariant::Alias(ref a) => self.is_type_eventually_an_atom_or_enum(module, &a.to), - } - } - - /// Return the type refererence, with aliases being resolved - pub fn unalias<'t>(&self, module: &'t Module, type_: &'t DataTypeRef) -> &'t DataTypeRef { - let inner_type = match type_ { - DataTypeRef::Atom(_) => return type_, - DataTypeRef::Defined(inner_type) => inner_type, - }; - let inner_data_type_entry = module.get_datatype(*inner_type).expect("defined datatype"); - if let DataTypeVariant::Alias(ref a) = inner_data_type_entry.entity.variant { - self.unalias(module, &a.to) - } else { - type_ - } - } - - pub fn type_name<'t>(&self, module: &'t Module, type_: &'t DataTypeRef) -> &'t str { - match type_ { - DataTypeRef::Atom(a) => CAtom::from(*a).native_type_name, - DataTypeRef::Defined(id) => { - &module - .get_datatype(*id) - .expect("alias has valid pointee") - .name - .name - } - } - } -} diff --git a/lucet-idl/src/c/prelude.rs b/lucet-idl/src/c/prelude.rs deleted file mode 100644 index b2a923ff7..000000000 --- a/lucet-idl/src/c/prelude.rs +++ /dev/null @@ -1,14 +0,0 @@ -use super::*; - -pub fn generate(pretty_writer: &mut PrettyWriter, target: Target) -> Result<(), IDLError> { - let prelude = r" -#include -#include -#include -#include "; - for line in prelude.lines() { - pretty_writer.write_line(line.as_ref())?; - } - pretty_writer.eob()?; - Ok(()) -} diff --git a/lucet-idl/src/c/struct.rs b/lucet-idl/src/c/struct.rs deleted file mode 100644 index 42e1fc343..000000000 --- a/lucet-idl/src/c/struct.rs +++ /dev/null @@ -1,50 +0,0 @@ -use super::*; - -pub fn generate( - gen: &mut CGenerator, - module: &Module, - dt: &Named, - struct_: &StructDataType, -) -> Result<(), IDLError> { - let dtname = &dt.name.name; - gen.w - .write_line(format!("struct {} {{", dtname).as_bytes())?; - let mut w_block = gen.w.new_block(); - for member in struct_.members.iter() { - w_block.indent()?; - w_block.write(gen.type_name(module, &member.type_).as_bytes())?; - w_block.space()?; - w_block.write(member.name.as_bytes())?; - w_block.write(b";")?; - w_block.eol()?; - } - gen.w.write_line(b"};")?; - gen.w.eob()?; - - // Add assertions to check that the target platform matches the expected alignment - // Also add a macro definition for the structure size - // Skip the first member, as it will always be at the beginning of the structure - for (i, member) in struct_.members.iter().enumerate().skip(1) { - gen.w.write_line( - format!( - "_Static_assert(offsetof(struct {}, {}) == {}, \"unexpected offset\");", - dtname, member.name, member.offset - ) - .as_bytes(), - )?; - } - - let struct_size = dt.entity.repr_size; - gen.w.write_line( - format!( - "_Static_assert(sizeof(struct {}) == {}, \"unexpected structure size\");", - dtname, struct_size, - ) - .as_bytes(), - )?; - gen.w.eob()?; - macros::define(gen, "BYTES", dtname, struct_size)?; - gen.w.eob()?; - - Ok(()) -} diff --git a/lucet-idl/src/rust/mod.rs b/lucet-idl/src/rust.rs similarity index 100% rename from lucet-idl/src/rust/mod.rs rename to lucet-idl/src/rust.rs From 589d1b2a09639fae6db75ac0040aa9df0b15ef99 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 15 May 2019 16:12:56 -0700 Subject: [PATCH 213/512] lucet-idl: switch rust offset properties to use bindgen-style ptr arith so we dont need to depend on memoffset and use cargo --- lucet-idl/lucet-idl-test/src/compile.rs | 32 ++++++--------------- lucet-idl/src/rust.rs | 4 +-- lucet-idl/tests/example.rs | 37 +++++++++---------------- 3 files changed, 23 insertions(+), 50 deletions(-) diff --git a/lucet-idl/lucet-idl-test/src/compile.rs b/lucet-idl/lucet-idl-test/src/compile.rs index 065023a3e..ef00dc596 100644 --- a/lucet-idl/lucet-idl-test/src/compile.rs +++ b/lucet-idl/lucet-idl-test/src/compile.rs @@ -1,5 +1,5 @@ use lucet_idl::{codegen, Backend, Config, Package, Target}; -use std::fs::{create_dir, File}; +use std::fs::File; use std::io::Write; use std::process::Command; use tempfile::TempDir; @@ -12,26 +12,8 @@ pub fn rust_codegen(package: &Package) { let tempdir = TempDir::new().expect("create tempdir"); - create_dir(tempdir.path().join("src")).expect("create src"); let gen_file = tempdir.path().join("src").join("lib.rs"); - let mut cargo_toml = - File::create(tempdir.path().join("Cargo.toml")).expect("create cargo.toml"); - cargo_toml - .write_all( - " -[package] -name = \"test\" -version = \"0.1.0\" -edition = \"2018\" -[lib] -crate-type=[\"rlib\"] -[dependencies] -memoffset=\"*\"" - .as_bytes(), - ) - .unwrap(); - drop(cargo_toml); codegen( package, &config, @@ -39,11 +21,15 @@ memoffset=\"*\"" ) .expect("lucet_idl codegen"); - let cmd_rustc = Command::new("cargo") - .arg("test") - .current_dir(tempdir.path()) + let cmd_rustc = Command::new("rustc") + .arg(gen_file.clone()) + .arg("--test") + .arg("--allow=dead_code") + .arg("-o") + .arg(tempdir.path().join("example")) .status() - .expect("run cargo test"); + .expect("run rustc"); + assert!(cmd_rustc.success(), "failure to compile generated code"); if !cmd_rustc.success() { Command::new("cat") diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index 0389b3125..716bfe98a 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -136,7 +136,7 @@ impl Generator for RustGenerator { for m in struct_.members.iter() { w.writeln(format!( - "assert_eq!({}, offset_of!(super::{}, {}));", + "assert_eq!({}, {{ let base = ::std::ptr::null::(); unsafe {{ (&(*base).{}) as *const _ as usize }} }});", m.offset, typename, m.name, ))?; } @@ -226,8 +226,6 @@ where w.writeln("#[cfg(test)]")?; w.writeln(format!("mod {} {{", name))?; let mut ww = w.new_block(); - ww.writeln("#[allow(unused_imports)]")?; - ww.writeln("use ::memoffset::offset_of;")?; ww.writeln("#[test]")?; ww.writeln("fn test() {")?; let mut www = ww.new_block(); diff --git a/lucet-idl/tests/example.rs b/lucet-idl/tests/example.rs index 534582e1c..16fd69e7c 100644 --- a/lucet-idl/tests/example.rs +++ b/lucet-idl/tests/example.rs @@ -1,5 +1,5 @@ use lucet_idl; -use std::fs::{create_dir, File}; +use std::fs::File; use std::io::prelude::*; use std::process::Command; use tempfile::TempDir; @@ -58,26 +58,7 @@ fn compile_and_run_rust() { let tempdir = TempDir::new().expect("create tempdir"); - create_dir(tempdir.path().join("src")).expect("create src"); - let gen_file = tempdir.path().join("src").join("lib.rs"); - - let mut cargo_toml = - File::create(tempdir.path().join("Cargo.toml")).expect("create cargo.toml"); - cargo_toml - .write_all( - " -[package] -name = \"test\" -version = \"0.1.0\" -edition = \"2018\" -[lib] -crate-type=[\"rlib\"] -[dependencies] -memoffset=\"*\"" - .as_bytes(), - ) - .unwrap(); - drop(cargo_toml); + let gen_file = tempdir.path().join("out.rs"); lucet_idl::run( &config, @@ -86,10 +67,18 @@ memoffset=\"*\"" ) .expect("run lucet_idl"); - let cmd_rustc = Command::new("cargo") - .arg("test") - .current_dir(tempdir.path()) + let cmd_rustc = Command::new("rustc") + .arg(gen_file.clone()) + .arg("--test") + .arg("--allow=dead_code") + .arg("-o") + .arg(tempdir.path().join("example")) .status() .expect("run rustcc"); assert!(cmd_rustc.success(), "failure to compile generated code"); + + let cmd_run = Command::new(tempdir.path().join("example")) + .status() + .expect("run generated code"); + assert!(cmd_run.success(), "failure to run generated code"); } From 22dc7cd4bce6ea0ba9e5d7d88f5428f7eb3426e1 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 15 May 2019 16:33:09 -0700 Subject: [PATCH 214/512] lucet-idl: fix c type name representation --- lucet-idl/lucet-idl-test/src/compile.rs | 1 - lucet-idl/src/c.rs | 53 ++++++++++++------------- lucet-idl/src/pretty_writer.rs | 6 --- lucet-idl/tests/example_driver.c | 2 +- 4 files changed, 27 insertions(+), 35 deletions(-) diff --git a/lucet-idl/lucet-idl-test/src/compile.rs b/lucet-idl/lucet-idl-test/src/compile.rs index ef00dc596..28a7e9eb5 100644 --- a/lucet-idl/lucet-idl-test/src/compile.rs +++ b/lucet-idl/lucet-idl-test/src/compile.rs @@ -1,6 +1,5 @@ use lucet_idl::{codegen, Backend, Config, Package, Target}; use std::fs::File; -use std::io::Write; use std::process::Command; use tempfile::TempDir; diff --git a/lucet-idl/src/c.rs b/lucet-idl/src/c.rs index 8a0bc98eb..00c98b9d5 100644 --- a/lucet-idl/src/c.rs +++ b/lucet-idl/src/c.rs @@ -35,11 +35,11 @@ impl Generator for CGenerator { dt: &Named, alias: &AliasDataType, ) -> Result<(), IDLError> { - let dtname = &dt.name.name; + let dtname = self.type_name(dt); self.w.indent()?; self.w.writeln(format!( "typedef {} {};", - self.type_name(module, &alias.to), + self.type_ref_name(module, &alias.to), dtname ))?; self.w.eob()?; @@ -60,16 +60,15 @@ impl Generator for CGenerator { dt: &Named, struct_: &StructDataType, ) -> Result<(), IDLError> { - let dtname = &dt.name.name; - self.w.writeln(format!("struct {} {{", dtname))?; + let dtname = self.type_name(dt); + self.w.writeln(format!("{} {{", dtname))?; let mut w_block = self.w.new_block(); for member in struct_.members.iter() { - w_block.indent()?; - w_block.write(self.type_name(module, &member.type_).as_bytes())?; - w_block.space()?; - w_block.write(member.name.as_bytes())?; - w_block.write(b";")?; - w_block.eol()?; + w_block.writeln(format!( + "{} {};", + self.type_ref_name(module, &member.type_), + member.name + ))?; } self.w.writeln("};")?; self.w.eob()?; @@ -79,14 +78,14 @@ impl Generator for CGenerator { // Skip the first member, as it will always be at the beginning of the structure for (i, member) in struct_.members.iter().enumerate().skip(1) { self.w.writeln(format!( - "_Static_assert(offsetof(struct {}, {}) == {}, \"unexpected offset\");", + "_Static_assert(offsetof({}, {}) == {}, \"unexpected offset\");", dtname, member.name, member.offset ))?; } let struct_size = dt.entity.repr_size; self.w.writeln(format!( - "_Static_assert(sizeof(struct {}) == {}, \"unexpected structure size\");", + "_Static_assert(sizeof({}) == {}, \"unexpected structure size\");", dtname, struct_size, ))?; self.w.eob()?; @@ -102,14 +101,9 @@ impl Generator for CGenerator { dt: &Named, enum_: &EnumDataType, ) -> Result<(), IDLError> { + let dtname = self.type_name(dt); let type_size = dt.entity.repr_size; - self.w.writeln(format!( - "typedef {} {}; // enum, should be in the [0...{}] range", - atom_type_name(&AtomType::U32), - dt.name.name, - enum_.members.len() - 1 - ))?; - self.w.writeln(format!("enum ___{} {{", dt.name.name))?; + self.w.writeln(format!("{} {{", dtname))?; let mut pretty_writer_i1 = self.w.new_block(); for (i, named_member) in enum_.members.iter().enumerate() { pretty_writer_i1.writeln(format!( @@ -122,7 +116,7 @@ impl Generator for CGenerator { self.w.eob()?; self.w.writeln(format!( "_Static_assert(sizeof({}) == {}, \"unexpected enumeration size\");", - dt.name.name, type_size + dtname, type_size ))?; self.w.eob()?; Ok(()) @@ -181,15 +175,20 @@ impl CGenerator { } } - pub fn type_name<'t>(&self, module: &'t Module, type_: &'t DataTypeRef) -> &'t str { + fn type_name(&self, dt: &Named) -> String { + match dt.entity.variant { + DataTypeVariant::Struct(_) => format!("struct {}", dt.name.name), + DataTypeVariant::Enum(_) => format!("enum {}", dt.name.name), + DataTypeVariant::Alias(_) => format!("{}", dt.name.name), + } + } + + fn type_ref_name(&self, module: &Module, type_: &DataTypeRef) -> String { match type_ { - DataTypeRef::Atom(a) => atom_type_name(a), + DataTypeRef::Atom(a) => atom_type_name(a).to_owned(), DataTypeRef::Defined(id) => { - &module - .get_datatype(*id) - .expect("alias has valid pointee") - .name - .name + let dt = &module.get_datatype(*id).expect("type_name of valid ref"); + self.type_name(dt) } } } diff --git a/lucet-idl/src/pretty_writer.rs b/lucet-idl/src/pretty_writer.rs index 45b5708f0..65828e7dc 100644 --- a/lucet-idl/src/pretty_writer.rs +++ b/lucet-idl/src/pretty_writer.rs @@ -57,12 +57,6 @@ impl PrettyWriter { Ok(self) } - /// Output a space - pub fn space(&mut self) -> Result<&mut Self, IDLError> { - self._write_all(b" ")?; - Ok(self) - } - /// Output an end of line pub fn eol(&mut self) -> Result<&mut Self, IDLError> { self._write_all(b"\n")?; diff --git a/lucet-idl/tests/example_driver.c b/lucet-idl/tests/example_driver.c index 36376ff63..626723b66 100644 --- a/lucet-idl/tests/example_driver.c +++ b/lucet-idl/tests/example_driver.c @@ -4,7 +4,7 @@ int main (int argc, char *argv[]) { - color c1 = COLOR_RED; + enum color c1 = COLOR_RED; colour c2 = COLOR_BLUE; col c3 = COLOR_GREEN; From 47915502a583c991ebb9ed77e9abf55221d59746 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 15 May 2019 16:42:26 -0700 Subject: [PATCH 215/512] lucet-idl: correct data layout alignment and repr size are distinct! --- lucet-idl/lucet-idl-test/src/compile.rs | 2 +- lucet-idl/lucet-idl-test/src/lib.rs | 2 +- .../src/{module/builder.rs => data_layout.rs} | 42 ++++++++++++------- lucet-idl/src/lib.rs | 1 + lucet-idl/src/module.rs | 10 ++--- lucet-idl/src/package.rs | 1 + lucet-idl/src/types.rs | 2 +- 7 files changed, 36 insertions(+), 24 deletions(-) rename lucet-idl/src/{module/builder.rs => data_layout.rs} (85%) diff --git a/lucet-idl/lucet-idl-test/src/compile.rs b/lucet-idl/lucet-idl-test/src/compile.rs index 28a7e9eb5..4dbc98635 100644 --- a/lucet-idl/lucet-idl-test/src/compile.rs +++ b/lucet-idl/lucet-idl-test/src/compile.rs @@ -11,7 +11,7 @@ pub fn rust_codegen(package: &Package) { let tempdir = TempDir::new().expect("create tempdir"); - let gen_file = tempdir.path().join("src").join("lib.rs"); + let gen_file = tempdir.path().join("lib.rs"); codegen( package, diff --git a/lucet-idl/lucet-idl-test/src/lib.rs b/lucet-idl/lucet-idl-test/src/lib.rs index cf4903580..dd8bb9263 100644 --- a/lucet-idl/lucet-idl-test/src/lib.rs +++ b/lucet-idl/lucet-idl-test/src/lib.rs @@ -9,7 +9,7 @@ mod tests { use proptest::prelude::*; proptest! { - //#[test] + #[test] fn generate_and_rust(spec in Spec::strat(20)) { let rendered = spec.render_idl(); let pkg = parse_package(&rendered).unwrap(); diff --git a/lucet-idl/src/module/builder.rs b/lucet-idl/src/data_layout.rs similarity index 85% rename from lucet-idl/src/module/builder.rs rename to lucet-idl/src/data_layout.rs index 44b5208fd..c928d0e41 100644 --- a/lucet-idl/src/module/builder.rs +++ b/lucet-idl/src/data_layout.rs @@ -91,27 +91,26 @@ impl DataTypeModuleBuilder { // If finalized type information has not yet been computed, we can now compute it: if !finalized_types.contains_key(&id) { let mut offset = 0; + let mut struct_align = 1; let mut members: Vec = Vec::new(); for mem in s.members.iter() { - let repr_size = datatype_repr_size(&mem.type_, finalized_types) - .expect("datatype is defined by prior dfs_walk"); + let (repr_size, align) = + datatype_repr_size_align(&mem.type_, finalized_types) + .expect("datatype is defined by prior dfs_walk"); - offset = align_to(offset, repr_size); + offset = align_to(offset, align); + struct_align = ::std::cmp::max(struct_align, align); members.push(StructMember { type_: mem.type_.clone(), name: mem.name.clone(), attrs: mem.attrs.clone(), - repr_size, offset, }); offset += repr_size; } - // Struct will be aligned to the size of the first element. Structs always have - // at least one element. - let first_elem_size = members[0].repr_size; - let repr_size = align_to(offset, first_elem_size); + let repr_size = align_to(offset, struct_align); finalized_types.insert( id, @@ -119,6 +118,7 @@ impl DataTypeModuleBuilder { variant: DataTypeVariant::Struct(StructDataType { members }), attrs: dt.attrs.clone(), repr_size, + align: struct_align, }, ); } @@ -128,7 +128,7 @@ impl DataTypeModuleBuilder { self.dfs_walk(pointee_id, visited, ordered, finalized_types)?; }; if !finalized_types.contains_key(&id) { - let repr_size = datatype_repr_size(&a.to, finalized_types) + let (repr_size, align) = datatype_repr_size_align(&a.to, finalized_types) .expect("datatype is defined by prior dfs_walk"); finalized_types.insert( id, @@ -136,6 +136,7 @@ impl DataTypeModuleBuilder { variant: DataTypeVariant::Alias(AliasDataType { to: a.to.clone() }), attrs: dt.attrs.clone(), repr_size, + align, }, ); } @@ -145,6 +146,7 @@ impl DataTypeModuleBuilder { if !finalized_types.contains_key(&id) { // x86_64 ABI says enum is 32 bits wide let repr_size = AtomType::U32.repr_size(); + let align = repr_size; finalized_types.insert( id, DataType { @@ -153,6 +155,7 @@ impl DataTypeModuleBuilder { }), attrs: dt.attrs.clone(), repr_size, + align, }, ); } @@ -191,16 +194,23 @@ impl DataTypeModuleBuilder { } } -fn datatype_repr_size( +fn datatype_repr_size_align( datatype_ref: &DataTypeRef, finalized_types: &HashMap, -) -> Option { - let r = match datatype_ref { - DataTypeRef::Atom(a) => a.repr_size(), - DataTypeRef::Defined(ref member_ident) => finalized_types.get(member_ident)?.repr_size, +) -> Option<(usize, usize)> { + let (size, align) = match datatype_ref { + DataTypeRef::Atom(a) => { + let s = a.repr_size(); + (s, s) + } + DataTypeRef::Defined(ref member_ident) => { + let t = finalized_types.get(member_ident)?; + (t.repr_size, t.align) + } }; - assert!(r > 0); - Some(r) + assert!(size > 0); + assert!(align > 0); + Some((size, align)) } fn align_to(offs: usize, alignment: usize) -> usize { offs + alignment - 1 - ((offs + alignment - 1) % alignment) diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index fa50ef875..b38187800 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -6,6 +6,7 @@ extern crate failure; mod backend; mod c; mod config; +mod data_layout; mod error; mod generator; mod lexer; diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index fee51cf09..1a538ee45 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -1,12 +1,12 @@ -mod builder; - +use crate::data_layout::{ + AliasIR, DataTypeModuleBuilder, EnumIR, StructIR, StructMemberIR, VariantIR, +}; use crate::error::ValidationError; use crate::parser::{SyntaxDecl, SyntaxRef}; use crate::types::{ Attr, DataType, DataTypeRef, EnumMember, FuncArg, FuncDecl, FuncRet, Ident, Location, Name, Named, }; -use builder::{AliasIR, DataTypeModuleBuilder, EnumIR, StructIR, StructMemberIR, VariantIR}; use std::collections::HashMap; #[derive(Debug, PartialEq, Eq, Clone)] @@ -341,20 +341,19 @@ mod tests { name: "a".to_owned(), type_: DataTypeRef::Atom(AtomType::I32), attrs: Vec::new(), - repr_size: 4, offset: 0, }, StructMember { name: "b".to_owned(), type_: DataTypeRef::Atom(AtomType::F32), attrs: Vec::new(), - repr_size: 4, offset: 4, }, ] }), attrs: Vec::new(), repr_size: 8, + align: 4, } ); } @@ -637,6 +636,7 @@ mod tests { }), attrs: Vec::new(), repr_size: 1, + align: 1, } )] .into_iter() diff --git a/lucet-idl/src/package.rs b/lucet-idl/src/package.rs index ff07a4e34..9778ad290 100644 --- a/lucet-idl/src/package.rs +++ b/lucet-idl/src/package.rs @@ -221,6 +221,7 @@ mod test { }), attrs: Vec::new(), repr_size: 1, + align: 1, } )] .into_iter() diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index 6e17eedc6..926bfa3bc 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -70,7 +70,6 @@ pub struct StructMember { pub type_: DataTypeRef, pub name: String, pub attrs: Vec, - pub repr_size: usize, pub offset: usize, } @@ -107,6 +106,7 @@ pub struct DataType { pub variant: DataTypeVariant, pub attrs: Vec, pub repr_size: usize, + pub align: usize, } #[derive(Debug, PartialEq, Eq, Clone)] From 037dbdea5a57f698de610dd03166de1f187f60cf Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 15 May 2019 17:06:21 -0700 Subject: [PATCH 216/512] lucet-idl-test: both c and rust tests pass now --- lucet-idl/lucet-idl-test/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lucet-idl/lucet-idl-test/src/lib.rs b/lucet-idl/lucet-idl-test/src/lib.rs index dd8bb9263..3f065c72d 100644 --- a/lucet-idl/lucet-idl-test/src/lib.rs +++ b/lucet-idl/lucet-idl-test/src/lib.rs @@ -16,7 +16,7 @@ mod tests { compile::rust_codegen(&pkg); } - #[test] + //#[test] fn generate_and_c(spec in Spec::strat(20)) { let rendered = spec.render_idl(); let pkg = parse_package(&rendered).unwrap(); From 9deb48b0822ca0835d8a522134e9b844e5b8704e Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 16 May 2019 14:38:29 -0700 Subject: [PATCH 217/512] lucet-idl-test: generate function decls as well --- lucet-idl/lucet-idl-test/src/compile.rs | 45 +++++++++++++++- lucet-idl/lucet-idl-test/src/lib.rs | 2 +- lucet-idl/lucet-idl-test/src/main.rs | 10 ++-- lucet-idl/lucet-idl-test/src/syntax.rs | 69 ++++++++++++++++++++++--- 4 files changed, 112 insertions(+), 14 deletions(-) diff --git a/lucet-idl/lucet-idl-test/src/compile.rs b/lucet-idl/lucet-idl-test/src/compile.rs index 4dbc98635..b35716d9b 100644 --- a/lucet-idl/lucet-idl-test/src/compile.rs +++ b/lucet-idl/lucet-idl-test/src/compile.rs @@ -1,9 +1,10 @@ use lucet_idl::{codegen, Backend, Config, Package, Target}; use std::fs::File; +use std::io::Read; use std::process::Command; use tempfile::TempDir; -pub fn rust_codegen(package: &Package) { +pub fn rust_test(package: &Package) { let config = Config { backend: Backend::Rust, target: Target::Generic, @@ -21,6 +22,7 @@ pub fn rust_codegen(package: &Package) { .expect("lucet_idl codegen"); let cmd_rustc = Command::new("rustc") + .arg("+stable") .arg(gen_file.clone()) .arg("--test") .arg("--allow=dead_code") @@ -28,7 +30,42 @@ pub fn rust_codegen(package: &Package) { .arg(tempdir.path().join("example")) .status() .expect("run rustc"); + + if !cmd_rustc.success() { + Command::new("cat") + .arg(gen_file.clone()) + .status() + .expect("debug output"); + } assert!(cmd_rustc.success(), "failure to compile generated code"); +} + +pub fn rust_wasm_codegen(package: &Package) -> Vec { + let config = Config { + backend: Backend::Rust, + target: Target::Generic, + }; + + let tempdir = TempDir::new().expect("create tempdir"); + + let gen_file = tempdir.path().join("lib.rs"); + let wasm_file = tempdir.path().join("example.wasm"); + + codegen( + package, + &config, + Box::new(File::create(gen_file.clone()).expect("create file")), + ) + .expect("lucet_idl codegen"); + + let cmd_rustc = Command::new("rustc") + .arg("+nightly") + .arg(gen_file.clone()) + .arg("--target=wasm32-unknown-wasi") + .arg("-o") + .arg(wasm_file.clone()) + .status() + .expect("run rustc"); if !cmd_rustc.success() { Command::new("cat") @@ -36,7 +73,13 @@ pub fn rust_codegen(package: &Package) { .status() .expect("debug output"); } + assert!(cmd_rustc.success(), "failure to compile generated code"); + + let mut wasm = File::open(wasm_file).expect("open wasm file"); + let mut buf = Vec::new(); + wasm.read_to_end(&mut buf).expect("read wasm file"); + buf } pub fn c_codegen(package: &Package) { diff --git a/lucet-idl/lucet-idl-test/src/lib.rs b/lucet-idl/lucet-idl-test/src/lib.rs index 3f065c72d..dd8bb9263 100644 --- a/lucet-idl/lucet-idl-test/src/lib.rs +++ b/lucet-idl/lucet-idl-test/src/lib.rs @@ -16,7 +16,7 @@ mod tests { compile::rust_codegen(&pkg); } - //#[test] + #[test] fn generate_and_c(spec in Spec::strat(20)) { let rendered = spec.render_idl(); let pkg = parse_package(&rendered).unwrap(); diff --git a/lucet-idl/lucet-idl-test/src/main.rs b/lucet-idl/lucet-idl-test/src/main.rs index 332d72dae..15e4c45b2 100644 --- a/lucet-idl/lucet-idl-test/src/main.rs +++ b/lucet-idl/lucet-idl-test/src/main.rs @@ -6,13 +6,11 @@ use proptest::test_runner::TestRunner; fn main() { let mut runner = TestRunner::default(); - let dts = prop::collection::vec(DatatypeSyntax::strat(), 0..20) - .new_tree(&mut runner) - .unwrap() - .current(); - let spec = Spec::from_decls(dts); + let spec = Spec::strat(10).new_tree(&mut runner).unwrap().current(); let rendered = spec.render_idl(); println!("{}", rendered); - let _pkg = parse_package(&rendered).expect("parse generated package"); + let pkg = parse_package(&rendered).expect("parse generated package"); + + let _wasm = lucet_idl_test::compile::rust_wasm_codegen(&pkg); } diff --git a/lucet-idl/lucet-idl-test/src/syntax.rs b/lucet-idl/lucet-idl-test/src/syntax.rs index c20ab2dc3..21248e698 100644 --- a/lucet-idl/lucet-idl-test/src/syntax.rs +++ b/lucet-idl/lucet-idl-test/src/syntax.rs @@ -198,28 +198,85 @@ impl DatatypeSyntax { } } +#[derive(Debug, Clone)] +pub struct FunctionSyntax { + args: Vec, + ret: Option, +} + +impl FunctionSyntax { + pub fn strat(max_args: usize) -> impl Strategy { + ( + prop::collection::vec(DatatypeRef::strat(), 0..max_args), + prop::option::of(DatatypeRef::strat()), + ) + .prop_map(|(args, ret)| FunctionSyntax { args, ret }) + } + + pub fn normalize(&self, highest_definition: usize) -> Self { + let args = self + .args + .iter() + .map(|a| a.normalize(highest_definition)) + .collect(); + let ret = self.ret.clone().map(|a| a.normalize(highest_definition)); + Self { args, ret } + } + + pub fn render_idl(&self, name: usize) -> String { + let mut args = String::new(); + for (ix, a) in self.args.iter().enumerate() { + args += &format!("a_{}: {}, ", ix, a.render_idl()); + } + let mut ret = String::new(); + if let Some(ref r) = self.ret { + ret += &format!("-> {}", r.render_idl()); + } + format!("fn f_{}({}){};", name, args, ret) + } +} + #[derive(Debug, Clone)] pub struct Spec { - pub decls: Vec, + pub datatype_decls: Vec, + pub function_decls: Vec, } impl Spec { pub fn strat(max_size: usize) -> impl Strategy { - prop::collection::vec(DatatypeSyntax::strat(), 1..max_size).prop_map(Self::from_decls) + ( + prop::collection::vec(DatatypeSyntax::strat(), 1..max_size), + prop::collection::vec(FunctionSyntax::strat(max_size), 1..max_size), + ) + .prop_map(|(ds, fs)| Self::from_decls(ds, fs)) } - pub fn from_decls(decls: Vec) -> Self { - let decls = decls + pub fn from_decls( + datatype_decls: Vec, + function_decls: Vec, + ) -> Self { + let datatype_decls: Vec = datatype_decls .iter() .enumerate() .map(|(ix, decl)| decl.normalize(ix)) .collect(); - Spec { decls } + let num_datatypes = datatype_decls.len(); + let function_decls = function_decls + .iter() + .map(|decl| decl.normalize(num_datatypes)) + .collect(); + Spec { + datatype_decls, + function_decls, + } } pub fn render_idl(&self) -> String { let mut s = String::new(); - for (ix, d) in self.decls.iter().enumerate() { + for (ix, d) in self.datatype_decls.iter().enumerate() { + s += &format!(" {}\n", d.render_idl(ix)); + } + for (ix, d) in self.function_decls.iter().enumerate() { s += &format!(" {}\n", d.render_idl(ix)); } format!("mod spec {{\n{}\n}}", s) From ead24b1e79185ec73f1e9ee914452922b7a1ad73 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 16 May 2019 17:50:32 -0700 Subject: [PATCH 218/512] lucet-idl: delete target, unused options, there should be 3 backends --- lucet-idl/lucet-idl-test/src/compile.rs | 6 +-- lucet-idl/src/backend.rs | 22 ++++---- lucet-idl/src/c.rs | 8 +-- lucet-idl/src/config.rs | 23 ++++----- lucet-idl/src/error.rs | 2 +- lucet-idl/src/lib.rs | 2 - lucet-idl/src/main.rs | 44 +++++++--------- lucet-idl/src/rust.rs | 27 ++-------- lucet-idl/src/target.rs | 67 ------------------------- lucet-idl/tests/example.rs | 6 +-- 10 files changed, 47 insertions(+), 160 deletions(-) delete mode 100644 lucet-idl/src/target.rs diff --git a/lucet-idl/lucet-idl-test/src/compile.rs b/lucet-idl/lucet-idl-test/src/compile.rs index b35716d9b..88dff220e 100644 --- a/lucet-idl/lucet-idl-test/src/compile.rs +++ b/lucet-idl/lucet-idl-test/src/compile.rs @@ -6,8 +6,7 @@ use tempfile::TempDir; pub fn rust_test(package: &Package) { let config = Config { - backend: Backend::Rust, - target: Target::Generic, + backend: Backend::RustHost, }; let tempdir = TempDir::new().expect("create tempdir"); @@ -42,8 +41,7 @@ pub fn rust_test(package: &Package) { pub fn rust_wasm_codegen(package: &Package) -> Vec { let config = Config { - backend: Backend::Rust, - target: Target::Generic, + backend: Backend::RustGuest, }; let tempdir = TempDir::new().expect("create tempdir"); diff --git a/lucet-idl/src/backend.rs b/lucet-idl/src/backend.rs index 5af0d5208..b238fa994 100644 --- a/lucet-idl/src/backend.rs +++ b/lucet-idl/src/backend.rs @@ -1,21 +1,17 @@ #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum Backend { - C, - Rust, + CGuest, + RustGuest, + RustHost, } -impl Default for Backend { - fn default() -> Self { - Backend::C - } -} - -impl> From for Backend { - fn from(s: T) -> Self { +impl Backend { + pub fn from_str>(s: T) -> Option { match s.as_ref() { - "c" => Backend::C, - "rust" => Backend::Rust, - _ => Backend::default(), + "c_guest" => Some(Backend::CGuest), + "rust_guest" => Some(Backend::RustGuest), + "rust_host" => Some(Backend::RustHost), + _ => None, } } } diff --git a/lucet-idl/src/c.rs b/lucet-idl/src/c.rs index 00c98b9d5..11aec6a2a 100644 --- a/lucet-idl/src/c.rs +++ b/lucet-idl/src/c.rs @@ -5,7 +5,6 @@ use crate::error::IDLError; use crate::generator::Generator; use crate::module::Module; use crate::pretty_writer::PrettyWriter; -use crate::target::Target; use crate::types::{ AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, FuncDecl, Named, StructDataType, @@ -14,7 +13,6 @@ use std::io::prelude::*; /// Generator for the C backend pub struct CGenerator { - pub target: Target, pub w: PrettyWriter, } @@ -73,8 +71,6 @@ impl Generator for CGenerator { self.w.writeln("};")?; self.w.eob()?; - // Add assertions to check that the target platform matches the expected alignment - // Also add a macro definition for the structure size // Skip the first member, as it will always be at the beginning of the structure for (i, member) in struct_.members.iter().enumerate().skip(1) { self.w.writeln(format!( @@ -133,7 +129,7 @@ impl Generator for CGenerator { } impl CGenerator { - pub fn new(target: Target, w: Box) -> Self { + pub fn new(w: Box) -> Self { let mut w = PrettyWriter::new(w); let prelude = r" #include @@ -144,7 +140,7 @@ impl CGenerator { w.write_line(line.as_ref()).unwrap(); } w.eob().unwrap(); - Self { target, w } + Self { w } } // Return `true` if the type is an atom, an emum, or an alias to one of these diff --git a/lucet-idl/src/config.rs b/lucet-idl/src/config.rs index 556a00762..5fad4ebaa 100644 --- a/lucet-idl/src/config.rs +++ b/lucet-idl/src/config.rs @@ -1,30 +1,27 @@ -use super::backend::Backend; -use super::target::Target; +use crate::backend::Backend; use crate::c::CGenerator; +use crate::error::IDLError; use crate::generator::Generator; use crate::rust::RustGenerator; use std::io::Write; -#[derive(Default, Clone, Debug)] +#[derive(Clone, Debug)] pub struct Config { - pub target: Target, pub backend: Backend, } impl Config { - pub fn parse(target_opt: &str, backend_opt: &str, zero_native_pointers: bool) -> Self { - let mut target = Target::from(target_opt); - let backend = Backend::from(backend_opt); - if zero_native_pointers { - target = Target::Generic; - } - Self { target, backend } + pub fn parse(backend_opt: &str) -> Result { + let backend = Backend::from_str(backend_opt) + .ok_or_else(|| IDLError::UsageError(format!("Invalid backend: {}", backend_opt)))?; + Ok(Self { backend }) } pub fn generator(&self, w: Box) -> Box { match self.backend { - Backend::C => Box::new(CGenerator::new(self.target, w)), - Backend::Rust => Box::new(RustGenerator::new(self.target, w)), + Backend::CGuest => Box::new(CGenerator::new(w)), + Backend::RustGuest => Box::new(RustGenerator::new(w)), + Backend::RustHost => unimplemented!(), } } } diff --git a/lucet-idl/src/error.rs b/lucet-idl/src/error.rs index 7626e577d..ffaee439e 100644 --- a/lucet-idl/src/error.rs +++ b/lucet-idl/src/error.rs @@ -10,7 +10,7 @@ pub enum IDLError { #[fail(display = "Internal error: {}", _0)] InternalError(&'static str), #[fail(display = "Incorrect usage: {}", _0)] - UsageError(&'static str), + UsageError(String), #[fail(display = "{}", _0)] ParseError(#[cause] parser::ParseError), #[fail(display = "{}", _0)] diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index b38187800..1c7891e54 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -15,7 +15,6 @@ mod package; mod parser; mod pretty_writer; mod rust; -mod target; mod types; pub use crate::backend::Backend; @@ -23,7 +22,6 @@ pub use crate::config::Config; pub use crate::error::IDLError; pub use crate::module::Module; pub use crate::package::Package; -pub use crate::target::Target; pub use crate::types::{ AtomType, Attr, DataType, DataTypeRef, FuncDecl, FuncRet, Ident, Location, Name, Named, }; diff --git a/lucet-idl/src/main.rs b/lucet-idl/src/main.rs index dd43ff30c..61d86bf2d 100644 --- a/lucet-idl/src/main.rs +++ b/lucet-idl/src/main.rs @@ -5,7 +5,7 @@ use std::io; use std::io::prelude::*; use std::path::PathBuf; -#[derive(Default, Clone, Debug)] +#[derive(Clone, Debug)] pub struct ExeConfig { pub input_path: PathBuf, pub output_path: Option, @@ -15,53 +15,40 @@ pub struct ExeConfig { impl ExeConfig { pub fn parse() -> Result { let matches = App::new("lucet-idl") - .version("1.0") + .version("0.1.0") .about("lucet_idl code generator") .arg( Arg::with_name("input") .required(true) .help("Path to the input file"), ) - .arg( - Arg::with_name("target") - .short("t") - .long("target") - .default_value("Generic") - .takes_value(true) - .required(false) - .help("Target, one of: x86, x86_64, x86_64_32, generic"), - ) .arg( Arg::with_name("backend") .short("b") .long("backend") - .default_value("c") + .default_value("c_guest") .takes_value(true) .required(false) - .help("Backend, one of: c, rust"), + .help("Backend, one of: c_guest, rust_guest, rust_host"), ) .arg( - Arg::with_name("zero-native-pointers") - .short("z") - .long("zero-native-pointers") - .takes_value(false) + Arg::with_name("output") + .short("o") + .takes_value(true) .required(false) - .help("Do not serialize native pointers"), + .help("output path"), ) .get_matches(); let input_path = PathBuf::from( matches .value_of("input") - .ok_or(IDLError::UsageError("Input file required"))?, - ); - let config = Config::parse( - matches.value_of("target").unwrap(), - matches.value_of("backend").unwrap(), - matches.is_present("zero-native-pointers"), + .ok_or(IDLError::UsageError("Input file required".to_owned()))?, ); + let output_path = matches.value_of("output").map(PathBuf::from); + let config = Config::parse(matches.value_of("backend").unwrap())?; Ok(ExeConfig { input_path, - output_path: None, + output_path, config, }) } @@ -71,7 +58,12 @@ fn doit() -> Result<(), IDLError> { let mut source = String::new(); File::open(&exe_config.input_path)?.read_to_string(&mut source)?; - run(&exe_config.config, &source, Box::new(io::stdout()))?; + let output: Box = match exe_config.output_path { + Some(ref p) => Box::new(File::create(p)?), + None => Box::new(io::stdout()), + }; + + run(&exe_config.config, &source, output)?; Ok(()) } diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index 716bfe98a..db0e58a5d 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -5,7 +5,6 @@ use crate::error::IDLError; use crate::generator::Generator; use crate::module::Module; use crate::pretty_writer::PrettyWriter; -use crate::target::Target; use crate::types::AtomType; use crate::types::{ AliasDataType, DataType, DataTypeRef, EnumDataType, FuncDecl, Ident, Named, StructDataType, @@ -14,29 +13,15 @@ use heck::{CamelCase, SnakeCase}; use std::collections::HashMap; use std::io::Write; -#[derive(Clone, Debug)] -struct CTypeInfo<'t> { - /// The native type name - type_name: String, - /// Alignment rules for that type - type_align: usize, - /// The native type size - type_size: usize, - /// The leaf type node - leaf_data_type_ref: &'t DataTypeRef, -} - -/// Generator for the C backend +/// Generator for the Rust backend pub struct RustGenerator { - pub target: Target, pub defined: HashMap, pub w: PrettyWriter, } impl RustGenerator { - pub fn new(target: Target, w: Box) -> Self { + pub fn new(w: Box) -> Self { Self { - target, defined: HashMap::new(), w: PrettyWriter::new(w), } @@ -207,13 +192,7 @@ impl Generator for RustGenerator { self.w .writeln("#[no_mangle]")? - .writeln("#[allow(unused_variables)]")? - .writeln(format!("pub fn {}({}) -> {} {{", name, args, rets))?; - - let mut w = self.w.new_block(); - w.writeln("unimplemented!()")?; - - self.w.writeln("}")?.eob()?; + .writeln(format!("extern \"C\" fn {}({}) -> {};", name, args, rets))?; Ok(()) } diff --git a/lucet-idl/src/target.rs b/lucet-idl/src/target.rs deleted file mode 100644 index af5d6b79f..000000000 --- a/lucet-idl/src/target.rs +++ /dev/null @@ -1,67 +0,0 @@ -use crate::types::*; - -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub enum Target { - X86, - X86_64_64, - X86_64_32, - Generic, -} - -impl Default for Target { - fn default() -> Self { - Target::Generic - } -} - -impl> From for Target { - fn from(s: T) -> Self { - match s.as_ref() { - "x86" => Target::X86, - "x86_64_64" | "x86_64" => Target::X86_64_64, - "x86_64_32" => Target::X86_64_32, - "generic" => Target::Generic, - _ => Target::default(), - } - } -} - -#[allow(dead_code)] -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub enum Endianness { - BigEndian, - LittleEndian, - Generic, -} - -impl Target { - pub fn reference_target() -> Target { - Target::X86_64_64 - } - - pub fn endianness(self) -> Endianness { - match self { - Target::Generic => Endianness::Generic, - _ => Endianness::LittleEndian, - } - } - - pub fn is_reference_target(self) -> bool { - self == Self::reference_target() - } - - pub fn is_reference_alignment_compatible(self) -> bool { - self != Target::Generic - } - - pub fn uses_reference_target_endianness(self) -> bool { - self.endianness() == Self::reference_target().endianness() - } - - pub fn uses_reference_target_endianness_for_atom_type(self, atom_type: AtomType) -> bool { - match atom_type { - AtomType::U8 | AtomType::I8 => true, - _ => self.uses_reference_target_endianness(), - } - } -} diff --git a/lucet-idl/tests/example.rs b/lucet-idl/tests/example.rs index 16fd69e7c..d0c5185f5 100644 --- a/lucet-idl/tests/example.rs +++ b/lucet-idl/tests/example.rs @@ -13,8 +13,7 @@ fn compile_and_run_c() { .expect("read example.idl"); let config = lucet_idl::Config { - backend: lucet_idl::Backend::C, - target: lucet_idl::Target::Generic, + backend: lucet_idl::Backend::CGuest, }; let tempdir = TempDir::new().expect("create tempdir"); @@ -52,8 +51,7 @@ fn compile_and_run_rust() { .expect("read example.idl"); let config = lucet_idl::Config { - backend: lucet_idl::Backend::Rust, - target: lucet_idl::Target::Generic, + backend: lucet_idl::Backend::RustHost, }; let tempdir = TempDir::new().expect("create tempdir"); From fc2cda7c7764ca6d5cc208e02ce08f5c6a900f88 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 16 May 2019 18:14:55 -0700 Subject: [PATCH 219/512] lucet-idl: generator doesnt need to be a trait orginization of modules, functions is a function of the backend itself --- lucet-idl/src/backend.rs | 17 ------------- lucet-idl/src/c.rs | 51 ++++++++++++++++++++++++-------------- lucet-idl/src/config.rs | 25 +++++++++++-------- lucet-idl/src/lib.rs | 21 ++++++---------- lucet-idl/src/rust.rs | 43 +++++++++++++++++++++++++++----- lucet-idl/tests/example.rs | 4 +-- 6 files changed, 95 insertions(+), 66 deletions(-) delete mode 100644 lucet-idl/src/backend.rs diff --git a/lucet-idl/src/backend.rs b/lucet-idl/src/backend.rs deleted file mode 100644 index b238fa994..000000000 --- a/lucet-idl/src/backend.rs +++ /dev/null @@ -1,17 +0,0 @@ -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub enum Backend { - CGuest, - RustGuest, - RustHost, -} - -impl Backend { - pub fn from_str>(s: T) -> Option { - match s.as_ref() { - "c_guest" => Some(Backend::CGuest), - "rust_guest" => Some(Backend::RustGuest), - "rust_host" => Some(Backend::RustHost), - _ => None, - } - } -} diff --git a/lucet-idl/src/c.rs b/lucet-idl/src/c.rs index 11aec6a2a..672513565 100644 --- a/lucet-idl/src/c.rs +++ b/lucet-idl/src/c.rs @@ -2,8 +2,8 @@ #![allow(unused_variables)] use crate::error::IDLError; -use crate::generator::Generator; use crate::module::Module; +use crate::package::Package; use crate::pretty_writer::PrettyWriter; use crate::types::{ AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, FuncDecl, Named, @@ -16,7 +16,38 @@ pub struct CGenerator { pub w: PrettyWriter, } -impl Generator for CGenerator { +impl CGenerator { + pub fn new(w: Box) -> Self { + let mut w = PrettyWriter::new(w); + let prelude = r" +#include +#include +#include +#include "; + for line in prelude.lines() { + w.write_line(line.as_ref()).unwrap(); + } + w.eob().unwrap(); + Self { w } + } + + pub fn generate_guest(&mut self, package: &Package) -> Result<(), IDLError> { + for (_ident, module) in package.modules.iter() { + for ref dt in module.datatypes() { + self.gen_type_header(module, dt)?; + match &dt.entity.variant { + DataTypeVariant::Struct(s) => self.gen_struct(module, dt, s)?, + DataTypeVariant::Alias(a) => self.gen_alias(module, dt, a)?, + DataTypeVariant::Enum(e) => self.gen_enum(module, dt, e)?, + } + } + for fdecl in module.func_decls() { + self.gen_function(module, &fdecl)?; + } + } + Ok(()) + } + fn gen_type_header(&mut self, _module: &Module, dt: &Named) -> Result<(), IDLError> { self.w .eob()? @@ -126,22 +157,6 @@ impl Generator for CGenerator { // UNIMPLEMENTED!! Ok(()) } -} - -impl CGenerator { - pub fn new(w: Box) -> Self { - let mut w = PrettyWriter::new(w); - let prelude = r" -#include -#include -#include -#include "; - for line in prelude.lines() { - w.write_line(line.as_ref()).unwrap(); - } - w.eob().unwrap(); - Self { w } - } // Return `true` if the type is an atom, an emum, or an alias to one of these pub fn is_type_eventually_an_atom_or_enum(&self, module: &Module, type_: &DataTypeRef) -> bool { diff --git a/lucet-idl/src/config.rs b/lucet-idl/src/config.rs index 5fad4ebaa..9bf995845 100644 --- a/lucet-idl/src/config.rs +++ b/lucet-idl/src/config.rs @@ -1,9 +1,4 @@ -use crate::backend::Backend; -use crate::c::CGenerator; use crate::error::IDLError; -use crate::generator::Generator; -use crate::rust::RustGenerator; -use std::io::Write; #[derive(Clone, Debug)] pub struct Config { @@ -16,12 +11,22 @@ impl Config { .ok_or_else(|| IDLError::UsageError(format!("Invalid backend: {}", backend_opt)))?; Ok(Self { backend }) } +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub enum Backend { + CGuest, + RustGuest, + RustHost, +} - pub fn generator(&self, w: Box) -> Box { - match self.backend { - Backend::CGuest => Box::new(CGenerator::new(w)), - Backend::RustGuest => Box::new(RustGenerator::new(w)), - Backend::RustHost => unimplemented!(), +impl Backend { + pub fn from_str>(s: T) -> Option { + match s.as_ref() { + "c_guest" => Some(Backend::CGuest), + "rust_guest" => Some(Backend::RustGuest), + "rust_host" => Some(Backend::RustHost), + _ => None, } } } diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 1c7891e54..bb8733b21 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -3,12 +3,10 @@ #[macro_use] extern crate failure; -mod backend; mod c; mod config; mod data_layout; mod error; -mod generator; mod lexer; mod module; mod package; @@ -17,8 +15,7 @@ mod pretty_writer; mod rust; mod types; -pub use crate::backend::Backend; -pub use crate::config::Config; +pub use crate::config::{Backend, Config}; pub use crate::error::IDLError; pub use crate::module::Module; pub use crate::package::Package; @@ -26,7 +23,9 @@ pub use crate::types::{ AtomType, Attr, DataType, DataTypeRef, FuncDecl, FuncRet, Ident, Location, Name, Named, }; +use crate::c::CGenerator; use crate::parser::Parser; +use crate::rust::RustGenerator; use std::io::Write; pub fn parse_package(input: &str) -> Result { @@ -37,16 +36,12 @@ pub fn parse_package(input: &str) -> Result { } pub fn codegen(package: &Package, config: &Config, output: Box) -> Result<(), IDLError> { - let mut generator = config.generator(output); - - for (_ident, mod_) in package.modules.iter() { - for dt in mod_.datatypes() { - generator.gen_datatype(mod_, &dt)?; - } - for fdecl in mod_.func_decls() { - generator.gen_function(mod_, &fdecl)?; - } + match config.backend { + Backend::CGuest => CGenerator::new(output).generate_guest(package)?, + Backend::RustGuest => RustGenerator::new(output).generate_guest(package)?, + Backend::RustHost => RustGenerator::new(output).generate_host(package)?, } + Ok(()) } diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index db0e58a5d..10fde9a46 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -2,12 +2,13 @@ #![allow(unused_variables)] use crate::error::IDLError; -use crate::generator::Generator; use crate::module::Module; +use crate::package::Package; use crate::pretty_writer::PrettyWriter; use crate::types::AtomType; use crate::types::{ - AliasDataType, DataType, DataTypeRef, EnumDataType, FuncDecl, Ident, Named, StructDataType, + AliasDataType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, FuncDecl, Ident, Named, + StructDataType, }; use heck::{CamelCase, SnakeCase}; use std::collections::HashMap; @@ -27,6 +28,38 @@ impl RustGenerator { } } + pub fn generate_guest(&mut self, package: &Package) -> Result<(), IDLError> { + for (_ident, module) in package.modules.iter() { + self.generate_datatypes(module)?; + for fdecl in module.func_decls() { + self.guest_function_import(module, &fdecl)?; + } + } + Ok(()) + } + + pub fn generate_host(&mut self, package: &Package) -> Result<(), IDLError> { + for (_ident, module) in package.modules.iter() { + self.generate_datatypes(module)?; + for fdecl in module.func_decls() { + unimplemented!(); // FIXME + } + } + Ok(()) + } + + fn generate_datatypes(&mut self, module: &Module) -> Result<(), IDLError> { + for ref dt in module.datatypes() { + self.gen_type_header(module, dt)?; + match &dt.entity.variant { + DataTypeVariant::Struct(s) => self.gen_struct(module, dt, s)?, + DataTypeVariant::Alias(a) => self.gen_alias(module, dt, a)?, + DataTypeVariant::Enum(e) => self.gen_enum(module, dt, e)?, + } + } + Ok(()) + } + fn define_name(&mut self, dt: &Named) -> String { let typename = dt.name.name.to_camel_case(); self.defined.insert(dt.id, typename.clone()); @@ -56,9 +89,7 @@ impl RustGenerator { F64 => "f64", } } -} -impl Generator for RustGenerator { fn gen_type_header(&mut self, _module: &Module, dt: &Named) -> Result<(), IDLError> { self.w .eob()? @@ -164,7 +195,7 @@ impl Generator for RustGenerator { Ok(()) } - fn gen_function( + fn guest_function_import( &mut self, module: &Module, func_decl_entry: &Named, @@ -192,7 +223,7 @@ impl Generator for RustGenerator { self.w .writeln("#[no_mangle]")? - .writeln(format!("extern \"C\" fn {}({}) -> {};", name, args, rets))?; + .writeln(format!("extern \"C\" fn {}({}) -> {} ;", name, args, rets))?; Ok(()) } diff --git a/lucet-idl/tests/example.rs b/lucet-idl/tests/example.rs index d0c5185f5..c8aa5d42e 100644 --- a/lucet-idl/tests/example.rs +++ b/lucet-idl/tests/example.rs @@ -43,7 +43,7 @@ fn compile_and_run_c() { } #[test] -fn compile_and_run_rust() { +fn compile_and_run_rust_guest() { let mut source = String::new(); File::open("tests/example.idl") .expect("open example.idl") @@ -51,7 +51,7 @@ fn compile_and_run_rust() { .expect("read example.idl"); let config = lucet_idl::Config { - backend: lucet_idl::Backend::RustHost, + backend: lucet_idl::Backend::RustGuest, }; let tempdir = TempDir::new().expect("create tempdir"); From d1cf675302748ad8ef9ea65e51e0736f720420f6 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 21 May 2019 15:40:47 -0700 Subject: [PATCH 220/512] lucet-idl: simplify pp --- lucet-idl/src/c.rs | 1 - lucet-idl/src/pretty_writer.rs | 12 ++++++++++-- lucet-idl/src/rust.rs | 17 +++++------------ 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/lucet-idl/src/c.rs b/lucet-idl/src/c.rs index 672513565..7ec3696ee 100644 --- a/lucet-idl/src/c.rs +++ b/lucet-idl/src/c.rs @@ -65,7 +65,6 @@ impl CGenerator { alias: &AliasDataType, ) -> Result<(), IDLError> { let dtname = self.type_name(dt); - self.w.indent()?; self.w.writeln(format!( "typedef {} {};", self.type_ref_name(module, &alias.to), diff --git a/lucet-idl/src/pretty_writer.rs b/lucet-idl/src/pretty_writer.rs index 65828e7dc..074a5cb22 100644 --- a/lucet-idl/src/pretty_writer.rs +++ b/lucet-idl/src/pretty_writer.rs @@ -36,6 +36,11 @@ impl PrettyWriter { } } + pub fn indent(&mut self) -> &mut Self { + self.indent += 1; + self + } + fn _write_all(&mut self, buf: &[u8]) -> Result<(), IDLError> { self.writer.borrow_mut().write_all(buf).map_err(Into::into) } @@ -47,7 +52,7 @@ impl PrettyWriter { } /// Output an indentation string - pub fn indent(&mut self) -> Result<&mut Self, IDLError> { + fn write_indent(&mut self) -> Result<&mut Self, IDLError> { let indent_bytes = &self.indent_bytes.clone(); { for _ in 0..self.indent { @@ -65,6 +70,9 @@ impl PrettyWriter { /// Output a block separator pub fn eob(&mut self) -> Result<&mut Self, IDLError> { + if self.indent > 0 { + self.indent -= 1; + } self.eol() } @@ -76,7 +84,7 @@ impl PrettyWriter { /// Indent, write raw data and terminate with an end of line pub fn write_line(&mut self, buf: &[u8]) -> Result<&mut Self, IDLError> { - self.indent()?.write(buf)?.eol() + self.write_indent()?.write(buf)?.eol() } /// Indent, write raw data and terminate with an end of line diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index 10fde9a46..a79b99351 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -31,9 +31,13 @@ impl RustGenerator { pub fn generate_guest(&mut self, package: &Package) -> Result<(), IDLError> { for (_ident, module) in package.modules.iter() { self.generate_datatypes(module)?; + self.w.writeln("extern \"C\" {")?; + self.w.indent(); for fdecl in module.func_decls() { self.guest_function_import(module, &fdecl)?; } + self.w.eob()?; + self.w.writeln("}")?; } Ok(()) } @@ -50,7 +54,6 @@ impl RustGenerator { fn generate_datatypes(&mut self, module: &Module) -> Result<(), IDLError> { for ref dt in module.datatypes() { - self.gen_type_header(module, dt)?; match &dt.entity.variant { DataTypeVariant::Struct(s) => self.gen_struct(module, dt, s)?, DataTypeVariant::Alias(a) => self.gen_alias(module, dt, a)?, @@ -90,13 +93,6 @@ impl RustGenerator { } } - fn gen_type_header(&mut self, _module: &Module, dt: &Named) -> Result<(), IDLError> { - self.w - .eob()? - .writeln(format!("/// {}: {:?}", dt.name.name, dt))?; - Ok(()) - } - fn gen_alias( &mut self, module: &Module, @@ -200,9 +196,6 @@ impl RustGenerator { module: &Module, func_decl_entry: &Named, ) -> Result<(), IDLError> { - self.w - .write_line(format!("// {:?}", func_decl_entry).as_bytes())?; - let name = func_decl_entry.name.name.to_snake_case(); let mut args = String::new(); for a in func_decl_entry.entity.args.iter() { @@ -223,7 +216,7 @@ impl RustGenerator { self.w .writeln("#[no_mangle]")? - .writeln(format!("extern \"C\" fn {}({}) -> {} ;", name, args, rets))?; + .writeln(format!("fn {}({}) -> {};", name, args, rets))?; Ok(()) } From ea351b49335a025387b0d492ce93444c9f2b02fd Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 21 May 2019 15:41:14 -0700 Subject: [PATCH 221/512] lucet-idl-test: build rust guest with latest wasm32-wasi nightly --- lucet-idl/lucet-idl-test/src/compile.rs | 32 ++++++++++++++++--------- lucet-idl/lucet-idl-test/src/main.rs | 4 ++-- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/lucet-idl/lucet-idl-test/src/compile.rs b/lucet-idl/lucet-idl-test/src/compile.rs index 88dff220e..194f386e7 100644 --- a/lucet-idl/lucet-idl-test/src/compile.rs +++ b/lucet-idl/lucet-idl-test/src/compile.rs @@ -1,6 +1,6 @@ -use lucet_idl::{codegen, Backend, Config, Package, Target}; +use lucet_idl::{codegen, Backend, Config, Package}; use std::fs::File; -use std::io::Read; +use std::io::{Read, Write}; use std::process::Command; use tempfile::TempDir; @@ -46,32 +46,43 @@ pub fn rust_wasm_codegen(package: &Package) -> Vec { let tempdir = TempDir::new().expect("create tempdir"); - let gen_file = tempdir.path().join("lib.rs"); + let idl_file = tempdir.path().join("idl.rs"); + let main_file = tempdir.path().join("main.rs"); let wasm_file = tempdir.path().join("example.wasm"); + let mut main = File::create(main_file.clone()).expect("create main"); + main.write_all( + b"#[allow(unused)] +mod idl; + +fn main() { + println!(\"hello, world\"); +} +", + ) + .expect("write contents of main"); + codegen( package, &config, - Box::new(File::create(gen_file.clone()).expect("create file")), + Box::new(File::create(idl_file.clone()).expect("create file")), ) .expect("lucet_idl codegen"); let cmd_rustc = Command::new("rustc") .arg("+nightly") - .arg(gen_file.clone()) - .arg("--target=wasm32-unknown-wasi") + .arg(main_file.clone()) + .arg("--target=wasm32-wasi") .arg("-o") .arg(wasm_file.clone()) .status() .expect("run rustc"); - if !cmd_rustc.success() { Command::new("cat") - .arg(gen_file.clone()) + .arg(idl_file.clone()) .status() .expect("debug output"); } - assert!(cmd_rustc.success(), "failure to compile generated code"); let mut wasm = File::open(wasm_file).expect("open wasm file"); @@ -82,8 +93,7 @@ pub fn rust_wasm_codegen(package: &Package) -> Vec { pub fn c_codegen(package: &Package) { let config = lucet_idl::Config { - backend: lucet_idl::Backend::C, - target: lucet_idl::Target::Generic, + backend: lucet_idl::Backend::CGuest, }; let tempdir = TempDir::new().expect("create tempdir"); diff --git a/lucet-idl/lucet-idl-test/src/main.rs b/lucet-idl/lucet-idl-test/src/main.rs index 15e4c45b2..acd644999 100644 --- a/lucet-idl/lucet-idl-test/src/main.rs +++ b/lucet-idl/lucet-idl-test/src/main.rs @@ -1,5 +1,5 @@ use lucet_idl::parse_package; -use lucet_idl_test::syntax::{DatatypeSyntax, Spec}; +use lucet_idl_test::syntax::Spec; use proptest::prelude::*; use proptest::strategy::ValueTree; use proptest::test_runner::TestRunner; @@ -8,7 +8,7 @@ fn main() { let mut runner = TestRunner::default(); let spec = Spec::strat(10).new_tree(&mut runner).unwrap().current(); let rendered = spec.render_idl(); - println!("{}", rendered); + //println!("{}", rendered); let pkg = parse_package(&rendered).expect("parse generated package"); From 6db6d0fb3f54843b753ab0b1dbe79beee5541451 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 21 May 2019 17:48:47 -0700 Subject: [PATCH 222/512] lucet-wasi: add bindings to crate --- lucet-wasi/Cargo.toml | 2 +- lucet-wasi/src/bindings.rs | 11 +++++++++++ lucet-wasi/src/lib.rs | 2 ++ lucet-wasi/tests/test_helpers/mod.rs | 8 +++----- 4 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 lucet-wasi/src/bindings.rs diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index 8d9ba2025..97b95c453 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -13,11 +13,11 @@ human-size = "0.4" libc = "0.2" lucet-runtime = { path = "../lucet-runtime" } lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals" } +lucetc = { path = "../lucetc" } nix = "0.13" rand = "0.6" [dev-dependencies] -lucetc = { path = "../lucetc" } lucet-wasi-sdk = { path = "../lucet-wasi-sdk" } tempfile = "3.0" diff --git a/lucet-wasi/src/bindings.rs b/lucet-wasi/src/bindings.rs new file mode 100644 index 000000000..4c0ec76b7 --- /dev/null +++ b/lucet-wasi/src/bindings.rs @@ -0,0 +1,11 @@ +use lucetc::Bindings; + +pub fn bindings() -> Bindings { + Bindings::from_str(include_str!("../bindings.json")).expect("lucet-wasi bindings.json is valid") +} + +#[cfg(test)] +#[test] +fn test_bindings_parses() { + let _ = bindings(); +} diff --git a/lucet-wasi/src/lib.rs b/lucet-wasi/src/lib.rs index 77dbf654b..70e133cfd 100644 --- a/lucet-wasi/src/lib.rs +++ b/lucet-wasi/src/lib.rs @@ -1,5 +1,6 @@ #![deny(bare_trait_objects)] +mod bindings; pub mod c_api; pub mod ctx; pub mod fdentry; @@ -8,4 +9,5 @@ pub mod hostcalls; pub mod memory; pub mod wasm32; +pub use bindings::bindings; pub use ctx::{WasiCtx, WasiCtxBuilder}; diff --git a/lucet-wasi/tests/test_helpers/mod.rs b/lucet-wasi/tests/test_helpers/mod.rs index 6ed75e9da..455928a92 100644 --- a/lucet-wasi/tests/test_helpers/mod.rs +++ b/lucet-wasi/tests/test_helpers/mod.rs @@ -1,9 +1,9 @@ use failure::{bail, Error}; use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region}; use lucet_wasi::host::__wasi_exitcode_t; -use lucet_wasi::{WasiCtx, WasiCtxBuilder}; +use lucet_wasi::{self, WasiCtx, WasiCtxBuilder}; use lucet_wasi_sdk::{CompileOpts, Link}; -use lucetc::{Bindings, Lucetc, LucetcOpts}; +use lucetc::{Lucetc, LucetcOpts}; use std::fs::File; use std::io::Read; use std::os::unix::io::{FromRawFd, IntoRawFd}; @@ -66,9 +66,7 @@ pub fn wasi_load>( workdir: &TempDir, wasm_file: P, ) -> Result, Error> { - let bindings = Bindings::from_file(Path::new(LUCET_WASI_ROOT).join("bindings.json"))?; - - let native_build = Lucetc::new(wasm_file).with_bindings(bindings); + let native_build = Lucetc::new(wasm_file).with_bindings(lucet_wasi::bindings()); let so_file = workdir.path().join("out.so"); From f79d210d64dac3bd34b06b31c73f15e45b86c2e0 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 21 May 2019 19:24:07 -0700 Subject: [PATCH 223/512] lucet-idl-test: towards using lucet-wasi to host programs --- Cargo.lock | 5 +- lucet-idl/lucet-idl-test/Cargo.toml | 5 +- lucet-idl/lucet-idl-test/src/compile.rs | 3 +- lucet-idl/lucet-idl-test/src/lib.rs | 1 + lucet-idl/lucet-idl-test/src/main.rs | 15 ++- lucet-idl/lucet-idl-test/src/wasi.rs | 120 ++++++++++++++++++++++++ 6 files changed, 144 insertions(+), 5 deletions(-) create mode 100644 lucet-idl/lucet-idl-test/src/wasi.rs diff --git a/Cargo.lock b/Cargo.lock index ed6352253..16aa391a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -790,9 +790,12 @@ dependencies = [ name = "lucet-idl-test" version = "0.1.0" dependencies = [ + "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-idl 0.1.0", "lucet-runtime 0.1.0", - "lucet-wasi-sdk 0.1.0", + "lucet-wasi 0.1.0", "lucetc 0.1.0", "proptest 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/lucet-idl/lucet-idl-test/Cargo.toml b/lucet-idl/lucet-idl-test/Cargo.toml index aa4be074d..9e19ae581 100644 --- a/lucet-idl/lucet-idl-test/Cargo.toml +++ b/lucet-idl/lucet-idl-test/Cargo.toml @@ -13,8 +13,11 @@ path = "src/main.rs" [dependencies] lucet-idl = { path = "../" } -lucet-wasi-sdk = { path = "../../lucet-wasi-sdk" } lucetc = { path = "../../lucetc" } lucet-runtime = { path = "../../lucet-runtime" } +lucet-wasi = { path = "../../lucet-wasi" } proptest = "0.9.3" tempfile = "3.0" +failure = "0.1" +log = "0.4" +env_logger = "0.6" diff --git a/lucet-idl/lucet-idl-test/src/compile.rs b/lucet-idl/lucet-idl-test/src/compile.rs index 194f386e7..ed7ccb94f 100644 --- a/lucet-idl/lucet-idl-test/src/compile.rs +++ b/lucet-idl/lucet-idl-test/src/compile.rs @@ -23,8 +23,8 @@ pub fn rust_test(package: &Package) { let cmd_rustc = Command::new("rustc") .arg("+stable") .arg(gen_file.clone()) - .arg("--test") .arg("--allow=dead_code") + .arg("--test") .arg("-o") .arg(tempdir.path().join("example")) .status() @@ -73,6 +73,7 @@ fn main() { .arg("+nightly") .arg(main_file.clone()) .arg("--target=wasm32-wasi") + .arg("--test") .arg("-o") .arg(wasm_file.clone()) .status() diff --git a/lucet-idl/lucet-idl-test/src/lib.rs b/lucet-idl/lucet-idl-test/src/lib.rs index dd8bb9263..22aafac56 100644 --- a/lucet-idl/lucet-idl-test/src/lib.rs +++ b/lucet-idl/lucet-idl-test/src/lib.rs @@ -1,5 +1,6 @@ pub mod compile; pub mod syntax; +pub mod wasi; #[cfg(test)] mod tests { diff --git a/lucet-idl/lucet-idl-test/src/main.rs b/lucet-idl/lucet-idl-test/src/main.rs index acd644999..87ebbdffc 100644 --- a/lucet-idl/lucet-idl-test/src/main.rs +++ b/lucet-idl/lucet-idl-test/src/main.rs @@ -1,16 +1,27 @@ +use env_logger; +use log::{debug, info}; use lucet_idl::parse_package; use lucet_idl_test::syntax::Spec; +use lucet_idl_test::wasi::WasiProject; use proptest::prelude::*; use proptest::strategy::ValueTree; use proptest::test_runner::TestRunner; fn main() { + env_logger::init(); + let mut runner = TestRunner::default(); let spec = Spec::strat(10).new_tree(&mut runner).unwrap().current(); let rendered = spec.render_idl(); - //println!("{}", rendered); + info!("generated spec:\n{}", rendered); let pkg = parse_package(&rendered).expect("parse generated package"); - let _wasm = lucet_idl_test::compile::rust_wasm_codegen(&pkg); + debug!("parsed package: {:?}", pkg); + let wasi_project = WasiProject::new(pkg); + + let _rust_guest = wasi_project + .codegen_rust_guest() + .expect("compile rust guest"); + let _rust_host = wasi_project.compile_rust_host().expect("compile rust host"); } diff --git a/lucet-idl/lucet-idl-test/src/wasi.rs b/lucet-idl/lucet-idl-test/src/wasi.rs new file mode 100644 index 000000000..a18e78183 --- /dev/null +++ b/lucet-idl/lucet-idl-test/src/wasi.rs @@ -0,0 +1,120 @@ +use failure::{format_err, Error}; +use log::info; +use lucet_idl::{self, Backend, Config, Package}; +use lucet_wasi; +use lucetc::{Lucetc, LucetcOpts}; +use std::fs::{self, File}; +use std::io::Write; +use std::path::{Path, PathBuf}; +use std::process::Command; +use tempfile::TempDir; + +pub struct WasiProject { + tempdir: TempDir, + package: Package, +} + +impl WasiProject { + pub fn new(package: Package) -> Self { + let tempdir = TempDir::new().expect("create tempdir for WasiProject"); + Self { tempdir, package } + } + + fn context(&self, name: &str) -> PathBuf { + let dir = self.tempdir.path().join(name); + fs::create_dir(dir.clone()).expect("create context subdir"); + dir + } + + fn create_rust_guest_source(&self, dir: &Path) -> Result { + let f = dir.join("idl.rs"); + info!("running lucet_idl::codegen for rust guest..."); + lucet_idl::codegen( + &self.package, + &Config { + backend: Backend::RustGuest, + }, + Box::new(File::create(f.clone()).expect("create rust guest idl")), + )?; + info!("done!"); + Ok(f) + } + + pub fn compile_rust_guest(&self) -> Result { + let dir = self.context("rust_guest_source"); + let wasm_file = self.context("compile_rust_guest").join("out.wasm"); + let rust_guest_source = self.create_rust_guest_source(&dir)?; + + info!("creating main.rs for rust guest..."); + let main_path = dir.join("main.rs"); + let mut main_file = File::create(&main_path)?; + main_file.write_all( + b" +#[allow(unused)] +mod idl; + +fn main() { + println!(\"hello, world\"); +}", + )?; + + info!("running rustc..."); + let cmd_rustc = Command::new("rustc") + .arg("+nightly") + .arg(main_path) + .arg("--target=wasm32-wasi") + .arg("--test") + .arg("-o") + .arg(wasm_file.clone()) + .status() + .expect("run rustc"); + info!("done!"); + if !cmd_rustc.success() { + Err(format_err!(""))? + } + Ok(wasm_file) + } + + pub fn codegen_rust_guest(&self) -> Result { + let dir = self.context("rust_guest_codegen"); + let so_file = dir.join("guest.so"); + let wasm_file = self.compile_rust_guest()?; + let lucetc = Lucetc::new(&wasm_file).with_bindings(lucet_wasi::bindings()); + lucetc.shared_object_file(&so_file)?; + Ok(so_file) + } + + fn create_rust_host_idl(&self, dir: &Path) -> Result { + let f = dir.join("idl.rs"); + info!("running lucet_idl::codegen for rust host..."); + lucet_idl::codegen( + &self.package, + &Config { + backend: Backend::RustHost, + }, + Box::new(File::create(f.clone()).expect("create rust host idl")), + )?; + info!("done!"); + Ok(f) + } + + pub fn compile_rust_host(&self) -> Result { + let dir = self.context("rust_host_source"); + let _ = self.create_rust_host_idl(&dir)?; + + info!("creating main.rs for rust host..."); + let mut main_file = File::create(dir.join("main.rs"))?; + main_file.write_all( + b" +#[allow(unused)] +mod idl; + +fn main() { + println!(\"hello, world\"); +}", + )?; + + info!("done!"); + unimplemented!() + } +} From 8663ca77efa9cf9447813cad6c26c30c6f6e9cc7 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 22 May 2019 15:06:47 -0700 Subject: [PATCH 224/512] lucet-idl-test: build out host build --- Cargo.toml | 1 + .../resources/rust_host/Cargo.toml | 17 ++++++++ .../resources/rust_host/src/idl.rs | 1 + .../resources/rust_host/src/main.rs | 6 +++ lucet-idl/lucet-idl-test/src/main.rs | 14 ++++--- lucet-idl/lucet-idl-test/src/wasi.rs | 41 ++++++++++++++----- 6 files changed, 64 insertions(+), 16 deletions(-) create mode 100644 lucet-idl/lucet-idl-test/resources/rust_host/Cargo.toml create mode 100644 lucet-idl/lucet-idl-test/resources/rust_host/src/idl.rs create mode 100644 lucet-idl/lucet-idl-test/resources/rust_host/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index 19f5085c4..ae1adde59 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "lucet-analyze", "lucet-idl", "lucet-idl/lucet-idl-test", + "lucet-idl/lucet-idl-test/resources/rust_host", "lucet-module-data", "lucet-runtime", "lucet-runtime/lucet-runtime-internals", diff --git a/lucet-idl/lucet-idl-test/resources/rust_host/Cargo.toml b/lucet-idl/lucet-idl-test/resources/rust_host/Cargo.toml new file mode 100644 index 000000000..5203602d5 --- /dev/null +++ b/lucet-idl/lucet-idl-test/resources/rust_host/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "lucet-idl-test-rust-host" +version = "0.1.0" +authors = ["Pat Hickey "] +edition = "2018" + +[[bin]] +name = "lucet-idl-test-rust-host" +path = "src/main.rs" + +[dependencies] +lucet-idl = { path = "../../../" } +lucet-runtime = { path = "../../../../lucet-runtime" } +lucet-wasi = { path = "../../../../lucet-wasi" } +failure = "0.1" +log = "0.4" +env_logger = "0.6" diff --git a/lucet-idl/lucet-idl-test/resources/rust_host/src/idl.rs b/lucet-idl/lucet-idl-test/resources/rust_host/src/idl.rs new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/lucet-idl/lucet-idl-test/resources/rust_host/src/idl.rs @@ -0,0 +1 @@ + diff --git a/lucet-idl/lucet-idl-test/resources/rust_host/src/main.rs b/lucet-idl/lucet-idl-test/resources/rust_host/src/main.rs new file mode 100644 index 000000000..361ac5e9a --- /dev/null +++ b/lucet-idl/lucet-idl-test/resources/rust_host/src/main.rs @@ -0,0 +1,6 @@ +#[allow(unused)] +mod idl; + +fn main() { + println!("hello, world! this is the rust host"); +} diff --git a/lucet-idl/lucet-idl-test/src/main.rs b/lucet-idl/lucet-idl-test/src/main.rs index 87ebbdffc..52d985baf 100644 --- a/lucet-idl/lucet-idl-test/src/main.rs +++ b/lucet-idl/lucet-idl-test/src/main.rs @@ -2,7 +2,7 @@ use env_logger; use log::{debug, info}; use lucet_idl::parse_package; use lucet_idl_test::syntax::Spec; -use lucet_idl_test::wasi::WasiProject; +use lucet_idl_test::wasi::{WasiHostBuild, WasiProject}; use proptest::prelude::*; use proptest::strategy::ValueTree; use proptest::test_runner::TestRunner; @@ -20,8 +20,12 @@ fn main() { debug!("parsed package: {:?}", pkg); let wasi_project = WasiProject::new(pkg); - let _rust_guest = wasi_project - .codegen_rust_guest() - .expect("compile rust guest"); - let _rust_host = wasi_project.compile_rust_host().expect("compile rust host"); + if false { + let _rust_guest = wasi_project + .codegen_rust_guest() + .expect("compile rust guest"); + let _rust_host = wasi_project.compile_rust_host().expect("compile rust host"); + } else { + let _wasi_host = WasiHostBuild::new().unwrap(); + } } diff --git a/lucet-idl/lucet-idl-test/src/wasi.rs b/lucet-idl/lucet-idl-test/src/wasi.rs index a18e78183..9b645bdb2 100644 --- a/lucet-idl/lucet-idl-test/src/wasi.rs +++ b/lucet-idl/lucet-idl-test/src/wasi.rs @@ -63,14 +63,13 @@ fn main() { .arg("+nightly") .arg(main_path) .arg("--target=wasm32-wasi") - .arg("--test") .arg("-o") .arg(wasm_file.clone()) .status() .expect("run rustc"); info!("done!"); if !cmd_rustc.success() { - Err(format_err!(""))? + Err(format_err!("rustc error building guest"))? } Ok(wasm_file) } @@ -104,17 +103,37 @@ fn main() { info!("creating main.rs for rust host..."); let mut main_file = File::create(dir.join("main.rs"))?; - main_file.write_all( - b" -#[allow(unused)] -mod idl; - -fn main() { - println!(\"hello, world\"); -}", - )?; + main_file.write_all(include_bytes!("../resources/rust_host/src/main.rs"))?; info!("done!"); unimplemented!() } } + +pub struct WasiHostBuild { + tempdir: TempDir, +} + +impl WasiHostBuild { + pub fn new() -> Result { + info!("starting wasi host build..."); + + let tempdir = TempDir::new().expect("create tempdir for WasiHostBuild"); + + let resource_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("resources") + .join("rust_host"); + let run_cargo = Command::new("cargo") + .arg("build") + .current_dir(resource_dir) + .status() + .expect("run cargo build"); + if !run_cargo.success() { + Err(format_err!("cargo died building host project"))? + } + + info!("done!"); + + Ok(WasiHostBuild { tempdir }) + } +} From 89d66c7811962b2b7612bd0cb7f2a80d1b24d411 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 23 May 2019 15:17:55 -0700 Subject: [PATCH 225/512] lucet-idl-test: guest and host build work --- Cargo.lock | 23 +++++ lucet-idl/lucet-idl-test/Cargo.toml | 1 + .../resources/rust_host/.gitignore | 1 + .../resources/rust_host/src/idl.rs | 3 +- .../resources/rust_host/src/main.rs | 18 +++- .../resources/rust_host/src/run.rs | 36 +++++++ lucet-idl/lucet-idl-test/src/main.rs | 17 ++-- lucet-idl/lucet-idl-test/src/wasi.rs | 95 +++++++++++++------ lucet-idl/src/rust.rs | 2 +- 9 files changed, 156 insertions(+), 40 deletions(-) create mode 100644 lucet-idl/lucet-idl-test/resources/rust_host/.gitignore create mode 100644 lucet-idl/lucet-idl-test/resources/rust_host/src/run.rs diff --git a/Cargo.lock b/Cargo.lock index 16aa391a0..cc8ab904b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -582,6 +582,15 @@ name = "fnv" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -792,6 +801,7 @@ version = "0.1.0" dependencies = [ "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-idl 0.1.0", "lucet-runtime 0.1.0", @@ -801,6 +811,18 @@ dependencies = [ "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lucet-idl-test-rust-host" +version = "0.1.0" +dependencies = [ + "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lucet-idl 0.1.0", + "lucet-runtime 0.1.0", + "lucet-wasi 0.1.0", +] + [[package]] name = "lucet-module-data" version = "0.1.0" @@ -1988,6 +2010,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum flate2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "246b6f24d8e616b0c176a8143486ddc8bb0bac2f30f0a0d3efbcf1e0d47cb7e5" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" +"checksum fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" diff --git a/lucet-idl/lucet-idl-test/Cargo.toml b/lucet-idl/lucet-idl-test/Cargo.toml index 9e19ae581..9ed132ba6 100644 --- a/lucet-idl/lucet-idl-test/Cargo.toml +++ b/lucet-idl/lucet-idl-test/Cargo.toml @@ -21,3 +21,4 @@ tempfile = "3.0" failure = "0.1" log = "0.4" env_logger = "0.6" +fs2 = "0.4" diff --git a/lucet-idl/lucet-idl-test/resources/rust_host/.gitignore b/lucet-idl/lucet-idl-test/resources/rust_host/.gitignore new file mode 100644 index 000000000..0da6c9a3e --- /dev/null +++ b/lucet-idl/lucet-idl-test/resources/rust_host/.gitignore @@ -0,0 +1 @@ +.*.lock diff --git a/lucet-idl/lucet-idl-test/resources/rust_host/src/idl.rs b/lucet-idl/lucet-idl-test/resources/rust_host/src/idl.rs index 8b1378917..1a9139565 100644 --- a/lucet-idl/lucet-idl-test/resources/rust_host/src/idl.rs +++ b/lucet-idl/lucet-idl-test/resources/rust_host/src/idl.rs @@ -1 +1,2 @@ - +// PLACEHOLDER FILE +// this file is overwritten, and restored, by lucet-idl-test diff --git a/lucet-idl/lucet-idl-test/resources/rust_host/src/main.rs b/lucet-idl/lucet-idl-test/resources/rust_host/src/main.rs index 361ac5e9a..ffc74bd57 100644 --- a/lucet-idl/lucet-idl-test/resources/rust_host/src/main.rs +++ b/lucet-idl/lucet-idl-test/resources/rust_host/src/main.rs @@ -1,6 +1,22 @@ +use std::env; +use std::path::PathBuf; + #[allow(unused)] mod idl; +mod run; fn main() { - println!("hello, world! this is the rust host"); + let args: Vec = env::args().collect(); + if args.len() != 2 { + eprintln!("usage: lucet-idl-test-rust-host "); + std::process::exit(1); + } + let module_path = PathBuf::from(&args[1]); + match run::run(module_path) { + Ok(()) => {} + Err(e) => { + eprintln!("{:?}", e); + std::process::exit(1); + } + } } diff --git a/lucet-idl/lucet-idl-test/resources/rust_host/src/run.rs b/lucet-idl/lucet-idl-test/resources/rust_host/src/run.rs new file mode 100644 index 000000000..23cd5614f --- /dev/null +++ b/lucet-idl/lucet-idl-test/resources/rust_host/src/run.rs @@ -0,0 +1,36 @@ +use failure::Error; +use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region}; +use lucet_wasi::{self, WasiCtxBuilder}; +use std::path::PathBuf; +use std::sync::Arc; + +pub fn run(module_path: PathBuf) -> Result<(), Error> { + lucet_wasi::hostcalls::ensure_linked(); + + let module = DlModule::load(&module_path)?; + + let region = MmapRegion::create( + 1, + &Limits { + heap_memory_size: 4 * 1024 * 1024 * 1024, + heap_address_space_size: 8 * 1024 * 1024 * 1024, + globals_size: 4 * 1024 * 1024, + stack_size: 4 * 1024 * 1024, + }, + )?; + + let ctx = WasiCtxBuilder::new() + .inherit_stdio() + .build() + .expect("create empty wasi ctx"); + + let mut inst = region + .new_instance_builder(module as Arc) + .with_embed_ctx(ctx) + .build() + .expect("construct instance"); + + inst.run("_start", &[])?; + + Ok(()) +} diff --git a/lucet-idl/lucet-idl-test/src/main.rs b/lucet-idl/lucet-idl-test/src/main.rs index 52d985baf..b784be2b2 100644 --- a/lucet-idl/lucet-idl-test/src/main.rs +++ b/lucet-idl/lucet-idl-test/src/main.rs @@ -2,7 +2,7 @@ use env_logger; use log::{debug, info}; use lucet_idl::parse_package; use lucet_idl_test::syntax::Spec; -use lucet_idl_test::wasi::{WasiHostBuild, WasiProject}; +use lucet_idl_test::wasi::WasiProject; use proptest::prelude::*; use proptest::strategy::ValueTree; use proptest::test_runner::TestRunner; @@ -20,12 +20,11 @@ fn main() { debug!("parsed package: {:?}", pkg); let wasi_project = WasiProject::new(pkg); - if false { - let _rust_guest = wasi_project - .codegen_rust_guest() - .expect("compile rust guest"); - let _rust_host = wasi_project.compile_rust_host().expect("compile rust host"); - } else { - let _wasi_host = WasiHostBuild::new().unwrap(); - } + let rust_guest = wasi_project + .codegen_rust_guest() + .expect("compile rust guest"); + + let rust_host = wasi_project.create_rust_host().expect("compile rust host"); + + rust_host.run(&rust_guest).expect("run host application"); } diff --git a/lucet-idl/lucet-idl-test/src/wasi.rs b/lucet-idl/lucet-idl-test/src/wasi.rs index 9b645bdb2..9a5abbc22 100644 --- a/lucet-idl/lucet-idl-test/src/wasi.rs +++ b/lucet-idl/lucet-idl-test/src/wasi.rs @@ -1,4 +1,5 @@ use failure::{format_err, Error}; +use fs2::FileExt; use log::info; use lucet_idl::{self, Backend, Config, Package}; use lucet_wasi; @@ -43,7 +44,7 @@ impl WasiProject { pub fn compile_rust_guest(&self) -> Result { let dir = self.context("rust_guest_source"); let wasm_file = self.context("compile_rust_guest").join("out.wasm"); - let rust_guest_source = self.create_rust_guest_source(&dir)?; + let _rust_guest_source = self.create_rust_guest_source(&dir)?; info!("creating main.rs for rust guest..."); let main_path = dir.join("main.rs"); @@ -83,57 +84,95 @@ fn main() { Ok(so_file) } - fn create_rust_host_idl(&self, dir: &Path) -> Result { - let f = dir.join("idl.rs"); + fn create_rust_host_idl(&self, f: File) -> Result<(), Error> { info!("running lucet_idl::codegen for rust host..."); lucet_idl::codegen( &self.package, &Config { backend: Backend::RustHost, }, - Box::new(File::create(f.clone()).expect("create rust host idl")), + Box::new(f), )?; info!("done!"); - Ok(f) + Ok(()) } - pub fn compile_rust_host(&self) -> Result { - let dir = self.context("rust_host_source"); - let _ = self.create_rust_host_idl(&dir)?; - - info!("creating main.rs for rust host..."); - let mut main_file = File::create(dir.join("main.rs"))?; - main_file.write_all(include_bytes!("../resources/rust_host/src/main.rs"))?; - - info!("done!"); - unimplemented!() + pub fn create_rust_host(&self) -> Result { + let resource_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("resources") + .join("rust_host"); + let mut host_app = HostApp::new(resource_dir)?; + let idl_file = host_app.source_file("idl.rs")?; + self.create_rust_host_idl(idl_file)?; + Ok(host_app) } } -pub struct WasiHostBuild { +pub struct HostApp { + root: PathBuf, + lockfile: File, tempdir: TempDir, + backups: Vec<(PathBuf, PathBuf)>, } -impl WasiHostBuild { - pub fn new() -> Result { - info!("starting wasi host build..."); +impl HostApp { + pub fn new>(root: P) -> Result { + let lockfile_path = root.as_ref().join(".rust_host.lock"); + if !lockfile_path.exists() { + File::create(&lockfile_path)?; + } - let tempdir = TempDir::new().expect("create tempdir for WasiHostBuild"); + let lockfile = File::open(lockfile_path)?; - let resource_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("resources") - .join("rust_host"); + lockfile.lock_exclusive()?; + + Ok(HostApp { + root: PathBuf::from(root.as_ref()), + lockfile, + tempdir: TempDir::new()?, + backups: Vec::new(), + }) + } + + pub fn source_file(&mut self, name: &str) -> Result { + let filepath = self.root.join("src").join(name); + if filepath.exists() { + let backup = self.tempdir.path().join(name); + if backup.exists() { + Err(format_err!( + "cannot overwrite source file '{}': already overwritten", + name + ))? + } + self.backups.push((backup.clone(), filepath.clone())); + fs::rename(&filepath, backup)?; + } + let f = File::create(filepath)?; + Ok(f) + } + + pub fn run>(&self, guest_path: P) -> Result<(), Error> { let run_cargo = Command::new("cargo") - .arg("build") - .current_dir(resource_dir) + .arg("run") + .arg("--bin") + .arg("lucet-idl-test-rust-host") + .arg("--") + .arg(guest_path.as_ref()) + .current_dir(&self.root) .status() .expect("run cargo build"); if !run_cargo.success() { Err(format_err!("cargo died building host project"))? } + Ok(()) + } +} - info!("done!"); - - Ok(WasiHostBuild { tempdir }) +impl Drop for HostApp { + fn drop(&mut self) { + for (backup, orig) in self.backups.iter() { + fs::rename(backup, orig).expect("restore backup") + } + self.lockfile.unlock().expect("unlock"); } } diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index a79b99351..5d007d5e2 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -46,7 +46,7 @@ impl RustGenerator { for (_ident, module) in package.modules.iter() { self.generate_datatypes(module)?; for fdecl in module.func_decls() { - unimplemented!(); // FIXME + self.w.writeln(format!("// UNIMPLEMENTED: {:?}", fdecl))?; } } Ok(()) From 7799530484a016f64b4c4cb7ef4d8d20d9794f60 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 23 May 2019 18:03:23 -0700 Subject: [PATCH 226/512] lucet-idl-test: finish refactoring the way we build guest & host apps --- lucet-idl/lucet-idl-test/src/c_guest.rs | 74 +++++++++ lucet-idl/lucet-idl-test/src/compile.rs | 132 --------------- lucet-idl/lucet-idl-test/src/host.rs | 102 ++++++++++++ lucet-idl/lucet-idl-test/src/lib.rs | 33 +++- lucet-idl/lucet-idl-test/src/main.rs | 16 +- lucet-idl/lucet-idl-test/src/rust_guest.rs | 71 ++++++++ lucet-idl/lucet-idl-test/src/wasi.rs | 178 --------------------- lucet-idl/lucet-idl-test/src/workspace.rs | 24 +++ 8 files changed, 304 insertions(+), 326 deletions(-) create mode 100644 lucet-idl/lucet-idl-test/src/c_guest.rs delete mode 100644 lucet-idl/lucet-idl-test/src/compile.rs create mode 100644 lucet-idl/lucet-idl-test/src/host.rs create mode 100644 lucet-idl/lucet-idl-test/src/rust_guest.rs delete mode 100644 lucet-idl/lucet-idl-test/src/wasi.rs create mode 100644 lucet-idl/lucet-idl-test/src/workspace.rs diff --git a/lucet-idl/lucet-idl-test/src/c_guest.rs b/lucet-idl/lucet-idl-test/src/c_guest.rs new file mode 100644 index 000000000..910719c30 --- /dev/null +++ b/lucet-idl/lucet-idl-test/src/c_guest.rs @@ -0,0 +1,74 @@ +use crate::workspace::Workspace; +use failure::{format_err, Error}; +use lucet_idl::{self, Backend, Config, Package}; +use lucet_wasi; +use lucetc::{Lucetc, LucetcOpts}; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; +use std::process::Command; + +pub struct CGuestApp { + work: Workspace, +} + +impl CGuestApp { + pub fn new() -> Result { + Ok(Self { + work: Workspace::new()?, + }) + } + + fn generate_idl_h(&mut self, package: &Package) -> Result<(), Error> { + lucet_idl::codegen( + package, + &Config { + backend: Backend::CGuest, + }, + Box::new(File::create(self.work.source_path("idl.h"))?), + )?; + Ok(()) + } + + fn generate_main_c(&mut self) -> Result<(), Error> { + let mut main_file = File::create(self.work.source_path("main.c"))?; + main_file.write_all( + b" +#include +#include \"idl.h\" + +int main(int argc, char* argv[]) { + printf(\"hello, world from c guest\"); +}", + )?; + Ok(()) + } + fn wasi_clang(&mut self) -> Result<(), Error> { + let wasi_sdk = + PathBuf::from(std::env::var("WASI_SDK").unwrap_or_else(|_| "/opt/wasi-sdk".to_owned())); + let cmd_cc = Command::new(wasi_sdk.join("bin").join("clang")) + .arg("--std=c99") + .arg(self.work.source_path("main.c")) + .arg("-I") + .arg(self.work.source_path("")) + .arg("-o") + .arg(self.work.output_path("out.wasm")) + .status()?; + + if !cmd_cc.success() { + Err(format_err!("clang error building guest"))? + } + Ok(()) + } + + pub fn build(&mut self, package: &Package) -> Result { + self.generate_idl_h(package)?; + self.generate_main_c()?; + self.wasi_clang()?; + let lucetc = + Lucetc::new(self.work.output_path("out.wasm")).with_bindings(lucet_wasi::bindings()); + let so_file = self.work.output_path("out.so"); + lucetc.shared_object_file(&so_file)?; + Ok(so_file) + } +} diff --git a/lucet-idl/lucet-idl-test/src/compile.rs b/lucet-idl/lucet-idl-test/src/compile.rs deleted file mode 100644 index ed7ccb94f..000000000 --- a/lucet-idl/lucet-idl-test/src/compile.rs +++ /dev/null @@ -1,132 +0,0 @@ -use lucet_idl::{codegen, Backend, Config, Package}; -use std::fs::File; -use std::io::{Read, Write}; -use std::process::Command; -use tempfile::TempDir; - -pub fn rust_test(package: &Package) { - let config = Config { - backend: Backend::RustHost, - }; - - let tempdir = TempDir::new().expect("create tempdir"); - - let gen_file = tempdir.path().join("lib.rs"); - - codegen( - package, - &config, - Box::new(File::create(gen_file.clone()).expect("create file")), - ) - .expect("lucet_idl codegen"); - - let cmd_rustc = Command::new("rustc") - .arg("+stable") - .arg(gen_file.clone()) - .arg("--allow=dead_code") - .arg("--test") - .arg("-o") - .arg(tempdir.path().join("example")) - .status() - .expect("run rustc"); - - if !cmd_rustc.success() { - Command::new("cat") - .arg(gen_file.clone()) - .status() - .expect("debug output"); - } - assert!(cmd_rustc.success(), "failure to compile generated code"); -} - -pub fn rust_wasm_codegen(package: &Package) -> Vec { - let config = Config { - backend: Backend::RustGuest, - }; - - let tempdir = TempDir::new().expect("create tempdir"); - - let idl_file = tempdir.path().join("idl.rs"); - let main_file = tempdir.path().join("main.rs"); - let wasm_file = tempdir.path().join("example.wasm"); - - let mut main = File::create(main_file.clone()).expect("create main"); - main.write_all( - b"#[allow(unused)] -mod idl; - -fn main() { - println!(\"hello, world\"); -} -", - ) - .expect("write contents of main"); - - codegen( - package, - &config, - Box::new(File::create(idl_file.clone()).expect("create file")), - ) - .expect("lucet_idl codegen"); - - let cmd_rustc = Command::new("rustc") - .arg("+nightly") - .arg(main_file.clone()) - .arg("--target=wasm32-wasi") - .arg("--test") - .arg("-o") - .arg(wasm_file.clone()) - .status() - .expect("run rustc"); - if !cmd_rustc.success() { - Command::new("cat") - .arg(idl_file.clone()) - .status() - .expect("debug output"); - } - assert!(cmd_rustc.success(), "failure to compile generated code"); - - let mut wasm = File::open(wasm_file).expect("open wasm file"); - let mut buf = Vec::new(); - wasm.read_to_end(&mut buf).expect("read wasm file"); - buf -} - -pub fn c_codegen(package: &Package) { - let config = lucet_idl::Config { - backend: lucet_idl::Backend::CGuest, - }; - - let tempdir = TempDir::new().expect("create tempdir"); - - codegen( - package, - &config, - Box::new(File::create(tempdir.path().join("example.c")).expect("create file")), - ) - .expect("lucet_idl codegen"); - - let cmd_cc = Command::new("cc") - .arg("--std=c99") - .arg("-c") - .arg(tempdir.path().join("example.c")) - .arg("-o") - .arg(tempdir.path().join("example.o")) - .status() - .expect("run cc"); - - if !cmd_cc.success() { - Command::new("cat") - .arg(tempdir.path().join("example.c")) - .status() - .expect("debug output"); - } - assert!(cmd_cc.success(), "failure to compile generated code"); - - /* - let cmd_run = Command::new(tempdir.path().join("example")) - .status() - .expect("run generated code"); - assert!(cmd_run.success(), "failure to run generated code"); - */ -} diff --git a/lucet-idl/lucet-idl-test/src/host.rs b/lucet-idl/lucet-idl-test/src/host.rs new file mode 100644 index 000000000..d577a8cb6 --- /dev/null +++ b/lucet-idl/lucet-idl-test/src/host.rs @@ -0,0 +1,102 @@ +use failure::{format_err, Error}; +use fs2::FileExt; +use lucet_idl::{self, Backend, Config, Package}; +use std::fs::{self, File}; +use std::path::{Path, PathBuf}; +use std::process::Command; +use tempfile::TempDir; + +pub struct HostApp { + root: PathBuf, + lockfile: File, + tempdir: TempDir, + backups: Vec<(PathBuf, PathBuf)>, +} + +impl HostApp { + pub fn new(package: &Package) -> Result { + // Need a system-wide lock on the source directory, because we will modify its contents and + // call `cargo run` on it. + // This way we can use the cache of compiled crates in the project cargo workspace. + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("resources") + .join("rust_host"); + let lockfile_path = root.join(".rust_host.lock"); + if !lockfile_path.exists() { + File::create(&lockfile_path)?; + } + + let lockfile = File::open(lockfile_path)?; + lockfile.lock_exclusive()?; + + let mut hostapp = HostApp { + root, + lockfile, + tempdir: TempDir::new()?, + backups: Vec::new(), + }; + + let idl_file = hostapp.source_file("idl.rs")?; + lucet_idl::codegen( + package, + &Config { + backend: Backend::RustHost, + }, + Box::new(idl_file), + )?; + + Ok(hostapp) + } + + fn source_file(&mut self, name: &str) -> Result { + let filepath = self.root.join("src").join(name); + if filepath.exists() { + let backup = self.tempdir.path().join(name); + if backup.exists() { + Err(format_err!( + "cannot overwrite source file '{}': already overwritten", + name + ))? + } + self.backups.push((backup.clone(), filepath.clone())); + fs::rename(&filepath, backup)?; + } + let f = File::create(filepath)?; + Ok(f) + } + + pub fn build(&mut self) -> Result<(), Error> { + let run_cargo = Command::new("cargo") + .arg("build") + .current_dir(&self.root) + .status()?; + if !run_cargo.success() { + Err(format_err!("cargo died building host project"))? + } + Ok(()) + } + + pub fn run>(&mut self, guest_path: P) -> Result<(), Error> { + let run_cargo = Command::new("cargo") + .arg("run") + .arg("--bin") + .arg("lucet-idl-test-rust-host") + .arg("--") + .arg(guest_path.as_ref()) + .current_dir(&self.root) + .status()?; + if !run_cargo.success() { + Err(format_err!("cargo died building host project"))? + } + Ok(()) + } +} + +impl Drop for HostApp { + fn drop(&mut self) { + for (backup, orig) in self.backups.iter() { + fs::rename(backup, orig).expect("restore backup") + } + self.lockfile.unlock().expect("unlock"); + } +} diff --git a/lucet-idl/lucet-idl-test/src/lib.rs b/lucet-idl/lucet-idl-test/src/lib.rs index 22aafac56..f968287e6 100644 --- a/lucet-idl/lucet-idl-test/src/lib.rs +++ b/lucet-idl/lucet-idl-test/src/lib.rs @@ -1,27 +1,44 @@ -pub mod compile; +mod c_guest; +mod host; +mod rust_guest; pub mod syntax; -pub mod wasi; +mod workspace; + +pub use c_guest::CGuestApp; +pub use host::HostApp; +pub use rust_guest::RustGuestApp; +pub use syntax::Spec; #[cfg(test)] mod tests { - use crate::compile; - use crate::syntax::Spec; + use crate::{CGuestApp, HostApp, RustGuestApp, Spec}; use lucet_idl::parse_package; use proptest::prelude::*; proptest! { #[test] - fn generate_and_rust(spec in Spec::strat(20)) { + fn generate_rust_guest(spec in Spec::strat(20)) { let rendered = spec.render_idl(); let pkg = parse_package(&rendered).unwrap(); - compile::rust_codegen(&pkg); + let mut rust_guest_app = RustGuestApp::new().expect("create rust guest app"); + let _rust_guest_so = rust_guest_app.build(&pkg).expect("compile rust guest app"); } #[test] - fn generate_and_c(spec in Spec::strat(20)) { + fn generate_c_guest(spec in Spec::strat(20)) { let rendered = spec.render_idl(); let pkg = parse_package(&rendered).unwrap(); - compile::c_codegen(&pkg); + let mut c_guest_app = CGuestApp::new().expect("create c guest app"); + let _c_guest_so = c_guest_app.build(&pkg).expect("compile c guest app"); } + + #[test] + fn generate_host(spec in Spec::strat(20)) { + let rendered = spec.render_idl(); + let pkg = parse_package(&rendered).unwrap(); + let mut host_app = HostApp::new(&pkg).expect("create host app"); + let _host_app = host_app.build().expect("compile host app"); + } + } } diff --git a/lucet-idl/lucet-idl-test/src/main.rs b/lucet-idl/lucet-idl-test/src/main.rs index b784be2b2..b18a1e456 100644 --- a/lucet-idl/lucet-idl-test/src/main.rs +++ b/lucet-idl/lucet-idl-test/src/main.rs @@ -1,8 +1,7 @@ use env_logger; use log::{debug, info}; use lucet_idl::parse_package; -use lucet_idl_test::syntax::Spec; -use lucet_idl_test::wasi::WasiProject; +use lucet_idl_test::{CGuestApp, HostApp, RustGuestApp, Spec}; use proptest::prelude::*; use proptest::strategy::ValueTree; use proptest::test_runner::TestRunner; @@ -18,13 +17,14 @@ fn main() { let pkg = parse_package(&rendered).expect("parse generated package"); debug!("parsed package: {:?}", pkg); - let wasi_project = WasiProject::new(pkg); - let rust_guest = wasi_project - .codegen_rust_guest() - .expect("compile rust guest"); + let mut rust_guest_app = RustGuestApp::new().expect("create rust guest app"); + let rust_guest_so = rust_guest_app.build(&pkg).expect("compile rust guest app"); - let rust_host = wasi_project.create_rust_host().expect("compile rust host"); + let mut c_guest_app = CGuestApp::new().expect("create c guest app"); + let c_guest_so = c_guest_app.build(&pkg).expect("compile c guest app"); - rust_host.run(&rust_guest).expect("run host application"); + let mut host_app = HostApp::new(&pkg).expect("create host app"); + host_app.run(&rust_guest_so).expect("run rust_guest_so"); + host_app.run(&c_guest_so).expect("run c_guest_so"); } diff --git a/lucet-idl/lucet-idl-test/src/rust_guest.rs b/lucet-idl/lucet-idl-test/src/rust_guest.rs new file mode 100644 index 000000000..135c2d870 --- /dev/null +++ b/lucet-idl/lucet-idl-test/src/rust_guest.rs @@ -0,0 +1,71 @@ +use crate::workspace::Workspace; +use failure::{format_err, Error}; +use lucet_idl::{self, Backend, Config, Package}; +use lucet_wasi; +use lucetc::{Lucetc, LucetcOpts}; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; +use std::process::Command; + +pub struct RustGuestApp { + work: Workspace, +} + +impl RustGuestApp { + pub fn new() -> Result { + Ok(Self { + work: Workspace::new()?, + }) + } + + fn generate_idl_rs(&mut self, package: &Package) -> Result<(), Error> { + lucet_idl::codegen( + package, + &Config { + backend: Backend::RustGuest, + }, + Box::new(File::create(self.work.source_path("idl.rs"))?), + )?; + Ok(()) + } + + fn generate_main_rs(&mut self) -> Result<(), Error> { + let mut main_file = File::create(self.work.source_path("main.rs"))?; + main_file.write_all( + b" +#[allow(unused)] +mod idl; + +fn main() { + println!(\"hello, world from rust guest\"); +}", + )?; + Ok(()) + } + + fn rustc(&mut self) -> Result<(), Error> { + let cmd_rustc = Command::new("rustc") + .arg("+nightly") + .arg(self.work.source_path("main.rs")) + .arg("--target=wasm32-wasi") + .arg("-o") + .arg(self.work.output_path("out.wasm")) + .status()?; + if !cmd_rustc.success() { + Err(format_err!("rustc error building guest"))? + } + Ok(()) + } + + pub fn build(&mut self, package: &Package) -> Result { + self.generate_idl_rs(package)?; + self.generate_main_rs()?; + self.rustc()?; + let lucetc = + Lucetc::new(self.work.output_path("out.wasm")).with_bindings(lucet_wasi::bindings()); + let so_file = self.work.output_path("out.so"); + lucetc.shared_object_file(&so_file)?; + Ok(so_file) + } +} diff --git a/lucet-idl/lucet-idl-test/src/wasi.rs b/lucet-idl/lucet-idl-test/src/wasi.rs deleted file mode 100644 index 9a5abbc22..000000000 --- a/lucet-idl/lucet-idl-test/src/wasi.rs +++ /dev/null @@ -1,178 +0,0 @@ -use failure::{format_err, Error}; -use fs2::FileExt; -use log::info; -use lucet_idl::{self, Backend, Config, Package}; -use lucet_wasi; -use lucetc::{Lucetc, LucetcOpts}; -use std::fs::{self, File}; -use std::io::Write; -use std::path::{Path, PathBuf}; -use std::process::Command; -use tempfile::TempDir; - -pub struct WasiProject { - tempdir: TempDir, - package: Package, -} - -impl WasiProject { - pub fn new(package: Package) -> Self { - let tempdir = TempDir::new().expect("create tempdir for WasiProject"); - Self { tempdir, package } - } - - fn context(&self, name: &str) -> PathBuf { - let dir = self.tempdir.path().join(name); - fs::create_dir(dir.clone()).expect("create context subdir"); - dir - } - - fn create_rust_guest_source(&self, dir: &Path) -> Result { - let f = dir.join("idl.rs"); - info!("running lucet_idl::codegen for rust guest..."); - lucet_idl::codegen( - &self.package, - &Config { - backend: Backend::RustGuest, - }, - Box::new(File::create(f.clone()).expect("create rust guest idl")), - )?; - info!("done!"); - Ok(f) - } - - pub fn compile_rust_guest(&self) -> Result { - let dir = self.context("rust_guest_source"); - let wasm_file = self.context("compile_rust_guest").join("out.wasm"); - let _rust_guest_source = self.create_rust_guest_source(&dir)?; - - info!("creating main.rs for rust guest..."); - let main_path = dir.join("main.rs"); - let mut main_file = File::create(&main_path)?; - main_file.write_all( - b" -#[allow(unused)] -mod idl; - -fn main() { - println!(\"hello, world\"); -}", - )?; - - info!("running rustc..."); - let cmd_rustc = Command::new("rustc") - .arg("+nightly") - .arg(main_path) - .arg("--target=wasm32-wasi") - .arg("-o") - .arg(wasm_file.clone()) - .status() - .expect("run rustc"); - info!("done!"); - if !cmd_rustc.success() { - Err(format_err!("rustc error building guest"))? - } - Ok(wasm_file) - } - - pub fn codegen_rust_guest(&self) -> Result { - let dir = self.context("rust_guest_codegen"); - let so_file = dir.join("guest.so"); - let wasm_file = self.compile_rust_guest()?; - let lucetc = Lucetc::new(&wasm_file).with_bindings(lucet_wasi::bindings()); - lucetc.shared_object_file(&so_file)?; - Ok(so_file) - } - - fn create_rust_host_idl(&self, f: File) -> Result<(), Error> { - info!("running lucet_idl::codegen for rust host..."); - lucet_idl::codegen( - &self.package, - &Config { - backend: Backend::RustHost, - }, - Box::new(f), - )?; - info!("done!"); - Ok(()) - } - - pub fn create_rust_host(&self) -> Result { - let resource_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("resources") - .join("rust_host"); - let mut host_app = HostApp::new(resource_dir)?; - let idl_file = host_app.source_file("idl.rs")?; - self.create_rust_host_idl(idl_file)?; - Ok(host_app) - } -} - -pub struct HostApp { - root: PathBuf, - lockfile: File, - tempdir: TempDir, - backups: Vec<(PathBuf, PathBuf)>, -} - -impl HostApp { - pub fn new>(root: P) -> Result { - let lockfile_path = root.as_ref().join(".rust_host.lock"); - if !lockfile_path.exists() { - File::create(&lockfile_path)?; - } - - let lockfile = File::open(lockfile_path)?; - - lockfile.lock_exclusive()?; - - Ok(HostApp { - root: PathBuf::from(root.as_ref()), - lockfile, - tempdir: TempDir::new()?, - backups: Vec::new(), - }) - } - - pub fn source_file(&mut self, name: &str) -> Result { - let filepath = self.root.join("src").join(name); - if filepath.exists() { - let backup = self.tempdir.path().join(name); - if backup.exists() { - Err(format_err!( - "cannot overwrite source file '{}': already overwritten", - name - ))? - } - self.backups.push((backup.clone(), filepath.clone())); - fs::rename(&filepath, backup)?; - } - let f = File::create(filepath)?; - Ok(f) - } - - pub fn run>(&self, guest_path: P) -> Result<(), Error> { - let run_cargo = Command::new("cargo") - .arg("run") - .arg("--bin") - .arg("lucet-idl-test-rust-host") - .arg("--") - .arg(guest_path.as_ref()) - .current_dir(&self.root) - .status() - .expect("run cargo build"); - if !run_cargo.success() { - Err(format_err!("cargo died building host project"))? - } - Ok(()) - } -} - -impl Drop for HostApp { - fn drop(&mut self) { - for (backup, orig) in self.backups.iter() { - fs::rename(backup, orig).expect("restore backup") - } - self.lockfile.unlock().expect("unlock"); - } -} diff --git a/lucet-idl/lucet-idl-test/src/workspace.rs b/lucet-idl/lucet-idl-test/src/workspace.rs new file mode 100644 index 000000000..bc64ac184 --- /dev/null +++ b/lucet-idl/lucet-idl-test/src/workspace.rs @@ -0,0 +1,24 @@ +use failure::Error; +use std::fs; +use std::path::PathBuf; +use tempfile::TempDir; +pub struct Workspace { + tempdir: TempDir, +} + +impl Workspace { + pub fn new() -> Result { + let tempdir = TempDir::new()?; + fs::create_dir(tempdir.path().join("src"))?; + fs::create_dir(tempdir.path().join("out"))?; + Ok(Self { tempdir }) + } + + pub fn source_path(&self, name: &str) -> PathBuf { + self.tempdir.path().join("src").join(name) + } + + pub fn output_path(&self, name: &str) -> PathBuf { + self.tempdir.path().join("out").join(name) + } +} From 05f9ff80ee3f142065a100687fb4a23fe73b9609 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 24 May 2019 14:18:12 -0700 Subject: [PATCH 227/512] lucet-idl-test: improvements to executable --- Cargo.lock | 1 + lucet-idl/lucet-idl-test/Cargo.toml | 1 + lucet-idl/lucet-idl-test/src/c_guest.rs | 4 + lucet-idl/lucet-idl-test/src/lib.rs | 1 + lucet-idl/lucet-idl-test/src/main.rs | 109 ++++++++++++++++++--- lucet-idl/lucet-idl-test/src/rust_guest.rs | 4 + 6 files changed, 107 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cc8ab904b..a600c887a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -799,6 +799,7 @@ dependencies = [ name = "lucet-idl-test" version = "0.1.0" dependencies = [ + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/lucet-idl/lucet-idl-test/Cargo.toml b/lucet-idl/lucet-idl-test/Cargo.toml index 9ed132ba6..b310979ec 100644 --- a/lucet-idl/lucet-idl-test/Cargo.toml +++ b/lucet-idl/lucet-idl-test/Cargo.toml @@ -22,3 +22,4 @@ failure = "0.1" log = "0.4" env_logger = "0.6" fs2 = "0.4" +clap = "2" diff --git a/lucet-idl/lucet-idl-test/src/c_guest.rs b/lucet-idl/lucet-idl-test/src/c_guest.rs index 910719c30..f408feefd 100644 --- a/lucet-idl/lucet-idl-test/src/c_guest.rs +++ b/lucet-idl/lucet-idl-test/src/c_guest.rs @@ -71,4 +71,8 @@ int main(int argc, char* argv[]) { lucetc.shared_object_file(&so_file)?; Ok(so_file) } + + pub fn into_workspace(self) -> Workspace { + self.work + } } diff --git a/lucet-idl/lucet-idl-test/src/lib.rs b/lucet-idl/lucet-idl-test/src/lib.rs index f968287e6..cab139291 100644 --- a/lucet-idl/lucet-idl-test/src/lib.rs +++ b/lucet-idl/lucet-idl-test/src/lib.rs @@ -8,6 +8,7 @@ pub use c_guest::CGuestApp; pub use host::HostApp; pub use rust_guest::RustGuestApp; pub use syntax::Spec; +pub use workspace::Workspace; #[cfg(test)] mod tests { diff --git a/lucet-idl/lucet-idl-test/src/main.rs b/lucet-idl/lucet-idl-test/src/main.rs index b18a1e456..5b3c64a4d 100644 --- a/lucet-idl/lucet-idl-test/src/main.rs +++ b/lucet-idl/lucet-idl-test/src/main.rs @@ -1,30 +1,113 @@ +use clap::{App, Arg}; use env_logger; use log::{debug, info}; use lucet_idl::parse_package; -use lucet_idl_test::{CGuestApp, HostApp, RustGuestApp, Spec}; +use lucet_idl_test::{CGuestApp, HostApp, RustGuestApp, Spec, Workspace}; use proptest::prelude::*; use proptest::strategy::ValueTree; use proptest::test_runner::TestRunner; +use std::fs::read_to_string; +use std::path::PathBuf; fn main() { env_logger::init(); + let exe_config = ExeConfig::parse(); - let mut runner = TestRunner::default(); - let spec = Spec::strat(10).new_tree(&mut runner).unwrap().current(); - let rendered = spec.render_idl(); - info!("generated spec:\n{}", rendered); + let input_idl = match exe_config.input { + Some(path) => read_to_string(path).expect("read contents of input file"), + None => { + let mut runner = TestRunner::default(); + let spec = Spec::strat(10).new_tree(&mut runner).unwrap().current(); + let rendered = spec.render_idl(); + info!("generated spec:\n{}", rendered); + rendered + } + }; - let pkg = parse_package(&rendered).expect("parse generated package"); + let pkg = parse_package(&input_idl).expect("parse generated package"); debug!("parsed package: {:?}", pkg); - let mut rust_guest_app = RustGuestApp::new().expect("create rust guest app"); - let rust_guest_so = rust_guest_app.build(&pkg).expect("compile rust guest app"); + // Workspace deleted when dropped - need to keep it alive for app to be run + let mut guest_apps: Vec<(PathBuf, Workspace)> = Vec::new(); - let mut c_guest_app = CGuestApp::new().expect("create c guest app"); - let c_guest_so = c_guest_app.build(&pkg).expect("compile c guest app"); + if exe_config.build_rust_guest { + let mut rust_guest_app = RustGuestApp::new().expect("create rust guest app"); + let rust_guest_so = rust_guest_app.build(&pkg).expect("compile rust guest app"); + guest_apps.push((rust_guest_so, rust_guest_app.into_workspace())); + } - let mut host_app = HostApp::new(&pkg).expect("create host app"); - host_app.run(&rust_guest_so).expect("run rust_guest_so"); - host_app.run(&c_guest_so).expect("run c_guest_so"); + if exe_config.build_c_guest { + let mut c_guest_app = CGuestApp::new().expect("create c guest app"); + let c_guest_so = c_guest_app.build(&pkg).expect("compile c guest app"); + guest_apps.push((c_guest_so, c_guest_app.into_workspace())); + } + + if exe_config.build_host { + let mut host_app = HostApp::new(&pkg).expect("create host app"); + if exe_config.run_guests { + for (guest_app_path, _ws) in guest_apps.iter() { + host_app.run(guest_app_path).expect("run guest app"); + } + } + } +} + +#[derive(Clone, Debug)] +struct ExeConfig { + pub input: Option, + pub build_host: bool, + pub build_rust_guest: bool, + pub build_c_guest: bool, + pub run_guests: bool, +} + +impl ExeConfig { + pub fn parse() -> Self { + let matches = App::new("lucet-idl-test") + .version("0.1.0") + .about("lucet-idl testing tool") + .arg( + Arg::with_name("input") + .required(false) + .help("Path to the input idl file. If not provided, input will be generated"), + ) + .arg( + Arg::with_name("no_host") + .required(false) + .takes_value(false) + .long("no-host") + .help(""), + ) + .arg( + Arg::with_name("no_c_guest") + .required(false) + .takes_value(false) + .long("no-c-guest") + .help(""), + ) + .arg( + Arg::with_name("no_rust_guest") + .required(false) + .takes_value(false) + .long("no-rust-guest") + .help(""), + ) + .arg( + Arg::with_name("no_run") + .required(false) + .takes_value(false) + .long("no-run") + .help(""), + ) + .get_matches(); + + ExeConfig { + input: matches.value_of("input").map(PathBuf::from), + build_host: !matches.is_present("no_host"), + build_c_guest: !matches.is_present("no_c_guest"), + build_rust_guest: !matches.is_present("no_rust_guest"), + run_guests: !matches.is_present("no_run") || !matches.is_present("no_host"), + } + } } diff --git a/lucet-idl/lucet-idl-test/src/rust_guest.rs b/lucet-idl/lucet-idl-test/src/rust_guest.rs index 135c2d870..ec4740458 100644 --- a/lucet-idl/lucet-idl-test/src/rust_guest.rs +++ b/lucet-idl/lucet-idl-test/src/rust_guest.rs @@ -68,4 +68,8 @@ fn main() { lucetc.shared_object_file(&so_file)?; Ok(so_file) } + + pub fn into_workspace(self) -> Workspace { + self.work + } } From 03c1c5d2b7a749dd4dd51bc209fd545504d6bdce Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 28 May 2019 14:42:35 -0700 Subject: [PATCH 228/512] lucetc: bindings can be serialized to json as well --- lucetc/src/bindings.rs | 92 ++++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 34 deletions(-) diff --git a/lucetc/src/bindings.rs b/lucetc/src/bindings.rs index e6cbf0a1e..7d72337bf 100644 --- a/lucetc/src/bindings.rs +++ b/lucetc/src/bindings.rs @@ -4,35 +4,6 @@ use std::collections::{hash_map::Entry, HashMap}; use std::fs; use std::path::Path; -fn parse_modules( - m: &Map, -) -> Result>, Error> { - let mut res = HashMap::new(); - for (modulename, values) in m { - match values.as_object() { - Some(methods) => { - let methodmap = parse_methods(methods)?; - res.insert(modulename.to_owned(), methodmap); - } - None => Err(format_err!(""))?, - } - } - Ok(res) -} - -fn parse_methods(m: &Map) -> Result, Error> { - let mut res = HashMap::new(); - for (method, i) in m { - match i.as_str() { - Some(importbinding) => { - res.insert(method.to_owned(), importbinding.to_owned()); - } - None => Err(format_err!(""))?, - } - } - Ok(res) -} - #[derive(Debug, Clone)] pub struct Bindings { bindings: HashMap>, @@ -54,11 +25,10 @@ impl Bindings { } pub fn from_json(v: &Value) -> Result { - let bindings = match v.as_object() { - Some(modules) => parse_modules(modules)?, + match v.as_object() { + Some(modules) => Self::parse_modules_json_obj(modules), None => Err(format_err!("top level json expected to be object"))?, - }; - Ok(Self::new(bindings)) + } } pub fn from_str(s: &str) -> Result { @@ -72,7 +42,6 @@ impl Bindings { } pub fn extend(&mut self, other: &Bindings) -> Result<(), Error> { - //self.bindings.extend(other.bindings); for (modname, othermodbindings) in other.bindings.iter() { match self.bindings.entry(modname.clone()) { Entry::Occupied(mut e) => { @@ -116,6 +85,61 @@ impl Bindings { )), } } + + fn parse_modules_json_obj(m: &Map) -> Result { + let mut res = HashMap::new(); + for (modulename, values) in m { + match values.as_object() { + Some(methods) => { + let methodmap = Self::parse_methods_json_obj(methods)?; + res.insert(modulename.to_owned(), methodmap); + } + None => Err(format_err!(""))?, + } + } + Ok(Self::new(res)) + } + + fn parse_methods_json_obj(m: &Map) -> Result, Error> { + let mut res = HashMap::new(); + for (method, i) in m { + match i.as_str() { + Some(importbinding) => { + res.insert(method.to_owned(), importbinding.to_owned()); + } + None => Err(format_err!(""))?, + } + } + Ok(res) + } + + pub fn to_string(&self) -> Result { + let s = serde_json::to_string(&self.to_json())?; + Ok(s) + } + + pub fn to_json(&self) -> Value { + Value::from(self.serialize_modules_json_obj()) + } + + fn serialize_modules_json_obj(&self) -> Map { + let mut m = Map::new(); + for (modulename, values) in self.bindings.iter() { + m.insert( + modulename.to_owned(), + Value::from(Self::serialize_methods_json_obj(values)), + ); + } + m + } + + fn serialize_methods_json_obj(methods: &HashMap) -> Map { + let mut m = Map::new(); + for (methodname, symbol) in methods.iter() { + m.insert(methodname.to_owned(), Value::from(symbol.to_owned())); + } + m + } } #[cfg(test)] From 334eb35d7337fd524fb9606f12b569d2cfe34e65 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 30 May 2019 11:44:01 -0700 Subject: [PATCH 229/512] lucet-idl: wip host func --- lucet-idl/src/rust.rs | 44 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index 5d007d5e2..a6bbffeaf 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -44,10 +44,15 @@ impl RustGenerator { pub fn generate_host(&mut self, package: &Package) -> Result<(), IDLError> { for (_ident, module) in package.modules.iter() { + self.w.writeln("use lucet_runtime::lucet_hostcalls;")?; self.generate_datatypes(module)?; + self.w.writeln("lucet_hostcalls! {")?; + self.w.indent(); for fdecl in module.func_decls() { - self.w.writeln(format!("// UNIMPLEMENTED: {:?}", fdecl))?; + self.host_function_definition(module, &fdecl)?; } + self.w.eob()?; + self.w.writeln("}")?; } Ok(()) } @@ -220,6 +225,43 @@ impl RustGenerator { Ok(()) } + + fn host_function_definition( + &mut self, + module: &Module, + func_decl_entry: &Named, + ) -> Result<(), IDLError> { + let name = func_decl_entry.name.name.to_snake_case(); + let mut args = format!("&mut vmctx,"); + for a in func_decl_entry.entity.args.iter() { + args += &format!( + "{}: {},", + a.name.to_snake_case(), + self.get_defined_typename(&a.type_) + ); + } + + let func_rets = &func_decl_entry.entity.rets; + let rets = if func_rets.len() == 0 { + "()".to_owned() + } else { + assert_eq!(func_rets.len(), 1); + self.get_defined_typename(&func_rets[0].type_).to_owned() + }; + + self.w.writeln("#[no_mangle]")?.writeln(format!( + "pub unsafe extern \"C\" fn {}({}) -> {} {{", + name, args, rets + ))?; + + self.w.indent(); + self.w.writeln("unimplemented!()")?; + self.w.eob()?; + + self.w.writeln("}")?; + + Ok(()) + } } fn gen_testcase(w: &mut PrettyWriter, name: &str, f: F) -> Result<(), IDLError> From 41b90e3a4e4c34fd316f1a3e5b10ccbd56f1ddc4 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 30 May 2019 15:21:26 -0700 Subject: [PATCH 230/512] lucet-idl: add TODO --- lucet-idl/TODO.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 lucet-idl/TODO.md diff --git a/lucet-idl/TODO.md b/lucet-idl/TODO.md new file mode 100644 index 000000000..3136370fb --- /dev/null +++ b/lucet-idl/TODO.md @@ -0,0 +1,12 @@ +* idl package generates a lucetc::Bindings, binding info accessible in modules / func AST +* idl-test generates arbitrary values for a given type +* describe ABI of functions: + * annotations to arguments saying whether they are in, out, or inout + * non-atomic arguments need to be passed by reference, cannot be return values +* idl package generates funcs that take a byte array (linear memory) and offset + and validate whether it is a valid repr of a type + * pointer, length validation + * enum variants + * bools +* add byte slices to language. + * hold off on other types of slices for now From 5320f2c44c61c6330cba41eb0c754b9e35588dce Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 3 Jun 2019 11:40:14 -0700 Subject: [PATCH 231/512] lucet-idl: calculate bindings of package, use in host code --- Cargo.lock | 1 + lucet-idl/Cargo.toml | 1 + lucet-idl/TODO.md | 1 - lucet-idl/lucet-idl-test/src/c_guest.rs | 5 +++-- lucet-idl/lucet-idl-test/src/rust_guest.rs | 5 +++-- lucet-idl/src/config.rs | 19 +++++++++++++++++-- lucet-idl/src/lib.rs | 11 ++++++++++- lucet-idl/src/main.rs | 6 +++++- lucet-idl/src/module.rs | 21 +++++++++++++++++++-- lucet-idl/src/package.rs | 21 +++++++++++++++++++-- lucet-idl/src/rust.rs | 9 +++++++-- lucet-idl/src/types.rs | 2 ++ 12 files changed, 87 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a600c887a..82bd6250a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -790,6 +790,7 @@ dependencies = [ "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ======= "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lucetc 0.1.0", "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", >>>>>>> lucet-idl: start stubbing out rust backend "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/lucet-idl/Cargo.toml b/lucet-idl/Cargo.toml index cabe34cd6..e7c6a65ee 100644 --- a/lucet-idl/Cargo.toml +++ b/lucet-idl/Cargo.toml @@ -19,6 +19,7 @@ clap = "2" failure = "0.1" xfailure = "0.1" heck = "0.3" +lucetc = { path = "../lucetc" } [dev-dependencies] tempfile = "3.0" diff --git a/lucet-idl/TODO.md b/lucet-idl/TODO.md index 3136370fb..a1ef3b638 100644 --- a/lucet-idl/TODO.md +++ b/lucet-idl/TODO.md @@ -1,4 +1,3 @@ -* idl package generates a lucetc::Bindings, binding info accessible in modules / func AST * idl-test generates arbitrary values for a given type * describe ABI of functions: * annotations to arguments saying whether they are in, out, or inout diff --git a/lucet-idl/lucet-idl-test/src/c_guest.rs b/lucet-idl/lucet-idl-test/src/c_guest.rs index f408feefd..1895d2d50 100644 --- a/lucet-idl/lucet-idl-test/src/c_guest.rs +++ b/lucet-idl/lucet-idl-test/src/c_guest.rs @@ -65,8 +65,9 @@ int main(int argc, char* argv[]) { self.generate_idl_h(package)?; self.generate_main_c()?; self.wasi_clang()?; - let lucetc = - Lucetc::new(self.work.output_path("out.wasm")).with_bindings(lucet_wasi::bindings()); + let mut bindings = lucet_wasi::bindings(); + bindings.extend(&package.bindings())?; + let lucetc = Lucetc::new(self.work.output_path("out.wasm")).with_bindings(bindings); let so_file = self.work.output_path("out.so"); lucetc.shared_object_file(&so_file)?; Ok(so_file) diff --git a/lucet-idl/lucet-idl-test/src/rust_guest.rs b/lucet-idl/lucet-idl-test/src/rust_guest.rs index ec4740458..87e628898 100644 --- a/lucet-idl/lucet-idl-test/src/rust_guest.rs +++ b/lucet-idl/lucet-idl-test/src/rust_guest.rs @@ -62,8 +62,9 @@ fn main() { self.generate_idl_rs(package)?; self.generate_main_rs()?; self.rustc()?; - let lucetc = - Lucetc::new(self.work.output_path("out.wasm")).with_bindings(lucet_wasi::bindings()); + let mut bindings = lucet_wasi::bindings(); + bindings.extend(&package.bindings())?; + let lucetc = Lucetc::new(self.work.output_path("out.wasm")).with_bindings(bindings); let so_file = self.work.output_path("out.so"); lucetc.shared_object_file(&so_file)?; Ok(so_file) diff --git a/lucet-idl/src/config.rs b/lucet-idl/src/config.rs index 9bf995845..d42a05803 100644 --- a/lucet-idl/src/config.rs +++ b/lucet-idl/src/config.rs @@ -7,8 +7,13 @@ pub struct Config { impl Config { pub fn parse(backend_opt: &str) -> Result { - let backend = Backend::from_str(backend_opt) - .ok_or_else(|| IDLError::UsageError(format!("Invalid backend: {}", backend_opt)))?; + let backend = Backend::from_str(backend_opt).ok_or_else(|| { + IDLError::UsageError(format!( + "Invalid backend: {}\nValid options are: {:?}", + backend_opt, + Backend::options() + )) + })?; Ok(Self { backend }) } } @@ -18,6 +23,7 @@ pub enum Backend { CGuest, RustGuest, RustHost, + Bindings, } impl Backend { @@ -26,7 +32,16 @@ impl Backend { "c_guest" => Some(Backend::CGuest), "rust_guest" => Some(Backend::RustGuest), "rust_host" => Some(Backend::RustHost), + "bindings" => Some(Backend::Bindings), _ => None, } } + pub fn options() -> Vec { + vec![ + "c_guest".to_owned(), + "rust_guest".to_owned(), + "rust_host".to_owned(), + "bindings".to_owned(), + ] + } } diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index bb8733b21..03423880e 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -26,6 +26,7 @@ pub use crate::types::{ use crate::c::CGenerator; use crate::parser::Parser; use crate::rust::RustGenerator; +use lucetc::Bindings; use std::io::Write; pub fn parse_package(input: &str) -> Result { @@ -40,8 +41,8 @@ pub fn codegen(package: &Package, config: &Config, output: Box) -> Re Backend::CGuest => CGenerator::new(output).generate_guest(package)?, Backend::RustGuest => RustGenerator::new(output).generate_guest(package)?, Backend::RustHost => RustGenerator::new(output).generate_host(package)?, + Backend::Bindings => generate_bindings(&package.bindings(), output)?, } - Ok(()) } @@ -49,3 +50,11 @@ pub fn run(config: &Config, input: &str, output: Box) -> Result<(), I let pkg = parse_package(input)?; codegen(&pkg, config, output) } + +fn generate_bindings(bindings: &Bindings, mut output: Box) -> Result<(), IDLError> { + let bindings_json = bindings + .to_string() + .map_err(|_| IDLError::InternalError("bindings generation"))?; + output.write_all(bindings_json.as_bytes())?; + Ok(()) +} diff --git a/lucet-idl/src/main.rs b/lucet-idl/src/main.rs index 61d86bf2d..2cf4f7e2d 100644 --- a/lucet-idl/src/main.rs +++ b/lucet-idl/src/main.rs @@ -4,6 +4,7 @@ use std::fs::File; use std::io; use std::io::prelude::*; use std::path::PathBuf; +use std::process; #[derive(Clone, Debug)] pub struct ExeConfig { @@ -69,5 +70,8 @@ fn doit() -> Result<(), IDLError> { } fn main() { - doit().unwrap(); + if let Err(e) = doit() { + eprintln!("{}", e); + process::exit(1); + } } diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index 1a538ee45..0e8b7c2d0 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -7,6 +7,7 @@ use crate::types::{ Attr, DataType, DataTypeRef, EnumMember, FuncArg, FuncDecl, FuncRet, Ident, Location, Name, Named, }; +use heck::SnakeCase; use std::collections::HashMap; #[derive(Debug, PartialEq, Eq, Clone)] @@ -16,16 +17,20 @@ pub struct Module { pub data_types: HashMap, pub data_type_ordering: Vec, pub funcs: HashMap, + pub module_name: String, + pub binding_prefix: String, } impl Module { - fn new(attrs: &[Attr]) -> Self { + fn new(attrs: &[Attr], module_name: String, binding_prefix: String) -> Self { Self { names: Vec::new(), attrs: attrs.to_vec(), data_types: HashMap::new(), data_type_ordering: Vec::new(), funcs: HashMap::new(), + module_name, + binding_prefix, } } @@ -180,6 +185,7 @@ impl Module { ); } SyntaxDecl::Function { + name, args, rets, attrs, @@ -225,10 +231,13 @@ impl Module { })? } + let binding_name = self.binding_prefix.clone() + "_" + &name.to_snake_case(); let decl = FuncDecl { args, rets, attrs: attrs.clone(), + field_name: name.clone(), + binding_name, }; if let Some(prev_def) = funcs_ir.insert(id, decl) { panic!("id {} already defined: {:?}", id, prev_def) @@ -242,8 +251,10 @@ impl Module { pub fn from_declarations( decls: &[SyntaxDecl], attrs: &[Attr], + module_name: String, + binding_prefix: String, ) -> Result { - let mut mod_ = Self::new(attrs); + let mut mod_ = Self::new(attrs, module_name, binding_prefix); let mut idents: Vec = Vec::new(); for decl in decls { match decl { @@ -308,6 +319,12 @@ impl Module { .iter() .map(move |(i, _)| self.get_func_decl(*i).unwrap()) } + + pub fn func_bindings(&self) -> HashMap { + self.func_decls() + .map(|d| (d.entity.field_name.clone(), d.entity.binding_name.clone())) + .collect() + } } #[cfg(test)] diff --git a/lucet-idl/src/package.rs b/lucet-idl/src/package.rs index 9778ad290..6a4cfeb16 100644 --- a/lucet-idl/src/package.rs +++ b/lucet-idl/src/package.rs @@ -2,6 +2,8 @@ use crate::error::ValidationError; use crate::module::Module; use crate::parser::SyntaxDecl; use crate::types::{Ident, Location, Name}; +use heck::SnakeCase; +use lucetc::Bindings; use std::collections::HashMap; #[derive(Debug, PartialEq, Eq, Clone)] @@ -75,8 +77,14 @@ impl Package { for (decl, id) in decls.iter().zip(&idents) { match decl { - SyntaxDecl::Module { decls, attrs, .. } => { - pkg.define_module(*id, Module::from_declarations(decls, attrs)?); + SyntaxDecl::Module { + decls, attrs, name, .. + } => { + let binding_prefix = "__".to_owned() + &name.to_snake_case(); + pkg.define_module( + *id, + Module::from_declarations(decls, attrs, name.clone(), binding_prefix)?, + ); } _ => unreachable!(), } @@ -84,6 +92,15 @@ impl Package { Ok(pkg) } + + pub fn bindings(&self) -> Bindings { + let b: HashMap> = self + .modules + .iter() + .map(|(_, m)| (m.module_name.clone(), m.func_bindings())) + .collect(); + Bindings::new(b) + } } #[cfg(test)] diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index a6bbffeaf..fc2731f0a 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -250,8 +250,13 @@ impl RustGenerator { }; self.w.writeln("#[no_mangle]")?.writeln(format!( - "pub unsafe extern \"C\" fn {}({}) -> {} {{", - name, args, rets + "// Wasm func {}::{} +pub unsafe extern \"C\" fn {}({}) -> {} {{", + module.module_name, + func_decl_entry.entity.field_name, + func_decl_entry.entity.binding_name, + args, + rets ))?; self.w.indent(); diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index 926bfa3bc..8f2b8c352 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -118,6 +118,8 @@ pub struct FuncArg { #[derive(Debug, PartialEq, Eq, Clone)] pub struct FuncDecl { + pub field_name: String, + pub binding_name: String, pub args: Vec, pub rets: Vec, pub attrs: Vec, From f17186f1419f56f596029ddbcebc87cccd14f60e Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 4 Jun 2019 17:35:32 -0700 Subject: [PATCH 232/512] lucet-idl-test: start of generator for values of a given idl wip, currently has a type error? --- lucet-idl/lucet-idl-test/src/lib.rs | 1 + lucet-idl/lucet-idl-test/src/values.rs | 105 +++++++++++++++++++++++++ lucet-idl/src/lib.rs | 3 +- 3 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 lucet-idl/lucet-idl-test/src/values.rs diff --git a/lucet-idl/lucet-idl-test/src/lib.rs b/lucet-idl/lucet-idl-test/src/lib.rs index cab139291..75efc6c6d 100644 --- a/lucet-idl/lucet-idl-test/src/lib.rs +++ b/lucet-idl/lucet-idl-test/src/lib.rs @@ -2,6 +2,7 @@ mod c_guest; mod host; mod rust_guest; pub mod syntax; +pub mod values; mod workspace; pub use c_guest::CGuestApp; diff --git a/lucet-idl/lucet-idl-test/src/values.rs b/lucet-idl/lucet-idl-test/src/values.rs new file mode 100644 index 000000000..13b405717 --- /dev/null +++ b/lucet-idl/lucet-idl-test/src/values.rs @@ -0,0 +1,105 @@ +use lucet_idl::{ + AliasDataType, AtomType, DataTypeRef, DataTypeVariant, EnumDataType, Module, StructDataType, + StructMember, +}; +use proptest::{self, prelude::*}; + +#[derive(Debug, Clone, PartialEq)] +pub enum AtomVal { + Bool(bool), + U8(u8), + U16(u16), + U32(u32), + U64(u64), + I8(i8), + I16(i16), + I32(i32), + I64(i64), + F32(f32), + F64(f64), +} + +impl AtomVal { + pub fn strat(atom_type: &AtomType) -> BoxedStrategy { + match atom_type { + AtomType::Bool => any::().prop_map(AtomVal::Bool).boxed(), + AtomType::U8 => any::().prop_map(AtomVal::U8).boxed(), + AtomType::U16 => any::().prop_map(AtomVal::U16).boxed(), + AtomType::U32 => any::().prop_map(AtomVal::U32).boxed(), + AtomType::U64 => any::().prop_map(AtomVal::U64).boxed(), + AtomType::I8 => any::().prop_map(AtomVal::I8).boxed(), + AtomType::I16 => any::().prop_map(AtomVal::I16).boxed(), + AtomType::I32 => any::().prop_map(AtomVal::I32).boxed(), + AtomType::I64 => any::().prop_map(AtomVal::I64).boxed(), + AtomType::F32 => any::().prop_map(AtomVal::F32).boxed(), + AtomType::F64 => any::().prop_map(AtomVal::F64).boxed(), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct EnumVal { + pub member_name: String, +} + +impl EnumVal { + pub fn strat(enum_datatype: &EnumDataType) -> impl Strategy { + proptest::sample::select(enum_datatype.members.clone()).prop_map(|mem| EnumVal { + member_name: mem.name, + }) + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct StructVal { + pub members: Vec, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct StructMemberVal { + pub name: String, + pub value: Box, +} + +impl StructMemberVal { + pub fn strat(struct_member: &StructMember, module: &Module) -> BoxedStrategy { + module + .datatype_strat(&struct_member.type_) + .prop_map(|value| StructMemberVal { + name: struct_member.name.clone(), + value: Box::new(value), + }) + .boxed() + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct AliasVal {} + +#[derive(Debug, Clone, PartialEq)] +pub enum DataTypeVal { + Enum(EnumVal), + Struct(StructVal), + Alias(AliasVal), + Atom(AtomVal), +} + +trait ModuleExt { + fn datatype_strat(&self, dtref: &DataTypeRef) -> BoxedStrategy; +} + +impl ModuleExt for Module { + fn datatype_strat(&self, dtref: &DataTypeRef) -> BoxedStrategy { + match dtref { + DataTypeRef::Defined(ident) => { + let dt = self.get_datatype(*ident).expect("ref to defined datatype"); + match dt.entity.variant { + DataTypeVariant::Struct(struct_dt) => unimplemented!(), + DataTypeVariant::Enum(enum_dt) => unimplemented!(), + DataTypeVariant::Alias(alias_dt) => unimplemented!(), + } + } + DataTypeRef::Atom(a) => AtomVal::strat(&a).prop_map(DataTypeVal::Atom).boxed(), + } + } +} diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 03423880e..2a801d806 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -20,7 +20,8 @@ pub use crate::error::IDLError; pub use crate::module::Module; pub use crate::package::Package; pub use crate::types::{ - AtomType, Attr, DataType, DataTypeRef, FuncDecl, FuncRet, Ident, Location, Name, Named, + AliasDataType, AtomType, Attr, DataType, DataTypeRef, DataTypeVariant, EnumDataType, FuncDecl, + FuncRet, Ident, Location, Name, Named, StructDataType, StructMember, }; use crate::c::CGenerator; From ccc2d204295d18d24f2505c84fa3cb8696a437cf Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 5 Jun 2019 14:22:04 -0700 Subject: [PATCH 233/512] lucet-idl-test: we can generate arbitrary values from an idl! next thing todo is render these values as rust and c source text --- lucet-idl/TODO.md | 2 + lucet-idl/lucet-idl-test/src/main.rs | 33 +++++++++++- lucet-idl/lucet-idl-test/src/values.rs | 75 +++++++++++++++++++++----- lucet-idl/src/types.rs | 16 ++++++ 4 files changed, 113 insertions(+), 13 deletions(-) diff --git a/lucet-idl/TODO.md b/lucet-idl/TODO.md index a1ef3b638..9334a8c1d 100644 --- a/lucet-idl/TODO.md +++ b/lucet-idl/TODO.md @@ -1,4 +1,6 @@ * idl-test generates arbitrary values for a given type + * generate rust literals + * generate C literals * describe ABI of functions: * annotations to arguments saying whether they are in, out, or inout * non-atomic arguments need to be passed by reference, cannot be return values diff --git a/lucet-idl/lucet-idl-test/src/main.rs b/lucet-idl/lucet-idl-test/src/main.rs index 5b3c64a4d..52f8a004b 100644 --- a/lucet-idl/lucet-idl-test/src/main.rs +++ b/lucet-idl/lucet-idl-test/src/main.rs @@ -1,13 +1,14 @@ use clap::{App, Arg}; use env_logger; use log::{debug, info}; -use lucet_idl::parse_package; +use lucet_idl::{parse_package, Package}; use lucet_idl_test::{CGuestApp, HostApp, RustGuestApp, Spec, Workspace}; use proptest::prelude::*; use proptest::strategy::ValueTree; use proptest::test_runner::TestRunner; use std::fs::read_to_string; use std::path::PathBuf; +use std::process; fn main() { env_logger::init(); @@ -28,6 +29,11 @@ fn main() { debug!("parsed package: {:?}", pkg); + if exe_config.generate_values { + generate_values(&pkg); + process::exit(0); + } + // Workspace deleted when dropped - need to keep it alive for app to be run let mut guest_apps: Vec<(PathBuf, Workspace)> = Vec::new(); @@ -60,6 +66,7 @@ struct ExeConfig { pub build_rust_guest: bool, pub build_c_guest: bool, pub run_guests: bool, + pub generate_values: bool, } impl ExeConfig { @@ -100,6 +107,13 @@ impl ExeConfig { .long("no-run") .help(""), ) + .arg( + Arg::with_name("generate_values") + .required(false) + .takes_value(false) + .long("generate-values") + .help(""), + ) .get_matches(); ExeConfig { @@ -108,6 +122,23 @@ impl ExeConfig { build_c_guest: !matches.is_present("no_c_guest"), build_rust_guest: !matches.is_present("no_rust_guest"), run_guests: !matches.is_present("no_run") || !matches.is_present("no_host"), + generate_values: matches.is_present("generate_values"), + } + } +} + +fn generate_values(package: &Package) { + use lucet_idl_test::values::*; + + for (_, m) in package.modules.iter() { + for dt in m.datatypes() { + let dt_generator = m.datatype_strat(&dt.datatype_ref()); + let mut runner = TestRunner::default(); + let value = dt_generator + .new_tree(&mut runner) + .expect("create valuetree") + .current(); + println!("type: {:?}\nvalue: {:?}", dt, value); } } } diff --git a/lucet-idl/lucet-idl-test/src/values.rs b/lucet-idl/lucet-idl-test/src/values.rs index 13b405717..98421bc0e 100644 --- a/lucet-idl/lucet-idl-test/src/values.rs +++ b/lucet-idl/lucet-idl-test/src/values.rs @@ -1,6 +1,6 @@ use lucet_idl::{ - AliasDataType, AtomType, DataTypeRef, DataTypeVariant, EnumDataType, Module, StructDataType, - StructMember, + AliasDataType, AtomType, DataTypeRef, DataTypeVariant, EnumDataType, Module, Named, + StructDataType, StructMember, }; use proptest::{self, prelude::*}; @@ -39,22 +39,46 @@ impl AtomVal { #[derive(Debug, Clone, PartialEq, Eq)] pub struct EnumVal { + pub enum_name: String, pub member_name: String, } impl EnumVal { - pub fn strat(enum_datatype: &EnumDataType) -> impl Strategy { - proptest::sample::select(enum_datatype.members.clone()).prop_map(|mem| EnumVal { - member_name: mem.name, + pub fn strat(enum_datatype: &Named) -> impl Strategy { + let name = enum_datatype.name.name.clone(); + proptest::sample::select(enum_datatype.entity.members.clone()).prop_map(move |mem| { + EnumVal { + enum_name: name.clone(), + member_name: mem.name, + } }) } } #[derive(Debug, Clone, PartialEq)] pub struct StructVal { + pub struct_name: String, pub members: Vec, } +impl StructVal { + pub fn strat(struct_dt: &Named, module: &Module) -> BoxedStrategy { + let name = struct_dt.name.name.clone(); + let member_strats: Vec> = struct_dt + .entity + .members + .iter() + .map(|m| StructMemberVal::strat(m, module)) + .collect(); + member_strats + .prop_map(move |members| StructVal { + struct_name: name.clone(), + members, + }) + .boxed() + } +} + #[derive(Debug, Clone, PartialEq)] pub struct StructMemberVal { pub name: String, @@ -63,10 +87,11 @@ pub struct StructMemberVal { impl StructMemberVal { pub fn strat(struct_member: &StructMember, module: &Module) -> BoxedStrategy { + let name = struct_member.name.clone(); module .datatype_strat(&struct_member.type_) - .prop_map(|value| StructMemberVal { - name: struct_member.name.clone(), + .prop_map(move |value| StructMemberVal { + name: name.clone(), value: Box::new(value), }) .boxed() @@ -74,7 +99,23 @@ impl StructMemberVal { } #[derive(Debug, Clone, PartialEq)] -pub struct AliasVal {} +pub struct AliasVal { + pub name: String, + pub value: Box, +} + +impl AliasVal { + pub fn strat(alias_dt: &Named, module: &Module) -> BoxedStrategy { + let name = alias_dt.name.name.clone(); + module + .datatype_strat(&alias_dt.entity.to) + .prop_map(move |value| AliasVal { + name: name.clone(), + value: Box::new(value), + }) + .boxed() + } +} #[derive(Debug, Clone, PartialEq)] pub enum DataTypeVal { @@ -84,7 +125,7 @@ pub enum DataTypeVal { Atom(AtomVal), } -trait ModuleExt { +pub trait ModuleExt { fn datatype_strat(&self, dtref: &DataTypeRef) -> BoxedStrategy; } @@ -94,9 +135,19 @@ impl ModuleExt for Module { DataTypeRef::Defined(ident) => { let dt = self.get_datatype(*ident).expect("ref to defined datatype"); match dt.entity.variant { - DataTypeVariant::Struct(struct_dt) => unimplemented!(), - DataTypeVariant::Enum(enum_dt) => unimplemented!(), - DataTypeVariant::Alias(alias_dt) => unimplemented!(), + DataTypeVariant::Struct(ref struct_dt) => { + StructVal::strat(&dt.using_name(struct_dt), self) + .prop_map(DataTypeVal::Struct) + .boxed() + } + DataTypeVariant::Enum(ref enum_dt) => EnumVal::strat(&dt.using_name(enum_dt)) + .prop_map(DataTypeVal::Enum) + .boxed(), + DataTypeVariant::Alias(ref alias_dt) => { + AliasVal::strat(&dt.using_name(alias_dt), self) + .prop_map(DataTypeVal::Alias) + .boxed() + } } } DataTypeRef::Atom(a) => AtomVal::strat(&a).prop_map(DataTypeVal::Atom).boxed(), diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index 8f2b8c352..cafb602d5 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -151,3 +151,19 @@ pub struct Named<'t, E> { pub name: &'t Name, pub entity: &'t E, } + +impl<'a, T> Named<'a, T> { + pub fn using_name(&self, other: &'a U) -> Named<'a, U> { + Named { + id: self.id, + name: self.name, + entity: other, + } + } +} + +impl<'a> Named<'a, DataType> { + pub fn datatype_ref(&self) -> DataTypeRef { + DataTypeRef::Defined(self.id) + } +} From d7050c96bd22606e2cc3bdf46443d755ec65a633 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 24 Jun 2019 12:25:09 -0700 Subject: [PATCH 234/512] docker: install rustfmt for 1.35.0; set rust-toolchain to 1.35.0 and there's no longer any reason to install cargo-audit and cargo-watch in /usr/local. devenv_build_container adds set -e to help debug --- Dockerfile | 7 +++---- devenv_build_container.sh | 1 + rust-toolchain | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 40d96c0b2..96b8e4a36 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,11 +32,10 @@ RUN curl https://sh.rustup.rs -sSf | \ /root/.cargo/bin/rustup update nightly ENV PATH=/root/.cargo/bin:$PATH -RUN rustup target add wasm32-unknown-wasi \ - --toolchain nightly +RUN rustup component add rustfmt --toolchain 1.35.0-x86_64-unknown-linux-gnu +RUN rustup target add wasm32-unknown-wasi -ENV PATH=/usr/local/bin:$PATH -RUN cargo install --root /usr/local cargo-audit cargo-watch rsign2 +RUN cargo install cargo-audit cargo-watch rsign2 RUN curl -sS -L -O https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-5/wasi-sdk_5.0_amd64.deb \ && dpkg -i wasi-sdk_5.0_amd64.deb && rm -f wasi-sdk_5.0_amd64.deb diff --git a/devenv_build_container.sh b/devenv_build_container.sh index 196cc3064..4c8d51bfa 100755 --- a/devenv_build_container.sh +++ b/devenv_build_container.sh @@ -1,4 +1,5 @@ #!/bin/sh +set -e . "$(dirname ${BASH_SOURCE:-$0})/config.inc" diff --git a/rust-toolchain b/rust-toolchain index 2bf5ad044..2aeaa11ee 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -stable +1.35.0 From 129f39a95f0b24c04946d28fd4d1ea3d635738f1 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 24 Jun 2019 13:41:10 -0700 Subject: [PATCH 235/512] lucet-idl: fixes --- lucet-idl/src/module.rs | 18 +++++++++++++++++- lucet-idl/src/package.rs | 10 ++++++++++ lucet-idl/src/rust.rs | 5 +++-- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index 0e8b7c2d0..3f70c62d1 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -336,7 +336,7 @@ mod tests { fn mod_(syntax: &str) -> Result { let mut parser = Parser::new(syntax); let decls = parser.match_decls().expect("parses"); - Module::from_declarations(&decls, &[]) + Module::from_declarations(&decls, &[], String::new(), String::new()) } #[test] @@ -548,6 +548,8 @@ mod tests { args: Vec::new(), rets: Vec::new(), attrs: Vec::new(), + binding_name: "_trivial".to_owned(), + field_name: "trivial".to_owned(), } )] .into_iter() @@ -555,6 +557,8 @@ mod tests { data_types: HashMap::new(), data_type_ordering: Vec::new(), attrs: Vec::new(), + module_name: String::new(), + binding_prefix: String::new(), } ); } @@ -577,6 +581,8 @@ mod tests { }], rets: Vec::new(), attrs: Vec::new(), + binding_name: "_trivial".to_owned(), + field_name: "trivial".to_owned(), } )] .into_iter() @@ -584,6 +590,8 @@ mod tests { data_types: HashMap::new(), data_type_ordering: Vec::new(), attrs: Vec::new(), + module_name: String::new(), + binding_prefix: String::new(), } ); } @@ -606,6 +614,8 @@ mod tests { attrs: Vec::new(), }], attrs: Vec::new(), + binding_name: "_trivial".to_owned(), + field_name: "trivial".to_owned(), } )] .into_iter() @@ -613,6 +623,8 @@ mod tests { data_types: HashMap::new(), data_type_ordering: Vec::new(), attrs: Vec::new(), + module_name: String::new(), + binding_prefix: String::new(), } ); } @@ -641,6 +653,8 @@ mod tests { attrs: Vec::new(), }], attrs: Vec::new(), + binding_name: "_trivial".to_owned(), + field_name: "trivial".to_owned(), } )] .into_iter() @@ -660,6 +674,8 @@ mod tests { .collect::>(), data_type_ordering: vec![Ident(1)], attrs: Vec::new(), + module_name: String::new(), + binding_prefix: String::new(), } ); } diff --git a/lucet-idl/src/package.rs b/lucet-idl/src/package.rs index 6a4cfeb16..85309c2d2 100644 --- a/lucet-idl/src/package.rs +++ b/lucet-idl/src/package.rs @@ -134,6 +134,8 @@ mod test { data_types: HashMap::new(), data_type_ordering: Vec::new(), funcs: HashMap::new(), + module_name: "empty".to_owned(), + binding_prefix: "__empty".to_owned(), } )] .into_iter() @@ -178,6 +180,8 @@ mod test { data_types: HashMap::new(), data_type_ordering: Vec::new(), funcs: HashMap::new(), + module_name: "empty1".to_owned(), + binding_prefix: "__empty1".to_owned(), } ), ( @@ -188,6 +192,8 @@ mod test { data_types: HashMap::new(), data_type_ordering: Vec::new(), funcs: HashMap::new(), + module_name: "empty2".to_owned(), + binding_prefix: "__empty2".to_owned(), } ), ( @@ -198,6 +204,8 @@ mod test { data_types: HashMap::new(), data_type_ordering: Vec::new(), funcs: HashMap::new(), + module_name: "empty3".to_owned(), + binding_prefix: "__empty3".to_owned(), } ) ] @@ -244,6 +252,8 @@ mod test { .into_iter() .collect::>(), data_type_ordering: vec![Ident(0)], + module_name: "foo".to_owned(), + binding_prefix: "__foo".to_owned(), } )] .into_iter() diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index fc2731f0a..5bbcea940 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -74,11 +74,12 @@ impl RustGenerator { typename } - fn get_defined_typename(&self, data_type_ref: &DataTypeRef) -> &str { + fn get_defined_typename(&self, data_type_ref: &DataTypeRef) -> String { match data_type_ref { DataTypeRef::Defined(id) => self.defined.get(id).expect("definition exists"), DataTypeRef::Atom(a) => Self::atom_name(a), } + .to_owned() } fn atom_name(atom_type: &AtomType) -> &'static str { @@ -111,7 +112,7 @@ impl RustGenerator { .writeln(format!("pub type {} = {};", typename, pointee_name))? .eob()?; - gen_testcase(&mut self.w, &dt.name.name.to_snake_case(), |w| { + gen_testcase(&mut self.w, &dt.name.name.to_snake_case(), move |w| { w.writeln(format!( "assert_eq!({}, ::std::mem::size_of::());", dt.entity.repr_size, typename From 453a5fb441e4aa9b70471e391aeccc36353f2d7c Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 24 Jun 2019 13:45:37 -0700 Subject: [PATCH 236/512] lucet-wasi-fuzz: ensure lucet_wasi hostcalls linked --- lucet-wasi-fuzz/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/lucet-wasi-fuzz/src/main.rs b/lucet-wasi-fuzz/src/main.rs index f8662ab1f..4c0b6e0ce 100644 --- a/lucet-wasi-fuzz/src/main.rs +++ b/lucet-wasi-fuzz/src/main.rs @@ -51,6 +51,7 @@ enum Config { fn main() { lucet_runtime::lucet_internal_ensure_linked(); + lucet_wasi::hostcalls::ensure_linked(); match Config::from_args() { Config::Fuzz { num_tests } => run_many(num_tests), From d24d3e8ae3ca750b2c8883f1f34ce241d533b835 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 25 Jun 2019 13:36:49 -0700 Subject: [PATCH 237/512] lucet-idl-test: normalization is self->Self --- lucet-idl/lucet-idl-test/src/syntax.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lucet-idl/lucet-idl-test/src/syntax.rs b/lucet-idl/lucet-idl-test/src/syntax.rs index 21248e698..9bc46cee1 100644 --- a/lucet-idl/lucet-idl-test/src/syntax.rs +++ b/lucet-idl/lucet-idl-test/src/syntax.rs @@ -53,7 +53,7 @@ impl DatatypeRef { any::().prop_map(DatatypeRef) } - pub fn normalize(&self, highest_definition: usize) -> Self { + pub fn normalize(self, highest_definition: usize) -> Self { assert!(highest_definition != 0); DatatypeRef(self.0 % highest_definition) } @@ -70,7 +70,7 @@ pub enum DatatypeName { } impl DatatypeName { - pub fn normalize(&self, highest_definition: usize) -> Self { + pub fn normalize(self, highest_definition: usize) -> Self { match self { DatatypeName::Defined(def) => { if highest_definition == 0 { @@ -128,10 +128,10 @@ impl StructSyntax { .prop_map(|members| StructSyntax { members }) } - pub fn normalize(&self, highest_definition: usize) -> Self { + pub fn normalize(self, highest_definition: usize) -> Self { let members = self .members - .iter() + .into_iter() .map(|m| m.normalize(highest_definition)) .collect(); Self { members } @@ -155,7 +155,7 @@ impl AliasSyntax { pub fn strat() -> impl Strategy { DatatypeName::strat().prop_map(|target| AliasSyntax { target }) } - pub fn normalize(&self, highest_definition: usize) -> Self { + pub fn normalize(self, highest_definition: usize) -> Self { Self { target: self.target.normalize(highest_definition), } @@ -181,7 +181,7 @@ impl DatatypeSyntax { ] } - pub fn normalize(&self, highest_definition: usize) -> Self { + pub fn normalize(self, highest_definition: usize) -> Self { match self { DatatypeSyntax::Enum(e) => DatatypeSyntax::Enum(e.clone()), DatatypeSyntax::Struct(s) => DatatypeSyntax::Struct(s.normalize(highest_definition)), @@ -213,10 +213,10 @@ impl FunctionSyntax { .prop_map(|(args, ret)| FunctionSyntax { args, ret }) } - pub fn normalize(&self, highest_definition: usize) -> Self { + pub fn normalize(self, highest_definition: usize) -> Self { let args = self .args - .iter() + .into_iter() .map(|a| a.normalize(highest_definition)) .collect(); let ret = self.ret.clone().map(|a| a.normalize(highest_definition)); @@ -256,13 +256,13 @@ impl Spec { function_decls: Vec, ) -> Self { let datatype_decls: Vec = datatype_decls - .iter() + .into_iter() .enumerate() .map(|(ix, decl)| decl.normalize(ix)) .collect(); let num_datatypes = datatype_decls.len(); let function_decls = function_decls - .iter() + .into_iter() .map(|decl| decl.normalize(num_datatypes)) .collect(); Spec { From 2bb55aedad98f046d487780d8054ab3b5e569bcb Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 25 Jun 2019 13:38:33 -0700 Subject: [PATCH 238/512] lucet-idl-test: comments --- lucet-idl/lucet-idl-test/src/syntax.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lucet-idl/lucet-idl-test/src/syntax.rs b/lucet-idl/lucet-idl-test/src/syntax.rs index 9bc46cee1..707f5f2c3 100644 --- a/lucet-idl/lucet-idl-test/src/syntax.rs +++ b/lucet-idl/lucet-idl-test/src/syntax.rs @@ -74,6 +74,7 @@ impl DatatypeName { match self { DatatypeName::Defined(def) => { if highest_definition == 0 { + // No defined type to normalize to - instead use an atom type. DatatypeName::Atom(AtomType::I64) } else { DatatypeName::Defined(def.normalize(highest_definition)) @@ -105,6 +106,7 @@ pub struct EnumSyntax { impl EnumSyntax { pub fn strat() -> impl Strategy { + // up to 20 variants for now. probably want to allow more in the future? (1..20usize).prop_map(|variants| EnumSyntax { variants }) } From 72272e970ecc19f2fa6c913eeee3fc57855e3bf4 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 25 Jun 2019 13:49:26 -0700 Subject: [PATCH 239/512] lucet-idl-test: dropping lockfile sufficient to unlock --- lucet-idl/lucet-idl-test/src/host.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lucet-idl/lucet-idl-test/src/host.rs b/lucet-idl/lucet-idl-test/src/host.rs index d577a8cb6..043c0fb7f 100644 --- a/lucet-idl/lucet-idl-test/src/host.rs +++ b/lucet-idl/lucet-idl-test/src/host.rs @@ -8,9 +8,11 @@ use tempfile::TempDir; pub struct HostApp { root: PathBuf, - lockfile: File, tempdir: TempDir, backups: Vec<(PathBuf, PathBuf)>, + // lockfile is never used in methods, it just needs to have the same lifetime as the app, it + // gets unlocked when HostApp drops + _lockfile: File, } impl HostApp { @@ -31,7 +33,7 @@ impl HostApp { let mut hostapp = HostApp { root, - lockfile, + _lockfile: lockfile, tempdir: TempDir::new()?, backups: Vec::new(), }; @@ -97,6 +99,5 @@ impl Drop for HostApp { for (backup, orig) in self.backups.iter() { fs::rename(backup, orig).expect("restore backup") } - self.lockfile.unlock().expect("unlock"); } } From 33a783c4c755b8a9eeb25f914a3ac99b62ef7a7a Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 25 Jun 2019 16:09:33 -0700 Subject: [PATCH 240/512] lucet-idl-test: use wasi sdk library rather than call executable --- lucet-idl/lucet-idl-test/Cargo.toml | 1 + lucet-idl/lucet-idl-test/src/c_guest.rs | 24 ++++++------------------ 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/lucet-idl/lucet-idl-test/Cargo.toml b/lucet-idl/lucet-idl-test/Cargo.toml index b310979ec..ca056d3e9 100644 --- a/lucet-idl/lucet-idl-test/Cargo.toml +++ b/lucet-idl/lucet-idl-test/Cargo.toml @@ -16,6 +16,7 @@ lucet-idl = { path = "../" } lucetc = { path = "../../lucetc" } lucet-runtime = { path = "../../lucet-runtime" } lucet-wasi = { path = "../../lucet-wasi" } +lucet-wasi-sdk = { path = "../../lucet-wasi-sdk" } proptest = "0.9.3" tempfile = "3.0" failure = "0.1" diff --git a/lucet-idl/lucet-idl-test/src/c_guest.rs b/lucet-idl/lucet-idl-test/src/c_guest.rs index 1895d2d50..2adad8fc8 100644 --- a/lucet-idl/lucet-idl-test/src/c_guest.rs +++ b/lucet-idl/lucet-idl-test/src/c_guest.rs @@ -2,6 +2,7 @@ use crate::workspace::Workspace; use failure::{format_err, Error}; use lucet_idl::{self, Backend, Config, Package}; use lucet_wasi; +use lucet_wasi_sdk::{CompileOpts, Link}; use lucetc::{Lucetc, LucetcOpts}; use std::fs::File; use std::io::Write; @@ -43,28 +44,15 @@ int main(int argc, char* argv[]) { )?; Ok(()) } - fn wasi_clang(&mut self) -> Result<(), Error> { - let wasi_sdk = - PathBuf::from(std::env::var("WASI_SDK").unwrap_or_else(|_| "/opt/wasi-sdk".to_owned())); - let cmd_cc = Command::new(wasi_sdk.join("bin").join("clang")) - .arg("--std=c99") - .arg(self.work.source_path("main.c")) - .arg("-I") - .arg(self.work.source_path("")) - .arg("-o") - .arg(self.work.output_path("out.wasm")) - .status()?; - - if !cmd_cc.success() { - Err(format_err!("clang error building guest"))? - } - Ok(()) - } pub fn build(&mut self, package: &Package) -> Result { self.generate_idl_h(package)?; self.generate_main_c()?; - self.wasi_clang()?; + + Link::new(&[self.work.source_path("main.c")]) + .with_include(self.work.source_path("")) + .link(&self.work.output_path("out.wasm"))?; + let mut bindings = lucet_wasi::bindings(); bindings.extend(&package.bindings())?; let lucetc = Lucetc::new(self.work.output_path("out.wasm")).with_bindings(bindings); From 1b47b377e0e2c254b247a5202ef96d778b2b6d04 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 25 Jun 2019 17:06:07 -0700 Subject: [PATCH 241/512] [lucet-wasi-fuzz] make clang configurable and add error code --- lucet-wasi-fuzz/src/main.rs | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/lucet-wasi-fuzz/src/main.rs b/lucet-wasi-fuzz/src/main.rs index 1757838df..2d7214ea9 100644 --- a/lucet-wasi-fuzz/src/main.rs +++ b/lucet-wasi-fuzz/src/main.rs @@ -49,6 +49,7 @@ enum Config { fn main() { lucet_runtime::lucet_internal_ensure_linked(); + lucet_wasi::hostcalls::ensure_linked(); match Config::from_args() { Config::Fuzz { num_tests } => run_many(num_tests), @@ -95,7 +96,7 @@ fn run_creduce_driver(seed: Seed) { .unwrap(); assert!(st.success()); - let st = Command::new("clang") + let st = Command::new(native_clang()) .arg("-I/usr/include/csmith") .arg("-m32") .arg("-E") @@ -191,7 +192,10 @@ fn run_one_seed(seed: Seed) { println!("lucet-wasi: {}", String::from_utf8_lossy(&actual)); exit(1); } - Ok(TestResult::Errored { error }) | Err(error) => println!("test errored: {}", error), + Ok(TestResult::Errored { error }) | Err(error) => { + println!("test errored: {}", error); + exit(1); + } } } @@ -277,8 +281,8 @@ fn run_both>( fn run_native>(tmpdir: &TempDir, gen_c_path: P) -> Result>, Error> { let gen_path = tmpdir.path().join("gen"); - let res = Command::new("clang") - .arg("-m32") + let mut cmd = Command::new(native_clang()); + cmd.arg("-m32") .arg("-std=c11") .arg("-Werror=format") .arg("-Werror=uninitialized") @@ -286,8 +290,14 @@ fn run_native>(tmpdir: &TempDir, gen_c_path: P) -> Result>(tmpdir: &TempDir, c_file: P) -> Result) } + +fn native_clang() -> PathBuf { + match std::env::var("NATIVE_CLANG") { + Ok(clang) => PathBuf::from(clang), + Err(_) => PathBuf::from("clang"), + } +} From 15388c5d352300662d1a870371e13b21574cfac1 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 25 Jun 2019 18:00:19 -0700 Subject: [PATCH 242/512] fix cargo.lock --- Cargo.lock | 117 +++++++++++++++++++++++++---------------------------- 1 file changed, 55 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 82bd6250a..79c422ed3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,7 +51,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -97,7 +97,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -152,7 +152,7 @@ dependencies = [ "block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -391,8 +391,8 @@ dependencies = [ "rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -452,7 +452,7 @@ name = "crypto-mac" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -464,7 +464,7 @@ dependencies = [ "csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -480,7 +480,7 @@ name = "digest" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -546,7 +546,7 @@ name = "failure" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.30 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -557,7 +557,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.38 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -568,7 +568,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "flate2" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -587,7 +587,7 @@ name = "fs2" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -603,7 +603,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "generic-array" -version = "0.12.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -786,13 +786,9 @@ version = "0.1.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -<<<<<<< 415d8fff3d93c96d4e5208f33d82ca2cf947c5bb - "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", -======= "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lucetc 0.1.0", - "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ->>>>>>> lucet-idl: start stubbing out rust backend + "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -808,9 +804,10 @@ dependencies = [ "lucet-idl 0.1.0", "lucet-runtime 0.1.0", "lucet-wasi 0.1.0", + "lucet-wasi-sdk 0.1.0", "lucetc 0.1.0", - "proptest 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -837,7 +834,7 @@ dependencies = [ "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "object 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -900,7 +897,7 @@ dependencies = [ "lucet-module-data 0.1.0", "lucet-runtime 0.1.0", "lucetc 0.1.0", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -980,7 +977,7 @@ dependencies = [ "lucet-wasi-sdk 0.1.0", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.35.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1084,7 +1081,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.38 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1140,7 +1137,7 @@ name = "object" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "flate2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1222,21 +1219,21 @@ dependencies = [ [[package]] name = "proptest" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "rusty-fork 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1485,7 +1482,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1523,7 +1520,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.38 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1553,20 +1550,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.38 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1576,7 +1573,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1604,8 +1601,8 @@ dependencies = [ "libloading 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "precision 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "printtable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1621,7 +1618,7 @@ name = "string-interner" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1646,7 +1643,7 @@ dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.38 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1656,7 +1653,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "0.15.36" +version = "0.15.38" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1671,7 +1668,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.38 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1757,7 +1754,7 @@ name = "tinytemplate" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1766,7 +1763,7 @@ name = "toml" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1824,8 +1821,8 @@ name = "wabt" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1867,8 +1864,8 @@ dependencies = [ "goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.35.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1963,7 +1960,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" -"checksum backtrace 0.3.30 (registry+https://github.com/rust-lang/crates.io-index)" = "ada4c783bb7e7443c14e0480f429ae2cc99da95065aeab7ee1b81ada0419404f" +"checksum backtrace 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)" = "e0f77aa27f55a4beb477ff6bc4d9bf72f90eb422b19c1d8e5a644b8aeb674d66" "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum bencher 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdb4953a096c551ce9ace855a604d702e6e62d77fac690575ae347571717f5" @@ -2010,12 +2007,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" -"checksum flate2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "246b6f24d8e616b0c176a8143486ddc8bb0bac2f30f0a0d3efbcf1e0d47cb7e5" +"checksum flate2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "550934ad4808d5d39365e5d61727309bf18b3b02c6c56b729cb92e7dd84bc3d8" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" -"checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" +"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" "checksum getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8d1dffef07351aafe6ef177e4dd2b8dcf503e6bc765dea3b0de9ed149a3db1ec" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6a4013e9182f2345c6b7829b9ef6e670bce0dfca12c6f974457ed2160c2c7fe9" @@ -2063,7 +2060,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum printtable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "69967dae4cac71681361899d9905d3d2985fc989d7afb32a8dff3aed5461ecdf" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b820305721858696053a7fd0215cfeeee16ecaaf96b7a209945428e02f1c44" -"checksum proptest 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2afed8cbdc8a64b58a5c021757a782351ec1afee85be374872721c84d5da5d80" +"checksum proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf147e022eacf0c8a054ab864914a7602618adba841d800a9a9868a5237a529f" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" @@ -2091,12 +2088,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rpassword 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34fa7bcae7fca3c8471e8417088bbc3ad9af8066b0ecf4f3c0d98a0d772716e" "checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -<<<<<<< 84f050b6702c8e478a056be5622527662dd6fd2f -"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f" -======= "checksum rusty-fork 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd93264e10c577503e926bd1430193eeb5d21b059148910082245309b424fae" -"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" ->>>>>>> lucet-idl-test: property-based testing of rust, c backends +"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f" "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f84d114ef17fd144153d608fba7c446b0145d038985e7a8cc5d08bb0ce20383" @@ -2104,8 +2097,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum scrypt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "656c79d0e90d0ab28ac86bf3c3d10bfbbac91450d3f190113b4e76d9fec3cfdd" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "32746bf0f26eab52f06af0d0aa1984f641341d06d8d673c693871da2d188c9be" -"checksum serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "46a3223d0c9ba936b61c0d2e3e559e3217dbfb8d65d06d26e8b3c25de38bae3e" +"checksum serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)" = "960e29cf7004b3b6e65fc5002981400eb3ccc017a08a2406940823e58e7179a9" +"checksum serde_derive 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)" = "c4cce6663696bd38272e90bf34a0267e1226156c33f52d3f3915a2dd5d802085" "checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" "checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" @@ -2114,7 +2107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fa19a5a708e22bb5be31c1b6108a2a902f909c4b9ba85cba44c06632386bc0ff" "checksum structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "c6d59d0ae8ef8de16e49e3ca7afa16024a3e0dfd974a75ef93fdc5464e34523f" "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" -"checksum syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)" = "8b4f551a91e2e3848aeef8751d0d4eec9489b6474c720fd4c55958d8d31a430c" +"checksum syn 0.15.38 (registry+https://github.com/rust-lang/crates.io-index)" = "37ea458a750f59ab679b47fef9b6722c586c5742f4cfe18a120bbc807e5e01fd" "checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" "checksum target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6923974ce4eb5bd28814756256d8ab71c28dd6e7483313fe7ab6614306bf633" "checksum target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b0ab4982b8945c35cc1c46a83a9094c414f6828a099ce5dcaa8ee2b04642dcb" From 9964c94283c35727ef10f23f92054d3e70635003 Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Thu, 27 Jun 2019 00:48:40 +0200 Subject: [PATCH 243/512] Move wasi-sdk tests from lucetc to wasi-sdk (#231) --- Cargo.lock | 1 - lucet-wasi-sdk/src/lib.rs | 98 +------------- lucet-wasi-sdk/{test => tests}/a.c | 0 lucet-wasi-sdk/{test => tests}/b.c | 0 .../wasi-sdk/a.c => lucet-wasi-sdk/tests/c.c | 2 +- lucet-wasi-sdk/tests/compile_and_link.rs | 91 +++++++++++++ lucet-wasi-sdk/tests/d.c | 7 + .../wasi-sdk => lucet-wasi-sdk/tests}/empty.c | 0 .../tests/lucetc.rs | 124 ++++++++---------- .../tests}/main_returns.c | 0 lucetc/Cargo.toml | 3 - lucetc/tests/wasi-sdk/b.c | 7 - 12 files changed, 160 insertions(+), 173 deletions(-) rename lucet-wasi-sdk/{test => tests}/a.c (100%) rename lucet-wasi-sdk/{test => tests}/b.c (100%) rename lucetc/tests/wasi-sdk/a.c => lucet-wasi-sdk/tests/c.c (62%) create mode 100644 lucet-wasi-sdk/tests/compile_and_link.rs create mode 100644 lucet-wasi-sdk/tests/d.c rename {lucetc/tests/wasi-sdk => lucet-wasi-sdk/tests}/empty.c (100%) rename lucetc/tests/wasi-sdk.rs => lucet-wasi-sdk/tests/lucetc.rs (58%) rename {lucetc/tests/wasi-sdk => lucet-wasi-sdk/tests}/main_returns.c (100%) delete mode 100644 lucetc/tests/wasi-sdk/b.c diff --git a/Cargo.lock b/Cargo.lock index 79c422ed3..42dd75367 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -974,7 +974,6 @@ dependencies = [ "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module-data 0.1.0", - "lucet-wasi-sdk 0.1.0", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.35.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/lucet-wasi-sdk/src/lib.rs b/lucet-wasi-sdk/src/lib.rs index 4791b33d2..6939a88dd 100644 --- a/lucet-wasi-sdk/src/lib.rs +++ b/lucet-wasi-sdk/src/lib.rs @@ -375,98 +375,8 @@ impl lucetc::AsLucetc for Lucetc { } } -#[cfg(test)] -mod tests { - use super::*; - use tempfile::TempDir; - #[test] - fn wasi_sdk_installed() { - let clang = wasm_clang(); - assert!(clang.exists(), "clang executable exists"); - } - - fn test_file(name: &str) -> PathBuf { - let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - p.push("test"); - p.push(name); - assert!(p.exists(), "test file does not exist"); - p - } - - #[test] - fn compile_a() { - let tmp = TempDir::new().expect("create temporary directory"); - - let compiler = Compile::new(test_file("a.c")); - - let objfile = tmp.path().join("a.o"); - - compiler.compile(objfile.clone()).expect("compile a.c"); - - assert!(objfile.exists(), "object file created"); - - let mut linker = Link::new(&[objfile]); - linker.cflag("-nostartfiles"); - linker.link_opt(LinkOpt::NoDefaultEntryPoint); - - let wasmfile = tmp.path().join("a.wasm"); - - linker.link(wasmfile.clone()).expect("link a.wasm"); - - assert!(wasmfile.exists(), "wasm file created"); - } - - #[test] - fn compile_b() { - let tmp = TempDir::new().expect("create temporary directory"); - - let compiler = Compile::new(test_file("b.c")); - - let objfile = tmp.path().join("b.o"); - - compiler.compile(objfile.clone()).expect("compile b.c"); - - assert!(objfile.exists(), "object file created"); - - let mut linker = Link::new(&[objfile]); - linker.cflag("-nostartfiles"); - linker.link_opt(LinkOpt::NoDefaultEntryPoint); - linker.link_opt(LinkOpt::AllowUndefinedAll); - - let wasmfile = tmp.path().join("b.wasm"); - - linker.link(wasmfile.clone()).expect("link b.wasm"); - - assert!(wasmfile.exists(), "wasm file created"); - } - - #[test] - fn compile_a_and_b() { - let tmp = TempDir::new().expect("create temporary directory"); - - let mut linker = Link::new(&[test_file("a.c"), test_file("b.c")]); - linker.cflag("-nostartfiles"); - linker.link_opt(LinkOpt::NoDefaultEntryPoint); - - let wasmfile = tmp.path().join("ab.wasm"); - - linker.link(wasmfile.clone()).expect("link ab.wasm"); - - assert!(wasmfile.exists(), "wasm file created"); - } - - #[test] - fn compile_to_lucet() { - let tmp = TempDir::new().expect("create temporary directory"); - - let mut lucetc = Lucetc::new(&[test_file("a.c"), test_file("b.c")]); - lucetc.cflag("-nostartfiles"); - lucetc.link_opt(LinkOpt::NoDefaultEntryPoint); - - let so_file = tmp.path().join("ab.so"); - - lucetc.build(&so_file).expect("compile ab.so"); - - assert!(so_file.exists(), "so file created"); - } +#[test] +fn wasi_sdk_installed() { + let clang = wasm_clang(); + assert!(clang.exists(), "clang executable exists"); } diff --git a/lucet-wasi-sdk/test/a.c b/lucet-wasi-sdk/tests/a.c similarity index 100% rename from lucet-wasi-sdk/test/a.c rename to lucet-wasi-sdk/tests/a.c diff --git a/lucet-wasi-sdk/test/b.c b/lucet-wasi-sdk/tests/b.c similarity index 100% rename from lucet-wasi-sdk/test/b.c rename to lucet-wasi-sdk/tests/b.c diff --git a/lucetc/tests/wasi-sdk/a.c b/lucet-wasi-sdk/tests/c.c similarity index 62% rename from lucetc/tests/wasi-sdk/a.c rename to lucet-wasi-sdk/tests/c.c index 76dad32b6..4e7984145 100644 --- a/lucetc/tests/wasi-sdk/a.c +++ b/lucet-wasi-sdk/tests/c.c @@ -1,5 +1,5 @@ -int a(int arg) +int c(int arg) { return arg + 1; } diff --git a/lucet-wasi-sdk/tests/compile_and_link.rs b/lucet-wasi-sdk/tests/compile_and_link.rs new file mode 100644 index 000000000..3544631f6 --- /dev/null +++ b/lucet-wasi-sdk/tests/compile_and_link.rs @@ -0,0 +1,91 @@ +#[cfg(test)] +mod compile_and_link_tests { + use lucet_wasi_sdk::*; + use std::path::PathBuf; + use tempfile::TempDir; + + fn test_file(name: &str) -> PathBuf { + let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + p.push("tests"); + p.push(name); + assert!(p.exists(), "test file does not exist"); + p + } + + #[test] + fn compile_a() { + let tmp = TempDir::new().expect("create temporary directory"); + + let compiler = Compile::new(test_file("a.c")); + + let objfile = tmp.path().join("a.o"); + + compiler.compile(objfile.clone()).expect("compile a.c"); + + assert!(objfile.exists(), "object file created"); + + let mut linker = Link::new(&[objfile]); + linker.cflag("-nostartfiles"); + linker.link_opt(LinkOpt::NoDefaultEntryPoint); + + let wasmfile = tmp.path().join("a.wasm"); + + linker.link(wasmfile.clone()).expect("link a.wasm"); + + assert!(wasmfile.exists(), "wasm file created"); + } + + #[test] + fn compile_b() { + let tmp = TempDir::new().expect("create temporary directory"); + + let compiler = Compile::new(test_file("b.c")); + + let objfile = tmp.path().join("b.o"); + + compiler.compile(objfile.clone()).expect("compile b.c"); + + assert!(objfile.exists(), "object file created"); + + let mut linker = Link::new(&[objfile]); + linker.cflag("-nostartfiles"); + linker.link_opt(LinkOpt::NoDefaultEntryPoint); + linker.link_opt(LinkOpt::AllowUndefinedAll); + + let wasmfile = tmp.path().join("b.wasm"); + + linker.link(wasmfile.clone()).expect("link b.wasm"); + + assert!(wasmfile.exists(), "wasm file created"); + } + + #[test] + fn compile_a_and_b() { + let tmp = TempDir::new().expect("create temporary directory"); + + let mut linker = Link::new(&[test_file("a.c"), test_file("b.c")]); + linker.cflag("-nostartfiles"); + linker.link_opt(LinkOpt::NoDefaultEntryPoint); + + let wasmfile = tmp.path().join("ab.wasm"); + + linker.link(wasmfile.clone()).expect("link ab.wasm"); + + assert!(wasmfile.exists(), "wasm file created"); + } + + #[test] + fn compile_to_lucet() { + let tmp = TempDir::new().expect("create temporary directory"); + + let mut lucetc = Lucetc::new(&[test_file("a.c"), test_file("b.c")]); + lucetc.cflag("-nostartfiles"); + lucetc.link_opt(LinkOpt::NoDefaultEntryPoint); + + let so_file = tmp.path().join("ab.so"); + + lucetc.build(&so_file).expect("compile ab.so"); + + assert!(so_file.exists(), "so file created"); + } +} diff --git a/lucet-wasi-sdk/tests/d.c b/lucet-wasi-sdk/tests/d.c new file mode 100644 index 000000000..950fe8e53 --- /dev/null +++ b/lucet-wasi-sdk/tests/d.c @@ -0,0 +1,7 @@ + +extern int c(int); + +int d(int arg) +{ + return 3 * c(arg); +} diff --git a/lucetc/tests/wasi-sdk/empty.c b/lucet-wasi-sdk/tests/empty.c similarity index 100% rename from lucetc/tests/wasi-sdk/empty.c rename to lucet-wasi-sdk/tests/empty.c diff --git a/lucetc/tests/wasi-sdk.rs b/lucet-wasi-sdk/tests/lucetc.rs similarity index 58% rename from lucetc/tests/wasi-sdk.rs rename to lucet-wasi-sdk/tests/lucetc.rs index 72f5172f2..ef1b5518e 100644 --- a/lucetc/tests/wasi-sdk.rs +++ b/lucet-wasi-sdk/tests/lucetc.rs @@ -1,55 +1,37 @@ -use failure::{Error, ResultExt}; -use lucet_wasi_sdk::{CompileOpts, Link, LinkOpt, LinkOpts}; -use lucetc::Bindings; -use std::collections::HashMap; -use std::fs::File; -use std::io::Read; -use std::path::PathBuf; -use std::str; -use tempfile; - -fn module_from_c(cfiles: &[&str], exports: &[&str]) -> Result, Error> { - let cfiles: Vec = cfiles - .iter() - .map(|ref name| PathBuf::from(format!("tests/wasi-sdk/{}.c", name))) - .collect(); - let tempdir = tempfile::Builder::new() - .prefix("wasi-sdk-test") - .tempdir() - .context("tempdir creation")?; - - let mut wasm = PathBuf::from(tempdir.path()); - wasm.push("out.wasm"); - - let mut linker = Link::new(&cfiles) - .with_cflag("-nostartfiles") - .with_link_opt(LinkOpt::NoDefaultEntryPoint) - .with_link_opt(LinkOpt::AllowUndefinedAll); - for export in exports { - linker.export(export); - } - linker.link(wasm.clone())?; - - let mut wasm_file = File::open(wasm)?; - let mut wasm_contents = Vec::new(); - wasm_file.read_to_end(&mut wasm_contents)?; - Ok(wasm_contents) -} - -fn b_only_test_bindings() -> Bindings { - let imports: HashMap = [ - ("a".into(), "a".into()), // b_only - ] - .iter() - .cloned() - .collect(); - - Bindings::env(imports) -} - -mod programs { - use super::{b_only_test_bindings, module_from_c}; +#[cfg(test)] +mod lucetc_tests { + use failure::Error; + use lucet_wasi_sdk::*; use lucetc::{Bindings, Compiler, HeapSettings, OptLevel}; + use std::collections::HashMap; + use std::fs::File; + use std::io::Read; + use std::path::PathBuf; + + fn module_from_c(cfiles: &[&str], exports: &[&str]) -> Result, Error> { + let cfiles: Vec = cfiles + .iter() + .map(|ref name| PathBuf::from(format!("tests/{}.c", name))) + .collect(); + let tempdir = tempfile::Builder::new().prefix("wasi-sdk-test").tempdir()?; + + let mut wasm = PathBuf::from(tempdir.path()); + wasm.push("out.wasm"); + + let mut linker = Link::new(&cfiles) + .with_cflag("-nostartfiles") + .with_link_opt(LinkOpt::NoDefaultEntryPoint) + .with_link_opt(LinkOpt::AllowUndefinedAll); + for export in exports { + linker.export(export); + } + linker.link(wasm.clone())?; + + let mut wasm_file = File::open(wasm)?; + let mut wasm_contents = Vec::new(); + wasm_file.read_to_end(&mut wasm_contents)?; + Ok(wasm_contents) + } #[test] fn empty() { @@ -75,15 +57,24 @@ mod programs { let _obj = c.object_file().expect("generate code from empty"); } - #[test] - fn just_a() { - let m = module_from_c(&["a"], &["a"]).expect("build module for a"); + fn d_only_test_bindings() -> Bindings { + let imports: HashMap = [ + ("c".into(), "c".into()), // d_only + ] + .iter() + .cloned() + .collect(); + Bindings::env(imports) + } + + #[test] + fn just_c() { + let m = module_from_c(&["c"], &["c"]).expect("build module for c"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile a"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile c"); let mdata = c.module_data().unwrap(); - assert_eq!(mdata.import_functions().len(), 0, "import functions"); assert_eq!(mdata.export_functions().len(), 1, "export functions"); @@ -91,15 +82,15 @@ mod programs { assert_eq!(num_import_globals(&p), 0, "import globals"); */ - let _obj = c.object_file().expect("generate code from a"); + let _obj = c.object_file().expect("generate code from c"); } #[test] - fn just_b() { - let m = module_from_c(&["b"], &["b"]).expect("build module for b"); - let b = b_only_test_bindings(); + fn just_d() { + let m = module_from_c(&["d"], &["d"]).expect("build module for d"); + let b = d_only_test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile b"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile d"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 1, "import functions"); assert_eq!(mdata.export_functions().len(), 1, "export functions"); @@ -107,15 +98,15 @@ mod programs { /* FIXME: module data doesn't contain the information to check these properties: assert_eq!(num_import_globals(&p), 0, "import globals"); */ - let _obj = c.object_file().expect("generate code from b"); + let _obj = c.object_file().expect("generate code from d"); } #[test] - fn a_and_b() { - let m = module_from_c(&["a", "b"], &["a", "b"]).expect("build module for a & b"); + fn c_and_d() { + let m = module_from_c(&["c", "d"], &["c", "d"]).expect("build module for c & d"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile a & b"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile c & d"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 0, "import functions"); assert_eq!(mdata.export_functions().len(), 2, "export functions"); @@ -123,7 +114,6 @@ mod programs { /* FIXME: module data doesn't contain the information to check these properties: assert_eq!(num_import_globals(&p), 0, "import globals"); */ - let _obj = c.object_file().expect("generate code from a & b"); + let _obj = c.object_file().expect("generate code from c & d"); } - } diff --git a/lucetc/tests/wasi-sdk/main_returns.c b/lucet-wasi-sdk/tests/main_returns.c similarity index 100% rename from lucetc/tests/wasi-sdk/main_returns.c rename to lucet-wasi-sdk/tests/main_returns.c diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index 9d7e25926..e34689b06 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -41,6 +41,3 @@ bimap = "0.2" human-size = "0.4" parity-wasm = "0.35" minisign = "0.5.11" - -[dev-dependencies] -lucet-wasi-sdk = { path = "../lucet-wasi-sdk" } diff --git a/lucetc/tests/wasi-sdk/b.c b/lucetc/tests/wasi-sdk/b.c deleted file mode 100644 index e0f9c0371..000000000 --- a/lucetc/tests/wasi-sdk/b.c +++ /dev/null @@ -1,7 +0,0 @@ - -extern int a(int); - -int b(int arg) -{ - return 3 * a(arg); -} From d4426eecd52ab3398640665fad852966ebe47942 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 26 Jun 2019 16:11:31 -0700 Subject: [PATCH 244/512] move Bindings from lucetc to lucet-module-data bindings are an (implicit) contract between compiler and runtime, so they belong there instead more importantly this breaks the dependency between lucet-wasi and lucetc. --- Cargo.lock | 7 +++++-- benchmarks/lucet-benchmarks/src/modules.rs | 4 ++-- lucet-idl/Cargo.toml | 1 + lucet-idl/src/lib.rs | 2 +- lucet-idl/src/package.rs | 2 +- lucet-module-data/Cargo.toml | 3 ++- {lucetc => lucet-module-data}/src/bindings.rs | 0 lucet-module-data/src/lib.rs | 1 + .../tests/bindings/bad_bindings.json | 0 .../tests/bindings/bindings_test.json | 0 {lucetc => lucet-module-data}/tests/bindings/garbage.json | 0 lucet-runtime/lucet-runtime-tests/src/build.rs | 3 ++- lucet-spectest/src/bindings.rs | 2 +- lucet-wasi-fuzz/Cargo.toml | 1 + lucet-wasi-fuzz/src/main.rs | 3 ++- lucet-wasi-sdk/Cargo.toml | 1 + lucet-wasi-sdk/tests/lucetc.rs | 3 ++- lucet-wasi/Cargo.toml | 3 ++- lucet-wasi/src/bindings.rs | 2 +- lucetc/Cargo.toml | 2 -- lucetc/src/compiler.rs | 2 +- lucetc/src/decls.rs | 2 +- lucetc/src/lib.rs | 3 +-- lucetc/src/main.rs | 4 ++-- lucetc/tests/wasm.rs | 5 +++-- 25 files changed, 33 insertions(+), 23 deletions(-) rename {lucetc => lucet-module-data}/src/bindings.rs (100%) rename {lucetc => lucet-module-data}/tests/bindings/bad_bindings.json (100%) rename {lucetc => lucet-module-data}/tests/bindings/bindings_test.json (100%) rename {lucetc => lucet-module-data}/tests/bindings/garbage.json (100%) diff --git a/Cargo.lock b/Cargo.lock index 42dd75367..4e99c4ea8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -787,6 +787,7 @@ dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lucet-module-data 0.1.0", "lucetc 0.1.0", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -835,6 +836,7 @@ dependencies = [ "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "object 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -913,6 +915,7 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "lucet-module-data 0.1.0", "lucet-runtime 0.1.0", "lucet-runtime-internals 0.1.0", "lucet-wasi-sdk 0.1.0", @@ -929,6 +932,7 @@ dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "lucet-module-data 0.1.0", "lucet-runtime 0.1.0", "lucet-wasi 0.1.0", "lucet-wasi-sdk 0.1.0", @@ -949,6 +953,7 @@ name = "lucet-wasi-sdk" version = "0.1.0" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lucet-module-data 0.1.0", "lucetc 0.1.0", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -976,8 +981,6 @@ dependencies = [ "lucet-module-data 0.1.0", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.35.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/benchmarks/lucet-benchmarks/src/modules.rs b/benchmarks/lucet-benchmarks/src/modules.rs index 7a6b51d50..5ee9fb824 100644 --- a/benchmarks/lucet-benchmarks/src/modules.rs +++ b/benchmarks/lucet-benchmarks/src/modules.rs @@ -1,10 +1,10 @@ -use lucet_module_data::{lucet_signature, FunctionPointer}; +use lucet_module_data::{bindings::Bindings, lucet_signature, FunctionPointer}; use lucet_runtime::lucet_hostcalls; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime_internals::module::{HeapSpec, MockModuleBuilder, Module}; use lucet_runtime_tests::helpers::MockExportBuilder; use lucet_wasi_sdk::{CompileOpts, Lucetc}; -use lucetc::{Bindings, LucetcOpts, OptLevel}; +use lucetc::{LucetcOpts, OptLevel}; use std::path::Path; use std::sync::Arc; diff --git a/lucet-idl/Cargo.toml b/lucet-idl/Cargo.toml index e7c6a65ee..ca1e5f53b 100644 --- a/lucet-idl/Cargo.toml +++ b/lucet-idl/Cargo.toml @@ -20,6 +20,7 @@ failure = "0.1" xfailure = "0.1" heck = "0.3" lucetc = { path = "../lucetc" } +lucet-module-data = { path = "../lucet-module-data" } [dev-dependencies] tempfile = "3.0" diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 2a801d806..70fa95d15 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -27,7 +27,7 @@ pub use crate::types::{ use crate::c::CGenerator; use crate::parser::Parser; use crate::rust::RustGenerator; -use lucetc::Bindings; +use lucet_module_data::bindings::Bindings; use std::io::Write; pub fn parse_package(input: &str) -> Result { diff --git a/lucet-idl/src/package.rs b/lucet-idl/src/package.rs index 85309c2d2..13df3e804 100644 --- a/lucet-idl/src/package.rs +++ b/lucet-idl/src/package.rs @@ -3,7 +3,7 @@ use crate::module::Module; use crate::parser::SyntaxDecl; use crate::types::{Ident, Location, Name}; use heck::SnakeCase; -use lucetc::Bindings; +use lucet_module_data::bindings::Bindings; use std::collections::HashMap; #[derive(Debug, PartialEq, Eq, Clone)] diff --git a/lucet-module-data/Cargo.toml b/lucet-module-data/Cargo.toml index 2767f934c..4d53045e6 100644 --- a/lucet-module-data/Cargo.toml +++ b/lucet-module-data/Cargo.toml @@ -9,9 +9,10 @@ edition = "2018" cranelift-codegen = { path = "../cranelift/cranelift-codegen" } failure = "0.1" serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" bincode = "~1.0.1" num-derive = "0.2" num-traits = "0.2" minisign = "0.5.11" object = "0.12" -byteorder = "1.3" \ No newline at end of file +byteorder = "1.3" diff --git a/lucetc/src/bindings.rs b/lucet-module-data/src/bindings.rs similarity index 100% rename from lucetc/src/bindings.rs rename to lucet-module-data/src/bindings.rs diff --git a/lucet-module-data/src/lib.rs b/lucet-module-data/src/lib.rs index 1f852f3c8..0b586318c 100644 --- a/lucet-module-data/src/lib.rs +++ b/lucet-module-data/src/lib.rs @@ -5,6 +5,7 @@ #![deny(bare_trait_objects)] +pub mod bindings; mod error; mod functions; mod globals; diff --git a/lucetc/tests/bindings/bad_bindings.json b/lucet-module-data/tests/bindings/bad_bindings.json similarity index 100% rename from lucetc/tests/bindings/bad_bindings.json rename to lucet-module-data/tests/bindings/bad_bindings.json diff --git a/lucetc/tests/bindings/bindings_test.json b/lucet-module-data/tests/bindings/bindings_test.json similarity index 100% rename from lucetc/tests/bindings/bindings_test.json rename to lucet-module-data/tests/bindings/bindings_test.json diff --git a/lucetc/tests/bindings/garbage.json b/lucet-module-data/tests/bindings/garbage.json similarity index 100% rename from lucetc/tests/bindings/garbage.json rename to lucet-module-data/tests/bindings/garbage.json diff --git a/lucet-runtime/lucet-runtime-tests/src/build.rs b/lucet-runtime/lucet-runtime-tests/src/build.rs index 479da2d3e..f1b8f5759 100644 --- a/lucet-runtime/lucet-runtime-tests/src/build.rs +++ b/lucet-runtime/lucet-runtime-tests/src/build.rs @@ -1,7 +1,8 @@ use failure::Error; +use lucet_module_data::bindings::Bindings; use lucet_runtime_internals::module::DlModule; use lucet_wasi_sdk::{CompileOpts, Link, LinkOpt, LinkOpts}; -use lucetc::{Bindings, Lucetc, LucetcOpts}; +use lucetc::{Lucetc, LucetcOpts}; use std::path::{Path, PathBuf}; use std::sync::Arc; use tempfile::TempDir; diff --git a/lucet-spectest/src/bindings.rs b/lucet-spectest/src/bindings.rs index 51b65c9cc..c642430f7 100644 --- a/lucet-spectest/src/bindings.rs +++ b/lucet-spectest/src/bindings.rs @@ -1,4 +1,4 @@ -use lucetc::Bindings; +use lucet_module_data::bindings::Bindings; use serde_json::json; pub fn spec_test_bindings() -> Bindings { diff --git a/lucet-wasi-fuzz/Cargo.toml b/lucet-wasi-fuzz/Cargo.toml index 05d7939ab..7cf19f5c7 100644 --- a/lucet-wasi-fuzz/Cargo.toml +++ b/lucet-wasi-fuzz/Cargo.toml @@ -10,6 +10,7 @@ failure = "0.1" libc = "0.2" lucetc = { path = "../lucetc" } lucet-runtime = { path = "../lucet-runtime" } +lucet-module-data = { path = "../lucet-module-data" } lucet-wasi = { path = "../lucet-wasi" } lucet-wasi-sdk = { path = "../lucet-wasi-sdk" } nix = "0.13" diff --git a/lucet-wasi-fuzz/src/main.rs b/lucet-wasi-fuzz/src/main.rs index 4c0b6e0ce..f43ce73f8 100644 --- a/lucet-wasi-fuzz/src/main.rs +++ b/lucet-wasi-fuzz/src/main.rs @@ -2,11 +2,12 @@ use failure::{bail, ensure, format_err, Error}; use libc::c_ulong; +use lucet_module_data::bindings::Bindings; use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region}; use lucet_wasi::host::__wasi_exitcode_t; use lucet_wasi::{WasiCtx, WasiCtxBuilder}; use lucet_wasi_sdk::{CompileOpts, Link}; -use lucetc::{Bindings, Lucetc, LucetcOpts}; +use lucetc::{Lucetc, LucetcOpts}; use rand::prelude::random; use rayon::prelude::*; use regex::Regex; diff --git a/lucet-wasi-sdk/Cargo.toml b/lucet-wasi-sdk/Cargo.toml index 853336a4a..e0e113494 100644 --- a/lucet-wasi-sdk/Cargo.toml +++ b/lucet-wasi-sdk/Cargo.toml @@ -8,4 +8,5 @@ license = "Apache-2.0 WITH LLVM-exception" [dependencies] failure = "0.1" lucetc = { path = "../lucetc" } +lucet-module-data = { path = "../lucet-module-data" } tempfile = "3.0" diff --git a/lucet-wasi-sdk/tests/lucetc.rs b/lucet-wasi-sdk/tests/lucetc.rs index ef1b5518e..61a32669c 100644 --- a/lucet-wasi-sdk/tests/lucetc.rs +++ b/lucet-wasi-sdk/tests/lucetc.rs @@ -1,8 +1,9 @@ #[cfg(test)] mod lucetc_tests { use failure::Error; + use lucet_module_data::bindings::Bindings; use lucet_wasi_sdk::*; - use lucetc::{Bindings, Compiler, HeapSettings, OptLevel}; + use lucetc::{Compiler, HeapSettings, OptLevel}; use std::collections::HashMap; use std::fs::File; use std::io::Read; diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index 97b95c453..0669ab6c5 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -13,12 +13,13 @@ human-size = "0.4" libc = "0.2" lucet-runtime = { path = "../lucet-runtime" } lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals" } -lucetc = { path = "../lucetc" } +lucet-module-data = { path = "../lucet-module-data" } nix = "0.13" rand = "0.6" [dev-dependencies] lucet-wasi-sdk = { path = "../lucet-wasi-sdk" } +lucetc = { path = "../lucetc" } tempfile = "3.0" [build-dependencies] diff --git a/lucet-wasi/src/bindings.rs b/lucet-wasi/src/bindings.rs index 4c0ec76b7..05a82a306 100644 --- a/lucet-wasi/src/bindings.rs +++ b/lucet-wasi/src/bindings.rs @@ -1,4 +1,4 @@ -use lucetc::Bindings; +use lucet_module_data::bindings::Bindings; pub fn bindings() -> Bindings { Bindings::from_str(include_str!("../bindings.json")).expect("lucet-wasi bindings.json is valid") diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index e34689b06..a19d5c334 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -31,8 +31,6 @@ log = "0.4" env_logger = "0.6" faerie = "0.10.0" failure = "0.1" -serde = "1.0" -serde_json = "1.0" byteorder = "1.2" wasmonkey = { path = "../lucet-builtins/wasmonkey" } wabt = "0.7" diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index bb06fa811..6cf05b23a 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -1,4 +1,3 @@ -use crate::bindings::Bindings; use crate::decls::ModuleDecls; use crate::error::{LucetcError, LucetcErrorKind}; use crate::function::FuncInfo; @@ -19,6 +18,7 @@ use cranelift_module::{Backend as ClifBackend, Module as ClifModule}; use cranelift_native; use cranelift_wasm::{translate_module, FuncTranslator, WasmError}; use failure::{format_err, Fail, ResultExt}; +use lucet_module_data::bindings::Bindings; use lucet_module_data::{FunctionSpec, ModuleData}; #[derive(Debug, Clone, Copy)] diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index 66f1d937a..86803b120 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -1,4 +1,3 @@ -use crate::bindings::Bindings; use crate::error::{LucetcError, LucetcErrorKind}; use crate::heap::HeapSettings; pub use crate::module::{Exportable, TableElems}; @@ -14,6 +13,7 @@ use cranelift_wasm::{ TableIndex, }; use failure::{format_err, Error, ResultExt}; +use lucet_module_data::bindings::Bindings; use lucet_module_data::{ owned::OwnedLinearMemorySpec, ExportFunction, FunctionIndex as LucetFunctionIndex, FunctionMetadata, Global as GlobalVariant, GlobalDef, GlobalSpec, HeapSpec, ImportFunction, diff --git a/lucetc/src/lib.rs b/lucetc/src/lib.rs index bc78e5eac..d0a486295 100644 --- a/lucetc/src/lib.rs +++ b/lucetc/src/lib.rs @@ -1,6 +1,5 @@ #![deny(bare_trait_objects)] -mod bindings; mod compiler; mod decls; mod error; @@ -22,7 +21,6 @@ mod traps; use crate::load::read_bytes; pub use crate::{ - bindings::Bindings, compiler::Compiler, compiler::OptLevel, error::{LucetcError, LucetcErrorKind}, @@ -31,6 +29,7 @@ pub use crate::{ patch::patch_module, }; use failure::{format_err, Error, ResultExt}; +use lucet_module_data::bindings::Bindings; use signature::{PublicKey, SecretKey}; use std::env; use std::path::{Path, PathBuf}; diff --git a/lucetc/src/main.rs b/lucetc/src/main.rs index c27766966..9c3a4a5df 100644 --- a/lucetc/src/main.rs +++ b/lucetc/src/main.rs @@ -3,11 +3,11 @@ mod options; use crate::options::{CodegenOutput, Options}; use failure::{format_err, Error, ResultExt}; use log::info; +use lucet_module_data::bindings::Bindings; use lucetc::{ signature::{self, PublicKey}, - Bindings, Lucetc, LucetcOpts, + Lucetc, LucetcOpts, }; - use std::io::{self, Write}; use std::path::PathBuf; use std::process; diff --git a/lucetc/tests/wasm.rs b/lucetc/tests/wasm.rs index 6e5d23dad..f7b700691 100644 --- a/lucetc/tests/wasm.rs +++ b/lucetc/tests/wasm.rs @@ -1,4 +1,4 @@ -use lucetc::Bindings; +use lucet_module_data::bindings::Bindings; use std::collections::HashMap; use std::path::PathBuf; @@ -32,7 +32,8 @@ fn test_bindings() -> Bindings { mod module_data { /// Tests of the `ModuleData` generated by the lucetc Compiler use super::load_wat_module; - use lucetc::{Bindings, Compiler, HeapSettings, LucetcErrorKind, OptLevel}; + use lucet_module_data::bindings::Bindings; + use lucetc::{Compiler, HeapSettings, LucetcErrorKind, OptLevel}; use std::path::PathBuf; #[test] From 85b1540a2ff4a1eb09858e2e0ed901b47774d729 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 26 Jun 2019 16:25:39 -0700 Subject: [PATCH 245/512] lucetc: pub use Bindings --- lucetc/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lucetc/src/lib.rs b/lucetc/src/lib.rs index d0a486295..4e080a3d9 100644 --- a/lucetc/src/lib.rs +++ b/lucetc/src/lib.rs @@ -29,7 +29,7 @@ pub use crate::{ patch::patch_module, }; use failure::{format_err, Error, ResultExt}; -use lucet_module_data::bindings::Bindings; +pub use lucet_module_data::bindings::Bindings; use signature::{PublicKey, SecretKey}; use std::env; use std::path::{Path, PathBuf}; From 94140ecb89297bbe8c285da3556e661a196c6635 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 26 Jun 2019 17:40:59 -0700 Subject: [PATCH 246/512] lucet-idl: delete attrs the idea was we would use these to annotate datatypes with backend-specific stuff, but we never ended up actually doing so. if we end up needing them for specific nodes in the AST, we can go back and add them just where they will be used. --- lucet-idl/src/data_layout.rs | 13 +- lucet-idl/src/lib.rs | 2 +- lucet-idl/src/module.rs | 53 +---- lucet-idl/src/package.rs | 12 +- lucet-idl/src/parser.rs | 366 +---------------------------------- lucet-idl/src/types.rs | 23 --- 6 files changed, 14 insertions(+), 455 deletions(-) diff --git a/lucet-idl/src/data_layout.rs b/lucet-idl/src/data_layout.rs index c928d0e41..4d4e6351d 100644 --- a/lucet-idl/src/data_layout.rs +++ b/lucet-idl/src/data_layout.rs @@ -1,14 +1,13 @@ use crate::error::ValidationError; use crate::types::{ - AliasDataType, AtomType, Attr, DataType, DataTypeRef, DataTypeVariant, EnumDataType, - EnumMember, Ident, Location, Name, StructDataType, StructMember, + AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, EnumMember, + Ident, Location, Name, StructDataType, StructMember, }; use std::collections::HashMap; #[derive(Debug, PartialEq, Eq, Clone)] struct DataTypeIR { pub variant: VariantIR, - pub attrs: Vec, pub location: Location, } @@ -16,7 +15,6 @@ struct DataTypeIR { pub struct StructMemberIR { pub type_: DataTypeRef, pub name: String, - pub attrs: Vec, } #[derive(Debug, PartialEq, Eq, Clone)] @@ -53,12 +51,11 @@ impl DataTypeModuleBuilder { } } - pub fn define(&mut self, id: Ident, variant: VariantIR, attrs: Vec, location: Location) { + pub fn define(&mut self, id: Ident, variant: VariantIR, location: Location) { if let Some(prev_def) = self.data_types.insert( id, DataTypeIR { variant, - attrs: attrs.clone(), location: location.clone(), }, ) { @@ -104,7 +101,6 @@ impl DataTypeModuleBuilder { members.push(StructMember { type_: mem.type_.clone(), name: mem.name.clone(), - attrs: mem.attrs.clone(), offset, }); offset += repr_size; @@ -116,7 +112,6 @@ impl DataTypeModuleBuilder { id, DataType { variant: DataTypeVariant::Struct(StructDataType { members }), - attrs: dt.attrs.clone(), repr_size, align: struct_align, }, @@ -134,7 +129,6 @@ impl DataTypeModuleBuilder { id, DataType { variant: DataTypeVariant::Alias(AliasDataType { to: a.to.clone() }), - attrs: dt.attrs.clone(), repr_size, align, }, @@ -153,7 +147,6 @@ impl DataTypeModuleBuilder { variant: DataTypeVariant::Enum(EnumDataType { members: e.members.clone(), }), - attrs: dt.attrs.clone(), repr_size, align, }, diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 70fa95d15..19875bdc6 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -20,7 +20,7 @@ pub use crate::error::IDLError; pub use crate::module::Module; pub use crate::package::Package; pub use crate::types::{ - AliasDataType, AtomType, Attr, DataType, DataTypeRef, DataTypeVariant, EnumDataType, FuncDecl, + AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, FuncDecl, FuncRet, Ident, Location, Name, Named, StructDataType, StructMember, }; diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index 3f70c62d1..d246271ce 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -4,8 +4,7 @@ use crate::data_layout::{ use crate::error::ValidationError; use crate::parser::{SyntaxDecl, SyntaxRef}; use crate::types::{ - Attr, DataType, DataTypeRef, EnumMember, FuncArg, FuncDecl, FuncRet, Ident, Location, Name, - Named, + DataType, DataTypeRef, EnumMember, FuncArg, FuncDecl, FuncRet, Ident, Location, Name, Named, }; use heck::SnakeCase; use std::collections::HashMap; @@ -13,7 +12,6 @@ use std::collections::HashMap; #[derive(Debug, PartialEq, Eq, Clone)] pub struct Module { pub names: Vec, - pub attrs: Vec, pub data_types: HashMap, pub data_type_ordering: Vec, pub funcs: HashMap, @@ -22,10 +20,9 @@ pub struct Module { } impl Module { - fn new(attrs: &[Attr], module_name: String, binding_prefix: String) -> Self { + fn new(module_name: String, binding_prefix: String) -> Self { Self { names: Vec::new(), - attrs: attrs.to_vec(), data_types: HashMap::new(), data_type_ordering: Vec::new(), funcs: HashMap::new(), @@ -92,7 +89,6 @@ impl Module { SyntaxDecl::Struct { name, members, - attrs, location, } => { let mut uniq_membs = HashMap::new(); @@ -119,7 +115,6 @@ impl Module { dtype_members.push(StructMemberIR { type_, name: mem.name.clone(), - attrs: mem.attrs.clone(), }) } @@ -128,14 +123,12 @@ impl Module { VariantIR::Struct(StructIR { members: dtype_members, }), - attrs.clone(), location.clone(), ); } SyntaxDecl::Enum { name, variants, - attrs, location, } => { let mut uniq_vars = HashMap::new(); @@ -158,7 +151,6 @@ impl Module { // build the struct with this as the member: dtype_members.push(EnumMember { name: var.name.clone(), - attrs: var.attrs.clone(), }) } data_types_ir.define( @@ -166,29 +158,17 @@ impl Module { VariantIR::Enum(EnumIR { members: dtype_members, }), - attrs.clone(), location.clone(), ); } - SyntaxDecl::Alias { - what, - attrs, - location, - .. - } => { + SyntaxDecl::Alias { what, location, .. } => { let to = self.get_ref(what)?; - data_types_ir.define( - id, - VariantIR::Alias(AliasIR { to }), - attrs.clone(), - location.clone(), - ); + data_types_ir.define(id, VariantIR::Alias(AliasIR { to }), location.clone()); } SyntaxDecl::Function { name, args, rets, - attrs, location, .. } => { @@ -209,7 +189,6 @@ impl Module { Ok(FuncArg { name: arg_syntax.name.clone(), type_, - attrs: arg_syntax.attrs.clone(), }) }) .collect::, _>>()?; @@ -218,10 +197,7 @@ impl Module { .iter() .map(|ret_syntax| { let type_ = self.get_ref(&ret_syntax.type_)?; - Ok(FuncRet { - type_, - attrs: ret_syntax.attrs.clone(), - }) + Ok(FuncRet { type_ }) }) .collect::, _>>()?; if rets.len() > 1 { @@ -235,7 +211,6 @@ impl Module { let decl = FuncDecl { args, rets, - attrs: attrs.clone(), field_name: name.clone(), binding_name, }; @@ -250,11 +225,10 @@ impl Module { pub fn from_declarations( decls: &[SyntaxDecl], - attrs: &[Attr], module_name: String, binding_prefix: String, ) -> Result { - let mut mod_ = Self::new(attrs, module_name, binding_prefix); + let mut mod_ = Self::new(module_name, binding_prefix); let mut idents: Vec = Vec::new(); for decl in decls { match decl { @@ -357,18 +331,15 @@ mod tests { StructMember { name: "a".to_owned(), type_: DataTypeRef::Atom(AtomType::I32), - attrs: Vec::new(), offset: 0, }, StructMember { name: "b".to_owned(), type_: DataTypeRef::Atom(AtomType::F32), - attrs: Vec::new(), offset: 4, }, ] }), - attrs: Vec::new(), repr_size: 8, align: 4, } @@ -547,7 +518,6 @@ mod tests { FuncDecl { args: Vec::new(), rets: Vec::new(), - attrs: Vec::new(), binding_name: "_trivial".to_owned(), field_name: "trivial".to_owned(), } @@ -556,7 +526,6 @@ mod tests { .collect::>(), data_types: HashMap::new(), data_type_ordering: Vec::new(), - attrs: Vec::new(), module_name: String::new(), binding_prefix: String::new(), } @@ -577,10 +546,8 @@ mod tests { args: vec![FuncArg { type_: DataTypeRef::Atom(AtomType::U8), name: "a".to_owned(), - attrs: Vec::new(), }], rets: Vec::new(), - attrs: Vec::new(), binding_name: "_trivial".to_owned(), field_name: "trivial".to_owned(), } @@ -589,7 +556,6 @@ mod tests { .collect::>(), data_types: HashMap::new(), data_type_ordering: Vec::new(), - attrs: Vec::new(), module_name: String::new(), binding_prefix: String::new(), } @@ -611,9 +577,7 @@ mod tests { args: Vec::new(), rets: vec![FuncRet { type_: DataTypeRef::Atom(AtomType::U8), - attrs: Vec::new(), }], - attrs: Vec::new(), binding_name: "_trivial".to_owned(), field_name: "trivial".to_owned(), } @@ -622,7 +586,6 @@ mod tests { .collect::>(), data_types: HashMap::new(), data_type_ordering: Vec::new(), - attrs: Vec::new(), module_name: String::new(), binding_prefix: String::new(), } @@ -650,9 +613,7 @@ mod tests { args: Vec::new(), rets: vec![FuncRet { type_: DataTypeRef::Defined(Ident(1)), - attrs: Vec::new(), }], - attrs: Vec::new(), binding_name: "_trivial".to_owned(), field_name: "trivial".to_owned(), } @@ -665,7 +626,6 @@ mod tests { variant: DataTypeVariant::Alias(AliasDataType { to: DataTypeRef::Atom(AtomType::U8), }), - attrs: Vec::new(), repr_size: 1, align: 1, } @@ -673,7 +633,6 @@ mod tests { .into_iter() .collect::>(), data_type_ordering: vec![Ident(1)], - attrs: Vec::new(), module_name: String::new(), binding_prefix: String::new(), } diff --git a/lucet-idl/src/package.rs b/lucet-idl/src/package.rs index 13df3e804..1c325b1ef 100644 --- a/lucet-idl/src/package.rs +++ b/lucet-idl/src/package.rs @@ -77,13 +77,11 @@ impl Package { for (decl, id) in decls.iter().zip(&idents) { match decl { - SyntaxDecl::Module { - decls, attrs, name, .. - } => { + SyntaxDecl::Module { decls, name, .. } => { let binding_prefix = "__".to_owned() + &name.to_snake_case(); pkg.define_module( *id, - Module::from_declarations(decls, attrs, name.clone(), binding_prefix)?, + Module::from_declarations(decls, name.clone(), binding_prefix)?, ); } _ => unreachable!(), @@ -130,7 +128,6 @@ mod test { Ident(0), Module { names: Vec::new(), - attrs: Vec::new(), data_types: HashMap::new(), data_type_ordering: Vec::new(), funcs: HashMap::new(), @@ -176,7 +173,6 @@ mod test { Ident(0), Module { names: Vec::new(), - attrs: Vec::new(), data_types: HashMap::new(), data_type_ordering: Vec::new(), funcs: HashMap::new(), @@ -188,7 +184,6 @@ mod test { Ident(1), Module { names: Vec::new(), - attrs: Vec::new(), data_types: HashMap::new(), data_type_ordering: Vec::new(), funcs: HashMap::new(), @@ -200,7 +195,6 @@ mod test { Ident(2), Module { names: Vec::new(), - attrs: Vec::new(), data_types: HashMap::new(), data_type_ordering: Vec::new(), funcs: HashMap::new(), @@ -236,7 +230,6 @@ mod test { column: 10 } }], - attrs: Vec::new(), funcs: HashMap::new(), data_types: vec![( Ident(0), @@ -244,7 +237,6 @@ mod test { variant: DataTypeVariant::Alias(AliasDataType { to: DataTypeRef::Atom(AtomType::U8) }), - attrs: Vec::new(), repr_size: 1, align: 1, } diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index ccbdbc9b7..8a51412ed 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -1,5 +1,5 @@ use super::lexer::{LexError, Lexer, LocatedError, LocatedToken, Token}; -use super::types::{AtomType, Attr, Location}; +use super::types::{AtomType, Location}; use std::error::Error; use std::fmt; @@ -8,32 +8,27 @@ pub enum SyntaxDecl { Struct { name: String, members: Vec, - attrs: Vec, location: Location, }, Enum { name: String, variants: Vec, - attrs: Vec, location: Location, }, Alias { name: String, what: SyntaxRef, - attrs: Vec, location: Location, }, Module { name: String, decls: Vec, - attrs: Vec, location: Location, }, Function { name: String, args: Vec, rets: Vec, - attrs: Vec, location: Location, }, } @@ -75,14 +70,12 @@ pub enum SyntaxRef { pub struct StructMember { pub name: String, pub type_: SyntaxRef, - pub attrs: Vec, pub location: Location, } #[derive(Debug, PartialEq, Eq, Clone)] pub struct EnumVariant { pub name: String, - pub attrs: Vec, pub location: Location, } @@ -90,14 +83,12 @@ pub struct EnumVariant { pub struct FuncArgSyntax { pub name: String, pub type_: SyntaxRef, - pub attrs: Vec, pub location: Location, } #[derive(Debug, PartialEq, Eq, Clone)] pub struct FuncRetSyntax { pub type_: SyntaxRef, - pub attrs: Vec, pub location: Location, } @@ -205,24 +196,8 @@ impl<'a> Parser<'a> { } } - fn match_attr_body(&mut self) -> Result { - let location = self.location; - self.match_token(Token::LBracket, "expected attribute start [")?; - let key = self.match_a_word("expected attribute key")?; - self.match_token(Token::Equals, "expected =")?; - let val = match self.token() { - Some(Token::Word(text)) => text, - Some(Token::Quote(text)) => text, - _ => parse_err!(self.location, "expected word or quoted string")?, - }; - self.consume(); - self.match_token(Token::RBracket, "expected ]")?; - Ok(Attr::new(key, val, location)) - } - fn match_struct_body(&mut self) -> Result, ParseError> { let mut members = Vec::new(); - let mut attrs = Vec::new(); loop { match self.token() { Some(Token::RBrace) => { @@ -231,7 +206,6 @@ impl<'a> Parser<'a> { } Some(Token::Hash) => { self.consume(); - attrs.push(self.match_attr_body()?); } Some(Token::Word(member_name)) => { let location = self.location; @@ -241,10 +215,8 @@ impl<'a> Parser<'a> { members.push(StructMember { name: member_name.to_string(), type_: member_ref, - attrs: attrs.clone(), location, }); - attrs.clear(); match self.token() { Some(Token::Comma) => { self.consume(); @@ -268,7 +240,6 @@ impl<'a> Parser<'a> { fn match_enum_body(&mut self) -> Result, ParseError> { let mut names = Vec::new(); - let mut attrs = Vec::new(); loop { match self.token() { Some(Token::RBrace) => { @@ -277,17 +248,14 @@ impl<'a> Parser<'a> { } Some(Token::Hash) => { self.consume(); - attrs.push(self.match_attr_body()?); } Some(Token::Word(name)) => { let location = self.location; self.consume(); names.push(EnumVariant { name: name.to_owned(), - attrs: attrs.clone(), location, }); - attrs.clear(); match self.token() { Some(Token::Comma) => { self.consume(); @@ -303,15 +271,11 @@ impl<'a> Parser<'a> { _ => parse_err!(self.location, "expected variant")?, } } - if !attrs.is_empty() { - parse_err!(self.location, "attributes unattached to an enum variant")? - } Ok(names) } fn match_func_args(&mut self) -> Result, ParseError> { let mut args = Vec::new(); - let mut attrs = Vec::new(); loop { match self.token() { Some(Token::RPar) => { @@ -320,7 +284,6 @@ impl<'a> Parser<'a> { } Some(Token::Hash) => { self.consume(); - attrs.push(self.match_attr_body()?); } Some(Token::Word(name)) => { let location = self.location; @@ -331,10 +294,8 @@ impl<'a> Parser<'a> { args.push(FuncArgSyntax { name: name.to_string(), type_: type_ref, - attrs: attrs.clone(), location, }); - attrs.clear(); match self.token() { Some(Token::Comma) => { self.consume(); @@ -350,18 +311,11 @@ impl<'a> Parser<'a> { _ => parse_err!(self.location, "expected argument, or )")?, } } - if !attrs.is_empty() { - parse_err!( - self.location, - "attributes unattached to a function argument" - )? - } Ok(args) } fn match_func_rets(&mut self) -> Result, ParseError> { let mut args = Vec::new(); - let mut attrs = Vec::new(); loop { match self.token() { Some(Token::Semi) => { @@ -370,17 +324,14 @@ impl<'a> Parser<'a> { } Some(Token::Hash) => { self.consume(); - attrs.push(self.match_attr_body()?); } _ => { let location = self.location; let type_ref = self.match_ref("expected type, attribute, or ;")?; args.push(FuncRetSyntax { type_: type_ref, - attrs: attrs.clone(), location, }); - attrs.clear(); match self.token() { Some(Token::Comma) => { self.consume(); @@ -395,17 +346,10 @@ impl<'a> Parser<'a> { } } } - if !attrs.is_empty() { - parse_err!( - self.location, - "attributes unattached to a function return type" - )? - } Ok(args) } pub fn match_decl(&mut self, err_msg: &str) -> Result, ParseError> { - let mut attrs = Vec::new(); loop { match self.token() { Some(Token::Word("struct")) => { @@ -417,7 +361,6 @@ impl<'a> Parser<'a> { return Ok(Some(SyntaxDecl::Struct { name: name.to_owned(), members, - attrs, location, })); } @@ -430,7 +373,6 @@ impl<'a> Parser<'a> { return Ok(Some(SyntaxDecl::Enum { name: name.to_owned(), variants, - attrs, location, })); } @@ -444,7 +386,6 @@ impl<'a> Parser<'a> { return Ok(Some(SyntaxDecl::Alias { name: name.to_owned(), what, - attrs, location, })); } @@ -471,7 +412,6 @@ impl<'a> Parser<'a> { return Ok(Some(SyntaxDecl::Module { name: name.to_owned(), decls, - attrs, location, })); } @@ -502,13 +442,11 @@ impl<'a> Parser<'a> { name: name.to_owned(), args, rets, - attrs, location, })); } Some(Token::Hash) => { self.consume(); - attrs.push(self.match_attr_body()?); continue; } Some(_) => { @@ -519,9 +457,6 @@ impl<'a> Parser<'a> { ) } None => { - if !attrs.is_empty() { - parse_err!(self.location, "attributes unattached to a declaration")? - } return Ok(None); } } @@ -577,7 +512,6 @@ mod tests { SyntaxDecl::Struct { name: "foo".to_string(), members: Vec::new(), - attrs: Vec::new(), location: Location { line: 1, column: 0 }, } ); @@ -602,13 +536,11 @@ mod tests { column: 15, }, }, - attrs: Vec::new(), location: Location { line: 1, column: 12, }, }], - attrs: Vec::new(), location: Location { line: 1, column: 0 }, } ); @@ -633,13 +565,11 @@ mod tests { column: 15, }, }, - attrs: Vec::new(), location: Location { line: 1, column: 12, }, }], - attrs: Vec::new(), location: Location { line: 1, column: 0 }, } ); @@ -665,7 +595,6 @@ mod tests { column: 14, }, }, - attrs: Vec::new(), location: Location { line: 1, column: 11, @@ -680,100 +609,12 @@ mod tests { column: 22, }, }, - attrs: Vec::new(), location: Location { line: 1, column: 19, }, }, ], - attrs: Vec::new(), - location: Location { line: 1, column: 0 }, - } - ); - } - #[test] - fn struct_empty_one_attribute() { - // Test out attributes: - let mut parser = Parser::new("#[key1=val1] struct foo {}"); - assert_eq!( - parser - .match_decl("empty struct") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Struct { - name: "foo".to_string(), - members: Vec::new(), - attrs: vec![Attr::new("key1", "val1", Location { line: 1, column: 0 })], - location: Location { - line: 1, - column: 13, - }, - } - ); - } - #[test] - fn struct_empty_one_attribute_with_spaces() { - let mut parser = Parser::new("#[key2=\"1 value with spaces!\"]\nstruct foo {}"); - assert_eq!( - parser - .match_decl("empty struct") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Struct { - name: "foo".to_string(), - members: Vec::new(), - attrs: vec![Attr::new( - "key2", - "1 value with spaces!", - Location { line: 1, column: 0 }, - )], - location: Location { line: 2, column: 0 }, - } - ); - } - #[test] - fn struct_empty_multiple_attributes() { - let mut parser = Parser::new("#[key1=val1]\n\t#[key2 = \"val2\" ]\nstruct foo {}"); - assert_eq!( - parser - .match_decl("empty struct") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Struct { - name: "foo".to_string(), - members: Vec::new(), - attrs: vec![ - Attr::new("key1", "val1", Location { line: 1, column: 0 }), - Attr::new("key2", "val2", Location { line: 2, column: 8 }), - ], - location: Location { line: 3, column: 0 }, - } - ); - } - #[test] - fn struct_member_attribute() { - let mut parser = Parser::new("struct foo {\n\t#[key=val]\n\tmem: f32,\n}"); - assert_eq!( - parser - .match_decl("empty struct") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Struct { - name: "foo".to_string(), - members: vec![StructMember { - name: "mem".to_owned(), - type_: SyntaxRef::Atom { - atom: AtomType::F32, - location: Location { - line: 3, - column: 13, - }, - }, - attrs: vec![Attr::new("key", "val", Location { line: 2, column: 8 })], - location: Location { line: 3, column: 8 }, - }], - attrs: Vec::new(), // location: Location { line: 1, column: 0 }, } ); @@ -800,7 +641,6 @@ mod tests { column: 15, }, }, - attrs: Vec::new(), location: Location { line: 1, column: 12, @@ -815,14 +655,12 @@ mod tests { column: 28, }, }, - attrs: Vec::new(), location: Location { line: 1, column: 20, }, } ], - attrs: Vec::new(), location: Location { line: 1, column: 0 }, } ); @@ -839,7 +677,6 @@ mod tests { SyntaxDecl::Enum { name: "foo".to_owned(), variants: Vec::new(), - attrs: Vec::new(), location: Location { line: 1, column: 0 }, }, ); @@ -857,13 +694,11 @@ mod tests { name: "foo".to_owned(), variants: vec![EnumVariant { name: "first".to_owned(), - attrs: Vec::new(), location: Location { line: 1, column: 10, }, }], - attrs: Vec::new(), location: Location { line: 1, column: 0 }, }, ); @@ -881,60 +716,16 @@ mod tests { name: "bar".to_owned(), variants: vec![EnumVariant { name: "first".to_owned(), - attrs: Vec::new(), location: Location { line: 1, column: 10, }, }], - attrs: Vec::new(), location: Location { line: 1, column: 0 }, }, ); } - #[test] - fn enum_one_entry_with_attr() { - let mut parser = Parser::new("enum bar { #[a=b] first}"); - // 0 5 10 - assert_eq!( - parser - .match_decl("one entry enum, no trailing comma") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Enum { - name: "bar".to_owned(), - variants: vec![EnumVariant { - name: "first".to_owned(), - attrs: vec![Attr::new( - "a", - "b", - Location { - line: 1, - column: 11 - } - ),], - location: Location { - line: 1, - column: 18, - }, - }], - attrs: Vec::new(), - location: Location { line: 1, column: 0 }, - }, - ); - } - #[test] - fn enum_one_entry_trailing_attr() { - assert!(Parser::new("enum bar { #[a=b] first, #[c=d] }") - .match_decl("one entry enum") - .is_err()); - } - #[test] - fn enum_no_entry_attr() { - assert!(Parser::new("enum bar { #[c=d] }") - .match_decl("zero entry enum") - .is_err()); - } + #[test] fn enum_four_entry() { let mut parser = Parser::new("enum baz { one, two, three\n, four, }"); @@ -949,7 +740,6 @@ mod tests { variants: vec![ EnumVariant { name: "one".to_owned(), - attrs: Vec::new(), location: Location { line: 1, column: 11, @@ -957,7 +747,6 @@ mod tests { }, EnumVariant { name: "two".to_owned(), - attrs: Vec::new(), location: Location { line: 1, column: 16, @@ -965,7 +754,6 @@ mod tests { }, EnumVariant { name: "three".to_owned(), - attrs: Vec::new(), location: Location { line: 1, column: 21, @@ -973,11 +761,9 @@ mod tests { }, EnumVariant { name: "four".to_owned(), - attrs: Vec::new(), location: Location { line: 2, column: 2 }, }, ], - attrs: Vec::new(), location: Location { line: 1, column: 0 }, }, ); @@ -995,7 +781,6 @@ mod tests { SyntaxDecl::Module { name: "empty".to_owned(), decls: Vec::new(), - attrs: Vec::new(), location: Location { line: 1, column: 0 }, } ); @@ -1017,19 +802,16 @@ mod tests { decls: vec![SyntaxDecl::Module { name: "three".to_owned(), decls: Vec::new(), - attrs: Vec::new(), location: Location { line: 1, column: 20 }, }], - attrs: Vec::new(), location: Location { line: 1, column: 10 }, }], - attrs: Vec::new(), location: Location { line: 1, column: 0 }, } ); @@ -1050,7 +832,6 @@ mod tests { SyntaxDecl::Enum { name: "foo".to_owned(), variants: Vec::new(), - attrs: Vec::new(), location: Location { line: 1, column: 10 @@ -1059,70 +840,23 @@ mod tests { SyntaxDecl::Struct { name: "bar".to_owned(), members: Vec::new(), - attrs: Vec::new(), location: Location { line: 1, column: 22 }, } ], - attrs: Vec::new(), location: Location { line: 1, column: 0 }, } ); } - #[test] - fn mod_attrs() { - let mut parser = Parser::new("#[a=b]\nmod one { #[c=d] enum foo {} struct bar {} }"); - // 0 5 10 15 20 25 30 - assert_eq!( - parser - .match_decl("module with types") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Module { - name: "one".to_owned(), - decls: vec![ - SyntaxDecl::Enum { - name: "foo".to_owned(), - variants: Vec::new(), - attrs: vec![Attr::new( - "c", - "d", - Location { - line: 2, - column: 10 - } - ),], - location: Location { - line: 2, - column: 17 - }, - }, - SyntaxDecl::Struct { - name: "bar".to_owned(), - members: Vec::new(), - attrs: Vec::new(), - location: Location { - line: 2, - column: 29 - }, - } - ], - attrs: vec![Attr::new("a", "b", Location { line: 1, column: 0 }),], - location: Location { line: 2, column: 0 }, - } - ); - } - #[test] fn fn_trivial() { let canonical = vec![SyntaxDecl::Function { name: "trivial".to_owned(), args: Vec::new(), rets: Vec::new(), - attrs: Vec::new(), location: Location { line: 1, column: 0 }, }]; assert_eq!( @@ -1161,13 +895,11 @@ mod tests { column: 14, }, }, - attrs: vec![], location: Location { line: 1, column: 14, }, }], - attrs: Vec::new(), location: Location { line: 1, column: 0 }, }]; assert_eq!( @@ -1206,11 +938,9 @@ mod tests { }, }, name: "a".to_owned(), - attrs: Vec::new(), location: Location { line: 1, column: 7 }, }], rets: Vec::new(), - attrs: Vec::new(), location: Location { line: 1, column: 0 }, }; assert_eq!( @@ -1245,7 +975,6 @@ mod tests { }, }, name: "a".to_owned(), - attrs: Vec::new(), location: Location { line: 1, column: 7 }, }, FuncArgSyntax { @@ -1257,7 +986,6 @@ mod tests { }, }, name: "b".to_owned(), - attrs: Vec::new(), location: Location { line: 1, column: 14, @@ -1265,7 +993,6 @@ mod tests { }, ], rets: Vec::new(), - attrs: Vec::new(), location: Location { line: 1, column: 0 }, }; assert_eq!( @@ -1306,7 +1033,6 @@ mod tests { column: 14, }, }, - attrs: vec![], location: Location { line: 1, column: 14, @@ -1320,7 +1046,6 @@ mod tests { column: 18, }, }, - attrs: vec![], location: Location { line: 1, column: 18, @@ -1334,99 +1059,12 @@ mod tests { column: 23, }, }, - attrs: vec![], location: Location { line: 1, column: 23, }, }, ], - attrs: Vec::new(), - location: Location { line: 1, column: 0 }, - } - ); - } - - #[test] - fn fn_many_returns_with_attrs() { - assert_eq!( - Parser::new("fn getch() -> #[a=b] u8, #[c=d] #[e=f] u16, u32;") - // 0 5 10 15 20 25 30 35 40 45 - .match_decl("returns u8") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Function { - name: "getch".to_owned(), - args: Vec::new(), - rets: vec![ - FuncRetSyntax { - type_: SyntaxRef::Atom { - atom: AtomType::U8, - location: Location { - line: 1, - column: 21, - }, - }, - attrs: vec![Attr::new( - "a", - "b", - Location { - line: 1, - column: 14 - } - )], - location: Location { - line: 1, - column: 21, - }, - }, - FuncRetSyntax { - type_: SyntaxRef::Atom { - atom: AtomType::U16, - location: Location { - line: 1, - column: 39, - }, - }, - attrs: vec![ - Attr::new( - "c", - "d", - Location { - line: 1, - column: 25 - } - ), - Attr::new( - "e", - "f", - Location { - line: 1, - column: 32 - } - ), - ], - location: Location { - line: 1, - column: 39, - }, - }, - FuncRetSyntax { - type_: SyntaxRef::Atom { - atom: AtomType::U32, - location: Location { - line: 1, - column: 44, - }, - }, - attrs: vec![], - location: Location { - line: 1, - column: 44, - }, - }, - ], - attrs: Vec::new(), location: Location { line: 1, column: 0 }, } ); diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index cafb602d5..a24bd3992 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -33,23 +33,6 @@ pub struct Location { pub column: usize, } -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Attr { - pub key: String, - pub val: String, - pub location: Location, -} - -impl Attr { - pub fn new(key: &str, val: &str, location: Location) -> Attr { - Attr { - key: key.to_owned(), - val: val.to_owned(), - location, - } - } -} - #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] pub struct Ident(pub usize); @@ -69,7 +52,6 @@ pub enum DataTypeRef { pub struct StructMember { pub type_: DataTypeRef, pub name: String, - pub attrs: Vec, pub offset: usize, } @@ -81,7 +63,6 @@ pub struct StructDataType { #[derive(Debug, PartialEq, Eq, Clone)] pub struct EnumMember { pub name: String, - pub attrs: Vec, } #[derive(Debug, PartialEq, Eq, Clone)] @@ -104,7 +85,6 @@ pub enum DataTypeVariant { #[derive(Debug, PartialEq, Eq, Clone)] pub struct DataType { pub variant: DataTypeVariant, - pub attrs: Vec, pub repr_size: usize, pub align: usize, } @@ -113,7 +93,6 @@ pub struct DataType { pub struct FuncArg { pub type_: DataTypeRef, pub name: String, - pub attrs: Vec, } #[derive(Debug, PartialEq, Eq, Clone)] @@ -122,13 +101,11 @@ pub struct FuncDecl { pub binding_name: String, pub args: Vec, pub rets: Vec, - pub attrs: Vec, } #[derive(Debug, PartialEq, Eq, Clone)] pub struct FuncRet { pub type_: DataTypeRef, - pub attrs: Vec, } #[derive(Debug, PartialEq, Eq, Clone)] From b64e86135ac1d887176a27299891ba283572e247 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 26 Jun 2019 18:58:53 -0700 Subject: [PATCH 247/512] lucet-idl: fix parser cases leftover from attrs --- lucet-idl/src/parser.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index 8a51412ed..e263496da 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -204,9 +204,6 @@ impl<'a> Parser<'a> { self.consume(); break; } - Some(Token::Hash) => { - self.consume(); - } Some(Token::Word(member_name)) => { let location = self.location; self.consume(); @@ -246,9 +243,6 @@ impl<'a> Parser<'a> { self.consume(); break; } - Some(Token::Hash) => { - self.consume(); - } Some(Token::Word(name)) => { let location = self.location; self.consume(); @@ -282,9 +276,6 @@ impl<'a> Parser<'a> { self.consume(); break; } - Some(Token::Hash) => { - self.consume(); - } Some(Token::Word(name)) => { let location = self.location; self.consume(); @@ -322,9 +313,6 @@ impl<'a> Parser<'a> { self.consume(); break; } - Some(Token::Hash) => { - self.consume(); - } _ => { let location = self.location; let type_ref = self.match_ref("expected type, attribute, or ;")?; @@ -445,10 +433,6 @@ impl<'a> Parser<'a> { location, })); } - Some(Token::Hash) => { - self.consume(); - continue; - } Some(_) => { return parse_err!( self.location, From b16292c8a19e8fafa7ddffc266b95118c8b04545 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 27 Jun 2019 12:02:07 -0700 Subject: [PATCH 248/512] lucet-idl: fix tests --- lucet-idl/src/module.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index d246271ce..2865d0788 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -310,7 +310,7 @@ mod tests { fn mod_(syntax: &str) -> Result { let mut parser = Parser::new(syntax); let decls = parser.match_decls().expect("parses"); - Module::from_declarations(&decls, &[], String::new(), String::new()) + Module::from_declarations(&decls, String::new(), String::new()) } #[test] From 18b4076e575f5d43543d502541bddc558948bab0 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 27 Jun 2019 12:03:22 -0700 Subject: [PATCH 249/512] lucet-runtime-tests: fix warning --- lucet-runtime/lucet-runtime-tests/src/strcmp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lucet-runtime/lucet-runtime-tests/src/strcmp.rs b/lucet-runtime/lucet-runtime-tests/src/strcmp.rs index 991f7833b..28f0cc7a3 100644 --- a/lucet-runtime/lucet-runtime-tests/src/strcmp.rs +++ b/lucet-runtime/lucet-runtime-tests/src/strcmp.rs @@ -1,7 +1,7 @@ #[macro_export] macro_rules! strcmp_tests { ( $TestRegion:path ) => { - use libc::{c_char, c_int, c_void, strcmp, uint64_t}; + use libc::{c_char, c_int, c_void, strcmp}; use lucet_runtime::vmctx::lucet_vmctx; use lucet_runtime::{lucet_hostcalls, Error, Limits, Region, Val, WASM_PAGE_SIZE}; use std::ffi::CString; From 2a702818c7fe7638a6bd42129ba95f20e3baf673 Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Thu, 27 Jun 2019 21:06:53 +0200 Subject: [PATCH 250/512] Update the Cargo.toml properties (#234) Add description, homepage, use the same license everywhere, reorder, add the webassembly category for crates.io --- benchmarks/lucet-benchmarks/Cargo.toml | 5 +++++ lucet-analyze/Cargo.toml | 6 ++++-- lucet-idl/Cargo.toml | 4 +++- lucet-module-data/Cargo.toml | 6 +++++- lucet-runtime/Cargo.toml | 6 ++++-- lucet-spectest/Cargo.toml | 4 +++- lucet-wasi-fuzz/Cargo.toml | 5 +++++ lucet-wasi-sdk/Cargo.toml | 6 +++++- lucet-wasi/Cargo.toml | 6 +++++- lucetc/Cargo.toml | 6 ++++-- 10 files changed, 43 insertions(+), 11 deletions(-) diff --git a/benchmarks/lucet-benchmarks/Cargo.toml b/benchmarks/lucet-benchmarks/Cargo.toml index f3eb926bd..9f580b3cc 100644 --- a/benchmarks/lucet-benchmarks/Cargo.toml +++ b/benchmarks/lucet-benchmarks/Cargo.toml @@ -1,6 +1,11 @@ [package] name = "lucet-benchmarks" version = "0.1.0" +description = "Benchmarks for the Lucet runtime" +homepage = "https://github.com/fastly/lucet" +repository = "https://github.com/fastly/lucet" +license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] authors = ["Adam C. Foltzer "] edition = "2018" diff --git a/lucet-analyze/Cargo.toml b/lucet-analyze/Cargo.toml index 117e72d7e..b60269bf5 100644 --- a/lucet-analyze/Cargo.toml +++ b/lucet-analyze/Cargo.toml @@ -1,10 +1,12 @@ [package] name = "lucet-analyze" version = "0.1.0" -description = "Analyze binaries emitted by lucetc" +description = "Analyze object files emitted by the Lucet compiler" +homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" -authors = ["tyler "] license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +authors = ["tyler "] edition = "2018" [dependencies] diff --git a/lucet-idl/Cargo.toml b/lucet-idl/Cargo.toml index ca1e5f53b..59518395b 100644 --- a/lucet-idl/Cargo.toml +++ b/lucet-idl/Cargo.toml @@ -2,9 +2,11 @@ name = "lucet-idl" version = "0.1.0" description = "Describe interfaces between WebAssembly guest programs and lucet-runtime hosts" -authors = ["Pat Hickey ", "Frank Denis "] +homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +authors = ["Pat Hickey ", "Frank Denis "] edition = "2018" [lib] diff --git a/lucet-module-data/Cargo.toml b/lucet-module-data/Cargo.toml index 4d53045e6..d7fe03f7e 100644 --- a/lucet-module-data/Cargo.toml +++ b/lucet-module-data/Cargo.toml @@ -1,8 +1,12 @@ [package] name = "lucet-module-data" version = "0.1.0" -authors = ["Pat Hickey "] +description = "A structured interface for Lucet module data and metadata" +homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" +license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +authors = ["Pat Hickey "] edition = "2018" [dependencies] diff --git a/lucet-runtime/Cargo.toml b/lucet-runtime/Cargo.toml index 33dfb8084..6862625a0 100644 --- a/lucet-runtime/Cargo.toml +++ b/lucet-runtime/Cargo.toml @@ -1,10 +1,12 @@ [package] name = "lucet-runtime" version = "0.1.0" -description = "Pure Rust runtime for lucet WebAssembly toolchain" +description = "Pure Rust runtime for Lucet WebAssembly toolchain" +homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" -authors = ["Adam C. Foltzer ", "Pat Hickey ", "Frank Denis ", "Tyler McMullen "] license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +authors = ["Adam C. Foltzer ", "Pat Hickey ", "Frank Denis ", "Tyler McMullen "] edition = "2018" [dependencies] diff --git a/lucet-spectest/Cargo.toml b/lucet-spectest/Cargo.toml index afd6a8fda..c72b488c0 100644 --- a/lucet-spectest/Cargo.toml +++ b/lucet-spectest/Cargo.toml @@ -2,9 +2,11 @@ name = "lucet-spectest" version = "0.1.0" description = "Test harness to run WebAssembly spec tests (.wast) against the Lucet toolchain" +homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" -authors = ["Pat Hickey "] license = "Apache-2.0 WITH LLVM-exception" +authors = ["Pat Hickey "] +categories = ["wasm"] edition = "2018" [lib] diff --git a/lucet-wasi-fuzz/Cargo.toml b/lucet-wasi-fuzz/Cargo.toml index 7cf19f5c7..400bdb322 100644 --- a/lucet-wasi-fuzz/Cargo.toml +++ b/lucet-wasi-fuzz/Cargo.toml @@ -1,6 +1,11 @@ [package] name = "lucet-wasi-fuzz" version = "0.1.0" +description = "Test the Lucet toolchain against native code execution using Csmith" +homepage = "https://github.com/fastly/lucet" +repository = "https://github.com/fastly/lucet" +license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] authors = ["Adam C. Foltzer "] edition = "2018" diff --git a/lucet-wasi-sdk/Cargo.toml b/lucet-wasi-sdk/Cargo.toml index e0e113494..4e84064ce 100644 --- a/lucet-wasi-sdk/Cargo.toml +++ b/lucet-wasi-sdk/Cargo.toml @@ -1,9 +1,13 @@ [package] name = "lucet-wasi-sdk" version = "0.1.0" +description = "A Rust interface to the wasi-sdk compiler and linker" +homepage = "https://github.com/fastly/lucet" +repository = "https://github.com/fastly/lucet" +license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] authors = ["Pat Hickey "] edition = "2018" -license = "Apache-2.0 WITH LLVM-exception" [dependencies] failure = "0.1" diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index 0669ab6c5..ef12f031c 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -1,9 +1,13 @@ [package] name = "lucet-wasi" version = "0.1.0" +description = "Fastly's runtime for the WebAssembly System Interface (WASI)" +homepage = "https://github.com/fastly/lucet" +repository = "https://github.com/fastly/lucet" +license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] authors = ["Adam C. Foltzer "] edition = "2018" -license = "Apache-2.0 WITH LLVM-exception" [dependencies] cast = "0.2" diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index a19d5c334..f67f7063f 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -1,10 +1,12 @@ [package] name = "lucetc" version = "0.1.0" -description = "Compile WebAssembly to native code" +description = "Fastly's WebAssembly to native code compiler" +homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" -authors = ["Pat Hickey ", "Frank Denis ", "Adam C. Foltzer ", "Tyler McMullen "] license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +authors = ["Pat Hickey ", "Frank Denis ", "Adam C. Foltzer ", "Tyler McMullen "] edition = "2018" [lib] From 06db2125494ce9236de23af8eaad420e7f08b106 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Thu, 27 Jun 2019 17:39:30 -0700 Subject: [PATCH 251/512] add temporary debug output to poll wasi test --- lucet-wasi/tests/guests/poll.c | 7 ++++++- lucet-wasi/tests/tests.rs | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lucet-wasi/tests/guests/poll.c b/lucet-wasi/tests/guests/poll.c index dc45ab58e..632248329 100644 --- a/lucet-wasi/tests/guests/poll.c +++ b/lucet-wasi/tests/guests/poll.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -19,14 +20,18 @@ int main(void) fds[0] = (struct pollfd){ .fd = 0, .events = POLLIN, .revents = 0 }; time(&before); + printf("time before = %lld\n", before); ret = poll(fds, 1, 2000); + printf("ret = %d\n", ret); time(&now); + printf("time now = %lld\n", now); assert(ret == 0); assert(now - before >= 2); sleep(1); time(&now); + printf("time now = %lld\n", now); assert(now - before >= 3); return 0; -} \ No newline at end of file +} diff --git a/lucet-wasi/tests/tests.rs b/lucet-wasi/tests/tests.rs index 18cdf386d..46fc5786d 100644 --- a/lucet-wasi/tests/tests.rs +++ b/lucet-wasi/tests/tests.rs @@ -369,7 +369,11 @@ fn pseudoquine() { #[test] fn poll() { - let ctx = WasiCtxBuilder::new().args(&["poll"]).build().unwrap(); + let ctx = WasiCtxBuilder::new() + .args(&["poll"]) + .inherit_stdio() + .build() + .unwrap(); let exitcode = run("poll.c", ctx).unwrap(); assert_eq!(exitcode, 0); } From 5428edf397c41a7be1c603b393cd548630f9345a Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Fri, 28 Jun 2019 22:20:37 +0200 Subject: [PATCH 252/512] Update wasmonkey (#237) We will eventually get rid of it, but meanwhile, this updates it to use the current versions of parity-wasm and goblin. --- Cargo.lock | 25 ++++++------------- lucet-builtins/wasmonkey/Cargo.toml | 21 ++++++++-------- .../wasmonkey/src/bin/config/mod.rs | 2 +- lucet-builtins/wasmonkey/src/bin/wasmonkey.rs | 6 +---- lucet-builtins/wasmonkey/src/functions_ids.rs | 16 ++++++------ .../wasmonkey/src/functions_names.rs | 12 ++++----- lucet-builtins/wasmonkey/src/lib.rs | 11 ++++---- lucet-builtins/wasmonkey/src/map.rs | 2 +- lucet-builtins/wasmonkey/src/patcher.rs | 20 +++++++-------- lucet-builtins/wasmonkey/src/symbols.rs | 10 ++++---- lucetc/Cargo.toml | 2 +- 11 files changed, 57 insertions(+), 70 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4e99c4ea8..943b07b3e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -980,11 +980,11 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module-data 0.1.0", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-wasm 0.35.7 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmonkey 0.1.4", + "wasmonkey 0.1.7", "wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1151,14 +1151,6 @@ name = "opaque-debug" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "parity-wasm" -version = "0.35.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "parity-wasm" version = "0.38.0" @@ -1612,7 +1604,7 @@ dependencies = [ [[package]] name = "siphasher" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1859,17 +1851,17 @@ dependencies = [ [[package]] name = "wasmonkey" -version = "0.1.4" +version = "0.1.7" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-wasm 0.35.7 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", - "siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "siphasher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2052,7 +2044,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum object 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df4af347f5ac3d0e83e78c26be33cd10e8e874dcb68517a909ad802ba50a90b5" "checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" -"checksum parity-wasm 0.35.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3e1e076c4e01399b6cd0793a8df42f90bba3ae424671ef421d1608a943155d93" "checksum parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)" = "20d7e522a7f994cc4ae32970b1ce0d99ecf91b8e1df080517a26faa6d2e2ee62" "checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" "checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" @@ -2103,7 +2094,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum serde_derive 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)" = "c4cce6663696bd38272e90bf34a0267e1226156c33f52d3f3915a2dd5d802085" "checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" -"checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" +"checksum siphasher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9913c75df657d84a03fa689c016b0bb2863ff0b497b26a8d6e9703f8d5df03a8" "checksum string-interner 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "abb38a0d8fe673c40b10b6b75abcb076a958cc10fb894f14993d9737c4c87000" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fa19a5a708e22bb5be31c1b6108a2a902f909c4b9ba85cba44c06632386bc0ff" diff --git a/lucet-builtins/wasmonkey/Cargo.toml b/lucet-builtins/wasmonkey/Cargo.toml index 8540880ba..65863fd62 100644 --- a/lucet-builtins/wasmonkey/Cargo.toml +++ b/lucet-builtins/wasmonkey/Cargo.toml @@ -1,21 +1,22 @@ [package] name = "wasmonkey" -version = "0.1.4" -authors = ["Frank Denis "] +version = "0.1.7" +authors = ["Lucet team "] description = "Patch a WASM object file to replace a set of exported functions with imported functions from another library" -license = "ISC" -homepage = "https://github.com/jedisct1/wasmonkey" -repository = "https://github.com/jedisct1/wasmonkey" +license = "Apache-2.0 WITH LLVM-exception" +homepage = "https://github.com/fastly/lucet" +repository = "https://github.com/fastly/lucet" categories = ["wasm"] +edition = "2018" [dependencies] -clap = "2.32" +clap = "2.33" failure = "0.1" -goblin = "0.0.21" -lazy_static = "1.2" -parity-wasm = "0.35" +goblin = "0.0.22" +lazy_static = "1.3" +parity-wasm = "0.38" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" -siphasher = "0.2" +siphasher = "0.3" xfailure = "0.1" diff --git a/lucet-builtins/wasmonkey/src/bin/config/mod.rs b/lucet-builtins/wasmonkey/src/bin/config/mod.rs index 87c7f8b02..3b2b60f51 100644 --- a/lucet-builtins/wasmonkey/src/bin/config/mod.rs +++ b/lucet-builtins/wasmonkey/src/bin/config/mod.rs @@ -1,6 +1,6 @@ +use crate::{PatcherConfig, WError}; use clap::{App, Arg}; use std::path::PathBuf; -use {PatcherConfig, WError}; #[derive(Default, Clone, Debug)] pub struct Config { diff --git a/lucet-builtins/wasmonkey/src/bin/wasmonkey.rs b/lucet-builtins/wasmonkey/src/bin/wasmonkey.rs index 1ee180b32..d90c6cbe0 100644 --- a/lucet-builtins/wasmonkey/src/bin/wasmonkey.rs +++ b/lucet-builtins/wasmonkey/src/bin/wasmonkey.rs @@ -1,10 +1,6 @@ -extern crate clap; -extern crate failure; -extern crate wasmonkey; - mod config; -use config::*; +use crate::config::*; use wasmonkey::*; fn main() -> Result<(), WError> { diff --git a/lucet-builtins/wasmonkey/src/functions_ids.rs b/lucet-builtins/wasmonkey/src/functions_ids.rs index c8db939fc..64850d85a 100644 --- a/lucet-builtins/wasmonkey/src/functions_ids.rs +++ b/lucet-builtins/wasmonkey/src/functions_ids.rs @@ -1,4 +1,4 @@ -use errors::*; +use crate::errors::*; use parity_wasm::elements::{ CodeSection, ElementSection, ExportSection, FuncBody, Instruction, Instructions, Internal, Module, @@ -12,8 +12,8 @@ fn shift_function_ids_in_code_section( for code_body in code_bodies.iter_mut() { let opcodes = code_body.code_mut().elements_mut(); for opcode in opcodes.iter_mut() { - if let Instruction::Call(ref mut function_id) = opcode { - *function_id = *function_id + shift + if let Instruction::Call(function_id) = *opcode { + *opcode = Instruction::Call(function_id + shift) } } } @@ -23,8 +23,8 @@ fn shift_function_ids_in_code_section( fn shift_function_ids_in_exports_section(export_section: &mut ExportSection, shift: u32) { for entry in export_section.entries_mut() { let internal = entry.internal_mut(); - if let Internal::Function(ref mut function_id) = internal { - *function_id = *function_id + shift + if let Internal::Function(function_id) = *internal { + *internal = Internal::Function(function_id + shift) } } } @@ -53,9 +53,9 @@ fn replace_function_id_in_code_section(code_section: &mut CodeSection, before: u for code_body in code_bodies.iter_mut() { let opcodes = code_body.code_mut().elements_mut(); for opcode in opcodes.iter_mut() { - match opcode { - Instruction::Call(ref mut function_id) if *function_id == before => { - *function_id = after + match *opcode { + Instruction::Call(function_id) if function_id == before => { + *opcode = Instruction::Call(after) } _ => {} } diff --git a/lucet-builtins/wasmonkey/src/functions_names.rs b/lucet-builtins/wasmonkey/src/functions_names.rs index 9c69d5e41..25ba00b9c 100644 --- a/lucet-builtins/wasmonkey/src/functions_names.rs +++ b/lucet-builtins/wasmonkey/src/functions_names.rs @@ -1,15 +1,15 @@ -use errors::*; -use parity_wasm::elements::{FunctionNameSection, IndexMap}; +use crate::errors::*; +use parity_wasm::elements::{FunctionNameSubsection, IndexMap}; pub fn prepend_function_name( - function_names_section: &mut FunctionNameSection, + function_names_subsection: &mut FunctionNameSubsection, name: String, ) -> Result<(), WError> { - let mut map_new = IndexMap::with_capacity(function_names_section.names().len() + 1 as usize); - for (idx, name) in function_names_section.names() { + let mut map_new = IndexMap::with_capacity(function_names_subsection.names().len() + 1 as usize); + for (idx, name) in function_names_subsection.names() { map_new.insert(idx + 1, name.clone()); } map_new.insert(0, name); - *function_names_section.names_mut() = map_new; + *function_names_subsection.names_mut() = map_new; Ok(()) } diff --git a/lucet-builtins/wasmonkey/src/lib.rs b/lucet-builtins/wasmonkey/src/lib.rs index a00d00961..fa3966bc7 100644 --- a/lucet-builtins/wasmonkey/src/lib.rs +++ b/lucet-builtins/wasmonkey/src/lib.rs @@ -1,13 +1,12 @@ -extern crate clap; #[macro_use] extern crate failure; -extern crate goblin; + #[cfg_attr(test, macro_use)] extern crate lazy_static; -extern crate parity_wasm; + #[macro_use] extern crate serde_derive; -extern crate serde_json; + #[cfg(test)] extern crate siphasher; #[macro_use] @@ -24,5 +23,5 @@ mod symbols; #[cfg(test)] mod tests; -pub use errors::*; -pub use patcher::*; +pub use crate::errors::*; +pub use crate::patcher::*; diff --git a/lucet-builtins/wasmonkey/src/map.rs b/lucet-builtins/wasmonkey/src/map.rs index 81d60c07c..ae50353ff 100644 --- a/lucet-builtins/wasmonkey/src/map.rs +++ b/lucet-builtins/wasmonkey/src/map.rs @@ -1,4 +1,4 @@ -use errors::*; +use crate::errors::*; use serde_json; use std::collections::HashMap; use std::fs::File; diff --git a/lucet-builtins/wasmonkey/src/patcher.rs b/lucet-builtins/wasmonkey/src/patcher.rs index 8514a0929..3eb0df26d 100644 --- a/lucet-builtins/wasmonkey/src/patcher.rs +++ b/lucet-builtins/wasmonkey/src/patcher.rs @@ -1,15 +1,15 @@ -use errors::*; -use functions_ids::*; -use functions_names::*; -use map::*; +use crate::errors::*; +use crate::functions_ids::*; +use crate::functions_names::*; +use crate::map::*; +use crate::sections::*; +use crate::symbols::{self, ExtractedSymbols}; use parity_wasm; use parity_wasm::elements::{ - self, External, ImportEntry, ImportSection, Internal, Module, NameSection, Section, + self, External, ImportEntry, ImportSection, Internal, Module, Section, }; -use sections::*; use std::collections::HashMap; use std::path::{Path, PathBuf}; -use symbols::{self, ExtractedSymbols}; pub const BUILTIN_PREFIX: &str = "builtin_"; @@ -176,11 +176,11 @@ fn prepend_builtin_to_names_section(module: &mut Module, builtin: &Builtin) -> R let names_section = module .names_section_mut() .expect("Names section not present"); - let function_names_section = match names_section { - NameSection::Function(function_names_section) => function_names_section, + let function_names_subsection = match names_section.functions_mut() { + Some(function_names_subsection) => function_names_subsection, _ => xbail!(WError::InternalError("Unexpected names section")), }; - prepend_function_name(function_names_section, import_name)?; + prepend_function_name(function_names_subsection, import_name)?; Ok(()) } diff --git a/lucet-builtins/wasmonkey/src/symbols.rs b/lucet-builtins/wasmonkey/src/symbols.rs index 411c6645d..0ab7d4ce1 100644 --- a/lucet-builtins/wasmonkey/src/symbols.rs +++ b/lucet-builtins/wasmonkey/src/symbols.rs @@ -1,8 +1,8 @@ -use errors::*; +use crate::errors::*; +use crate::patcher::BUILTIN_PREFIX; use goblin::elf::Elf; use goblin::mach::{self, Mach, MachO}; use goblin::Object; -use patcher::BUILTIN_PREFIX; use std::fs::File; use std::io::Read; use std::path::Path; @@ -36,7 +36,7 @@ impl ExtractedSymbols { pub fn merge_additional(mut self, additional_names: &[String]) -> Self { let mut additional_symbols: Vec<_> = additional_names - .into_iter() + .iter() .map(|name| ExtractedSymbol { name: name.to_string(), }) @@ -47,7 +47,7 @@ impl ExtractedSymbols { } } -fn parse_elf(elf: &Elf) -> Result { +fn parse_elf(elf: &Elf<'_>) -> Result { let mut symbols = vec![]; for symbol in elf @@ -67,7 +67,7 @@ fn parse_elf(elf: &Elf) -> Result { Ok(symbols.into()) } -fn parse_macho(macho: &MachO) -> Result { +fn parse_macho(macho: &MachO<'_>) -> Result { let mut symbols = vec![]; // Start by finding the boundaries of the text section diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index f67f7063f..012a6f6d7 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -39,5 +39,5 @@ wabt = "0.7" tempfile = "3.0" bimap = "0.2" human-size = "0.4" -parity-wasm = "0.35" +parity-wasm = "0.38" minisign = "0.5.11" From 3693c0f1a12e52dba2194691a92d98d7ad07e73b Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Sat, 29 Jun 2019 00:11:00 +0200 Subject: [PATCH 253/512] Last bits to make Lucet publishable on crates.io (#238) --- Cargo.lock | 181 ++- Cargo.toml | 2 +- benchmarks/lucet-benchmarks/Cargo.toml | 4 +- cranelift | 2 +- helpers/bump-global-version.sh | 2 +- lucet-analyze/Cargo.toml | 6 +- lucet-idl/Cargo.toml | 4 +- lucet-module-data/Cargo.toml | 6 +- lucet-runtime/Cargo.toml | 10 +- .../lucet-runtime-internals/Cargo.toml | 13 +- lucet-runtime/lucet-runtime-tests/Cargo.toml | 17 +- lucet-spectest/Cargo.toml | 10 +- lucet-wasi-fuzz/Cargo.toml | 4 +- lucet-wasi-sdk/Cargo.toml | 8 +- lucet-wasi/Cargo.toml | 33 +- lucet-wasi/build.rs | 20 +- lucet-wasi/src/host.rs | 2 +- lucet-wasi/src/wasi_host.rs | 1035 +++++++++++++++++ lucetc/Cargo.toml | 22 +- 19 files changed, 1229 insertions(+), 152 deletions(-) create mode 100644 lucet-wasi/src/wasi_host.rs diff --git a/Cargo.lock b/Cargo.lock index 943b07b3e..7d705ad7e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -273,18 +273,18 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.30.0" +version = "0.31.0" dependencies = [ - "cranelift-entity 0.30.0", + "cranelift-entity 0.31.0", ] [[package]] name = "cranelift-codegen" -version = "0.30.0" +version = "0.31.0" dependencies = [ - "cranelift-bforest 0.30.0", - "cranelift-codegen-meta 0.30.0", - "cranelift-entity 0.30.0", + "cranelift-bforest 0.31.0", + "cranelift-codegen-meta 0.31.0", + "cranelift-entity 0.31.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -293,67 +293,66 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.30.0" +version = "0.31.0" dependencies = [ - "cranelift-entity 0.30.0", + "cranelift-entity 0.31.0", ] [[package]] name = "cranelift-entity" -version = "0.30.0" +version = "0.31.0" [[package]] name = "cranelift-faerie" -version = "0.30.0" +version = "0.31.0" dependencies = [ - "cranelift-codegen 0.30.0", - "cranelift-module 0.30.0", + "cranelift-codegen 0.31.0", + "cranelift-module 0.31.0", "faerie 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-frontend" -version = "0.30.0" +version = "0.31.0" dependencies = [ - "cranelift-codegen 0.30.0", + "cranelift-codegen 0.31.0", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-module" -version = "0.30.0" +version = "0.31.0" dependencies = [ - "cranelift-codegen 0.30.0", - "cranelift-entity 0.30.0", + "cranelift-codegen 0.31.0", + "cranelift-entity 0.31.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-native" -version = "0.30.0" +version = "0.31.0" dependencies = [ - "cranelift-codegen 0.30.0", + "cranelift-codegen 0.31.0", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-wasm" -version = "0.30.0" +version = "0.31.0" dependencies = [ - "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.30.0", - "cranelift-entity 0.30.0", - "cranelift-frontend 0.30.0", + "cranelift-codegen 0.31.0", + "cranelift-entity 0.31.0", + "cranelift-frontend 0.31.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.31.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -754,26 +753,26 @@ dependencies = [ [[package]] name = "lucet-analyze" -version = "0.1.0" +version = "0.1.1" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", + "lucet-module-data 0.1.1", ] [[package]] name = "lucet-benchmarks" -version = "0.1.0" +version = "0.1.1" dependencies = [ "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", - "lucet-runtime 0.1.0", - "lucet-runtime-internals 0.1.0", - "lucet-runtime-tests 0.1.0", - "lucet-wasi 0.1.0", - "lucet-wasi-sdk 0.1.0", - "lucetc 0.1.0", + "lucet-module-data 0.1.1", + "lucet-runtime 0.1.1", + "lucet-runtime-internals 0.1.1", + "lucet-runtime-tests 0.1.1", + "lucet-wasi 0.1.1", + "lucet-wasi-sdk 0.1.1", + "lucetc 0.1.1", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -782,13 +781,13 @@ dependencies = [ [[package]] name = "lucet-idl" -version = "0.1.0" +version = "0.1.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", - "lucetc 0.1.0", + "lucet-module-data 0.1.1", + "lucetc 0.1.1", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -802,11 +801,11 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-idl 0.1.0", - "lucet-runtime 0.1.0", - "lucet-wasi 0.1.0", - "lucet-wasi-sdk 0.1.0", - "lucetc 0.1.0", + "lucet-idl 0.1.1", + "lucet-runtime 0.1.1", + "lucet-wasi 0.1.1", + "lucet-wasi-sdk 0.1.1", + "lucetc 0.1.1", "proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -818,18 +817,18 @@ dependencies = [ "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-idl 0.1.0", - "lucet-runtime 0.1.0", - "lucet-wasi 0.1.0", + "lucet-idl 0.1.1", + "lucet-runtime 0.1.1", + "lucet-wasi 0.1.1", ] [[package]] name = "lucet-module-data" -version = "0.1.0" +version = "0.1.1" dependencies = [ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.30.0", + "cranelift-codegen 0.31.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -841,15 +840,15 @@ dependencies = [ [[package]] name = "lucet-runtime" -version = "0.1.0" +version = "0.1.1" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", - "lucet-runtime-internals 0.1.0", - "lucet-runtime-tests 0.1.0", + "lucet-module-data 0.1.1", + "lucet-runtime-internals 0.1.1", + "lucet-runtime-tests 0.1.1", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -857,18 +856,18 @@ dependencies = [ [[package]] name = "lucet-runtime-internals" -version = "0.1.0" +version = "0.1.1" dependencies = [ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.30.0", + "cranelift-codegen 0.31.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", + "lucet-module-data 0.1.1", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -878,27 +877,27 @@ dependencies = [ [[package]] name = "lucet-runtime-tests" -version = "0.1.0" +version = "0.1.1" dependencies = [ "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", - "lucet-runtime-internals 0.1.0", - "lucet-wasi-sdk 0.1.0", - "lucetc 0.1.0", + "lucet-module-data 0.1.1", + "lucet-runtime-internals 0.1.1", + "lucet-wasi-sdk 0.1.1", + "lucetc 0.1.1", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucet-spectest" -version = "0.1.0" +version = "0.1.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", - "lucet-runtime 0.1.0", - "lucetc 0.1.0", + "lucet-module-data 0.1.1", + "lucet-runtime 0.1.1", + "lucetc 0.1.1", "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -907,7 +906,7 @@ dependencies = [ [[package]] name = "lucet-wasi" -version = "0.1.0" +version = "0.1.1" dependencies = [ "bindgen 0.47.3 (registry+https://github.com/rust-lang/crates.io-index)", "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -915,11 +914,11 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", - "lucet-runtime 0.1.0", - "lucet-runtime-internals 0.1.0", - "lucet-wasi-sdk 0.1.0", - "lucetc 0.1.0", + "lucet-module-data 0.1.1", + "lucet-runtime 0.1.1", + "lucet-runtime-internals 0.1.1", + "lucet-wasi-sdk 0.1.1", + "lucetc 0.1.1", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -927,16 +926,16 @@ dependencies = [ [[package]] name = "lucet-wasi-fuzz" -version = "0.1.0" +version = "0.1.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", - "lucet-runtime 0.1.0", - "lucet-wasi 0.1.0", - "lucet-wasi-sdk 0.1.0", - "lucetc 0.1.0", + "lucet-module-data 0.1.1", + "lucet-runtime 0.1.1", + "lucet-wasi 0.1.1", + "lucet-wasi-sdk 0.1.1", + "lucetc 0.1.1", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -950,35 +949,35 @@ dependencies = [ [[package]] name = "lucet-wasi-sdk" -version = "0.1.0" +version = "0.1.1" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", - "lucetc 0.1.0", + "lucet-module-data 0.1.1", + "lucetc 0.1.1", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucetc" -version = "0.1.0" +version = "0.1.1" dependencies = [ "bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.30.0", - "cranelift-entity 0.30.0", - "cranelift-faerie 0.30.0", - "cranelift-frontend 0.30.0", - "cranelift-module 0.30.0", - "cranelift-native 0.30.0", - "cranelift-wasm 0.30.0", + "cranelift-codegen 0.31.0", + "cranelift-entity 0.31.0", + "cranelift-faerie 0.31.0", + "cranelift-frontend 0.31.0", + "cranelift-module 0.31.0", + "cranelift-native 0.31.0", + "cranelift-wasm 0.31.0", "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "faerie 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", + "lucet-module-data 0.1.1", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1872,7 +1871,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "wasmparser" -version = "0.29.2" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2127,7 +2126,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c7904a7e2bb3cdf0cf5e783f44204a85a37a93151738fa349f06680f59a98b45" "checksum wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5e01c420bc7d36e778bd242e1167b079562ba8b34087122cc9057187026d060" -"checksum wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)" = "981a8797cf89762e0233ec45fae731cb79a4dfaee12d9f0fe6cee01e4ac58d00" +"checksum wasmparser 0.31.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6f324afc05fd8282bbc49dae854a1c20f74aeff10a575b5a43453d1864db97" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" diff --git a/Cargo.toml b/Cargo.toml index ae1adde59..ac9c143c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,4 @@ -# Lucet version 0.1.0 +# Lucet version 0.1.1 [workspace] members = [ diff --git a/benchmarks/lucet-benchmarks/Cargo.toml b/benchmarks/lucet-benchmarks/Cargo.toml index 9f580b3cc..34a619be7 100644 --- a/benchmarks/lucet-benchmarks/Cargo.toml +++ b/benchmarks/lucet-benchmarks/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "lucet-benchmarks" -version = "0.1.0" +version = "0.1.1" description = "Benchmarks for the Lucet runtime" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" license = "Apache-2.0 WITH LLVM-exception" categories = ["wasm"] -authors = ["Adam C. Foltzer "] +authors = ["Lucet team "] edition = "2018" [dependencies] diff --git a/cranelift b/cranelift index 42bd100d9..faae51807 160000 --- a/cranelift +++ b/cranelift @@ -1 +1 @@ -Subproject commit 42bd100d9d12e12cea029ba4213c4c154ea0adcb +Subproject commit faae51807d46e5ab2ec2ee257ed5a607b108af11 diff --git a/helpers/bump-global-version.sh b/helpers/bump-global-version.sh index 05f275170..7a9783dc1 100755 --- a/helpers/bump-global-version.sh +++ b/helpers/bump-global-version.sh @@ -6,7 +6,7 @@ VERSION=$(grep '#*Lucet version ' Cargo.toml | sed 's/^ *# Lucet version *//') dry_run() { echo "Checking if the package can be published (dry run)..." echo - find lucetc lucet-* benchmarks/lucet-* -type f -maxdepth 1 -name 'Cargo.toml' -print | while read -r file; do + find lucetc lucet-* benchmarks/lucet-* lucet-runtime/lucet-* lucet-idl/lucet-* -type f -maxdepth 1 -name 'Cargo.toml' -print | while read -r file; do dir="$(dirname $file)" echo "* Checking [$dir]" (cd "$dir" && cargo publish --allow-dirty --dry-run >/dev/null) || exit 1 diff --git a/lucet-analyze/Cargo.toml b/lucet-analyze/Cargo.toml index b60269bf5..fea8da725 100644 --- a/lucet-analyze/Cargo.toml +++ b/lucet-analyze/Cargo.toml @@ -1,16 +1,16 @@ [package] name = "lucet-analyze" -version = "0.1.0" +version = "0.1.1" description = "Analyze object files emitted by the Lucet compiler" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" license = "Apache-2.0 WITH LLVM-exception" categories = ["wasm"] -authors = ["tyler "] +authors = ["Lucet team "] edition = "2018" [dependencies] goblin="0.0.21" byteorder="1.2.1" colored="1.6.1" -lucet-module-data = { path = "../lucet-module-data" } +lucet-module-data = { path = "../lucet-module-data", version = "0.1.1" } diff --git a/lucet-idl/Cargo.toml b/lucet-idl/Cargo.toml index 59518395b..e7988444a 100644 --- a/lucet-idl/Cargo.toml +++ b/lucet-idl/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "lucet-idl" -version = "0.1.0" +version = "0.1.1" description = "Describe interfaces between WebAssembly guest programs and lucet-runtime hosts" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" license = "Apache-2.0 WITH LLVM-exception" categories = ["wasm"] -authors = ["Pat Hickey ", "Frank Denis "] +authors = ["Lucet team "] edition = "2018" [lib] diff --git a/lucet-module-data/Cargo.toml b/lucet-module-data/Cargo.toml index d7fe03f7e..997bff62d 100644 --- a/lucet-module-data/Cargo.toml +++ b/lucet-module-data/Cargo.toml @@ -1,16 +1,16 @@ [package] name = "lucet-module-data" -version = "0.1.0" +version = "0.1.1" description = "A structured interface for Lucet module data and metadata" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" license = "Apache-2.0 WITH LLVM-exception" categories = ["wasm"] -authors = ["Pat Hickey "] +authors = ["Lucet team "] edition = "2018" [dependencies] -cranelift-codegen = { path = "../cranelift/cranelift-codegen" } +cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.31.0" } failure = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/lucet-runtime/Cargo.toml b/lucet-runtime/Cargo.toml index 6862625a0..a84c284b2 100644 --- a/lucet-runtime/Cargo.toml +++ b/lucet-runtime/Cargo.toml @@ -1,18 +1,18 @@ [package] name = "lucet-runtime" -version = "0.1.0" +version = "0.1.1" description = "Pure Rust runtime for Lucet WebAssembly toolchain" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" license = "Apache-2.0 WITH LLVM-exception" categories = ["wasm"] -authors = ["Adam C. Foltzer ", "Pat Hickey ", "Frank Denis ", "Tyler McMullen "] +authors = ["Lucet team "] edition = "2018" [dependencies] libc = "0.2.48" -lucet-runtime-internals = { path = "lucet-runtime-internals" } -lucet-module-data = { path = "../lucet-module-data" } +lucet-runtime-internals = { path = "lucet-runtime-internals", version = "0.1.1" } +lucet-module-data = { path = "../lucet-module-data", version = "0.1.1" } num-traits = "0.2" num-derive = "0.2" @@ -20,7 +20,7 @@ num-derive = "0.2" byteorder = "1.2" failure = "0.1" lazy_static = "1.1" -lucet-runtime-tests = { path = "lucet-runtime-tests" } +lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.1.1" } nix = "0.13" [lib] diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index a9a388825..5b06eeb14 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -1,16 +1,21 @@ [package] name = "lucet-runtime-internals" -version = "0.1.0" -authors = ["Adam C. Foltzer "] +version = "0.1.1" +description = "Pure Rust runtime for Lucet WebAssembly toolchain (internals)" +homepage = "https://github.com/fastly/lucet" +repository = "https://github.com/fastly/lucet" +license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +authors = ["Lucet team "] edition = "2018" [dependencies] -lucet-module-data = { path = "../../lucet-module-data" } +lucet-module-data = { path = "../../lucet-module-data", version = "0.1.1" } bitflags = "1.0" bincode = "~1.0.1" byteorder = "1.3" -cranelift-codegen = { path = "../../cranelift/cranelift-codegen" } +cranelift-codegen = { path = "../../cranelift/cranelift-codegen", version = "0.31.0" } failure = "0.1" lazy_static = "1.1" libc = "0.2.47" diff --git a/lucet-runtime/lucet-runtime-tests/Cargo.toml b/lucet-runtime/lucet-runtime-tests/Cargo.toml index dcf514ad4..f16c4a7b7 100644 --- a/lucet-runtime/lucet-runtime-tests/Cargo.toml +++ b/lucet-runtime/lucet-runtime-tests/Cargo.toml @@ -1,7 +1,12 @@ [package] name = "lucet-runtime-tests" -version = "0.1.0" -authors = ["Adam C. Foltzer "] +version = "0.1.1" +description = "Pure Rust runtime for Lucet WebAssembly toolchain (tests)" +homepage = "https://github.com/fastly/lucet" +repository = "https://github.com/fastly/lucet" +license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +authors = ["Lucet team "] edition = "2018" [lib] @@ -13,10 +18,10 @@ test = false failure = "0.1" lazy_static = "1.1" tempfile = "3.0" -lucet-module-data = { path = "../../lucet-module-data" } -lucet-runtime-internals = { path = "../lucet-runtime-internals" } -lucet-wasi-sdk = { path = "../../lucet-wasi-sdk" } -lucetc = { path = "../../lucetc" } +lucet-module-data = { path = "../../lucet-module-data", version = "0.1.1" } +lucet-runtime-internals = { path = "../lucet-runtime-internals", version = "0.1.1" } +lucet-wasi-sdk = { path = "../../lucet-wasi-sdk", version = "0.1.1" } +lucetc = { path = "../../lucetc", version = "0.1.1" } [build-dependencies] cc = "1.0" diff --git a/lucet-spectest/Cargo.toml b/lucet-spectest/Cargo.toml index c72b488c0..72860d675 100644 --- a/lucet-spectest/Cargo.toml +++ b/lucet-spectest/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "lucet-spectest" -version = "0.1.0" +version = "0.1.1" description = "Test harness to run WebAssembly spec tests (.wast) against the Lucet toolchain" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" license = "Apache-2.0 WITH LLVM-exception" -authors = ["Pat Hickey "] +authors = ["Lucet team "] categories = ["wasm"] edition = "2018" @@ -17,9 +17,9 @@ name = "spec-test" path = "src/main.rs" [dependencies] -lucetc = { path = "../lucetc" } -lucet-module-data = { path = "../lucet-module-data" } -lucet-runtime = { path = "../lucet-runtime" } +lucetc = { path = "../lucetc", version = "0.1.1" } +lucet-module-data = { path = "../lucet-module-data", version = "0.1.1" } +lucet-runtime = { path = "../lucet-runtime", version = "0.1.1" } wabt = "0.7" serde = "1.0" serde_json = "1.0" diff --git a/lucet-wasi-fuzz/Cargo.toml b/lucet-wasi-fuzz/Cargo.toml index 400bdb322..6e97b9a14 100644 --- a/lucet-wasi-fuzz/Cargo.toml +++ b/lucet-wasi-fuzz/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "lucet-wasi-fuzz" -version = "0.1.0" +version = "0.1.1" description = "Test the Lucet toolchain against native code execution using Csmith" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" license = "Apache-2.0 WITH LLVM-exception" categories = ["wasm"] -authors = ["Adam C. Foltzer "] +authors = ["Lucet team "] edition = "2018" [dependencies] diff --git a/lucet-wasi-sdk/Cargo.toml b/lucet-wasi-sdk/Cargo.toml index 4e84064ce..0b759ad44 100644 --- a/lucet-wasi-sdk/Cargo.toml +++ b/lucet-wasi-sdk/Cargo.toml @@ -1,16 +1,16 @@ [package] name = "lucet-wasi-sdk" -version = "0.1.0" +version = "0.1.1" description = "A Rust interface to the wasi-sdk compiler and linker" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" license = "Apache-2.0 WITH LLVM-exception" categories = ["wasm"] -authors = ["Pat Hickey "] +authors = ["Lucet team "] edition = "2018" [dependencies] failure = "0.1" -lucetc = { path = "../lucetc" } -lucet-module-data = { path = "../lucet-module-data" } +lucetc = { path = "../lucetc", version = "0.1.1" } +lucet-module-data = { path = "../lucet-module-data", version = "0.1.1" } tempfile = "3.0" diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index ef12f031c..c01b9ebfa 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -1,33 +1,48 @@ [package] name = "lucet-wasi" -version = "0.1.0" +version = "0.1.1" description = "Fastly's runtime for the WebAssembly System Interface (WASI)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" license = "Apache-2.0 WITH LLVM-exception" categories = ["wasm"] -authors = ["Adam C. Foltzer "] +authors = ["Lucet team "] edition = "2018" +# `src/wasi_host.rs` is automatically generated using clang and +# wasi-libc headers. This requires these to be present, and installed +# at specific paths, which is not something we can rely on outside +# of our environment. +# So, we follow what most other tools using `bindgen` do, and provide +# a pre-generated version of the file, along with a way to update it. +# This is what the `update-bindings` feature do. It requires the WASI SDK +# to be either installed in `/opt/wasi-sdk`, or at a location defined by +# a `WASI_SDK` environment variable, as well as `clang` headers either +# being part of `WASI_SDK`, or found in a path defined by a +# `CLANG_ROOT` environment variable. +[features] +update-bindings = ["bindgen"] + [dependencies] cast = "0.2" clap = "2.23" failure = "0.1" human-size = "0.4" libc = "0.2" -lucet-runtime = { path = "../lucet-runtime" } -lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals" } -lucet-module-data = { path = "../lucet-module-data" } +lucet-runtime = { path = "../lucet-runtime", version = "0.1.1" } +lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.1.1" } +lucet-module-data = { path = "../lucet-module-data", version = "0.1.1" } nix = "0.13" rand = "0.6" [dev-dependencies] -lucet-wasi-sdk = { path = "../lucet-wasi-sdk" } -lucetc = { path = "../lucetc" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.1.1" } +lucetc = { path = "../lucetc", version = "0.1.1" } tempfile = "3.0" -[build-dependencies] -bindgen = "0.47" +[build-dependencies.bindgen] +version = "0.47" +optional = true [lib] name = "lucet_wasi" diff --git a/lucet-wasi/build.rs b/lucet-wasi/build.rs index 0e39fb489..d880ca37f 100644 --- a/lucet-wasi/build.rs +++ b/lucet-wasi/build.rs @@ -1,3 +1,5 @@ +#![allow(unused)] + use std::env; use std::fs::File; use std::path::{Path, PathBuf}; @@ -32,6 +34,21 @@ fn wasm_clang_root() -> PathBuf { } } +// `src/wasi_host.rs` is automatically generated using clang and +// wasi-libc headers. This requires these to be present, and installed +// at specific paths, which is not something we can rely on outside +// of our environment. +// So, we follow what most other tools using `bindgen` do, and provide +// a pre-generated version of the file, along with a way to update it. +// This is what the `update-bindings` feature do. It requires the WASI SDK +// to be either installed in `/opt/wasi-sdk`, or at a location defined by +// a `WASI_SDK` environment variable, as well as `clang` headers either +// being part of `WASI_SDK`, or found in a path defined by a +// `CLANG_ROOT` environment variable. +#[cfg(not(feature = "update-bindings"))] +fn main() {} + +#[cfg(feature = "update-bindings")] fn main() { let wasi_sysroot = wasi_sysroot(); let wasm_clang_root = wasm_clang_root(); @@ -88,9 +105,10 @@ fn main() { .whitelist_type("__wasi_.*") .whitelist_var("__WASI_.*"); + let src_path = Path::new("src"); host_builder .generate() .expect("can generate host bindings") - .write_to_file(out_path.join("wasi_host.rs")) + .write_to_file(src_path.join("wasi_host.rs")) .expect("can write host bindings"); } diff --git a/lucet-wasi/src/host.rs b/lucet-wasi/src/host.rs index fb2c35b6a..e1a6027d0 100644 --- a/lucet-wasi/src/host.rs +++ b/lucet-wasi/src/host.rs @@ -1,7 +1,7 @@ #![allow(non_camel_case_types)] #![allow(non_snake_case)] -include!(concat!(env!("OUT_DIR"), "/wasi_host.rs")); +include!("wasi_host.rs"); pub type void = ::std::os::raw::c_void; diff --git a/lucet-wasi/src/wasi_host.rs b/lucet-wasi/src/wasi_host.rs new file mode 100644 index 000000000..08ae16363 --- /dev/null +++ b/lucet-wasi/src/wasi_host.rs @@ -0,0 +1,1035 @@ +/* automatically generated by rust-bindgen */ + +pub const __WASI_ADVICE_NORMAL: u32 = 0; +pub const __WASI_ADVICE_SEQUENTIAL: u32 = 1; +pub const __WASI_ADVICE_RANDOM: u32 = 2; +pub const __WASI_ADVICE_WILLNEED: u32 = 3; +pub const __WASI_ADVICE_DONTNEED: u32 = 4; +pub const __WASI_ADVICE_NOREUSE: u32 = 5; +pub const __WASI_CLOCK_REALTIME: u32 = 0; +pub const __WASI_CLOCK_MONOTONIC: u32 = 1; +pub const __WASI_CLOCK_PROCESS_CPUTIME_ID: u32 = 2; +pub const __WASI_CLOCK_THREAD_CPUTIME_ID: u32 = 3; +pub const __WASI_DIRCOOKIE_START: u32 = 0; +pub const __WASI_ESUCCESS: u32 = 0; +pub const __WASI_E2BIG: u32 = 1; +pub const __WASI_EACCES: u32 = 2; +pub const __WASI_EADDRINUSE: u32 = 3; +pub const __WASI_EADDRNOTAVAIL: u32 = 4; +pub const __WASI_EAFNOSUPPORT: u32 = 5; +pub const __WASI_EAGAIN: u32 = 6; +pub const __WASI_EALREADY: u32 = 7; +pub const __WASI_EBADF: u32 = 8; +pub const __WASI_EBADMSG: u32 = 9; +pub const __WASI_EBUSY: u32 = 10; +pub const __WASI_ECANCELED: u32 = 11; +pub const __WASI_ECHILD: u32 = 12; +pub const __WASI_ECONNABORTED: u32 = 13; +pub const __WASI_ECONNREFUSED: u32 = 14; +pub const __WASI_ECONNRESET: u32 = 15; +pub const __WASI_EDEADLK: u32 = 16; +pub const __WASI_EDESTADDRREQ: u32 = 17; +pub const __WASI_EDOM: u32 = 18; +pub const __WASI_EDQUOT: u32 = 19; +pub const __WASI_EEXIST: u32 = 20; +pub const __WASI_EFAULT: u32 = 21; +pub const __WASI_EFBIG: u32 = 22; +pub const __WASI_EHOSTUNREACH: u32 = 23; +pub const __WASI_EIDRM: u32 = 24; +pub const __WASI_EILSEQ: u32 = 25; +pub const __WASI_EINPROGRESS: u32 = 26; +pub const __WASI_EINTR: u32 = 27; +pub const __WASI_EINVAL: u32 = 28; +pub const __WASI_EIO: u32 = 29; +pub const __WASI_EISCONN: u32 = 30; +pub const __WASI_EISDIR: u32 = 31; +pub const __WASI_ELOOP: u32 = 32; +pub const __WASI_EMFILE: u32 = 33; +pub const __WASI_EMLINK: u32 = 34; +pub const __WASI_EMSGSIZE: u32 = 35; +pub const __WASI_EMULTIHOP: u32 = 36; +pub const __WASI_ENAMETOOLONG: u32 = 37; +pub const __WASI_ENETDOWN: u32 = 38; +pub const __WASI_ENETRESET: u32 = 39; +pub const __WASI_ENETUNREACH: u32 = 40; +pub const __WASI_ENFILE: u32 = 41; +pub const __WASI_ENOBUFS: u32 = 42; +pub const __WASI_ENODEV: u32 = 43; +pub const __WASI_ENOENT: u32 = 44; +pub const __WASI_ENOEXEC: u32 = 45; +pub const __WASI_ENOLCK: u32 = 46; +pub const __WASI_ENOLINK: u32 = 47; +pub const __WASI_ENOMEM: u32 = 48; +pub const __WASI_ENOMSG: u32 = 49; +pub const __WASI_ENOPROTOOPT: u32 = 50; +pub const __WASI_ENOSPC: u32 = 51; +pub const __WASI_ENOSYS: u32 = 52; +pub const __WASI_ENOTCONN: u32 = 53; +pub const __WASI_ENOTDIR: u32 = 54; +pub const __WASI_ENOTEMPTY: u32 = 55; +pub const __WASI_ENOTRECOVERABLE: u32 = 56; +pub const __WASI_ENOTSOCK: u32 = 57; +pub const __WASI_ENOTSUP: u32 = 58; +pub const __WASI_ENOTTY: u32 = 59; +pub const __WASI_ENXIO: u32 = 60; +pub const __WASI_EOVERFLOW: u32 = 61; +pub const __WASI_EOWNERDEAD: u32 = 62; +pub const __WASI_EPERM: u32 = 63; +pub const __WASI_EPIPE: u32 = 64; +pub const __WASI_EPROTO: u32 = 65; +pub const __WASI_EPROTONOSUPPORT: u32 = 66; +pub const __WASI_EPROTOTYPE: u32 = 67; +pub const __WASI_ERANGE: u32 = 68; +pub const __WASI_EROFS: u32 = 69; +pub const __WASI_ESPIPE: u32 = 70; +pub const __WASI_ESRCH: u32 = 71; +pub const __WASI_ESTALE: u32 = 72; +pub const __WASI_ETIMEDOUT: u32 = 73; +pub const __WASI_ETXTBSY: u32 = 74; +pub const __WASI_EXDEV: u32 = 75; +pub const __WASI_ENOTCAPABLE: u32 = 76; +pub const __WASI_EVENT_FD_READWRITE_HANGUP: u32 = 1; +pub const __WASI_EVENTTYPE_CLOCK: u32 = 0; +pub const __WASI_EVENTTYPE_FD_READ: u32 = 1; +pub const __WASI_EVENTTYPE_FD_WRITE: u32 = 2; +pub const __WASI_FDFLAG_APPEND: u32 = 1; +pub const __WASI_FDFLAG_DSYNC: u32 = 2; +pub const __WASI_FDFLAG_NONBLOCK: u32 = 4; +pub const __WASI_FDFLAG_RSYNC: u32 = 8; +pub const __WASI_FDFLAG_SYNC: u32 = 16; +pub const __WASI_FILETYPE_UNKNOWN: u32 = 0; +pub const __WASI_FILETYPE_BLOCK_DEVICE: u32 = 1; +pub const __WASI_FILETYPE_CHARACTER_DEVICE: u32 = 2; +pub const __WASI_FILETYPE_DIRECTORY: u32 = 3; +pub const __WASI_FILETYPE_REGULAR_FILE: u32 = 4; +pub const __WASI_FILETYPE_SOCKET_DGRAM: u32 = 5; +pub const __WASI_FILETYPE_SOCKET_STREAM: u32 = 6; +pub const __WASI_FILETYPE_SYMBOLIC_LINK: u32 = 7; +pub const __WASI_FILESTAT_SET_ATIM: u32 = 1; +pub const __WASI_FILESTAT_SET_ATIM_NOW: u32 = 2; +pub const __WASI_FILESTAT_SET_MTIM: u32 = 4; +pub const __WASI_FILESTAT_SET_MTIM_NOW: u32 = 8; +pub const __WASI_LOOKUP_SYMLINK_FOLLOW: u32 = 1; +pub const __WASI_O_CREAT: u32 = 1; +pub const __WASI_O_DIRECTORY: u32 = 2; +pub const __WASI_O_EXCL: u32 = 4; +pub const __WASI_O_TRUNC: u32 = 8; +pub const __WASI_SOCK_RECV_PEEK: u32 = 1; +pub const __WASI_SOCK_RECV_WAITALL: u32 = 2; +pub const __WASI_RIGHT_FD_DATASYNC: u32 = 1; +pub const __WASI_RIGHT_FD_READ: u32 = 2; +pub const __WASI_RIGHT_FD_SEEK: u32 = 4; +pub const __WASI_RIGHT_FD_FDSTAT_SET_FLAGS: u32 = 8; +pub const __WASI_RIGHT_FD_SYNC: u32 = 16; +pub const __WASI_RIGHT_FD_TELL: u32 = 32; +pub const __WASI_RIGHT_FD_WRITE: u32 = 64; +pub const __WASI_RIGHT_FD_ADVISE: u32 = 128; +pub const __WASI_RIGHT_FD_ALLOCATE: u32 = 256; +pub const __WASI_RIGHT_PATH_CREATE_DIRECTORY: u32 = 512; +pub const __WASI_RIGHT_PATH_CREATE_FILE: u32 = 1024; +pub const __WASI_RIGHT_PATH_LINK_SOURCE: u32 = 2048; +pub const __WASI_RIGHT_PATH_LINK_TARGET: u32 = 4096; +pub const __WASI_RIGHT_PATH_OPEN: u32 = 8192; +pub const __WASI_RIGHT_FD_READDIR: u32 = 16384; +pub const __WASI_RIGHT_PATH_READLINK: u32 = 32768; +pub const __WASI_RIGHT_PATH_RENAME_SOURCE: u32 = 65536; +pub const __WASI_RIGHT_PATH_RENAME_TARGET: u32 = 131072; +pub const __WASI_RIGHT_PATH_FILESTAT_GET: u32 = 262144; +pub const __WASI_RIGHT_PATH_FILESTAT_SET_SIZE: u32 = 524288; +pub const __WASI_RIGHT_PATH_FILESTAT_SET_TIMES: u32 = 1048576; +pub const __WASI_RIGHT_FD_FILESTAT_GET: u32 = 2097152; +pub const __WASI_RIGHT_FD_FILESTAT_SET_SIZE: u32 = 4194304; +pub const __WASI_RIGHT_FD_FILESTAT_SET_TIMES: u32 = 8388608; +pub const __WASI_RIGHT_PATH_SYMLINK: u32 = 16777216; +pub const __WASI_RIGHT_PATH_REMOVE_DIRECTORY: u32 = 33554432; +pub const __WASI_RIGHT_PATH_UNLINK_FILE: u32 = 67108864; +pub const __WASI_RIGHT_POLL_FD_READWRITE: u32 = 134217728; +pub const __WASI_RIGHT_SOCK_SHUTDOWN: u32 = 268435456; +pub const __WASI_SOCK_RECV_DATA_TRUNCATED: u32 = 1; +pub const __WASI_SHUT_RD: u32 = 1; +pub const __WASI_SHUT_WR: u32 = 2; +pub const __WASI_SIGHUP: u32 = 1; +pub const __WASI_SIGINT: u32 = 2; +pub const __WASI_SIGQUIT: u32 = 3; +pub const __WASI_SIGILL: u32 = 4; +pub const __WASI_SIGTRAP: u32 = 5; +pub const __WASI_SIGABRT: u32 = 6; +pub const __WASI_SIGBUS: u32 = 7; +pub const __WASI_SIGFPE: u32 = 8; +pub const __WASI_SIGKILL: u32 = 9; +pub const __WASI_SIGUSR1: u32 = 10; +pub const __WASI_SIGSEGV: u32 = 11; +pub const __WASI_SIGUSR2: u32 = 12; +pub const __WASI_SIGPIPE: u32 = 13; +pub const __WASI_SIGALRM: u32 = 14; +pub const __WASI_SIGTERM: u32 = 15; +pub const __WASI_SIGCHLD: u32 = 16; +pub const __WASI_SIGCONT: u32 = 17; +pub const __WASI_SIGSTOP: u32 = 18; +pub const __WASI_SIGTSTP: u32 = 19; +pub const __WASI_SIGTTIN: u32 = 20; +pub const __WASI_SIGTTOU: u32 = 21; +pub const __WASI_SIGURG: u32 = 22; +pub const __WASI_SIGXCPU: u32 = 23; +pub const __WASI_SIGXFSZ: u32 = 24; +pub const __WASI_SIGVTALRM: u32 = 25; +pub const __WASI_SIGPROF: u32 = 26; +pub const __WASI_SIGWINCH: u32 = 27; +pub const __WASI_SIGPOLL: u32 = 28; +pub const __WASI_SIGPWR: u32 = 29; +pub const __WASI_SIGSYS: u32 = 30; +pub const __WASI_SUBSCRIPTION_CLOCK_ABSTIME: u32 = 1; +pub const __WASI_WHENCE_CUR: u32 = 0; +pub const __WASI_WHENCE_END: u32 = 1; +pub const __WASI_WHENCE_SET: u32 = 2; +pub const __WASI_PREOPENTYPE_DIR: u32 = 0; +pub type __wasi_advice_t = u8; +pub type __wasi_clockid_t = u32; +pub type __wasi_device_t = u64; +pub type __wasi_dircookie_t = u64; +pub type __wasi_errno_t = u16; +pub type __wasi_eventrwflags_t = u16; +pub type __wasi_eventtype_t = u8; +pub type __wasi_exitcode_t = u32; +pub type __wasi_fd_t = u32; +pub type __wasi_fdflags_t = u16; +pub type __wasi_filedelta_t = i64; +pub type __wasi_filesize_t = u64; +pub type __wasi_filetype_t = u8; +pub type __wasi_fstflags_t = u16; +pub type __wasi_inode_t = u64; +pub type __wasi_linkcount_t = u32; +pub type __wasi_lookupflags_t = u32; +pub type __wasi_oflags_t = u16; +pub type __wasi_riflags_t = u16; +pub type __wasi_rights_t = u64; +pub type __wasi_roflags_t = u16; +pub type __wasi_sdflags_t = u8; +pub type __wasi_siflags_t = u16; +pub type __wasi_signal_t = u8; +pub type __wasi_subclockflags_t = u16; +pub type __wasi_timestamp_t = u64; +pub type __wasi_userdata_t = u64; +pub type __wasi_whence_t = u8; +pub type __wasi_preopentype_t = u8; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __wasi_dirent_t { + pub d_next: __wasi_dircookie_t, + pub d_ino: __wasi_inode_t, + pub d_namlen: u32, + pub d_type: __wasi_filetype_t, +} +#[test] +fn bindgen_test_layout___wasi_dirent_t() { + assert_eq!( + ::std::mem::size_of::<__wasi_dirent_t>(), + 24usize, + concat!("Size of: ", stringify!(__wasi_dirent_t)) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_dirent_t>(), + 8usize, + concat!("Alignment of ", stringify!(__wasi_dirent_t)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_next as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_dirent_t), + "::", + stringify!(d_next) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_ino as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__wasi_dirent_t), + "::", + stringify!(d_ino) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_namlen as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(__wasi_dirent_t), + "::", + stringify!(d_namlen) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_type as *const _ as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(__wasi_dirent_t), + "::", + stringify!(d_type) + ) + ); +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct __wasi_event_t { + pub userdata: __wasi_userdata_t, + pub error: __wasi_errno_t, + pub type_: __wasi_eventtype_t, + pub u: __wasi_event_t___wasi_event_u, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union __wasi_event_t___wasi_event_u { + pub fd_readwrite: __wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t, + _bindgen_union_align: [u64; 2usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { + pub nbytes: __wasi_filesize_t, + pub flags: __wasi_eventrwflags_t, +} +#[test] +fn bindgen_test_layout___wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t() { + assert_eq!( + ::std::mem::size_of::<__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t>(), + 16usize, + concat!( + "Size of: ", + stringify!(__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t) + ) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t>(), + 8usize, + concat!( + "Alignment of ", + stringify!(__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::<__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t>())) + .nbytes as *const _ as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t), + "::", + stringify!(nbytes) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::<__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t>())) + .flags as *const _ as usize + }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t), + "::", + stringify!(flags) + ) + ); +} +#[test] +fn bindgen_test_layout___wasi_event_t___wasi_event_u() { + assert_eq!( + ::std::mem::size_of::<__wasi_event_t___wasi_event_u>(), + 16usize, + concat!("Size of: ", stringify!(__wasi_event_t___wasi_event_u)) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_event_t___wasi_event_u>(), + 8usize, + concat!("Alignment of ", stringify!(__wasi_event_t___wasi_event_u)) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::<__wasi_event_t___wasi_event_u>())).fd_readwrite as *const _ + as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_event_t___wasi_event_u), + "::", + stringify!(fd_readwrite) + ) + ); +} +#[test] +fn bindgen_test_layout___wasi_event_t() { + assert_eq!( + ::std::mem::size_of::<__wasi_event_t>(), + 32usize, + concat!("Size of: ", stringify!(__wasi_event_t)) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_event_t>(), + 8usize, + concat!("Alignment of ", stringify!(__wasi_event_t)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).userdata as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_event_t), + "::", + stringify!(userdata) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).error as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__wasi_event_t), + "::", + stringify!(error) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).type_ as *const _ as usize }, + 10usize, + concat!( + "Offset of field: ", + stringify!(__wasi_event_t), + "::", + stringify!(type_) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).u as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(__wasi_event_t), + "::", + stringify!(u) + ) + ); +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct __wasi_prestat_t { + pub pr_type: __wasi_preopentype_t, + pub u: __wasi_prestat_t___wasi_prestat_u, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union __wasi_prestat_t___wasi_prestat_u { + pub dir: __wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t, + _bindgen_union_align: u64, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t { + pub pr_name_len: usize, +} +#[test] +fn bindgen_test_layout___wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t() { + assert_eq!( + ::std::mem::size_of::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>(), + 8usize, + concat!( + "Size of: ", + stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t) + ) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>(), + 8usize, + concat!( + "Alignment of ", + stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>())) + .pr_name_len as *const _ as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t), + "::", + stringify!(pr_name_len) + ) + ); +} +#[test] +fn bindgen_test_layout___wasi_prestat_t___wasi_prestat_u() { + assert_eq!( + ::std::mem::size_of::<__wasi_prestat_t___wasi_prestat_u>(), + 8usize, + concat!("Size of: ", stringify!(__wasi_prestat_t___wasi_prestat_u)) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_prestat_t___wasi_prestat_u>(), + 8usize, + concat!( + "Alignment of ", + stringify!(__wasi_prestat_t___wasi_prestat_u) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::<__wasi_prestat_t___wasi_prestat_u>())).dir as *const _ as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_prestat_t___wasi_prestat_u), + "::", + stringify!(dir) + ) + ); +} +#[test] +fn bindgen_test_layout___wasi_prestat_t() { + assert_eq!( + ::std::mem::size_of::<__wasi_prestat_t>(), + 16usize, + concat!("Size of: ", stringify!(__wasi_prestat_t)) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_prestat_t>(), + 8usize, + concat!("Alignment of ", stringify!(__wasi_prestat_t)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_prestat_t>())).pr_type as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_prestat_t), + "::", + stringify!(pr_type) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_prestat_t>())).u as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__wasi_prestat_t), + "::", + stringify!(u) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __wasi_fdstat_t { + pub fs_filetype: __wasi_filetype_t, + pub fs_flags: __wasi_fdflags_t, + pub fs_rights_base: __wasi_rights_t, + pub fs_rights_inheriting: __wasi_rights_t, +} +#[test] +fn bindgen_test_layout___wasi_fdstat_t() { + assert_eq!( + ::std::mem::size_of::<__wasi_fdstat_t>(), + 24usize, + concat!("Size of: ", stringify!(__wasi_fdstat_t)) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_fdstat_t>(), + 8usize, + concat!("Alignment of ", stringify!(__wasi_fdstat_t)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_filetype as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_fdstat_t), + "::", + stringify!(fs_filetype) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_flags as *const _ as usize }, + 2usize, + concat!( + "Offset of field: ", + stringify!(__wasi_fdstat_t), + "::", + stringify!(fs_flags) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_rights_base as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__wasi_fdstat_t), + "::", + stringify!(fs_rights_base) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_rights_inheriting as *const _ as usize + }, + 16usize, + concat!( + "Offset of field: ", + stringify!(__wasi_fdstat_t), + "::", + stringify!(fs_rights_inheriting) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __wasi_filestat_t { + pub st_dev: __wasi_device_t, + pub st_ino: __wasi_inode_t, + pub st_filetype: __wasi_filetype_t, + pub st_nlink: __wasi_linkcount_t, + pub st_size: __wasi_filesize_t, + pub st_atim: __wasi_timestamp_t, + pub st_mtim: __wasi_timestamp_t, + pub st_ctim: __wasi_timestamp_t, +} +#[test] +fn bindgen_test_layout___wasi_filestat_t() { + assert_eq!( + ::std::mem::size_of::<__wasi_filestat_t>(), + 56usize, + concat!("Size of: ", stringify!(__wasi_filestat_t)) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_filestat_t>(), + 8usize, + concat!("Alignment of ", stringify!(__wasi_filestat_t)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_dev as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_filestat_t), + "::", + stringify!(st_dev) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_ino as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__wasi_filestat_t), + "::", + stringify!(st_ino) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_filetype as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(__wasi_filestat_t), + "::", + stringify!(st_filetype) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_nlink as *const _ as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(__wasi_filestat_t), + "::", + stringify!(st_nlink) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_size as *const _ as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(__wasi_filestat_t), + "::", + stringify!(st_size) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_atim as *const _ as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(__wasi_filestat_t), + "::", + stringify!(st_atim) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_mtim as *const _ as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(__wasi_filestat_t), + "::", + stringify!(st_mtim) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_ctim as *const _ as usize }, + 48usize, + concat!( + "Offset of field: ", + stringify!(__wasi_filestat_t), + "::", + stringify!(st_ctim) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __wasi_ciovec_t { + pub buf: *const ::std::os::raw::c_void, + pub buf_len: usize, +} +#[test] +fn bindgen_test_layout___wasi_ciovec_t() { + assert_eq!( + ::std::mem::size_of::<__wasi_ciovec_t>(), + 16usize, + concat!("Size of: ", stringify!(__wasi_ciovec_t)) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_ciovec_t>(), + 8usize, + concat!("Alignment of ", stringify!(__wasi_ciovec_t)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_ciovec_t>())).buf as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_ciovec_t), + "::", + stringify!(buf) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_ciovec_t>())).buf_len as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__wasi_ciovec_t), + "::", + stringify!(buf_len) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __wasi_iovec_t { + pub buf: *mut ::std::os::raw::c_void, + pub buf_len: usize, +} +#[test] +fn bindgen_test_layout___wasi_iovec_t() { + assert_eq!( + ::std::mem::size_of::<__wasi_iovec_t>(), + 16usize, + concat!("Size of: ", stringify!(__wasi_iovec_t)) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_iovec_t>(), + 8usize, + concat!("Alignment of ", stringify!(__wasi_iovec_t)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_iovec_t>())).buf as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_iovec_t), + "::", + stringify!(buf) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_iovec_t>())).buf_len as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__wasi_iovec_t), + "::", + stringify!(buf_len) + ) + ); +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct __wasi_subscription_t { + pub userdata: __wasi_userdata_t, + pub type_: __wasi_eventtype_t, + pub u: __wasi_subscription_t___wasi_subscription_u, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union __wasi_subscription_t___wasi_subscription_u { + pub clock: __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, + pub fd_readwrite: + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t, + _bindgen_union_align: [u64; 5usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t { + pub identifier: __wasi_userdata_t, + pub clock_id: __wasi_clockid_t, + pub timeout: __wasi_timestamp_t, + pub precision: __wasi_timestamp_t, + pub flags: __wasi_subclockflags_t, +} +#[test] +fn bindgen_test_layout___wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t() { + assert_eq!( + ::std::mem::size_of::< + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, + >(), + 40usize, + concat!( + "Size of: ", + stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t) + ) + ); + assert_eq!( + ::std::mem::align_of::< + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, + >(), + 8usize, + concat!( + "Alignment of ", + stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::< + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, + >())) + .identifier as *const _ as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t), + "::", + stringify!(identifier) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::< + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, + >())) + .clock_id as *const _ as usize + }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t), + "::", + stringify!(clock_id) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::< + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, + >())) + .timeout as *const _ as usize + }, + 16usize, + concat!( + "Offset of field: ", + stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t), + "::", + stringify!(timeout) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::< + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, + >())) + .precision as *const _ as usize + }, + 24usize, + concat!( + "Offset of field: ", + stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t), + "::", + stringify!(precision) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::< + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, + >())) + .flags as *const _ as usize + }, + 32usize, + concat!( + "Offset of field: ", + stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t), + "::", + stringify!(flags) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t { + pub fd: __wasi_fd_t, +} +#[test] +fn bindgen_test_layout___wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t( +) { + assert_eq!( + ::std::mem::size_of::< + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t, + >(), + 4usize, + concat!( + "Size of: ", + stringify!( + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t + ) + ) + ); + assert_eq!( + ::std::mem::align_of::< + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t, + >(), + 4usize, + concat!( + "Alignment of ", + stringify!( + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t + ) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::< + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t, + >())) + .fd as *const _ as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!( + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t + ), + "::", + stringify!(fd) + ) + ); +} +#[test] +fn bindgen_test_layout___wasi_subscription_t___wasi_subscription_u() { + assert_eq!( + ::std::mem::size_of::<__wasi_subscription_t___wasi_subscription_u>(), + 40usize, + concat!( + "Size of: ", + stringify!(__wasi_subscription_t___wasi_subscription_u) + ) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_subscription_t___wasi_subscription_u>(), + 8usize, + concat!( + "Alignment of ", + stringify!(__wasi_subscription_t___wasi_subscription_u) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::<__wasi_subscription_t___wasi_subscription_u>())).clock + as *const _ as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_subscription_t___wasi_subscription_u), + "::", + stringify!(clock) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::<__wasi_subscription_t___wasi_subscription_u>())).fd_readwrite + as *const _ as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_subscription_t___wasi_subscription_u), + "::", + stringify!(fd_readwrite) + ) + ); +} +#[test] +fn bindgen_test_layout___wasi_subscription_t() { + assert_eq!( + ::std::mem::size_of::<__wasi_subscription_t>(), + 56usize, + concat!("Size of: ", stringify!(__wasi_subscription_t)) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_subscription_t>(), + 8usize, + concat!("Alignment of ", stringify!(__wasi_subscription_t)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_subscription_t>())).userdata as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_subscription_t), + "::", + stringify!(userdata) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_subscription_t>())).type_ as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__wasi_subscription_t), + "::", + stringify!(type_) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_subscription_t>())).u as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(__wasi_subscription_t), + "::", + stringify!(u) + ) + ); +} diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index 012a6f6d7..4b01eb5a0 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "lucetc" -version = "0.1.0" +version = "0.1.1" description = "Fastly's WebAssembly to native code compiler" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" license = "Apache-2.0 WITH LLVM-exception" categories = ["wasm"] -authors = ["Pat Hickey ", "Frank Denis ", "Adam C. Foltzer ", "Tyler McMullen "] +authors = ["Lucet team "] edition = "2018" [lib] @@ -18,15 +18,15 @@ path = "src/main.rs" [dependencies] bincode = "~1.0.1" -cranelift-codegen = { path = "../cranelift/cranelift-codegen" } -cranelift-entity = { path = "../cranelift/cranelift-entity" } -cranelift-native = { path = "../cranelift/cranelift-native" } -cranelift-frontend = { path = "../cranelift/cranelift-frontend" } -cranelift-module = { path = "../cranelift/cranelift-module" } -cranelift-faerie = { path = "../cranelift/cranelift-faerie" } -cranelift-wasm = { path = "../cranelift/cranelift-wasm" } +cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.31.0" } +cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.31.0" } +cranelift-native = { path = "../cranelift/cranelift-native", version = "0.31.0" } +cranelift-frontend = { path = "../cranelift/cranelift-frontend", version = "0.31.0" } +cranelift-module = { path = "../cranelift/cranelift-module", version = "0.31.0" } +cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.31.0" } +cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.31.0" } target-lexicon = "0.3" -lucet-module-data = { path = "../lucet-module-data" } +lucet-module-data = { path = "../lucet-module-data", version = "0.1.1" } wasmparser = "0.23" clap="2.32" log = "0.4" @@ -34,7 +34,7 @@ env_logger = "0.6" faerie = "0.10.0" failure = "0.1" byteorder = "1.2" -wasmonkey = { path = "../lucet-builtins/wasmonkey" } +wasmonkey = { path = "../lucet-builtins/wasmonkey", version = "0.1.7" } wabt = "0.7" tempfile = "3.0" bimap = "0.2" From 36c3c3bf9781c0b605c0fa9d295eb09e8b1ae5a3 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 1 Jul 2019 11:58:31 -0700 Subject: [PATCH 254/512] make the signature testing script work with partial target dirs --- helpers/lucet-toolchain-tests/signature.sh | 31 +++++++++++++++------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/helpers/lucet-toolchain-tests/signature.sh b/helpers/lucet-toolchain-tests/signature.sh index 73343a8a4..6cef39ccc 100755 --- a/helpers/lucet-toolchain-tests/signature.sh +++ b/helpers/lucet-toolchain-tests/signature.sh @@ -1,11 +1,24 @@ #! /bin/sh LUCET_DIR="." -LUCET_TARGET_DIR="${LUCET_DIR}/target/debug" TMPDIR="$(mktemp -d)" -if [ -d "${LUCET_DIR}/target/release" ]; then - LUCET_TARGET_DIR="${LUCET_DIR}/target/release" +if [ -x "${LUCET_DIR}/target/release/lucetc" ]; then + LUCETC="${LUCET_DIR}/target/release/lucetc" +elif [ -x "${LUCET_DIR}/target/debug/lucetc" ]; then + LUCETC="${LUCET_DIR}/target/debug/lucetc" +else + echo "lucetc not found" >&2 + exit 1 +fi + +if [ -x "${LUCET_DIR}/target/release/lucet-wasi" ]; then + LUCET_WASI="${LUCET_DIR}/target/release/lucet-wasi" +elif [ -x "${LUCET_DIR}/target/debug/lucet-wasi" ]; then + LUCET_WASI="${LUCET_DIR}/target/debug/lucet-wasi" +else + echo "lucet-wasi not found" >&2 + exit 1 fi if ! command -v rsign >/dev/null; then @@ -24,7 +37,7 @@ cp "${LUCET_DIR}/lucetc/tests/wasm/call.wat" "${TMPDIR}/test.wat" echo x | rsign sign -p "${TMPDIR}/src_public.key" -s "${TMPDIR}/src_secret.key" "${TMPDIR}/test.wat" >/dev/null echo "Creating a key pair using lucetc for the compiled code" -if ! "${LUCET_TARGET_DIR}/lucetc" \ +if ! "${LUCETC}" \ --signature-keygen \ --signature-pk="${TMPDIR}/public.key" \ --signature-sk="raw:${TMPDIR}/secret.key"; then @@ -33,7 +46,7 @@ if ! "${LUCET_TARGET_DIR}/lucetc" \ fi echo "Trying to compile source code whose signature is invalid" -if "${LUCET_TARGET_DIR}/lucetc" \ +if "${LUCETC}" \ "${TMPDIR}/test.wat" \ -o "${TMPDIR}/test.so" \ --signature-verify \ @@ -43,7 +56,7 @@ if "${LUCET_TARGET_DIR}/lucetc" \ fi echo "Compiling the verified source code" -if ! "${LUCET_TARGET_DIR}/lucetc" \ +if ! "${LUCETC}" \ "${TMPDIR}/test.wat" \ -o "${TMPDIR}/test.so" \ --signature-verify \ @@ -53,7 +66,7 @@ if ! "${LUCET_TARGET_DIR}/lucetc" \ fi echo "Compiling the verified source code and embedding a signature into the resulting object" -if ! "${LUCET_TARGET_DIR}/lucetc" \ +if ! "${LUCETC}" \ "${TMPDIR}/test.wat" \ -o "${TMPDIR}/test.so" \ --signature-create \ @@ -65,7 +78,7 @@ if ! "${LUCET_TARGET_DIR}/lucetc" \ fi echo "Running the resulting object" -if ! "${LUCET_TARGET_DIR}/lucet-wasi" \ +if ! "${LUCET_WASI}" \ "${TMPDIR}/test.so" \ --signature-verify \ --signature-pk="${TMPDIR}/public.key" \ @@ -77,7 +90,7 @@ fi echo >>"${TMPDIR}/test.so" echo "Trying to run a tampered version of the object" -if "${LUCET_TARGET_DIR}/lucet-wasi" \ +if "${LUCET_WASI}" \ "${TMPDIR}/test.so" \ --signature-verify \ --signature-pk="${TMPDIR}/public.key" \ From ccfcbdf6f866f3eca5235732feb940155f288cd3 Mon Sep 17 00:00:00 2001 From: awortman-fastly <49215183+awortman-fastly@users.noreply.github.com> Date: Mon, 8 Jul 2019 09:50:17 -0700 Subject: [PATCH 255/512] Improve import/export function support (#203) * add (failing) test around exported imports of functions * update function manifest entries with imported function addresses this is performed by adding relocations to update function manifest pointers when the module is loaded, which itself this involves bumping `target_lexicon` to match what faerie and cranelift use. this is necessary to support calling imported functions as an instance entrypoint * add exported import test for lucet-runtime this fails, but due to declaration issues with the artifact * don't declare exported imports as export functions exported imports will never have a corresponding function definition for a function body local to the artifact. as a result, imported exports cause a panic at artifact generation time * add support for mock module builder to behave like an exported import is present * add lucetc test around multiple import behavior * rewrite write_relocated_slice to be clear about imported cases * add some functions spectests depended on this fixes the `func_ptrs` spectests! --- Cargo.lock | 14 +--- lucet-module-data/src/bindings.rs | 4 +- .../src/module/mock.rs | 25 ++++++ .../guests/entrypoint/bindings.json | 3 +- .../guests/entrypoint/calculator.wat | 1 + .../lucet-runtime-tests/src/entrypoint.rs | 53 +++++++++++++ lucet-spectest/src/bindings.rs | 23 ++++++ lucetc/Cargo.toml | 3 +- lucetc/src/compiler.rs | 2 +- lucetc/src/decls.rs | 78 ++++++++++++++----- lucetc/src/function_manifest.rs | 62 ++++++++++++--- lucetc/tests/wasm.rs | 40 +++++++++- lucetc/tests/wasm/exported_import.wat | 12 +++ lucetc/tests/wasm/multiple_import.wat | 7 ++ 14 files changed, 279 insertions(+), 48 deletions(-) create mode 100644 lucetc/tests/wasm/exported_import.wat create mode 100644 lucetc/tests/wasm/multiple_import.wat diff --git a/Cargo.lock b/Cargo.lock index 7d705ad7e..1e51bfd5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -975,12 +975,13 @@ dependencies = [ "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "faerie 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module-data 0.1.1", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "wasmonkey 0.1.7", @@ -1665,16 +1666,6 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "target-lexicon" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "target-lexicon" version = "0.4.0" @@ -2101,7 +2092,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" "checksum syn 0.15.38 (registry+https://github.com/rust-lang/crates.io-index)" = "37ea458a750f59ab679b47fef9b6722c586c5742f4cfe18a120bbc807e5e01fd" "checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" -"checksum target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6923974ce4eb5bd28814756256d8ab71c28dd6e7483313fe7ab6614306bf633" "checksum target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b0ab4982b8945c35cc1c46a83a9094c414f6828a099ce5dcaa8ee2b04642dcb" "checksum tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dc4738f2e68ed2855de5ac9cdbe05c9216773ecde4739b2f095002ab03a13ef" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" diff --git a/lucet-module-data/src/bindings.rs b/lucet-module-data/src/bindings.rs index 7d72337bf..3c1dab385 100644 --- a/lucet-module-data/src/bindings.rs +++ b/lucet-module-data/src/bindings.rs @@ -72,10 +72,10 @@ impl Bindings { Ok(()) } - pub fn translate(&self, module: &str, symbol: &str) -> Result { + pub fn translate(&self, module: &str, symbol: &str) -> Result<&str, Error> { match self.bindings.get(module) { Some(m) => match m.get(symbol) { - Some(s) => Ok(s.clone()), + Some(s) => Ok(s), None => Err(format_err!("Unknown symbol `{}::{}`", module, symbol)), }, None => Err(format_err!( diff --git a/lucet-runtime/lucet-runtime-internals/src/module/mock.rs b/lucet-runtime/lucet-runtime-internals/src/module/mock.rs index a1c215060..5e125e923 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/mock.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/mock.rs @@ -145,6 +145,31 @@ impl MockModuleBuilder { self } + pub fn with_exported_import_func( + mut self, + export_name: &'static str, + import_fn_ptr: FunctionPointer, + sig: Signature, + ) -> Self { + self.export_funcs.insert(export_name, import_fn_ptr); + let sig_idx = self.record_sig(sig); + self.function_info.push(OwnedFunctionMetadata { + signature: sig_idx, + name: Some(export_name.to_string()), + }); + self.exports.push(OwnedExportFunction { + fn_idx: FunctionIndex::from_u32(self.function_manifest.len() as u32), + names: vec![export_name.to_string()], + }); + self.function_manifest.push(FunctionSpec::new( + import_fn_ptr.as_usize() as u64, + 0u32, + 0u64, + 0u64, + )); + self + } + pub fn with_table_func(mut self, table_idx: u32, func_idx: u32, func: FunctionPointer) -> Self { self.func_table.insert((table_idx, func_idx), func); self diff --git a/lucet-runtime/lucet-runtime-tests/guests/entrypoint/bindings.json b/lucet-runtime/lucet-runtime-tests/guests/entrypoint/bindings.json index 39f1e1074..bab61d8f5 100644 --- a/lucet-runtime/lucet-runtime-tests/guests/entrypoint/bindings.json +++ b/lucet-runtime/lucet-runtime-tests/guests/entrypoint/bindings.json @@ -1,6 +1,7 @@ { "env": { "black_box": "black_box", - "callback_hostcall": "callback_hostcall" + "callback_hostcall": "callback_hostcall", + "add_4_hostcall": "add_4_hostcall" } } diff --git a/lucet-runtime/lucet-runtime-tests/guests/entrypoint/calculator.wat b/lucet-runtime/lucet-runtime-tests/guests/entrypoint/calculator.wat index 12f50724c..34db1679f 100644 --- a/lucet-runtime/lucet-runtime-tests/guests/entrypoint/calculator.wat +++ b/lucet-runtime/lucet-runtime-tests/guests/entrypoint/calculator.wat @@ -1,4 +1,5 @@ (module + (func $add_4 (export "add_4_reexport") (import "env" "add_4_hostcall") (param i64 i64 i64 i64) (result i64)) (memory 1) (func $add_2 (export "add_2") (param i64 i64) (result i64) (i64.add (get_local 0) (get_local 1)) diff --git a/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs b/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs index 66421f815..f5e252151 100644 --- a/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs +++ b/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs @@ -14,6 +14,16 @@ pub fn mock_calculator_module() -> Arc { arg0 + arg1 } + extern "C" fn add_4_hostcall( + _vmctx: *mut lucet_vmctx, + arg0: u64, + arg1: u64, + arg2: u64, + arg3: u64, + ) -> u64 { + arg0 + arg1 + arg2 + arg3 + } + extern "C" fn add_10( _vmctx: *mut lucet_vmctx, arg0: u64, @@ -124,6 +134,11 @@ pub fn mock_calculator_module() -> Arc { MockExportBuilder::new("add_2", FunctionPointer::from_usize(add_2 as usize)) .with_sig(lucet_signature!((I64, I64) -> I64)), ) + .with_exported_import_func( + "add_4_reexport", + FunctionPointer::from_usize(add_4_hostcall as usize), + lucet_signature!((I64, I64, I64, I64) -> I64), + ) .with_export_func( MockExportBuilder::new("add_10", FunctionPointer::from_usize(add_10 as usize)) .with_sig(lucet_signature!( @@ -585,6 +600,31 @@ macro_rules! entrypoint_tests { } } + #[test] + fn mock_imported_entrypoint() { + imported_entrypoint(mock_calculator_module()) + } + + #[test] + fn wat_imported_entrypoint() { + imported_entrypoint(wat_calculator_module()) + } + + fn imported_entrypoint(module: Arc) { + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + match inst.run( + "add_4_reexport", + &[123u64.into(), 456u64.into(), 789u64.into(), 432u64.into()], + ) { + Ok(res) => assert_eq!(u64::from(res), 1800), + res => panic!("unexpected result: {:?}", res), + } + } + use $crate::build::test_module_c; const TEST_REGION_INIT_VAL: libc::c_int = 123; const TEST_REGION_SIZE: libc::size_t = 4; @@ -853,6 +893,19 @@ macro_rules! entrypoint_tests { } } + lucet_hostcalls! { + #[no_mangle] + pub unsafe extern "C" fn add_4_hostcall( + &mut vmctx, + x: u64, + y: u64, + z: u64, + w: u64, + ) -> u64 { + x + y + z + w + } + } + #[test] fn entrypoint_callback() { let module = diff --git a/lucet-spectest/src/bindings.rs b/lucet-spectest/src/bindings.rs index c642430f7..ca62ec87c 100644 --- a/lucet-spectest/src/bindings.rs +++ b/lucet-spectest/src/bindings.rs @@ -1,6 +1,29 @@ use lucet_module_data::bindings::Bindings; use serde_json::json; +use lucet_runtime::lucet_hostcalls; + +lucet_hostcalls! { + #[no_mangle] + pub unsafe extern "C" fn print(&mut _vmctx,) -> () { + println!("hello, world!"); + } +} + +lucet_hostcalls! { + #[no_mangle] + pub unsafe extern "C" fn print_i32(&mut _vmctx, x: i32,) -> () { + println!("{}", x); + } +} + +lucet_hostcalls! { + #[no_mangle] + pub unsafe extern "C" fn print_f32(&mut _vmctx, x: i32,) -> () { + println!("{}", x); + } +} + pub fn spec_test_bindings() -> Bindings { let imports: serde_json::Value = json!({ "test": { diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index 4b01eb5a0..3e5377705 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -25,13 +25,14 @@ cranelift-frontend = { path = "../cranelift/cranelift-frontend", version = "0.31 cranelift-module = { path = "../cranelift/cranelift-module", version = "0.31.0" } cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.31.0" } cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.31.0" } -target-lexicon = "0.3" +target-lexicon = "0.4.0" lucet-module-data = { path = "../lucet-module-data", version = "0.1.1" } wasmparser = "0.23" clap="2.32" log = "0.4" env_logger = "0.6" faerie = "0.10.0" +goblin = "0.0.22" failure = "0.1" byteorder = "1.2" wasmonkey = { path = "../lucet-builtins/wasmonkey", version = "0.1.7" } diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index 6cf05b23a..4f9569584 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -54,7 +54,7 @@ impl<'a> Compiler<'a> { pub fn new( wasm_binary: &'a [u8], opt_level: OptLevel, - bindings: &Bindings, + bindings: &'a Bindings, heap_settings: HeapSettings, ) -> Result { let isa = Self::target_isa(opt_level); diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index 86803b120..7a0009cb7 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -79,7 +79,7 @@ impl<'a> ModuleDecls<'a> { pub fn new( info: ModuleInfo<'a>, clif_module: &mut ClifModule, - bindings: &Bindings, + bindings: &'a Bindings, runtime: Runtime, heap_settings: HeapSettings, ) -> Result { @@ -109,7 +109,7 @@ impl<'a> ModuleDecls<'a> { fn declare_funcs( decls: &mut ModuleDecls<'a>, clif_module: &mut ClifModule, - bindings: &Bindings, + bindings: &'a Bindings, ) -> Result<(), LucetcError> { for ix in 0..decls.info.functions.len() { let func_index = UniqueFuncIndex::new(ix); @@ -117,7 +117,7 @@ impl<'a> ModuleDecls<'a> { fn export_name_for<'a>( func_ix: UniqueFuncIndex, decls: &mut ModuleDecls<'a>, - ) -> Option<(String, Linkage)> { + ) -> Option { let export = decls.info.functions.get(func_ix).unwrap(); if !export.export_names.is_empty() { @@ -126,10 +126,7 @@ impl<'a> ModuleDecls<'a> { names: export.export_names.clone(), }); - Some(( - format!("guest_func_{}", export.export_names[0]), - Linkage::Export, - )) + Some(format!("guest_func_{}", export.export_names[0])) } else { None } @@ -138,28 +135,51 @@ impl<'a> ModuleDecls<'a> { fn import_name_for<'a>( func_ix: UniqueFuncIndex, decls: &mut ModuleDecls<'a>, - bindings: &Bindings, - ) -> Result, failure::Context> { + bindings: &'a Bindings, + ) -> Result, failure::Context> { if let Some((import_mod, import_field)) = decls.info.imported_funcs.get(func_ix) { + let import_symbol = bindings + .translate(import_mod, import_field) + .context(LucetcErrorKind::TranslatingModule)?; decls.imports.push(ImportFunction { fn_idx: LucetFunctionIndex::from_u32(decls.function_names.len() as u32), module: import_mod, name: import_field, }); - let import_symbol = bindings - .translate(import_mod, import_field) - .context(LucetcErrorKind::TranslatingModule)?; - Ok(Some((import_symbol, Linkage::Import))) + Ok(Some(import_symbol.to_string())) } else { Ok(None) } }; - let (decl_sym, decl_linkage) = import_name_for(func_index, decls, bindings)? - .or_else(|| export_name_for(func_index, decls)) - .unwrap_or_else(|| (format!("guest_func_{}", ix), Linkage::Local)); + let import_info = import_name_for(func_index, decls, bindings)?; + let export_info = export_name_for(func_index, decls); - decls.declare_function(clif_module, decl_sym, decl_linkage, func_index)?; + match (import_info, export_info) { + (Some(import_sym), _) => { + // if a function is only an import, declare the corresponding artifact import. + // if a function is an export and import, it will not have a real function body + // in this program, and we must not declare it with Linkage::Export (there will + // never be a define to satisfy the symbol!) + + decls.declare_function(clif_module, import_sym, Linkage::Import, func_index)?; + } + (None, Some(export_sym)) => { + // This is a function that is only exported, so there will be a body in this + // artifact. We can declare the export. + decls.declare_function(clif_module, export_sym, Linkage::Export, func_index)?; + } + (None, None) => { + // No import or export for this function. It's local, and we have to make up a + // name. + decls.declare_function( + clif_module, + format!("guest_func_{}", ix), + Linkage::Local, + func_index, + )?; + } + } } Ok(()) } @@ -177,7 +197,9 @@ impl<'a> ModuleDecls<'a> { ) -> Result { let (new_funcidx, _) = self.info.declare_func_with_sig(signature); - self.declare_function(clif_module, decl_sym, decl_linkage, new_funcidx) + self.declare_function(clif_module, decl_sym, decl_linkage, new_funcidx)?; + + Ok(new_funcidx) } /// The internal side of fixing up a new function declaration. This is also the work that must @@ -189,6 +211,13 @@ impl<'a> ModuleDecls<'a> { decl_linkage: Linkage, func_ix: UniqueFuncIndex, ) -> Result { + // This function declaration may be a subsequent additional declaration for a function + // we've already been told about. In that case, func_ix will already be a valid index for a + // function name, and we should not try to declare it again. + // + // Regardless of the function being known internally, we must forward the additional + // declaration to `clif_module` so functions with multiple forms of linkage (import + + // export, exported twice, ...) are correctly declared in the resultant artifact. let funcid = clif_module .declare_function( &decl_sym, @@ -196,7 +225,18 @@ impl<'a> ModuleDecls<'a> { self.info.signature_for_function(func_ix), ) .context(LucetcErrorKind::TranslatingModule)?; - self.function_names.push(Name::new_func(decl_sym, funcid)); + + if func_ix.as_u32() as usize >= self.function_names.len() { + // `func_ix` is new, so we need to add the name. If func_ix is new, it should be + // an index for the Name we're about to add. That is, it should be the same as the + // current value for `self.function_names.len()`. + // + // If this fails, we're declaring functions out of order. oops! + debug_assert!(func_ix.as_u32() as usize == self.function_names.len()); + + self.function_names.push(Name::new_func(decl_sym, funcid)); + } + Ok(UniqueFuncIndex::new(self.function_names.len() - 1)) } diff --git a/lucetc/src/function_manifest.rs b/lucetc/src/function_manifest.rs index b7f2105a3..809eb7123 100644 --- a/lucetc/src/function_manifest.rs +++ b/lucetc/src/function_manifest.rs @@ -5,21 +5,58 @@ use failure::{Error, ResultExt}; use lucet_module_data::FunctionSpec; use std::io::Cursor; use std::mem::size_of; +use target_lexicon::BinaryFormat; fn write_relocated_slice( obj: &mut Artifact, buf: &mut Cursor>, from: &str, - to: &str, + to: Option<&str>, len: u64, ) -> Result<(), Error> { - if len > 0 { - obj.link(Link { - from, // the data at `from` + `at` (eg. manifest_sym) - to, // is a reference to `to` (eg. fn_name) - at: buf.position(), - }) - .context(format!("linking {} into function manifest", to))?; + match (to, len) { + (Some(to), 0) => { + // This is an imported slice of unknown size + let absolute_reloc = match obj.target.binary_format { + BinaryFormat::Elf => faerie::artifact::Reloc::Raw { + reloc: goblin::elf::reloc::R_X86_64_64, + addend: 0, + }, + BinaryFormat::Macho => faerie::artifact::Reloc::Raw { + reloc: goblin::mach::relocation::X86_64_RELOC_UNSIGNED as u32, + addend: 0, + }, + _ => panic!("Unsupported target format!"), + }; + + obj.link_with( + Link { + from, + to, + at: buf.position(), + }, + absolute_reloc, + ) + .context(format!("linking {} into function manifest", to))?; + } + (Some(to), _len) => { + // This is a local buffer of known size + obj.link(Link { + from, // the data at `from` + `at` (eg. manifest_sym) + to, // is a reference to `to` (eg. fn_name) + at: buf.position(), + }) + .context(format!("linking {} into function manifest", to))?; + } + (None, len) => { + // There's actually no relocation to add, because there's no slice to put here. + // + // Since there's no slice, its length must be zero. + assert!( + len == 0, + "Invalid slice: no data, but there are more than zero bytes of it" + ); + } } buf.write_u64::(0).unwrap(); @@ -70,15 +107,20 @@ pub fn write_function_manifest( obj, &mut manifest_buf, &manifest_sym, - fn_name, + Some(fn_name), fn_spec.code_len() as u64, )?; // Writes a (ptr, len) pair with relocation for this function's trap table + let trap_sym = trap_sym_for_func(fn_name); write_relocated_slice( obj, &mut manifest_buf, &manifest_sym, - &trap_sym_for_func(fn_name), + if fn_spec.traps_len() > 0 { + Some(&trap_sym) + } else { + None + }, fn_spec.traps_len() as u64, )?; } diff --git a/lucetc/tests/wasm.rs b/lucetc/tests/wasm.rs index f7b700691..84b695cca 100644 --- a/lucetc/tests/wasm.rs +++ b/lucetc/tests/wasm.rs @@ -21,6 +21,7 @@ fn test_bindings() -> Bindings { ("imp_1".into(), "imp_1".into()), // import_many ("imp_2".into(), "imp_2".into()), // import_many ("imp_3".into(), "imp_3".into()), // import_many + ("imported_main".into(), "imported_main".into()), // exported_import ] .iter() .cloned() @@ -36,6 +37,40 @@ mod module_data { use lucetc::{Compiler, HeapSettings, LucetcErrorKind, OptLevel}; use std::path::PathBuf; + #[test] + fn exported_import() { + let m = load_wat_module("exported_import"); + let b = super::test_bindings(); + let h = HeapSettings::default(); + let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compiling exported_import"); + let mdata = c.module_data().unwrap(); + assert_eq!(mdata.globals_spec().len(), 0); + + assert_eq!(mdata.import_functions().len(), 2); + assert_eq!(mdata.export_functions().len(), 2); + assert_eq!(mdata.function_info().len(), 4); + // This ordering is actually arbitrary. Cranelift hoists additional declaration modifiers + // up to the function declaration. This means inc comes first, and main second, in + // `exported_import.wat`. + assert_eq!(mdata.export_functions()[0].names, vec!["exported_inc"]); + assert_eq!(mdata.export_functions()[1].names, vec!["exported_main"]); + } + + #[test] + fn multiple_import() { + let m = load_wat_module("multiple_import"); + let b = super::test_bindings(); + let h = HeapSettings::default(); + let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compiling multiple_import"); + let mdata = c.module_data().unwrap(); + assert_eq!(mdata.globals_spec().len(), 0); + + assert_eq!(mdata.import_functions().len(), 2); + assert_eq!(mdata.export_functions().len(), 1); + assert_eq!(mdata.function_info().len(), 4); + assert_eq!(mdata.export_functions()[0].names, vec!["exported_inc"]); + } + #[test] fn globals_export() { let m = load_wat_module("globals_export"); @@ -100,8 +135,9 @@ mod module_data { assert_eq!(mdata.function_info()[0].name, Some("host_read")); assert_eq!(mdata.function_info()[1].name, Some("host_write")); assert_eq!(mdata.function_info()[2].name, Some("guest_func__start")); - assert_eq!(mdata.export_functions().len(), 1); - assert_eq!(mdata.export_functions()[0].names, ["_start"]); + assert_eq!(mdata.export_functions().len(), 3); + assert_eq!(mdata.export_functions()[0].names, ["read_2", "read"]); + assert_eq!(mdata.export_functions()[2].names, ["_start"]); assert_eq!(mdata.globals_spec().len(), 0); } diff --git a/lucetc/tests/wasm/exported_import.wat b/lucetc/tests/wasm/exported_import.wat new file mode 100644 index 000000000..fce3d74c7 --- /dev/null +++ b/lucetc/tests/wasm/exported_import.wat @@ -0,0 +1,12 @@ +(module + (func (import "env" "inc")) + (func $main (export "exported_main") (import "env" "imported_main")) + + ;; cranelift_wasm bundles up import/export/declaration statements and + ;; declares them together. lucetc depends on function declaration + ;; components not being interwoven, so test that this is still bundled + ;; up by exporting after declaring a new function ("$main", above) + (export "exported_inc" (func 0)) + + (start $main) +) diff --git a/lucetc/tests/wasm/multiple_import.wat b/lucetc/tests/wasm/multiple_import.wat new file mode 100644 index 000000000..be54dfcf5 --- /dev/null +++ b/lucetc/tests/wasm/multiple_import.wat @@ -0,0 +1,7 @@ +(module + (func $inc (import "env" "inc")) + (func $inc_duplicate (import "env" "inc")) + (func $foo (import "env" "imported_main")) + (func $inc_another_duplicate (export "exported_inc") (import "env" "inc")) + (start $inc) +) From 2d6519d051fef9faca44f036d87b5e7698d3e008 Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Mon, 8 Jul 2019 19:57:53 +0200 Subject: [PATCH 256/512] Update to Rust 1.0.36 (#240) * Update to Rust 1.36.0 Remove now deprecated `std::mem::uninitialized()` usage. `rustfmt` includes bug fixes but doesn't seem to change the indentation rules. * Remove the last mem:uninitialized bits --- Dockerfile | 6 ++-- helpers/indent.sh | 4 +-- .../src/instance/signals.rs | 34 +++++++++---------- .../lucet-runtime-internals/src/module/dl.rs | 8 ++--- .../lucet-runtime-tests/src/guest_fault.rs | 13 +++---- lucet-wasi/src/hostcalls/fs.rs | 16 +++++---- lucet-wasi/src/hostcalls/misc.rs | 12 ++++--- rust-toolchain | 2 +- 8 files changed, 51 insertions(+), 44 deletions(-) diff --git a/Dockerfile b/Dockerfile index 96b8e4a36..bc0278740 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,12 +28,12 @@ RUN update-alternatives --install /usr/bin/clang clang /usr/bin/clang-6.0 100 ENV LD_LIBRARY_PATH=/usr/local/lib RUN curl https://sh.rustup.rs -sSf | \ - sh -s -- --default-toolchain 1.35.0 -y && \ + sh -s -- --default-toolchain 1.36.0 -y && \ /root/.cargo/bin/rustup update nightly ENV PATH=/root/.cargo/bin:$PATH -RUN rustup component add rustfmt --toolchain 1.35.0-x86_64-unknown-linux-gnu -RUN rustup target add wasm32-unknown-wasi +RUN rustup component add rustfmt --toolchain 1.36.0-x86_64-unknown-linux-gnu +RUN rustup target add wasm32-wasi RUN cargo install cargo-audit cargo-watch rsign2 diff --git a/helpers/indent.sh b/helpers/indent.sh index 664b7fcc5..654755184 100755 --- a/helpers/indent.sh +++ b/helpers/indent.sh @@ -10,8 +10,8 @@ cleanup() { } trap cleanup 1 2 3 6 15 -if ! rustfmt --version | grep -q "rustfmt 1.2.0-stable"; then - echo "indent requires rustfmt 1.2.0-stable" +if ! rustfmt --version | grep -q "rustfmt 1.2.2-stable"; then + echo "indent requires rustfmt 1.2.2-stable" exit 1 fi diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs index 5b367bbe0..d4deed3d8 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs @@ -11,6 +11,7 @@ use lucet_module_data::TrapCode; use nix::sys::signal::{ pthread_sigmask, raise, sigaction, SaFlags, SigAction, SigHandler, SigSet, SigmaskHow, Signal, }; +use std::mem::MaybeUninit; use std::panic; use std::sync::{Arc, Mutex}; @@ -374,18 +375,20 @@ pub struct SigStack { impl SigStack { pub fn new(sp: *mut libc::c_void, flags: SigStackFlags, size: libc::size_t) -> SigStack { - let mut stack = unsafe { std::mem::uninitialized::() }; - stack.ss_sp = sp; - stack.ss_flags = flags.bits(); - stack.ss_size = size; + let stack = libc::stack_t { + ss_sp: sp, + ss_flags: flags.bits(), + ss_size: size, + }; SigStack { stack } } pub fn disabled() -> SigStack { - let mut stack = unsafe { std::mem::uninitialized::() }; - stack.ss_sp = std::ptr::null_mut(); - stack.ss_flags = SigStackFlags::SS_DISABLE.bits(); - stack.ss_size = libc::SIGSTKSZ; + let stack = libc::stack_t { + ss_sp: std::ptr::null_mut(), + ss_flags: SigStackFlags::SS_DISABLE.bits(), + ss_size: libc::SIGSTKSZ, + }; SigStack { stack } } @@ -414,7 +417,7 @@ bitflags! { } pub unsafe fn sigaltstack(new_sigstack: Option) -> nix::Result> { - let mut previous_stack = std::mem::uninitialized::(); + let mut previous_stack = MaybeUninit::::uninit(); let disabled_sigstack = SigStack::disabled(); let new_stack = match new_sigstack { None => &disabled_sigstack.stack, @@ -422,11 +425,11 @@ pub unsafe fn sigaltstack(new_sigstack: Option) -> nix::Result) -> nix::Result nix::Result { - let mut current_stack = std::mem::uninitialized::(); - let res = libc::sigaltstack( - std::ptr::null_mut(), - &mut current_stack as *mut libc::stack_t, - ); + let mut current_stack = MaybeUninit::::uninit(); + let res = libc::sigaltstack(std::ptr::null_mut(), current_stack.as_mut_ptr()); nix::errno::Errno::result(res) - .map(|_| SigStackFlags::from_bits_truncate(current_stack.ss_flags)) + .map(|_| SigStackFlags::from_bits_truncate(current_stack.assume_init().ss_flags)) } diff --git a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs index b9ef9cbc8..6923aa51c 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs @@ -7,7 +7,7 @@ use lucet_module_data::{ PublicKey, Signature, }; use std::ffi::CStr; -use std::mem; +use std::mem::MaybeUninit; use std::path::Path; use std::slice; use std::slice::from_raw_parts; @@ -267,10 +267,10 @@ fn is_undefined_symbol(e: &std::io::Error) -> bool { // TODO: PR to nix or libloading? // TODO: possibly not safe to use without grabbing the mutex within libloading::Library? fn dladdr(addr: *const c_void) -> Option { - let mut info = unsafe { mem::uninitialized::() }; - let res = unsafe { libc::dladdr(addr, &mut info as *mut libc::Dl_info) }; + let mut info = MaybeUninit::::uninit(); + let res = unsafe { libc::dladdr(addr, info.as_mut_ptr()) }; if res != 0 { - Some(info) + Some(unsafe { info.assume_init() }) } else { None } diff --git a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs index a99df235e..b729160a3 100644 --- a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs +++ b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs @@ -700,14 +700,15 @@ macro_rules! guest_fault_tests { #[test] fn sigaltstack_restores() { use libc::*; + use std::mem::MaybeUninit; test_nonex(|| { // any alternate stack present before a thread runs an instance should be restored // after the instance returns + let mut beforestack = MaybeUninit::::uninit(); let beforestack = unsafe { - let mut beforestack = std::mem::uninitialized::(); - sigaltstack(std::ptr::null(), &mut beforestack as *mut stack_t); - beforestack + sigaltstack(std::ptr::null(), beforestack.as_mut_ptr()); + beforestack.assume_init() }; let module = mock_traps_module(); @@ -718,10 +719,10 @@ macro_rules! guest_fault_tests { .expect("instance can be created"); run_onetwothree(&mut inst); + let mut afterstack = MaybeUninit::::uninit(); let afterstack = unsafe { - let mut afterstack = std::mem::uninitialized::(); - sigaltstack(std::ptr::null(), &mut afterstack as *mut stack_t); - afterstack + sigaltstack(std::ptr::null(), afterstack.as_mut_ptr()); + afterstack.assume_init() }; assert_eq!(beforestack.ss_sp, afterstack.ss_sp); diff --git a/lucet-wasi/src/hostcalls/fs.rs b/lucet-wasi/src/hostcalls/fs.rs index 01bd835e6..7eaee5352 100644 --- a/lucet-wasi/src/hostcalls/fs.rs +++ b/lucet-wasi/src/hostcalls/fs.rs @@ -11,6 +11,7 @@ use lucet_runtime::vmctx::Vmctx; use nix::libc::{self, c_long, c_void, off_t}; use std::ffi::OsStr; +use std::mem::MaybeUninit; use std::os::unix::prelude::{FromRawFd, OsStrExt}; pub fn wasi_fd_close(vmctx: &mut Vmctx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t { @@ -819,11 +820,12 @@ pub fn wasi_fd_filestat_set_times( let fst_flags = dec_fstflags(fst_flags); if fst_flags & (host::__WASI_FILESTAT_SET_MTIM_NOW as host::__wasi_fstflags_t) != 0 { let clock_id = libc::CLOCK_REALTIME; - let mut timespec = unsafe { std::mem::uninitialized::() }; - let res = unsafe { libc::clock_gettime(clock_id, &mut timespec as *mut libc::timespec) }; + let mut timespec = MaybeUninit::::uninit(); + let res = unsafe { libc::clock_gettime(clock_id, timespec.as_mut_ptr()) }; if res != 0 { return wasm32::errno_from_nix(nix::errno::Errno::last()); } + let timespec = unsafe { timespec.assume_init() }; let time_ns = match (timespec.tv_sec as host::__wasi_timestamp_t) .checked_mul(1_000_000_000) .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t)) @@ -887,11 +889,12 @@ pub fn wasi_path_filestat_set_times( let fst_flags = dec_fstflags(fst_flags); if fst_flags & (host::__WASI_FILESTAT_SET_MTIM_NOW as host::__wasi_fstflags_t) != 0 { let clock_id = libc::CLOCK_REALTIME; - let mut timespec = unsafe { std::mem::uninitialized::() }; - let res = unsafe { libc::clock_gettime(clock_id, &mut timespec as *mut libc::timespec) }; + let mut timespec = MaybeUninit::::uninit(); + let res = unsafe { libc::clock_gettime(clock_id, timespec.as_mut_ptr()) }; if res != 0 { return wasm32::errno_from_nix(nix::errno::Errno::last()); } + let timespec = unsafe { timespec.assume_init() }; let time_ns = match (timespec.tv_sec as host::__wasi_timestamp_t) .checked_mul(1_000_000_000) .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t)) @@ -1052,18 +1055,19 @@ pub fn wasi_fd_readdir( if cookie != wasm32::__WASI_DIRCOOKIE_START { unsafe { seekdir(dir, cookie as c_long) }; } - let mut entry_buf = unsafe { std::mem::uninitialized::() }; + let mut entry_buf = MaybeUninit::::uninit(); let mut left = host_buf_len; let mut host_buf_offset: usize = 0; while left > 0 { let mut host_entry: *mut dirent = std::ptr::null_mut(); - let res = unsafe { readdir_r(dir, &mut entry_buf, &mut host_entry) }; + let res = unsafe { readdir_r(dir, entry_buf.as_mut_ptr(), &mut host_entry) }; if res == -1 { return wasm32::errno_from_nix(nix::errno::Errno::last()); } if host_entry.is_null() { break; } + unsafe { entry_buf.assume_init() }; let entry: wasm32::__wasi_dirent_t = match dirent_from_host(&unsafe { *host_entry }) { Ok(entry) => entry, Err(e) => return enc_errno(e), diff --git a/lucet-wasi/src/hostcalls/misc.rs b/lucet-wasi/src/hostcalls/misc.rs index a96161ebc..75f060009 100644 --- a/lucet-wasi/src/hostcalls/misc.rs +++ b/lucet-wasi/src/hostcalls/misc.rs @@ -12,6 +12,7 @@ use lucet_runtime::vmctx::Vmctx; use nix::convert_ioctl_res; use nix::libc::{self, c_int}; use std::cmp; +use std::mem::MaybeUninit; use std::time::SystemTime; // define the `fionread()` function, equivalent to `ioctl(fd, FIONREAD, *bytes)` @@ -123,11 +124,12 @@ pub fn wasi_clock_res_get( }; // no `nix` wrapper for clock_getres, so we do it ourselves - let mut timespec = unsafe { std::mem::uninitialized::() }; - let res = unsafe { libc::clock_getres(clock_id, &mut timespec as *mut libc::timespec) }; + let mut timespec = MaybeUninit::::uninit(); + let res = unsafe { libc::clock_getres(clock_id, timespec.as_mut_ptr()) }; if res != 0 { return wasm32::errno_from_nix(nix::errno::Errno::last()); } + let timespec = unsafe { timespec.assume_init() }; // convert to nanoseconds, returning EOVERFLOW in case of overflow; this is freelancing a bit // from the spec but seems like it'll be an unusual situation to hit @@ -166,12 +168,12 @@ pub fn wasi_clock_time_get( }; // no `nix` wrapper for clock_getres, so we do it ourselves - let mut timespec = unsafe { std::mem::uninitialized::() }; - let res = unsafe { libc::clock_gettime(clock_id, &mut timespec as *mut libc::timespec) }; + let mut timespec = MaybeUninit::::uninit(); + let res = unsafe { libc::clock_gettime(clock_id, timespec.as_mut_ptr()) }; if res != 0 { return wasm32::errno_from_nix(nix::errno::Errno::last()); } - + let timespec = unsafe { timespec.assume_init() }; // convert to nanoseconds, returning EOVERFLOW in case of overflow; this is freelancing a bit // from the spec but seems like it'll be an unusual situation to hit (timespec.tv_sec as host::__wasi_timestamp_t) diff --git a/rust-toolchain b/rust-toolchain index 2aeaa11ee..39fc130ef 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -1.35.0 +1.36.0 From e6f7b5474e8ebd426e6ab4ac3ce7ac7b9aa8a594 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 8 Jul 2019 14:17:47 -0700 Subject: [PATCH 257/512] merge latest changes from master --- Cargo.lock | 251 ++-- Cargo.toml | 2 +- Dockerfile | 6 +- benchmarks/lucet-benchmarks/Cargo.toml | 9 +- cranelift | 2 +- helpers/bump-global-version.sh | 2 +- helpers/indent.sh | 4 +- helpers/lucet-toolchain-tests/signature.sh | 31 +- lucet-analyze/Cargo.toml | 10 +- lucet-builtins/wasmonkey/Cargo.toml | 21 +- .../wasmonkey/src/bin/config/mod.rs | 2 +- lucet-builtins/wasmonkey/src/bin/wasmonkey.rs | 6 +- lucet-builtins/wasmonkey/src/functions_ids.rs | 16 +- .../wasmonkey/src/functions_names.rs | 12 +- lucet-builtins/wasmonkey/src/lib.rs | 11 +- lucet-builtins/wasmonkey/src/map.rs | 2 +- lucet-builtins/wasmonkey/src/patcher.rs | 20 +- lucet-builtins/wasmonkey/src/symbols.rs | 10 +- lucet-idl/Cargo.toml | 6 +- lucet-idl/src/data_layout.rs | 13 +- lucet-idl/src/lib.rs | 2 +- lucet-idl/src/module.rs | 55 +- lucet-idl/src/package.rs | 12 +- lucet-idl/src/parser.rs | 382 +----- lucet-idl/src/types.rs | 23 - lucet-module-data/Cargo.toml | 10 +- lucet-module-data/src/bindings.rs | 4 +- lucet-runtime/Cargo.toml | 14 +- .../lucet-runtime-internals/Cargo.toml | 13 +- .../src/instance/signals.rs | 34 +- .../lucet-runtime-internals/src/module/dl.rs | 8 +- .../src/module/mock.rs | 25 + lucet-runtime/lucet-runtime-tests/Cargo.toml | 17 +- .../guests/entrypoint/bindings.json | 3 +- .../guests/entrypoint/calculator.wat | 1 + .../lucet-runtime-tests/src/entrypoint.rs | 53 + .../lucet-runtime-tests/src/guest_fault.rs | 13 +- lucet-spectest/Cargo.toml | 12 +- lucet-spectest/src/bindings.rs | 23 + lucet-wasi-fuzz/Cargo.toml | 9 +- lucet-wasi-sdk/Cargo.toml | 14 +- lucet-wasi/Cargo.toml | 39 +- lucet-wasi/build.rs | 20 +- lucet-wasi/src/host.rs | 2 +- lucet-wasi/src/hostcalls/fs.rs | 16 +- lucet-wasi/src/hostcalls/misc.rs | 12 +- lucet-wasi/src/wasi_host.rs | 1035 +++++++++++++++++ lucetc/Cargo.toml | 31 +- lucetc/src/compiler.rs | 2 +- lucetc/src/decls.rs | 78 +- lucetc/src/function_manifest.rs | 62 +- lucetc/tests/wasm.rs | 40 +- lucetc/tests/wasm/exported_import.wat | 12 + lucetc/tests/wasm/multiple_import.wat | 7 + rust-toolchain | 2 +- 55 files changed, 1706 insertions(+), 815 deletions(-) create mode 100644 lucet-wasi/src/wasi_host.rs create mode 100644 lucetc/tests/wasm/exported_import.wat create mode 100644 lucetc/tests/wasm/multiple_import.wat diff --git a/Cargo.lock b/Cargo.lock index 757da8f96..5be28521b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,10 +51,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.32" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace-sys 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -62,7 +63,7 @@ dependencies = [ [[package]] name = "backtrace-sys" -version = "0.1.29" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -272,18 +273,18 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.30.0" +version = "0.31.0" dependencies = [ - "cranelift-entity 0.30.0", + "cranelift-entity 0.31.0", ] [[package]] name = "cranelift-codegen" -version = "0.30.0" +version = "0.31.0" dependencies = [ - "cranelift-bforest 0.30.0", - "cranelift-codegen-meta 0.30.0", - "cranelift-entity 0.30.0", + "cranelift-bforest 0.31.0", + "cranelift-codegen-meta 0.31.0", + "cranelift-entity 0.31.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -292,67 +293,66 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.30.0" +version = "0.31.0" dependencies = [ - "cranelift-entity 0.30.0", + "cranelift-entity 0.31.0", ] [[package]] name = "cranelift-entity" -version = "0.30.0" +version = "0.31.0" [[package]] name = "cranelift-faerie" -version = "0.30.0" +version = "0.31.0" dependencies = [ - "cranelift-codegen 0.30.0", - "cranelift-module 0.30.0", + "cranelift-codegen 0.31.0", + "cranelift-module 0.31.0", "faerie 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-frontend" -version = "0.30.0" +version = "0.31.0" dependencies = [ - "cranelift-codegen 0.30.0", + "cranelift-codegen 0.31.0", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-module" -version = "0.30.0" +version = "0.31.0" dependencies = [ - "cranelift-codegen 0.30.0", - "cranelift-entity 0.30.0", + "cranelift-codegen 0.31.0", + "cranelift-entity 0.31.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-native" -version = "0.30.0" +version = "0.31.0" dependencies = [ - "cranelift-codegen 0.30.0", + "cranelift-codegen 0.31.0", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-wasm" -version = "0.30.0" +version = "0.31.0" dependencies = [ - "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.30.0", - "cranelift-entity 0.30.0", - "cranelift-frontend 0.30.0", + "cranelift-codegen 0.31.0", + "cranelift-entity 0.31.0", + "cranelift-frontend 0.31.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.31.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -529,8 +529,8 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "string-interner 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -545,7 +545,7 @@ name = "failure" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -753,25 +753,25 @@ dependencies = [ [[package]] name = "lucet-analyze" -version = "0.1.0" +version = "0.1.1" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", + "lucet-module-data 0.1.1", ] [[package]] name = "lucet-benchmarks" -version = "0.1.0" +version = "0.1.1" dependencies = [ "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", - "lucet-runtime 0.1.0", - "lucet-runtime-internals 0.1.0", - "lucet-wasi 0.1.0", - "lucet-wasi-sdk 0.1.0", - "lucetc 0.1.0", + "lucet-module-data 0.1.1", + "lucet-runtime 0.1.1", + "lucet-runtime-internals 0.1.1", + "lucet-wasi 0.1.1", + "lucet-wasi-sdk 0.1.1", + "lucetc 0.1.1", "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -780,13 +780,13 @@ dependencies = [ [[package]] name = "lucet-idl" -version = "0.1.0" +version = "0.1.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", - "lucetc 0.1.0", + "lucet-module-data 0.1.1", + "lucetc 0.1.1", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -800,11 +800,11 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-idl 0.1.0", - "lucet-runtime 0.1.0", - "lucet-wasi 0.1.0", - "lucet-wasi-sdk 0.1.0", - "lucetc 0.1.0", + "lucet-idl 0.1.1", + "lucet-runtime 0.1.1", + "lucet-wasi 0.1.1", + "lucet-wasi-sdk 0.1.1", + "lucetc 0.1.1", "proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -816,18 +816,18 @@ dependencies = [ "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-idl 0.1.0", - "lucet-runtime 0.1.0", - "lucet-wasi 0.1.0", + "lucet-idl 0.1.1", + "lucet-runtime 0.1.1", + "lucet-wasi 0.1.1", ] [[package]] name = "lucet-module-data" -version = "0.1.0" +version = "0.1.1" dependencies = [ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.30.0", + "cranelift-codegen 0.31.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -839,18 +839,18 @@ dependencies = [ [[package]] name = "lucet-runtime" -version = "0.1.0" +version = "0.1.1" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", - "lucet-runtime-internals 0.1.0", - "lucet-runtime-tests 0.1.0", - "lucet-wasi-sdk 0.1.0", - "lucetc 0.1.0", + "lucet-module-data 0.1.1", + "lucet-runtime-internals 0.1.1", + "lucet-runtime-tests 0.1.1", + "lucet-wasi-sdk 0.1.1", + "lucetc 0.1.1", "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -859,18 +859,18 @@ dependencies = [ [[package]] name = "lucet-runtime-internals" -version = "0.1.0" +version = "0.1.1" dependencies = [ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.30.0", + "cranelift-codegen 0.31.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", + "lucet-module-data 0.1.1", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -880,27 +880,27 @@ dependencies = [ [[package]] name = "lucet-runtime-tests" -version = "0.1.0" +version = "0.1.1" dependencies = [ "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", - "lucet-runtime-internals 0.1.0", - "lucet-wasi-sdk 0.1.0", - "lucetc 0.1.0", + "lucet-module-data 0.1.1", + "lucet-runtime-internals 0.1.1", + "lucet-wasi-sdk 0.1.1", + "lucetc 0.1.1", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucet-spectest" -version = "0.1.0" +version = "0.1.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", - "lucet-runtime 0.1.0", - "lucetc 0.1.0", + "lucet-module-data 0.1.1", + "lucet-runtime 0.1.1", + "lucetc 0.1.1", "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -909,7 +909,7 @@ dependencies = [ [[package]] name = "lucet-wasi" -version = "0.1.0" +version = "0.1.1" dependencies = [ "bindgen 0.47.3 (registry+https://github.com/rust-lang/crates.io-index)", "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -917,11 +917,11 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", - "lucet-runtime 0.1.0", - "lucet-runtime-internals 0.1.0", - "lucet-wasi-sdk 0.1.0", - "lucetc 0.1.0", + "lucet-module-data 0.1.1", + "lucet-runtime 0.1.1", + "lucet-runtime-internals 0.1.1", + "lucet-wasi-sdk 0.1.1", + "lucetc 0.1.1", "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -929,64 +929,65 @@ dependencies = [ [[package]] name = "lucet-wasi-fuzz" -version = "0.1.0" +version = "0.1.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", - "lucet-runtime 0.1.0", - "lucet-wasi 0.1.0", - "lucet-wasi-sdk 0.1.0", - "lucetc 0.1.0", + "lucet-module-data 0.1.1", + "lucet-runtime 0.1.1", + "lucet-wasi 0.1.1", + "lucet-wasi-sdk 0.1.1", + "lucetc 0.1.1", "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucet-wasi-sdk" -version = "0.1.0" +version = "0.1.1" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", - "lucetc 0.1.0", + "lucet-module-data 0.1.1", + "lucetc 0.1.1", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucetc" -version = "0.1.0" +version = "0.1.1" dependencies = [ "bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.30.0", - "cranelift-entity 0.30.0", - "cranelift-faerie 0.30.0", - "cranelift-frontend 0.30.0", - "cranelift-module 0.30.0", - "cranelift-native 0.30.0", - "cranelift-wasm 0.30.0", + "cranelift-codegen 0.31.0", + "cranelift-entity 0.31.0", + "cranelift-faerie 0.31.0", + "cranelift-frontend 0.31.0", + "cranelift-module 0.31.0", + "cranelift-native 0.31.0", + "cranelift-wasm 0.31.0", "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "faerie 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.0", + "lucet-module-data 0.1.1", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-wasm 0.35.7 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmonkey 0.1.4", + "wasmonkey 0.1.7", "wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1153,14 +1154,6 @@ name = "opaque-debug" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "parity-wasm" -version = "0.35.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "parity-wasm" version = "0.38.0" @@ -1614,7 +1607,7 @@ dependencies = [ [[package]] name = "siphasher" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1632,16 +1625,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "structopt" -version = "0.2.18" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "structopt-derive" -version = "0.2.18" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1676,16 +1669,6 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "target-lexicon" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "target-lexicon" version = "0.4.0" @@ -1861,17 +1844,17 @@ dependencies = [ [[package]] name = "wasmonkey" -version = "0.1.4" +version = "0.1.7" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-wasm 0.35.7 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", - "siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "siphasher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1882,7 +1865,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "wasmparser" -version = "0.29.2" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1964,8 +1947,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" -"checksum backtrace 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)" = "18b50f5258d1a9ad8396d2d345827875de4261b158124d4c819d9b351454fae5" -"checksum backtrace-sys 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "12cb9f1eef1d1fc869ad5a26c9fa48516339a15e54a227a25460fc304815fdb3" +"checksum backtrace 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)" = "e0f77aa27f55a4beb477ff6bc4d9bf72f90eb422b19c1d8e5a644b8aeb674d66" +"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum bencher 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdb4953a096c551ce9ace855a604d702e6e62d77fac690575ae347571717f5" "checksum bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "505e45beaf0a1462f5548fe885edf2d83e62022b2ce8b10fef0f7686b48c9266" @@ -2054,7 +2037,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum object 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df4af347f5ac3d0e83e78c26be33cd10e8e874dcb68517a909ad802ba50a90b5" "checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" -"checksum parity-wasm 0.35.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3e1e076c4e01399b6cd0793a8df42f90bba3ae424671ef421d1608a943155d93" "checksum parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)" = "20d7e522a7f994cc4ae32970b1ce0d99ecf91b8e1df080517a26faa6d2e2ee62" "checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" "checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" @@ -2105,15 +2087,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum serde_derive 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)" = "c4cce6663696bd38272e90bf34a0267e1226156c33f52d3f3915a2dd5d802085" "checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" -"checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" +"checksum siphasher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9913c75df657d84a03fa689c016b0bb2863ff0b497b26a8d6e9703f8d5df03a8" "checksum string-interner 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "abb38a0d8fe673c40b10b6b75abcb076a958cc10fb894f14993d9737c4c87000" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" -"checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" +"checksum structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fa19a5a708e22bb5be31c1b6108a2a902f909c4b9ba85cba44c06632386bc0ff" +"checksum structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "c6d59d0ae8ef8de16e49e3ca7afa16024a3e0dfd974a75ef93fdc5464e34523f" "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" "checksum syn 0.15.38 (registry+https://github.com/rust-lang/crates.io-index)" = "37ea458a750f59ab679b47fef9b6722c586c5742f4cfe18a120bbc807e5e01fd" "checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" -"checksum target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6923974ce4eb5bd28814756256d8ab71c28dd6e7483313fe7ab6614306bf633" "checksum target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b0ab4982b8945c35cc1c46a83a9094c414f6828a099ce5dcaa8ee2b04642dcb" "checksum tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dc4738f2e68ed2855de5ac9cdbe05c9216773ecde4739b2f095002ab03a13ef" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" @@ -2138,7 +2119,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c7904a7e2bb3cdf0cf5e783f44204a85a37a93151738fa349f06680f59a98b45" "checksum wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5e01c420bc7d36e778bd242e1167b079562ba8b34087122cc9057187026d060" -"checksum wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)" = "981a8797cf89762e0233ec45fae731cb79a4dfaee12d9f0fe6cee01e4ac58d00" +"checksum wasmparser 0.31.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6f324afc05fd8282bbc49dae854a1c20f74aeff10a575b5a43453d1864db97" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" diff --git a/Cargo.toml b/Cargo.toml index ae1adde59..ac9c143c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,4 @@ -# Lucet version 0.1.0 +# Lucet version 0.1.1 [workspace] members = [ diff --git a/Dockerfile b/Dockerfile index 96b8e4a36..bc0278740 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,12 +28,12 @@ RUN update-alternatives --install /usr/bin/clang clang /usr/bin/clang-6.0 100 ENV LD_LIBRARY_PATH=/usr/local/lib RUN curl https://sh.rustup.rs -sSf | \ - sh -s -- --default-toolchain 1.35.0 -y && \ + sh -s -- --default-toolchain 1.36.0 -y && \ /root/.cargo/bin/rustup update nightly ENV PATH=/root/.cargo/bin:$PATH -RUN rustup component add rustfmt --toolchain 1.35.0-x86_64-unknown-linux-gnu -RUN rustup target add wasm32-unknown-wasi +RUN rustup component add rustfmt --toolchain 1.36.0-x86_64-unknown-linux-gnu +RUN rustup target add wasm32-wasi RUN cargo install cargo-audit cargo-watch rsign2 diff --git a/benchmarks/lucet-benchmarks/Cargo.toml b/benchmarks/lucet-benchmarks/Cargo.toml index e7a49d223..0ae829ca7 100644 --- a/benchmarks/lucet-benchmarks/Cargo.toml +++ b/benchmarks/lucet-benchmarks/Cargo.toml @@ -1,7 +1,12 @@ [package] name = "lucet-benchmarks" -version = "0.1.0" -authors = ["Adam C. Foltzer "] +version = "0.1.1" +description = "Benchmarks for the Lucet runtime" +homepage = "https://github.com/fastly/lucet" +repository = "https://github.com/fastly/lucet" +license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +authors = ["Lucet team "] edition = "2018" [dependencies] diff --git a/cranelift b/cranelift index 42bd100d9..faae51807 160000 --- a/cranelift +++ b/cranelift @@ -1 +1 @@ -Subproject commit 42bd100d9d12e12cea029ba4213c4c154ea0adcb +Subproject commit faae51807d46e5ab2ec2ee257ed5a607b108af11 diff --git a/helpers/bump-global-version.sh b/helpers/bump-global-version.sh index 05f275170..7a9783dc1 100755 --- a/helpers/bump-global-version.sh +++ b/helpers/bump-global-version.sh @@ -6,7 +6,7 @@ VERSION=$(grep '#*Lucet version ' Cargo.toml | sed 's/^ *# Lucet version *//') dry_run() { echo "Checking if the package can be published (dry run)..." echo - find lucetc lucet-* benchmarks/lucet-* -type f -maxdepth 1 -name 'Cargo.toml' -print | while read -r file; do + find lucetc lucet-* benchmarks/lucet-* lucet-runtime/lucet-* lucet-idl/lucet-* -type f -maxdepth 1 -name 'Cargo.toml' -print | while read -r file; do dir="$(dirname $file)" echo "* Checking [$dir]" (cd "$dir" && cargo publish --allow-dirty --dry-run >/dev/null) || exit 1 diff --git a/helpers/indent.sh b/helpers/indent.sh index 664b7fcc5..654755184 100755 --- a/helpers/indent.sh +++ b/helpers/indent.sh @@ -10,8 +10,8 @@ cleanup() { } trap cleanup 1 2 3 6 15 -if ! rustfmt --version | grep -q "rustfmt 1.2.0-stable"; then - echo "indent requires rustfmt 1.2.0-stable" +if ! rustfmt --version | grep -q "rustfmt 1.2.2-stable"; then + echo "indent requires rustfmt 1.2.2-stable" exit 1 fi diff --git a/helpers/lucet-toolchain-tests/signature.sh b/helpers/lucet-toolchain-tests/signature.sh index 73343a8a4..6cef39ccc 100755 --- a/helpers/lucet-toolchain-tests/signature.sh +++ b/helpers/lucet-toolchain-tests/signature.sh @@ -1,11 +1,24 @@ #! /bin/sh LUCET_DIR="." -LUCET_TARGET_DIR="${LUCET_DIR}/target/debug" TMPDIR="$(mktemp -d)" -if [ -d "${LUCET_DIR}/target/release" ]; then - LUCET_TARGET_DIR="${LUCET_DIR}/target/release" +if [ -x "${LUCET_DIR}/target/release/lucetc" ]; then + LUCETC="${LUCET_DIR}/target/release/lucetc" +elif [ -x "${LUCET_DIR}/target/debug/lucetc" ]; then + LUCETC="${LUCET_DIR}/target/debug/lucetc" +else + echo "lucetc not found" >&2 + exit 1 +fi + +if [ -x "${LUCET_DIR}/target/release/lucet-wasi" ]; then + LUCET_WASI="${LUCET_DIR}/target/release/lucet-wasi" +elif [ -x "${LUCET_DIR}/target/debug/lucet-wasi" ]; then + LUCET_WASI="${LUCET_DIR}/target/debug/lucet-wasi" +else + echo "lucet-wasi not found" >&2 + exit 1 fi if ! command -v rsign >/dev/null; then @@ -24,7 +37,7 @@ cp "${LUCET_DIR}/lucetc/tests/wasm/call.wat" "${TMPDIR}/test.wat" echo x | rsign sign -p "${TMPDIR}/src_public.key" -s "${TMPDIR}/src_secret.key" "${TMPDIR}/test.wat" >/dev/null echo "Creating a key pair using lucetc for the compiled code" -if ! "${LUCET_TARGET_DIR}/lucetc" \ +if ! "${LUCETC}" \ --signature-keygen \ --signature-pk="${TMPDIR}/public.key" \ --signature-sk="raw:${TMPDIR}/secret.key"; then @@ -33,7 +46,7 @@ if ! "${LUCET_TARGET_DIR}/lucetc" \ fi echo "Trying to compile source code whose signature is invalid" -if "${LUCET_TARGET_DIR}/lucetc" \ +if "${LUCETC}" \ "${TMPDIR}/test.wat" \ -o "${TMPDIR}/test.so" \ --signature-verify \ @@ -43,7 +56,7 @@ if "${LUCET_TARGET_DIR}/lucetc" \ fi echo "Compiling the verified source code" -if ! "${LUCET_TARGET_DIR}/lucetc" \ +if ! "${LUCETC}" \ "${TMPDIR}/test.wat" \ -o "${TMPDIR}/test.so" \ --signature-verify \ @@ -53,7 +66,7 @@ if ! "${LUCET_TARGET_DIR}/lucetc" \ fi echo "Compiling the verified source code and embedding a signature into the resulting object" -if ! "${LUCET_TARGET_DIR}/lucetc" \ +if ! "${LUCETC}" \ "${TMPDIR}/test.wat" \ -o "${TMPDIR}/test.so" \ --signature-create \ @@ -65,7 +78,7 @@ if ! "${LUCET_TARGET_DIR}/lucetc" \ fi echo "Running the resulting object" -if ! "${LUCET_TARGET_DIR}/lucet-wasi" \ +if ! "${LUCET_WASI}" \ "${TMPDIR}/test.so" \ --signature-verify \ --signature-pk="${TMPDIR}/public.key" \ @@ -77,7 +90,7 @@ fi echo >>"${TMPDIR}/test.so" echo "Trying to run a tampered version of the object" -if "${LUCET_TARGET_DIR}/lucet-wasi" \ +if "${LUCET_WASI}" \ "${TMPDIR}/test.so" \ --signature-verify \ --signature-pk="${TMPDIR}/public.key" \ diff --git a/lucet-analyze/Cargo.toml b/lucet-analyze/Cargo.toml index 117e72d7e..fea8da725 100644 --- a/lucet-analyze/Cargo.toml +++ b/lucet-analyze/Cargo.toml @@ -1,14 +1,16 @@ [package] name = "lucet-analyze" -version = "0.1.0" -description = "Analyze binaries emitted by lucetc" +version = "0.1.1" +description = "Analyze object files emitted by the Lucet compiler" +homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" -authors = ["tyler "] license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +authors = ["Lucet team "] edition = "2018" [dependencies] goblin="0.0.21" byteorder="1.2.1" colored="1.6.1" -lucet-module-data = { path = "../lucet-module-data" } +lucet-module-data = { path = "../lucet-module-data", version = "0.1.1" } diff --git a/lucet-builtins/wasmonkey/Cargo.toml b/lucet-builtins/wasmonkey/Cargo.toml index 8540880ba..65863fd62 100644 --- a/lucet-builtins/wasmonkey/Cargo.toml +++ b/lucet-builtins/wasmonkey/Cargo.toml @@ -1,21 +1,22 @@ [package] name = "wasmonkey" -version = "0.1.4" -authors = ["Frank Denis "] +version = "0.1.7" +authors = ["Lucet team "] description = "Patch a WASM object file to replace a set of exported functions with imported functions from another library" -license = "ISC" -homepage = "https://github.com/jedisct1/wasmonkey" -repository = "https://github.com/jedisct1/wasmonkey" +license = "Apache-2.0 WITH LLVM-exception" +homepage = "https://github.com/fastly/lucet" +repository = "https://github.com/fastly/lucet" categories = ["wasm"] +edition = "2018" [dependencies] -clap = "2.32" +clap = "2.33" failure = "0.1" -goblin = "0.0.21" -lazy_static = "1.2" -parity-wasm = "0.35" +goblin = "0.0.22" +lazy_static = "1.3" +parity-wasm = "0.38" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" -siphasher = "0.2" +siphasher = "0.3" xfailure = "0.1" diff --git a/lucet-builtins/wasmonkey/src/bin/config/mod.rs b/lucet-builtins/wasmonkey/src/bin/config/mod.rs index 87c7f8b02..3b2b60f51 100644 --- a/lucet-builtins/wasmonkey/src/bin/config/mod.rs +++ b/lucet-builtins/wasmonkey/src/bin/config/mod.rs @@ -1,6 +1,6 @@ +use crate::{PatcherConfig, WError}; use clap::{App, Arg}; use std::path::PathBuf; -use {PatcherConfig, WError}; #[derive(Default, Clone, Debug)] pub struct Config { diff --git a/lucet-builtins/wasmonkey/src/bin/wasmonkey.rs b/lucet-builtins/wasmonkey/src/bin/wasmonkey.rs index 1ee180b32..d90c6cbe0 100644 --- a/lucet-builtins/wasmonkey/src/bin/wasmonkey.rs +++ b/lucet-builtins/wasmonkey/src/bin/wasmonkey.rs @@ -1,10 +1,6 @@ -extern crate clap; -extern crate failure; -extern crate wasmonkey; - mod config; -use config::*; +use crate::config::*; use wasmonkey::*; fn main() -> Result<(), WError> { diff --git a/lucet-builtins/wasmonkey/src/functions_ids.rs b/lucet-builtins/wasmonkey/src/functions_ids.rs index c8db939fc..64850d85a 100644 --- a/lucet-builtins/wasmonkey/src/functions_ids.rs +++ b/lucet-builtins/wasmonkey/src/functions_ids.rs @@ -1,4 +1,4 @@ -use errors::*; +use crate::errors::*; use parity_wasm::elements::{ CodeSection, ElementSection, ExportSection, FuncBody, Instruction, Instructions, Internal, Module, @@ -12,8 +12,8 @@ fn shift_function_ids_in_code_section( for code_body in code_bodies.iter_mut() { let opcodes = code_body.code_mut().elements_mut(); for opcode in opcodes.iter_mut() { - if let Instruction::Call(ref mut function_id) = opcode { - *function_id = *function_id + shift + if let Instruction::Call(function_id) = *opcode { + *opcode = Instruction::Call(function_id + shift) } } } @@ -23,8 +23,8 @@ fn shift_function_ids_in_code_section( fn shift_function_ids_in_exports_section(export_section: &mut ExportSection, shift: u32) { for entry in export_section.entries_mut() { let internal = entry.internal_mut(); - if let Internal::Function(ref mut function_id) = internal { - *function_id = *function_id + shift + if let Internal::Function(function_id) = *internal { + *internal = Internal::Function(function_id + shift) } } } @@ -53,9 +53,9 @@ fn replace_function_id_in_code_section(code_section: &mut CodeSection, before: u for code_body in code_bodies.iter_mut() { let opcodes = code_body.code_mut().elements_mut(); for opcode in opcodes.iter_mut() { - match opcode { - Instruction::Call(ref mut function_id) if *function_id == before => { - *function_id = after + match *opcode { + Instruction::Call(function_id) if function_id == before => { + *opcode = Instruction::Call(after) } _ => {} } diff --git a/lucet-builtins/wasmonkey/src/functions_names.rs b/lucet-builtins/wasmonkey/src/functions_names.rs index 9c69d5e41..25ba00b9c 100644 --- a/lucet-builtins/wasmonkey/src/functions_names.rs +++ b/lucet-builtins/wasmonkey/src/functions_names.rs @@ -1,15 +1,15 @@ -use errors::*; -use parity_wasm::elements::{FunctionNameSection, IndexMap}; +use crate::errors::*; +use parity_wasm::elements::{FunctionNameSubsection, IndexMap}; pub fn prepend_function_name( - function_names_section: &mut FunctionNameSection, + function_names_subsection: &mut FunctionNameSubsection, name: String, ) -> Result<(), WError> { - let mut map_new = IndexMap::with_capacity(function_names_section.names().len() + 1 as usize); - for (idx, name) in function_names_section.names() { + let mut map_new = IndexMap::with_capacity(function_names_subsection.names().len() + 1 as usize); + for (idx, name) in function_names_subsection.names() { map_new.insert(idx + 1, name.clone()); } map_new.insert(0, name); - *function_names_section.names_mut() = map_new; + *function_names_subsection.names_mut() = map_new; Ok(()) } diff --git a/lucet-builtins/wasmonkey/src/lib.rs b/lucet-builtins/wasmonkey/src/lib.rs index a00d00961..fa3966bc7 100644 --- a/lucet-builtins/wasmonkey/src/lib.rs +++ b/lucet-builtins/wasmonkey/src/lib.rs @@ -1,13 +1,12 @@ -extern crate clap; #[macro_use] extern crate failure; -extern crate goblin; + #[cfg_attr(test, macro_use)] extern crate lazy_static; -extern crate parity_wasm; + #[macro_use] extern crate serde_derive; -extern crate serde_json; + #[cfg(test)] extern crate siphasher; #[macro_use] @@ -24,5 +23,5 @@ mod symbols; #[cfg(test)] mod tests; -pub use errors::*; -pub use patcher::*; +pub use crate::errors::*; +pub use crate::patcher::*; diff --git a/lucet-builtins/wasmonkey/src/map.rs b/lucet-builtins/wasmonkey/src/map.rs index 81d60c07c..ae50353ff 100644 --- a/lucet-builtins/wasmonkey/src/map.rs +++ b/lucet-builtins/wasmonkey/src/map.rs @@ -1,4 +1,4 @@ -use errors::*; +use crate::errors::*; use serde_json; use std::collections::HashMap; use std::fs::File; diff --git a/lucet-builtins/wasmonkey/src/patcher.rs b/lucet-builtins/wasmonkey/src/patcher.rs index 8514a0929..3eb0df26d 100644 --- a/lucet-builtins/wasmonkey/src/patcher.rs +++ b/lucet-builtins/wasmonkey/src/patcher.rs @@ -1,15 +1,15 @@ -use errors::*; -use functions_ids::*; -use functions_names::*; -use map::*; +use crate::errors::*; +use crate::functions_ids::*; +use crate::functions_names::*; +use crate::map::*; +use crate::sections::*; +use crate::symbols::{self, ExtractedSymbols}; use parity_wasm; use parity_wasm::elements::{ - self, External, ImportEntry, ImportSection, Internal, Module, NameSection, Section, + self, External, ImportEntry, ImportSection, Internal, Module, Section, }; -use sections::*; use std::collections::HashMap; use std::path::{Path, PathBuf}; -use symbols::{self, ExtractedSymbols}; pub const BUILTIN_PREFIX: &str = "builtin_"; @@ -176,11 +176,11 @@ fn prepend_builtin_to_names_section(module: &mut Module, builtin: &Builtin) -> R let names_section = module .names_section_mut() .expect("Names section not present"); - let function_names_section = match names_section { - NameSection::Function(function_names_section) => function_names_section, + let function_names_subsection = match names_section.functions_mut() { + Some(function_names_subsection) => function_names_subsection, _ => xbail!(WError::InternalError("Unexpected names section")), }; - prepend_function_name(function_names_section, import_name)?; + prepend_function_name(function_names_subsection, import_name)?; Ok(()) } diff --git a/lucet-builtins/wasmonkey/src/symbols.rs b/lucet-builtins/wasmonkey/src/symbols.rs index 411c6645d..0ab7d4ce1 100644 --- a/lucet-builtins/wasmonkey/src/symbols.rs +++ b/lucet-builtins/wasmonkey/src/symbols.rs @@ -1,8 +1,8 @@ -use errors::*; +use crate::errors::*; +use crate::patcher::BUILTIN_PREFIX; use goblin::elf::Elf; use goblin::mach::{self, Mach, MachO}; use goblin::Object; -use patcher::BUILTIN_PREFIX; use std::fs::File; use std::io::Read; use std::path::Path; @@ -36,7 +36,7 @@ impl ExtractedSymbols { pub fn merge_additional(mut self, additional_names: &[String]) -> Self { let mut additional_symbols: Vec<_> = additional_names - .into_iter() + .iter() .map(|name| ExtractedSymbol { name: name.to_string(), }) @@ -47,7 +47,7 @@ impl ExtractedSymbols { } } -fn parse_elf(elf: &Elf) -> Result { +fn parse_elf(elf: &Elf<'_>) -> Result { let mut symbols = vec![]; for symbol in elf @@ -67,7 +67,7 @@ fn parse_elf(elf: &Elf) -> Result { Ok(symbols.into()) } -fn parse_macho(macho: &MachO) -> Result { +fn parse_macho(macho: &MachO<'_>) -> Result { let mut symbols = vec![]; // Start by finding the boundaries of the text section diff --git a/lucet-idl/Cargo.toml b/lucet-idl/Cargo.toml index ca1e5f53b..e7988444a 100644 --- a/lucet-idl/Cargo.toml +++ b/lucet-idl/Cargo.toml @@ -1,10 +1,12 @@ [package] name = "lucet-idl" -version = "0.1.0" +version = "0.1.1" description = "Describe interfaces between WebAssembly guest programs and lucet-runtime hosts" -authors = ["Pat Hickey ", "Frank Denis "] +homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +authors = ["Lucet team "] edition = "2018" [lib] diff --git a/lucet-idl/src/data_layout.rs b/lucet-idl/src/data_layout.rs index c928d0e41..4d4e6351d 100644 --- a/lucet-idl/src/data_layout.rs +++ b/lucet-idl/src/data_layout.rs @@ -1,14 +1,13 @@ use crate::error::ValidationError; use crate::types::{ - AliasDataType, AtomType, Attr, DataType, DataTypeRef, DataTypeVariant, EnumDataType, - EnumMember, Ident, Location, Name, StructDataType, StructMember, + AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, EnumMember, + Ident, Location, Name, StructDataType, StructMember, }; use std::collections::HashMap; #[derive(Debug, PartialEq, Eq, Clone)] struct DataTypeIR { pub variant: VariantIR, - pub attrs: Vec, pub location: Location, } @@ -16,7 +15,6 @@ struct DataTypeIR { pub struct StructMemberIR { pub type_: DataTypeRef, pub name: String, - pub attrs: Vec, } #[derive(Debug, PartialEq, Eq, Clone)] @@ -53,12 +51,11 @@ impl DataTypeModuleBuilder { } } - pub fn define(&mut self, id: Ident, variant: VariantIR, attrs: Vec, location: Location) { + pub fn define(&mut self, id: Ident, variant: VariantIR, location: Location) { if let Some(prev_def) = self.data_types.insert( id, DataTypeIR { variant, - attrs: attrs.clone(), location: location.clone(), }, ) { @@ -104,7 +101,6 @@ impl DataTypeModuleBuilder { members.push(StructMember { type_: mem.type_.clone(), name: mem.name.clone(), - attrs: mem.attrs.clone(), offset, }); offset += repr_size; @@ -116,7 +112,6 @@ impl DataTypeModuleBuilder { id, DataType { variant: DataTypeVariant::Struct(StructDataType { members }), - attrs: dt.attrs.clone(), repr_size, align: struct_align, }, @@ -134,7 +129,6 @@ impl DataTypeModuleBuilder { id, DataType { variant: DataTypeVariant::Alias(AliasDataType { to: a.to.clone() }), - attrs: dt.attrs.clone(), repr_size, align, }, @@ -153,7 +147,6 @@ impl DataTypeModuleBuilder { variant: DataTypeVariant::Enum(EnumDataType { members: e.members.clone(), }), - attrs: dt.attrs.clone(), repr_size, align, }, diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 70fa95d15..19875bdc6 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -20,7 +20,7 @@ pub use crate::error::IDLError; pub use crate::module::Module; pub use crate::package::Package; pub use crate::types::{ - AliasDataType, AtomType, Attr, DataType, DataTypeRef, DataTypeVariant, EnumDataType, FuncDecl, + AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, FuncDecl, FuncRet, Ident, Location, Name, Named, StructDataType, StructMember, }; diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index 3f70c62d1..2865d0788 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -4,8 +4,7 @@ use crate::data_layout::{ use crate::error::ValidationError; use crate::parser::{SyntaxDecl, SyntaxRef}; use crate::types::{ - Attr, DataType, DataTypeRef, EnumMember, FuncArg, FuncDecl, FuncRet, Ident, Location, Name, - Named, + DataType, DataTypeRef, EnumMember, FuncArg, FuncDecl, FuncRet, Ident, Location, Name, Named, }; use heck::SnakeCase; use std::collections::HashMap; @@ -13,7 +12,6 @@ use std::collections::HashMap; #[derive(Debug, PartialEq, Eq, Clone)] pub struct Module { pub names: Vec, - pub attrs: Vec, pub data_types: HashMap, pub data_type_ordering: Vec, pub funcs: HashMap, @@ -22,10 +20,9 @@ pub struct Module { } impl Module { - fn new(attrs: &[Attr], module_name: String, binding_prefix: String) -> Self { + fn new(module_name: String, binding_prefix: String) -> Self { Self { names: Vec::new(), - attrs: attrs.to_vec(), data_types: HashMap::new(), data_type_ordering: Vec::new(), funcs: HashMap::new(), @@ -92,7 +89,6 @@ impl Module { SyntaxDecl::Struct { name, members, - attrs, location, } => { let mut uniq_membs = HashMap::new(); @@ -119,7 +115,6 @@ impl Module { dtype_members.push(StructMemberIR { type_, name: mem.name.clone(), - attrs: mem.attrs.clone(), }) } @@ -128,14 +123,12 @@ impl Module { VariantIR::Struct(StructIR { members: dtype_members, }), - attrs.clone(), location.clone(), ); } SyntaxDecl::Enum { name, variants, - attrs, location, } => { let mut uniq_vars = HashMap::new(); @@ -158,7 +151,6 @@ impl Module { // build the struct with this as the member: dtype_members.push(EnumMember { name: var.name.clone(), - attrs: var.attrs.clone(), }) } data_types_ir.define( @@ -166,29 +158,17 @@ impl Module { VariantIR::Enum(EnumIR { members: dtype_members, }), - attrs.clone(), location.clone(), ); } - SyntaxDecl::Alias { - what, - attrs, - location, - .. - } => { + SyntaxDecl::Alias { what, location, .. } => { let to = self.get_ref(what)?; - data_types_ir.define( - id, - VariantIR::Alias(AliasIR { to }), - attrs.clone(), - location.clone(), - ); + data_types_ir.define(id, VariantIR::Alias(AliasIR { to }), location.clone()); } SyntaxDecl::Function { name, args, rets, - attrs, location, .. } => { @@ -209,7 +189,6 @@ impl Module { Ok(FuncArg { name: arg_syntax.name.clone(), type_, - attrs: arg_syntax.attrs.clone(), }) }) .collect::, _>>()?; @@ -218,10 +197,7 @@ impl Module { .iter() .map(|ret_syntax| { let type_ = self.get_ref(&ret_syntax.type_)?; - Ok(FuncRet { - type_, - attrs: ret_syntax.attrs.clone(), - }) + Ok(FuncRet { type_ }) }) .collect::, _>>()?; if rets.len() > 1 { @@ -235,7 +211,6 @@ impl Module { let decl = FuncDecl { args, rets, - attrs: attrs.clone(), field_name: name.clone(), binding_name, }; @@ -250,11 +225,10 @@ impl Module { pub fn from_declarations( decls: &[SyntaxDecl], - attrs: &[Attr], module_name: String, binding_prefix: String, ) -> Result { - let mut mod_ = Self::new(attrs, module_name, binding_prefix); + let mut mod_ = Self::new(module_name, binding_prefix); let mut idents: Vec = Vec::new(); for decl in decls { match decl { @@ -336,7 +310,7 @@ mod tests { fn mod_(syntax: &str) -> Result { let mut parser = Parser::new(syntax); let decls = parser.match_decls().expect("parses"); - Module::from_declarations(&decls, &[], String::new(), String::new()) + Module::from_declarations(&decls, String::new(), String::new()) } #[test] @@ -357,18 +331,15 @@ mod tests { StructMember { name: "a".to_owned(), type_: DataTypeRef::Atom(AtomType::I32), - attrs: Vec::new(), offset: 0, }, StructMember { name: "b".to_owned(), type_: DataTypeRef::Atom(AtomType::F32), - attrs: Vec::new(), offset: 4, }, ] }), - attrs: Vec::new(), repr_size: 8, align: 4, } @@ -547,7 +518,6 @@ mod tests { FuncDecl { args: Vec::new(), rets: Vec::new(), - attrs: Vec::new(), binding_name: "_trivial".to_owned(), field_name: "trivial".to_owned(), } @@ -556,7 +526,6 @@ mod tests { .collect::>(), data_types: HashMap::new(), data_type_ordering: Vec::new(), - attrs: Vec::new(), module_name: String::new(), binding_prefix: String::new(), } @@ -577,10 +546,8 @@ mod tests { args: vec![FuncArg { type_: DataTypeRef::Atom(AtomType::U8), name: "a".to_owned(), - attrs: Vec::new(), }], rets: Vec::new(), - attrs: Vec::new(), binding_name: "_trivial".to_owned(), field_name: "trivial".to_owned(), } @@ -589,7 +556,6 @@ mod tests { .collect::>(), data_types: HashMap::new(), data_type_ordering: Vec::new(), - attrs: Vec::new(), module_name: String::new(), binding_prefix: String::new(), } @@ -611,9 +577,7 @@ mod tests { args: Vec::new(), rets: vec![FuncRet { type_: DataTypeRef::Atom(AtomType::U8), - attrs: Vec::new(), }], - attrs: Vec::new(), binding_name: "_trivial".to_owned(), field_name: "trivial".to_owned(), } @@ -622,7 +586,6 @@ mod tests { .collect::>(), data_types: HashMap::new(), data_type_ordering: Vec::new(), - attrs: Vec::new(), module_name: String::new(), binding_prefix: String::new(), } @@ -650,9 +613,7 @@ mod tests { args: Vec::new(), rets: vec![FuncRet { type_: DataTypeRef::Defined(Ident(1)), - attrs: Vec::new(), }], - attrs: Vec::new(), binding_name: "_trivial".to_owned(), field_name: "trivial".to_owned(), } @@ -665,7 +626,6 @@ mod tests { variant: DataTypeVariant::Alias(AliasDataType { to: DataTypeRef::Atom(AtomType::U8), }), - attrs: Vec::new(), repr_size: 1, align: 1, } @@ -673,7 +633,6 @@ mod tests { .into_iter() .collect::>(), data_type_ordering: vec![Ident(1)], - attrs: Vec::new(), module_name: String::new(), binding_prefix: String::new(), } diff --git a/lucet-idl/src/package.rs b/lucet-idl/src/package.rs index 13df3e804..1c325b1ef 100644 --- a/lucet-idl/src/package.rs +++ b/lucet-idl/src/package.rs @@ -77,13 +77,11 @@ impl Package { for (decl, id) in decls.iter().zip(&idents) { match decl { - SyntaxDecl::Module { - decls, attrs, name, .. - } => { + SyntaxDecl::Module { decls, name, .. } => { let binding_prefix = "__".to_owned() + &name.to_snake_case(); pkg.define_module( *id, - Module::from_declarations(decls, attrs, name.clone(), binding_prefix)?, + Module::from_declarations(decls, name.clone(), binding_prefix)?, ); } _ => unreachable!(), @@ -130,7 +128,6 @@ mod test { Ident(0), Module { names: Vec::new(), - attrs: Vec::new(), data_types: HashMap::new(), data_type_ordering: Vec::new(), funcs: HashMap::new(), @@ -176,7 +173,6 @@ mod test { Ident(0), Module { names: Vec::new(), - attrs: Vec::new(), data_types: HashMap::new(), data_type_ordering: Vec::new(), funcs: HashMap::new(), @@ -188,7 +184,6 @@ mod test { Ident(1), Module { names: Vec::new(), - attrs: Vec::new(), data_types: HashMap::new(), data_type_ordering: Vec::new(), funcs: HashMap::new(), @@ -200,7 +195,6 @@ mod test { Ident(2), Module { names: Vec::new(), - attrs: Vec::new(), data_types: HashMap::new(), data_type_ordering: Vec::new(), funcs: HashMap::new(), @@ -236,7 +230,6 @@ mod test { column: 10 } }], - attrs: Vec::new(), funcs: HashMap::new(), data_types: vec![( Ident(0), @@ -244,7 +237,6 @@ mod test { variant: DataTypeVariant::Alias(AliasDataType { to: DataTypeRef::Atom(AtomType::U8) }), - attrs: Vec::new(), repr_size: 1, align: 1, } diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index ccbdbc9b7..e263496da 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -1,5 +1,5 @@ use super::lexer::{LexError, Lexer, LocatedError, LocatedToken, Token}; -use super::types::{AtomType, Attr, Location}; +use super::types::{AtomType, Location}; use std::error::Error; use std::fmt; @@ -8,32 +8,27 @@ pub enum SyntaxDecl { Struct { name: String, members: Vec, - attrs: Vec, location: Location, }, Enum { name: String, variants: Vec, - attrs: Vec, location: Location, }, Alias { name: String, what: SyntaxRef, - attrs: Vec, location: Location, }, Module { name: String, decls: Vec, - attrs: Vec, location: Location, }, Function { name: String, args: Vec, rets: Vec, - attrs: Vec, location: Location, }, } @@ -75,14 +70,12 @@ pub enum SyntaxRef { pub struct StructMember { pub name: String, pub type_: SyntaxRef, - pub attrs: Vec, pub location: Location, } #[derive(Debug, PartialEq, Eq, Clone)] pub struct EnumVariant { pub name: String, - pub attrs: Vec, pub location: Location, } @@ -90,14 +83,12 @@ pub struct EnumVariant { pub struct FuncArgSyntax { pub name: String, pub type_: SyntaxRef, - pub attrs: Vec, pub location: Location, } #[derive(Debug, PartialEq, Eq, Clone)] pub struct FuncRetSyntax { pub type_: SyntaxRef, - pub attrs: Vec, pub location: Location, } @@ -205,34 +196,14 @@ impl<'a> Parser<'a> { } } - fn match_attr_body(&mut self) -> Result { - let location = self.location; - self.match_token(Token::LBracket, "expected attribute start [")?; - let key = self.match_a_word("expected attribute key")?; - self.match_token(Token::Equals, "expected =")?; - let val = match self.token() { - Some(Token::Word(text)) => text, - Some(Token::Quote(text)) => text, - _ => parse_err!(self.location, "expected word or quoted string")?, - }; - self.consume(); - self.match_token(Token::RBracket, "expected ]")?; - Ok(Attr::new(key, val, location)) - } - fn match_struct_body(&mut self) -> Result, ParseError> { let mut members = Vec::new(); - let mut attrs = Vec::new(); loop { match self.token() { Some(Token::RBrace) => { self.consume(); break; } - Some(Token::Hash) => { - self.consume(); - attrs.push(self.match_attr_body()?); - } Some(Token::Word(member_name)) => { let location = self.location; self.consume(); @@ -241,10 +212,8 @@ impl<'a> Parser<'a> { members.push(StructMember { name: member_name.to_string(), type_: member_ref, - attrs: attrs.clone(), location, }); - attrs.clear(); match self.token() { Some(Token::Comma) => { self.consume(); @@ -268,26 +237,19 @@ impl<'a> Parser<'a> { fn match_enum_body(&mut self) -> Result, ParseError> { let mut names = Vec::new(); - let mut attrs = Vec::new(); loop { match self.token() { Some(Token::RBrace) => { self.consume(); break; } - Some(Token::Hash) => { - self.consume(); - attrs.push(self.match_attr_body()?); - } Some(Token::Word(name)) => { let location = self.location; self.consume(); names.push(EnumVariant { name: name.to_owned(), - attrs: attrs.clone(), location, }); - attrs.clear(); match self.token() { Some(Token::Comma) => { self.consume(); @@ -303,25 +265,17 @@ impl<'a> Parser<'a> { _ => parse_err!(self.location, "expected variant")?, } } - if !attrs.is_empty() { - parse_err!(self.location, "attributes unattached to an enum variant")? - } Ok(names) } fn match_func_args(&mut self) -> Result, ParseError> { let mut args = Vec::new(); - let mut attrs = Vec::new(); loop { match self.token() { Some(Token::RPar) => { self.consume(); break; } - Some(Token::Hash) => { - self.consume(); - attrs.push(self.match_attr_body()?); - } Some(Token::Word(name)) => { let location = self.location; self.consume(); @@ -331,10 +285,8 @@ impl<'a> Parser<'a> { args.push(FuncArgSyntax { name: name.to_string(), type_: type_ref, - attrs: attrs.clone(), location, }); - attrs.clear(); match self.token() { Some(Token::Comma) => { self.consume(); @@ -350,37 +302,24 @@ impl<'a> Parser<'a> { _ => parse_err!(self.location, "expected argument, or )")?, } } - if !attrs.is_empty() { - parse_err!( - self.location, - "attributes unattached to a function argument" - )? - } Ok(args) } fn match_func_rets(&mut self) -> Result, ParseError> { let mut args = Vec::new(); - let mut attrs = Vec::new(); loop { match self.token() { Some(Token::Semi) => { self.consume(); break; } - Some(Token::Hash) => { - self.consume(); - attrs.push(self.match_attr_body()?); - } _ => { let location = self.location; let type_ref = self.match_ref("expected type, attribute, or ;")?; args.push(FuncRetSyntax { type_: type_ref, - attrs: attrs.clone(), location, }); - attrs.clear(); match self.token() { Some(Token::Comma) => { self.consume(); @@ -395,17 +334,10 @@ impl<'a> Parser<'a> { } } } - if !attrs.is_empty() { - parse_err!( - self.location, - "attributes unattached to a function return type" - )? - } Ok(args) } pub fn match_decl(&mut self, err_msg: &str) -> Result, ParseError> { - let mut attrs = Vec::new(); loop { match self.token() { Some(Token::Word("struct")) => { @@ -417,7 +349,6 @@ impl<'a> Parser<'a> { return Ok(Some(SyntaxDecl::Struct { name: name.to_owned(), members, - attrs, location, })); } @@ -430,7 +361,6 @@ impl<'a> Parser<'a> { return Ok(Some(SyntaxDecl::Enum { name: name.to_owned(), variants, - attrs, location, })); } @@ -444,7 +374,6 @@ impl<'a> Parser<'a> { return Ok(Some(SyntaxDecl::Alias { name: name.to_owned(), what, - attrs, location, })); } @@ -471,7 +400,6 @@ impl<'a> Parser<'a> { return Ok(Some(SyntaxDecl::Module { name: name.to_owned(), decls, - attrs, location, })); } @@ -502,15 +430,9 @@ impl<'a> Parser<'a> { name: name.to_owned(), args, rets, - attrs, location, })); } - Some(Token::Hash) => { - self.consume(); - attrs.push(self.match_attr_body()?); - continue; - } Some(_) => { return parse_err!( self.location, @@ -519,9 +441,6 @@ impl<'a> Parser<'a> { ) } None => { - if !attrs.is_empty() { - parse_err!(self.location, "attributes unattached to a declaration")? - } return Ok(None); } } @@ -577,7 +496,6 @@ mod tests { SyntaxDecl::Struct { name: "foo".to_string(), members: Vec::new(), - attrs: Vec::new(), location: Location { line: 1, column: 0 }, } ); @@ -602,13 +520,11 @@ mod tests { column: 15, }, }, - attrs: Vec::new(), location: Location { line: 1, column: 12, }, }], - attrs: Vec::new(), location: Location { line: 1, column: 0 }, } ); @@ -633,13 +549,11 @@ mod tests { column: 15, }, }, - attrs: Vec::new(), location: Location { line: 1, column: 12, }, }], - attrs: Vec::new(), location: Location { line: 1, column: 0 }, } ); @@ -665,7 +579,6 @@ mod tests { column: 14, }, }, - attrs: Vec::new(), location: Location { line: 1, column: 11, @@ -680,100 +593,12 @@ mod tests { column: 22, }, }, - attrs: Vec::new(), location: Location { line: 1, column: 19, }, }, ], - attrs: Vec::new(), - location: Location { line: 1, column: 0 }, - } - ); - } - #[test] - fn struct_empty_one_attribute() { - // Test out attributes: - let mut parser = Parser::new("#[key1=val1] struct foo {}"); - assert_eq!( - parser - .match_decl("empty struct") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Struct { - name: "foo".to_string(), - members: Vec::new(), - attrs: vec![Attr::new("key1", "val1", Location { line: 1, column: 0 })], - location: Location { - line: 1, - column: 13, - }, - } - ); - } - #[test] - fn struct_empty_one_attribute_with_spaces() { - let mut parser = Parser::new("#[key2=\"1 value with spaces!\"]\nstruct foo {}"); - assert_eq!( - parser - .match_decl("empty struct") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Struct { - name: "foo".to_string(), - members: Vec::new(), - attrs: vec![Attr::new( - "key2", - "1 value with spaces!", - Location { line: 1, column: 0 }, - )], - location: Location { line: 2, column: 0 }, - } - ); - } - #[test] - fn struct_empty_multiple_attributes() { - let mut parser = Parser::new("#[key1=val1]\n\t#[key2 = \"val2\" ]\nstruct foo {}"); - assert_eq!( - parser - .match_decl("empty struct") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Struct { - name: "foo".to_string(), - members: Vec::new(), - attrs: vec![ - Attr::new("key1", "val1", Location { line: 1, column: 0 }), - Attr::new("key2", "val2", Location { line: 2, column: 8 }), - ], - location: Location { line: 3, column: 0 }, - } - ); - } - #[test] - fn struct_member_attribute() { - let mut parser = Parser::new("struct foo {\n\t#[key=val]\n\tmem: f32,\n}"); - assert_eq!( - parser - .match_decl("empty struct") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Struct { - name: "foo".to_string(), - members: vec![StructMember { - name: "mem".to_owned(), - type_: SyntaxRef::Atom { - atom: AtomType::F32, - location: Location { - line: 3, - column: 13, - }, - }, - attrs: vec![Attr::new("key", "val", Location { line: 2, column: 8 })], - location: Location { line: 3, column: 8 }, - }], - attrs: Vec::new(), // location: Location { line: 1, column: 0 }, } ); @@ -800,7 +625,6 @@ mod tests { column: 15, }, }, - attrs: Vec::new(), location: Location { line: 1, column: 12, @@ -815,14 +639,12 @@ mod tests { column: 28, }, }, - attrs: Vec::new(), location: Location { line: 1, column: 20, }, } ], - attrs: Vec::new(), location: Location { line: 1, column: 0 }, } ); @@ -839,7 +661,6 @@ mod tests { SyntaxDecl::Enum { name: "foo".to_owned(), variants: Vec::new(), - attrs: Vec::new(), location: Location { line: 1, column: 0 }, }, ); @@ -857,13 +678,11 @@ mod tests { name: "foo".to_owned(), variants: vec![EnumVariant { name: "first".to_owned(), - attrs: Vec::new(), location: Location { line: 1, column: 10, }, }], - attrs: Vec::new(), location: Location { line: 1, column: 0 }, }, ); @@ -881,60 +700,16 @@ mod tests { name: "bar".to_owned(), variants: vec![EnumVariant { name: "first".to_owned(), - attrs: Vec::new(), location: Location { line: 1, column: 10, }, }], - attrs: Vec::new(), location: Location { line: 1, column: 0 }, }, ); } - #[test] - fn enum_one_entry_with_attr() { - let mut parser = Parser::new("enum bar { #[a=b] first}"); - // 0 5 10 - assert_eq!( - parser - .match_decl("one entry enum, no trailing comma") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Enum { - name: "bar".to_owned(), - variants: vec![EnumVariant { - name: "first".to_owned(), - attrs: vec![Attr::new( - "a", - "b", - Location { - line: 1, - column: 11 - } - ),], - location: Location { - line: 1, - column: 18, - }, - }], - attrs: Vec::new(), - location: Location { line: 1, column: 0 }, - }, - ); - } - #[test] - fn enum_one_entry_trailing_attr() { - assert!(Parser::new("enum bar { #[a=b] first, #[c=d] }") - .match_decl("one entry enum") - .is_err()); - } - #[test] - fn enum_no_entry_attr() { - assert!(Parser::new("enum bar { #[c=d] }") - .match_decl("zero entry enum") - .is_err()); - } + #[test] fn enum_four_entry() { let mut parser = Parser::new("enum baz { one, two, three\n, four, }"); @@ -949,7 +724,6 @@ mod tests { variants: vec![ EnumVariant { name: "one".to_owned(), - attrs: Vec::new(), location: Location { line: 1, column: 11, @@ -957,7 +731,6 @@ mod tests { }, EnumVariant { name: "two".to_owned(), - attrs: Vec::new(), location: Location { line: 1, column: 16, @@ -965,7 +738,6 @@ mod tests { }, EnumVariant { name: "three".to_owned(), - attrs: Vec::new(), location: Location { line: 1, column: 21, @@ -973,11 +745,9 @@ mod tests { }, EnumVariant { name: "four".to_owned(), - attrs: Vec::new(), location: Location { line: 2, column: 2 }, }, ], - attrs: Vec::new(), location: Location { line: 1, column: 0 }, }, ); @@ -995,7 +765,6 @@ mod tests { SyntaxDecl::Module { name: "empty".to_owned(), decls: Vec::new(), - attrs: Vec::new(), location: Location { line: 1, column: 0 }, } ); @@ -1017,19 +786,16 @@ mod tests { decls: vec![SyntaxDecl::Module { name: "three".to_owned(), decls: Vec::new(), - attrs: Vec::new(), location: Location { line: 1, column: 20 }, }], - attrs: Vec::new(), location: Location { line: 1, column: 10 }, }], - attrs: Vec::new(), location: Location { line: 1, column: 0 }, } ); @@ -1050,7 +816,6 @@ mod tests { SyntaxDecl::Enum { name: "foo".to_owned(), variants: Vec::new(), - attrs: Vec::new(), location: Location { line: 1, column: 10 @@ -1059,70 +824,23 @@ mod tests { SyntaxDecl::Struct { name: "bar".to_owned(), members: Vec::new(), - attrs: Vec::new(), location: Location { line: 1, column: 22 }, } ], - attrs: Vec::new(), location: Location { line: 1, column: 0 }, } ); } - #[test] - fn mod_attrs() { - let mut parser = Parser::new("#[a=b]\nmod one { #[c=d] enum foo {} struct bar {} }"); - // 0 5 10 15 20 25 30 - assert_eq!( - parser - .match_decl("module with types") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Module { - name: "one".to_owned(), - decls: vec![ - SyntaxDecl::Enum { - name: "foo".to_owned(), - variants: Vec::new(), - attrs: vec![Attr::new( - "c", - "d", - Location { - line: 2, - column: 10 - } - ),], - location: Location { - line: 2, - column: 17 - }, - }, - SyntaxDecl::Struct { - name: "bar".to_owned(), - members: Vec::new(), - attrs: Vec::new(), - location: Location { - line: 2, - column: 29 - }, - } - ], - attrs: vec![Attr::new("a", "b", Location { line: 1, column: 0 }),], - location: Location { line: 2, column: 0 }, - } - ); - } - #[test] fn fn_trivial() { let canonical = vec![SyntaxDecl::Function { name: "trivial".to_owned(), args: Vec::new(), rets: Vec::new(), - attrs: Vec::new(), location: Location { line: 1, column: 0 }, }]; assert_eq!( @@ -1161,13 +879,11 @@ mod tests { column: 14, }, }, - attrs: vec![], location: Location { line: 1, column: 14, }, }], - attrs: Vec::new(), location: Location { line: 1, column: 0 }, }]; assert_eq!( @@ -1206,11 +922,9 @@ mod tests { }, }, name: "a".to_owned(), - attrs: Vec::new(), location: Location { line: 1, column: 7 }, }], rets: Vec::new(), - attrs: Vec::new(), location: Location { line: 1, column: 0 }, }; assert_eq!( @@ -1245,7 +959,6 @@ mod tests { }, }, name: "a".to_owned(), - attrs: Vec::new(), location: Location { line: 1, column: 7 }, }, FuncArgSyntax { @@ -1257,7 +970,6 @@ mod tests { }, }, name: "b".to_owned(), - attrs: Vec::new(), location: Location { line: 1, column: 14, @@ -1265,7 +977,6 @@ mod tests { }, ], rets: Vec::new(), - attrs: Vec::new(), location: Location { line: 1, column: 0 }, }; assert_eq!( @@ -1306,7 +1017,6 @@ mod tests { column: 14, }, }, - attrs: vec![], location: Location { line: 1, column: 14, @@ -1320,7 +1030,6 @@ mod tests { column: 18, }, }, - attrs: vec![], location: Location { line: 1, column: 18, @@ -1334,99 +1043,12 @@ mod tests { column: 23, }, }, - attrs: vec![], location: Location { line: 1, column: 23, }, }, ], - attrs: Vec::new(), - location: Location { line: 1, column: 0 }, - } - ); - } - - #[test] - fn fn_many_returns_with_attrs() { - assert_eq!( - Parser::new("fn getch() -> #[a=b] u8, #[c=d] #[e=f] u16, u32;") - // 0 5 10 15 20 25 30 35 40 45 - .match_decl("returns u8") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Function { - name: "getch".to_owned(), - args: Vec::new(), - rets: vec![ - FuncRetSyntax { - type_: SyntaxRef::Atom { - atom: AtomType::U8, - location: Location { - line: 1, - column: 21, - }, - }, - attrs: vec![Attr::new( - "a", - "b", - Location { - line: 1, - column: 14 - } - )], - location: Location { - line: 1, - column: 21, - }, - }, - FuncRetSyntax { - type_: SyntaxRef::Atom { - atom: AtomType::U16, - location: Location { - line: 1, - column: 39, - }, - }, - attrs: vec![ - Attr::new( - "c", - "d", - Location { - line: 1, - column: 25 - } - ), - Attr::new( - "e", - "f", - Location { - line: 1, - column: 32 - } - ), - ], - location: Location { - line: 1, - column: 39, - }, - }, - FuncRetSyntax { - type_: SyntaxRef::Atom { - atom: AtomType::U32, - location: Location { - line: 1, - column: 44, - }, - }, - attrs: vec![], - location: Location { - line: 1, - column: 44, - }, - }, - ], - attrs: Vec::new(), location: Location { line: 1, column: 0 }, } ); diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index cafb602d5..a24bd3992 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -33,23 +33,6 @@ pub struct Location { pub column: usize, } -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Attr { - pub key: String, - pub val: String, - pub location: Location, -} - -impl Attr { - pub fn new(key: &str, val: &str, location: Location) -> Attr { - Attr { - key: key.to_owned(), - val: val.to_owned(), - location, - } - } -} - #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] pub struct Ident(pub usize); @@ -69,7 +52,6 @@ pub enum DataTypeRef { pub struct StructMember { pub type_: DataTypeRef, pub name: String, - pub attrs: Vec, pub offset: usize, } @@ -81,7 +63,6 @@ pub struct StructDataType { #[derive(Debug, PartialEq, Eq, Clone)] pub struct EnumMember { pub name: String, - pub attrs: Vec, } #[derive(Debug, PartialEq, Eq, Clone)] @@ -104,7 +85,6 @@ pub enum DataTypeVariant { #[derive(Debug, PartialEq, Eq, Clone)] pub struct DataType { pub variant: DataTypeVariant, - pub attrs: Vec, pub repr_size: usize, pub align: usize, } @@ -113,7 +93,6 @@ pub struct DataType { pub struct FuncArg { pub type_: DataTypeRef, pub name: String, - pub attrs: Vec, } #[derive(Debug, PartialEq, Eq, Clone)] @@ -122,13 +101,11 @@ pub struct FuncDecl { pub binding_name: String, pub args: Vec, pub rets: Vec, - pub attrs: Vec, } #[derive(Debug, PartialEq, Eq, Clone)] pub struct FuncRet { pub type_: DataTypeRef, - pub attrs: Vec, } #[derive(Debug, PartialEq, Eq, Clone)] diff --git a/lucet-module-data/Cargo.toml b/lucet-module-data/Cargo.toml index 4d53045e6..997bff62d 100644 --- a/lucet-module-data/Cargo.toml +++ b/lucet-module-data/Cargo.toml @@ -1,12 +1,16 @@ [package] name = "lucet-module-data" -version = "0.1.0" -authors = ["Pat Hickey "] +version = "0.1.1" +description = "A structured interface for Lucet module data and metadata" +homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" +license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +authors = ["Lucet team "] edition = "2018" [dependencies] -cranelift-codegen = { path = "../cranelift/cranelift-codegen" } +cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.31.0" } failure = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/lucet-module-data/src/bindings.rs b/lucet-module-data/src/bindings.rs index 7d72337bf..3c1dab385 100644 --- a/lucet-module-data/src/bindings.rs +++ b/lucet-module-data/src/bindings.rs @@ -72,10 +72,10 @@ impl Bindings { Ok(()) } - pub fn translate(&self, module: &str, symbol: &str) -> Result { + pub fn translate(&self, module: &str, symbol: &str) -> Result<&str, Error> { match self.bindings.get(module) { Some(m) => match m.get(symbol) { - Some(s) => Ok(s.clone()), + Some(s) => Ok(s), None => Err(format_err!("Unknown symbol `{}::{}`", module, symbol)), }, None => Err(format_err!( diff --git a/lucet-runtime/Cargo.toml b/lucet-runtime/Cargo.toml index 64a9aa284..688d830ef 100644 --- a/lucet-runtime/Cargo.toml +++ b/lucet-runtime/Cargo.toml @@ -1,16 +1,18 @@ [package] name = "lucet-runtime" -version = "0.1.0" -description = "Pure Rust runtime for lucet WebAssembly toolchain" +version = "0.1.1" +description = "Pure Rust runtime for Lucet WebAssembly toolchain" +homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" -authors = ["Adam C. Foltzer ", "Pat Hickey ", "Frank Denis ", "Tyler McMullen "] license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +authors = ["Lucet team "] edition = "2018" [dependencies] libc = "=0.2.54" -lucet-runtime-internals = { path = "lucet-runtime-internals" } -lucet-module-data = { path = "../lucet-module-data" } +lucet-runtime-internals = { path = "lucet-runtime-internals", version = "0.1.1" } +lucet-module-data = { path = "../lucet-module-data", version = "0.1.1" } num-traits = "0.2" num-derive = "0.2" @@ -19,7 +21,7 @@ byteorder = "1.2" failure = "0.1" lazy_static = "1.1" lucetc = { path = "../lucetc" } -lucet-runtime-tests = { path = "lucet-runtime-tests" } +lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.1.1" } lucet-wasi-sdk = { path = "../lucet-wasi-sdk" } nix = "0.13" tempfile = "3.0" diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index eab5235c6..ab5dcc8f1 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -1,16 +1,21 @@ [package] name = "lucet-runtime-internals" -version = "0.1.0" -authors = ["Adam C. Foltzer "] +version = "0.1.1" +description = "Pure Rust runtime for Lucet WebAssembly toolchain (internals)" +homepage = "https://github.com/fastly/lucet" +repository = "https://github.com/fastly/lucet" +license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +authors = ["Lucet team "] edition = "2018" [dependencies] -lucet-module-data = { path = "../../lucet-module-data" } +lucet-module-data = { path = "../../lucet-module-data", version = "0.1.1" } bitflags = "1.0" bincode = "~1.0.1" byteorder = "1.3" -cranelift-codegen = { path = "../../cranelift/cranelift-codegen" } +cranelift-codegen = { path = "../../cranelift/cranelift-codegen", version = "0.31.0" } failure = "0.1" lazy_static = "1.1" libc = "=0.2.54" diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs index 5b367bbe0..d4deed3d8 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs @@ -11,6 +11,7 @@ use lucet_module_data::TrapCode; use nix::sys::signal::{ pthread_sigmask, raise, sigaction, SaFlags, SigAction, SigHandler, SigSet, SigmaskHow, Signal, }; +use std::mem::MaybeUninit; use std::panic; use std::sync::{Arc, Mutex}; @@ -374,18 +375,20 @@ pub struct SigStack { impl SigStack { pub fn new(sp: *mut libc::c_void, flags: SigStackFlags, size: libc::size_t) -> SigStack { - let mut stack = unsafe { std::mem::uninitialized::() }; - stack.ss_sp = sp; - stack.ss_flags = flags.bits(); - stack.ss_size = size; + let stack = libc::stack_t { + ss_sp: sp, + ss_flags: flags.bits(), + ss_size: size, + }; SigStack { stack } } pub fn disabled() -> SigStack { - let mut stack = unsafe { std::mem::uninitialized::() }; - stack.ss_sp = std::ptr::null_mut(); - stack.ss_flags = SigStackFlags::SS_DISABLE.bits(); - stack.ss_size = libc::SIGSTKSZ; + let stack = libc::stack_t { + ss_sp: std::ptr::null_mut(), + ss_flags: SigStackFlags::SS_DISABLE.bits(), + ss_size: libc::SIGSTKSZ, + }; SigStack { stack } } @@ -414,7 +417,7 @@ bitflags! { } pub unsafe fn sigaltstack(new_sigstack: Option) -> nix::Result> { - let mut previous_stack = std::mem::uninitialized::(); + let mut previous_stack = MaybeUninit::::uninit(); let disabled_sigstack = SigStack::disabled(); let new_stack = match new_sigstack { None => &disabled_sigstack.stack, @@ -422,11 +425,11 @@ pub unsafe fn sigaltstack(new_sigstack: Option) -> nix::Result) -> nix::Result nix::Result { - let mut current_stack = std::mem::uninitialized::(); - let res = libc::sigaltstack( - std::ptr::null_mut(), - &mut current_stack as *mut libc::stack_t, - ); + let mut current_stack = MaybeUninit::::uninit(); + let res = libc::sigaltstack(std::ptr::null_mut(), current_stack.as_mut_ptr()); nix::errno::Errno::result(res) - .map(|_| SigStackFlags::from_bits_truncate(current_stack.ss_flags)) + .map(|_| SigStackFlags::from_bits_truncate(current_stack.assume_init().ss_flags)) } diff --git a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs index b9ef9cbc8..6923aa51c 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs @@ -7,7 +7,7 @@ use lucet_module_data::{ PublicKey, Signature, }; use std::ffi::CStr; -use std::mem; +use std::mem::MaybeUninit; use std::path::Path; use std::slice; use std::slice::from_raw_parts; @@ -267,10 +267,10 @@ fn is_undefined_symbol(e: &std::io::Error) -> bool { // TODO: PR to nix or libloading? // TODO: possibly not safe to use without grabbing the mutex within libloading::Library? fn dladdr(addr: *const c_void) -> Option { - let mut info = unsafe { mem::uninitialized::() }; - let res = unsafe { libc::dladdr(addr, &mut info as *mut libc::Dl_info) }; + let mut info = MaybeUninit::::uninit(); + let res = unsafe { libc::dladdr(addr, info.as_mut_ptr()) }; if res != 0 { - Some(info) + Some(unsafe { info.assume_init() }) } else { None } diff --git a/lucet-runtime/lucet-runtime-internals/src/module/mock.rs b/lucet-runtime/lucet-runtime-internals/src/module/mock.rs index a1c215060..5e125e923 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/mock.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/mock.rs @@ -145,6 +145,31 @@ impl MockModuleBuilder { self } + pub fn with_exported_import_func( + mut self, + export_name: &'static str, + import_fn_ptr: FunctionPointer, + sig: Signature, + ) -> Self { + self.export_funcs.insert(export_name, import_fn_ptr); + let sig_idx = self.record_sig(sig); + self.function_info.push(OwnedFunctionMetadata { + signature: sig_idx, + name: Some(export_name.to_string()), + }); + self.exports.push(OwnedExportFunction { + fn_idx: FunctionIndex::from_u32(self.function_manifest.len() as u32), + names: vec![export_name.to_string()], + }); + self.function_manifest.push(FunctionSpec::new( + import_fn_ptr.as_usize() as u64, + 0u32, + 0u64, + 0u64, + )); + self + } + pub fn with_table_func(mut self, table_idx: u32, func_idx: u32, func: FunctionPointer) -> Self { self.func_table.insert((table_idx, func_idx), func); self diff --git a/lucet-runtime/lucet-runtime-tests/Cargo.toml b/lucet-runtime/lucet-runtime-tests/Cargo.toml index dcf514ad4..f16c4a7b7 100644 --- a/lucet-runtime/lucet-runtime-tests/Cargo.toml +++ b/lucet-runtime/lucet-runtime-tests/Cargo.toml @@ -1,7 +1,12 @@ [package] name = "lucet-runtime-tests" -version = "0.1.0" -authors = ["Adam C. Foltzer "] +version = "0.1.1" +description = "Pure Rust runtime for Lucet WebAssembly toolchain (tests)" +homepage = "https://github.com/fastly/lucet" +repository = "https://github.com/fastly/lucet" +license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +authors = ["Lucet team "] edition = "2018" [lib] @@ -13,10 +18,10 @@ test = false failure = "0.1" lazy_static = "1.1" tempfile = "3.0" -lucet-module-data = { path = "../../lucet-module-data" } -lucet-runtime-internals = { path = "../lucet-runtime-internals" } -lucet-wasi-sdk = { path = "../../lucet-wasi-sdk" } -lucetc = { path = "../../lucetc" } +lucet-module-data = { path = "../../lucet-module-data", version = "0.1.1" } +lucet-runtime-internals = { path = "../lucet-runtime-internals", version = "0.1.1" } +lucet-wasi-sdk = { path = "../../lucet-wasi-sdk", version = "0.1.1" } +lucetc = { path = "../../lucetc", version = "0.1.1" } [build-dependencies] cc = "1.0" diff --git a/lucet-runtime/lucet-runtime-tests/guests/entrypoint/bindings.json b/lucet-runtime/lucet-runtime-tests/guests/entrypoint/bindings.json index 39f1e1074..bab61d8f5 100644 --- a/lucet-runtime/lucet-runtime-tests/guests/entrypoint/bindings.json +++ b/lucet-runtime/lucet-runtime-tests/guests/entrypoint/bindings.json @@ -1,6 +1,7 @@ { "env": { "black_box": "black_box", - "callback_hostcall": "callback_hostcall" + "callback_hostcall": "callback_hostcall", + "add_4_hostcall": "add_4_hostcall" } } diff --git a/lucet-runtime/lucet-runtime-tests/guests/entrypoint/calculator.wat b/lucet-runtime/lucet-runtime-tests/guests/entrypoint/calculator.wat index 12f50724c..34db1679f 100644 --- a/lucet-runtime/lucet-runtime-tests/guests/entrypoint/calculator.wat +++ b/lucet-runtime/lucet-runtime-tests/guests/entrypoint/calculator.wat @@ -1,4 +1,5 @@ (module + (func $add_4 (export "add_4_reexport") (import "env" "add_4_hostcall") (param i64 i64 i64 i64) (result i64)) (memory 1) (func $add_2 (export "add_2") (param i64 i64) (result i64) (i64.add (get_local 0) (get_local 1)) diff --git a/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs b/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs index 66421f815..f5e252151 100644 --- a/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs +++ b/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs @@ -14,6 +14,16 @@ pub fn mock_calculator_module() -> Arc { arg0 + arg1 } + extern "C" fn add_4_hostcall( + _vmctx: *mut lucet_vmctx, + arg0: u64, + arg1: u64, + arg2: u64, + arg3: u64, + ) -> u64 { + arg0 + arg1 + arg2 + arg3 + } + extern "C" fn add_10( _vmctx: *mut lucet_vmctx, arg0: u64, @@ -124,6 +134,11 @@ pub fn mock_calculator_module() -> Arc { MockExportBuilder::new("add_2", FunctionPointer::from_usize(add_2 as usize)) .with_sig(lucet_signature!((I64, I64) -> I64)), ) + .with_exported_import_func( + "add_4_reexport", + FunctionPointer::from_usize(add_4_hostcall as usize), + lucet_signature!((I64, I64, I64, I64) -> I64), + ) .with_export_func( MockExportBuilder::new("add_10", FunctionPointer::from_usize(add_10 as usize)) .with_sig(lucet_signature!( @@ -585,6 +600,31 @@ macro_rules! entrypoint_tests { } } + #[test] + fn mock_imported_entrypoint() { + imported_entrypoint(mock_calculator_module()) + } + + #[test] + fn wat_imported_entrypoint() { + imported_entrypoint(wat_calculator_module()) + } + + fn imported_entrypoint(module: Arc) { + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + match inst.run( + "add_4_reexport", + &[123u64.into(), 456u64.into(), 789u64.into(), 432u64.into()], + ) { + Ok(res) => assert_eq!(u64::from(res), 1800), + res => panic!("unexpected result: {:?}", res), + } + } + use $crate::build::test_module_c; const TEST_REGION_INIT_VAL: libc::c_int = 123; const TEST_REGION_SIZE: libc::size_t = 4; @@ -853,6 +893,19 @@ macro_rules! entrypoint_tests { } } + lucet_hostcalls! { + #[no_mangle] + pub unsafe extern "C" fn add_4_hostcall( + &mut vmctx, + x: u64, + y: u64, + z: u64, + w: u64, + ) -> u64 { + x + y + z + w + } + } + #[test] fn entrypoint_callback() { let module = diff --git a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs index 6d88caa74..7345caaf2 100644 --- a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs +++ b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs @@ -701,14 +701,15 @@ macro_rules! guest_fault_tests { #[test] fn sigaltstack_restores() { use libc::*; + use std::mem::MaybeUninit; test_nonex(|| { // any alternate stack present before a thread runs an instance should be restored // after the instance returns + let mut beforestack = MaybeUninit::::uninit(); let beforestack = unsafe { - let mut beforestack = std::mem::uninitialized::(); - sigaltstack(std::ptr::null(), &mut beforestack as *mut stack_t); - beforestack + sigaltstack(std::ptr::null(), beforestack.as_mut_ptr()); + beforestack.assume_init() }; let module = mock_traps_module(); @@ -719,10 +720,10 @@ macro_rules! guest_fault_tests { .expect("instance can be created"); run_onetwothree(&mut inst); + let mut afterstack = MaybeUninit::::uninit(); let afterstack = unsafe { - let mut afterstack = std::mem::uninitialized::(); - sigaltstack(std::ptr::null(), &mut afterstack as *mut stack_t); - afterstack + sigaltstack(std::ptr::null(), afterstack.as_mut_ptr()); + afterstack.assume_init() }; assert_eq!(beforestack.ss_sp, afterstack.ss_sp); diff --git a/lucet-spectest/Cargo.toml b/lucet-spectest/Cargo.toml index afd6a8fda..72860d675 100644 --- a/lucet-spectest/Cargo.toml +++ b/lucet-spectest/Cargo.toml @@ -1,10 +1,12 @@ [package] name = "lucet-spectest" -version = "0.1.0" +version = "0.1.1" description = "Test harness to run WebAssembly spec tests (.wast) against the Lucet toolchain" +homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" -authors = ["Pat Hickey "] license = "Apache-2.0 WITH LLVM-exception" +authors = ["Lucet team "] +categories = ["wasm"] edition = "2018" [lib] @@ -15,9 +17,9 @@ name = "spec-test" path = "src/main.rs" [dependencies] -lucetc = { path = "../lucetc" } -lucet-module-data = { path = "../lucet-module-data" } -lucet-runtime = { path = "../lucet-runtime" } +lucetc = { path = "../lucetc", version = "0.1.1" } +lucet-module-data = { path = "../lucet-module-data", version = "0.1.1" } +lucet-runtime = { path = "../lucet-runtime", version = "0.1.1" } wabt = "0.7" serde = "1.0" serde_json = "1.0" diff --git a/lucet-spectest/src/bindings.rs b/lucet-spectest/src/bindings.rs index c642430f7..ca62ec87c 100644 --- a/lucet-spectest/src/bindings.rs +++ b/lucet-spectest/src/bindings.rs @@ -1,6 +1,29 @@ use lucet_module_data::bindings::Bindings; use serde_json::json; +use lucet_runtime::lucet_hostcalls; + +lucet_hostcalls! { + #[no_mangle] + pub unsafe extern "C" fn print(&mut _vmctx,) -> () { + println!("hello, world!"); + } +} + +lucet_hostcalls! { + #[no_mangle] + pub unsafe extern "C" fn print_i32(&mut _vmctx, x: i32,) -> () { + println!("{}", x); + } +} + +lucet_hostcalls! { + #[no_mangle] + pub unsafe extern "C" fn print_f32(&mut _vmctx, x: i32,) -> () { + println!("{}", x); + } +} + pub fn spec_test_bindings() -> Bindings { let imports: serde_json::Value = json!({ "test": { diff --git a/lucet-wasi-fuzz/Cargo.toml b/lucet-wasi-fuzz/Cargo.toml index 561ddd112..c5554cc81 100644 --- a/lucet-wasi-fuzz/Cargo.toml +++ b/lucet-wasi-fuzz/Cargo.toml @@ -1,7 +1,12 @@ [package] name = "lucet-wasi-fuzz" -version = "0.1.0" -authors = ["Adam C. Foltzer "] +version = "0.1.1" +description = "Test the Lucet toolchain against native code execution using Csmith" +homepage = "https://github.com/fastly/lucet" +repository = "https://github.com/fastly/lucet" +license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +authors = ["Lucet team "] edition = "2018" [dependencies] diff --git a/lucet-wasi-sdk/Cargo.toml b/lucet-wasi-sdk/Cargo.toml index e0e113494..0b759ad44 100644 --- a/lucet-wasi-sdk/Cargo.toml +++ b/lucet-wasi-sdk/Cargo.toml @@ -1,12 +1,16 @@ [package] name = "lucet-wasi-sdk" -version = "0.1.0" -authors = ["Pat Hickey "] -edition = "2018" +version = "0.1.1" +description = "A Rust interface to the wasi-sdk compiler and linker" +homepage = "https://github.com/fastly/lucet" +repository = "https://github.com/fastly/lucet" license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +authors = ["Lucet team "] +edition = "2018" [dependencies] failure = "0.1" -lucetc = { path = "../lucetc" } -lucet-module-data = { path = "../lucet-module-data" } +lucetc = { path = "../lucetc", version = "0.1.1" } +lucet-module-data = { path = "../lucet-module-data", version = "0.1.1" } tempfile = "3.0" diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index 047f5b1dc..f90e2a2c6 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -1,9 +1,27 @@ [package] name = "lucet-wasi" -version = "0.1.0" -authors = ["Adam C. Foltzer "] -edition = "2018" +version = "0.1.1" +description = "Fastly's runtime for the WebAssembly System Interface (WASI)" +homepage = "https://github.com/fastly/lucet" +repository = "https://github.com/fastly/lucet" license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +authors = ["Lucet team "] +edition = "2018" + +# `src/wasi_host.rs` is automatically generated using clang and +# wasi-libc headers. This requires these to be present, and installed +# at specific paths, which is not something we can rely on outside +# of our environment. +# So, we follow what most other tools using `bindgen` do, and provide +# a pre-generated version of the file, along with a way to update it. +# This is what the `update-bindings` feature do. It requires the WASI SDK +# to be either installed in `/opt/wasi-sdk`, or at a location defined by +# a `WASI_SDK` environment variable, as well as `clang` headers either +# being part of `WASI_SDK`, or found in a path defined by a +# `CLANG_ROOT` environment variable. +[features] +update-bindings = ["bindgen"] [dependencies] cast = "0.2" @@ -11,19 +29,20 @@ clap = "2.23" failure = "0.1" human-size = "0.4" libc = "=0.2.54" -lucet-runtime = { path = "../lucet-runtime" } -lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals" } -lucet-module-data = { path = "../lucet-module-data" } +lucet-runtime = { path = "../lucet-runtime", version = "0.1.1" } +lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.1.1" } +lucet-module-data = { path = "../lucet-module-data", version = "0.1.1" } nix = "0.13" rand = "0.6" [dev-dependencies] -lucet-wasi-sdk = { path = "../lucet-wasi-sdk" } -lucetc = { path = "../lucetc" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.1.1" } +lucetc = { path = "../lucetc", version = "0.1.1" } tempfile = "3.0" -[build-dependencies] -bindgen = "0.47" +[build-dependencies.bindgen] +version = "0.47" +optional = true [lib] name = "lucet_wasi" diff --git a/lucet-wasi/build.rs b/lucet-wasi/build.rs index 0e39fb489..d880ca37f 100644 --- a/lucet-wasi/build.rs +++ b/lucet-wasi/build.rs @@ -1,3 +1,5 @@ +#![allow(unused)] + use std::env; use std::fs::File; use std::path::{Path, PathBuf}; @@ -32,6 +34,21 @@ fn wasm_clang_root() -> PathBuf { } } +// `src/wasi_host.rs` is automatically generated using clang and +// wasi-libc headers. This requires these to be present, and installed +// at specific paths, which is not something we can rely on outside +// of our environment. +// So, we follow what most other tools using `bindgen` do, and provide +// a pre-generated version of the file, along with a way to update it. +// This is what the `update-bindings` feature do. It requires the WASI SDK +// to be either installed in `/opt/wasi-sdk`, or at a location defined by +// a `WASI_SDK` environment variable, as well as `clang` headers either +// being part of `WASI_SDK`, or found in a path defined by a +// `CLANG_ROOT` environment variable. +#[cfg(not(feature = "update-bindings"))] +fn main() {} + +#[cfg(feature = "update-bindings")] fn main() { let wasi_sysroot = wasi_sysroot(); let wasm_clang_root = wasm_clang_root(); @@ -88,9 +105,10 @@ fn main() { .whitelist_type("__wasi_.*") .whitelist_var("__WASI_.*"); + let src_path = Path::new("src"); host_builder .generate() .expect("can generate host bindings") - .write_to_file(out_path.join("wasi_host.rs")) + .write_to_file(src_path.join("wasi_host.rs")) .expect("can write host bindings"); } diff --git a/lucet-wasi/src/host.rs b/lucet-wasi/src/host.rs index fb2c35b6a..e1a6027d0 100644 --- a/lucet-wasi/src/host.rs +++ b/lucet-wasi/src/host.rs @@ -1,7 +1,7 @@ #![allow(non_camel_case_types)] #![allow(non_snake_case)] -include!(concat!(env!("OUT_DIR"), "/wasi_host.rs")); +include!("wasi_host.rs"); pub type void = ::std::os::raw::c_void; diff --git a/lucet-wasi/src/hostcalls/fs.rs b/lucet-wasi/src/hostcalls/fs.rs index 01bd835e6..7eaee5352 100644 --- a/lucet-wasi/src/hostcalls/fs.rs +++ b/lucet-wasi/src/hostcalls/fs.rs @@ -11,6 +11,7 @@ use lucet_runtime::vmctx::Vmctx; use nix::libc::{self, c_long, c_void, off_t}; use std::ffi::OsStr; +use std::mem::MaybeUninit; use std::os::unix::prelude::{FromRawFd, OsStrExt}; pub fn wasi_fd_close(vmctx: &mut Vmctx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t { @@ -819,11 +820,12 @@ pub fn wasi_fd_filestat_set_times( let fst_flags = dec_fstflags(fst_flags); if fst_flags & (host::__WASI_FILESTAT_SET_MTIM_NOW as host::__wasi_fstflags_t) != 0 { let clock_id = libc::CLOCK_REALTIME; - let mut timespec = unsafe { std::mem::uninitialized::() }; - let res = unsafe { libc::clock_gettime(clock_id, &mut timespec as *mut libc::timespec) }; + let mut timespec = MaybeUninit::::uninit(); + let res = unsafe { libc::clock_gettime(clock_id, timespec.as_mut_ptr()) }; if res != 0 { return wasm32::errno_from_nix(nix::errno::Errno::last()); } + let timespec = unsafe { timespec.assume_init() }; let time_ns = match (timespec.tv_sec as host::__wasi_timestamp_t) .checked_mul(1_000_000_000) .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t)) @@ -887,11 +889,12 @@ pub fn wasi_path_filestat_set_times( let fst_flags = dec_fstflags(fst_flags); if fst_flags & (host::__WASI_FILESTAT_SET_MTIM_NOW as host::__wasi_fstflags_t) != 0 { let clock_id = libc::CLOCK_REALTIME; - let mut timespec = unsafe { std::mem::uninitialized::() }; - let res = unsafe { libc::clock_gettime(clock_id, &mut timespec as *mut libc::timespec) }; + let mut timespec = MaybeUninit::::uninit(); + let res = unsafe { libc::clock_gettime(clock_id, timespec.as_mut_ptr()) }; if res != 0 { return wasm32::errno_from_nix(nix::errno::Errno::last()); } + let timespec = unsafe { timespec.assume_init() }; let time_ns = match (timespec.tv_sec as host::__wasi_timestamp_t) .checked_mul(1_000_000_000) .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t)) @@ -1052,18 +1055,19 @@ pub fn wasi_fd_readdir( if cookie != wasm32::__WASI_DIRCOOKIE_START { unsafe { seekdir(dir, cookie as c_long) }; } - let mut entry_buf = unsafe { std::mem::uninitialized::() }; + let mut entry_buf = MaybeUninit::::uninit(); let mut left = host_buf_len; let mut host_buf_offset: usize = 0; while left > 0 { let mut host_entry: *mut dirent = std::ptr::null_mut(); - let res = unsafe { readdir_r(dir, &mut entry_buf, &mut host_entry) }; + let res = unsafe { readdir_r(dir, entry_buf.as_mut_ptr(), &mut host_entry) }; if res == -1 { return wasm32::errno_from_nix(nix::errno::Errno::last()); } if host_entry.is_null() { break; } + unsafe { entry_buf.assume_init() }; let entry: wasm32::__wasi_dirent_t = match dirent_from_host(&unsafe { *host_entry }) { Ok(entry) => entry, Err(e) => return enc_errno(e), diff --git a/lucet-wasi/src/hostcalls/misc.rs b/lucet-wasi/src/hostcalls/misc.rs index a96161ebc..75f060009 100644 --- a/lucet-wasi/src/hostcalls/misc.rs +++ b/lucet-wasi/src/hostcalls/misc.rs @@ -12,6 +12,7 @@ use lucet_runtime::vmctx::Vmctx; use nix::convert_ioctl_res; use nix::libc::{self, c_int}; use std::cmp; +use std::mem::MaybeUninit; use std::time::SystemTime; // define the `fionread()` function, equivalent to `ioctl(fd, FIONREAD, *bytes)` @@ -123,11 +124,12 @@ pub fn wasi_clock_res_get( }; // no `nix` wrapper for clock_getres, so we do it ourselves - let mut timespec = unsafe { std::mem::uninitialized::() }; - let res = unsafe { libc::clock_getres(clock_id, &mut timespec as *mut libc::timespec) }; + let mut timespec = MaybeUninit::::uninit(); + let res = unsafe { libc::clock_getres(clock_id, timespec.as_mut_ptr()) }; if res != 0 { return wasm32::errno_from_nix(nix::errno::Errno::last()); } + let timespec = unsafe { timespec.assume_init() }; // convert to nanoseconds, returning EOVERFLOW in case of overflow; this is freelancing a bit // from the spec but seems like it'll be an unusual situation to hit @@ -166,12 +168,12 @@ pub fn wasi_clock_time_get( }; // no `nix` wrapper for clock_getres, so we do it ourselves - let mut timespec = unsafe { std::mem::uninitialized::() }; - let res = unsafe { libc::clock_gettime(clock_id, &mut timespec as *mut libc::timespec) }; + let mut timespec = MaybeUninit::::uninit(); + let res = unsafe { libc::clock_gettime(clock_id, timespec.as_mut_ptr()) }; if res != 0 { return wasm32::errno_from_nix(nix::errno::Errno::last()); } - + let timespec = unsafe { timespec.assume_init() }; // convert to nanoseconds, returning EOVERFLOW in case of overflow; this is freelancing a bit // from the spec but seems like it'll be an unusual situation to hit (timespec.tv_sec as host::__wasi_timestamp_t) diff --git a/lucet-wasi/src/wasi_host.rs b/lucet-wasi/src/wasi_host.rs new file mode 100644 index 000000000..08ae16363 --- /dev/null +++ b/lucet-wasi/src/wasi_host.rs @@ -0,0 +1,1035 @@ +/* automatically generated by rust-bindgen */ + +pub const __WASI_ADVICE_NORMAL: u32 = 0; +pub const __WASI_ADVICE_SEQUENTIAL: u32 = 1; +pub const __WASI_ADVICE_RANDOM: u32 = 2; +pub const __WASI_ADVICE_WILLNEED: u32 = 3; +pub const __WASI_ADVICE_DONTNEED: u32 = 4; +pub const __WASI_ADVICE_NOREUSE: u32 = 5; +pub const __WASI_CLOCK_REALTIME: u32 = 0; +pub const __WASI_CLOCK_MONOTONIC: u32 = 1; +pub const __WASI_CLOCK_PROCESS_CPUTIME_ID: u32 = 2; +pub const __WASI_CLOCK_THREAD_CPUTIME_ID: u32 = 3; +pub const __WASI_DIRCOOKIE_START: u32 = 0; +pub const __WASI_ESUCCESS: u32 = 0; +pub const __WASI_E2BIG: u32 = 1; +pub const __WASI_EACCES: u32 = 2; +pub const __WASI_EADDRINUSE: u32 = 3; +pub const __WASI_EADDRNOTAVAIL: u32 = 4; +pub const __WASI_EAFNOSUPPORT: u32 = 5; +pub const __WASI_EAGAIN: u32 = 6; +pub const __WASI_EALREADY: u32 = 7; +pub const __WASI_EBADF: u32 = 8; +pub const __WASI_EBADMSG: u32 = 9; +pub const __WASI_EBUSY: u32 = 10; +pub const __WASI_ECANCELED: u32 = 11; +pub const __WASI_ECHILD: u32 = 12; +pub const __WASI_ECONNABORTED: u32 = 13; +pub const __WASI_ECONNREFUSED: u32 = 14; +pub const __WASI_ECONNRESET: u32 = 15; +pub const __WASI_EDEADLK: u32 = 16; +pub const __WASI_EDESTADDRREQ: u32 = 17; +pub const __WASI_EDOM: u32 = 18; +pub const __WASI_EDQUOT: u32 = 19; +pub const __WASI_EEXIST: u32 = 20; +pub const __WASI_EFAULT: u32 = 21; +pub const __WASI_EFBIG: u32 = 22; +pub const __WASI_EHOSTUNREACH: u32 = 23; +pub const __WASI_EIDRM: u32 = 24; +pub const __WASI_EILSEQ: u32 = 25; +pub const __WASI_EINPROGRESS: u32 = 26; +pub const __WASI_EINTR: u32 = 27; +pub const __WASI_EINVAL: u32 = 28; +pub const __WASI_EIO: u32 = 29; +pub const __WASI_EISCONN: u32 = 30; +pub const __WASI_EISDIR: u32 = 31; +pub const __WASI_ELOOP: u32 = 32; +pub const __WASI_EMFILE: u32 = 33; +pub const __WASI_EMLINK: u32 = 34; +pub const __WASI_EMSGSIZE: u32 = 35; +pub const __WASI_EMULTIHOP: u32 = 36; +pub const __WASI_ENAMETOOLONG: u32 = 37; +pub const __WASI_ENETDOWN: u32 = 38; +pub const __WASI_ENETRESET: u32 = 39; +pub const __WASI_ENETUNREACH: u32 = 40; +pub const __WASI_ENFILE: u32 = 41; +pub const __WASI_ENOBUFS: u32 = 42; +pub const __WASI_ENODEV: u32 = 43; +pub const __WASI_ENOENT: u32 = 44; +pub const __WASI_ENOEXEC: u32 = 45; +pub const __WASI_ENOLCK: u32 = 46; +pub const __WASI_ENOLINK: u32 = 47; +pub const __WASI_ENOMEM: u32 = 48; +pub const __WASI_ENOMSG: u32 = 49; +pub const __WASI_ENOPROTOOPT: u32 = 50; +pub const __WASI_ENOSPC: u32 = 51; +pub const __WASI_ENOSYS: u32 = 52; +pub const __WASI_ENOTCONN: u32 = 53; +pub const __WASI_ENOTDIR: u32 = 54; +pub const __WASI_ENOTEMPTY: u32 = 55; +pub const __WASI_ENOTRECOVERABLE: u32 = 56; +pub const __WASI_ENOTSOCK: u32 = 57; +pub const __WASI_ENOTSUP: u32 = 58; +pub const __WASI_ENOTTY: u32 = 59; +pub const __WASI_ENXIO: u32 = 60; +pub const __WASI_EOVERFLOW: u32 = 61; +pub const __WASI_EOWNERDEAD: u32 = 62; +pub const __WASI_EPERM: u32 = 63; +pub const __WASI_EPIPE: u32 = 64; +pub const __WASI_EPROTO: u32 = 65; +pub const __WASI_EPROTONOSUPPORT: u32 = 66; +pub const __WASI_EPROTOTYPE: u32 = 67; +pub const __WASI_ERANGE: u32 = 68; +pub const __WASI_EROFS: u32 = 69; +pub const __WASI_ESPIPE: u32 = 70; +pub const __WASI_ESRCH: u32 = 71; +pub const __WASI_ESTALE: u32 = 72; +pub const __WASI_ETIMEDOUT: u32 = 73; +pub const __WASI_ETXTBSY: u32 = 74; +pub const __WASI_EXDEV: u32 = 75; +pub const __WASI_ENOTCAPABLE: u32 = 76; +pub const __WASI_EVENT_FD_READWRITE_HANGUP: u32 = 1; +pub const __WASI_EVENTTYPE_CLOCK: u32 = 0; +pub const __WASI_EVENTTYPE_FD_READ: u32 = 1; +pub const __WASI_EVENTTYPE_FD_WRITE: u32 = 2; +pub const __WASI_FDFLAG_APPEND: u32 = 1; +pub const __WASI_FDFLAG_DSYNC: u32 = 2; +pub const __WASI_FDFLAG_NONBLOCK: u32 = 4; +pub const __WASI_FDFLAG_RSYNC: u32 = 8; +pub const __WASI_FDFLAG_SYNC: u32 = 16; +pub const __WASI_FILETYPE_UNKNOWN: u32 = 0; +pub const __WASI_FILETYPE_BLOCK_DEVICE: u32 = 1; +pub const __WASI_FILETYPE_CHARACTER_DEVICE: u32 = 2; +pub const __WASI_FILETYPE_DIRECTORY: u32 = 3; +pub const __WASI_FILETYPE_REGULAR_FILE: u32 = 4; +pub const __WASI_FILETYPE_SOCKET_DGRAM: u32 = 5; +pub const __WASI_FILETYPE_SOCKET_STREAM: u32 = 6; +pub const __WASI_FILETYPE_SYMBOLIC_LINK: u32 = 7; +pub const __WASI_FILESTAT_SET_ATIM: u32 = 1; +pub const __WASI_FILESTAT_SET_ATIM_NOW: u32 = 2; +pub const __WASI_FILESTAT_SET_MTIM: u32 = 4; +pub const __WASI_FILESTAT_SET_MTIM_NOW: u32 = 8; +pub const __WASI_LOOKUP_SYMLINK_FOLLOW: u32 = 1; +pub const __WASI_O_CREAT: u32 = 1; +pub const __WASI_O_DIRECTORY: u32 = 2; +pub const __WASI_O_EXCL: u32 = 4; +pub const __WASI_O_TRUNC: u32 = 8; +pub const __WASI_SOCK_RECV_PEEK: u32 = 1; +pub const __WASI_SOCK_RECV_WAITALL: u32 = 2; +pub const __WASI_RIGHT_FD_DATASYNC: u32 = 1; +pub const __WASI_RIGHT_FD_READ: u32 = 2; +pub const __WASI_RIGHT_FD_SEEK: u32 = 4; +pub const __WASI_RIGHT_FD_FDSTAT_SET_FLAGS: u32 = 8; +pub const __WASI_RIGHT_FD_SYNC: u32 = 16; +pub const __WASI_RIGHT_FD_TELL: u32 = 32; +pub const __WASI_RIGHT_FD_WRITE: u32 = 64; +pub const __WASI_RIGHT_FD_ADVISE: u32 = 128; +pub const __WASI_RIGHT_FD_ALLOCATE: u32 = 256; +pub const __WASI_RIGHT_PATH_CREATE_DIRECTORY: u32 = 512; +pub const __WASI_RIGHT_PATH_CREATE_FILE: u32 = 1024; +pub const __WASI_RIGHT_PATH_LINK_SOURCE: u32 = 2048; +pub const __WASI_RIGHT_PATH_LINK_TARGET: u32 = 4096; +pub const __WASI_RIGHT_PATH_OPEN: u32 = 8192; +pub const __WASI_RIGHT_FD_READDIR: u32 = 16384; +pub const __WASI_RIGHT_PATH_READLINK: u32 = 32768; +pub const __WASI_RIGHT_PATH_RENAME_SOURCE: u32 = 65536; +pub const __WASI_RIGHT_PATH_RENAME_TARGET: u32 = 131072; +pub const __WASI_RIGHT_PATH_FILESTAT_GET: u32 = 262144; +pub const __WASI_RIGHT_PATH_FILESTAT_SET_SIZE: u32 = 524288; +pub const __WASI_RIGHT_PATH_FILESTAT_SET_TIMES: u32 = 1048576; +pub const __WASI_RIGHT_FD_FILESTAT_GET: u32 = 2097152; +pub const __WASI_RIGHT_FD_FILESTAT_SET_SIZE: u32 = 4194304; +pub const __WASI_RIGHT_FD_FILESTAT_SET_TIMES: u32 = 8388608; +pub const __WASI_RIGHT_PATH_SYMLINK: u32 = 16777216; +pub const __WASI_RIGHT_PATH_REMOVE_DIRECTORY: u32 = 33554432; +pub const __WASI_RIGHT_PATH_UNLINK_FILE: u32 = 67108864; +pub const __WASI_RIGHT_POLL_FD_READWRITE: u32 = 134217728; +pub const __WASI_RIGHT_SOCK_SHUTDOWN: u32 = 268435456; +pub const __WASI_SOCK_RECV_DATA_TRUNCATED: u32 = 1; +pub const __WASI_SHUT_RD: u32 = 1; +pub const __WASI_SHUT_WR: u32 = 2; +pub const __WASI_SIGHUP: u32 = 1; +pub const __WASI_SIGINT: u32 = 2; +pub const __WASI_SIGQUIT: u32 = 3; +pub const __WASI_SIGILL: u32 = 4; +pub const __WASI_SIGTRAP: u32 = 5; +pub const __WASI_SIGABRT: u32 = 6; +pub const __WASI_SIGBUS: u32 = 7; +pub const __WASI_SIGFPE: u32 = 8; +pub const __WASI_SIGKILL: u32 = 9; +pub const __WASI_SIGUSR1: u32 = 10; +pub const __WASI_SIGSEGV: u32 = 11; +pub const __WASI_SIGUSR2: u32 = 12; +pub const __WASI_SIGPIPE: u32 = 13; +pub const __WASI_SIGALRM: u32 = 14; +pub const __WASI_SIGTERM: u32 = 15; +pub const __WASI_SIGCHLD: u32 = 16; +pub const __WASI_SIGCONT: u32 = 17; +pub const __WASI_SIGSTOP: u32 = 18; +pub const __WASI_SIGTSTP: u32 = 19; +pub const __WASI_SIGTTIN: u32 = 20; +pub const __WASI_SIGTTOU: u32 = 21; +pub const __WASI_SIGURG: u32 = 22; +pub const __WASI_SIGXCPU: u32 = 23; +pub const __WASI_SIGXFSZ: u32 = 24; +pub const __WASI_SIGVTALRM: u32 = 25; +pub const __WASI_SIGPROF: u32 = 26; +pub const __WASI_SIGWINCH: u32 = 27; +pub const __WASI_SIGPOLL: u32 = 28; +pub const __WASI_SIGPWR: u32 = 29; +pub const __WASI_SIGSYS: u32 = 30; +pub const __WASI_SUBSCRIPTION_CLOCK_ABSTIME: u32 = 1; +pub const __WASI_WHENCE_CUR: u32 = 0; +pub const __WASI_WHENCE_END: u32 = 1; +pub const __WASI_WHENCE_SET: u32 = 2; +pub const __WASI_PREOPENTYPE_DIR: u32 = 0; +pub type __wasi_advice_t = u8; +pub type __wasi_clockid_t = u32; +pub type __wasi_device_t = u64; +pub type __wasi_dircookie_t = u64; +pub type __wasi_errno_t = u16; +pub type __wasi_eventrwflags_t = u16; +pub type __wasi_eventtype_t = u8; +pub type __wasi_exitcode_t = u32; +pub type __wasi_fd_t = u32; +pub type __wasi_fdflags_t = u16; +pub type __wasi_filedelta_t = i64; +pub type __wasi_filesize_t = u64; +pub type __wasi_filetype_t = u8; +pub type __wasi_fstflags_t = u16; +pub type __wasi_inode_t = u64; +pub type __wasi_linkcount_t = u32; +pub type __wasi_lookupflags_t = u32; +pub type __wasi_oflags_t = u16; +pub type __wasi_riflags_t = u16; +pub type __wasi_rights_t = u64; +pub type __wasi_roflags_t = u16; +pub type __wasi_sdflags_t = u8; +pub type __wasi_siflags_t = u16; +pub type __wasi_signal_t = u8; +pub type __wasi_subclockflags_t = u16; +pub type __wasi_timestamp_t = u64; +pub type __wasi_userdata_t = u64; +pub type __wasi_whence_t = u8; +pub type __wasi_preopentype_t = u8; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __wasi_dirent_t { + pub d_next: __wasi_dircookie_t, + pub d_ino: __wasi_inode_t, + pub d_namlen: u32, + pub d_type: __wasi_filetype_t, +} +#[test] +fn bindgen_test_layout___wasi_dirent_t() { + assert_eq!( + ::std::mem::size_of::<__wasi_dirent_t>(), + 24usize, + concat!("Size of: ", stringify!(__wasi_dirent_t)) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_dirent_t>(), + 8usize, + concat!("Alignment of ", stringify!(__wasi_dirent_t)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_next as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_dirent_t), + "::", + stringify!(d_next) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_ino as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__wasi_dirent_t), + "::", + stringify!(d_ino) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_namlen as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(__wasi_dirent_t), + "::", + stringify!(d_namlen) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_type as *const _ as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(__wasi_dirent_t), + "::", + stringify!(d_type) + ) + ); +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct __wasi_event_t { + pub userdata: __wasi_userdata_t, + pub error: __wasi_errno_t, + pub type_: __wasi_eventtype_t, + pub u: __wasi_event_t___wasi_event_u, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union __wasi_event_t___wasi_event_u { + pub fd_readwrite: __wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t, + _bindgen_union_align: [u64; 2usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { + pub nbytes: __wasi_filesize_t, + pub flags: __wasi_eventrwflags_t, +} +#[test] +fn bindgen_test_layout___wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t() { + assert_eq!( + ::std::mem::size_of::<__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t>(), + 16usize, + concat!( + "Size of: ", + stringify!(__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t) + ) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t>(), + 8usize, + concat!( + "Alignment of ", + stringify!(__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::<__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t>())) + .nbytes as *const _ as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t), + "::", + stringify!(nbytes) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::<__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t>())) + .flags as *const _ as usize + }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t), + "::", + stringify!(flags) + ) + ); +} +#[test] +fn bindgen_test_layout___wasi_event_t___wasi_event_u() { + assert_eq!( + ::std::mem::size_of::<__wasi_event_t___wasi_event_u>(), + 16usize, + concat!("Size of: ", stringify!(__wasi_event_t___wasi_event_u)) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_event_t___wasi_event_u>(), + 8usize, + concat!("Alignment of ", stringify!(__wasi_event_t___wasi_event_u)) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::<__wasi_event_t___wasi_event_u>())).fd_readwrite as *const _ + as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_event_t___wasi_event_u), + "::", + stringify!(fd_readwrite) + ) + ); +} +#[test] +fn bindgen_test_layout___wasi_event_t() { + assert_eq!( + ::std::mem::size_of::<__wasi_event_t>(), + 32usize, + concat!("Size of: ", stringify!(__wasi_event_t)) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_event_t>(), + 8usize, + concat!("Alignment of ", stringify!(__wasi_event_t)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).userdata as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_event_t), + "::", + stringify!(userdata) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).error as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__wasi_event_t), + "::", + stringify!(error) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).type_ as *const _ as usize }, + 10usize, + concat!( + "Offset of field: ", + stringify!(__wasi_event_t), + "::", + stringify!(type_) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).u as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(__wasi_event_t), + "::", + stringify!(u) + ) + ); +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct __wasi_prestat_t { + pub pr_type: __wasi_preopentype_t, + pub u: __wasi_prestat_t___wasi_prestat_u, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union __wasi_prestat_t___wasi_prestat_u { + pub dir: __wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t, + _bindgen_union_align: u64, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t { + pub pr_name_len: usize, +} +#[test] +fn bindgen_test_layout___wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t() { + assert_eq!( + ::std::mem::size_of::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>(), + 8usize, + concat!( + "Size of: ", + stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t) + ) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>(), + 8usize, + concat!( + "Alignment of ", + stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>())) + .pr_name_len as *const _ as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t), + "::", + stringify!(pr_name_len) + ) + ); +} +#[test] +fn bindgen_test_layout___wasi_prestat_t___wasi_prestat_u() { + assert_eq!( + ::std::mem::size_of::<__wasi_prestat_t___wasi_prestat_u>(), + 8usize, + concat!("Size of: ", stringify!(__wasi_prestat_t___wasi_prestat_u)) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_prestat_t___wasi_prestat_u>(), + 8usize, + concat!( + "Alignment of ", + stringify!(__wasi_prestat_t___wasi_prestat_u) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::<__wasi_prestat_t___wasi_prestat_u>())).dir as *const _ as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_prestat_t___wasi_prestat_u), + "::", + stringify!(dir) + ) + ); +} +#[test] +fn bindgen_test_layout___wasi_prestat_t() { + assert_eq!( + ::std::mem::size_of::<__wasi_prestat_t>(), + 16usize, + concat!("Size of: ", stringify!(__wasi_prestat_t)) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_prestat_t>(), + 8usize, + concat!("Alignment of ", stringify!(__wasi_prestat_t)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_prestat_t>())).pr_type as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_prestat_t), + "::", + stringify!(pr_type) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_prestat_t>())).u as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__wasi_prestat_t), + "::", + stringify!(u) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __wasi_fdstat_t { + pub fs_filetype: __wasi_filetype_t, + pub fs_flags: __wasi_fdflags_t, + pub fs_rights_base: __wasi_rights_t, + pub fs_rights_inheriting: __wasi_rights_t, +} +#[test] +fn bindgen_test_layout___wasi_fdstat_t() { + assert_eq!( + ::std::mem::size_of::<__wasi_fdstat_t>(), + 24usize, + concat!("Size of: ", stringify!(__wasi_fdstat_t)) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_fdstat_t>(), + 8usize, + concat!("Alignment of ", stringify!(__wasi_fdstat_t)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_filetype as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_fdstat_t), + "::", + stringify!(fs_filetype) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_flags as *const _ as usize }, + 2usize, + concat!( + "Offset of field: ", + stringify!(__wasi_fdstat_t), + "::", + stringify!(fs_flags) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_rights_base as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__wasi_fdstat_t), + "::", + stringify!(fs_rights_base) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_rights_inheriting as *const _ as usize + }, + 16usize, + concat!( + "Offset of field: ", + stringify!(__wasi_fdstat_t), + "::", + stringify!(fs_rights_inheriting) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __wasi_filestat_t { + pub st_dev: __wasi_device_t, + pub st_ino: __wasi_inode_t, + pub st_filetype: __wasi_filetype_t, + pub st_nlink: __wasi_linkcount_t, + pub st_size: __wasi_filesize_t, + pub st_atim: __wasi_timestamp_t, + pub st_mtim: __wasi_timestamp_t, + pub st_ctim: __wasi_timestamp_t, +} +#[test] +fn bindgen_test_layout___wasi_filestat_t() { + assert_eq!( + ::std::mem::size_of::<__wasi_filestat_t>(), + 56usize, + concat!("Size of: ", stringify!(__wasi_filestat_t)) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_filestat_t>(), + 8usize, + concat!("Alignment of ", stringify!(__wasi_filestat_t)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_dev as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_filestat_t), + "::", + stringify!(st_dev) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_ino as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__wasi_filestat_t), + "::", + stringify!(st_ino) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_filetype as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(__wasi_filestat_t), + "::", + stringify!(st_filetype) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_nlink as *const _ as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(__wasi_filestat_t), + "::", + stringify!(st_nlink) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_size as *const _ as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(__wasi_filestat_t), + "::", + stringify!(st_size) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_atim as *const _ as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(__wasi_filestat_t), + "::", + stringify!(st_atim) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_mtim as *const _ as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(__wasi_filestat_t), + "::", + stringify!(st_mtim) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_ctim as *const _ as usize }, + 48usize, + concat!( + "Offset of field: ", + stringify!(__wasi_filestat_t), + "::", + stringify!(st_ctim) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __wasi_ciovec_t { + pub buf: *const ::std::os::raw::c_void, + pub buf_len: usize, +} +#[test] +fn bindgen_test_layout___wasi_ciovec_t() { + assert_eq!( + ::std::mem::size_of::<__wasi_ciovec_t>(), + 16usize, + concat!("Size of: ", stringify!(__wasi_ciovec_t)) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_ciovec_t>(), + 8usize, + concat!("Alignment of ", stringify!(__wasi_ciovec_t)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_ciovec_t>())).buf as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_ciovec_t), + "::", + stringify!(buf) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_ciovec_t>())).buf_len as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__wasi_ciovec_t), + "::", + stringify!(buf_len) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __wasi_iovec_t { + pub buf: *mut ::std::os::raw::c_void, + pub buf_len: usize, +} +#[test] +fn bindgen_test_layout___wasi_iovec_t() { + assert_eq!( + ::std::mem::size_of::<__wasi_iovec_t>(), + 16usize, + concat!("Size of: ", stringify!(__wasi_iovec_t)) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_iovec_t>(), + 8usize, + concat!("Alignment of ", stringify!(__wasi_iovec_t)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_iovec_t>())).buf as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_iovec_t), + "::", + stringify!(buf) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_iovec_t>())).buf_len as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__wasi_iovec_t), + "::", + stringify!(buf_len) + ) + ); +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct __wasi_subscription_t { + pub userdata: __wasi_userdata_t, + pub type_: __wasi_eventtype_t, + pub u: __wasi_subscription_t___wasi_subscription_u, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union __wasi_subscription_t___wasi_subscription_u { + pub clock: __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, + pub fd_readwrite: + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t, + _bindgen_union_align: [u64; 5usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t { + pub identifier: __wasi_userdata_t, + pub clock_id: __wasi_clockid_t, + pub timeout: __wasi_timestamp_t, + pub precision: __wasi_timestamp_t, + pub flags: __wasi_subclockflags_t, +} +#[test] +fn bindgen_test_layout___wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t() { + assert_eq!( + ::std::mem::size_of::< + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, + >(), + 40usize, + concat!( + "Size of: ", + stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t) + ) + ); + assert_eq!( + ::std::mem::align_of::< + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, + >(), + 8usize, + concat!( + "Alignment of ", + stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::< + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, + >())) + .identifier as *const _ as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t), + "::", + stringify!(identifier) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::< + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, + >())) + .clock_id as *const _ as usize + }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t), + "::", + stringify!(clock_id) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::< + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, + >())) + .timeout as *const _ as usize + }, + 16usize, + concat!( + "Offset of field: ", + stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t), + "::", + stringify!(timeout) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::< + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, + >())) + .precision as *const _ as usize + }, + 24usize, + concat!( + "Offset of field: ", + stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t), + "::", + stringify!(precision) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::< + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, + >())) + .flags as *const _ as usize + }, + 32usize, + concat!( + "Offset of field: ", + stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t), + "::", + stringify!(flags) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t { + pub fd: __wasi_fd_t, +} +#[test] +fn bindgen_test_layout___wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t( +) { + assert_eq!( + ::std::mem::size_of::< + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t, + >(), + 4usize, + concat!( + "Size of: ", + stringify!( + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t + ) + ) + ); + assert_eq!( + ::std::mem::align_of::< + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t, + >(), + 4usize, + concat!( + "Alignment of ", + stringify!( + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t + ) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::< + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t, + >())) + .fd as *const _ as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!( + __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t + ), + "::", + stringify!(fd) + ) + ); +} +#[test] +fn bindgen_test_layout___wasi_subscription_t___wasi_subscription_u() { + assert_eq!( + ::std::mem::size_of::<__wasi_subscription_t___wasi_subscription_u>(), + 40usize, + concat!( + "Size of: ", + stringify!(__wasi_subscription_t___wasi_subscription_u) + ) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_subscription_t___wasi_subscription_u>(), + 8usize, + concat!( + "Alignment of ", + stringify!(__wasi_subscription_t___wasi_subscription_u) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::<__wasi_subscription_t___wasi_subscription_u>())).clock + as *const _ as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_subscription_t___wasi_subscription_u), + "::", + stringify!(clock) + ) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::<__wasi_subscription_t___wasi_subscription_u>())).fd_readwrite + as *const _ as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_subscription_t___wasi_subscription_u), + "::", + stringify!(fd_readwrite) + ) + ); +} +#[test] +fn bindgen_test_layout___wasi_subscription_t() { + assert_eq!( + ::std::mem::size_of::<__wasi_subscription_t>(), + 56usize, + concat!("Size of: ", stringify!(__wasi_subscription_t)) + ); + assert_eq!( + ::std::mem::align_of::<__wasi_subscription_t>(), + 8usize, + concat!("Alignment of ", stringify!(__wasi_subscription_t)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_subscription_t>())).userdata as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__wasi_subscription_t), + "::", + stringify!(userdata) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_subscription_t>())).type_ as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__wasi_subscription_t), + "::", + stringify!(type_) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<__wasi_subscription_t>())).u as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(__wasi_subscription_t), + "::", + stringify!(u) + ) + ); +} diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index a19d5c334..3e5377705 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -1,10 +1,12 @@ [package] name = "lucetc" -version = "0.1.0" -description = "Compile WebAssembly to native code" +version = "0.1.1" +description = "Fastly's WebAssembly to native code compiler" +homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" -authors = ["Pat Hickey ", "Frank Denis ", "Adam C. Foltzer ", "Tyler McMullen "] license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +authors = ["Lucet team "] edition = "2018" [lib] @@ -16,26 +18,27 @@ path = "src/main.rs" [dependencies] bincode = "~1.0.1" -cranelift-codegen = { path = "../cranelift/cranelift-codegen" } -cranelift-entity = { path = "../cranelift/cranelift-entity" } -cranelift-native = { path = "../cranelift/cranelift-native" } -cranelift-frontend = { path = "../cranelift/cranelift-frontend" } -cranelift-module = { path = "../cranelift/cranelift-module" } -cranelift-faerie = { path = "../cranelift/cranelift-faerie" } -cranelift-wasm = { path = "../cranelift/cranelift-wasm" } -target-lexicon = "0.3" -lucet-module-data = { path = "../lucet-module-data" } +cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.31.0" } +cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.31.0" } +cranelift-native = { path = "../cranelift/cranelift-native", version = "0.31.0" } +cranelift-frontend = { path = "../cranelift/cranelift-frontend", version = "0.31.0" } +cranelift-module = { path = "../cranelift/cranelift-module", version = "0.31.0" } +cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.31.0" } +cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.31.0" } +target-lexicon = "0.4.0" +lucet-module-data = { path = "../lucet-module-data", version = "0.1.1" } wasmparser = "0.23" clap="2.32" log = "0.4" env_logger = "0.6" faerie = "0.10.0" +goblin = "0.0.22" failure = "0.1" byteorder = "1.2" -wasmonkey = { path = "../lucet-builtins/wasmonkey" } +wasmonkey = { path = "../lucet-builtins/wasmonkey", version = "0.1.7" } wabt = "0.7" tempfile = "3.0" bimap = "0.2" human-size = "0.4" -parity-wasm = "0.35" +parity-wasm = "0.38" minisign = "0.5.11" diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index 6cf05b23a..4f9569584 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -54,7 +54,7 @@ impl<'a> Compiler<'a> { pub fn new( wasm_binary: &'a [u8], opt_level: OptLevel, - bindings: &Bindings, + bindings: &'a Bindings, heap_settings: HeapSettings, ) -> Result { let isa = Self::target_isa(opt_level); diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index 86803b120..7a0009cb7 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -79,7 +79,7 @@ impl<'a> ModuleDecls<'a> { pub fn new( info: ModuleInfo<'a>, clif_module: &mut ClifModule, - bindings: &Bindings, + bindings: &'a Bindings, runtime: Runtime, heap_settings: HeapSettings, ) -> Result { @@ -109,7 +109,7 @@ impl<'a> ModuleDecls<'a> { fn declare_funcs( decls: &mut ModuleDecls<'a>, clif_module: &mut ClifModule, - bindings: &Bindings, + bindings: &'a Bindings, ) -> Result<(), LucetcError> { for ix in 0..decls.info.functions.len() { let func_index = UniqueFuncIndex::new(ix); @@ -117,7 +117,7 @@ impl<'a> ModuleDecls<'a> { fn export_name_for<'a>( func_ix: UniqueFuncIndex, decls: &mut ModuleDecls<'a>, - ) -> Option<(String, Linkage)> { + ) -> Option { let export = decls.info.functions.get(func_ix).unwrap(); if !export.export_names.is_empty() { @@ -126,10 +126,7 @@ impl<'a> ModuleDecls<'a> { names: export.export_names.clone(), }); - Some(( - format!("guest_func_{}", export.export_names[0]), - Linkage::Export, - )) + Some(format!("guest_func_{}", export.export_names[0])) } else { None } @@ -138,28 +135,51 @@ impl<'a> ModuleDecls<'a> { fn import_name_for<'a>( func_ix: UniqueFuncIndex, decls: &mut ModuleDecls<'a>, - bindings: &Bindings, - ) -> Result, failure::Context> { + bindings: &'a Bindings, + ) -> Result, failure::Context> { if let Some((import_mod, import_field)) = decls.info.imported_funcs.get(func_ix) { + let import_symbol = bindings + .translate(import_mod, import_field) + .context(LucetcErrorKind::TranslatingModule)?; decls.imports.push(ImportFunction { fn_idx: LucetFunctionIndex::from_u32(decls.function_names.len() as u32), module: import_mod, name: import_field, }); - let import_symbol = bindings - .translate(import_mod, import_field) - .context(LucetcErrorKind::TranslatingModule)?; - Ok(Some((import_symbol, Linkage::Import))) + Ok(Some(import_symbol.to_string())) } else { Ok(None) } }; - let (decl_sym, decl_linkage) = import_name_for(func_index, decls, bindings)? - .or_else(|| export_name_for(func_index, decls)) - .unwrap_or_else(|| (format!("guest_func_{}", ix), Linkage::Local)); + let import_info = import_name_for(func_index, decls, bindings)?; + let export_info = export_name_for(func_index, decls); - decls.declare_function(clif_module, decl_sym, decl_linkage, func_index)?; + match (import_info, export_info) { + (Some(import_sym), _) => { + // if a function is only an import, declare the corresponding artifact import. + // if a function is an export and import, it will not have a real function body + // in this program, and we must not declare it with Linkage::Export (there will + // never be a define to satisfy the symbol!) + + decls.declare_function(clif_module, import_sym, Linkage::Import, func_index)?; + } + (None, Some(export_sym)) => { + // This is a function that is only exported, so there will be a body in this + // artifact. We can declare the export. + decls.declare_function(clif_module, export_sym, Linkage::Export, func_index)?; + } + (None, None) => { + // No import or export for this function. It's local, and we have to make up a + // name. + decls.declare_function( + clif_module, + format!("guest_func_{}", ix), + Linkage::Local, + func_index, + )?; + } + } } Ok(()) } @@ -177,7 +197,9 @@ impl<'a> ModuleDecls<'a> { ) -> Result { let (new_funcidx, _) = self.info.declare_func_with_sig(signature); - self.declare_function(clif_module, decl_sym, decl_linkage, new_funcidx) + self.declare_function(clif_module, decl_sym, decl_linkage, new_funcidx)?; + + Ok(new_funcidx) } /// The internal side of fixing up a new function declaration. This is also the work that must @@ -189,6 +211,13 @@ impl<'a> ModuleDecls<'a> { decl_linkage: Linkage, func_ix: UniqueFuncIndex, ) -> Result { + // This function declaration may be a subsequent additional declaration for a function + // we've already been told about. In that case, func_ix will already be a valid index for a + // function name, and we should not try to declare it again. + // + // Regardless of the function being known internally, we must forward the additional + // declaration to `clif_module` so functions with multiple forms of linkage (import + + // export, exported twice, ...) are correctly declared in the resultant artifact. let funcid = clif_module .declare_function( &decl_sym, @@ -196,7 +225,18 @@ impl<'a> ModuleDecls<'a> { self.info.signature_for_function(func_ix), ) .context(LucetcErrorKind::TranslatingModule)?; - self.function_names.push(Name::new_func(decl_sym, funcid)); + + if func_ix.as_u32() as usize >= self.function_names.len() { + // `func_ix` is new, so we need to add the name. If func_ix is new, it should be + // an index for the Name we're about to add. That is, it should be the same as the + // current value for `self.function_names.len()`. + // + // If this fails, we're declaring functions out of order. oops! + debug_assert!(func_ix.as_u32() as usize == self.function_names.len()); + + self.function_names.push(Name::new_func(decl_sym, funcid)); + } + Ok(UniqueFuncIndex::new(self.function_names.len() - 1)) } diff --git a/lucetc/src/function_manifest.rs b/lucetc/src/function_manifest.rs index b7f2105a3..809eb7123 100644 --- a/lucetc/src/function_manifest.rs +++ b/lucetc/src/function_manifest.rs @@ -5,21 +5,58 @@ use failure::{Error, ResultExt}; use lucet_module_data::FunctionSpec; use std::io::Cursor; use std::mem::size_of; +use target_lexicon::BinaryFormat; fn write_relocated_slice( obj: &mut Artifact, buf: &mut Cursor>, from: &str, - to: &str, + to: Option<&str>, len: u64, ) -> Result<(), Error> { - if len > 0 { - obj.link(Link { - from, // the data at `from` + `at` (eg. manifest_sym) - to, // is a reference to `to` (eg. fn_name) - at: buf.position(), - }) - .context(format!("linking {} into function manifest", to))?; + match (to, len) { + (Some(to), 0) => { + // This is an imported slice of unknown size + let absolute_reloc = match obj.target.binary_format { + BinaryFormat::Elf => faerie::artifact::Reloc::Raw { + reloc: goblin::elf::reloc::R_X86_64_64, + addend: 0, + }, + BinaryFormat::Macho => faerie::artifact::Reloc::Raw { + reloc: goblin::mach::relocation::X86_64_RELOC_UNSIGNED as u32, + addend: 0, + }, + _ => panic!("Unsupported target format!"), + }; + + obj.link_with( + Link { + from, + to, + at: buf.position(), + }, + absolute_reloc, + ) + .context(format!("linking {} into function manifest", to))?; + } + (Some(to), _len) => { + // This is a local buffer of known size + obj.link(Link { + from, // the data at `from` + `at` (eg. manifest_sym) + to, // is a reference to `to` (eg. fn_name) + at: buf.position(), + }) + .context(format!("linking {} into function manifest", to))?; + } + (None, len) => { + // There's actually no relocation to add, because there's no slice to put here. + // + // Since there's no slice, its length must be zero. + assert!( + len == 0, + "Invalid slice: no data, but there are more than zero bytes of it" + ); + } } buf.write_u64::(0).unwrap(); @@ -70,15 +107,20 @@ pub fn write_function_manifest( obj, &mut manifest_buf, &manifest_sym, - fn_name, + Some(fn_name), fn_spec.code_len() as u64, )?; // Writes a (ptr, len) pair with relocation for this function's trap table + let trap_sym = trap_sym_for_func(fn_name); write_relocated_slice( obj, &mut manifest_buf, &manifest_sym, - &trap_sym_for_func(fn_name), + if fn_spec.traps_len() > 0 { + Some(&trap_sym) + } else { + None + }, fn_spec.traps_len() as u64, )?; } diff --git a/lucetc/tests/wasm.rs b/lucetc/tests/wasm.rs index f7b700691..84b695cca 100644 --- a/lucetc/tests/wasm.rs +++ b/lucetc/tests/wasm.rs @@ -21,6 +21,7 @@ fn test_bindings() -> Bindings { ("imp_1".into(), "imp_1".into()), // import_many ("imp_2".into(), "imp_2".into()), // import_many ("imp_3".into(), "imp_3".into()), // import_many + ("imported_main".into(), "imported_main".into()), // exported_import ] .iter() .cloned() @@ -36,6 +37,40 @@ mod module_data { use lucetc::{Compiler, HeapSettings, LucetcErrorKind, OptLevel}; use std::path::PathBuf; + #[test] + fn exported_import() { + let m = load_wat_module("exported_import"); + let b = super::test_bindings(); + let h = HeapSettings::default(); + let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compiling exported_import"); + let mdata = c.module_data().unwrap(); + assert_eq!(mdata.globals_spec().len(), 0); + + assert_eq!(mdata.import_functions().len(), 2); + assert_eq!(mdata.export_functions().len(), 2); + assert_eq!(mdata.function_info().len(), 4); + // This ordering is actually arbitrary. Cranelift hoists additional declaration modifiers + // up to the function declaration. This means inc comes first, and main second, in + // `exported_import.wat`. + assert_eq!(mdata.export_functions()[0].names, vec!["exported_inc"]); + assert_eq!(mdata.export_functions()[1].names, vec!["exported_main"]); + } + + #[test] + fn multiple_import() { + let m = load_wat_module("multiple_import"); + let b = super::test_bindings(); + let h = HeapSettings::default(); + let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compiling multiple_import"); + let mdata = c.module_data().unwrap(); + assert_eq!(mdata.globals_spec().len(), 0); + + assert_eq!(mdata.import_functions().len(), 2); + assert_eq!(mdata.export_functions().len(), 1); + assert_eq!(mdata.function_info().len(), 4); + assert_eq!(mdata.export_functions()[0].names, vec!["exported_inc"]); + } + #[test] fn globals_export() { let m = load_wat_module("globals_export"); @@ -100,8 +135,9 @@ mod module_data { assert_eq!(mdata.function_info()[0].name, Some("host_read")); assert_eq!(mdata.function_info()[1].name, Some("host_write")); assert_eq!(mdata.function_info()[2].name, Some("guest_func__start")); - assert_eq!(mdata.export_functions().len(), 1); - assert_eq!(mdata.export_functions()[0].names, ["_start"]); + assert_eq!(mdata.export_functions().len(), 3); + assert_eq!(mdata.export_functions()[0].names, ["read_2", "read"]); + assert_eq!(mdata.export_functions()[2].names, ["_start"]); assert_eq!(mdata.globals_spec().len(), 0); } diff --git a/lucetc/tests/wasm/exported_import.wat b/lucetc/tests/wasm/exported_import.wat new file mode 100644 index 000000000..fce3d74c7 --- /dev/null +++ b/lucetc/tests/wasm/exported_import.wat @@ -0,0 +1,12 @@ +(module + (func (import "env" "inc")) + (func $main (export "exported_main") (import "env" "imported_main")) + + ;; cranelift_wasm bundles up import/export/declaration statements and + ;; declares them together. lucetc depends on function declaration + ;; components not being interwoven, so test that this is still bundled + ;; up by exporting after declaring a new function ("$main", above) + (export "exported_inc" (func 0)) + + (start $main) +) diff --git a/lucetc/tests/wasm/multiple_import.wat b/lucetc/tests/wasm/multiple_import.wat new file mode 100644 index 000000000..be54dfcf5 --- /dev/null +++ b/lucetc/tests/wasm/multiple_import.wat @@ -0,0 +1,7 @@ +(module + (func $inc (import "env" "inc")) + (func $inc_duplicate (import "env" "inc")) + (func $foo (import "env" "imported_main")) + (func $inc_another_duplicate (export "exported_inc") (import "env" "inc")) + (start $inc) +) diff --git a/rust-toolchain b/rust-toolchain index 2aeaa11ee..39fc130ef 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -1.35.0 +1.36.0 From f496e327d7b570b91714e246fc08e581bcc80eb8 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 8 Jul 2019 17:59:59 -0700 Subject: [PATCH 258/512] clean up debugging output and change some names --- lucet-wasi-fuzz/src/main.rs | 10 +++++----- lucet-wasi/tests/guests/poll.c | 5 ----- lucet-wasi/tests/tests.rs | 6 +----- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/lucet-wasi-fuzz/src/main.rs b/lucet-wasi-fuzz/src/main.rs index d47f35934..e475e32d2 100644 --- a/lucet-wasi-fuzz/src/main.rs +++ b/lucet-wasi-fuzz/src/main.rs @@ -99,7 +99,7 @@ fn run_creduce_driver(seed: Seed) { .unwrap(); assert!(st.success()); - let st = Command::new(native_clang()) + let st = Command::new(host_clang()) .arg("-I/usr/include/csmith") .arg("-m32") .arg("-E") @@ -284,7 +284,7 @@ fn run_both>( fn run_native>(tmpdir: &TempDir, gen_c_path: P) -> Result>, Error> { let gen_path = tmpdir.path().join("gen"); - let mut cmd = Command::new(native_clang()); + let mut cmd = Command::new(host_clang()); cmd.arg("-m32") .arg("-std=c11") .arg("-Werror=format") @@ -294,7 +294,7 @@ fn run_native>(tmpdir: &TempDir, gen_c_path: P) -> Result>(tmpdir: &TempDir, c_file: P) -> Result) } -fn native_clang() -> PathBuf { - match std::env::var("NATIVE_CLANG") { +fn host_clang() -> PathBuf { + match std::env::var("HOST_CLANG") { Ok(clang) => PathBuf::from(clang), Err(_) => PathBuf::from("clang"), } diff --git a/lucet-wasi/tests/guests/poll.c b/lucet-wasi/tests/guests/poll.c index 632248329..d8f9a8c1d 100644 --- a/lucet-wasi/tests/guests/poll.c +++ b/lucet-wasi/tests/guests/poll.c @@ -1,6 +1,5 @@ #include #include -#include #include #include @@ -20,17 +19,13 @@ int main(void) fds[0] = (struct pollfd){ .fd = 0, .events = POLLIN, .revents = 0 }; time(&before); - printf("time before = %lld\n", before); ret = poll(fds, 1, 2000); - printf("ret = %d\n", ret); time(&now); - printf("time now = %lld\n", now); assert(ret == 0); assert(now - before >= 2); sleep(1); time(&now); - printf("time now = %lld\n", now); assert(now - before >= 3); return 0; diff --git a/lucet-wasi/tests/tests.rs b/lucet-wasi/tests/tests.rs index 46fc5786d..18cdf386d 100644 --- a/lucet-wasi/tests/tests.rs +++ b/lucet-wasi/tests/tests.rs @@ -369,11 +369,7 @@ fn pseudoquine() { #[test] fn poll() { - let ctx = WasiCtxBuilder::new() - .args(&["poll"]) - .inherit_stdio() - .build() - .unwrap(); + let ctx = WasiCtxBuilder::new().args(&["poll"]).build().unwrap(); let exitcode = run("poll.c", ctx).unwrap(); assert_eq!(exitcode, 0); } From 2c2b035415703499c8d1e03ac54c12deb694fe45 Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Tue, 9 Jul 2019 23:40:45 +0200 Subject: [PATCH 259/512] Parse sizes in lucet-wasi and lucetc the same way (#243) In `lucetc`, units are optional. In `lucet-wasi`, units are mandatory. Not having a trailing "B" after a size given in bytes yields a confusing message about the size being invalid. Parse sizes the same way. So that, e.g. the same value can be used with `--reserved-size` and `--max-heap-size`. --- lucet-wasi/src/main.rs | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/lucet-wasi/src/main.rs b/lucet-wasi/src/main.rs index c4bc36a47..c6e01b579 100644 --- a/lucet-wasi/src/main.rs +++ b/lucet-wasi/src/main.rs @@ -4,7 +4,7 @@ extern crate clap; use clap::Arg; -use human_size::{Byte, Size}; +use failure::{format_err, Error}; use lucet_runtime::{self, DlModule, Limits, MmapRegion, Module, PublicKey, Region}; use lucet_runtime_internals::module::ModuleInternal; use lucet_wasi::{hostcalls, WasiCtxBuilder}; @@ -22,6 +22,18 @@ struct Config<'a> { pk_path: Option, } +fn parse_humansized(desc: &str) -> Result { + use human_size::{Byte, ParsingError, Size, SpecificSize}; + match desc.parse::() { + Ok(s) => { + let bytes: SpecificSize = s.into(); + Ok(bytes.value() as u64) + } + Err(ParsingError::MissingMultiple) => Ok(desc.parse::()?), + Err(e) => Err(e)?, + } +} + fn main() { // No-ops, but makes sure the linker doesn't throw away parts // of the runtime: @@ -128,14 +140,17 @@ fn main() { }) .unwrap_or(vec![]); - let heap_memory_size = value_t!(matches, "heap_memory_size", Size) - .unwrap_or_else(|e| e.exit()) - .into::() - .value() as usize; - let heap_address_space_size = value_t!(matches, "heap_address_space_size", Size) - .unwrap_or_else(|e| e.exit()) - .into::() - .value() as usize; + let heap_memory_size = matches + .value_of("heap_memory_size") + .ok_or_else(|| format_err!("missing heap memory size")) + .and_then(|v| parse_humansized(v)) + .unwrap() as usize; + + let heap_address_space_size = matches + .value_of("heap_address_space_size") + .ok_or_else(|| format_err!("missing heap address space size")) + .and_then(|v| parse_humansized(v)) + .unwrap() as usize; if heap_memory_size > heap_address_space_size { println!("`heap-address-space` must be at least as large as `max-heap-size`"); @@ -143,10 +158,11 @@ fn main() { std::process::exit(1); } - let stack_size = value_t!(matches, "stack_size", Size) - .unwrap_or_else(|e| e.exit()) - .into::() - .value() as usize; + let stack_size = matches + .value_of("stack_size") + .ok_or_else(|| format_err!("missing stack size")) + .and_then(|v| parse_humansized(v)) + .unwrap() as usize; let limits = Limits { heap_memory_size, From f3c3497d898a84fbe94f140bb1058dfe442d8c53 Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Wed, 10 Jul 2019 22:59:18 +0200 Subject: [PATCH 260/512] Update AssemblyScript, WASA and the AssemblyScript example and instructions (#212) * Update AssemblyScript, WASA and the AssemblyScript example and instructions This is an update to the AssemblyScript module and example, after the new runtimes landed into the AssemblyScript compiler. WASA, the WASI bindings, got a major update, not only to support the new ASC, but also to support most of WASI as it is today. Breaking changes were made to the API to make is both safer and closer to the NodeJS filesystem API. wasm-crypto was updated for the new runtime as well. The example was updated for the new runtime and the new WASA API. The AssemblyScript compiler still has some rough edges regarding garbage collection. So, switch the runtime from `full` (default) to `stub` for now, until some known regressions have been ironed out. * Explain that the public key and the signature must be replaced --- assemblyscript/examples/signatures/README.md | 17 +- .../examples/signatures/assembly/index.ts | 49 +- .../__tests__/faRistrettoPoint.spec.ts | 6 +- .../wasm-crypto/__tests__/hash.spec.ts | 9 + .../wasm-crypto/__tests__/utils.spec.ts | 6 +- .../signatures/assembly/wasm-crypto/crypto.ts | 59 +- .../examples/signatures/package-lock.json | 153 ++++ .../examples/signatures/package.json | 22 +- assemblyscript/modules/wasa/README.md | 7 +- assemblyscript/modules/wasa/assembly/index.ts | 10 +- assemblyscript/modules/wasa/assembly/wasa.ts | 786 ++++++++++++++---- assemblyscript/modules/wasa/bindings.json | 63 +- assemblyscript/modules/wasa/package.json | 9 +- 13 files changed, 931 insertions(+), 265 deletions(-) create mode 100644 assemblyscript/examples/signatures/assembly/wasm-crypto/__tests__/hash.spec.ts create mode 100644 assemblyscript/examples/signatures/package-lock.json diff --git a/assemblyscript/examples/signatures/README.md b/assemblyscript/examples/signatures/README.md index 9c69f0b02..e1e8738b0 100644 --- a/assemblyscript/examples/signatures/README.md +++ b/assemblyscript/examples/signatures/README.md @@ -24,6 +24,7 @@ npm install npm run asbuild:optimized lucetc -o example \ + --reserved-size=64MB \ --bindings /opt/lucet/share/assemblyscript/modules/wasa/bindings.json \ build/optimized.wasm ``` @@ -31,7 +32,7 @@ lucetc -o example \ ## Running the example using lucet-wasi ```sh -lucet-wasi --entrypoint main --dir /lucet:/lucet example help +lucet-wasi --entrypoint main --dir .:. example help ``` Unlike C and Rust applications, AssemblyScript requires an entry point to be explicitly defined. @@ -43,7 +44,7 @@ Since files are going to be read and written to, a descriptor to a pre-opened di This is the purpose of the `--dir` command-line option. Without this, the webassembly module cannot access the filesystem at all. -Here, the `/lucet` virtual directory, as seen by the application, maps to the `/lucet` directory in the container. +Here, the current virtual directory (`.`), as seen by the application, maps to the current directory in the container. ## What the example does @@ -54,7 +55,7 @@ The main code is in `assembly/index.ts`. Key pair creation: ```sh -lucet-wasi --entrypoint main --dir /lucet:/lucet example keypair +lucet-wasi --entrypoint main --dir .:. example keypair ``` ```text @@ -63,7 +64,7 @@ Key pair created and saved into [keypair.bin] Public key: [94b8eb14373eb245c1daaacb2c24e2cb554bdd723009423aae5a8ca5fa99fa16] ``` -A new file `keypair.bin` is created on the local filesystem, at the root of the first mount point (`/lucet`). +A new file `keypair.bin` is created on the local filesystem, at the root of the first mount point (the current directory). An environment variable called `KEYPAIR_FILE`, can be used in order to change the file name and location. @@ -72,21 +73,23 @@ The WASA wrapper automatically sets the minimum required WASI capabilities in or File signature: ```sh -lucet-wasi --entrypoint main --dir /lucet:/lucet example sign LICENSE +lucet-wasi --entrypoint main --dir .:. example sign README.md ``` ```text Signature for that file: [deedf3910d5b166ca17e0e307312a422cb50efcbcc90754cf0e2d528a9159c4ad3ac973e3cd9b2c2986fb2e467a0506bc9a5ceb9c7d6d30e360fb4d1cef3c50d] ``` -This command reads the `/lucet/LICENSE` file, as well as the key pair, and computes a signature of the file's content that can be verified using the public key. +This command reads the `README.md` file, as well as the key pair, and computes a signature of the file's content that can be verified using the public key. Signature verification: ```sh -lucet-wasi --entrypoint main --dir /lucet:/lucet example verify LICENSE 94b8eb14373eb245c1daaacb2c24e2cb554bdd723009423aae5a8ca5fa99fa16 deedf3910d5b166ca17e0e307312a422cb50efcbcc90754cf0e2d528a9159c4ad3ac973e3cd9b2c2986fb2e467a0506bc9a5ceb9c7d6d30e360fb4d1cef3c50d +lucet-wasi --entrypoint main --dir .:. example verify README.md ``` +`` and `` must be replaced with output from the previous commands. + ```text This is a valid signature for that file ``` diff --git a/assemblyscript/examples/signatures/assembly/index.ts b/assemblyscript/examples/signatures/assembly/index.ts index b5f0e0170..2644afd47 100644 --- a/assemblyscript/examples/signatures/assembly/index.ts +++ b/assemblyscript/examples/signatures/assembly/index.ts @@ -1,11 +1,8 @@ -import 'allocator/arena'; -export { memory }; - import { SIGN_RANDBYTES, SIGN_SEEDBYTES, SIGN_KEYPAIRBYTES, SIGN_BYTES, SIGN_PUBLICKEYBYTES, signKeypairFromSeed, signPublicKey, sign, signVerify, bin2hex, hex2bin } from "./wasm-crypto/crypto"; -import { Console, Random, CommandLine, Process, Filesystem, IO, Environ } +import { Console, Random, CommandLine, Process, FileSystem, Environ } from "../../../modules/wasa/assembly/wasa"; /** @@ -16,17 +13,17 @@ function createKeypair(keypair_file: string): void { Console.log("Creating a new keypair..."); let seed = Random.randomBytes(SIGN_SEEDBYTES); let keypair = signKeypairFromSeed(seed); - let fd = Filesystem.openForWrite(keypair_file); + let fd = FileSystem.open(keypair_file, "w"); if (fd === null) { Console.error("Unable to create the keypair file"); Process.exit(1); } - let keypair_array: Array = []; + let keypair_array = new Array(keypair.length); for (let i = 0; i < keypair.length; i++) { - keypair_array[i] = unchecked(keypair[i]); + keypair_array[i] = keypair[i]; } - IO.write(fd!, keypair_array); - IO.close(fd!); + fd!.write(keypair_array); + fd!.close(); Console.log("Key pair created and saved into [" + keypair_file + "]"); let pk_hex = bin2hex(signPublicKey(keypair)); Console.log("Public key: [" + pk_hex + "]"); @@ -38,37 +35,37 @@ function createKeypair(keypair_file: string): void { * @param keypair_file file containing a key pair */ function createSignature(file: string, keypair_file: string): void { - let fd = Filesystem.openForRead(keypair_file); + let fd = FileSystem.open(keypair_file, "r"); if (fd === null) { Console.error("Unable to read the keypair file"); Process.exit(1); } - let keypair_ = IO.readAll(fd!); - IO.close(fd!); - if (keypair_ === null || keypair_!.length !== SIGN_KEYPAIRBYTES) { + let keypair_ = fd!.readAll(); + fd!.close(); + if (keypair_ === null || keypair_.length !== SIGN_KEYPAIRBYTES) { Console.error("Invalid keypair file content"); Process.exit(1); } let keypair = new Uint8Array(SIGN_KEYPAIRBYTES); for (let i = 0; i < SIGN_KEYPAIRBYTES; i++) { - keypair[i] = unchecked(keypair_![i]); + keypair[i] = keypair_![i]; } - fd = Filesystem.openForRead(file); + fd = FileSystem.open(file, "r"); if (fd === null) { Console.error("Unable to open the file to sign"); Process.exit(1); } - let data_ = IO.readAll(fd!); + let data_ = fd!.readAll(); if (data_ === null) { Console.error("Error while reading the file to sign"); Process.exit(1); } - IO.close(fd!); + fd!.close(); let data = data_!; let data_len = data.length; let data_u8 = new Uint8Array(data.length); for (let i = 0; i < data_len; i++) { - data_u8[i] = unchecked(data[i]); + data_u8[i] = data[i]; } let z = Random.randomBytes(SIGN_RANDBYTES); let signature = sign(data_u8, keypair, z); @@ -84,31 +81,31 @@ function createSignature(file: string, keypair_file: string): void { */ function verifySignature(file: string, publickey_hex: string, signature_hex: string): void { let publickey = hex2bin(publickey_hex); - if (publickey === null || publickey!.length !== SIGN_PUBLICKEYBYTES) { + if (publickey === null || publickey.length !== SIGN_PUBLICKEYBYTES) { Console.error("Invalid public key"); Process.exit(1); } let signature = hex2bin(signature_hex); - if (signature === null || signature!.length !== SIGN_BYTES) { + if (signature === null || signature.length !== SIGN_BYTES) { Console.error("Invalid signature"); Process.exit(1); } - let fd = Filesystem.openForRead(file); + let fd = FileSystem.open(file, "r"); if (fd === null) { Console.error("Unable to open the file to sign"); Process.exit(1); } - let data_ = IO.readAll(fd!); + let data_ = fd!.readAll(); if (data_ === null) { Console.error("Error while reading the file to sign"); Process.exit(1); } - IO.close(fd!); + fd!.close(); let data = data_!; let data_len = data.length; let data_u8 = new Uint8Array(data.length); for (let i = 0; i < data_len; i++) { - data_u8[i] = unchecked(data[i]); + data_u8[i] = data[i]; } if (signVerify(signature!, data_u8, publickey!) === false) { Console.error("The signature didn't verify"); @@ -151,9 +148,9 @@ export function main(): void { keypair_file = "keypair.bin"; } if (command == "keypair") { - createKeypair(keypair_file); + createKeypair(keypair_file!); } else if (command == "sign" && args.length == 3) { - createSignature(args[2], keypair_file); + createSignature(args[2], keypair_file!); } else if (command == "verify" && args.length == 5) { verifySignature(args[2], args[3], args[4]); } else { diff --git a/assemblyscript/examples/signatures/assembly/wasm-crypto/__tests__/faRistrettoPoint.spec.ts b/assemblyscript/examples/signatures/assembly/wasm-crypto/__tests__/faRistrettoPoint.spec.ts index 5409b6b44..c3f9a659a 100644 --- a/assemblyscript/examples/signatures/assembly/wasm-crypto/__tests__/faRistrettoPoint.spec.ts +++ b/assemblyscript/examples/signatures/assembly/wasm-crypto/__tests__/faRistrettoPoint.spec.ts @@ -4,7 +4,7 @@ describe("Ristretto arithmetic", (): void => { for (let i = 0; i < 64; i++) { uniform[i] = i; } - let p = faPointFromUniform(uniform); + let p = faPointFromHash(uniform); expect(faPointValidate(p)).toBeTruthy(); p[0]++; expect(faPointValidate(p)).toBeFalsy(); @@ -14,7 +14,7 @@ describe("Ristretto arithmetic", (): void => { for (let i = 0; i < 64; i++) { uniform2[i] = ~i; } - let p2 = faPointFromUniform(uniform2); + let p2 = faPointFromHash(uniform2); expect(faPointValidate(p2)).toBeTruthy(); p2[0]++; expect(faPointValidate(p2)).toBeFalsy(); @@ -36,4 +36,4 @@ describe("Ristretto arithmetic", (): void => { let zero = faPointSub(p3, p); expect(faPointValidate(zero)).toBeFalsy(); }); -}); \ No newline at end of file +}); diff --git a/assemblyscript/examples/signatures/assembly/wasm-crypto/__tests__/hash.spec.ts b/assemblyscript/examples/signatures/assembly/wasm-crypto/__tests__/hash.spec.ts new file mode 100644 index 000000000..2a72c31a8 --- /dev/null +++ b/assemblyscript/examples/signatures/assembly/wasm-crypto/__tests__/hash.spec.ts @@ -0,0 +1,9 @@ +describe("hashing", (): void => { + it("should compute the hash of an empty string", (): void => { + let h = hashFinal(hashInit()); + let hex = bin2hex(h); + expect(hex).toBe( + "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" + ); + }); +}); diff --git a/assemblyscript/examples/signatures/assembly/wasm-crypto/__tests__/utils.spec.ts b/assemblyscript/examples/signatures/assembly/wasm-crypto/__tests__/utils.spec.ts index 087331158..1a0b62586 100644 --- a/assemblyscript/examples/signatures/assembly/wasm-crypto/__tests__/utils.spec.ts +++ b/assemblyscript/examples/signatures/assembly/wasm-crypto/__tests__/utils.spec.ts @@ -37,11 +37,11 @@ describe("bin2hex", (): void => { describe("hex2bin", (): void => { it("shoud decode from hex", (): void => { let hex = "00050a0f14191e23282d32373c41464b50555a5f64696e7378"; - let bin = hex2bin(hex)!; + let bin = hex2bin(hex); let ref = new Uint8Array(25); for (let i = 0; i < 25; i++) { ref[i] = i * 5; } - expect(equals(ref, bin)).toBeTruthy(); + expect(equals(ref, bin!)).toBeTruthy(); }) -}) \ No newline at end of file +}) diff --git a/assemblyscript/examples/signatures/assembly/wasm-crypto/crypto.ts b/assemblyscript/examples/signatures/assembly/wasm-crypto/crypto.ts index 18c067e20..b5ba3ed27 100644 --- a/assemblyscript/examples/signatures/assembly/wasm-crypto/crypto.ts +++ b/assemblyscript/examples/signatures/assembly/wasm-crypto/crypto.ts @@ -1,11 +1,12 @@ // tslint:disable-next-line:no-reference /// -import { LOAD, STORE } from 'internal/arraybuffer'; import { precompBase } from './precomp'; const RELEASE: bool = true; +export const U8ARRAY_ID = idof(); + // Helpers @inline function setU8(t: Uint8Array, s: Uint8Array, o: isize = 0): void { @@ -40,12 +41,12 @@ const RELEASE: bool = true; return (x & y) ^ (x & z) ^ (y & z); } -function load64(x: Uint8Array, offset: isize): u64 { - return LOAD(x.buffer, 0, offset); +function load64_be(x: Uint8Array, offset: isize): u64 { + return bswap(load(changetype(x.buffer) + offset)); } -function store64(x: Uint8Array, offset: isize, u: u64): void { - STORE(x.buffer, 0, u, offset); +function store64_be(x: Uint8Array, offset: isize, u: u64): void { + store(changetype(x.buffer) + offset, bswap(u)); } const K: u64[] = [ @@ -79,12 +80,12 @@ function _hashblocks(st: Uint8Array, m: Uint8Array, n: isize): isize { t: u64; for (let i = 0; i < 8; ++i) { - z[i] = a[i] = load64(st, i << 3); + z[i] = a[i] = load64_be(st, i << 3); } let pos = 0; while (n >= 128) { for (let i = 0; i < 16; ++i) { - w[i] = load64(m, (i << 3) + pos); + w[i] = load64_be(m, (i << 3) + pos); } for (let i = 0; i < 80; ++i) { for (let j = 0; j < 8; ++j) { @@ -110,7 +111,7 @@ function _hashblocks(st: Uint8Array, m: Uint8Array, n: isize): isize { n -= 128; } for (let i = 0; i < 8; ++i) { - store64(st, i << 3, z[i]); + store64_be(st, i << 3, z[i]); } return n; } @@ -138,14 +139,13 @@ function _hashInit(): Uint8Array { function _hashUpdate(st: Uint8Array, m: Uint8Array, n: isize, r: isize): isize { let w = st.subarray(64); - let pos = 0; let av = 128 - r; let tc = min(n, av); setU8(w, m.subarray(0, tc), r); r += tc; n -= tc; - pos += tc; + let pos = tc; if (r === 128) { _hashblocks(st, w, 128); r = 0; @@ -153,8 +153,8 @@ function _hashUpdate(st: Uint8Array, m: Uint8Array, n: isize, r: isize): isize { if (r === 0 && n > 0) { let rb = _hashblocks(st, m.subarray(pos), n); if (rb > 0) { - setU8(w, m.subarray(pos + n - rb), r); - r += rb; + setU8(w, m.subarray(pos + n - rb)); + r = rb; } } return r; @@ -168,7 +168,7 @@ function _hashFinal(st: Uint8Array, out: Uint8Array, t: isize, r: isize): void { x[r] = 128; r = 256 - (isize(r < 112) << 7); x[r - 9] = 0; - store64(x, r - 8, t << 3); + store64_be(x, r - 8, t << 3); _hashblocks(st, x, r); for (let i = 0; i < 64; ++i) { out[i] = st[i]; @@ -574,9 +574,9 @@ function fe25519Pack(o: Fe25519Packed, n: Fe25519): void { } function fe25519Unpack(o: Fe25519, n: Fe25519Packed): void { - let nb = n.buffer; + let nb = changetype(n.buffer); for (let i = 0; i < 16; ++i) { - o[i] = LOAD(nb, i); + o[i] = load(nb + 2 * i) as i64; } o[15] &= 0x7fff; } @@ -832,7 +832,7 @@ function scalarmult(p: Ge, s: ScalarPacked, q: Ge): void { } } -@inline function fe25519CopyA(r: Fe25519, a: Array): void { +@inline function fe25519CopyPrecomp(r: Fe25519, a: Array): void { r[0] = unchecked(a[0]); r[1] = unchecked(a[1]); r[2] = unchecked(a[2]); @@ -867,10 +867,9 @@ function scalarmultBase(p: Ge, s: ScalarPacked): void { for (let i = 0; i <= 255; ++i) { b = (s[(i >>> 3)] >>> (i as u8 & 7)) & 1; let precomp = precomp_base[i]; - - fe25519CopyA(q.x, precomp[0]); - fe25519CopyA(q.y, precomp[1]); - fe25519CopyA(q.t, precomp[2]); + fe25519CopyPrecomp(q.x, precomp[0]); + fe25519CopyPrecomp(q.y, precomp[1]); + fe25519CopyPrecomp(q.t, precomp[2]); geCopy(t, p); add(t, q); cmov(p, t, b); @@ -1124,9 +1123,9 @@ function ristrettoElligator(p: Ge, t: Fe25519): void { fe25519Mult(p.t, w0, w2); } -type Uniform = Uint8Array(64); +type Hash512 = Uint8Array(64); -function ristrettoFromUniform(s: GePacked, r: Uniform): void { +function ristrettoFromHash(s: GePacked, r: Hash512): void { let r0 = newFe25519(), r1 = newFe25519(); let p0 = newGe(), p1 = newGe(); @@ -1613,14 +1612,14 @@ function _signVerifyDetached(sig: Signature, m: Uint8Array, pk: GePacked): bool * @param m (partial) message */ @global export function hashUpdate(st: Uint8Array, m: Uint8Array): void { - let r = load64(st, 64 + 128); - let t = load64(st, 64 + 128 + 8); + let r = load64_be(st, 64 + 128); + let t = load64_be(st, 64 + 128 + 8); let n = m.length; t += n; r = _hashUpdate(st, m, n, r as isize); - store64(st, 64 + 128, r as u64); - store64(st, 64 + 128 + 8, t as u64); + store64_be(st, 64 + 128, r as u64); + store64_be(st, 64 + 128 + 8, t as u64); } /** @@ -1630,8 +1629,8 @@ function _signVerifyDetached(sig: Signature, m: Uint8Array, pk: GePacked): bool */ @global export function hashFinal(st: Uint8Array): Uint8Array { let h = new Uint8Array(HASH_BYTES); - let r = load64(st, 64 + 128); - let t = load64(st, 64 + 128 + 8); + let r = load64_be(st, 64 + 128); + let t = load64_be(st, 64 + 128 + 8); _hashFinal(st, h, t as isize, r as isize); @@ -2024,10 +2023,10 @@ function _signVerifyDetached(sig: Signature, m: Uint8Array, pk: GePacked): bool * @param r 512 bit hash * @returns Ristretto-compressed EC point */ -@global export function faPointFromUniform(r: Uint8Array): Uint8Array { +@global export function faPointFromHash(r: Uint8Array): Uint8Array { let p = newGePacked(); - ristrettoFromUniform(p, r); + ristrettoFromHash(p, r); return p; } diff --git a/assemblyscript/examples/signatures/package-lock.json b/assemblyscript/examples/signatures/package-lock.json new file mode 100644 index 000000000..a95025b20 --- /dev/null +++ b/assemblyscript/examples/signatures/package-lock.json @@ -0,0 +1,153 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=", + "dev": true + }, + "assemblyscript": { + "version": "github:AssemblyScript/assemblyscript#678593d7bd8ee9573eadbd43e3635e0bc0b8e15e", + "from": "github:AssemblyScript/assemblyscript", + "dev": true, + "requires": { + "@protobufjs/utf8": "^1.1.0", + "binaryen": "84.0.0-nightly.20190522", + "glob": "^7.1.4", + "long": "^4.0.0", + "opencollective-postinstall": "^2.0.0", + "source-map-support": "^0.5.12" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "binaryen": { + "version": "84.0.0-nightly.20190522", + "resolved": "https://registry.npmjs.org/binaryen/-/binaryen-84.0.0-nightly.20190522.tgz", + "integrity": "sha512-bxSPi3MOkFmK5W6VIlqxnOc1nYzpUCzT/tHz3C7sgbz7jTR2lOBlZnKStTJlBt018xeZK9/JpK/jXdduH7eQFg==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "opencollective-postinstall": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz", + "integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", + "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + } + } +} diff --git a/assemblyscript/examples/signatures/package.json b/assemblyscript/examples/signatures/package.json index dc4162078..548cf87de 100644 --- a/assemblyscript/examples/signatures/package.json +++ b/assemblyscript/examples/signatures/package.json @@ -1,13 +1,11 @@ { - "scripts": { - "asbuild:untouched": "asc assembly/index.ts -b build/untouched.wasm", - "asbuild:small": "asc assembly/index.ts -b build/small.wasm -t build/small.wat -O3z --importMemory", - "asbuild:optimized": "asc assembly/index.ts -b build/optimized.wasm -t build/optimized.wat -O3 --importMemory", - "asbuild": "npm run asbuild:optimized", - "test": "asp" - }, - "devDependencies": { - "as-pect": "github:jtenner/as-pect", - "assemblyscript": "github:AssemblyScript/assemblyscript" - } -} \ No newline at end of file + "scripts": { + "asbuild:untouched": "asc assembly/index.ts -b build/untouched.wasm --runtime stub --use abort=wasi_abort", + "asbuild:small": "asc assembly/index.ts -b build/small.wasm -t build/small.wat -O3z --runtime stub --use abort=wasi_abort", + "asbuild:optimized": "asc assembly/index.ts -b build/optimized.wasm -t build/optimized.wat -O3 --runtime stub --use abort=wasi_abort", + "asbuild": "npm run asbuild:optimized" + }, + "devDependencies": { + "assemblyscript": "github:AssemblyScript/assemblyscript" + } +} diff --git a/assemblyscript/modules/wasa/README.md b/assemblyscript/modules/wasa/README.md index 308cc5ddf..589c96df9 100644 --- a/assemblyscript/modules/wasa/README.md +++ b/assemblyscript/modules/wasa/README.md @@ -1,6 +1,6 @@ # An AssemblyScript layer for the WebAssembly System Interface (WASI) -[WASI](https://github.com/CraneStation/wasmtime-wasi/blob/wasi/docs/WASI-overview.md) is an API providing access to the external world to WebAssembly modules. +[WASI](https://wasi.dev) is an API providing access to the external world to WebAssembly modules. WASA is an effort to expose the WASI standard set of system calls to AssemblyScript. @@ -9,10 +9,9 @@ WASA is an effort to expose the WASI standard set of system calls to AssemblyScr Example usage of the `Console` and `Environ` classes: ```typescript -import "allocator/arena"; import { Console, Environ } from "../node_modules/wasa/assembly"; let env = new Environ(); -let home = env.get("HOME") as String; +let home = env.get("HOME")!; Console.log(home); -``` \ No newline at end of file +``` diff --git a/assemblyscript/modules/wasa/assembly/index.ts b/assemblyscript/modules/wasa/assembly/index.ts index 110b2f97f..a04fec277 100644 --- a/assemblyscript/modules/wasa/assembly/index.ts +++ b/assemblyscript/modules/wasa/assembly/index.ts @@ -1,5 +1,9 @@ -import { IO, Console, Random, Date, Process, EnvironEntry, Environ, CommandLine, Filesystem } from "./wasa"; +import { + WASAError, Descriptor, + Console, Random, Date, Process, EnvironEntry, Environ, CommandLine, FileSystem, FileStat +} from "./wasa"; export { - IO, Console, Random, Date, Process, EnvironEntry, Environ, CommandLine, Filesystem -} + WASAError, Descriptor, + Console, Random, Date, Process, EnvironEntry, Environ, CommandLine, FileSystem, FileStat +}; diff --git a/assemblyscript/modules/wasa/assembly/wasa.ts b/assemblyscript/modules/wasa/assembly/wasa.ts index b0d04990d..c38cbe89a 100644 --- a/assemblyscript/modules/wasa/assembly/wasa.ts +++ b/assemblyscript/modules/wasa/assembly/wasa.ts @@ -1,178 +1,348 @@ -// The entry file of your WebAssembly module. - import { - errno, - clockid, - fd_write, - fd_read, - random_get, - clock_time_get, + advice, + args_get, + args_sizes_get, clock_res_get, - proc_exit, - environ_sizes_get, + clock_time_get, + clockid, + dircookie, environ_get, - args_sizes_get, - args_get, - path_open, - oflags, - rights, - lookupflags, + environ_sizes_get, + errno, + fd_advise, + fd_allocate, + fd_close, + fd_datasync, + fd_fdstat_get, + fd_fdstat_set_flags, + fd_filestat_get, + fd_filestat_set_size, + fd_filestat_set_times, + fd_prestat_dir_name, + fd_read, + fd_readdir, + fd_seek, + fd_sync, + fd_tell, + fd_write, fd, fdflags, - fd_close, -} from 'bindings/wasi'; + fdstat, + whence, + filesize, + filestat, + filetype, + fstflags, + lookupflags, + oflags, + path_create_directory, + path_filestat_get, + path_link, + path_open, + path_rename, + path_remove_directory, + path_symlink, + path_unlink_file, + proc_exit, + random_get, + rights, +} from "bindings/wasi"; + +/** + * A WASA error + */ +export class WASAError extends Error { + constructor(message: string = "") { + super(message); + this.name = "WASAError"; + } +} -export type Descriptor = fd; +/** + * Portable information about a file + */ +export class FileStat { + file_type: filetype; + file_size: filesize; + access_time: f64; + modification_time: f64; + creation_time: f64; + + constructor(st_buf: usize) { + this.file_type = load(st_buf + 16); + this.file_size = load(st_buf + 24); + this.access_time = (load(st_buf + 32) as f64) / 1e9; + this.modification_time = (load(st_buf + 40) as f64) / 1e9; + this.creation_time = (load(st_buf + 48) as f64) / 1e9; + } +} -export class Filesystem { +/** + * A descriptor, that doesn't necessarily have to represent a file + */ +export class Descriptor { /** - * A simplified interface to open a file for read operations - * @param path Path - * @param dirfd Base directory descriptor (will be automatically set soon) + * An invalid file descriptor, that can represent an error */ - static openForRead(path: string, dirfd: Descriptor = 3): Descriptor | null { - let fd_lookup_flags = lookupflags.SYMLINK_FOLLOW; - let fd_oflags: oflags = 0; - let fd_rights = rights.FD_READ | rights.FD_SEEK | - rights.FD_TELL | rights.FD_FILESTAT_GET; - let fd_rights_inherited = fd_rights; - let fd_flags: fdflags = 0; - let path_utf8_len: usize = path.lengthUTF8 - 1; - let path_utf8 = path.toUTF8(); - let fd_buf = memory.allocate(sizeof()); - let res = path_open(dirfd as fd, fd_lookup_flags, path_utf8, path_utf8_len, - fd_oflags, fd_rights, fd_rights_inherited, fd_flags, fd_buf); - if (res != errno.SUCCESS) { - return null; + static Invalid(): Descriptor { return new Descriptor(-1); }; + + /** + * The standard input + */ + static Stdin(): Descriptor { return new Descriptor(0); }; + + /** + * The standard output + */ + static Stdout(): Descriptor { return new Descriptor(1); }; + + /** + * The standard error + */ + static Stderr(): Descriptor { return new Descriptor(2); }; + + /** + * Build a new descriptor from a raw WASI file descriptor + * @param rawfd a raw file descriptor + */ + constructor(readonly rawfd: fd) { } + + /** + * Hint at how the data accessible via the descriptor will be used + * @offset offset + * @len length + * @advice `advice.{NORMAL, SEQUENTIAL, RANDOM, WILLNEED, DONTNEED, NOREUSE}` + * @returns `true` on success, `false` on error + */ + advise(offset: u64, len: u64, advice: advice): bool { + return fd_advise(this.rawfd, offset, len, advice) === errno.SUCCESS; + } + + /** + * Preallocate data + * @param offset where to start preallocating data in the file + * @param len bytes to preallocate + * @returns `true` on success, `false` on error + */ + allocate(offset: u64, len: u64): bool { + return fd_allocate(this.rawfd, offset, len) === errno.SUCCESS; + } + + /** + * Wait for the data to be written + * @returns `true` on success, `false` on error + */ + fdatasync(): bool { + return fd_datasync(this.rawfd) === errno.SUCCESS; + } + + /** + * Wait for the data and metadata to be written + * @returns `true` on success, `false` on error + */ + fsync(): bool { + return fd_sync(this.rawfd) === errno.SUCCESS; + } + + /** + * Return the file type + */ + fileType(): filetype { + let st_buf = changetype(new ArrayBuffer(24)); + if (fd_fdstat_get(this.rawfd, changetype(st_buf)) !== errno.SUCCESS) { + throw new WASAError("Unable to get the file type"); } - let fd = load(fd_buf); - memory.free(fd_buf); + let file_type: u8 = load(st_buf); - return fd as Descriptor; + return file_type; } /** - * A simplified interface to open a file for write operations - * @param path Path - * @param dirfd Base directory descriptor (will be automatically set soon) - */ - static openForWrite(path: string, dirfd: Descriptor = 3): Descriptor | null { - let fd_lookup_flags = lookupflags.SYMLINK_FOLLOW; - let fd_oflags: oflags = oflags.CREAT; - let fd_rights = rights.FD_WRITE | rights.FD_SEEK | - rights.FD_TELL | rights.FD_FILESTAT_GET | rights.PATH_CREATE_FILE; - let fd_rights_inherited = fd_rights; - let fd_flags: fdflags = 0; - let path_utf8_len: usize = path.lengthUTF8 - 1; - let path_utf8 = path.toUTF8(); - let fd_buf = memory.allocate(sizeof()); - let res = path_open(dirfd as fd, fd_lookup_flags, path_utf8, path_utf8_len, - fd_oflags, fd_rights, fd_rights_inherited, fd_flags, fd_buf); - if (res != errno.SUCCESS) { - return null; + * Set WASI flags for that descriptor + * @params flags: one or more of `fdflags.{APPEND, DSYNC, NONBLOCK, RSYNC, SYNC}` + * @returns `true` on success, `false` on error + */ + setFlags(flags: fdflags): bool { + return fd_fdstat_set_flags(this.rawfd, flags) === errno.SUCCESS; + } + + /** + * Retrieve information about a descriptor + * @returns a `FileStat` object` + */ + stat(): FileStat { + let st_buf = changetype(new ArrayBuffer(56)); + if (fd_filestat_get(this.rawfd, changetype(st_buf)) !== errno.SUCCESS) { + throw new WASAError("Unable to get the file information"); } - let fd = load(fd_buf); - memory.free(fd_buf); + return new FileStat(st_buf); + } - return fd as Descriptor; + /** + * Change the size of a file + * @param size new size + * @returns `true` on success, `false` on error + */ + ftruncate(size: u64 = 0): bool { + return fd_filestat_set_size(this.rawfd, size) === errno.SUCCESS; + } + + /** + * Update the access time + * @ts timestamp in seconds + * @returns `true` on success, `false` on error + */ + fatime(ts: f64): bool { + return ( + fd_filestat_set_times(this.rawfd, (ts * 1e9) as u64, 0, fstflags.SET_ATIM) === + errno.SUCCESS + ); + } + + /** + * Update the modification time + * @ts timestamp in seconds + * @returns `true` on success, `false` on error + */ + fmtime(ts: f64): bool { + return ( + fd_filestat_set_times(this.rawfd, 0, (ts * 1e9) as u64, fstflags.SET_MTIM) === + errno.SUCCESS + ); + } + + /** + * Update both the access and the modification times + * @atime timestamp in seconds + * @mtime timestamp in seconds + * @returns `true` on success, `false` on error + */ + futimes(atime: f64, mtime: f64): bool { + return ( + fd_filestat_set_times(this.rawfd, (atime * 1e9) as u64, (mtime * 1e9) as u64, + fstflags.SET_ATIM | fstflags.SET_ATIM) === errno.SUCCESS + ); + } + + /** + * Update the timestamp of the object represented by the descriptor + * @returns `true` on success, `false` on error + */ + touch(): bool { + return ( + fd_filestat_set_times( + this.rawfd, + 0, + 0, + fstflags.SET_ATIM_NOW | fstflags.SET_MTIM_NOW + ) === errno.SUCCESS + ); + } + + /** + * Return the directory associated to that descriptor + */ + dirName(): String { + let path_max: usize = 4096; + for (; ;) { + let path_buf = changetype(new ArrayBuffer(path_max)); + let ret = fd_prestat_dir_name(this.rawfd, path_buf, path_max); + if (ret === errno.NAMETOOLONG) { + path_max = path_max * 2; + continue; + } + let path_len = 0; + while (load(path_buf + path_len) !== 0) { + path_len++; + } + return String.UTF8.decodeUnsafe(path_buf, path_len); + } } -} -export class IO { /** * Close a file descriptor - * @param fd file descriptor */ - static close(fd: Descriptor): void { - fd_close(fd); + close(): void { + fd_close(this.rawfd); } /** * Write data to a file descriptor - * @param fd file descriptor * @param data data */ - static write(fd: Descriptor, data: Array): void { + write(data: Array): void { let data_buf_len = data.length; - let data_buf = memory.allocate(data_buf_len); + let data_buf = changetype(new ArrayBuffer(data_buf_len)); for (let i = 0; i < data_buf_len; i++) { store(data_buf + i, unchecked(data[i])); } - let iov = memory.allocate(2 * sizeof()); + let iov = changetype(new ArrayBuffer(2 * sizeof())); store(iov, data_buf); store(iov + sizeof(), data_buf_len); - let written_ptr = memory.allocate(sizeof()); - fd_write(fd, iov, 1, written_ptr); - memory.free(written_ptr); - memory.free(data_buf); + + let written_ptr = changetype(new ArrayBuffer(sizeof())); + fd_write(this.rawfd, iov, 1, written_ptr); } /** - * Write a string to a file descriptor, after encoding it to UTF8 - * @param fd file descriptor - * @param s string - * @param newline `true` to add a newline after the string - */ - static writeString(fd: Descriptor, s: string, newline: bool = false): void { + * Write a string to a file descriptor, after encoding it to UTF8 + * @param s string + * @param newline `true` to add a newline after the string + */ + writeString(s: string, newline: bool = false): void { if (newline) { - this.writeStringLn(fd, s); + this.writeStringLn(s); return; } - let s_utf8_len: usize = s.lengthUTF8 - 1; - let s_utf8 = s.toUTF8(); - let iov = memory.allocate(2 * sizeof()); + let s_utf8_len: usize = String.UTF8.byteLength(s); + let s_utf8 = changetype(String.UTF8.encode(s)); + let iov = changetype(new ArrayBuffer(2 * sizeof())); store(iov, s_utf8); store(iov + sizeof(), s_utf8_len); - let written_ptr = memory.allocate(sizeof()); - fd_write(fd, iov, 1, written_ptr); - memory.free(written_ptr); - memory.free(s_utf8); + let written_ptr = changetype(new ArrayBuffer(sizeof())); + fd_write(this.rawfd, iov, 1, written_ptr); } /** * Write a string to a file descriptor, after encoding it to UTF8, with a newline - * @param fd file descriptor * @param s string */ - static writeStringLn(fd: Descriptor, s: string): void { - let s_utf8_len: usize = s.lengthUTF8 - 1; - let s_utf8 = s.toUTF8(); - let iov = memory.allocate(4 * sizeof()); + writeStringLn(s: string): void { + let s_utf8_len: usize = String.UTF8.byteLength(s); + let s_utf8 = changetype(String.UTF8.encode(s)); + let iov = changetype(new ArrayBuffer(4 * sizeof())); store(iov, s_utf8); store(iov + sizeof(), s_utf8_len); - let lf = memory.allocate(1); + let lf = changetype(new ArrayBuffer(1)); store(lf, 10); store(iov + sizeof() * 2, lf); store(iov + sizeof() * 3, 1); - let written_ptr = memory.allocate(sizeof()); - fd_write(fd, iov, 2, written_ptr); - memory.free(written_ptr); - memory.free(s_utf8); + let written_ptr = changetype(new ArrayBuffer(sizeof())); + fd_write(this.rawfd, iov, 2, written_ptr); } /** * Read data from a file descriptor - * @param fd file descriptor * @param data existing array to push data to * @param chunk_size chunk size (default: 4096) */ - static read(fd: Descriptor, data: Array = [], chunk_size: usize = 4096): Array | null { + read( + data: Array = [], + chunk_size: usize = 4096 + ): Array | null { let data_partial_len = chunk_size; - let data_partial = memory.allocate(data_partial_len); - let iov = memory.allocate(2 * sizeof()); + let data_partial = changetype(new ArrayBuffer(data_partial_len)); + let iov = changetype(new ArrayBuffer(2 * sizeof())); store(iov, data_partial); store(iov + sizeof(), data_partial_len); - let read_ptr = memory.allocate(sizeof()); - fd_read(fd, iov, 1, read_ptr); + let read_ptr = changetype(new ArrayBuffer(sizeof())); + fd_read(this.rawfd, iov, 1, read_ptr); let read = load(read_ptr); if (read > 0) { for (let i: usize = 0; i < read; i++) { data.push(load(data_partial + i)); } } - memory.free(read_ptr); - memory.free(data_partial); - if (read <= 0) { return null; } @@ -181,20 +351,22 @@ export class IO { /** * Read from a file descriptor until the end of the stream - * @param fd file descriptor * @param data existing array to push data to * @param chunk_size chunk size (default: 4096) */ - static readAll(fd: Descriptor, data: Array = [], chunk_size: usize = 4096): Array | null { + readAll( + data: Array = [], + chunk_size: usize = 4096 + ): Array | null { let data_partial_len = chunk_size; - let data_partial = memory.allocate(data_partial_len); - let iov = memory.allocate(2 * sizeof()); + let data_partial = changetype(new ArrayBuffer(data_partial_len)); + let iov = changetype(new ArrayBuffer(2 * sizeof())); store(iov, data_partial); store(iov + sizeof(), data_partial_len); - let read_ptr = memory.allocate(sizeof()); + let read_ptr = changetype(new ArrayBuffer(sizeof())); let read: usize = 0; for (; ;) { - if (fd_read(fd, iov, 1, read_ptr) != errno.SUCCESS) { + if (fd_read(this.rawfd, iov, 1, read_ptr) !== errno.SUCCESS) { break; } read = load(read_ptr); @@ -205,9 +377,6 @@ export class IO { data.push(load(data_partial + i)); } } - memory.free(read_ptr); - memory.free(data_partial); - if (read < 0) { return null; } @@ -216,25 +385,311 @@ export class IO { /** * Read an UTF8 string from a file descriptor, convert it to a native string - * @param fd file descriptor * @param chunk_size chunk size (default: 4096) */ - static readString(fd: Descriptor, chunk_size: usize = 4096): string | null { - let s_utf8_ = IO.readAll(fd); - if (s_utf8_ === null) { + readString(chunk_size: usize = 4096): string | null { + let s_utf8 = this.readAll(); + if (s_utf8 === null) { return null; } - let s_utf8 = s_utf8_!; let s_utf8_len = s_utf8.length; - let s_utf8_buf = memory.allocate(s_utf8_len); + let s_utf8_buf = changetype(new ArrayBuffer(s_utf8_len)); for (let i = 0; i < s_utf8_len; i++) { store(s_utf8_buf + i, s_utf8[i]); } - let s = String.fromUTF8(s_utf8_buf, s_utf8.length); - memory.free(s_utf8_buf); + let s = String.UTF8.decodeUnsafe(s_utf8_buf, s_utf8.length); return s; } + + /** + * Seek into a stream + * @off offset + * @w the position relative to which to set the offset of the file descriptor. + */ + seek(off: u64, w: whence): bool { + let fodder = changetype(new ArrayBuffer(8)); + let res = fd_seek(this.rawfd, off, w, fodder); + + return res === errno.SUCCESS; + } + + /** + * Return the current offset in the stream + * @returns offset + */ + tell(): u64 { + let buf_off = changetype(new ArrayBuffer(8)); + let res = fd_tell(this.rawfd, buf_off); + if (res !== errno.SUCCESS) { + abort(); + } + return load(buf_off); + } +} + +/** + * A class to access a filesystem + */ +export class FileSystem { + /** + * Open a path + * @path path + * @flags r, r+, w, wx, w+ or xw+ + * @returns a descriptor + */ + static open(path: string, flags: string = "r"): Descriptor | null { + let dirfd = this.dirfdForPath(path); + let fd_lookup_flags = lookupflags.SYMLINK_FOLLOW; + let fd_oflags: u16 = 0; + let fd_rights: u64 = 0; + if (flags === "r") { + fd_rights = rights.FD_READ | rights.FD_SEEK | rights.FD_TELL | rights.FD_FILESTAT_GET | rights.FD_READDIR; + } else if (flags === "r+") { + fd_rights = + rights.FD_READ | rights.FD_SEEK | rights.FD_TELL | rights.FD_FILESTAT_GET | rights.FD_WRITE | + rights.FD_SEEK | rights.FD_TELL | rights.FD_FILESTAT_GET | rights.PATH_CREATE_FILE; + } else if (flags === "w") { + fd_oflags = oflags.CREAT | oflags.TRUNC; + fd_rights = rights.FD_WRITE | rights.FD_SEEK | rights.FD_TELL | rights.FD_FILESTAT_GET | rights.PATH_CREATE_FILE; + } else if (flags === "wx") { + fd_oflags = oflags.CREAT | oflags.TRUNC | oflags.EXCL; + fd_rights = rights.FD_WRITE | rights.FD_SEEK | rights.FD_TELL | rights.FD_FILESTAT_GET | rights.PATH_CREATE_FILE; + } else if (flags === "w+") { + fd_oflags = oflags.CREAT | oflags.TRUNC; + fd_rights = + rights.FD_READ | rights.FD_SEEK | rights.FD_TELL | rights.FD_FILESTAT_GET | rights.FD_WRITE | + rights.FD_SEEK | rights.FD_TELL | rights.FD_FILESTAT_GET | rights.PATH_CREATE_FILE; + } else if (flags === "xw+") { + fd_oflags = oflags.CREAT | oflags.TRUNC | oflags.EXCL; + fd_rights = + rights.FD_READ | rights.FD_SEEK | rights.FD_TELL | rights.FD_FILESTAT_GET | rights.FD_WRITE | + rights.FD_SEEK | rights.FD_TELL | rights.FD_FILESTAT_GET | rights.PATH_CREATE_FILE; + } else { + return null; + } + let fd_rights_inherited = fd_rights; + let fd_flags: fdflags = 0; + let path_utf8_len: usize = String.UTF8.byteLength(path); + let path_utf8 = changetype(String.UTF8.encode(path)); + let fd_buf = changetype(new ArrayBuffer(sizeof())); + let res = path_open( + dirfd as fd, + fd_lookup_flags, + path_utf8, + path_utf8_len, + fd_oflags, + fd_rights, + fd_rights_inherited, + fd_flags, + fd_buf + ); + if (res !== errno.SUCCESS) { + return null; + } + let fd = load(fd_buf); + + return new Descriptor(fd); + } + + /** + * Create a new directory + * @path path + * @returns `true` on success, `false` on failure + */ + static mkdir(path: string): bool { + let dirfd = this.dirfdForPath(path); + let path_utf8_len: usize = String.UTF8.byteLength(path); + let path_utf8 = changetype(String.UTF8.encode(path)); + let res = path_create_directory(dirfd, path_utf8, path_utf8_len); + + return res === errno.SUCCESS; + } + + /** + * Check if a file exists at a given path + * @path path + * @returns `true` on success, `false` on failure + */ + static exists(path: string): bool { + let dirfd = this.dirfdForPath(path); + let path_utf8_len: usize = String.UTF8.byteLength(path); + let path_utf8 = changetype(String.UTF8.encode(path)); + let fd_lookup_flags = lookupflags.SYMLINK_FOLLOW; + let st_buf = changetype(new ArrayBuffer(56)); + let res = path_filestat_get(dirfd, fd_lookup_flags, path_utf8, path_utf8_len, + changetype(st_buf)); + + return res === errno.SUCCESS; + } + + /** + * Create a hard link + * @old_path old path + * @new_path new path + * @returns `true` on success, `false` on failure + */ + static link(old_path: string, new_path: string): bool { + let old_dirfd = this.dirfdForPath(old_path); + let old_path_utf8_len: usize = String.UTF8.byteLength(old_path); + let old_path_utf8 = changetype(String.UTF8.encode(old_path)); + let new_dirfd = this.dirfdForPath(new_path); + let new_path_utf8_len: usize = String.UTF8.byteLength(new_path); + let new_path_utf8 = changetype(String.UTF8.encode(new_path)); + let fd_lookup_flags = lookupflags.SYMLINK_FOLLOW; + let res = path_link(old_dirfd, fd_lookup_flags, old_path_utf8, old_path_utf8_len, + new_dirfd, new_path_utf8, new_path_utf8_len); + + return res === errno.SUCCESS; + } + + /** + * Create a symbolic link + * @old_path old path + * @new_path new path + * @returns `true` on success, `false` on failure + */ + static symlink(old_path: string, new_path: string): bool { + let old_path_utf8_len: usize = String.UTF8.byteLength(old_path); + let old_path_utf8 = changetype(String.UTF8.encode(old_path)); + let new_dirfd = this.dirfdForPath(new_path); + let new_path_utf8_len: usize = String.UTF8.byteLength(new_path); + let new_path_utf8 = changetype(String.UTF8.encode(new_path)); + let res = path_symlink(old_path_utf8, old_path_utf8_len, + new_dirfd, new_path_utf8, new_path_utf8_len); + + return res === errno.SUCCESS; + } + + /** + * Unlink a file + * @path path + * @returns `true` on success, `false` on failure + */ + static unlink(path: string): bool { + let dirfd = this.dirfdForPath(path); + let path_utf8_len: usize = String.UTF8.byteLength(path); + let path_utf8 = changetype(String.UTF8.encode(path)); + let res = path_unlink_file(dirfd, path_utf8, path_utf8_len); + + return res === errno.SUCCESS; + } + + /** + * Remove a directory + * @path path + * @returns `true` on success, `false` on failure + */ + static rmdir(path: string): bool { + let dirfd = this.dirfdForPath(path); + let path_utf8_len: usize = String.UTF8.byteLength(path); + let path_utf8 = changetype(String.UTF8.encode(path)); + let res = path_remove_directory(dirfd, path_utf8, path_utf8_len); + + return res === errno.SUCCESS; + } + + /** + * Retrieve information about a file + * @path path + * @returns a `FileStat` object + */ + static stat(path: string): FileStat { + let dirfd = this.dirfdForPath(path); + let path_utf8_len: usize = String.UTF8.byteLength(path); + let path_utf8 = changetype(String.UTF8.encode(path)); + let fd_lookup_flags = lookupflags.SYMLINK_FOLLOW; + let st_buf = changetype(new ArrayBuffer(56)); + if (path_filestat_get(dirfd, fd_lookup_flags, path_utf8, path_utf8_len, changetype(st_buf)) !== errno.SUCCESS) { + throw new WASAError("Unable to get the file information"); + } + return new FileStat(st_buf); + } + + /** + * Retrieve information about a file or a symbolic link + * @path path + * @returns a `FileStat` object + */ + static lstat(path: string): FileStat { + let dirfd = this.dirfdForPath(path); + let path_utf8_len: usize = String.UTF8.byteLength(path); + let path_utf8 = changetype(String.UTF8.encode(path)); + let fd_lookup_flags = 0; + let st_buf = changetype(new ArrayBuffer(56)); + if (path_filestat_get(dirfd, fd_lookup_flags, path_utf8, path_utf8_len, changetype(st_buf)) !== errno.SUCCESS) { + throw new WASAError("Unable to get the file information"); + } + return new FileStat(st_buf); + } + + /** + * Rename a file + * @old_path old path + * @new_path new path + * @returns `true` on success, `false` on failure + */ + static rename(old_path: string, new_path: string): bool { + let old_dirfd = this.dirfdForPath(old_path); + let old_path_utf8_len: usize = String.UTF8.byteLength(old_path); + let old_path_utf8 = changetype(String.UTF8.encode(old_path)); + let new_dirfd = this.dirfdForPath(new_path); + let new_path_utf8_len: usize = String.UTF8.byteLength(new_path); + let new_path_utf8 = changetype(String.UTF8.encode(new_path)); + let res = path_rename(old_dirfd, old_path_utf8, old_path_utf8_len, + new_dirfd, new_path_utf8, new_path_utf8_len); + + return res === errno.SUCCESS; + } + + /** + * Get the content of a directory + * @param path the directory path + * @returns An array of file names + */ + static readdir(path: string): Array | null { + let fd = this.open(path, "r"); + if (fd === null) { + return null; + } + let out = new Array(); + let buf = null; + let buf_size = 4096; + let buf_used_p = changetype(new ArrayBuffer(4)); + let buf_used = 0; + for (; ;) { + buf = __alloc(buf_size, 0); + if (fd_readdir(fd.rawfd, buf, buf_size, 0 as dircookie, buf_used_p) !== errno.SUCCESS) { + fd.close(); + } + buf_used = load(buf_used_p); + if (buf_used < buf_size) { + break; + } + buf_size <<= 1; + __free(buf); + } + let offset = 0; + while (offset < buf_used) { + offset += 16; + let name_len = load(buf + offset); + offset += 8; + if (offset + name_len > buf_used) { + return null; + } + let name = String.UTF8.decodeUnsafe(buf + offset, name_len); + out.push(name); + offset += name_len; + } + __free(buf); + fd.close(); + + return out; + } + + protected static dirfdForPath(path: string): fd { + return 3; + } } @global @@ -245,14 +700,14 @@ export class Console { * @param newline `false` to avoid inserting a newline after the string */ static write(s: string, newline: bool = true): void { - IO.writeString(1, s, newline); + Descriptor.Stdout().writeString(s, newline); } /** * Read an UTF8 string from the console, convert it to a native string */ static readAll(): string | null { - return IO.readString(0); + return Descriptor.Stdin().readString(); } /** @@ -268,7 +723,7 @@ export class Console { * @param newline `false` to avoid inserting a newline after the string */ static error(s: string, newline: bool = true): void { - IO.writeString(2, s, newline); + Descriptor.Stderr().writeString(s, newline); } } @@ -279,10 +734,10 @@ export class Random { */ static randomFill(buffer: ArrayBuffer): void { let len = buffer.byteLength; - let ptr = buffer.data; + let ptr = changetype(buffer); while (len > 0) { let chunk = min(len, 256); - if (random_get(ptr, chunk) != errno.SUCCESS) { + if (random_get(ptr, chunk) !== errno.SUCCESS) { abort(); } len -= chunk; @@ -306,20 +761,20 @@ export class Date { * Return the current timestamp, as a number of milliseconds since the epoch */ static now(): f64 { - let time_ptr = memory.allocate(8); + let time_ptr = changetype(new ArrayBuffer(8)); clock_time_get(clockid.REALTIME, 1000, time_ptr); let unix_ts = load(time_ptr); - memory.free(time_ptr); - return unix_ts as f64 / 1000.0; + + return (unix_ts as f64) / 1000.0; } } export class Performance { static now(): f64 { - let time_ptr = memory.allocate(8); + let time_ptr = changetype(new ArrayBuffer(8)); clock_res_get(clockid.MONOTONIC, time_ptr); let res_ts = load(time_ptr); - memory.free(time_ptr); + return res_ts as f64; } } @@ -330,12 +785,12 @@ export class Process { * @param status exit code */ static exit(status: u32): void { - proc_exit(status) + proc_exit(status); } } export class EnvironEntry { - constructor(readonly key: string, readonly value: string) { }; + constructor(readonly key: string, readonly value: string) { } } export class Environ { @@ -343,16 +798,20 @@ export class Environ { constructor() { this.env = []; - let count_and_size = memory.allocate(2 * sizeof()); + let count_and_size = changetype( + new ArrayBuffer(2 * sizeof()) + ); let ret = environ_sizes_get(count_and_size, count_and_size + 4); - if (ret != errno.SUCCESS) { + if (ret !== errno.SUCCESS) { abort(); } let count = load(count_and_size); let size = load(count_and_size + sizeof()); - let env_ptrs = memory.allocate((count + 1) * sizeof()); - let buf = memory.allocate(size); - if (environ_get(env_ptrs, buf) != errno.SUCCESS) { + let env_ptrs = changetype( + new ArrayBuffer((count + 1) * sizeof()) + ); + let buf = changetype(new ArrayBuffer(size)); + if (environ_get(env_ptrs, buf) !== errno.SUCCESS) { abort(); } for (let i: usize = 0; i < count; i++) { @@ -362,8 +821,6 @@ export class Environ { let value = env_ptr_split[1]; this.env.push(new EnvironEntry(key, value)); } - memory.free(buf); - memory.free(env_ptrs); } /** @@ -379,7 +836,7 @@ export class Environ { */ get(key: string): string | null { for (let i = 0, j = this.env.length; i < j; i++) { - if (this.env[i].key == key) { + if (this.env[i].key === key) { return this.env[i].value; } } @@ -388,20 +845,24 @@ export class Environ { } export class CommandLine { - args: Array; + args: Array; constructor() { this.args = []; - let count_and_size = memory.allocate(2 * sizeof()); + let count_and_size = changetype( + new ArrayBuffer(2 * sizeof()) + ); let ret = args_sizes_get(count_and_size, count_and_size + 4); - if (ret != errno.SUCCESS) { + if (ret !== errno.SUCCESS) { abort(); } let count = load(count_and_size); let size = load(count_and_size + sizeof()); - let env_ptrs = memory.allocate((count + 1) * sizeof()); - let buf = memory.allocate(size); - if (args_get(env_ptrs, buf) != errno.SUCCESS) { + let env_ptrs = changetype( + new ArrayBuffer((count + 1) * sizeof()) + ); + let buf = changetype(new ArrayBuffer(size)); + if (args_get(env_ptrs, buf) !== errno.SUCCESS) { abort(); } for (let i: usize = 0; i < count; i++) { @@ -409,14 +870,12 @@ export class CommandLine { let arg = StringUtils.fromCString(env_ptr); this.args.push(arg); } - memory.free(buf); - memory.free(env_ptrs); } /** * Return all the command-line arguments */ - all(): Array { + all(): Array { return this.args; } @@ -434,11 +893,28 @@ export class CommandLine { } class StringUtils { + /** + * Returns a native string from a zero-terminated C string + * @param cstring + * @returns native string + */ static fromCString(cstring: usize): string { let size = 0; - while (load(cstring + size) != 0) { + while (load(cstring + size) !== 0) { size++; } - return String.fromUTF8(cstring, size); + return String.UTF8.decodeUnsafe(cstring, size); } } + +@global +export function wasi_abort( + message: string | null = "", + fileName: string | null = "", + lineNumber: u32 = 0, + columnNumber: u32 = 0 +): void { + Console.error(fileName! + ":" + lineNumber.toString() + ":" + columnNumber.toString() + + ": error: " + message!); + proc_exit(255); +} diff --git a/assemblyscript/modules/wasa/bindings.json b/assemblyscript/modules/wasa/bindings.json index 9d037f3a2..1eec11f6b 100644 --- a/assemblyscript/modules/wasa/bindings.json +++ b/assemblyscript/modules/wasa/bindings.json @@ -1,19 +1,48 @@ { - "env": { - "abort": "abort" - }, - "wasi_unstable": { - "fd_write": "__wasi_fd_write", - "fd_read": "__wasi_fd_read", - "fd_close": "__wasi_fd_close", - "random_get": "__wasi_random_get", - "clock_time_get": "__wasi_clock_time_get", - "clock_res_get": "__wasi_clock_res_get", - "proc_exit": "__wasi_proc_exit", - "environ_sizes_get": "__wasi_environ_sizes_get", - "environ_get": "__wasi_environ_get", - "args_sizes_get": "__wasi_args_sizes_get", - "args_get": "__wasi_args_get", - "path_open": "__wasi_path_open" - } + "env": { + "abort": "abort" + }, + "wasi_unstable": { + "args_get": "__wasi_args_get", + "args_sizes_get": "__wasi_args_sizes_get", + "clock_res_get": "__wasi_clock_res_get", + "clock_time_get": "__wasi_clock_time_get", + "environ_get": "__wasi_environ_get", + "environ_sizes_get": "__wasi_environ_sizes_get", + "fd_advise": "__wasi_fd_advise", + "fd_allocate": "__wasi_fd_allocate", + "fd_close": "__wasi_fd_close", + "fd_datasync": "__wasi_fd_datasync", + "fd_fdstat_get": "__wasi_fd_fdstat_get", + "fd_fdstat_set_flags": "__wasi_fd_fdstat_set_flags", + "fd_fdstat_set_rights": "__wasi_fd_fdstat_set_rights", + "fd_filestat_get": "__wasi_fd_filestat_get", + "fd_filestat_set_size": "__wasi_fd_filestat_set_size", + "fd_filestat_set_times": "__wasi_fd_filestat_set_times", + "fd_pread": "__wasi_fd_pread", + "fd_prestat_dir_name": "__wasi_fd_prestat_dir_name", + "fd_prestat_get": "__wasi_fd_prestat_get", + "fd_pwrite": "__wasi_fd_pwrite", + "fd_read": "__wasi_fd_read", + "fd_readdir": "__wasi_fd_readdir", + "fd_renumber": "__wasi_fd_renumber", + "fd_seek": "__wasi_fd_seek", + "fd_sync": "__wasi_fd_sync", + "fd_tell": "__wasi_fd_tell", + "fd_write": "__wasi_fd_write", + "path_create_directory": "__wasi_path_create_directory", + "path_filestat_get": "__wasi_path_filestat_get", + "path_filestat_set_times": "__wasi_path_filestat_set_times", + "path_link": "__wasi_path_link", + "path_open": "__wasi_path_open", + "path_readlink": "__wasi_path_readlink", + "path_remove_directory": "__wasi_path_remove_directory", + "path_rename": "__wasi_path_rename", + "path_symlink": "__wasi_path_symlink", + "path_unlink_file": "__wasi_path_unlink_file", + "poll_oneoff": "__wasi_poll_oneoff", + "proc_exit": "__wasi_proc_exit", + "random_get": "__wasi_random_get", + "sched_yield": "__wasi_sched_yield" + } } diff --git a/assemblyscript/modules/wasa/package.json b/assemblyscript/modules/wasa/package.json index db5095b86..ad6184530 100644 --- a/assemblyscript/modules/wasa/package.json +++ b/assemblyscript/modules/wasa/package.json @@ -1,10 +1,9 @@ { "scripts": { - "asbuild:untouched": "asc assembly/index.ts assembly/wasa.ts -b build/untouched.wasm", - "asbuild:small": "asc assembly/index.ts assembly/wasa.ts -b build/small.wasm -t build/small.wat -O3z", - "asbuild:optimized": "asc assembly/index.ts assembly/wasa.ts -b build/optimized.wasm -t build/optimized.wat -O3", - "asbuild": "npm run asbuild:optimized", - "test": "asp" + "asbuild:untouched": "asc assembly/index.ts -b build/untouched.wasm -t build/untouched.wat --use abort=wasi_abort --debug", + "asbuild:small": "asc assembly/index.ts -b build/optimized.wasm -t build/optimized.wat --use abort=wasi_abort --validate -O3z ", + "asbuild:optimized": "asc assembly/index.ts -b build/optimized.wasm -t build/optimized.wat --use abort=wasi_abort --validate -O3", + "asbuild": "npm run asbuild:optimized" }, "devDependencies": { "as-pect": "github:jtenner/as-pect", From aeb100ada01feeaa7944e88856f5ecfe4db94e8d Mon Sep 17 00:00:00 2001 From: awortman-fastly <49215183+awortman-fastly@users.noreply.github.com> Date: Wed, 10 Jul 2019 14:09:01 -0700 Subject: [PATCH 261/512] Reorganize lucet module binary format (#242) * add a single struct, SerializedModule, for module data to be reachable from this also moves tables to be behind a pointer, so all tables can be reached from a single contiguous array --- lucet-analyze/src/main.rs | 467 ++++++++---------- lucet-module-data/src/lib.rs | 6 +- lucet-module-data/src/module.rs | 27 + lucet-module-data/src/module_data.rs | 2 + lucet-module-data/src/signature.rs | 30 +- lucet-module-data/src/tables.rs | 14 + .../lucet-runtime-internals/src/module.rs | 9 +- .../lucet-runtime-internals/src/module/dl.rs | 152 +++--- lucetc/src/compiler.rs | 56 +-- lucetc/src/decls.rs | 33 +- lucetc/src/function.rs | 19 +- lucetc/src/function_manifest.rs | 87 +--- lucetc/src/output.rs | 127 ++++- lucetc/src/table.rs | 67 ++- 14 files changed, 565 insertions(+), 531 deletions(-) create mode 100644 lucet-module-data/src/module.rs create mode 100644 lucet-module-data/src/tables.rs diff --git a/lucet-analyze/src/main.rs b/lucet-analyze/src/main.rs index 15ac64c1e..e46f0d703 100644 --- a/lucet-analyze/src/main.rs +++ b/lucet-analyze/src/main.rs @@ -1,6 +1,8 @@ #![deny(bare_trait_objects)] -use lucet_module_data::{Error, FunctionSpec, ModuleData, TrapManifest, TrapSite}; +use lucet_module_data::{ + FunctionSpec, Module, ModuleData, SerializedModule, TableElement, TrapManifest, TrapSite, +}; use byteorder::{LittleEndian, ReadBytesExt}; use colored::Colorize; @@ -9,6 +11,7 @@ use std::env; use std::fs::File; use std::io::Cursor; use std::io::Read; +use std::mem; #[derive(Debug)] struct ArtifactSummary<'a> { @@ -16,20 +19,14 @@ struct ArtifactSummary<'a> { elf: &'a elf::Elf<'a>, symbols: StandardSymbols, data_segments: Option, - module_data_bytes: Vec, - module_data: Option, Error>>, + serialized_module: Option, exported_functions: Vec<&'a str>, imported_symbols: Vec<&'a str>, } #[derive(Debug)] struct StandardSymbols { - wasm_data_segments: Option, - wasm_data_segments_len: Option, - lucet_module_data: Option, - lucet_module_data_len: Option, - lucet_function_manifest: Option, - lucet_function_manifest_len: Option, + lucet_module: Option, } #[derive(Debug)] @@ -49,17 +46,9 @@ impl<'a> ArtifactSummary<'a> { Self { buffer: buffer, elf: elf, - symbols: StandardSymbols { - wasm_data_segments: None, - wasm_data_segments_len: None, - lucet_module_data: None, - lucet_module_data_len: None, - lucet_function_manifest: None, - lucet_function_manifest_len: None, - }, + symbols: StandardSymbols { lucet_module: None }, data_segments: None, - module_data_bytes: vec![], - module_data: None, + serialized_module: None, exported_functions: Vec::new(), imported_symbols: Vec::new(), } @@ -91,16 +80,7 @@ impl<'a> ArtifactSummary<'a> { .expect("strtab entry"); match name { - "lucet_module_data" => self.symbols.lucet_module_data = Some(sym.clone()), - "lucet_module_data_len" => self.symbols.lucet_module_data_len = Some(sym.clone()), - "lucet_function_manifest" => { - self.symbols.lucet_function_manifest = Some(sym.clone()) - } - "lucet_function_manifest_len" => { - self.symbols.lucet_function_manifest_len = Some(sym.clone()) - } - "wasm_data_segments" => self.symbols.wasm_data_segments = Some(sym.clone()), - "wasm_data_segments_len" => self.symbols.wasm_data_segments_len = Some(sym.clone()), + "lucet_module" => self.symbols.lucet_module = Some(sym.clone()), _ => { if sym.st_bind() == elf::sym::STB_GLOBAL { if sym.is_function() { @@ -112,130 +92,25 @@ impl<'a> ArtifactSummary<'a> { } } } - } - - fn load_module_data(&self) -> Option, Error>> { - if let (Some(ref data_sym), Some(ref data_len_sym)) = ( - &self.symbols.lucet_module_data, - &self.symbols.lucet_module_data_len, - ) { - // TODO: validate that sym.st_size == 4 - let buffer = self - .read_memory(data_len_sym.st_value, data_len_sym.st_size) - .unwrap(); - let mut rdr = Cursor::new(buffer); - let data_len = rdr.read_u32::().unwrap(); - - if data_len as u64 != data_sym.st_size { - print!("{}", - format!( - "Module data reported size ({} bytes) does not match size declared for symbol ({} bytes).", - data_len, - data_sym.st_size - ).red().bold() - ); - println!(" Assuming the symbol is correct, wish me luck!"); - } - - let module_data_bytes = self - .read_memory(data_sym.st_value, data_sym.st_size) - .unwrap(); - Some(ModuleData::deserialize(module_data_bytes)) - } else { - None - } - } - fn load_function_manifest(&self) -> Option<&'a [FunctionSpec]> { - if let (Some(ref data_sym), Some(ref data_len_sym)) = ( - &self.symbols.lucet_function_manifest, - &self.symbols.lucet_function_manifest_len, - ) { - // TODO: validate that sym.st_size == 4 + self.serialized_module = self.symbols.lucet_module.as_ref().map(|module_sym| { let buffer = self - .read_memory(data_len_sym.st_value, data_len_sym.st_size) + .read_memory( + module_sym.st_value, + mem::size_of::() as u64, + ) .unwrap(); let mut rdr = Cursor::new(buffer); - let data_len = rdr.read_u32::().unwrap(); - - // cast up to u64 here to not overflow if data_len were an order of magnitude or so - // from u32::MAX - let expected_data_size = data_len as u64 * std::mem::size_of::() as u64; - if expected_data_size != data_sym.st_size { - println!("{}", - format!( - "Function manifest expected size ({} bytes) does not match size declared for symbol ({} bytes).", - expected_data_size, - data_sym.st_size - ).red().bold() - ); - println!(" Assuming the symbol is correct, wish me luck!"); - } - - let module_data_bytes = self - .read_memory(data_sym.st_value, data_sym.st_size) - .unwrap(); - Some(unsafe { - std::slice::from_raw_parts( - module_data_bytes.as_ptr() as *const FunctionSpec, - data_len as usize, - ) - }) - } else { - None - } - } - - fn parse_data_segments(&self) -> Option { - if let Some(ref data_sym) = self.symbols.wasm_data_segments { - if let Some(ref data_len_sym) = self.symbols.wasm_data_segments_len { - let mut data_segments = DataSegments { - segments: Vec::new(), - }; - - // TODO: validate that sym.st_size == 4 - let buffer = self - .read_memory(data_len_sym.st_value, data_len_sym.st_size) - .unwrap(); - let mut rdr = Cursor::new(buffer); - let data_len = rdr.read_u32::().unwrap(); - // TODO: validate that data_len == data_sym.st_size - - let buffer = self - .read_memory(data_sym.st_value, data_sym.st_size) - .unwrap(); - let mut rdr = Cursor::new(&buffer); - - while rdr.position() < data_len as u64 { - let _memory_index = rdr.read_u32::(); - // TODO: validate that memory_index == 0 - let offset = rdr.read_u32::().unwrap(); - let len = rdr.read_u32::().unwrap(); - - let pos = rdr.position() as usize; - let data_slice = &buffer[pos..pos + len as usize]; - - let mut data = Vec::new(); - data.extend_from_slice(data_slice); - - let pad = (8 - (pos + len as usize) % 8) % 8; - let new_pos = pos as u64 + len as u64 + pad as u64; - rdr.set_position(new_pos); - - data_segments.segments.push(DataSegment { - offset: offset, - len: len, - data: data, - }); - } - Some(data_segments) - } else { - None + SerializedModule { + module_data_ptr: rdr.read_u64::().unwrap(), + module_data_len: rdr.read_u64::().unwrap(), + tables_ptr: rdr.read_u64::().unwrap(), + tables_len: rdr.read_u64::().unwrap(), + function_manifest_ptr: rdr.read_u64::().unwrap(), + function_manifest_len: rdr.read_u64::().unwrap(), } - } else { - None - } + }); } fn get_func_name_for_addr(&self, addr: u64) -> Option<&str> { @@ -308,10 +183,45 @@ fn parse_trap_manifest<'a>( } } -fn summarize_module_data<'a, 'b: 'a>( +fn load_module<'b, 'a: 'b>( summary: &'a ArtifactSummary<'a>, - module_data: ModuleData<'b>, -) { + serialized_module: &SerializedModule, + tables: &'b [&[TableElement]], +) -> Module<'b> { + let module_data_bytes = summary + .read_memory( + serialized_module.module_data_ptr, + serialized_module.module_data_len, + ) + .unwrap(); + + let module_data = + ModuleData::deserialize(module_data_bytes).expect("ModuleData can be deserialized"); + + let function_manifest_bytes = summary + .read_memory( + serialized_module.function_manifest_ptr, + serialized_module.function_manifest_len, + ) + .unwrap(); + let function_manifest = unsafe { + std::slice::from_raw_parts( + function_manifest_bytes.as_ptr() as *const FunctionSpec, + serialized_module.function_manifest_len as usize, + ) + }; + Module { + module_data, + tables, + function_manifest, + } +} + +fn summarize_module<'a, 'b: 'a>(summary: &'a ArtifactSummary<'a>, module: &Module<'b>) { + let module_data = &module.module_data; + let tables = module.tables; + let function_manifest = module.function_manifest; + println!(" Heap Specification:"); if let Some(heap_spec) = module_data.heap_spec() { println!(" {:9}: {} bytes", "Reserved", heap_spec.reserved_size); @@ -323,7 +233,7 @@ fn summarize_module_data<'a, 'b: 'a>( println!(" {:9}: None", "Maximum"); } } else { - println!(" {}", "MISSING".red().bold()); + println!(" {}", "MISSING".red().bold()); } println!(""); @@ -365,6 +275,16 @@ fn summarize_module_data<'a, 'b: 'a>( println!(" {}", "MISSING!".red().bold()); } + println!(""); + println!("Tables:"); + if tables.len() == 0 { + println!(" No tables."); + } else { + for (i, table) in tables.iter().enumerate() { + println!(" Table {}: {:?}", i, table); + } + } + println!(""); println!("Signatures:"); for (i, s) in module_data.signatures().iter().enumerate() { @@ -373,88 +293,84 @@ fn summarize_module_data<'a, 'b: 'a>( println!(""); println!("Functions:"); - if let Some(function_manifest) = summary.load_function_manifest() { - if function_manifest.len() != module_data.function_info().len() { - println!( - " {} function manifest and function info have diverging function counts", - "lucetc bug:".red().bold() - ); + if function_manifest.len() != module_data.function_info().len() { + println!( + " {} function manifest and function info have diverging function counts", + "lucetc bug:".red().bold() + ); + println!( + " function_manifest length : {}", + function_manifest.len() + ); + println!( + " module data function count : {}", + module_data.function_info().len() + ); + println!(" Will attempt to display information about functions anyway, but trap/code information may be misaligned with symbols and signatures."); + } + + for (i, f) in function_manifest.iter().enumerate() { + let header_name = summary.get_func_name_for_addr(f.ptr().as_usize() as u64); + + if i >= module_data.function_info().len() { + // This is one form of the above-mentioned bug case + // Half the function information is missing, so just report the issue and continue. println!( - " function_manifest length : {}", - function_manifest.len() + " Function {} {}", + i, + "is missing the module data part of its declaration".red() ); + match header_name { + Some(name) => { + println!(" ELF header name: {}", name); + } + None => { + println!(" No corresponding ELF symbol."); + } + }; + break; + } + + let colorize_name = |x: Option<&str>| match x { + Some(name) => name.green(), + None => "None".red().bold(), + }; + + let fn_meta = &module_data.function_info()[i]; + println!(" Function {} (name: {}):", i, colorize_name(fn_meta.name)); + if fn_meta.name != header_name { println!( - " module data function count : {}", - module_data.function_info().len() + " Name {} with name declared in ELF headers: {}", + "DISAGREES".red().bold(), + colorize_name(header_name) ); - println!(" Will attempt to display information about functions anyway, but trap/code information may be misaligned with symbols and signatures."); } - for (i, f) in function_manifest.iter().enumerate() { - let header_name = summary.get_func_name_for_addr(f.ptr().as_usize() as u64); + println!( + " Signature (index {}): {}", + fn_meta.signature.as_u32() as usize, + module_data.signatures()[fn_meta.signature.as_u32() as usize] + ); - if i >= module_data.function_info().len() { - // This is one form of the above-mentioned bug case - // Half the function information is missing, so just report the issue and continue. - println!( - " Function {} {}", - i, - "is missing the module data part of its declaration".red() - ); - match header_name { - Some(name) => { - println!(" ELF header name: {}", name); - } - None => { - println!(" No corresponding ELF symbol."); - } - }; - break; - } - - let colorize_name = |x: Option<&str>| match x { - Some(name) => name.green(), - None => "None".red().bold(), - }; + println!(" Start: {:#010x}", f.ptr().as_usize()); + println!(" Code length: {} bytes", f.code_len()); + if let Some(trap_manifest) = parse_trap_manifest(&summary, f) { + let trap_count = trap_manifest.traps.len(); - let fn_meta = &module_data.function_info()[i]; - println!(" Function {} (name: {}):", i, colorize_name(fn_meta.name)); - if fn_meta.name != header_name { + println!(" Trap information:"); + if trap_count > 0 { println!( - " Name {} with name declared in ELF headers: {}", - "DISAGREES".red().bold(), - colorize_name(header_name) + " {} {} ...", + trap_manifest.traps.len(), + if trap_count == 1 { "trap" } else { "traps" }, ); - } - - println!( - " Signature (index {}): {}", - fn_meta.signature.as_u32() as usize, - module_data.signatures()[fn_meta.signature.as_u32() as usize] - ); - - println!(" Start: {:#010x}", f.ptr().as_usize()); - println!(" Code length: {} bytes", f.code_len()); - if let Some(trap_manifest) = parse_trap_manifest(&summary, f) { - let trap_count = trap_manifest.traps.len(); - - println!(" Trap information:"); - if trap_count > 0 { - println!( - " {} {} ...", - trap_manifest.traps.len(), - if trap_count == 1 { "trap" } else { "traps" }, - ); - for trap in trap_manifest.traps { - println!(" $+{:#06x}: {:?}", trap.offset, trap.code); - } - } else { - println!(" No traps for this function"); + for trap in trap_manifest.traps { + println!(" $+{:#06x}: {:?}", trap.offset, trap.code); } + } else { + println!(" No traps for this function"); } } - } else { - println!(" {}", "MISSING!".red().bold()); } println!(""); @@ -536,52 +452,67 @@ fn print_summary(summary: ArtifactSummary<'_>) { println!("Required Symbols:"); println!( " {:30}: {}", - "lucet_module_data", - exists_to_str(&summary.symbols.lucet_module_data) - ); - println!( - " {:30}: {}", - "lucet_module_data_len", - exists_to_str(&summary.symbols.lucet_module_data_len) - ); - println!( - " {:30}: {}", - "lucet_function_manifest", - exists_to_str(&summary.symbols.lucet_function_manifest) + "lucet_module", + exists_to_str(&summary.symbols.lucet_module) ); - println!( - " {:30}: {}", - "lucet_function_manifest_len", - exists_to_str(&summary.symbols.lucet_function_manifest_len) - ); - println!( - " {:30}: {}", - "wasm_data_segments", - exists_to_str(&summary.symbols.wasm_data_segments) - ); - println!( - " {:30}: {}", - "wasm_data_segments_len", - exists_to_str(&summary.symbols.wasm_data_segments_len) - ); - - println!("\nModule data:"); - match summary.load_module_data() { - Some(Ok(module_data)) => { - summarize_module_data(&summary, module_data); - } - Some(Err(e)) => { - println!(" ERROR: {}", e.to_string().red().bold()); - } - None => { - println!(" MISSING SYMBOL:"); - if summary.symbols.lucet_module_data.is_none() { - println!(" - {}", "lucet_module_data".red().bold()); - } - if summary.symbols.lucet_module_data_len.is_none() { - println!(" - {}", "lucet_module_data_len".red().bold()); - } + if let Some(ref serialized_module) = summary.serialized_module { + println!("Native module components:"); + println!( + " {:30}: {}", + "module_data_ptr", + ptr_to_str(serialized_module.module_data_ptr) + ); + println!( + " {:30}: {}", + "module_data_len", serialized_module.module_data_len + ); + println!( + " {:30}: {}", + "tables_ptr", + ptr_to_str(serialized_module.tables_ptr) + ); + println!(" {:30}: {}", "tables_len", serialized_module.tables_len); + println!( + " {:30}: {}", + "function_manifest_ptr", + ptr_to_str(serialized_module.function_manifest_ptr) + ); + println!( + " {:30}: {}", + "function_manifest_len", serialized_module.function_manifest_len + ); + + let tables = unsafe { + std::slice::from_raw_parts( + serialized_module.tables_ptr as *const &[TableElement], + serialized_module.tables_len as usize, + ) + }; + let mut reconstructed_tables = Vec::new(); + // same situation as trap tables - these slices are valid as if the module was + // dlopen'd, but we jsut read it as a flat file. So read through the ELF view and use + // pointers to that for the real slices. + + for table in tables { + let table_bytes = summary + .read_memory( + table.as_ptr() as usize as u64, + (table.len() * mem::size_of::()) as u64, + ) + .unwrap(); + reconstructed_tables.push(unsafe { + std::slice::from_raw_parts( + table_bytes.as_ptr() as *const TableElement, + table.len() as usize, + ) + }); } + + let module = load_module(&summary, serialized_module, &reconstructed_tables); + println!("\nModule:"); + summarize_module(&summary, &module); + } else { + println!("The symbol `lucet_module` is {}, so lucet-analyze cannot look at most of the interesting parts.", "MISSING".red().bold()); } println!(""); @@ -599,6 +530,14 @@ fn print_summary(summary: ArtifactSummary<'_>) { } } +fn ptr_to_str(p: u64) -> colored::ColoredString { + if p != 0 { + format!("exists; address: {:#x}", p).green() + } else { + "MISSING!".red().bold() + } +} + fn exists_to_str(p: &Option) -> colored::ColoredString { return match p { Some(_) => "exists".green(), diff --git a/lucet-module-data/src/lib.rs b/lucet-module-data/src/lib.rs index 0b586318c..ee1543b92 100644 --- a/lucet-module-data/src/lib.rs +++ b/lucet-module-data/src/lib.rs @@ -10,8 +10,10 @@ mod error; mod functions; mod globals; mod linear_memory; +mod module; mod module_data; mod signature; +mod tables; mod traps; mod types; @@ -22,8 +24,10 @@ pub use crate::functions::{ }; pub use crate::globals::{Global, GlobalDef, GlobalSpec, GlobalValue}; pub use crate::linear_memory::{HeapSpec, LinearMemorySpec, SparseData}; -pub use crate::module_data::ModuleData; +pub use crate::module::{Module, SerializedModule, LUCET_MODULE_SYM}; +pub use crate::module_data::{ModuleData, MODULE_DATA_SYM}; pub use crate::signature::{ModuleSignature, PublicKey}; +pub use crate::tables::TableElement; pub use crate::traps::{TrapCode, TrapManifest, TrapSite}; pub use crate::types::{Signature, ValueType}; diff --git a/lucet-module-data/src/module.rs b/lucet-module-data/src/module.rs new file mode 100644 index 000000000..793a94382 --- /dev/null +++ b/lucet-module-data/src/module.rs @@ -0,0 +1,27 @@ +use crate::functions::FunctionSpec; +use crate::module_data::ModuleData; +use crate::tables::TableElement; + +pub const LUCET_MODULE_SYM: &str = "lucet_module"; + +/// Module is the exposed structure that contains all the data backing a Lucet-compiled object. +#[derive(Debug)] +pub struct Module<'a> { + pub module_data: ModuleData<'a>, + pub tables: &'a [&'a [TableElement]], + pub function_manifest: &'a [FunctionSpec], +} + +/// SerializedModule is a serialization-friendly form of Module, in that the `module_data_*` fields +/// here refer to a serialized `ModuleData`, while `tables_*` and `function_manifest_*` refer to +/// the actual tables and function manifest written in the binary. +#[repr(C)] +#[derive(Debug)] +pub struct SerializedModule { + pub module_data_ptr: u64, + pub module_data_len: u64, + pub tables_ptr: u64, + pub tables_len: u64, + pub function_manifest_ptr: u64, + pub function_manifest_len: u64, +} diff --git a/lucet-module-data/src/module_data.rs b/lucet-module-data/src/module_data.rs index 9ec2b8317..9baaeeeb7 100644 --- a/lucet-module-data/src/module_data.rs +++ b/lucet-module-data/src/module_data.rs @@ -10,6 +10,8 @@ use crate::{ use minisign::SignatureBones; use serde::{Deserialize, Serialize}; +pub const MODULE_DATA_SYM: &str = "lucet_module_data"; + /// The metadata (and some data) for a Lucet module. /// /// The lifetime parameter exists to support zero-copy deserialization for the `&str` and `&[u8]` diff --git a/lucet-module-data/src/signature.rs b/lucet-module-data/src/signature.rs index 99a1e6df9..5e6e52b4f 100644 --- a/lucet-module-data/src/signature.rs +++ b/lucet-module-data/src/signature.rs @@ -1,4 +1,6 @@ use crate::error::Error::{self, IOError, ModuleSignatureError}; +use crate::module::LUCET_MODULE_SYM; +use crate::module_data::MODULE_DATA_SYM; use crate::ModuleData; use byteorder::{ByteOrder, LittleEndian}; pub use minisign::{PublicKey, SecretKey}; @@ -60,6 +62,7 @@ impl ModuleSignature { } } +#[allow(dead_code)] struct SymbolData { offset: usize, len: usize, @@ -76,25 +79,28 @@ impl RawModuleAndData { let mut obj_bin: Vec = Vec::new(); File::open(&path)?.read_to_end(&mut obj_bin)?; - let module_data_symbol_data = Self::symbol_data(&obj_bin, "lucet_module_data", true)? - .ok_or(io::Error::new( + let native_data_symbol_data = + Self::symbol_data(&obj_bin, LUCET_MODULE_SYM, true)?.ok_or(io::Error::new( io::ErrorKind::InvalidInput, - "module data not found", + format!("`{}` symbol not present", LUCET_MODULE_SYM), ))?; - let module_data_len_symbol_data = - Self::symbol_data(&obj_bin, "lucet_module_data_len", true)?.ok_or(io::Error::new( + + // While `module_data` is the first field of the `SerializedModule` that `lucet_module` points + // to, it is a virtual address, not a file offset. The translation is somewhat tricky at + // the moment, so just look at the corresponding `lucet_module_data` symbol for now. + let module_data_symbol_data = + Self::symbol_data(&obj_bin, MODULE_DATA_SYM, true)?.ok_or(io::Error::new( io::ErrorKind::InvalidInput, - "module length not found", + format!("`{}` symbol not present", MODULE_DATA_SYM), ))?; - assert_eq!(module_data_len_symbol_data.len, 4); - assert_eq!( - LittleEndian::read_u32(&obj_bin[module_data_len_symbol_data.offset..]) as usize, - module_data_symbol_data.len - ); + + let module_data_len = + LittleEndian::read_u64(&obj_bin[(native_data_symbol_data.offset + 8)..]) as usize; + Ok(RawModuleAndData { obj_bin, module_data_offset: module_data_symbol_data.offset, - module_data_len: module_data_symbol_data.len, + module_data_len: module_data_len, }) } diff --git a/lucet-module-data/src/tables.rs b/lucet-module-data/src/tables.rs new file mode 100644 index 000000000..b8ecb0d0f --- /dev/null +++ b/lucet-module-data/src/tables.rs @@ -0,0 +1,14 @@ +use crate::functions::FunctionPointer; + +#[repr(C)] +#[derive(Clone, Debug)] +pub struct TableElement { + ty: u64, + func: u64, +} + +impl TableElement { + pub fn function_pointer(&self) -> FunctionPointer { + FunctionPointer::from_usize(self.func as usize) + } +} diff --git a/lucet-runtime/lucet-runtime-internals/src/module.rs b/lucet-runtime/lucet-runtime-internals/src/module.rs index fc1607469..4f273c93e 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module.rs @@ -6,20 +6,13 @@ pub use crate::module::dl::DlModule; pub use crate::module::mock::{MockExportBuilder, MockModuleBuilder}; pub use lucet_module_data::{ FunctionHandle, FunctionIndex, FunctionPointer, FunctionSpec, Global, GlobalSpec, GlobalValue, - HeapSpec, Signature, TrapCode, TrapManifest, ValueType, + HeapSpec, Signature, TableElement, TrapCode, TrapManifest, ValueType, }; use crate::alloc::Limits; use crate::error::Error; use libc::c_void; -#[repr(C)] -#[derive(Clone, Debug)] -pub struct TableElement { - ty: u64, - rf: u64, -} - /// Details about a program address. /// /// It is possible to determine whether an address lies within the module code if the module is diff --git a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs index 6923aa51c..948fc0cc5 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs @@ -1,10 +1,10 @@ use crate::error::Error; use crate::module::{AddrDetails, GlobalSpec, HeapSpec, Module, ModuleInternal, TableElement}; use libc::c_void; -use libloading::{Library, Symbol}; +use libloading::Library; use lucet_module_data::{ FunctionHandle, FunctionIndex, FunctionPointer, FunctionSpec, ModuleData, ModuleSignature, - PublicKey, Signature, + PublicKey, SerializedModule, Signature, LUCET_MODULE_SYM, }; use std::ffi::CStr; use std::mem::MaybeUninit; @@ -21,9 +21,7 @@ pub struct DlModule { fbase: *const c_void, /// Metadata decoded from inside the module - module_data: ModuleData<'static>, - - function_manifest: &'static [FunctionSpec], + module: lucet_module_data::Module<'static>, } // for the one raw pointer only @@ -53,20 +51,15 @@ impl DlModule { let abs_so_path = so_path.as_ref().canonicalize().map_err(Error::DlError)?; let lib = Library::new(abs_so_path.as_os_str()).map_err(Error::DlError)?; - let module_data_ptr = unsafe { - lib.get::<*const u8>(b"lucet_module_data").map_err(|e| { - lucet_incorrect_module!("error loading required symbol `lucet_module_data`: {}", e) - })? + let serialized_module_ptr = unsafe { + lib.get::<*const SerializedModule>(LUCET_MODULE_SYM.as_bytes()) + .map_err(|e| { + lucet_incorrect_module!("error loading required symbol `lucet_module`: {}", e) + })? }; - let module_data_len = unsafe { - lib.get::(b"lucet_module_data_len").map_err(|e| { - lucet_incorrect_module!( - "error loading required symbol `lucet_module_data_len`: {}", - e - ) - })? - }; + let serialized_module: &SerializedModule = + unsafe { serialized_module_ptr.as_ref().unwrap() }; // Deserialize the slice into ModuleData, which will hold refs into the loaded // shared object file in `module_data_slice`. Both of these get a 'static lifetime because @@ -75,8 +68,12 @@ impl DlModule { // // The exposed lifetime of ModuleData will be the same as the lifetime of the // dynamically loaded library. This makes the interface safe. - let module_data_slice: &'static [u8] = - unsafe { slice::from_raw_parts(*module_data_ptr, *module_data_len) }; + let module_data_slice: &'static [u8] = unsafe { + slice::from_raw_parts( + serialized_module.module_data_ptr as *const u8, + serialized_module.module_data_len as usize, + ) + }; let module_data = ModuleData::deserialize(module_data_slice)?; // If a public key has been provided, verify the module signature @@ -85,63 +82,43 @@ impl DlModule { ModuleSignature::verify(so_path, &pk, &module_data)?; } - let fbase = if let Some(dli) = dladdr(*module_data_ptr as *const c_void) { + let fbase = if let Some(dli) = + dladdr(serialized_module as *const SerializedModule as *const c_void) + { dli.dli_fbase } else { std::ptr::null() }; - let function_manifest = unsafe { - let manifest_len_ptr = lib.get::<*const u32>(b"lucet_function_manifest_len"); - let manifest_ptr = lib.get::<*const FunctionSpec>(b"lucet_function_manifest"); - - match (manifest_ptr, manifest_len_ptr) { - (Ok(ptr), Ok(len_ptr)) => { - let manifest_len = len_ptr.as_ref().ok_or(lucet_incorrect_module!( - "`lucet_function_manifest_len` is defined but null" - ))?; - let manifest = ptr.as_ref().ok_or(lucet_incorrect_module!( - "`lucet_function_manifest` is defined but null" - ))?; + if serialized_module.tables_len > std::u32::MAX as u64 { + lucet_incorrect_module!("table segment too long: {}", serialized_module.tables_len); + } + let tables: &'static [&'static [TableElement]] = unsafe { + from_raw_parts( + serialized_module.tables_ptr as *const &[TableElement], + serialized_module.tables_len as usize, + ) + }; - from_raw_parts(manifest, *manifest_len as usize) - } - (Err(ptr_err), Err(len_err)) => { - if is_undefined_symbol(&ptr_err) && is_undefined_symbol(&len_err) { - &[] - } else { - // This is an unfortunate situation. Both attempts to look up symbols - // failed, but at least one is not due to an undefined symbol. - if !is_undefined_symbol(&ptr_err) { - // This returns `ptr_err` (rather than `len_err` or some mix) because - // of the following hunch: if both failed, and neither are undefined - // symbols, they are probably the same error. - return Err(Error::DlError(ptr_err)); - } else { - return Err(Error::DlError(len_err)); - } - } - } - (Ok(_), Err(e)) => { - return Err(lucet_incorrect_module!( - "error loading symbol `lucet_function_manifest_len`: {}", - e - )); - } - (Err(e), Ok(_)) => { - return Err(lucet_incorrect_module!( - "error loading symbol `lucet_function_manifest`: {}", - e - )); - } + let function_manifest = if serialized_module.function_manifest_ptr != 0 { + unsafe { + from_raw_parts( + serialized_module.function_manifest_ptr as *const FunctionSpec, + serialized_module.function_manifest_len as usize, + ) } + } else { + &[] }; Ok(Arc::new(DlModule { lib, fbase, - module_data, - function_manifest, + module: lucet_module_data::Module { + module_data, + tables, + function_manifest, + }, })) } } @@ -150,15 +127,15 @@ impl Module for DlModule {} impl ModuleInternal for DlModule { fn heap_spec(&self) -> Option<&HeapSpec> { - self.module_data.heap_spec() + self.module.module_data.heap_spec() } fn globals(&self) -> &[GlobalSpec<'_>] { - self.module_data.globals_spec() + self.module.module_data.globals_spec() } fn get_sparse_page_data(&self, page: usize) -> Option<&[u8]> { - if let Some(ref sparse_data) = self.module_data.sparse_data() { + if let Some(ref sparse_data) = self.module.module_data.sparse_data() { *sparse_data.get_page(page) } else { None @@ -166,29 +143,23 @@ impl ModuleInternal for DlModule { } fn sparse_page_data_len(&self) -> usize { - self.module_data.sparse_data().map(|d| d.len()).unwrap_or(0) + self.module + .module_data + .sparse_data() + .map(|d| d.len()) + .unwrap_or(0) } fn table_elements(&self) -> Result<&[TableElement], Error> { - let p_table_segment: Symbol<'_, *const TableElement> = unsafe { - self.lib.get(b"guest_table_0").map_err(|e| { - lucet_incorrect_module!("error loading required symbol `guest_table_0`: {}", e) - })? - }; - let p_table_segment_len: Symbol<'_, *const usize> = unsafe { - self.lib.get(b"guest_table_0_len").map_err(|e| { - lucet_incorrect_module!("error loading required symbol `guest_table_0_len`: {}", e) - })? - }; - let len = unsafe { **p_table_segment_len }; - if len > std::u32::MAX as usize { - lucet_incorrect_module!("table segment too long: {}", len); + match self.module.tables.get(0) { + Some(table) => Ok(table), + None => Err(lucet_incorrect_module!("table 0 is not present")), } - Ok(unsafe { from_raw_parts(*p_table_segment, **p_table_segment_len as usize) }) } fn get_export_func(&self, sym: &str) -> Result { - self.module_data + self.module + .module_data .get_export_func_id(sym) .ok_or_else(|| Error::SymbolNotFound(sym.to_string())) .map(|id| { @@ -202,9 +173,9 @@ impl ModuleInternal for DlModule { return Err(Error::FuncNotFound(table_id, func_id)); } let table = self.table_elements()?; - let func: FunctionPointer = table + let func = table .get(func_id as usize) - .map(|element| FunctionPointer::from_usize(element.rf as usize)) + .map(|element| element.function_pointer()) .ok_or(Error::FuncNotFound(table_id, func_id))?; Ok(self.function_handle_from_ptr(func)) @@ -227,7 +198,7 @@ impl ModuleInternal for DlModule { } fn function_manifest(&self) -> &[FunctionSpec] { - self.function_manifest + self.module.function_manifest } fn addr_details(&self, addr: *const c_void) -> Result, Error> { @@ -253,17 +224,10 @@ impl ModuleInternal for DlModule { } fn get_signature(&self, fn_id: FunctionIndex) -> &Signature { - self.module_data.get_signature(fn_id) + self.module.module_data.get_signature(fn_id) } } -fn is_undefined_symbol(e: &std::io::Error) -> bool { - // gross, but I'm not sure how else to differentiate this type of error from other - // IO errors - let msg = format!("{}", e); - msg.contains("undefined symbol") || msg.contains("symbol not found") -} - // TODO: PR to nix or libloading? // TODO: possibly not safe to use without grabbing the mutex within libloading::Library? fn dladdr(addr: *const c_void) -> Option { diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index 4f9569584..c7ae5bd99 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -19,7 +19,7 @@ use cranelift_native; use cranelift_wasm::{translate_module, FuncTranslator, WasmError}; use failure::{format_err, Fail, ResultExt}; use lucet_module_data::bindings::Bindings; -use lucet_module_data::{FunctionSpec, ModuleData}; +use lucet_module_data::{FunctionSpec, ModuleData, MODULE_DATA_SYM}; #[derive(Debug, Clone, Copy)] pub enum OptLevel { @@ -135,9 +135,9 @@ impl<'a> Compiler<'a> { stack_probe::declare_metadata(&mut self.decls, &mut self.clif_module).unwrap(); - write_module_data(&mut self.clif_module, &self.decls)?; + let module_data_len = write_module_data(&mut self.clif_module, &self.decls)?; write_startfunc_data(&mut self.clif_module, &self.decls)?; - write_table_data(&mut self.clif_module, &self.decls)?; + let table_names = write_table_data(&mut self.clif_module, &self.decls)?; let function_manifest: Vec<(String, FunctionSpec)> = self .clif_module @@ -155,8 +155,13 @@ impl<'a> Compiler<'a> { }) .collect(); - let obj = ObjectFile::new(self.clif_module.finish(), function_manifest) - .context(LucetcErrorKind::Output)?; + let obj = ObjectFile::new( + self.clif_module.finish(), + module_data_len, + function_manifest, + table_names, + ) + .context(LucetcErrorKind::Output)?; Ok(obj) } @@ -196,42 +201,27 @@ impl<'a> Compiler<'a> { fn write_module_data( clif_module: &mut ClifModule, decls: &ModuleDecls<'_>, -) -> Result<(), LucetcError> { - use byteorder::{LittleEndian, WriteBytesExt}; +) -> Result { use cranelift_module::{DataContext, Linkage}; let module_data_serialized: Vec = decls .get_module_data()? .serialize() .context(LucetcErrorKind::ModuleData)?; - { - let mut serialized_len: Vec = Vec::new(); - serialized_len - .write_u32::(module_data_serialized.len() as u32) - .unwrap(); - let mut data_len_ctx = DataContext::new(); - data_len_ctx.define(serialized_len.into_boxed_slice()); - - let data_len_decl = clif_module - .declare_data("lucet_module_data_len", Linkage::Export, false, None) - .context(LucetcErrorKind::ModuleData)?; - clif_module - .define_data(data_len_decl, &data_len_ctx) - .context(LucetcErrorKind::ModuleData)?; - } - { - let mut module_data_ctx = DataContext::new(); - module_data_ctx.define(module_data_serialized.into_boxed_slice()); + let module_data_len = module_data_serialized.len(); - let module_data_decl = clif_module - .declare_data("lucet_module_data", Linkage::Export, true, None) - .context(LucetcErrorKind::ModuleData)?; - clif_module - .define_data(module_data_decl, &module_data_ctx) - .context(LucetcErrorKind::ModuleData)?; - } - Ok(()) + let mut module_data_ctx = DataContext::new(); + module_data_ctx.define(module_data_serialized.into_boxed_slice()); + + let module_data_decl = clif_module + .declare_data(MODULE_DATA_SYM, Linkage::Local, true, None) + .context(LucetcErrorKind::ModuleData)?; + clif_module + .define_data(module_data_decl, &module_data_ctx) + .context(LucetcErrorKind::ModuleData)?; + + Ok(module_data_len) } fn write_startfunc_data( diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index 7a0009cb7..360af58b8 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -4,6 +4,7 @@ pub use crate::module::{Exportable, TableElems}; use crate::module::{ModuleInfo, UniqueFuncIndex}; use crate::name::Name; use crate::runtime::{Runtime, RuntimeFunc}; +use crate::table::TABLE_SYM; use cranelift_codegen::entity::{EntityRef, PrimaryMap}; use cranelift_codegen::ir; use cranelift_codegen::isa::TargetFrontendConfig; @@ -61,7 +62,6 @@ pub struct TableDecl<'a> { pub table: &'a Table, pub elems: &'a [TableElems], pub contents_name: Name, - pub len_name: Name, } pub struct ModuleDecls<'a> { @@ -69,7 +69,8 @@ pub struct ModuleDecls<'a> { function_names: PrimaryMap, imports: Vec>, exports: Vec>, - table_names: PrimaryMap, + tables_list_name: Name, + table_names: PrimaryMap, runtime_names: HashMap, globals_spec: Vec>, linear_memory_spec: Option, @@ -84,7 +85,7 @@ impl<'a> ModuleDecls<'a> { heap_settings: HeapSettings, ) -> Result { let imports: Vec> = Vec::with_capacity(info.imported_funcs.len()); - let table_names = Self::declare_tables(&info, clif_module)?; + let (tables_list_name, table_names) = Self::declare_tables(&info, clif_module)?; let globals_spec = Self::build_globals_spec(&info)?; let linear_memory_spec = Self::build_linear_memory_spec(&info, heap_settings)?; let mut decls = Self { @@ -92,6 +93,7 @@ impl<'a> ModuleDecls<'a> { function_names: PrimaryMap::new(), imports, exports: vec![], + tables_list_name, table_names, runtime_names: HashMap::new(), globals_spec, @@ -243,7 +245,7 @@ impl<'a> ModuleDecls<'a> { fn declare_tables( info: &ModuleInfo<'a>, clif_module: &mut ClifModule, - ) -> Result, LucetcError> { + ) -> Result<(Name, PrimaryMap), LucetcError> { let mut table_names = PrimaryMap::new(); for ix in 0..info.tables.len() { let def_symbol = format!("guest_table_{}", ix); @@ -252,15 +254,15 @@ impl<'a> ModuleDecls<'a> { .context(LucetcErrorKind::TranslatingModule)?; let def_name = Name::new_data(def_symbol, def_data_id); - let len_symbol = format!("guest_table_{}_len", ix); - let len_data_id = clif_module - .declare_data(&len_symbol, Linkage::Export, false, None) - .context(LucetcErrorKind::TranslatingModule)?; - let len_name = Name::new_data(len_symbol, len_data_id); - - table_names.push((def_name, len_name)); + table_names.push(def_name); } - Ok(table_names) + + let tables_list_id = clif_module + .declare_data(TABLE_SYM, Linkage::Export, false, None) + .context(LucetcErrorKind::Table)?; + let tables_list = Name::new_data(TABLE_SYM.to_string(), tables_list_id); + + Ok((tables_list, table_names)) } fn declare_runtime( @@ -431,8 +433,12 @@ impl<'a> ModuleDecls<'a> { }) } + pub fn get_tables_list_name(&self) -> &Name { + &self.tables_list_name + } + pub fn get_table(&self, table_index: TableIndex) -> Result, Error> { - let (contents_name, len_name) = self + let contents_name = self .table_names .get(table_index) .ok_or_else(|| format_err!("table index out of bounds: {:?}", table_index))?; @@ -445,7 +451,6 @@ impl<'a> ModuleDecls<'a> { export_names: exportable_tbl.export_names.clone(), import_name: import_name.cloned(), contents_name: contents_name.clone(), - len_name: len_name.clone(), }) } diff --git a/lucetc/src/function.rs b/lucetc/src/function.rs index 6090bfc19..933e64ac8 100644 --- a/lucetc/src/function.rs +++ b/lucetc/src/function.rs @@ -1,6 +1,7 @@ use super::runtime::RuntimeFunc; use crate::decls::ModuleDecls; use crate::pointer::{NATIVE_POINTER, NATIVE_POINTER_SIZE}; +use crate::table::TABLE_REF_SIZE; use cranelift_codegen::cursor::FuncCursor; use cranelift_codegen::entity::EntityRef; use cranelift_codegen::ir::{self, InstBuilder}; @@ -131,15 +132,25 @@ impl<'a> FuncEnvironment for FuncInfo<'a> { offset: 0.into(), colocated: true, }); - let bound_ptr_gv = func.create_global_value(ir::GlobalValueData::Symbol { - name: table_decl.len_name.into(), + let tables_list_gv = func.create_global_value(ir::GlobalValueData::Symbol { + name: self.module_decls.get_tables_list_name().as_externalname(), offset: 0.into(), colocated: true, }); + + let table_bound_offset = (TABLE_REF_SIZE as u32) + .checked_mul(index.as_u32()) + .and_then(|entry| entry.checked_add(NATIVE_POINTER_SIZE as u32)) + .ok_or(WasmError::ImplLimitExceeded)?; + + if table_bound_offset > std::i32::MAX as u32 { + return Err(WasmError::ImplLimitExceeded); + } + let bound_gv = func.create_global_value(ir::GlobalValueData::Load { - base: bound_ptr_gv, + base: tables_list_gv, global_type: index_type, - offset: 0.into(), + offset: (table_bound_offset as i32).into(), readonly: true, }); let element_size = ((NATIVE_POINTER_SIZE * 2) as u64).into(); diff --git a/lucetc/src/function_manifest.rs b/lucetc/src/function_manifest.rs index 809eb7123..4871f8325 100644 --- a/lucetc/src/function_manifest.rs +++ b/lucetc/src/function_manifest.rs @@ -1,69 +1,12 @@ +use crate::output::write_relocated_slice; use crate::traps::trap_sym_for_func; -use byteorder::{LittleEndian, WriteBytesExt}; -use faerie::{Artifact, Decl, Link}; +use faerie::{Artifact, Decl}; use failure::{Error, ResultExt}; use lucet_module_data::FunctionSpec; use std::io::Cursor; use std::mem::size_of; -use target_lexicon::BinaryFormat; -fn write_relocated_slice( - obj: &mut Artifact, - buf: &mut Cursor>, - from: &str, - to: Option<&str>, - len: u64, -) -> Result<(), Error> { - match (to, len) { - (Some(to), 0) => { - // This is an imported slice of unknown size - let absolute_reloc = match obj.target.binary_format { - BinaryFormat::Elf => faerie::artifact::Reloc::Raw { - reloc: goblin::elf::reloc::R_X86_64_64, - addend: 0, - }, - BinaryFormat::Macho => faerie::artifact::Reloc::Raw { - reloc: goblin::mach::relocation::X86_64_RELOC_UNSIGNED as u32, - addend: 0, - }, - _ => panic!("Unsupported target format!"), - }; - - obj.link_with( - Link { - from, - to, - at: buf.position(), - }, - absolute_reloc, - ) - .context(format!("linking {} into function manifest", to))?; - } - (Some(to), _len) => { - // This is a local buffer of known size - obj.link(Link { - from, // the data at `from` + `at` (eg. manifest_sym) - to, // is a reference to `to` (eg. fn_name) - at: buf.position(), - }) - .context(format!("linking {} into function manifest", to))?; - } - (None, len) => { - // There's actually no relocation to add, because there's no slice to put here. - // - // Since there's no slice, its length must be zero. - assert!( - len == 0, - "Invalid slice: no data, but there are more than zero bytes of it" - ); - } - } - - buf.write_u64::(0).unwrap(); - buf.write_u64::(len).unwrap(); - - Ok(()) -} +pub const FUNCTION_MANIFEST_SYM: &str = "lucet_function_manifest"; /// /// Writes a manifest of functions, with relocations, to the artifact. @@ -72,20 +15,8 @@ pub fn write_function_manifest( functions: &[(String, FunctionSpec)], obj: &mut Artifact, ) -> Result<(), Error> { - let manifest_len_sym = "lucet_function_manifest_len"; - obj.declare(&manifest_len_sym, Decl::data().global()) - .context(format!("declaring {}", &manifest_len_sym))?; - - let manifest_sym = "lucet_function_manifest"; - obj.declare(&manifest_sym, Decl::data().global()) - .context(format!("declaring {}", &manifest_sym))?; - - let mut manifest_len_buf: Vec = Vec::new(); - manifest_len_buf - .write_u32::(functions.len() as u32) - .unwrap(); - obj.define(manifest_len_sym, manifest_len_buf) - .context(format!("defining {}", &manifest_len_sym))?; + obj.declare(FUNCTION_MANIFEST_SYM, Decl::data()) + .context(format!("declaring {}", FUNCTION_MANIFEST_SYM))?; let mut manifest_buf: Cursor> = Cursor::new(Vec::with_capacity( functions.len() * size_of::(), @@ -106,7 +37,7 @@ pub fn write_function_manifest( write_relocated_slice( obj, &mut manifest_buf, - &manifest_sym, + FUNCTION_MANIFEST_SYM, Some(fn_name), fn_spec.code_len() as u64, )?; @@ -115,7 +46,7 @@ pub fn write_function_manifest( write_relocated_slice( obj, &mut manifest_buf, - &manifest_sym, + FUNCTION_MANIFEST_SYM, if fn_spec.traps_len() > 0 { Some(&trap_sym) } else { @@ -125,8 +56,8 @@ pub fn write_function_manifest( )?; } - obj.define(&manifest_sym, manifest_buf.into_inner()) - .context(format!("defining {}", &manifest_sym))?; + obj.define(FUNCTION_MANIFEST_SYM, manifest_buf.into_inner()) + .context(format!("defining {}", FUNCTION_MANIFEST_SYM))?; Ok(()) } diff --git a/lucetc/src/output.rs b/lucetc/src/output.rs index a0d6d578e..2a73d5d0d 100644 --- a/lucetc/src/output.rs +++ b/lucetc/src/output.rs @@ -1,17 +1,21 @@ use crate::error::LucetcErrorKind; -use crate::function_manifest::write_function_manifest; +use crate::function_manifest::{write_function_manifest, FUNCTION_MANIFEST_SYM}; use crate::name::Name; +use crate::pointer::NATIVE_POINTER_SIZE; use crate::stack_probe; +use crate::table::{link_tables, TABLE_SYM}; use crate::traps::write_trap_tables; +use byteorder::{LittleEndian, WriteBytesExt}; use cranelift_codegen::{ir, isa}; use cranelift_faerie::FaerieProduct; -use faerie::Artifact; +use faerie::{Artifact, Decl, Link}; use failure::{format_err, Error, ResultExt}; -use lucet_module_data::FunctionSpec; +use lucet_module_data::{FunctionSpec, LUCET_MODULE_SYM, MODULE_DATA_SYM}; use std::collections::HashMap; use std::fs::File; -use std::io::Write; +use std::io::{Cursor, Write}; use std::path::Path; +use target_lexicon::BinaryFormat; pub struct CraneliftFuncs { funcs: HashMap, @@ -43,13 +47,16 @@ pub struct ObjectFile { impl ObjectFile { pub fn new( mut product: FaerieProduct, + module_data_len: usize, mut function_manifest: Vec<(String, FunctionSpec)>, + table_manifest: Vec, ) -> Result { stack_probe::declare_and_define(&mut product)?; - // stack_probe::declare_and_define never exists as clif, and as a result never exist as - // compiled code. This means the declared length of the stack probe's code is 0. This is - // incorrect, and must be fixed up before writing out the function manifest. + // stack_probe::declare_and_define never exists as clif, and as a result never exists a + // cranelift-compiled function. As a result, the declared length of the stack probe's + // "code" is 0. This is incorrect, and must be fixed up before writing out the function + // manifest. // because the stack probe is the last declared function... let last_idx = function_manifest.len() - 1; @@ -97,11 +104,21 @@ impl ObjectFile { write_trap_tables(trap_manifest, &mut product.artifact)?; write_function_manifest(function_manifest.as_slice(), &mut product.artifact)?; + link_tables(table_manifest.as_slice(), &mut product.artifact)?; + + // And now write out the actual structure tying together all the data in this module. + write_module( + module_data_len, + table_manifest.len(), + function_manifest.len(), + &mut product.artifact, + )?; Ok(Self { artifact: product.artifact, }) } + pub fn write>(&self, path: P) -> Result<(), Error> { let _ = path.as_ref().file_name().ok_or(format_err!( "path {:?} needs to have filename", @@ -112,3 +129,99 @@ impl ObjectFile { Ok(()) } } + +fn write_module( + module_data_len: usize, + table_manifest_len: usize, + function_manifest_len: usize, + obj: &mut Artifact, +) -> Result<(), Error> { + let mut native_data = Cursor::new(Vec::with_capacity(NATIVE_POINTER_SIZE * 4)); + obj.declare(LUCET_MODULE_SYM, Decl::data().global()) + .context(format!("declaring {}", LUCET_MODULE_SYM))?; + + write_relocated_slice( + obj, + &mut native_data, + LUCET_MODULE_SYM, + Some(MODULE_DATA_SYM), + module_data_len as u64, + )?; + write_relocated_slice( + obj, + &mut native_data, + LUCET_MODULE_SYM, + Some(TABLE_SYM), + table_manifest_len as u64, + )?; + write_relocated_slice( + obj, + &mut native_data, + LUCET_MODULE_SYM, + Some(FUNCTION_MANIFEST_SYM), + function_manifest_len as u64, + )?; + + obj.define(LUCET_MODULE_SYM, native_data.into_inner()) + .context(format!("defining {}", LUCET_MODULE_SYM))?; + + Ok(()) +} + +pub(crate) fn write_relocated_slice( + obj: &mut Artifact, + buf: &mut Cursor>, + from: &str, + to: Option<&str>, + len: u64, +) -> Result<(), Error> { + match (to, len) { + (Some(to), 0) => { + // This is an imported slice of unknown size + let absolute_reloc = match obj.target.binary_format { + BinaryFormat::Elf => faerie::artifact::Reloc::Raw { + reloc: goblin::elf::reloc::R_X86_64_64, + addend: 0, + }, + BinaryFormat::Macho => faerie::artifact::Reloc::Raw { + reloc: goblin::mach::relocation::X86_64_RELOC_UNSIGNED as u32, + addend: 0, + }, + _ => panic!("Unsupported target format!"), + }; + + obj.link_with( + Link { + from, + to, + at: buf.position(), + }, + absolute_reloc, + ) + .context(format!("linking {} into function manifest", to))?; + } + (Some(to), _len) => { + // This is a local buffer of known size + obj.link(Link { + from, // the data at `from` + `at` (eg. FUNCTION_MANIFEST_SYM) + to, // is a reference to `to` (eg. fn_name) + at: buf.position(), + }) + .context(format!("linking {} into function manifest", to))?; + } + (None, len) => { + // There's actually no relocation to add, because there's no slice to put here. + // + // Since there's no slice, its length must be zero. + assert!( + len == 0, + "Invalid slice: no data, but there are more than zero bytes of it" + ); + } + } + + buf.write_u64::(0).unwrap(); + buf.write_u64::(len).unwrap(); + + Ok(()) +} diff --git a/lucetc/src/table.rs b/lucetc/src/table.rs index 8663afaa8..967372c3a 100644 --- a/lucetc/src/table.rs +++ b/lucetc/src/table.rs @@ -1,14 +1,23 @@ use crate::decls::{ModuleDecls, TableDecl}; use crate::error::{LucetcError, LucetcErrorKind}; use crate::module::UniqueFuncIndex; +use crate::name::Name; use crate::pointer::NATIVE_POINTER_SIZE; use byteorder::{LittleEndian, WriteBytesExt}; use cranelift_codegen::entity::EntityRef; use cranelift_module::{Backend as ClifBackend, DataContext, Module as ClifModule}; use cranelift_wasm::{TableElementType, TableIndex}; -use failure::{format_err, ResultExt}; +use faerie::{Artifact, Link}; +use failure::{format_err, Error, ResultExt}; use std::io::Cursor; +/// This symbol will be used to reference the `tables` field in `Module` - a sequence of tables. +/// At the moment it will either be one or no tables, but in the future may grow. +pub const TABLE_SYM: &str = "lucet_tables"; +/// This is functionally the size of `&[TableEntry]`, but defined here because it may not +/// necessarily have the same field ordering. +pub const TABLE_REF_SIZE: usize = NATIVE_POINTER_SIZE * 2; + #[derive(Debug, Clone)] enum Elem { Func(UniqueFuncIndex), @@ -44,10 +53,25 @@ fn table_elements(decl: &TableDecl<'_>) -> Result, LucetcError> { Ok(elems) } +pub fn link_tables(tables: &[Name], obj: &mut Artifact) -> Result<(), Error> { + for (idx, table) in tables.iter().enumerate() { + obj.link(Link { + from: TABLE_SYM, + to: table.symbol(), + at: (TABLE_REF_SIZE * idx) as u64, + }) + .context(LucetcErrorKind::Table)?; + } + Ok(()) +} + pub fn write_table_data( clif_module: &mut ClifModule, decls: &ModuleDecls<'_>, -) -> Result<(), LucetcError> { +) -> Result, LucetcError> { + let mut tables_vec = Cursor::new(Vec::new()); + let mut table_names: Vec = Vec::new(); + if let Ok(table_decl) = decls.get_table(TableIndex::new(0)) { // Indirect calls are performed by looking up the callee function and type in a table that // is present in the same object file. @@ -105,19 +129,30 @@ pub fn write_table_data( .define_data(table_id, &table_ctx) .context(LucetcErrorKind::Table)?; - { - // Define the length of the table as a u64: - let mut len_data = Cursor::new(Vec::with_capacity(8)); - len_data - .write_u64::(elements.len() as u64) - .unwrap(); - let mut table_len_ctx = DataContext::new(); - table_len_ctx.define(len_data.into_inner().into_boxed_slice()); - let table_len_id = table_decl.len_name.as_dataid().expect("tables are data"); - clif_module - .define_data(table_len_id, &table_len_ctx) - .context(LucetcErrorKind::Table)?; - } + // have to link TABLE_SYM, table_id, + // add space for the TABLE_SYM pointer + tables_vec.write_u64::(0).unwrap(); + + // Define the length of the table as a u64: + tables_vec + .write_u64::(elements.len() as u64) + .unwrap(); + table_names.push(table_decl.contents_name.clone()) } - Ok(()) + + let inner = tables_vec.into_inner(); + + let mut table_data_ctx = DataContext::new(); + table_data_ctx.define(inner.into_boxed_slice()); + + clif_module + .define_data( + decls + .get_tables_list_name() + .as_dataid() + .expect("lucet_tables is declared as data"), + &table_data_ctx, + ) + .context(LucetcErrorKind::Table)?; + Ok(table_names) } From 4d759577f73aed180953e7467e57d0b87bad8f96 Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Thu, 11 Jul 2019 23:44:19 +0200 Subject: [PATCH 262/512] shootout benchmark: rand and rand2 don't have a teardown function (#247) --- benchmarks/shootout/wrapper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmarks/shootout/wrapper.c b/benchmarks/shootout/wrapper.c index 68d78060b..e3af3aec4 100644 --- a/benchmarks/shootout/wrapper.c +++ b/benchmarks/shootout/wrapper.c @@ -164,11 +164,11 @@ TEARDOWN_NOWRAP(nestedloop) SETUP(random2) BODY(random2) -TEARDOWN(random2) +TEARDOWN_NOWRAP(random2) SETUP(random) BODY(random) -TEARDOWN(random) +TEARDOWN_NOWRAP(random) SETUP(ratelimit) BODY(ratelimit) From c6514856d2ee24ee8cdc5412a7fca2b672486c0c Mon Sep 17 00:00:00 2001 From: awortman-fastly <49215183+awortman-fastly@users.noreply.github.com> Date: Thu, 11 Jul 2019 14:55:35 -0700 Subject: [PATCH 263/512] Rename "lucet-module-data" to "lucet-module" (#244) * rename lucet-module-data to lucet-module --- Cargo.lock | 24 ++++++++--------- Cargo.toml | 2 +- Makefile | 4 +-- benchmarks/lucet-benchmarks/Cargo.toml | 2 +- benchmarks/lucet-benchmarks/src/modules.rs | 2 +- lucet-analyze/Cargo.toml | 2 +- lucet-analyze/src/main.rs | 2 +- lucet-idl/Cargo.toml | 2 +- lucet-idl/src/lib.rs | 2 +- lucet-idl/src/package.rs | 2 +- .../Cargo.toml | 4 +-- .../src/bindings.rs | 0 .../src/error.rs | 0 .../src/functions.rs | 0 .../src/globals.rs | 0 .../src/lib.rs | 2 +- .../src/linear_memory.rs | 0 .../src/module.rs | 0 .../src/module_data.rs | 0 .../src/signature.rs | 0 .../src/tables.rs | 0 .../src/traps.rs | 0 .../src/types.rs | 0 .../tests/bindings/bad_bindings.json | 0 .../tests/bindings/bindings_test.json | 0 .../tests/bindings/garbage.json | 0 lucet-runtime/Cargo.toml | 2 +- .../lucet-runtime-internals/Cargo.toml | 2 +- .../lucet-runtime-internals/src/alloc/mod.rs | 2 +- .../lucet-runtime-internals/src/error.rs | 6 ++--- .../src/instance/signals.rs | 2 +- .../lucet-runtime-internals/src/module.rs | 2 +- .../lucet-runtime-internals/src/module/dl.rs | 6 ++--- .../src/module/mock.rs | 4 +-- .../lucet-runtime-internals/src/val.rs | 2 +- .../lucet-runtime-internals/src/vmctx.rs | 2 +- lucet-runtime/lucet-runtime-tests/Cargo.toml | 2 +- .../lucet-runtime-tests/src/build.rs | 2 +- .../lucet-runtime-tests/src/entrypoint.rs | 2 +- .../lucet-runtime-tests/src/globals.rs | 2 +- .../lucet-runtime-tests/src/guest_fault.rs | 2 +- lucet-runtime/src/c_api.rs | 2 +- lucet-runtime/src/lib.rs | 2 +- lucet-spectest/Cargo.toml | 2 +- lucet-spectest/src/bindings.rs | 2 +- lucet-wasi-fuzz/Cargo.toml | 2 +- lucet-wasi-fuzz/src/main.rs | 2 +- lucet-wasi-sdk/Cargo.toml | 2 +- lucet-wasi-sdk/tests/lucetc.rs | 2 +- lucet-wasi/Cargo.toml | 2 +- lucet-wasi/src/bindings.rs | 2 +- lucetc/Cargo.toml | 2 +- lucetc/src/compiler.rs | 4 +-- lucetc/src/decls.rs | 4 +-- lucetc/src/function_manifest.rs | 2 +- lucetc/src/lib.rs | 2 +- lucetc/src/main.rs | 2 +- lucetc/src/module.rs | 2 +- lucetc/src/output.rs | 2 +- lucetc/src/signature.rs | 2 +- lucetc/src/sparsedata.rs | 6 ++--- lucetc/src/traps.rs | 26 +++++++++---------- lucetc/tests/wasm.rs | 10 +++---- 63 files changed, 87 insertions(+), 87 deletions(-) rename {lucet-module-data => lucet-module}/Cargo.toml (84%) rename {lucet-module-data => lucet-module}/src/bindings.rs (100%) rename {lucet-module-data => lucet-module}/src/error.rs (100%) rename {lucet-module-data => lucet-module}/src/functions.rs (100%) rename {lucet-module-data => lucet-module}/src/globals.rs (100%) rename {lucet-module-data => lucet-module}/src/lib.rs (95%) rename {lucet-module-data => lucet-module}/src/linear_memory.rs (100%) rename {lucet-module-data => lucet-module}/src/module.rs (100%) rename {lucet-module-data => lucet-module}/src/module_data.rs (100%) rename {lucet-module-data => lucet-module}/src/signature.rs (100%) rename {lucet-module-data => lucet-module}/src/tables.rs (100%) rename {lucet-module-data => lucet-module}/src/traps.rs (100%) rename {lucet-module-data => lucet-module}/src/types.rs (100%) rename {lucet-module-data => lucet-module}/tests/bindings/bad_bindings.json (100%) rename {lucet-module-data => lucet-module}/tests/bindings/bindings_test.json (100%) rename {lucet-module-data => lucet-module}/tests/bindings/garbage.json (100%) diff --git a/Cargo.lock b/Cargo.lock index 7d6ebfad6..798a4a11b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -758,7 +758,7 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.1", + "lucet-module 0.1.1", ] [[package]] @@ -766,7 +766,7 @@ name = "lucet-benchmarks" version = "0.1.1" dependencies = [ "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.1", + "lucet-module 0.1.1", "lucet-runtime 0.1.1", "lucet-runtime-internals 0.1.1", "lucet-wasi 0.1.1", @@ -785,7 +785,7 @@ dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.1", + "lucet-module 0.1.1", "lucetc 0.1.1", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -822,7 +822,7 @@ dependencies = [ ] [[package]] -name = "lucet-module-data" +name = "lucet-module" version = "0.1.1" dependencies = [ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -846,7 +846,7 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.1", + "lucet-module 0.1.1", "lucet-runtime-internals 0.1.1", "lucet-runtime-tests 0.1.1", "lucet-wasi-sdk 0.1.1", @@ -870,7 +870,7 @@ dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.1", + "lucet-module 0.1.1", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -885,7 +885,7 @@ dependencies = [ "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.1", + "lucet-module 0.1.1", "lucet-runtime-internals 0.1.1", "lucet-wasi-sdk 0.1.1", "lucetc 0.1.1", @@ -898,7 +898,7 @@ version = "0.1.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.1", + "lucet-module 0.1.1", "lucet-runtime 0.1.1", "lucetc 0.1.1", "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", @@ -917,7 +917,7 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.1", + "lucet-module 0.1.1", "lucet-runtime 0.1.1", "lucet-runtime-internals 0.1.1", "lucet-wasi-sdk 0.1.1", @@ -934,7 +934,7 @@ dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.1", + "lucet-module 0.1.1", "lucet-runtime 0.1.1", "lucet-wasi 0.1.1", "lucet-wasi-sdk 0.1.1", @@ -955,7 +955,7 @@ name = "lucet-wasi-sdk" version = "0.1.1" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.1", + "lucet-module 0.1.1", "lucetc 0.1.1", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -981,7 +981,7 @@ dependencies = [ "goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module-data 0.1.1", + "lucet-module 0.1.1", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index ac9c143c2..fe6b0e39f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ members = [ "lucet-idl", "lucet-idl/lucet-idl-test", "lucet-idl/lucet-idl-test/resources/rust_host", - "lucet-module-data", + "lucet-module", "lucet-runtime", "lucet-runtime/lucet-runtime-internals", "lucet-runtime/lucet-runtime-tests", diff --git a/Makefile b/Makefile index b844264b5..9a57bda72 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ test: indent-check cargo test --no-fail-fast \ -p lucet-runtime-internals \ -p lucet-runtime \ - -p lucet-module-data \ + -p lucet-module \ -p lucetc \ -p lucet-idl \ -p lucet-wasi-sdk \ @@ -68,7 +68,7 @@ watch: cargo watch --exec "test \ -p lucet-runtime-internals \ -p lucet-runtime \ - -p lucet-module-data \ + -p lucet-module \ -p lucetc \ -p lucet-idl \ -p lucet-wasi-sdk \ diff --git a/benchmarks/lucet-benchmarks/Cargo.toml b/benchmarks/lucet-benchmarks/Cargo.toml index 0ae829ca7..0eb323e62 100644 --- a/benchmarks/lucet-benchmarks/Cargo.toml +++ b/benchmarks/lucet-benchmarks/Cargo.toml @@ -12,7 +12,7 @@ edition = "2018" [dependencies] criterion = "0.2" lucetc = { path = "../../lucetc" } -lucet-module-data = { path = "../../lucet-module-data" } +lucet-module = { path = "../../lucet-module" } lucet-runtime = { path = "../../lucet-runtime" } lucet-runtime-internals = { path = "../../lucet-runtime/lucet-runtime-internals" } lucet-wasi = { path = "../../lucet-wasi" } diff --git a/benchmarks/lucet-benchmarks/src/modules.rs b/benchmarks/lucet-benchmarks/src/modules.rs index d28cd7c0f..c57d4edb2 100644 --- a/benchmarks/lucet-benchmarks/src/modules.rs +++ b/benchmarks/lucet-benchmarks/src/modules.rs @@ -1,4 +1,4 @@ -use lucet_module_data::lucet_signature; +use lucet_module::lucet_signature; use lucet_runtime::lucet_hostcalls; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime_internals::module::{ diff --git a/lucet-analyze/Cargo.toml b/lucet-analyze/Cargo.toml index fea8da725..41cabaa49 100644 --- a/lucet-analyze/Cargo.toml +++ b/lucet-analyze/Cargo.toml @@ -13,4 +13,4 @@ edition = "2018" goblin="0.0.21" byteorder="1.2.1" colored="1.6.1" -lucet-module-data = { path = "../lucet-module-data", version = "0.1.1" } +lucet-module = { path = "../lucet-module", version = "0.1.1" } diff --git a/lucet-analyze/src/main.rs b/lucet-analyze/src/main.rs index e46f0d703..2c20655e8 100644 --- a/lucet-analyze/src/main.rs +++ b/lucet-analyze/src/main.rs @@ -1,6 +1,6 @@ #![deny(bare_trait_objects)] -use lucet_module_data::{ +use lucet_module::{ FunctionSpec, Module, ModuleData, SerializedModule, TableElement, TrapManifest, TrapSite, }; diff --git a/lucet-idl/Cargo.toml b/lucet-idl/Cargo.toml index e7988444a..0909d7aa9 100644 --- a/lucet-idl/Cargo.toml +++ b/lucet-idl/Cargo.toml @@ -22,7 +22,7 @@ failure = "0.1" xfailure = "0.1" heck = "0.3" lucetc = { path = "../lucetc" } -lucet-module-data = { path = "../lucet-module-data" } +lucet-module = { path = "../lucet-module" } [dev-dependencies] tempfile = "3.0" diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 19875bdc6..64a4dfb52 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -27,7 +27,7 @@ pub use crate::types::{ use crate::c::CGenerator; use crate::parser::Parser; use crate::rust::RustGenerator; -use lucet_module_data::bindings::Bindings; +use lucet_module::bindings::Bindings; use std::io::Write; pub fn parse_package(input: &str) -> Result { diff --git a/lucet-idl/src/package.rs b/lucet-idl/src/package.rs index 1c325b1ef..ea082e40a 100644 --- a/lucet-idl/src/package.rs +++ b/lucet-idl/src/package.rs @@ -3,7 +3,7 @@ use crate::module::Module; use crate::parser::SyntaxDecl; use crate::types::{Ident, Location, Name}; use heck::SnakeCase; -use lucet_module_data::bindings::Bindings; +use lucet_module::bindings::Bindings; use std::collections::HashMap; #[derive(Debug, PartialEq, Eq, Clone)] diff --git a/lucet-module-data/Cargo.toml b/lucet-module/Cargo.toml similarity index 84% rename from lucet-module-data/Cargo.toml rename to lucet-module/Cargo.toml index 997bff62d..527536ce6 100644 --- a/lucet-module-data/Cargo.toml +++ b/lucet-module/Cargo.toml @@ -1,7 +1,7 @@ [package] -name = "lucet-module-data" +name = "lucet-module" version = "0.1.1" -description = "A structured interface for Lucet module data and metadata" +description = "A structured interface for Lucet modules" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" license = "Apache-2.0 WITH LLVM-exception" diff --git a/lucet-module-data/src/bindings.rs b/lucet-module/src/bindings.rs similarity index 100% rename from lucet-module-data/src/bindings.rs rename to lucet-module/src/bindings.rs diff --git a/lucet-module-data/src/error.rs b/lucet-module/src/error.rs similarity index 100% rename from lucet-module-data/src/error.rs rename to lucet-module/src/error.rs diff --git a/lucet-module-data/src/functions.rs b/lucet-module/src/functions.rs similarity index 100% rename from lucet-module-data/src/functions.rs rename to lucet-module/src/functions.rs diff --git a/lucet-module-data/src/globals.rs b/lucet-module/src/globals.rs similarity index 100% rename from lucet-module-data/src/globals.rs rename to lucet-module/src/globals.rs diff --git a/lucet-module-data/src/lib.rs b/lucet-module/src/lib.rs similarity index 95% rename from lucet-module-data/src/lib.rs rename to lucet-module/src/lib.rs index ee1543b92..c34243c3f 100644 --- a/lucet-module-data/src/lib.rs +++ b/lucet-module/src/lib.rs @@ -1,4 +1,4 @@ -//! Common types for representing Lucet module data and metadata. +//! Common types for representing Lucet modules. //! //! These types are used both in `lucetc` and `lucet-runtime`, with values serialized in //! [`bincode`](https://github.com/TyOverby/bincode) format to the compiled Lucet modules. diff --git a/lucet-module-data/src/linear_memory.rs b/lucet-module/src/linear_memory.rs similarity index 100% rename from lucet-module-data/src/linear_memory.rs rename to lucet-module/src/linear_memory.rs diff --git a/lucet-module-data/src/module.rs b/lucet-module/src/module.rs similarity index 100% rename from lucet-module-data/src/module.rs rename to lucet-module/src/module.rs diff --git a/lucet-module-data/src/module_data.rs b/lucet-module/src/module_data.rs similarity index 100% rename from lucet-module-data/src/module_data.rs rename to lucet-module/src/module_data.rs diff --git a/lucet-module-data/src/signature.rs b/lucet-module/src/signature.rs similarity index 100% rename from lucet-module-data/src/signature.rs rename to lucet-module/src/signature.rs diff --git a/lucet-module-data/src/tables.rs b/lucet-module/src/tables.rs similarity index 100% rename from lucet-module-data/src/tables.rs rename to lucet-module/src/tables.rs diff --git a/lucet-module-data/src/traps.rs b/lucet-module/src/traps.rs similarity index 100% rename from lucet-module-data/src/traps.rs rename to lucet-module/src/traps.rs diff --git a/lucet-module-data/src/types.rs b/lucet-module/src/types.rs similarity index 100% rename from lucet-module-data/src/types.rs rename to lucet-module/src/types.rs diff --git a/lucet-module-data/tests/bindings/bad_bindings.json b/lucet-module/tests/bindings/bad_bindings.json similarity index 100% rename from lucet-module-data/tests/bindings/bad_bindings.json rename to lucet-module/tests/bindings/bad_bindings.json diff --git a/lucet-module-data/tests/bindings/bindings_test.json b/lucet-module/tests/bindings/bindings_test.json similarity index 100% rename from lucet-module-data/tests/bindings/bindings_test.json rename to lucet-module/tests/bindings/bindings_test.json diff --git a/lucet-module-data/tests/bindings/garbage.json b/lucet-module/tests/bindings/garbage.json similarity index 100% rename from lucet-module-data/tests/bindings/garbage.json rename to lucet-module/tests/bindings/garbage.json diff --git a/lucet-runtime/Cargo.toml b/lucet-runtime/Cargo.toml index 998c9d9f7..794798113 100644 --- a/lucet-runtime/Cargo.toml +++ b/lucet-runtime/Cargo.toml @@ -12,7 +12,7 @@ edition = "2018" [dependencies] libc = "=0.2.59" lucet-runtime-internals = { path = "lucet-runtime-internals", version = "0.1.1" } -lucet-module-data = { path = "../lucet-module-data", version = "0.1.1" } +lucet-module = { path = "../lucet-module", version = "0.1.1" } num-traits = "0.2" num-derive = "0.2" diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index b1b32457c..84fd54fa2 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Lucet team "] edition = "2018" [dependencies] -lucet-module-data = { path = "../../lucet-module-data", version = "0.1.1" } +lucet-module = { path = "../../lucet-module", version = "0.1.1" } bitflags = "1.0" bincode = "~1.0.1" diff --git a/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs b/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs index 5d5105aab..8cd8378f3 100644 --- a/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs @@ -2,7 +2,7 @@ use crate::error::Error; use crate::module::Module; use crate::region::RegionInternal; use libc::{c_void, SIGSTKSZ}; -use lucet_module_data::GlobalValue; +use lucet_module::GlobalValue; use nix::unistd::{sysconf, SysconfVar}; use std::sync::{Arc, Once, Weak}; diff --git a/lucet-runtime/lucet-runtime-internals/src/error.rs b/lucet-runtime/lucet-runtime-internals/src/error.rs index 07c8c3caa..759047872 100644 --- a/lucet-runtime/lucet-runtime-internals/src/error.rs +++ b/lucet-runtime/lucet-runtime-internals/src/error.rs @@ -85,8 +85,8 @@ impl From for Error { } } -impl From for Error { - fn from(e: lucet_module_data::Error) -> Error { +impl From for Error { + fn from(e: lucet_module::Error) -> Error { Error::ModuleError(ModuleError::ModuleDataError(e)) } } @@ -100,7 +100,7 @@ pub enum ModuleError { /// An error occurred with the module data section, likely during deserialization. #[fail(display = "Module data error: {}", _0)] - ModuleDataError(#[cause] lucet_module_data::Error), + ModuleDataError(#[cause] lucet_module::Error), } #[macro_export] diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs index d4deed3d8..1f4c8917a 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs @@ -7,7 +7,7 @@ use crate::sysdeps::UContextPtr; use failure::Error; use lazy_static::lazy_static; use libc::{c_int, c_void, siginfo_t, SIGBUS, SIGSEGV}; -use lucet_module_data::TrapCode; +use lucet_module::TrapCode; use nix::sys::signal::{ pthread_sigmask, raise, sigaction, SaFlags, SigAction, SigHandler, SigSet, SigmaskHow, Signal, }; diff --git a/lucet-runtime/lucet-runtime-internals/src/module.rs b/lucet-runtime/lucet-runtime-internals/src/module.rs index 4f273c93e..22ddd9f74 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module.rs @@ -4,7 +4,7 @@ mod sparse_page_data; pub use crate::module::dl::DlModule; pub use crate::module::mock::{MockExportBuilder, MockModuleBuilder}; -pub use lucet_module_data::{ +pub use lucet_module::{ FunctionHandle, FunctionIndex, FunctionPointer, FunctionSpec, Global, GlobalSpec, GlobalValue, HeapSpec, Signature, TableElement, TrapCode, TrapManifest, ValueType, }; diff --git a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs index 948fc0cc5..350a08640 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs @@ -2,7 +2,7 @@ use crate::error::Error; use crate::module::{AddrDetails, GlobalSpec, HeapSpec, Module, ModuleInternal, TableElement}; use libc::c_void; use libloading::Library; -use lucet_module_data::{ +use lucet_module::{ FunctionHandle, FunctionIndex, FunctionPointer, FunctionSpec, ModuleData, ModuleSignature, PublicKey, SerializedModule, Signature, LUCET_MODULE_SYM, }; @@ -21,7 +21,7 @@ pub struct DlModule { fbase: *const c_void, /// Metadata decoded from inside the module - module: lucet_module_data::Module<'static>, + module: lucet_module::Module<'static>, } // for the one raw pointer only @@ -114,7 +114,7 @@ impl DlModule { Ok(Arc::new(DlModule { lib, fbase, - module: lucet_module_data::Module { + module: lucet_module::Module { module_data, tables, function_manifest, diff --git a/lucet-runtime/lucet-runtime-internals/src/module/mock.rs b/lucet-runtime/lucet-runtime-internals/src/module/mock.rs index 5e125e923..80ff9bbab 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/mock.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/mock.rs @@ -1,11 +1,11 @@ use crate::error::Error; use crate::module::{AddrDetails, GlobalSpec, HeapSpec, Module, ModuleInternal, TableElement}; use libc::c_void; -use lucet_module_data::owned::{ +use lucet_module::owned::{ OwnedExportFunction, OwnedFunctionMetadata, OwnedGlobalSpec, OwnedImportFunction, OwnedLinearMemorySpec, OwnedModuleData, OwnedSparseData, }; -use lucet_module_data::{ +use lucet_module::{ FunctionHandle, FunctionIndex, FunctionPointer, FunctionSpec, ModuleData, Signature, TrapSite, UniqueSignatureIndex, }; diff --git a/lucet-runtime/lucet-runtime-internals/src/val.rs b/lucet-runtime/lucet-runtime-internals/src/val.rs index cb9f98344..c2f2fe51c 100644 --- a/lucet-runtime/lucet-runtime-internals/src/val.rs +++ b/lucet-runtime/lucet-runtime-internals/src/val.rs @@ -7,7 +7,7 @@ use std::arch::x86_64::{ _mm_storeu_pd, _mm_storeu_ps, }; -use lucet_module_data::ValueType; +use lucet_module::ValueType; impl Val { pub fn value_type(&self) -> ValueType { diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index f95c3a603..5c7d5bab4 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -11,7 +11,7 @@ use crate::error::Error; use crate::instance::{ Instance, InstanceInternal, State, TerminationDetails, CURRENT_INSTANCE, HOST_CTX, }; -use lucet_module_data::{FunctionHandle, GlobalValue}; +use lucet_module::{FunctionHandle, GlobalValue}; use std::any::Any; use std::borrow::{Borrow, BorrowMut}; use std::cell::{Ref, RefCell, RefMut}; diff --git a/lucet-runtime/lucet-runtime-tests/Cargo.toml b/lucet-runtime/lucet-runtime-tests/Cargo.toml index f16c4a7b7..8d8b39246 100644 --- a/lucet-runtime/lucet-runtime-tests/Cargo.toml +++ b/lucet-runtime/lucet-runtime-tests/Cargo.toml @@ -18,7 +18,7 @@ test = false failure = "0.1" lazy_static = "1.1" tempfile = "3.0" -lucet-module-data = { path = "../../lucet-module-data", version = "0.1.1" } +lucet-module = { path = "../../lucet-module", version = "0.1.1" } lucet-runtime-internals = { path = "../lucet-runtime-internals", version = "0.1.1" } lucet-wasi-sdk = { path = "../../lucet-wasi-sdk", version = "0.1.1" } lucetc = { path = "../../lucetc", version = "0.1.1" } diff --git a/lucet-runtime/lucet-runtime-tests/src/build.rs b/lucet-runtime/lucet-runtime-tests/src/build.rs index f1b8f5759..ad00f2c68 100644 --- a/lucet-runtime/lucet-runtime-tests/src/build.rs +++ b/lucet-runtime/lucet-runtime-tests/src/build.rs @@ -1,5 +1,5 @@ use failure::Error; -use lucet_module_data::bindings::Bindings; +use lucet_module::bindings::Bindings; use lucet_runtime_internals::module::DlModule; use lucet_wasi_sdk::{CompileOpts, Link, LinkOpt, LinkOpts}; use lucetc::{Lucetc, LucetcOpts}; diff --git a/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs b/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs index f5e252151..e53e0d76b 100644 --- a/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs +++ b/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs @@ -1,6 +1,6 @@ use crate::build::test_module_wasm; use crate::helpers::{MockExportBuilder, MockModuleBuilder}; -use lucet_module_data::{lucet_signature, FunctionPointer}; +use lucet_module::{lucet_signature, FunctionPointer}; use lucet_runtime_internals::module::Module; use lucet_runtime_internals::vmctx::lucet_vmctx; use std::sync::Arc; diff --git a/lucet-runtime/lucet-runtime-tests/src/globals.rs b/lucet-runtime/lucet-runtime-tests/src/globals.rs index ce78d968e..f32a40d50 100644 --- a/lucet-runtime/lucet-runtime-tests/src/globals.rs +++ b/lucet-runtime/lucet-runtime-tests/src/globals.rs @@ -1,7 +1,7 @@ #[macro_export] macro_rules! globals_tests { ( $TestRegion:path ) => { - use lucet_module_data::{lucet_signature, FunctionPointer, GlobalValue}; + use lucet_module::{lucet_signature, FunctionPointer, GlobalValue}; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime::{Error, Limits, Module, Region}; use std::sync::Arc; diff --git a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs index 7345caaf2..ebd16aa99 100644 --- a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs +++ b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs @@ -1,5 +1,5 @@ use crate::helpers::{MockExportBuilder, MockModuleBuilder}; -use lucet_module_data::{FunctionPointer, TrapCode, TrapSite}; +use lucet_module::{FunctionPointer, TrapCode, TrapSite}; use lucet_runtime_internals::module::Module; use lucet_runtime_internals::vmctx::lucet_vmctx; use std::sync::Arc; diff --git a/lucet-runtime/src/c_api.rs b/lucet-runtime/src/c_api.rs index ef70456c8..8d4f79652 100644 --- a/lucet-runtime/src/c_api.rs +++ b/lucet-runtime/src/c_api.rs @@ -1,6 +1,6 @@ use crate::{DlModule, Instance, Limits, MmapRegion, Module, Region}; use libc::{c_char, c_int, c_void}; -use lucet_module_data::TrapCode; +use lucet_module::TrapCode; use lucet_runtime_internals::c_api::*; use lucet_runtime_internals::instance::{ instance_handle_from_raw, instance_handle_to_raw, InstanceInternal, diff --git a/lucet-runtime/src/lib.rs b/lucet-runtime/src/lib.rs index e7a781853..3e6218394 100644 --- a/lucet-runtime/src/lib.rs +++ b/lucet-runtime/src/lib.rs @@ -202,7 +202,7 @@ pub mod c_api; -pub use lucet_module_data::{PublicKey, TrapCode}; +pub use lucet_module::{PublicKey, TrapCode}; pub use lucet_runtime_internals::alloc::Limits; pub use lucet_runtime_internals::error::Error; pub use lucet_runtime_internals::instance::{ diff --git a/lucet-spectest/Cargo.toml b/lucet-spectest/Cargo.toml index 72860d675..3cc808a22 100644 --- a/lucet-spectest/Cargo.toml +++ b/lucet-spectest/Cargo.toml @@ -18,7 +18,7 @@ path = "src/main.rs" [dependencies] lucetc = { path = "../lucetc", version = "0.1.1" } -lucet-module-data = { path = "../lucet-module-data", version = "0.1.1" } +lucet-module = { path = "../lucet-module", version = "0.1.1" } lucet-runtime = { path = "../lucet-runtime", version = "0.1.1" } wabt = "0.7" serde = "1.0" diff --git a/lucet-spectest/src/bindings.rs b/lucet-spectest/src/bindings.rs index ca62ec87c..3e3bd32c2 100644 --- a/lucet-spectest/src/bindings.rs +++ b/lucet-spectest/src/bindings.rs @@ -1,4 +1,4 @@ -use lucet_module_data::bindings::Bindings; +use lucet_module::bindings::Bindings; use serde_json::json; use lucet_runtime::lucet_hostcalls; diff --git a/lucet-wasi-fuzz/Cargo.toml b/lucet-wasi-fuzz/Cargo.toml index 4a65ce647..0ef37b1b1 100644 --- a/lucet-wasi-fuzz/Cargo.toml +++ b/lucet-wasi-fuzz/Cargo.toml @@ -15,7 +15,7 @@ failure = "0.1" libc = "=0.2.59" lucetc = { path = "../lucetc" } lucet-runtime = { path = "../lucet-runtime" } -lucet-module-data = { path = "../lucet-module-data" } +lucet-module = { path = "../lucet-module" } lucet-wasi = { path = "../lucet-wasi" } lucet-wasi-sdk = { path = "../lucet-wasi-sdk" } nix = "0.13" diff --git a/lucet-wasi-fuzz/src/main.rs b/lucet-wasi-fuzz/src/main.rs index e475e32d2..ae90cd13f 100644 --- a/lucet-wasi-fuzz/src/main.rs +++ b/lucet-wasi-fuzz/src/main.rs @@ -2,7 +2,7 @@ use failure::{bail, ensure, format_err, Error}; use libc::c_ulong; -use lucet_module_data::bindings::Bindings; +use lucet_module::bindings::Bindings; use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region}; use lucet_wasi::host::__wasi_exitcode_t; use lucet_wasi::{WasiCtx, WasiCtxBuilder}; diff --git a/lucet-wasi-sdk/Cargo.toml b/lucet-wasi-sdk/Cargo.toml index 0b759ad44..870cf437b 100644 --- a/lucet-wasi-sdk/Cargo.toml +++ b/lucet-wasi-sdk/Cargo.toml @@ -12,5 +12,5 @@ edition = "2018" [dependencies] failure = "0.1" lucetc = { path = "../lucetc", version = "0.1.1" } -lucet-module-data = { path = "../lucet-module-data", version = "0.1.1" } +lucet-module = { path = "../lucet-module", version = "0.1.1" } tempfile = "3.0" diff --git a/lucet-wasi-sdk/tests/lucetc.rs b/lucet-wasi-sdk/tests/lucetc.rs index 61a32669c..adec574a0 100644 --- a/lucet-wasi-sdk/tests/lucetc.rs +++ b/lucet-wasi-sdk/tests/lucetc.rs @@ -1,7 +1,7 @@ #[cfg(test)] mod lucetc_tests { use failure::Error; - use lucet_module_data::bindings::Bindings; + use lucet_module::bindings::Bindings; use lucet_wasi_sdk::*; use lucetc::{Compiler, HeapSettings, OptLevel}; use std::collections::HashMap; diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index 148823e3d..19a239bb1 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -31,7 +31,7 @@ human-size = "0.4" libc = "=0.2.59" lucet-runtime = { path = "../lucet-runtime", version = "0.1.1" } lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.1.1" } -lucet-module-data = { path = "../lucet-module-data", version = "0.1.1" } +lucet-module = { path = "../lucet-module", version = "0.1.1" } nix = "0.13" rand = "0.6" diff --git a/lucet-wasi/src/bindings.rs b/lucet-wasi/src/bindings.rs index 05a82a306..0d454a1f0 100644 --- a/lucet-wasi/src/bindings.rs +++ b/lucet-wasi/src/bindings.rs @@ -1,4 +1,4 @@ -use lucet_module_data::bindings::Bindings; +use lucet_module::bindings::Bindings; pub fn bindings() -> Bindings { Bindings::from_str(include_str!("../bindings.json")).expect("lucet-wasi bindings.json is valid") diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index 3e5377705..27a1ff251 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -26,7 +26,7 @@ cranelift-module = { path = "../cranelift/cranelift-module", version = "0.31.0" cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.31.0" } cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.31.0" } target-lexicon = "0.4.0" -lucet-module-data = { path = "../lucet-module-data", version = "0.1.1" } +lucet-module = { path = "../lucet-module", version = "0.1.1" } wasmparser = "0.23" clap="2.32" log = "0.4" diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index c7ae5bd99..5a1d9afa1 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -18,8 +18,8 @@ use cranelift_module::{Backend as ClifBackend, Module as ClifModule}; use cranelift_native; use cranelift_wasm::{translate_module, FuncTranslator, WasmError}; use failure::{format_err, Fail, ResultExt}; -use lucet_module_data::bindings::Bindings; -use lucet_module_data::{FunctionSpec, ModuleData, MODULE_DATA_SYM}; +use lucet_module::bindings::Bindings; +use lucet_module::{FunctionSpec, ModuleData, MODULE_DATA_SYM}; #[derive(Debug, Clone, Copy)] pub enum OptLevel { diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index 360af58b8..55992c3cd 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -14,8 +14,8 @@ use cranelift_wasm::{ TableIndex, }; use failure::{format_err, Error, ResultExt}; -use lucet_module_data::bindings::Bindings; -use lucet_module_data::{ +use lucet_module::bindings::Bindings; +use lucet_module::{ owned::OwnedLinearMemorySpec, ExportFunction, FunctionIndex as LucetFunctionIndex, FunctionMetadata, Global as GlobalVariant, GlobalDef, GlobalSpec, HeapSpec, ImportFunction, ModuleData, Signature as LucetSignature, UniqueSignatureIndex, diff --git a/lucetc/src/function_manifest.rs b/lucetc/src/function_manifest.rs index 4871f8325..eff20a7c8 100644 --- a/lucetc/src/function_manifest.rs +++ b/lucetc/src/function_manifest.rs @@ -2,7 +2,7 @@ use crate::output::write_relocated_slice; use crate::traps::trap_sym_for_func; use faerie::{Artifact, Decl}; use failure::{Error, ResultExt}; -use lucet_module_data::FunctionSpec; +use lucet_module::FunctionSpec; use std::io::Cursor; use std::mem::size_of; diff --git a/lucetc/src/lib.rs b/lucetc/src/lib.rs index 4e080a3d9..5c7830b84 100644 --- a/lucetc/src/lib.rs +++ b/lucetc/src/lib.rs @@ -29,7 +29,7 @@ pub use crate::{ patch::patch_module, }; use failure::{format_err, Error, ResultExt}; -pub use lucet_module_data::bindings::Bindings; +pub use lucet_module::bindings::Bindings; use signature::{PublicKey, SecretKey}; use std::env; use std::path::{Path, PathBuf}; diff --git a/lucetc/src/main.rs b/lucetc/src/main.rs index 9c3a4a5df..14b064f3b 100644 --- a/lucetc/src/main.rs +++ b/lucetc/src/main.rs @@ -3,7 +3,7 @@ mod options; use crate::options::{CodegenOutput, Options}; use failure::{format_err, Error, ResultExt}; use log::info; -use lucet_module_data::bindings::Bindings; +use lucet_module::bindings::Bindings; use lucetc::{ signature::{self, PublicKey}, Lucetc, LucetcOpts, diff --git a/lucetc/src/module.rs b/lucetc/src/module.rs index a1bb7bb0f..aa605f9e2 100644 --- a/lucetc/src/module.rs +++ b/lucetc/src/module.rs @@ -7,7 +7,7 @@ use cranelift_wasm::{ FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, ModuleEnvironment, SignatureIndex, Table, TableElementType, TableIndex, WasmResult, }; -use lucet_module_data::UniqueSignatureIndex; +use lucet_module::UniqueSignatureIndex; use std::collections::{hash_map::Entry, HashMap}; /// UniqueFuncIndex names a function after merging duplicate function declarations to a single diff --git a/lucetc/src/output.rs b/lucetc/src/output.rs index 2a73d5d0d..08d65f997 100644 --- a/lucetc/src/output.rs +++ b/lucetc/src/output.rs @@ -10,7 +10,7 @@ use cranelift_codegen::{ir, isa}; use cranelift_faerie::FaerieProduct; use faerie::{Artifact, Decl, Link}; use failure::{format_err, Error, ResultExt}; -use lucet_module_data::{FunctionSpec, LUCET_MODULE_SYM, MODULE_DATA_SYM}; +use lucet_module::{FunctionSpec, LUCET_MODULE_SYM, MODULE_DATA_SYM}; use std::collections::HashMap; use std::fs::File; use std::io::{Cursor, Write}; diff --git a/lucetc/src/signature.rs b/lucetc/src/signature.rs index ad2e18385..17a64b3ad 100644 --- a/lucetc/src/signature.rs +++ b/lucetc/src/signature.rs @@ -1,5 +1,5 @@ use failure::*; -use lucet_module_data::ModuleSignature; +use lucet_module::ModuleSignature; pub use minisign::{KeyPair, PublicKey, SecretKey, SignatureBones, SignatureBox}; use std::fs::File; use std::io::{Cursor, Read, Write}; diff --git a/lucetc/src/sparsedata.rs b/lucetc/src/sparsedata.rs index 418923dfb..cdbffd881 100644 --- a/lucetc/src/sparsedata.rs +++ b/lucetc/src/sparsedata.rs @@ -1,12 +1,12 @@ use crate::error::{LucetcError, LucetcErrorKind}; use crate::module::DataInitializer; use failure::{format_err, ResultExt}; -use lucet_module_data::owned::OwnedSparseData; -use lucet_module_data::HeapSpec; +use lucet_module::owned::OwnedSparseData; +use lucet_module::HeapSpec; use std::collections::hash_map::Entry; use std::collections::HashMap; -pub use lucet_module_data::SparseData; +pub use lucet_module::SparseData; const PAGE_SIZE: usize = 4096; diff --git a/lucetc/src/traps.rs b/lucetc/src/traps.rs index 3c60fbad0..7aac74435 100644 --- a/lucetc/src/traps.rs +++ b/lucetc/src/traps.rs @@ -3,7 +3,7 @@ use cranelift_faerie::traps::FaerieTrapManifest; use faerie::{Artifact, Decl}; use failure::{Error, ResultExt}; -use lucet_module_data::TrapSite; +use lucet_module::TrapSite; pub fn write_trap_tables(manifest: &FaerieTrapManifest, obj: &mut Artifact) -> Result<(), Error> { for sink in manifest.sinks.iter() { @@ -49,19 +49,19 @@ pub(crate) fn trap_sym_for_func(sym: &str) -> String { // // Not all types have subtypes. Currently, only the user User type has a // subtype. -fn translate_trapcode(code: ir::TrapCode) -> lucet_module_data::TrapCode { +fn translate_trapcode(code: ir::TrapCode) -> lucet_module::TrapCode { match code { - ir::TrapCode::StackOverflow => lucet_module_data::TrapCode::StackOverflow, - ir::TrapCode::HeapOutOfBounds => lucet_module_data::TrapCode::HeapOutOfBounds, - ir::TrapCode::OutOfBounds => lucet_module_data::TrapCode::OutOfBounds, - ir::TrapCode::IndirectCallToNull => lucet_module_data::TrapCode::IndirectCallToNull, - ir::TrapCode::BadSignature => lucet_module_data::TrapCode::BadSignature, - ir::TrapCode::IntegerOverflow => lucet_module_data::TrapCode::IntegerOverflow, - ir::TrapCode::IntegerDivisionByZero => lucet_module_data::TrapCode::IntegerDivByZero, - ir::TrapCode::BadConversionToInteger => lucet_module_data::TrapCode::BadConversionToInteger, - ir::TrapCode::Interrupt => lucet_module_data::TrapCode::Interrupt, - ir::TrapCode::TableOutOfBounds => lucet_module_data::TrapCode::TableOutOfBounds, - ir::TrapCode::UnreachableCodeReached => lucet_module_data::TrapCode::Unreachable, + ir::TrapCode::StackOverflow => lucet_module::TrapCode::StackOverflow, + ir::TrapCode::HeapOutOfBounds => lucet_module::TrapCode::HeapOutOfBounds, + ir::TrapCode::OutOfBounds => lucet_module::TrapCode::OutOfBounds, + ir::TrapCode::IndirectCallToNull => lucet_module::TrapCode::IndirectCallToNull, + ir::TrapCode::BadSignature => lucet_module::TrapCode::BadSignature, + ir::TrapCode::IntegerOverflow => lucet_module::TrapCode::IntegerOverflow, + ir::TrapCode::IntegerDivisionByZero => lucet_module::TrapCode::IntegerDivByZero, + ir::TrapCode::BadConversionToInteger => lucet_module::TrapCode::BadConversionToInteger, + ir::TrapCode::Interrupt => lucet_module::TrapCode::Interrupt, + ir::TrapCode::TableOutOfBounds => lucet_module::TrapCode::TableOutOfBounds, + ir::TrapCode::UnreachableCodeReached => lucet_module::TrapCode::Unreachable, ir::TrapCode::User(_) => panic!("we should never emit a user trapcode"), } } diff --git a/lucetc/tests/wasm.rs b/lucetc/tests/wasm.rs index 84b695cca..7ca2d65f1 100644 --- a/lucetc/tests/wasm.rs +++ b/lucetc/tests/wasm.rs @@ -1,4 +1,4 @@ -use lucet_module_data::bindings::Bindings; +use lucet_module::bindings::Bindings; use std::collections::HashMap; use std::path::PathBuf; @@ -33,7 +33,7 @@ fn test_bindings() -> Bindings { mod module_data { /// Tests of the `ModuleData` generated by the lucetc Compiler use super::load_wat_module; - use lucet_module_data::bindings::Bindings; + use lucet_module::bindings::Bindings; use lucetc::{Compiler, HeapSettings, LucetcErrorKind, OptLevel}; use std::path::PathBuf; @@ -244,7 +244,7 @@ mod module_data { #[test] fn globals_import() { - use lucet_module_data::Global as GlobalVariant; + use lucet_module::Global as GlobalVariant; let m = load_wat_module("globals_import"); let b = Bindings::empty(); let h = HeapSettings::default(); @@ -266,7 +266,7 @@ mod module_data { #[test] fn heap_spec_import() { - use lucet_module_data::HeapSpec; + use lucet_module::HeapSpec; let m = load_wat_module("heap_spec_import"); let b = Bindings::empty(); let h = HeapSettings::default(); @@ -289,7 +289,7 @@ mod module_data { #[test] fn heap_spec_definition() { - use lucet_module_data::HeapSpec; + use lucet_module::HeapSpec; let m = load_wat_module("heap_spec_definition"); let b = Bindings::empty(); let h = HeapSettings::default(); From 464460e039d127051a9d6b2442a7cfeaca0ddd84 Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Fri, 12 Jul 2019 12:11:28 +0200 Subject: [PATCH 264/512] wasmonkey: create a new name section if there isn't any (#246) We used to assume that there was always a name section. But running wasm-opt can strip that section. --- Cargo.lock | 17 ++++++++++++++--- lucet-builtins/wasmonkey/Cargo.toml | 4 ++-- lucet-builtins/wasmonkey/src/patcher.rs | 9 ++++++++- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 798a4a11b..bf4035515 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -644,6 +644,16 @@ dependencies = [ "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "goblin" +version = "0.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hashbrown" version = "0.1.8" @@ -987,7 +997,7 @@ dependencies = [ "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmonkey 0.1.7", + "wasmonkey 0.1.8", "wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1844,11 +1854,11 @@ dependencies = [ [[package]] name = "wasmonkey" -version = "0.1.7" +version = "0.1.8" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.0.23 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2004,6 +2014,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6a4013e9182f2345c6b7829b9ef6e670bce0dfca12c6f974457ed2160c2c7fe9" "checksum goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "7f55d53401eb2fd30afd025c570b1946b6966344acf21b42e31286f3bf89e6a8" +"checksum goblin 0.0.23 (registry+https://github.com/rust-lang/crates.io-index)" = "ac56b4753b6b8c2e052ca30717e5a09acf1b02a2c1681bf3d883bd660e5d22bd" "checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f127a908633569f208325f86f71255d3363c79721d7f9fe31cd5569908819771" diff --git a/lucet-builtins/wasmonkey/Cargo.toml b/lucet-builtins/wasmonkey/Cargo.toml index 65863fd62..c1abb5fa8 100644 --- a/lucet-builtins/wasmonkey/Cargo.toml +++ b/lucet-builtins/wasmonkey/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmonkey" -version = "0.1.7" +version = "0.1.8" authors = ["Lucet team "] description = "Patch a WASM object file to replace a set of exported functions with imported functions from another library" license = "Apache-2.0 WITH LLVM-exception" @@ -12,7 +12,7 @@ edition = "2018" [dependencies] clap = "2.33" failure = "0.1" -goblin = "0.0.22" +goblin = "0.0.23" lazy_static = "1.3" parity-wasm = "0.38" serde = "1.0" diff --git a/lucet-builtins/wasmonkey/src/patcher.rs b/lucet-builtins/wasmonkey/src/patcher.rs index 3eb0df26d..8e018060e 100644 --- a/lucet-builtins/wasmonkey/src/patcher.rs +++ b/lucet-builtins/wasmonkey/src/patcher.rs @@ -6,7 +6,8 @@ use crate::sections::*; use crate::symbols::{self, ExtractedSymbols}; use parity_wasm; use parity_wasm::elements::{ - self, External, ImportEntry, ImportSection, Internal, Module, Section, + self, External, FunctionNameSubsection, ImportEntry, ImportSection, Internal, Module, + NameSection, Section, }; use std::collections::HashMap; use std::path::{Path, PathBuf}; @@ -173,6 +174,12 @@ fn prepend_builtin_to_import_section(module: &mut Module, builtin: &Builtin) -> fn prepend_builtin_to_names_section(module: &mut Module, builtin: &Builtin) -> Result<(), WError> { let import_name = builtin.import_name(); + if module.names_section().is_none() { + let sections = module.sections_mut(); + let function_names_subsection = FunctionNameSubsection::default(); + let name_section = NameSection::new(None, Some(function_names_subsection), None); + sections.push(Section::Name(name_section)); + } let names_section = module .names_section_mut() .expect("Names section not present"); From cc46ba9137df2e62531539b01709dacb36fa3fa0 Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Mon, 15 Jul 2019 18:35:31 +0200 Subject: [PATCH 265/512] Install wasm-opt and wasm-reduce, use wasm-opt for benchmarking wasm code (#248) --- Dockerfile | 10 ++++++++++ benchmarks/shootout/Makefile | 11 +++++++++-- helpers/install.sh | 6 ++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index bc0278740..069707fe6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -41,3 +41,13 @@ RUN curl -sS -L -O https://github.com/CraneStation/wasi-sdk/releases/download/wa && dpkg -i wasi-sdk_5.0_amd64.deb && rm -f wasi-sdk_5.0_amd64.deb ENV WASI_SDK=/opt/wasi-sdk + +ENV BINARYEN_DIR=/opt/binaryen +ENV BINARYEN_VERSION=86 +RUN curl -sS -L "https://github.com/WebAssembly/binaryen/archive/version_${BINARYEN_VERSION}.tar.gz" | tar xzf - && \ + mkdir -p binaryen-build && ( cd binaryen-build && cmake "../binaryen-version_${BINARYEN_VERSION}" && \ + make wasm-opt wasm-reduce ) && \ + install -d -v "${BINARYEN_DIR}/bin" && \ + for tool in wasm-opt wasm-reduce; do install -v "binaryen-build/bin/${tool}" "${BINARYEN_DIR}/bin/"; done && \ + rm -fr binaryen-build binaryen-version_${BINARYEN_VERSION} +ENV PATH=$BINARYEN_DIR:$PATH diff --git a/benchmarks/shootout/Makefile b/benchmarks/shootout/Makefile index ac5607998..6ab2406d1 100644 --- a/benchmarks/shootout/Makefile +++ b/benchmarks/shootout/Makefile @@ -1,7 +1,9 @@ LUCET_ROOT:=$(abspath ../..) WASI_SDK?=/opt/wasi-sdk -WASI_CC=$(WASI_SDK)/bin/clang +WASI_CC?=$(WASI_SDK)/bin/clang +BINARYEN_DIR?=/opt/binaryen +WASM_OPT?=$(shell command -v wasm-opt || echo $(BINARYEN_DIR)/bin/wasm-opt) LUCETC:=$(LUCET_ROOT)/target/release/lucetc @@ -23,6 +25,8 @@ SHOOTOUT_NATIVE_CFLAGS:=-march=native -fPIC \ -DIMPL_REFERENCE -DUSE_LEND \ -Dmalloc=lend_malloc -Dcalloc=lend_calloc -Dfree=lend_free +BINARYEN_VERSION=86 + ifdef CI SIGHTGLASS_ARGS:=--quick endif @@ -60,10 +64,13 @@ build/lucet/shootout/%.o: $(SHOOTOUT)/%.c @mkdir -p $(@D) $(WASI_CC) $(COMMON_CFLAGS) -c $^ -o $@ -build/lucet/module.wasm: $(patsubst %.c, %.o, $(addprefix build/lucet/shootout/, $(notdir $(SHOOTOUT_SRCS)))) +build/lucet/module.wasm.unoptimized: $(patsubst %.c, %.o, $(addprefix build/lucet/shootout/, $(notdir $(SHOOTOUT_SRCS)))) @mkdir -p $(@D) $(WASI_CC) $^ -o $@ -nostartfiles -Wl,--no-entry -Wl,--export-all +build/lucet/module.wasm: build/lucet/module.wasm.unoptimized + $(WASM_OPT) -mvp --disable-mutable-globals -O4 -o $@ $^ + # Don't emit the shared object, we need a saparate link step below. build/lucet/module.o: build/lucet/module.wasm $(LIBBUILTINS) @mkdir -p $(@D) diff --git a/helpers/install.sh b/helpers/install.sh index 253bde343..25ef61d0e 100755 --- a/helpers/install.sh +++ b/helpers/install.sh @@ -29,6 +29,8 @@ LUCET_BUNDLE_DOC_DIR=${LUCET_BUNDLE_DOC_DIR:-"${LUCET_DOC_DIR}/lucet"} WASI_SDK_PREFIX=${WASI_SDK_PREFIX:-${WASI_SDK:-"/opt/wasi-sdk"}} WASI_TARGET=${WASI_TARGET:-"wasm32-wasi"} WASI_BIN_PREFIX=${WASI_BIN_PREFIX:-"$WASI_TARGET"} +BINARYEN_DIR=${BINARYEN_DIR:-"/opt/binaryen"} +BINARYEN_BIN_DIR=${BINARYEN_BIN_DIR:-"${BINARYEN_DIR}/bin"} if [ "$(uname -s)" = "Darwin" ]; then DYLIB_SUFFIX="dylib" @@ -218,6 +220,10 @@ rm -f "$wrapper_file" find assemblyscript -type f -exec install -p -v -m 0644 "{}" "${LUCET_SHARE_DIR}/{}" \; ) +for file in wasm-opt wasm-reduce; do + ln -sfv "${BINARYEN_BIN_DIR}/${file}" "${LUCET_BIN_DIR}/${file}" +done + if test -t 0; then echo echo "Lucet has been installed in [${LUCET_PREFIX}]" From bc8aaef0a338c540b4775610dcb51abbb3155e1c Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Mon, 15 Jul 2019 18:35:47 +0200 Subject: [PATCH 266/512] Don't just unwrap() on references to non-local tables (#251) * Don't just unwrap() on references to non-local tables Fixes #250 * Add LucetcErrorKind::Unsupported context --- lucetc/src/decls.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index 55992c3cd..3903aad98 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -444,7 +444,15 @@ impl<'a> ModuleDecls<'a> { .ok_or_else(|| format_err!("table index out of bounds: {:?}", table_index))?; let exportable_tbl = self.info.tables.get(table_index).unwrap(); let import_name = self.info.imported_tables.get(table_index); - let elems = self.info.table_elems.get(&table_index).unwrap().as_slice(); + let elems = self + .info + .table_elems + .get(&table_index) + .ok_or_else(|| { + format_err!("table is not local: {:?}", table_index) + .context(LucetcErrorKind::Unsupported) + })? + .as_slice(); Ok(TableDecl { table: &exportable_tbl.entity, elems, From 613fae3d53e000929db04f6fc2272460125cdfed Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Fri, 26 Jul 2019 15:07:23 -0700 Subject: [PATCH 267/512] [lucet-runtime-internals] add `Context::swap_yield()` and some tests --- .../src/context/mod.rs | 8 ++ .../src/context/tests/rust_child.rs | 99 +++++++++++++++++++ 2 files changed, 107 insertions(+) diff --git a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs index da957d636..745c96bd1 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs @@ -7,6 +7,7 @@ use crate::val::{val_to_reg, val_to_stack, RegVal, UntypedRetVal, Val}; use failure::Fail; use nix; use nix::sys::signal; +use std::any::Any; use std::arch::x86_64::{__m128, _mm_setzero_ps}; use std::mem; use std::ptr::NonNull; @@ -115,6 +116,7 @@ pub struct Context { retvals_gp: [u64; 2], retval_fp: __m128, sigset: signal::SigSet, + yielded: Option>, } impl Context { @@ -126,6 +128,7 @@ impl Context { retvals_gp: [0; 2], retval_fp: unsafe { _mm_setzero_ps() }, sigset: signal::SigSet::empty(), + yielded: None, } } } @@ -448,6 +451,11 @@ impl Context { lucet_context_swap(from as *mut Context, to as *const Context); } + pub unsafe fn swap_yield(from: &mut Context, to: &Context, val: A) { + from.yielded = Some(Box::new(val)); + Context::swap(from, to); + } + /// Swap to another context without saving the current context. /// /// - `to`: the context to read from and swap to diff --git a/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs b/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs index 7292114b9..19aee7085 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs @@ -478,3 +478,102 @@ fn guest_access_tls() { assert_output_eq!("tls = 42"); }); } + +#[test] +fn yield_nil() { + unsafe extern "C" fn guest_fn() { + Context::swap_yield(CHILD.as_mut().unwrap(), PARENT.as_ref().unwrap(), ()); + } + + test_body!(stack, { + init_and_swap!(stack, guest_fn, []); + unsafe { + assert!(CHILD.as_ref().unwrap().yielded.is_some()); + } + }); +} + +#[test] +fn yield_5() { + unsafe extern "C" fn guest_fn() { + Context::swap_yield(CHILD.as_mut().unwrap(), PARENT.as_ref().unwrap(), 5u64); + } + + test_body!(stack, { + init_and_swap!(stack, guest_fn, []); + unsafe { + let yielded = CHILD.as_mut().unwrap().yielded.take().unwrap(); + let val = yielded.downcast::().unwrap(); + assert_eq!(*val, 5u64); + } + }); +} + +#[test] +fn yield_factorials() { + unsafe extern "C" fn guest_fn(n: u64) -> u64 { + if n <= 1 { + Context::swap_yield(CHILD.as_mut().unwrap(), PARENT.as_ref().unwrap(), 1u64); + 1 + } else { + let n = n * guest_fn(n - 1); + Context::swap_yield(CHILD.as_mut().unwrap(), PARENT.as_ref().unwrap(), n); + n + } + } + + test_body!(stack, { + init_and_swap!(stack, guest_fn, [5u64.into()]); + let mut facs = vec![]; + while let Some(yielded) = unsafe { CHILD.as_mut().unwrap().yielded.take() } { + facs.push(*yielded.downcast::().unwrap()); + unsafe { + Context::swap(PARENT.as_mut().unwrap(), CHILD.as_ref().unwrap()); + } + } + assert_eq!(facs.as_slice(), &[1, 2, 6, 24, 120]); + }); +} + +#[test] +fn coop_factorials() { + unsafe extern "C" fn guest_fn(n: u64) -> u64 { + if n <= 1 { + Context::swap_yield(CHILD.as_mut().unwrap(), PARENT.as_ref().unwrap(), 1u64); + 1 + } else { + let n_rec = guest_fn(n - 1); + Context::swap_yield( + CHILD.as_mut().unwrap(), + PARENT.as_ref().unwrap(), + (n, n_rec), + ); + + let yielded = PARENT.as_mut().unwrap().yielded.take().unwrap(); + let n = *yielded.downcast::().unwrap(); + + Context::swap_yield(CHILD.as_mut().unwrap(), PARENT.as_ref().unwrap(), n); + n + } + } + + test_body!(stack, { + init_and_swap!(stack, guest_fn, [5u64.into()]); + let mut facs = vec![]; + while let Some(yielded) = unsafe { CHILD.as_mut().unwrap().yielded.take() } { + if let Some(ns) = yielded.downcast_ref::<(u64, u64)>() { + let (n, n_rec) = *ns; + let n = n * n_rec; + unsafe { + Context::swap_yield(PARENT.as_mut().unwrap(), CHILD.as_ref().unwrap(), n); + } + } else if let Some(n) = yielded.downcast_ref::() { + facs.push(*n); + unsafe { + Context::swap(PARENT.as_mut().unwrap(), CHILD.as_ref().unwrap()); + } + } + } + assert_eq!(facs.as_slice(), &[1, 2, 6, 24, 120]); + }); +} From 196215f7c38047b78380d2a4e80ac0753fdf2d24 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Fri, 26 Jul 2019 17:56:07 -0700 Subject: [PATCH 268/512] [lucet-runtime] add yield/resume APIs to `Instance` and `Vmctx` Still need to document these, add corresponding C APIs, and remove the initial Context-based experiment --- lucet-runtime/include/lucet_types.h | 7 + .../lucet-runtime-internals/src/c_api.rs | 35 +++- .../lucet-runtime-internals/src/error.rs | 5 +- .../lucet-runtime-internals/src/instance.rs | 94 ++++++++- .../lucet-runtime-internals/src/vmctx.rs | 44 +++- lucet-runtime/lucet-runtime-tests/src/host.rs | 195 ++++++++++++++++++ lucet-runtime/src/c_api.rs | 4 +- 7 files changed, 379 insertions(+), 5 deletions(-) diff --git a/lucet-runtime/include/lucet_types.h b/lucet-runtime/include/lucet_types.h index 9f1ba37b1..1d3cb4ed7 100644 --- a/lucet-runtime/include/lucet_types.h +++ b/lucet-runtime/include/lucet_types.h @@ -27,6 +27,7 @@ enum lucet_error { lucet_error_func_not_found, lucet_error_runtime_fault, lucet_error_runtime_terminated, + lucet_error_instance_yielded, lucet_error_dl, lucet_error_internal, lucet_error_unsupported, @@ -48,6 +49,7 @@ enum lucet_state_tag { enum lucet_terminated_reason { lucet_terminated_reason_signal, lucet_terminated_reason_ctx_not_found, + lucet_terminated_reason_yield_type_mismatch, lucet_terminated_reason_borrow_error, lucet_terminated_reason_provided, }; @@ -160,11 +162,16 @@ struct lucet_terminated { void * provided; }; +struct lucet_yielded { + void *val; +}; + union lucet_state_val { struct lucet_untyped_retval returned; bool running; struct lucet_runtime_fault fault; struct lucet_terminated terminated; + struct lucet_yielded yielded; }; struct lucet_state { diff --git a/lucet-runtime/lucet-runtime-internals/src/c_api.rs b/lucet-runtime/lucet-runtime-internals/src/c_api.rs index c50d56514..63c57a812 100644 --- a/lucet-runtime/lucet-runtime-internals/src/c_api.rs +++ b/lucet-runtime/lucet-runtime-internals/src/c_api.rs @@ -75,6 +75,7 @@ pub enum lucet_error { FuncNotFound, RuntimeFault, RuntimeTerminated, + InstanceYielded, Dl, Internal, Unsupported, @@ -92,6 +93,7 @@ impl From for lucet_error { Error::FuncNotFound(_, _) => lucet_error::FuncNotFound, Error::RuntimeFault(_) => lucet_error::RuntimeFault, Error::RuntimeTerminated(_) => lucet_error::RuntimeTerminated, + Error::InstanceYielded(_) => lucet_error::InstanceYielded, Error::DlError(_) => lucet_error::Dl, Error::InternalError(_) => lucet_error::Internal, Error::Unsupported(_) => lucet_error::Unsupported, @@ -205,8 +207,15 @@ pub struct CTerminationDetails { unsafe impl Send for CTerminationDetails {} unsafe impl Sync for CTerminationDetails {} +pub struct CYieldedVal { + pub val: *mut c_void, +} + +unsafe impl Send for CYieldedVal {} +unsafe impl Sync for CYieldedVal {} + pub mod lucet_state { - use crate::c_api::{lucet_val, CTerminationDetails}; + use crate::c_api::{lucet_val, CTerminationDetails, CYieldedVal}; use crate::instance::{State, TerminationDetails}; use crate::module::{AddrDetails, TrapCode}; use crate::sysdeps::UContext; @@ -257,6 +266,10 @@ pub mod lucet_state { reason: lucet_terminated_reason::CtxNotFound, provided: std::ptr::null_mut(), }, + TerminationDetails::YieldTypeMismatch => lucet_terminated { + reason: lucet_terminated_reason::YieldTypeMismatch, + provided: std::ptr::null_mut(), + }, TerminationDetails::BorrowError(_) => lucet_terminated { reason: lucet_terminated_reason::BorrowError, provided: std::ptr::null_mut(), @@ -271,6 +284,17 @@ pub mod lucet_state { }, }, }, + State::Yielded { val, .. } => lucet_state { + tag: lucet_state_tag::Yielded, + val: lucet_state_val { + yielded: lucet_yielded { + val: val + .downcast_ref() + .map(|CYieldedVal { val }| *val) + .unwrap_or(std::ptr::null_mut()), + }, + }, + }, } } } @@ -289,6 +313,7 @@ pub mod lucet_state { Running, Fault, Terminated, + Yielded, } #[repr(C)] @@ -299,6 +324,7 @@ pub mod lucet_state { pub running: bool, pub fault: lucet_runtime_fault, pub terminated: lucet_terminated, + pub yielded: lucet_yielded, } #[repr(C)] @@ -313,10 +339,17 @@ pub mod lucet_state { pub enum lucet_terminated_reason { Signal, CtxNotFound, + YieldTypeMismatch, BorrowError, Provided, } + #[repr(C)] + #[derive(Clone, Copy)] + pub struct lucet_yielded { + pub val: *mut c_void, + } + #[repr(C)] #[derive(Clone, Copy)] pub struct lucet_runtime_fault { diff --git a/lucet-runtime/lucet-runtime-internals/src/error.rs b/lucet-runtime/lucet-runtime-internals/src/error.rs index 759047872..a96b25b9a 100644 --- a/lucet-runtime/lucet-runtime-internals/src/error.rs +++ b/lucet-runtime/lucet-runtime-internals/src/error.rs @@ -1,4 +1,4 @@ -use crate::instance::{FaultDetails, TerminationDetails}; +use crate::instance::{FaultDetails, TerminationDetails, YieldedVal}; use failure::Fail; /// Lucet runtime errors. @@ -45,6 +45,9 @@ pub enum Error { #[fail(display = "Runtime terminated")] RuntimeTerminated(TerminationDetails), + #[fail(display = "Instance yielded")] + InstanceYielded(YieldedVal), + /// IO errors arising during dynamic loading with [`DlModule`](struct.DlModule.html). #[fail(display = "Dynamic loading error: {}", _0)] DlError(#[cause] std::io::Error), diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index add2e1d0d..e6b8eb33f 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -187,7 +187,7 @@ pub struct Instance { module: Arc, /// The `Context` in which the guest program runs - ctx: Context, + pub(crate) ctx: Context, /// Instance state and error information pub(crate) state: State, @@ -216,6 +216,8 @@ pub struct Instance { /// Pointer to the function used as the entrypoint (for use in backtraces) entrypoint: Option, + pub(crate) val_from_host: Option>, + /// `_padding` must be the last member of the structure. /// This marks where the padding starts to make the structure exactly 4096 bytes long. /// It is also used to compute the size of the structure up to that point, i.e. without padding. @@ -517,6 +519,7 @@ impl Instance { c_fatal_handler: None, signal_handler: Box::new(signal_handler_none) as Box, entrypoint: None, + val_from_host: None, _padding: (), }; inst.set_globals_ptr(globals_ptr); @@ -595,6 +598,30 @@ impl Instance { ) })?; + self.swap_and_return() + } + + pub fn resume(&mut self) -> Result { + lucet_ensure!( + self.state.is_yielded(), + "can only resume from a call to `Vmctx::yield_*()`" + ); + + self.swap_and_return() + } + + pub fn resume_with_val(&mut self, val: A) -> Result { + lucet_ensure!( + self.state.is_yielded(), + "can only resume from a call to `Vmctx::yield_*()`" + ); + + self.val_from_host = Some(Box::new(val) as Box); + + self.swap_and_return() + } + + fn swap_and_return(&mut self) -> Result { self.state = State::Running; // there should never be another instance running on this thread when we enter this function @@ -634,6 +661,7 @@ impl Instance { Ok(retval) } State::Terminated { details, .. } => Err(Error::RuntimeTerminated(details.clone())), + State::Yielded { val, .. } => Err(Error::InstanceYielded(val.clone())), State::Fault { .. } => { // Sandbox is no longer runnable. It's unsafe to determine all error details in the signal // handler, so we fill in extra details here. @@ -707,6 +735,9 @@ pub enum State { Terminated { details: TerminationDetails, }, + Yielded { + val: YieldedVal, + }, } /// Information about a runtime fault. @@ -772,6 +803,7 @@ pub enum TerminationDetails { Signal, /// Returned when `get_embed_ctx` or `get_embed_ctx_mut` are used with a type that is not present. CtxNotFound, + YieldTypeMismatch, /// Returned when dynamic borrowing rules of methods like `Vmctx::heap()` are violated. BorrowError(&'static str), /// Calls to `lucet_hostcall_terminate` provide a payload for use by the embedder. @@ -823,6 +855,7 @@ impl std::fmt::Debug for TerminationDetails { TerminationDetails::Signal => write!(f, "Signal"), TerminationDetails::BorrowError(msg) => write!(f, "BorrowError({})", msg), TerminationDetails::CtxNotFound => write!(f, "CtxNotFound"), + TerminationDetails::YieldTypeMismatch => write!(f, "YieldTypeMismatch"), TerminationDetails::Provided(_) => write!(f, "Provided(Any)"), } } @@ -831,6 +864,56 @@ impl std::fmt::Debug for TerminationDetails { unsafe impl Send for TerminationDetails {} unsafe impl Sync for TerminationDetails {} +#[derive(Clone)] +pub struct YieldedVal { + val: Option>, +} + +impl std::fmt::Debug for YieldedVal { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.val.is_none() { + write!(f, "YieldedVal {{ val: None }}") + } else { + write!(f, "YieldedVal {{ val: Some }}") + } + } +} + +impl YieldedVal { + pub(crate) fn some(val: A) -> Self { + YieldedVal { + val: Some(Arc::new(val)), + } + } + + pub(crate) fn none() -> Self { + YieldedVal { val: None } + } + + pub fn is_none(&self) -> bool { + self.val.is_none() + } + + pub fn is_some(&self) -> bool { + self.val.is_some() + } + + pub fn downcast(self) -> Result, YieldedVal> { + if let Some(val) = self.val { + match val.downcast() { + Ok(val) => Ok(val), + Err(val) => Err(YieldedVal { val: Some(val) }), + } + } else { + Err(self) + } + } + + pub fn downcast_ref(&self) -> Option<&A> { + self.val.as_ref().and_then(|val| val.downcast_ref()) + } +} + impl std::fmt::Display for State { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -860,6 +943,7 @@ impl std::fmt::Display for State { Ok(()) } State::Terminated { .. } => write!(f, "terminated"), + State::Yielded { .. } => write!(f, "yielded"), } } } @@ -908,6 +992,14 @@ impl State { false } } + + pub fn is_yielded(&self) -> bool { + if let State::Yielded { .. } = self { + true + } else { + false + } + } } fn default_fatal_handler(inst: &Instance) -> ! { diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index 5c7d5bab4..3915ab5dc 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -9,7 +9,7 @@ use crate::alloc::instance_heap_offset; use crate::context::Context; use crate::error::Error; use crate::instance::{ - Instance, InstanceInternal, State, TerminationDetails, CURRENT_INSTANCE, HOST_CTX, + Instance, InstanceInternal, State, TerminationDetails, YieldedVal, CURRENT_INSTANCE, HOST_CTX, }; use lucet_module::{FunctionHandle, GlobalValue}; use std::any::Any; @@ -268,6 +268,48 @@ impl Vmctx { .module() .get_func_from_idx(table_idx, func_idx) } + + pub fn yield_(&self) { + let inst = unsafe { self.instance_mut() }; + inst.state = State::Yielded { + val: YieldedVal::none(), + }; + HOST_CTX.with(|host_ctx| unsafe { Context::swap(&mut inst.ctx, &mut *host_ctx.get()) }); + } + + pub fn yield_expecting_val(&self) -> R { + self.yield_(); + self.get_expected_val() + } + + pub fn yield_val(&self, val: A) { + let inst = unsafe { self.instance_mut() }; + inst.state = State::Yielded { + val: YieldedVal::some(val), + }; + HOST_CTX.with(|host_ctx| unsafe { Context::swap(&mut inst.ctx, &mut *host_ctx.get()) }); + } + + pub fn yield_val_expecting_val( + &self, + val: A, + ) -> R { + self.yield_val(val); + self.get_expected_val() + } + + fn get_expected_val(&self) -> R { + let inst = unsafe { self.instance_mut() }; + if let Some(val) = inst.val_from_host.take() { + if let Ok(val) = val.downcast() { + *val + } else { + panic!(TerminationDetails::YieldTypeMismatch) + } + } else { + panic!(TerminationDetails::YieldTypeMismatch) + } + } } /// Get an `Instance` from the `vmctx` pointer. diff --git a/lucet-runtime/lucet-runtime-tests/src/host.rs b/lucet-runtime/lucet-runtime-tests/src/host.rs index b84f48c32..5246deaf8 100644 --- a/lucet-runtime/lucet-runtime-tests/src/host.rs +++ b/lucet-runtime/lucet-runtime-tests/src/host.rs @@ -100,6 +100,64 @@ macro_rules! host_tests { res } + + #[no_mangle] + pub unsafe extern "C" fn hostcall_yields( + &mut vmctx, + ) -> () { + vmctx.yield_(); + } + + #[no_mangle] + pub unsafe extern "C" fn hostcall_yield_expects_5( + &mut vmctx, + ) -> u64 { + vmctx.yield_expecting_val() + } + + #[no_mangle] + pub unsafe extern "C" fn hostcall_yields_5( + &mut vmctx, + ) -> () { + vmctx.yield_val(5u64); + } + + #[no_mangle] + pub unsafe extern "C" fn hostcall_yield_facts( + &mut vmctx, + n: u64, + ) -> () { + fn fact(vmctx: &mut Vmctx, n: u64) -> u64 { + if n <= 1 { + vmctx.yield_val(1u64); + 1 + } else { + let n = n * fact(vmctx, n - 1); + vmctx.yield_val(n); + n + } + } + fact(vmctx, n); + } + + #[no_mangle] + pub unsafe extern "C" fn hostcall_coop_facts( + &mut vmctx, + n: u64, + ) -> () { + fn fact(vmctx: &mut Vmctx, n: u64) -> u64 { + if n <= 1 { + vmctx.yield_val(1u64); + 1 + } else { + let n_rec = fact(vmctx, n - 1); + let n = vmctx.yield_val_expecting_val((n, n_rec)); + vmctx.yield_val(n); + n + } + } + fact(vmctx, n); + } } #[test] @@ -295,5 +353,142 @@ macro_rules! host_tests { let retval = inst.run("f", &[]).expect("instance runs"); assert_eq!(bool::from(retval), true); } + + #[test] + fn run_hostcall_yields_5() { + extern "C" { + fn hostcall_yields_5(vmctx: *mut lucet_vmctx); + } + + unsafe extern "C" fn f(vmctx: *mut lucet_vmctx) { + hostcall_yields_5(vmctx); + } + + let module = MockModuleBuilder::new() + .with_export_func(MockExportBuilder::new( + "f", + FunctionPointer::from_usize(f as usize), + )) + .build(); + + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + if let Err(Error::InstanceYielded(val)) = inst.run("f", &[]) { + assert_eq!(*val.downcast::().unwrap(), 5u64); + } else { + panic!("instance didn't yield"); + } + } + + #[test] + fn run_hostcall_yield_expects_5() { + extern "C" { + fn hostcall_yield_expects_5(vmctx: *mut lucet_vmctx) -> u64; + } + + unsafe extern "C" fn f(vmctx: *mut lucet_vmctx) -> u64 { + hostcall_yield_expects_5(vmctx) + } + + let module = MockModuleBuilder::new() + .with_export_func(MockExportBuilder::new( + "f", + FunctionPointer::from_usize(f as usize), + )) + .build(); + + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + if let Err(Error::InstanceYielded(val)) = inst.run("f", &[]) { + assert!(val.is_none()); + } else { + panic!("instance didn't yield"); + } + + let retval = inst.resume_with_val(5u64).expect("instance resumes"); + assert_eq!(u64::from(retval), 5u64); + } + + #[test] + fn yield_factorials() { + extern "C" { + fn hostcall_yield_facts(vmctx: *mut lucet_vmctx, n: u64); + } + + unsafe extern "C" fn f(vmctx: *mut lucet_vmctx) { + hostcall_yield_facts(vmctx, 5); + } + + let module = MockModuleBuilder::new() + .with_export_func(MockExportBuilder::new( + "f", + FunctionPointer::from_usize(f as usize), + )) + .build(); + + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + let mut facts = vec![]; + + let mut res = inst.run("f", &[]); + + while let Err(Error::InstanceYielded(val)) = res { + facts.push(*val.downcast::().unwrap()); + res = inst.resume(); + } + + assert_eq!(facts.as_slice(), &[1, 2, 6, 24, 120]); + } + + #[test] + fn coop_factorials() { + extern "C" { + fn hostcall_coop_facts(vmctx: *mut lucet_vmctx, n: u64); + } + + unsafe extern "C" fn f(vmctx: *mut lucet_vmctx) { + hostcall_coop_facts(vmctx, 5); + } + + let module = MockModuleBuilder::new() + .with_export_func(MockExportBuilder::new( + "f", + FunctionPointer::from_usize(f as usize), + )) + .build(); + + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + let mut facts = vec![]; + + let mut res = inst.run("f", &[]); + + while let Err(Error::InstanceYielded(val)) = res { + if let Some((n, n_rec)) = val.downcast_ref::<(u64, u64)>() { + // guest wants us to multiply for it + res = inst.resume_with_val(n * n_rec); + } else if let Some(n) = val.downcast_ref::() { + // guest is returning an answer + facts.push(*n); + res = inst.resume(); + } else { + panic!("didn't yield with expected type"); + } + } + + assert_eq!(facts.as_slice(), &[1, 2, 6, 24, 120]); + } }; } diff --git a/lucet-runtime/src/c_api.rs b/lucet-runtime/src/c_api.rs index 8d4f79652..f37675590 100644 --- a/lucet-runtime/src/c_api.rs +++ b/lucet-runtime/src/c_api.rs @@ -45,6 +45,7 @@ pub extern "C" fn lucet_error_name(e: c_int) -> *const c_char { FuncNotFound => "lucet_error_func_not_found\0".as_ptr() as _, RuntimeFault => "lucet_error_runtime_fault\0".as_ptr() as _, RuntimeTerminated => "lucet_error_runtime_terminated\0".as_ptr() as _, + InstanceYielded => "lucet_error_instance_yielded\0".as_ptr() as _, Dl => "lucet_error_dl\0".as_ptr() as _, Internal => "lucet_error_internal\0".as_ptr() as _, Unsupported => "lucet_error_unsupported\0".as_ptr() as _, @@ -63,6 +64,7 @@ pub extern "C" fn lucet_state_tag_name(tag: libc::c_int) -> *const c_char { Running => "lucet_state_tag_running\0".as_ptr() as _, Fault => "lucet_state_tag_fault\0".as_ptr() as _, Terminated => "lucet_state_tag_terminated\0".as_ptr() as _, + Yielded => "lucet_state_tag_yielded\0".as_ptr() as _, } } else { "!!! unknown lucet_state_tag variant!\0".as_ptr() as _ @@ -430,7 +432,7 @@ lucet_hostcalls! { &mut _vmctx, details: *mut c_void, ) -> () { - lucet_hostcall_terminate!(CTerminationDetails { details}); + lucet_hostcall_terminate!(CTerminationDetails { details }); } #[no_mangle] From b1dd907f5fdfeab187a150d5ca6fce7bc6fd9773 Mon Sep 17 00:00:00 2001 From: awortman-fastly <49215183+awortman-fastly@users.noreply.github.com> Date: Mon, 29 Jul 2019 09:48:59 -0700 Subject: [PATCH 269/512] Update dependency versions (#256) * update dependency versions * pin `getrandom` to an early version to avoid pulling in `spin` Newer versions of `getrandom` used a feature that caused `spin` to be used for synchronization by `lazy_static`. This was causing a nondeterministic segfault in our signal handler tests. This commit should be revisited once a new `getrandom` release is cut, since newer code no longer pulls in this dependency. * fully excise memoffset 0.2.1 --- Cargo.lock | 562 ++++++++++-------- Cargo.toml | 2 +- faerie | 2 +- .../lucet-runtime-internals/Cargo.toml | 9 +- 4 files changed, 319 insertions(+), 256 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bf4035515..b738c8874 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7,10 +7,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "aho-corasick" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -28,7 +28,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "arrayvec" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -36,26 +36,24 @@ dependencies = [ [[package]] name = "atty" -version = "0.2.11" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "autocfg" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.31" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -63,10 +61,10 @@ dependencies = [ [[package]] name = "backtrace-sys" -version = "0.1.28" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -97,7 +95,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -110,14 +108,14 @@ dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "clang-sys 0.26.4 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -164,9 +162,15 @@ dependencies = [ ] [[package]] -name = "build_const" -version = "0.2.1" +name = "bstr" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "byte-tools" @@ -178,6 +182,15 @@ name = "byteorder" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "c2-chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cast" version = "0.2.2" @@ -185,7 +198,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cc" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -218,7 +231,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "libloading 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -227,7 +240,7 @@ version = "2.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -248,7 +261,7 @@ name = "cmake" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -287,7 +300,7 @@ dependencies = [ "cranelift-entity 0.31.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -308,7 +321,7 @@ version = "0.31.0" dependencies = [ "cranelift-codegen 0.31.0", "cranelift-module 0.31.0", - "faerie 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "faerie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -319,7 +332,7 @@ name = "cranelift-frontend" version = "0.31.0" dependencies = [ "cranelift-codegen 0.31.0", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -330,7 +343,7 @@ dependencies = [ "cranelift-codegen 0.31.0", "cranelift-entity 0.31.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -351,18 +364,10 @@ dependencies = [ "cranelift-frontend 0.31.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "wasmparser 0.31.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crc" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "crc32fast" version = "1.2.0" @@ -376,11 +381,11 @@ name = "criterion" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "csv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", @@ -390,11 +395,11 @@ dependencies = [ "rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -412,21 +417,21 @@ name = "crossbeam-deque" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-epoch" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -434,12 +439,12 @@ name = "crossbeam-queue" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-utils" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -457,26 +462,27 @@ dependencies = [ [[package]] name = "csv" -version = "1.0.7" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "bstr 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "csv-core" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "digest" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -489,13 +495,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "env_logger" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -520,32 +526,32 @@ dependencies = [ [[package]] name = "faerie" -version = "0.10.0" +version = "0.10.1" dependencies = [ - "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.0.23 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "string-interner 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "faerie" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -replace = "faerie 0.10.0" +replace = "faerie 0.10.1" [[package]] name = "failure" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.33 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -555,8 +561,8 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.38 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -573,7 +579,7 @@ dependencies = [ "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide_c_api 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -629,7 +635,7 @@ name = "goblin" version = "0.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -639,7 +645,7 @@ name = "goblin" version = "0.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -649,7 +655,17 @@ name = "goblin" version = "0.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "goblin" +version = "0.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -673,11 +689,11 @@ dependencies = [ [[package]] name = "hmac" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -703,7 +719,7 @@ dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -746,16 +762,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libloading" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "log" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -785,7 +801,7 @@ dependencies = [ "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -797,7 +813,7 @@ dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", "lucetc 0.1.1", - "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -806,26 +822,26 @@ name = "lucet-idl-test" version = "0.1.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-idl 0.1.1", "lucet-runtime 0.1.1", "lucet-wasi 0.1.1", "lucet-wasi-sdk 0.1.1", "lucetc 0.1.1", "proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucet-idl-test-rust-host" version = "0.1.0" dependencies = [ - "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-idl 0.1.1", "lucet-runtime 0.1.1", "lucet-wasi 0.1.1", @@ -843,8 +859,8 @@ dependencies = [ "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "object 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -852,7 +868,7 @@ name = "lucet-runtime" version = "0.1.1" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", @@ -864,7 +880,7 @@ dependencies = [ "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -874,14 +890,15 @@ dependencies = [ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-codegen 0.31.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "libloading 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -892,14 +909,14 @@ dependencies = [ name = "lucet-runtime-tests" version = "0.1.1" dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", "lucet-runtime-internals 0.1.1", "lucet-wasi-sdk 0.1.1", "lucetc 0.1.1", - "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -911,9 +928,9 @@ dependencies = [ "lucet-module 0.1.1", "lucet-runtime 0.1.1", "lucetc 0.1.1", - "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -934,7 +951,7 @@ dependencies = [ "lucetc 0.1.1", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -954,9 +971,9 @@ dependencies = [ "progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -967,7 +984,7 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", "lucetc 0.1.1", - "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -985,17 +1002,17 @@ dependencies = [ "cranelift-module 0.31.0", "cranelift-native 0.31.0", "cranelift-wasm 0.31.0", - "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "faerie 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "faerie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "wasmonkey 0.1.8", "wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1003,7 +1020,7 @@ dependencies = [ [[package]] name = "memchr" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1011,8 +1028,11 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.2.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "minisign" @@ -1030,13 +1050,13 @@ name = "miniz-sys" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "miniz_oxide" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1044,13 +1064,13 @@ dependencies = [ [[package]] name = "miniz_oxide_c_api" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1059,7 +1079,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1075,7 +1095,7 @@ name = "nom" version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1095,8 +1115,8 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.38 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1104,7 +1124,7 @@ name = "num-integer" version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1113,7 +1133,7 @@ name = "num-iter" version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1131,7 +1151,7 @@ name = "num-traits" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1142,11 +1162,6 @@ dependencies = [ "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "numtoa" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "object" version = "0.12.0" @@ -1185,7 +1200,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "pkg-config" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1193,12 +1208,17 @@ name = "plain" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "ppv-lite86" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "precision" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1238,9 +1258,9 @@ dependencies = [ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "rusty-fork 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1250,7 +1270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "quote" -version = "0.6.12" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1273,7 +1293,7 @@ name = "rand" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1286,15 +1306,36 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_chacha" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_chacha" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_core" version = "0.3.1" @@ -1308,6 +1349,14 @@ name = "rand_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rand_core" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_hc" version = "0.1.0" @@ -1316,6 +1365,14 @@ dependencies = [ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_isaac" version = "0.1.1" @@ -1352,7 +1409,7 @@ name = "rand_pcg" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1379,7 +1436,7 @@ version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1400,7 +1457,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1415,35 +1472,35 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.1.54" +version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "redox_termios" -version = "0.1.1" +name = "regex" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "regex" -version = "1.1.7" +name = "regex-automata" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" -version = "0.6.7" +version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ucd-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1489,18 +1546,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ryu" -version = "0.2.8" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "same-file" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1511,6 +1568,11 @@ name = "scopeguard" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "scopeguard" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "scroll" version = "0.9.2" @@ -1526,8 +1588,8 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.38 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1537,7 +1599,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1557,30 +1619,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.93" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.93" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.38 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1589,7 +1651,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1602,15 +1664,15 @@ dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "core_affinity 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "hwloc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "libloading 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "precision 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "printtable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1625,7 +1687,7 @@ name = "string-interner" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1635,22 +1697,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "structopt" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "structopt-derive" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.38 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1660,11 +1722,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "0.15.38" +version = "0.15.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1674,8 +1736,8 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.38 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1686,18 +1748,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tempfile" -version = "3.0.8" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1719,17 +1781,6 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "termion" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "textwrap" version = "0.11.0" @@ -1751,8 +1802,8 @@ name = "tinytemplate" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1760,7 +1811,7 @@ name = "toml" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1770,7 +1821,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ucd-util" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1818,9 +1869,9 @@ name = "wabt" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1829,7 +1880,7 @@ name = "wabt-sys" version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1844,10 +1895,10 @@ dependencies = [ [[package]] name = "walkdir" -version = "2.2.8" +version = "2.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1861,9 +1912,9 @@ dependencies = [ "goblin 0.0.23 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "siphasher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1951,14 +2002,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" -"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" +"checksum aho-corasick 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "36b7aa1ccb7d7ea3f437cf025a2ab1c47cc6c1bc9fc84918ff449def12f5e282" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94" -"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" -"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" -"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" -"checksum backtrace 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)" = "e0f77aa27f55a4beb477ff6bc4d9bf72f90eb422b19c1d8e5a644b8aeb674d66" -"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" +"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" +"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" +"checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b" +"checksum backtrace 0.3.33 (registry+https://github.com/rust-lang/crates.io-index)" = "88fb679bc9af8fa639198790a77f52d345fe13656c08b43afa9424c206b731c6" +"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum bencher 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdb4953a096c551ce9ace855a604d702e6e62d77fac690575ae347571717f5" "checksum bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "505e45beaf0a1462f5548fe885edf2d83e62022b2ce8b10fef0f7686b48c9266" @@ -1970,11 +2021,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" "checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" -"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" +"checksum bstr 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e0a692f1c740e7e821ca71a22cf99b9b2322dfa94d10f71443befb1797b3946a" "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" -"checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d" +"checksum cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "ce400c638d48ee0e9ab75aef7997609ec57367ccfe1463f21bf53c3eca67bf46" "checksum cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7fa24eb00d5ffab90eaeaf1092ac85c04c64aaf358ea6f84505b8116d24c6af" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c" @@ -1984,23 +2036,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cmake 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "2ca4386c8954b76a8415b63959337d940d724b336cabd3afe189c2b51a7e1ff0" "checksum colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cdb90b60f2927f8d76139c72dbde7e10c3a2bc47c8594c9c7a66529f2687c03" "checksum core_affinity 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6d162c6e463c31dbf78fefa99d042156c1c74d404e299cfe3df2923cb857595b" -"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0363053954f3e679645fc443321ca128b7b950a6fe288cf5f9335cc22ee58394" "checksum criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76f9212ddf2f4a9eb2d401635190600656a1f88a932ef53d06e7fa4c7e02fb8e" "checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" -"checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" +"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" -"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" +"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" -"checksum csv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9044e25afb0924b5a5fc5511689b0918629e85d68ea591e5e87fbf1e85ea1b3b" -"checksum csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5cdef62f37e6ffe7d1f07a381bc0db32b7a3ff1cac0de56cb0d81e71f53d65" -"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" +"checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d" +"checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" +"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" "checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" -"checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a" +"checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" "checksum errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2a071601ed01b988f896ab14b95e67335d1eeb50190932a1320f7fe3cadc84e" "checksum errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067" -"checksum faerie 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c6d75e6376216d6228fbab8025087523666623d9302ff17dd023d024bf98302" +"checksum faerie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6cb48b9db9869b6209c63d5cc2fd99f0b85d1a407cb09fe8ed730c21ab945e3d" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" @@ -2015,9 +2066,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6a4013e9182f2345c6b7829b9ef6e670bce0dfca12c6f974457ed2160c2c7fe9" "checksum goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "7f55d53401eb2fd30afd025c570b1946b6966344acf21b42e31286f3bf89e6a8" "checksum goblin 0.0.23 (registry+https://github.com/rust-lang/crates.io-index)" = "ac56b4753b6b8c2e052ca30717e5a09acf1b02a2c1681bf3d883bd660e5d22bd" +"checksum goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "e3fa261d919c1ae9d1e4533c4a2f99e10938603c4208d56c05bec7a872b661b0" "checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" -"checksum hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f127a908633569f208325f86f71255d3363c79721d7f9fe31cd5569908819771" +"checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" "checksum human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bec6e801ef7367625bd94ad7e2965e6027189f3e9deef422388d993af2814a0" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" "checksum hwloc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2934f84993b8b4bcae9b6a4e5f0aca638462dda9c7b4f26a570241494f21e0f4" @@ -2027,14 +2079,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)" = "3262021842bf00fe07dbd6cf34ff25c99d7a7ebef8deea84db72be3ea3bb0aff" -"checksum libloading 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5692f82b51823e27c4118b3e5c0d98aee9be90633ebc71ad12afef380b50219" -"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" -"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" -"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" +"checksum libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" +"checksum log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c275b6ad54070ac2d665eef9197db647b32239c9d244bfb6f041a766d00da5b3" +"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" +"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" "checksum minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "185d3531e38475163c1652a0915ac612be3f2655756af43f10789d6145f527c2" "checksum miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9e3ae51cea1576ceba0dde3d484d30e6e5b86dee0b2d412fe3a16a15c98202" -"checksum miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c468f2369f07d651a5d0bb2c9079f8488a66d5466efe42d0c5c6466edcb7f71e" -"checksum miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7fe927a42e3807ef71defb191dc87d4e24479b221e67015fe38ae2b7b447bab" +"checksum miniz_oxide 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c061edee74a88eb35d876ce88b94d77a0448a201de111c244b70d047f5820516" +"checksum miniz_oxide_c_api 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6c675792957b0d19933816c4e1d56663c341dd9bfa31cb2140ff2267c1d8ecf4" "checksum nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4dbdc256eaac2e3bd236d93ad999d3479ef775c863dbda3068c4006a92eec51b" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" @@ -2045,27 +2097,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" -"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum object 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df4af347f5ac3d0e83e78c26be33cd10e8e874dcb68517a909ad802ba50a90b5" "checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" "checksum parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)" = "20d7e522a7f994cc4ae32970b1ce0d99ecf91b8e1df080517a26faa6d2e2ee62" "checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" "checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" -"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" +"checksum pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c1d2cfa5a714db3b5f24f0915e74fcdf91d09d496ba61329705dda7774d2af" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum precision 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "83f0b3de90e9edd6382604f4f28509ce25272deb065b94045fc47abcde567d55" "checksum printtable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "69967dae4cac71681361899d9905d3d2985fc989d7afb32a8dff3aed5461ecdf" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b820305721858696053a7fd0215cfeeee16ecaaf96b7a209945428e02f1c44" "checksum proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf147e022eacf0c8a054ab864914a7602618adba841d800a9a9868a5237a529f" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" -"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" +"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" +"checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" "checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" @@ -2076,47 +2132,47 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4b0186e22767d5b9738a05eab7c6ac90b15db17e5b5f9bd87976dd7d89a10a4" "checksum rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe0df8435ac0c397d467b6cad6d25543d06e8a019ef3f6af3c384597515bd2" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" -"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0b2f0808e7d7e4fb1cb07feb6ff2f4bc827938f24f8c2e6a3beb7370af544bdd" -"checksum regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d76410686f9e3a17f06128962e0ecc5755870bb890c34820c7af7f1db2e1d48" +"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +"checksum regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b23da8dfd98a84bd7e08700190a5d9f7d2d38abd4369dd1dae651bc40bfd2cc" +"checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9" +"checksum regex-syntax 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5485bf1523a9ed51c4964273f22f63f24e31632adb5dad134f488f86a3875c" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" "checksum rgb 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)" = "4f089652ca87f5a82a62935ec6172a534066c7b97be003cc8f702ee9a7a59c92" "checksum rpassword 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34fa7bcae7fca3c8471e8417088bbc3ad9af8066b0ecf4f3c0d98a0d772716e" "checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rusty-fork 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd93264e10c577503e926bd1430193eeb5d21b059148910082245309b424fae" -"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f" -"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" +"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" +"checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" +"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" "checksum scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f84d114ef17fd144153d608fba7c446b0145d038985e7a8cc5d08bb0ce20383" "checksum scroll_derive 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1aa96c45e7f5a91cb7fabe7b279f02fea7126239fc40b732316e8b6a2d0fcb" "checksum scrypt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "656c79d0e90d0ab28ac86bf3c3d10bfbbac91450d3f190113b4e76d9fec3cfdd" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)" = "960e29cf7004b3b6e65fc5002981400eb3ccc017a08a2406940823e58e7179a9" -"checksum serde_derive 1.0.93 (registry+https://github.com/rust-lang/crates.io-index)" = "c4cce6663696bd38272e90bf34a0267e1226156c33f52d3f3915a2dd5d802085" -"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" +"checksum serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)" = "d46b3dfedb19360a74316866cef04687cd4d6a70df8e6a506c63512790769b72" +"checksum serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)" = "c22a0820adfe2f257b098714323563dd06426502abbbce4f51b72ef544c5027f" +"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" "checksum siphasher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9913c75df657d84a03fa689c016b0bb2863ff0b497b26a8d6e9703f8d5df03a8" "checksum string-interner 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "abb38a0d8fe673c40b10b6b75abcb076a958cc10fb894f14993d9737c4c87000" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fa19a5a708e22bb5be31c1b6108a2a902f909c4b9ba85cba44c06632386bc0ff" -"checksum structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "c6d59d0ae8ef8de16e49e3ca7afa16024a3e0dfd974a75ef93fdc5464e34523f" +"checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" +"checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" -"checksum syn 0.15.38 (registry+https://github.com/rust-lang/crates.io-index)" = "37ea458a750f59ab679b47fef9b6722c586c5742f4cfe18a120bbc807e5e01fd" +"checksum syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)" = "eadc09306ca51a40555dd6fc2b415538e9e18bc9f870e47b1a524a79fe2dcf5e" "checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" "checksum target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b0ab4982b8945c35cc1c46a83a9094c414f6828a099ce5dcaa8ee2b04642dcb" -"checksum tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dc4738f2e68ed2855de5ac9cdbe05c9216773ecde4739b2f095002ab03a13ef" +"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" "checksum terminal_size 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "023345d35850b69849741bd9a5432aa35290e3d8eb76af8717026f270d1cf133" -"checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4574b75faccaacddb9b284faecdf0b544b80b6b294f3d062d325c5726a209c20" "checksum toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8c96d7873fa7ef8bdeb3a9cda3ac48389b4154f32b9803b4bc26220b677b039" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" -"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" +"checksum ucd-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa9b3b49edd3468c0e6565d85783f51af95212b6fa3986a5500954f00b460874" "checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" @@ -2128,7 +2184,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "74e463a508e390cc7447e70f640fbf44ad52e1bd095314ace1fdf99516d32add" "checksum wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a6265b25719e82598d104b3717375e37661d41753e2c84cde3f51050c7ed7e3c" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" -"checksum walkdir 2.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c7904a7e2bb3cdf0cf5e783f44204a85a37a93151738fa349f06680f59a98b45" +"checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" "checksum wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5e01c420bc7d36e778bd242e1167b079562ba8b34087122cc9057187026d060" "checksum wasmparser 0.31.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6f324afc05fd8282bbc49dae854a1c20f74aeff10a575b5a43453d1864db97" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" diff --git a/Cargo.toml b/Cargo.toml index fe6b0e39f..f3502f0e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,4 +24,4 @@ exclude = ["cranelift"] rpath = true [replace] -"faerie:0.10.0" = { path = "faerie" } +"faerie:0.10.1" = { path = "faerie" } diff --git a/faerie b/faerie index dcb671a99..926b3765b 160000 --- a/faerie +++ b/faerie @@ -1 +1 @@ -Subproject commit dcb671a99faa32b72fac88d2406e952a41844636 +Subproject commit 926b3765b8f3751fb17f26321626b41b30b894e2 diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index 84fd54fa2..5823263cf 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -20,12 +20,19 @@ failure = "0.1" lazy_static = "1.1" libc = "=0.2.59" libloading = "0.5" -memoffset = "0.2" +memoffset = "0.5" nix = "0.13" num-derive = "0.2" num-traits = "0.2" xfailure = "0.1" +# This is only a dependency to ensure that other crates don't pick a newer version as a transitive +# dependency. `0.1.3 < getrandom <= 0.1.6` cause `lazy_static` to pull in spinlock implementations +# of concurrency primitives, which for unknown reasons cause our signal handling code to +# nondeterministically segfault. The maintainers have since removed the `lazy_static` dependency +# from `getrandom`, but until a new release is cut, this keeps it on a safe version. +getrandom = "=0.1.3" + [dev-dependencies] byteorder = "1.2" From 9e64d968d39fb544ff1c1872ab428180840a6504 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 29 Jul 2019 10:16:17 -0700 Subject: [PATCH 270/512] [lucet-runtime-internals] remove Context-based yielding --- .../src/context/mod.rs | 8 -- .../src/context/tests/rust_child.rs | 99 ------------------- 2 files changed, 107 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs index 745c96bd1..da957d636 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs @@ -7,7 +7,6 @@ use crate::val::{val_to_reg, val_to_stack, RegVal, UntypedRetVal, Val}; use failure::Fail; use nix; use nix::sys::signal; -use std::any::Any; use std::arch::x86_64::{__m128, _mm_setzero_ps}; use std::mem; use std::ptr::NonNull; @@ -116,7 +115,6 @@ pub struct Context { retvals_gp: [u64; 2], retval_fp: __m128, sigset: signal::SigSet, - yielded: Option>, } impl Context { @@ -128,7 +126,6 @@ impl Context { retvals_gp: [0; 2], retval_fp: unsafe { _mm_setzero_ps() }, sigset: signal::SigSet::empty(), - yielded: None, } } } @@ -451,11 +448,6 @@ impl Context { lucet_context_swap(from as *mut Context, to as *const Context); } - pub unsafe fn swap_yield(from: &mut Context, to: &Context, val: A) { - from.yielded = Some(Box::new(val)); - Context::swap(from, to); - } - /// Swap to another context without saving the current context. /// /// - `to`: the context to read from and swap to diff --git a/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs b/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs index 19aee7085..7292114b9 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs @@ -478,102 +478,3 @@ fn guest_access_tls() { assert_output_eq!("tls = 42"); }); } - -#[test] -fn yield_nil() { - unsafe extern "C" fn guest_fn() { - Context::swap_yield(CHILD.as_mut().unwrap(), PARENT.as_ref().unwrap(), ()); - } - - test_body!(stack, { - init_and_swap!(stack, guest_fn, []); - unsafe { - assert!(CHILD.as_ref().unwrap().yielded.is_some()); - } - }); -} - -#[test] -fn yield_5() { - unsafe extern "C" fn guest_fn() { - Context::swap_yield(CHILD.as_mut().unwrap(), PARENT.as_ref().unwrap(), 5u64); - } - - test_body!(stack, { - init_and_swap!(stack, guest_fn, []); - unsafe { - let yielded = CHILD.as_mut().unwrap().yielded.take().unwrap(); - let val = yielded.downcast::().unwrap(); - assert_eq!(*val, 5u64); - } - }); -} - -#[test] -fn yield_factorials() { - unsafe extern "C" fn guest_fn(n: u64) -> u64 { - if n <= 1 { - Context::swap_yield(CHILD.as_mut().unwrap(), PARENT.as_ref().unwrap(), 1u64); - 1 - } else { - let n = n * guest_fn(n - 1); - Context::swap_yield(CHILD.as_mut().unwrap(), PARENT.as_ref().unwrap(), n); - n - } - } - - test_body!(stack, { - init_and_swap!(stack, guest_fn, [5u64.into()]); - let mut facs = vec![]; - while let Some(yielded) = unsafe { CHILD.as_mut().unwrap().yielded.take() } { - facs.push(*yielded.downcast::().unwrap()); - unsafe { - Context::swap(PARENT.as_mut().unwrap(), CHILD.as_ref().unwrap()); - } - } - assert_eq!(facs.as_slice(), &[1, 2, 6, 24, 120]); - }); -} - -#[test] -fn coop_factorials() { - unsafe extern "C" fn guest_fn(n: u64) -> u64 { - if n <= 1 { - Context::swap_yield(CHILD.as_mut().unwrap(), PARENT.as_ref().unwrap(), 1u64); - 1 - } else { - let n_rec = guest_fn(n - 1); - Context::swap_yield( - CHILD.as_mut().unwrap(), - PARENT.as_ref().unwrap(), - (n, n_rec), - ); - - let yielded = PARENT.as_mut().unwrap().yielded.take().unwrap(); - let n = *yielded.downcast::().unwrap(); - - Context::swap_yield(CHILD.as_mut().unwrap(), PARENT.as_ref().unwrap(), n); - n - } - } - - test_body!(stack, { - init_and_swap!(stack, guest_fn, [5u64.into()]); - let mut facs = vec![]; - while let Some(yielded) = unsafe { CHILD.as_mut().unwrap().yielded.take() } { - if let Some(ns) = yielded.downcast_ref::<(u64, u64)>() { - let (n, n_rec) = *ns; - let n = n * n_rec; - unsafe { - Context::swap_yield(PARENT.as_mut().unwrap(), CHILD.as_ref().unwrap(), n); - } - } else if let Some(n) = yielded.downcast_ref::() { - facs.push(*n); - unsafe { - Context::swap(PARENT.as_mut().unwrap(), CHILD.as_ref().unwrap()); - } - } - } - assert_eq!(facs.as_slice(), &[1, 2, 6, 24, 120]); - }); -} From d300f347ce56a804919402cf34a242c91ec36d05 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 29 Jul 2019 11:58:10 -0700 Subject: [PATCH 271/512] [lucet-runtime] add C API and a test for the yield/resume interface --- lucet-runtime/Makefile | 42 ------ lucet-runtime/include/lucet.h | 2 + lucet-runtime/include/lucet_types.h | 1 + lucet-runtime/include/lucet_vmctx.h | 2 + .../lucet-runtime-internals/src/vmctx.rs | 37 ++--- lucet-runtime/src/c_api.rs | 71 +++++++++- lucet-runtime/tests/c_api.c | 127 ++++++++++++++++++ lucet-runtime/tests/guests/yield_resume.c | 8 ++ .../tests/guests/yield_resume_bindings.json | 5 + 9 files changed, 236 insertions(+), 59 deletions(-) delete mode 100644 lucet-runtime/Makefile create mode 100644 lucet-runtime/tests/guests/yield_resume.c create mode 100644 lucet-runtime/tests/guests/yield_resume_bindings.json diff --git a/lucet-runtime/Makefile b/lucet-runtime/Makefile deleted file mode 100644 index 8e067daca..000000000 --- a/lucet-runtime/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -# This Makefile exists primarily to allow running just the test suite for lucet-runtime, rather than -# for the whole workspace. - -export GUEST_MODULE_PREFIX=$(abspath $(CURDIR)/..) - -default: build - -.PHONY: lucetc -lucetc: - cargo build -p lucetc - -LUCET_LIBC:=../lucet-libc -.PHONY: $(LUCET_LIBC) -$(LUCET_LIBC): - make -C $(LUCET_LIBC) - -LUCET_TESTS:=../tests -.PHONY: $(LUCET_TESTS) -$(LUCET_TESTS): $(LUCET_LIBC) lucetc - make -C $(LUCET_TESTS) guests - -TEST_DEPS:= $(LUCET_LIB_C) $(LUCET_TESTS) - -.PHONY: build -build: - cargo build -p lucet-runtime - -.PHONY: release -release: - cargo build --release -p lucet-runtime - -.PHONY: test -test: build $(TEST_DEPS) - cargo test --no-fail-fast -p lucet-runtime -p lucet-runtime-internals - -.PHONY: audit -audit: - cargo audit - -.PHONY: clean -clean: - cargo clean -p lucet-runtime lucet-runtime-internals lucet-runtime-tests diff --git a/lucet-runtime/include/lucet.h b/lucet-runtime/include/lucet.h index 2c3385cd8..f6372e3c1 100644 --- a/lucet-runtime/include/lucet.h +++ b/lucet-runtime/include/lucet.h @@ -46,6 +46,8 @@ enum lucet_error lucet_instance_run_func_idx(struct lucet_instance * inst, uintptr_t argc, const struct lucet_val *argv); +enum lucet_error lucet_instance_resume(struct lucet_instance *inst, void *val); + enum lucet_error lucet_instance_set_fatal_handler(struct lucet_instance *inst, lucet_fatal_handler fatal_handler); diff --git a/lucet-runtime/include/lucet_types.h b/lucet-runtime/include/lucet_types.h index 1d3cb4ed7..918d01300 100644 --- a/lucet-runtime/include/lucet_types.h +++ b/lucet-runtime/include/lucet_types.h @@ -44,6 +44,7 @@ enum lucet_state_tag { lucet_state_tag_running, lucet_state_tag_fault, lucet_state_tag_terminated, + lucet_state_tag_yielded, }; enum lucet_terminated_reason { diff --git a/lucet-runtime/include/lucet_vmctx.h b/lucet-runtime/include/lucet_vmctx.h index 73917d186..76af4afe5 100644 --- a/lucet-runtime/include/lucet_vmctx.h +++ b/lucet-runtime/include/lucet_vmctx.h @@ -26,6 +26,8 @@ void *lucet_vmctx_get_delegate(struct lucet_vmctx const *); void lucet_vmctx_terminate(struct lucet_vmctx const *, void *info); +void *lucet_vmctx_yield(struct lucet_vmctx const *, void *val); + // returns the current number of wasm pages uint32_t lucet_vmctx_current_memory(struct lucet_vmctx const *); diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index 3915ab5dc..be769c380 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -58,6 +58,8 @@ pub trait VmctxInternal { /// you could not use orthogonal `&mut` refs that come from `Vmctx`, like the heap or /// terminating the instance. unsafe fn instance_mut(&self) -> &mut Instance; + + fn try_take_yielded_val(&self) -> Option; } impl VmctxInternal for Vmctx { @@ -68,6 +70,19 @@ impl VmctxInternal for Vmctx { unsafe fn instance_mut(&self) -> &mut Instance { instance_from_vmctx(self.vmctx) } + + fn try_take_yielded_val(&self) -> Option { + let inst = unsafe { self.instance_mut() }; + if let Some(val) = inst.val_from_host.take() { + if let Ok(val) = val.downcast() { + Some(*val) + } else { + None + } + } else { + None + } + } } impl Vmctx { @@ -277,9 +292,9 @@ impl Vmctx { HOST_CTX.with(|host_ctx| unsafe { Context::swap(&mut inst.ctx, &mut *host_ctx.get()) }); } - pub fn yield_expecting_val(&self) -> R { + pub fn yield_expecting_val(&self) -> R { self.yield_(); - self.get_expected_val() + self.take_yielded_val() } pub fn yield_val(&self, val: A) { @@ -290,25 +305,17 @@ impl Vmctx { HOST_CTX.with(|host_ctx| unsafe { Context::swap(&mut inst.ctx, &mut *host_ctx.get()) }); } - pub fn yield_val_expecting_val( + pub fn yield_val_expecting_val( &self, val: A, ) -> R { self.yield_val(val); - self.get_expected_val() + self.take_yielded_val() } - fn get_expected_val(&self) -> R { - let inst = unsafe { self.instance_mut() }; - if let Some(val) = inst.val_from_host.take() { - if let Ok(val) = val.downcast() { - *val - } else { - panic!(TerminationDetails::YieldTypeMismatch) - } - } else { - panic!(TerminationDetails::YieldTypeMismatch) - } + fn take_yielded_val(&self) -> R { + self.try_take_yielded_val() + .unwrap_or_else(|| panic!(TerminationDetails::YieldTypeMismatch)) } } diff --git a/lucet-runtime/src/c_api.rs b/lucet-runtime/src/c_api.rs index f37675590..610891e78 100644 --- a/lucet-runtime/src/c_api.rs +++ b/lucet-runtime/src/c_api.rs @@ -210,6 +210,24 @@ pub unsafe extern "C" fn lucet_instance_run_func_idx( }) } +#[no_mangle] +pub unsafe extern "C" fn lucet_instance_resume( + inst: *const lucet_instance, + val: *mut c_void, +) -> lucet_error { + with_instance_ptr!(inst, { + if val.is_null() { + inst.resume() + .map(|_| lucet_error::Ok) + .unwrap_or_else(|e| e.into()) + } else { + inst.resume_with_val(CYieldedVal { val }) + .map(|_| lucet_error::Ok) + .unwrap_or_else(|e| e.into()) + } + }) +} + #[no_mangle] pub unsafe extern "C" fn lucet_instance_state( inst: *const lucet_instance, @@ -447,18 +465,41 @@ lucet_hostcalls! { .map(|r| r.map(|p| *p).unwrap_or(ptr::null_mut())) .unwrap_or(std::ptr::null_mut()) } + + #[no_mangle] + pub unsafe extern "C" fn lucet_vmctx_yield( + &mut vmctx, + val: *mut c_void, + ) -> *mut c_void { + // only yield a value if val is non-NULL + if val.is_null() { + vmctx.yield_(); + } else { + vmctx.yield_val(CYieldedVal { val }); + } + + // return any `CYieldedVal` pointer that comes back, otherwise NULL + if let Some(CYieldedVal { val }) = vmctx.try_take_yielded_val() { + val + } else { + std::ptr::null_mut() + } + } } #[cfg(test)] mod tests { use super::lucet_dl_module; use crate::DlModule; - use lucet_wasi_sdk::{LinkOpt, LinkOpts, Lucetc}; + use lucet_module::bindings::Bindings; + use lucet_wasi_sdk::{CompileOpts, LinkOpt, LinkOpts, Lucetc}; + use lucetc::LucetcOpts; use std::sync::Arc; use tempfile::TempDir; extern "C" { fn lucet_runtime_test_expand_heap(module: *mut lucet_dl_module) -> bool; + fn lucet_runtime_test_yield_resume(module: *mut lucet_dl_module) -> bool; } #[test] @@ -466,8 +507,10 @@ mod tests { let workdir = TempDir::new().expect("create working directory"); let native_build = Lucetc::new(&["tests/guests/null.c"]) + .with_cflag("-nostartfiles") .with_link_opt(LinkOpt::NoDefaultEntryPoint) - .with_link_opt(LinkOpt::AllowUndefinedAll); + .with_link_opt(LinkOpt::AllowUndefinedAll) + .with_link_opt(LinkOpt::ExportAll); let so_file = workdir.path().join("null.so"); @@ -481,4 +524,28 @@ mod tests { )); } } + + #[test] + fn yield_resume() { + let workdir = TempDir::new().expect("create working directory"); + + let native_build = Lucetc::new(&["tests/guests/yield_resume.c"]) + .with_cflag("-nostartfiles") + .with_link_opt(LinkOpt::NoDefaultEntryPoint) + .with_link_opt(LinkOpt::AllowUndefinedAll) + .with_link_opt(LinkOpt::ExportAll) + .with_bindings(Bindings::from_file("tests/guests/yield_resume_bindings.json").unwrap()); + + let so_file = workdir.path().join("yield_resume.so"); + + native_build.build(so_file.clone()).unwrap(); + + let dlmodule = DlModule::load(so_file).unwrap(); + + unsafe { + assert!(lucet_runtime_test_yield_resume( + Arc::into_raw(dlmodule) as *mut lucet_dl_module + )); + } + } } diff --git a/lucet-runtime/tests/c_api.c b/lucet-runtime/tests/c_api.c index ae5bb5d51..1ce160f89 100644 --- a/lucet-runtime/tests/c_api.c +++ b/lucet-runtime/tests/c_api.c @@ -35,6 +35,7 @@ bool lucet_runtime_test_expand_heap(struct lucet_dl_module *mod) goto fail3; } + lucet_instance_release(inst); lucet_region_release(region); lucet_dl_module_release(mod); @@ -48,3 +49,129 @@ bool lucet_runtime_test_expand_heap(struct lucet_dl_module *mod) lucet_dl_module_release(mod); return false; } + +enum yield_resume_tag { + yield_resume_tag_mult, + yield_resume_tag_result, +}; + +struct yield_resume_mult { + uint64_t x; + uint64_t y; +}; + +union yield_resume_val_inner { + struct yield_resume_mult mult; + uint64_t result; +}; + +struct yield_resume_val { + enum yield_resume_tag tag; + union yield_resume_val_inner val; +}; + +uint64_t lucet_runtime_test_hostcall_yield_resume(struct lucet_vmctx *vmctx, uint64_t n) +{ + if (n <= 1) { + struct yield_resume_val result_val = { .tag = yield_resume_tag_result, + .val = { .result = 1 } }; + lucet_vmctx_yield(vmctx, &result_val); + return 1; + } else { + uint64_t n_rec = lucet_runtime_test_hostcall_yield_resume(vmctx, n - 1); + struct yield_resume_val mult_val = { .tag = yield_resume_tag_mult, + .val = { .mult = { .x = n, .y = n_rec } } }; + uint64_t n = *(uint64_t *) lucet_vmctx_yield(vmctx, &mult_val); + struct yield_resume_val result_val = { .tag = yield_resume_tag_result, + .val = { .result = n } }; + lucet_vmctx_yield(vmctx, &result_val); + return n; + } +} + +bool lucet_runtime_test_yield_resume(struct lucet_dl_module *mod) +{ + struct lucet_region * region; + struct lucet_alloc_limits limits = { + .heap_memory_size = 4 * 1024 * 1024, + .heap_address_space_size = 8 * 1024 * 1024, + .stack_size = 64 * 1024, + .globals_size = 4096, + }; + + enum lucet_error err; + + err = lucet_mmap_region_create(1, &limits, ®ion); + if (err != lucet_error_ok) { + fprintf(stderr, "failed to create region\n"); + goto fail1; + } + + struct lucet_instance *inst; + err = lucet_region_new_instance(region, mod, &inst); + if (err != lucet_error_ok) { + fprintf(stderr, "failed to create instance\n"); + goto fail2; + } + + uint64_t results[5] = { 0 }; + size_t i = 0; + + err = lucet_instance_run(inst, "f", 0, (const struct lucet_val[]){}); + while (err == lucet_error_instance_yielded) { + if (i >= 5) { + fprintf(stderr, "hostcall yielded too many results\n"); + goto fail3; + } + + struct lucet_state st; + err = lucet_instance_state(inst, &st); + if (err != lucet_error_ok) { + fprintf(stderr, "couldn't get instance state\n"); + goto fail3; + } + if (st.tag != lucet_state_tag_yielded) { + fprintf(stderr, "instance state wasn't yielded\n"); + goto fail3; + } + struct yield_resume_val val = *(struct yield_resume_val *) st.val.yielded.val; + + switch (val.tag) { + case yield_resume_tag_mult:; + uint64_t mult_result = val.val.mult.x * val.val.mult.y; + err = lucet_instance_resume(inst, &mult_result); + continue; + case yield_resume_tag_result: + results[i++] = val.val.result; + err = lucet_instance_resume(inst, NULL); + continue; + default: + fprintf(stderr, "unexpected yield_resume_tag\n"); + goto fail3; + } + } + if (err != lucet_error_ok) { + fprintf(stderr, "instance finished with non-ok error\n"); + goto fail3; + } + + lucet_instance_release(inst); + lucet_region_release(region); + lucet_dl_module_release(mod); + + uint64_t expected_results[5] = { 1, 2, 6, 24, 120 }; + bool results_correct = true; + for (i = 0; i < 5; i++) { + results_correct = results_correct && (results[i] == expected_results[i]); + } + + return results_correct; + +fail3: + lucet_instance_release(inst); +fail2: + lucet_region_release(region); +fail1: + lucet_dl_module_release(mod); + return false; +} diff --git a/lucet-runtime/tests/guests/yield_resume.c b/lucet-runtime/tests/guests/yield_resume.c new file mode 100644 index 000000000..7e06531d0 --- /dev/null +++ b/lucet-runtime/tests/guests/yield_resume.c @@ -0,0 +1,8 @@ +#include + +extern uint64_t lucet_runtime_test_hostcall_yield_resume(uint64_t n); + +void f() +{ + lucet_runtime_test_hostcall_yield_resume(5); +} diff --git a/lucet-runtime/tests/guests/yield_resume_bindings.json b/lucet-runtime/tests/guests/yield_resume_bindings.json new file mode 100644 index 000000000..fe9ffc6af --- /dev/null +++ b/lucet-runtime/tests/guests/yield_resume_bindings.json @@ -0,0 +1,5 @@ +{ + "env": { + "lucet_runtime_test_hostcall_yield_resume": "lucet_runtime_test_hostcall_yield_resume" + } +} From bfe7f9790b3bc84476c7e63e9bcf6ce6d41a8c73 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 29 Jul 2019 12:59:05 -0700 Subject: [PATCH 272/512] [lucet-runtime-tests] make the coop continuation type explicit --- lucet-runtime/lucet-runtime-tests/src/host.rs | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/lucet-runtime/lucet-runtime-tests/src/host.rs b/lucet-runtime/lucet-runtime-tests/src/host.rs index 5246deaf8..4559f6437 100644 --- a/lucet-runtime/lucet-runtime-tests/src/host.rs +++ b/lucet-runtime/lucet-runtime-tests/src/host.rs @@ -139,7 +139,14 @@ macro_rules! host_tests { } fact(vmctx, n); } + } + + pub enum CoopFactsK { + Mult(u64, u64), + Result(u64), + } + lucet_hostcalls! { #[no_mangle] pub unsafe extern "C" fn hostcall_coop_facts( &mut vmctx, @@ -147,12 +154,12 @@ macro_rules! host_tests { ) -> () { fn fact(vmctx: &mut Vmctx, n: u64) -> u64 { if n <= 1 { - vmctx.yield_val(1u64); + vmctx.yield_val(CoopFactsK::Result(1)); 1 } else { let n_rec = fact(vmctx, n - 1); - let n = vmctx.yield_val_expecting_val((n, n_rec)); - vmctx.yield_val(n); + let n = vmctx.yield_val_expecting_val(CoopFactsK::Mult(n, n_rec)); + vmctx.yield_val(CoopFactsK::Result(n)); n } } @@ -476,13 +483,18 @@ macro_rules! host_tests { let mut res = inst.run("f", &[]); while let Err(Error::InstanceYielded(val)) = res { - if let Some((n, n_rec)) = val.downcast_ref::<(u64, u64)>() { - // guest wants us to multiply for it - res = inst.resume_with_val(n * n_rec); - } else if let Some(n) = val.downcast_ref::() { - // guest is returning an answer - facts.push(*n); - res = inst.resume(); + if let Some(k) = val.downcast_ref::() { + match k { + CoopFactsK::Mult(n, n_rec) => { + // guest wants us to multiply for it + res = inst.resume_with_val(n * n_rec); + } + CoopFactsK::Result(n) => { + // guest is returning an answer + facts.push(*n); + res = inst.resume(); + } + } } else { panic!("didn't yield with expected type"); } From 20b5956bfc4bbbc038497130bacfdcf904547fe1 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 29 Jul 2019 15:42:07 -0700 Subject: [PATCH 273/512] [lucet-runtime] clean up and document yield/resume --- .../lucet-runtime-internals/src/error.rs | 17 ++- .../lucet-runtime-internals/src/instance.rs | 93 ++++++++++--- .../lucet-runtime-internals/src/vmctx.rs | 51 ++++++- lucet-runtime/src/c_api.rs | 2 +- lucet-runtime/src/lib.rs | 129 +++++++++++++++++- 5 files changed, 260 insertions(+), 32 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/error.rs b/lucet-runtime/lucet-runtime-internals/src/error.rs index a96b25b9a..5364206e7 100644 --- a/lucet-runtime/lucet-runtime-internals/src/error.rs +++ b/lucet-runtime/lucet-runtime-internals/src/error.rs @@ -40,11 +40,26 @@ pub enum Error { /// An instance terminated, potentially with extra information about the termination. /// /// This condition can arise from a hostcall explicitly calling - /// [`Vmctx::terminate()`](struct.Vmctx.html#method.terminate), or via a custom signal handler + /// [`Vmctx::terminate()`](vmctx/struct.Vmctx.html#method.terminate), or via a custom signal handler /// that returns [`SignalBehavior::Terminate`](enum.SignalBehavior.html#variant.Terminate). #[fail(display = "Runtime terminated")] RuntimeTerminated(TerminationDetails), + /// An instance yielded, potentially with a value. + /// + /// This arises when a hostcall invokes one of the + /// [`Vmctx::yield_*()`](vmctx/struct.Vmctx.html#method.yield_) family of methods. Depending on which + /// variant is used, the `YieldedVal` may contain a value passed from the guest context to the + /// host. + /// + /// An instance that has returned may only be resumed + /// ([with](struct.Instance.html#method.resume_with_val) or + /// [without](struct.Instance.html#method.resume) a value to returned to the guest), + /// [reset](struct.Instance.html#method.reset), or dropped. Attempting to run an instance that + /// has yielded will result in an error. + /// + /// **Note**: This is not really an error, so once the `Try` trait is stabilized, this will + /// likely be moved out of this type and into a custom return type for `Instance::run()`. #[fail(display = "Instance yielded")] InstanceYielded(YieldedVal), diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index e6b8eb33f..1603d2655 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -216,7 +216,8 @@ pub struct Instance { /// Pointer to the function used as the entrypoint (for use in backtraces) entrypoint: Option, - pub(crate) val_from_host: Option>, + /// The value passed back to the guest when resuming a yielded instance. + pub(crate) resumed_val: Option>, /// `_padding` must be the last member of the structure. /// This marks where the padding starts to make the structure exactly 4096 bytes long. @@ -330,6 +331,52 @@ impl Instance { self.run_func(func, &args) } + /// Resume execution of an instance that has yielded without providing a value to the guest. + /// + /// This should only be used when the guest yielded with + /// [`Vmctx::yield_()`](vmctx/struct.Vmctx.html#method.yield_) or + /// [`Vmctx::yield_val()`](vmctx/struct.Vmctx.html#method.yield_val). Otherwise, the guest will + /// be expecting a value to be returned from the host, and will terminate the instance when one + /// is not found. + /// + /// The foreign code safety caveat of [`Instance::run()`](struct.Instance.html#method.run) + /// applies. + pub fn resume(&mut self) -> Result { + lucet_ensure!( + self.state.is_yielded(), + "can only resume from a call to `Vmctx::yield_*()`" + ); + + self.swap_and_return() + } + + /// Resume execution of an instance that has yielded, providing a value to the guest. + /// + /// If the guest yielded with [`Vmctx::yield_()`](vmctx/struct.Vmctx.html#method.yield_) or + /// [`Vmctx::yield_val()`](vmctx/struct.Vmctx.html#method.yield_val), the provided value will be + /// ignored. Otherwise, the type of the provided value must match the type expected by + /// [`Vmctx::yield_expecting_val()`](vmctx/struct.Vmctx.html#method.yield_expecting_val) or + /// [`Vmctx::yield_val_expecting_val()`](vmctx/struct.Vmctx.html#method.yield_val_expecting_val). + /// + /// The guest will dynamically check that the types match, and will terminate the instance with + /// `TerminationDetails::YieldTypeMismatch` if the check fails. + /// + /// The foreign code safety caveat of [`Instance::run()`](struct.Instance.html#method.run) + /// applies. + pub fn resume_with_val( + &mut self, + val: A, + ) -> Result { + lucet_ensure!( + self.state.is_yielded(), + "can only resume from a call to `Vmctx::yield_*()`" + ); + + self.resumed_val = Some(Box::new(val) as Box); + + self.swap_and_return() + } + /// Reset the instance's heap and global variables to their initial state. /// /// The WebAssembly `start` section will also be run, if one exists. @@ -519,7 +566,7 @@ impl Instance { c_fatal_handler: None, signal_handler: Box::new(signal_handler_none) as Box, entrypoint: None, - val_from_host: None, + resumed_val: None, _padding: (), }; inst.set_globals_ptr(globals_ptr); @@ -601,27 +648,16 @@ impl Instance { self.swap_and_return() } - pub fn resume(&mut self) -> Result { - lucet_ensure!( - self.state.is_yielded(), - "can only resume from a call to `Vmctx::yield_*()`" - ); - - self.swap_and_return() - } - - pub fn resume_with_val(&mut self, val: A) -> Result { - lucet_ensure!( - self.state.is_yielded(), - "can only resume from a call to `Vmctx::yield_*()`" - ); - - self.val_from_host = Some(Box::new(val) as Box); - - self.swap_and_return() - } - + /// The core routine for context switching into a guest, and extracting a result. + /// + /// This must only be called for an instance in a ready, non-fatally faulted, or yielded + /// state. The public wrappers around this function should make sure the state is appropriate. fn swap_and_return(&mut self) -> Result { + debug_assert!( + self.state.is_ready() + || (self.state.is_fault() && !self.state.is_fatal()) + || self.state.is_yielded() + ); self.state = State::Running; // there should never be another instance running on this thread when we enter this function @@ -803,6 +839,9 @@ pub enum TerminationDetails { Signal, /// Returned when `get_embed_ctx` or `get_embed_ctx_mut` are used with a type that is not present. CtxNotFound, + /// Returned when the type of the value passed to `Instance::resume_with_val()` does not match + /// the type expected by `Vmctx::yield_expecting_val()` or `Vmctx::yield_val_expecting_val`, or + /// if `Instance::resume()` was called when a value was expected. YieldTypeMismatch, /// Returned when dynamic borrowing rules of methods like `Vmctx::heap()` are violated. BorrowError(&'static str), @@ -864,6 +903,10 @@ impl std::fmt::Debug for TerminationDetails { unsafe impl Send for TerminationDetails {} unsafe impl Sync for TerminationDetails {} +/// The value yielded by the guest and returned to the host. +/// +/// **Note**: The `Sync` trait bound is only present because yielded values are (temporarily) +/// returned as a variant of `Error`. In the future, this bound may be dropped. #[derive(Clone)] pub struct YieldedVal { val: Option>, @@ -890,14 +933,18 @@ impl YieldedVal { YieldedVal { val: None } } + /// Returns `true` if the guest yielded without a value. pub fn is_none(&self) -> bool { self.val.is_none() } + /// Returns `true` if the guest yielded with a value. pub fn is_some(&self) -> bool { self.val.is_some() } + /// Attempt to downcast the yielded value to a concrete type, returning the original + /// `YieldedVal` if unsuccessful. pub fn downcast(self) -> Result, YieldedVal> { if let Some(val) = self.val { match val.downcast() { @@ -909,6 +956,8 @@ impl YieldedVal { } } + /// Returns a reference to the yielded value if it is present and of type `A`, or `None` if it + /// isn't. pub fn downcast_ref(&self) -> Option<&A> { self.val.as_ref().and_then(|val| val.downcast_ref()) } diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index be769c380..bb4dad763 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -59,7 +59,11 @@ pub trait VmctxInternal { /// terminating the instance. unsafe fn instance_mut(&self) -> &mut Instance; - fn try_take_yielded_val(&self) -> Option; + /// Try to take and return the value passed to `Instance::resume_with_val()`. + /// + /// If there is no resumed value, or if the dynamic type check of the value fails, this returns + /// `None`. + fn try_take_resumed_val(&self) -> Option; } impl VmctxInternal for Vmctx { @@ -71,9 +75,9 @@ impl VmctxInternal for Vmctx { instance_from_vmctx(self.vmctx) } - fn try_take_yielded_val(&self) -> Option { + fn try_take_resumed_val(&self) -> Option { let inst = unsafe { self.instance_mut() }; - if let Some(val) = inst.val_from_host.take() { + if let Some(val) = inst.resumed_val.take() { if let Ok(val) = val.downcast() { Some(*val) } else { @@ -284,6 +288,13 @@ impl Vmctx { .get_func_from_idx(table_idx, func_idx) } + /// Suspend the instance, returning an empty `Error::InstanceYielded` to where the instance was + /// run or resumed. + /// + /// After suspending, the instance may be resumed by the host using + /// [`Instance::resume()`](../struct.Instance.html#method.resume) or + /// [`Instance::resume_with_val()`](../struct.Instance.html#method.resume_with_val), although + /// the value passed in the latter case will be ignored. pub fn yield_(&self) { let inst = unsafe { self.instance_mut() }; inst.state = State::Yielded { @@ -292,11 +303,26 @@ impl Vmctx { HOST_CTX.with(|host_ctx| unsafe { Context::swap(&mut inst.ctx, &mut *host_ctx.get()) }); } + /// Suspend the instance, returning an empty `Error::InstanceYielded` to where the instance was + /// run or resumed. + /// + /// After suspending, the instance may be resumed by the host + /// [`Instance::resume_with_val()`](../struct.Instance.html#method.resume_with_val). The type of + /// the value passed when resuming must match the return type of this function. If the types do + /// not match, or if [`Instance::resume()`](../struct.Instance.html#method.resume) is used + /// instead, the instance will terminate. pub fn yield_expecting_val(&self) -> R { self.yield_(); - self.take_yielded_val() + self.take_resumed_val() } + /// Suspend the instance, returning a value in `Error::InstanceYielded` to where the instance + /// was run or resumed. + /// + /// After suspending, the instance may be resumed by the host using + /// [`Instance::resume()`](../struct.Instance.html#method.resume) or + /// [`Instance::resume_with_val()`](../struct.Instance.html#method.resume_with_val), although + /// the value passed in the latter case will be ignored. pub fn yield_val(&self, val: A) { let inst = unsafe { self.instance_mut() }; inst.state = State::Yielded { @@ -305,16 +331,27 @@ impl Vmctx { HOST_CTX.with(|host_ctx| unsafe { Context::swap(&mut inst.ctx, &mut *host_ctx.get()) }); } + /// Suspend the instance, returning a value in `Error::InstanceYielded` to where the instance + /// was run or resumed. + /// + /// After suspending, the instance may be resumed by the host + /// [`Instance::resume_with_val()`](../struct.Instance.html#method.resume_with_val). The type of + /// the value passed when resuming must match the return type of this function. If the types do + /// not match, or if [`Instance::resume()`](../struct.Instance.html#method.resume) is used + /// instead, the instance will terminate. pub fn yield_val_expecting_val( &self, val: A, ) -> R { self.yield_val(val); - self.take_yielded_val() + self.take_resumed_val() } - fn take_yielded_val(&self) -> R { - self.try_take_yielded_val() + /// Take and return the value passed to + /// [`Instance::resume_with_val()`](../struct.Instance.html#method.resume_with_val), terminating + /// the instance if there is no value present, or the dynamic type check of the value fails. + fn take_resumed_val(&self) -> R { + self.try_take_resumed_val() .unwrap_or_else(|| panic!(TerminationDetails::YieldTypeMismatch)) } } diff --git a/lucet-runtime/src/c_api.rs b/lucet-runtime/src/c_api.rs index 610891e78..a65db8a0e 100644 --- a/lucet-runtime/src/c_api.rs +++ b/lucet-runtime/src/c_api.rs @@ -479,7 +479,7 @@ lucet_hostcalls! { } // return any `CYieldedVal` pointer that comes back, otherwise NULL - if let Some(CYieldedVal { val }) = vmctx.try_take_yielded_val() { + if let Some(CYieldedVal { val }) = vmctx.try_take_resumed_val() { val } else { std::ptr::null_mut() diff --git a/lucet-runtime/src/lib.rs b/lucet-runtime/src/lib.rs index 3e6218394..0f705c5dd 100644 --- a/lucet-runtime/src/lib.rs +++ b/lucet-runtime/src/lib.rs @@ -133,6 +133,133 @@ //! unsafe { Box::from_raw(foreign_ctx) }; //! ``` //! +//! ## Yielding and Resuming +//! +//! Lucet hostcalls can use the `vmctx` argument to yield, suspending themselves and optionally +//! returning a value back to the host context. A yielded instance can then be resumed by the host, +//! and execution will continue from the point of the yield. +//! +//! Four yield methods are available for hostcall implementors: +//! +//! | | Yields value? | Expects value? | +//! |--------------------------------------------------------------------|---------------|----------------| +//! | [`yield_`](vmctx/struct.Vmctx.html#method.yield_) | ❌ | ❌ | +//! | [`yield_val`](vmctx/struct.Vmctx.html#method.yield_) | ✅ | ❌ | +//! | [`yield_expecting_val`](vmctx/struct.Vmctx.html#method.yield_) | ❌ | ✅ | +//! | [`yield_val_expecting_val`](vmctx/struct.Vmctx.html#method.yield_) | ✅ | ✅ | +//! +//! The host is free to ignore values yielded by guests, but a yielded instance must be resumed with +//! a value of the correct type using +//! [`Instance::resume_with_val()`](struct.Instance.html#method.resume_with_val), if one is +//! expected. Otherwise, the instance will terminate. +//! +//! ### Factorial example +//! +//! In this example, we use yielding and resuming to offload multiplication to the host context, and +//! to incrementally return results to the host. While certainly overkill for computing a factorial +//! function, this structure mirrors that of many asynchronous I/O interfaces. +//! +//! Since the focus of this example is on the behavior of hostcalls that yield, our Lucet guest +//! program just calls a hostcall: +//! +//! ```no_run +//! // factorials_guest.rs +//! extern "C" { +//! fn hostcall_factorials(n: u64); +//! } +//! +//! #[no_mangle] +//! pub extern "C" fn run() { +//! unsafe { +//! hostcall_factorials(5); +//! } +//! } +//! ``` +//! +//! In our hostcall, there are two changes from a standard recursive implementation of factorial. +//! +//! - Instead of performing the `n * fact(n - 1)` multiplication ourselves, we yield the operands +//! and expect the product when resumed. +//! +//! - Whenever we have an intermediate answer, we yield it. +//! +//! To implement this, we introduce a new `enum` type to represent what we want the host to do next, +//! and yield it when appropriate. +//! +//! ```no_run +//! use lucet_runtime::lucet_hostcalls; +//! use lucet_runtime::vmctx::Vmctx; +//! +//! pub enum FactorialsK { +//! Mult(u64, u64), +//! Result(u64), +//! } +//! +//! lucet_hostcalls! { +//! #[no_mangle] +//! pub unsafe extern "C" fn hostcall_factorials( +//! &mut vmctx, +//! n: u64, +//! ) -> () { +//! fn fact(vmctx: &mut Vmctx, n: u64) -> u64 { +//! if n <= 1 { +//! // yield an answer +//! vmctx.yield_val(FactorialsK::Result(1)); +//! 1 +//! } else { +//! let n_rec = fact(vmctx, n - 1); +//! // yield a request for the host to perform multiplication +//! let n = vmctx.yield_val_expecting_val(FactorialsK::Mult(n, n_rec)); +//! // yield an answer +//! vmctx.yield_val(FactorialsK::Result(n)); +//! n +//! } +//! } +//! fact(vmctx, n); +//! } +//! } +//! ``` +//! +//! The host side of the code, then, is an interpreter that repeatedly checks the yielded value and +//! performs the appropriate operation. The hostcall returns normally when it is finished, so we +//! exit the loop when the run/resume result is `Ok`. +//! +//! ```no_run +//! # pub enum FactorialsK { +//! # Mult(u64, u64), +//! # Result(u64), +//! # } +//! use lucet_runtime::{DlModule, Error, Limits, MmapRegion, Region}; +//! +//! let module = DlModule::load("factorials_guest.so").unwrap(); +//! let region = MmapRegion::create(1, &Limits::default()).unwrap(); +//! let mut inst = region.new_instance(module).unwrap(); +//! +//! let mut factorials = vec![]; +//! +//! let mut res = inst.run("run", &[]); +//! +//! while let Err(Error::InstanceYielded(val)) = res { +//! if let Some(k) = val.downcast_ref::() { +//! match k { +//! FactorialsK::Mult(n, n_rec) => { +//! // guest wants us to multiply for it +//! res = inst.resume_with_val(n * n_rec); +//! } +//! FactorialsK::Result(n) => { +//! // guest is returning an answer +//! factorials.push(*n); +//! res = inst.resume(); +//! } +//! } +//! } else { +//! panic!("didn't yield with expected type"); +//! } +//! } +//! +//! assert_eq!(factorials.as_slice(), &[1, 2, 6, 24, 120]); +//! ``` +//! //! ## Custom Signal Handlers //! //! Since Lucet programs are run as native machine code, signals such as `SIGSEGV` and `SIGFPE` can @@ -206,7 +333,7 @@ pub use lucet_module::{PublicKey, TrapCode}; pub use lucet_runtime_internals::alloc::Limits; pub use lucet_runtime_internals::error::Error; pub use lucet_runtime_internals::instance::{ - FaultDetails, Instance, InstanceHandle, SignalBehavior, TerminationDetails, + FaultDetails, Instance, InstanceHandle, SignalBehavior, TerminationDetails, YieldedVal, }; pub use lucet_runtime_internals::module::{DlModule, Module}; pub use lucet_runtime_internals::region::mmap::MmapRegion; From 21493c5271f15911d900bb9b3fe0334a4b644050 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 29 Jul 2019 16:02:17 -0700 Subject: [PATCH 274/512] [lucet-runtime] replace resumed val if typecheck fails Also some doc tweaks for yield/resume --- lucet-runtime/lucet-runtime-internals/src/error.rs | 6 +++--- lucet-runtime/lucet-runtime-internals/src/vmctx.rs | 10 ++++++---- lucet-runtime/src/lib.rs | 8 ++++---- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/error.rs b/lucet-runtime/lucet-runtime-internals/src/error.rs index 5364206e7..2c1007b36 100644 --- a/lucet-runtime/lucet-runtime-internals/src/error.rs +++ b/lucet-runtime/lucet-runtime-internals/src/error.rs @@ -52,11 +52,11 @@ pub enum Error { /// variant is used, the `YieldedVal` may contain a value passed from the guest context to the /// host. /// - /// An instance that has returned may only be resumed + /// An instance that has yielded may only be resumed /// ([with](struct.Instance.html#method.resume_with_val) or /// [without](struct.Instance.html#method.resume) a value to returned to the guest), - /// [reset](struct.Instance.html#method.reset), or dropped. Attempting to run an instance that - /// has yielded will result in an error. + /// [reset](struct.Instance.html#method.reset), or dropped. Attempting to run an instance from a + /// new entrypoint after it has yielded but without first resetting will result in an error. /// /// **Note**: This is not really an error, so once the `Try` trait is stabilized, this will /// likely be moved out of this type and into a custom return type for `Instance::run()`. diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index bb4dad763..307f13700 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -78,10 +78,12 @@ impl VmctxInternal for Vmctx { fn try_take_resumed_val(&self) -> Option { let inst = unsafe { self.instance_mut() }; if let Some(val) = inst.resumed_val.take() { - if let Ok(val) = val.downcast() { - Some(*val) - } else { - None + match val.downcast() { + Ok(val) => Some(*val), + Err(val) => { + inst.resumed_val = Some(val); + None + } } } else { None diff --git a/lucet-runtime/src/lib.rs b/lucet-runtime/src/lib.rs index 0f705c5dd..3e8fb310d 100644 --- a/lucet-runtime/src/lib.rs +++ b/lucet-runtime/src/lib.rs @@ -148,8 +148,8 @@ //! | [`yield_expecting_val`](vmctx/struct.Vmctx.html#method.yield_) | ❌ | ✅ | //! | [`yield_val_expecting_val`](vmctx/struct.Vmctx.html#method.yield_) | ✅ | ✅ | //! -//! The host is free to ignore values yielded by guests, but a yielded instance must be resumed with -//! a value of the correct type using +//! The host is free to ignore values yielded by guests, but a yielded instance may only be resumed +//! with a value of the correct type using //! [`Instance::resume_with_val()`](struct.Instance.html#method.resume_with_val), if one is //! expected. Otherwise, the instance will terminate. //! @@ -157,10 +157,10 @@ //! //! In this example, we use yielding and resuming to offload multiplication to the host context, and //! to incrementally return results to the host. While certainly overkill for computing a factorial -//! function, this structure mirrors that of many asynchronous I/O interfaces. +//! function, this structure mirrors that of many asynchronous workflows. //! //! Since the focus of this example is on the behavior of hostcalls that yield, our Lucet guest -//! program just calls a hostcall: +//! program just invokes a hostcall: //! //! ```no_run //! // factorials_guest.rs From 7648168508d4e311bd52595b5dd3afb8fe8d7584 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 30 Jul 2019 09:16:57 -0700 Subject: [PATCH 275/512] [lucet-runtime] add dynamic typechecking to `resume_with_val` This moves type errors for resumed values to the host caller side, rather than terminating instances when the typecheck fails. --- .../lucet-runtime-internals/src/instance.rs | 56 +++++++--- .../lucet-runtime-internals/src/vmctx.rs | 39 ++++--- lucet-runtime/lucet-runtime-tests/src/host.rs | 105 ++++++++++++++++++ lucet-runtime/src/lib.rs | 2 +- 4 files changed, 169 insertions(+), 33 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index 1603d2655..758056af7 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -18,6 +18,7 @@ use memoffset::offset_of; use std::any::Any; use std::cell::{BorrowError, BorrowMutError, Ref, RefCell, RefMut, UnsafeCell}; use std::ffi::{CStr, CString}; +use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut}; use std::ptr::{self, NonNull}; @@ -335,31 +336,33 @@ impl Instance { /// /// This should only be used when the guest yielded with /// [`Vmctx::yield_()`](vmctx/struct.Vmctx.html#method.yield_) or - /// [`Vmctx::yield_val()`](vmctx/struct.Vmctx.html#method.yield_val). Otherwise, the guest will - /// be expecting a value to be returned from the host, and will terminate the instance when one - /// is not found. + /// [`Vmctx::yield_val()`](vmctx/struct.Vmctx.html#method.yield_val). Otherwise, this call will + /// fail with `Error::InvalidArgument`. /// /// The foreign code safety caveat of [`Instance::run()`](struct.Instance.html#method.run) /// applies. pub fn resume(&mut self) -> Result { - lucet_ensure!( - self.state.is_yielded(), - "can only resume from a call to `Vmctx::yield_*()`" - ); + match &self.state { + State::Yielded { expected: None, .. } => (), + State::Yielded { expected: _, .. } => { + return Err(Error::InvalidArgument( + "yielded instance expects a value when resuming", + )) + } + _ => lucet_bail!("can only resume a yielded instance"), + } self.swap_and_return() } /// Resume execution of an instance that has yielded, providing a value to the guest. /// - /// If the guest yielded with [`Vmctx::yield_()`](vmctx/struct.Vmctx.html#method.yield_) or - /// [`Vmctx::yield_val()`](vmctx/struct.Vmctx.html#method.yield_val), the provided value will be - /// ignored. Otherwise, the type of the provided value must match the type expected by + /// The type of the provided value must match the type expected by /// [`Vmctx::yield_expecting_val()`](vmctx/struct.Vmctx.html#method.yield_expecting_val) or /// [`Vmctx::yield_val_expecting_val()`](vmctx/struct.Vmctx.html#method.yield_val_expecting_val). /// - /// The guest will dynamically check that the types match, and will terminate the instance with - /// `TerminationDetails::YieldTypeMismatch` if the check fails. + /// The provided value will be dynamically typechecked against the type the guest expects to + /// receive, and if that check fails, this call will fail with `Error::InvalidArgument`. /// /// The foreign code safety caveat of [`Instance::run()`](struct.Instance.html#method.run) /// applies. @@ -367,10 +370,24 @@ impl Instance { &mut self, val: A, ) -> Result { - lucet_ensure!( - self.state.is_yielded(), - "can only resume from a call to `Vmctx::yield_*()`" - ); + match &self.state { + State::Yielded { + expected: Some(expected), + .. + } => { + if !expected.is::>() { + return Err(Error::InvalidArgument( + "type mismatch between yielded instance expected value and resumed value", + )); + } + } + State::Yielded { expected: None, .. } => { + return Err(Error::InvalidArgument( + "yielded instance does not expect a value when resuming", + )) + } + _ => lucet_bail!("can only resume a yielded instance"), + } self.resumed_val = Some(Box::new(val) as Box); @@ -773,6 +790,9 @@ pub enum State { }, Yielded { val: YieldedVal, + /// Concretely, this should only ever be `Option>>` where `R` is the type + /// the guest expects upon resumption. + expected: Option>, }, } @@ -842,6 +862,10 @@ pub enum TerminationDetails { /// Returned when the type of the value passed to `Instance::resume_with_val()` does not match /// the type expected by `Vmctx::yield_expecting_val()` or `Vmctx::yield_val_expecting_val`, or /// if `Instance::resume()` was called when a value was expected. + /// + /// **Note**: If you see this termination value, please report it as a Lucet bug. The types of + /// resumed values are dynamically checked by `Instance::resume()` and + /// `Instance::resume_with_val()`, so this should never arise. YieldTypeMismatch, /// Returned when dynamic borrowing rules of methods like `Vmctx::heap()` are violated. BorrowError(&'static str), diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index 307f13700..072a24872 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -15,6 +15,7 @@ use lucet_module::{FunctionHandle, GlobalValue}; use std::any::Any; use std::borrow::{Borrow, BorrowMut}; use std::cell::{Ref, RefCell, RefMut}; +use std::marker::PhantomData; /// An opaque handle to a running instance's context. #[derive(Debug)] @@ -294,13 +295,12 @@ impl Vmctx { /// run or resumed. /// /// After suspending, the instance may be resumed by the host using - /// [`Instance::resume()`](../struct.Instance.html#method.resume) or - /// [`Instance::resume_with_val()`](../struct.Instance.html#method.resume_with_val), although - /// the value passed in the latter case will be ignored. + /// [`Instance::resume()`](../struct.Instance.html#method.resume). pub fn yield_(&self) { let inst = unsafe { self.instance_mut() }; inst.state = State::Yielded { val: YieldedVal::none(), + expected: None, }; HOST_CTX.with(|host_ctx| unsafe { Context::swap(&mut inst.ctx, &mut *host_ctx.get()) }); } @@ -309,12 +309,16 @@ impl Vmctx { /// run or resumed. /// /// After suspending, the instance may be resumed by the host - /// [`Instance::resume_with_val()`](../struct.Instance.html#method.resume_with_val). The type of - /// the value passed when resuming must match the return type of this function. If the types do - /// not match, or if [`Instance::resume()`](../struct.Instance.html#method.resume) is used - /// instead, the instance will terminate. + /// [`Instance::resume_with_val()`](../struct.Instance.html#method.resume_with_val) with a value + /// of type `R`. pub fn yield_expecting_val(&self) -> R { - self.yield_(); + let inst = unsafe { self.instance_mut() }; + let expected: Box> = Box::new(PhantomData); + inst.state = State::Yielded { + val: YieldedVal::none(), + expected: Some(expected as Box), + }; + HOST_CTX.with(|host_ctx| unsafe { Context::swap(&mut inst.ctx, &mut *host_ctx.get()) }); self.take_resumed_val() } @@ -322,13 +326,12 @@ impl Vmctx { /// was run or resumed. /// /// After suspending, the instance may be resumed by the host using - /// [`Instance::resume()`](../struct.Instance.html#method.resume) or - /// [`Instance::resume_with_val()`](../struct.Instance.html#method.resume_with_val), although - /// the value passed in the latter case will be ignored. + /// [`Instance::resume()`](../struct.Instance.html#method.resume). pub fn yield_val(&self, val: A) { let inst = unsafe { self.instance_mut() }; inst.state = State::Yielded { val: YieldedVal::some(val), + expected: None, }; HOST_CTX.with(|host_ctx| unsafe { Context::swap(&mut inst.ctx, &mut *host_ctx.get()) }); } @@ -337,15 +340,19 @@ impl Vmctx { /// was run or resumed. /// /// After suspending, the instance may be resumed by the host - /// [`Instance::resume_with_val()`](../struct.Instance.html#method.resume_with_val). The type of - /// the value passed when resuming must match the return type of this function. If the types do - /// not match, or if [`Instance::resume()`](../struct.Instance.html#method.resume) is used - /// instead, the instance will terminate. + /// [`Instance::resume_with_val()`](../struct.Instance.html#method.resume_with_val) with a value + /// of type `R`. pub fn yield_val_expecting_val( &self, val: A, ) -> R { - self.yield_val(val); + let inst = unsafe { self.instance_mut() }; + let expected: Box> = Box::new(PhantomData); + inst.state = State::Yielded { + val: YieldedVal::some(val), + expected: Some(expected as Box), + }; + HOST_CTX.with(|host_ctx| unsafe { Context::swap(&mut inst.ctx, &mut *host_ctx.get()) }); self.take_resumed_val() } diff --git a/lucet-runtime/lucet-runtime-tests/src/host.rs b/lucet-runtime/lucet-runtime-tests/src/host.rs index 4559f6437..70ab31c79 100644 --- a/lucet-runtime/lucet-runtime-tests/src/host.rs +++ b/lucet-runtime/lucet-runtime-tests/src/host.rs @@ -502,5 +502,110 @@ macro_rules! host_tests { assert_eq!(facts.as_slice(), &[1, 2, 6, 24, 120]); } + + #[test] + fn resume_unexpected() { + extern "C" { + fn hostcall_yields_5(vmctx: *mut lucet_vmctx); + } + + unsafe extern "C" fn f(vmctx: *mut lucet_vmctx) { + hostcall_yields_5(vmctx); + } + + let module = MockModuleBuilder::new() + .with_export_func(MockExportBuilder::new( + "f", + FunctionPointer::from_usize(f as usize), + )) + .build(); + + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + if let Err(Error::InstanceYielded(val)) = inst.run("f", &[]) { + assert_eq!(*val.downcast::().unwrap(), 5u64); + } else { + panic!("instance didn't yield"); + } + + match inst.resume_with_val(5u64) { + Err(Error::InvalidArgument(_)) => (), + Err(e) => panic!("unexpected error: {}", e), + Ok(_) => panic!("unexpected success"), + } + } + + #[test] + fn missing_resume_val() { + extern "C" { + fn hostcall_yield_expects_5(vmctx: *mut lucet_vmctx) -> u64; + } + + unsafe extern "C" fn f(vmctx: *mut lucet_vmctx) -> u64 { + hostcall_yield_expects_5(vmctx) + } + + let module = MockModuleBuilder::new() + .with_export_func(MockExportBuilder::new( + "f", + FunctionPointer::from_usize(f as usize), + )) + .build(); + + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + if let Err(Error::InstanceYielded(val)) = inst.run("f", &[]) { + assert!(val.is_none()); + } else { + panic!("instance didn't yield"); + } + + match inst.resume() { + Err(Error::InvalidArgument(_)) => (), + Err(e) => panic!("unexpected error: {}", e), + Ok(_) => panic!("unexpected success"), + } + } + + #[test] + fn resume_wrong_type() { + extern "C" { + fn hostcall_yield_expects_5(vmctx: *mut lucet_vmctx) -> u64; + } + + unsafe extern "C" fn f(vmctx: *mut lucet_vmctx) -> u64 { + hostcall_yield_expects_5(vmctx) + } + + let module = MockModuleBuilder::new() + .with_export_func(MockExportBuilder::new( + "f", + FunctionPointer::from_usize(f as usize), + )) + .build(); + + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + if let Err(Error::InstanceYielded(val)) = inst.run("f", &[]) { + assert!(val.is_none()); + } else { + panic!("instance didn't yield"); + } + + match inst.resume_with_val(true) { + Err(Error::InvalidArgument(_)) => (), + Err(e) => panic!("unexpected error: {}", e), + Ok(_) => panic!("unexpected success"), + } + } }; } diff --git a/lucet-runtime/src/lib.rs b/lucet-runtime/src/lib.rs index 3e8fb310d..761daa185 100644 --- a/lucet-runtime/src/lib.rs +++ b/lucet-runtime/src/lib.rs @@ -151,7 +151,7 @@ //! The host is free to ignore values yielded by guests, but a yielded instance may only be resumed //! with a value of the correct type using //! [`Instance::resume_with_val()`](struct.Instance.html#method.resume_with_val), if one is -//! expected. Otherwise, the instance will terminate. +//! expected. //! //! ### Factorial example //! From c38230d35e1215486dbdd4c63275f8d2f37311e3 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 30 Jul 2019 10:12:38 -0700 Subject: [PATCH 276/512] [lucet-runtime] fix C resume API and address review comments Since the yield/resume API for C does a sort of duck typing thing with null pointers, the new dynamic typechecking was a little too strict. This makes the typechecking optional in a private interface that the C API now uses. In addition to some doc fixups, the factorial examples now return values normally in addition to yielding intermediate values, hopefully reducing confusion about what the functions are doing. --- .../lucet-runtime-internals/src/instance.rs | 74 ++++++++++--------- .../lucet-runtime-internals/src/vmctx.rs | 3 + lucet-runtime/lucet-runtime-tests/src/host.rs | 44 +++++------ lucet-runtime/src/c_api.rs | 7 +- lucet-runtime/src/lib.rs | 49 ++++++------ lucet-runtime/tests/c_api.c | 11 ++- 6 files changed, 105 insertions(+), 83 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index 758056af7..5280cef6b 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -252,6 +252,11 @@ pub trait InstanceInternal { fn module(&self) -> &dyn Module; fn state(&self) -> &State; fn valid_magic(&self) -> bool; + fn resume_impl( + &mut self, + val: Option, + typecheck: bool, + ) -> Result; } impl InstanceInternal for Instance { @@ -279,6 +284,39 @@ impl InstanceInternal for Instance { fn valid_magic(&self) -> bool { self.magic == LUCET_INSTANCE_MAGIC } + + fn resume_impl( + &mut self, + val: Option, + typecheck: bool, + ) -> Result { + match &self.state { + State::Yielded { + expected: Some(expected), + .. + } => { + if typecheck + && ((val.is_some() && !expected.is::>()) || val.is_none()) + { + return Err(Error::InvalidArgument( + "type mismatch between yielded instance expected value and resumed value", + )); + } + } + State::Yielded { expected: None, .. } => { + if typecheck && val.is_some() { + return Err(Error::InvalidArgument( + "yielded instance does not expect a value when resuming", + )); + } + } + _ => lucet_bail!("can only resume a yielded instance"), + } + + self.resumed_val = val.map(|val| Box::new(val) as Box); + + self.swap_and_return() + } } // Public API @@ -342,17 +380,8 @@ impl Instance { /// The foreign code safety caveat of [`Instance::run()`](struct.Instance.html#method.run) /// applies. pub fn resume(&mut self) -> Result { - match &self.state { - State::Yielded { expected: None, .. } => (), - State::Yielded { expected: _, .. } => { - return Err(Error::InvalidArgument( - "yielded instance expects a value when resuming", - )) - } - _ => lucet_bail!("can only resume a yielded instance"), - } - - self.swap_and_return() + let none: Option<()> = None; + self.resume_impl(none, true) } /// Resume execution of an instance that has yielded, providing a value to the guest. @@ -370,28 +399,7 @@ impl Instance { &mut self, val: A, ) -> Result { - match &self.state { - State::Yielded { - expected: Some(expected), - .. - } => { - if !expected.is::>() { - return Err(Error::InvalidArgument( - "type mismatch between yielded instance expected value and resumed value", - )); - } - } - State::Yielded { expected: None, .. } => { - return Err(Error::InvalidArgument( - "yielded instance does not expect a value when resuming", - )) - } - _ => lucet_bail!("can only resume a yielded instance"), - } - - self.resumed_val = Some(Box::new(val) as Box); - - self.swap_and_return() + self.resume_impl(Some(val), true) } /// Reset the instance's heap and global variables to their initial state. diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index 072a24872..139a43e16 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -296,6 +296,9 @@ impl Vmctx { /// /// After suspending, the instance may be resumed by the host using /// [`Instance::resume()`](../struct.Instance.html#method.resume). + /// + /// (The reason for the trailing underscore in the name is that Rust reserves `yield` as a + /// keyword for future use.) pub fn yield_(&self) { let inst = unsafe { self.instance_mut() }; inst.state = State::Yielded { diff --git a/lucet-runtime/lucet-runtime-tests/src/host.rs b/lucet-runtime/lucet-runtime-tests/src/host.rs index 70ab31c79..656507b71 100644 --- a/lucet-runtime/lucet-runtime-tests/src/host.rs +++ b/lucet-runtime/lucet-runtime-tests/src/host.rs @@ -126,18 +126,17 @@ macro_rules! host_tests { pub unsafe extern "C" fn hostcall_yield_facts( &mut vmctx, n: u64, - ) -> () { + ) -> u64 { fn fact(vmctx: &mut Vmctx, n: u64) -> u64 { - if n <= 1 { - vmctx.yield_val(1u64); + let result = if n <= 1 { 1 } else { - let n = n * fact(vmctx, n - 1); - vmctx.yield_val(n); - n - } + n * fact(vmctx, n - 1) + }; + vmctx.yield_val(result); + result } - fact(vmctx, n); + fact(vmctx, n) } } @@ -151,19 +150,18 @@ macro_rules! host_tests { pub unsafe extern "C" fn hostcall_coop_facts( &mut vmctx, n: u64, - ) -> () { + ) -> u64 { fn fact(vmctx: &mut Vmctx, n: u64) -> u64 { - if n <= 1 { - vmctx.yield_val(CoopFactsK::Result(1)); + let result = if n <= 1 { 1 } else { let n_rec = fact(vmctx, n - 1); - let n = vmctx.yield_val_expecting_val(CoopFactsK::Mult(n, n_rec)); - vmctx.yield_val(CoopFactsK::Result(n)); - n - } + vmctx.yield_val_expecting_val(CoopFactsK::Mult(n, n_rec)) + }; + vmctx.yield_val(CoopFactsK::Result(result)); + result } - fact(vmctx, n); + fact(vmctx, n) } } @@ -425,11 +423,11 @@ macro_rules! host_tests { #[test] fn yield_factorials() { extern "C" { - fn hostcall_yield_facts(vmctx: *mut lucet_vmctx, n: u64); + fn hostcall_yield_facts(vmctx: *mut lucet_vmctx, n: u64) -> u64; } - unsafe extern "C" fn f(vmctx: *mut lucet_vmctx) { - hostcall_yield_facts(vmctx, 5); + unsafe extern "C" fn f(vmctx: *mut lucet_vmctx) -> u64 { + hostcall_yield_facts(vmctx, 5) } let module = MockModuleBuilder::new() @@ -454,16 +452,17 @@ macro_rules! host_tests { } assert_eq!(facts.as_slice(), &[1, 2, 6, 24, 120]); + assert_eq!(u64::from(res.unwrap()), 120u64); } #[test] fn coop_factorials() { extern "C" { - fn hostcall_coop_facts(vmctx: *mut lucet_vmctx, n: u64); + fn hostcall_coop_facts(vmctx: *mut lucet_vmctx, n: u64) -> u64; } - unsafe extern "C" fn f(vmctx: *mut lucet_vmctx) { - hostcall_coop_facts(vmctx, 5); + unsafe extern "C" fn f(vmctx: *mut lucet_vmctx) -> u64 { + hostcall_coop_facts(vmctx, 5) } let module = MockModuleBuilder::new() @@ -501,6 +500,7 @@ macro_rules! host_tests { } assert_eq!(facts.as_slice(), &[1, 2, 6, 24, 120]); + assert_eq!(u64::from(res.unwrap()), 120u64); } #[test] diff --git a/lucet-runtime/src/c_api.rs b/lucet-runtime/src/c_api.rs index a65db8a0e..006d7e6e5 100644 --- a/lucet-runtime/src/c_api.rs +++ b/lucet-runtime/src/c_api.rs @@ -216,12 +216,15 @@ pub unsafe extern "C" fn lucet_instance_resume( val: *mut c_void, ) -> lucet_error { with_instance_ptr!(inst, { + // resume without typechecking, since the C version of `yield` translates type errors into + // null/non-null return values if val.is_null() { - inst.resume() + let none: Option<()> = None; + inst.resume_impl(none, false) .map(|_| lucet_error::Ok) .unwrap_or_else(|e| e.into()) } else { - inst.resume_with_val(CYieldedVal { val }) + inst.resume_impl(Some(CYieldedVal { val }), false) .map(|_| lucet_error::Ok) .unwrap_or_else(|e| e.into()) } diff --git a/lucet-runtime/src/lib.rs b/lucet-runtime/src/lib.rs index 761daa185..0088a2b33 100644 --- a/lucet-runtime/src/lib.rs +++ b/lucet-runtime/src/lib.rs @@ -141,12 +141,12 @@ //! //! Four yield methods are available for hostcall implementors: //! -//! | | Yields value? | Expects value? | -//! |--------------------------------------------------------------------|---------------|----------------| -//! | [`yield_`](vmctx/struct.Vmctx.html#method.yield_) | ❌ | ❌ | -//! | [`yield_val`](vmctx/struct.Vmctx.html#method.yield_) | ✅ | ❌ | -//! | [`yield_expecting_val`](vmctx/struct.Vmctx.html#method.yield_) | ❌ | ✅ | -//! | [`yield_val_expecting_val`](vmctx/struct.Vmctx.html#method.yield_) | ✅ | ✅ | +//! | | Yields value? | Expects value? | +//! |-------------------------------------------------------------------------------------|---------------|----------------| +//! | [`yield_`](vmctx/struct.Vmctx.html#method.yield_) | ❌ | ❌ | +//! | [`yield_val`](vmctx/struct.Vmctx.html#method.yield_val) | ✅ | ❌ | +//! | [`yield_expecting_val`](vmctx/struct.Vmctx.html#method.yield_expecting_val) | ❌ | ✅ | +//! | [`yield_val_expecting_val`](vmctx/struct.Vmctx.html#method.yield_val_expecting_val) | ✅ | ✅ | //! //! The host is free to ignore values yielded by guests, but a yielded instance may only be resumed //! with a value of the correct type using @@ -165,13 +165,13 @@ //! ```no_run //! // factorials_guest.rs //! extern "C" { -//! fn hostcall_factorials(n: u64); +//! fn hostcall_factorials(n: u64) -> u64; //! } //! //! #[no_mangle] -//! pub extern "C" fn run() { +//! pub extern "C" fn run() -> u64 { //! unsafe { -//! hostcall_factorials(5); +//! hostcall_factorials(5) //! } //! } //! ``` @@ -181,7 +181,10 @@ //! - Instead of performing the `n * fact(n - 1)` multiplication ourselves, we yield the operands //! and expect the product when resumed. //! -//! - Whenever we have an intermediate answer, we yield it. +//! - Whenever we have computed a factorial, including both intermediate values and the final +//! answer, we yield it. +//! +//! The final answer is returned normally as the result of the guest function. //! //! To implement this, we introduce a new `enum` type to represent what we want the host to do next, //! and yield it when appropriate. @@ -200,29 +203,28 @@ //! pub unsafe extern "C" fn hostcall_factorials( //! &mut vmctx, //! n: u64, -//! ) -> () { +//! ) -> u64 { //! fn fact(vmctx: &mut Vmctx, n: u64) -> u64 { -//! if n <= 1 { -//! // yield an answer -//! vmctx.yield_val(FactorialsK::Result(1)); +//! let result = if n <= 1 { //! 1 //! } else { //! let n_rec = fact(vmctx, n - 1); //! // yield a request for the host to perform multiplication -//! let n = vmctx.yield_val_expecting_val(FactorialsK::Mult(n, n_rec)); -//! // yield an answer -//! vmctx.yield_val(FactorialsK::Result(n)); -//! n -//! } +//! vmctx.yield_val_expecting_val(FactorialsK::Mult(n, n_rec)) +//! // once resumed, that yield evaluates to the multiplication result +//! }; +//! // yield a result +//! vmctx.yield_val(FactorialsK::Result(result)); +//! result //! } -//! fact(vmctx, n); +//! fact(vmctx, n) //! } //! } //! ``` //! //! The host side of the code, then, is an interpreter that repeatedly checks the yielded value and -//! performs the appropriate operation. The hostcall returns normally when it is finished, so we -//! exit the loop when the run/resume result is `Ok`. +//! performs the appropriate operation. The hostcall returns normally with the final answer when it +//! is finished, so we exit the loop when the run/resume result is `Ok`. //! //! ```no_run //! # pub enum FactorialsK { @@ -257,7 +259,10 @@ //! } //! } //! +//! // intermediate values are correct //! assert_eq!(factorials.as_slice(), &[1, 2, 6, 24, 120]); +//! // final value is correct +//! assert_eq!(u64::from(res.unwrap()), 120u64); //! ``` //! //! ## Custom Signal Handlers diff --git a/lucet-runtime/tests/c_api.c b/lucet-runtime/tests/c_api.c index 1ce160f89..f6d9b4e76 100644 --- a/lucet-runtime/tests/c_api.c +++ b/lucet-runtime/tests/c_api.c @@ -137,21 +137,24 @@ bool lucet_runtime_test_yield_resume(struct lucet_dl_module *mod) struct yield_resume_val val = *(struct yield_resume_val *) st.val.yielded.val; switch (val.tag) { - case yield_resume_tag_mult:; + case yield_resume_tag_mult: { uint64_t mult_result = val.val.mult.x * val.val.mult.y; err = lucet_instance_resume(inst, &mult_result); continue; - case yield_resume_tag_result: + } + case yield_resume_tag_result: { results[i++] = val.val.result; err = lucet_instance_resume(inst, NULL); continue; - default: + } + default: { fprintf(stderr, "unexpected yield_resume_tag\n"); goto fail3; } + } } if (err != lucet_error_ok) { - fprintf(stderr, "instance finished with non-ok error\n"); + fprintf(stderr, "instance finished with non-ok error: %s\n", lucet_error_name(err)); goto fail3; } From 7b84fa091d4d33e59c2c742f809928958aa275c9 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 30 Jul 2019 10:19:34 -0700 Subject: [PATCH 277/512] [lucet-runtime] return final factorial result in C test as well --- lucet-runtime/tests/c_api.c | 16 +++++++++++++++- lucet-runtime/tests/guests/yield_resume.c | 4 ++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/lucet-runtime/tests/c_api.c b/lucet-runtime/tests/c_api.c index f6d9b4e76..e6c0ed43d 100644 --- a/lucet-runtime/tests/c_api.c +++ b/lucet-runtime/tests/c_api.c @@ -158,12 +158,26 @@ bool lucet_runtime_test_yield_resume(struct lucet_dl_module *mod) goto fail3; } + struct lucet_state st; + err = lucet_instance_state(inst, &st); + if (err != lucet_error_ok) { + fprintf(stderr, "couldn't get instance state\n"); + goto fail3; + } + + if (st.tag != lucet_state_tag_returned) { + fprintf(stderr, "final instance state wasn't returned\n"); + goto fail3; + } + + uint64_t final_result = LUCET_UNTYPED_RETVAL_TO_U64(st.val.returned); + lucet_instance_release(inst); lucet_region_release(region); lucet_dl_module_release(mod); uint64_t expected_results[5] = { 1, 2, 6, 24, 120 }; - bool results_correct = true; + bool results_correct = final_result == 120; for (i = 0; i < 5; i++) { results_correct = results_correct && (results[i] == expected_results[i]); } diff --git a/lucet-runtime/tests/guests/yield_resume.c b/lucet-runtime/tests/guests/yield_resume.c index 7e06531d0..22b68f37e 100644 --- a/lucet-runtime/tests/guests/yield_resume.c +++ b/lucet-runtime/tests/guests/yield_resume.c @@ -2,7 +2,7 @@ extern uint64_t lucet_runtime_test_hostcall_yield_resume(uint64_t n); -void f() +uint64_t f() { - lucet_runtime_test_hostcall_yield_resume(5); + return lucet_runtime_test_hostcall_yield_resume(5); } From 54a26e1f4f5a5f7c0081671eb80bfb27f5dd55e5 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 30 Jul 2019 15:00:26 -0700 Subject: [PATCH 278/512] [lucet-runtime] add `RunResult` and unify yield implementations This ends the experiment with putting yields in `Err` so we could hang desperately onto `Result`, but is worth the change. This also introduces a zero-sized `EmptyYieldVal` to use as a placeholder when a yield/resume is not providing/expecting a value. This lets us unify the implementation of the various yield operators. Also changes the C yield/resume API to always provide and expect a wrapped pointer, simplifying the yield implementations further. Finally, includes some stray fixes to docs and exports, including a new method on `Module` so that `lucet-wasi` doesn't have to import internals in its `main.rs`. --- lucet-runtime/include/lucet_types.h | 2 +- .../lucet-runtime-internals/src/c_api.rs | 8 +- .../lucet-runtime-internals/src/error.rs | 29 +- .../lucet-runtime-internals/src/instance.rs | 258 ++++++++++++------ .../src/instance/signals.rs | 2 +- .../lucet-runtime-internals/src/module.rs | 7 +- .../lucet-runtime-internals/src/vmctx.rs | 92 ++++--- .../lucet-runtime-tests/src/entrypoint.rs | 48 ++-- .../lucet-runtime-tests/src/globals.rs | 45 ++- .../lucet-runtime-tests/src/guest_fault.rs | 5 +- lucet-runtime/lucet-runtime-tests/src/host.rs | 76 +++--- .../lucet-runtime-tests/src/memory.rs | 5 +- .../lucet-runtime-tests/src/stack.rs | 1 + .../lucet-runtime-tests/src/strcmp.rs | 3 +- lucet-runtime/src/c_api.rs | 36 +-- lucet-runtime/src/lib.rs | 23 +- lucet-runtime/tests/c_api.c | 14 +- lucet-spectest/src/script.rs | 1 + lucet-wasi/src/main.rs | 9 +- 19 files changed, 402 insertions(+), 262 deletions(-) diff --git a/lucet-runtime/include/lucet_types.h b/lucet-runtime/include/lucet_types.h index 918d01300..16df2be2d 100644 --- a/lucet-runtime/include/lucet_types.h +++ b/lucet-runtime/include/lucet_types.h @@ -27,8 +27,8 @@ enum lucet_error { lucet_error_func_not_found, lucet_error_runtime_fault, lucet_error_runtime_terminated, - lucet_error_instance_yielded, lucet_error_dl, + lucet_error_start_yielded, lucet_error_internal, lucet_error_unsupported, }; diff --git a/lucet-runtime/lucet-runtime-internals/src/c_api.rs b/lucet-runtime/lucet-runtime-internals/src/c_api.rs index 63c57a812..ce55a3b1a 100644 --- a/lucet-runtime/lucet-runtime-internals/src/c_api.rs +++ b/lucet-runtime/lucet-runtime-internals/src/c_api.rs @@ -75,8 +75,10 @@ pub enum lucet_error { FuncNotFound, RuntimeFault, RuntimeTerminated, - InstanceYielded, Dl, + InstanceNotReturned, + InstanceNotYielded, + StartYielded, Internal, Unsupported, } @@ -93,8 +95,10 @@ impl From for lucet_error { Error::FuncNotFound(_, _) => lucet_error::FuncNotFound, Error::RuntimeFault(_) => lucet_error::RuntimeFault, Error::RuntimeTerminated(_) => lucet_error::RuntimeTerminated, - Error::InstanceYielded(_) => lucet_error::InstanceYielded, Error::DlError(_) => lucet_error::Dl, + Error::InstanceNotReturned => lucet_error::InstanceNotReturned, + Error::InstanceNotYielded => lucet_error::InstanceNotYielded, + Error::StartYielded => lucet_error::StartYielded, Error::InternalError(_) => lucet_error::Internal, Error::Unsupported(_) => lucet_error::Unsupported, } diff --git a/lucet-runtime/lucet-runtime-internals/src/error.rs b/lucet-runtime/lucet-runtime-internals/src/error.rs index 2c1007b36..9bd927a0f 100644 --- a/lucet-runtime/lucet-runtime-internals/src/error.rs +++ b/lucet-runtime/lucet-runtime-internals/src/error.rs @@ -1,4 +1,4 @@ -use crate::instance::{FaultDetails, TerminationDetails, YieldedVal}; +use crate::instance::{FaultDetails, TerminationDetails}; use failure::Fail; /// Lucet runtime errors. @@ -45,28 +45,19 @@ pub enum Error { #[fail(display = "Runtime terminated")] RuntimeTerminated(TerminationDetails), - /// An instance yielded, potentially with a value. - /// - /// This arises when a hostcall invokes one of the - /// [`Vmctx::yield_*()`](vmctx/struct.Vmctx.html#method.yield_) family of methods. Depending on which - /// variant is used, the `YieldedVal` may contain a value passed from the guest context to the - /// host. - /// - /// An instance that has yielded may only be resumed - /// ([with](struct.Instance.html#method.resume_with_val) or - /// [without](struct.Instance.html#method.resume) a value to returned to the guest), - /// [reset](struct.Instance.html#method.reset), or dropped. Attempting to run an instance from a - /// new entrypoint after it has yielded but without first resetting will result in an error. - /// - /// **Note**: This is not really an error, so once the `Try` trait is stabilized, this will - /// likely be moved out of this type and into a custom return type for `Instance::run()`. - #[fail(display = "Instance yielded")] - InstanceYielded(YieldedVal), - /// IO errors arising during dynamic loading with [`DlModule`](struct.DlModule.html). #[fail(display = "Dynamic loading error: {}", _0)] DlError(#[cause] std::io::Error), + #[fail(display = "Instance not returned")] + InstanceNotReturned, + + #[fail(display = "Instance not yielded")] + InstanceNotYielded, + + #[fail(display = "Start function yielded")] + StartYielded, + /// A catch-all for internal errors that are likely unrecoverable by the runtime user. /// /// As the API matures, these will likely become rarer, replaced by new variants of this enum, diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index 5280cef6b..5728974ca 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -241,6 +241,114 @@ impl Drop for Instance { } } +/// The result of running or resuming an [`Instance`](struct.Instance.html). +#[derive(Debug)] +pub enum RunResult { + /// An instance returned with a value. + /// + /// The actual type of the contained value depends on the return type of the guest function that + /// was called. For guest functions with no return value, it is undefined behavior to do + /// anything with this value. + Returned(UntypedRetVal), + /// An instance yielded, potentially with a value. + /// + /// This arises when a hostcall invokes one of the + /// [`Vmctx::yield_*()`](vmctx/struct.Vmctx.html#method.yield_) family of methods. Depending on which + /// variant is used, the `YieldedVal` may contain a value passed from the guest context to the + /// host. + /// + /// An instance that has yielded may only be resumed + /// ([with](struct.Instance.html#method.resume_with_val) or + /// [without](struct.Instance.html#method.resume) a value to returned to the guest), + /// [reset](struct.Instance.html#method.reset), or dropped. Attempting to run an instance from a + /// new entrypoint after it has yielded but without first resetting will result in an error. + Yielded(YieldedVal), +} + +impl RunResult { + /// Try to get a return value from a run result, returning `Error::InstanceNotReturned` if the + /// instance instead yielded. + pub fn returned(self) -> Result { + match self { + RunResult::Returned(rv) => Ok(rv), + RunResult::Yielded(_) => Err(Error::InstanceNotReturned), + } + } + + /// Try to get a reference to a return value from a run result, returning + /// `Error::InstanceNotReturned` if the instance instead yielded. + pub fn returned_ref(&self) -> Result<&UntypedRetVal, Error> { + match self { + RunResult::Returned(rv) => Ok(rv), + RunResult::Yielded(_) => Err(Error::InstanceNotReturned), + } + } + + /// Returns `true` if the instance returned a value. + pub fn is_returned(&self) -> bool { + self.returned_ref().is_ok() + } + + /// Unwraps a run result into a return value. + /// + /// # Panics + /// + /// Panics if the instance instead yielded, with a panic message including the passed message. + pub fn expect_returned(self, msg: &str) -> UntypedRetVal { + self.returned().expect(msg) + } + + /// Unwraps a run result into a returned value. + /// + /// # Panics + /// + /// Panics if the instance instead yielded. + pub fn unwrap_returned(self) -> UntypedRetVal { + self.returned().unwrap() + } + + /// Try to get a yielded value from a run result, returning `Error::InstanceNotYielded` if the + /// instance instead returned. + pub fn yielded(self) -> Result { + match self { + RunResult::Returned(_) => Err(Error::InstanceNotYielded), + RunResult::Yielded(yv) => Ok(yv), + } + } + + /// Try to get a reference to a yielded value from a run result, returning + /// `Error::InstanceNotYielded` if the instance instead returned. + pub fn yielded_ref(&self) -> Result<&YieldedVal, Error> { + match self { + RunResult::Returned(_) => Err(Error::InstanceNotYielded), + RunResult::Yielded(yv) => Ok(yv), + } + } + + /// Returns `true` if the instance yielded. + pub fn is_yielded(&self) -> bool { + self.yielded_ref().is_ok() + } + + /// Unwraps a run result into a yielded value. + /// + /// # Panics + /// + /// Panics if the instance instead returned, with a panic message including the passed message. + pub fn expect_yielded(self, msg: &str) -> YieldedVal { + self.yielded().expect(msg) + } + + /// Unwraps a run result into a yielded value. + /// + /// # Panics + /// + /// Panics if the instance instead returned. + pub fn unwrap_yielded(self) -> YieldedVal { + self.yielded().unwrap() + } +} + /// APIs that are internal, but useful to implementors of extension modules; you probably don't want /// this trait! /// @@ -252,11 +360,6 @@ pub trait InstanceInternal { fn module(&self) -> &dyn Module; fn state(&self) -> &State; fn valid_magic(&self) -> bool; - fn resume_impl( - &mut self, - val: Option, - typecheck: bool, - ) -> Result; } impl InstanceInternal for Instance { @@ -284,39 +387,6 @@ impl InstanceInternal for Instance { fn valid_magic(&self) -> bool { self.magic == LUCET_INSTANCE_MAGIC } - - fn resume_impl( - &mut self, - val: Option, - typecheck: bool, - ) -> Result { - match &self.state { - State::Yielded { - expected: Some(expected), - .. - } => { - if typecheck - && ((val.is_some() && !expected.is::>()) || val.is_none()) - { - return Err(Error::InvalidArgument( - "type mismatch between yielded instance expected value and resumed value", - )); - } - } - State::Yielded { expected: None, .. } => { - if typecheck && val.is_some() { - return Err(Error::InvalidArgument( - "yielded instance does not expect a value when resuming", - )); - } - } - _ => lucet_bail!("can only resume a yielded instance"), - } - - self.resumed_val = val.map(|val| Box::new(val) as Box); - - self.swap_and_return() - } } // Public API @@ -327,7 +397,7 @@ impl Instance { /// # use lucet_runtime_internals::instance::InstanceHandle; /// # let instance: InstanceHandle = unimplemented!(); /// // regular execution yields `Ok(UntypedRetVal)` - /// let retval = instance.run("factorial", &[5u64.into()]).unwrap(); + /// let retval = instance.run("factorial", &[5u64.into()]).unwrap().unwrap_returned(); /// assert_eq!(u64::from(retval), 120u64); /// /// // runtime faults yield `Err(Error)` @@ -351,7 +421,7 @@ impl Instance { /// /// For the moment, we do not mark this as `unsafe` in the Rust type system, but that may change /// in the future. - pub fn run(&mut self, entrypoint: &str, args: &[Val]) -> Result { + pub fn run(&mut self, entrypoint: &str, args: &[Val]) -> Result { let func = self.module.get_export_func(entrypoint)?; self.run_func(func, &args) } @@ -359,13 +429,15 @@ impl Instance { /// Run a function with arguments in the guest context from the [WebAssembly function /// table](https://webassembly.github.io/spec/core/syntax/modules.html#tables). /// + /// # Safety + /// /// The same safety caveats of [`Instance::run()`](struct.Instance.html#method.run) apply. pub fn run_func_idx( &mut self, table_idx: u32, func_idx: u32, args: &[Val], - ) -> Result { + ) -> Result { let func = self.module.get_func_from_idx(table_idx, func_idx)?; self.run_func(func, &args) } @@ -377,11 +449,12 @@ impl Instance { /// [`Vmctx::yield_val()`](vmctx/struct.Vmctx.html#method.yield_val). Otherwise, this call will /// fail with `Error::InvalidArgument`. /// + /// # Safety + /// /// The foreign code safety caveat of [`Instance::run()`](struct.Instance.html#method.run) /// applies. - pub fn resume(&mut self) -> Result { - let none: Option<()> = None; - self.resume_impl(none, true) + pub fn resume(&mut self) -> Result { + self.resume_with_val(EmptyYieldVal) } /// Resume execution of an instance that has yielded, providing a value to the guest. @@ -393,13 +466,26 @@ impl Instance { /// The provided value will be dynamically typechecked against the type the guest expects to /// receive, and if that check fails, this call will fail with `Error::InvalidArgument`. /// + /// # Safety + /// /// The foreign code safety caveat of [`Instance::run()`](struct.Instance.html#method.run) /// applies. - pub fn resume_with_val( - &mut self, - val: A, - ) -> Result { - self.resume_impl(Some(val), true) + pub fn resume_with_val(&mut self, val: A) -> Result { + match &self.state { + State::Yielded { expected, .. } => { + // make sure the resumed value is of the right type + if !expected.is::>() { + return Err(Error::InvalidArgument( + "type mismatch between yielded instance expected value and resumed value", + )); + } + } + _ => return Err(Error::InvalidArgument("can only resume a yielded instance")), + } + + self.resumed_val = Some(Box::new(val) as Box); + + self.swap_and_return() } /// Reset the instance's heap and global variables to their initial state. @@ -607,7 +693,8 @@ impl Instance { // For this reason, the alignment of the structure is set to 4096, and we define accessors that // read/write the globals pointer as bytes [4096-8..4096] of that structure represented as raw bytes. #[inline] - pub fn get_globals_ptr(&self) -> *const i64 { + #[allow(dead_code)] + fn get_globals_ptr(&self) -> *const i64 { unsafe { *((self as *const _ as *const u8) .offset((HOST_PAGE_SIZE_EXPECTED - mem::size_of::<*mut i64>()) as isize) @@ -616,7 +703,7 @@ impl Instance { } #[inline] - pub fn set_globals_ptr(&mut self, globals_ptr: *const i64) { + fn set_globals_ptr(&mut self, globals_ptr: *const i64) { unsafe { *((self as *mut _ as *mut u8) .offset((HOST_PAGE_SIZE_EXPECTED - mem::size_of::<*mut i64>()) as isize) @@ -625,11 +712,12 @@ impl Instance { } /// Run a function in guest context at the given entrypoint. - fn run_func(&mut self, func: FunctionHandle, args: &[Val]) -> Result { - lucet_ensure!( - self.state.is_ready() || (self.state.is_fault() && !self.state.is_fatal()), - "instance must be ready or non-fatally faulted" - ); + fn run_func(&mut self, func: FunctionHandle, args: &[Val]) -> Result { + if !(self.state.is_ready() || (self.state.is_fault() && !self.state.is_fatal())) { + return Err(Error::InvalidArgument( + "instance must be ready or non-fatally faulted", + )); + } if func.ptr.as_usize() == 0 { return Err(Error::InvalidArgument( "entrypoint function cannot be null; this is probably a malformed module", @@ -677,7 +765,7 @@ impl Instance { /// /// This must only be called for an instance in a ready, non-fatally faulted, or yielded /// state. The public wrappers around this function should make sure the state is appropriate. - fn swap_and_return(&mut self) -> Result { + fn swap_and_return(&mut self) -> Result { debug_assert!( self.state.is_ready() || (self.state.is_fault() && !self.state.is_fatal()) @@ -719,10 +807,10 @@ impl Instance { State::Running => { let retval = self.ctx.get_untyped_retval(); self.state = State::Ready { retval }; - Ok(retval) + Ok(RunResult::Returned(retval)) } State::Terminated { details, .. } => Err(Error::RuntimeTerminated(details.clone())), - State::Yielded { val, .. } => Err(Error::InstanceYielded(val.clone())), + State::Yielded { val, .. } => Ok(RunResult::Yielded(val.clone())), State::Fault { .. } => { // Sandbox is no longer runnable. It's unsafe to determine all error details in the signal // handler, so we fill in extra details here. @@ -757,7 +845,10 @@ impl Instance { fn run_start(&mut self) -> Result<(), Error> { if let Some(start) = self.module.get_start_func()? { - self.run_func(start, &[])?; + let res = self.run_func(start, &[])?; + if res.is_yielded() { + return Err(Error::StartYielded); + } } Ok(()) } @@ -798,9 +889,9 @@ pub enum State { }, Yielded { val: YieldedVal, - /// Concretely, this should only ever be `Option>>` where `R` is the type + /// Concretely, this should only ever be `Box>` where `R` is the type /// the guest expects upon resumption. - expected: Option>, + expected: Box, }, } @@ -935,18 +1026,16 @@ impl std::fmt::Debug for TerminationDetails { unsafe impl Send for TerminationDetails {} unsafe impl Sync for TerminationDetails {} -/// The value yielded by the guest and returned to the host. -/// -/// **Note**: The `Sync` trait bound is only present because yielded values are (temporarily) -/// returned as a variant of `Error`. In the future, this bound may be dropped. +/// The value yielded by an instance through a [`Vmctx`](vmctx/struct.Vmctx.html) and returned to +/// the host. #[derive(Clone)] pub struct YieldedVal { - val: Option>, + val: Arc, } impl std::fmt::Debug for YieldedVal { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if self.val.is_none() { + if self.is_none() { write!(f, "YieldedVal {{ val: None }}") } else { write!(f, "YieldedVal {{ val: Some }}") @@ -955,46 +1044,43 @@ impl std::fmt::Debug for YieldedVal { } impl YieldedVal { - pub(crate) fn some(val: A) -> Self { - YieldedVal { - val: Some(Arc::new(val)), - } - } - - pub(crate) fn none() -> Self { - YieldedVal { val: None } + pub(crate) fn new(val: A) -> Self { + YieldedVal { val: Arc::new(val) } } /// Returns `true` if the guest yielded without a value. pub fn is_none(&self) -> bool { - self.val.is_none() + self.val.is::() } /// Returns `true` if the guest yielded with a value. pub fn is_some(&self) -> bool { - self.val.is_some() + !self.is_none() } /// Attempt to downcast the yielded value to a concrete type, returning the original /// `YieldedVal` if unsuccessful. pub fn downcast(self) -> Result, YieldedVal> { - if let Some(val) = self.val { - match val.downcast() { - Ok(val) => Ok(val), - Err(val) => Err(YieldedVal { val: Some(val) }), - } - } else { - Err(self) + match self.val.downcast() { + Ok(val) => Ok(val), + Err(val) => Err(YieldedVal { val }), } } /// Returns a reference to the yielded value if it is present and of type `A`, or `None` if it /// isn't. pub fn downcast_ref(&self) -> Option<&A> { - self.val.as_ref().and_then(|val| val.downcast_ref()) + self.val.downcast_ref() } } +/// A marker value to indicate a yield or resume with no value. +/// +/// This exists to unify the implementations of the various operators, and should only ever be +/// created by internal code. +#[derive(Debug)] +pub(crate) struct EmptyYieldVal; + impl std::fmt::Display for State { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs index 1f4c8917a..646935f79 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs @@ -1,10 +1,10 @@ use crate::context::Context; +use crate::error::Error; use crate::instance::{ siginfo_ext::SiginfoExt, FaultDetails, Instance, State, TerminationDetails, CURRENT_INSTANCE, HOST_CTX, }; use crate::sysdeps::UContextPtr; -use failure::Error; use lazy_static::lazy_static; use libc::{c_int, c_void, siginfo_t, SIGBUS, SIGSEGV}; use lucet_module::TrapCode; diff --git a/lucet-runtime/lucet-runtime-internals/src/module.rs b/lucet-runtime/lucet-runtime-internals/src/module.rs index 22ddd9f74..6cbf679e9 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module.rs @@ -30,7 +30,12 @@ pub struct AddrDetails { /// /// Types that implement this trait are suitable for use with /// [`Region::new_instance()`](trait.Region.html#method.new_instance). -pub trait Module: ModuleInternal {} +pub trait Module: ModuleInternal { + /// Calculate the initial size in bytes of the module's Wasm globals. + fn initial_globals_size(&self) -> usize { + self.globals().len() * std::mem::size_of::() + } +} pub trait ModuleInternal: Send + Sync { fn heap_spec(&self) -> Option<&HeapSpec>; diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index 139a43e16..0f2a2a822 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -9,7 +9,8 @@ use crate::alloc::instance_heap_offset; use crate::context::Context; use crate::error::Error; use crate::instance::{ - Instance, InstanceInternal, State, TerminationDetails, YieldedVal, CURRENT_INSTANCE, HOST_CTX, + EmptyYieldVal, Instance, InstanceInternal, State, TerminationDetails, YieldedVal, + CURRENT_INSTANCE, HOST_CTX, }; use lucet_module::{FunctionHandle, GlobalValue}; use std::any::Any; @@ -65,6 +66,22 @@ pub trait VmctxInternal { /// If there is no resumed value, or if the dynamic type check of the value fails, this returns /// `None`. fn try_take_resumed_val(&self) -> Option; + + /// Suspend the instance, returning a value in + /// [`RunResult::Yielded`](../enum.RunResult.html#variant.Yielded) to where the instance was run + /// or resumed. + /// + /// After suspending, the instance may be resumed by calling + /// [`Instance::resume_with_val()`](../struct.Instance.html#method.resume_with_val) from the + /// host with a value of type `R`. If resumed with a value of some other type, this returns + /// `None`. + /// + /// The dynamic type checks used by the other yield methods should make this explicit option + /// type redundant, however this interface is used to avoid exposing a panic to the C API. + fn yield_val_try_val( + &self, + val: A, + ) -> Option; } impl VmctxInternal for Vmctx { @@ -90,6 +107,14 @@ impl VmctxInternal for Vmctx { None } } + + fn yield_val_try_val( + &self, + val: A, + ) -> Option { + self.yield_impl::(val); + self.try_take_resumed_val() + } } impl Vmctx { @@ -291,8 +316,9 @@ impl Vmctx { .get_func_from_idx(table_idx, func_idx) } - /// Suspend the instance, returning an empty `Error::InstanceYielded` to where the instance was - /// run or resumed. + /// Suspend the instance, returning an empty + /// [`RunResult::Yielded`](../enum.RunResult.html#variant.Yielded) to where the instance was run + /// or resumed. /// /// After suspending, the instance may be resumed by the host using /// [`Instance::resume()`](../struct.Instance.html#method.resume). @@ -300,63 +326,53 @@ impl Vmctx { /// (The reason for the trailing underscore in the name is that Rust reserves `yield` as a /// keyword for future use.) pub fn yield_(&self) { - let inst = unsafe { self.instance_mut() }; - inst.state = State::Yielded { - val: YieldedVal::none(), - expected: None, - }; - HOST_CTX.with(|host_ctx| unsafe { Context::swap(&mut inst.ctx, &mut *host_ctx.get()) }); + self.yield_val_expecting_val::(EmptyYieldVal); } - /// Suspend the instance, returning an empty `Error::InstanceYielded` to where the instance was - /// run or resumed. + /// Suspend the instance, returning an empty + /// [`RunResult::Yielded`](../enum.RunResult.html#variant.Yielded) to where the instance was run + /// or resumed. /// - /// After suspending, the instance may be resumed by the host - /// [`Instance::resume_with_val()`](../struct.Instance.html#method.resume_with_val) with a value - /// of type `R`. + /// After suspending, the instance may be resumed by calling + /// [`Instance::resume_with_val()`](../struct.Instance.html#method.resume_with_val) from the + /// host with a value of type `R`. pub fn yield_expecting_val(&self) -> R { - let inst = unsafe { self.instance_mut() }; - let expected: Box> = Box::new(PhantomData); - inst.state = State::Yielded { - val: YieldedVal::none(), - expected: Some(expected as Box), - }; - HOST_CTX.with(|host_ctx| unsafe { Context::swap(&mut inst.ctx, &mut *host_ctx.get()) }); - self.take_resumed_val() + self.yield_val_expecting_val::(EmptyYieldVal) } - /// Suspend the instance, returning a value in `Error::InstanceYielded` to where the instance - /// was run or resumed. + /// Suspend the instance, returning a value in + /// [`RunResult::Yielded`](../enum.RunResult.html#variant.Yielded) to where the instance was run + /// or resumed. /// /// After suspending, the instance may be resumed by the host using /// [`Instance::resume()`](../struct.Instance.html#method.resume). pub fn yield_val(&self, val: A) { - let inst = unsafe { self.instance_mut() }; - inst.state = State::Yielded { - val: YieldedVal::some(val), - expected: None, - }; - HOST_CTX.with(|host_ctx| unsafe { Context::swap(&mut inst.ctx, &mut *host_ctx.get()) }); + self.yield_val_expecting_val::(val); } - /// Suspend the instance, returning a value in `Error::InstanceYielded` to where the instance - /// was run or resumed. + /// Suspend the instance, returning a value in + /// [`RunResult::Yielded`](../enum.RunResult.html#variant.Yielded) to where the instance was run + /// or resumed. /// - /// After suspending, the instance may be resumed by the host - /// [`Instance::resume_with_val()`](../struct.Instance.html#method.resume_with_val) with a value - /// of type `R`. + /// After suspending, the instance may be resumed by calling + /// [`Instance::resume_with_val()`](../struct.Instance.html#method.resume_with_val) from the + /// host with a value of type `R`. pub fn yield_val_expecting_val( &self, val: A, ) -> R { + self.yield_impl::(val); + self.take_resumed_val() + } + + fn yield_impl(&self, val: A) { let inst = unsafe { self.instance_mut() }; let expected: Box> = Box::new(PhantomData); inst.state = State::Yielded { - val: YieldedVal::some(val), - expected: Some(expected as Box), + val: YieldedVal::new(val), + expected: expected as Box, }; HOST_CTX.with(|host_ctx| unsafe { Context::swap(&mut inst.ctx, &mut *host_ctx.get()) }); - self.take_resumed_val() } /// Take and return the value passed to diff --git a/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs b/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs index e53e0d76b..db1bb3048 100644 --- a/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs +++ b/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs @@ -226,7 +226,8 @@ macro_rules! entrypoint_tests { let retval = inst .run("add_2", &[123u64.into(), 456u64.into()]) - .expect("instance runs"); + .expect("instance runs") + .unwrap_returned(); assert_eq!(u64::from(retval), 123u64 + 456); } @@ -269,7 +270,8 @@ macro_rules! entrypoint_tests { 10u64.into(), ], ) - .expect("instance runs"); + .expect("instance runs") + .unwrap_returned(); assert_eq!(u64::from(retval), 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10); } @@ -292,7 +294,8 @@ macro_rules! entrypoint_tests { let retval = inst .run("mul_2", &[123u64.into(), 456u64.into()]) - .expect("instance runs"); + .expect("instance runs") + .unwrap_returned(); assert_eq!(u64::from(retval), 123 * 456); } @@ -310,13 +313,15 @@ macro_rules! entrypoint_tests { let retval = inst .run("add_2", &[111u64.into(), 222u64.into()]) - .expect("instance runs"); + .expect("instance runs") + .unwrap_returned(); assert_eq!(u64::from(retval), 111 + 222); let retval = inst .run("mul_2", &[333u64.into(), 444u64.into()]) - .expect("instance runs"); + .expect("instance runs") + .unwrap_returned(); assert_eq!(u64::from(retval), 333 * 444); } @@ -360,7 +365,8 @@ macro_rules! entrypoint_tests { let retval = inst .run("add_f32_2", &[(-6.9f32).into(), 4.2f32.into()]) - .expect("instance runs"); + .expect("instance runs") + .unwrap_returned(); assert_eq!(f32::from(retval), -6.9 + 4.2); } @@ -381,7 +387,8 @@ macro_rules! entrypoint_tests { let retval = inst .run("add_f64_2", &[(-6.9f64).into(), 4.2f64.into()]) - .expect("instance runs"); + .expect("instance runs") + .unwrap_returned(); assert_eq!(f64::from(retval), -6.9 + 4.2); } @@ -416,7 +423,8 @@ macro_rules! entrypoint_tests { 1.0f32.into(), ], ) - .expect("instance runs"); + .expect("instance runs") + .unwrap_returned(); assert_eq!( f32::from(retval), @@ -454,7 +462,8 @@ macro_rules! entrypoint_tests { 1.0f64.into(), ], ) - .expect("instance runs"); + .expect("instance runs") + .unwrap_returned(); assert_eq!( f64::from(retval), @@ -499,7 +508,8 @@ macro_rules! entrypoint_tests { 19u64.into(), ], ) - .expect("instance runs"); + .expect("instance runs") + .unwrap_returned(); assert_eq!( f64::from(retval), @@ -616,13 +626,14 @@ macro_rules! entrypoint_tests { .new_instance(module) .expect("instance can be created"); - match inst.run( - "add_4_reexport", - &[123u64.into(), 456u64.into(), 789u64.into(), 432u64.into()], - ) { - Ok(res) => assert_eq!(u64::from(res), 1800), - res => panic!("unexpected result: {:?}", res), - } + let retval = inst + .run( + "add_4_reexport", + &[123u64.into(), 456u64.into(), 789u64.into(), 432u64.into()], + ) + .unwrap() + .unwrap_returned(); + assert_eq!(u64::from(retval), 1800); } use $crate::build::test_module_c; @@ -918,7 +929,8 @@ macro_rules! entrypoint_tests { let retval = inst .run("callback_entrypoint", &[0u64.into()]) - .expect("instance runs"); + .expect("instance runs") + .unwrap_returned(); assert_eq!(u64::from(retval), 3); } }; diff --git a/lucet-runtime/lucet-runtime-tests/src/globals.rs b/lucet-runtime/lucet-runtime-tests/src/globals.rs index f32a40d50..4add0d788 100644 --- a/lucet-runtime/lucet-runtime-tests/src/globals.rs +++ b/lucet-runtime/lucet-runtime-tests/src/globals.rs @@ -1,13 +1,13 @@ #[macro_export] macro_rules! globals_tests { ( $TestRegion:path ) => { + use $crate::build::test_module_wasm; + use $crate::helpers::{MockExportBuilder, MockModuleBuilder}; use lucet_module::{lucet_signature, FunctionPointer, GlobalValue}; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime::{Error, Limits, Module, Region}; use std::sync::Arc; use $TestRegion as TestRegion; - use $crate::build::test_module_wasm; - use $crate::helpers::{MockExportBuilder, MockModuleBuilder}; #[test] fn defined_globals() { @@ -84,16 +84,25 @@ macro_rules! globals_tests { .with_global(0, -1) .with_global(1, 420) .with_export_func( - MockExportBuilder::new("get_global0", FunctionPointer::from_usize(get_global0 as usize)) - .with_sig(lucet_signature!(() -> I64)) + MockExportBuilder::new( + "get_global0", + FunctionPointer::from_usize(get_global0 as usize), + ) + .with_sig(lucet_signature!(() -> I64)), ) .with_export_func( - MockExportBuilder::new("set_global0", FunctionPointer::from_usize(set_global0 as usize)) - .with_sig(lucet_signature!((I64) -> ())) + MockExportBuilder::new( + "set_global0", + FunctionPointer::from_usize(set_global0 as usize), + ) + .with_sig(lucet_signature!((I64) -> ())), ) .with_export_func( - MockExportBuilder::new("get_global1", FunctionPointer::from_usize(get_global1 as usize)) - .with_sig(lucet_signature!(() -> I64)) + MockExportBuilder::new( + "get_global1", + FunctionPointer::from_usize(get_global1 as usize), + ) + .with_sig(lucet_signature!(() -> I64)), ) .build() } @@ -121,7 +130,10 @@ macro_rules! globals_tests { .new_instance(module) .expect("instance can be created"); - let retval = inst.run("get_global0", &[]).expect("instance runs"); + let retval = inst + .run("get_global0", &[]) + .expect("instance runs") + .unwrap_returned(); assert_eq!(i64::from(retval), -1); } @@ -133,10 +145,16 @@ macro_rules! globals_tests { .new_instance(module) .expect("instance can be created"); - let retval = inst.run("get_global0", &[]).expect("instance runs"); + let retval = inst + .run("get_global0", &[]) + .expect("instance runs") + .unwrap_returned(); assert_eq!(i64::from(retval), -1); - let retval = inst.run("get_global1", &[]).expect("instance runs"); + let retval = inst + .run("get_global1", &[]) + .expect("instance runs") + .unwrap_returned(); assert_eq!(i64::from(retval), 420); } @@ -151,7 +169,10 @@ macro_rules! globals_tests { inst.run("set_global0", &[666i64.into()]) .expect("instance runs"); - let retval = inst.run("get_global0", &[]).expect("instance runs"); + let retval = inst + .run("get_global0", &[]) + .expect("instance runs") + .unwrap_returned(); assert_eq!(i64::from(retval), 666); } }; diff --git a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs index ebd16aa99..ff898eff6 100644 --- a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs +++ b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs @@ -195,7 +195,10 @@ macro_rules! guest_fault_tests { } fn run_onetwothree(inst: &mut Instance) { - let retval = inst.run("onetwothree", &[]).expect("instance runs"); + let retval = inst + .run("onetwothree", &[]) + .expect("instance runs") + .unwrap_returned(); assert_eq!(libc::c_int::from(retval), 123); } diff --git a/lucet-runtime/lucet-runtime-tests/src/host.rs b/lucet-runtime/lucet-runtime-tests/src/host.rs index 656507b71..f71de1cf3 100644 --- a/lucet-runtime/lucet-runtime-tests/src/host.rs +++ b/lucet-runtime/lucet-runtime-tests/src/host.rs @@ -355,7 +355,10 @@ macro_rules! host_tests { .new_instance(module) .expect("instance can be created"); - let retval = inst.run("f", &[]).expect("instance runs"); + let retval = inst + .run("f", &[]) + .expect("instance runs") + .expect_returned("instance returned"); assert_eq!(bool::from(retval), true); } @@ -381,11 +384,15 @@ macro_rules! host_tests { .new_instance(module) .expect("instance can be created"); - if let Err(Error::InstanceYielded(val)) = inst.run("f", &[]) { - assert_eq!(*val.downcast::().unwrap(), 5u64); - } else { - panic!("instance didn't yield"); - } + assert_eq!( + *inst + .run("f", &[]) + .unwrap() + .unwrap_yielded() + .downcast::() + .unwrap(), + 5u64 + ); } #[test] @@ -410,13 +417,12 @@ macro_rules! host_tests { .new_instance(module) .expect("instance can be created"); - if let Err(Error::InstanceYielded(val)) = inst.run("f", &[]) { - assert!(val.is_none()); - } else { - panic!("instance didn't yield"); - } + assert!(inst.run("f", &[]).unwrap().unwrap_yielded().is_none()); - let retval = inst.resume_with_val(5u64).expect("instance resumes"); + let retval = inst + .resume_with_val(5u64) + .expect("instance resumes") + .unwrap_returned(); assert_eq!(u64::from(retval), 5u64); } @@ -444,15 +450,15 @@ macro_rules! host_tests { let mut facts = vec![]; - let mut res = inst.run("f", &[]); + let mut res = inst.run("f", &[]).unwrap(); - while let Err(Error::InstanceYielded(val)) = res { - facts.push(*val.downcast::().unwrap()); - res = inst.resume(); + while res.is_yielded() { + facts.push(*res.unwrap_yielded().downcast::().unwrap()); + res = inst.resume().unwrap(); } assert_eq!(facts.as_slice(), &[1, 2, 6, 24, 120]); - assert_eq!(u64::from(res.unwrap()), 120u64); + assert_eq!(u64::from(res.unwrap_returned()), 120u64); } #[test] @@ -479,19 +485,19 @@ macro_rules! host_tests { let mut facts = vec![]; - let mut res = inst.run("f", &[]); + let mut res = inst.run("f", &[]).unwrap(); - while let Err(Error::InstanceYielded(val)) = res { + while let Ok(val) = res.yielded_ref() { if let Some(k) = val.downcast_ref::() { match k { CoopFactsK::Mult(n, n_rec) => { // guest wants us to multiply for it - res = inst.resume_with_val(n * n_rec); + res = inst.resume_with_val(n * n_rec).unwrap(); } CoopFactsK::Result(n) => { // guest is returning an answer facts.push(*n); - res = inst.resume(); + res = inst.resume().unwrap(); } } } else { @@ -500,7 +506,7 @@ macro_rules! host_tests { } assert_eq!(facts.as_slice(), &[1, 2, 6, 24, 120]); - assert_eq!(u64::from(res.unwrap()), 120u64); + assert_eq!(u64::from(res.unwrap_returned()), 120u64); } #[test] @@ -525,11 +531,15 @@ macro_rules! host_tests { .new_instance(module) .expect("instance can be created"); - if let Err(Error::InstanceYielded(val)) = inst.run("f", &[]) { - assert_eq!(*val.downcast::().unwrap(), 5u64); - } else { - panic!("instance didn't yield"); - } + assert_eq!( + *inst + .run("f", &[]) + .unwrap() + .unwrap_yielded() + .downcast::() + .unwrap(), + 5u64 + ); match inst.resume_with_val(5u64) { Err(Error::InvalidArgument(_)) => (), @@ -560,11 +570,7 @@ macro_rules! host_tests { .new_instance(module) .expect("instance can be created"); - if let Err(Error::InstanceYielded(val)) = inst.run("f", &[]) { - assert!(val.is_none()); - } else { - panic!("instance didn't yield"); - } + assert!(inst.run("f", &[]).unwrap().unwrap_yielded().is_none()); match inst.resume() { Err(Error::InvalidArgument(_)) => (), @@ -595,11 +601,7 @@ macro_rules! host_tests { .new_instance(module) .expect("instance can be created"); - if let Err(Error::InstanceYielded(val)) = inst.run("f", &[]) { - assert!(val.is_none()); - } else { - panic!("instance didn't yield"); - } + assert!(inst.run("f", &[]).unwrap().unwrap_yielded().is_none()); match inst.resume_with_val(true) { Err(Error::InvalidArgument(_)) => (), diff --git a/lucet-runtime/lucet-runtime-tests/src/memory.rs b/lucet-runtime/lucet-runtime-tests/src/memory.rs index b24cab9cb..bf2a964f6 100644 --- a/lucet-runtime/lucet-runtime-tests/src/memory.rs +++ b/lucet-runtime/lucet-runtime-tests/src/memory.rs @@ -16,7 +16,10 @@ macro_rules! memory_tests { .new_instance(module) .expect("instance can be created"); - let retval = inst.run("main", &[]).expect("instance runs"); + let retval = inst + .run("main", &[]) + .expect("instance runs") + .unwrap_returned(); assert_eq!(u32::from(retval), 4); } diff --git a/lucet-runtime/lucet-runtime-tests/src/stack.rs b/lucet-runtime/lucet-runtime-tests/src/stack.rs index 76ec20df5..bc794f289 100644 --- a/lucet-runtime/lucet-runtime-tests/src/stack.rs +++ b/lucet-runtime/lucet-runtime-tests/src/stack.rs @@ -90,6 +90,7 @@ macro_rules! stack_tests { .expect("instance can be created"); inst.run("localpalooza", &[recursion_depth.into()]) + .and_then(|rr| rr.returned()) } fn expect_ok(module: Arc, recursion_depth: i32) { diff --git a/lucet-runtime/lucet-runtime-tests/src/strcmp.rs b/lucet-runtime/lucet-runtime-tests/src/strcmp.rs index 28f0cc7a3..9dc4032cb 100644 --- a/lucet-runtime/lucet-runtime-tests/src/strcmp.rs +++ b/lucet-runtime/lucet-runtime-tests/src/strcmp.rs @@ -48,7 +48,8 @@ macro_rules! strcmp_tests { "run_strcmp", &[Val::GuestPtr(s1_ptr as u32), Val::GuestPtr(s2_ptr as u32)], ) - .expect("instance runs"), + .expect("instance runs") + .unwrap_returned(), ); let host_strcmp_res = diff --git a/lucet-runtime/src/c_api.rs b/lucet-runtime/src/c_api.rs index 006d7e6e5..35de8359f 100644 --- a/lucet-runtime/src/c_api.rs +++ b/lucet-runtime/src/c_api.rs @@ -45,8 +45,10 @@ pub extern "C" fn lucet_error_name(e: c_int) -> *const c_char { FuncNotFound => "lucet_error_func_not_found\0".as_ptr() as _, RuntimeFault => "lucet_error_runtime_fault\0".as_ptr() as _, RuntimeTerminated => "lucet_error_runtime_terminated\0".as_ptr() as _, - InstanceYielded => "lucet_error_instance_yielded\0".as_ptr() as _, Dl => "lucet_error_dl\0".as_ptr() as _, + InstanceNotReturned => "lucet_error_instance_not_returned\0".as_ptr() as _, + InstanceNotYielded => "lucet_error_instance_not_yielded\0".as_ptr() as _, + StartYielded => "lucet_error_start_yielded\0".as_ptr() as _, Internal => "lucet_error_internal\0".as_ptr() as _, Unsupported => "lucet_error_unsupported\0".as_ptr() as _, } @@ -216,18 +218,9 @@ pub unsafe extern "C" fn lucet_instance_resume( val: *mut c_void, ) -> lucet_error { with_instance_ptr!(inst, { - // resume without typechecking, since the C version of `yield` translates type errors into - // null/non-null return values - if val.is_null() { - let none: Option<()> = None; - inst.resume_impl(none, false) - .map(|_| lucet_error::Ok) - .unwrap_or_else(|e| e.into()) - } else { - inst.resume_impl(Some(CYieldedVal { val }), false) - .map(|_| lucet_error::Ok) - .unwrap_or_else(|e| e.into()) - } + inst.resume_with_val(CYieldedVal { val }) + .map(|_| lucet_error::Ok) + .unwrap_or_else(|e| e.into()) }) } @@ -474,19 +467,10 @@ lucet_hostcalls! { &mut vmctx, val: *mut c_void, ) -> *mut c_void { - // only yield a value if val is non-NULL - if val.is_null() { - vmctx.yield_(); - } else { - vmctx.yield_val(CYieldedVal { val }); - } - - // return any `CYieldedVal` pointer that comes back, otherwise NULL - if let Some(CYieldedVal { val }) = vmctx.try_take_resumed_val() { - val - } else { - std::ptr::null_mut() - } + vmctx + .yield_val_try_val(CYieldedVal { val }) + .map(|CYieldedVal { val }| val) + .unwrap_or(std::ptr::null_mut()) } } diff --git a/lucet-runtime/src/lib.rs b/lucet-runtime/src/lib.rs index 0088a2b33..fd5511773 100644 --- a/lucet-runtime/src/lib.rs +++ b/lucet-runtime/src/lib.rs @@ -37,10 +37,18 @@ //! arguments. These can be created using `From` implementations of primitive types, for example //! `5u64.into()` in the example below. //! +//! - [`RunResult`](enum.RunResult.html): the result of running or resuming an instance. These +//! contain either `UntypedRetVal`s for WebAssembly functions that have returned, or `YieldedVal`s +//! for WebAssembly programs that have yielded. +//! //! - [`UntypedRetVal`](struct.UntypedRetVal.html): values returned from WebAssembly //! functions. These must be interpreted at the correct type by the user via `From` implementations //! or `retval.as_T()` methods, for example `u64::from(retval)` in the example below. //! +//! - [`YieldedVal`](struct.YieldedVal.html): dynamically-values yielded by WebAssembly +//! programs. Not all yield points are given values, so this may be empty. To use the values, if +//! present, you must first downcast them with the provided methods. +//! //! To run a Lucet program, you start by creating a region, capable of backing a number of //! instances. You then load a module and then create a new instance using the region and the //! module. You can then run any of the functions that the Lucet program exports, retrieve return @@ -53,7 +61,7 @@ //! let region = MmapRegion::create(1, &Limits::default()).unwrap(); //! let mut inst = region.new_instance(module).unwrap(); //! -//! let retval = inst.run("factorial", &[5u64.into()]).unwrap(); +//! let retval = inst.run("factorial", &[5u64.into()]).unwrap().unwrap_returned(); //! assert_eq!(u64::from(retval), 120u64); //! ``` //! @@ -239,19 +247,19 @@ //! //! let mut factorials = vec![]; //! -//! let mut res = inst.run("run", &[]); +//! let mut res = inst.run("run", &[]).unwrap(); //! -//! while let Err(Error::InstanceYielded(val)) = res { +//! while let Ok(val) = res.yielded_ref() { //! if let Some(k) = val.downcast_ref::() { //! match k { //! FactorialsK::Mult(n, n_rec) => { //! // guest wants us to multiply for it -//! res = inst.resume_with_val(n * n_rec); +//! res = inst.resume_with_val(n * n_rec).unwrap(); //! } //! FactorialsK::Result(n) => { //! // guest is returning an answer //! factorials.push(*n); -//! res = inst.resume(); +//! res = inst.resume().unwrap(); //! } //! } //! } else { @@ -262,7 +270,7 @@ //! // intermediate values are correct //! assert_eq!(factorials.as_slice(), &[1, 2, 6, 24, 120]); //! // final value is correct -//! assert_eq!(u64::from(res.unwrap()), 120u64); +//! assert_eq!(u64::from(res.unwrap_returned()), 120u64); //! ``` //! //! ## Custom Signal Handlers @@ -338,7 +346,8 @@ pub use lucet_module::{PublicKey, TrapCode}; pub use lucet_runtime_internals::alloc::Limits; pub use lucet_runtime_internals::error::Error; pub use lucet_runtime_internals::instance::{ - FaultDetails, Instance, InstanceHandle, SignalBehavior, TerminationDetails, YieldedVal, + FaultDetails, Instance, InstanceHandle, RunResult, SignalBehavior, TerminationDetails, + YieldedVal, }; pub use lucet_runtime_internals::module::{DlModule, Module}; pub use lucet_runtime_internals::region::mmap::MmapRegion; diff --git a/lucet-runtime/tests/c_api.c b/lucet-runtime/tests/c_api.c index e6c0ed43d..69eaa3812 100644 --- a/lucet-runtime/tests/c_api.c +++ b/lucet-runtime/tests/c_api.c @@ -118,12 +118,7 @@ bool lucet_runtime_test_yield_resume(struct lucet_dl_module *mod) size_t i = 0; err = lucet_instance_run(inst, "f", 0, (const struct lucet_val[]){}); - while (err == lucet_error_instance_yielded) { - if (i >= 5) { - fprintf(stderr, "hostcall yielded too many results\n"); - goto fail3; - } - + while (err == lucet_error_ok) { struct lucet_state st; err = lucet_instance_state(inst, &st); if (err != lucet_error_ok) { @@ -131,9 +126,14 @@ bool lucet_runtime_test_yield_resume(struct lucet_dl_module *mod) goto fail3; } if (st.tag != lucet_state_tag_yielded) { - fprintf(stderr, "instance state wasn't yielded\n"); + break; + } + + if (i >= 5) { + fprintf(stderr, "hostcall yielded too many results\n"); goto fail3; } + struct yield_resume_val val = *(struct yield_resume_val *) st.val.yielded.val; switch (val.tag) { diff --git a/lucet-spectest/src/script.rs b/lucet-spectest/src/script.rs index b6e5f58ae..0004e0318 100644 --- a/lucet-spectest/src/script.rs +++ b/lucet-spectest/src/script.rs @@ -160,6 +160,7 @@ impl ScriptEnv { ) -> Result { let (_, ref mut inst) = self.instance_named_mut(name)?; inst.run(field, &args) + .and_then(|rr| rr.returned()) .map_err(|e| ScriptError::RuntimeError(e)) } diff --git a/lucet-wasi/src/main.rs b/lucet-wasi/src/main.rs index c6e01b579..7919e3662 100644 --- a/lucet-wasi/src/main.rs +++ b/lucet-wasi/src/main.rs @@ -5,8 +5,7 @@ extern crate clap; use clap::Arg; use failure::{format_err, Error}; -use lucet_runtime::{self, DlModule, Limits, MmapRegion, Module, PublicKey, Region}; -use lucet_runtime_internals::module::ModuleInternal; +use lucet_runtime::{self, DlModule, Limits, MmapRegion, Module, PublicKey, Region, RunResult}; use lucet_wasi::{hostcalls, WasiCtxBuilder}; use std::fs::File; use std::path::PathBuf; @@ -209,7 +208,7 @@ fn run(config: Config<'_>) { } else { DlModule::load(&config.lucet_module).expect("module can be loaded") }; - let min_globals_size = module.globals().len() * std::mem::size_of::(); + let min_globals_size = module.initial_globals_size(); let globals_size = ((min_globals_size + 4096 - 1) / 4096) * 4096; let region = MmapRegion::create( @@ -240,7 +239,9 @@ fn run(config: Config<'_>) { match inst.run(config.entrypoint, &[]) { // normal termination implies 0 exit code - Ok(_) => 0, + Ok(RunResult::Returned(_)) => 0, + // none of the WASI hostcalls use yield yet, so this shouldn't happen + Ok(RunResult::Yielded(_)) => panic!("lucet-wasi unexpectedly yielded"), Err(lucet_runtime::Error::RuntimeTerminated( lucet_runtime::TerminationDetails::Provided(any), )) => *any From b21e25a68458a914dbff237e3e15fee82ad81f47 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 30 Jul 2019 15:05:54 -0700 Subject: [PATCH 279/512] [lucet-runtime] fix up C error enum --- lucet-runtime/include/lucet_types.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lucet-runtime/include/lucet_types.h b/lucet-runtime/include/lucet_types.h index 16df2be2d..a04af69de 100644 --- a/lucet-runtime/include/lucet_types.h +++ b/lucet-runtime/include/lucet_types.h @@ -28,6 +28,8 @@ enum lucet_error { lucet_error_runtime_fault, lucet_error_runtime_terminated, lucet_error_dl, + lucet_error_instance_not_returned, + lucet_error_instance_not_yielded, lucet_error_start_yielded, lucet_error_internal, lucet_error_unsupported, From 6199d6cedbde510bd0b164f427906adf4fe64717 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Wed, 31 Jul 2019 13:35:19 -0700 Subject: [PATCH 280/512] [lucet-runtime] refactor `State` and associated C APIs These changes reduce the number of times that our types must be `Clone`able simply in order to keep a copy around in the `State` while also returning a result. This had cascading implications, like having to store termination and yield values in `Arc`s, which are all now gone. The only restrictions on these values now is `Any + 'static`, which actually reflecs the semantics we care about. The downside to this is there are now more complicated invariants about states, but those are now noted in docs on the struct. Accommodating these changes in the C API meant ripping out the explicit `lucet_instance_state()` function and replacing it with an out-parameter on run/resume. `lucet_state` is now `lucet_result`, and is more analogous to `Result`. Along the way, the pointers to strings for file and symbol names were replaced with fixed-length buffers so that we don't need a free function for `lucet_result`. This all makes the C API nicer, in addition to supporting the `State` refactoring. --- lucet-runtime/include/lucet.h | 16 +- lucet-runtime/include/lucet_types.h | 48 ++--- .../lucet-runtime-internals/src/c_api.rs | 190 +++++++++--------- .../src/hostcall_macros.rs | 11 +- .../lucet-runtime-internals/src/instance.rs | 117 ++++++----- .../src/instance/signals.rs | 2 +- .../lucet-runtime-internals/src/vmctx.rs | 33 ++- lucet-runtime/src/c_api.rs | 80 ++++---- lucet-runtime/tests/c_api.c | 34 +--- 9 files changed, 253 insertions(+), 278 deletions(-) diff --git a/lucet-runtime/include/lucet.h b/lucet-runtime/include/lucet.h index f6372e3c1..b360784ce 100644 --- a/lucet-runtime/include/lucet.h +++ b/lucet-runtime/include/lucet.h @@ -38,15 +38,18 @@ enum lucet_error lucet_instance_reset(struct lucet_instance *inst); enum lucet_error lucet_instance_run(struct lucet_instance * inst, const char * entrypoint, uintptr_t argc, - const struct lucet_val *argv); + const struct lucet_val *argv, + struct lucet_result * result_out); enum lucet_error lucet_instance_run_func_idx(struct lucet_instance * inst, uint32_t table_idx, uint32_t func_idx, uintptr_t argc, - const struct lucet_val *argv); + const struct lucet_val *argv, + struct lucet_result * result_out); -enum lucet_error lucet_instance_resume(struct lucet_instance *inst, void *val); +enum lucet_error +lucet_instance_resume(struct lucet_instance *inst, void *val, struct lucet_result *result_out); enum lucet_error lucet_instance_set_fatal_handler(struct lucet_instance *inst, lucet_fatal_handler fatal_handler); @@ -57,9 +60,6 @@ enum lucet_error lucet_instance_set_fatal_handler(struct lucet_instance *inst, enum lucet_error lucet_instance_set_signal_handler(struct lucet_instance *inst, lucet_signal_handler signal_handler); -enum lucet_error lucet_instance_state(const struct lucet_instance *inst, - struct lucet_state * state_out); - enum lucet_error lucet_mmap_region_create(uint64_t instance_capacity, const struct lucet_alloc_limits *limits, struct lucet_region ** region_out); @@ -81,8 +81,6 @@ double lucet_retval_f64(const struct lucet_untyped_retval *retval); union lucet_retval_gp lucet_retval_gp(const struct lucet_untyped_retval *retval); -void lucet_state_release(struct lucet_state *state); - -const char *lucet_state_tag_name(enum lucet_state_tag tag); +const char *lucet_result_tag_name(enum lucet_result_tag tag); #endif /* LUCET_H */ diff --git a/lucet-runtime/include/lucet_types.h b/lucet-runtime/include/lucet_types.h index a04af69de..820f943ce 100644 --- a/lucet-runtime/include/lucet_types.h +++ b/lucet-runtime/include/lucet_types.h @@ -41,14 +41,6 @@ enum lucet_signal_behavior { lucet_signal_behavior_terminate, }; -enum lucet_state_tag { - lucet_state_tag_returned, - lucet_state_tag_running, - lucet_state_tag_fault, - lucet_state_tag_terminated, - lucet_state_tag_yielded, -}; - enum lucet_terminated_reason { lucet_terminated_reason_signal, lucet_terminated_reason_ctx_not_found, @@ -144,20 +136,20 @@ struct lucet_untyped_retval { char gp[8]; }; +#define LUCET_MODULE_ADDR_DETAILS_NAME_LEN 256 + struct lucet_module_addr_details { - bool module_code_resolvable; - bool in_module_code; - const char *file_name; - const char *sym_name; + bool module_code_resolvable; + bool in_module_code; + char file_name[LUCET_MODULE_ADDR_DETAILS_NAME_LEN]; + char sym_name[LUCET_MODULE_ADDR_DETAILS_NAME_LEN]; }; -struct lucet_runtime_fault { +struct lucet_runtime_faulted { bool fatal; enum lucet_trapcode trapcode; uintptr_t rip_addr; struct lucet_module_addr_details rip_addr_details; - siginfo_t signal_info; - ucontext_t context; }; struct lucet_terminated { @@ -169,17 +161,25 @@ struct lucet_yielded { void *val; }; -union lucet_state_val { - struct lucet_untyped_retval returned; - bool running; - struct lucet_runtime_fault fault; - struct lucet_terminated terminated; - struct lucet_yielded yielded; +union lucet_result_val { + struct lucet_untyped_retval returned; + struct lucet_yielded yielded; + struct lucet_runtime_faulted faulted; + struct lucet_terminated terminated; + enum lucet_error errored; +}; + +enum lucet_result_tag { + lucet_result_tag_returned, + lucet_result_tag_yielded, + lucet_result_tag_faulted, + lucet_result_tag_terminated, + lucet_result_tag_errored, }; -struct lucet_state { - enum lucet_state_tag tag; - union lucet_state_val val; +struct lucet_result { + enum lucet_result_tag tag; + union lucet_result_val val; }; union lucet_retval_gp { diff --git a/lucet-runtime/lucet-runtime-internals/src/c_api.rs b/lucet-runtime/lucet-runtime-internals/src/c_api.rs index ce55a3b1a..02aa0a156 100644 --- a/lucet-runtime/lucet-runtime-internals/src/c_api.rs +++ b/lucet-runtime/lucet-runtime-internals/src/c_api.rs @@ -1,6 +1,6 @@ #![allow(non_camel_case_types)] -pub use self::lucet_state::*; +pub use self::lucet_result::*; pub use self::lucet_val::*; use crate::alloc::Limits; @@ -85,6 +85,12 @@ pub enum lucet_error { impl From for lucet_error { fn from(e: Error) -> lucet_error { + lucet_error::from(&e) + } +} + +impl From<&Error> for lucet_error { + fn from(e: &Error) -> lucet_error { match e { Error::InvalidArgument(_) => lucet_error::InvalidArgument, Error::RegionFull(_) => lucet_error::RegionFull, @@ -196,7 +202,7 @@ impl From<&lucet_signal_behavior> for SignalBehavior { pub type lucet_signal_handler = unsafe extern "C" fn( inst: *mut lucet_instance, - trap: lucet_state::lucet_trapcode, + trap: lucet_result::lucet_trapcode, signum: c_int, siginfo: *const libc::siginfo_t, context: *const c_void, @@ -218,86 +224,83 @@ pub struct CYieldedVal { unsafe impl Send for CYieldedVal {} unsafe impl Sync for CYieldedVal {} -pub mod lucet_state { +pub mod lucet_result { + use super::lucet_error; use crate::c_api::{lucet_val, CTerminationDetails, CYieldedVal}; - use crate::instance::{State, TerminationDetails}; + use crate::error::Error; + use crate::instance::{RunResult, TerminationDetails}; use crate::module::{AddrDetails, TrapCode}; - use crate::sysdeps::UContext; - use libc::{c_char, c_void}; + use libc::{c_uchar, c_void}; use num_derive::FromPrimitive; use std::ffi::CString; use std::ptr; - impl From<&State> for lucet_state { - fn from(state: &State) -> lucet_state { - match state { - State::Ready { retval } => lucet_state { - tag: lucet_state_tag::Returned, - val: lucet_state_val { + impl From> for lucet_result { + fn from(res: Result) -> lucet_result { + match res { + Ok(RunResult::Returned(retval)) => lucet_result { + tag: lucet_result_tag::Returned, + val: lucet_result_val { returned: retval.into(), }, }, - State::Running => lucet_state { - tag: lucet_state_tag::Running, - val: lucet_state_val { running: true }, + Ok(RunResult::Yielded(val)) => lucet_result { + tag: lucet_result_tag::Yielded, + val: lucet_result_val { + yielded: lucet_yielded { + val: val + .downcast_ref() + .map(|CYieldedVal { val }| *val) + .unwrap_or(ptr::null_mut()), + }, + }, }, - State::Fault { - details, - siginfo, - context, - } => lucet_state { - tag: lucet_state_tag::Fault, - val: lucet_state_val { - fault: lucet_runtime_fault { + // TODO: test this path; currently our C API tests don't include any faulting tests + Err(Error::RuntimeFault(details)) => lucet_result { + tag: lucet_result_tag::Faulted, + val: lucet_result_val { + fault: lucet_runtime_faulted { fatal: details.fatal, trapcode: details.trapcode.into(), rip_addr: details.rip_addr, - rip_addr_details: (&details.rip_addr_details).into(), - signal_info: *siginfo, - context: *context, + rip_addr_details: details.rip_addr_details.into(), }, }, }, - State::Terminated { details } => lucet_state { - tag: lucet_state_tag::Terminated, - val: lucet_state_val { + // TODO: test this path; currently our C API tests don't include any terminating tests + Err(Error::RuntimeTerminated(details)) => lucet_result { + tag: lucet_result_tag::Terminated, + val: lucet_result_val { terminated: match details { TerminationDetails::Signal => lucet_terminated { reason: lucet_terminated_reason::Signal, - provided: std::ptr::null_mut(), + provided: ptr::null_mut(), }, TerminationDetails::CtxNotFound => lucet_terminated { reason: lucet_terminated_reason::CtxNotFound, - provided: std::ptr::null_mut(), + provided: ptr::null_mut(), }, TerminationDetails::YieldTypeMismatch => lucet_terminated { reason: lucet_terminated_reason::YieldTypeMismatch, - provided: std::ptr::null_mut(), + provided: ptr::null_mut(), }, TerminationDetails::BorrowError(_) => lucet_terminated { reason: lucet_terminated_reason::BorrowError, - provided: std::ptr::null_mut(), + provided: ptr::null_mut(), }, TerminationDetails::Provided(p) => lucet_terminated { reason: lucet_terminated_reason::Provided, provided: p .downcast_ref() .map(|CTerminationDetails { details }| *details) - .unwrap_or(std::ptr::null_mut()), + .unwrap_or(ptr::null_mut()), }, }, }, }, - State::Yielded { val, .. } => lucet_state { - tag: lucet_state_tag::Yielded, - val: lucet_state_val { - yielded: lucet_yielded { - val: val - .downcast_ref() - .map(|CYieldedVal { val }| *val) - .unwrap_or(std::ptr::null_mut()), - }, - }, + Err(e) => lucet_result { + tag: lucet_result_tag::Errored, + val: lucet_result_val { errored: e.into() }, }, } } @@ -305,30 +308,29 @@ pub mod lucet_state { #[repr(C)] #[derive(Clone, Copy)] - pub struct lucet_state { - pub tag: lucet_state_tag, - pub val: lucet_state_val, + pub struct lucet_result { + pub tag: lucet_result_tag, + pub val: lucet_result_val, } #[repr(C)] #[derive(Clone, Copy, Debug, FromPrimitive)] - pub enum lucet_state_tag { + pub enum lucet_result_tag { Returned, - Running, - Fault, - Terminated, Yielded, + Faulted, + Terminated, + Errored, } #[repr(C)] #[derive(Clone, Copy)] - pub union lucet_state_val { + pub union lucet_result_val { pub returned: lucet_val::lucet_untyped_retval, - // no meaning to this boolean, it's just there so the type is FFI-safe - pub running: bool, - pub fault: lucet_runtime_fault, - pub terminated: lucet_terminated, pub yielded: lucet_yielded, + pub fault: lucet_runtime_faulted, + pub terminated: lucet_terminated, + pub errored: lucet_error, } #[repr(C)] @@ -356,13 +358,11 @@ pub mod lucet_state { #[repr(C)] #[derive(Clone, Copy)] - pub struct lucet_runtime_fault { + pub struct lucet_runtime_faulted { pub fatal: bool, pub trapcode: lucet_trapcode, pub rip_addr: libc::uintptr_t, pub rip_addr_details: lucet_module_addr_details, - pub signal_info: libc::siginfo_t, - pub context: UContext, } #[repr(C)] @@ -410,13 +410,17 @@ pub mod lucet_state { } } + const ADDR_DETAILS_NAME_LEN: usize = 256; + + /// Half a kilobyte is too substantial for `Copy`, but we must have it because [unions with + /// non-`Copy` fields are unstable](https://github.com/rust-lang/rust/issues/32836). #[repr(C)] - #[derive(Clone, Copy, Debug)] + #[derive(Clone, Copy)] pub struct lucet_module_addr_details { pub module_code_resolvable: bool, pub in_module_code: bool, - pub file_name: *const c_char, - pub sym_name: *const c_char, + pub file_name: [c_uchar; ADDR_DETAILS_NAME_LEN], + pub sym_name: [c_uchar; ADDR_DETAILS_NAME_LEN], } impl Default for lucet_module_addr_details { @@ -424,45 +428,49 @@ pub mod lucet_state { lucet_module_addr_details { module_code_resolvable: false, in_module_code: false, - file_name: ptr::null(), - sym_name: ptr::null(), + file_name: [0; ADDR_DETAILS_NAME_LEN], + sym_name: [0; ADDR_DETAILS_NAME_LEN], } } } impl From> for lucet_module_addr_details { fn from(details: Option) -> Self { - (&details).into() - } - } + /// Convert a string into C-compatible bytes, truncate it to length + /// `ADDR_DETAILS_NAME_LEN`, and make sure it has a trailing nul. + fn trunc_c_str_bytes(s: &str) -> Vec { + let s = CString::new(s); + let mut bytes = s.ok().map(|s| s.into_bytes_with_nul()).unwrap_or(vec![0]); + bytes.truncate(ADDR_DETAILS_NAME_LEN); + // we always have at least the 0, so this `last` can be unwrapped + *bytes.last_mut().unwrap() = 0; + bytes + } - impl From<&Option> for lucet_module_addr_details { - fn from(details: &Option) -> Self { - details + let mut ret = details .as_ref() .map(|details| lucet_module_addr_details { module_code_resolvable: true, in_module_code: details.in_module_code, - file_name: details - .file_name - .as_ref() - .and_then(|s| { - CString::new(s.clone()) - .ok() - .map(|s| s.into_raw() as *const _) - }) - .unwrap_or(ptr::null()), - sym_name: details - .sym_name - .as_ref() - .and_then(|s| { - CString::new(s.clone()) - .ok() - .map(|s| s.into_raw() as *const _) - }) - .unwrap_or(ptr::null()), + file_name: [0; ADDR_DETAILS_NAME_LEN], + sym_name: [0; ADDR_DETAILS_NAME_LEN], }) - .unwrap_or_default() + .unwrap_or_default(); + + // get truncated C-compatible bytes for each string, or "\0" if they're not present + let file_name_bytes = details + .as_ref() + .and_then(|details| details.file_name.as_ref().map(|s| trunc_c_str_bytes(s))) + .unwrap_or_else(|| vec![0]); + let sym_name_bytes = details + .and_then(|details| details.sym_name.as_ref().map(|s| trunc_c_str_bytes(s))) + .unwrap_or_else(|| vec![0]); + + // copy the bytes into the array, making sure to copy only as many as are in the string + ret.file_name[0..file_name_bytes.len()].copy_from_slice(file_name_bytes.as_slice()); + ret.sym_name[0..sym_name_bytes.len()].copy_from_slice(sym_name_bytes.as_slice()); + + ret } } } @@ -629,8 +637,8 @@ pub mod lucet_val { pub as_i64: i64, } - impl From<&UntypedRetVal> for lucet_untyped_retval { - fn from(retval: &UntypedRetVal) -> lucet_untyped_retval { + impl From for lucet_untyped_retval { + fn from(retval: UntypedRetVal) -> lucet_untyped_retval { let mut v = lucet_untyped_retval { fp: [0; 16], gp: [0; 8], diff --git a/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs b/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs index 1ff975fc4..3c11f8807 100644 --- a/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs +++ b/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs @@ -51,11 +51,12 @@ macro_rules! lucet_hostcalls { match res { Ok(res) => res, Err(e) => { - if let Some(details) = e.downcast_ref::<$crate::instance::TerminationDetails>() { - let mut vmctx = $crate::vmctx::Vmctx::from_raw(vmctx_raw); - vmctx.terminate_no_unwind(details.clone()); - } else { - std::panic::resume_unwind(e); + match e.downcast::<$crate::instance::TerminationDetails>() { + Ok(details) => { + let mut vmctx = $crate::vmctx::Vmctx::from_raw(vmctx_raw); + vmctx.terminate_no_unwind(*details) + }, + Err(e) => std::panic::resume_unwind(e), } } } diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index 5728974ca..74965df05 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -218,7 +218,7 @@ pub struct Instance { entrypoint: Option, /// The value passed back to the guest when resuming a yielded instance. - pub(crate) resumed_val: Option>, + pub(crate) resumed_val: Option>, /// `_padding` must be the last member of the structure. /// This marks where the padding starts to make the structure exactly 4096 bytes long. @@ -470,7 +470,7 @@ impl Instance { /// /// The foreign code safety caveat of [`Instance::run()`](struct.Instance.html#method.run) /// applies. - pub fn resume_with_val(&mut self, val: A) -> Result { + pub fn resume_with_val(&mut self, val: A) -> Result { match &self.state { State::Yielded { expected, .. } => { // make sure the resumed value is of the right type @@ -483,7 +483,7 @@ impl Instance { _ => return Err(Error::InvalidArgument("can only resume a yielded instance")), } - self.resumed_val = Some(Box::new(val) as Box); + self.resumed_val = Some(Box::new(val) as Box); self.swap_and_return() } @@ -800,41 +800,58 @@ impl Instance { // Sandbox has jumped back to the host process, indicating it has either: // - // * trapped, or called hostcall_error: state tag changed to something other than `Running` + // * returned: state should be `Running`; transition to Ready and return a RunResult + // * yielded: state should be `Yielded`; take the yielded value and return a RunResult + // * trapped: state should be `Fault`; populate details and return an error or call a hanlder as appropriate + // * terminated: state should be `Terminated`; take the termination details and return as an Err // * function body returned: set state back to `Ready` with return value + // + // The state should never be `Ready` at this point - match &self.state { + match &mut self.state { State::Running => { let retval = self.ctx.get_untyped_retval(); self.state = State::Ready { retval }; Ok(RunResult::Returned(retval)) } - State::Terminated { details, .. } => Err(Error::RuntimeTerminated(details.clone())), - State::Yielded { val, .. } => Ok(RunResult::Yielded(val.clone())), - State::Fault { .. } => { + State::Terminated { details, .. } => { + Err(Error::RuntimeTerminated(details.take().ok_or_else( + || lucet_format_err!("terminated state contained no details"), + )?)) + } + State::Yielded { val, .. } => { + Ok(RunResult::Yielded(val.take().ok_or_else(|| { + lucet_format_err!("yielded state contained no value") + })?)) + } + State::Fault { + ref mut details, .. + } => { // Sandbox is no longer runnable. It's unsafe to determine all error details in the signal // handler, so we fill in extra details here. - self.populate_fault_detail()?; - if let State::Fault { ref details, .. } = self.state { - if details.fatal { - // Some errors indicate that the guest is not functioning correctly or that - // the loaded code violated some assumption, so bail out via the fatal - // handler. - - // Run the C-style fatal handler, if it exists. - self.c_fatal_handler - .map(|h| unsafe { h(self as *mut Instance) }); - - // If there is no C-style fatal handler, or if it (erroneously) returns, - // call the Rust handler that we know will not return - (self.fatal_handler)(self) - } else { - // leave the full fault details in the instance state, and return the - // higher-level info to the user - Err(Error::RuntimeFault(details.clone())) - } + // + // FIXME after lucet-module is complete it should be possible to fill this in without + // consulting the process symbol table + details.rip_addr_details = self + .module + .addr_details(details.rip_addr as *const c_void)?; + + if details.fatal { + // Some errors indicate that the guest is not functioning correctly or that + // the loaded code violated some assumption, so bail out via the fatal + // handler. + + // Run the C-style fatal handler, if it exists. + self.c_fatal_handler + .map(|h| unsafe { h(self as *mut Instance) }); + + // If there is no C-style fatal handler, or if it (erroneously) returns, + // call the Rust handler that we know will not return + (self.fatal_handler)(self) } else { - panic!("state remains Fault after populate_fault_detail()") + // leave the full fault details in the instance state, and return the + // higher-level info to the user + Err(Error::RuntimeFault(details.clone())) } } State::Ready { .. } => { @@ -852,26 +869,6 @@ impl Instance { } Ok(()) } - - fn populate_fault_detail(&mut self) -> Result<(), Error> { - if let State::Fault { - details: - FaultDetails { - rip_addr, - ref mut rip_addr_details, - .. - }, - .. - } = self.state - { - // We do this after returning from the signal handler because it requires `dladdr` - // calls, which are not signal safe - // FIXME after lucet-module is complete it should be possible to fill this in without - // consulting the process symbol table - *rip_addr_details = self.module.addr_details(rip_addr as *const c_void)?.clone(); - } - Ok(()) - } } pub enum State { @@ -885,10 +882,14 @@ pub enum State { context: UContext, }, Terminated { - details: TerminationDetails, + /// This is always expected to be a `Some` when a terminating instance context switches back + /// to the host, but is `take`n to popuate the resulting `Error`. + details: Option, }, Yielded { - val: YieldedVal, + /// This is always expected to be a `Some` when a yielding instance context switches back to + /// the host, but is `take`n to popuate the `RunResult`. + val: Option, /// Concretely, this should only ever be `Box>` where `R` is the type /// the guest expects upon resumption. expected: Box, @@ -952,7 +953,6 @@ impl std::fmt::Display for FaultDetails { /// Guests are terminated either explicitly by `Vmctx::terminate()`, or implicitly by signal /// handlers that return `SignalBehavior::Terminate`. It usually indicates that an unrecoverable /// error has occurred in a hostcall, rather than in WebAssembly code. -#[derive(Clone)] pub enum TerminationDetails { /// Returned when a signal handler terminates the instance. Signal, @@ -969,12 +969,12 @@ pub enum TerminationDetails { /// Returned when dynamic borrowing rules of methods like `Vmctx::heap()` are violated. BorrowError(&'static str), /// Calls to `lucet_hostcall_terminate` provide a payload for use by the embedder. - Provided(Arc), + Provided(Box), } impl TerminationDetails { - pub fn provide(details: A) -> Self { - TerminationDetails::Provided(Arc::new(details)) + pub fn provide(details: A) -> Self { + TerminationDetails::Provided(Box::new(details)) } pub fn provided_details(&self) -> Option<&dyn Any> { match self { @@ -1028,9 +1028,8 @@ unsafe impl Sync for TerminationDetails {} /// The value yielded by an instance through a [`Vmctx`](vmctx/struct.Vmctx.html) and returned to /// the host. -#[derive(Clone)] pub struct YieldedVal { - val: Arc, + val: Box, } impl std::fmt::Debug for YieldedVal { @@ -1044,8 +1043,8 @@ impl std::fmt::Debug for YieldedVal { } impl YieldedVal { - pub(crate) fn new(val: A) -> Self { - YieldedVal { val: Arc::new(val) } + pub(crate) fn new(val: A) -> Self { + YieldedVal { val: Box::new(val) } } /// Returns `true` if the guest yielded without a value. @@ -1060,7 +1059,7 @@ impl YieldedVal { /// Attempt to downcast the yielded value to a concrete type, returning the original /// `YieldedVal` if unsuccessful. - pub fn downcast(self) -> Result, YieldedVal> { + pub fn downcast(self) -> Result, YieldedVal> { match self.val.downcast() { Ok(val) => Ok(val), Err(val) => Err(YieldedVal { val }), diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs index 646935f79..41a2f9853 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs @@ -175,7 +175,7 @@ extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext SignalBehavior::Terminate => { // set the state before jumping back to the host context inst.state = State::Terminated { - details: TerminationDetails::Signal, + details: Some(TerminationDetails::Signal), }; true } diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index 0f2a2a822..40c489849 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -65,7 +65,7 @@ pub trait VmctxInternal { /// /// If there is no resumed value, or if the dynamic type check of the value fails, this returns /// `None`. - fn try_take_resumed_val(&self) -> Option; + fn try_take_resumed_val(&self) -> Option; /// Suspend the instance, returning a value in /// [`RunResult::Yielded`](../enum.RunResult.html#variant.Yielded) to where the instance was run @@ -78,10 +78,7 @@ pub trait VmctxInternal { /// /// The dynamic type checks used by the other yield methods should make this explicit option /// type redundant, however this interface is used to avoid exposing a panic to the C API. - fn yield_val_try_val( - &self, - val: A, - ) -> Option; + fn yield_val_try_val(&self, val: A) -> Option; } impl VmctxInternal for Vmctx { @@ -93,7 +90,7 @@ impl VmctxInternal for Vmctx { instance_from_vmctx(self.vmctx) } - fn try_take_resumed_val(&self) -> Option { + fn try_take_resumed_val(&self) -> Option { let inst = unsafe { self.instance_mut() }; if let Some(val) = inst.resumed_val.take() { match val.downcast() { @@ -108,10 +105,7 @@ impl VmctxInternal for Vmctx { } } - fn yield_val_try_val( - &self, - val: A, - ) -> Option { + fn yield_val_try_val(&self, val: A) -> Option { self.yield_impl::(val); self.try_take_resumed_val() } @@ -336,7 +330,7 @@ impl Vmctx { /// After suspending, the instance may be resumed by calling /// [`Instance::resume_with_val()`](../struct.Instance.html#method.resume_with_val) from the /// host with a value of type `R`. - pub fn yield_expecting_val(&self) -> R { + pub fn yield_expecting_val(&self) -> R { self.yield_val_expecting_val::(EmptyYieldVal) } @@ -346,7 +340,7 @@ impl Vmctx { /// /// After suspending, the instance may be resumed by the host using /// [`Instance::resume()`](../struct.Instance.html#method.resume). - pub fn yield_val(&self, val: A) { + pub fn yield_val(&self, val: A) { self.yield_val_expecting_val::(val); } @@ -357,19 +351,16 @@ impl Vmctx { /// After suspending, the instance may be resumed by calling /// [`Instance::resume_with_val()`](../struct.Instance.html#method.resume_with_val) from the /// host with a value of type `R`. - pub fn yield_val_expecting_val( - &self, - val: A, - ) -> R { + pub fn yield_val_expecting_val(&self, val: A) -> R { self.yield_impl::(val); self.take_resumed_val() } - fn yield_impl(&self, val: A) { + fn yield_impl(&self, val: A) { let inst = unsafe { self.instance_mut() }; let expected: Box> = Box::new(PhantomData); inst.state = State::Yielded { - val: YieldedVal::new(val), + val: Some(YieldedVal::new(val)), expected: expected as Box, }; HOST_CTX.with(|host_ctx| unsafe { Context::swap(&mut inst.ctx, &mut *host_ctx.get()) }); @@ -378,7 +369,7 @@ impl Vmctx { /// Take and return the value passed to /// [`Instance::resume_with_val()`](../struct.Instance.html#method.resume_with_val), terminating /// the instance if there is no value present, or the dynamic type check of the value fails. - fn take_resumed_val(&self) -> R { + fn take_resumed_val(&self) -> R { self.try_take_resumed_val() .unwrap_or_else(|| panic!(TerminationDetails::YieldTypeMismatch)) } @@ -421,7 +412,9 @@ impl Instance { /// This is almost certainly not what you want to use to terminate from a hostcall; use panics /// with `TerminationDetails` instead. unsafe fn terminate(&mut self, details: TerminationDetails) -> ! { - self.state = State::Terminated { details }; + self.state = State::Terminated { + details: Some(details), + }; #[allow(unused_unsafe)] // The following unsafe will be incorrectly warned as unused HOST_CTX.with(|host_ctx| unsafe { Context::set(&*host_ctx.get()) }) } diff --git a/lucet-runtime/src/c_api.rs b/lucet-runtime/src/c_api.rs index 35de8359f..d8ab48187 100644 --- a/lucet-runtime/src/c_api.rs +++ b/lucet-runtime/src/c_api.rs @@ -58,18 +58,18 @@ pub extern "C" fn lucet_error_name(e: c_int) -> *const c_char { } #[no_mangle] -pub extern "C" fn lucet_state_tag_name(tag: libc::c_int) -> *const c_char { - if let Some(tag) = lucet_state_tag::from_i32(tag) { - use self::lucet_state_tag::*; +pub extern "C" fn lucet_result_tag_name(tag: libc::c_int) -> *const c_char { + if let Some(tag) = lucet_result_tag::from_i32(tag) { + use self::lucet_result_tag::*; match tag { - Returned => "lucet_state_tag_returned\0".as_ptr() as _, - Running => "lucet_state_tag_running\0".as_ptr() as _, - Fault => "lucet_state_tag_fault\0".as_ptr() as _, - Terminated => "lucet_state_tag_terminated\0".as_ptr() as _, - Yielded => "lucet_state_tag_yielded\0".as_ptr() as _, + Returned => "lucet_result_tag_returned\0".as_ptr() as _, + Yielded => "lucet_result_tag_yielded\0".as_ptr() as _, + Faulted => "lucet_result_tag_faulted\0".as_ptr() as _, + Terminated => "lucet_result_tag_terminated\0".as_ptr() as _, + Errored => "lucet_result_tag_errored\0".as_ptr() as _, } } else { - "!!! unknown lucet_state_tag variant!\0".as_ptr() as _ + "!!! unknown lucet_result_tag variant!\0".as_ptr() as _ } } @@ -156,6 +156,7 @@ pub unsafe extern "C" fn lucet_instance_run( entrypoint: *const c_char, argc: usize, argv: *const lucet_val::lucet_val, + result_out: *mut lucet_result::lucet_result, ) -> lucet_error { assert_nonnull!(entrypoint); if argc != 0 && argv.is_null() { @@ -177,12 +178,15 @@ pub unsafe extern "C" fn lucet_instance_run( }; with_instance_ptr!(inst, { - inst.run(entrypoint, args.as_slice()) + let res = inst.run(entrypoint, args.as_slice()); + let ret = res + .as_ref() .map(|_| lucet_error::Ok) - .unwrap_or_else(|e| { - eprintln!("{}", e); - e.into() - }) + .unwrap_or_else(|e| e.into()); + if !result_out.is_null() { + std::ptr::write(result_out, res.into()); + } + ret }) } @@ -193,6 +197,7 @@ pub unsafe extern "C" fn lucet_instance_run_func_idx( func_idx: u32, argc: usize, argv: *const lucet_val::lucet_val, + result_out: *mut lucet_result::lucet_result, ) -> lucet_error { if argc != 0 && argv.is_null() { return lucet_error::InvalidArgument; @@ -206,9 +211,15 @@ pub unsafe extern "C" fn lucet_instance_run_func_idx( .collect() }; with_instance_ptr!(inst, { - inst.run_func_idx(table_idx, func_idx, args.as_slice()) + let res = inst.run_func_idx(table_idx, func_idx, args.as_slice()); + let ret = res + .as_ref() .map(|_| lucet_error::Ok) - .unwrap_or_else(|e| e.into()) + .unwrap_or_else(|e| e.into()); + if !result_out.is_null() { + std::ptr::write(result_out, res.into()); + } + ret }) } @@ -216,40 +227,21 @@ pub unsafe extern "C" fn lucet_instance_run_func_idx( pub unsafe extern "C" fn lucet_instance_resume( inst: *const lucet_instance, val: *mut c_void, + result_out: *mut lucet_result::lucet_result, ) -> lucet_error { with_instance_ptr!(inst, { - inst.resume_with_val(CYieldedVal { val }) + let res = inst.resume_with_val(CYieldedVal { val }); + let ret = res + .as_ref() .map(|_| lucet_error::Ok) - .unwrap_or_else(|e| e.into()) - }) -} - -#[no_mangle] -pub unsafe extern "C" fn lucet_instance_state( - inst: *const lucet_instance, - state_out: *mut lucet_state::lucet_state, -) -> lucet_error { - assert_nonnull!(state_out); - with_instance_ptr!(inst, { - state_out.write(inst.state().into()); - lucet_error::Ok + .unwrap_or_else(|e| e.into()); + if !result_out.is_null() { + std::ptr::write(result_out, res.into()); + } + ret }) } -#[no_mangle] -pub unsafe extern "C" fn lucet_state_release(state: *mut lucet_state::lucet_state) { - use lucet_runtime_internals::c_api::lucet_state::*; - use std::ffi::CString; - - let state = state.read(); - if let lucet_state_tag::Fault = state.tag { - let addr_details = state.val.fault.rip_addr_details; - // free the strings - CString::from_raw(addr_details.file_name as *mut _); - CString::from_raw(addr_details.sym_name as *mut _); - } -} - #[no_mangle] pub unsafe extern "C" fn lucet_instance_reset(inst: *mut lucet_instance) -> lucet_error { with_instance_ptr!(inst, { diff --git a/lucet-runtime/tests/c_api.c b/lucet-runtime/tests/c_api.c index 69eaa3812..4f2dc3418 100644 --- a/lucet-runtime/tests/c_api.c +++ b/lucet-runtime/tests/c_api.c @@ -117,34 +117,25 @@ bool lucet_runtime_test_yield_resume(struct lucet_dl_module *mod) uint64_t results[5] = { 0 }; size_t i = 0; - err = lucet_instance_run(inst, "f", 0, (const struct lucet_val[]){}); - while (err == lucet_error_ok) { - struct lucet_state st; - err = lucet_instance_state(inst, &st); - if (err != lucet_error_ok) { - fprintf(stderr, "couldn't get instance state\n"); - goto fail3; - } - if (st.tag != lucet_state_tag_yielded) { - break; - } - + struct lucet_result res; + lucet_instance_run(inst, "f", 0, (const struct lucet_val[]){}, &res); + while (res.tag == lucet_result_tag_yielded) { if (i >= 5) { fprintf(stderr, "hostcall yielded too many results\n"); goto fail3; } - struct yield_resume_val val = *(struct yield_resume_val *) st.val.yielded.val; + struct yield_resume_val val = *(struct yield_resume_val *) res.val.yielded.val; switch (val.tag) { case yield_resume_tag_mult: { uint64_t mult_result = val.val.mult.x * val.val.mult.y; - err = lucet_instance_resume(inst, &mult_result); + lucet_instance_resume(inst, &mult_result, &res); continue; } case yield_resume_tag_result: { results[i++] = val.val.result; - err = lucet_instance_resume(inst, NULL); + lucet_instance_resume(inst, NULL, &res); continue; } default: { @@ -158,19 +149,12 @@ bool lucet_runtime_test_yield_resume(struct lucet_dl_module *mod) goto fail3; } - struct lucet_state st; - err = lucet_instance_state(inst, &st); - if (err != lucet_error_ok) { - fprintf(stderr, "couldn't get instance state\n"); - goto fail3; - } - - if (st.tag != lucet_state_tag_returned) { - fprintf(stderr, "final instance state wasn't returned\n"); + if (res.tag != lucet_result_tag_returned) { + fprintf(stderr, "final instance result wasn't returned\n"); goto fail3; } - uint64_t final_result = LUCET_UNTYPED_RETVAL_TO_U64(st.val.returned); + uint64_t final_result = LUCET_UNTYPED_RETVAL_TO_U64(res.val.returned); lucet_instance_release(inst); lucet_region_release(region); From 60eb374afcdea306234e69451377f3291186ba78 Mon Sep 17 00:00:00 2001 From: awortman-fastly <49215183+awortman-fastly@users.noreply.github.com> Date: Thu, 1 Aug 2019 14:10:34 -0700 Subject: [PATCH 281/512] bump cranelift version (#261) cranelift bump involves somewhat more aggressive optimizations, which optimized out the local variables in the localpalooza test case. switched around arithmetic to not be so easily optimized, and worked around cranelift keeping locals in registers rather than the stack --- Cargo.lock | 70 +++++++++---------- cranelift | 2 +- lucet-module/Cargo.toml | 2 +- .../lucet-runtime-internals/Cargo.toml | 2 +- .../lucet-runtime-tests/src/stack.rs | 20 ++++-- lucetc/Cargo.toml | 14 ++-- 6 files changed, 60 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b738c8874..994a0425b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -286,18 +286,18 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.31.0" +version = "0.37.0" dependencies = [ - "cranelift-entity 0.31.0", + "cranelift-entity 0.37.0", ] [[package]] name = "cranelift-codegen" -version = "0.31.0" +version = "0.37.0" dependencies = [ - "cranelift-bforest 0.31.0", - "cranelift-codegen-meta 0.31.0", - "cranelift-entity 0.31.0", + "cranelift-bforest 0.37.0", + "cranelift-codegen-meta 0.37.0", + "cranelift-entity 0.37.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -306,21 +306,21 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.31.0" +version = "0.37.0" dependencies = [ - "cranelift-entity 0.31.0", + "cranelift-entity 0.37.0", ] [[package]] name = "cranelift-entity" -version = "0.31.0" +version = "0.37.0" [[package]] name = "cranelift-faerie" -version = "0.31.0" +version = "0.37.0" dependencies = [ - "cranelift-codegen 0.31.0", - "cranelift-module 0.31.0", + "cranelift-codegen 0.37.0", + "cranelift-module 0.37.0", "faerie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)", @@ -329,43 +329,43 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.31.0" +version = "0.37.0" dependencies = [ - "cranelift-codegen 0.31.0", + "cranelift-codegen 0.37.0", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-module" -version = "0.31.0" +version = "0.37.0" dependencies = [ - "cranelift-codegen 0.31.0", - "cranelift-entity 0.31.0", + "cranelift-codegen 0.37.0", + "cranelift-entity 0.37.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-native" -version = "0.31.0" +version = "0.37.0" dependencies = [ - "cranelift-codegen 0.31.0", + "cranelift-codegen 0.37.0", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-wasm" -version = "0.31.0" +version = "0.37.0" dependencies = [ - "cranelift-codegen 0.31.0", - "cranelift-entity 0.31.0", - "cranelift-frontend 0.31.0", + "cranelift-codegen 0.37.0", + "cranelift-entity 0.37.0", + "cranelift-frontend 0.37.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.31.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.32.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -853,7 +853,7 @@ version = "0.1.1" dependencies = [ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.31.0", + "cranelift-codegen 0.37.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -891,7 +891,7 @@ dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.31.0", + "cranelift-codegen 0.37.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -995,13 +995,13 @@ dependencies = [ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.31.0", - "cranelift-entity 0.31.0", - "cranelift-faerie 0.31.0", - "cranelift-frontend 0.31.0", - "cranelift-module 0.31.0", - "cranelift-native 0.31.0", - "cranelift-wasm 0.31.0", + "cranelift-codegen 0.37.0", + "cranelift-entity 0.37.0", + "cranelift-faerie 0.37.0", + "cranelift-frontend 0.37.0", + "cranelift-module 0.37.0", + "cranelift-native 0.37.0", + "cranelift-wasm 0.37.0", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "faerie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1926,7 +1926,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "wasmparser" -version = "0.31.1" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2186,7 +2186,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" "checksum wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5e01c420bc7d36e778bd242e1167b079562ba8b34087122cc9057187026d060" -"checksum wasmparser 0.31.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6f324afc05fd8282bbc49dae854a1c20f74aeff10a575b5a43453d1864db97" +"checksum wasmparser 0.32.1 (registry+https://github.com/rust-lang/crates.io-index)" = "22d1801de30f112ddaf665291097694ee33a36d1cb414b53a921d05b3519674a" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" diff --git a/cranelift b/cranelift index faae51807..05d22df6c 160000 --- a/cranelift +++ b/cranelift @@ -1 +1 @@ -Subproject commit faae51807d46e5ab2ec2ee257ed5a607b108af11 +Subproject commit 05d22df6cbf98a072d7525cff4599d930af142a7 diff --git a/lucet-module/Cargo.toml b/lucet-module/Cargo.toml index 527536ce6..0b3b104a8 100644 --- a/lucet-module/Cargo.toml +++ b/lucet-module/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Lucet team "] edition = "2018" [dependencies] -cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.31.0" } +cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.37.0" } failure = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index 5823263cf..da9e91f36 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -15,7 +15,7 @@ lucet-module = { path = "../../lucet-module", version = "0.1.1" } bitflags = "1.0" bincode = "~1.0.1" byteorder = "1.3" -cranelift-codegen = { path = "../../cranelift/cranelift-codegen", version = "0.31.0" } +cranelift-codegen = { path = "../../cranelift/cranelift-codegen", version = "0.37.0" } failure = "0.1" lazy_static = "1.1" libc = "=0.2.59" diff --git a/lucet-runtime/lucet-runtime-tests/src/stack.rs b/lucet-runtime/lucet-runtime-tests/src/stack.rs index bc794f289..976866ab6 100644 --- a/lucet-runtime/lucet-runtime-tests/src/stack.rs +++ b/lucet-runtime/lucet-runtime-tests/src/stack.rs @@ -35,9 +35,10 @@ fn generate_test_wat(num_locals: usize) -> String { // Use each local for the first time: for i in 1..num_locals { module.push_str(&format!( - "(set_local {} (i32.add (get_local {}) (get_local {})))\n", + "(set_local {} (i32.add (get_local {}) (i32.xor (get_local {}) (i32.const {}))))\n", i, i - 1, + i, i )); } @@ -45,9 +46,10 @@ fn generate_test_wat(num_locals: usize) -> String { // Use each local for a second time, so they get pushed to the stack between uses: for i in 2..(num_locals - 1) { module.push_str(&format!( - "(set_local {} (i32.add (get_local {}) (get_local {})))\n", + "(set_local {} (i32.add (get_local {}) (i32.and (get_local {}) (i32.const {}))))\n", i, i - 1, + i, i )); } @@ -139,14 +141,22 @@ macro_rules! stack_tests { } #[test] - fn expect_ok_locals64_480() { - expect_ok(stack_testcase(64).expect("generate stack_testcase 64"), 480); + fn expect_ok_locals64_481() { + // We use 64 local variables, but cranelift optimizes many of them into registers + // rather than stack space. Four of those are callee-saved, for n > 18 local + // variables, we actually use n + 4 stack spaces. So we use 64 spaces at 64 - 4 = 60 + // local variables. + expect_ok( + stack_testcase(64 - 4).expect("generate stack_testcase 64"), + 480, + ); } #[test] fn expect_stack_overflow_locals64_481() { expect_stack_overflow( - stack_testcase(64).expect("generate stack_testcase 64"), + // Same note as `expect_ok_locals64_481` + stack_testcase(64 - 4).expect("generate stack_testcase 64"), 481, true, ); diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index 27a1ff251..491a8d00e 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -18,13 +18,13 @@ path = "src/main.rs" [dependencies] bincode = "~1.0.1" -cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.31.0" } -cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.31.0" } -cranelift-native = { path = "../cranelift/cranelift-native", version = "0.31.0" } -cranelift-frontend = { path = "../cranelift/cranelift-frontend", version = "0.31.0" } -cranelift-module = { path = "../cranelift/cranelift-module", version = "0.31.0" } -cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.31.0" } -cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.31.0" } +cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.37.0" } +cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.37.0" } +cranelift-native = { path = "../cranelift/cranelift-native", version = "0.37.0" } +cranelift-frontend = { path = "../cranelift/cranelift-frontend", version = "0.37.0" } +cranelift-module = { path = "../cranelift/cranelift-module", version = "0.37.0" } +cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.37.0" } +cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.37.0" } target-lexicon = "0.4.0" lucet-module = { path = "../lucet-module", version = "0.1.1" } wasmparser = "0.23" From dbedcd547085a46241e33412efacf418f24d95ba Mon Sep 17 00:00:00 2001 From: awortman-fastly <49215183+awortman-fastly@users.noreply.github.com> Date: Thu, 1 Aug 2019 15:43:06 -0700 Subject: [PATCH 282/512] Supprt counting executed wasm operations (#252) * add struct for shared representation of values accessed from runtime and guest code * add documentation describing the layout of an instance in memory and how MmapRegion lays out a Slot * add option to insert instrumentation that counts wasm instructions executed * add tests around counting executed wasm operations --- Cargo.lock | 10 +- lucet-module/src/lib.rs | 2 + lucet-module/src/runtime.rs | 8 + lucet-runtime/Cargo.toml | 1 + .../lucet-runtime-internals/Cargo.toml | 2 +- .../lucet-runtime-internals/src/instance.rs | 79 ++++++- .../src/region/mmap.rs | 42 +++- lucet-runtime/tests/instruction_counting.rs | 71 ++++++ .../instruction_counting/arithmetic_count.wat | 11 + .../instruction_counting/br_table_count.wat | 25 +++ .../tests/instruction_counting/calls.wat | 22 ++ .../instruction_counting/count_after_br.wat | 21 ++ .../tests/instruction_counting/empty_loop.wat | 9 + .../instruction_counting/empty_loop_2.wat | 11 + .../tests/instruction_counting/if_count.wat | 21 ++ .../if_not_taken_count.wat | 21 ++ .../instruction_counting/indirect_calls.wat | 68 ++++++ .../tests/instruction_counting/loops.wat | 30 +++ lucet-spectest/src/script.rs | 10 +- lucet-wasi-sdk/tests/lucetc.rs | 8 +- lucetc/Cargo.toml | 3 +- lucetc/src/compiler.rs | 7 +- lucetc/src/function.rs | 211 +++++++++++++++++- lucetc/src/lib.rs | 16 ++ lucetc/src/main.rs | 4 + lucetc/src/options.rs | 9 + lucetc/tests/wasm.rs | 37 +-- 27 files changed, 705 insertions(+), 54 deletions(-) create mode 100644 lucet-module/src/runtime.rs create mode 100644 lucet-runtime/tests/instruction_counting.rs create mode 100644 lucet-runtime/tests/instruction_counting/arithmetic_count.wat create mode 100644 lucet-runtime/tests/instruction_counting/br_table_count.wat create mode 100644 lucet-runtime/tests/instruction_counting/calls.wat create mode 100644 lucet-runtime/tests/instruction_counting/count_after_br.wat create mode 100644 lucet-runtime/tests/instruction_counting/empty_loop.wat create mode 100644 lucet-runtime/tests/instruction_counting/empty_loop_2.wat create mode 100644 lucet-runtime/tests/instruction_counting/if_count.wat create mode 100644 lucet-runtime/tests/instruction_counting/if_not_taken_count.wat create mode 100644 lucet-runtime/tests/instruction_counting/indirect_calls.wat create mode 100644 lucet-runtime/tests/instruction_counting/loops.wat diff --git a/Cargo.lock b/Cargo.lock index 994a0425b..c3ef4fcd5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -880,6 +880,7 @@ dependencies = [ "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1009,13 +1010,14 @@ dependencies = [ "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", + "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "wasmonkey 0.1.8", - "wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.32.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1919,11 +1921,6 @@ dependencies = [ "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "wasmparser" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "wasmparser" version = "0.32.1" @@ -2185,7 +2182,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a6265b25719e82598d104b3717375e37661d41753e2c84cde3f51050c7ed7e3c" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" -"checksum wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5e01c420bc7d36e778bd242e1167b079562ba8b34087122cc9057187026d060" "checksum wasmparser 0.32.1 (registry+https://github.com/rust-lang/crates.io-index)" = "22d1801de30f112ddaf665291097694ee33a36d1cb414b53a921d05b3519674a" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" diff --git a/lucet-module/src/lib.rs b/lucet-module/src/lib.rs index c34243c3f..8be0f1797 100644 --- a/lucet-module/src/lib.rs +++ b/lucet-module/src/lib.rs @@ -12,6 +12,7 @@ mod globals; mod linear_memory; mod module; mod module_data; +mod runtime; mod signature; mod tables; mod traps; @@ -26,6 +27,7 @@ pub use crate::globals::{Global, GlobalDef, GlobalSpec, GlobalValue}; pub use crate::linear_memory::{HeapSpec, LinearMemorySpec, SparseData}; pub use crate::module::{Module, SerializedModule, LUCET_MODULE_SYM}; pub use crate::module_data::{ModuleData, MODULE_DATA_SYM}; +pub use crate::runtime::InstanceRuntimeData; pub use crate::signature::{ModuleSignature, PublicKey}; pub use crate::tables::TableElement; pub use crate::traps::{TrapCode, TrapManifest, TrapSite}; diff --git a/lucet-module/src/runtime.rs b/lucet-module/src/runtime.rs new file mode 100644 index 000000000..864344dc9 --- /dev/null +++ b/lucet-module/src/runtime.rs @@ -0,0 +1,8 @@ +/// This struct describes the handful of fields that Lucet-compiled programs may directly interact with, but +/// are provided through VMContext. +#[repr(C)] +#[repr(align(8))] +pub struct InstanceRuntimeData { + pub globals_ptr: *mut i64, + pub instruction_count: u64, +} diff --git a/lucet-runtime/Cargo.toml b/lucet-runtime/Cargo.toml index 794798113..7f021f79d 100644 --- a/lucet-runtime/Cargo.toml +++ b/lucet-runtime/Cargo.toml @@ -24,6 +24,7 @@ lucetc = { path = "../lucetc" } lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.1.1" } lucet-wasi-sdk = { path = "../lucet-wasi-sdk" } nix = "0.13" +rayon = "1.0" tempfile = "3.0" [build-dependencies] diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index da9e91f36..4e5ddc36c 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -20,7 +20,7 @@ failure = "0.1" lazy_static = "1.1" libc = "=0.2.59" libloading = "0.5" -memoffset = "0.5" +memoffset = "0.5.1" nix = "0.13" num-derive = "0.2" num-traits = "0.2" diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index 5728974ca..8adb058c1 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -14,6 +14,7 @@ use crate::sysdeps::UContext; use crate::val::{UntypedRetVal, Val}; use crate::WASM_PAGE_SIZE; use libc::{c_void, siginfo_t, uintptr_t, SIGBUS, SIGSEGV}; +use lucet_module::InstanceRuntimeData; use memoffset::offset_of; use std::any::Any; use std::cell::{BorrowError, BorrowMutError, Ref, RefCell, RefMut, UnsafeCell}; @@ -170,10 +171,41 @@ impl Drop for InstanceHandle { /// WebAssembly heap. /// /// `Instance`s are never created by runtime users directly, but rather are acquired from -/// [`Region`](trait.Region.html)s and often accessed through -/// [`InstanceHandle`](struct.InstanceHandle.html) smart pointers. This guarantees that instances +/// [`Region`](../region/trait.Region.html)s and often accessed through +/// [`InstanceHandle`](../instance/struct.InstanceHandle.html) smart pointers. This guarantees that instances /// and their fields are never moved in memory, otherwise raw pointers in the metadata could be /// unsafely invalidated. +/// +/// An instance occupies one 4096-byte page in memory, with a layout like: +/// ```text +/// 0xXXXXX000: +/// Instance { +/// .magic +/// .embed_ctx +/// ... etc ... +/// } +/// +/// // unused space +/// +/// InstanceInternals { +/// .globals +/// .instruction_counter +/// } // last address *inside* `InstanceInternals` is 0xXXXXXFFF +/// 0xXXXXY000: // start of next page, VMContext points here +/// Heap { +/// .. +/// } +/// ``` +/// +/// This layout allows modules to tightly couple to a handful of fields related to the instance, +/// rather than possibly requiring compiler-side changes (and recompiles) whenever `Instance` +/// changes. +/// +/// It also obligates `Instance` to be immediately followed by the heap, but otherwise leaves the +/// locations of the stack, globals, and any other data, to be implementation-defined by the +/// `Region` that actually creates `Slot`s onto which `Instance` are mapped. +/// For information about the layout of all instance-related memory, see the documentation of +/// [MmapRegion](../region/mmap/struct.MmapRegion.html). #[repr(C)] #[repr(align(4096))] pub struct Instance { @@ -658,6 +690,16 @@ impl Instance { pub fn set_c_fatal_handler(&mut self, handler: unsafe extern "C" fn(*mut Instance)) { self.c_fatal_handler = Some(handler); } + + #[inline] + pub fn get_instruction_count(&self) -> u64 { + self.get_instance_implicits().instruction_count + } + + #[inline] + pub fn set_instruction_count(&mut self, instruction_count: u64) { + self.get_instance_implicits_mut().instruction_count = instruction_count; + } } // Private API @@ -681,6 +723,7 @@ impl Instance { _padding: (), }; inst.set_globals_ptr(globals_ptr); + inst.set_instruction_count(0); assert_eq!(mem::size_of::(), HOST_PAGE_SIZE_EXPECTED); let unpadded_size = offset_of!(Instance, _padding); @@ -692,25 +735,39 @@ impl Instance { // so that it is 8 bytes before the heap. // For this reason, the alignment of the structure is set to 4096, and we define accessors that // read/write the globals pointer as bytes [4096-8..4096] of that structure represented as raw bytes. + // InstanceRuntimeData is placed such that it ends at the end of the page this `Instance` starts + // on. So we can access it by *self + PAGE_SIZE - size_of:: #[inline] - #[allow(dead_code)] - fn get_globals_ptr(&self) -> *const i64 { + fn get_instance_implicits(&self) -> &InstanceRuntimeData { unsafe { - *((self as *const _ as *const u8) - .offset((HOST_PAGE_SIZE_EXPECTED - mem::size_of::<*mut i64>()) as isize) - as *const *const i64) + let implicits_ptr = (self as *const _ as *const u8) + .offset((HOST_PAGE_SIZE_EXPECTED - mem::size_of::()) as isize) + as *const InstanceRuntimeData; + mem::transmute::<*const InstanceRuntimeData, &InstanceRuntimeData>(implicits_ptr) } } #[inline] - fn set_globals_ptr(&mut self, globals_ptr: *const i64) { + fn get_instance_implicits_mut(&mut self) -> &mut InstanceRuntimeData { unsafe { - *((self as *mut _ as *mut u8) - .offset((HOST_PAGE_SIZE_EXPECTED - mem::size_of::<*mut i64>()) as isize) - as *mut *const i64) = globals_ptr; + let implicits_ptr = (self as *mut _ as *mut u8) + .offset((HOST_PAGE_SIZE_EXPECTED - mem::size_of::()) as isize) + as *mut InstanceRuntimeData; + mem::transmute::<*mut InstanceRuntimeData, &mut InstanceRuntimeData>(implicits_ptr) } } + #[allow(dead_code)] + #[inline] + fn get_globals_ptr(&self) -> *mut i64 { + self.get_instance_implicits().globals_ptr + } + + #[inline] + fn set_globals_ptr(&mut self, globals_ptr: *mut i64) { + self.get_instance_implicits_mut().globals_ptr = globals_ptr + } + /// Run a function in guest context at the given entrypoint. fn run_func(&mut self, func: FunctionHandle, args: &[Val]) -> Result { if !(self.state.is_ready() || (self.state.is_fault() && !self.state.is_fatal())) { diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs index 525364792..2a3cc5e07 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs @@ -11,7 +11,47 @@ use nix::sys::mman::{madvise, mmap, munmap, MapFlags, MmapAdvise, ProtFlags}; use std::ptr; use std::sync::{Arc, Mutex, Weak}; -/// A [`Region`](trait.Region.html) backed by `mmap`. +/// A [`Region`](../trait.Region.html) backed by `mmap`. +/// +/// `MmapRegion` lays out memory for instances in a contiguous block, +/// with an Instance's space reserved, followed by heap, stack, globals, and sigstack. +/// +/// This results in an actual layout of an instance on an `MmapRegion`-produced `Slot` being: +/// ```text +/// 0x0000: +-----------------------+ <-- Instance +/// 0x0000: | .magic | +/// 0x0008: | ... | +/// 0x000X: | ... | +/// 0x0XXX: | .alloc -> Alloc { | +/// 0x0XXX: | .start = 0x0000 | +/// 0x0XXX: | .heap = 0x1000 | +/// 0x0XXX: | .stack = 0xN000 | +/// 0x0XXX: | .globals = 0xM000 | +/// 0x0XXX: | .sigstack = 0xS000 | +/// 0x0XXX: | } | +/// 0x0XXX: | ... | +/// 0x0XXX: ~ ~padding~ ~ +/// 0x0XXX: | ... | +/// 0x0XXX: | .globals = 0xM000 | <-- InstanceRuntimeData +/// 0x0XXX: | .inst_count = 0x0000 | +/// 0x1000: +-----------------------+ <-- Heap, and `lucet_vmctx`. One page into the allocation. +/// 0x1XXX: | | +/// 0xXXXX: ~ .......heap....... ~ // heap size is governed by limits.heap_address_space_size +/// 0xXXXX: | | +/// 0xN000: +-----------------------| <-- Stack (at heap_start + limits.heap_address_space_size) +/// 0xNXXX: | | +/// 0xXXXX: ~ .......stack...... ~ // stack size is governed by limits.stack_size +/// 0xXXXX: | | +/// 0xXXXx: --- stack guard page ---- +/// 0xM000: +-----------------------| <-- Globals (at stack_start + limits.stack_size + PAGE_SIZE) +/// 0xMXXX: | | +/// 0xXXXX: ~ ......globals..... ~ +/// 0xXXXX: | | +/// 0xXXXX --- global guard page --- +/// 0xS000: +-----------------------| <-- Sigstack (at globals_start + globals_size + PAGE_SIZE) +/// 0xSXXX: | ......sigstack.... | // sigstack is SIGSTKSZ bytes +/// 0xSXXX: +-----------------------| +/// ``` pub struct MmapRegion { capacity: usize, freelist: Mutex>, diff --git a/lucet-runtime/tests/instruction_counting.rs b/lucet-runtime/tests/instruction_counting.rs new file mode 100644 index 000000000..fd1bf8862 --- /dev/null +++ b/lucet-runtime/tests/instruction_counting.rs @@ -0,0 +1,71 @@ +use lucet_runtime::{DlModule, Error, Limits, MmapRegion, Region, RunResult}; +use lucetc::{Lucetc, LucetcOpts}; +use rayon::prelude::*; +use std::fs::DirEntry; +use std::path::Path; +use std::sync::Arc; +use tempfile::TempDir; + +pub fn wasm_test>(wasm_file: P) -> Result, Error> { + let workdir = TempDir::new().expect("create working directory"); + + let native_build = Lucetc::new(wasm_file).with_count_instructions(true); + + let so_file = workdir.path().join("out.so"); + + native_build.shared_object_file(so_file.clone())?; + + let dlmodule = DlModule::load(so_file)?; + + Ok(dlmodule) +} + +#[test] +pub fn check_instruction_counts() { + let files: Vec = std::fs::read_dir("./tests/instruction_counting") + .expect("can iterate test files") + .map(|ent| { + let ent = ent.expect("can get test files"); + assert!( + ent.file_type().unwrap().is_file(), + "directories not supported in test/instruction_counting" + ); + ent + }) + .collect(); + + assert!( + files.len() > 0, + "there are no test cases in the `instruction_counting` directory" + ); + + files.par_iter().for_each(|ent| { + let wasm_path = ent.path(); + let module = wasm_test(&wasm_path).expect("can load module"); + + let region = MmapRegion::create(1, &Limits::default()).expect("region can be created"); + + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + inst.run("test_function", &[]).expect("instance runs"); + + let instruction_count = inst.get_instruction_count(); + + assert_eq!( + instruction_count, + match inst + .run("instruction_count", &[]) + .expect("instance still runs") + { + RunResult::Returned(value) => value.as_i64() as u64, + RunResult::Yielded(_) => { + panic!("instruction counting test runner doesn't support yielding"); + } + }, + "instruction count for test case {} is incorrect", + wasm_path.display() + ); + }); +} diff --git a/lucet-runtime/tests/instruction_counting/arithmetic_count.wat b/lucet-runtime/tests/instruction_counting/arithmetic_count.wat new file mode 100644 index 000000000..90891313a --- /dev/null +++ b/lucet-runtime/tests/instruction_counting/arithmetic_count.wat @@ -0,0 +1,11 @@ +(module + (func $main (export "test_function") + i32.const 4 + i32.const -5 + i32.add + drop + ) + (func $instruction_count (export "instruction_count") (result i64) + i64.const 3 + ) +) diff --git a/lucet-runtime/tests/instruction_counting/br_table_count.wat b/lucet-runtime/tests/instruction_counting/br_table_count.wat new file mode 100644 index 000000000..29846f083 --- /dev/null +++ b/lucet-runtime/tests/instruction_counting/br_table_count.wat @@ -0,0 +1,25 @@ +(module + (func $main (export "test_function") + block $a + i64.const 1 + drop + + block $b + i64.const 2 + drop + + block $c + i64.const 3 + drop + + ;; 3 for above consts, one for i32.const below, 2 for br_table + ;; totalling to an expected count of 6 + (br_table 0 1 2 3 (i32.const 4)) + end + end + end + ) + (func $instruction_count (export "instruction_count") (result i64) + i64.const 6 + ) +) diff --git a/lucet-runtime/tests/instruction_counting/calls.wat b/lucet-runtime/tests/instruction_counting/calls.wat new file mode 100644 index 000000000..6fba4c4e6 --- /dev/null +++ b/lucet-runtime/tests/instruction_counting/calls.wat @@ -0,0 +1,22 @@ +(module + (func $mul2 (param $in i64) (result i64) + get_local $in + get_local $in + i64.mul + ) + (func $main (export "test_function") + i64.const 1 + call $mul2 ;; one from the call, three from the called function, one for the return + drop + i64.const 2 + call $mul2 ;; and again + drop + i64.const 3 + call $mul2 ;; and again + ;; for a total of 3 * 6 == 18 instructions + drop + ) + (func $instruction_count (export "instruction_count") (result i64) + i64.const 18 + ) +) diff --git a/lucet-runtime/tests/instruction_counting/count_after_br.wat b/lucet-runtime/tests/instruction_counting/count_after_br.wat new file mode 100644 index 000000000..52e180f6f --- /dev/null +++ b/lucet-runtime/tests/instruction_counting/count_after_br.wat @@ -0,0 +1,21 @@ +(module + (func $main (export "test_function") + block $ops + i32.const 11 + i32.const 10 + i32.add + + br 0 ;; branch to enclosing scope (end of this block) + ;; at this point we've counted four operations... + end + + i32.const 14 + i32.const 15 + i32.add + ;; this puts us at 7 operations + drop + ) + (func $instruction_count (export "instruction_count") (result i64) + i64.const 7 + ) +) diff --git a/lucet-runtime/tests/instruction_counting/empty_loop.wat b/lucet-runtime/tests/instruction_counting/empty_loop.wat new file mode 100644 index 000000000..181774313 --- /dev/null +++ b/lucet-runtime/tests/instruction_counting/empty_loop.wat @@ -0,0 +1,9 @@ +(module + (func $main (export "test_function") (local $i i32) + loop $inner + end + ) + (func $instruction_count (export "instruction_count") (result i64) + i64.const 0 + ) +) diff --git a/lucet-runtime/tests/instruction_counting/empty_loop_2.wat b/lucet-runtime/tests/instruction_counting/empty_loop_2.wat new file mode 100644 index 000000000..302e0df8e --- /dev/null +++ b/lucet-runtime/tests/instruction_counting/empty_loop_2.wat @@ -0,0 +1,11 @@ +(module + (func $main (export "test_function") (local $i i32) + block $a + loop $inner + end + end + ) + (func $instruction_count (export "instruction_count") (result i64) + i64.const 0 + ) +) diff --git a/lucet-runtime/tests/instruction_counting/if_count.wat b/lucet-runtime/tests/instruction_counting/if_count.wat new file mode 100644 index 000000000..e4bcb617e --- /dev/null +++ b/lucet-runtime/tests/instruction_counting/if_count.wat @@ -0,0 +1,21 @@ +(module + (func $main (export "test_function") + i32.const 11 + i32.const 10 + i32.gt_s + ;; this counts up to 3 + (if ;; this makes 4 + (then + i64.const 5 + i64.const 10 + i64.mul + ;; and these were another 3 + drop + ;; drop is ignored for a total of 7 operations + ) + ) + ) + (func $instruction_count (export "instruction_count") (result i64) + i64.const 7 + ) +) diff --git a/lucet-runtime/tests/instruction_counting/if_not_taken_count.wat b/lucet-runtime/tests/instruction_counting/if_not_taken_count.wat new file mode 100644 index 000000000..af5794d5a --- /dev/null +++ b/lucet-runtime/tests/instruction_counting/if_not_taken_count.wat @@ -0,0 +1,21 @@ +(module + (func $main (export "test_function") + i32.const 10 + i32.const 11 + i32.gt_s + ;; this counts up to 3 + (if ;; this makes 4 + ;; but the `then` branch is not taken + (then + i64.const 5 + i64.const 10 + i64.mul + drop + ) + ) + ;; so we only execute 4 operations + ) + (func $instruction_count (export "instruction_count") (result i64) + i64.const 4 + ) +) diff --git a/lucet-runtime/tests/instruction_counting/indirect_calls.wat b/lucet-runtime/tests/instruction_counting/indirect_calls.wat new file mode 100644 index 000000000..e6a5bbf99 --- /dev/null +++ b/lucet-runtime/tests/instruction_counting/indirect_calls.wat @@ -0,0 +1,68 @@ +(module + (type $mulfn (func (param i64) (result i64))) + + ;; mul2 is 3 operations + (func $mul2 (param $in i64) (result i64) + get_local $in + get_local $in + i64.add + ) + ;; mul4 is 2 * |mul2| + 2 call + 3 == 13 + (func $mul4 (param $in i64) (result i64) + get_local $in + call $mul2 + get_local $in + call $mul2 + i64.add + ) + ;; mul8 is 2 * |mul4| + 2 call + 3 == 33 + (func $mul8 (param $in i64) (result i64) + get_local $in + call $mul4 + get_local $in + call $mul4 + i64.add + ) + ;; mul16 is 2 * |mul8| + 2 call + 3 == 73 + ;; by entire accident the number of instructions for + ;; subsequent similar functions for higher powers is given by + ;; mul(n^2) == 10 * (2 ^ (n - 1)) - 10 + 3 + (func $mul16 (param $in i64) (result i64) + get_local $in + call $mul8 + get_local $in + call $mul8 + i64.add + ) + + (table anyfunc + (elem + $mul2 $mul4 $mul8 $mul16 + ) + ) + + (func $main (export "test_function") + ;; call_indirect here is 2, plus 1 for the const, one for the index, and + ;; 1 for return + ;; the called function (mul2) is 3 instructions, for 8 total. + (call_indirect (type $mulfn) (i64.const 0) (i32.const 0)) + drop + + ;; call_indirect here is 2, plus 1 for the const, one for the index, and + ;; 1 for return + ;; the called function (mul4) is 13 instructions, for 18 total. + (call_indirect (type $mulfn) (i64.const 1) (i32.const 1)) + drop + + ;; call_indirect here is 2, plus 1 for the const, one for the index, and + ;; 1 for return + ;; the called function (mul16) is 73 instructions, for 78 total. + (call_indirect (type $mulfn) (i64.const 2) (i32.const 3)) + drop + + ;; for a total of 8 + 18 + 78 == 104 instructions + ) + (func $instruction_count (export "instruction_count") (result i64) + i64.const 104 + ) +) diff --git a/lucet-runtime/tests/instruction_counting/loops.wat b/lucet-runtime/tests/instruction_counting/loops.wat new file mode 100644 index 000000000..3b68a0abd --- /dev/null +++ b/lucet-runtime/tests/instruction_counting/loops.wat @@ -0,0 +1,30 @@ +(module + (func $main (export "test_function") (local $i i32) + i32.const 0 + set_local $i + block $outer + loop $inner + ;; each loop iteration is: + ;; * 4 operations to increment i + ;; * 3 operations to test i == 10 + ;; * 1 branch to break (untaken) + ;; * 1 branch to loop + get_local $i + i32.const 1 + i32.add + set_local $i + get_local $i + i32.const 10 + i32.eq + br_if $outer + br $inner + end + end + ;; iterating i = 0..9, that's 10 * 8 instructions from full executions, + ;; plus 9 instructions from the last round. + ;; add two for initializing i and that gives 80 + 9 + 2 = 91 instructions + ) + (func $instruction_count (export "instruction_count") (result i64) + i64.const 91 + ) +) diff --git a/lucet-spectest/src/script.rs b/lucet-spectest/src/script.rs index 0004e0318..7afbf755f 100644 --- a/lucet-spectest/src/script.rs +++ b/lucet-spectest/src/script.rs @@ -67,8 +67,14 @@ impl ScriptEnv { } pub fn instantiate(&mut self, module: &[u8], name: &Option) -> Result<(), ScriptError> { let bindings = bindings::spec_test_bindings(); - let compiler = Compiler::new(module, OptLevel::Fast, &bindings, HeapSettings::default()) - .map_err(program_error)?; + let compiler = Compiler::new( + module, + OptLevel::Fast, + &bindings, + HeapSettings::default(), + true, + ) + .map_err(program_error)?; let dir = tempfile::Builder::new().prefix("codegen").tempdir()?; let objfile_path = dir.path().join("a.o"); diff --git a/lucet-wasi-sdk/tests/lucetc.rs b/lucet-wasi-sdk/tests/lucetc.rs index adec574a0..a1186509f 100644 --- a/lucet-wasi-sdk/tests/lucetc.rs +++ b/lucet-wasi-sdk/tests/lucetc.rs @@ -39,7 +39,7 @@ mod lucetc_tests { let m = module_from_c(&["empty"], &[]).expect("build module for empty"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile empty"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile empty"); let mdata = c.module_data().unwrap(); assert!(mdata.heap_spec().is_some()); // clang creates 3 globals: @@ -74,7 +74,7 @@ mod lucetc_tests { let m = module_from_c(&["c"], &["c"]).expect("build module for c"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile c"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile c"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 0, "import functions"); assert_eq!(mdata.export_functions().len(), 1, "export functions"); @@ -91,7 +91,7 @@ mod lucetc_tests { let m = module_from_c(&["d"], &["d"]).expect("build module for d"); let b = d_only_test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile d"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile d"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 1, "import functions"); assert_eq!(mdata.export_functions().len(), 1, "export functions"); @@ -107,7 +107,7 @@ mod lucetc_tests { let m = module_from_c(&["c", "d"], &["c", "d"]).expect("build module for c & d"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile c & d"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile c & d"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 0, "import functions"); assert_eq!(mdata.export_functions().len(), 2, "export functions"); diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index 491a8d00e..b3c1738d6 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -27,7 +27,7 @@ cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.37.0" cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.37.0" } target-lexicon = "0.4.0" lucet-module = { path = "../lucet-module", version = "0.1.1" } -wasmparser = "0.23" +wasmparser = "0.32.1" clap="2.32" log = "0.4" env_logger = "0.6" @@ -42,3 +42,4 @@ bimap = "0.2" human-size = "0.4" parity-wasm = "0.38" minisign = "0.5.11" +memoffset = "0.5.1" diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index 5a1d9afa1..954cc3a12 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -48,6 +48,7 @@ pub struct Compiler<'a> { decls: ModuleDecls<'a>, clif_module: ClifModule, opt_level: OptLevel, + count_instructions: bool, } impl<'a> Compiler<'a> { @@ -56,6 +57,7 @@ impl<'a> Compiler<'a> { opt_level: OptLevel, bindings: &'a Bindings, heap_settings: HeapSettings, + count_instructions: bool, ) -> Result { let isa = Self::target_isa(opt_level); @@ -106,6 +108,7 @@ impl<'a> Compiler<'a> { decls, clif_module, opt_level, + count_instructions, }) } @@ -117,7 +120,7 @@ impl<'a> Compiler<'a> { let mut func_translator = FuncTranslator::new(); for (ref func, (code, code_offset)) in self.decls.function_bodies() { - let mut func_info = FuncInfo::new(&self.decls); + let mut func_info = FuncInfo::new(&self.decls, self.count_instructions); let mut clif_context = ClifContext::new(); clif_context.func.name = func.name.as_externalname(); clif_context.func.signature = func.signature.clone(); @@ -172,7 +175,7 @@ impl<'a> Compiler<'a> { let mut func_translator = FuncTranslator::new(); for (ref func, (code, code_offset)) in self.decls.function_bodies() { - let mut func_info = FuncInfo::new(&self.decls); + let mut func_info = FuncInfo::new(&self.decls, self.count_instructions); let mut clif_context = ClifContext::new(); clif_context.func.name = func.name.as_externalname(); clif_context.func.signature = func.signature.clone(); diff --git a/lucetc/src/function.rs b/lucetc/src/function.rs index 933e64ac8..a260f306a 100644 --- a/lucetc/src/function.rs +++ b/lucetc/src/function.rs @@ -6,27 +6,31 @@ use cranelift_codegen::cursor::FuncCursor; use cranelift_codegen::entity::EntityRef; use cranelift_codegen::ir::{self, InstBuilder}; use cranelift_codegen::isa::TargetFrontendConfig; +use cranelift_frontend::FunctionBuilder; use cranelift_wasm::{ FuncEnvironment, FuncIndex, GlobalIndex, GlobalVariable, MemoryIndex, SignatureIndex, - TableIndex, WasmError, WasmResult, + TableIndex, VisibleTranslationState, WasmError, WasmResult, }; +use lucet_module::InstanceRuntimeData; +use memoffset::offset_of; use std::collections::HashMap; - -// VMContext points directly to the heap (offset 0). -// Directly before the heao is a pointer to the globals (offset -NATIVE_POINTER_SIZE). -const GLOBAL_BASE_OFFSET: i32 = -1 * NATIVE_POINTER_SIZE as i32; +use wasmparser::Operator; pub struct FuncInfo<'a> { module_decls: &'a ModuleDecls<'a>, + count_instructions: bool, + scope_costs: Vec, vmctx_value: Option, global_base_value: Option, runtime_funcs: HashMap, } impl<'a> FuncInfo<'a> { - pub fn new(module_decls: &'a ModuleDecls<'a>) -> Self { + pub fn new(module_decls: &'a ModuleDecls<'a>, count_instructions: bool) -> Self { Self { module_decls, + count_instructions, + scope_costs: vec![0], vmctx_value: None, global_base_value: None, runtime_funcs: HashMap::new(), @@ -46,7 +50,9 @@ impl<'a> FuncInfo<'a> { let vmctx = self.get_vmctx(func); let global_base_value = func.create_global_value(ir::GlobalValueData::Load { base: vmctx, - offset: GLOBAL_BASE_OFFSET.into(), + offset: (-(std::mem::size_of::() as i32) + + (offset_of!(InstanceRuntimeData, globals_ptr) as i32)) + .into(), global_type: ir::types::I64, readonly: false, }); @@ -78,6 +84,185 @@ impl<'a> FuncInfo<'a> { fref }) } + + fn update_instruction_count_instrumentation( + &mut self, + op: &Operator, + builder: &mut FunctionBuilder, + reachable: bool, + ) -> WasmResult<()> { + // So the operation counting works like this: + // record a stack corresponding with the stack of control flow in the wasm function. + // for non-control-flow-affecting instructions, increment the top of the stack. + // for control-flow-affecting operations (If, Else, Unreachable, Call, End, Return, Block, + // Loop, BrIf, CallIndirect), update the wasm instruction counter and: + // * if the operation introduces a new scope (If, Block, Loop), push a new 0 on the + // stack corresponding with that frame. + // * if the operation does not introduce a new scope (Else, Call, CallIndirect, BrIf), + // reset the top of stack to 0 + // * if the operation completes a scope (End), pop the top of the stack and reset the new + // top of stack to 0 + // * this leaves no special behavior for Unreachable and Return. This is acceptable as they + // are always followed by an End and are either about to trap, or return from a function. + // * Unreachable is either the end of VM execution and we are off by one instruction, or, + // is about to dispatch to an exception handler, which we should account for out of band + // anyway (exception dispatch is much more expensive than a single wasm op) + // * Return corresponds to exactly one function call, so we can count it by resetting the + // stack to 1 at return of a function. + + fn flush_counter(environ: &mut FuncInfo, builder: &mut FunctionBuilder) { + if environ.scope_costs.last() == Some(&0) { + return; + } + let instr_count_offset: ir::immediates::Offset32 = + (-(std::mem::size_of::() as i32) + + offset_of!(InstanceRuntimeData, instruction_count) as i32) + .into(); + let vmctx_gv = environ.get_vmctx(builder.func); + let addr = builder.ins().global_value(environ.pointer_type(), vmctx_gv); + let trusted_mem = ir::MemFlags::trusted(); + + // Now insert a sequence of clif that is, functionally: + // + // let instruction_count_ptr: &mut u64 = vmctx.instruction_count; + // let mut instruction_count: u64 = *instruction_count_ptr; + // instruction_count += ; + // *instruction_count_ptr = instruction_count; + + let cur_instr_count = + builder + .ins() + .load(ir::types::I64, trusted_mem, addr, instr_count_offset); + let update_const = builder.ins().iconst( + ir::types::I64, + i64::from(*environ.scope_costs.last().unwrap()), + ); + let new_instr_count = builder.ins().iadd(cur_instr_count, update_const.into()); + builder + .ins() + .store(trusted_mem, new_instr_count, addr, instr_count_offset); + + *environ.scope_costs.last_mut().unwrap() = 0; + }; + + // Only update or flush the counter when the scope is not sealed. + // + // Cranelift dutifully translates the entire wasm body, including dead code, and we can try + // to insert instrumentation for dead code, but Cranelift seals blocks at operations that + // involve control flow away from the current block. So we have to track when operations + // are unreachable and not instrument them, lest we cause a Cranelift panic trying to + // modify sealed basic blocks. + if reachable { + // Update the instruction counter, if necessary + let op_cost = match op { + // Opening a scope is a syntactic operation, and free. + Operator::Block { .. } | + // These do not add counts, see above comment about return/unreachable + Operator::Unreachable | + Operator::Return => 0, + // Call is quick + Operator::Call { .. } => 1, + // but indirect calls take some extra work to validate at runtime + Operator::CallIndirect { .. } => 2, + // Testing for an if involve some overhead, for now say it's also 1 + Operator::If { .. } => 1, + // Else is a fallthrough or alternate case for something that's been tested as `if`, so + // it's already counted + Operator::Else => 0, + // Entering a loop is a syntactic operation, and free. + Operator::Loop { .. } => 0, + // Closing a scope is a syntactic operation, and free. + Operator::End => 0, + // Taking a branch is an operation + Operator::Br { .. } => 1, + // brif might be two operations? + Operator::BrIf { .. } => 1, + // brtable is kind of cpu intensive compared to other wasm ops + Operator::BrTable { .. } => 2, + // nop and drop are free + Operator::Nop | + Operator::Drop => 0, + // everything else, just call it one operation. + _ => 1, + }; + self.scope_costs.last_mut().map(|x| *x += op_cost); + + // apply flushing behavior if applicable + match op { + Operator::Unreachable + | Operator::Return + | Operator::CallIndirect { .. } + | Operator::Call { .. } + | Operator::Block { .. } + | Operator::Loop { .. } + | Operator::If { .. } + | Operator::Else + | Operator::Br { .. } + | Operator::BrIf { .. } + | Operator::BrTable { .. } => { + flush_counter(self, builder); + } + Operator::End => { + // We have to be really careful here to avoid violating a cranelift invariant: + // if the next operation is `End` as well, this end will have marked the block + // finished, and attempting to add instructions to update the instruction counter + // will cause a panic. + // + // The only situation where this can occur is if the last structure in a scope is a + // subscope (the body of a Loop, If, or Else), so we flush the counter entering + // those structures, and guarantee the `End` for their enclosing scope will have a + // counter value of 0. In other cases, we're not at risk of closing a scope leading + // to closing another scope, and it's safe to flush the counter. + // + // An example to help: + // ``` + // block + // i32.const 4 ; counter += 1 + // i32.const -5 ; counter += 1 + // i32.add ; counter += 1 + // block ; flush counter (counter = 3 -> 0), flush here to avoid having + // ; accumulated count at the + // ; final `end` + // i32.const 4 ; counter += 1 + // i32.add ; counter += 1 + // end ; flush counter (counter = 2 -> 0) + // end ; flush counter (counter = 0 -> 0) and is a no-op + // ``` + flush_counter(self, builder); + } + _ => { /* regular operation, do nothing */ } + } + } else { + // just a consistency check - the counter must be 0 when exiting a region of + // unreachable code. If this assertion fails it means we either counted instructions + // we shouldn't (because they're unreachable), or we didn't flush the counter before + // starting to also instrument unreachable instructions (and would have tried to + // overcount) + assert_eq!(*self.scope_costs.last().unwrap(), 0); + } + + // finally, we might have to set up a new counter for a new scope, or fix up counts a bit. + // + // Note that nothing is required for `Else`, because it will have been preceded by an `End` + // to close the "then" arm of its enclosing `If`, so the counter will have already been + // flushed and reset to 0. + match op { + Operator::CallIndirect { .. } | Operator::Call { .. } => { + // add 1 to count the return from the called function + self.scope_costs.last_mut().map(|x| *x = 1); + } + Operator::Block { .. } | Operator::Loop { .. } | Operator::If { .. } => { + // opening a scope, which starts having executed zero wasm ops + self.scope_costs.push(0); + } + Operator::End => { + // close the top scope + self.scope_costs.pop(); + } + _ => {} + } + Ok(()) + } } impl<'a> FuncEnvironment for FuncInfo<'a> { @@ -302,4 +487,16 @@ impl<'a> FuncEnvironment for FuncInfo<'a> { let inst = pos.ins().call(mem_size_func, &[vmctx]); Ok(*pos.func.dfg.inst_results(inst).first().unwrap()) } + + fn before_translate_operator( + &mut self, + op: &Operator, + builder: &mut FunctionBuilder, + state: &VisibleTranslationState, + ) -> WasmResult<()> { + if self.count_instructions { + self.update_instruction_count_instrumentation(op, builder, state.reachable())?; + } + Ok(()) + } } diff --git a/lucetc/src/lib.rs b/lucetc/src/lib.rs index 5c7830b84..d11a095a2 100644 --- a/lucetc/src/lib.rs +++ b/lucetc/src/lib.rs @@ -50,6 +50,7 @@ pub struct Lucetc { pk: Option, sign: bool, verify: bool, + count_instructions: bool, } pub trait AsLucetc { @@ -98,6 +99,8 @@ pub trait LucetcOpts { fn with_verify(self) -> Self; fn sign(&mut self); fn with_sign(self) -> Self; + fn count_instructions(&mut self, enable_count: bool); + fn with_count_instructions(self, enable_count: bool) -> Self; } impl LucetcOpts for T { @@ -202,6 +205,15 @@ impl LucetcOpts for T { self.sign(); self } + + fn count_instructions(&mut self, count_instructions: bool) { + self.as_lucetc().count_instructions = count_instructions; + } + + fn with_count_instructions(mut self, count_instructions: bool) -> Self { + self.count_instructions(count_instructions); + self + } } impl Lucetc { @@ -217,6 +229,7 @@ impl Lucetc { sk: None, sign: false, verify: false, + count_instructions: false, } } @@ -232,6 +245,7 @@ impl Lucetc { sk: None, sign: false, verify: false, + count_instructions: false, }) } @@ -271,6 +285,7 @@ impl Lucetc { self.opt_level, &bindings, self.heap.clone(), + self.count_instructions, )?; let obj = compiler.object_file()?; @@ -286,6 +301,7 @@ impl Lucetc { self.opt_level, &bindings, self.heap.clone(), + self.count_instructions, )?; compiler diff --git a/lucetc/src/main.rs b/lucetc/src/main.rs index 14b064f3b..d1b89cbd1 100644 --- a/lucetc/src/main.rs +++ b/lucetc/src/main.rs @@ -91,6 +91,10 @@ pub fn run(opts: &Options) -> Result<(), Error> { c.sign(); } + if opts.count_instructions { + c.count_instructions(true); + } + match opts.codegen { CodegenOutput::Obj => c.object_file(&opts.output)?, CodegenOutput::SharedObj => c.shared_object_file(&opts.output)?, diff --git a/lucetc/src/options.rs b/lucetc/src/options.rs index 8e3c42a6c..e9fad6433 100644 --- a/lucetc/src/options.rs +++ b/lucetc/src/options.rs @@ -46,6 +46,7 @@ pub struct Options { pub verify: bool, pub pk_path: Option, pub sk_path: Option, + pub count_instructions: bool, } impl Options { @@ -111,6 +112,7 @@ impl Options { let verify = m.is_present("verify"); let sk_path = m.value_of("sk_path").map(PathBuf::from); let pk_path = m.value_of("pk_path").map(PathBuf::from); + let count_instructions = m.is_present("count_instructions"); Ok(Options { output, @@ -128,6 +130,7 @@ impl Options { verify, sk_path, pk_path, + count_instructions, }) } pub fn get() -> Result { @@ -244,6 +247,12 @@ impl Options { .takes_value(true) .help("Path to the secret key to sign the object file. The file can be prefixed with \"raw:\" in order to store a raw, unencrypted secret key") ) + .arg( + Arg::with_name("count_instructions") + .long("--count-instructions") + .takes_value(false) + .help("Instrument the produced binary to count the number of wasm operations the translated program executes") + ) .get_matches(); Self::from_args(&m) diff --git a/lucetc/tests/wasm.rs b/lucetc/tests/wasm.rs index 7ca2d65f1..46e820edc 100644 --- a/lucetc/tests/wasm.rs +++ b/lucetc/tests/wasm.rs @@ -42,7 +42,7 @@ mod module_data { let m = load_wat_module("exported_import"); let b = super::test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compiling exported_import"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compiling exported_import"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.globals_spec().len(), 0); @@ -61,7 +61,7 @@ mod module_data { let m = load_wat_module("multiple_import"); let b = super::test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compiling multiple_import"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compiling multiple_import"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.globals_spec().len(), 0); @@ -76,7 +76,7 @@ mod module_data { let m = load_wat_module("globals_export"); let b = super::test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compiling globals_export"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compiling globals_export"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.globals_spec().len(), 1); @@ -92,7 +92,7 @@ mod module_data { let m = load_wat_module("fibonacci"); let b = super::test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compiling fibonacci"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compiling fibonacci"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.globals_spec().len(), 0); @@ -106,7 +106,7 @@ mod module_data { let m = load_wat_module("arith"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compiling arith"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compiling arith"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.globals_spec().len(), 0); @@ -123,7 +123,7 @@ mod module_data { )) .unwrap(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile duplicate_imports"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile duplicate_imports"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 2); @@ -149,7 +149,7 @@ mod module_data { )) .unwrap(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile icall"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile icall"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 1); @@ -185,7 +185,7 @@ mod module_data { let m = load_wat_module("icall"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile icall"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile icall"); let _module_data = c.module_data().unwrap(); /* TODO can't express these with module data @@ -210,7 +210,7 @@ mod module_data { let m = load_wat_module("icall_sparse"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile icall_sparse"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile icall_sparse"); let _module_data = c.module_data().unwrap(); /* TODO can't express these with module data @@ -249,7 +249,7 @@ mod module_data { let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile globals_import"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile globals_import"); let module_data = c.module_data().unwrap(); let gspec = module_data.globals_spec(); @@ -270,8 +270,8 @@ mod module_data { let m = load_wat_module("heap_spec_import"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = - Compiler::new(&m, OptLevel::Fast, &b, h.clone()).expect("compiling heap_spec_import"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h.clone(), false) + .expect("compiling heap_spec_import"); assert_eq!( c.module_data().unwrap().heap_spec(), @@ -293,7 +293,7 @@ mod module_data { let m = load_wat_module("heap_spec_definition"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h.clone()) + let c = Compiler::new(&m, OptLevel::Fast, &b, h.clone(), false) .expect("compiling heap_spec_definition"); assert_eq!( @@ -315,7 +315,7 @@ mod module_data { let m = load_wat_module("heap_spec_none"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compiling heap_spec_none"); + let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compiling heap_spec_none"); assert_eq!(c.module_data().unwrap().heap_spec(), None,); } @@ -324,7 +324,7 @@ mod module_data { let m = load_wat_module("oversize_data_segment"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h); + let c = Compiler::new(&m, OptLevel::Fast, &b, h, false); assert!( c.is_err(), "compilation error because data initializers are oversized" @@ -347,7 +347,7 @@ mod module_data { let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h); + let c = Compiler::new(&m, OptLevel::Fast, &b, h, false); assert!( c.is_err(), "compilation error because wasm module is invalid" @@ -360,7 +360,7 @@ mod module_data { let m = load_wat_module("start_section"); let b = Bindings::empty(); let h = HeapSettings::default(); - let _c = Compiler::new(&m, OptLevel::Fast, &b, h).expect("compile start_section"); + let _c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile start_section"); /* assert!( p.module().start_section().is_some(), @@ -378,7 +378,8 @@ mod compile { let m = load_wat_module(file); let b = super::test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h).expect(&format!("compile {}", file)); + let c = + Compiler::new(&m, OptLevel::Fast, &b, h, false).expect(&format!("compile {}", file)); let _obj = c.object_file().expect(&format!("codegen {}", file)); } macro_rules! compile_test { From 56970cbfac79d699ab9bce0cfd7863d5bd078386 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Sun, 4 Aug 2019 11:42:49 -0700 Subject: [PATCH 283/512] [lucet-runtime] make State variants more explicit and document them This applies the distributive property on the states involved in termination and yielding, so that they no longer rely on having optional types with invariants we maintain manually. This also moves the definition of `State` into its own module, along with docs explaining which states can transition to other states. At first, I tried adding a state transition function that would encode transition validity in executable form, but adding the overhead of a function call turned out to be too much for an operation that needs to be able to happen within a signal handler. Specifically, the compiler was asking for a 77KiB stack probe upon entry to the transition function, which was blowing both guest stacks and signal stacks. I suspect something was up with the closure argument that was needed to let state transitions move values from previous states. --- .../lucet-runtime-internals/src/instance.rs | 196 ++++-------------- .../src/instance/signals.rs | 6 +- .../src/instance/state.rs | 178 ++++++++++++++++ .../lucet-runtime-internals/src/vmctx.rs | 12 +- 4 files changed, 224 insertions(+), 168 deletions(-) create mode 100644 lucet-runtime/lucet-runtime-internals/src/instance/state.rs diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index 74965df05..5f72fd137 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -1,23 +1,22 @@ mod siginfo_ext; pub mod signals; +pub mod state; pub use crate::instance::signals::{signal_handler_none, SignalBehavior, SignalHandler}; +pub use crate::instance::state::State; use crate::alloc::{Alloc, HOST_PAGE_SIZE_EXPECTED}; use crate::context::Context; use crate::embed_ctx::CtxMap; use crate::error::Error; -use crate::instance::siginfo_ext::SiginfoExt; use crate::module::{self, FunctionHandle, FunctionPointer, Global, GlobalValue, Module, TrapCode}; use crate::region::RegionInternal; -use crate::sysdeps::UContext; use crate::val::{UntypedRetVal, Val}; use crate::WASM_PAGE_SIZE; -use libc::{c_void, siginfo_t, uintptr_t, SIGBUS, SIGSEGV}; +use libc::{c_void, siginfo_t, uintptr_t}; use memoffset::offset_of; use std::any::Any; use std::cell::{BorrowError, BorrowMutError, Ref, RefCell, RefMut, UnsafeCell}; -use std::ffi::{CStr, CString}; use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut}; @@ -472,9 +471,9 @@ impl Instance { /// applies. pub fn resume_with_val(&mut self, val: A) -> Result { match &self.state { - State::Yielded { expected, .. } => { + State::Yielded { expecting, .. } => { // make sure the resumed value is of the right type - if !expected.is::>() { + if !expecting.is::>() { return Err(Error::InvalidArgument( "type mismatch between yielded instance expected value and resumed value", )); @@ -517,9 +516,7 @@ impl Instance { }; } - self.state = State::Ready { - retval: UntypedRetVal::default(), - }; + self.state = State::Ready; self.run_start()?; @@ -669,9 +666,7 @@ impl Instance { embed_ctx: embed_ctx, module, ctx: Context::new(), - state: State::Ready { - retval: UntypedRetVal::default(), - }, + state: State::Ready, alloc, fatal_handler: default_fatal_handler, c_fatal_handler: None, @@ -800,32 +795,34 @@ impl Instance { // Sandbox has jumped back to the host process, indicating it has either: // - // * returned: state should be `Running`; transition to Ready and return a RunResult - // * yielded: state should be `Yielded`; take the yielded value and return a RunResult - // * trapped: state should be `Fault`; populate details and return an error or call a hanlder as appropriate - // * terminated: state should be `Terminated`; take the termination details and return as an Err - // * function body returned: set state back to `Ready` with return value + // * returned: state should be `Running`; transition to `Ready` and return a RunResult + // * yielded: state should be `Yielding`; transition to `Yielded` and return a RunResult + // * trapped: state should be `Faulted`; populate details and return an error or call a handler as appropriate + // * terminated: state should be `Terminating`; transition to `Terminated` and return the termination details as an Err // - // The state should never be `Ready` at this point + // The state should never be `Ready`, `Terminated`, `Yielded`, or `Transitioning` at this point + + // Set transitioning state temporarily so that we can move values out of the current state + let st = mem::replace(&mut self.state, State::Transitioning); - match &mut self.state { + match st { State::Running => { let retval = self.ctx.get_untyped_retval(); - self.state = State::Ready { retval }; + self.state = State::Ready; Ok(RunResult::Returned(retval)) } - State::Terminated { details, .. } => { - Err(Error::RuntimeTerminated(details.take().ok_or_else( - || lucet_format_err!("terminated state contained no details"), - )?)) + State::Terminating { details, .. } => { + self.state = State::Terminated; + Err(Error::RuntimeTerminated(details)) } - State::Yielded { val, .. } => { - Ok(RunResult::Yielded(val.take().ok_or_else(|| { - lucet_format_err!("yielded state contained no value") - })?)) + State::Yielding { val, expecting } => { + self.state = State::Yielded { expecting }; + Ok(RunResult::Yielded(val)) } - State::Fault { - ref mut details, .. + State::Faulted { + mut details, + siginfo, + context, } => { // Sandbox is no longer runnable. It's unsafe to determine all error details in the signal // handler, so we fill in extra details here. @@ -836,6 +833,13 @@ impl Instance { .module .addr_details(details.rip_addr as *const c_void)?; + // fill the state back in with the updated details in case fatal handlers need it + self.state = State::Faulted { + details: details.clone(), + siginfo, + context, + }; + if details.fatal { // Some errors indicate that the guest is not functioning correctly or that // the loaded code violated some assumption, so bail out via the fatal @@ -851,12 +855,12 @@ impl Instance { } else { // leave the full fault details in the instance state, and return the // higher-level info to the user - Err(Error::RuntimeFault(details.clone())) + Err(Error::RuntimeFault(details)) } } - State::Ready { .. } => { - panic!("instance in Ready state after returning from guest context") - } + State::Ready | State::Terminated | State::Yielded { .. } | State::Transitioning => Err( + lucet_format_err!("\"impossible\" state found in `swap_and_return()`: {}", st), + ), } } @@ -871,31 +875,6 @@ impl Instance { } } -pub enum State { - Ready { - retval: UntypedRetVal, - }, - Running, - Fault { - details: FaultDetails, - siginfo: libc::siginfo_t, - context: UContext, - }, - Terminated { - /// This is always expected to be a `Some` when a terminating instance context switches back - /// to the host, but is `take`n to popuate the resulting `Error`. - details: Option, - }, - Yielded { - /// This is always expected to be a `Some` when a yielding instance context switches back to - /// the host, but is `take`n to popuate the `RunResult`. - val: Option, - /// Concretely, this should only ever be `Box>` where `R` is the type - /// the guest expects upon resumption. - expected: Box, - }, -} - /// Information about a runtime fault. /// /// Runtime faults are raised implictly by signal handlers that return `SignalBehavior::Default` in @@ -1080,105 +1059,6 @@ impl YieldedVal { #[derive(Debug)] pub(crate) struct EmptyYieldVal; -impl std::fmt::Display for State { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - State::Ready { .. } => write!(f, "ready"), - State::Running => write!(f, "running"), - State::Fault { - details, siginfo, .. - } => { - write!(f, "{}", details)?; - write!( - f, - " triggered by {}: ", - strsignal_wrapper(siginfo.si_signo) - .into_string() - .expect("strsignal returns valid UTF-8") - )?; - - if siginfo.si_signo == SIGSEGV || siginfo.si_signo == SIGBUS { - // We know this is inside the heap guard, because by the time we get here, - // `lucet_error_verify_trap_safety` will have run and validated it. - write!( - f, - " accessed memory at {:p} (inside heap guard)", - siginfo.si_addr_ext() - )?; - } - Ok(()) - } - State::Terminated { .. } => write!(f, "terminated"), - State::Yielded { .. } => write!(f, "yielded"), - } - } -} - -impl State { - pub fn is_ready(&self) -> bool { - if let State::Ready { .. } = self { - true - } else { - false - } - } - - pub fn is_running(&self) -> bool { - if let State::Running = self { - true - } else { - false - } - } - - pub fn is_fault(&self) -> bool { - if let State::Fault { .. } = self { - true - } else { - false - } - } - - pub fn is_fatal(&self) -> bool { - if let State::Fault { - details: FaultDetails { fatal, .. }, - .. - } = self - { - *fatal - } else { - false - } - } - - pub fn is_terminated(&self) -> bool { - if let State::Terminated { .. } = self { - true - } else { - false - } - } - - pub fn is_yielded(&self) -> bool { - if let State::Yielded { .. } = self { - true - } else { - false - } - } -} - fn default_fatal_handler(inst: &Instance) -> ! { panic!("> instance {:p} had fatal error: {}", inst, inst.state); } - -// TODO: PR into `libc` -extern "C" { - #[no_mangle] - fn strsignal(sig: libc::c_int) -> *mut libc::c_char; -} - -// TODO: PR into `nix` -fn strsignal_wrapper(sig: libc::c_int) -> CString { - unsafe { CStr::from_ptr(strsignal(sig)).to_owned() } -} diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs index 41a2f9853..72a0fa4fe 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs @@ -174,8 +174,8 @@ extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext } SignalBehavior::Terminate => { // set the state before jumping back to the host context - inst.state = State::Terminated { - details: Some(TerminationDetails::Signal), + inst.state = State::Terminating { + details: TerminationDetails::Signal, }; true } @@ -193,7 +193,7 @@ extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext && !inst.alloc.addr_in_heap_guard(siginfo.si_addr_ext()); // record the fault and jump back to the host context - inst.state = State::Fault { + inst.state = State::Faulted { details: FaultDetails { fatal: unknown_fault || outside_guard, trapcode: trapcode, diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/state.rs b/lucet-runtime/lucet-runtime-internals/src/instance/state.rs new file mode 100644 index 000000000..1be034667 --- /dev/null +++ b/lucet-runtime/lucet-runtime-internals/src/instance/state.rs @@ -0,0 +1,178 @@ +use crate::instance::siginfo_ext::SiginfoExt; +use crate::instance::{FaultDetails, TerminationDetails, YieldedVal}; +use crate::sysdeps::UContext; +use libc::{SIGBUS, SIGSEGV}; +use std::any::Any; +use std::ffi::{CStr, CString}; + +/// The representation of a Lucet instance's state machine. +pub enum State { + /// The instance is ready to run. + /// + /// Transitions to `Running` when the instance is run, or to `Ready` when it's reset. + Ready, + + /// The instance is running. + /// + /// Transitions to `Ready` when the guest function returns normally, or to `Faulted`, + /// `Terminating`, or `Yielding` if the instance faults, terminates, or yields. + Running, + + /// The instance has faulted, potentially fatally. + /// + /// Transitions to `Faulted` when filling in additional fault details, to `Running` if + /// re-running a non-fatally faulted instance, or to `Ready` when the instance is reset. + Faulted { + details: FaultDetails, + siginfo: libc::siginfo_t, + context: UContext, + }, + + /// The instance is in the process of terminating. + /// + /// Transitions only to `Terminated`; the `TerminationDetails` are always extracted into a + /// `RunResult` before anything else happens to the instance. + Terminating { details: TerminationDetails }, + + /// The instance has terminated, and must be reset before running again. + /// + /// Transitions to `Ready` if the instance is reset. + Terminated, + + /// The instance is in the process of yielding. + /// + /// Transitions only to `Yielded`; the `YieldedVal` is always extracted into a + /// `RunResult` before anything else happens to the instance. + Yielding { + val: YieldedVal, + /// A phantom value carrying the type of the expected resumption value. + /// + /// Concretely, this should only ever be `Box>` where `R` is the type + /// the guest expects upon resumption. + expecting: Box, + }, + + /// The instance has yielded. + /// + /// Transitions to `Running` if the instance is resumed, or to `Ready` if the instance is reset. + Yielded { + /// A phantom value carrying the type of the expected resumption value. + /// + /// Concretely, this should only ever be `Box>` where `R` is the type + /// the guest expects upon resumption. + expecting: Box, + }, + + /// A placeholder state used with `std::mem::replace()` when a new state must be constructed by + /// moving values out of an old state. + /// + /// This is used so that we do not need a `Clone` impl for this type, which would add + /// unnecessary constraints to the types of values instances could yield or terminate with. + /// + /// It is an error for this state to appear outside of a transition between other states. + Transitioning, +} + +impl std::fmt::Display for State { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + State::Ready => write!(f, "ready"), + State::Running => write!(f, "running"), + State::Faulted { + details, siginfo, .. + } => { + write!(f, "{}", details)?; + write!( + f, + " triggered by {}: ", + strsignal_wrapper(siginfo.si_signo) + .into_string() + .expect("strsignal returns valid UTF-8") + )?; + + if siginfo.si_signo == SIGSEGV || siginfo.si_signo == SIGBUS { + // We know this is inside the heap guard, because by the time we get here, + // `lucet_error_verify_trap_safety` will have run and validated it. + write!( + f, + " accessed memory at {:p} (inside heap guard)", + siginfo.si_addr_ext() + )?; + } + Ok(()) + } + State::Terminated { .. } => write!(f, "terminated"), + State::Terminating { .. } => write!(f, "terminating"), + State::Yielding { .. } => write!(f, "yielding"), + State::Yielded { .. } => write!(f, "yielded"), + State::Transitioning { .. } => { + write!(f, "transitioning (IF YOU SEE THIS, THERE'S PROBABLY A BUG)") + } + } + } +} + +impl State { + pub fn is_ready(&self) -> bool { + if let State::Ready { .. } = self { + true + } else { + false + } + } + + pub fn is_running(&self) -> bool { + if let State::Running = self { + true + } else { + false + } + } + + pub fn is_fault(&self) -> bool { + if let State::Faulted { .. } = self { + true + } else { + false + } + } + + pub fn is_fatal(&self) -> bool { + if let State::Faulted { + details: FaultDetails { fatal, .. }, + .. + } = self + { + *fatal + } else { + false + } + } + + pub fn is_terminated(&self) -> bool { + if let State::Terminated { .. } = self { + true + } else { + false + } + } + + pub fn is_yielded(&self) -> bool { + if let State::Yielded { .. } = self { + true + } else { + false + } + } +} + +// TODO: PR into `libc` +extern "C" { + #[no_mangle] + fn strsignal(sig: libc::c_int) -> *mut libc::c_char; +} + +// TODO: PR into `nix` +fn strsignal_wrapper(sig: libc::c_int) -> CString { + unsafe { CStr::from_ptr(strsignal(sig)).to_owned() } +} diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index 40c489849..61897a38e 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -358,10 +358,10 @@ impl Vmctx { fn yield_impl(&self, val: A) { let inst = unsafe { self.instance_mut() }; - let expected: Box> = Box::new(PhantomData); - inst.state = State::Yielded { - val: Some(YieldedVal::new(val)), - expected: expected as Box, + let expecting: Box> = Box::new(PhantomData); + inst.state = State::Yielding { + val: YieldedVal::new(val), + expecting: expecting as Box, }; HOST_CTX.with(|host_ctx| unsafe { Context::swap(&mut inst.ctx, &mut *host_ctx.get()) }); } @@ -412,9 +412,7 @@ impl Instance { /// This is almost certainly not what you want to use to terminate from a hostcall; use panics /// with `TerminationDetails` instead. unsafe fn terminate(&mut self, details: TerminationDetails) -> ! { - self.state = State::Terminated { - details: Some(details), - }; + self.state = State::Terminating { details }; #[allow(unused_unsafe)] // The following unsafe will be incorrectly warned as unused HOST_CTX.with(|host_ctx| unsafe { Context::set(&*host_ctx.get()) }) } From 6544ed77ecb99ba082d5fb42002351f8a8443774 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 5 Aug 2019 12:15:23 -0700 Subject: [PATCH 284/512] upgrade wasi-sdk to 6.0, which uses llvm 8.0.1 --- Dockerfile | 4 ++-- lucet-wasi-sdk/src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 069707fe6..e44be13fb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,8 +37,8 @@ RUN rustup target add wasm32-wasi RUN cargo install cargo-audit cargo-watch rsign2 -RUN curl -sS -L -O https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-5/wasi-sdk_5.0_amd64.deb \ - && dpkg -i wasi-sdk_5.0_amd64.deb && rm -f wasi-sdk_5.0_amd64.deb +RUN curl -sS -L -O https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-6/wasi-sdk_6.0_amd64.deb \ + && dpkg -i wasi-sdk_6.0_amd64.deb && rm -f wasi-sdk_6.0_amd64.deb ENV WASI_SDK=/opt/wasi-sdk diff --git a/lucet-wasi-sdk/src/lib.rs b/lucet-wasi-sdk/src/lib.rs index 6939a88dd..612e43bd7 100644 --- a/lucet-wasi-sdk/src/lib.rs +++ b/lucet-wasi-sdk/src/lib.rs @@ -60,7 +60,7 @@ fn wasi_sysroot() -> PathBuf { Err(_) => { let mut path = wasi_sdk(); path.push("share"); - path.push("sysroot"); + path.push("wasi-sysroot"); path } } From 4bd84e4f5c54187da217702e4fd77a7280cfbe26 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 7 Aug 2019 10:35:13 -0700 Subject: [PATCH 285/512] wasi-sdk 6.0: update other references package version updated in Dockerfile.toolchain path to sysroot updated in devenv_build_toolchain_only.sh, helpers/install.sh, lucet-wasi/build.rs --- Dockerfile.toolchain | 2 +- devenv_build_toolchain_only.sh | 2 +- helpers/install.sh | 2 +- lucet-wasi/build.rs | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Dockerfile.toolchain b/Dockerfile.toolchain index a034d5b69..0ce351908 100644 --- a/Dockerfile.toolchain +++ b/Dockerfile.toolchain @@ -10,5 +10,5 @@ RUN apt-get update && \ rm -rf /var/lib/apt/lists/* && \ update-alternatives --install /usr/bin/wasm-ld wasm-ld /usr/bin/wasm-ld-8 100 -RUN curl -sL https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-5/libclang_rt.builtins-wasm32-wasi-5.0.tar.gz | tar x -zf - -C /usr/lib/llvm-8/lib/clang/8.0.0 +RUN curl -sL https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-6/libclang_rt.builtins-wasm32-wasi-6.0.tar.gz | tar x -zf - -C /usr/lib/llvm-8/lib/clang/8.0.0 diff --git a/devenv_build_toolchain_only.sh b/devenv_build_toolchain_only.sh index 516075409..42439f231 100755 --- a/devenv_build_toolchain_only.sh +++ b/devenv_build_toolchain_only.sh @@ -28,7 +28,7 @@ docker exec lucet tar c -pf - -C /opt lucet | docker exec lucet-toolchain mkdir /opt/wasi-sysroot -docker exec lucet tar c -pf - -C /opt/wasi-sdk/share/sysroot . | +docker exec lucet tar c -pf - -C /opt/wasi-sdk/share/wasi-sysroot . | docker exec -i lucet-toolchain tar x -pf - -C /opt/wasi-sysroot docker exec lucet-toolchain sh -c 'rm -f /opt/lucet/bin/wasm32-*' diff --git a/helpers/install.sh b/helpers/install.sh index 25ef61d0e..9fc6ca840 100755 --- a/helpers/install.sh +++ b/helpers/install.sh @@ -70,7 +70,7 @@ if ! install -d "$LUCET_PREFIX" 2>/dev/null; then fi # Find a WASI sysroot -for wasi_sysroot in $WASI_SYSROOT ${WASI_SDK_PREFIX}/share/sysroot /opt/wasi-sysroot; do +for wasi_sysroot in $WASI_SYSROOT ${WASI_SDK_PREFIX}/share/wasi-sysroot /opt/wasi-sysroot; do if [ -e "${wasi_sysroot}/include/wasi/core.h" ]; then WASI_SYSROOT="$wasi_sysroot" fi diff --git a/lucet-wasi/build.rs b/lucet-wasi/build.rs index d880ca37f..068e214fa 100644 --- a/lucet-wasi/build.rs +++ b/lucet-wasi/build.rs @@ -15,7 +15,7 @@ fn wasi_sysroot() -> PathBuf { Err(_) => { let mut path = wasi_sdk(); path.push("share"); - path.push("sysroot"); + path.push("wasi-sysroot"); path } } @@ -28,7 +28,7 @@ fn wasm_clang_root() -> PathBuf { let mut path = wasi_sdk(); path.push("lib"); path.push("clang"); - path.push("8.0.0"); + path.push("8.0.1"); path } } From eb9f0b6e709665effaee9db93b789ca5f02a5860 Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Fri, 9 Aug 2019 12:05:52 -0700 Subject: [PATCH 286/512] fix benchmarks to match lucet-runtime C api changes --- benchmarks/shootout/wrapper.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/benchmarks/shootout/wrapper.c b/benchmarks/shootout/wrapper.c index e3af3aec4..57c7e2bc7 100644 --- a/benchmarks/shootout/wrapper.c +++ b/benchmarks/shootout/wrapper.c @@ -62,7 +62,8 @@ static void setup_wrapper(const char *name, void *global_ctx_, void **ctx_p) (void) global_ctx_; ASSERT_OK(lucet_instance_run( lucet_ctx.inst, name, 2, - (struct lucet_val[]){ LUCET_VAL_GUEST_PTR(0), LUCET_VAL_GUEST_PTR(lucet_ctx.ctx_p) })); + (struct lucet_val[]){ LUCET_VAL_GUEST_PTR(0), LUCET_VAL_GUEST_PTR(lucet_ctx.ctx_p) }, + NULL)); *ctx_p = (void *) (uintptr_t) * (guest_ptr_t *) &lucet_ctx.heap[lucet_ctx.ctx_p]; } @@ -84,7 +85,8 @@ static void setup_wrapper(const char *name, void *global_ctx_, void **ctx_p) static void body_wrapper(const char *name, void *ctx) { lucet_instance_run(lucet_ctx.inst, name, 1, - (struct lucet_val[]){ LUCET_VAL_GUEST_PTR((guest_ptr_t)(uintptr_t) ctx) }); + (struct lucet_val[]){ LUCET_VAL_GUEST_PTR((guest_ptr_t)(uintptr_t) ctx) }, + NULL); } #define BODY(NAME) \ @@ -93,7 +95,8 @@ static void body_wrapper(const char *name, void *ctx) static void teardown_wrapper(const char *name, void *ctx) { lucet_instance_run(lucet_ctx.inst, name, 1, - (struct lucet_val[]){ LUCET_VAL_GUEST_PTR((guest_ptr_t)(uintptr_t) ctx) }); + (struct lucet_val[]){ LUCET_VAL_GUEST_PTR((guest_ptr_t)(uintptr_t) ctx) }, + NULL); } #define TEARDOWN(NAME) \ From f52cc7efe446d780bb50f62a75c1a37a0bacfcbb Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Mon, 19 Aug 2019 10:31:48 -0700 Subject: [PATCH 287/512] do not try to count returns for unreachable calls as executed --- .../instruction_counting/unreachable_call.wat | 17 +++++++++++++++++ lucetc/src/function.rs | 8 ++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 lucet-runtime/tests/instruction_counting/unreachable_call.wat diff --git a/lucet-runtime/tests/instruction_counting/unreachable_call.wat b/lucet-runtime/tests/instruction_counting/unreachable_call.wat new file mode 100644 index 000000000..3caf47428 --- /dev/null +++ b/lucet-runtime/tests/instruction_counting/unreachable_call.wat @@ -0,0 +1,17 @@ +(module + (func $main (export "test_function") (result i64) + ;; counting the const + i64.const 1 + ;; return is counted by the caller, so we count 1 so far + return + + ;; we had a bug where calls in unreachable code would still add + ;; one to the instruction counter to track a matching return, + ;; but the call would never be made, so the return would never + ;; occur, and the count was in error. + call $main + ) + (func $instruction_count (export "instruction_count") (result i64) + i64.const 1 + ) +) diff --git a/lucetc/src/function.rs b/lucetc/src/function.rs index a260f306a..2c953039d 100644 --- a/lucetc/src/function.rs +++ b/lucetc/src/function.rs @@ -248,8 +248,12 @@ impl<'a> FuncInfo<'a> { // flushed and reset to 0. match op { Operator::CallIndirect { .. } | Operator::Call { .. } => { - // add 1 to count the return from the called function - self.scope_costs.last_mut().map(|x| *x = 1); + // only track the expected return if this call was reachable - if the call is not + // reachable, the "called" function won't return! + if reachable { + // add 1 to count the return from the called function + self.scope_costs.last_mut().map(|x| *x = 1); + } } Operator::Block { .. } | Operator::Loop { .. } | Operator::If { .. } => { // opening a scope, which starts having executed zero wasm ops From bbfb467f31b29a82017b7bf910c279fb2f664e28 Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Mon, 19 Aug 2019 11:32:58 -0700 Subject: [PATCH 288/512] update comments alongside spec test runner --- lucet-spectest/tests/wasm-spec.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/lucet-spectest/tests/wasm-spec.rs b/lucet-spectest/tests/wasm-spec.rs index 29403c558..51410a729 100644 --- a/lucet-spectest/tests/wasm-spec.rs +++ b/lucet-spectest/tests/wasm-spec.rs @@ -35,7 +35,7 @@ core_spec_test!(break_drop, "break-drop"); // PASS core_spec_test!(br_if); // PASS core_spec_test!(br_table); // PASS core_spec_test!(br); // PASS -core_spec_test!(call_indirect); // FAIL: BadSignature runtime error in AssertReturn. BUG: we check type index equality, but the same type may exist at multiple indexes. +core_spec_test!(call_indirect); // PASS core_spec_test!(call); // PASS core_spec_test!(comments); // PASS core_spec_test!(const_, "const"); // PASS @@ -57,14 +57,16 @@ core_spec_test!(float_literals); // PASS core_spec_test!(float_memory); // PASS core_spec_test!(float_misc); // PASS core_spec_test!(forward); // PASS -core_spec_test!(func_ptrs); // FAIL: dlopen error, need print_i32 etc -core_spec_test!(func); // FAIL: in BadSignature runtime error AssertReturn +core_spec_test!(func_ptrs); // PASS +core_spec_test!(func); // PASS core_spec_test!(get_local); // PASS core_spec_test!(globals); // FAIL: exports mutable globals, which wabt does not support core_spec_test!(i32_, "i32"); // PASS core_spec_test!(i64_, "i64"); // PASS core_spec_test!(if_, "if"); // PASS -core_spec_test!(imports); // FAIL: lots of unexpected success or incorrect results, some BadSignature faults, some "symbol not found" errors indicating test harness isnt correct + // currently stops at 'creation of elements for undeclared table!', which is actually due to an elem section populating an imported table. + // past that, lots of unexpected success or incorrect results, some BadSignature faults, some "symbol not found" errors indicating test harness isnt correct. +core_spec_test!(imports); // FAIL: see above comment core_spec_test!(inline_module, "inline-module"); // PASS core_spec_test!(int_exprs); // PASS core_spec_test!(int_literals); // PASS @@ -72,19 +74,19 @@ core_spec_test!(labels); // PASS core_spec_test!(left_to_right, "left-to-right"); // PASS core_spec_test!(linking); // FAIL: exports mutable globals core_spec_test!(loop_, "loop"); // PASS -core_spec_test!(memory_grow); // FAIL but i think its because a test asked for 4gb of memory? could increase memory limit in test harness. +core_spec_test!(memory_grow); // PASS core_spec_test!(memory_redundancy); // PASS -core_spec_test!(memory_trap); // FAIL incorrect result -core_spec_test!(memory); // FAIL panic related to heap guard +core_spec_test!(memory_trap); // PASS +core_spec_test!(memory); // PASS // too noisy to keep enabled: // core_spec_test!(names); // FAIL hundreds of errors because we dont support unicode names yet. core_spec_test!(nop); // PASS core_spec_test!(return_, "return"); // PASS core_spec_test!(select); // PASS core_spec_test!(set_local); // PASS -core_spec_test!(skip_stack_guard_page, "skip-stack-guard-page"); // PASS but takes over 1 minute +core_spec_test!(skip_stack_guard_page, "skip-stack-guard-page"); // PASS but takes over 1 minute in cranelift building function-with-many-locals core_spec_test!(stack); // PASS -core_spec_test!(start); // FAIL imports print functions +core_spec_test!(start); // PASS core_spec_test!(store_retval); // PASS core_spec_test!(switch); // PASS core_spec_test!(tee_local); // PASS From 54ac5c880135fd2967e56c93eabcf4e4e23502fa Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 21 Aug 2019 15:42:45 -0700 Subject: [PATCH 289/512] lucet-runtime-internals: delete dep on cranelift-codegen it is not used and should never be a dep. --- lucet-runtime/lucet-runtime-internals/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index 4e5ddc36c..0962ee9e1 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -15,7 +15,6 @@ lucet-module = { path = "../../lucet-module", version = "0.1.1" } bitflags = "1.0" bincode = "~1.0.1" byteorder = "1.3" -cranelift-codegen = { path = "../../cranelift/cranelift-codegen", version = "0.37.0" } failure = "0.1" lazy_static = "1.1" libc = "=0.2.59" From 994dfef2c341cf11dd27cdbb086c57fdadb35f99 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 21 Aug 2019 15:56:06 -0700 Subject: [PATCH 290/512] lucet-module: upgrade to cranelift 0.40.0 depend on entity directly. leave a comment that depending on codegen is not desirable, because then codegen ends up transitively available in runtime --- lucet-module/Cargo.toml | 6 +++++- lucet-module/src/functions.rs | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lucet-module/Cargo.toml b/lucet-module/Cargo.toml index 0b3b104a8..da0c76e82 100644 --- a/lucet-module/Cargo.toml +++ b/lucet-module/Cargo.toml @@ -10,7 +10,11 @@ authors = ["Lucet team "] edition = "2018" [dependencies] -cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.37.0" } +cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.40.0" } +# We only depend on the types in codegen used inside ir::Signature. TODO: make +# a lucet-module version of those types, and make lucetc responsible for translating +# from the cranelift-codegen::ir::Signature to a lucet-module::Signature +cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.40.0" } failure = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/lucet-module/src/functions.rs b/lucet-module/src/functions.rs index a703e8d10..87f0b68d9 100644 --- a/lucet-module/src/functions.rs +++ b/lucet-module/src/functions.rs @@ -1,5 +1,5 @@ use crate::traps::{TrapManifest, TrapSite}; -use cranelift_codegen::entity::entity_impl; +use cranelift_entity::entity_impl; use serde::{Deserialize, Serialize}; use std::slice::from_raw_parts; From a10a39cf423e194ed1bf1f8e8b0423f44a25a0e6 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 21 Aug 2019 16:01:54 -0700 Subject: [PATCH 291/512] upgrade to cranelift 0.40.0 --- Cargo.lock | 74 +++++++++++++++++++------------------- cranelift | 2 +- lucetc/Cargo.toml | 16 ++++----- lucetc/src/module.rs | 85 ++++++++++++++++++++++++++++++++++---------- 4 files changed, 112 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c3ef4fcd5..3167e45b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -286,18 +286,18 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.37.0" +version = "0.40.0" dependencies = [ - "cranelift-entity 0.37.0", + "cranelift-entity 0.40.0", ] [[package]] name = "cranelift-codegen" -version = "0.37.0" +version = "0.40.0" dependencies = [ - "cranelift-bforest 0.37.0", - "cranelift-codegen-meta 0.37.0", - "cranelift-entity 0.37.0", + "cranelift-bforest 0.40.0", + "cranelift-codegen-meta 0.40.0", + "cranelift-entity 0.40.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -306,66 +306,66 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.37.0" +version = "0.40.0" dependencies = [ - "cranelift-entity 0.37.0", + "cranelift-entity 0.40.0", ] [[package]] name = "cranelift-entity" -version = "0.37.0" +version = "0.40.0" [[package]] name = "cranelift-faerie" -version = "0.37.0" +version = "0.40.0" dependencies = [ - "cranelift-codegen 0.37.0", - "cranelift-module 0.37.0", + "cranelift-codegen 0.40.0", + "cranelift-module 0.40.0", "faerie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-frontend" -version = "0.37.0" +version = "0.40.0" dependencies = [ - "cranelift-codegen 0.37.0", + "cranelift-codegen 0.40.0", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-module" -version = "0.37.0" +version = "0.40.0" dependencies = [ - "cranelift-codegen 0.37.0", - "cranelift-entity 0.37.0", + "cranelift-codegen 0.40.0", + "cranelift-entity 0.40.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-native" -version = "0.37.0" +version = "0.40.0" dependencies = [ - "cranelift-codegen 0.37.0", + "cranelift-codegen 0.40.0", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-wasm" -version = "0.37.0" +version = "0.40.0" dependencies = [ - "cranelift-codegen 0.37.0", - "cranelift-entity 0.37.0", - "cranelift-frontend 0.37.0", + "cranelift-codegen 0.40.0", + "cranelift-entity 0.40.0", + "cranelift-frontend 0.40.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.32.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.36.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -853,7 +853,8 @@ version = "0.1.1" dependencies = [ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.37.0", + "cranelift-codegen 0.40.0", + "cranelift-entity 0.40.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -892,7 +893,6 @@ dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.37.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -996,13 +996,13 @@ dependencies = [ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.37.0", - "cranelift-entity 0.37.0", - "cranelift-faerie 0.37.0", - "cranelift-frontend 0.37.0", - "cranelift-module 0.37.0", - "cranelift-native 0.37.0", - "cranelift-wasm 0.37.0", + "cranelift-codegen 0.40.0", + "cranelift-entity 0.40.0", + "cranelift-faerie 0.40.0", + "cranelift-frontend 0.40.0", + "cranelift-module 0.40.0", + "cranelift-native 0.40.0", + "cranelift-wasm 0.40.0", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "faerie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1017,7 +1017,7 @@ dependencies = [ "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "wasmonkey 0.1.8", - "wasmparser 0.32.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.36.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1923,7 +1923,7 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.32.1" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2182,7 +2182,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a6265b25719e82598d104b3717375e37661d41753e2c84cde3f51050c7ed7e3c" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" -"checksum wasmparser 0.32.1 (registry+https://github.com/rust-lang/crates.io-index)" = "22d1801de30f112ddaf665291097694ee33a36d1cb414b53a921d05b3519674a" +"checksum wasmparser 0.36.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a014c25b9ddb665ad952d4260413931948a0b279b3504307870a5b73051526c" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" diff --git a/cranelift b/cranelift index 05d22df6c..5534fd2c2 160000 --- a/cranelift +++ b/cranelift @@ -1 +1 @@ -Subproject commit 05d22df6cbf98a072d7525cff4599d930af142a7 +Subproject commit 5534fd2c2f411dcdb981f992239fc0e96790312b diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index b3c1738d6..32466e1e2 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -18,16 +18,16 @@ path = "src/main.rs" [dependencies] bincode = "~1.0.1" -cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.37.0" } -cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.37.0" } -cranelift-native = { path = "../cranelift/cranelift-native", version = "0.37.0" } -cranelift-frontend = { path = "../cranelift/cranelift-frontend", version = "0.37.0" } -cranelift-module = { path = "../cranelift/cranelift-module", version = "0.37.0" } -cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.37.0" } -cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.37.0" } +cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.40.0" } +cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.40.0" } +cranelift-native = { path = "../cranelift/cranelift-native", version = "0.40.0" } +cranelift-frontend = { path = "../cranelift/cranelift-frontend", version = "0.40.0" } +cranelift-module = { path = "../cranelift/cranelift-module", version = "0.40.0" } +cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.40.0" } +cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.40.0" } target-lexicon = "0.4.0" lucet-module = { path = "../lucet-module", version = "0.1.1" } -wasmparser = "0.32.1" +wasmparser = "0.36.0" clap="2.32" log = "0.4" env_logger = "0.6" diff --git a/lucetc/src/module.rs b/lucetc/src/module.rs index aa605f9e2..171dd178a 100644 --- a/lucetc/src/module.rs +++ b/lucetc/src/module.rs @@ -130,9 +130,10 @@ impl<'a> ModuleInfo<'a> { sig: ir::Signature, ) -> (UniqueFuncIndex, SignatureIndex) { let new_sigidx = SignatureIndex::from_u32(self.signature_mapping.len() as u32); - self.declare_signature(sig); + self.declare_signature(sig).expect("declaring signature"); let new_funcidx = UniqueFuncIndex::from_u32(self.functions.len() as u32); - self.declare_func_type(new_sigidx); + self.declare_func_type(new_sigidx) + .expect("declaring func type"); (new_funcidx, new_sigidx) } } @@ -142,7 +143,7 @@ impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { self.target_config } - fn declare_signature(&mut self, mut sig: ir::Signature) { + fn declare_signature(&mut self, mut sig: ir::Signature) -> WasmResult<()> { sig.params.insert( 0, ir::AbiParam::special(NATIVE_POINTER, ir::ArgumentPurpose::VMContext), @@ -160,9 +161,15 @@ impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { }); self.signature_mapping.push(match_key); + Ok(()) } - fn declare_func_import(&mut self, sig_index: SignatureIndex, module: &'a str, field: &'a str) { + fn declare_func_import( + &mut self, + sig_index: SignatureIndex, + module: &'a str, + field: &'a str, + ) -> WasmResult<()> { debug_assert_eq!( self.functions.len(), self.imported_funcs.len(), @@ -181,9 +188,15 @@ impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { }); self.function_mapping.push(unique_fn_index); + Ok(()) } - fn declare_global_import(&mut self, global: Global, module: &'a str, field: &'a str) { + fn declare_global_import( + &mut self, + global: Global, + module: &'a str, + field: &'a str, + ) -> WasmResult<()> { debug_assert_eq!( self.globals.len(), self.imported_globals.len(), @@ -191,9 +204,15 @@ impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { ); self.globals.push(Exportable::new(global)); self.imported_globals.push((module, field)); + Ok(()) } - fn declare_table_import(&mut self, table: Table, module: &'a str, field: &'a str) { + fn declare_table_import( + &mut self, + table: Table, + module: &'a str, + field: &'a str, + ) -> WasmResult<()> { debug_assert_eq!( self.tables.len(), self.imported_tables.len(), @@ -201,9 +220,15 @@ impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { ); self.tables.push(Exportable::new(table)); self.imported_tables.push((module, field)); + Ok(()) } - fn declare_memory_import(&mut self, memory: Memory, module: &'a str, field: &'a str) { + fn declare_memory_import( + &mut self, + memory: Memory, + module: &'a str, + field: &'a str, + ) -> WasmResult<()> { debug_assert_eq!( self.memories.len(), self.imported_memories.len(), @@ -213,31 +238,36 @@ impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { .insert(MemoryIndex::new(self.memories.len()), vec![]); self.memories.push(Exportable::new(memory)); self.imported_memories.push((module, field)); + Ok(()) } - fn declare_func_type(&mut self, sig_index: SignatureIndex) { + fn declare_func_type(&mut self, sig_index: SignatureIndex) -> WasmResult<()> { self.functions.push(Exportable::new(sig_index)); self.function_mapping .push(UniqueFuncIndex::from_u32(self.functions.len() as u32 - 1)); + Ok(()) } - fn declare_table(&mut self, table: Table) { + fn declare_table(&mut self, table: Table) -> WasmResult<()> { self.table_elems .insert(TableIndex::new(self.tables.len()), vec![]); self.tables.push(Exportable::new(table)); + Ok(()) } - fn declare_memory(&mut self, memory: Memory) { + fn declare_memory(&mut self, memory: Memory) -> WasmResult<()> { self.data_initializers .insert(MemoryIndex::new(self.memories.len()), vec![]); self.memories.push(Exportable::new(memory)); + Ok(()) } - fn declare_global(&mut self, global: Global) { + fn declare_global(&mut self, global: Global) -> WasmResult<()> { self.globals.push(Exportable::new(global)); + Ok(()) } - fn declare_func_export(&mut self, func_index: FuncIndex, name: &'a str) { + fn declare_func_export(&mut self, func_index: FuncIndex, name: &'a str) -> WasmResult<()> { let unique_func_index = *self .function_mapping .get(func_index) @@ -246,30 +276,42 @@ impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { .get_mut(unique_func_index) .expect("export of declared function") .push_export(name); + Ok(()) } - fn declare_table_export(&mut self, table_index: TableIndex, name: &'a str) { + fn declare_table_export(&mut self, table_index: TableIndex, name: &'a str) -> WasmResult<()> { self.tables .get_mut(table_index) .expect("export of declared table") .push_export(name); + Ok(()) } - fn declare_memory_export(&mut self, memory_index: MemoryIndex, name: &'a str) { + fn declare_memory_export( + &mut self, + memory_index: MemoryIndex, + name: &'a str, + ) -> WasmResult<()> { self.memories .get_mut(memory_index) .expect("export of declared memory") .push_export(name); + Ok(()) } - fn declare_global_export(&mut self, global_index: GlobalIndex, name: &'a str) { + fn declare_global_export( + &mut self, + global_index: GlobalIndex, + name: &'a str, + ) -> WasmResult<()> { self.globals .get_mut(global_index) .expect("export of declared global") .push_export(name); + Ok(()) } - fn declare_start_func(&mut self, func_index: FuncIndex) { + fn declare_start_func(&mut self, func_index: FuncIndex) -> WasmResult<()> { let unique_func_index = *self .function_mapping .get(func_index) @@ -279,6 +321,7 @@ impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { "start func can only be defined once" ); self.start_func = Some(unique_func_index); + Ok(()) } fn define_function_body(&mut self, body_bytes: &'a [u8], body_offset: usize) -> WasmResult<()> { @@ -295,7 +338,7 @@ impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { base: Option, offset: usize, elements: Box<[FuncIndex]>, - ) { + ) -> WasmResult<()> { let elements_vec: Vec = elements.into(); let uniquified_elements = elements_vec .into_iter() @@ -327,6 +370,7 @@ impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { } } } + Ok(()) } fn declare_data_initialization( @@ -335,14 +379,17 @@ impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { base: Option, offset: usize, data: &'a [u8], - ) { + ) -> WasmResult<()> { let data_init = DataInitializer { base, offset, data }; match self.data_initializers.entry(memory_index) { - Entry::Occupied(mut occ) => occ.get_mut().push(data_init), + Entry::Occupied(mut occ) => { + occ.get_mut().push(data_init); + } Entry::Vacant(_) => panic!( "data initializer for undeclared memory {:?}: {:?}", memory_index, data_init ), } + Ok(()) } } From cc4c8bad0dabbcd45cebb8bc9d97480032bfcbd3 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 22 Aug 2019 10:30:25 -0700 Subject: [PATCH 292/512] lucetc: propogate WasmResult into LucetcError --- lucetc/src/decls.rs | 2 +- lucetc/src/module.rs | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index 3903aad98..9240271ba 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -197,7 +197,7 @@ impl<'a> ModuleDecls<'a> { decl_linkage: Linkage, signature: ir::Signature, ) -> Result { - let (new_funcidx, _) = self.info.declare_func_with_sig(signature); + let (new_funcidx, _) = self.info.declare_func_with_sig(signature)?; self.declare_function(clif_module, decl_sym, decl_linkage, new_funcidx)?; diff --git a/lucetc/src/module.rs b/lucetc/src/module.rs index 171dd178a..9a1e995bd 100644 --- a/lucetc/src/module.rs +++ b/lucetc/src/module.rs @@ -1,4 +1,5 @@ //! Implements ModuleEnvironment for cranelift-wasm. Code derived from cranelift-wasm/environ/dummy.rs +use crate::error::{LucetcError, LucetcErrorKind}; use crate::pointer::NATIVE_POINTER; use cranelift_codegen::entity::{entity_impl, EntityRef, PrimaryMap}; use cranelift_codegen::ir; @@ -7,6 +8,7 @@ use cranelift_wasm::{ FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, ModuleEnvironment, SignatureIndex, Table, TableElementType, TableIndex, WasmResult, }; +use failure::ResultExt; use lucet_module::UniqueSignatureIndex; use std::collections::{hash_map::Entry, HashMap}; @@ -128,13 +130,14 @@ impl<'a> ModuleInfo<'a> { pub fn declare_func_with_sig( &mut self, sig: ir::Signature, - ) -> (UniqueFuncIndex, SignatureIndex) { + ) -> Result<(UniqueFuncIndex, SignatureIndex), LucetcError> { let new_sigidx = SignatureIndex::from_u32(self.signature_mapping.len() as u32); - self.declare_signature(sig).expect("declaring signature"); + self.declare_signature(sig) + .context(LucetcErrorKind::TranslatingModule)?; let new_funcidx = UniqueFuncIndex::from_u32(self.functions.len() as u32); self.declare_func_type(new_sigidx) - .expect("declaring func type"); - (new_funcidx, new_sigidx) + .context(LucetcErrorKind::TranslatingModule)?; + Ok((new_funcidx, new_sigidx)) } } From 99295598f92814fb69e01d9c6845361419daacdd Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 26 Jun 2019 18:57:44 -0700 Subject: [PATCH 293/512] lucet-idl: function args and rets are abi types only, rets are named and some scaffolding for "where clause" where itll describe what the args and rets bind to. --- lucet-idl/src/lib.rs | 4 +- lucet-idl/src/module.rs | 151 ++++++++---------------------- lucet-idl/src/parser.rs | 181 +++++++++++++++++------------------- lucet-idl/src/rust.rs | 27 ++++-- lucet-idl/src/types.rs | 51 ++++++++-- lucet-idl/tests/example.idl | 4 +- 6 files changed, 192 insertions(+), 226 deletions(-) diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 64a4dfb52..31205b08e 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -20,8 +20,8 @@ pub use crate::error::IDLError; pub use crate::module::Module; pub use crate::package::Package; pub use crate::types::{ - AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, FuncDecl, - FuncRet, Ident, Location, Name, Named, StructDataType, StructMember, + AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, FuncDecl, Ident, + Location, Name, Named, StructDataType, StructMember, }; use crate::c::CGenerator; diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index 2865d0788..7c3e4b28f 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -2,9 +2,9 @@ use crate::data_layout::{ AliasIR, DataTypeModuleBuilder, EnumIR, StructIR, StructMemberIR, VariantIR, }; use crate::error::ValidationError; -use crate::parser::{SyntaxDecl, SyntaxRef}; +use crate::parser::{FuncArgSyntax, SyntaxDecl, SyntaxRef}; use crate::types::{ - DataType, DataTypeRef, EnumMember, FuncArg, FuncDecl, FuncRet, Ident, Location, Name, Named, + DataType, DataTypeRef, EnumMember, FuncArg, FuncDecl, Ident, Location, Name, Named, }; use heck::SnakeCase; use std::collections::HashMap; @@ -172,34 +172,35 @@ impl Module { location, .. } => { - let mut arg_names: HashMap = HashMap::new(); - let args = args - .iter() - .map(|arg_syntax| { - let type_ = self.get_ref(&arg_syntax.type_)?; - if let Some(previous_location) = arg_names.get(&arg_syntax.name) { - Err(ValidationError::NameAlreadyExists { + fn unique_args( + arg_names: &mut HashMap, + args: &[FuncArgSyntax], + ) -> Result, ValidationError> { + args.iter() + .map(|arg_syntax| { + if let Some(previous_location) = arg_names.get(&arg_syntax.name) { + Err(ValidationError::NameAlreadyExists { + name: arg_syntax.name.clone(), + at_location: arg_syntax.location, + previous_location: previous_location.clone(), + })?; + } else { + arg_names + .insert(arg_syntax.name.clone(), arg_syntax.location.clone()); + } + Ok(FuncArg { name: arg_syntax.name.clone(), - at_location: arg_syntax.location, - previous_location: previous_location.clone(), - })?; - } else { - arg_names.insert(arg_syntax.name.clone(), arg_syntax.location.clone()); - } - Ok(FuncArg { - name: arg_syntax.name.clone(), - type_, + type_: arg_syntax.type_.clone(), + }) }) - }) - .collect::, _>>()?; + .collect::, _>>() + } + + let mut arg_names: HashMap = HashMap::new(); + + let args = unique_args(&mut arg_names, args)?; + let rets = unique_args(&mut arg_names, rets)?; - let rets = rets - .iter() - .map(|ret_syntax| { - let type_ = self.get_ref(&ret_syntax.type_)?; - Ok(FuncRet { type_ }) - }) - .collect::, _>>()?; if rets.len() > 1 { Err(ValidationError::Syntax { expected: "at most one return value", @@ -305,7 +306,7 @@ impl Module { mod tests { use super::*; use crate::parser::Parser; - use crate::types::{AliasDataType, AtomType, DataTypeVariant, StructDataType, StructMember}; + use crate::types::{AbiType, AtomType, DataTypeVariant, StructDataType, StructMember}; fn mod_(syntax: &str) -> Result { let mut parser = Parser::new(syntax); @@ -534,7 +535,7 @@ mod tests { #[test] fn func_one_arg() { assert_eq!( - mod_("fn trivial(a: u8);").ok().unwrap(), + mod_("fn trivial(a: i64);").ok().unwrap(), Module { names: vec![Name { name: "trivial".to_owned(), @@ -544,7 +545,7 @@ mod tests { Ident(0), FuncDecl { args: vec![FuncArg { - type_: DataTypeRef::Atom(AtomType::U8), + type_: AbiType::I64, name: "a".to_owned(), }], rets: Vec::new(), @@ -565,7 +566,7 @@ mod tests { #[test] fn func_one_ret() { assert_eq!( - mod_("fn trivial() -> u8;").ok().unwrap(), + mod_("fn trivial() -> r: i64;").ok().unwrap(), Module { names: vec![Name { name: "trivial".to_owned(), @@ -575,8 +576,9 @@ mod tests { Ident(0), FuncDecl { args: Vec::new(), - rets: vec![FuncRet { - type_: DataTypeRef::Atom(AtomType::U8), + rets: vec![FuncArg { + name: "r".to_owned(), + type_: AbiType::I64, }], binding_name: "_trivial".to_owned(), field_name: "trivial".to_owned(), @@ -592,85 +594,12 @@ mod tests { ); } - #[test] - fn func_one_ret_defined_type() { - assert_eq!( - mod_("fn trivial() -> foo;\ntype foo = u8;").ok().unwrap(), - Module { - names: vec![ - Name { - name: "trivial".to_owned(), - location: Location { line: 1, column: 0 } - }, - Name { - name: "foo".to_owned(), - location: Location { line: 2, column: 0 } - } - ], - funcs: vec![( - Ident(0), - FuncDecl { - args: Vec::new(), - rets: vec![FuncRet { - type_: DataTypeRef::Defined(Ident(1)), - }], - binding_name: "_trivial".to_owned(), - field_name: "trivial".to_owned(), - } - )] - .into_iter() - .collect::>(), - data_types: vec![( - Ident(1), - DataType { - variant: DataTypeVariant::Alias(AliasDataType { - to: DataTypeRef::Atom(AtomType::U8), - }), - repr_size: 1, - align: 1, - } - )] - .into_iter() - .collect::>(), - data_type_ordering: vec![Ident(1)], - module_name: String::new(), - binding_prefix: String::new(), - } - ); - } - - #[test] - fn func_unknown_arg_type() { - assert_eq!( - mod_("fn trivial(a: foo);").err().unwrap(), - ValidationError::NameNotFound { - name: "foo".to_owned(), - use_location: Location { - line: 1, - column: 14 - }, - } - ); - } - - #[test] - fn func_unknown_ret_type() { - assert_eq!( - mod_("fn trivial(a: u8) -> foo;").err().unwrap(), - ValidationError::NameNotFound { - name: "foo".to_owned(), - use_location: Location { - line: 1, - column: 21 - }, - } - ); - } - #[test] fn func_multiple_returns() { assert_eq!( - mod_("fn trivial(a: u8) -> bool, bool;").err().unwrap(), + mod_("fn trivial(a: i32) -> r1: i32, r2: i32;") + .err() + .unwrap(), ValidationError::Syntax { expected: "at most one return value", location: Location { line: 1, column: 0 }, @@ -681,12 +610,12 @@ mod tests { #[test] fn func_duplicate_arg() { assert_eq!( - mod_("fn trivial(a: u8, a: u8);").err().unwrap(), + mod_("fn trivial(a: i32, a: i32);").err().unwrap(), ValidationError::NameAlreadyExists { name: "a".to_owned(), at_location: Location { line: 1, - column: 18 + column: 19 }, previous_location: Location { line: 1, diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index e263496da..6df94db4a 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -1,5 +1,5 @@ use super::lexer::{LexError, Lexer, LocatedError, LocatedToken, Token}; -use super::types::{AtomType, Location}; +use super::types::{AbiType, AtomType, Location}; use std::error::Error; use std::fmt; @@ -28,7 +28,8 @@ pub enum SyntaxDecl { Function { name: String, args: Vec, - rets: Vec, + rets: Vec, + where_clause: Vec, location: Location, }, } @@ -82,13 +83,7 @@ pub struct EnumVariant { #[derive(Debug, PartialEq, Eq, Clone)] pub struct FuncArgSyntax { pub name: String, - pub type_: SyntaxRef, - pub location: Location, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct FuncRetSyntax { - pub type_: SyntaxRef, + pub type_: AbiType, pub location: Location, } @@ -280,11 +275,11 @@ impl<'a> Parser<'a> { let location = self.location; self.consume(); self.match_token(Token::Colon, "expected :")?; - let type_ref = self.match_ref("expected type")?; + let type_ = self.match_abitype()?; args.push(FuncArgSyntax { name: name.to_string(), - type_: type_ref, + type_, location, }); match self.token() { @@ -305,19 +300,21 @@ impl<'a> Parser<'a> { Ok(args) } - fn match_func_rets(&mut self) -> Result, ParseError> { + fn match_func_rets(&mut self) -> Result, ParseError> { let mut args = Vec::new(); loop { match self.token() { - Some(Token::Semi) => { - self.consume(); + Some(Token::Semi) | Some(Token::Word("where")) => { break; } - _ => { + Some(Token::Word(name)) => { let location = self.location; - let type_ref = self.match_ref("expected type, attribute, or ;")?; - args.push(FuncRetSyntax { - type_: type_ref, + self.consume(); + self.match_token(Token::Colon, "expected :")?; + let type_ = self.match_abitype()?; + args.push(FuncArgSyntax { + type_, + name: name.to_string(), location, }); match self.token() { @@ -325,13 +322,13 @@ impl<'a> Parser<'a> { self.consume(); continue; } - Some(Token::Semi) => { - self.consume(); + Some(Token::Semi) | Some(Token::Word("where")) => { break; } - _ => parse_err!(self.location, "expected , or ;")?, + x => parse_err!(self.location, "expected ',', where, or ;, got {:?}", x)?, } } + x => parse_err!(self.location, "expected func return value, got {:?}", x)?, } } Ok(args) @@ -416,20 +413,33 @@ impl<'a> Parser<'a> { self.consume(); err_ctx!(err_msg, self.match_func_rets())? } + Some(Token::Semi) | Some(Token::Word("where")) => Vec::new(), + t => err_ctx!( + err_msg, + parse_err!(self.location, "expected where, -> or ;, got {:?}", t) + )?, + }; + + let where_clause = match self.token() { Some(Token::Semi) => { self.consume(); Vec::new() } - t => err_ctx!( - err_msg, - parse_err!(self.location, "expected -> or ;, got {:?}", t) - )?, + Some(Token::Word("where")) => { + self.consume(); + unimplemented!() + } + x => unreachable!( + "match func rets didnt leave us with semi or where: {:?}", + x + ), }; return Ok(Some(SyntaxDecl::Function { name: name.to_owned(), args, rets, + where_clause, location, })); } @@ -480,6 +490,20 @@ impl<'a> Parser<'a> { ), } } + + fn match_abitype(&mut self) -> Result { + match self.token() { + Some(Token::Atom(atom)) => match AbiType::of_atom(atom) { + Some(abitype) => { + self.consume(); + Ok(abitype) + } + None => parse_err!(self.location, "expected abi type, got non-abi atom type"), + }, + Some(Token::Word(w)) => parse_err!(self.location, "expected abi type, got '{}'", w), + _ => parse_err!(self.location, "expected abi type"), + } + } } #[cfg(test)] @@ -841,6 +865,7 @@ mod tests { name: "trivial".to_owned(), args: Vec::new(), rets: Vec::new(), + where_clause: Vec::new(), location: Location { line: 1, column: 0 }, }]; assert_eq!( @@ -867,41 +892,37 @@ mod tests { } #[test] - fn fn_return_u8() { + fn fn_return_i32() { let canonical = vec![SyntaxDecl::Function { name: "getch".to_owned(), args: Vec::new(), - rets: vec![FuncRetSyntax { - type_: SyntaxRef::Atom { - atom: AtomType::U8, - location: Location { - line: 1, - column: 14, - }, - }, + rets: vec![FuncArgSyntax { + type_: AbiType::I32, + name: "r".to_owned(), location: Location { line: 1, column: 14, }, }], + where_clause: Vec::new(), location: Location { line: 1, column: 0 }, }]; assert_eq!( - Parser::new("fn getch() -> u8;") + Parser::new("fn getch() -> r:i32;") // 0 5 10 .match_decls() .expect("valid decls"), canonical ); assert_eq!( - Parser::new("fn getch() -> u8,;") + Parser::new("fn getch() -> r: i32,;") // 0 5 10 .match_decls() .expect("valid decls"), canonical ); assert_eq!( - Parser::new("fn getch() -> u8 , ;") + Parser::new("fn getch() -> r :i32 , ;") // 0 5 10 .match_decls() .expect("valid decls"), @@ -914,31 +935,26 @@ mod tests { let canonical = SyntaxDecl::Function { name: "foo".to_owned(), args: vec![FuncArgSyntax { - type_: SyntaxRef::Atom { - atom: AtomType::U8, - location: Location { - line: 1, - column: 10, - }, - }, + type_: AbiType::I32, name: "a".to_owned(), location: Location { line: 1, column: 7 }, }], rets: Vec::new(), + where_clause: Vec::new(), location: Location { line: 1, column: 0 }, }; assert_eq!( - Parser::new("fn foo(a: u8);") + Parser::new("fn foo(a: i32);") // 0 5 10 15 20 25 - .match_decl("returns u8") + .match_decl("returns i32") .expect("valid parse") .expect("valid decl"), canonical ); assert_eq!( - Parser::new("fn foo(a: u8,);") + Parser::new("fn foo(a: i32,);") // 0 5 10 15 20 25 - .match_decl("returns u8") + .match_decl("returns i32") .expect("valid parse") .expect("valid decl"), canonical @@ -951,46 +967,35 @@ mod tests { name: "foo".to_owned(), args: vec![ FuncArgSyntax { - type_: SyntaxRef::Atom { - atom: AtomType::U8, - location: Location { - line: 1, - column: 10, - }, - }, + type_: AbiType::I32, name: "a".to_owned(), location: Location { line: 1, column: 7 }, }, FuncArgSyntax { - type_: SyntaxRef::Atom { - atom: AtomType::F64, - location: Location { - line: 1, - column: 17, - }, - }, + type_: AbiType::F64, name: "b".to_owned(), location: Location { line: 1, - column: 14, + column: 15, }, }, ], rets: Vec::new(), + where_clause: Vec::new(), location: Location { line: 1, column: 0 }, }; assert_eq!( - Parser::new("fn foo(a: u8, b: f64);") + Parser::new("fn foo(a: i32, b: f64);") // 0 5 10 15 20 25 - .match_decl("returns u8") + .match_decl("two args") .expect("valid parse") .expect("valid decl"), canonical ); assert_eq!( - Parser::new("fn foo(a: u8, b: f64, );") + Parser::new("fn foo(a: i32, b: f64, );") // 0 5 10 15 20 25 - .match_decl("returns u8") + .match_decl("two args with trailing comma") .expect("valid parse") .expect("valid decl"), canonical @@ -1000,8 +1005,8 @@ mod tests { #[test] fn fn_many_returns() { assert_eq!( - Parser::new("fn getch() -> u8, u16, u32;") - // 0 5 10 15 20 25 + Parser::new("fn getch() -> r1: i32, r2: i64, r3: f32;") + // 0 5 10 15 20 25 30 .match_decl("returns u8") .expect("valid parse") .expect("valid decl"), @@ -1009,46 +1014,32 @@ mod tests { name: "getch".to_owned(), args: Vec::new(), rets: vec![ - FuncRetSyntax { - type_: SyntaxRef::Atom { - atom: AtomType::U8, - location: Location { - line: 1, - column: 14, - }, - }, + FuncArgSyntax { + type_: AbiType::I32, + name: "r1".to_owned(), location: Location { line: 1, column: 14, }, }, - FuncRetSyntax { - type_: SyntaxRef::Atom { - atom: AtomType::U16, - location: Location { - line: 1, - column: 18, - }, - }, + FuncArgSyntax { + type_: AbiType::I64, + name: "r2".to_owned(), location: Location { line: 1, - column: 18, + column: 23, }, }, - FuncRetSyntax { - type_: SyntaxRef::Atom { - atom: AtomType::U32, - location: Location { - line: 1, - column: 23, - }, - }, + FuncArgSyntax { + type_: AbiType::F32, + name: "r3".to_owned(), location: Location { line: 1, - column: 23, + column: 32, }, }, ], + where_clause: Vec::new(), location: Location { line: 1, column: 0 }, } ); diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index 5bbcea940..82a95988a 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -5,10 +5,9 @@ use crate::error::IDLError; use crate::module::Module; use crate::package::Package; use crate::pretty_writer::PrettyWriter; -use crate::types::AtomType; use crate::types::{ - AliasDataType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, FuncDecl, Ident, Named, - StructDataType, + AbiType, AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, + FuncDecl, Ident, Named, StructDataType, }; use heck::{CamelCase, SnakeCase}; use std::collections::HashMap; @@ -99,6 +98,16 @@ impl RustGenerator { } } + fn abitype_name(abi_type: &AbiType) -> &'static str { + use AbiType::*; + match abi_type { + I32 => "i32", + I64 => "i64", + F32 => "f32", + F64 => "f64", + } + } + fn gen_alias( &mut self, module: &Module, @@ -208,16 +217,16 @@ impl RustGenerator { args += &format!( "{}: {},", a.name.to_snake_case(), - self.get_defined_typename(&a.type_) + Self::abitype_name(&a.type_) ); } let func_rets = &func_decl_entry.entity.rets; let rets = if func_rets.len() == 0 { - "()".to_owned() + "()" } else { assert_eq!(func_rets.len(), 1); - self.get_defined_typename(&func_rets[0].type_).to_owned() + Self::abitype_name(&func_rets[0].type_) }; self.w @@ -238,16 +247,16 @@ impl RustGenerator { args += &format!( "{}: {},", a.name.to_snake_case(), - self.get_defined_typename(&a.type_) + Self::abitype_name(&a.type_) ); } let func_rets = &func_decl_entry.entity.rets; let rets = if func_rets.len() == 0 { - "()".to_owned() + "()" } else { assert_eq!(func_rets.len(), 1); - self.get_defined_typename(&func_rets[0].type_).to_owned() + Self::abitype_name(&func_rets[0].type_) }; self.w.writeln("#[no_mangle]")?.writeln(format!( diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index a24bd3992..6e169c446 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -27,6 +27,48 @@ impl AtomType { } } +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum AbiType { + I32, + I64, + F32, + F64, +} + +impl AbiType { + pub fn repr_size(&self) -> usize { + match self { + AbiType::I32 | AbiType::F32 => 4, + AbiType::I64 | AbiType::F64 => 8, + } + } + + pub fn from_atom>(a: A) -> Self { + match a.as_ref() { + AtomType::Bool + | AtomType::U8 + | AtomType::I8 + | AtomType::U16 + | AtomType::I16 + | AtomType::U32 + | AtomType::I32 => AbiType::I32, + AtomType::I64 | AtomType::U64 => AbiType::I64, + AtomType::F32 => AbiType::F32, + AtomType::F64 => AbiType::F64, + } + } + + pub fn of_atom(a: AtomType) -> Option { + match a { + AtomType::I32 => Some(AbiType::I32), + AtomType::I64 => Some(AbiType::I64), + AtomType::F32 => Some(AbiType::F32), + AtomType::F64 => Some(AbiType::F64), + _ => None, + } + } +} + #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] pub struct Location { pub line: usize, @@ -91,7 +133,7 @@ pub struct DataType { #[derive(Debug, PartialEq, Eq, Clone)] pub struct FuncArg { - pub type_: DataTypeRef, + pub type_: AbiType, pub name: String, } @@ -100,12 +142,7 @@ pub struct FuncDecl { pub field_name: String, pub binding_name: String, pub args: Vec, - pub rets: Vec, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct FuncRet { - pub type_: DataTypeRef, + pub rets: Vec, } #[derive(Debug, PartialEq, Eq, Clone)] diff --git a/lucet-idl/tests/example.idl b/lucet-idl/tests/example.idl index 0b9256ce0..55a48e147 100644 --- a/lucet-idl/tests/example.idl +++ b/lucet-idl/tests/example.idl @@ -25,7 +25,7 @@ mod example { // functions - fn set_color(to: color) -> bool; + fn set_color(to: i32) -> r: i32; - fn get_structure(of: color) -> st; + fn get_structure(of: i32) -> s: i32; } From 8bd4775405c9a3be4fa400a193cba81a2eb46f9a Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 27 Jun 2019 17:49:03 -0700 Subject: [PATCH 294/512] lucet-idl: parse binding expressions for functions lexer now has both arrows, too --- lucet-idl/src/lexer.rs | 27 ++++++- lucet-idl/src/parser.rs | 167 +++++++++++++++++++++++++++++++++++++--- lucet-idl/src/types.rs | 7 ++ 3 files changed, 187 insertions(+), 14 deletions(-) diff --git a/lucet-idl/src/lexer.rs b/lucet-idl/src/lexer.rs index 33516a0a4..691f741c8 100644 --- a/lucet-idl/src/lexer.rs +++ b/lucet-idl/src/lexer.rs @@ -15,7 +15,8 @@ pub enum Token<'a> { Comma, // , Hash, // # Equals, // = - Arrow, // -> + LArrow, // <- + RArrow, // -> Atom(AtomType), Word(&'a str), Quote(&'a str), // Found between balanced "". No escaping. @@ -219,10 +220,20 @@ impl<'a> Lexer<'a> { if self.looking_at("->") { self.next_ch(); // Consume - self.next_ch(); // Consume > - token(Token::Arrow, loc) + token(Token::RArrow, loc) } else { self.next_ch(); - error(LexError::InvalidChar('/'), loc) + error(LexError::InvalidChar('-'), loc) + } + } + '<' => { + if self.looking_at("<-") { + self.next_ch(); // Consume < + self.next_ch(); // Consume - + token(Token::LArrow, loc) + } else { + self.next_ch(); + error(LexError::InvalidChar('<'), loc) } } '/' => { @@ -351,4 +362,14 @@ mod tests { assert_eq!(lex.next(), token(Token::Semi, 1, 14)); assert_eq!(lex.next(), None); } + + #[test] + fn arrows() { + let mut lex = Lexer::new("<-->\n<- ->"); + assert_eq!(lex.next(), token(Token::LArrow, 1, 0)); + assert_eq!(lex.next(), token(Token::RArrow, 1, 2)); + assert_eq!(lex.next(), token(Token::LArrow, 2, 0)); + assert_eq!(lex.next(), token(Token::RArrow, 2, 3)); + assert_eq!(lex.next(), None); + } } diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index 6df94db4a..e6b94b987 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -1,5 +1,5 @@ use super::lexer::{LexError, Lexer, LocatedError, LocatedToken, Token}; -use super::types::{AbiType, AtomType, Location}; +use super::types::{AbiType, AtomType, BindDirection, Location}; use std::error::Error; use std::fmt; @@ -29,7 +29,7 @@ pub enum SyntaxDecl { name: String, args: Vec, rets: Vec, - where_clause: Vec, + bindings: Vec, location: Location, }, } @@ -93,6 +93,22 @@ pub struct ParseError { pub message: String, } +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct BindingSyntax { + pub name: String, + pub type_: SyntaxRef, + pub direction: BindDirection, + pub from: BindingRefSyntax, + pub location: Location, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum BindingRefSyntax { + Ptr(Box), + Slice(Box, Box), + Name(String), +} + impl fmt::Display for ParseError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( @@ -334,6 +350,76 @@ impl<'a> Parser<'a> { Ok(args) } + fn match_binding_exprs(&mut self) -> Result, ParseError> { + let mut bindings = Vec::new(); + loop { + match self.token() { + Some(Token::Semi) => break, + Some(Token::Word(name)) => { + let location = self.location; + self.consume(); + self.match_token(Token::Colon, "expected :")?; + let type_ = self.match_ref("type value")?; + self.match_token(Token::LArrow, "expected <-")?; + let direction = self.match_bind_direction()?; + let from = self.match_binding_ref()?; + bindings.push(BindingSyntax { + name: name.to_string(), + type_, + direction, + from, + location, + }); + match self.token() { + Some(Token::Semi) => break, + Some(Token::Comma) => { + self.consume(); + continue; + } + _ => parse_err!(self.location, "expected , or ;")?, + } + } + _ => parse_err!(self.location, "expected binding expression")?, + } + } + Ok(bindings) + } + + fn match_bind_direction(&mut self) -> Result { + match self.token() { + Some(Token::Word("in")) => { + self.consume(); + Ok(BindDirection::In) + } + Some(Token::Word("inout")) | Some(Token::Word("io")) => { + self.consume(); + Ok(BindDirection::InOut) + } + Some(Token::Word("out")) => { + self.consume(); + Ok(BindDirection::Out) + } + _ => parse_err!( + self.location, + "expected binding direction (in, out, inout, io)" + ), + } + } + + fn match_binding_ref(&mut self) -> Result { + match self.token() { + Some(Token::Star) => { + self.consume(); + Ok(BindingRefSyntax::Ptr(Box::new(self.match_binding_ref()?))) + } + Some(Token::Word(name)) => { + self.consume(); + Ok(BindingRefSyntax::Name(name.to_string())) + } + x => parse_err!(self.location, "expected binding ref, got {:?}", x), + } + } + pub fn match_decl(&mut self, err_msg: &str) -> Result, ParseError> { loop { match self.token() { @@ -409,7 +495,7 @@ impl<'a> Parser<'a> { let args = err_ctx!(err_msg, self.match_func_args())?; let rets = match self.token() { - Some(Token::Arrow) => { + Some(Token::RArrow) => { self.consume(); err_ctx!(err_msg, self.match_func_rets())? } @@ -420,14 +506,14 @@ impl<'a> Parser<'a> { )?, }; - let where_clause = match self.token() { + let bindings = match self.token() { Some(Token::Semi) => { self.consume(); Vec::new() } Some(Token::Word("where")) => { self.consume(); - unimplemented!() + err_ctx!(err_msg, self.match_binding_exprs())? } x => unreachable!( "match func rets didnt leave us with semi or where: {:?}", @@ -439,7 +525,7 @@ impl<'a> Parser<'a> { name: name.to_owned(), args, rets, - where_clause, + bindings, location, })); } @@ -865,7 +951,7 @@ mod tests { name: "trivial".to_owned(), args: Vec::new(), rets: Vec::new(), - where_clause: Vec::new(), + bindings: Vec::new(), location: Location { line: 1, column: 0 }, }]; assert_eq!( @@ -904,7 +990,7 @@ mod tests { column: 14, }, }], - where_clause: Vec::new(), + bindings: Vec::new(), location: Location { line: 1, column: 0 }, }]; assert_eq!( @@ -940,7 +1026,7 @@ mod tests { location: Location { line: 1, column: 7 }, }], rets: Vec::new(), - where_clause: Vec::new(), + bindings: Vec::new(), location: Location { line: 1, column: 0 }, }; assert_eq!( @@ -981,7 +1067,7 @@ mod tests { }, ], rets: Vec::new(), - where_clause: Vec::new(), + bindings: Vec::new(), location: Location { line: 1, column: 0 }, }; assert_eq!( @@ -1039,7 +1125,66 @@ mod tests { }, }, ], - where_clause: Vec::new(), + bindings: Vec::new(), + location: Location { line: 1, column: 0 }, + } + ); + } + + #[test] + fn fn_with_bindings() { + assert_eq!( + Parser::new( + "fn fgetch(fptr: i32) -> r: i32 where +file: file_t <- in *fptr, +r: u8 <- out r;" + ) + // 0 5 10 15 20 25 30 + .match_decl("returns u8") + .expect("valid parse") + .expect("valid decl"), + SyntaxDecl::Function { + name: "fgetch".to_owned(), + args: vec![FuncArgSyntax { + type_: AbiType::I32, + name: "fptr".to_owned(), + location: Location { + line: 1, + column: 10, + }, + },], + rets: vec![FuncArgSyntax { + type_: AbiType::I32, + name: "r".to_owned(), + location: Location { + line: 1, + column: 24, + }, + }], + bindings: vec![ + BindingSyntax { + name: "file".to_owned(), + type_: SyntaxRef::Name { + name: "file_t".to_owned(), + location: Location { line: 2, column: 6 }, + }, + direction: BindDirection::In, + from: BindingRefSyntax::Ptr(Box::new(BindingRefSyntax::Name( + "fptr".to_owned() + ))), + location: Location { line: 2, column: 0 }, + }, + BindingSyntax { + name: "r".to_owned(), + type_: SyntaxRef::Atom { + atom: AtomType::U8, + location: Location { line: 3, column: 3 }, + }, + direction: BindDirection::Out, + from: BindingRefSyntax::Name("r".to_owned()), + location: Location { line: 3, column: 0 }, + } + ], location: Location { line: 1, column: 0 }, } ); diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index 6e169c446..ec4b040a1 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -145,6 +145,13 @@ pub struct FuncDecl { pub rets: Vec, } +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum BindDirection { + In, + Out, + InOut, +} + #[derive(Debug, PartialEq, Eq, Clone)] pub struct Name { pub name: String, From 6d284a245afe2232b606e3bf9d2d09cababd134d Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 1 Jul 2019 13:43:29 -0700 Subject: [PATCH 295/512] lucet-idl: validator for bindings! still needs testing --- lucet-idl/src/error.rs | 23 ++++ lucet-idl/src/function.rs | 262 ++++++++++++++++++++++++++++++++++++++ lucet-idl/src/lib.rs | 1 + lucet-idl/src/module.rs | 107 ++++++++-------- lucet-idl/src/parser.rs | 31 +++-- lucet-idl/src/types.rs | 21 ++- 6 files changed, 374 insertions(+), 71 deletions(-) create mode 100644 lucet-idl/src/function.rs diff --git a/lucet-idl/src/error.rs b/lucet-idl/src/error.rs index ffaee439e..528e802c4 100644 --- a/lucet-idl/src/error.rs +++ b/lucet-idl/src/error.rs @@ -60,6 +60,15 @@ pub enum ValidationError { expected: &'static str, location: Location, }, + BindingNameAlreadyBound { + name: String, + at_location: Location, + bound_location: Location, + }, + BindingTypeError { + expected: &'static str, + location: Location, + }, } impl fmt::Display for ValidationError { @@ -90,6 +99,20 @@ impl fmt::Display for ValidationError { "Invalid syntax: expected {} at line {}", expected, location.line ), + ValidationError::BindingNameAlreadyBound { + name, + at_location, + bound_location, + } => write!( + f, + "Argument {} used in binding at line {} - previously bound at line {}", + name, at_location.line, bound_location.line + ), + ValidationError::BindingTypeError { expected, location } => write!( + f, + "type error: expected {} - in binding at line {}", + expected, location.line, + ), } } } diff --git a/lucet-idl/src/function.rs b/lucet-idl/src/function.rs new file mode 100644 index 000000000..595ac0707 --- /dev/null +++ b/lucet-idl/src/function.rs @@ -0,0 +1,262 @@ +use crate::error::ValidationError; +use crate::module::Module; +use crate::parser::{BindingRefSyntax, BindingSyntax, FuncArgSyntax}; +use crate::types::{ + AbiType, BindDirection, BindingRef, DataTypeRef, FuncArg, FuncBinding, Location, +}; +use std::collections::HashMap; +use std::ops::Deref; + +#[derive(Debug, Clone, PartialEq, Eq)] +enum Position { + Arg(usize), + Ret(usize), +} + +struct FuncValidator<'a> { + // arg name to declaration location and argument position + arg_names: HashMap, + // Arg positions index into this vector: + args: Vec, + // Ret positions index into this vector: + rets: Vec, + // binding name to + binding_names: HashMap, + // arg name to binding location + arg_use_sites: HashMap, + bindings: Vec, + location: &'a Location, + module: &'a Module, +} + +impl<'a> FuncValidator<'a> { + fn new(location: &'a Location, module: &'a Module) -> Self { + Self { + arg_names: HashMap::new(), + args: Vec::new(), + rets: Vec::new(), + binding_names: HashMap::new(), + bindings: Vec::new(), + arg_use_sites: HashMap::new(), + location, + module, + } + } + fn introduce_arg_name( + &mut self, + arg_syntax: &FuncArgSyntax, + position: Position, + ) -> Result { + if let Some((previous_location, _)) = self.arg_names.get(&arg_syntax.name) { + Err(ValidationError::NameAlreadyExists { + name: arg_syntax.name.clone(), + at_location: arg_syntax.location, + previous_location: previous_location.clone(), + })?; + } else { + self.arg_names.insert( + arg_syntax.name.clone(), + (arg_syntax.location.clone(), position), + ); + } + Ok(FuncArg { + name: arg_syntax.name.clone(), + type_: arg_syntax.type_.clone(), + }) + } + + fn introduce_args(&mut self, args: &[FuncArgSyntax]) -> Result<(), ValidationError> { + for (ix, a) in args.iter().enumerate() { + let a = self.introduce_arg_name(a, Position::Arg(ix))?; + self.args.push(a); + } + Ok(()) + } + fn introduce_rets(&mut self, rets: &[FuncArgSyntax]) -> Result<(), ValidationError> { + if rets.len() > 1 { + Err(ValidationError::Syntax { + expected: "at most one return value", + location: self.location.clone(), + })? + } + for (ix, r) in rets.iter().enumerate() { + let r = self.introduce_arg_name(r, Position::Ret(ix))?; + self.rets.push(r); + } + Ok(()) + } + + fn introduce_bindings(&mut self, bindings: &[BindingSyntax]) -> Result<(), ValidationError> { + for (ix, binding) in bindings.iter().enumerate() { + let b = self.introduce_binding(binding, ix)?; + self.bindings.push(b); + } + Ok(()) + } + + fn introduce_binding( + &mut self, + binding: &BindingSyntax, + position: usize, + ) -> Result { + // 1. make sure binding name is unique + if let Some((previous_location, _)) = self.binding_names.get(&binding.name) { + Err(ValidationError::NameAlreadyExists { + name: binding.name.clone(), + at_location: binding.location, + previous_location: previous_location.clone(), + })?; + } else { + self.binding_names + .insert(binding.name.clone(), (binding.location.clone(), position)); + } + + // 2. resolve type_ SyntaxRef to a DataTypeRef + let type_ = self.module.get_typeref(&binding.type_)?; + + // 3. typecheck the binding: + let from = self.validate_binding_ref(&binding, &type_)?; + + Ok(FuncBinding { + name: binding.name.clone(), + direction: binding.direction.clone(), + type_, + from, + }) + } + + fn get_arg(&self, arg_name: &String) -> Option<(Position, FuncArg)> { + let (_, position) = self.arg_names.get(arg_name)?; + match position { + Position::Arg(ix) => Some(( + position.clone(), + self.args.get(*ix).expect("in-bounds arg index").clone(), + )), + Position::Ret(ix) => Some(( + position.clone(), + self.rets.get(*ix).expect("in-bounds ret index").clone(), + )), + } + } + + fn validate_binding_arg_mapping( + &mut self, + name: &String, + location: &Location, + ) -> Result<(Position, FuncArg), ValidationError> { + // Check that it refers to a valid arg: + let pos_and_arg = self.get_arg(name).ok_or_else(|| ValidationError::Syntax { + expected: "name of an argument or return value", + location: location.clone(), + })?; + // Check that the arg has only been used once: + if let Some(use_location) = self.arg_use_sites.get(name) { + Err(ValidationError::BindingNameAlreadyBound { + name: name.clone(), + at_location: location.clone(), + bound_location: use_location.clone(), + })?; + } else { + self.arg_use_sites.insert(name.clone(), location.clone()); + } + Ok(pos_and_arg) + } + + fn validate_binding_ref( + &mut self, + binding: &BindingSyntax, + target_type: &DataTypeRef, + ) -> Result { + match &binding.from { + // A pointer to a name is accepted: + BindingRefSyntax::Ptr(bref) => match bref.deref() { + BindingRefSyntax::Name(ref name) => { + let (position, funcarg) = + self.validate_binding_arg_mapping(name, &binding.location)?; + if funcarg.type_ != AbiType::I32 { + Err(ValidationError::BindingTypeError { + expected: "pointer bindings to be represented as an i32", + location: binding.location.clone(), + })?; + } + match position { + Position::Arg(_) => { + // all good! Arg pointers are valid for in, inout, or out binding. + } + Position::Ret(_) => { + if binding.direction != BindDirection::Out { + Err(ValidationError::BindingTypeError { + expected: "return pointer must be output-only binding", + location: binding.location.clone(), + })?; + } + } + } + Ok(BindingRef::Ptr(name.clone())) + } + _ => Err(ValidationError::Syntax { + expected: "FIXME binding must be only one pointer deep from arg", + location: binding.location.clone(), + }), + }, + // A bare name is accepted: + BindingRefSyntax::Name(ref name) => { + let (position, funcarg) = + self.validate_binding_arg_mapping(name, &binding.location)?; + + // make sure funcarg.type_ is a valid representation of target type + match self.module.get_abi_repr(target_type) { + Some(target_repr) => { + if target_repr != funcarg.type_ { + Err(ValidationError::BindingTypeError { + expected: "binding type representation to match argument type", + location: binding.location.clone(), + })?; + } + } + None => { + Err(ValidationError::BindingTypeError { + expected: "binding type to be representable as value (try passing by reference instead)", + location: binding.location.clone(), + })?; + } + } + // Arg values must be in-only bindings, Ret values must be out-only bindings + match position { + Position::Arg(_) => { + if binding.direction != BindDirection::In { + Err(ValidationError::BindingTypeError { + expected: "argument value must be input-only binding", + location: binding.location.clone(), + })?; + } + } + Position::Ret(_) => { + if binding.direction != BindDirection::Out { + Err(ValidationError::BindingTypeError { + expected: "return value must be output-only binding", + location: binding.location.clone(), + })?; + } + } + } + Ok(BindingRef::Value(name.clone())) + } + } + } +} + +pub fn validate_func_args( + args: &[FuncArgSyntax], + rets: &[FuncArgSyntax], + bindings: &[BindingSyntax], + location: &Location, + module: &Module, +) -> Result<(Vec, Vec, Vec), ValidationError> { + let mut validator = FuncValidator::new(location, module); + validator.introduce_args(args)?; + validator.introduce_rets(rets)?; + validator.introduce_bindings(bindings)?; + + Ok((validator.args, validator.rets, validator.bindings)) +} diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 31205b08e..2dda80fe7 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -7,6 +7,7 @@ mod c; mod config; mod data_layout; mod error; +mod function; mod lexer; mod module; mod package; diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index 7c3e4b28f..34e36ddbb 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -2,9 +2,11 @@ use crate::data_layout::{ AliasIR, DataTypeModuleBuilder, EnumIR, StructIR, StructMemberIR, VariantIR, }; use crate::error::ValidationError; -use crate::parser::{FuncArgSyntax, SyntaxDecl, SyntaxRef}; +use crate::function::validate_func_args; +use crate::parser::{SyntaxDecl, SyntaxTypeRef}; use crate::types::{ - DataType, DataTypeRef, EnumMember, FuncArg, FuncDecl, Ident, Location, Name, Named, + AbiType, DataType, DataTypeRef, DataTypeVariant, EnumMember, FuncDecl, Ident, Location, Name, + Named, }; use heck::SnakeCase; use std::collections::HashMap; @@ -65,10 +67,10 @@ impl Module { None } - fn get_ref(&self, syntax_ref: &SyntaxRef) -> Result { + pub fn get_typeref(&self, syntax_ref: &SyntaxTypeRef) -> Result { match syntax_ref { - SyntaxRef::Atom { atom, .. } => Ok(DataTypeRef::Atom(*atom)), - SyntaxRef::Name { name, location } => match self.id_for_name(name) { + SyntaxTypeRef::Atom { atom, .. } => Ok(DataTypeRef::Atom(*atom)), + SyntaxTypeRef::Name { name, location } => match self.id_for_name(name) { Some(id) => Ok(DataTypeRef::Defined(id)), None => Err(ValidationError::NameNotFound { name: name.clone(), @@ -78,6 +80,37 @@ impl Module { } } + // If a DataType is representable by an atomic AbiType, get it. Otherwise the DataType must + // be pointed to across ABI boundaries + pub fn get_abi_repr(&self, dtref: &DataTypeRef) -> Option { + match dtref { + DataTypeRef::Defined(ident) => { + let dt = self + .data_types + .get(ident) + .expect("abi representation of valid dtref"); + match &dt.variant { + DataTypeVariant::Struct(struct_) => { + if struct_.members.len() == 1 { + self.get_abi_repr(&struct_.members[0].type_) + } else { + None + } + } + DataTypeVariant::Enum(enum_) => { + if enum_.members.len() < u32::max_value() as usize { + Some(AbiType::I32) + } else { + None + } + } + DataTypeVariant::Alias(alias) => self.get_abi_repr(&alias.to), + } + } + DataTypeRef::Atom(atom) => Some(AbiType::from_atom(atom)), + } + } + fn decl_to_ir( &self, id: Ident, @@ -110,7 +143,7 @@ impl Module { } // Get the DataTypeRef for the member, which ensures that it refers only to // defined types: - let type_ = self.get_ref(&mem.type_)?; + let type_ = self.get_typeref(&mem.type_)?; // build the struct with this as the member: dtype_members.push(StructMemberIR { type_, @@ -162,7 +195,7 @@ impl Module { ); } SyntaxDecl::Alias { what, location, .. } => { - let to = self.get_ref(what)?; + let to = self.get_typeref(what)?; data_types_ir.define(id, VariantIR::Alias(AliasIR { to }), location.clone()); } SyntaxDecl::Function { @@ -170,50 +203,17 @@ impl Module { args, rets, location, - .. + bindings, } => { - fn unique_args( - arg_names: &mut HashMap, - args: &[FuncArgSyntax], - ) -> Result, ValidationError> { - args.iter() - .map(|arg_syntax| { - if let Some(previous_location) = arg_names.get(&arg_syntax.name) { - Err(ValidationError::NameAlreadyExists { - name: arg_syntax.name.clone(), - at_location: arg_syntax.location, - previous_location: previous_location.clone(), - })?; - } else { - arg_names - .insert(arg_syntax.name.clone(), arg_syntax.location.clone()); - } - Ok(FuncArg { - name: arg_syntax.name.clone(), - type_: arg_syntax.type_.clone(), - }) - }) - .collect::, _>>() - } - - let mut arg_names: HashMap = HashMap::new(); - - let args = unique_args(&mut arg_names, args)?; - let rets = unique_args(&mut arg_names, rets)?; - - if rets.len() > 1 { - Err(ValidationError::Syntax { - expected: "at most one return value", - location: location.clone(), - })? - } - + let (args, rets, bindings) = + validate_func_args(args, rets, bindings, location, self)?; let binding_name = self.binding_prefix.clone() + "_" + &name.to_snake_case(); let decl = FuncDecl { - args, - rets, field_name: name.clone(), binding_name, + args, + rets, + bindings, }; if let Some(prev_def) = funcs_ir.insert(id, decl) { panic!("id {} already defined: {:?}", id, prev_def) @@ -517,10 +517,11 @@ mod tests { funcs: vec![( Ident(0), FuncDecl { - args: Vec::new(), - rets: Vec::new(), binding_name: "_trivial".to_owned(), field_name: "trivial".to_owned(), + args: Vec::new(), + rets: Vec::new(), + bindings: Vec::new(), } )] .into_iter() @@ -544,13 +545,14 @@ mod tests { funcs: vec![( Ident(0), FuncDecl { + binding_name: "_trivial".to_owned(), + field_name: "trivial".to_owned(), args: vec![FuncArg { type_: AbiType::I64, name: "a".to_owned(), }], rets: Vec::new(), - binding_name: "_trivial".to_owned(), - field_name: "trivial".to_owned(), + bindings: Vec::new(), } )] .into_iter() @@ -575,13 +577,14 @@ mod tests { funcs: vec![( Ident(0), FuncDecl { + binding_name: "_trivial".to_owned(), + field_name: "trivial".to_owned(), args: Vec::new(), rets: vec![FuncArg { name: "r".to_owned(), type_: AbiType::I64, }], - binding_name: "_trivial".to_owned(), - field_name: "trivial".to_owned(), + bindings: Vec::new(), } )] .into_iter() diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index e6b94b987..4bb0c8c43 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -17,7 +17,7 @@ pub enum SyntaxDecl { }, Alias { name: String, - what: SyntaxRef, + what: SyntaxTypeRef, location: Location, }, Module { @@ -62,7 +62,7 @@ impl SyntaxDecl { } #[derive(Debug, PartialEq, Eq, Clone)] -pub enum SyntaxRef { +pub enum SyntaxTypeRef { Atom { atom: AtomType, location: Location }, Name { name: String, location: Location }, } @@ -70,7 +70,7 @@ pub enum SyntaxRef { #[derive(Debug, PartialEq, Eq, Clone)] pub struct StructMember { pub name: String, - pub type_: SyntaxRef, + pub type_: SyntaxTypeRef, pub location: Location, } @@ -96,7 +96,7 @@ pub struct ParseError { #[derive(Debug, PartialEq, Eq, Clone)] pub struct BindingSyntax { pub name: String, - pub type_: SyntaxRef, + pub type_: SyntaxTypeRef, pub direction: BindDirection, pub from: BindingRefSyntax, pub location: Location, @@ -105,7 +105,6 @@ pub struct BindingSyntax { #[derive(Debug, PartialEq, Eq, Clone)] pub enum BindingRefSyntax { Ptr(Box), - Slice(Box, Box), Name(String), } @@ -555,17 +554,17 @@ impl<'a> Parser<'a> { Ok(decls) } - fn match_ref(&mut self, err_msg: &str) -> Result { + fn match_ref(&mut self, err_msg: &str) -> Result { match self.token() { Some(Token::Atom(atom)) => { let location = self.location; self.consume(); - Ok(SyntaxRef::Atom { atom, location }) + Ok(SyntaxTypeRef::Atom { atom, location }) } Some(Token::Word(name)) => { let location = self.location; self.consume(); - Ok(SyntaxRef::Name { + Ok(SyntaxTypeRef::Name { name: name.to_string(), location, }) @@ -623,7 +622,7 @@ mod tests { name: "foo".to_string(), members: vec![StructMember { name: "a".to_owned(), - type_: SyntaxRef::Atom { + type_: SyntaxTypeRef::Atom { atom: AtomType::I32, location: Location { line: 1, @@ -652,7 +651,7 @@ mod tests { name: "foo".to_string(), members: vec![StructMember { name: "b".to_owned(), - type_: SyntaxRef::Atom { + type_: SyntaxTypeRef::Atom { atom: AtomType::I32, location: Location { line: 1, @@ -682,7 +681,7 @@ mod tests { members: vec![ StructMember { name: "d".to_owned(), - type_: SyntaxRef::Atom { + type_: SyntaxTypeRef::Atom { atom: AtomType::F64, location: Location { line: 1, @@ -696,7 +695,7 @@ mod tests { }, StructMember { name: "e".to_owned(), - type_: SyntaxRef::Atom { + type_: SyntaxTypeRef::Atom { atom: AtomType::U8, location: Location { line: 1, @@ -728,7 +727,7 @@ mod tests { members: vec![ StructMember { name: "a".to_owned(), - type_: SyntaxRef::Name { + type_: SyntaxTypeRef::Name { name: "mod".to_owned(), location: Location { line: 1, @@ -742,7 +741,7 @@ mod tests { }, StructMember { name: "struct".to_owned(), - type_: SyntaxRef::Name { + type_: SyntaxTypeRef::Name { name: "enum".to_owned(), location: Location { line: 1, @@ -1164,7 +1163,7 @@ r: u8 <- out r;" bindings: vec![ BindingSyntax { name: "file".to_owned(), - type_: SyntaxRef::Name { + type_: SyntaxTypeRef::Name { name: "file_t".to_owned(), location: Location { line: 2, column: 6 }, }, @@ -1176,7 +1175,7 @@ r: u8 <- out r;" }, BindingSyntax { name: "r".to_owned(), - type_: SyntaxRef::Atom { + type_: SyntaxTypeRef::Atom { atom: AtomType::U8, location: Location { line: 3, column: 3 }, }, diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index ec4b040a1..c68440dad 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -43,8 +43,8 @@ impl AbiType { } } - pub fn from_atom>(a: A) -> Self { - match a.as_ref() { + pub fn from_atom(a: &AtomType) -> Self { + match a { AtomType::Bool | AtomType::U8 | AtomType::I8 @@ -133,8 +133,8 @@ pub struct DataType { #[derive(Debug, PartialEq, Eq, Clone)] pub struct FuncArg { - pub type_: AbiType, pub name: String, + pub type_: AbiType, } #[derive(Debug, PartialEq, Eq, Clone)] @@ -143,6 +143,21 @@ pub struct FuncDecl { pub binding_name: String, pub args: Vec, pub rets: Vec, + pub bindings: Vec, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct FuncBinding { + pub name: String, + pub type_: DataTypeRef, + pub direction: BindDirection, + pub from: BindingRef, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum BindingRef { + Ptr(String), // Treat the argument of that name as a pointer + Value(String), // Treat the argument of that name as a value } #[derive(Debug, PartialEq, Eq, Clone)] From 89757a9c58e5072a3c59b601e65369adecc32de8 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 3 Jul 2019 15:29:24 -0700 Subject: [PATCH 296/512] lucet-idl: add a bunch of tests for binding validation --- lucet-idl/src/module.rs | 318 +++++++++++++++++++++++++++++++++++++++- lucet-idl/src/parser.rs | 15 +- 2 files changed, 326 insertions(+), 7 deletions(-) diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index 34e36ddbb..afb9d8921 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -306,7 +306,10 @@ impl Module { mod tests { use super::*; use crate::parser::Parser; - use crate::types::{AbiType, AtomType, DataTypeVariant, StructDataType, StructMember}; + use crate::types::{ + AbiType, AtomType, BindDirection, BindingRef, DataTypeVariant, FuncArg, FuncBinding, + StructDataType, StructMember, + }; fn mod_(syntax: &str) -> Result { let mut parser = Parser::new(syntax); @@ -627,4 +630,317 @@ mod tests { } ); } + + #[test] + fn func_one_arg_value_binding() { + assert_eq!( + mod_("fn trivial(a: i32) where\na_binding: in i8 <- a;") + .ok() + .unwrap(), + Module { + names: vec![Name { + name: "trivial".to_owned(), + location: Location { line: 1, column: 0 } + }], + funcs: vec![( + Ident(0), + FuncDecl { + binding_name: "_trivial".to_owned(), + field_name: "trivial".to_owned(), + args: vec![FuncArg { + type_: AbiType::I32, + name: "a".to_owned(), + }], + rets: Vec::new(), + bindings: vec![FuncBinding { + name: "a_binding".to_owned(), + type_: DataTypeRef::Atom(AtomType::I8), + direction: BindDirection::In, + from: BindingRef::Value("a".to_owned()), + }], + } + )] + .into_iter() + .collect::>(), + data_types: HashMap::new(), + data_type_ordering: Vec::new(), + module_name: String::new(), + binding_prefix: String::new(), + } + ); + } + + #[test] + fn func_one_arg_ptr_binding() { + assert_eq!( + mod_("fn trivial(a: i32) where\na_binding: inout i8 <- *a;") + .ok() + .unwrap(), + Module { + names: vec![Name { + name: "trivial".to_owned(), + location: Location { line: 1, column: 0 } + }], + funcs: vec![( + Ident(0), + FuncDecl { + binding_name: "_trivial".to_owned(), + field_name: "trivial".to_owned(), + args: vec![FuncArg { + type_: AbiType::I32, + name: "a".to_owned(), + }], + rets: Vec::new(), + bindings: vec![FuncBinding { + name: "a_binding".to_owned(), + type_: DataTypeRef::Atom(AtomType::I8), + direction: BindDirection::InOut, + from: BindingRef::Ptr("a".to_owned()), + }], + } + )] + .into_iter() + .collect::>(), + data_types: HashMap::new(), + data_type_ordering: Vec::new(), + module_name: String::new(), + binding_prefix: String::new(), + } + ); + } + + #[test] + fn func_one_arg_binding_wrong_direction() { + assert_eq!( + mod_("fn trivial(a: i32) where\na_binding: out i8 <- a;") + .err() + .unwrap(), + ValidationError::BindingTypeError { + expected: "argument value must be input-only binding", + location: Location { line: 2, column: 0 } + }, + ); + } + + #[test] + fn func_one_arg_binding_wrong_type() { + // Cant convert int to float + assert_eq!( + mod_("fn trivial(a: i32) where\na_binding: out f32 <- a;") + .err() + .unwrap(), + ValidationError::BindingTypeError { + expected: "binding type representation to match argument type", + location: Location { line: 2, column: 0 } + }, + ); + // Cant convert float to int + assert_eq!( + mod_("fn trivial(a: f32) where\na_binding: out i32 <- a;") + .err() + .unwrap(), + ValidationError::BindingTypeError { + expected: "binding type representation to match argument type", + location: Location { line: 2, column: 0 } + }, + ); + // Cant represent i64 with i32 + assert_eq!( + mod_("fn trivial(a: i32) where\na_binding: out i64 <- a;") + .err() + .unwrap(), + ValidationError::BindingTypeError { + expected: "binding type representation to match argument type", + location: Location { line: 2, column: 0 } + }, + ); + // Cant represent ptr with float + assert_eq!( + mod_("fn trivial(a: f32) where\na_binding: out i8 <- *a;") + .err() + .unwrap(), + ValidationError::BindingTypeError { + expected: "pointer bindings to be represented as an i32", + location: Location { line: 2, column: 0 } + }, + ); + // Cant represent ptr with i64 + assert_eq!( + mod_("fn trivial(a: i64) where\na_binding: out i8 <- *a;") + .err() + .unwrap(), + ValidationError::BindingTypeError { + expected: "pointer bindings to be represented as an i32", + location: Location { line: 2, column: 0 } + }, + ); + } + + #[test] + fn func_one_ret_value_binding() { + assert_eq!( + mod_("fn trivial() -> a: i32 where\na_binding: out i8 <- a;") + .ok() + .unwrap(), + Module { + names: vec![Name { + name: "trivial".to_owned(), + location: Location { line: 1, column: 0 } + }], + funcs: vec![( + Ident(0), + FuncDecl { + binding_name: "_trivial".to_owned(), + field_name: "trivial".to_owned(), + args: Vec::new(), + rets: vec![FuncArg { + type_: AbiType::I32, + name: "a".to_owned(), + }], + bindings: vec![FuncBinding { + name: "a_binding".to_owned(), + type_: DataTypeRef::Atom(AtomType::I8), + direction: BindDirection::Out, + from: BindingRef::Value("a".to_owned()), + }], + } + )] + .into_iter() + .collect::>(), + data_types: HashMap::new(), + data_type_ordering: Vec::new(), + module_name: String::new(), + binding_prefix: String::new(), + } + ); + } + + #[test] + fn func_one_ret_pointer_binding() { + assert_eq!( + mod_("fn trivial() -> a: i32 where\na_binding: out i8 <- *a;") + .ok() + .unwrap(), + Module { + names: vec![Name { + name: "trivial".to_owned(), + location: Location { line: 1, column: 0 } + }], + funcs: vec![( + Ident(0), + FuncDecl { + binding_name: "_trivial".to_owned(), + field_name: "trivial".to_owned(), + args: Vec::new(), + rets: vec![FuncArg { + type_: AbiType::I32, + name: "a".to_owned(), + }], + bindings: vec![FuncBinding { + name: "a_binding".to_owned(), + type_: DataTypeRef::Atom(AtomType::I8), + direction: BindDirection::Out, + from: BindingRef::Ptr("a".to_owned()), + }], + } + )] + .into_iter() + .collect::>(), + data_types: HashMap::new(), + data_type_ordering: Vec::new(), + module_name: String::new(), + binding_prefix: String::new(), + } + ); + } + #[test] + fn func_one_ret_wrong_direction() { + assert_eq!( + mod_("fn trivial() -> a: i32 where\na_binding: in i8 <- a;") + .err() + .unwrap(), + ValidationError::BindingTypeError { + expected: "return value must be output-only binding", + location: Location { line: 2, column: 0 } + }, + ); + } + #[test] + fn func_buncha_bindings() { + assert_eq!( + mod_( + "fn nontrivial(a: i32, b: i32, c: f32) -> d: i32 where\n\ + a_binding: out u8 <- *a,\n\ + b_binding: inout u16 <- *b,\n\ + c_binding: in f32 <- c,\n\ + d_binding: out i8 <- *d;\n\ + " + ) + .ok() + .unwrap(), + Module { + names: vec![Name { + name: "nontrivial".to_owned(), + location: Location { line: 1, column: 0 } + }], + funcs: vec![( + Ident(0), + FuncDecl { + binding_name: "_nontrivial".to_owned(), + field_name: "nontrivial".to_owned(), + args: vec![ + FuncArg { + type_: AbiType::I32, + name: "a".to_owned(), + }, + FuncArg { + type_: AbiType::I32, + name: "b".to_owned(), + }, + FuncArg { + type_: AbiType::F32, + name: "c".to_owned(), + } + ], + rets: vec![FuncArg { + type_: AbiType::I32, + name: "d".to_owned(), + }], + bindings: vec![ + FuncBinding { + name: "a_binding".to_owned(), + type_: DataTypeRef::Atom(AtomType::U8), + direction: BindDirection::Out, + from: BindingRef::Ptr("a".to_owned()), + }, + FuncBinding { + name: "b_binding".to_owned(), + type_: DataTypeRef::Atom(AtomType::U16), + direction: BindDirection::InOut, + from: BindingRef::Ptr("b".to_owned()), + }, + FuncBinding { + name: "c_binding".to_owned(), + type_: DataTypeRef::Atom(AtomType::F32), + direction: BindDirection::In, + from: BindingRef::Value("c".to_owned()), + }, + FuncBinding { + name: "d_binding".to_owned(), + type_: DataTypeRef::Atom(AtomType::I8), + direction: BindDirection::Out, + from: BindingRef::Ptr("d".to_owned()), + }, + ], + } + )] + .into_iter() + .collect::>(), + data_types: HashMap::new(), + data_type_ordering: Vec::new(), + module_name: String::new(), + binding_prefix: String::new(), + } + ); + } } diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index 4bb0c8c43..a9c26a2c9 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -358,9 +358,9 @@ impl<'a> Parser<'a> { let location = self.location; self.consume(); self.match_token(Token::Colon, "expected :")?; + let direction = self.match_bind_direction()?; let type_ = self.match_ref("type value")?; self.match_token(Token::LArrow, "expected <-")?; - let direction = self.match_bind_direction()?; let from = self.match_binding_ref()?; bindings.push(BindingSyntax { name: name.to_string(), @@ -370,7 +370,10 @@ impl<'a> Parser<'a> { location, }); match self.token() { - Some(Token::Semi) => break, + Some(Token::Semi) => { + self.consume(); + break; + } Some(Token::Comma) => { self.consume(); continue; @@ -1135,8 +1138,8 @@ mod tests { assert_eq!( Parser::new( "fn fgetch(fptr: i32) -> r: i32 where -file: file_t <- in *fptr, -r: u8 <- out r;" +file: in file_t <- *fptr, +r: out u8 <- r;" ) // 0 5 10 15 20 25 30 .match_decl("returns u8") @@ -1165,7 +1168,7 @@ r: u8 <- out r;" name: "file".to_owned(), type_: SyntaxTypeRef::Name { name: "file_t".to_owned(), - location: Location { line: 2, column: 6 }, + location: Location { line: 2, column: 9 }, }, direction: BindDirection::In, from: BindingRefSyntax::Ptr(Box::new(BindingRefSyntax::Name( @@ -1177,7 +1180,7 @@ r: u8 <- out r;" name: "r".to_owned(), type_: SyntaxTypeRef::Atom { atom: AtomType::U8, - location: Location { line: 3, column: 3 }, + location: Location { line: 3, column: 7 }, }, direction: BindDirection::Out, from: BindingRefSyntax::Name("r".to_owned()), From c16daa830919d3e2b4d3a600809e7183542506fe Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 3 Jul 2019 16:56:44 -0700 Subject: [PATCH 297/512] lucet-idl: bindings to slices --- lucet-idl/src/function.rs | 54 ++++++++++++++++++++++++++++++++++++- lucet-idl/src/module.rs | 48 +++++++++++++++++++++++++++++++++ lucet-idl/src/parser.rs | 37 ++++++++++++++++++++++--- lucet-idl/src/types.rs | 5 ++-- lucet-idl/tests/example.idl | 4 +++ 5 files changed, 141 insertions(+), 7 deletions(-) diff --git a/lucet-idl/src/function.rs b/lucet-idl/src/function.rs index 595ac0707..8c1ad6b4d 100644 --- a/lucet-idl/src/function.rs +++ b/lucet-idl/src/function.rs @@ -195,10 +195,62 @@ impl<'a> FuncValidator<'a> { Ok(BindingRef::Ptr(name.clone())) } _ => Err(ValidationError::Syntax { - expected: "FIXME binding must be only one pointer deep from arg", + expected: "pointer binding must be of form *arg", location: binding.location.clone(), }), }, + // A slice of two names is accepted: + BindingRefSyntax::Slice(ref ptr_ref, ref len_ref) => { + match (ptr_ref.deref(), len_ref.deref()) { + ( + BindingRefSyntax::Name(ref ptr_name), + BindingRefSyntax::Name(ref len_name), + ) => { + let (ptr_position, ptr_arg) = + self.validate_binding_arg_mapping(ptr_name, &binding.location)?; + if ptr_arg.type_ != AbiType::I32 { + Err(ValidationError::BindingTypeError { + expected: "slice pointer must be i32", + location: binding.location.clone(), + })?; + } + let (len_position, len_arg) = + self.validate_binding_arg_mapping(len_name, &binding.location)?; + if len_arg.type_ != AbiType::I32 { + Err(ValidationError::BindingTypeError { + expected: "slice len must be i32", + location: binding.location.clone(), + })?; + } + match (ptr_position, len_position) { + (Position::Arg(_), Position::Arg(_)) => {} + _ => { + Err(ValidationError::BindingTypeError { + expected: "slice bindings must be inputs", + location: binding.location.clone(), + })?; + } + } + Ok(BindingRef::Slice(ptr_name.to_owned(), len_name.to_owned())) + } + ( + BindingRefSyntax::Name(ref _ptr_name), + BindingRefSyntax::Ptr(ref len_ptr_ref), + ) => match len_ptr_ref.deref() { + BindingRefSyntax::Name(_len_ptr_name) => { + unimplemented!("slice syntax [ptr, *len] for an output slice"); + } + _ => Err(ValidationError::Syntax { + expected: "slice binding must be of form [ptr, len] or [ptr, *len]", + location: binding.location.clone(), + }), + }, + _ => Err(ValidationError::Syntax { + expected: "slice binding must be of form [ptr, len] or [ptr, *len]", + location: binding.location.clone(), + }), + } + } // A bare name is accepted: BindingRefSyntax::Name(ref name) => { let (position, funcarg) = diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index afb9d8921..cdd3a5053 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -865,6 +865,54 @@ mod tests { }, ); } + + #[test] + fn func_two_arg_slice_binding() { + assert_eq!( + mod_( + "fn trivial(a_ptr: i32, a_len: i32) where\na_binding: inout i8 <- [a_ptr, a_len];" + ) + .ok() + .unwrap(), + Module { + names: vec![Name { + name: "trivial".to_owned(), + location: Location { line: 1, column: 0 } + }], + funcs: vec![( + Ident(0), + FuncDecl { + binding_name: "_trivial".to_owned(), + field_name: "trivial".to_owned(), + args: vec![ + FuncArg { + type_: AbiType::I32, + name: "a_ptr".to_owned(), + }, + FuncArg { + type_: AbiType::I32, + name: "a_len".to_owned(), + } + ], + rets: Vec::new(), + bindings: vec![FuncBinding { + name: "a_binding".to_owned(), + type_: DataTypeRef::Atom(AtomType::I8), + direction: BindDirection::InOut, + from: BindingRef::Slice("a_ptr".to_owned(), "a_len".to_owned()), + }], + } + )] + .into_iter() + .collect::>(), + data_types: HashMap::new(), + data_type_ordering: Vec::new(), + module_name: String::new(), + binding_prefix: String::new(), + } + ); + } + #[test] fn func_buncha_bindings() { assert_eq!( diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index a9c26a2c9..52b1302ad 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -105,6 +105,7 @@ pub struct BindingSyntax { #[derive(Debug, PartialEq, Eq, Clone)] pub enum BindingRefSyntax { Ptr(Box), + Slice(Box, Box), Name(String), } @@ -418,6 +419,17 @@ impl<'a> Parser<'a> { self.consume(); Ok(BindingRefSyntax::Name(name.to_string())) } + Some(Token::LBracket) => { + self.consume(); + let ptr_arg = self.match_binding_ref()?; + let _ = self.match_token(Token::Comma, ", in binding ref slice"); + let len_arg = self.match_binding_ref()?; + let _ = self.match_token(Token::RBracket, "] at end of binding ref slice"); + Ok(BindingRefSyntax::Slice( + Box::new(ptr_arg), + Box::new(len_arg), + )) + } x => parse_err!(self.location, "expected binding ref, got {:?}", x), } } @@ -1137,11 +1149,12 @@ mod tests { fn fn_with_bindings() { assert_eq!( Parser::new( - "fn fgetch(fptr: i32) -> r: i32 where -file: in file_t <- *fptr, -r: out u8 <- r;" + "fn fgetch(fptr: i32) -> r: i32 where \n\ + file: in file_t <- *fptr,\n\ + r: out u8 <- r,\n\ + some_slice: out something <- [a, b];" ) - // 0 5 10 15 20 25 30 + // 0 5 10 15 20 25 30 .match_decl("returns u8") .expect("valid parse") .expect("valid decl"), @@ -1185,6 +1198,22 @@ r: out u8 <- r;" direction: BindDirection::Out, from: BindingRefSyntax::Name("r".to_owned()), location: Location { line: 3, column: 0 }, + }, + BindingSyntax { + name: "some_slice".to_owned(), + type_: SyntaxTypeRef::Name { + name: "something".to_owned(), + location: Location { + line: 4, + column: 16 + }, + }, + direction: BindDirection::Out, + from: BindingRefSyntax::Slice( + Box::new(BindingRefSyntax::Name("a".to_owned())), + Box::new(BindingRefSyntax::Name("b".to_owned())) + ), + location: Location { line: 4, column: 0 }, } ], location: Location { line: 1, column: 0 }, diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index c68440dad..17fd93266 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -156,8 +156,9 @@ pub struct FuncBinding { #[derive(Debug, PartialEq, Eq, Clone)] pub enum BindingRef { - Ptr(String), // Treat the argument of that name as a pointer - Value(String), // Treat the argument of that name as a value + Ptr(String), // Treat the argument of that name as a pointer + Slice(String, String), // Treat first argument as a pointer, second as the length + Value(String), // Treat the argument of that name as a value } #[derive(Debug, PartialEq, Eq, Clone)] diff --git a/lucet-idl/tests/example.idl b/lucet-idl/tests/example.idl index 55a48e147..be8996386 100644 --- a/lucet-idl/tests/example.idl +++ b/lucet-idl/tests/example.idl @@ -28,4 +28,8 @@ mod example { fn set_color(to: i32) -> r: i32; fn get_structure(of: i32) -> s: i32; + + fn debug_str(ptr: i32, len: i32) -> r: i32 + where str: out u8 <- [ptr, len]; + } From 1774274d849f101dd0f7dbea9012e6ff98dc0c15 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 12 Jul 2019 14:40:18 -0700 Subject: [PATCH 298/512] lucet-idl: C backend emits abi-level func decl --- lucet-idl/src/c.rs | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/lucet-idl/src/c.rs b/lucet-idl/src/c.rs index 7ec3696ee..5f35a9ded 100644 --- a/lucet-idl/src/c.rs +++ b/lucet-idl/src/c.rs @@ -6,8 +6,8 @@ use crate::module::Module; use crate::package::Package; use crate::pretty_writer::PrettyWriter; use crate::types::{ - AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, FuncDecl, Named, - StructDataType, + AbiType, AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, + FuncDecl, Named, StructDataType, }; use std::io::prelude::*; @@ -148,12 +148,28 @@ impl CGenerator { Ok(()) } - fn gen_function( - &mut self, - _module: &Module, - _func_decl_entry: &Named, - ) -> Result<(), IDLError> { - // UNIMPLEMENTED!! + /// Currently support generating ABI level definition for C guests. Bindings not supported. + fn gen_function(&mut self, _module: &Module, func: &Named) -> Result<(), IDLError> { + let func = func.entity; + + let return_decl = match func.rets.len() { + 0 => "void", + 1 => abi_type_name(&func.rets[0].type_), + _ => unreachable!("functions limited to 0 or 1 return arguments"), + }; + + let arg_list = func + .args + .iter() + .map(|a| format!("{} {}", abi_type_name(&a.type_), a.name)) + .collect::>() + .join(","); + + self.w.writeln(format!( + "extern {} {}({});", + return_decl, func.binding_name, arg_list, + ))?; + Ok(()) } @@ -204,6 +220,15 @@ impl CGenerator { } } +fn abi_type_name(abi_type: &AbiType) -> &'static str { + match abi_type { + AbiType::I32 => atom_type_name(&AtomType::I32), + AbiType::I64 => atom_type_name(&AtomType::I64), + AbiType::F32 => atom_type_name(&AtomType::F32), + AbiType::F64 => atom_type_name(&AtomType::F64), + } +} + fn atom_type_name(atom_type: &AtomType) -> &'static str { match atom_type { AtomType::Bool => "bool", From 4a1b501648aff5c7f42b3a4705d6b9c2898ee564 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 16 Jul 2019 13:43:19 -0700 Subject: [PATCH 299/512] lucet-idl: decent progress on defining rust guest funcs --- lucet-idl/src/c.rs | 4 +- lucet-idl/src/rust.rs | 209 ++++++++++++++++++++++++++++++------ lucet-idl/src/types.rs | 38 +++++++ lucet-idl/tests/example.idl | 6 +- 4 files changed, 222 insertions(+), 35 deletions(-) diff --git a/lucet-idl/src/c.rs b/lucet-idl/src/c.rs index 5f35a9ded..1d58e1f2b 100644 --- a/lucet-idl/src/c.rs +++ b/lucet-idl/src/c.rs @@ -163,11 +163,11 @@ impl CGenerator { .iter() .map(|a| format!("{} {}", abi_type_name(&a.type_), a.name)) .collect::>() - .join(","); + .join(", "); self.w.writeln(format!( "extern {} {}({});", - return_decl, func.binding_name, arg_list, + return_decl, func.field_name, arg_list, ))?; Ok(()) diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index 82a95988a..25df5c4e8 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -6,8 +6,8 @@ use crate::module::Module; use crate::package::Package; use crate::pretty_writer::PrettyWriter; use crate::types::{ - AbiType, AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, - FuncDecl, Ident, Named, StructDataType, + AbiType, AliasDataType, AtomType, BindDirection, BindingRef, DataType, DataTypeRef, + DataTypeVariant, EnumDataType, FuncDecl, Ident, Named, StructDataType, }; use heck::{CamelCase, SnakeCase}; use std::collections::HashMap; @@ -30,13 +30,26 @@ impl RustGenerator { pub fn generate_guest(&mut self, package: &Package) -> Result<(), IDLError> { for (_ident, module) in package.modules.iter() { self.generate_datatypes(module)?; + + for fdecl in module.func_decls() { + self.guest_idiomatic_def(module, &fdecl.entity)?; + } + + self.w.writeln("mod abi {")?; + self.w.indent(); + self.w.writeln(format!( + "#[link(wasm_import_module=\"{}\")]", + module.module_name + ))?; self.w.writeln("extern \"C\" {")?; self.w.indent(); for fdecl in module.func_decls() { - self.guest_function_import(module, &fdecl)?; + self.guest_abi_import(module, &fdecl.entity)?; } self.w.eob()?; self.w.writeln("}")?; + self.w.eob()?; + self.w.writeln("}")?; } Ok(()) } @@ -48,7 +61,7 @@ impl RustGenerator { self.w.writeln("lucet_hostcalls! {")?; self.w.indent(); for fdecl in module.func_decls() { - self.host_function_definition(module, &fdecl)?; + self.host_abi_definition(module, &fdecl.entity)?; } self.w.eob()?; self.w.writeln("}")?; @@ -206,14 +219,9 @@ impl RustGenerator { Ok(()) } - fn guest_function_import( - &mut self, - module: &Module, - func_decl_entry: &Named, - ) -> Result<(), IDLError> { - let name = func_decl_entry.name.name.to_snake_case(); + fn guest_abi_import(&mut self, module: &Module, func: &FuncDecl) -> Result<(), IDLError> { let mut args = String::new(); - for a in func_decl_entry.entity.args.iter() { + for a in func.args.iter() { args += &format!( "{}: {},", a.name.to_snake_case(), @@ -221,29 +229,171 @@ impl RustGenerator { ); } - let func_rets = &func_decl_entry.entity.rets; - let rets = if func_rets.len() == 0 { + let rets = if func.rets.len() == 0 { "()" } else { - assert_eq!(func_rets.len(), 1); - Self::abitype_name(&func_rets[0].type_) + assert_eq!(func.rets.len(), 1); + Self::abitype_name(&func.rets[0].type_) }; self.w .writeln("#[no_mangle]")? - .writeln(format!("fn {}({}) -> {};", name, args, rets))?; + .writeln(format!("pub fn {}({}) -> {};", func.field_name, args, rets))?; Ok(()) } - fn host_function_definition( - &mut self, - module: &Module, - func_decl_entry: &Named, - ) -> Result<(), IDLError> { - let name = func_decl_entry.name.name.to_snake_case(); + fn guest_idiomatic_def(&mut self, module: &Module, func: &FuncDecl) -> Result<(), IDLError> { + let mut args = Vec::new(); + + let mut before_abi_call: Vec = Vec::new(); + let mut after_abi_call: Vec = Vec::new(); + + for input in func.bindings_with(BindDirection::In) { + match &input.from { + BindingRef::Ptr(ptr) => { + args.push(format!( + "{}: &{}", + input.name, + self.get_defined_typename(&input.type_) + )); + before_abi_call + .push(format!("let {} = {} as *const _ as i32;", ptr, input.name,)); + } + BindingRef::Slice(ptr, len) => { + args.push(format!( + "{}: &[{}]", + input.name, + self.get_defined_typename(&input.type_) + )); + before_abi_call.push(format!("let {} = {}.as_ptr() as i32;", ptr, input.name,)); + before_abi_call.push(format!("let {} = {}.len() as i32;", len, input.name,)); + } + BindingRef::Value(val) => { + args.push(format!( + "{}: {}", + input.name, + self.get_defined_typename(&input.type_) + )); + before_abi_call.push(format!("// TODO: cast {} to abi type", val,)); + } + } + } + + for io in func.bindings_with(BindDirection::InOut) { + match &io.from { + BindingRef::Ptr(ptr) => { + args.push(format!( + "{}: &mut {}", + io.name, + self.get_defined_typename(&io.type_) + )); + before_abi_call.push(format!( + "// TODO: cast the ref to a pointer, and then to u32 named {}: {:?}", + ptr, io + )); + } + BindingRef::Slice(ptr, len) => { + args.push(format!( + "{}: &mut [{}]", + io.name, + self.get_defined_typename(&io.type_) + )); + before_abi_call.push(format!( + "// TODO: destructure {} into ptr {} and arg {}", + io.name, ptr, len + )); + } + BindingRef::Value(_val) => { + panic!("it should not be possible to have an inout value {:?}", io); + } + } + + args.push(format!("/* FIXME inout binding {:?} */", io)); + } + + for input in func.unbound_args() { + args.push(format!( + "{}: {}", + input.name, + Self::abitype_name(&input.type_) + )); + } + + let mut rets = Vec::new(); + for o in func.bindings_with(BindDirection::Out) { + match &o.from { + BindingRef::Ptr(ptr) => { + rets.push(format!("&'static {}", self.get_defined_typename(&o.type_))); // XXX this should be boxed? need to define allocation protocol like we did in terrarium? + after_abi_call.push(format!( + "// TODO: cast the u32 named {} ptr, then to a ref, {:?}. FALLIBLE!!", + ptr, o + )); + } + BindingRef::Value(val) => { + rets.push(format!("{}", self.get_defined_typename(&o.type_))); + after_abi_call.push(format!( + "// TODO: cast the ret named {} to a value {:?}", + val, o + )); + } + BindingRef::Slice(_ptr, _len) => { + panic!("it should not be possible to have an out slice {:?}", o); + } + } + } + for o in func.unbound_rets() { + rets.push(Self::abitype_name(&o.type_).to_owned()); + } + + let name = func.field_name.to_snake_case(); + let arg_syntax = args.join(", "); + let ret_syntax = if rets.is_empty() { + "Result<(),()>".to_owned() + } else { + assert_eq!(rets.len(), 1); + format!("Result<{},()>", rets[0]) + }; + self.w.writeln(format!( + "pub fn {}({}) -> {} {{", + name, arg_syntax, ret_syntax + ))?; + self.w.indent(); + for l in before_abi_call { + self.w.writeln(l)?; + } + + { + // Do the ABI call + let ret_syntax = if func.rets.is_empty() { + String::new() + } else { + format!("let {} = ", func.rets[0].name) + }; + let arg_syntax = func + .args + .iter() + .map(|a| a.name.clone()) + .collect::>() + .join(", "); + self.w + .writeln(format!("{}abi::{}({});", ret_syntax, name, arg_syntax))?; + } + for l in after_abi_call { + self.w.writeln(l)?; + } + if !func.rets.is_empty() { + self.w + .writeln(format!("Ok({})", func.rets[0].name.clone()))?; + } + self.w.eob()?; + self.w.writeln("}")?; + Ok(()) + } + + fn host_abi_definition(&mut self, module: &Module, func: &FuncDecl) -> Result<(), IDLError> { let mut args = format!("&mut vmctx,"); - for a in func_decl_entry.entity.args.iter() { + for a in func.args.iter() { args += &format!( "{}: {},", a.name.to_snake_case(), @@ -251,22 +401,17 @@ impl RustGenerator { ); } - let func_rets = &func_decl_entry.entity.rets; - let rets = if func_rets.len() == 0 { + let rets = if func.rets.len() == 0 { "()" } else { - assert_eq!(func_rets.len(), 1); - Self::abitype_name(&func_rets[0].type_) + assert_eq!(func.rets.len(), 1); + Self::abitype_name(&func.rets[0].type_) }; self.w.writeln("#[no_mangle]")?.writeln(format!( "// Wasm func {}::{} pub unsafe extern \"C\" fn {}({}) -> {} {{", - module.module_name, - func_decl_entry.entity.field_name, - func_decl_entry.entity.binding_name, - args, - rets + module.module_name, func.field_name, func.binding_name, args, rets ))?; self.w.indent(); diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index 17fd93266..8ae248889 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -146,6 +146,34 @@ pub struct FuncDecl { pub bindings: Vec, } +impl FuncDecl { + pub fn bindings_with(&self, direction: BindDirection) -> impl Iterator { + self.bindings + .iter() + .filter(move |b| b.direction == direction) + } + + fn bound_params(&self) -> Vec { + self.bindings.iter().flat_map(|b| b.referents()).collect() + } + + pub fn unbound_args(&self) -> Vec<&FuncArg> { + let bound = self.bound_params(); + self.args + .iter() + .filter(|a| !bound.contains(&a.name)) + .collect() + } + + pub fn unbound_rets(&self) -> Vec<&FuncArg> { + let bound = self.bound_params(); + self.rets + .iter() + .filter(|a| !bound.contains(&a.name)) + .collect() + } +} + #[derive(Debug, PartialEq, Eq, Clone)] pub struct FuncBinding { pub name: String, @@ -154,6 +182,16 @@ pub struct FuncBinding { pub from: BindingRef, } +impl FuncBinding { + pub fn referents(&self) -> Vec { + match &self.from { + BindingRef::Ptr(s) => vec![s.clone()], + BindingRef::Slice(s1, s2) => vec![s1.clone(), s2.clone()], + BindingRef::Value(s) => vec![s.clone()], + } + } +} + #[derive(Debug, PartialEq, Eq, Clone)] pub enum BindingRef { Ptr(String), // Treat the argument of that name as a pointer diff --git a/lucet-idl/tests/example.idl b/lucet-idl/tests/example.idl index be8996386..455acf9f0 100644 --- a/lucet-idl/tests/example.idl +++ b/lucet-idl/tests/example.idl @@ -27,9 +27,13 @@ mod example { fn set_color(to: i32) -> r: i32; + fn get_color_as_ptr() -> c_ptr: i32 + where color: out color <- *c_ptr; + + fn get_structure(of: i32) -> s: i32; fn debug_str(ptr: i32, len: i32) -> r: i32 - where str: out u8 <- [ptr, len]; + where str: in u8 <- [ptr, len]; } From 0081a2a66e37724b44f45ad93282b320891a1dd9 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 16 Jul 2019 16:14:57 -0700 Subject: [PATCH 300/512] lucet-idl: refactoring bindings repr, unbound params get implicit binding this simplifies code generation a lot --- lucet-idl/src/function.rs | 214 ++++++++++++++++++++++++++---------- lucet-idl/src/module.rs | 136 ++++++++++------------- lucet-idl/src/parser.rs | 25 +++-- lucet-idl/src/rust.rs | 62 ++++++----- lucet-idl/src/types.rs | 87 ++------------- lucet-idl/tests/example.idl | 4 +- 6 files changed, 282 insertions(+), 246 deletions(-) diff --git a/lucet-idl/src/function.rs b/lucet-idl/src/function.rs index 8c1ad6b4d..bcb5e98f1 100644 --- a/lucet-idl/src/function.rs +++ b/lucet-idl/src/function.rs @@ -1,30 +1,24 @@ use crate::error::ValidationError; use crate::module::Module; -use crate::parser::{BindingRefSyntax, BindingSyntax, FuncArgSyntax}; -use crate::types::{ - AbiType, BindDirection, BindingRef, DataTypeRef, FuncArg, FuncBinding, Location, -}; +use crate::parser::{BindingDirSyntax, BindingRefSyntax, BindingSyntax, FuncArgSyntax}; +use crate::types::{AbiType, DataTypeRef, Location}; use std::collections::HashMap; use std::ops::Deref; -#[derive(Debug, Clone, PartialEq, Eq)] -enum Position { - Arg(usize), - Ret(usize), -} - struct FuncValidator<'a> { // arg name to declaration location and argument position - arg_names: HashMap, + arg_names: HashMap, // Arg positions index into this vector: args: Vec, // Ret positions index into this vector: rets: Vec, // binding name to binding_names: HashMap, - // arg name to binding location - arg_use_sites: HashMap, - bindings: Vec, + // param position to binding syntax + param_binding_sites: HashMap, + in_bindings: Vec, + inout_bindings: Vec, + out_bindings: Vec, location: &'a Location, module: &'a Module, } @@ -36,8 +30,10 @@ impl<'a> FuncValidator<'a> { args: Vec::new(), rets: Vec::new(), binding_names: HashMap::new(), - bindings: Vec::new(), - arg_use_sites: HashMap::new(), + in_bindings: Vec::new(), + inout_bindings: Vec::new(), + out_bindings: Vec::new(), + param_binding_sites: HashMap::new(), location, module, } @@ -45,7 +41,7 @@ impl<'a> FuncValidator<'a> { fn introduce_arg_name( &mut self, arg_syntax: &FuncArgSyntax, - position: Position, + position: ParamPosition, ) -> Result { if let Some((previous_location, _)) = self.arg_names.get(&arg_syntax.name) { Err(ValidationError::NameAlreadyExists { @@ -67,7 +63,7 @@ impl<'a> FuncValidator<'a> { fn introduce_args(&mut self, args: &[FuncArgSyntax]) -> Result<(), ValidationError> { for (ix, a) in args.iter().enumerate() { - let a = self.introduce_arg_name(a, Position::Arg(ix))?; + let a = self.introduce_arg_name(a, ParamPosition::Arg(ix))?; self.args.push(a); } Ok(()) @@ -80,7 +76,7 @@ impl<'a> FuncValidator<'a> { })? } for (ix, r) in rets.iter().enumerate() { - let r = self.introduce_arg_name(r, Position::Ret(ix))?; + let r = self.introduce_arg_name(r, ParamPosition::Ret(ix))?; self.rets.push(r); } Ok(()) @@ -89,7 +85,25 @@ impl<'a> FuncValidator<'a> { fn introduce_bindings(&mut self, bindings: &[BindingSyntax]) -> Result<(), ValidationError> { for (ix, binding) in bindings.iter().enumerate() { let b = self.introduce_binding(binding, ix)?; - self.bindings.push(b); + match binding.direction { + BindingDirSyntax::In => self.in_bindings.push(b), + BindingDirSyntax::InOut => self.inout_bindings.push(b), + BindingDirSyntax::Out => self.out_bindings.push(b), + } + } + for (ix, arg) in self.args.iter().enumerate() { + let position = ParamPosition::Arg(ix); + if !self.param_binding_sites.contains_key(&position) { + self.in_bindings + .push(self.implicit_value_binding(&arg, position)?); + } + } + for (ix, ret) in self.rets.iter().enumerate() { + let position = ParamPosition::Ret(ix); + if !self.param_binding_sites.contains_key(&position) { + self.out_bindings + .push(self.implicit_value_binding(&ret, position)?); + } } Ok(()) } @@ -119,20 +133,49 @@ impl<'a> FuncValidator<'a> { Ok(FuncBinding { name: binding.name.clone(), - direction: binding.direction.clone(), type_, from, }) } - fn get_arg(&self, arg_name: &String) -> Option<(Position, FuncArg)> { + fn implicit_value_binding( + &self, + arg: &FuncArg, + position: ParamPosition, + ) -> Result { + // 1. make sure binding name is unique. We're re-using the arg name + // for the binding. If another binding overlapped with the arg name, + // it is now at fault. (complicated, huh... :/) + if let Some((previous_location, _)) = self.binding_names.get(&arg.name) { + let (arg_location, _) = self.arg_names.get(&arg.name).expect("arg introduced"); + Err(ValidationError::BindingNameAlreadyBound { + name: arg.name.clone(), + at_location: previous_location.clone(), + bound_location: arg_location.clone(), + })?; + } + + // 2. resolve type + let type_ = DataTypeRef::Atom(arg.type_.into()); + + // 3. no need to validate ref- we can construct it ourselves + let from = BindingRef::Value(position); + + Ok(FuncBinding { + name: arg.name.clone(), + type_, + from, + }) + } + + fn get_arg(&self, arg_name: &String) -> Option<(ParamPosition, FuncArg)> { let (_, position) = self.arg_names.get(arg_name)?; match position { - Position::Arg(ix) => Some(( + ParamPosition::Arg(ix) => Some(( position.clone(), self.args.get(*ix).expect("in-bounds arg index").clone(), )), - Position::Ret(ix) => Some(( + ParamPosition::Ret(ix) => Some(( position.clone(), self.rets.get(*ix).expect("in-bounds ret index").clone(), )), @@ -143,23 +186,24 @@ impl<'a> FuncValidator<'a> { &mut self, name: &String, location: &Location, - ) -> Result<(Position, FuncArg), ValidationError> { + ) -> Result<(ParamPosition, FuncArg), ValidationError> { // Check that it refers to a valid arg: - let pos_and_arg = self.get_arg(name).ok_or_else(|| ValidationError::Syntax { + let (position, arg) = self.get_arg(name).ok_or_else(|| ValidationError::Syntax { expected: "name of an argument or return value", location: location.clone(), })?; // Check that the arg has only been used once: - if let Some(use_location) = self.arg_use_sites.get(name) { + if let Some(use_location) = self.param_binding_sites.get(&position) { Err(ValidationError::BindingNameAlreadyBound { name: name.clone(), at_location: location.clone(), bound_location: use_location.clone(), })?; } else { - self.arg_use_sites.insert(name.clone(), location.clone()); + self.param_binding_sites + .insert(position.clone(), location.clone()); } - Ok(pos_and_arg) + Ok((position, arg)) } fn validate_binding_ref( @@ -180,19 +224,17 @@ impl<'a> FuncValidator<'a> { })?; } match position { - Position::Arg(_) => { + ParamPosition::Arg(_) => { // all good! Arg pointers are valid for in, inout, or out binding. } - Position::Ret(_) => { - if binding.direction != BindDirection::Out { - Err(ValidationError::BindingTypeError { - expected: "return pointer must be output-only binding", - location: binding.location.clone(), - })?; - } + ParamPosition::Ret(_) => { + Err(ValidationError::BindingTypeError { + expected: "return value cannot be bound to pointer", + location: binding.location.clone(), + })?; } } - Ok(BindingRef::Ptr(name.clone())) + Ok(BindingRef::Ptr(position)) } _ => Err(ValidationError::Syntax { expected: "pointer binding must be of form *arg", @@ -222,8 +264,8 @@ impl<'a> FuncValidator<'a> { location: binding.location.clone(), })?; } - match (ptr_position, len_position) { - (Position::Arg(_), Position::Arg(_)) => {} + match (&ptr_position, &len_position) { + (ParamPosition::Arg(_), ParamPosition::Arg(_)) => {} _ => { Err(ValidationError::BindingTypeError { expected: "slice bindings must be inputs", @@ -231,7 +273,7 @@ impl<'a> FuncValidator<'a> { })?; } } - Ok(BindingRef::Slice(ptr_name.to_owned(), len_name.to_owned())) + Ok(BindingRef::Slice(ptr_position, len_position)) } ( BindingRefSyntax::Name(ref _ptr_name), @@ -275,16 +317,16 @@ impl<'a> FuncValidator<'a> { } // Arg values must be in-only bindings, Ret values must be out-only bindings match position { - Position::Arg(_) => { - if binding.direction != BindDirection::In { + ParamPosition::Arg(_) => { + if binding.direction != BindingDirSyntax::In { Err(ValidationError::BindingTypeError { expected: "argument value must be input-only binding", location: binding.location.clone(), })?; } } - Position::Ret(_) => { - if binding.direction != BindDirection::Out { + ParamPosition::Ret(_) => { + if binding.direction != BindingDirSyntax::Out { Err(ValidationError::BindingTypeError { expected: "return value must be output-only binding", location: binding.location.clone(), @@ -292,23 +334,79 @@ impl<'a> FuncValidator<'a> { } } } - Ok(BindingRef::Value(name.clone())) + Ok(BindingRef::Value(position)) } } } } -pub fn validate_func_args( - args: &[FuncArgSyntax], - rets: &[FuncArgSyntax], - bindings: &[BindingSyntax], - location: &Location, - module: &Module, -) -> Result<(Vec, Vec, Vec), ValidationError> { - let mut validator = FuncValidator::new(location, module); - validator.introduce_args(args)?; - validator.introduce_rets(rets)?; - validator.introduce_bindings(bindings)?; +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct FuncArg { + pub name: String, + pub type_: AbiType, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct FuncBinding { + pub name: String, + pub type_: DataTypeRef, + pub from: BindingRef, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum BindingRef { + Ptr(ParamPosition), // Treat the argument of that name as a pointer + Slice(ParamPosition, ParamPosition), // Treat first argument as a pointer, second as the length + Value(ParamPosition), // Treat the argument of that name as a value +} - Ok((validator.args, validator.rets, validator.bindings)) +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum ParamPosition { + Arg(usize), + Ret(usize), +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct FuncDecl { + pub field_name: String, + pub binding_name: String, + pub args: Vec, + pub rets: Vec, + pub in_bindings: Vec, + pub inout_bindings: Vec, + pub out_bindings: Vec, +} + +impl FuncDecl { + pub fn from_syntax( + field_name: String, + binding_name: String, + args: &[FuncArgSyntax], + rets: &[FuncArgSyntax], + bindings: &[BindingSyntax], + location: &Location, + module: &Module, + ) -> Result { + let mut validator = FuncValidator::new(location, module); + validator.introduce_args(args)?; + validator.introduce_rets(rets)?; + validator.introduce_bindings(bindings)?; + + Ok(FuncDecl { + field_name, + binding_name, + args: validator.args, + rets: validator.rets, + in_bindings: validator.in_bindings, + inout_bindings: validator.inout_bindings, + out_bindings: validator.out_bindings, + }) + } + + pub fn get_param(&self, loc: &ParamPosition) -> Option<&FuncArg> { + match loc { + ParamPosition::Arg(a) => self.args.get(*a), + ParamPosition::Ret(r) => self.rets.get(*r), + } + } } diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index cdd3a5053..131e7c987 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -2,11 +2,10 @@ use crate::data_layout::{ AliasIR, DataTypeModuleBuilder, EnumIR, StructIR, StructMemberIR, VariantIR, }; use crate::error::ValidationError; -use crate::function::validate_func_args; +use crate::function::FuncDecl; use crate::parser::{SyntaxDecl, SyntaxTypeRef}; use crate::types::{ - AbiType, DataType, DataTypeRef, DataTypeVariant, EnumMember, FuncDecl, Ident, Location, Name, - Named, + AbiType, DataType, DataTypeRef, DataTypeVariant, EnumMember, Ident, Location, Name, Named, }; use heck::SnakeCase; use std::collections::HashMap; @@ -205,16 +204,16 @@ impl Module { location, bindings, } => { - let (args, rets, bindings) = - validate_func_args(args, rets, bindings, location, self)?; let binding_name = self.binding_prefix.clone() + "_" + &name.to_snake_case(); - let decl = FuncDecl { - field_name: name.clone(), + let decl = FuncDecl::from_syntax( + name.clone(), binding_name, args, rets, bindings, - }; + location, + self, + )?; if let Some(prev_def) = funcs_ir.insert(id, decl) { panic!("id {} already defined: {:?}", id, prev_def) } @@ -305,12 +304,9 @@ impl Module { #[cfg(test)] mod tests { use super::*; + use crate::function::{BindingRef, FuncArg, FuncBinding, ParamPosition}; use crate::parser::Parser; - use crate::types::{ - AbiType, AtomType, BindDirection, BindingRef, DataTypeVariant, FuncArg, FuncBinding, - StructDataType, StructMember, - }; - + use crate::types::{AbiType, AtomType, DataTypeVariant, StructDataType, StructMember}; fn mod_(syntax: &str) -> Result { let mut parser = Parser::new(syntax); let decls = parser.match_decls().expect("parses"); @@ -524,7 +520,9 @@ mod tests { field_name: "trivial".to_owned(), args: Vec::new(), rets: Vec::new(), - bindings: Vec::new(), + in_bindings: Vec::new(), + inout_bindings: Vec::new(), + out_bindings: Vec::new(), } )] .into_iter() @@ -555,7 +553,13 @@ mod tests { name: "a".to_owned(), }], rets: Vec::new(), - bindings: Vec::new(), + in_bindings: vec![FuncBinding { + name: "a".to_owned(), + type_: DataTypeRef::Atom(AtomType::I64), + from: BindingRef::Value(ParamPosition::Arg(0)), + },], + inout_bindings: Vec::new(), + out_bindings: Vec::new(), } )] .into_iter() @@ -587,7 +591,13 @@ mod tests { name: "r".to_owned(), type_: AbiType::I64, }], - bindings: Vec::new(), + in_bindings: Vec::new(), + inout_bindings: Vec::new(), + out_bindings: vec![FuncBinding { + name: "r".to_owned(), + type_: DataTypeRef::Atom(AtomType::I64), + from: BindingRef::Value(ParamPosition::Ret(0)), + },] } )] .into_iter() @@ -652,12 +662,13 @@ mod tests { name: "a".to_owned(), }], rets: Vec::new(), - bindings: vec![FuncBinding { + in_bindings: vec![FuncBinding { name: "a_binding".to_owned(), type_: DataTypeRef::Atom(AtomType::I8), - direction: BindDirection::In, - from: BindingRef::Value("a".to_owned()), + from: BindingRef::Value(ParamPosition::Arg(0)), }], + inout_bindings: Vec::new(), + out_bindings: Vec::new(), } )] .into_iter() @@ -691,12 +702,13 @@ mod tests { name: "a".to_owned(), }], rets: Vec::new(), - bindings: vec![FuncBinding { + in_bindings: Vec::new(), + inout_bindings: vec![FuncBinding { name: "a_binding".to_owned(), type_: DataTypeRef::Atom(AtomType::I8), - direction: BindDirection::InOut, - from: BindingRef::Ptr("a".to_owned()), + from: BindingRef::Ptr(ParamPosition::Arg(0)), }], + out_bindings: Vec::new(), } )] .into_iter() @@ -797,11 +809,12 @@ mod tests { type_: AbiType::I32, name: "a".to_owned(), }], - bindings: vec![FuncBinding { + in_bindings: Vec::new(), + inout_bindings: Vec::new(), + out_bindings: vec![FuncBinding { name: "a_binding".to_owned(), type_: DataTypeRef::Atom(AtomType::I8), - direction: BindDirection::Out, - from: BindingRef::Value("a".to_owned()), + from: BindingRef::Value(ParamPosition::Ret(0)), }], } )] @@ -819,37 +832,11 @@ mod tests { fn func_one_ret_pointer_binding() { assert_eq!( mod_("fn trivial() -> a: i32 where\na_binding: out i8 <- *a;") - .ok() + .err() .unwrap(), - Module { - names: vec![Name { - name: "trivial".to_owned(), - location: Location { line: 1, column: 0 } - }], - funcs: vec![( - Ident(0), - FuncDecl { - binding_name: "_trivial".to_owned(), - field_name: "trivial".to_owned(), - args: Vec::new(), - rets: vec![FuncArg { - type_: AbiType::I32, - name: "a".to_owned(), - }], - bindings: vec![FuncBinding { - name: "a_binding".to_owned(), - type_: DataTypeRef::Atom(AtomType::I8), - direction: BindDirection::Out, - from: BindingRef::Ptr("a".to_owned()), - }], - } - )] - .into_iter() - .collect::>(), - data_types: HashMap::new(), - data_type_ordering: Vec::new(), - module_name: String::new(), - binding_prefix: String::new(), + ValidationError::BindingTypeError { + expected: "return value cannot be bound to pointer", + location: Location { line: 2, column: 0 }, } ); } @@ -895,12 +882,13 @@ mod tests { } ], rets: Vec::new(), - bindings: vec![FuncBinding { + in_bindings: Vec::new(), + inout_bindings: vec![FuncBinding { name: "a_binding".to_owned(), type_: DataTypeRef::Atom(AtomType::I8), - direction: BindDirection::InOut, - from: BindingRef::Slice("a_ptr".to_owned(), "a_len".to_owned()), + from: BindingRef::Slice(ParamPosition::Arg(0), ParamPosition::Arg(1)), }], + out_bindings: Vec::new(), } )] .into_iter() @@ -921,7 +909,7 @@ mod tests { a_binding: out u8 <- *a,\n\ b_binding: inout u16 <- *b,\n\ c_binding: in f32 <- c,\n\ - d_binding: out i8 <- *d;\n\ + d_binding: out i8 <- d;\n\ " ) .ok() @@ -954,30 +942,26 @@ mod tests { type_: AbiType::I32, name: "d".to_owned(), }], - bindings: vec![ + in_bindings: vec![FuncBinding { + name: "c_binding".to_owned(), + type_: DataTypeRef::Atom(AtomType::F32), + from: BindingRef::Value(ParamPosition::Arg(2)), + },], + inout_bindings: vec![FuncBinding { + name: "b_binding".to_owned(), + type_: DataTypeRef::Atom(AtomType::U16), + from: BindingRef::Ptr(ParamPosition::Arg(1)), + },], + out_bindings: vec![ FuncBinding { name: "a_binding".to_owned(), type_: DataTypeRef::Atom(AtomType::U8), - direction: BindDirection::Out, - from: BindingRef::Ptr("a".to_owned()), - }, - FuncBinding { - name: "b_binding".to_owned(), - type_: DataTypeRef::Atom(AtomType::U16), - direction: BindDirection::InOut, - from: BindingRef::Ptr("b".to_owned()), - }, - FuncBinding { - name: "c_binding".to_owned(), - type_: DataTypeRef::Atom(AtomType::F32), - direction: BindDirection::In, - from: BindingRef::Value("c".to_owned()), + from: BindingRef::Ptr(ParamPosition::Arg(0)), }, FuncBinding { name: "d_binding".to_owned(), type_: DataTypeRef::Atom(AtomType::I8), - direction: BindDirection::Out, - from: BindingRef::Ptr("d".to_owned()), + from: BindingRef::Value(ParamPosition::Ret(0)), }, ], } diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index 52b1302ad..4f9c3ed49 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -1,5 +1,5 @@ use super::lexer::{LexError, Lexer, LocatedError, LocatedToken, Token}; -use super::types::{AbiType, AtomType, BindDirection, Location}; +use super::types::{AbiType, AtomType, Location}; use std::error::Error; use std::fmt; @@ -93,11 +93,18 @@ pub struct ParseError { pub message: String, } +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum BindingDirSyntax { + In, + Out, + InOut, +} + #[derive(Debug, PartialEq, Eq, Clone)] pub struct BindingSyntax { pub name: String, pub type_: SyntaxTypeRef, - pub direction: BindDirection, + pub direction: BindingDirSyntax, pub from: BindingRefSyntax, pub location: Location, } @@ -388,19 +395,19 @@ impl<'a> Parser<'a> { Ok(bindings) } - fn match_bind_direction(&mut self) -> Result { + fn match_bind_direction(&mut self) -> Result { match self.token() { Some(Token::Word("in")) => { self.consume(); - Ok(BindDirection::In) + Ok(BindingDirSyntax::In) } Some(Token::Word("inout")) | Some(Token::Word("io")) => { self.consume(); - Ok(BindDirection::InOut) + Ok(BindingDirSyntax::InOut) } Some(Token::Word("out")) => { self.consume(); - Ok(BindDirection::Out) + Ok(BindingDirSyntax::Out) } _ => parse_err!( self.location, @@ -1183,7 +1190,7 @@ mod tests { name: "file_t".to_owned(), location: Location { line: 2, column: 9 }, }, - direction: BindDirection::In, + direction: BindingDirSyntax::In, from: BindingRefSyntax::Ptr(Box::new(BindingRefSyntax::Name( "fptr".to_owned() ))), @@ -1195,7 +1202,7 @@ mod tests { atom: AtomType::U8, location: Location { line: 3, column: 7 }, }, - direction: BindDirection::Out, + direction: BindingDirSyntax::Out, from: BindingRefSyntax::Name("r".to_owned()), location: Location { line: 3, column: 0 }, }, @@ -1208,7 +1215,7 @@ mod tests { column: 16 }, }, - direction: BindDirection::Out, + direction: BindingDirSyntax::Out, from: BindingRefSyntax::Slice( Box::new(BindingRefSyntax::Name("a".to_owned())), Box::new(BindingRefSyntax::Name("b".to_owned())) diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index 25df5c4e8..8349249c8 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -2,12 +2,13 @@ #![allow(unused_variables)] use crate::error::IDLError; +use crate::function::{BindingRef, FuncDecl}; use crate::module::Module; use crate::package::Package; use crate::pretty_writer::PrettyWriter; use crate::types::{ - AbiType, AliasDataType, AtomType, BindDirection, BindingRef, DataType, DataTypeRef, - DataTypeVariant, EnumDataType, FuncDecl, Ident, Named, StructDataType, + AbiType, AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, Ident, + Named, StructDataType, }; use heck::{CamelCase, SnakeCase}; use std::collections::HashMap; @@ -249,58 +250,71 @@ impl RustGenerator { let mut before_abi_call: Vec = Vec::new(); let mut after_abi_call: Vec = Vec::new(); - for input in func.bindings_with(BindDirection::In) { + for input in func.in_bindings.iter() { match &input.from { BindingRef::Ptr(ptr) => { + let ptr = func.get_param(ptr).expect("valid param"); args.push(format!( "{}: &{}", input.name, self.get_defined_typename(&input.type_) )); - before_abi_call - .push(format!("let {} = {} as *const _ as i32;", ptr, input.name,)); + before_abi_call.push(format!( + "let {} = {} as *const _ as i32;", + ptr.name, input.name, + )); } BindingRef::Slice(ptr, len) => { + let ptr = func.get_param(ptr).expect("valid param"); + let len = func.get_param(len).expect("lenid param"); args.push(format!( "{}: &[{}]", input.name, self.get_defined_typename(&input.type_) )); - before_abi_call.push(format!("let {} = {}.as_ptr() as i32;", ptr, input.name,)); - before_abi_call.push(format!("let {} = {}.len() as i32;", len, input.name,)); + before_abi_call.push(format!( + "let {} = {}.as_ptr() as i32;", + ptr.name, input.name, + )); + before_abi_call + .push(format!("let {} = {}.len() as i32;", len.name, input.name,)); } BindingRef::Value(val) => { + let val = func.get_param(val).expect("valid param"); args.push(format!( "{}: {}", input.name, self.get_defined_typename(&input.type_) )); - before_abi_call.push(format!("// TODO: cast {} to abi type", val,)); + before_abi_call.push(format!("// TODO: cast {:?} to abi type", val,)); } } } - for io in func.bindings_with(BindDirection::InOut) { + for io in func.inout_bindings.iter() { match &io.from { BindingRef::Ptr(ptr) => { + let ptr = func.get_param(ptr).expect("valid param"); args.push(format!( "{}: &mut {}", io.name, self.get_defined_typename(&io.type_) )); before_abi_call.push(format!( - "// TODO: cast the ref to a pointer, and then to u32 named {}: {:?}", + "// TODO: cast the ref to a pointer, and then to u32 {:?}: {:?}", ptr, io )); } BindingRef::Slice(ptr, len) => { + let ptr = func.get_param(ptr).expect("ptrid param"); + let len = func.get_param(len).expect("lenid param"); args.push(format!( "{}: &mut [{}]", io.name, self.get_defined_typename(&io.type_) )); before_abi_call.push(format!( - "// TODO: destructure {} into ptr {} and arg {}", + "// TODO: destructure {} into ptr {:?} and arg {:?}", io.name, ptr, len )); } @@ -312,28 +326,27 @@ impl RustGenerator { args.push(format!("/* FIXME inout binding {:?} */", io)); } - for input in func.unbound_args() { - args.push(format!( - "{}: {}", - input.name, - Self::abitype_name(&input.type_) - )); - } - let mut rets = Vec::new(); - for o in func.bindings_with(BindDirection::Out) { + for o in func.out_bindings.iter() { match &o.from { BindingRef::Ptr(ptr) => { - rets.push(format!("&'static {}", self.get_defined_typename(&o.type_))); // XXX this should be boxed? need to define allocation protocol like we did in terrarium? + let ptr = func.get_param(ptr).expect("valid param"); + let otypename = self.get_defined_typename(&o.type_); + rets.push(otypename.clone()); + before_abi_call.push(format!( + "let mut {} = ::std::mem::MaybeUninit::<{}>::uninit();", + ptr.name, otypename + )); after_abi_call.push(format!( - "// TODO: cast the u32 named {} ptr, then to a ref, {:?}. FALLIBLE!!", + "// TODO: cast the u32 {:?} ptr, then to a ref, {:?}. FALLIBLE!!", ptr, o )); } BindingRef::Value(val) => { + let val = func.get_param(val).expect("valid param"); rets.push(format!("{}", self.get_defined_typename(&o.type_))); after_abi_call.push(format!( - "// TODO: cast the ret named {} to a value {:?}", + "// TODO: cast the ret {:?} to a value {:?}", val, o )); } @@ -342,9 +355,6 @@ impl RustGenerator { } } } - for o in func.unbound_rets() { - rets.push(Self::abitype_name(&o.type_).to_owned()); - } let name = func.field_name.to_snake_case(); let arg_syntax = args.join(", "); diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index 8ae248889..22af184f8 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -1,3 +1,4 @@ +pub use crate::function::{BindingRef, FuncArg, FuncDecl, ParamPosition}; use std::fmt; #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -69,6 +70,17 @@ impl AbiType { } } +impl From for AtomType { + fn from(abi: AbiType) -> AtomType { + match abi { + AbiType::I32 => AtomType::I32, + AbiType::I64 => AtomType::I64, + AbiType::F32 => AtomType::F32, + AbiType::F64 => AtomType::F64, + } + } +} + #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] pub struct Location { pub line: usize, @@ -131,81 +143,6 @@ pub struct DataType { pub align: usize, } -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct FuncArg { - pub name: String, - pub type_: AbiType, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct FuncDecl { - pub field_name: String, - pub binding_name: String, - pub args: Vec, - pub rets: Vec, - pub bindings: Vec, -} - -impl FuncDecl { - pub fn bindings_with(&self, direction: BindDirection) -> impl Iterator { - self.bindings - .iter() - .filter(move |b| b.direction == direction) - } - - fn bound_params(&self) -> Vec { - self.bindings.iter().flat_map(|b| b.referents()).collect() - } - - pub fn unbound_args(&self) -> Vec<&FuncArg> { - let bound = self.bound_params(); - self.args - .iter() - .filter(|a| !bound.contains(&a.name)) - .collect() - } - - pub fn unbound_rets(&self) -> Vec<&FuncArg> { - let bound = self.bound_params(); - self.rets - .iter() - .filter(|a| !bound.contains(&a.name)) - .collect() - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct FuncBinding { - pub name: String, - pub type_: DataTypeRef, - pub direction: BindDirection, - pub from: BindingRef, -} - -impl FuncBinding { - pub fn referents(&self) -> Vec { - match &self.from { - BindingRef::Ptr(s) => vec![s.clone()], - BindingRef::Slice(s1, s2) => vec![s1.clone(), s2.clone()], - BindingRef::Value(s) => vec![s.clone()], - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum BindingRef { - Ptr(String), // Treat the argument of that name as a pointer - Slice(String, String), // Treat first argument as a pointer, second as the length - Value(String), // Treat the argument of that name as a value -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum BindDirection { - In, - Out, - InOut, -} - #[derive(Debug, PartialEq, Eq, Clone)] pub struct Name { pub name: String, diff --git a/lucet-idl/tests/example.idl b/lucet-idl/tests/example.idl index 455acf9f0..7aeb61001 100644 --- a/lucet-idl/tests/example.idl +++ b/lucet-idl/tests/example.idl @@ -27,8 +27,8 @@ mod example { fn set_color(to: i32) -> r: i32; - fn get_color_as_ptr() -> c_ptr: i32 - where color: out color <- *c_ptr; + fn get_color_by_ptr(color_ptr: i32) + where color: out color <- *color_ptr; fn get_structure(of: i32) -> s: i32; From 63018193926a7b5db77d4ce26706a98e21f1770a Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 17 Jul 2019 11:47:47 -0700 Subject: [PATCH 301/512] lucet-idl: pretty-writer doesnt need to be fallible we dont handle the error any differently, and we really are just going to panic, so lets not muddy the syntax unnecessarily --- lucet-idl/src/c.rs | 74 ++++++++--------- lucet-idl/src/pretty_writer.rs | 33 ++++---- lucet-idl/src/rust.rs | 141 ++++++++++++++++----------------- 3 files changed, 123 insertions(+), 125 deletions(-) diff --git a/lucet-idl/src/c.rs b/lucet-idl/src/c.rs index 1d58e1f2b..3f4e010d4 100644 --- a/lucet-idl/src/c.rs +++ b/lucet-idl/src/c.rs @@ -25,9 +25,9 @@ impl CGenerator { #include #include "; for line in prelude.lines() { - w.write_line(line.as_ref()).unwrap(); + w.write_line(line.as_ref()); } - w.eob().unwrap(); + w.eob(); Self { w } } @@ -50,9 +50,9 @@ impl CGenerator { fn gen_type_header(&mut self, _module: &Module, dt: &Named) -> Result<(), IDLError> { self.w - .eob()? - .writeln(format!("// ---------- {} ----------", dt.name.name))? - .eob()?; + .eob() + .writeln(format!("// ---------- {} ----------", dt.name.name)) + .eob(); Ok(()) } @@ -65,19 +65,21 @@ impl CGenerator { alias: &AliasDataType, ) -> Result<(), IDLError> { let dtname = self.type_name(dt); - self.w.writeln(format!( - "typedef {} {};", - self.type_ref_name(module, &alias.to), - dtname - ))?; - self.w.eob()?; + self.w + .writeln(format!( + "typedef {} {};", + self.type_ref_name(module, &alias.to), + dtname + )) + .eob(); // Add an assertion to check that resolved size is the one we computed - self.w.writeln(format!( - "_Static_assert(sizeof({}) == {}, \"unexpected alias size\");", - dtname, dt.entity.repr_size - ))?; - self.w.eob()?; + self.w + .writeln(format!( + "_Static_assert(sizeof({}) == {}, \"unexpected alias size\");", + dtname, dt.entity.repr_size + )) + .eob(); Ok(()) } @@ -89,32 +91,32 @@ impl CGenerator { struct_: &StructDataType, ) -> Result<(), IDLError> { let dtname = self.type_name(dt); - self.w.writeln(format!("{} {{", dtname))?; + self.w.writeln(format!("{} {{", dtname)); let mut w_block = self.w.new_block(); for member in struct_.members.iter() { w_block.writeln(format!( "{} {};", self.type_ref_name(module, &member.type_), member.name - ))?; + )); } - self.w.writeln("};")?; - self.w.eob()?; + self.w.writeln("};").eob(); // Skip the first member, as it will always be at the beginning of the structure for (i, member) in struct_.members.iter().enumerate().skip(1) { self.w.writeln(format!( "_Static_assert(offsetof({}, {}) == {}, \"unexpected offset\");", dtname, member.name, member.offset - ))?; + )); } let struct_size = dt.entity.repr_size; - self.w.writeln(format!( - "_Static_assert(sizeof({}) == {}, \"unexpected structure size\");", - dtname, struct_size, - ))?; - self.w.eob()?; + self.w + .writeln(format!( + "_Static_assert(sizeof({}) == {}, \"unexpected structure size\");", + dtname, struct_size, + )) + .eob(); Ok(()) } @@ -129,22 +131,22 @@ impl CGenerator { ) -> Result<(), IDLError> { let dtname = self.type_name(dt); let type_size = dt.entity.repr_size; - self.w.writeln(format!("{} {{", dtname))?; + self.w.writeln(format!("{} {{", dtname)); let mut pretty_writer_i1 = self.w.new_block(); for (i, named_member) in enum_.members.iter().enumerate() { pretty_writer_i1.writeln(format!( "{}, // {}", macro_for(&dt.name.name, &named_member.name), i - ))?; + )); } - self.w.writeln("};")?; - self.w.eob()?; - self.w.writeln(format!( - "_Static_assert(sizeof({}) == {}, \"unexpected enumeration size\");", - dtname, type_size - ))?; - self.w.eob()?; + self.w.writeln("};").eob(); + self.w + .writeln(format!( + "_Static_assert(sizeof({}) == {}, \"unexpected enumeration size\");", + dtname, type_size + )) + .eob(); Ok(()) } @@ -168,7 +170,7 @@ impl CGenerator { self.w.writeln(format!( "extern {} {}({});", return_decl, func.field_name, arg_list, - ))?; + )); Ok(()) } diff --git a/lucet-idl/src/pretty_writer.rs b/lucet-idl/src/pretty_writer.rs index 074a5cb22..adcd41aeb 100644 --- a/lucet-idl/src/pretty_writer.rs +++ b/lucet-idl/src/pretty_writer.rs @@ -41,8 +41,11 @@ impl PrettyWriter { self } - fn _write_all(&mut self, buf: &[u8]) -> Result<(), IDLError> { - self.writer.borrow_mut().write_all(buf).map_err(Into::into) + fn _write_all(&mut self, buf: &[u8]) { + self.writer + .borrow_mut() + .write_all(buf) + .expect("pretty_writer write_all") } /// Return the current indentation level @@ -52,24 +55,24 @@ impl PrettyWriter { } /// Output an indentation string - fn write_indent(&mut self) -> Result<&mut Self, IDLError> { + fn write_indent(&mut self) -> &mut Self { let indent_bytes = &self.indent_bytes.clone(); { for _ in 0..self.indent { - self._write_all(indent_bytes)? + self._write_all(indent_bytes) } } - Ok(self) + self } /// Output an end of line - pub fn eol(&mut self) -> Result<&mut Self, IDLError> { - self._write_all(b"\n")?; - Ok(self) + pub fn eol(&mut self) -> &mut Self { + self._write_all(b"\n"); + self } /// Output a block separator - pub fn eob(&mut self) -> Result<&mut Self, IDLError> { + pub fn eob(&mut self) -> &mut Self { if self.indent > 0 { self.indent -= 1; } @@ -77,18 +80,18 @@ impl PrettyWriter { } /// Write raw data - pub fn write(&mut self, buf: &[u8]) -> Result<&mut Self, IDLError> { - self._write_all(buf)?; - Ok(self) + pub fn write(&mut self, buf: &[u8]) -> &mut Self { + self._write_all(buf); + self } /// Indent, write raw data and terminate with an end of line - pub fn write_line(&mut self, buf: &[u8]) -> Result<&mut Self, IDLError> { - self.write_indent()?.write(buf)?.eol() + pub fn write_line(&mut self, buf: &[u8]) -> &mut Self { + self.write_indent().write(buf).eol() } /// Indent, write raw data and terminate with an end of line - pub fn writeln>(&mut self, buf: S) -> Result<&mut Self, IDLError> { + pub fn writeln>(&mut self, buf: S) -> &mut Self { self.write_line(buf.as_ref().as_bytes()) } } diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index 8349249c8..74aeb3d01 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -36,36 +36,34 @@ impl RustGenerator { self.guest_idiomatic_def(module, &fdecl.entity)?; } - self.w.writeln("mod abi {")?; - self.w.indent(); - self.w.writeln(format!( - "#[link(wasm_import_module=\"{}\")]", - module.module_name - ))?; - self.w.writeln("extern \"C\" {")?; - self.w.indent(); + self.w + .writeln("mod abi {") + .indent() + .writeln(format!( + "#[link(wasm_import_module=\"{}\")]", + module.module_name + )) + .writeln("extern \"C\" {") + .indent(); for fdecl in module.func_decls() { - self.guest_abi_import(module, &fdecl.entity)?; + self.guest_abi_import(module, &fdecl.entity); } - self.w.eob()?; - self.w.writeln("}")?; - self.w.eob()?; - self.w.writeln("}")?; + self.w.eob().writeln("}").eob().writeln("}"); } Ok(()) } pub fn generate_host(&mut self, package: &Package) -> Result<(), IDLError> { for (_ident, module) in package.modules.iter() { - self.w.writeln("use lucet_runtime::lucet_hostcalls;")?; + self.w.writeln("use lucet_runtime::lucet_hostcalls;"); self.generate_datatypes(module)?; - self.w.writeln("lucet_hostcalls! {")?; + self.w.writeln("lucet_hostcalls! {"); self.w.indent(); for fdecl in module.func_decls() { self.host_abi_definition(module, &fdecl.entity)?; } - self.w.eob()?; - self.w.writeln("}")?; + self.w.eob(); + self.w.writeln("}"); } Ok(()) } @@ -132,14 +130,14 @@ impl RustGenerator { let pointee_name = self.get_defined_typename(&alias.to); self.w - .writeln(format!("pub type {} = {};", typename, pointee_name))? - .eob()?; + .writeln(format!("pub type {} = {};", typename, pointee_name)) + .eob(); gen_testcase(&mut self.w, &dt.name.name.to_snake_case(), move |w| { w.writeln(format!( "assert_eq!({}, ::std::mem::size_of::());", dt.entity.repr_size, typename - ))?; + )); Ok(()) })?; @@ -155,8 +153,8 @@ impl RustGenerator { let typename = self.define_name(dt); self.w - .writeln("#[repr(C)]")? - .writeln(format!("pub struct {} {{", typename))?; + .writeln("#[repr(C)]") + .writeln(format!("pub struct {} {{", typename)); let mut w = self.w.new_block(); for m in struct_.members.iter() { @@ -164,22 +162,22 @@ impl RustGenerator { "{}: {},", m.name.to_snake_case(), self.get_defined_typename(&m.type_) - ))?; + )); } - self.w.writeln("}")?.eob()?; + self.w.writeln("}").eob(); gen_testcase(&mut self.w, &dt.name.name.to_snake_case(), |w| { w.writeln(format!( "assert_eq!({}, ::std::mem::size_of::());", dt.entity.repr_size, typename - ))?; + )); for m in struct_.members.iter() { w.writeln(format!( "assert_eq!({}, {{ let base = ::std::ptr::null::(); unsafe {{ (&(*base).{}) as *const _ as usize }} }});", m.offset, typename, m.name, - ))?; + )); } Ok(()) })?; @@ -198,22 +196,22 @@ impl RustGenerator { let typename = self.define_name(dt); self.w - .writeln("#[repr(C)]")? - .writeln("#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]")? - .writeln(format!("pub enum {} {{", typename))?; + .writeln("#[repr(C)]") + .writeln("#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]") + .writeln(format!("pub enum {} {{", typename)); let mut w = self.w.new_block(); for m in enum_.members.iter() { - w.writeln(format!("{},", m.name.to_camel_case()))?; + w.writeln(format!("{},", m.name.to_camel_case())); } - self.w.writeln("}")?.eob()?; + self.w.writeln("}").eob(); gen_testcase(&mut self.w, &dt.name.name.to_snake_case(), |w| { w.writeln(format!( "assert_eq!({}, ::std::mem::size_of::());", dt.entity.repr_size, typename - ))?; + )); Ok(()) })?; @@ -238,8 +236,8 @@ impl RustGenerator { }; self.w - .writeln("#[no_mangle]")? - .writeln(format!("pub fn {}({}) -> {};", func.field_name, args, rets))?; + .writeln("#[no_mangle]") + .writeln(format!("pub fn {}({}) -> {};", func.field_name, args, rets)); Ok(()) } @@ -364,40 +362,39 @@ impl RustGenerator { assert_eq!(rets.len(), 1); format!("Result<{},()>", rets[0]) }; - self.w.writeln(format!( - "pub fn {}({}) -> {} {{", - name, arg_syntax, ret_syntax - ))?; - self.w.indent(); + self.w + .writeln(format!( + "pub fn {}({}) -> {} {{", + name, arg_syntax, ret_syntax + )) + .indent(); + for l in before_abi_call { - self.w.writeln(l)?; + self.w.writeln(l); } - { - // Do the ABI call - let ret_syntax = if func.rets.is_empty() { - String::new() - } else { - format!("let {} = ", func.rets[0].name) - }; - let arg_syntax = func - .args - .iter() - .map(|a| a.name.clone()) - .collect::>() - .join(", "); - self.w - .writeln(format!("{}abi::{}({});", ret_syntax, name, arg_syntax))?; - } + // Do the ABI call + let ret_syntax = if func.rets.is_empty() { + String::new() + } else { + format!("let {} = ", func.rets[0].name) + }; + let arg_syntax = func + .args + .iter() + .map(|a| a.name.clone()) + .collect::>() + .join(", "); + self.w + .writeln(format!("{}abi::{}({});", ret_syntax, name, arg_syntax)); + for l in after_abi_call { - self.w.writeln(l)?; + self.w.writeln(l); } if !func.rets.is_empty() { - self.w - .writeln(format!("Ok({})", func.rets[0].name.clone()))?; + self.w.writeln(format!("Ok({})", func.rets[0].name.clone())); } - self.w.eob()?; - self.w.writeln("}")?; + self.w.eob().writeln("}"); Ok(()) } @@ -418,17 +415,16 @@ impl RustGenerator { Self::abitype_name(&func.rets[0].type_) }; - self.w.writeln("#[no_mangle]")?.writeln(format!( + self.w.writeln("#[no_mangle]").writeln(format!( "// Wasm func {}::{} pub unsafe extern \"C\" fn {}({}) -> {} {{", module.module_name, func.field_name, func.binding_name, args, rets - ))?; + )); self.w.indent(); - self.w.writeln("unimplemented!()")?; - self.w.eob()?; + self.w.writeln("unimplemented!()"); - self.w.writeln("}")?; + self.w.eob().writeln("}"); Ok(()) } @@ -438,16 +434,13 @@ fn gen_testcase(w: &mut PrettyWriter, name: &str, f: F) -> Result<(), IDLErro where F: FnOnce(&mut PrettyWriter) -> Result<(), IDLError>, { - w.writeln("#[cfg(test)]")?; - w.writeln(format!("mod {} {{", name))?; + w.writeln("#[cfg(test)]") + .writeln(format!("mod {} {{", name)); let mut ww = w.new_block(); - ww.writeln("#[test]")?; - ww.writeln("fn test() {")?; + ww.writeln("#[test]").writeln("fn test() {"); let mut www = ww.new_block(); f(&mut www)?; - ww.writeln("}")?; - ww.eob()?; - w.writeln("}")?; - w.eob()?; + ww.writeln("}").eob(); + w.writeln("}").eob(); Ok(()) } From e539e5f230202541e446dd8f6542929d03184f83 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 17 Jul 2019 17:40:44 -0700 Subject: [PATCH 302/512] lucet-idl: generating guest funcs is restructured, todos fixed and the example should exercise all of the cases i think? --- lucet-idl/src/pretty_writer.rs | 2 - lucet-idl/src/rust.rs | 155 +++++++++++++----------------- lucet-idl/src/rust/guest_funcs.rs | 154 +++++++++++++++++++++++++++++ lucet-idl/tests/example.idl | 18 +++- 4 files changed, 234 insertions(+), 95 deletions(-) create mode 100644 lucet-idl/src/rust/guest_funcs.rs diff --git a/lucet-idl/src/pretty_writer.rs b/lucet-idl/src/pretty_writer.rs index adcd41aeb..de043f33c 100644 --- a/lucet-idl/src/pretty_writer.rs +++ b/lucet-idl/src/pretty_writer.rs @@ -1,6 +1,4 @@ -use super::error::IDLError; use std::cell::RefCell; -use std::convert::Into; use std::io::prelude::*; use std::rc::Rc; diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index 74aeb3d01..b956f1208 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -14,6 +14,8 @@ use heck::{CamelCase, SnakeCase}; use std::collections::HashMap; use std::io::Write; +mod guest_funcs; + /// Generator for the Rust backend pub struct RustGenerator { pub defined: HashMap, @@ -46,7 +48,7 @@ impl RustGenerator { .writeln("extern \"C\" {") .indent(); for fdecl in module.func_decls() { - self.guest_abi_import(module, &fdecl.entity); + self.guest_abi_import(module, &fdecl.entity)?; } self.w.eob().writeln("}").eob().writeln("}"); } @@ -243,110 +245,122 @@ impl RustGenerator { } fn guest_idiomatic_def(&mut self, module: &Module, func: &FuncDecl) -> Result<(), IDLError> { - let mut args = Vec::new(); + use guest_funcs::{AbiCallBuilder, FuncBuilder}; - let mut before_abi_call: Vec = Vec::new(); - let mut after_abi_call: Vec = Vec::new(); + let name = func.field_name.to_snake_case(); + let mut def = FuncBuilder::new(name, "()".to_owned()); + let mut abi_call = AbiCallBuilder::new(func); for input in func.in_bindings.iter() { match &input.from { - BindingRef::Ptr(ptr) => { - let ptr = func.get_param(ptr).expect("valid param"); - args.push(format!( + BindingRef::Ptr(ptr_pos) => { + let ptr = func.get_param(ptr_pos).expect("valid param"); + def.arg(format!( "{}: &{}", input.name, self.get_defined_typename(&input.type_) )); - before_abi_call.push(format!( + abi_call.before(format!( "let {} = {} as *const _ as i32;", ptr.name, input.name, )); + abi_call.param(ptr_pos, ptr.name.clone()); } - BindingRef::Slice(ptr, len) => { - let ptr = func.get_param(ptr).expect("valid param"); - let len = func.get_param(len).expect("lenid param"); - args.push(format!( + BindingRef::Slice(ptr_pos, len_pos) => { + let ptr = func.get_param(ptr_pos).expect("valid param"); + let len = func.get_param(len_pos).expect("lenid param"); + def.arg(format!( "{}: &[{}]", input.name, self.get_defined_typename(&input.type_) )); - before_abi_call.push(format!( + + abi_call.before(format!( "let {} = {}.as_ptr() as i32;", ptr.name, input.name, )); - before_abi_call - .push(format!("let {} = {}.len() as i32;", len.name, input.name,)); + abi_call.param(ptr_pos, ptr.name.clone()); + + abi_call.before(format!("let {} = {}.len() as i32;", len.name, input.name,)); + abi_call.param(len_pos, len.name.clone()); } - BindingRef::Value(val) => { - let val = func.get_param(val).expect("valid param"); - args.push(format!( + BindingRef::Value(val_pos) => { + let val = func.get_param(val_pos).expect("valid param"); + def.arg(format!( "{}: {}", input.name, self.get_defined_typename(&input.type_) )); - before_abi_call.push(format!("// TODO: cast {:?} to abi type", val,)); + abi_call.before(format!( + "let {} = {} as {};", + val.name, + input.name, + Self::abitype_name(&val.type_) + )); + abi_call.param(val_pos, val.name.clone()); } } } for io in func.inout_bindings.iter() { match &io.from { - BindingRef::Ptr(ptr) => { - let ptr = func.get_param(ptr).expect("valid param"); - args.push(format!( + BindingRef::Ptr(ptr_pos) => { + let ptr = func.get_param(ptr_pos).expect("valid param"); + def.arg(format!( "{}: &mut {}", io.name, self.get_defined_typename(&io.type_) )); - before_abi_call.push(format!( - "// TODO: cast the ref to a pointer, and then to u32 {:?}: {:?}", - ptr, io - )); + abi_call.before(format!("let {} = {} as *mut _ as i32;", ptr.name, io.name)); + abi_call.param(ptr_pos, ptr.name.clone()); } - BindingRef::Slice(ptr, len) => { - let ptr = func.get_param(ptr).expect("ptrid param"); - let len = func.get_param(len).expect("lenid param"); - args.push(format!( + BindingRef::Slice(ptr_pos, len_pos) => { + let ptr = func.get_param(ptr_pos).expect("ptrid param"); + let len = func.get_param(len_pos).expect("lenid param"); + def.arg(format!( "{}: &mut [{}]", io.name, self.get_defined_typename(&io.type_) )); - before_abi_call.push(format!( - "// TODO: destructure {} into ptr {:?} and arg {:?}", - io.name, ptr, len - )); + abi_call.before(format!("let {} = {}.as_ptr() as i32;", ptr.name, io.name)); + abi_call.before(format!("let {} = {}.len() as i32;", len.name, io.name)); + abi_call.param(ptr_pos, ptr.name.clone()); + abi_call.param(len_pos, len.name.clone()); } BindingRef::Value(_val) => { panic!("it should not be possible to have an inout value {:?}", io); } } - - args.push(format!("/* FIXME inout binding {:?} */", io)); } - let mut rets = Vec::new(); for o in func.out_bindings.iter() { match &o.from { - BindingRef::Ptr(ptr) => { - let ptr = func.get_param(ptr).expect("valid param"); + BindingRef::Ptr(ptr_pos) => { + let ptr = func.get_param(ptr_pos).expect("valid param"); let otypename = self.get_defined_typename(&o.type_); - rets.push(otypename.clone()); - before_abi_call.push(format!( + def.ok_type(otypename.clone()); + abi_call.before(format!( "let mut {} = ::std::mem::MaybeUninit::<{}>::uninit();", ptr.name, otypename )); - after_abi_call.push(format!( - "// TODO: cast the u32 {:?} ptr, then to a ref, {:?}. FALLIBLE!!", - ptr, o + abi_call.param(ptr_pos, format!("{}.as_mut_ptr() as i32", ptr.name)); + abi_call.after(format!( + "let {} = unsafe {{ {}.assume_init() }};", + ptr.name, ptr.name )); + def.ok_value(ptr.name.clone()); } - BindingRef::Value(val) => { - let val = func.get_param(val).expect("valid param"); - rets.push(format!("{}", self.get_defined_typename(&o.type_))); - after_abi_call.push(format!( - "// TODO: cast the ret {:?} to a value {:?}", - val, o + BindingRef::Value(val_pos) => { + let val = func.get_param(val_pos).expect("valid param"); + def.ok_type(self.get_defined_typename(&o.type_)); + abi_call.param(val_pos, val.name.clone()); + abi_call.after(format!( + "let {} = {} as {};", + val.name, + val.name, + self.get_defined_typename(&o.type_), )); + def.ok_value(val.name.clone()); } BindingRef::Slice(_ptr, _len) => { panic!("it should not be possible to have an out slice {:?}", o); @@ -354,47 +368,8 @@ impl RustGenerator { } } - let name = func.field_name.to_snake_case(); - let arg_syntax = args.join(", "); - let ret_syntax = if rets.is_empty() { - "Result<(),()>".to_owned() - } else { - assert_eq!(rets.len(), 1); - format!("Result<{},()>", rets[0]) - }; - self.w - .writeln(format!( - "pub fn {}({}) -> {} {{", - name, arg_syntax, ret_syntax - )) - .indent(); - - for l in before_abi_call { - self.w.writeln(l); - } - - // Do the ABI call - let ret_syntax = if func.rets.is_empty() { - String::new() - } else { - format!("let {} = ", func.rets[0].name) - }; - let arg_syntax = func - .args - .iter() - .map(|a| a.name.clone()) - .collect::>() - .join(", "); - self.w - .writeln(format!("{}abi::{}({});", ret_syntax, name, arg_syntax)); + def.render(&mut self.w, |mut w| abi_call.render(&mut w))?; - for l in after_abi_call { - self.w.writeln(l); - } - if !func.rets.is_empty() { - self.w.writeln(format!("Ok({})", func.rets[0].name.clone())); - } - self.w.eob().writeln("}"); Ok(()) } diff --git a/lucet-idl/src/rust/guest_funcs.rs b/lucet-idl/src/rust/guest_funcs.rs new file mode 100644 index 000000000..1ba053a92 --- /dev/null +++ b/lucet-idl/src/rust/guest_funcs.rs @@ -0,0 +1,154 @@ +use crate::error::IDLError; +use crate::function::{FuncDecl, ParamPosition}; +use crate::pretty_writer::PrettyWriter; +use heck::SnakeCase; + +pub struct AbiCallBuilder<'a> { + decl: &'a FuncDecl, + before: Vec, + after: Vec, + args: Vec>, + rets: Vec>, +} + +impl<'a> AbiCallBuilder<'a> { + pub fn new(decl: &'a FuncDecl) -> Self { + let arg_len = decl.args.len(); + let ret_len = decl.rets.len(); + AbiCallBuilder { + decl, + before: Vec::new(), + after: Vec::new(), + args: vec![None; arg_len], + rets: vec![None; ret_len], + } + } + + pub fn param(&mut self, position: &ParamPosition, value: String) { + match position { + ParamPosition::Arg(n) => { + self.args[*n] = Some(value); + } + ParamPosition::Ret(n) => { + self.rets[*n] = Some(value); + } + } + } + + pub fn before(&mut self, stmt: String) { + self.before.push(stmt); + } + + pub fn after(&mut self, stmt: String) { + self.after.push(stmt); + } + + pub fn render(&self, w: &mut PrettyWriter) -> Result<(), IDLError> { + let name = self.decl.field_name.to_snake_case(); + + let arg_syntax = self + .args + .iter() + .map(|v| { + v.clone() + .ok_or(IDLError::InternalError("unconstructed abi arg")) + }) + .collect::, IDLError>>()? + .join(", "); + let rets = self + .rets + .iter() + .map(|v| { + v.clone() + .ok_or(IDLError::InternalError("unconstructed abi ret")) + }) + .collect::, IDLError>>()?; + let ret_syntax = if rets.is_empty() { + String::new() + } else { + assert_eq!(rets.len(), 1); + format!("let {} = ", rets[0]) + }; + + for b in self.before.iter() { + w.writeln(b); + } + + w.writeln(format!( + "{}unsafe {{ abi::{}({}) }};", + ret_syntax, name, arg_syntax + )); + + for a in self.after.iter() { + w.writeln(a); + } + + Ok(()) + } +} + +pub struct FuncBuilder { + name: String, + error_type: String, + args: Vec, + ok_types: Vec, + ok_values: Vec, +} + +impl FuncBuilder { + pub fn new(name: String, error_type: String) -> Self { + FuncBuilder { + name, + error_type, + args: Vec::new(), + ok_types: Vec::new(), + ok_values: Vec::new(), + } + } + + pub fn arg(&mut self, arg: String) { + self.args.push(arg) + } + + pub fn ok_type(&mut self, arg: String) { + self.ok_types.push(arg); + } + + pub fn ok_value(&mut self, val: String) { + self.ok_values.push(val); + } + + fn render_tuple(members: &[String]) -> String { + match members.len() { + 0 => "()".to_owned(), + 1 => members[0].clone(), + _ => format!("({})", members.join(", ")), + } + } + + pub fn render(&self, w: &mut PrettyWriter, body: F) -> Result<(), IDLError> + where + F: FnOnce(&mut PrettyWriter) -> Result<(), IDLError>, + { + if self.ok_types.len() != self.ok_values.len() { + Err(IDLError::InternalError( + "func builder ok types do not match ok values", + ))?; + } + let arg_syntax = self.args.join(", "); + let ret_syntax = format!( + "Result<{},{}>", + Self::render_tuple(&self.ok_types), + self.error_type + ); + w.writeln(format!( + "pub fn {}({}) -> {} {{", + self.name, arg_syntax, ret_syntax + )) + .indent(); + body(w)?; + w.writeln(format!("Ok({})", Self::render_tuple(&self.ok_values))); + w.eob().writeln("}".to_owned()); + Ok(()) + } +} diff --git a/lucet-idl/tests/example.idl b/lucet-idl/tests/example.idl index 7aeb61001..d6c864272 100644 --- a/lucet-idl/tests/example.idl +++ b/lucet-idl/tests/example.idl @@ -25,15 +25,27 @@ mod example { // functions + // implicit bindings: in value, out value. fn set_color(to: i32) -> r: i32; - fn get_color_by_ptr(color_ptr: i32) - where color: out color <- *color_ptr; + // binding: in pointer + fn set_struct(struct_pointer: i32) + where st: in st <- *struct_pointer; + // binding: out pointer + fn get_color_to_ptr(color_ptr: i32) + where color: out color <- *color_ptr; - fn get_structure(of: i32) -> s: i32; + // binding: inout pointer + fn swap_color_by_ptr(color_ptr: i32) + where color: inout color <- *color_ptr; + // binding: in slice fn debug_str(ptr: i32, len: i32) -> r: i32 where str: in u8 <- [ptr, len]; + // binding: inout slice + fn inout_str(ptr: i32, len: i32) -> r: i32 + where str: inout u8 <- [ptr, len]; + } From f85af7fcaadd027ab691cbecfff4913c78fce190 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 18 Jul 2019 17:27:20 -0700 Subject: [PATCH 303/512] lucet-idl: export func types --- lucet-idl/src/c.rs | 5 +++-- lucet-idl/src/lib.rs | 3 ++- lucet-idl/src/rust.rs | 27 +++++++++++++++++++-------- lucet-idl/src/types.rs | 1 - 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/lucet-idl/src/c.rs b/lucet-idl/src/c.rs index 3f4e010d4..71bd796dd 100644 --- a/lucet-idl/src/c.rs +++ b/lucet-idl/src/c.rs @@ -2,12 +2,13 @@ #![allow(unused_variables)] use crate::error::IDLError; +use crate::function::FuncDecl; use crate::module::Module; use crate::package::Package; use crate::pretty_writer::PrettyWriter; use crate::types::{ - AbiType, AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, - FuncDecl, Named, StructDataType, + AbiType, AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, Named, + StructDataType, }; use std::io::prelude::*; diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 2dda80fe7..4c2c5fd4b 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -18,10 +18,11 @@ mod types; pub use crate::config::{Backend, Config}; pub use crate::error::IDLError; +pub use crate::function::{BindingRef, FuncArg, FuncBinding, FuncDecl, ParamPosition}; pub use crate::module::Module; pub use crate::package::Package; pub use crate::types::{ - AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, FuncDecl, Ident, + AbiType, AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, Ident, Location, Name, Named, StructDataType, StructMember, }; diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index b956f1208..e1440cf2b 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -59,13 +59,12 @@ impl RustGenerator { for (_ident, module) in package.modules.iter() { self.w.writeln("use lucet_runtime::lucet_hostcalls;"); self.generate_datatypes(module)?; - self.w.writeln("lucet_hostcalls! {"); - self.w.indent(); + + self.w.writeln("lucet_hostcalls! {").indent(); for fdecl in module.func_decls() { self.host_abi_definition(module, &fdecl.entity)?; } - self.w.eob(); - self.w.writeln("}"); + self.w.eob().writeln("}"); } Ok(()) } @@ -384,15 +383,15 @@ impl RustGenerator { } let rets = if func.rets.len() == 0 { - "()" + format!(" -> ()") } else { assert_eq!(func.rets.len(), 1); - Self::abitype_name(&func.rets[0].type_) + format!(" -> {}", Self::abitype_name(&func.rets[0].type_)) }; self.w.writeln("#[no_mangle]").writeln(format!( - "// Wasm func {}::{} -pub unsafe extern \"C\" fn {}({}) -> {} {{", + "// Wasm func {}::{} \n\ + pub unsafe extern \"C\" fn {}({}){} {{", module.module_name, func.field_name, func.binding_name, args, rets )); @@ -403,6 +402,18 @@ pub unsafe extern \"C\" fn {}({}) -> {} {{", Ok(()) } + + fn host_trait_definition(&mut self, module: &Module) -> Result<(), IDLError> { + self.w + .writeln(format!( + "pub trait {} {{", + module.module_name.to_camel_case() + )) + .indent(); + + self.w.eob().writeln("}"); + Ok(()) + } } fn gen_testcase(w: &mut PrettyWriter, name: &str, f: F) -> Result<(), IDLError> diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index 22af184f8..ec8e9b295 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -1,4 +1,3 @@ -pub use crate::function::{BindingRef, FuncArg, FuncDecl, ParamPosition}; use std::fmt; #[derive(Debug, PartialEq, Eq, Clone, Copy)] From 1dcd50057d6e1f4fb0e60f07736ec6e8ea095dab Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 18 Jul 2019 17:27:49 -0700 Subject: [PATCH 304/512] lucet-idl-test: fix generator for new function bindings --- lucet-idl/lucet-idl-test/src/c_guest.rs | 3 +- lucet-idl/lucet-idl-test/src/syntax.rs | 168 +++++++++++++++++++++--- 2 files changed, 150 insertions(+), 21 deletions(-) diff --git a/lucet-idl/lucet-idl-test/src/c_guest.rs b/lucet-idl/lucet-idl-test/src/c_guest.rs index 2adad8fc8..d35d747c5 100644 --- a/lucet-idl/lucet-idl-test/src/c_guest.rs +++ b/lucet-idl/lucet-idl-test/src/c_guest.rs @@ -1,5 +1,5 @@ use crate::workspace::Workspace; -use failure::{format_err, Error}; +use failure::Error; use lucet_idl::{self, Backend, Config, Package}; use lucet_wasi; use lucet_wasi_sdk::{CompileOpts, Link}; @@ -7,7 +7,6 @@ use lucetc::{Lucetc, LucetcOpts}; use std::fs::File; use std::io::Write; use std::path::PathBuf; -use std::process::Command; pub struct CGuestApp { work: Workspace, diff --git a/lucet-idl/lucet-idl-test/src/syntax.rs b/lucet-idl/lucet-idl-test/src/syntax.rs index 707f5f2c3..4d32b4e89 100644 --- a/lucet-idl/lucet-idl-test/src/syntax.rs +++ b/lucet-idl/lucet-idl-test/src/syntax.rs @@ -1,7 +1,7 @@ -use lucet_idl::AtomType; +use lucet_idl::{AbiType, AtomType}; use proptest::prelude::*; -pub trait AtomTypeExt +pub trait ArbTypeExt where Self: Sized, { @@ -9,7 +9,7 @@ where fn render_idl(&self) -> String; } -impl AtomTypeExt for AtomType { +impl ArbTypeExt for AtomType { fn strat() -> BoxedStrategy { prop_oneof![ Just(AtomType::Bool), @@ -45,6 +45,28 @@ impl AtomTypeExt for AtomType { } } +impl ArbTypeExt for AbiType { + fn strat() -> BoxedStrategy { + prop_oneof![ + Just(AbiType::I32), + Just(AbiType::I64), + Just(AbiType::F32), + Just(AbiType::F64), + ] + .boxed() + } + fn render_idl(&self) -> String { + use AbiType::*; + match self { + I32 => "i32", + I64 => "i64", + F32 => "f32", + F64 => "f64", + } + .to_owned() + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct DatatypeRef(usize); @@ -200,41 +222,149 @@ impl DatatypeSyntax { } } +#[derive(Debug, Clone)] +pub enum FuncArgBindingSyntax { + InValue(AtomType), + InPtr(DatatypeRef), + OutPtr(DatatypeRef), + InOutPtr(DatatypeRef), + InSlice(DatatypeRef), + InOutSlice(DatatypeRef), +} + +impl FuncArgBindingSyntax { + pub fn strat() -> BoxedStrategy { + use FuncArgBindingSyntax::*; + prop_oneof![ + AtomType::strat().prop_map(InValue), + DatatypeRef::strat().prop_map(InPtr), + DatatypeRef::strat().prop_map(OutPtr), + DatatypeRef::strat().prop_map(InOutPtr), + DatatypeRef::strat().prop_map(InSlice), + DatatypeRef::strat().prop_map(InOutSlice), + ] + .boxed() + } + + pub fn normalize(self, highest_definition: usize) -> Self { + use FuncArgBindingSyntax::*; + match self { + InValue(atomtype) => InValue(atomtype), + InPtr(dt) => InPtr(dt.normalize(highest_definition)), + OutPtr(dt) => OutPtr(dt.normalize(highest_definition)), + InOutPtr(dt) => InOutPtr(dt.normalize(highest_definition)), + InSlice(dt) => InSlice(dt.normalize(highest_definition)), + InOutSlice(dt) => InOutSlice(dt.normalize(highest_definition)), + } + } +} + #[derive(Debug, Clone)] pub struct FunctionSyntax { - args: Vec, - ret: Option, + arg_bindings: Vec, + ret_binding: Option, } impl FunctionSyntax { pub fn strat(max_args: usize) -> impl Strategy { ( - prop::collection::vec(DatatypeRef::strat(), 0..max_args), - prop::option::of(DatatypeRef::strat()), + prop::collection::vec(FuncArgBindingSyntax::strat(), 0..max_args), + prop::option::of(AtomType::strat()), ) - .prop_map(|(args, ret)| FunctionSyntax { args, ret }) + .prop_map(|(arg_bindings, ret_binding)| FunctionSyntax { + arg_bindings, + ret_binding, + }) } pub fn normalize(self, highest_definition: usize) -> Self { - let args = self - .args + let arg_bindings = self + .arg_bindings .into_iter() .map(|a| a.normalize(highest_definition)) .collect(); - let ret = self.ret.clone().map(|a| a.normalize(highest_definition)); - Self { args, ret } + Self { + arg_bindings, + ret_binding: self.ret_binding, + } } pub fn render_idl(&self, name: usize) -> String { - let mut args = String::new(); - for (ix, a) in self.args.iter().enumerate() { - args += &format!("a_{}: {}, ", ix, a.render_idl()); + let mut arg_syntax: Vec = Vec::new(); + let mut binding_syntax: Vec = Vec::new(); + + for (ix, a) in self.arg_bindings.iter().enumerate() { + use FuncArgBindingSyntax::*; + match a { + InValue(atomtype) => { + arg_syntax.push(format!( + "a_{}: {}", + ix, + AbiType::from_atom(&atomtype).render_idl() + )); + binding_syntax.push(format!( + "b_{}: in {} <- a_{}", + ix, + atomtype.render_idl(), + ix + )); + } + InPtr(dt) => { + arg_syntax.push(format!("a_{}: i32", ix)); + binding_syntax.push(format!("b_{}: in {} <- *a_{}", ix, dt.render_idl(), ix)); + } + OutPtr(dt) => { + arg_syntax.push(format!("a_{}: i32", ix)); + binding_syntax.push(format!("b_{}: out {} <- *a_{}", ix, dt.render_idl(), ix)); + } + InOutPtr(dt) => { + arg_syntax.push(format!("a_{}: i32", ix)); + binding_syntax.push(format!( + "b_{}: inout {} <- *a_{}", + ix, + dt.render_idl(), + ix + )); + } + InSlice(dt) => { + arg_syntax.push(format!("a_{}_ptr: i32", ix)); + arg_syntax.push(format!("a_{}_len: i32", ix)); + binding_syntax.push(format!( + "b_{}: in {} <- [a_{}_ptr, a_{}_len]", + ix, + dt.render_idl(), + ix, + ix + )); + } + InOutSlice(dt) => { + arg_syntax.push(format!("a_{}_ptr: i32", ix)); + arg_syntax.push(format!("a_{}_len: i32", ix)); + binding_syntax.push(format!( + "b_{}: inout {} <- [a_{}_ptr, a_{}_len]", + ix, + dt.render_idl(), + ix, + ix + )); + } + } } - let mut ret = String::new(); - if let Some(ref r) = self.ret { - ret += &format!("-> {}", r.render_idl()); + + let mut ret_syntax = None; + if let Some(b) = self.ret_binding { + ret_syntax = Some(format!("r: {}", AbiType::from_atom(&b).render_idl())); + let ix = self.arg_bindings.len(); + binding_syntax.push(format!("b_{}: out {} <- r", ix, b.render_idl(),)); } - format!("fn f_{}({}){};", name, args, ret) + + format!( + "fn f_{}({}){}\nwhere {};", + name, + arg_syntax.join(", "), + ret_syntax.map(|r| format!("-> {}", r)).unwrap_or_default(), + binding_syntax.join(",\n"), + ) } } From 4cfc5666d0b0035ceb4a4104b5efc107c35d8ae3 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 18 Jul 2019 19:04:49 -0700 Subject: [PATCH 305/512] lucet-idl-test: generator for func call predicates --- lucet-idl/lucet-idl-test/src/values.rs | 80 +++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 8 deletions(-) diff --git a/lucet-idl/lucet-idl-test/src/values.rs b/lucet-idl/lucet-idl-test/src/values.rs index 98421bc0e..9a525c99e 100644 --- a/lucet-idl/lucet-idl-test/src/values.rs +++ b/lucet-idl/lucet-idl-test/src/values.rs @@ -1,8 +1,8 @@ use lucet_idl::{ - AliasDataType, AtomType, DataTypeRef, DataTypeVariant, EnumDataType, Module, Named, - StructDataType, StructMember, + AliasDataType, AtomType, BindingRef, DataTypeRef, DataTypeVariant, EnumDataType, FuncBinding, + FuncDecl, Module, Named, StructDataType, StructMember, }; -use proptest::{self, prelude::*}; +use proptest::prelude::*; #[derive(Debug, Clone, PartialEq)] pub enum AtomVal { @@ -46,11 +46,9 @@ pub struct EnumVal { impl EnumVal { pub fn strat(enum_datatype: &Named) -> impl Strategy { let name = enum_datatype.name.name.clone(); - proptest::sample::select(enum_datatype.entity.members.clone()).prop_map(move |mem| { - EnumVal { - enum_name: name.clone(), - member_name: mem.name, - } + prop::sample::select(enum_datatype.entity.members.clone()).prop_map(move |mem| EnumVal { + enum_name: name.clone(), + member_name: mem.name, }) } } @@ -127,6 +125,7 @@ pub enum DataTypeVal { pub trait ModuleExt { fn datatype_strat(&self, dtref: &DataTypeRef) -> BoxedStrategy; + fn function_strat(&self) -> BoxedStrategy; } impl ModuleExt for Module { @@ -153,4 +152,69 @@ impl ModuleExt for Module { DataTypeRef::Atom(a) => AtomVal::strat(&a).prop_map(DataTypeVal::Atom).boxed(), } } + + fn function_strat(&self) -> BoxedStrategy { + let decls = self.funcs.values().cloned().collect::>(); + prop::sample::select(decls).boxed() + } +} + +#[derive(Debug, Clone, PartialEq)] +pub enum BindingVal { + Value(DataTypeVal), + Array(Vec), +} + +impl BindingVal { + fn value_strat(module: &Module, dtref: &DataTypeRef) -> BoxedStrategy { + module + .datatype_strat(dtref) + .prop_map(BindingVal::Value) + .boxed() + } + fn array_strat(module: &Module, dtref: &DataTypeRef) -> BoxedStrategy { + prop::collection::vec(module.datatype_strat(dtref), 100) + .prop_map(BindingVal::Array) + .boxed() + } + + fn binding_strat(module: &Module, binding: &FuncBinding) -> BoxedStrategy<(String, Self)> { + let name = binding.name.clone(); + match binding.from { + BindingRef::Value(_) | BindingRef::Ptr(_) => Self::value_strat(module, &binding.type_) + .prop_map(move |v| (name.clone(), v)) + .boxed(), + BindingRef::Slice(_, _) => Self::array_strat(module, &binding.type_) + .prop_map(move |v| (name.clone(), v)) + .boxed(), + } + } +} + +#[derive(Debug, Clone)] +pub struct FuncCallPredicate { + pub pre: Vec<(String, BindingVal)>, + pub post: Vec<(String, BindingVal)>, +} + +impl FuncCallPredicate { + pub fn strat(module: &Module, func: &FuncDecl) -> BoxedStrategy { + let pre_strat: Vec> = func + .in_bindings + .iter() + .chain(func.inout_bindings.iter()) + .map(|binding| BindingVal::binding_strat(module, binding)) + .collect(); + + let post_strat: Vec> = func + .inout_bindings + .iter() + .chain(func.out_bindings.iter()) + .map(|binding| BindingVal::binding_strat(module, binding)) + .collect(); + + (pre_strat, post_strat) + .prop_map(|(pre, post)| FuncCallPredicate { pre, post }) + .boxed() + } } From b453589bfad108ebfc91b89d3aa0f06e1b8007ea Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 19 Jul 2019 12:13:10 -0700 Subject: [PATCH 306/512] lucet-idl-test: generate function calls!! --- lucet-idl/lucet-idl-test/src/main.rs | 32 +++++ lucet-idl/lucet-idl-test/src/values.rs | 173 ++++++++++++++++++++++--- 2 files changed, 186 insertions(+), 19 deletions(-) diff --git a/lucet-idl/lucet-idl-test/src/main.rs b/lucet-idl/lucet-idl-test/src/main.rs index 52f8a004b..945126356 100644 --- a/lucet-idl/lucet-idl-test/src/main.rs +++ b/lucet-idl/lucet-idl-test/src/main.rs @@ -34,6 +34,10 @@ fn main() { process::exit(0); } + if exe_config.generate_calls { + generate_calls(&pkg); + process::exit(0); + } // Workspace deleted when dropped - need to keep it alive for app to be run let mut guest_apps: Vec<(PathBuf, Workspace)> = Vec::new(); @@ -67,6 +71,7 @@ struct ExeConfig { pub build_c_guest: bool, pub run_guests: bool, pub generate_values: bool, + pub generate_calls: bool, } impl ExeConfig { @@ -114,6 +119,13 @@ impl ExeConfig { .long("generate-values") .help(""), ) + .arg( + Arg::with_name("generate_calls") + .required(false) + .takes_value(false) + .long("generate-calls") + .help(""), + ) .get_matches(); ExeConfig { @@ -123,6 +135,7 @@ impl ExeConfig { build_rust_guest: !matches.is_present("no_rust_guest"), run_guests: !matches.is_present("no_run") || !matches.is_present("no_host"), generate_values: matches.is_present("generate_values"), + generate_calls: matches.is_present("generate_calls"), } } } @@ -142,3 +155,22 @@ fn generate_values(package: &Package) { } } } + +fn generate_calls(package: &Package) { + use lucet_idl_test::values::*; + + for (_, m) in package.modules.iter() { + for fdecl in m.func_decls() { + let func_pred_gen = FuncCallPredicate::strat(&m, &fdecl.entity); + let mut runner = TestRunner::default(); + let value = func_pred_gen + .new_tree(&mut runner) + .expect("create valuetree") + .current(); + println!( + "==========\n{}\n=========", + value.render_caller().join("\n") + ); + } + } +} diff --git a/lucet-idl/lucet-idl-test/src/values.rs b/lucet-idl/lucet-idl-test/src/values.rs index 9a525c99e..2e002fcea 100644 --- a/lucet-idl/lucet-idl-test/src/values.rs +++ b/lucet-idl/lucet-idl-test/src/values.rs @@ -35,6 +35,21 @@ impl AtomVal { AtomType::F64 => any::().prop_map(AtomVal::F64).boxed(), } } + pub fn render_rustval(&self) -> String { + match self { + AtomVal::Bool(v) => format!("{}", v), + AtomVal::U8(v) => format!("{}", v), + AtomVal::U16(v) => format!("{}", v), + AtomVal::U32(v) => format!("{}", v), + AtomVal::U64(v) => format!("{}", v), + AtomVal::I8(v) => format!("{}", v), + AtomVal::I16(v) => format!("{}", v), + AtomVal::I32(v) => format!("{}", v), + AtomVal::I64(v) => format!("{}", v), + AtomVal::F32(v) => format!("{}f32", v), + AtomVal::F64(v) => format!("{}f64", v), + } + } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -51,6 +66,9 @@ impl EnumVal { member_name: mem.name, }) } + pub fn render_rustval(&self) -> String { + format!("{}::{}", self.enum_name, self.member_name) + } } #[derive(Debug, Clone, PartialEq)] @@ -75,6 +93,14 @@ impl StructVal { }) .boxed() } + pub fn render_rustval(&self) -> String { + let members = self + .members + .iter() + .map(|v| format!("{}: {}", v.name, v.value.render_rustval())) + .collect::>(); + format!("{} {{ {} }}", self.struct_name, members.join(", ")) + } } #[derive(Debug, Clone, PartialEq)] @@ -113,6 +139,9 @@ impl AliasVal { }) .boxed() } + pub fn render_rustval(&self) -> String { + self.value.render_rustval() + } } #[derive(Debug, Clone, PartialEq)] @@ -123,6 +152,17 @@ pub enum DataTypeVal { Atom(AtomVal), } +impl DataTypeVal { + pub fn render_rustval(&self) -> String { + match self { + DataTypeVal::Enum(a) => a.render_rustval(), + DataTypeVal::Struct(a) => a.render_rustval(), + DataTypeVal::Alias(a) => a.render_rustval(), + DataTypeVal::Atom(a) => a.render_rustval(), + } + } +} + pub trait ModuleExt { fn datatype_strat(&self, dtref: &DataTypeRef) -> BoxedStrategy; fn function_strat(&self) -> BoxedStrategy; @@ -162,39 +202,62 @@ impl ModuleExt for Module { #[derive(Debug, Clone, PartialEq)] pub enum BindingVal { Value(DataTypeVal), + Ptr(DataTypeVal), Array(Vec), } impl BindingVal { - fn value_strat(module: &Module, dtref: &DataTypeRef) -> BoxedStrategy { - module - .datatype_strat(dtref) - .prop_map(BindingVal::Value) - .boxed() - } - fn array_strat(module: &Module, dtref: &DataTypeRef) -> BoxedStrategy { - prop::collection::vec(module.datatype_strat(dtref), 100) - .prop_map(BindingVal::Array) - .boxed() - } - fn binding_strat(module: &Module, binding: &FuncBinding) -> BoxedStrategy<(String, Self)> { let name = binding.name.clone(); match binding.from { - BindingRef::Value(_) | BindingRef::Ptr(_) => Self::value_strat(module, &binding.type_) - .prop_map(move |v| (name.clone(), v)) + BindingRef::Value(_) => module + .datatype_strat(&binding.type_) + .prop_map(move |v| (name.clone(), BindingVal::Value(v))) .boxed(), - BindingRef::Slice(_, _) => Self::array_strat(module, &binding.type_) - .prop_map(move |v| (name.clone(), v)) + BindingRef::Ptr(_) => module + .datatype_strat(&binding.type_) + .prop_map(move |v| (name.clone(), BindingVal::Ptr(v))) .boxed(), + BindingRef::Slice(_, _) => { + prop::collection::vec(module.datatype_strat(&binding.type_), 100) + .prop_map(move |v| (name.clone(), BindingVal::Array(v))) + .boxed() + } + } + } + fn render_rust_constructor(&self) -> String { + match self { + BindingVal::Value(v) => v.render_rustval(), + BindingVal::Ptr(v) => v.render_rustval(), + BindingVal::Array(vs) => format!( + "vec![{}]", + vs.iter() + .map(|v| v.render_rustval()) + .collect::>() + .join(", ") + ), + } + } + fn render_rust_ref(&self) -> String { + match self { + BindingVal::Value(v) => v.render_rustval(), + BindingVal::Ptr(v) => format!("&{}", v.render_rustval()), + BindingVal::Array(vs) => format!( + "&[{}]", + vs.iter() + .map(|v| v.render_rustval()) + .collect::>() + .join(", ") + ), } } } #[derive(Debug, Clone)] pub struct FuncCallPredicate { - pub pre: Vec<(String, BindingVal)>, - pub post: Vec<(String, BindingVal)>, + func: FuncDecl, + pre: Vec<(String, BindingVal)>, + post: Vec<(String, BindingVal)>, } impl FuncCallPredicate { @@ -213,8 +276,80 @@ impl FuncCallPredicate { .map(|binding| BindingVal::binding_strat(module, binding)) .collect(); + let func = func.clone(); (pre_strat, post_strat) - .prop_map(|(pre, post)| FuncCallPredicate { pre, post }) + .prop_map(move |(pre, post)| FuncCallPredicate { + pre, + post, + func: func.clone(), + }) .boxed() } + + pub fn render_caller(&self) -> Vec { + let mut lines: Vec = self + .pre + .iter() + .map(|(name, val)| format!("let {} = {};", name, val.render_rust_constructor())) + .collect(); + + let mut arg_syntax = Vec::new(); + for in_binding in self.func.in_bindings.iter() { + arg_syntax.push(match in_binding.from { + BindingRef::Ptr(_) => format!("&{}", in_binding.name), + BindingRef::Slice(_, _) => format!("&{}", in_binding.name), + BindingRef::Value(_) => in_binding.name.clone(), + }) + } + for io_binding in self.func.inout_bindings.iter() { + arg_syntax.push(match io_binding.from { + BindingRef::Ptr(_) => format!("&mut {}", io_binding.name), + BindingRef::Slice(_, _) => format!("&mut {}", io_binding.name), + BindingRef::Value(_) => unreachable!("should be no such thing as an io value"), + }) + } + + lines.push(format!( + "let {} = {}({});", + render_tuple( + self.func + .out_bindings + .iter() + .map(|b| b.name.clone()) + .collect::>(), + "_" + ), + self.func.field_name, + arg_syntax.join(",") + )); + lines.append( + &mut self + .post + .iter() + .map(|(name, val)| format!("assert_eq!({}, {});", name, val.render_rust_ref())) + .collect(), + ); + lines + } + + pub fn render_postcondition_bindings(&self) -> Vec { + self.post + .iter() + .map(|(name, val)| format!("let {} = {};", name, val.render_rust_constructor())) + .collect() + } + pub fn render_postcondition_assertions(&self) -> Vec { + self.post + .iter() + .map(|(name, val)| format!("assert_eq!({}, {});", name, val.render_rust_ref())) + .collect() + } +} + +fn render_tuple(vs: Vec, base_case: &str) -> String { + match vs.len() { + 0 => base_case.to_owned(), + 1 => vs[0].clone(), + _ => format!("({})", vs.join(", ")), + } } From bfaef11ea1d616843bf64f94b69b161934b7af47 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 22 Jul 2019 13:43:38 -0700 Subject: [PATCH 307/512] lucet-idl-test: value gen fixes --- Cargo.lock | 366 ++++++++++++------------- lucet-idl/lucet-idl-test/Cargo.toml | 1 + lucet-idl/lucet-idl-test/src/values.rs | 96 +++++-- 3 files changed, 254 insertions(+), 209 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3167e45b4..055c7e228 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7,7 +7,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "aho-corasick" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -45,18 +45,18 @@ dependencies = [ [[package]] name = "autocfg" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.33" +version = "0.3.35" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -64,7 +64,7 @@ name = "backtrace-sys" version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -95,7 +95,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -110,12 +110,12 @@ dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -163,13 +163,13 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -187,7 +187,7 @@ name = "c2-chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -198,7 +198,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cc" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -244,7 +244,7 @@ dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -258,10 +258,10 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -269,7 +269,7 @@ name = "colored" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -300,7 +300,7 @@ dependencies = [ "cranelift-entity 0.40.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -321,7 +321,7 @@ version = "0.40.0" dependencies = [ "cranelift-codegen 0.40.0", "cranelift-module 0.40.0", - "faerie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "faerie 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -332,7 +332,7 @@ name = "cranelift-frontend" version = "0.40.0" dependencies = [ "cranelift-codegen 0.40.0", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -343,7 +343,7 @@ dependencies = [ "cranelift-codegen 0.40.0", "cranelift-entity 0.40.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -364,7 +364,7 @@ dependencies = [ "cranelift-frontend 0.40.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "wasmparser 0.36.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -387,7 +387,7 @@ dependencies = [ "criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -395,8 +395,8 @@ dependencies = [ "rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -429,7 +429,7 @@ dependencies = [ "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -448,7 +448,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -465,11 +465,11 @@ name = "csv" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bstr 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "bstr 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -500,8 +500,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -526,32 +526,24 @@ dependencies = [ [[package]] name = "faerie" -version = "0.10.1" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.23 (registry+https://github.com/rust-lang/crates.io-index)", - "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "string-interner 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "faerie" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -replace = "faerie 0.10.1" - [[package]] name = "failure" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.33 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -562,7 +554,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -573,13 +565,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "flate2" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide_c_api 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -611,7 +603,7 @@ name = "generic-array" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -635,7 +627,7 @@ name = "goblin" version = "0.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -645,7 +637,7 @@ name = "goblin" version = "0.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -655,7 +647,7 @@ name = "goblin" version = "0.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -665,7 +657,7 @@ name = "goblin" version = "0.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -725,7 +717,7 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.0.2" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -752,7 +744,7 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -765,13 +757,13 @@ name = "libloading" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "log" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -825,7 +817,8 @@ dependencies = [ "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-idl 0.1.1", "lucet-runtime 0.1.1", "lucet-wasi 0.1.1", @@ -841,7 +834,7 @@ version = "0.1.0" dependencies = [ "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-idl 0.1.1", "lucet-runtime 0.1.1", "lucet-wasi 0.1.1", @@ -860,7 +853,7 @@ dependencies = [ "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "object 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -869,9 +862,9 @@ name = "lucet-runtime" version = "0.1.1" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", "lucet-runtime-internals 0.1.1", @@ -892,10 +885,10 @@ dependencies = [ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", @@ -910,9 +903,9 @@ dependencies = [ name = "lucet-runtime-tests" version = "0.1.1" dependencies = [ - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", "lucet-runtime-internals 0.1.1", "lucet-wasi-sdk 0.1.1", @@ -929,7 +922,7 @@ dependencies = [ "lucet-module 0.1.1", "lucet-runtime 0.1.1", "lucetc 0.1.1", - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -972,7 +965,7 @@ dependencies = [ "progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1004,11 +997,11 @@ dependencies = [ "cranelift-native 0.40.0", "cranelift-wasm 0.40.0", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "faerie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "faerie 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1052,36 +1045,25 @@ name = "miniz-sys" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "miniz_oxide" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "miniz_oxide_c_api" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", - "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "nix" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1118,7 +1100,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1126,7 +1108,7 @@ name = "num-integer" version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1135,7 +1117,7 @@ name = "num-iter" version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1153,7 +1135,7 @@ name = "num-traits" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1169,7 +1151,7 @@ name = "object" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "flate2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1178,7 +1160,7 @@ dependencies = [ [[package]] name = "opaque-debug" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1220,7 +1202,7 @@ name = "precision" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1238,6 +1220,14 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "proc-macro2" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "progress" version = "0.2.0" @@ -1254,13 +1244,13 @@ dependencies = [ "bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "rusty-fork 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1278,6 +1268,14 @@ dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand" version = "0.4.6" @@ -1295,10 +1293,10 @@ name = "rand" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1325,7 +1323,7 @@ name = "rand_chacha" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1343,12 +1341,12 @@ name = "rand_core" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_core" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1389,7 +1387,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1401,7 +1399,7 @@ dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1411,8 +1409,8 @@ name = "rand_pcg" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1438,7 +1436,7 @@ version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1460,7 +1458,7 @@ dependencies = [ "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1479,14 +1477,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "regex" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1499,11 +1496,8 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.10" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ucd-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "remove_dir_all" @@ -1515,7 +1509,7 @@ dependencies = [ [[package]] name = "rgb" -version = "0.8.13" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1530,7 +1524,7 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1591,7 +1585,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1621,20 +1615,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.97" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.97" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1644,7 +1638,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1655,7 +1649,7 @@ dependencies = [ "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1672,10 +1666,10 @@ dependencies = [ "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "precision 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "printtable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1689,7 +1683,7 @@ name = "string-interner" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1714,7 +1708,7 @@ dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1724,7 +1718,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "0.15.42" +version = "0.15.44" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1732,6 +1726,16 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "syn" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "synstructure" version = "0.10.2" @@ -1739,7 +1743,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1771,7 +1775,7 @@ name = "termcolor" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1788,7 +1792,7 @@ name = "textwrap" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1796,7 +1800,7 @@ name = "thread_local" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1804,26 +1808,21 @@ name = "tinytemplate" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "toml" -version = "0.5.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "typenum" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "ucd-util" -version = "0.1.5" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1833,7 +1832,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-width" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1842,8 +1841,8 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "utf8-ranges" -version = "1.0.3" +name = "unicode-xid" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1871,8 +1870,8 @@ name = "wabt" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1882,8 +1881,8 @@ name = "wabt-sys" version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", - "cmake 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1912,10 +1911,10 @@ dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.23 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "siphasher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1974,7 +1973,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "wincolor" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1987,8 +1986,8 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rgb 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1999,13 +1998,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" -"checksum aho-corasick 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "36b7aa1ccb7d7ea3f437cf025a2ab1c47cc6c1bc9fc84918ff449def12f5e282" +"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94" "checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" -"checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b" -"checksum backtrace 0.3.33 (registry+https://github.com/rust-lang/crates.io-index)" = "88fb679bc9af8fa639198790a77f52d345fe13656c08b43afa9424c206b731c6" +"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" +"checksum backtrace 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "1371048253fa3bac6704bfd6bbfc922ee9bdcee8881330d40f308b81cc5adc55" "checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum bencher 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdb4953a096c551ce9ace855a604d702e6e62d77fac690575ae347571717f5" @@ -2018,19 +2017,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" "checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" -"checksum bstr 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e0a692f1c740e7e821ca71a22cf99b9b2322dfa94d10f71443befb1797b3946a" +"checksum bstr 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94cdf78eb7e94c566c1f5dbe2abf8fc70a548fc902942a48c4b3a98b48ca9ade" "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" -"checksum cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "ce400c638d48ee0e9ab75aef7997609ec57367ccfe1463f21bf53c3eca67bf46" +"checksum cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "b548a4ee81fccb95919d4e22cfea83c7693ebfd78f0495493178db20b3139da7" "checksum cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7fa24eb00d5ffab90eaeaf1092ac85c04c64aaf358ea6f84505b8116d24c6af" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c" "checksum clang-sys 0.26.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ef0c1bcf2e99c649104bd7a7012d8f8802684400e03db0ec0af48583c6fa0e4" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum cmake 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "2ca4386c8954b76a8415b63959337d940d724b336cabd3afe189c2b51a7e1ff0" +"checksum cmake 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "3c84c596dcf125d6781f58e3f4254677ec2a6d8aa56e8501ac277100990b3229" "checksum colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cdb90b60f2927f8d76139c72dbde7e10c3a2bc47c8594c9c7a66529f2687c03" "checksum core_affinity 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6d162c6e463c31dbf78fefa99d042156c1c74d404e299cfe3df2923cb857595b" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" @@ -2048,11 +2047,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" "checksum errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2a071601ed01b988f896ab14b95e67335d1eeb50190932a1320f7fe3cadc84e" "checksum errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067" -"checksum faerie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6cb48b9db9869b6209c63d5cc2fd99f0b85d1a407cb09fe8ed730c21ab945e3d" +"checksum faerie 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1d2467155f3071b96447d53af110805cadbe9162f5be6c300792fb76c0e54051" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" -"checksum flate2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "550934ad4808d5d39365e5d61727309bf18b3b02c6c56b729cb92e7dd84bc3d8" +"checksum flate2 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "2adaffba6388640136149e18ed080b77a78611c1e1d6de75aedcdf78df5d4682" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" @@ -2070,20 +2069,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bec6e801ef7367625bd94ad7e2965e6027189f3e9deef422388d993af2814a0" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" "checksum hwloc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2934f84993b8b4bcae9b6a4e5f0aca638462dda9c7b4f26a570241494f21e0f4" -"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" +"checksum indexmap 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4d6d89e0948bf10c08b9ecc8ac5b83f07f857ebe2c0cbe38de15b4e4f510356" "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)" = "3262021842bf00fe07dbd6cf34ff25c99d7a7ebef8deea84db72be3ea3bb0aff" "checksum libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" -"checksum log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c275b6ad54070ac2d665eef9197db647b32239c9d244bfb6f041a766d00da5b3" +"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" "checksum minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "185d3531e38475163c1652a0915ac612be3f2655756af43f10789d6145f527c2" "checksum miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9e3ae51cea1576ceba0dde3d484d30e6e5b86dee0b2d412fe3a16a15c98202" -"checksum miniz_oxide 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c061edee74a88eb35d876ce88b94d77a0448a201de111c244b70d047f5820516" -"checksum miniz_oxide_c_api 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6c675792957b0d19933816c4e1d56663c341dd9bfa31cb2140ff2267c1d8ecf4" +"checksum miniz_oxide 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7108aff85b876d06f22503dcce091e29f76733b2bfdd91eebce81f5e68203a10" "checksum nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4dbdc256eaac2e3bd236d93ad999d3479ef775c863dbda3068c4006a92eec51b" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" @@ -2095,7 +2093,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" "checksum object 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df4af347f5ac3d0e83e78c26be33cd10e8e874dcb68517a909ad802ba50a90b5" -"checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" +"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" "checksum parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)" = "20d7e522a7f994cc4ae32970b1ce0d99ecf91b8e1df080517a26faa6d2e2ee62" "checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" "checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" @@ -2105,17 +2103,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum precision 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "83f0b3de90e9edd6382604f4f28509ce25272deb065b94045fc47abcde567d55" "checksum printtable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "69967dae4cac71681361899d9905d3d2985fc989d7afb32a8dff3aed5461ecdf" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +"checksum proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c5c2380ae88876faae57698be9e9775e3544decad214599c3a6266cca6ac802" "checksum progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b820305721858696053a7fd0215cfeeee16ecaaf96b7a209945428e02f1c44" "checksum proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf147e022eacf0c8a054ab864914a7602618adba841d800a9a9868a5237a529f" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" +"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" "checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" @@ -2130,13 +2130,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe0df8435ac0c397d467b6cad6d25543d06e8a019ef3f6af3c384597515bd2" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" -"checksum regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b23da8dfd98a84bd7e08700190a5d9f7d2d38abd4369dd1dae651bc40bfd2cc" +"checksum regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88c3d9193984285d544df4a30c23a4e62ead42edf70a4452ceb76dac1ce05c26" "checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9" -"checksum regex-syntax 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5485bf1523a9ed51c4964273f22f63f24e31632adb5dad134f488f86a3875c" +"checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" -"checksum rgb 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)" = "4f089652ca87f5a82a62935ec6172a534066c7b97be003cc8f702ee9a7a59c92" +"checksum rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2089e4031214d129e201f8c3c8c2fe97cd7322478a0d1cdf78e7029b0042efdb" "checksum rpassword 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34fa7bcae7fca3c8471e8417088bbc3ad9af8066b0ecf4f3c0d98a0d772716e" -"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af" +"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rusty-fork 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd93264e10c577503e926bd1430193eeb5d21b059148910082245309b424fae" "checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" @@ -2148,8 +2148,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum scrypt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "656c79d0e90d0ab28ac86bf3c3d10bfbbac91450d3f190113b4e76d9fec3cfdd" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)" = "d46b3dfedb19360a74316866cef04687cd4d6a70df8e6a506c63512790769b72" -"checksum serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)" = "c22a0820adfe2f257b098714323563dd06426502abbbce4f51b72ef544c5027f" +"checksum serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" +"checksum serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "cb4dc18c61206b08dc98216c98faa0232f4337e1e1b8574551d5bad29ea1b425" "checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" "checksum siphasher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9913c75df657d84a03fa689c016b0bb2863ff0b497b26a8d6e9703f8d5df03a8" @@ -2158,7 +2158,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" "checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" -"checksum syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)" = "eadc09306ca51a40555dd6fc2b415538e9e18bc9f870e47b1a524a79fe2dcf5e" +"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" "checksum target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b0ab4982b8945c35cc1c46a83a9094c414f6828a099ce5dcaa8ee2b04642dcb" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" @@ -2167,13 +2168,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4574b75faccaacddb9b284faecdf0b544b80b6b294f3d062d325c5726a209c20" -"checksum toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8c96d7873fa7ef8bdeb3a9cda3ac48389b4154f32b9803b4bc26220b677b039" -"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" -"checksum ucd-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa9b3b49edd3468c0e6565d85783f51af95212b6fa3986a5500954f00b460874" +"checksum toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c7aabe75941d914b72bf3e5d3932ed92ce0664d49d8432305a8b547c37227724" +"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" "checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9" -"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" +"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9d50aa7650df78abf942826607c62468ce18d9019673d4a2ebe1865dbb96ffde" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" @@ -2190,6 +2190,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" +"checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" "checksum winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef84b96d10db72dd980056666d7f1e7663ce93d82fa33b63e71c966f4cf5032" "checksum xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da90eac47bf1d7871b75004b9b631d107df15f37669383b23f0b5297bc7516b6" diff --git a/lucet-idl/lucet-idl-test/Cargo.toml b/lucet-idl/lucet-idl-test/Cargo.toml index ca056d3e9..1f10f2402 100644 --- a/lucet-idl/lucet-idl-test/Cargo.toml +++ b/lucet-idl/lucet-idl-test/Cargo.toml @@ -24,3 +24,4 @@ log = "0.4" env_logger = "0.6" fs2 = "0.4" clap = "2" +heck= "0.3" diff --git a/lucet-idl/lucet-idl-test/src/values.rs b/lucet-idl/lucet-idl-test/src/values.rs index 2e002fcea..2b69af157 100644 --- a/lucet-idl/lucet-idl-test/src/values.rs +++ b/lucet-idl/lucet-idl-test/src/values.rs @@ -1,3 +1,4 @@ +use heck::CamelCase; use lucet_idl::{ AliasDataType, AtomType, BindingRef, DataTypeRef, DataTypeVariant, EnumDataType, FuncBinding, FuncDecl, Module, Named, StructDataType, StructMember, @@ -67,7 +68,11 @@ impl EnumVal { }) } pub fn render_rustval(&self) -> String { - format!("{}::{}", self.enum_name, self.member_name) + format!( + "{}::{}", + self.enum_name.to_camel_case(), + self.member_name.to_camel_case() + ) } } @@ -99,7 +104,11 @@ impl StructVal { .iter() .map(|v| format!("{}: {}", v.name, v.value.render_rustval())) .collect::>(); - format!("{} {{ {} }}", self.struct_name, members.join(", ")) + format!( + "{} {{ {} }}", + self.struct_name.to_camel_case(), + members.join(", ") + ) } } @@ -200,36 +209,64 @@ impl ModuleExt for Module { } #[derive(Debug, Clone, PartialEq)] -pub enum BindingVal { +pub struct BindingVal { + name: String, + mutable: bool, + variant: BindingValVariant, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum BindingValVariant { Value(DataTypeVal), Ptr(DataTypeVal), Array(Vec), } impl BindingVal { - fn binding_strat(module: &Module, binding: &FuncBinding) -> BoxedStrategy<(String, Self)> { + fn binding_strat(module: &Module, binding: &FuncBinding, mutable: bool) -> BoxedStrategy { let name = binding.name.clone(); match binding.from { BindingRef::Value(_) => module .datatype_strat(&binding.type_) - .prop_map(move |v| (name.clone(), BindingVal::Value(v))) + .prop_map(move |v| BindingVal { + name: name.clone(), + mutable, + variant: BindingValVariant::Value(v), + }) .boxed(), BindingRef::Ptr(_) => module .datatype_strat(&binding.type_) - .prop_map(move |v| (name.clone(), BindingVal::Ptr(v))) + .prop_map(move |v| BindingVal { + name: name.clone(), + mutable, + variant: BindingValVariant::Ptr(v), + }) .boxed(), BindingRef::Slice(_, _) => { prop::collection::vec(module.datatype_strat(&binding.type_), 100) - .prop_map(move |v| (name.clone(), BindingVal::Array(v))) + .prop_map(move |v| BindingVal { + name: name.clone(), + mutable, + variant: BindingValVariant::Array(v), + }) .boxed() } } } + fn render_rust_binding(&self) -> String { + format!( + "let {}{} = {};", + if self.mutable { "mut " } else { "" }, + self.name, + self.render_rust_constructor(), + ) + } + fn render_rust_constructor(&self) -> String { - match self { - BindingVal::Value(v) => v.render_rustval(), - BindingVal::Ptr(v) => v.render_rustval(), - BindingVal::Array(vs) => format!( + match &self.variant { + BindingValVariant::Value(v) => v.render_rustval(), + BindingValVariant::Ptr(v) => v.render_rustval(), + BindingValVariant::Array(vs) => format!( "vec![{}]", vs.iter() .map(|v| v.render_rustval()) @@ -238,11 +275,12 @@ impl BindingVal { ), } } + fn render_rust_ref(&self) -> String { - match self { - BindingVal::Value(v) => v.render_rustval(), - BindingVal::Ptr(v) => format!("&{}", v.render_rustval()), - BindingVal::Array(vs) => format!( + match &self.variant { + BindingValVariant::Value(v) => v.render_rustval(), + BindingValVariant::Ptr(v) => format!("&{}", v.render_rustval()), + BindingValVariant::Array(vs) => format!( "&[{}]", vs.iter() .map(|v| v.render_rustval()) @@ -256,24 +294,30 @@ impl BindingVal { #[derive(Debug, Clone)] pub struct FuncCallPredicate { func: FuncDecl, - pre: Vec<(String, BindingVal)>, - post: Vec<(String, BindingVal)>, + pre: Vec, + post: Vec, } impl FuncCallPredicate { pub fn strat(module: &Module, func: &FuncDecl) -> BoxedStrategy { - let pre_strat: Vec> = func + let mut pre_strat: Vec> = func .in_bindings .iter() - .chain(func.inout_bindings.iter()) - .map(|binding| BindingVal::binding_strat(module, binding)) + .map(|binding| BindingVal::binding_strat(module, binding, false)) .collect(); - let post_strat: Vec> = func + pre_strat.append( + &mut func + .inout_bindings + .iter() + .map(|binding| BindingVal::binding_strat(module, binding, true)) + .collect(), + ); + let post_strat: Vec> = func .inout_bindings .iter() .chain(func.out_bindings.iter()) - .map(|binding| BindingVal::binding_strat(module, binding)) + .map(|binding| BindingVal::binding_strat(module, binding, false)) .collect(); let func = func.clone(); @@ -290,7 +334,7 @@ impl FuncCallPredicate { let mut lines: Vec = self .pre .iter() - .map(|(name, val)| format!("let {} = {};", name, val.render_rust_constructor())) + .map(|val| val.render_rust_binding()) .collect(); let mut arg_syntax = Vec::new(); @@ -326,7 +370,7 @@ impl FuncCallPredicate { &mut self .post .iter() - .map(|(name, val)| format!("assert_eq!({}, {});", name, val.render_rust_ref())) + .map(|val| format!("assert_eq!({}, {});", val.name, val.render_rust_ref())) .collect(), ); lines @@ -335,13 +379,13 @@ impl FuncCallPredicate { pub fn render_postcondition_bindings(&self) -> Vec { self.post .iter() - .map(|(name, val)| format!("let {} = {};", name, val.render_rust_constructor())) + .map(|val| format!("let {} = {};", val.name, val.render_rust_constructor())) .collect() } pub fn render_postcondition_assertions(&self) -> Vec { self.post .iter() - .map(|(name, val)| format!("assert_eq!({}, {});", name, val.render_rust_ref())) + .map(|val| format!("assert_eq!({}, {});", val.name, val.render_rust_ref())) .collect() } } From 7460cb869623afddbd161e560926aaed0dc654f6 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 23 Jul 2019 14:48:01 -0700 Subject: [PATCH 308/512] lucet-idl: rust host getting fleshed out --- lucet-idl/src/pretty_writer.rs | 8 + lucet-idl/src/rust.rs | 267 ++++++++++++++++++++++++++++-- lucet-idl/src/rust/guest_funcs.rs | 21 +-- 3 files changed, 264 insertions(+), 32 deletions(-) diff --git a/lucet-idl/src/pretty_writer.rs b/lucet-idl/src/pretty_writer.rs index de043f33c..0a6e54f23 100644 --- a/lucet-idl/src/pretty_writer.rs +++ b/lucet-idl/src/pretty_writer.rs @@ -92,4 +92,12 @@ impl PrettyWriter { pub fn writeln>(&mut self, buf: S) -> &mut Self { self.write_line(buf.as_ref().as_bytes()) } + + /// Indent, write raw data and terminate with an end of line + pub fn writelns>(&mut self, lines: &[S]) -> &mut Self { + for line in lines.iter() { + self.write_line(line.as_ref().as_bytes()); + } + self + } } diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index e1440cf2b..5127dfc86 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -57,9 +57,13 @@ impl RustGenerator { pub fn generate_host(&mut self, package: &Package) -> Result<(), IDLError> { for (_ident, module) in package.modules.iter() { - self.w.writeln("use lucet_runtime::lucet_hostcalls;"); self.generate_datatypes(module)?; + self.host_trait_definition(module)?; + self.w.eob(); + + self.w + .writeln("use lucet_runtime::{lucet_hostcalls, lucet_hostcall_terminate};"); self.w.writeln("lucet_hostcalls! {").indent(); for fdecl in module.func_decls() { self.host_abi_definition(module, &fdecl.entity)?; @@ -327,7 +331,7 @@ impl RustGenerator { abi_call.param(len_pos, len.name.clone()); } BindingRef::Value(_val) => { - panic!("it should not be possible to have an inout value {:?}", io); + unreachable!("it should not be possible to have an inout value {:?}", io); } } } @@ -362,7 +366,7 @@ impl RustGenerator { def.ok_value(val.name.clone()); } BindingRef::Slice(_ptr, _len) => { - panic!("it should not be possible to have an out slice {:?}", o); + unreachable!("it should not be possible to have an out slice {:?}", o); } } } @@ -373,36 +377,197 @@ impl RustGenerator { } fn host_abi_definition(&mut self, module: &Module, func: &FuncDecl) -> Result<(), IDLError> { - let mut args = format!("&mut vmctx,"); + let mut args = vec![format!("&mut vmctx")]; for a in func.args.iter() { - args += &format!( - "{}: {},", + args.push(format!( + "{}: {}", a.name.to_snake_case(), Self::abitype_name(&a.type_) - ); + )); } - let rets = if func.rets.len() == 0 { - format!(" -> ()") + let abi_rettype = if func.rets.len() == 0 { + "()" } else { assert_eq!(func.rets.len(), 1); - format!(" -> {}", Self::abitype_name(&func.rets[0].type_)) + Self::abitype_name(&func.rets[0].type_) }; - self.w.writeln("#[no_mangle]").writeln(format!( - "// Wasm func {}::{} \n\ - pub unsafe extern \"C\" fn {}({}){} {{", - module.module_name, func.field_name, func.binding_name, args, rets - )); + self.w + .writeln("#[no_mangle]") + .writeln(format!( + "// Wasm func {}::{}", + module.module_name, func.field_name + )) + .writeln(format!( + "pub unsafe extern \"C\" fn {}({},) -> {} {{", + func.binding_name, + args.join(", "), + abi_rettype + )); self.w.indent(); - self.w.writeln("unimplemented!()"); + let typename = module.module_name.to_camel_case(); + + self.w.writeln(format!( + "fn inner(obj: &mut dyn {}, {}) -> Result<{},()> {{", + typename, + func.args + .iter() + .map(|a| format!( + "{}: {}", + a.name.to_snake_case(), + Self::abitype_name(&a.type_) + )) + .collect::>() + .join(", "), + abi_rettype, + )); + self.w.indent(); + { + let (pre, post, trait_args, trait_rets, func_rets) = self.trait_dispatch(func); + self.w.writelns(&pre); + self.w.writeln(format!( + "let {} = obj.{}({})?;", + render_tuple(&trait_rets), + func.field_name.to_snake_case(), + trait_args.join(", ") + )); + self.w.writelns(&post); + self.w.writeln(format!("Ok({})", render_tuple(&func_rets))); + } + self.w.eob().writeln("}"); + + self.w.writeln(format!( + "let mut ctx: ::std::cell::RefMut> = vmctx.get_embed_ctx_mut::>();", + typename = typename + )); + self.w.writeln(format!( + "match inner(&mut **ctx, {}) {{ Ok(v) => v, Err(e) => lucet_hostcall_terminate!(\"FIXME\"), }}", + func.args + .iter() + .map(|a| a.name.to_snake_case()) + .collect::>() + .join(", "), + )); self.w.eob().writeln("}"); Ok(()) } + fn trait_dispatch( + &self, + func: &FuncDecl, + ) -> ( + Vec, + Vec, + Vec, + Vec, + Vec, + ) { + let mut pre = Vec::new(); + let mut post = Vec::new(); + let mut trait_args = Vec::new(); + let mut trait_rets = Vec::new(); + let mut func_rets = Vec::new(); + + for input in func.in_bindings.iter() { + match &input.from { + BindingRef::Ptr(ptr_pos) => { + let ptr = func.get_param(ptr_pos).expect("valid param"); + pre.push(format!( + "let {}: &{} = unimplemented!(); // convert pointer in linear memory to ref, or fail: {:?}", + input.name, + self.get_defined_typename(&input.type_), + ptr + )); + trait_args.push(input.name.clone()); + } + BindingRef::Slice(ptr_pos, len_pos) => { + let ptr = func.get_param(ptr_pos).expect("valid param"); + let len = func.get_param(len_pos).expect("valid param"); + pre.push(format!( + "let {}: &[{}] = unimplemented!(); // convert pointer, len to slice {:?} {:?}", + input.name, + self.get_defined_typename(&input.type_), + ptr, + len + )); + trait_args.push(input.name.clone()); + } + BindingRef::Value(value_pos) => { + let value = func.get_param(value_pos).expect("valid param"); + pre.push(format!( + "let {}: {} = unimplemented!(); // cast value {:?}", + input.name, + self.get_defined_typename(&input.type_), + value + )); + trait_args.push(value.name.clone()); + } + } + } + for io in func.inout_bindings.iter() { + match &io.from { + BindingRef::Ptr(ptr_pos) => { + let ptr = func.get_param(ptr_pos).expect("valid param"); + pre.push(format!( + "let mut {}: &{} = unimplemented!(); // convert pointer to mut ref {:?}", + io.name, + self.get_defined_typename(&io.type_), + ptr, + )); + trait_args.push(format!("&mut {}", io.name)); + } + BindingRef::Slice(ptr_pos, len_pos) => { + let ptr = func.get_param(ptr_pos).expect("valid param"); + let len = func.get_param(len_pos).expect("valid param"); + pre.push(format!( + "let mut {}: &[{}] = unimplemented!(); // convert pointer, len to slice {:?} {:?}", + io.name, + self.get_defined_typename(&io.type_), + ptr, + len + )); + trait_args.push(format!("&mut {}", io.name.clone())); + } + BindingRef::Value { .. } => unreachable!(), + } + } + for out in func.out_bindings.iter() { + match &out.from { + BindingRef::Ptr(ptr_pos) => { + let ptr = func.get_param(ptr_pos).expect("valid param"); + pre.push(format!( + "let mut {}: &{} = unimplemented!(); // pointer to {:?}", + ptr.name, + self.get_defined_typename(&out.type_), + ptr, + )); + trait_rets.push(out.name.clone()); + post.push(format!( + "*{} = {}; // Copy into out-pointer reference", + ptr.name, out.name, + )); + } + BindingRef::Value(value_pos) => { + let value = func.get_param(value_pos).expect("valid param"); + trait_rets.push(out.name.clone()); + post.push(format!( + "let {}: {} = unimplemented!(); // cast value to abi type {:?}", + value.name, + Self::abitype_name(&value.type_), + out + )); + func_rets.push(value.name.clone()) + } + BindingRef::Slice { .. } => unreachable!(), + } + } + (pre, post, trait_args, trait_rets, func_rets) + } + fn host_trait_definition(&mut self, module: &Module) -> Result<(), IDLError> { self.w .writeln(format!( @@ -410,10 +575,72 @@ impl RustGenerator { module.module_name.to_camel_case() )) .indent(); + for fdecl in module.func_decls() { + let func_name = fdecl.entity.field_name.to_snake_case(); + + let (mut args, rets) = self.trait_idiomatic_params(&fdecl.entity); + args.insert(0, "&mut self".to_owned()); + + self.w.writeln(format!( + "fn {}({}) -> {};", + func_name, + args.join(", "), + format!("Result<{},()>", render_tuple(&rets)), + )); + } self.w.eob().writeln("}"); + Ok(()) } + + fn trait_idiomatic_params(&self, func: &FuncDecl) -> (Vec, Vec) { + let mut args = Vec::new(); + for input in func.in_bindings.iter() { + match &input.from { + BindingRef::Ptr { .. } => args.push(format!( + "{}: &{}", + input.name, + self.get_defined_typename(&input.type_) + )), + BindingRef::Slice { .. } => args.push(format!( + "{}: &[{}]", + input.name, + self.get_defined_typename(&input.type_) + )), + BindingRef::Value { .. } => args.push(format!( + "{}: {}", + input.name, + self.get_defined_typename(&input.type_) + )), + } + } + for io in func.inout_bindings.iter() { + match &io.from { + BindingRef::Ptr { .. } => args.push(format!( + "{}: &mut {}", + io.name, + self.get_defined_typename(&io.type_) + )), + BindingRef::Slice { .. } => args.push(format!( + "{}: &mut [{}]", + io.name, + self.get_defined_typename(&io.type_) + )), + BindingRef::Value { .. } => unreachable!(), + } + } + let mut rets = Vec::new(); + for out in func.out_bindings.iter() { + match &out.from { + BindingRef::Ptr { .. } | BindingRef::Value { .. } => { + rets.push(format!("{}", self.get_defined_typename(&out.type_))) + } + BindingRef::Slice { .. } => unreachable!(), + } + } + (args, rets) + } } fn gen_testcase(w: &mut PrettyWriter, name: &str, f: F) -> Result<(), IDLError> @@ -430,3 +657,11 @@ where w.writeln("}").eob(); Ok(()) } + +pub fn render_tuple(members: &[String]) -> String { + match members.len() { + 0 => "()".to_owned(), + 1 => members[0].clone(), + _ => format!("({})", members.join(", ")), + } +} diff --git a/lucet-idl/src/rust/guest_funcs.rs b/lucet-idl/src/rust/guest_funcs.rs index 1ba053a92..25a3e7107 100644 --- a/lucet-idl/src/rust/guest_funcs.rs +++ b/lucet-idl/src/rust/guest_funcs.rs @@ -1,3 +1,4 @@ +use super::render_tuple; use crate::error::IDLError; use crate::function::{FuncDecl, ParamPosition}; use crate::pretty_writer::PrettyWriter; @@ -70,18 +71,14 @@ impl<'a> AbiCallBuilder<'a> { format!("let {} = ", rets[0]) }; - for b in self.before.iter() { - w.writeln(b); - } + w.writelns(&self.before); w.writeln(format!( "{}unsafe {{ abi::{}({}) }};", ret_syntax, name, arg_syntax )); - for a in self.after.iter() { - w.writeln(a); - } + w.writelns(&self.after); Ok(()) } @@ -118,14 +115,6 @@ impl FuncBuilder { self.ok_values.push(val); } - fn render_tuple(members: &[String]) -> String { - match members.len() { - 0 => "()".to_owned(), - 1 => members[0].clone(), - _ => format!("({})", members.join(", ")), - } - } - pub fn render(&self, w: &mut PrettyWriter, body: F) -> Result<(), IDLError> where F: FnOnce(&mut PrettyWriter) -> Result<(), IDLError>, @@ -138,7 +127,7 @@ impl FuncBuilder { let arg_syntax = self.args.join(", "); let ret_syntax = format!( "Result<{},{}>", - Self::render_tuple(&self.ok_types), + render_tuple(&self.ok_types), self.error_type ); w.writeln(format!( @@ -147,7 +136,7 @@ impl FuncBuilder { )) .indent(); body(w)?; - w.writeln(format!("Ok({})", Self::render_tuple(&self.ok_values))); + w.writeln(format!("Ok({})", render_tuple(&self.ok_values))); w.eob().writeln("}".to_owned()); Ok(()) } From c87f2e6665c4147364dbdc53ef782f79078c001b Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 23 Jul 2019 18:15:16 -0700 Subject: [PATCH 309/512] lucet-idl: host side unpacking and validating input bindings i think i just need to follow this pattern for the inout and out ones, pretty straightforward? --- lucet-idl/lucet-idl-test/src/values.rs | 12 +++++ lucet-idl/src/data_layout.rs | 2 +- lucet-idl/src/lib.rs | 2 +- lucet-idl/src/module.rs | 15 ++++++- lucet-idl/src/rust.rs | 61 +++++++++++++++++++------- lucet-idl/src/types.rs | 21 ++++++++- 6 files changed, 92 insertions(+), 21 deletions(-) diff --git a/lucet-idl/lucet-idl-test/src/values.rs b/lucet-idl/lucet-idl-test/src/values.rs index 2b69af157..56625868d 100644 --- a/lucet-idl/lucet-idl-test/src/values.rs +++ b/lucet-idl/lucet-idl-test/src/values.rs @@ -388,6 +388,18 @@ impl FuncCallPredicate { .map(|val| format!("assert_eq!({}, {});", val.name, val.render_rust_ref())) .collect() } + + pub fn render_callee(&self, module: &Module) -> Vec { + let mut lines = Vec::new(); + lines.push("struct Test;".to_owned()); + lines.push(format!( + "impl {} for Test {{", + module.module_name.to_camel_case() + )); + + lines.push("}".to_owned()); + lines + } } fn render_tuple(vs: Vec, base_case: &str) -> String { diff --git a/lucet-idl/src/data_layout.rs b/lucet-idl/src/data_layout.rs index 4d4e6351d..b6685088d 100644 --- a/lucet-idl/src/data_layout.rs +++ b/lucet-idl/src/data_layout.rs @@ -1,7 +1,7 @@ use crate::error::ValidationError; use crate::types::{ AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, EnumMember, - Ident, Location, Name, StructDataType, StructMember, + Ident, Location, MemArea, Name, StructDataType, StructMember, }; use std::collections::HashMap; diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 4c2c5fd4b..4c05ce695 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -23,7 +23,7 @@ pub use crate::module::Module; pub use crate::package::Package; pub use crate::types::{ AbiType, AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, Ident, - Location, Name, Named, StructDataType, StructMember, + Location, MemArea, Name, Named, StructDataType, StructMember, }; use crate::c::CGenerator; diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index 131e7c987..c7f464501 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -5,7 +5,8 @@ use crate::error::ValidationError; use crate::function::FuncDecl; use crate::parser::{SyntaxDecl, SyntaxTypeRef}; use crate::types::{ - AbiType, DataType, DataTypeRef, DataTypeVariant, EnumMember, Ident, Location, Name, Named, + AbiType, DataType, DataTypeRef, DataTypeVariant, EnumMember, Ident, Location, MemArea, Name, + Named, }; use heck::SnakeCase; use std::collections::HashMap; @@ -269,6 +270,18 @@ impl Module { } } + pub fn get_mem_area(&self, dtref: &DataTypeRef) -> Box { + match dtref { + DataTypeRef::Defined(ident) => Box::new( + self.get_datatype(*ident) + .expect("valid datatype") + .entity + .clone(), + ), + DataTypeRef::Atom(atom) => Box::new(*atom), + } + } + /// Retrieve information about a function declaration given its identifier pub fn get_func_decl(&self, id: Ident) -> Option> { let name = &self.names[id.0]; diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index 5127dfc86..a7ec1f125 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -411,7 +411,7 @@ impl RustGenerator { let typename = module.module_name.to_camel_case(); self.w.writeln(format!( - "fn inner(obj: &mut dyn {}, {}) -> Result<{},()> {{", + "fn inner(heap: &mut [u8], obj: &mut dyn {}, {}) -> Result<{},()> {{", typename, func.args .iter() @@ -426,7 +426,7 @@ impl RustGenerator { )); self.w.indent(); { - let (pre, post, trait_args, trait_rets, func_rets) = self.trait_dispatch(func); + let (pre, post, trait_args, trait_rets, func_rets) = self.trait_dispatch(module, func); self.w.writelns(&pre); self.w.writeln(format!( "let {} = obj.{}({})?;", @@ -443,8 +443,9 @@ impl RustGenerator { "let mut ctx: ::std::cell::RefMut> = vmctx.get_embed_ctx_mut::>();", typename = typename )); + self.w.writeln("let mut heap = vmctx.heap_mut();"); self.w.writeln(format!( - "match inner(&mut **ctx, {}) {{ Ok(v) => v, Err(e) => lucet_hostcall_terminate!(\"FIXME\"), }}", + "match inner(&mut *heap, &mut **ctx, {}) {{ Ok(v) => v, Err(e) => lucet_hostcall_terminate!(\"FIXME\"), }}", func.args .iter() .map(|a| a.name.to_snake_case()) @@ -458,6 +459,7 @@ impl RustGenerator { fn trait_dispatch( &self, + module: &Module, func: &FuncDecl, ) -> ( Vec, @@ -473,36 +475,63 @@ impl RustGenerator { let mut func_rets = Vec::new(); for input in func.in_bindings.iter() { + let input_mem = module.get_mem_area(&input.type_); match &input.from { BindingRef::Ptr(ptr_pos) => { let ptr = func.get_param(ptr_pos).expect("valid param"); + pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name)); pre.push(format!( - "let {}: &{} = unimplemented!(); // convert pointer in linear memory to ref, or fail: {:?}", - input.name, - self.get_defined_typename(&input.type_), - ptr + "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", + ptr = ptr.name, + align = input_mem.align(), + )); + pre.push(format!( + "#[allow(non_snake_case)] let {name}___MEM: &[u8] = heap.get({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", + name = input.name, + ptr = ptr.name, + len = input_mem.repr_size(), + )); + pre.push(format!( + "let {name}: &{typename} = unsafe {{ ({name}___MEM.as_ptr() as *const {typename}).as_ref().unwrap() }}; // convert pointer in linear memory to ref, or fail: {:?}", + name = input.name, + typename = self.get_defined_typename(&input.type_), )); trait_args.push(input.name.clone()); } BindingRef::Slice(ptr_pos, len_pos) => { let ptr = func.get_param(ptr_pos).expect("valid param"); let len = func.get_param(len_pos).expect("valid param"); + + pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name)); + pre.push(format!("let {len} = {len} as usize;", len = len.name)); pre.push(format!( - "let {}: &[{}] = unimplemented!(); // convert pointer, len to slice {:?} {:?}", - input.name, - self.get_defined_typename(&input.type_), - ptr, - len + "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", + ptr = ptr.name, + align = input_mem.align(), + )); + pre.push(format!( + "#[allow(non_snake_case)] let {name}___MEM: &[u8] = heap.get({ptr}..({ptr}+({len}*{elem_len}))).ok_or_else(|| () /* FIXME: bounds check failed */)?;", + name = input.name, + ptr = ptr.name, + len = len.name, + elem_len = input_mem.repr_size(), + )); + + pre.push(format!( + "let {}: &[{}] = unsafe {{ ::std::slice::from_raw_parts({name}___MEM.as_ptr() as *const {typename}, {len}) }};", + name = input.name, + typename = self.get_defined_typename(&input.type_), + len = len.name, )); trait_args.push(input.name.clone()); } BindingRef::Value(value_pos) => { let value = func.get_param(value_pos).expect("valid param"); pre.push(format!( - "let {}: {} = unimplemented!(); // cast value {:?}", - input.name, - self.get_defined_typename(&input.type_), - value + "let {name}: {typename} = {value} as {typename};", + name = input.name, + typename = self.get_defined_typename(&input.type_), + value = value.name )); trait_args.push(value.name.clone()); } diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index ec8e9b295..a153de632 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -1,5 +1,10 @@ use std::fmt; +pub trait MemArea { + fn repr_size(&self) -> usize; + fn align(&self) -> usize; +} + #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum AtomType { Bool, @@ -15,8 +20,8 @@ pub enum AtomType { F64, } -impl AtomType { - pub fn repr_size(&self) -> usize { +impl MemArea for AtomType { + fn repr_size(&self) -> usize { match self { AtomType::Bool => 1, AtomType::U8 | AtomType::I8 => 1, @@ -25,6 +30,9 @@ impl AtomType { AtomType::U64 | AtomType::I64 | AtomType::F64 => 8, } } + fn align(&self) -> usize { + self.repr_size() + } } #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -148,6 +156,15 @@ pub struct Name { pub location: Location, } +impl MemArea for DataType { + fn repr_size(&self) -> usize { + self.repr_size + } + fn align(&self) -> usize { + self.align + } +} + impl fmt::Display for Name { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.name) From 473d282ad6c166b8ddd4367f08574880e5b32749 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 24 Jul 2019 10:20:10 -0700 Subject: [PATCH 310/512] lucet-idl: host io bindings typecheck --- lucet-idl/src/rust.rs | 48 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index a7ec1f125..df7d6ef27 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -492,7 +492,7 @@ impl RustGenerator { len = input_mem.repr_size(), )); pre.push(format!( - "let {name}: &{typename} = unsafe {{ ({name}___MEM.as_ptr() as *const {typename}).as_ref().unwrap() }}; // convert pointer in linear memory to ref, or fail: {:?}", + "let {name}: &{typename} = unsafe {{ ({name}___MEM.as_ptr() as *const {typename}).as_ref().unwrap() }}; // convert pointer in linear memory to ref", name = input.name, typename = self.get_defined_typename(&input.type_), )); @@ -538,27 +538,55 @@ impl RustGenerator { } } for io in func.inout_bindings.iter() { + let io_mem = module.get_mem_area(&io.type_); match &io.from { BindingRef::Ptr(ptr_pos) => { let ptr = func.get_param(ptr_pos).expect("valid param"); + pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name)); pre.push(format!( - "let mut {}: &{} = unimplemented!(); // convert pointer to mut ref {:?}", - io.name, - self.get_defined_typename(&io.type_), - ptr, + "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", + ptr = ptr.name, + align = io_mem.align(), + )); + pre.push(format!( + "#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", + name = io.name, + ptr = ptr.name, + len = io_mem.repr_size(), + )); + pre.push(format!( + "let mut {name}: &mut {typename} = unsafe {{ ({name}___MEM.as_mut_ptr() as *mut {typename}).as_mut().unwrap() }}; // convert pointer in linear memory to ref", + name = io.name, + typename = self.get_defined_typename(&io.type_), )); trait_args.push(format!("&mut {}", io.name)); } BindingRef::Slice(ptr_pos, len_pos) => { let ptr = func.get_param(ptr_pos).expect("valid param"); let len = func.get_param(len_pos).expect("valid param"); + + pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name)); + pre.push(format!("let {len} = {len} as usize;", len = len.name)); pre.push(format!( - "let mut {}: &[{}] = unimplemented!(); // convert pointer, len to slice {:?} {:?}", - io.name, - self.get_defined_typename(&io.type_), - ptr, - len + "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", + ptr = ptr.name, + align = io_mem.align(), )); + pre.push(format!( + "#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+({len}*{elem_len}))).ok_or_else(|| () /* FIXME: bounds check failed */)?;", + name = io.name, + ptr = ptr.name, + len = len.name, + elem_len = io_mem.repr_size(), + )); + + pre.push(format!( + "let mut {}: &mut [{}] = unsafe {{ ::std::slice::from_raw_parts_mut({name}___MEM.as_mut_ptr() as *mut {typename}, {len}) }};", + name = io.name, + typename = self.get_defined_typename(&io.type_), + len = len.name, + )); + trait_args.push(format!("&mut {}", io.name.clone())); } BindingRef::Value { .. } => unreachable!(), From f2bd531175bbc4caaeecee372cc00b2cd6e54da8 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 25 Jul 2019 11:15:08 -0700 Subject: [PATCH 311/512] lucet-idl-test: some work towards rendering host-side of test harness... --- .../resources/rust_host/src/harness.rs | 6 ++ .../resources/rust_host/src/idl.rs | 1 + .../resources/rust_host/src/main.rs | 2 +- .../resources/rust_host/src/run.rs | 5 ++ lucet-idl/lucet-idl-test/src/host.rs | 14 +++++ lucet-idl/lucet-idl-test/src/values.rs | 55 ++++++++++++++----- 6 files changed, 67 insertions(+), 16 deletions(-) create mode 100644 lucet-idl/lucet-idl-test/resources/rust_host/src/harness.rs diff --git a/lucet-idl/lucet-idl-test/resources/rust_host/src/harness.rs b/lucet-idl/lucet-idl-test/resources/rust_host/src/harness.rs new file mode 100644 index 000000000..b74497767 --- /dev/null +++ b/lucet-idl/lucet-idl-test/resources/rust_host/src/harness.rs @@ -0,0 +1,6 @@ +// PLACEHOLDER FILE +// this file is overwritten, and restored, by lucet-idl-test +pub struct Ctx; +fn ctx() -> Box { + Box::new(Ctx) +} diff --git a/lucet-idl/lucet-idl-test/resources/rust_host/src/idl.rs b/lucet-idl/lucet-idl-test/resources/rust_host/src/idl.rs index 1a9139565..8228ef8d1 100644 --- a/lucet-idl/lucet-idl-test/resources/rust_host/src/idl.rs +++ b/lucet-idl/lucet-idl-test/resources/rust_host/src/idl.rs @@ -1,2 +1,3 @@ // PLACEHOLDER FILE // this file is overwritten, and restored, by lucet-idl-test +fn ensure_linked() {} diff --git a/lucet-idl/lucet-idl-test/resources/rust_host/src/main.rs b/lucet-idl/lucet-idl-test/resources/rust_host/src/main.rs index ffc74bd57..1bf200fb1 100644 --- a/lucet-idl/lucet-idl-test/resources/rust_host/src/main.rs +++ b/lucet-idl/lucet-idl-test/resources/rust_host/src/main.rs @@ -1,7 +1,7 @@ use std::env; use std::path::PathBuf; -#[allow(unused)] +mod harness; mod idl; mod run; diff --git a/lucet-idl/lucet-idl-test/resources/rust_host/src/run.rs b/lucet-idl/lucet-idl-test/resources/rust_host/src/run.rs index 23cd5614f..86d9d0f60 100644 --- a/lucet-idl/lucet-idl-test/resources/rust_host/src/run.rs +++ b/lucet-idl/lucet-idl-test/resources/rust_host/src/run.rs @@ -1,3 +1,4 @@ +use crate::{harness, idl}; use failure::Error; use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region}; use lucet_wasi::{self, WasiCtxBuilder}; @@ -6,6 +7,7 @@ use std::sync::Arc; pub fn run(module_path: PathBuf) -> Result<(), Error> { lucet_wasi::hostcalls::ensure_linked(); + idl::ensure_linked(); let module = DlModule::load(&module_path)?; @@ -24,9 +26,12 @@ pub fn run(module_path: PathBuf) -> Result<(), Error> { .build() .expect("create empty wasi ctx"); + let harness_ctx = harness::ctx(); + let mut inst = region .new_instance_builder(module as Arc) .with_embed_ctx(ctx) + .with_embed_ctx(harness_ctx) .build() .expect("construct instance"); diff --git a/lucet-idl/lucet-idl-test/src/host.rs b/lucet-idl/lucet-idl-test/src/host.rs index 043c0fb7f..05e06c4b8 100644 --- a/lucet-idl/lucet-idl-test/src/host.rs +++ b/lucet-idl/lucet-idl-test/src/host.rs @@ -17,6 +17,12 @@ pub struct HostApp { impl HostApp { pub fn new(package: &Package) -> Result { + if package.modules.len() != 1 { + Err(format_err!( + "only one module per package supported at this time" + ))? + } + // Need a system-wide lock on the source directory, because we will modify its contents and // call `cargo run` on it. // This way we can use the cache of compiled crates in the project cargo workspace. @@ -47,6 +53,12 @@ impl HostApp { Box::new(idl_file), )?; + let harness_file = hostapp.source_file("harness.rs")?; + self.test_harness( + Box::new(harness_file), + package.modules.get(0).expect("one module per package"), + )?; + Ok(hostapp) } @@ -101,3 +113,5 @@ impl Drop for HostApp { } } } + +fn test_harness(out: Box, module: &Module) -> Result<(), Error> {} diff --git a/lucet-idl/lucet-idl-test/src/values.rs b/lucet-idl/lucet-idl-test/src/values.rs index 56625868d..e6789313a 100644 --- a/lucet-idl/lucet-idl-test/src/values.rs +++ b/lucet-idl/lucet-idl-test/src/values.rs @@ -376,27 +376,52 @@ impl FuncCallPredicate { lines } - pub fn render_postcondition_bindings(&self) -> Vec { - self.post - .iter() - .map(|val| format!("let {} = {};", val.name, val.render_rust_constructor())) - .collect() - } - pub fn render_postcondition_assertions(&self) -> Vec { - self.post - .iter() - .map(|val| format!("assert_eq!({}, {});", val.name, val.render_rust_ref())) - .collect() + pub fn render_callee(&self) -> Vec { + let mut lines = Vec::new(); + // Assert preconditions hold + lines.append( + &mut self + .pre + .iter() + .map(|val| format!("assert_eq!({}, {};", val.name, val.render_rust_ref())) + .collect(), + ); + // Make postconditions hold + lines.append( + &mut self + .post + .iter() + .map(|val| format!("*{} = {};", val.name, val.render_rust_constructor())) + .collect(), + ); + lines } - pub fn render_callee(&self, module: &Module) -> Vec { + pub fn render_host_trait(&self, module: &Module) -> Vec { let mut lines = Vec::new(); - lines.push("struct Test;".to_owned()); + lines.push("struct TestHarness;".to_owned()); lines.push(format!( - "impl {} for Test {{", + "impl {} for TesHarnesst {{", module.module_name.to_camel_case() )); - + for func in module.func_decls() { + let func = func.entity; + let mut args: Vec = Vec::new(); + for input in func.in_bindings.iter() {} + let mut rets = Vec::new(); + lines.push(format!( + "fn {}(&mut self, {}) -> Result<{}, ()>", + func.field_name, + args.join(","), + render_tuple(rets, "()") + )); + if func.field_name == self.func.field_name { + lines.append(&mut self.render_callee()); + } else { + lines.push("panic!(\"should not be called\")".to_owned()); + } + lines.push("}".to_owned()); + } lines.push("}".to_owned()); lines } From 111e6980929dc4cab7de6c5b1996fb6d25ddbab6 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 25 Jul 2019 11:18:32 -0700 Subject: [PATCH 312/512] lucet-idl: out bindings work --- lucet-idl/src/rust.rs | 46 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index df7d6ef27..c790a6ac7 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -69,6 +69,8 @@ impl RustGenerator { self.host_abi_definition(module, &fdecl.entity)?; } self.w.eob().writeln("}"); + + self.host_ensure_linked(module); } Ok(()) } @@ -593,15 +595,30 @@ impl RustGenerator { } } for out in func.out_bindings.iter() { + let out_mem = module.get_mem_area(&out.type_); match &out.from { BindingRef::Ptr(ptr_pos) => { let ptr = func.get_param(ptr_pos).expect("valid param"); + + pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name)); pre.push(format!( - "let mut {}: &{} = unimplemented!(); // pointer to {:?}", - ptr.name, - self.get_defined_typename(&out.type_), - ptr, + "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", + ptr = ptr.name, + align = out_mem.align(), )); + pre.push(format!( + "#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", + name = out.name, + ptr = ptr.name, + len = out_mem.repr_size(), + )); + pre.push(format!( + "let mut {ptr}: &mut {typename} = unsafe {{ ({name}___MEM.as_mut_ptr() as *mut {typename}).as_mut().unwrap() }}; // convert pointer in linear memory to ref", + name = out.name, + typename = self.get_defined_typename(&out.type_), + ptr = ptr.name, + )); + trait_rets.push(out.name.clone()); post.push(format!( "*{} = {}; // Copy into out-pointer reference", @@ -612,10 +629,10 @@ impl RustGenerator { let value = func.get_param(value_pos).expect("valid param"); trait_rets.push(out.name.clone()); post.push(format!( - "let {}: {} = unimplemented!(); // cast value to abi type {:?}", - value.name, - Self::abitype_name(&value.type_), - out + "let {value}: {typename} = {arg} as {typename};", + value = value.name, + typename = Self::abitype_name(&value.type_), + arg = out.name, )); func_rets.push(value.name.clone()) } @@ -698,6 +715,19 @@ impl RustGenerator { } (args, rets) } + + fn host_ensure_linked(&mut self, module: &Module) { + self.w.writeln("pub fn ensure_linked() {").indent(); + self.w.writeln("unsafe {"); + for fdecl in module.func_decls() { + self.w.writeln(format!( + "::std::ptr::read_volatile({} as *const extern \"C\" fn());", + fdecl.entity.binding_name, + )); + } + self.w.eob().writeln("}"); + self.w.eob().writeln("}"); + } } fn gen_testcase(w: &mut PrettyWriter, name: &str, f: F) -> Result<(), IDLError> From e96e05d0ea0ed8b5b1e0b098f186413c1eb4e00d Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 25 Jul 2019 11:19:12 -0700 Subject: [PATCH 313/512] lucet-idl: refactor wip --- lucet-idl/src/datatypes.rs | 87 ++++++++++++++++++++++++++++++++++++ lucet-idl/src/lib.rs | 1 + lucet-idl/src/module.rs | 2 +- lucet-idl/src/types.rs | 90 +------------------------------------- 4 files changed, 91 insertions(+), 89 deletions(-) create mode 100644 lucet-idl/src/datatypes.rs diff --git a/lucet-idl/src/datatypes.rs b/lucet-idl/src/datatypes.rs new file mode 100644 index 000000000..d8e7e6b26 --- /dev/null +++ b/lucet-idl/src/datatypes.rs @@ -0,0 +1,87 @@ +pub trait MemArea { + fn repr_size(&self) -> usize; + fn align(&self) -> usize; +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum AtomType { + Bool, + U8, + U16, + U32, + U64, + I8, + I16, + I32, + I64, + F32, + F64, +} + +impl MemArea for AtomType { + fn repr_size(&self) -> usize { + match self { + AtomType::Bool => 1, + AtomType::U8 | AtomType::I8 => 1, + AtomType::U16 | AtomType::I16 => 2, + AtomType::U32 | AtomType::I32 | AtomType::F32 => 4, + AtomType::U64 | AtomType::I64 | AtomType::F64 => 8, + } + } + fn align(&self) -> usize { + self.repr_size() + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum AbiType { + I32, + I64, + F32, + F64, +} + +impl AbiType { + pub fn repr_size(&self) -> usize { + match self { + AbiType::I32 | AbiType::F32 => 4, + AbiType::I64 | AbiType::F64 => 8, + } + } + + pub fn from_atom(a: &AtomType) -> Self { + match a { + AtomType::Bool + | AtomType::U8 + | AtomType::I8 + | AtomType::U16 + | AtomType::I16 + | AtomType::U32 + | AtomType::I32 => AbiType::I32, + AtomType::I64 | AtomType::U64 => AbiType::I64, + AtomType::F32 => AbiType::F32, + AtomType::F64 => AbiType::F64, + } + } + + pub fn of_atom(a: AtomType) -> Option { + match a { + AtomType::I32 => Some(AbiType::I32), + AtomType::I64 => Some(AbiType::I64), + AtomType::F32 => Some(AbiType::F32), + AtomType::F64 => Some(AbiType::F64), + _ => None, + } + } +} + +impl From for AtomType { + fn from(abi: AbiType) -> AtomType { + match abi { + AbiType::I32 => AtomType::I32, + AbiType::I64 => AtomType::I64, + AbiType::F32 => AtomType::F32, + AbiType::F64 => AtomType::F64, + } + } +} diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 4c05ce695..44a3234b4 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -6,6 +6,7 @@ extern crate failure; mod c; mod config; mod data_layout; +mod datatypes; mod error; mod function; mod lexer; diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs index c7f464501..013168230 100644 --- a/lucet-idl/src/module.rs +++ b/lucet-idl/src/module.rs @@ -255,7 +255,7 @@ impl Module { Ok(mod_) } - + /* ACCESSORS */ /// Retrieve information about a data type given its identifier pub fn get_datatype(&self, id: Ident) -> Option> { let name = &self.names[id.0]; diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index a153de632..967994fdc 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -1,92 +1,6 @@ -use std::fmt; - -pub trait MemArea { - fn repr_size(&self) -> usize; - fn align(&self) -> usize; -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum AtomType { - Bool, - U8, - U16, - U32, - U64, - I8, - I16, - I32, - I64, - F32, - F64, -} - -impl MemArea for AtomType { - fn repr_size(&self) -> usize { - match self { - AtomType::Bool => 1, - AtomType::U8 | AtomType::I8 => 1, - AtomType::U16 | AtomType::I16 => 2, - AtomType::U32 | AtomType::I32 | AtomType::F32 => 4, - AtomType::U64 | AtomType::I64 | AtomType::F64 => 8, - } - } - fn align(&self) -> usize { - self.repr_size() - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum AbiType { - I32, - I64, - F32, - F64, -} +pub use crate::datatypes::{AbiType, AtomType, MemArea}; -impl AbiType { - pub fn repr_size(&self) -> usize { - match self { - AbiType::I32 | AbiType::F32 => 4, - AbiType::I64 | AbiType::F64 => 8, - } - } - - pub fn from_atom(a: &AtomType) -> Self { - match a { - AtomType::Bool - | AtomType::U8 - | AtomType::I8 - | AtomType::U16 - | AtomType::I16 - | AtomType::U32 - | AtomType::I32 => AbiType::I32, - AtomType::I64 | AtomType::U64 => AbiType::I64, - AtomType::F32 => AbiType::F32, - AtomType::F64 => AbiType::F64, - } - } - - pub fn of_atom(a: AtomType) -> Option { - match a { - AtomType::I32 => Some(AbiType::I32), - AtomType::I64 => Some(AbiType::I64), - AtomType::F32 => Some(AbiType::F32), - AtomType::F64 => Some(AbiType::F64), - _ => None, - } - } -} - -impl From for AtomType { - fn from(abi: AbiType) -> AtomType { - match abi { - AbiType::I32 => AtomType::I32, - AbiType::I64 => AtomType::I64, - AbiType::F32 => AtomType::F32, - AbiType::F64 => AtomType::F64, - } - } -} +use std::fmt; #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] pub struct Location { From d6eb290b56e7cb8248aa26c3c22ff5af573e8a45 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 29 Jul 2019 10:31:05 -0700 Subject: [PATCH 314/512] lucet-idl: refactoring the internal repr into new module easier to port modules to it one-by-one than by breaking everything at once --- lucet-idl/src/env/mod.rs | 1 + lucet-idl/src/env/types.rs | 130 +++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 lucet-idl/src/env/mod.rs create mode 100644 lucet-idl/src/env/types.rs diff --git a/lucet-idl/src/env/mod.rs b/lucet-idl/src/env/mod.rs new file mode 100644 index 000000000..cd408564e --- /dev/null +++ b/lucet-idl/src/env/mod.rs @@ -0,0 +1 @@ +pub mod types; diff --git a/lucet-idl/src/env/types.rs b/lucet-idl/src/env/types.rs new file mode 100644 index 000000000..5ffb43fb4 --- /dev/null +++ b/lucet-idl/src/env/types.rs @@ -0,0 +1,130 @@ +use crate::datatypes::{AbiType, AtomType}; + +use cranelift_entity::{entity_impl, PrimaryMap}; + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct ModuleIx(u32); +entity_impl!(ModuleIx); + +#[derive(Debug, Clone)] +struct PackageRepr { + pub names: Vec, + pub modules: PrimaryMap, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct DatatypeIx(u32); +entity_impl!(DatatypeIx); + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct DatatypeIdent(ModuleIx, DatatypeIx); + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct FuncIx(u32); +entity_impl!(FuncIx); + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct FuncIdent(ModuleIx, FuncIx); + +#[derive(Debug, Clone)] +pub struct ModuleRepr { + pub datatype_names: Vec, + pub datatypes: PrimaryMap, + pub func_names: Vec, + pub funcs: PrimaryMap, +} + +#[derive(Debug, Clone)] +pub struct DatatypeRepr { + pub variant: DatatypeVariant, + pub repr_size: usize, + pub align: usize, +} + +#[derive(Debug, Clone)] +pub enum DatatypeVariant { + Atom(AtomType), + Struct(StructDatatype), + Enum(EnumDatatype), + Alias(AliasDatatype), +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct StructMember { + pub type_: DatatypeIdent, + pub name: String, + pub offset: usize, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct StructDatatype { + pub members: Vec, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct EnumMember { + pub name: String, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct EnumDatatype { + pub members: Vec, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct AliasDatatype { + pub to: DatatypeIdent, +} + +#[derive(Debug, Clone)] +pub struct FuncRepr { + pub args: PrimaryMap, + pub rets: PrimaryMap, + pub bindings: PrimaryMap, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct ArgIx(u32); +entity_impl!(ArgIx); + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct RetIx(u32); +entity_impl!(RetIx); + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ParamIx { + Arg(ArgIx), + Ret(RetIx), +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct BindingIx(u32); +entity_impl!(BindingIx); + +#[derive(Debug, Clone)] +pub struct ParamRepr { + pub name: String, + pub type_: AbiType, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct BindingRepr { + pub name: String, + pub type_: DatatypeIdent, + pub direction: BindingDirection, + pub from: BindingFromRepr, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum BindingDirection { + In, + InOut, + Out, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum BindingFromRepr { + Ptr(ParamIx), + Slice(ParamIx, ParamIx), + Value(ParamIx), +} From 8707749f7376b156d335b9b167daebfb7ec604a9 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 29 Jul 2019 16:26:42 -0700 Subject: [PATCH 315/512] lucet-idl: a nice interface to new repr! --- Cargo.lock | 1 + lucet-idl/Cargo.toml | 1 + lucet-idl/src/env/cursor.rs | 242 +++++++++++++++++++++++++++++++++++ lucet-idl/src/env/memarea.rs | 34 +++++ lucet-idl/src/env/mod.rs | 4 + lucet-idl/src/env/prelude.rs | 108 ++++++++++++++++ lucet-idl/src/env/types.rs | 114 ++++++++++++++--- lucet-idl/src/lib.rs | 1 + 8 files changed, 487 insertions(+), 18 deletions(-) create mode 100644 lucet-idl/src/env/cursor.rs create mode 100644 lucet-idl/src/env/memarea.rs create mode 100644 lucet-idl/src/env/prelude.rs diff --git a/Cargo.lock b/Cargo.lock index 055c7e228..87f28fbd0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -801,6 +801,7 @@ name = "lucet-idl" version = "0.1.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-entity 0.31.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", diff --git a/lucet-idl/Cargo.toml b/lucet-idl/Cargo.toml index 0909d7aa9..ac86769b8 100644 --- a/lucet-idl/Cargo.toml +++ b/lucet-idl/Cargo.toml @@ -23,6 +23,7 @@ xfailure = "0.1" heck = "0.3" lucetc = { path = "../lucetc" } lucet-module = { path = "../lucet-module" } +cranelift-entity = { path = "../cranelift/cranelift-entity" } [dev-dependencies] tempfile = "3.0" diff --git a/lucet-idl/src/env/cursor.rs b/lucet-idl/src/env/cursor.rs new file mode 100644 index 000000000..4ffeaa3a7 --- /dev/null +++ b/lucet-idl/src/env/cursor.rs @@ -0,0 +1,242 @@ +use crate::env::memarea::MemArea; +pub use crate::env::types::EnumMember; +use crate::env::types::{ + AliasDatatypeRepr, AtomType, DatatypeIdent, DatatypeRepr, DatatypeVariantRepr, + EnumDatatypeRepr, ModuleIx, ModuleRepr, PackageRepr, StructDatatypeRepr, StructMemberRepr, +}; + +pub struct Package { + repr: PackageRepr, +} + +impl Package { + pub fn module<'a>(&'a self, name: &str) -> Option> { + if let Some((ix, _)) = self.repr.names.iter().find(|(_, n)| *n == name) { + Some(Module { + pkg: &self.repr, + ix, + }) + } else { + None + } + } +} + +pub struct Module<'a> { + pkg: &'a PackageRepr, + ix: ModuleIx, +} + +impl<'a> Module<'a> { + fn repr(&self) -> &'a ModuleRepr { + self.pkg.modules.get(self.ix).expect("i exist") + } + + pub fn name(&self) -> &str { + self.pkg.names.get(self.ix).expect("i exist") + } + + pub fn datatype(&self, name: &str) -> Option> { + if let Some((ix, _)) = self.repr().datatypes.names.iter().find(|(_, n)| *n == name) { + Some(Datatype { + pkg: self.pkg, + id: DatatypeIdent::new(self.ix, ix), + }) + } else { + None + } + } + + pub fn datatypes(&self) -> impl Iterator> { + let pkg = self.pkg; + let mix = self.ix; + self.repr() + .datatypes + .datatypes + .keys() + .map(move |ix| Datatype { + pkg, + id: DatatypeIdent::new(mix, ix), + }) + } +} + +pub struct Datatype<'a> { + pkg: &'a PackageRepr, + id: DatatypeIdent, +} + +impl<'a> Datatype<'a> { + fn repr(&self) -> &'a DatatypeRepr { + self.pkg + .modules + .get(self.id.module) + .expect("my mod exists") + .datatypes + .datatypes + .get(self.id.datatype) + .expect("i exist") + } + + pub fn name(&self) -> &'a str { + self.pkg + .modules + .get(self.id.module) + .expect("my mod exists") + .datatypes + .names + .get(self.id.datatype) + .expect("i exist") + } + + pub fn variant(&'a self) -> DatatypeVariant<'a> { + match self.repr().variant { + DatatypeVariantRepr::Atom(a) => DatatypeVariant::Atom(a), + DatatypeVariantRepr::Struct(ref repr) => DatatypeVariant::Struct(StructDatatype { + pkg: self.pkg, + repr: &repr, + id: self.id, + }), + DatatypeVariantRepr::Enum(ref repr) => DatatypeVariant::Enum(EnumDatatype { + pkg: self.pkg, + repr: &repr, + id: self.id, + }), + DatatypeVariantRepr::Alias(ref repr) => DatatypeVariant::Alias(AliasDatatype { + pkg: self.pkg, + repr: &repr, + id: self.id, + }), + } + } +} + +impl<'a> MemArea for Datatype<'a> { + fn repr_size(&self) -> usize { + self.repr().repr_size + } + fn align(&self) -> usize { + self.repr().align + } +} + +#[derive(Debug, Clone)] +pub enum DatatypeVariant<'a> { + Atom(AtomType), + Struct(StructDatatype<'a>), + Enum(EnumDatatype<'a>), + Alias(AliasDatatype<'a>), +} + +#[derive(Debug, Clone)] +pub struct StructDatatype<'a> { + pkg: &'a PackageRepr, + repr: &'a StructDatatypeRepr, + id: DatatypeIdent, +} + +impl<'a> StructDatatype<'a> { + pub fn name(&self) -> &str { + Datatype { + pkg: self.pkg, + id: self.id, + } + .name() + } + pub fn members(&self) -> impl Iterator> { + let pkg = self.pkg; + self.repr + .members + .iter() + .map(move |repr| StructMember { pkg, repr }) + } +} + +impl<'a> From> for Datatype<'a> { + fn from(s: StructDatatype<'a>) -> Datatype<'a> { + Datatype { + pkg: s.pkg, + id: s.id, + } + } +} + +pub struct StructMember<'a> { + pkg: &'a PackageRepr, + repr: &'a StructMemberRepr, +} + +impl<'a> StructMember<'a> { + pub fn name(&self) -> &str { + &self.repr.name + } + pub fn offset(&self) -> usize { + self.repr.offset + } + pub fn type_(&self) -> Datatype<'a> { + Datatype { + pkg: self.pkg, + id: self.repr.type_, + } + } +} + +#[derive(Debug, Clone)] +pub struct EnumDatatype<'a> { + pkg: &'a PackageRepr, + repr: &'a EnumDatatypeRepr, + id: DatatypeIdent, +} + +impl<'a> EnumDatatype<'a> { + pub fn name(&self) -> &str { + Datatype { + pkg: self.pkg, + id: self.id, + } + .name() + } + pub fn members(&self) -> &'a [EnumMember] { + &self.repr.members + } +} +impl<'a> From> for Datatype<'a> { + fn from(e: EnumDatatype<'a>) -> Datatype<'a> { + Datatype { + pkg: e.pkg, + id: e.id, + } + } +} + +#[derive(Debug, Clone)] +pub struct AliasDatatype<'a> { + pkg: &'a PackageRepr, + repr: &'a AliasDatatypeRepr, + id: DatatypeIdent, +} + +impl<'a> AliasDatatype<'a> { + pub fn name(&self) -> &str { + Datatype { + pkg: self.pkg, + id: self.id, + } + .name() + } + pub fn to(&self) -> Datatype<'a> { + Datatype { + pkg: self.pkg, + id: self.repr.to, + } + } +} + +impl<'a> From> for Datatype<'a> { + fn from(a: AliasDatatype<'a>) -> Datatype<'a> { + Datatype { + pkg: a.pkg, + id: a.id, + } + } +} diff --git a/lucet-idl/src/env/memarea.rs b/lucet-idl/src/env/memarea.rs new file mode 100644 index 000000000..6b6b7b565 --- /dev/null +++ b/lucet-idl/src/env/memarea.rs @@ -0,0 +1,34 @@ +use crate::env::types::{AbiType, AtomType}; + +pub trait MemArea { + fn repr_size(&self) -> usize; + fn align(&self) -> usize; +} + +impl MemArea for AtomType { + fn repr_size(&self) -> usize { + match self { + AtomType::Bool => 1, + AtomType::U8 | AtomType::I8 => 1, + AtomType::U16 | AtomType::I16 => 2, + AtomType::U32 | AtomType::I32 | AtomType::F32 => 4, + AtomType::U64 | AtomType::I64 | AtomType::F64 => 8, + } + } + fn align(&self) -> usize { + self.repr_size() + } +} + +impl MemArea for AbiType { + fn repr_size(&self) -> usize { + match self { + AbiType::I32 | AbiType::F32 => 4, + AbiType::I64 | AbiType::F64 => 8, + } + } + + fn align(&self) -> usize { + self.repr_size() + } +} diff --git a/lucet-idl/src/env/mod.rs b/lucet-idl/src/env/mod.rs index cd408564e..404816fd0 100644 --- a/lucet-idl/src/env/mod.rs +++ b/lucet-idl/src/env/mod.rs @@ -1 +1,5 @@ +pub mod cursor; +pub mod prelude; pub mod types; +//pub mod data_layout; +pub mod memarea; diff --git a/lucet-idl/src/env/prelude.rs b/lucet-idl/src/env/prelude.rs new file mode 100644 index 000000000..53afce022 --- /dev/null +++ b/lucet-idl/src/env/prelude.rs @@ -0,0 +1,108 @@ +use crate::env::memarea::MemArea; +use crate::env::types::{ + AtomType, DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, ModuleDatatypesRepr, + ModuleFuncsRepr, ModuleIx, ModuleRepr, PackageRepr, +}; +use cranelift_entity::{EntityRef, PrimaryMap}; + +pub fn base_package() -> PackageRepr { + let mut names = PrimaryMap::new(); + names.push("std".to_owned()); + let mut modules = PrimaryMap::new(); + modules.push(ModuleRepr { + datatypes: atom_datatypes(), + funcs: ModuleFuncsRepr { + names: PrimaryMap::new(), + funcs: PrimaryMap::new(), + }, + }); + PackageRepr { names, modules } +} + +fn atom_datatypes() -> ModuleDatatypesRepr { + fn create_atom( + names: &mut PrimaryMap, + datatypes: &mut PrimaryMap, + name: &str, + atom: AtomType, + ) { + let ix = names.push(name.to_owned()); + let repr_size = atom.repr_size(); + let align = atom.align(); + let dix = datatypes.push(DatatypeRepr { + variant: DatatypeVariantRepr::Atom(atom), + repr_size, + align, + }); + assert_eq!(ix, dix, "names and datatypes out of sync"); + } + + let mut names = PrimaryMap::new(); + let mut datatypes = PrimaryMap::new(); + create_atom(&mut names, &mut datatypes, "bool", AtomType::Bool); + create_atom(&mut names, &mut datatypes, "u8", AtomType::U8); + create_atom(&mut names, &mut datatypes, "u16", AtomType::U16); + create_atom(&mut names, &mut datatypes, "u32", AtomType::U32); + create_atom(&mut names, &mut datatypes, "u64", AtomType::U64); + create_atom(&mut names, &mut datatypes, "i8", AtomType::I8); + create_atom(&mut names, &mut datatypes, "i16", AtomType::I16); + create_atom(&mut names, &mut datatypes, "i32", AtomType::I32); + create_atom(&mut names, &mut datatypes, "i64", AtomType::I64); + create_atom(&mut names, &mut datatypes, "f32", AtomType::F32); + create_atom(&mut names, &mut datatypes, "f64", AtomType::F64); + + ModuleDatatypesRepr { names, datatypes } +} + +impl AtomType { + pub fn datatype_ident(&self) -> DatatypeIdent { + use AtomType::*; + match self { + Bool => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(0)), + U8 => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(1)), + U16 => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(2)), + U32 => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(3)), + U64 => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(4)), + I8 => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(5)), + I16 => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(6)), + I32 => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(7)), + I64 => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(8)), + F32 => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(9)), + F64 => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(10)), + } + } +} + +#[cfg(test)] +mod test { + use super::base_package; + use crate::env::types::{AtomType, DatatypeIdent, DatatypeVariantRepr, PackageRepr}; + #[test] + fn atom_idents() { + use AtomType::*; + let prelude = base_package(); + fn lookup_atom(package: &PackageRepr, ident: DatatypeIdent) -> AtomType { + let module = package.modules.get(ident.module).expect("valid moduleix"); + let dt = module + .datatypes + .datatypes + .get(ident.datatype) + .expect("valid datatypeix"); + match dt.variant { + DatatypeVariantRepr::Atom(a) => a, + _ => panic!("expected atom datatype, got {:?}", dt), + } + } + assert_eq!(Bool, lookup_atom(&prelude, Bool.datatype_ident())); + assert_eq!(U8, lookup_atom(&prelude, U8.datatype_ident())); + assert_eq!(U16, lookup_atom(&prelude, U16.datatype_ident())); + assert_eq!(U32, lookup_atom(&prelude, U32.datatype_ident())); + assert_eq!(U64, lookup_atom(&prelude, U64.datatype_ident())); + assert_eq!(I8, lookup_atom(&prelude, I8.datatype_ident())); + assert_eq!(I16, lookup_atom(&prelude, I16.datatype_ident())); + assert_eq!(I32, lookup_atom(&prelude, I32.datatype_ident())); + assert_eq!(I64, lookup_atom(&prelude, I64.datatype_ident())); + assert_eq!(F32, lookup_atom(&prelude, F32.datatype_ident())); + assert_eq!(F64, lookup_atom(&prelude, F64.datatype_ident())); + } +} diff --git a/lucet-idl/src/env/types.rs b/lucet-idl/src/env/types.rs index 5ffb43fb4..23775b0cf 100644 --- a/lucet-idl/src/env/types.rs +++ b/lucet-idl/src/env/types.rs @@ -1,5 +1,3 @@ -use crate::datatypes::{AbiType, AtomType}; - use cranelift_entity::{entity_impl, PrimaryMap}; #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -7,8 +5,8 @@ pub struct ModuleIx(u32); entity_impl!(ModuleIx); #[derive(Debug, Clone)] -struct PackageRepr { - pub names: Vec, +pub struct PackageRepr { + pub names: PrimaryMap, pub modules: PrimaryMap, } @@ -16,8 +14,17 @@ struct PackageRepr { pub struct DatatypeIx(u32); entity_impl!(DatatypeIx); -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct DatatypeIdent(ModuleIx, DatatypeIx); +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct DatatypeIdent { + pub module: ModuleIx, + pub datatype: DatatypeIx, +} + +impl DatatypeIdent { + pub fn new(module: ModuleIx, datatype: DatatypeIx) -> Self { + DatatypeIdent { module, datatype } + } +} #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct FuncIx(u32); @@ -28,37 +35,108 @@ pub struct FuncIdent(ModuleIx, FuncIx); #[derive(Debug, Clone)] pub struct ModuleRepr { - pub datatype_names: Vec, + pub datatypes: ModuleDatatypesRepr, + pub funcs: ModuleFuncsRepr, +} + +#[derive(Debug, Clone)] +pub struct ModuleDatatypesRepr { + pub names: PrimaryMap, pub datatypes: PrimaryMap, - pub func_names: Vec, +} + +#[derive(Debug, Clone)] +pub struct ModuleFuncsRepr { + pub names: PrimaryMap, pub funcs: PrimaryMap, } #[derive(Debug, Clone)] pub struct DatatypeRepr { - pub variant: DatatypeVariant, + pub variant: DatatypeVariantRepr, pub repr_size: usize, pub align: usize, } #[derive(Debug, Clone)] -pub enum DatatypeVariant { +pub enum DatatypeVariantRepr { Atom(AtomType), - Struct(StructDatatype), - Enum(EnumDatatype), - Alias(AliasDatatype), + Struct(StructDatatypeRepr), + Enum(EnumDatatypeRepr), + Alias(AliasDatatypeRepr), +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum AtomType { + Bool, + U8, + U16, + U32, + U64, + I8, + I16, + I32, + I64, + F32, + F64, +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum AbiType { + I32, + I64, + F32, + F64, +} + +impl AbiType { + pub fn from_atom(a: &AtomType) -> Self { + match a { + AtomType::Bool + | AtomType::U8 + | AtomType::I8 + | AtomType::U16 + | AtomType::I16 + | AtomType::U32 + | AtomType::I32 => AbiType::I32, + AtomType::I64 | AtomType::U64 => AbiType::I64, + AtomType::F32 => AbiType::F32, + AtomType::F64 => AbiType::F64, + } + } + + pub fn of_atom(a: AtomType) -> Option { + match a { + AtomType::I32 => Some(AbiType::I32), + AtomType::I64 => Some(AbiType::I64), + AtomType::F32 => Some(AbiType::F32), + AtomType::F64 => Some(AbiType::F64), + _ => None, + } + } +} + +impl From for AtomType { + fn from(abi: AbiType) -> AtomType { + match abi { + AbiType::I32 => AtomType::I32, + AbiType::I64 => AtomType::I64, + AbiType::F32 => AtomType::F32, + AbiType::F64 => AtomType::F64, + } + } } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct StructMember { +pub struct StructMemberRepr { pub type_: DatatypeIdent, pub name: String, pub offset: usize, } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct StructDatatype { - pub members: Vec, +pub struct StructDatatypeRepr { + pub members: Vec, } #[derive(Debug, PartialEq, Eq, Clone)] @@ -67,12 +145,12 @@ pub struct EnumMember { } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct EnumDatatype { +pub struct EnumDatatypeRepr { pub members: Vec, } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct AliasDatatype { +pub struct AliasDatatypeRepr { pub to: DatatypeIdent, } diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 44a3234b4..898f25fbb 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -7,6 +7,7 @@ mod c; mod config; mod data_layout; mod datatypes; +pub mod env; mod error; mod function; mod lexer; From ece010efa48b265989c16f5f5b1a545ed86675bc Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 30 Jul 2019 15:25:02 -0700 Subject: [PATCH 316/512] lucet-idl: moved half of datatype validation & layout code to new side --- lucet-idl/src/datatypes.rs | 89 +------- lucet-idl/src/env/datatypes.rs | 384 +++++++++++++++++++++++++++++++++ lucet-idl/src/env/mod.rs | 4 +- 3 files changed, 388 insertions(+), 89 deletions(-) create mode 100644 lucet-idl/src/env/datatypes.rs diff --git a/lucet-idl/src/datatypes.rs b/lucet-idl/src/datatypes.rs index d8e7e6b26..a5fe3a757 100644 --- a/lucet-idl/src/datatypes.rs +++ b/lucet-idl/src/datatypes.rs @@ -1,87 +1,2 @@ -pub trait MemArea { - fn repr_size(&self) -> usize; - fn align(&self) -> usize; -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum AtomType { - Bool, - U8, - U16, - U32, - U64, - I8, - I16, - I32, - I64, - F32, - F64, -} - -impl MemArea for AtomType { - fn repr_size(&self) -> usize { - match self { - AtomType::Bool => 1, - AtomType::U8 | AtomType::I8 => 1, - AtomType::U16 | AtomType::I16 => 2, - AtomType::U32 | AtomType::I32 | AtomType::F32 => 4, - AtomType::U64 | AtomType::I64 | AtomType::F64 => 8, - } - } - fn align(&self) -> usize { - self.repr_size() - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum AbiType { - I32, - I64, - F32, - F64, -} - -impl AbiType { - pub fn repr_size(&self) -> usize { - match self { - AbiType::I32 | AbiType::F32 => 4, - AbiType::I64 | AbiType::F64 => 8, - } - } - - pub fn from_atom(a: &AtomType) -> Self { - match a { - AtomType::Bool - | AtomType::U8 - | AtomType::I8 - | AtomType::U16 - | AtomType::I16 - | AtomType::U32 - | AtomType::I32 => AbiType::I32, - AtomType::I64 | AtomType::U64 => AbiType::I64, - AtomType::F32 => AbiType::F32, - AtomType::F64 => AbiType::F64, - } - } - - pub fn of_atom(a: AtomType) -> Option { - match a { - AtomType::I32 => Some(AbiType::I32), - AtomType::I64 => Some(AbiType::I64), - AtomType::F32 => Some(AbiType::F32), - AtomType::F64 => Some(AbiType::F64), - _ => None, - } - } -} - -impl From for AtomType { - fn from(abi: AbiType) -> AtomType { - match abi { - AbiType::I32 => AtomType::I32, - AbiType::I64 => AtomType::I64, - AbiType::F32 => AtomType::F32, - AbiType::F64 => AtomType::F64, - } - } -} +pub use crate::env::memarea::MemArea; +pub use crate::env::types::{AbiType, AtomType}; diff --git a/lucet-idl/src/env/datatypes.rs b/lucet-idl/src/env/datatypes.rs new file mode 100644 index 000000000..6fd0028bd --- /dev/null +++ b/lucet-idl/src/env/datatypes.rs @@ -0,0 +1,384 @@ +#![allow(unused_imports)] // XXX remove me when more complete +use crate::env::memarea::MemArea; +use crate::env::types::{ + AliasDatatypeRepr, AtomType, DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, + EnumDatatypeRepr, EnumMember, ModuleIx, StructDatatypeRepr, StructMemberRepr, +}; +use crate::error::ValidationError; +use crate::parser::{ + EnumVariant as EnumVariantSyntax, StructMember as StructMemberSyntax, SyntaxTypeRef, +}; +use crate::types::Location; +use cranelift_entity::PrimaryMap; +use std::collections::HashMap; + +#[derive(Debug, PartialEq, Eq, Clone)] +struct DatatypeIR { + pub variant: VariantIR, + pub location: Location, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +struct StructMemberIR { + type_: DatatypeIdent, + name: String, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +struct StructIR { + members: Vec, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +struct EnumIR { + members: Vec, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +struct AliasIR { + to: DatatypeIdent, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +enum VariantIR { + Struct(StructIR), + Enum(EnumIR), + Alias(AliasIR), +} + +#[derive(Debug, Clone)] +pub struct DatatypeModuleBuilder { + module: ModuleIx, + name_decls: HashMap, + name_map: PrimaryMap, + types: PrimaryMap, +} + +impl DatatypeModuleBuilder { + pub fn new(module: ModuleIx) -> Self { + Self { + module, + name_decls: HashMap::new(), + name_map: PrimaryMap::new(), + types: PrimaryMap::new(), + } + } + + pub fn introduce_name( + &mut self, + name: &str, + location: &Location, + ) -> Result { + if let Some((prev_loc, _prev_ix)) = self.name_decls.get(name) { + Err(ValidationError::NameAlreadyExists { + name: name.to_owned(), + at_location: *location, + previous_location: *prev_loc, + })?; + } + let dix = self.name_map.push(name.to_owned()); + self.name_decls.insert(name.to_owned(), (*location, dix)); + Ok(dix) + } + + pub fn lookup_datatype_ident( + &self, + syntax: &SyntaxTypeRef, + ) -> Result { + match syntax { + SyntaxTypeRef::Name { name, location } => self + .name_decls + .get(name) + .map(|(_loc, ix)| DatatypeIdent::new(self.module, *ix)) + .ok_or_else(|| ValidationError::NameNotFound { + name: name.clone(), + use_location: *location, + }), + SyntaxTypeRef::Atom { atom, .. } => Ok(atom.datatype_ident()), + } + } + + pub fn introduce_struct( + &mut self, + ix: DatatypeIx, + members_syntax: &[StructMemberSyntax], + location: &Location, + ) -> Result<(), ValidationError> { + let name = self.name_map.get(ix).expect("name is introduced"); + if members_syntax.is_empty() { + Err(ValidationError::Empty { + name: name.clone(), + location: *location, + })? + } + + let mut uniq_membs = HashMap::new(); + let mut members = Vec::new(); + for mem in members_syntax { + // Ensure that each member name is unique: + if let Some(existing) = uniq_membs.insert(mem.name.clone(), mem) { + Err(ValidationError::NameAlreadyExists { + name: mem.name.clone(), + at_location: mem.location, + previous_location: existing.location, + })? + } + // Get the DatatypeIdent for the member, which ensures that it refers only to + // defined types: + let type_ = self.lookup_datatype_ident(&mem.type_)?; + // build the struct with this as the member: + members.push(StructMemberIR { + type_, + name: mem.name.clone(), + }); + } + let type_ix = self.types.push(DatatypeIR { + variant: VariantIR::Struct(StructIR { members }), + location: *location, + }); + + assert_eq!( + ix, type_ix, + "datatypes must be introduced in the same order as their names" + ); + + Ok(()) + } + + pub fn introduce_enum( + &mut self, + ix: DatatypeIx, + variants: &[EnumVariantSyntax], + location: &Location, + ) -> Result<(), ValidationError> { + let name = self.name_map.get(ix).expect("name is introduced"); + if variants.is_empty() { + Err(ValidationError::Empty { + name: name.clone(), + location: *location, + })? + } + + let mut uniq_vars = HashMap::new(); + let mut members = Vec::new(); + for var in variants { + // Ensure that each member name is unique: + if let Some(existing) = uniq_vars.insert(var.name.clone(), var) { + Err(ValidationError::NameAlreadyExists { + name: var.name.clone(), + at_location: var.location, + previous_location: existing.location, + })? + } + // build the struct with this as the member: + members.push(EnumMember { + name: var.name.clone(), + }) + } + let type_ix = self.types.push(DatatypeIR { + variant: VariantIR::Enum(EnumIR { members }), + location: *location, + }); + assert_eq!( + ix, type_ix, + "datatypes must be introduced in the same order as their names" + ); + Ok(()) + } + + pub fn introduce_alias( + &mut self, + ix: DatatypeIx, + dest: &SyntaxTypeRef, + location: &Location, + ) -> Result<(), ValidationError> { + let to = self.lookup_datatype_ident(dest)?; + let type_ix = self.types.push(DatatypeIR { + variant: VariantIR::Alias(AliasIR { to }), + location: *location, + }); + assert_eq!( + ix, type_ix, + "datatypes must be introduced in the same order as their names" + ); + Ok(()) + } + + /* + pub fn validate_datatypes( + &self, + names: &[Name], + ) -> Result<(HashMap, Vec), ValidationError> { + let mut finalized = HashMap::new(); + let mut ordered = Vec::new(); + // Important to iterate in name order, so error messages are consistient. + // HashMap iteration order is not stable. + for (ix, name) in names.iter().enumerate() { + let id = Ident(ix); + if let Some(decl) = self.data_types.get(&id) { + // First, make sure datatypes are finite + let mut visited = Vec::new(); + visited.resize(names.len(), false); + + self.dfs_walk(id, &mut visited, &mut ordered, &mut finalized) + .map_err(|_| ValidationError::Infinite { + name: name.name.clone(), + location: decl.location.clone(), + })?; + } + } + Ok((finalized, ordered)) + } + + fn dfs_walk( + &self, + id: Ident, + visited: &mut [bool], + ordered: &mut Vec, + finalized_types: &mut HashMap, + ) -> Result<(), ()> { + if visited[id.0] { + Err(())? + } + visited[id.0] = true; + let dt = self.data_types.get(&id).expect("data type IR is defined"); + + match &dt.variant { + VariantIR::Struct(ref s) => { + // First, iterate down the member to ensure this is finite, and fill in type + // info for leaves first + for mem in s.members.iter() { + if let DataTypeRef::Defined(id) = mem.type_ { + self.dfs_walk(id, visited, ordered, finalized_types)?; + }; + } + // If finalized type information has not yet been computed, we can now compute it: + if !finalized_types.contains_key(&id) { + let mut offset = 0; + let mut struct_align = 1; + let mut members: Vec = Vec::new(); + for mem in s.members.iter() { + let (repr_size, align) = + datatype_repr_size_align(&mem.type_, finalized_types) + .expect("datatype is defined by prior dfs_walk"); + + offset = align_to(offset, align); + struct_align = ::std::cmp::max(struct_align, align); + + members.push(StructMember { + type_: mem.type_.clone(), + name: mem.name.clone(), + offset, + }); + offset += repr_size; + } + + let repr_size = align_to(offset, struct_align); + + finalized_types.insert( + id, + DataType { + variant: DataTypeVariant::Struct(StructDataType { members }), + repr_size, + align: struct_align, + }, + ); + } + } + VariantIR::Alias(ref a) => { + if let DataTypeRef::Defined(pointee_id) = a.to { + self.dfs_walk(pointee_id, visited, ordered, finalized_types)?; + }; + if !finalized_types.contains_key(&id) { + let (repr_size, align) = datatype_repr_size_align(&a.to, finalized_types) + .expect("datatype is defined by prior dfs_walk"); + finalized_types.insert( + id, + DataType { + variant: DataTypeVariant::Alias(AliasDataType { to: a.to.clone() }), + repr_size, + align, + }, + ); + } + } + VariantIR::Enum(ref e) => { + // No recursion to do on the dfs. + if !finalized_types.contains_key(&id) { + // x86_64 ABI says enum is 32 bits wide + let repr_size = AtomType::U32.repr_size(); + let align = repr_size; + finalized_types.insert( + id, + DataType { + variant: DataTypeVariant::Enum(EnumDataType { + members: e.members.clone(), + }), + repr_size, + align, + }, + ); + } + } + } + if !ordered.contains(&id) { + ordered.push(id) + } + visited[id.0] = false; + Ok(()) + } + + */ +} + +/* +fn datatype_repr_size_align( + datatype_ref: &DataTypeRef, + finalized_types: &HashMap, +) -> Option<(usize, usize)> { + let (size, align) = match datatype_ref { + DataTypeRef::Atom(a) => { + let s = a.repr_size(); + (s, s) + } + DataTypeRef::Defined(ref member_ident) => { + let t = finalized_types.get(member_ident)?; + (t.repr_size, t.align) + } + }; + assert!(size > 0); + assert!(align > 0); + Some((size, align)) +} +*/ + +fn align_to(offs: usize, alignment: usize) -> usize { + offs + alignment - 1 - ((offs + alignment - 1) % alignment) +} + +#[cfg(test)] +mod align_test { + use super::align_to; + #[test] + fn align_test() { + assert_eq!(0, align_to(0, 1)); + assert_eq!(0, align_to(0, 2)); + assert_eq!(0, align_to(0, 4)); + assert_eq!(0, align_to(0, 8)); + + assert_eq!(1, align_to(1, 1)); + assert_eq!(2, align_to(1, 2)); + assert_eq!(4, align_to(1, 4)); + assert_eq!(8, align_to(1, 8)); + + assert_eq!(2, align_to(2, 1)); + assert_eq!(2, align_to(2, 2)); + assert_eq!(4, align_to(2, 4)); + assert_eq!(8, align_to(2, 8)); + + assert_eq!(5, align_to(5, 1)); + assert_eq!(6, align_to(5, 2)); + assert_eq!(8, align_to(5, 4)); + assert_eq!(8, align_to(5, 8)); + } +} diff --git a/lucet-idl/src/env/mod.rs b/lucet-idl/src/env/mod.rs index 404816fd0..65b14838f 100644 --- a/lucet-idl/src/env/mod.rs +++ b/lucet-idl/src/env/mod.rs @@ -1,5 +1,5 @@ pub mod cursor; +pub mod datatypes; +pub mod memarea; pub mod prelude; pub mod types; -//pub mod data_layout; -pub mod memarea; From bced904fdef19aa67b9dc6772e0b9713e163b64f Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 30 Jul 2019 18:03:23 -0700 Subject: [PATCH 317/512] lucet-idl: datatype validation & layout calculated in new stuff --- lucet-idl/src/data_layout.rs | 4 +- lucet-idl/src/datatypes.rs | 2 - lucet-idl/src/env/atoms.rs | 90 +++++++ lucet-idl/src/env/cursor.rs | 57 +++-- lucet-idl/src/env/datatypes.rs | 308 +++++++++++++----------- lucet-idl/src/env/memarea.rs | 34 --- lucet-idl/src/env/mod.rs | 9 +- lucet-idl/src/env/prelude.rs | 61 ++--- lucet-idl/src/env/{types.rs => repr.rs} | 67 +----- lucet-idl/src/lexer.rs | 2 +- lucet-idl/src/lib.rs | 1 - lucet-idl/src/rust.rs | 20 +- lucet-idl/src/types.rs | 7 +- 13 files changed, 365 insertions(+), 297 deletions(-) delete mode 100644 lucet-idl/src/datatypes.rs create mode 100644 lucet-idl/src/env/atoms.rs delete mode 100644 lucet-idl/src/env/memarea.rs rename lucet-idl/src/env/{types.rs => repr.rs} (70%) diff --git a/lucet-idl/src/data_layout.rs b/lucet-idl/src/data_layout.rs index b6685088d..7eaaa5893 100644 --- a/lucet-idl/src/data_layout.rs +++ b/lucet-idl/src/data_layout.rs @@ -139,7 +139,7 @@ impl DataTypeModuleBuilder { // No recursion to do on the dfs. if !finalized_types.contains_key(&id) { // x86_64 ABI says enum is 32 bits wide - let repr_size = AtomType::U32.repr_size(); + let repr_size = AtomType::U32.mem_size(); let align = repr_size; finalized_types.insert( id, @@ -193,7 +193,7 @@ fn datatype_repr_size_align( ) -> Option<(usize, usize)> { let (size, align) = match datatype_ref { DataTypeRef::Atom(a) => { - let s = a.repr_size(); + let s = a.mem_size(); (s, s) } DataTypeRef::Defined(ref member_ident) => { diff --git a/lucet-idl/src/datatypes.rs b/lucet-idl/src/datatypes.rs deleted file mode 100644 index a5fe3a757..000000000 --- a/lucet-idl/src/datatypes.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub use crate::env::memarea::MemArea; -pub use crate::env::types::{AbiType, AtomType}; diff --git a/lucet-idl/src/env/atoms.rs b/lucet-idl/src/env/atoms.rs new file mode 100644 index 000000000..f58b7cf82 --- /dev/null +++ b/lucet-idl/src/env/atoms.rs @@ -0,0 +1,90 @@ +use crate::env::MemArea; + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum AtomType { + Bool, + U8, + U16, + U32, + U64, + I8, + I16, + I32, + I64, + F32, + F64, +} + +impl MemArea for AtomType { + fn mem_size(&self) -> usize { + match self { + AtomType::Bool => 1, + AtomType::U8 | AtomType::I8 => 1, + AtomType::U16 | AtomType::I16 => 2, + AtomType::U32 | AtomType::I32 | AtomType::F32 => 4, + AtomType::U64 | AtomType::I64 | AtomType::F64 => 8, + } + } + fn mem_align(&self) -> usize { + self.mem_size() + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum AbiType { + I32, + I64, + F32, + F64, +} + +impl AbiType { + pub fn from_atom(a: &AtomType) -> Self { + match a { + AtomType::Bool + | AtomType::U8 + | AtomType::I8 + | AtomType::U16 + | AtomType::I16 + | AtomType::U32 + | AtomType::I32 => AbiType::I32, + AtomType::I64 | AtomType::U64 => AbiType::I64, + AtomType::F32 => AbiType::F32, + AtomType::F64 => AbiType::F64, + } + } + + pub fn of_atom(a: AtomType) -> Option { + match a { + AtomType::I32 => Some(AbiType::I32), + AtomType::I64 => Some(AbiType::I64), + AtomType::F32 => Some(AbiType::F32), + AtomType::F64 => Some(AbiType::F64), + _ => None, + } + } +} + +impl From for AtomType { + fn from(abi: AbiType) -> AtomType { + match abi { + AbiType::I32 => AtomType::I32, + AbiType::I64 => AtomType::I64, + AbiType::F32 => AtomType::F32, + AbiType::F64 => AtomType::F64, + } + } +} + +impl MemArea for AbiType { + fn mem_size(&self) -> usize { + match self { + AbiType::I32 | AbiType::F32 => 4, + AbiType::I64 | AbiType::F64 => 8, + } + } + + fn mem_align(&self) -> usize { + self.mem_size() + } +} diff --git a/lucet-idl/src/env/cursor.rs b/lucet-idl/src/env/cursor.rs index 4ffeaa3a7..1b67c2e07 100644 --- a/lucet-idl/src/env/cursor.rs +++ b/lucet-idl/src/env/cursor.rs @@ -1,17 +1,27 @@ -use crate::env::memarea::MemArea; -pub use crate::env::types::EnumMember; -use crate::env::types::{ - AliasDatatypeRepr, AtomType, DatatypeIdent, DatatypeRepr, DatatypeVariantRepr, - EnumDatatypeRepr, ModuleIx, ModuleRepr, PackageRepr, StructDatatypeRepr, StructMemberRepr, +use crate::env::atoms::AtomType; +use crate::env::repr::{ + AliasDatatypeRepr, DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, + EnumDatatypeRepr, EnumMember, ModuleIx, ModuleRepr, PackageRepr, StructDatatypeRepr, + StructMemberRepr, }; +use crate::env::MemArea; -pub struct Package { - repr: PackageRepr, +#[derive(Debug, Clone)] +pub struct Package<'a> { + repr: &'a PackageRepr, } -impl Package { - pub fn module<'a>(&'a self, name: &str) -> Option> { - if let Some((ix, _)) = self.repr.names.iter().find(|(_, n)| *n == name) { +impl<'a> Package<'a> { + pub fn module(&self, name: &str) -> Option> { + self.repr + .names + .iter() + .find(|(_, n)| *n == name) + .and_then(|(ix, _)| self.module_by_ix(ix)) + } + + pub(crate) fn module_by_ix(&self, ix: ModuleIx) -> Option> { + if self.repr.modules.is_valid(ix) { Some(Module { pkg: &self.repr, ix, @@ -20,8 +30,14 @@ impl Package { None } } + + pub(crate) fn datatype_by_id(&self, id: DatatypeIdent) -> Option> { + self.module_by_ix(id.module) + .and_then(|m| m.datatype_by_ix(id.datatype)) + } } +#[derive(Debug, Clone)] pub struct Module<'a> { pkg: &'a PackageRepr, ix: ModuleIx, @@ -37,7 +53,16 @@ impl<'a> Module<'a> { } pub fn datatype(&self, name: &str) -> Option> { - if let Some((ix, _)) = self.repr().datatypes.names.iter().find(|(_, n)| *n == name) { + self.repr() + .datatypes + .names + .iter() + .find(|(_, n)| *n == name) + .and_then(|(ix, _)| self.datatype_by_ix(ix)) + } + + pub(crate) fn datatype_by_ix(&self, ix: DatatypeIx) -> Option> { + if self.repr().datatypes.datatypes.is_valid(ix) { Some(Datatype { pkg: self.pkg, id: DatatypeIdent::new(self.ix, ix), @@ -61,6 +86,7 @@ impl<'a> Module<'a> { } } +#[derive(Debug, Clone)] pub struct Datatype<'a> { pkg: &'a PackageRepr, id: DatatypeIdent, @@ -112,11 +138,11 @@ impl<'a> Datatype<'a> { } impl<'a> MemArea for Datatype<'a> { - fn repr_size(&self) -> usize { - self.repr().repr_size + fn mem_size(&self) -> usize { + self.repr().mem_size } - fn align(&self) -> usize { - self.repr().align + fn mem_align(&self) -> usize { + self.repr().mem_align } } @@ -161,6 +187,7 @@ impl<'a> From> for Datatype<'a> { } } +#[derive(Debug, Clone)] pub struct StructMember<'a> { pkg: &'a PackageRepr, repr: &'a StructMemberRepr, diff --git a/lucet-idl/src/env/datatypes.rs b/lucet-idl/src/env/datatypes.rs index 6fd0028bd..dcc4d1209 100644 --- a/lucet-idl/src/env/datatypes.rs +++ b/lucet-idl/src/env/datatypes.rs @@ -1,21 +1,24 @@ #![allow(unused_imports)] // XXX remove me when more complete -use crate::env::memarea::MemArea; -use crate::env::types::{ - AliasDatatypeRepr, AtomType, DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, - EnumDatatypeRepr, EnumMember, ModuleIx, StructDatatypeRepr, StructMemberRepr, +use crate::env::atoms::AtomType; +use crate::env::cursor::Package; +use crate::env::repr::{ + AliasDatatypeRepr, DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, + EnumDatatypeRepr, EnumMember, ModuleDatatypesRepr, ModuleIx, StructDatatypeRepr, + StructMemberRepr, }; +use crate::env::MemArea; use crate::error::ValidationError; use crate::parser::{ EnumVariant as EnumVariantSyntax, StructMember as StructMemberSyntax, SyntaxTypeRef, }; use crate::types::Location; -use cranelift_entity::PrimaryMap; +use cranelift_entity::{PrimaryMap, SecondaryMap}; use std::collections::HashMap; #[derive(Debug, PartialEq, Eq, Clone)] struct DatatypeIR { - pub variant: VariantIR, - pub location: Location, + variant: VariantIR, + location: Location, } #[derive(Debug, PartialEq, Eq, Clone)] @@ -46,17 +49,19 @@ enum VariantIR { Alias(AliasIR), } -#[derive(Debug, Clone)] -pub struct DatatypeModuleBuilder { +#[derive(Clone)] +pub struct DatatypeModuleBuilder<'a> { + env: Package<'a>, module: ModuleIx, name_decls: HashMap, name_map: PrimaryMap, types: PrimaryMap, } -impl DatatypeModuleBuilder { - pub fn new(module: ModuleIx) -> Self { +impl<'a> DatatypeModuleBuilder<'a> { + pub fn new(env: Package<'a>, module: ModuleIx) -> Self { Self { + env, module, name_decls: HashMap::new(), name_map: PrimaryMap::new(), @@ -81,7 +86,7 @@ impl DatatypeModuleBuilder { Ok(dix) } - pub fn lookup_datatype_ident( + fn datatype_ident_from_syntax( &self, syntax: &SyntaxTypeRef, ) -> Result { @@ -125,23 +130,20 @@ impl DatatypeModuleBuilder { } // Get the DatatypeIdent for the member, which ensures that it refers only to // defined types: - let type_ = self.lookup_datatype_ident(&mem.type_)?; + let type_ = self.datatype_ident_from_syntax(&mem.type_)?; // build the struct with this as the member: members.push(StructMemberIR { type_, name: mem.name.clone(), }); } - let type_ix = self.types.push(DatatypeIR { - variant: VariantIR::Struct(StructIR { members }), - location: *location, - }); - - assert_eq!( - ix, type_ix, - "datatypes must be introduced in the same order as their names" + self.define_datatype( + ix, + DatatypeIR { + variant: VariantIR::Struct(StructIR { members }), + location: *location, + }, ); - Ok(()) } @@ -175,13 +177,12 @@ impl DatatypeModuleBuilder { name: var.name.clone(), }) } - let type_ix = self.types.push(DatatypeIR { - variant: VariantIR::Enum(EnumIR { members }), - location: *location, - }); - assert_eq!( - ix, type_ix, - "datatypes must be introduced in the same order as their names" + self.define_datatype( + ix, + DatatypeIR { + variant: VariantIR::Enum(EnumIR { members }), + location: *location, + }, ); Ok(()) } @@ -192,165 +193,204 @@ impl DatatypeModuleBuilder { dest: &SyntaxTypeRef, location: &Location, ) -> Result<(), ValidationError> { - let to = self.lookup_datatype_ident(dest)?; - let type_ix = self.types.push(DatatypeIR { - variant: VariantIR::Alias(AliasIR { to }), - location: *location, - }); + let to = self.datatype_ident_from_syntax(dest)?; + self.define_datatype( + ix, + DatatypeIR { + variant: VariantIR::Alias(AliasIR { to }), + location: *location, + }, + ); + Ok(()) + } + + fn define_datatype(&mut self, ix: DatatypeIx, ir: DatatypeIR) { + let type_ix = self.types.push(ir); assert_eq!( ix, type_ix, "datatypes must be introduced in the same order as their names" ); - Ok(()) } - /* - pub fn validate_datatypes( - &self, - names: &[Name], - ) -> Result<(HashMap, Vec), ValidationError> { - let mut finalized = HashMap::new(); + pub fn build(self) -> Result { + let mut finalized = SecondaryMap::new(); let mut ordered = Vec::new(); // Important to iterate in name order, so error messages are consistient. // HashMap iteration order is not stable. - for (ix, name) in names.iter().enumerate() { - let id = Ident(ix); - if let Some(decl) = self.data_types.get(&id) { - // First, make sure datatypes are finite - let mut visited = Vec::new(); - visited.resize(names.len(), false); - - self.dfs_walk(id, &mut visited, &mut ordered, &mut finalized) - .map_err(|_| ValidationError::Infinite { - name: name.name.clone(), - location: decl.location.clone(), - })?; - } + for (ix, name) in self.name_map.iter() { + let decl = self + .types + .get(ix) + .expect("all datatypes declared were defined"); + + // Depth first search through datatypes will return an error if they + // are infinite, and insert + let mut visited = SecondaryMap::new(); + visited.resize(self.name_map.len()); + + self.dfs_walk(ix, &mut visited, &mut ordered, &mut finalized) + .map_err(|_| ValidationError::Infinite { + name: name.clone(), + location: decl.location.clone(), + })?; + } + + let mut datatypes = PrimaryMap::new(); + for dt in finalized.values() { + datatypes.push(dt.clone().expect("all datatypes finalized")); } - Ok((finalized, ordered)) + + assert_eq!( + self.name_map.len(), + datatypes.len(), + "each datatype defined" + ); + assert_eq!( + self.name_map.len(), + ordered.len(), + "each datatype present in topological sort" + ); + + Ok(ModuleDatatypesRepr { + names: self.name_map, + datatypes, + topological_order: ordered, + }) } fn dfs_walk( &self, - id: Ident, - visited: &mut [bool], - ordered: &mut Vec, - finalized_types: &mut HashMap, + ix: DatatypeIx, + visited: &mut SecondaryMap, + ordered: &mut Vec, + finalized_types: &mut SecondaryMap>, ) -> Result<(), ()> { - if visited[id.0] { + // Ensure that dfs terminates: + if visited[ix] { Err(())? } - visited[id.0] = true; - let dt = self.data_types.get(&id).expect("data type IR is defined"); + visited[ix] = true; + + let dt = self.types.get(ix).expect("data type IR is defined"); match &dt.variant { VariantIR::Struct(ref s) => { // First, iterate down the member to ensure this is finite, and fill in type - // info for leaves first + // info for leaves first. + // IMPORTANT: assumes any type defined outside this module is an atom! for mem in s.members.iter() { - if let DataTypeRef::Defined(id) = mem.type_ { - self.dfs_walk(id, visited, ordered, finalized_types)?; - }; + if mem.type_.module == self.module { + self.dfs_walk(mem.type_.datatype, visited, ordered, finalized_types)?; + } } // If finalized type information has not yet been computed, we can now compute it: - if !finalized_types.contains_key(&id) { + if finalized_types + .get(ix) + .expect("ix exists in types") + .is_none() + { let mut offset = 0; let mut struct_align = 1; - let mut members: Vec = Vec::new(); + let mut members: Vec = Vec::new(); for mem in s.members.iter() { - let (repr_size, align) = - datatype_repr_size_align(&mem.type_, finalized_types) - .expect("datatype is defined by prior dfs_walk"); + let (mem_size, align) = + self.datatype_size_align(mem.type_, finalized_types); offset = align_to(offset, align); struct_align = ::std::cmp::max(struct_align, align); - members.push(StructMember { + members.push(StructMemberRepr { type_: mem.type_.clone(), name: mem.name.clone(), offset, }); - offset += repr_size; + offset += mem_size; } - let repr_size = align_to(offset, struct_align); + let mem_size = align_to(offset, struct_align); - finalized_types.insert( - id, - DataType { - variant: DataTypeVariant::Struct(StructDataType { members }), - repr_size, - align: struct_align, - }, - ); + finalized_types[ix] = Some(DatatypeRepr { + variant: DatatypeVariantRepr::Struct(StructDatatypeRepr { members }), + mem_size, + mem_align: struct_align, + }); } } VariantIR::Alias(ref a) => { - if let DataTypeRef::Defined(pointee_id) = a.to { - self.dfs_walk(pointee_id, visited, ordered, finalized_types)?; - }; - if !finalized_types.contains_key(&id) { - let (repr_size, align) = datatype_repr_size_align(&a.to, finalized_types) - .expect("datatype is defined by prior dfs_walk"); - finalized_types.insert( - id, - DataType { - variant: DataTypeVariant::Alias(AliasDataType { to: a.to.clone() }), - repr_size, - align, - }, - ); + // Iterate down the pointer to ensure this is finite, and fill in type + // info for pointee first. + // IMPORTANT: assumes any type defined outside this module is an atom! + if a.to.module == self.module { + self.dfs_walk(a.to.datatype, visited, ordered, finalized_types)?; + } + + // If finalized type information has not yet been computed, we can now compute it: + if finalized_types + .get(ix) + .expect("ix exists in types") + .is_none() + { + let (mem_size, mem_align) = self.datatype_size_align(a.to, finalized_types); + finalized_types[ix] = Some(DatatypeRepr { + variant: DatatypeVariantRepr::Alias(AliasDatatypeRepr { to: a.to.clone() }), + mem_size, + mem_align, + }); } } VariantIR::Enum(ref e) => { // No recursion to do on the dfs. - if !finalized_types.contains_key(&id) { + if finalized_types + .get(ix) + .expect("ix exists in types") + .is_none() + { // x86_64 ABI says enum is 32 bits wide - let repr_size = AtomType::U32.repr_size(); - let align = repr_size; - finalized_types.insert( - id, - DataType { - variant: DataTypeVariant::Enum(EnumDataType { - members: e.members.clone(), - }), - repr_size, - align, - }, - ); + let mem_size = AtomType::U32.mem_size(); + let mem_align = mem_size; + finalized_types[ix] = Some(DatatypeRepr { + variant: DatatypeVariantRepr::Enum(EnumDatatypeRepr { + members: e.members.clone(), + }), + mem_size, + mem_align, + }); } } } - if !ordered.contains(&id) { - ordered.push(id) + if !ordered.contains(&ix) { + ordered.push(ix) } - visited[id.0] = false; + + // dfs: allowed to visit here again + visited[ix] = false; Ok(()) } - */ -} - -/* -fn datatype_repr_size_align( - datatype_ref: &DataTypeRef, - finalized_types: &HashMap, -) -> Option<(usize, usize)> { - let (size, align) = match datatype_ref { - DataTypeRef::Atom(a) => { - let s = a.repr_size(); - (s, s) - } - DataTypeRef::Defined(ref member_ident) => { - let t = finalized_types.get(member_ident)?; - (t.repr_size, t.align) - } - }; - assert!(size > 0); - assert!(align > 0); - Some((size, align)) + fn datatype_size_align( + &self, + id: DatatypeIdent, + finalized_types: &SecondaryMap>, + ) -> (usize, usize) { + let (size, align) = if id.module == self.module { + let t = finalized_types + .get(id.datatype) + .cloned() + .expect("looking up identifier in this module") + .expect("looking up type defined in this module"); + (t.mem_size, t.mem_align) + } else { + let dt = self + .env + .datatype_by_id(id) + .expect("looking up identifier external to this module"); + (dt.mem_size(), dt.mem_align()) + }; + assert!(size > 0); + assert!(align > 0); + (size, align) + } } -*/ fn align_to(offs: usize, alignment: usize) -> usize { offs + alignment - 1 - ((offs + alignment - 1) % alignment) diff --git a/lucet-idl/src/env/memarea.rs b/lucet-idl/src/env/memarea.rs deleted file mode 100644 index 6b6b7b565..000000000 --- a/lucet-idl/src/env/memarea.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::env::types::{AbiType, AtomType}; - -pub trait MemArea { - fn repr_size(&self) -> usize; - fn align(&self) -> usize; -} - -impl MemArea for AtomType { - fn repr_size(&self) -> usize { - match self { - AtomType::Bool => 1, - AtomType::U8 | AtomType::I8 => 1, - AtomType::U16 | AtomType::I16 => 2, - AtomType::U32 | AtomType::I32 | AtomType::F32 => 4, - AtomType::U64 | AtomType::I64 | AtomType::F64 => 8, - } - } - fn align(&self) -> usize { - self.repr_size() - } -} - -impl MemArea for AbiType { - fn repr_size(&self) -> usize { - match self { - AbiType::I32 | AbiType::F32 => 4, - AbiType::I64 | AbiType::F64 => 8, - } - } - - fn align(&self) -> usize { - self.repr_size() - } -} diff --git a/lucet-idl/src/env/mod.rs b/lucet-idl/src/env/mod.rs index 65b14838f..fa5aefeec 100644 --- a/lucet-idl/src/env/mod.rs +++ b/lucet-idl/src/env/mod.rs @@ -1,5 +1,10 @@ +pub mod atoms; pub mod cursor; pub mod datatypes; -pub mod memarea; pub mod prelude; -pub mod types; +pub mod repr; + +pub trait MemArea { + fn mem_size(&self) -> usize; + fn mem_align(&self) -> usize; +} diff --git a/lucet-idl/src/env/prelude.rs b/lucet-idl/src/env/prelude.rs index 53afce022..1fe2815c4 100644 --- a/lucet-idl/src/env/prelude.rs +++ b/lucet-idl/src/env/prelude.rs @@ -1,8 +1,9 @@ -use crate::env::memarea::MemArea; -use crate::env::types::{ - AtomType, DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, ModuleDatatypesRepr, +use crate::env::atoms::AtomType; +use crate::env::repr::{ + DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, ModuleDatatypesRepr, ModuleFuncsRepr, ModuleIx, ModuleRepr, PackageRepr, }; +use crate::env::MemArea; use cranelift_entity::{EntityRef, PrimaryMap}; pub fn base_package() -> PackageRepr { @@ -20,38 +21,37 @@ pub fn base_package() -> PackageRepr { } fn atom_datatypes() -> ModuleDatatypesRepr { - fn create_atom( - names: &mut PrimaryMap, - datatypes: &mut PrimaryMap, - name: &str, - atom: AtomType, - ) { - let ix = names.push(name.to_owned()); - let repr_size = atom.repr_size(); - let align = atom.align(); - let dix = datatypes.push(DatatypeRepr { + fn create_atom(repr: &mut ModuleDatatypesRepr, name: &str, atom: AtomType) { + let ix = repr.names.push(name.to_owned()); + let mem_size = atom.mem_size(); + let mem_align = atom.mem_align(); + let dix = repr.datatypes.push(DatatypeRepr { variant: DatatypeVariantRepr::Atom(atom), - repr_size, - align, + mem_size, + mem_align, }); assert_eq!(ix, dix, "names and datatypes out of sync"); + repr.topological_order.push(ix); } - let mut names = PrimaryMap::new(); - let mut datatypes = PrimaryMap::new(); - create_atom(&mut names, &mut datatypes, "bool", AtomType::Bool); - create_atom(&mut names, &mut datatypes, "u8", AtomType::U8); - create_atom(&mut names, &mut datatypes, "u16", AtomType::U16); - create_atom(&mut names, &mut datatypes, "u32", AtomType::U32); - create_atom(&mut names, &mut datatypes, "u64", AtomType::U64); - create_atom(&mut names, &mut datatypes, "i8", AtomType::I8); - create_atom(&mut names, &mut datatypes, "i16", AtomType::I16); - create_atom(&mut names, &mut datatypes, "i32", AtomType::I32); - create_atom(&mut names, &mut datatypes, "i64", AtomType::I64); - create_atom(&mut names, &mut datatypes, "f32", AtomType::F32); - create_atom(&mut names, &mut datatypes, "f64", AtomType::F64); + let mut repr = ModuleDatatypesRepr { + names: PrimaryMap::new(), + datatypes: PrimaryMap::new(), + topological_order: Vec::new(), + }; + create_atom(&mut repr, "bool", AtomType::Bool); + create_atom(&mut repr, "u8", AtomType::U8); + create_atom(&mut repr, "u16", AtomType::U16); + create_atom(&mut repr, "u32", AtomType::U32); + create_atom(&mut repr, "u64", AtomType::U64); + create_atom(&mut repr, "i8", AtomType::I8); + create_atom(&mut repr, "i16", AtomType::I16); + create_atom(&mut repr, "i32", AtomType::I32); + create_atom(&mut repr, "i64", AtomType::I64); + create_atom(&mut repr, "f32", AtomType::F32); + create_atom(&mut repr, "f64", AtomType::F64); - ModuleDatatypesRepr { names, datatypes } + repr } impl AtomType { @@ -76,7 +76,8 @@ impl AtomType { #[cfg(test)] mod test { use super::base_package; - use crate::env::types::{AtomType, DatatypeIdent, DatatypeVariantRepr, PackageRepr}; + use crate::env::atoms::AtomType; + use crate::env::repr::{DatatypeIdent, DatatypeVariantRepr, PackageRepr}; #[test] fn atom_idents() { use AtomType::*; diff --git a/lucet-idl/src/env/types.rs b/lucet-idl/src/env/repr.rs similarity index 70% rename from lucet-idl/src/env/types.rs rename to lucet-idl/src/env/repr.rs index 23775b0cf..68551c70e 100644 --- a/lucet-idl/src/env/types.rs +++ b/lucet-idl/src/env/repr.rs @@ -1,3 +1,4 @@ +use crate::env::atoms::{AbiType, AtomType}; use cranelift_entity::{entity_impl, PrimaryMap}; #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -43,6 +44,7 @@ pub struct ModuleRepr { pub struct ModuleDatatypesRepr { pub names: PrimaryMap, pub datatypes: PrimaryMap, + pub topological_order: Vec, } #[derive(Debug, Clone)] @@ -54,8 +56,8 @@ pub struct ModuleFuncsRepr { #[derive(Debug, Clone)] pub struct DatatypeRepr { pub variant: DatatypeVariantRepr, - pub repr_size: usize, - pub align: usize, + pub mem_size: usize, + pub mem_align: usize, } #[derive(Debug, Clone)] @@ -66,67 +68,6 @@ pub enum DatatypeVariantRepr { Alias(AliasDatatypeRepr), } -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum AtomType { - Bool, - U8, - U16, - U32, - U64, - I8, - I16, - I32, - I64, - F32, - F64, -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum AbiType { - I32, - I64, - F32, - F64, -} - -impl AbiType { - pub fn from_atom(a: &AtomType) -> Self { - match a { - AtomType::Bool - | AtomType::U8 - | AtomType::I8 - | AtomType::U16 - | AtomType::I16 - | AtomType::U32 - | AtomType::I32 => AbiType::I32, - AtomType::I64 | AtomType::U64 => AbiType::I64, - AtomType::F32 => AbiType::F32, - AtomType::F64 => AbiType::F64, - } - } - - pub fn of_atom(a: AtomType) -> Option { - match a { - AtomType::I32 => Some(AbiType::I32), - AtomType::I64 => Some(AbiType::I64), - AtomType::F32 => Some(AbiType::F32), - AtomType::F64 => Some(AbiType::F64), - _ => None, - } - } -} - -impl From for AtomType { - fn from(abi: AbiType) -> AtomType { - match abi { - AbiType::I32 => AtomType::I32, - AbiType::I64 => AtomType::I64, - AbiType::F32 => AtomType::F32, - AbiType::F64 => AtomType::F64, - } - } -} - #[derive(Debug, PartialEq, Eq, Clone)] pub struct StructMemberRepr { pub type_: DatatypeIdent, diff --git a/lucet-idl/src/lexer.rs b/lucet-idl/src/lexer.rs index 691f741c8..4078cdf86 100644 --- a/lucet-idl/src/lexer.rs +++ b/lucet-idl/src/lexer.rs @@ -1,4 +1,4 @@ -use super::types::{AtomType, Location}; +use crate::types::{AtomType, Location}; use std::str::CharIndices; #[derive(Debug, PartialEq, Eq, Clone, Copy)] diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 898f25fbb..d6a413454 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -6,7 +6,6 @@ extern crate failure; mod c; mod config; mod data_layout; -mod datatypes; pub mod env; mod error; mod function; diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index c790a6ac7..edf0e731f 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -485,13 +485,13 @@ impl RustGenerator { pre.push(format!( "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", ptr = ptr.name, - align = input_mem.align(), + align = input_mem.mem_align(), )); pre.push(format!( "#[allow(non_snake_case)] let {name}___MEM: &[u8] = heap.get({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", name = input.name, ptr = ptr.name, - len = input_mem.repr_size(), + len = input_mem.mem_size(), )); pre.push(format!( "let {name}: &{typename} = unsafe {{ ({name}___MEM.as_ptr() as *const {typename}).as_ref().unwrap() }}; // convert pointer in linear memory to ref", @@ -509,14 +509,14 @@ impl RustGenerator { pre.push(format!( "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", ptr = ptr.name, - align = input_mem.align(), + align = input_mem.mem_align(), )); pre.push(format!( "#[allow(non_snake_case)] let {name}___MEM: &[u8] = heap.get({ptr}..({ptr}+({len}*{elem_len}))).ok_or_else(|| () /* FIXME: bounds check failed */)?;", name = input.name, ptr = ptr.name, len = len.name, - elem_len = input_mem.repr_size(), + elem_len = input_mem.mem_size(), )); pre.push(format!( @@ -548,13 +548,13 @@ impl RustGenerator { pre.push(format!( "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", ptr = ptr.name, - align = io_mem.align(), + align = io_mem.mem_align(), )); pre.push(format!( "#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", name = io.name, ptr = ptr.name, - len = io_mem.repr_size(), + len = io_mem.mem_size(), )); pre.push(format!( "let mut {name}: &mut {typename} = unsafe {{ ({name}___MEM.as_mut_ptr() as *mut {typename}).as_mut().unwrap() }}; // convert pointer in linear memory to ref", @@ -572,14 +572,14 @@ impl RustGenerator { pre.push(format!( "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", ptr = ptr.name, - align = io_mem.align(), + align = io_mem.mem_align(), )); pre.push(format!( "#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+({len}*{elem_len}))).ok_or_else(|| () /* FIXME: bounds check failed */)?;", name = io.name, ptr = ptr.name, len = len.name, - elem_len = io_mem.repr_size(), + elem_len = io_mem.mem_size(), )); pre.push(format!( @@ -604,13 +604,13 @@ impl RustGenerator { pre.push(format!( "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", ptr = ptr.name, - align = out_mem.align(), + align = out_mem.mem_align(), )); pre.push(format!( "#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", name = out.name, ptr = ptr.name, - len = out_mem.repr_size(), + len = out_mem.mem_size(), )); pre.push(format!( "let mut {ptr}: &mut {typename} = unsafe {{ ({name}___MEM.as_mut_ptr() as *mut {typename}).as_mut().unwrap() }}; // convert pointer in linear memory to ref", diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index 967994fdc..5ea7ba739 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -1,4 +1,5 @@ -pub use crate::datatypes::{AbiType, AtomType, MemArea}; +pub use crate::env::atoms::{AbiType, AtomType}; +pub use crate::env::MemArea; use std::fmt; @@ -71,10 +72,10 @@ pub struct Name { } impl MemArea for DataType { - fn repr_size(&self) -> usize { + fn mem_size(&self) -> usize { self.repr_size } - fn align(&self) -> usize { + fn mem_align(&self) -> usize { self.align } } From 0ff7b5eae12c272406837eb3e62d7c8942cad25a Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 30 Jul 2019 20:46:34 -0700 Subject: [PATCH 318/512] lucet-idl: port in func validator --- lucet-idl/src/env/cursor.rs | 47 +++- lucet-idl/src/env/datatypes.rs | 1 - lucet-idl/src/env/function.rs | 385 +++++++++++++++++++++++++++++++++ lucet-idl/src/env/mod.rs | 1 + lucet-idl/src/env/repr.rs | 6 +- 5 files changed, 432 insertions(+), 8 deletions(-) create mode 100644 lucet-idl/src/env/function.rs diff --git a/lucet-idl/src/env/cursor.rs b/lucet-idl/src/env/cursor.rs index 1b67c2e07..1418d0e05 100644 --- a/lucet-idl/src/env/cursor.rs +++ b/lucet-idl/src/env/cursor.rs @@ -1,10 +1,11 @@ -use crate::env::atoms::AtomType; +use crate::env::atoms::{AbiType, AtomType}; use crate::env::repr::{ AliasDatatypeRepr, DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, EnumDatatypeRepr, EnumMember, ModuleIx, ModuleRepr, PackageRepr, StructDatatypeRepr, StructMemberRepr, }; use crate::env::MemArea; +use crate::parser::SyntaxTypeRef; #[derive(Debug, Clone)] pub struct Package<'a> { @@ -20,7 +21,12 @@ impl<'a> Package<'a> { .and_then(|(ix, _)| self.module_by_ix(ix)) } - pub(crate) fn module_by_ix(&self, ix: ModuleIx) -> Option> { + pub fn modules(&self) -> impl Iterator> { + let pkg = self.repr; + self.repr.names.keys().map(move |ix| Module { pkg, ix }) + } + + pub fn module_by_ix(&self, ix: ModuleIx) -> Option> { if self.repr.modules.is_valid(ix) { Some(Module { pkg: &self.repr, @@ -31,7 +37,7 @@ impl<'a> Package<'a> { } } - pub(crate) fn datatype_by_id(&self, id: DatatypeIdent) -> Option> { + pub fn datatype_by_id(&self, id: DatatypeIdent) -> Option> { self.module_by_ix(id.module) .and_then(|m| m.datatype_by_ix(id.datatype)) } @@ -48,6 +54,10 @@ impl<'a> Module<'a> { self.pkg.modules.get(self.ix).expect("i exist") } + pub fn package(&self) -> Package<'a> { + Package { repr: self.pkg } + } + pub fn name(&self) -> &str { self.pkg.names.get(self.ix).expect("i exist") } @@ -61,7 +71,7 @@ impl<'a> Module<'a> { .and_then(|(ix, _)| self.datatype_by_ix(ix)) } - pub(crate) fn datatype_by_ix(&self, ix: DatatypeIx) -> Option> { + pub fn datatype_by_ix(&self, ix: DatatypeIx) -> Option> { if self.repr().datatypes.datatypes.is_valid(ix) { Some(Datatype { pkg: self.pkg, @@ -84,6 +94,16 @@ impl<'a> Module<'a> { id: DatatypeIdent::new(mix, ix), }) } + + // XXX move this to a trait that we dont export, eventaully... + pub fn datatype_by_syntax(&self, tref: &SyntaxTypeRef) -> Option> { + match tref { + SyntaxTypeRef::Name { name, .. } => self.datatype(name), + SyntaxTypeRef::Atom { atom, .. } => { + self.package().datatype_by_id(atom.datatype_ident()) + } + } + } } #[derive(Debug, Clone)] @@ -104,6 +124,10 @@ impl<'a> Datatype<'a> { .expect("i exist") } + pub fn id(&self) -> DatatypeIdent { + self.id + } + pub fn name(&self) -> &'a str { self.pkg .modules @@ -135,6 +159,10 @@ impl<'a> Datatype<'a> { }), } } + + pub fn abi_type(&self) -> Option { + self.variant().abi_type() + } } impl<'a> MemArea for Datatype<'a> { @@ -154,6 +182,17 @@ pub enum DatatypeVariant<'a> { Alias(AliasDatatype<'a>), } +impl<'a> DatatypeVariant<'a> { + pub fn abi_type(&self) -> Option { + match self { + DatatypeVariant::Atom(a) => Some(AbiType::from_atom(a)), + DatatypeVariant::Struct(_) => None, + DatatypeVariant::Enum(_) => Some(AbiType::I32), + DatatypeVariant::Alias(a) => a.to().abi_type(), + } + } +} + #[derive(Debug, Clone)] pub struct StructDatatype<'a> { pkg: &'a PackageRepr, diff --git a/lucet-idl/src/env/datatypes.rs b/lucet-idl/src/env/datatypes.rs index dcc4d1209..817f6bc86 100644 --- a/lucet-idl/src/env/datatypes.rs +++ b/lucet-idl/src/env/datatypes.rs @@ -1,4 +1,3 @@ -#![allow(unused_imports)] // XXX remove me when more complete use crate::env::atoms::AtomType; use crate::env::cursor::Package; use crate::env::repr::{ diff --git a/lucet-idl/src/env/function.rs b/lucet-idl/src/env/function.rs new file mode 100644 index 000000000..7c0bd4a95 --- /dev/null +++ b/lucet-idl/src/env/function.rs @@ -0,0 +1,385 @@ +use crate::env::atoms::{AbiType, AtomType}; +use crate::env::cursor::{Datatype, Module}; +use crate::env::repr::{ + ArgIx, BindingDirection, BindingFromRepr, BindingIx, BindingRepr, FuncRepr, ParamIx, ParamRepr, + RetIx, +}; +use crate::error::ValidationError; +use crate::parser::{BindingDirSyntax, BindingRefSyntax, BindingSyntax, FuncArgSyntax}; +use crate::types::Location; +use cranelift_entity::{EntityRef, PrimaryMap}; +use std::collections::HashMap; +use std::ops::Deref; + +struct FuncValidator<'a> { + // arg name to declaration location and argument position + param_names: HashMap, + // Arg positions index into this vector: + args: PrimaryMap, + // Ret positions index into this vector: + rets: PrimaryMap, + // binding name to + binding_names: HashMap, + // param position to binding syntax + bindings: PrimaryMap, + param_binding_sites: HashMap, + location: Location, + module: &'a Module<'a>, +} + +impl<'a> FuncValidator<'a> { + fn new(location: Location, module: &'a Module<'a>) -> Self { + Self { + param_names: HashMap::new(), + args: PrimaryMap::new(), + rets: PrimaryMap::new(), + binding_names: HashMap::new(), + bindings: PrimaryMap::new(), + param_binding_sites: HashMap::new(), + location, + module, + } + } + fn introduce_param_name( + &mut self, + arg_syntax: &FuncArgSyntax, + position: ParamIx, + ) -> Result { + if let Some((previous_location, _)) = self.param_names.get(&arg_syntax.name) { + Err(ValidationError::NameAlreadyExists { + name: arg_syntax.name.clone(), + at_location: arg_syntax.location, + previous_location: previous_location.clone(), + })?; + } else { + self.param_names.insert( + arg_syntax.name.clone(), + (arg_syntax.location.clone(), position), + ); + } + Ok(ParamRepr { + name: arg_syntax.name.clone(), + type_: arg_syntax.type_.clone(), + }) + } + + fn introduce_args(&mut self, args: &[FuncArgSyntax]) -> Result<(), ValidationError> { + for (ix, arg) in args.iter().enumerate() { + let arg_ix = ArgIx::new(ix); + let a = self.introduce_param_name(arg, ParamIx::Arg(arg_ix))?; + let pushed_arg_ix = self.args.push(a); + assert_eq!(arg_ix, pushed_arg_ix); + } + Ok(()) + } + fn introduce_rets(&mut self, rets: &[FuncArgSyntax]) -> Result<(), ValidationError> { + if rets.len() > 1 { + Err(ValidationError::Syntax { + expected: "at most one return value", + location: self.location.clone(), + })? + } + for (ix, r) in rets.iter().enumerate() { + let ret_ix = RetIx::new(ix); + let r = self.introduce_param_name(r, ParamIx::Ret(ret_ix))?; + let pushed_ret_ix = self.rets.push(r); + assert_eq!(ret_ix, pushed_ret_ix); + } + Ok(()) + } + + fn introduce_bindings(&mut self, bindings: &[BindingSyntax]) -> Result<(), ValidationError> { + for (ix, binding) in bindings.iter().enumerate() { + let ix = BindingIx::new(ix); + let b = self.introduce_binding(binding, ix)?; + let pushed_ix = self.bindings.push(b); + assert_eq!(ix, pushed_ix); + } + for (ix, arg) in self.args.iter() { + let position = ParamIx::Arg(ix); + if !self.param_binding_sites.contains_key(&position) { + self.bindings + .push(self.implicit_value_binding(&arg, position)?); + } + } + for (ix, ret) in self.rets.iter() { + let position = ParamIx::Ret(ix); + if !self.param_binding_sites.contains_key(&position) { + self.bindings + .push(self.implicit_value_binding(&ret, position)?); + } + } + Ok(()) + } + + fn introduce_binding( + &mut self, + binding: &BindingSyntax, + ix: BindingIx, + ) -> Result { + // 1. make sure binding name is unique + if let Some((previous_location, _)) = self.binding_names.get(&binding.name) { + Err(ValidationError::NameAlreadyExists { + name: binding.name.clone(), + at_location: binding.location, + previous_location: previous_location.clone(), + })?; + } else { + self.binding_names + .insert(binding.name.clone(), (binding.location.clone(), ix)); + } + + // 2. resolve type_ SyntaxRef to a Datatype + let type_ = self + .module + .datatype_by_syntax(&binding.type_) + .ok_or_else(|| ValidationError::NameNotFound { + name: format!("{:?}", binding.type_), // XXX FIXME + use_location: binding.location, + })?; + + // 3. typecheck the binding: + let from = self.validate_binding_ref(&binding, &type_)?; + + // 4. direction from syntax: + let direction = match binding.direction { + BindingDirSyntax::In => BindingDirection::In, + BindingDirSyntax::InOut => BindingDirection::InOut, + BindingDirSyntax::Out => BindingDirection::Out, + }; + + Ok(BindingRepr { + name: binding.name.clone(), + type_: type_.id(), + direction, + from, + }) + } + + fn implicit_value_binding( + &self, + arg: &ParamRepr, + position: ParamIx, + ) -> Result { + // 1. make sure binding name is unique. We're re-using the arg name + // for the binding. If another binding overlapped with the arg name, + // it is now at fault. (complicated, huh... :/) + if let Some((previous_location, _)) = self.binding_names.get(&arg.name) { + let (arg_location, _) = self.param_names.get(&arg.name).expect("arg introduced"); + Err(ValidationError::BindingNameAlreadyBound { + name: arg.name.clone(), + at_location: previous_location.clone(), + bound_location: arg_location.clone(), + })?; + } + + // 2. resolve type + let type_ = AtomType::from(arg.type_).datatype_ident(); + + // 3. no need to validate ref- we can construct it ourselves + let from = BindingFromRepr::Value(position); + + // 4. direction depends on whether param is an arg or ret + let direction = match position { + ParamIx::Arg(_) => BindingDirection::In, + ParamIx::Ret(_) => BindingDirection::Out, + }; + + Ok(BindingRepr { + name: arg.name.clone(), + type_, + direction, + from, + }) + } + + fn get_arg(&self, arg_name: &String) -> Option<(ParamIx, ParamRepr)> { + let (_, position) = self.param_names.get(arg_name)?; + match position { + ParamIx::Arg(ix) => Some(( + *position, + self.args.get(*ix).expect("in-bounds arg index").clone(), + )), + ParamIx::Ret(ix) => Some(( + *position, + self.rets.get(*ix).expect("in-bounds ret index").clone(), + )), + } + } + + fn validate_binding_arg_mapping( + &mut self, + name: &String, + location: &Location, + ) -> Result<(ParamIx, ParamRepr), ValidationError> { + // Check that it refers to a valid arg: + let (position, arg) = self.get_arg(name).ok_or_else(|| ValidationError::Syntax { + expected: "name of an argument or return value", + location: location.clone(), + })?; + // Check that the arg has only been used once: + if let Some(use_location) = self.param_binding_sites.get(&position) { + Err(ValidationError::BindingNameAlreadyBound { + name: name.clone(), + at_location: location.clone(), + bound_location: use_location.clone(), + })?; + } else { + self.param_binding_sites + .insert(position.clone(), location.clone()); + } + Ok((position, arg)) + } + + fn validate_binding_ref( + &mut self, + binding: &BindingSyntax, + target_type: &Datatype<'a>, + ) -> Result { + match &binding.from { + // A pointer to a name is accepted: + BindingRefSyntax::Ptr(bref) => match bref.deref() { + BindingRefSyntax::Name(ref name) => { + let (position, funcarg) = + self.validate_binding_arg_mapping(name, &binding.location)?; + if funcarg.type_ != AbiType::I32 { + Err(ValidationError::BindingTypeError { + expected: "pointer bindings to be represented as an i32", + location: binding.location.clone(), + })?; + } + match position { + ParamIx::Arg(_) => { + // all good! Arg pointers are valid for in, inout, or out binding. + } + ParamIx::Ret(_) => { + Err(ValidationError::BindingTypeError { + expected: "return value cannot be bound to pointer", + location: binding.location.clone(), + })?; + } + } + Ok(BindingFromRepr::Ptr(position)) + } + _ => Err(ValidationError::Syntax { + expected: "pointer binding must be of form *arg", + location: binding.location.clone(), + }), + }, + // A slice of two names is accepted: + BindingRefSyntax::Slice(ref ptr_ref, ref len_ref) => { + match (ptr_ref.deref(), len_ref.deref()) { + ( + BindingRefSyntax::Name(ref ptr_name), + BindingRefSyntax::Name(ref len_name), + ) => { + let (ptr_position, ptr_arg) = + self.validate_binding_arg_mapping(ptr_name, &binding.location)?; + if ptr_arg.type_ != AbiType::I32 { + Err(ValidationError::BindingTypeError { + expected: "slice pointer must be i32", + location: binding.location.clone(), + })?; + } + let (len_position, len_arg) = + self.validate_binding_arg_mapping(len_name, &binding.location)?; + if len_arg.type_ != AbiType::I32 { + Err(ValidationError::BindingTypeError { + expected: "slice len must be i32", + location: binding.location.clone(), + })?; + } + match (&ptr_position, &len_position) { + (ParamIx::Arg(_), ParamIx::Arg(_)) => {} + _ => { + Err(ValidationError::BindingTypeError { + expected: "slice bindings must be inputs", + location: binding.location.clone(), + })?; + } + } + Ok(BindingFromRepr::Slice(ptr_position, len_position)) + } + ( + BindingRefSyntax::Name(ref _ptr_name), + BindingRefSyntax::Ptr(ref len_ptr_ref), + ) => match len_ptr_ref.deref() { + BindingRefSyntax::Name(_len_ptr_name) => { + unimplemented!("slice syntax [ptr, *len] for an output slice"); + } + _ => Err(ValidationError::Syntax { + expected: "slice binding must be of form [ptr, len] or [ptr, *len]", + location: binding.location.clone(), + }), + }, + _ => Err(ValidationError::Syntax { + expected: "slice binding must be of form [ptr, len] or [ptr, *len]", + location: binding.location.clone(), + }), + } + } + // A bare name is accepted: + BindingRefSyntax::Name(ref name) => { + let (position, funcarg) = + self.validate_binding_arg_mapping(name, &binding.location)?; + + // make sure funcarg.type_ is a valid representation of target type + match target_type.abi_type() { + Some(target_repr) => { + if target_repr != funcarg.type_ { + Err(ValidationError::BindingTypeError { + expected: "binding type representation to match argument type", + location: binding.location.clone(), + })?; + } + } + None => { + Err(ValidationError::BindingTypeError { + expected: "binding type to be representable as value (try passing by reference instead)", + location: binding.location.clone(), + })?; + } + } + // Arg values must be in-only bindings, Ret values must be out-only bindings + match position { + ParamIx::Arg(_) => { + if binding.direction != BindingDirSyntax::In { + Err(ValidationError::BindingTypeError { + expected: "argument value must be input-only binding", + location: binding.location.clone(), + })?; + } + } + ParamIx::Ret(_) => { + if binding.direction != BindingDirSyntax::Out { + Err(ValidationError::BindingTypeError { + expected: "return value must be output-only binding", + location: binding.location.clone(), + })?; + } + } + } + Ok(BindingFromRepr::Value(position)) + } + } + } +} + +pub fn func_repr_from_syntax( + args: &[FuncArgSyntax], + rets: &[FuncArgSyntax], + bindings: &[BindingSyntax], + location: Location, + module: &Module, +) -> Result { + let mut validator = FuncValidator::new(location, module); + validator.introduce_args(args)?; + validator.introduce_rets(rets)?; + validator.introduce_bindings(bindings)?; + + Ok(FuncRepr { + args: validator.args, + rets: validator.rets, + bindings: validator.bindings, + }) +} diff --git a/lucet-idl/src/env/mod.rs b/lucet-idl/src/env/mod.rs index fa5aefeec..90116b7b6 100644 --- a/lucet-idl/src/env/mod.rs +++ b/lucet-idl/src/env/mod.rs @@ -1,6 +1,7 @@ pub mod atoms; pub mod cursor; pub mod datatypes; +pub mod function; pub mod prelude; pub mod repr; diff --git a/lucet-idl/src/env/repr.rs b/lucet-idl/src/env/repr.rs index 68551c70e..899c7bc44 100644 --- a/lucet-idl/src/env/repr.rs +++ b/lucet-idl/src/env/repr.rs @@ -102,15 +102,15 @@ pub struct FuncRepr { pub bindings: PrimaryMap, } -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct ArgIx(u32); entity_impl!(ArgIx); -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct RetIx(u32); entity_impl!(RetIx); -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum ParamIx { Arg(ArgIx), Ret(RetIx), From 113a619099315ec2c84ee1e13c77c540437a6d30 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 31 Jul 2019 13:17:11 -0700 Subject: [PATCH 319/512] lucet-idl: factor module names into their own validator put all validators behind a single module name --- lucet-idl/src/env/cursor.rs | 4 + lucet-idl/src/env/mod.rs | 3 +- lucet-idl/src/env/repr.rs | 15 +++ lucet-idl/src/env/{ => validate}/datatypes.rs | 94 ++++++--------- lucet-idl/src/env/{ => validate}/function.rs | 82 +++++++++---- lucet-idl/src/env/validate/mod.rs | 6 + lucet-idl/src/env/validate/module.rs | 97 +++++++++++++++ lucet-idl/src/env/validate/names.rs | 111 ++++++++++++++++++ lucet-idl/src/error.rs | 14 +++ 9 files changed, 340 insertions(+), 86 deletions(-) rename lucet-idl/src/env/{ => validate}/datatypes.rs (83%) rename lucet-idl/src/env/{ => validate}/function.rs (89%) create mode 100644 lucet-idl/src/env/validate/mod.rs create mode 100644 lucet-idl/src/env/validate/module.rs create mode 100644 lucet-idl/src/env/validate/names.rs diff --git a/lucet-idl/src/env/cursor.rs b/lucet-idl/src/env/cursor.rs index 1418d0e05..682f6e089 100644 --- a/lucet-idl/src/env/cursor.rs +++ b/lucet-idl/src/env/cursor.rs @@ -13,6 +13,10 @@ pub struct Package<'a> { } impl<'a> Package<'a> { + pub fn new(repr: &'a PackageRepr) -> Package<'a> { + Package { repr } + } + pub fn module(&self, name: &str) -> Option> { self.repr .names diff --git a/lucet-idl/src/env/mod.rs b/lucet-idl/src/env/mod.rs index 90116b7b6..1a97745e2 100644 --- a/lucet-idl/src/env/mod.rs +++ b/lucet-idl/src/env/mod.rs @@ -1,9 +1,8 @@ pub mod atoms; pub mod cursor; -pub mod datatypes; -pub mod function; pub mod prelude; pub mod repr; +pub mod validate; pub trait MemArea { fn mem_size(&self) -> usize; diff --git a/lucet-idl/src/env/repr.rs b/lucet-idl/src/env/repr.rs index 899c7bc44..9b48ae83c 100644 --- a/lucet-idl/src/env/repr.rs +++ b/lucet-idl/src/env/repr.rs @@ -40,6 +40,21 @@ pub struct ModuleRepr { pub funcs: ModuleFuncsRepr, } +impl ModuleRepr { + pub fn new(datatypes: ModuleDatatypesRepr, funcs: ModuleFuncsRepr) -> Self { + Self { datatypes, funcs } + } + pub fn from_datatypes(datatypes: ModuleDatatypesRepr) -> Self { + Self::new( + datatypes, + ModuleFuncsRepr { + names: PrimaryMap::new(), + funcs: PrimaryMap::new(), + }, + ) + } +} + #[derive(Debug, Clone)] pub struct ModuleDatatypesRepr { pub names: PrimaryMap, diff --git a/lucet-idl/src/env/datatypes.rs b/lucet-idl/src/env/validate/datatypes.rs similarity index 83% rename from lucet-idl/src/env/datatypes.rs rename to lucet-idl/src/env/validate/datatypes.rs index 817f6bc86..8ba8a4ec2 100644 --- a/lucet-idl/src/env/datatypes.rs +++ b/lucet-idl/src/env/validate/datatypes.rs @@ -1,9 +1,9 @@ +use super::names::ModNamesBuilder; use crate::env::atoms::AtomType; use crate::env::cursor::Package; use crate::env::repr::{ AliasDatatypeRepr, DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, - EnumDatatypeRepr, EnumMember, ModuleDatatypesRepr, ModuleIx, StructDatatypeRepr, - StructMemberRepr, + EnumDatatypeRepr, EnumMember, ModuleDatatypesRepr, StructDatatypeRepr, StructMemberRepr, }; use crate::env::MemArea; use crate::error::ValidationError; @@ -51,67 +51,32 @@ enum VariantIR { #[derive(Clone)] pub struct DatatypeModuleBuilder<'a> { env: Package<'a>, - module: ModuleIx, - name_decls: HashMap, - name_map: PrimaryMap, + names: &'a ModNamesBuilder, types: PrimaryMap, } impl<'a> DatatypeModuleBuilder<'a> { - pub fn new(env: Package<'a>, module: ModuleIx) -> Self { + pub fn new(env: Package<'a>, names: &'a ModNamesBuilder) -> Self { Self { env, - module, - name_decls: HashMap::new(), - name_map: PrimaryMap::new(), + names, types: PrimaryMap::new(), } } - pub fn introduce_name( - &mut self, - name: &str, - location: &Location, - ) -> Result { - if let Some((prev_loc, _prev_ix)) = self.name_decls.get(name) { - Err(ValidationError::NameAlreadyExists { - name: name.to_owned(), - at_location: *location, - previous_location: *prev_loc, - })?; - } - let dix = self.name_map.push(name.to_owned()); - self.name_decls.insert(name.to_owned(), (*location, dix)); - Ok(dix) - } - - fn datatype_ident_from_syntax( - &self, - syntax: &SyntaxTypeRef, - ) -> Result { - match syntax { - SyntaxTypeRef::Name { name, location } => self - .name_decls - .get(name) - .map(|(_loc, ix)| DatatypeIdent::new(self.module, *ix)) - .ok_or_else(|| ValidationError::NameNotFound { - name: name.clone(), - use_location: *location, - }), - SyntaxTypeRef::Atom { atom, .. } => Ok(atom.datatype_ident()), - } - } - pub fn introduce_struct( &mut self, - ix: DatatypeIx, + name: &str, members_syntax: &[StructMemberSyntax], location: &Location, ) -> Result<(), ValidationError> { - let name = self.name_map.get(ix).expect("name is introduced"); + let ix = self + .names + .datatype_from_name(name) + .expect("name is introduced"); if members_syntax.is_empty() { Err(ValidationError::Empty { - name: name.clone(), + name: name.to_owned(), location: *location, })? } @@ -129,7 +94,7 @@ impl<'a> DatatypeModuleBuilder<'a> { } // Get the DatatypeIdent for the member, which ensures that it refers only to // defined types: - let type_ = self.datatype_ident_from_syntax(&mem.type_)?; + let type_ = self.names.datatype_ident_from_syntax(&mem.type_)?; // build the struct with this as the member: members.push(StructMemberIR { type_, @@ -148,14 +113,17 @@ impl<'a> DatatypeModuleBuilder<'a> { pub fn introduce_enum( &mut self, - ix: DatatypeIx, + name: &str, variants: &[EnumVariantSyntax], location: &Location, ) -> Result<(), ValidationError> { - let name = self.name_map.get(ix).expect("name is introduced"); + let ix = self + .names + .datatype_from_name(name) + .expect("name is introduced"); if variants.is_empty() { Err(ValidationError::Empty { - name: name.clone(), + name: name.to_owned(), location: *location, })? } @@ -188,11 +156,15 @@ impl<'a> DatatypeModuleBuilder<'a> { pub fn introduce_alias( &mut self, - ix: DatatypeIx, + name: &str, dest: &SyntaxTypeRef, location: &Location, ) -> Result<(), ValidationError> { - let to = self.datatype_ident_from_syntax(dest)?; + let ix = self + .names + .datatype_from_name(name) + .expect("name is introduced"); + let to = self.names.datatype_ident_from_syntax(dest)?; self.define_datatype( ix, DatatypeIR { @@ -216,7 +188,7 @@ impl<'a> DatatypeModuleBuilder<'a> { let mut ordered = Vec::new(); // Important to iterate in name order, so error messages are consistient. // HashMap iteration order is not stable. - for (ix, name) in self.name_map.iter() { + for (ix, name) in self.names.types.iter() { let decl = self .types .get(ix) @@ -225,7 +197,7 @@ impl<'a> DatatypeModuleBuilder<'a> { // Depth first search through datatypes will return an error if they // are infinite, and insert let mut visited = SecondaryMap::new(); - visited.resize(self.name_map.len()); + visited.resize(self.names.types.len()); self.dfs_walk(ix, &mut visited, &mut ordered, &mut finalized) .map_err(|_| ValidationError::Infinite { @@ -240,18 +212,18 @@ impl<'a> DatatypeModuleBuilder<'a> { } assert_eq!( - self.name_map.len(), + self.names.types.len(), datatypes.len(), "each datatype defined" ); assert_eq!( - self.name_map.len(), + datatypes.len(), ordered.len(), - "each datatype present in topological sort" + "is each datatype present in topological sort? lengths dont match" ); Ok(ModuleDatatypesRepr { - names: self.name_map, + names: self.names.types.clone(), datatypes, topological_order: ordered, }) @@ -278,7 +250,7 @@ impl<'a> DatatypeModuleBuilder<'a> { // info for leaves first. // IMPORTANT: assumes any type defined outside this module is an atom! for mem in s.members.iter() { - if mem.type_.module == self.module { + if mem.type_.module == self.names.module { self.dfs_walk(mem.type_.datatype, visited, ordered, finalized_types)?; } } @@ -319,7 +291,7 @@ impl<'a> DatatypeModuleBuilder<'a> { // Iterate down the pointer to ensure this is finite, and fill in type // info for pointee first. // IMPORTANT: assumes any type defined outside this module is an atom! - if a.to.module == self.module { + if a.to.module == self.names.module { self.dfs_walk(a.to.datatype, visited, ordered, finalized_types)?; } @@ -371,7 +343,7 @@ impl<'a> DatatypeModuleBuilder<'a> { id: DatatypeIdent, finalized_types: &SecondaryMap>, ) -> (usize, usize) { - let (size, align) = if id.module == self.module { + let (size, align) = if id.module == self.names.module { let t = finalized_types .get(id.datatype) .cloned() diff --git a/lucet-idl/src/env/function.rs b/lucet-idl/src/env/validate/function.rs similarity index 89% rename from lucet-idl/src/env/function.rs rename to lucet-idl/src/env/validate/function.rs index 7c0bd4a95..ab732a945 100644 --- a/lucet-idl/src/env/function.rs +++ b/lucet-idl/src/env/validate/function.rs @@ -1,8 +1,9 @@ +use super::names::ModNamesBuilder; use crate::env::atoms::{AbiType, AtomType}; use crate::env::cursor::{Datatype, Module}; use crate::env::repr::{ - ArgIx, BindingDirection, BindingFromRepr, BindingIx, BindingRepr, FuncRepr, ParamIx, ParamRepr, - RetIx, + ArgIx, BindingDirection, BindingFromRepr, BindingIx, BindingRepr, FuncIx, FuncRepr, + ModuleFuncsRepr, ParamIx, ParamRepr, RetIx, }; use crate::error::ValidationError; use crate::parser::{BindingDirSyntax, BindingRefSyntax, BindingSyntax, FuncArgSyntax}; @@ -11,6 +12,60 @@ use cranelift_entity::{EntityRef, PrimaryMap}; use std::collections::HashMap; use std::ops::Deref; +pub struct FunctionModuleBuilder<'a> { + env: Module<'a>, + names: &'a ModNamesBuilder, + funcs: PrimaryMap, +} + +impl<'a> FunctionModuleBuilder<'a> { + pub fn new(env: Module<'a>, names: &'a ModNamesBuilder) -> Self { + Self { + env, + names, + funcs: PrimaryMap::new(), + } + } + + pub fn introduce_func( + &mut self, + name: &str, + args: &[FuncArgSyntax], + rets: &[FuncArgSyntax], + bindings: &[BindingSyntax], + location: &Location, + ) -> Result<(), ValidationError> { + let mut validator = FuncValidator::new(location, &self.env); + validator.introduce_args(args)?; + validator.introduce_rets(rets)?; + validator.introduce_bindings(bindings)?; + + let defined_ix = self.funcs.push(FuncRepr { + args: validator.args, + rets: validator.rets, + bindings: validator.bindings, + }); + let declared_ix = self.names.func_from_name(name).expect("declared func"); + assert_eq!( + defined_ix, declared_ix, + "funcs defined in different order than declared" + ); + Ok(()) + } + + pub fn build(self) -> ModuleFuncsRepr { + assert_eq!( + self.names.funcs.len(), + self.funcs.len(), + "each func declared has been defined" + ); + ModuleFuncsRepr { + names: self.names.funcs.clone(), + funcs: self.funcs, + } + } +} + struct FuncValidator<'a> { // arg name to declaration location and argument position param_names: HashMap, @@ -23,12 +78,12 @@ struct FuncValidator<'a> { // param position to binding syntax bindings: PrimaryMap, param_binding_sites: HashMap, - location: Location, + location: &'a Location, module: &'a Module<'a>, } impl<'a> FuncValidator<'a> { - fn new(location: Location, module: &'a Module<'a>) -> Self { + fn new(location: &'a Location, module: &'a Module<'a>) -> Self { Self { param_names: HashMap::new(), args: PrimaryMap::new(), @@ -364,22 +419,3 @@ impl<'a> FuncValidator<'a> { } } } - -pub fn func_repr_from_syntax( - args: &[FuncArgSyntax], - rets: &[FuncArgSyntax], - bindings: &[BindingSyntax], - location: Location, - module: &Module, -) -> Result { - let mut validator = FuncValidator::new(location, module); - validator.introduce_args(args)?; - validator.introduce_rets(rets)?; - validator.introduce_bindings(bindings)?; - - Ok(FuncRepr { - args: validator.args, - rets: validator.rets, - bindings: validator.bindings, - }) -} diff --git a/lucet-idl/src/env/validate/mod.rs b/lucet-idl/src/env/validate/mod.rs new file mode 100644 index 000000000..5e307a1c1 --- /dev/null +++ b/lucet-idl/src/env/validate/mod.rs @@ -0,0 +1,6 @@ +mod datatypes; +mod function; +mod module; +mod names; + +pub use module::module_from_declarations; diff --git a/lucet-idl/src/env/validate/module.rs b/lucet-idl/src/env/validate/module.rs new file mode 100644 index 000000000..03da9dd3b --- /dev/null +++ b/lucet-idl/src/env/validate/module.rs @@ -0,0 +1,97 @@ +#![allow(unused)] +use super::datatypes::DatatypeModuleBuilder; +use super::function::FunctionModuleBuilder; +use super::names::ModNamesBuilder; +use crate::env::cursor::Package; +use crate::env::repr::{DatatypeIx, FuncIx, ModuleIx, ModuleRepr, PackageRepr}; +use crate::error::ValidationError; +use crate::parser::SyntaxDecl; +use crate::types::Location; +use std::collections::HashMap; + +pub fn module_from_declarations( + env: &PackageRepr, + ix: ModuleIx, + decls: &[SyntaxDecl], +) -> Result { + // First, we need to declare names of all the declarations + let mut names = ModNamesBuilder::new(ix); + for decl in decls.iter() { + match decl { + SyntaxDecl::Struct { name, location, .. } + | SyntaxDecl::Enum { name, location, .. } + | SyntaxDecl::Alias { name, location, .. } => { + names.introduce_datatype(name, location)?; + } + SyntaxDecl::Function { name, location, .. } => { + names.introduce_function(name, location)?; + } + SyntaxDecl::Module { .. } => unreachable!(), + } + } + + // Datatypes are defined in terms of the parent environment: + let data_env = Package::new(env); + let mut datatypes_builder = DatatypeModuleBuilder::new(data_env, &names); + + // Then, we can define each datatype + for decl in decls.iter() { + match decl { + SyntaxDecl::Struct { + name, + location, + members, + } => { + datatypes_builder.introduce_struct(name, members, location)?; + } + SyntaxDecl::Enum { + name, + location, + variants, + } => { + datatypes_builder.introduce_enum(name, variants, location)?; + } + SyntaxDecl::Alias { + name, + location, + what, + } => { + datatypes_builder.introduce_alias(name, what, location)?; + } + _ => {} + } + } + + // Finalize the datatypes - ensure finite, calculate layout information: + let datatypes_module = datatypes_builder.build()?; + + // Cons these datatypes onto the packagerepr, then create a Module cursor + let mut funcs_env_repr = env.clone(); + funcs_env_repr + .modules + .push(ModuleRepr::from_datatypes(datatypes_module.clone())); + let funcs_env = Package::new(&funcs_env_repr).module_by_ix(ix).unwrap(); + + // Now we can define each function: + let mut funcs_builder = FunctionModuleBuilder::new(funcs_env, &names); + + for decl in decls { + if let SyntaxDecl::Function { + name, + args, + rets, + bindings, + location, + } = decl + { + funcs_builder.introduce_func(name, args, rets, bindings, location)?; + } + } + + let funcs_module = funcs_builder.build(); + + Ok(ModuleRepr { + datatypes: datatypes_module, + funcs: funcs_module, + }) +} diff --git a/lucet-idl/src/env/validate/names.rs b/lucet-idl/src/env/validate/names.rs new file mode 100644 index 000000000..7c476de1f --- /dev/null +++ b/lucet-idl/src/env/validate/names.rs @@ -0,0 +1,111 @@ +use crate::env::repr::{DatatypeIdent, DatatypeIx, FuncIx, ModuleIx}; +use crate::error::ValidationError; +use crate::parser::SyntaxTypeRef; +use crate::types::Location; +use cranelift_entity::PrimaryMap; +use std::collections::HashMap; + +pub struct ModNamesBuilder { + pub module: ModuleIx, + pub funcs: PrimaryMap, + pub types: PrimaryMap, + names: HashMap, +} + +impl ModNamesBuilder { + pub fn new(module: ModuleIx) -> Self { + Self { + module, + names: HashMap::new(), + funcs: PrimaryMap::new(), + types: PrimaryMap::new(), + } + } + + pub fn introduce_datatype( + &mut self, + name: &str, + location: &Location, + ) -> Result<(), ValidationError> { + if let Some((_, prev_loc)) = self.names.get(name) { + Err(ValidationError::NameAlreadyExists { + name: name.to_owned(), + at_location: *location, + previous_location: *prev_loc, + })?; + } + let ix = self.types.push(name.to_owned()); + self.names + .insert(name.to_owned(), (ModContentIx::Datatype(ix), *location)); + Ok(()) + } + + pub fn introduce_function( + &mut self, + name: &str, + location: &Location, + ) -> Result<(), ValidationError> { + if let Some((_, prev_loc)) = self.names.get(name) { + Err(ValidationError::NameAlreadyExists { + name: name.to_owned(), + at_location: *location, + previous_location: *prev_loc, + })?; + } + let ix = self.funcs.push(name.to_owned()); + self.names + .insert(name.to_owned(), (ModContentIx::Func(ix), *location)); + Ok(()) + } + + pub fn datatype_ident_from_syntax( + &self, + syntax: &SyntaxTypeRef, + ) -> Result { + match syntax { + SyntaxTypeRef::Atom { atom, .. } => Ok(atom.datatype_ident()), + SyntaxTypeRef::Name { name, location } => match self.names.get(name) { + Some((ModContentIx::Datatype(ix), _loc)) => { + Ok(DatatypeIdent::new(self.module, *ix)) + } + Some((_, bound_loc)) => Err(ValidationError::NameSortError { + name: name.to_owned(), + use_location: *location, + bound_location: *bound_loc, + }), + None => Err(ValidationError::NameNotFound { + name: name.to_owned(), + use_location: *location, + }), + }, + } + } + + pub fn datatype_from_name(&self, name: &str) -> Option { + self.names.get(name).and_then(|(ix, _)| ix.datatype()) + } + + pub fn func_from_name(&self, name: &str) -> Option { + self.names.get(name).and_then(|(ix, _)| ix.func()) + } +} + +enum ModContentIx { + Datatype(DatatypeIx), + Func(FuncIx), +} + +impl ModContentIx { + fn datatype(&self) -> Option { + match self { + ModContentIx::Datatype(d) => Some(*d), + _ => None, + } + } + fn func(&self) -> Option { + match self { + ModContentIx::Func(f) => Some(*f), + _ => None, + } + } +} diff --git a/lucet-idl/src/error.rs b/lucet-idl/src/error.rs index 528e802c4..b31f4ff07 100644 --- a/lucet-idl/src/error.rs +++ b/lucet-idl/src/error.rs @@ -60,6 +60,11 @@ pub enum ValidationError { expected: &'static str, location: Location, }, + NameSortError { + name: String, + use_location: Location, + bound_location: Location, + }, BindingNameAlreadyBound { name: String, at_location: Location, @@ -99,6 +104,15 @@ impl fmt::Display for ValidationError { "Invalid syntax: expected {} at line {}", expected, location.line ), + ValidationError::NameSortError { + name, + use_location, + bound_location, + } => write!( + f, + "Name {} at line {} - bound to another sort at line {}", + name, use_location.line, bound_location.line + ), ValidationError::BindingNameAlreadyBound { name, at_location, From b456836d9027cc86c4f78488a955857b8933f6e1 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 31 Jul 2019 15:26:00 -0700 Subject: [PATCH 320/512] lucet-idl: port module datatype tests into new code --- lucet-idl/src/env/cursor.rs | 44 ++++- lucet-idl/src/env/repr.rs | 4 +- lucet-idl/src/env/validate/datatypes.rs | 7 +- lucet-idl/src/env/validate/module.rs | 236 ++++++++++++++++++++++++ 4 files changed, 282 insertions(+), 9 deletions(-) diff --git a/lucet-idl/src/env/cursor.rs b/lucet-idl/src/env/cursor.rs index 682f6e089..462f647b2 100644 --- a/lucet-idl/src/env/cursor.rs +++ b/lucet-idl/src/env/cursor.rs @@ -1,8 +1,7 @@ use crate::env::atoms::{AbiType, AtomType}; use crate::env::repr::{ AliasDatatypeRepr, DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, - EnumDatatypeRepr, EnumMember, ModuleIx, ModuleRepr, PackageRepr, StructDatatypeRepr, - StructMemberRepr, + EnumDatatypeRepr, ModuleIx, ModuleRepr, PackageRepr, StructDatatypeRepr, StructMemberRepr, }; use crate::env::MemArea; use crate::parser::SyntaxTypeRef; @@ -212,6 +211,15 @@ impl<'a> StructDatatype<'a> { } .name() } + pub fn member(&self, name: &str) -> Option> { + let pkg = self.pkg; + self.repr + .members + .iter() + .find(|m| m.name == name) + .map(move |repr| StructMember { pkg, repr }) + } + pub fn members(&self) -> impl Iterator> { let pkg = self.pkg; self.repr @@ -266,10 +274,21 @@ impl<'a> EnumDatatype<'a> { } .name() } - pub fn members(&self) -> &'a [EnumMember] { - &self.repr.members + pub fn variants(&self) -> impl Iterator> { + let repr = self.clone(); + (0..self.repr.members.len()) + .into_iter() + .map(move |ix| EnumMember { + repr: repr.clone(), + index: ix, + }) + } + + pub fn variant(&self, name: &str) -> Option> { + self.variants().find(|v| v.name() == name) } } + impl<'a> From> for Datatype<'a> { fn from(e: EnumDatatype<'a>) -> Datatype<'a> { Datatype { @@ -279,6 +298,23 @@ impl<'a> From> for Datatype<'a> { } } +pub struct EnumMember<'a> { + repr: EnumDatatype<'a>, + index: usize, +} + +impl<'a> EnumMember<'a> { + pub fn parent(&self) -> EnumDatatype<'a> { + self.repr.clone() + } + pub fn name(&self) -> &str { + &self.repr.repr.members[self.index].name + } + pub fn value(&self) -> usize { + self.index + } +} + #[derive(Debug, Clone)] pub struct AliasDatatype<'a> { pkg: &'a PackageRepr, diff --git a/lucet-idl/src/env/repr.rs b/lucet-idl/src/env/repr.rs index 9b48ae83c..110861ade 100644 --- a/lucet-idl/src/env/repr.rs +++ b/lucet-idl/src/env/repr.rs @@ -96,13 +96,13 @@ pub struct StructDatatypeRepr { } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct EnumMember { +pub struct EnumMemberRepr { pub name: String, } #[derive(Debug, PartialEq, Eq, Clone)] pub struct EnumDatatypeRepr { - pub members: Vec, + pub members: Vec, } #[derive(Debug, PartialEq, Eq, Clone)] diff --git a/lucet-idl/src/env/validate/datatypes.rs b/lucet-idl/src/env/validate/datatypes.rs index 8ba8a4ec2..c4c5d8d95 100644 --- a/lucet-idl/src/env/validate/datatypes.rs +++ b/lucet-idl/src/env/validate/datatypes.rs @@ -3,7 +3,7 @@ use crate::env::atoms::AtomType; use crate::env::cursor::Package; use crate::env::repr::{ AliasDatatypeRepr, DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, - EnumDatatypeRepr, EnumMember, ModuleDatatypesRepr, StructDatatypeRepr, StructMemberRepr, + EnumDatatypeRepr, EnumMemberRepr, ModuleDatatypesRepr, StructDatatypeRepr, StructMemberRepr, }; use crate::env::MemArea; use crate::error::ValidationError; @@ -33,7 +33,7 @@ struct StructIR { #[derive(Debug, PartialEq, Eq, Clone)] struct EnumIR { - members: Vec, + members: Vec, } #[derive(Debug, PartialEq, Eq, Clone)] @@ -140,7 +140,7 @@ impl<'a> DatatypeModuleBuilder<'a> { })? } // build the struct with this as the member: - members.push(EnumMember { + members.push(EnumMemberRepr { name: var.name.clone(), }) } @@ -185,6 +185,7 @@ impl<'a> DatatypeModuleBuilder<'a> { pub fn build(self) -> Result { let mut finalized = SecondaryMap::new(); + finalized.resize(self.names.types.len()); let mut ordered = Vec::new(); // Important to iterate in name order, so error messages are consistient. // HashMap iteration order is not stable. diff --git a/lucet-idl/src/env/validate/module.rs b/lucet-idl/src/env/validate/module.rs index 03da9dd3b..66285e06e 100644 --- a/lucet-idl/src/env/validate/module.rs +++ b/lucet-idl/src/env/validate/module.rs @@ -95,3 +95,239 @@ pub fn module_from_declarations( funcs: funcs_module, }) } + +#[cfg(test)] +mod tests { + use super::*; + use crate::env::cursor::{DatatypeVariant, Module}; + use crate::env::prelude::base_package; + use crate::env::MemArea; + use crate::parser::Parser; + fn mod_syntax(syntax: &str) -> Result { + let mut parser = Parser::new(syntax); + let decls = parser.match_decls().expect("parses"); + + let mut pkg = base_package(); + let mod_ix = pkg.names.push("mod".to_owned()); + let module_repr = module_from_declarations(&pkg, mod_ix, &decls)?; + pkg.modules.push(module_repr); + Ok(pkg) + } + + #[test] + fn structs_basic() { + assert!(mod_syntax("struct foo { a: i32}").is_ok()); + assert!(mod_syntax("struct foo { a: i32, b: f32 }").is_ok()); + } + + #[test] + fn struct_two_atoms() { + let pkg_r = mod_syntax("struct foo { a: i32, b: f32 }").expect("valid"); + let module = Package::new(&pkg_r).module("mod").unwrap(); + let foo = module.datatype("foo").expect("foo datatype defined"); + assert_eq!(foo.mem_size(), 8); + assert_eq!(foo.mem_align(), 4); + match foo.variant() { + DatatypeVariant::Struct(s) => { + assert_eq!(s.members().collect::>().len(), 2); + let a = s.member("a").expect("get member a"); + assert_eq!(a.name(), "a"); + assert_eq!(a.type_().name(), "i32"); + assert_eq!(a.offset(), 0); + + let b = s.member("b").expect("get member b"); + assert_eq!(b.name(), "b"); + assert_eq!(b.type_().name(), "f32"); + assert_eq!(b.offset(), 4); + } + _ => panic!("foo is a struct!"), + } + } + + #[test] + fn struct_prev_definition() { + // Refer to a struct defined previously: + assert!(mod_syntax("struct foo { a: i32, b: f64 } struct bar { a: foo }").is_ok()); + } + + #[test] + fn struct_next_definition() { + // Refer to a struct defined afterwards: + assert!(mod_syntax("struct foo { a: i32, b: bar} struct bar { a: i32 }").is_ok()); + } + + #[test] + fn struct_self_referential() { + // Refer to itself + let e = mod_syntax("struct list { next: list, thing: i32 }"); + assert!(e.is_err()); + assert_eq!( + e.err().unwrap(), + ValidationError::Infinite { + name: "list".to_owned(), + location: Location { line: 1, column: 0 }, + } + ); + } + + #[test] + fn struct_empty() { + // No members + assert_eq!( + mod_syntax("struct foo {}").err().unwrap(), + ValidationError::Empty { + name: "foo".to_owned(), + location: Location { line: 1, column: 0 }, + } + ); + } + + #[test] + fn struct_duplicate_member() { + // Duplicate member in struct + assert_eq!( + mod_syntax("struct foo { \na: i32, \na: f64}") + .err() + .unwrap(), + ValidationError::NameAlreadyExists { + name: "a".to_owned(), + at_location: Location { line: 3, column: 0 }, + previous_location: Location { line: 2, column: 0 }, + } + ); + } + + #[test] + fn struct_duplicate_definition() { + // Duplicate definition of struct + assert_eq!( + mod_syntax("struct foo { a: i32 }\nstruct foo { a: i32 } ") + .err() + .unwrap(), + ValidationError::NameAlreadyExists { + name: "foo".to_owned(), + at_location: Location { line: 2, column: 0 }, + previous_location: Location { line: 1, column: 0 }, + } + ); + } + + #[test] + fn struct_undeclared_member() { + // Refer to type that is not declared + assert_eq!( + mod_syntax("struct foo { \nb: bar }").err().unwrap(), + ValidationError::NameNotFound { + name: "bar".to_owned(), + use_location: Location { line: 2, column: 3 }, + } + ); + } + + #[test] + fn enums() { + assert!(mod_syntax("enum foo { a }").is_ok()); + assert!(mod_syntax("enum foo { a, b }").is_ok()); + + { + let pkg_repr = mod_syntax("enum foo { a, b }").expect("valid syntax"); + let m = Package::new(&pkg_repr).module("mod").expect("get module"); + let foo = m.datatype("foo").expect("get foo"); + match foo.variant() { + DatatypeVariant::Enum(e) => { + assert_eq!(e.variants().collect::>().len(), 2); + let a = e.variant("a").expect("variant a exists"); + assert_eq!(a.name(), "a"); + assert_eq!(a.value(), 0); + let b = e.variant("b").expect("variant b exists"); + assert_eq!(b.name(), "b"); + assert_eq!(b.value(), 1); + } + _ => panic!("foo is an enum!"), + } + } + + // No members + assert_eq!( + mod_syntax("enum foo {}").err().unwrap(), + ValidationError::Empty { + name: "foo".to_owned(), + location: Location { line: 1, column: 0 }, + } + ); + + // Duplicate member in enum + assert_eq!( + mod_syntax("enum foo { \na,\na }").err().unwrap(), + ValidationError::NameAlreadyExists { + name: "a".to_owned(), + at_location: Location { line: 3, column: 0 }, + previous_location: Location { line: 2, column: 0 }, + } + ); + + // Duplicate definition of enum + assert_eq!( + mod_syntax("enum foo { a }\nenum foo { a } ").err().unwrap(), + ValidationError::NameAlreadyExists { + name: "foo".to_owned(), + at_location: Location { line: 2, column: 0 }, + previous_location: Location { line: 1, column: 0 }, + } + ); + } + + #[test] + fn aliases() { + assert!(mod_syntax("type foo = i32;").is_ok()); + assert!(mod_syntax("type foo = f64;").is_ok()); + assert!(mod_syntax("type foo = u8;").is_ok()); + assert!(mod_syntax("type link = u32;\nstruct list { next: link, thing: i32 }").is_ok()); + + let pkg_repr = mod_syntax("type foo = bar;\nenum bar { a }").expect("valid"); + let m = Package::new(&pkg_repr).module("mod").expect("get module"); + let foo = m.datatype("foo").expect("get foo"); + + match foo.variant() { + DatatypeVariant::Alias(a) => { + assert_eq!(a.name(), "foo"); + assert_eq!(a.to().name(), "bar"); + } + _ => panic!("foo is an alias"), + } + } + + #[test] + fn infinite() { + assert_eq!( + mod_syntax("type foo = bar;\ntype bar = foo;") + .err() + .unwrap(), + ValidationError::Infinite { + name: "foo".to_owned(), + location: Location { line: 1, column: 0 }, + } + ); + + assert_eq!( + mod_syntax("type foo = bar;\nstruct bar { a: foo }") + .err() + .unwrap(), + ValidationError::Infinite { + name: "foo".to_owned(), + location: Location { line: 1, column: 0 }, + } + ); + + assert_eq!( + mod_syntax("type foo = bar;\nstruct bar { a: baz }\nstruct baz { c: i32, e: foo }") + .err() + .unwrap(), + ValidationError::Infinite { + name: "foo".to_owned(), + location: Location { line: 1, column: 0 }, + } + ); + } + +} From 9b59f9a36bdd9e837252f44e23a8a08752b9abd2 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 31 Jul 2019 18:13:19 -0700 Subject: [PATCH 321/512] lucet-idl: build out cursor, module validation for funcs --- lucet-idl/src/env/cursor.rs | 223 +++++++++++++++++++++++- lucet-idl/src/env/prelude.rs | 24 +-- lucet-idl/src/env/repr.rs | 11 +- lucet-idl/src/env/validate/datatypes.rs | 4 +- lucet-idl/src/env/validate/function.rs | 2 +- lucet-idl/src/env/validate/module.rs | 67 ++++++- lucet-idl/src/env/validate/names.rs | 4 +- 7 files changed, 311 insertions(+), 24 deletions(-) diff --git a/lucet-idl/src/env/cursor.rs b/lucet-idl/src/env/cursor.rs index 462f647b2..b061f7dcd 100644 --- a/lucet-idl/src/env/cursor.rs +++ b/lucet-idl/src/env/cursor.rs @@ -1,7 +1,9 @@ use crate::env::atoms::{AbiType, AtomType}; +pub use crate::env::repr::BindingDirection; use crate::env::repr::{ - AliasDatatypeRepr, DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, - EnumDatatypeRepr, ModuleIx, ModuleRepr, PackageRepr, StructDatatypeRepr, StructMemberRepr, + AliasDatatypeRepr, BindingFromRepr, BindingIx, BindingRepr, DatatypeIdent, DatatypeIx, + DatatypeRepr, DatatypeVariantRepr, EnumDatatypeRepr, FuncIdent, FuncIx, FuncRepr, ModuleIx, + ModuleRepr, PackageRepr, ParamIx, ParamRepr, StructDatatypeRepr, StructMemberRepr, }; use crate::env::MemArea; use crate::parser::SyntaxTypeRef; @@ -102,11 +104,38 @@ impl<'a> Module<'a> { pub fn datatype_by_syntax(&self, tref: &SyntaxTypeRef) -> Option> { match tref { SyntaxTypeRef::Name { name, .. } => self.datatype(name), - SyntaxTypeRef::Atom { atom, .. } => { - self.package().datatype_by_id(atom.datatype_ident()) - } + SyntaxTypeRef::Atom { atom, .. } => self.package().datatype_by_id(atom.datatype_id()), } } + + pub fn function(&self, name: &str) -> Option> { + self.repr() + .funcs + .names + .iter() + .find(|(_, n)| *n == name) + .and_then(|(ix, _)| self.function_by_ix(ix)) + } + + pub fn function_by_ix(&self, ix: FuncIx) -> Option> { + if self.repr().funcs.funcs.is_valid(ix) { + Some(Function { + pkg: self.pkg, + id: FuncIdent::new(self.ix, ix), + }) + } else { + None + } + } + + pub fn functions(&self) -> impl Iterator> { + let pkg = self.pkg; + let mix = self.ix; + self.repr().funcs.funcs.keys().map(move |ix| Function { + pkg, + id: FuncIdent::new(mix, ix), + }) + } } #[derive(Debug, Clone)] @@ -346,3 +375,187 @@ impl<'a> From> for Datatype<'a> { } } } + +#[derive(Debug, Clone)] +pub struct Function<'a> { + pkg: &'a PackageRepr, + id: FuncIdent, +} + +impl<'a> Function<'a> { + fn repr(&self) -> &'a FuncRepr { + &self.pkg.modules[self.id.module].funcs.funcs[self.id.func] + } + + pub fn name(&self) -> &str { + &self.pkg.modules[self.id.module].funcs.names[self.id.func] + } + + pub fn arg(&self, name: &str) -> Option> { + let func = self.clone(); + self.repr() + .args + .iter() + .find(|(_, param)| param.name == name) + .map(move |(ix, _)| FuncParam { + func, + ix: ParamIx::Arg(ix), + }) + } + + pub fn args(&self) -> impl Iterator> { + let func = self.clone(); + self.repr().args.iter().map(move |(ix, _)| FuncParam { + func: func.clone(), + ix: ParamIx::Arg(ix), + }) + } + + pub fn ret(&self, name: &str) -> Option> { + let func = self.clone(); + self.repr() + .rets + .iter() + .find(|(_, param)| param.name == name) + .map(move |(ix, _)| FuncParam { + func, + ix: ParamIx::Ret(ix), + }) + } + + pub fn rets(&self) -> impl Iterator> { + let func = self.clone(); + self.repr().rets.iter().map(move |(ix, _)| FuncParam { + func: func.clone(), + ix: ParamIx::Ret(ix), + }) + } + + pub fn param(&self, name: &str) -> Option> { + self.arg(name).or_else(|| self.ret(name)) + } + + pub fn params(&self) -> impl Iterator> { + self.args().chain(self.rets()) + } + + pub fn binding(&self, name: &str) -> Option> { + let func = self.clone(); + self.repr() + .bindings + .iter() + .find(|(_, bind)| bind.name == name) + .map(move |(ix, _)| FuncBinding { func, ix }) + } + + pub fn bindings(&self) -> impl Iterator> { + let func = self.clone(); + self.repr().bindings.iter().map(move |(ix, _)| FuncBinding { + func: func.clone(), + ix, + }) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ParamType { + Arg, + Ret, +} + +#[derive(Debug, Clone)] +pub struct FuncParam<'a> { + func: Function<'a>, + ix: ParamIx, +} + +impl<'a> FuncParam<'a> { + fn repr(&self) -> &'a ParamRepr { + match self.ix { + ParamIx::Arg(ix) => &self.func.repr().args[ix], + ParamIx::Ret(ix) => &self.func.repr().rets[ix], + } + } + pub fn name(&self) -> &str { + &self.repr().name + } + pub fn abi_type(&self) -> AbiType { + self.repr().type_ + } + pub fn type_(&self) -> Datatype<'a> { + Package::new(self.func.pkg) + .datatype_by_id(AtomType::from(self.repr().type_).datatype_id()) + .expect("valid type") + } + pub fn param_type(&self) -> ParamType { + match self.ix { + ParamIx::Arg { .. } => ParamType::Arg, + ParamIx::Ret { .. } => ParamType::Ret, + } + } + pub fn binding(&self) -> FuncBinding<'a> { + let func = self.func.clone(); + self.func + .repr() + .bindings + .iter() + .find(|(_ix, b)| match b.from { + BindingFromRepr::Ptr(ix) | BindingFromRepr::Value(ix) => ix == self.ix, + BindingFromRepr::Slice(ptr_ix, len_ix) => ptr_ix == self.ix || len_ix == self.ix, + }) + .map(|(ix, _)| FuncBinding { func, ix }) + .expect("must be a binding for param") + } +} + +#[derive(Debug, Clone)] +pub struct FuncBinding<'a> { + func: Function<'a>, + ix: BindingIx, +} + +impl<'a> FuncBinding<'a> { + fn repr(&self) -> &'a BindingRepr { + &self.func.repr().bindings[self.ix] + } + pub fn name(&self) -> &str { + &self.repr().name + } + pub fn type_(&self) -> Datatype<'a> { + Package::new(self.func.pkg) + .datatype_by_id(self.repr().type_) + .expect("valid type") + } + pub fn direction(&self) -> BindingDirection { + self.repr().direction + } + pub fn param(&self) -> BindingParam<'a> { + match self.repr().from { + BindingFromRepr::Ptr(ix) => BindingParam::Ptr(FuncParam { + func: self.func.clone(), + ix, + }), + BindingFromRepr::Slice(ptr_ix, len_ix) => BindingParam::Slice( + FuncParam { + func: self.func.clone(), + ix: ptr_ix, + }, + FuncParam { + func: self.func.clone(), + ix: len_ix, + }, + ), + BindingFromRepr::Value(ix) => BindingParam::Value(FuncParam { + func: self.func.clone(), + ix, + }), + } + } +} + +#[derive(Debug, Clone)] +pub enum BindingParam<'a> { + Ptr(FuncParam<'a>), + Slice(FuncParam<'a>, FuncParam<'a>), + Value(FuncParam<'a>), +} diff --git a/lucet-idl/src/env/prelude.rs b/lucet-idl/src/env/prelude.rs index 1fe2815c4..d196dcc12 100644 --- a/lucet-idl/src/env/prelude.rs +++ b/lucet-idl/src/env/prelude.rs @@ -55,7 +55,7 @@ fn atom_datatypes() -> ModuleDatatypesRepr { } impl AtomType { - pub fn datatype_ident(&self) -> DatatypeIdent { + pub fn datatype_id(&self) -> DatatypeIdent { use AtomType::*; match self { Bool => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(0)), @@ -94,16 +94,16 @@ mod test { _ => panic!("expected atom datatype, got {:?}", dt), } } - assert_eq!(Bool, lookup_atom(&prelude, Bool.datatype_ident())); - assert_eq!(U8, lookup_atom(&prelude, U8.datatype_ident())); - assert_eq!(U16, lookup_atom(&prelude, U16.datatype_ident())); - assert_eq!(U32, lookup_atom(&prelude, U32.datatype_ident())); - assert_eq!(U64, lookup_atom(&prelude, U64.datatype_ident())); - assert_eq!(I8, lookup_atom(&prelude, I8.datatype_ident())); - assert_eq!(I16, lookup_atom(&prelude, I16.datatype_ident())); - assert_eq!(I32, lookup_atom(&prelude, I32.datatype_ident())); - assert_eq!(I64, lookup_atom(&prelude, I64.datatype_ident())); - assert_eq!(F32, lookup_atom(&prelude, F32.datatype_ident())); - assert_eq!(F64, lookup_atom(&prelude, F64.datatype_ident())); + assert_eq!(Bool, lookup_atom(&prelude, Bool.datatype_id())); + assert_eq!(U8, lookup_atom(&prelude, U8.datatype_id())); + assert_eq!(U16, lookup_atom(&prelude, U16.datatype_id())); + assert_eq!(U32, lookup_atom(&prelude, U32.datatype_id())); + assert_eq!(U64, lookup_atom(&prelude, U64.datatype_id())); + assert_eq!(I8, lookup_atom(&prelude, I8.datatype_id())); + assert_eq!(I16, lookup_atom(&prelude, I16.datatype_id())); + assert_eq!(I32, lookup_atom(&prelude, I32.datatype_id())); + assert_eq!(I64, lookup_atom(&prelude, I64.datatype_id())); + assert_eq!(F32, lookup_atom(&prelude, F32.datatype_id())); + assert_eq!(F64, lookup_atom(&prelude, F64.datatype_id())); } } diff --git a/lucet-idl/src/env/repr.rs b/lucet-idl/src/env/repr.rs index 110861ade..7264b2d11 100644 --- a/lucet-idl/src/env/repr.rs +++ b/lucet-idl/src/env/repr.rs @@ -32,7 +32,16 @@ pub struct FuncIx(u32); entity_impl!(FuncIx); #[derive(Debug, Clone, PartialEq, Eq)] -pub struct FuncIdent(ModuleIx, FuncIx); +pub struct FuncIdent { + pub module: ModuleIx, + pub func: FuncIx, +} + +impl FuncIdent { + pub fn new(module: ModuleIx, func: FuncIx) -> Self { + FuncIdent { module, func } + } +} #[derive(Debug, Clone)] pub struct ModuleRepr { diff --git a/lucet-idl/src/env/validate/datatypes.rs b/lucet-idl/src/env/validate/datatypes.rs index c4c5d8d95..fc86878c9 100644 --- a/lucet-idl/src/env/validate/datatypes.rs +++ b/lucet-idl/src/env/validate/datatypes.rs @@ -94,7 +94,7 @@ impl<'a> DatatypeModuleBuilder<'a> { } // Get the DatatypeIdent for the member, which ensures that it refers only to // defined types: - let type_ = self.names.datatype_ident_from_syntax(&mem.type_)?; + let type_ = self.names.datatype_id_from_syntax(&mem.type_)?; // build the struct with this as the member: members.push(StructMemberIR { type_, @@ -164,7 +164,7 @@ impl<'a> DatatypeModuleBuilder<'a> { .names .datatype_from_name(name) .expect("name is introduced"); - let to = self.names.datatype_ident_from_syntax(dest)?; + let to = self.names.datatype_id_from_syntax(dest)?; self.define_datatype( ix, DatatypeIR { diff --git a/lucet-idl/src/env/validate/function.rs b/lucet-idl/src/env/validate/function.rs index ab732a945..2804419b6 100644 --- a/lucet-idl/src/env/validate/function.rs +++ b/lucet-idl/src/env/validate/function.rs @@ -229,7 +229,7 @@ impl<'a> FuncValidator<'a> { } // 2. resolve type - let type_ = AtomType::from(arg.type_).datatype_ident(); + let type_ = AtomType::from(arg.type_).datatype_id(); // 3. no need to validate ref- we can construct it ourselves let from = BindingFromRepr::Value(position); diff --git a/lucet-idl/src/env/validate/module.rs b/lucet-idl/src/env/validate/module.rs index 66285e06e..855f044ab 100644 --- a/lucet-idl/src/env/validate/module.rs +++ b/lucet-idl/src/env/validate/module.rs @@ -99,7 +99,7 @@ pub fn module_from_declarations( #[cfg(test)] mod tests { use super::*; - use crate::env::cursor::{DatatypeVariant, Module}; + use crate::env::cursor::{BindingDirection, BindingParam, DatatypeVariant, Module, ParamType}; use crate::env::prelude::base_package; use crate::env::MemArea; use crate::parser::Parser; @@ -330,4 +330,69 @@ mod tests { ); } + #[test] + fn func_trivial() { + let pkg_repr = mod_syntax("fn foo();").expect("valid module"); + let m = Package::new(&pkg_repr).module("mod").expect("get module"); + let foo = m.function("foo").expect("get foo"); + assert_eq!(foo.name(), "foo"); + assert_eq!(foo.params().collect::>().len(), 0); + assert_eq!(foo.bindings().collect::>().len(), 0); + } + + #[test] + fn func_one_arg() { + let pkg_repr = mod_syntax("fn foo(a: i64);").expect("valid module"); + let m = Package::new(&pkg_repr).module("mod").expect("get module"); + let foo = m.function("foo").expect("get foo"); + + assert_eq!(foo.args().collect::>().len(), 1); + let a = foo.arg("a").expect("arg a exists"); + assert_eq!(a.name(), "a"); + assert_eq!(a.type_().name(), "i64"); + assert_eq!(a.binding().name(), "a"); + + assert_eq!(foo.rets().collect::>().len(), 0); + assert_eq!(foo.bindings().collect::>().len(), 1); + + let a_bind = foo.binding("a").expect("binding a exists"); + assert_eq!(a_bind.name(), "a"); + assert_eq!(a_bind.type_().name(), "i64"); + assert_eq!(a_bind.direction(), BindingDirection::In); + match a_bind.param() { + BindingParam::Value(v) => { + assert_eq!(v.name(), "a"); + assert_eq!(v.param_type(), ParamType::Arg); + } + _ => panic!("a binding is a value"), + } + } + + #[test] + fn func_one_ret() { + let pkg_repr = mod_syntax("fn foo() -> r: i64;").expect("valid module"); + let m = Package::new(&pkg_repr).module("mod").expect("get module"); + let foo = m.function("foo").expect("get foo"); + + assert_eq!(foo.rets().collect::>().len(), 1); + let r = foo.ret("r").expect("ret r exists"); + assert_eq!(r.name(), "r"); + assert_eq!(r.type_().name(), "i64"); + assert_eq!(r.binding().name(), "r"); + + assert_eq!(foo.args().collect::>().len(), 0); + assert_eq!(foo.bindings().collect::>().len(), 1); + + let r_bind = foo.binding("r").expect("binding r exists"); + assert_eq!(r_bind.name(), "r"); + assert_eq!(r_bind.type_().name(), "i64"); + assert_eq!(r_bind.direction(), BindingDirection::Out); + match r_bind.param() { + BindingParam::Value(v) => { + assert_eq!(v.name(), "r"); + assert_eq!(v.param_type(), ParamType::Ret); + } + _ => panic!("r binding is a value"), + } + } } diff --git a/lucet-idl/src/env/validate/names.rs b/lucet-idl/src/env/validate/names.rs index 7c476de1f..fab293e45 100644 --- a/lucet-idl/src/env/validate/names.rs +++ b/lucet-idl/src/env/validate/names.rs @@ -58,12 +58,12 @@ impl ModNamesBuilder { Ok(()) } - pub fn datatype_ident_from_syntax( + pub fn datatype_id_from_syntax( &self, syntax: &SyntaxTypeRef, ) -> Result { match syntax { - SyntaxTypeRef::Atom { atom, .. } => Ok(atom.datatype_ident()), + SyntaxTypeRef::Atom { atom, .. } => Ok(atom.datatype_id()), SyntaxTypeRef::Name { name, location } => match self.names.get(name) { Some((ModContentIx::Datatype(ix), _loc)) => { Ok(DatatypeIdent::new(self.module, *ix)) From e898f5db97c3ea452168c7c3c7d89ca1f70d3455 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 1 Aug 2019 10:50:08 -0700 Subject: [PATCH 322/512] lucet-idl: finish up module tests in env --- lucet-idl/src/env/cursor.rs | 21 +++ lucet-idl/src/env/validate/module.rs | 271 +++++++++++++++++++++++++-- 2 files changed, 279 insertions(+), 13 deletions(-) diff --git a/lucet-idl/src/env/cursor.rs b/lucet-idl/src/env/cursor.rs index b061f7dcd..f255b7ddb 100644 --- a/lucet-idl/src/env/cursor.rs +++ b/lucet-idl/src/env/cursor.rs @@ -559,3 +559,24 @@ pub enum BindingParam<'a> { Slice(FuncParam<'a>, FuncParam<'a>), Value(FuncParam<'a>), } + +impl<'a> BindingParam<'a> { + pub fn ptr(self) -> Option> { + match self { + BindingParam::Ptr(p) => Some(p), + _ => None, + } + } + pub fn slice(self) -> Option<(FuncParam<'a>, FuncParam<'a>)> { + match self { + BindingParam::Slice(p, l) => Some((p, l)), + _ => None, + } + } + pub fn value(self) -> Option> { + match self { + BindingParam::Value(v) => Some(v), + _ => None, + } + } +} diff --git a/lucet-idl/src/env/validate/module.rs b/lucet-idl/src/env/validate/module.rs index 855f044ab..d713b103e 100644 --- a/lucet-idl/src/env/validate/module.rs +++ b/lucet-idl/src/env/validate/module.rs @@ -359,13 +359,9 @@ mod tests { assert_eq!(a_bind.name(), "a"); assert_eq!(a_bind.type_().name(), "i64"); assert_eq!(a_bind.direction(), BindingDirection::In); - match a_bind.param() { - BindingParam::Value(v) => { - assert_eq!(v.name(), "a"); - assert_eq!(v.param_type(), ParamType::Arg); - } - _ => panic!("a binding is a value"), - } + let a_val = a_bind.param().value().expect("binding is a value"); + assert_eq!(a_val.name(), "a"); + assert_eq!(a_val.param_type(), ParamType::Arg); } #[test] @@ -387,12 +383,261 @@ mod tests { assert_eq!(r_bind.name(), "r"); assert_eq!(r_bind.type_().name(), "i64"); assert_eq!(r_bind.direction(), BindingDirection::Out); - match r_bind.param() { - BindingParam::Value(v) => { - assert_eq!(v.name(), "r"); - assert_eq!(v.param_type(), ParamType::Ret); + let r_val = r_bind.param().value().expect("binding is a value"); + assert_eq!(r_val.name(), "r"); + assert_eq!(r_val.param_type(), ParamType::Ret); + } + + #[test] + fn func_multiple_returns() { + assert_eq!( + mod_syntax("fn trivial(a: i32) -> r1: i32, r2: i32;") + .err() + .unwrap(), + ValidationError::Syntax { + expected: "at most one return value", + location: Location { line: 1, column: 0 }, } - _ => panic!("r binding is a value"), - } + ); + } + + #[test] + fn func_duplicate_arg() { + assert_eq!( + mod_syntax("fn trivial(a: i32, a: i32);").err().unwrap(), + ValidationError::NameAlreadyExists { + name: "a".to_owned(), + at_location: Location { + line: 1, + column: 19 + }, + previous_location: Location { + line: 1, + column: 11 + }, + } + ); + } + + #[test] + fn func_one_arg_value_binding() { + let pkg_repr = mod_syntax("fn foo(a: i32) where\na_binding: in i8 <- a;").expect("valid"); + let m = Package::new(&pkg_repr).module("mod").expect("get module"); + let foo = m.function("foo").expect("get foo"); + + assert_eq!(foo.args().collect::>().len(), 1); + assert_eq!(foo.bindings().collect::>().len(), 1); + + let a = foo.arg("a").expect("arg a exists"); + assert_eq!(a.name(), "a"); + assert_eq!(a.type_().name(), "i32"); + assert_eq!(a.binding().direction(), BindingDirection::In); + assert_eq!(a.binding().name(), "a_binding"); + a.binding() + .param() + .value() + .expect("binding param used as value"); + assert_eq!(a.binding().type_().name(), "i8"); + } + + #[test] + fn func_one_arg_ptr_binding() { + let pkg_repr = + mod_syntax("fn foo(a: i32) where\na_binding: inout i8 <- *a;").expect("valid"); + let m = Package::new(&pkg_repr).module("mod").expect("get module"); + let foo = m.function("foo").expect("get foo"); + + assert_eq!(foo.args().collect::>().len(), 1); + assert_eq!(foo.bindings().collect::>().len(), 1); + + let a = foo.arg("a").expect("arg a exists"); + assert_eq!(a.name(), "a"); + assert_eq!(a.type_().name(), "i32"); + assert_eq!(a.binding().direction(), BindingDirection::InOut); + assert_eq!(a.binding().name(), "a_binding"); + a.binding() + .param() + .ptr() + .expect("binding param used as ptr"); + assert_eq!(a.binding().type_().name(), "i8"); + } + + #[test] + fn func_one_arg_binding_wrong_direction() { + assert_eq!( + mod_syntax("fn foo(a: i32) where\na_binding: out i8 <- a;") + .err() + .unwrap(), + ValidationError::BindingTypeError { + expected: "argument value must be input-only binding", + location: Location { line: 2, column: 0 } + }, + ); + } + + #[test] + fn func_one_arg_binding_wrong_type() { + // Cant convert int to float + assert_eq!( + mod_syntax("fn trivial(a: i32) where\na_binding: out f32 <- a;") + .err() + .unwrap(), + ValidationError::BindingTypeError { + expected: "binding type representation to match argument type", + location: Location { line: 2, column: 0 } + }, + ); + // Cant convert float to int + assert_eq!( + mod_syntax("fn trivial(a: f32) where\na_binding: out i32 <- a;") + .err() + .unwrap(), + ValidationError::BindingTypeError { + expected: "binding type representation to match argument type", + location: Location { line: 2, column: 0 } + }, + ); + // Cant represent i64 with i32 + assert_eq!( + mod_syntax("fn trivial(a: i32) where\na_binding: out i64 <- a;") + .err() + .unwrap(), + ValidationError::BindingTypeError { + expected: "binding type representation to match argument type", + location: Location { line: 2, column: 0 } + }, + ); + // Cant represent ptr with float + assert_eq!( + mod_syntax("fn trivial(a: f32) where\na_binding: out i8 <- *a;") + .err() + .unwrap(), + ValidationError::BindingTypeError { + expected: "pointer bindings to be represented as an i32", + location: Location { line: 2, column: 0 } + }, + ); + // Cant represent ptr with i64 + assert_eq!( + mod_syntax("fn trivial(a: i64) where\na_binding: out i8 <- *a;") + .err() + .unwrap(), + ValidationError::BindingTypeError { + expected: "pointer bindings to be represented as an i32", + location: Location { line: 2, column: 0 } + }, + ); + } + + #[test] + fn func_one_ret_value_binding() { + let pkg_repr = + mod_syntax("fn foo() -> a: i32 where\na_binding: out i8 <- a;").expect("valid"); + + let m = Package::new(&pkg_repr).module("mod").expect("get module"); + let foo = m.function("foo").expect("get foo"); + + assert_eq!(foo.rets().collect::>().len(), 1); + assert_eq!(foo.bindings().collect::>().len(), 1); + + let a = foo.ret("a").expect("ret a exists"); + assert_eq!(a.name(), "a"); + assert_eq!(a.type_().name(), "i32"); + assert_eq!(a.binding().direction(), BindingDirection::Out); + assert_eq!(a.binding().name(), "a_binding"); + a.binding() + .param() + .value() + .expect("binding param used as value"); + assert_eq!(a.binding().type_().name(), "i8"); + } + + #[test] + fn func_one_ret_pointer_binding() { + assert_eq!( + mod_syntax("fn trivial() -> a: i32 where\na_binding: out i8 <- *a;") + .err() + .unwrap(), + ValidationError::BindingTypeError { + expected: "return value cannot be bound to pointer", + location: Location { line: 2, column: 0 }, + } + ); + } + + #[test] + fn func_one_ret_wrong_direction() { + assert_eq!( + mod_syntax("fn trivial() -> a: i32 where\na_binding: in i8 <- a;") + .err() + .unwrap(), + ValidationError::BindingTypeError { + expected: "return value must be output-only binding", + location: Location { line: 2, column: 0 } + }, + ); + } + + #[test] + fn func_two_arg_slice_binding() { + let pkg_repr = mod_syntax( + "fn foo(a_ptr: i32, a_len: i32) where\na_binding: inout i8 <- [a_ptr, a_len];", + ) + .expect("valid"); + let m = Package::new(&pkg_repr).module("mod").expect("get module"); + let foo = m.function("foo").expect("get foo"); + + assert_eq!(foo.args().collect::>().len(), 2); + assert_eq!(foo.bindings().collect::>().len(), 1); + + let a_ptr = foo.arg("a_ptr").expect("arg a_ptr exists"); + let a_len = foo.arg("a_len").expect("arg a_len exists"); + assert_eq!(a_ptr.type_().name(), "i32"); + assert_eq!(a_len.type_().name(), "i32"); + + assert_eq!(a_ptr.binding().name(), "a_binding"); + assert_eq!(a_len.binding().name(), "a_binding"); + assert_eq!(a_ptr.binding().type_().name(), "i8"); + let (a_ptr_2, a_len_2) = a_ptr + .binding() + .param() + .slice() + .expect("binding param used as slice"); + assert_eq!(a_ptr_2.name(), "a_ptr"); + assert_eq!(a_len_2.name(), "a_len"); + } + + #[test] + fn func_buncha_bindings() { + let pkg_repr = mod_syntax( + "fn nontrivial(a: i32, b: i32, c: f32) -> d: i32 where\n\ + a_binding: out u8 <- *a,\n\ + b_binding: inout u16 <- *b,\n\ + c_binding: in f32 <- c,\n\ + d_binding: out i8 <- d;\n\ + ", + ) + .expect("valid"); + + let m = Package::new(&pkg_repr).module("mod").expect("get module"); + let nontrivial = m.function("nontrivial").expect("get nontrivial"); + + assert_eq!(nontrivial.args().collect::>().len(), 3); + assert_eq!(nontrivial.rets().collect::>().len(), 1); + assert_eq!(nontrivial.bindings().collect::>().len(), 4); + + let a = nontrivial.arg("a").expect("arg a exists"); + let b = nontrivial.arg("b").expect("arg b exists"); + let c = nontrivial.arg("c").expect("arg c exists"); + let d = nontrivial.ret("d").expect("ret d exists"); + + let a_binding = nontrivial.binding("a_binding").expect("a_binding exists"); + assert_eq!(a_binding.direction(), BindingDirection::Out); + let b_binding = nontrivial.binding("b_binding").expect("b_binding exists"); + assert_eq!(b_binding.direction(), BindingDirection::InOut); + let c_binding = nontrivial.binding("c_binding").expect("c_binding exists"); + assert_eq!(c_binding.direction(), BindingDirection::In); + let d_binding = nontrivial.binding("d_binding").expect("d_binding exists"); + assert_eq!(d_binding.direction(), BindingDirection::Out); } } From f24c07d2bc40f048c043ed46cfe8980766248a09 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 1 Aug 2019 16:07:27 -0700 Subject: [PATCH 323/512] lucet-idl: add package-level validation and tests to new side --- lucet-idl/src/env/cursor.rs | 25 ++++ lucet-idl/src/env/prelude.rs | 89 +++++++----- lucet-idl/src/env/validate/mod.rs | 1 + lucet-idl/src/env/validate/module.rs | 31 ++-- lucet-idl/src/env/validate/package.rs | 196 ++++++++++++++++++++++++++ lucet-idl/src/generator.rs | 50 ------- 6 files changed, 295 insertions(+), 97 deletions(-) create mode 100644 lucet-idl/src/env/validate/package.rs delete mode 100644 lucet-idl/src/generator.rs diff --git a/lucet-idl/src/env/cursor.rs b/lucet-idl/src/env/cursor.rs index f255b7ddb..8ca139c0a 100644 --- a/lucet-idl/src/env/cursor.rs +++ b/lucet-idl/src/env/cursor.rs @@ -223,6 +223,31 @@ impl<'a> DatatypeVariant<'a> { DatatypeVariant::Alias(a) => a.to().abi_type(), } } + + pub fn atom(self) -> Option { + match self { + DatatypeVariant::Atom(a) => Some(a), + _ => None, + } + } + pub fn struct_(self) -> Option> { + match self { + DatatypeVariant::Struct(s) => Some(s), + _ => None, + } + } + pub fn enum_(self) -> Option> { + match self { + DatatypeVariant::Enum(e) => Some(e), + _ => None, + } + } + pub fn alias(self) -> Option> { + match self { + DatatypeVariant::Alias(a) => Some(a), + _ => None, + } + } } #[derive(Debug, Clone)] diff --git a/lucet-idl/src/env/prelude.rs b/lucet-idl/src/env/prelude.rs index d196dcc12..33a940a32 100644 --- a/lucet-idl/src/env/prelude.rs +++ b/lucet-idl/src/env/prelude.rs @@ -1,26 +1,22 @@ use crate::env::atoms::AtomType; use crate::env::repr::{ DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, ModuleDatatypesRepr, - ModuleFuncsRepr, ModuleIx, ModuleRepr, PackageRepr, + ModuleFuncsRepr, ModuleIx, ModuleRepr, }; use crate::env::MemArea; use cranelift_entity::{EntityRef, PrimaryMap}; -pub fn base_package() -> PackageRepr { - let mut names = PrimaryMap::new(); - names.push("std".to_owned()); - let mut modules = PrimaryMap::new(); - modules.push(ModuleRepr { - datatypes: atom_datatypes(), +pub fn std_module() -> ModuleRepr { + ModuleRepr { + datatypes: std_datatypes(), funcs: ModuleFuncsRepr { names: PrimaryMap::new(), funcs: PrimaryMap::new(), }, - }); - PackageRepr { names, modules } + } } -fn atom_datatypes() -> ModuleDatatypesRepr { +fn std_datatypes() -> ModuleDatatypesRepr { fn create_atom(repr: &mut ModuleDatatypesRepr, name: &str, atom: AtomType) { let ix = repr.names.push(name.to_owned()); let mem_size = atom.mem_size(); @@ -75,35 +71,58 @@ impl AtomType { #[cfg(test)] mod test { - use super::base_package; + use super::std_module; use crate::env::atoms::AtomType; - use crate::env::repr::{DatatypeIdent, DatatypeVariantRepr, PackageRepr}; + use crate::env::cursor::Package; + use crate::env::repr::{DatatypeIdent, PackageRepr}; + use cranelift_entity::PrimaryMap; #[test] fn atom_idents() { use AtomType::*; - let prelude = base_package(); - fn lookup_atom(package: &PackageRepr, ident: DatatypeIdent) -> AtomType { - let module = package.modules.get(ident.module).expect("valid moduleix"); - let dt = module - .datatypes - .datatypes - .get(ident.datatype) - .expect("valid datatypeix"); - match dt.variant { - DatatypeVariantRepr::Atom(a) => a, - _ => panic!("expected atom datatype, got {:?}", dt), - } + + let mut names = PrimaryMap::new(); + names.push("std".to_owned()); + let mut modules = PrimaryMap::new(); + modules.push(std_module()); + let pkg_repr = PackageRepr { names, modules }; + let prelude = Package::new(&pkg_repr); + + fn lookup_atom_by_id(package: &Package, ident: DatatypeIdent) -> AtomType { + let dt = package.datatype_by_id(ident).expect("get by id"); + dt.variant().atom().expect("datatype is atom") } - assert_eq!(Bool, lookup_atom(&prelude, Bool.datatype_id())); - assert_eq!(U8, lookup_atom(&prelude, U8.datatype_id())); - assert_eq!(U16, lookup_atom(&prelude, U16.datatype_id())); - assert_eq!(U32, lookup_atom(&prelude, U32.datatype_id())); - assert_eq!(U64, lookup_atom(&prelude, U64.datatype_id())); - assert_eq!(I8, lookup_atom(&prelude, I8.datatype_id())); - assert_eq!(I16, lookup_atom(&prelude, I16.datatype_id())); - assert_eq!(I32, lookup_atom(&prelude, I32.datatype_id())); - assert_eq!(I64, lookup_atom(&prelude, I64.datatype_id())); - assert_eq!(F32, lookup_atom(&prelude, F32.datatype_id())); - assert_eq!(F64, lookup_atom(&prelude, F64.datatype_id())); + + assert_eq!(Bool, lookup_atom_by_id(&prelude, Bool.datatype_id())); + assert_eq!(U8, lookup_atom_by_id(&prelude, U8.datatype_id())); + assert_eq!(U16, lookup_atom_by_id(&prelude, U16.datatype_id())); + assert_eq!(U32, lookup_atom_by_id(&prelude, U32.datatype_id())); + assert_eq!(U64, lookup_atom_by_id(&prelude, U64.datatype_id())); + assert_eq!(I8, lookup_atom_by_id(&prelude, I8.datatype_id())); + assert_eq!(I16, lookup_atom_by_id(&prelude, I16.datatype_id())); + assert_eq!(I32, lookup_atom_by_id(&prelude, I32.datatype_id())); + assert_eq!(I64, lookup_atom_by_id(&prelude, I64.datatype_id())); + assert_eq!(F32, lookup_atom_by_id(&prelude, F32.datatype_id())); + assert_eq!(F64, lookup_atom_by_id(&prelude, F64.datatype_id())); + + fn lookup_atom_by_name(package: &Package, name: &str) -> AtomType { + let dt = package + .module("std") + .expect("std module exists") + .datatype(name) + .expect("get by name"); + dt.variant().atom().expect("datatype is atom") + } + + assert_eq!(Bool, lookup_atom_by_name(&prelude, "bool")); + assert_eq!(U8, lookup_atom_by_name(&prelude, "u8")); + assert_eq!(U16, lookup_atom_by_name(&prelude, "u16")); + assert_eq!(U32, lookup_atom_by_name(&prelude, "u32")); + assert_eq!(U64, lookup_atom_by_name(&prelude, "u64")); + assert_eq!(I8, lookup_atom_by_name(&prelude, "i8")); + assert_eq!(I16, lookup_atom_by_name(&prelude, "i16")); + assert_eq!(I32, lookup_atom_by_name(&prelude, "i32")); + assert_eq!(I64, lookup_atom_by_name(&prelude, "i64")); + assert_eq!(F32, lookup_atom_by_name(&prelude, "f32")); + assert_eq!(F64, lookup_atom_by_name(&prelude, "f64")); } } diff --git a/lucet-idl/src/env/validate/mod.rs b/lucet-idl/src/env/validate/mod.rs index 5e307a1c1..ea0a4eaf1 100644 --- a/lucet-idl/src/env/validate/mod.rs +++ b/lucet-idl/src/env/validate/mod.rs @@ -2,5 +2,6 @@ mod datatypes; mod function; mod module; mod names; +pub mod package; pub use module::module_from_declarations; diff --git a/lucet-idl/src/env/validate/module.rs b/lucet-idl/src/env/validate/module.rs index d713b103e..90c7695a4 100644 --- a/lucet-idl/src/env/validate/module.rs +++ b/lucet-idl/src/env/validate/module.rs @@ -1,13 +1,10 @@ -#![allow(unused)] use super::datatypes::DatatypeModuleBuilder; use super::function::FunctionModuleBuilder; use super::names::ModNamesBuilder; use crate::env::cursor::Package; -use crate::env::repr::{DatatypeIx, FuncIx, ModuleIx, ModuleRepr, PackageRepr}; +use crate::env::repr::{ModuleIx, ModuleRepr, PackageRepr}; use crate::error::ValidationError; use crate::parser::SyntaxDecl; -use crate::types::Location; -use std::collections::HashMap; pub fn module_from_declarations( env: &PackageRepr, @@ -26,7 +23,10 @@ pub fn module_from_declarations( SyntaxDecl::Function { name, location, .. } => { names.introduce_function(name, location)?; } - SyntaxDecl::Module { .. } => unreachable!(), + SyntaxDecl::Module { location, .. } => Err(ValidationError::Syntax { + expected: "type or function declaration", + location: *location, + })?, } } @@ -99,19 +99,22 @@ pub fn module_from_declarations( #[cfg(test)] mod tests { use super::*; - use crate::env::cursor::{BindingDirection, BindingParam, DatatypeVariant, Module, ParamType}; - use crate::env::prelude::base_package; + use crate::env::cursor::{BindingDirection, DatatypeVariant, ParamType}; + use crate::env::validate::package::PackageBuilder; use crate::env::MemArea; use crate::parser::Parser; + use crate::types::Location; fn mod_syntax(syntax: &str) -> Result { let mut parser = Parser::new(syntax); let decls = parser.match_decls().expect("parses"); - let mut pkg = base_package(); - let mod_ix = pkg.names.push("mod".to_owned()); - let module_repr = module_from_declarations(&pkg, mod_ix, &decls)?; - pkg.modules.push(module_repr); - Ok(pkg) + let mut pkg_builder = PackageBuilder::new(); + let mod_ix = pkg_builder + .introduce_name("mod", &Location { line: 0, column: 0 }) + .expect("declare name ok"); + let module_repr = module_from_declarations(pkg_builder.repr(), mod_ix, &decls)?; + pkg_builder.define_module(mod_ix, module_repr); + Ok(pkg_builder.build()) } #[test] @@ -627,9 +630,13 @@ mod tests { assert_eq!(nontrivial.bindings().collect::>().len(), 4); let a = nontrivial.arg("a").expect("arg a exists"); + assert_eq!(a.type_().name(), "i32"); let b = nontrivial.arg("b").expect("arg b exists"); + assert_eq!(b.type_().name(), "i32"); let c = nontrivial.arg("c").expect("arg c exists"); + assert_eq!(c.type_().name(), "f32"); let d = nontrivial.ret("d").expect("ret d exists"); + assert_eq!(d.type_().name(), "i32"); let a_binding = nontrivial.binding("a_binding").expect("a_binding exists"); assert_eq!(a_binding.direction(), BindingDirection::Out); diff --git a/lucet-idl/src/env/validate/package.rs b/lucet-idl/src/env/validate/package.rs new file mode 100644 index 000000000..9630fc798 --- /dev/null +++ b/lucet-idl/src/env/validate/package.rs @@ -0,0 +1,196 @@ +#![allow(unused)] +use super::module::module_from_declarations; +use crate::env::prelude::std_module; +use crate::env::repr::{ModuleIx, ModuleRepr, PackageRepr}; +use crate::error::ValidationError; +use crate::parser::SyntaxDecl; +use crate::types::Location; +use cranelift_entity::PrimaryMap; +use std::collections::HashMap; + +pub fn package_from_declarations( + package_decls: &[SyntaxDecl], +) -> Result { + let mut pkg = PackageBuilder::new(); + for decl in package_decls { + match decl { + SyntaxDecl::Module { + name, + location, + decls, + } => { + let module_ix = pkg.introduce_name(name, location)?; + let module_repr = module_from_declarations(pkg.repr(), module_ix, decls)?; + pkg.define_module(module_ix, module_repr); + } + _ => Err(ValidationError::Syntax { + expected: "module", + location: *decl.location(), + })?, + } + } + Ok(pkg.build()) +} + +pub struct PackageBuilder { + name_decls: HashMap)>, + repr: PackageRepr, +} + +impl PackageBuilder { + pub fn new() -> Self { + let mut repr = PackageRepr { + names: PrimaryMap::new(), + modules: PrimaryMap::new(), + }; + let mut name_decls = HashMap::new(); + repr.names.push("std".to_owned()); + let base_ix = repr.modules.push(std_module()); + name_decls.insert("std".to_owned(), (base_ix, None)); + + Self { name_decls, repr } + } + + pub fn introduce_name( + &mut self, + name: &str, + location: &Location, + ) -> Result { + if let Some((_, prev_loc)) = self.name_decls.get(name) { + match prev_loc { + Some(prev_loc) => { + Err(ValidationError::NameAlreadyExists { + name: name.to_owned(), + at_location: *location, + previous_location: *prev_loc, + })?; + } + None => { + Err(ValidationError::Syntax { + expected: "non-reserved module name", + location: *location, + })?; + } + } + } + let ix = self.repr.names.push(name.to_owned()); + self.name_decls + .insert(name.to_owned(), (ix, Some(*location))); + Ok(ix) + } + + pub fn repr(&self) -> &PackageRepr { + &self.repr + } + + pub fn define_module(&mut self, ix: ModuleIx, mod_repr: ModuleRepr) { + assert!(self.repr.names.is_valid(ix)); + let pushed_ix = self.repr.modules.push(mod_repr); + assert_eq!(ix, pushed_ix); + } + + pub fn build(self) -> PackageRepr { + self.repr + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::env::cursor::Package; + use crate::parser::Parser; + + fn pkg_(syntax: &str) -> Result { + let mut parser = Parser::new(syntax); + let decls = parser.match_decls().expect("parses"); + package_from_declarations(&decls) + } + + #[test] + fn one_empty_mod() { + let repr = pkg_("mod empty {}").expect("valid package"); + let pkg = Package::new(&repr); + let empty = pkg.module("empty").expect("mod empty exists"); + assert_eq!(empty.name(), "empty"); + assert_eq!(empty.datatypes().collect::>().len(), 0); + assert_eq!(empty.functions().collect::>().len(), 0); + } + + #[test] + fn multiple_empty_mod() { + let repr = pkg_("mod empty1 {} mod empty2{}mod\nempty3{//\n}").expect("valid package"); + let pkg = Package::new(&repr); + let _ = pkg.module("empty1").expect("mod empty1 exists"); + let _ = pkg.module("empty2").expect("mod empty2 exists"); + let _ = pkg.module("empty3").expect("mod empty3 exists"); + } + + #[test] + fn mod_with_a_type() { + let repr = pkg_("mod foo { type bar = u8; }").expect("valid package"); + let pkg = Package::new(&repr); + let foo = pkg.module("foo").expect("mod foo exists"); + let _bar = foo.datatype("bar").expect("foo::bar exists"); + } + + #[test] + fn no_mod_std_name() { + let err = pkg_("mod std {}").err().expect("error package"); + assert_eq!( + err, + ValidationError::Syntax { + expected: "non-reserved module name", + location: Location { line: 1, column: 0 }, + } + ); + } + + #[test] + fn no_mod_duplicate_name() { + let err = pkg_("mod foo {}\nmod foo {}").err().expect("error package"); + assert_eq!( + err, + ValidationError::NameAlreadyExists { + name: "foo".to_owned(), + at_location: Location { line: 2, column: 0 }, + previous_location: Location { line: 1, column: 0 }, + } + ); + } + + #[test] + fn no_mod_in_mod() { + let err = pkg_("mod foo { mod bar { }}").err().expect("error package"); + assert_eq!( + err, + ValidationError::Syntax { + expected: "type or function declaration", + location: Location { + line: 1, + column: 10 + } + } + ); + pkg_("mod foo { enum whatever {} mod bar { }}") + .err() + .expect("error package"); + } + + #[test] + fn no_top_level_types() { + let err = pkg_("mod foo { } enum bar {}") + .err() + .expect("error package"); + assert_eq!( + err, + ValidationError::Syntax { + expected: "module", + location: Location { + line: 1, + column: 12 + } + } + ); + } + +} diff --git a/lucet-idl/src/generator.rs b/lucet-idl/src/generator.rs deleted file mode 100644 index bd67532b2..000000000 --- a/lucet-idl/src/generator.rs +++ /dev/null @@ -1,50 +0,0 @@ -use crate::error::IDLError; -use crate::module::Module; -use crate::types::{ - AliasDataType, DataType, DataTypeVariant, EnumDataType, FuncDecl, Named, StructDataType, -}; - -pub trait Generator { - fn gen_type_header( - &mut self, - module: &Module, - data_type_entry: &Named, - ) -> Result<(), IDLError>; - - fn gen_alias( - &mut self, - module: &Module, - data_type_entry: &Named, - alias_: &AliasDataType, - ) -> Result<(), IDLError>; - - fn gen_struct( - &mut self, - module: &Module, - data_type_entry: &Named, - struct_: &StructDataType, - ) -> Result<(), IDLError>; - - fn gen_enum( - &mut self, - module: &Module, - data_type_entry: &Named, - enum_: &EnumDataType, - ) -> Result<(), IDLError>; - - fn gen_function( - &mut self, - module: &Module, - func_decl_entry: &Named, - ) -> Result<(), IDLError>; - - fn gen_datatype(&mut self, module: &Module, dt: &Named) -> Result<(), IDLError> { - self.gen_type_header(module, dt)?; - match &dt.entity.variant { - DataTypeVariant::Struct(s) => self.gen_struct(module, dt, s)?, - DataTypeVariant::Alias(a) => self.gen_alias(module, dt, a)?, - DataTypeVariant::Enum(e) => self.gen_enum(module, dt, e)?, - } - Ok(()) - } -} From 56716564d6ae50c2636c0613edcecff5dc0e060b Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 1 Aug 2019 16:25:51 -0700 Subject: [PATCH 324/512] lucet-idl: move new repr/cursor stuff to root of crate. codegen disabled! --- lucet-idl/src/{env => }/atoms.rs | 2 +- lucet-idl/src/{env => }/cursor.rs | 10 +- lucet-idl/src/data_layout.rs | 237 ----- lucet-idl/src/env/mod.rs | 9 - lucet-idl/src/env/validate/mod.rs | 7 - lucet-idl/src/error.rs | 2 +- lucet-idl/src/function.rs | 412 -------- lucet-idl/src/lexer.rs | 2 +- lucet-idl/src/lib.rs | 57 +- lucet-idl/src/module.rs | 991 ------------------ lucet-idl/src/package.rs | 275 ----- lucet-idl/src/parser.rs | 2 +- lucet-idl/src/{env => }/prelude.rs | 12 +- lucet-idl/src/{env => }/repr.rs | 6 +- lucet-idl/src/types.rs | 112 -- lucet-idl/src/{env => }/validate/datatypes.rs | 14 +- lucet-idl/src/{env => }/validate/function.rs | 9 +- lucet-idl/src/validate/mod.rs | 7 + lucet-idl/src/{env => }/validate/module.rs | 11 +- lucet-idl/src/{env => }/validate/names.rs | 5 +- lucet-idl/src/{env => }/validate/package.rs | 8 +- 21 files changed, 76 insertions(+), 2114 deletions(-) rename lucet-idl/src/{env => }/atoms.rs (98%) rename lucet-idl/src/{env => }/cursor.rs (99%) delete mode 100644 lucet-idl/src/data_layout.rs delete mode 100644 lucet-idl/src/env/validate/mod.rs delete mode 100644 lucet-idl/src/function.rs delete mode 100644 lucet-idl/src/module.rs delete mode 100644 lucet-idl/src/package.rs rename lucet-idl/src/{env => }/prelude.rs (96%) rename lucet-idl/src/{env => }/repr.rs (96%) rename lucet-idl/src/{env => }/validate/datatypes.rs (98%) rename lucet-idl/src/{env => }/validate/function.rs (98%) create mode 100644 lucet-idl/src/validate/mod.rs rename lucet-idl/src/{env => }/validate/module.rs (98%) rename lucet-idl/src/{env => }/validate/names.rs (96%) rename lucet-idl/src/{env => }/validate/package.rs (97%) diff --git a/lucet-idl/src/env/atoms.rs b/lucet-idl/src/atoms.rs similarity index 98% rename from lucet-idl/src/env/atoms.rs rename to lucet-idl/src/atoms.rs index f58b7cf82..420f474c3 100644 --- a/lucet-idl/src/env/atoms.rs +++ b/lucet-idl/src/atoms.rs @@ -1,4 +1,4 @@ -use crate::env::MemArea; +use crate::MemArea; #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum AtomType { diff --git a/lucet-idl/src/env/cursor.rs b/lucet-idl/src/cursor.rs similarity index 99% rename from lucet-idl/src/env/cursor.rs rename to lucet-idl/src/cursor.rs index 8ca139c0a..362184ec7 100644 --- a/lucet-idl/src/env/cursor.rs +++ b/lucet-idl/src/cursor.rs @@ -1,12 +1,12 @@ -use crate::env::atoms::{AbiType, AtomType}; -pub use crate::env::repr::BindingDirection; -use crate::env::repr::{ +pub use crate::atoms::{AbiType, AtomType}; +use crate::parser::SyntaxTypeRef; +pub use crate::repr::BindingDirection; +use crate::repr::{ AliasDatatypeRepr, BindingFromRepr, BindingIx, BindingRepr, DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, EnumDatatypeRepr, FuncIdent, FuncIx, FuncRepr, ModuleIx, ModuleRepr, PackageRepr, ParamIx, ParamRepr, StructDatatypeRepr, StructMemberRepr, }; -use crate::env::MemArea; -use crate::parser::SyntaxTypeRef; +use crate::MemArea; #[derive(Debug, Clone)] pub struct Package<'a> { diff --git a/lucet-idl/src/data_layout.rs b/lucet-idl/src/data_layout.rs deleted file mode 100644 index 7eaaa5893..000000000 --- a/lucet-idl/src/data_layout.rs +++ /dev/null @@ -1,237 +0,0 @@ -use crate::error::ValidationError; -use crate::types::{ - AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, EnumMember, - Ident, Location, MemArea, Name, StructDataType, StructMember, -}; -use std::collections::HashMap; - -#[derive(Debug, PartialEq, Eq, Clone)] -struct DataTypeIR { - pub variant: VariantIR, - pub location: Location, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct StructMemberIR { - pub type_: DataTypeRef, - pub name: String, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct StructIR { - pub members: Vec, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct EnumIR { - pub members: Vec, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct AliasIR { - pub to: DataTypeRef, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum VariantIR { - Struct(StructIR), - Enum(EnumIR), - Alias(AliasIR), -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct DataTypeModuleBuilder { - data_types: HashMap, -} - -impl DataTypeModuleBuilder { - pub fn new() -> Self { - Self { - data_types: HashMap::new(), - } - } - - pub fn define(&mut self, id: Ident, variant: VariantIR, location: Location) { - if let Some(prev_def) = self.data_types.insert( - id, - DataTypeIR { - variant, - location: location.clone(), - }, - ) { - panic!("id {} already defined: {:?}", id, prev_def) - } - } - - fn dfs_walk( - &self, - id: Ident, - visited: &mut [bool], - ordered: &mut Vec, - finalized_types: &mut HashMap, - ) -> Result<(), ()> { - if visited[id.0] { - Err(())? - } - visited[id.0] = true; - let dt = self.data_types.get(&id).expect("data type IR is defined"); - - match &dt.variant { - VariantIR::Struct(ref s) => { - // First, iterate down the member to ensure this is finite, and fill in type - // info for leaves first - for mem in s.members.iter() { - if let DataTypeRef::Defined(id) = mem.type_ { - self.dfs_walk(id, visited, ordered, finalized_types)?; - }; - } - // If finalized type information has not yet been computed, we can now compute it: - if !finalized_types.contains_key(&id) { - let mut offset = 0; - let mut struct_align = 1; - let mut members: Vec = Vec::new(); - for mem in s.members.iter() { - let (repr_size, align) = - datatype_repr_size_align(&mem.type_, finalized_types) - .expect("datatype is defined by prior dfs_walk"); - - offset = align_to(offset, align); - struct_align = ::std::cmp::max(struct_align, align); - - members.push(StructMember { - type_: mem.type_.clone(), - name: mem.name.clone(), - offset, - }); - offset += repr_size; - } - - let repr_size = align_to(offset, struct_align); - - finalized_types.insert( - id, - DataType { - variant: DataTypeVariant::Struct(StructDataType { members }), - repr_size, - align: struct_align, - }, - ); - } - } - VariantIR::Alias(ref a) => { - if let DataTypeRef::Defined(pointee_id) = a.to { - self.dfs_walk(pointee_id, visited, ordered, finalized_types)?; - }; - if !finalized_types.contains_key(&id) { - let (repr_size, align) = datatype_repr_size_align(&a.to, finalized_types) - .expect("datatype is defined by prior dfs_walk"); - finalized_types.insert( - id, - DataType { - variant: DataTypeVariant::Alias(AliasDataType { to: a.to.clone() }), - repr_size, - align, - }, - ); - } - } - VariantIR::Enum(ref e) => { - // No recursion to do on the dfs. - if !finalized_types.contains_key(&id) { - // x86_64 ABI says enum is 32 bits wide - let repr_size = AtomType::U32.mem_size(); - let align = repr_size; - finalized_types.insert( - id, - DataType { - variant: DataTypeVariant::Enum(EnumDataType { - members: e.members.clone(), - }), - repr_size, - align, - }, - ); - } - } - } - if !ordered.contains(&id) { - ordered.push(id) - } - visited[id.0] = false; - Ok(()) - } - - pub fn validate_datatypes( - &self, - names: &[Name], - ) -> Result<(HashMap, Vec), ValidationError> { - let mut finalized = HashMap::new(); - let mut ordered = Vec::new(); - // Important to iterate in name order, so error messages are consistient. - // HashMap iteration order is not stable. - for (ix, name) in names.iter().enumerate() { - let id = Ident(ix); - if let Some(decl) = self.data_types.get(&id) { - // First, make sure datatypes are finite - let mut visited = Vec::new(); - visited.resize(names.len(), false); - - self.dfs_walk(id, &mut visited, &mut ordered, &mut finalized) - .map_err(|_| ValidationError::Infinite { - name: name.name.clone(), - location: decl.location.clone(), - })?; - } - } - Ok((finalized, ordered)) - } -} - -fn datatype_repr_size_align( - datatype_ref: &DataTypeRef, - finalized_types: &HashMap, -) -> Option<(usize, usize)> { - let (size, align) = match datatype_ref { - DataTypeRef::Atom(a) => { - let s = a.mem_size(); - (s, s) - } - DataTypeRef::Defined(ref member_ident) => { - let t = finalized_types.get(member_ident)?; - (t.repr_size, t.align) - } - }; - assert!(size > 0); - assert!(align > 0); - Some((size, align)) -} -fn align_to(offs: usize, alignment: usize) -> usize { - offs + alignment - 1 - ((offs + alignment - 1) % alignment) -} - -#[cfg(test)] -mod align_test { - use super::align_to; - #[test] - fn align_test() { - assert_eq!(0, align_to(0, 1)); - assert_eq!(0, align_to(0, 2)); - assert_eq!(0, align_to(0, 4)); - assert_eq!(0, align_to(0, 8)); - - assert_eq!(1, align_to(1, 1)); - assert_eq!(2, align_to(1, 2)); - assert_eq!(4, align_to(1, 4)); - assert_eq!(8, align_to(1, 8)); - - assert_eq!(2, align_to(2, 1)); - assert_eq!(2, align_to(2, 2)); - assert_eq!(4, align_to(2, 4)); - assert_eq!(8, align_to(2, 8)); - - assert_eq!(5, align_to(5, 1)); - assert_eq!(6, align_to(5, 2)); - assert_eq!(8, align_to(5, 4)); - assert_eq!(8, align_to(5, 8)); - } -} diff --git a/lucet-idl/src/env/mod.rs b/lucet-idl/src/env/mod.rs index 1a97745e2..8b1378917 100644 --- a/lucet-idl/src/env/mod.rs +++ b/lucet-idl/src/env/mod.rs @@ -1,10 +1 @@ -pub mod atoms; -pub mod cursor; -pub mod prelude; -pub mod repr; -pub mod validate; -pub trait MemArea { - fn mem_size(&self) -> usize; - fn mem_align(&self) -> usize; -} diff --git a/lucet-idl/src/env/validate/mod.rs b/lucet-idl/src/env/validate/mod.rs deleted file mode 100644 index ea0a4eaf1..000000000 --- a/lucet-idl/src/env/validate/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod datatypes; -mod function; -mod module; -mod names; -pub mod package; - -pub use module::module_from_declarations; diff --git a/lucet-idl/src/error.rs b/lucet-idl/src/error.rs index b31f4ff07..d28f1b41d 100644 --- a/lucet-idl/src/error.rs +++ b/lucet-idl/src/error.rs @@ -1,5 +1,5 @@ use crate::parser; -use crate::types::Location; +use crate::Location; use std::error::Error; use std::fmt; use std::io; diff --git a/lucet-idl/src/function.rs b/lucet-idl/src/function.rs deleted file mode 100644 index bcb5e98f1..000000000 --- a/lucet-idl/src/function.rs +++ /dev/null @@ -1,412 +0,0 @@ -use crate::error::ValidationError; -use crate::module::Module; -use crate::parser::{BindingDirSyntax, BindingRefSyntax, BindingSyntax, FuncArgSyntax}; -use crate::types::{AbiType, DataTypeRef, Location}; -use std::collections::HashMap; -use std::ops::Deref; - -struct FuncValidator<'a> { - // arg name to declaration location and argument position - arg_names: HashMap, - // Arg positions index into this vector: - args: Vec, - // Ret positions index into this vector: - rets: Vec, - // binding name to - binding_names: HashMap, - // param position to binding syntax - param_binding_sites: HashMap, - in_bindings: Vec, - inout_bindings: Vec, - out_bindings: Vec, - location: &'a Location, - module: &'a Module, -} - -impl<'a> FuncValidator<'a> { - fn new(location: &'a Location, module: &'a Module) -> Self { - Self { - arg_names: HashMap::new(), - args: Vec::new(), - rets: Vec::new(), - binding_names: HashMap::new(), - in_bindings: Vec::new(), - inout_bindings: Vec::new(), - out_bindings: Vec::new(), - param_binding_sites: HashMap::new(), - location, - module, - } - } - fn introduce_arg_name( - &mut self, - arg_syntax: &FuncArgSyntax, - position: ParamPosition, - ) -> Result { - if let Some((previous_location, _)) = self.arg_names.get(&arg_syntax.name) { - Err(ValidationError::NameAlreadyExists { - name: arg_syntax.name.clone(), - at_location: arg_syntax.location, - previous_location: previous_location.clone(), - })?; - } else { - self.arg_names.insert( - arg_syntax.name.clone(), - (arg_syntax.location.clone(), position), - ); - } - Ok(FuncArg { - name: arg_syntax.name.clone(), - type_: arg_syntax.type_.clone(), - }) - } - - fn introduce_args(&mut self, args: &[FuncArgSyntax]) -> Result<(), ValidationError> { - for (ix, a) in args.iter().enumerate() { - let a = self.introduce_arg_name(a, ParamPosition::Arg(ix))?; - self.args.push(a); - } - Ok(()) - } - fn introduce_rets(&mut self, rets: &[FuncArgSyntax]) -> Result<(), ValidationError> { - if rets.len() > 1 { - Err(ValidationError::Syntax { - expected: "at most one return value", - location: self.location.clone(), - })? - } - for (ix, r) in rets.iter().enumerate() { - let r = self.introduce_arg_name(r, ParamPosition::Ret(ix))?; - self.rets.push(r); - } - Ok(()) - } - - fn introduce_bindings(&mut self, bindings: &[BindingSyntax]) -> Result<(), ValidationError> { - for (ix, binding) in bindings.iter().enumerate() { - let b = self.introduce_binding(binding, ix)?; - match binding.direction { - BindingDirSyntax::In => self.in_bindings.push(b), - BindingDirSyntax::InOut => self.inout_bindings.push(b), - BindingDirSyntax::Out => self.out_bindings.push(b), - } - } - for (ix, arg) in self.args.iter().enumerate() { - let position = ParamPosition::Arg(ix); - if !self.param_binding_sites.contains_key(&position) { - self.in_bindings - .push(self.implicit_value_binding(&arg, position)?); - } - } - for (ix, ret) in self.rets.iter().enumerate() { - let position = ParamPosition::Ret(ix); - if !self.param_binding_sites.contains_key(&position) { - self.out_bindings - .push(self.implicit_value_binding(&ret, position)?); - } - } - Ok(()) - } - - fn introduce_binding( - &mut self, - binding: &BindingSyntax, - position: usize, - ) -> Result { - // 1. make sure binding name is unique - if let Some((previous_location, _)) = self.binding_names.get(&binding.name) { - Err(ValidationError::NameAlreadyExists { - name: binding.name.clone(), - at_location: binding.location, - previous_location: previous_location.clone(), - })?; - } else { - self.binding_names - .insert(binding.name.clone(), (binding.location.clone(), position)); - } - - // 2. resolve type_ SyntaxRef to a DataTypeRef - let type_ = self.module.get_typeref(&binding.type_)?; - - // 3. typecheck the binding: - let from = self.validate_binding_ref(&binding, &type_)?; - - Ok(FuncBinding { - name: binding.name.clone(), - type_, - from, - }) - } - - fn implicit_value_binding( - &self, - arg: &FuncArg, - position: ParamPosition, - ) -> Result { - // 1. make sure binding name is unique. We're re-using the arg name - // for the binding. If another binding overlapped with the arg name, - // it is now at fault. (complicated, huh... :/) - if let Some((previous_location, _)) = self.binding_names.get(&arg.name) { - let (arg_location, _) = self.arg_names.get(&arg.name).expect("arg introduced"); - Err(ValidationError::BindingNameAlreadyBound { - name: arg.name.clone(), - at_location: previous_location.clone(), - bound_location: arg_location.clone(), - })?; - } - - // 2. resolve type - let type_ = DataTypeRef::Atom(arg.type_.into()); - - // 3. no need to validate ref- we can construct it ourselves - let from = BindingRef::Value(position); - - Ok(FuncBinding { - name: arg.name.clone(), - type_, - from, - }) - } - - fn get_arg(&self, arg_name: &String) -> Option<(ParamPosition, FuncArg)> { - let (_, position) = self.arg_names.get(arg_name)?; - match position { - ParamPosition::Arg(ix) => Some(( - position.clone(), - self.args.get(*ix).expect("in-bounds arg index").clone(), - )), - ParamPosition::Ret(ix) => Some(( - position.clone(), - self.rets.get(*ix).expect("in-bounds ret index").clone(), - )), - } - } - - fn validate_binding_arg_mapping( - &mut self, - name: &String, - location: &Location, - ) -> Result<(ParamPosition, FuncArg), ValidationError> { - // Check that it refers to a valid arg: - let (position, arg) = self.get_arg(name).ok_or_else(|| ValidationError::Syntax { - expected: "name of an argument or return value", - location: location.clone(), - })?; - // Check that the arg has only been used once: - if let Some(use_location) = self.param_binding_sites.get(&position) { - Err(ValidationError::BindingNameAlreadyBound { - name: name.clone(), - at_location: location.clone(), - bound_location: use_location.clone(), - })?; - } else { - self.param_binding_sites - .insert(position.clone(), location.clone()); - } - Ok((position, arg)) - } - - fn validate_binding_ref( - &mut self, - binding: &BindingSyntax, - target_type: &DataTypeRef, - ) -> Result { - match &binding.from { - // A pointer to a name is accepted: - BindingRefSyntax::Ptr(bref) => match bref.deref() { - BindingRefSyntax::Name(ref name) => { - let (position, funcarg) = - self.validate_binding_arg_mapping(name, &binding.location)?; - if funcarg.type_ != AbiType::I32 { - Err(ValidationError::BindingTypeError { - expected: "pointer bindings to be represented as an i32", - location: binding.location.clone(), - })?; - } - match position { - ParamPosition::Arg(_) => { - // all good! Arg pointers are valid for in, inout, or out binding. - } - ParamPosition::Ret(_) => { - Err(ValidationError::BindingTypeError { - expected: "return value cannot be bound to pointer", - location: binding.location.clone(), - })?; - } - } - Ok(BindingRef::Ptr(position)) - } - _ => Err(ValidationError::Syntax { - expected: "pointer binding must be of form *arg", - location: binding.location.clone(), - }), - }, - // A slice of two names is accepted: - BindingRefSyntax::Slice(ref ptr_ref, ref len_ref) => { - match (ptr_ref.deref(), len_ref.deref()) { - ( - BindingRefSyntax::Name(ref ptr_name), - BindingRefSyntax::Name(ref len_name), - ) => { - let (ptr_position, ptr_arg) = - self.validate_binding_arg_mapping(ptr_name, &binding.location)?; - if ptr_arg.type_ != AbiType::I32 { - Err(ValidationError::BindingTypeError { - expected: "slice pointer must be i32", - location: binding.location.clone(), - })?; - } - let (len_position, len_arg) = - self.validate_binding_arg_mapping(len_name, &binding.location)?; - if len_arg.type_ != AbiType::I32 { - Err(ValidationError::BindingTypeError { - expected: "slice len must be i32", - location: binding.location.clone(), - })?; - } - match (&ptr_position, &len_position) { - (ParamPosition::Arg(_), ParamPosition::Arg(_)) => {} - _ => { - Err(ValidationError::BindingTypeError { - expected: "slice bindings must be inputs", - location: binding.location.clone(), - })?; - } - } - Ok(BindingRef::Slice(ptr_position, len_position)) - } - ( - BindingRefSyntax::Name(ref _ptr_name), - BindingRefSyntax::Ptr(ref len_ptr_ref), - ) => match len_ptr_ref.deref() { - BindingRefSyntax::Name(_len_ptr_name) => { - unimplemented!("slice syntax [ptr, *len] for an output slice"); - } - _ => Err(ValidationError::Syntax { - expected: "slice binding must be of form [ptr, len] or [ptr, *len]", - location: binding.location.clone(), - }), - }, - _ => Err(ValidationError::Syntax { - expected: "slice binding must be of form [ptr, len] or [ptr, *len]", - location: binding.location.clone(), - }), - } - } - // A bare name is accepted: - BindingRefSyntax::Name(ref name) => { - let (position, funcarg) = - self.validate_binding_arg_mapping(name, &binding.location)?; - - // make sure funcarg.type_ is a valid representation of target type - match self.module.get_abi_repr(target_type) { - Some(target_repr) => { - if target_repr != funcarg.type_ { - Err(ValidationError::BindingTypeError { - expected: "binding type representation to match argument type", - location: binding.location.clone(), - })?; - } - } - None => { - Err(ValidationError::BindingTypeError { - expected: "binding type to be representable as value (try passing by reference instead)", - location: binding.location.clone(), - })?; - } - } - // Arg values must be in-only bindings, Ret values must be out-only bindings - match position { - ParamPosition::Arg(_) => { - if binding.direction != BindingDirSyntax::In { - Err(ValidationError::BindingTypeError { - expected: "argument value must be input-only binding", - location: binding.location.clone(), - })?; - } - } - ParamPosition::Ret(_) => { - if binding.direction != BindingDirSyntax::Out { - Err(ValidationError::BindingTypeError { - expected: "return value must be output-only binding", - location: binding.location.clone(), - })?; - } - } - } - Ok(BindingRef::Value(position)) - } - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct FuncArg { - pub name: String, - pub type_: AbiType, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct FuncBinding { - pub name: String, - pub type_: DataTypeRef, - pub from: BindingRef, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum BindingRef { - Ptr(ParamPosition), // Treat the argument of that name as a pointer - Slice(ParamPosition, ParamPosition), // Treat first argument as a pointer, second as the length - Value(ParamPosition), // Treat the argument of that name as a value -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ParamPosition { - Arg(usize), - Ret(usize), -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct FuncDecl { - pub field_name: String, - pub binding_name: String, - pub args: Vec, - pub rets: Vec, - pub in_bindings: Vec, - pub inout_bindings: Vec, - pub out_bindings: Vec, -} - -impl FuncDecl { - pub fn from_syntax( - field_name: String, - binding_name: String, - args: &[FuncArgSyntax], - rets: &[FuncArgSyntax], - bindings: &[BindingSyntax], - location: &Location, - module: &Module, - ) -> Result { - let mut validator = FuncValidator::new(location, module); - validator.introduce_args(args)?; - validator.introduce_rets(rets)?; - validator.introduce_bindings(bindings)?; - - Ok(FuncDecl { - field_name, - binding_name, - args: validator.args, - rets: validator.rets, - in_bindings: validator.in_bindings, - inout_bindings: validator.inout_bindings, - out_bindings: validator.out_bindings, - }) - } - - pub fn get_param(&self, loc: &ParamPosition) -> Option<&FuncArg> { - match loc { - ParamPosition::Arg(a) => self.args.get(*a), - ParamPosition::Ret(r) => self.rets.get(*r), - } - } -} diff --git a/lucet-idl/src/lexer.rs b/lucet-idl/src/lexer.rs index 4078cdf86..91200ca89 100644 --- a/lucet-idl/src/lexer.rs +++ b/lucet-idl/src/lexer.rs @@ -1,4 +1,4 @@ -use crate::types::{AtomType, Location}; +use crate::{AtomType, Location}; use std::str::CharIndices; #[derive(Debug, PartialEq, Eq, Clone, Copy)] diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index d6a413454..0bcd510b7 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -3,55 +3,64 @@ #[macro_use] extern crate failure; -mod c; +mod atoms; +mod cursor; +mod prelude; +mod repr; +mod validate; +//mod c; mod config; -mod data_layout; pub mod env; mod error; -mod function; mod lexer; -mod module; -mod package; mod parser; mod pretty_writer; -mod rust; -mod types; +//mod rust; pub use crate::config::{Backend, Config}; -pub use crate::error::IDLError; -pub use crate::function::{BindingRef, FuncArg, FuncBinding, FuncDecl, ParamPosition}; -pub use crate::module::Module; -pub use crate::package::Package; -pub use crate::types::{ - AbiType, AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, Ident, - Location, MemArea, Name, Named, StructDataType, StructMember, -}; +pub use crate::cursor::*; +pub use crate::error::{IDLError, ValidationError}; +pub use crate::repr::{BindingDirection, PackageRepr}; +pub use crate::{AbiType, AtomType}; -use crate::c::CGenerator; +//use crate::c::CGenerator; use crate::parser::Parser; -use crate::rust::RustGenerator; +//use crate::rust::RustGenerator; +use crate::validate::package_from_declarations; use lucet_module::bindings::Bindings; use std::io::Write; -pub fn parse_package(input: &str) -> Result { +#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] +pub struct Location { + pub line: usize, + pub column: usize, +} + +pub trait MemArea { + fn mem_size(&self) -> usize; + fn mem_align(&self) -> usize; +} + +pub fn parse_package(input: &str) -> Result { let mut parser = Parser::new(&input); let decls = parser.match_decls()?; - let pkg = Package::from_declarations(&decls)?; + let pkg = package_from_declarations(&decls)?; Ok(pkg) } pub fn codegen(package: &Package, config: &Config, output: Box) -> Result<(), IDLError> { match config.backend { - Backend::CGuest => CGenerator::new(output).generate_guest(package)?, - Backend::RustGuest => RustGenerator::new(output).generate_guest(package)?, - Backend::RustHost => RustGenerator::new(output).generate_host(package)?, - Backend::Bindings => generate_bindings(&package.bindings(), output)?, + Backend::CGuest => unimplemented!(), //CGenerator::new(output).generate_guest(package)?, + Backend::RustGuest => unimplemented!(), //RustGenerator::new(output).generate_guest(package)?, + Backend::RustHost => unimplemented!(), //RustGenerator::new(output).generate_host(package)?, + Backend::Bindings => unimplemented!(), //generate_bindings(&package.bindings(), output)?, } Ok(()) } pub fn run(config: &Config, input: &str, output: Box) -> Result<(), IDLError> { - let pkg = parse_package(input)?; + let pkg_repr = parse_package(input)?; + let pkg = Package::new(&pkg_repr); codegen(&pkg, config, output) } diff --git a/lucet-idl/src/module.rs b/lucet-idl/src/module.rs deleted file mode 100644 index 013168230..000000000 --- a/lucet-idl/src/module.rs +++ /dev/null @@ -1,991 +0,0 @@ -use crate::data_layout::{ - AliasIR, DataTypeModuleBuilder, EnumIR, StructIR, StructMemberIR, VariantIR, -}; -use crate::error::ValidationError; -use crate::function::FuncDecl; -use crate::parser::{SyntaxDecl, SyntaxTypeRef}; -use crate::types::{ - AbiType, DataType, DataTypeRef, DataTypeVariant, EnumMember, Ident, Location, MemArea, Name, - Named, -}; -use heck::SnakeCase; -use std::collections::HashMap; - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Module { - pub names: Vec, - pub data_types: HashMap, - pub data_type_ordering: Vec, - pub funcs: HashMap, - pub module_name: String, - pub binding_prefix: String, -} - -impl Module { - fn new(module_name: String, binding_prefix: String) -> Self { - Self { - names: Vec::new(), - data_types: HashMap::new(), - data_type_ordering: Vec::new(), - funcs: HashMap::new(), - module_name, - binding_prefix, - } - } - - fn introduce_name( - &mut self, - name: &str, - location: &Location, - ) -> Result { - if let Some(existing) = self.id_for_name(&name) { - let prev = self - .names - .get(existing.0) - .expect("lookup told us name exists"); - Err(ValidationError::NameAlreadyExists { - name: name.to_owned(), - at_location: *location, - previous_location: prev.location, - }) - } else { - let id = self.names.len(); - self.names.push(Name { - name: name.to_owned(), - location: *location, - }); - Ok(Ident(id)) - } - } - - fn id_for_name(&self, name: &str) -> Option { - for (id, n) in self.names.iter().enumerate() { - if n.name == name { - return Some(Ident(id)); - } - } - None - } - - pub fn get_typeref(&self, syntax_ref: &SyntaxTypeRef) -> Result { - match syntax_ref { - SyntaxTypeRef::Atom { atom, .. } => Ok(DataTypeRef::Atom(*atom)), - SyntaxTypeRef::Name { name, location } => match self.id_for_name(name) { - Some(id) => Ok(DataTypeRef::Defined(id)), - None => Err(ValidationError::NameNotFound { - name: name.clone(), - use_location: *location, - }), - }, - } - } - - // If a DataType is representable by an atomic AbiType, get it. Otherwise the DataType must - // be pointed to across ABI boundaries - pub fn get_abi_repr(&self, dtref: &DataTypeRef) -> Option { - match dtref { - DataTypeRef::Defined(ident) => { - let dt = self - .data_types - .get(ident) - .expect("abi representation of valid dtref"); - match &dt.variant { - DataTypeVariant::Struct(struct_) => { - if struct_.members.len() == 1 { - self.get_abi_repr(&struct_.members[0].type_) - } else { - None - } - } - DataTypeVariant::Enum(enum_) => { - if enum_.members.len() < u32::max_value() as usize { - Some(AbiType::I32) - } else { - None - } - } - DataTypeVariant::Alias(alias) => self.get_abi_repr(&alias.to), - } - } - DataTypeRef::Atom(atom) => Some(AbiType::from_atom(atom)), - } - } - - fn decl_to_ir( - &self, - id: Ident, - decl: &SyntaxDecl, - data_types_ir: &mut DataTypeModuleBuilder, - funcs_ir: &mut HashMap, - ) -> Result<(), ValidationError> { - match decl { - SyntaxDecl::Struct { - name, - members, - location, - } => { - let mut uniq_membs = HashMap::new(); - let mut dtype_members = Vec::new(); - if members.is_empty() { - Err(ValidationError::Empty { - name: name.clone(), - location: *location, - })? - } - for mem in members { - // Ensure that each member name is unique: - if let Some(existing) = uniq_membs.insert(mem.name.clone(), mem) { - Err(ValidationError::NameAlreadyExists { - name: mem.name.clone(), - at_location: mem.location, - previous_location: existing.location, - })? - } - // Get the DataTypeRef for the member, which ensures that it refers only to - // defined types: - let type_ = self.get_typeref(&mem.type_)?; - // build the struct with this as the member: - dtype_members.push(StructMemberIR { - type_, - name: mem.name.clone(), - }) - } - - data_types_ir.define( - id, - VariantIR::Struct(StructIR { - members: dtype_members, - }), - location.clone(), - ); - } - SyntaxDecl::Enum { - name, - variants, - location, - } => { - let mut uniq_vars = HashMap::new(); - let mut dtype_members = Vec::new(); - if variants.is_empty() { - Err(ValidationError::Empty { - name: name.clone(), - location: *location, - })? - } - for var in variants { - // Ensure that each member name is unique: - if let Some(existing) = uniq_vars.insert(var.name.clone(), var) { - Err(ValidationError::NameAlreadyExists { - name: var.name.clone(), - at_location: var.location, - previous_location: existing.location, - })? - } - // build the struct with this as the member: - dtype_members.push(EnumMember { - name: var.name.clone(), - }) - } - data_types_ir.define( - id, - VariantIR::Enum(EnumIR { - members: dtype_members, - }), - location.clone(), - ); - } - SyntaxDecl::Alias { what, location, .. } => { - let to = self.get_typeref(what)?; - data_types_ir.define(id, VariantIR::Alias(AliasIR { to }), location.clone()); - } - SyntaxDecl::Function { - name, - args, - rets, - location, - bindings, - } => { - let binding_name = self.binding_prefix.clone() + "_" + &name.to_snake_case(); - let decl = FuncDecl::from_syntax( - name.clone(), - binding_name, - args, - rets, - bindings, - location, - self, - )?; - if let Some(prev_def) = funcs_ir.insert(id, decl) { - panic!("id {} already defined: {:?}", id, prev_def) - } - } - SyntaxDecl::Module { .. } => unreachable!(), // Should be excluded by from_declarations constructor - } - Ok(()) - } - - pub fn from_declarations( - decls: &[SyntaxDecl], - module_name: String, - binding_prefix: String, - ) -> Result { - let mut mod_ = Self::new(module_name, binding_prefix); - let mut idents: Vec = Vec::new(); - for decl in decls { - match decl { - SyntaxDecl::Module { .. } => Err(ValidationError::Syntax { - expected: "type or function declaration", - location: *decl.location(), - })?, - _ => idents.push(mod_.introduce_name(decl.name(), decl.location())?), - } - } - - let mut data_types_ir = DataTypeModuleBuilder::new(); - let mut funcs_ir = HashMap::new(); - for (decl, id) in decls.iter().zip(&idents) { - mod_.decl_to_ir(id.clone(), decl, &mut data_types_ir, &mut funcs_ir)? - } - - let (data_types, ordering) = data_types_ir.validate_datatypes(&mod_.names)?; - mod_.data_types = data_types; - mod_.data_type_ordering = ordering; - - mod_.funcs = funcs_ir; - - Ok(mod_) - } - /* ACCESSORS */ - /// Retrieve information about a data type given its identifier - pub fn get_datatype(&self, id: Ident) -> Option> { - let name = &self.names[id.0]; - if let Some(data_type) = &self.data_types.get(&id) { - Some(Named { - id, - name, - entity: data_type, - }) - } else { - None - } - } - - pub fn get_mem_area(&self, dtref: &DataTypeRef) -> Box { - match dtref { - DataTypeRef::Defined(ident) => Box::new( - self.get_datatype(*ident) - .expect("valid datatype") - .entity - .clone(), - ), - DataTypeRef::Atom(atom) => Box::new(*atom), - } - } - - /// Retrieve information about a function declaration given its identifier - pub fn get_func_decl(&self, id: Ident) -> Option> { - let name = &self.names[id.0]; - if let Some(func_decl) = &self.funcs.get(&id) { - Some(Named { - id, - name, - entity: func_decl, - }) - } else { - None - } - } - pub fn datatypes(&self) -> impl Iterator> { - self.data_type_ordering - .iter() - .map(move |i| self.get_datatype(*i).unwrap()) - } - - pub fn func_decls(&self) -> impl Iterator> { - self.funcs - .iter() - .map(move |(i, _)| self.get_func_decl(*i).unwrap()) - } - - pub fn func_bindings(&self) -> HashMap { - self.func_decls() - .map(|d| (d.entity.field_name.clone(), d.entity.binding_name.clone())) - .collect() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::function::{BindingRef, FuncArg, FuncBinding, ParamPosition}; - use crate::parser::Parser; - use crate::types::{AbiType, AtomType, DataTypeVariant, StructDataType, StructMember}; - fn mod_(syntax: &str) -> Result { - let mut parser = Parser::new(syntax); - let decls = parser.match_decls().expect("parses"); - Module::from_declarations(&decls, String::new(), String::new()) - } - - #[test] - fn structs_basic() { - assert!(mod_("struct foo { a: i32}").is_ok()); - assert!(mod_("struct foo { a: i32, b: f32 }").is_ok()); - } - - #[test] - fn struct_two_atoms() { - { - let d = mod_("struct foo { a: i32, b: f32 }").unwrap(); - assert_eq!( - d.data_types[&Ident(0)], - DataType { - variant: DataTypeVariant::Struct(StructDataType { - members: vec![ - StructMember { - name: "a".to_owned(), - type_: DataTypeRef::Atom(AtomType::I32), - offset: 0, - }, - StructMember { - name: "b".to_owned(), - type_: DataTypeRef::Atom(AtomType::F32), - offset: 4, - }, - ] - }), - repr_size: 8, - align: 4, - } - ); - } - } - - #[test] - fn struct_prev_definition() { - // Refer to a struct defined previously: - assert!(mod_("struct foo { a: i32, b: f64 } struct bar { a: foo }").is_ok()); - } - - #[test] - fn struct_next_definition() { - // Refer to a struct defined afterwards: - assert!(mod_("struct foo { a: i32, b: bar} struct bar { a: i32 }").is_ok()); - } - - #[test] - fn struct_self_referential() { - // Refer to itself - assert!(mod_("struct list { next: list, thing: i32 }").is_err()); - } - - #[test] - fn struct_empty() { - // No members - assert_eq!( - mod_("struct foo {}").err().unwrap(), - ValidationError::Empty { - name: "foo".to_owned(), - location: Location { line: 1, column: 0 }, - } - ); - } - - #[test] - fn struct_duplicate_member() { - // Duplicate member in struct - assert_eq!( - mod_("struct foo { \na: i32, \na: f64}").err().unwrap(), - ValidationError::NameAlreadyExists { - name: "a".to_owned(), - at_location: Location { line: 3, column: 0 }, - previous_location: Location { line: 2, column: 0 }, - } - ); - } - - #[test] - fn struct_duplicate_definition() { - // Duplicate definition of struct - assert_eq!( - mod_("struct foo { a: i32 }\nstruct foo { a: i32 } ") - .err() - .unwrap(), - ValidationError::NameAlreadyExists { - name: "foo".to_owned(), - at_location: Location { line: 2, column: 0 }, - previous_location: Location { line: 1, column: 0 }, - } - ); - } - - #[test] - fn struct_undeclared_member() { - // Refer to type that is not declared - assert_eq!( - mod_("struct foo { \nb: bar }").err().unwrap(), - ValidationError::NameNotFound { - name: "bar".to_owned(), - use_location: Location { line: 2, column: 3 }, - } - ); - } - - #[test] - fn enums() { - assert!(mod_("enum foo { a }").is_ok()); - assert!(mod_("enum foo { a, b }").is_ok()); - - { - let d = mod_("enum foo { a, b }").unwrap(); - let members = match &d.data_types[&Ident(0)].variant { - DataTypeVariant::Enum(e) => &e.members, - _ => panic!("Unexpected type"), - }; - assert_eq!(members[0].name, "a"); - assert_eq!(members[1].name, "b"); - } - - // No members - assert_eq!( - mod_("enum foo {}").err().unwrap(), - ValidationError::Empty { - name: "foo".to_owned(), - location: Location { line: 1, column: 0 }, - } - ); - - // Duplicate member in enum - assert_eq!( - mod_("enum foo { \na,\na }").err().unwrap(), - ValidationError::NameAlreadyExists { - name: "a".to_owned(), - at_location: Location { line: 3, column: 0 }, - previous_location: Location { line: 2, column: 0 }, - } - ); - - // Duplicate definition of enum - assert_eq!( - mod_("enum foo { a }\nenum foo { a } ").err().unwrap(), - ValidationError::NameAlreadyExists { - name: "foo".to_owned(), - at_location: Location { line: 2, column: 0 }, - previous_location: Location { line: 1, column: 0 }, - } - ); - } - - #[test] - fn aliases() { - assert!(mod_("type foo = i32;").is_ok()); - assert!(mod_("type foo = f64;").is_ok()); - assert!(mod_("type foo = u8;").is_ok()); - - assert!(mod_("type foo = bar;\nenum bar { a }").is_ok()); - - assert!(mod_("type link = u32;\nstruct list { next: link, thing: i32 }").is_ok()); - } - - #[test] - fn infinite() { - assert_eq!( - mod_("type foo = bar;\ntype bar = foo;").err().unwrap(), - ValidationError::Infinite { - name: "foo".to_owned(), - location: Location { line: 1, column: 0 }, - } - ); - - assert_eq!( - mod_("type foo = bar;\nstruct bar { a: foo }") - .err() - .unwrap(), - ValidationError::Infinite { - name: "foo".to_owned(), - location: Location { line: 1, column: 0 }, - } - ); - - assert_eq!( - mod_("type foo = bar;\nstruct bar { a: baz }\nstruct baz { c: i32, e: foo }") - .err() - .unwrap(), - ValidationError::Infinite { - name: "foo".to_owned(), - location: Location { line: 1, column: 0 }, - } - ); - } - - #[test] - fn func_trivial() { - assert_eq!( - mod_("fn trivial();").ok().unwrap(), - Module { - names: vec![Name { - name: "trivial".to_owned(), - location: Location { line: 1, column: 0 } - }], - funcs: vec![( - Ident(0), - FuncDecl { - binding_name: "_trivial".to_owned(), - field_name: "trivial".to_owned(), - args: Vec::new(), - rets: Vec::new(), - in_bindings: Vec::new(), - inout_bindings: Vec::new(), - out_bindings: Vec::new(), - } - )] - .into_iter() - .collect::>(), - data_types: HashMap::new(), - data_type_ordering: Vec::new(), - module_name: String::new(), - binding_prefix: String::new(), - } - ); - } - #[test] - fn func_one_arg() { - assert_eq!( - mod_("fn trivial(a: i64);").ok().unwrap(), - Module { - names: vec![Name { - name: "trivial".to_owned(), - location: Location { line: 1, column: 0 } - }], - funcs: vec![( - Ident(0), - FuncDecl { - binding_name: "_trivial".to_owned(), - field_name: "trivial".to_owned(), - args: vec![FuncArg { - type_: AbiType::I64, - name: "a".to_owned(), - }], - rets: Vec::new(), - in_bindings: vec![FuncBinding { - name: "a".to_owned(), - type_: DataTypeRef::Atom(AtomType::I64), - from: BindingRef::Value(ParamPosition::Arg(0)), - },], - inout_bindings: Vec::new(), - out_bindings: Vec::new(), - } - )] - .into_iter() - .collect::>(), - data_types: HashMap::new(), - data_type_ordering: Vec::new(), - module_name: String::new(), - binding_prefix: String::new(), - } - ); - } - - #[test] - fn func_one_ret() { - assert_eq!( - mod_("fn trivial() -> r: i64;").ok().unwrap(), - Module { - names: vec![Name { - name: "trivial".to_owned(), - location: Location { line: 1, column: 0 } - }], - funcs: vec![( - Ident(0), - FuncDecl { - binding_name: "_trivial".to_owned(), - field_name: "trivial".to_owned(), - args: Vec::new(), - rets: vec![FuncArg { - name: "r".to_owned(), - type_: AbiType::I64, - }], - in_bindings: Vec::new(), - inout_bindings: Vec::new(), - out_bindings: vec![FuncBinding { - name: "r".to_owned(), - type_: DataTypeRef::Atom(AtomType::I64), - from: BindingRef::Value(ParamPosition::Ret(0)), - },] - } - )] - .into_iter() - .collect::>(), - data_types: HashMap::new(), - data_type_ordering: Vec::new(), - module_name: String::new(), - binding_prefix: String::new(), - } - ); - } - - #[test] - fn func_multiple_returns() { - assert_eq!( - mod_("fn trivial(a: i32) -> r1: i32, r2: i32;") - .err() - .unwrap(), - ValidationError::Syntax { - expected: "at most one return value", - location: Location { line: 1, column: 0 }, - } - ); - } - - #[test] - fn func_duplicate_arg() { - assert_eq!( - mod_("fn trivial(a: i32, a: i32);").err().unwrap(), - ValidationError::NameAlreadyExists { - name: "a".to_owned(), - at_location: Location { - line: 1, - column: 19 - }, - previous_location: Location { - line: 1, - column: 11 - }, - } - ); - } - - #[test] - fn func_one_arg_value_binding() { - assert_eq!( - mod_("fn trivial(a: i32) where\na_binding: in i8 <- a;") - .ok() - .unwrap(), - Module { - names: vec![Name { - name: "trivial".to_owned(), - location: Location { line: 1, column: 0 } - }], - funcs: vec![( - Ident(0), - FuncDecl { - binding_name: "_trivial".to_owned(), - field_name: "trivial".to_owned(), - args: vec![FuncArg { - type_: AbiType::I32, - name: "a".to_owned(), - }], - rets: Vec::new(), - in_bindings: vec![FuncBinding { - name: "a_binding".to_owned(), - type_: DataTypeRef::Atom(AtomType::I8), - from: BindingRef::Value(ParamPosition::Arg(0)), - }], - inout_bindings: Vec::new(), - out_bindings: Vec::new(), - } - )] - .into_iter() - .collect::>(), - data_types: HashMap::new(), - data_type_ordering: Vec::new(), - module_name: String::new(), - binding_prefix: String::new(), - } - ); - } - - #[test] - fn func_one_arg_ptr_binding() { - assert_eq!( - mod_("fn trivial(a: i32) where\na_binding: inout i8 <- *a;") - .ok() - .unwrap(), - Module { - names: vec![Name { - name: "trivial".to_owned(), - location: Location { line: 1, column: 0 } - }], - funcs: vec![( - Ident(0), - FuncDecl { - binding_name: "_trivial".to_owned(), - field_name: "trivial".to_owned(), - args: vec![FuncArg { - type_: AbiType::I32, - name: "a".to_owned(), - }], - rets: Vec::new(), - in_bindings: Vec::new(), - inout_bindings: vec![FuncBinding { - name: "a_binding".to_owned(), - type_: DataTypeRef::Atom(AtomType::I8), - from: BindingRef::Ptr(ParamPosition::Arg(0)), - }], - out_bindings: Vec::new(), - } - )] - .into_iter() - .collect::>(), - data_types: HashMap::new(), - data_type_ordering: Vec::new(), - module_name: String::new(), - binding_prefix: String::new(), - } - ); - } - - #[test] - fn func_one_arg_binding_wrong_direction() { - assert_eq!( - mod_("fn trivial(a: i32) where\na_binding: out i8 <- a;") - .err() - .unwrap(), - ValidationError::BindingTypeError { - expected: "argument value must be input-only binding", - location: Location { line: 2, column: 0 } - }, - ); - } - - #[test] - fn func_one_arg_binding_wrong_type() { - // Cant convert int to float - assert_eq!( - mod_("fn trivial(a: i32) where\na_binding: out f32 <- a;") - .err() - .unwrap(), - ValidationError::BindingTypeError { - expected: "binding type representation to match argument type", - location: Location { line: 2, column: 0 } - }, - ); - // Cant convert float to int - assert_eq!( - mod_("fn trivial(a: f32) where\na_binding: out i32 <- a;") - .err() - .unwrap(), - ValidationError::BindingTypeError { - expected: "binding type representation to match argument type", - location: Location { line: 2, column: 0 } - }, - ); - // Cant represent i64 with i32 - assert_eq!( - mod_("fn trivial(a: i32) where\na_binding: out i64 <- a;") - .err() - .unwrap(), - ValidationError::BindingTypeError { - expected: "binding type representation to match argument type", - location: Location { line: 2, column: 0 } - }, - ); - // Cant represent ptr with float - assert_eq!( - mod_("fn trivial(a: f32) where\na_binding: out i8 <- *a;") - .err() - .unwrap(), - ValidationError::BindingTypeError { - expected: "pointer bindings to be represented as an i32", - location: Location { line: 2, column: 0 } - }, - ); - // Cant represent ptr with i64 - assert_eq!( - mod_("fn trivial(a: i64) where\na_binding: out i8 <- *a;") - .err() - .unwrap(), - ValidationError::BindingTypeError { - expected: "pointer bindings to be represented as an i32", - location: Location { line: 2, column: 0 } - }, - ); - } - - #[test] - fn func_one_ret_value_binding() { - assert_eq!( - mod_("fn trivial() -> a: i32 where\na_binding: out i8 <- a;") - .ok() - .unwrap(), - Module { - names: vec![Name { - name: "trivial".to_owned(), - location: Location { line: 1, column: 0 } - }], - funcs: vec![( - Ident(0), - FuncDecl { - binding_name: "_trivial".to_owned(), - field_name: "trivial".to_owned(), - args: Vec::new(), - rets: vec![FuncArg { - type_: AbiType::I32, - name: "a".to_owned(), - }], - in_bindings: Vec::new(), - inout_bindings: Vec::new(), - out_bindings: vec![FuncBinding { - name: "a_binding".to_owned(), - type_: DataTypeRef::Atom(AtomType::I8), - from: BindingRef::Value(ParamPosition::Ret(0)), - }], - } - )] - .into_iter() - .collect::>(), - data_types: HashMap::new(), - data_type_ordering: Vec::new(), - module_name: String::new(), - binding_prefix: String::new(), - } - ); - } - - #[test] - fn func_one_ret_pointer_binding() { - assert_eq!( - mod_("fn trivial() -> a: i32 where\na_binding: out i8 <- *a;") - .err() - .unwrap(), - ValidationError::BindingTypeError { - expected: "return value cannot be bound to pointer", - location: Location { line: 2, column: 0 }, - } - ); - } - #[test] - fn func_one_ret_wrong_direction() { - assert_eq!( - mod_("fn trivial() -> a: i32 where\na_binding: in i8 <- a;") - .err() - .unwrap(), - ValidationError::BindingTypeError { - expected: "return value must be output-only binding", - location: Location { line: 2, column: 0 } - }, - ); - } - - #[test] - fn func_two_arg_slice_binding() { - assert_eq!( - mod_( - "fn trivial(a_ptr: i32, a_len: i32) where\na_binding: inout i8 <- [a_ptr, a_len];" - ) - .ok() - .unwrap(), - Module { - names: vec![Name { - name: "trivial".to_owned(), - location: Location { line: 1, column: 0 } - }], - funcs: vec![( - Ident(0), - FuncDecl { - binding_name: "_trivial".to_owned(), - field_name: "trivial".to_owned(), - args: vec![ - FuncArg { - type_: AbiType::I32, - name: "a_ptr".to_owned(), - }, - FuncArg { - type_: AbiType::I32, - name: "a_len".to_owned(), - } - ], - rets: Vec::new(), - in_bindings: Vec::new(), - inout_bindings: vec![FuncBinding { - name: "a_binding".to_owned(), - type_: DataTypeRef::Atom(AtomType::I8), - from: BindingRef::Slice(ParamPosition::Arg(0), ParamPosition::Arg(1)), - }], - out_bindings: Vec::new(), - } - )] - .into_iter() - .collect::>(), - data_types: HashMap::new(), - data_type_ordering: Vec::new(), - module_name: String::new(), - binding_prefix: String::new(), - } - ); - } - - #[test] - fn func_buncha_bindings() { - assert_eq!( - mod_( - "fn nontrivial(a: i32, b: i32, c: f32) -> d: i32 where\n\ - a_binding: out u8 <- *a,\n\ - b_binding: inout u16 <- *b,\n\ - c_binding: in f32 <- c,\n\ - d_binding: out i8 <- d;\n\ - " - ) - .ok() - .unwrap(), - Module { - names: vec![Name { - name: "nontrivial".to_owned(), - location: Location { line: 1, column: 0 } - }], - funcs: vec![( - Ident(0), - FuncDecl { - binding_name: "_nontrivial".to_owned(), - field_name: "nontrivial".to_owned(), - args: vec![ - FuncArg { - type_: AbiType::I32, - name: "a".to_owned(), - }, - FuncArg { - type_: AbiType::I32, - name: "b".to_owned(), - }, - FuncArg { - type_: AbiType::F32, - name: "c".to_owned(), - } - ], - rets: vec![FuncArg { - type_: AbiType::I32, - name: "d".to_owned(), - }], - in_bindings: vec![FuncBinding { - name: "c_binding".to_owned(), - type_: DataTypeRef::Atom(AtomType::F32), - from: BindingRef::Value(ParamPosition::Arg(2)), - },], - inout_bindings: vec![FuncBinding { - name: "b_binding".to_owned(), - type_: DataTypeRef::Atom(AtomType::U16), - from: BindingRef::Ptr(ParamPosition::Arg(1)), - },], - out_bindings: vec![ - FuncBinding { - name: "a_binding".to_owned(), - type_: DataTypeRef::Atom(AtomType::U8), - from: BindingRef::Ptr(ParamPosition::Arg(0)), - }, - FuncBinding { - name: "d_binding".to_owned(), - type_: DataTypeRef::Atom(AtomType::I8), - from: BindingRef::Value(ParamPosition::Ret(0)), - }, - ], - } - )] - .into_iter() - .collect::>(), - data_types: HashMap::new(), - data_type_ordering: Vec::new(), - module_name: String::new(), - binding_prefix: String::new(), - } - ); - } -} diff --git a/lucet-idl/src/package.rs b/lucet-idl/src/package.rs deleted file mode 100644 index ea082e40a..000000000 --- a/lucet-idl/src/package.rs +++ /dev/null @@ -1,275 +0,0 @@ -use crate::error::ValidationError; -use crate::module::Module; -use crate::parser::SyntaxDecl; -use crate::types::{Ident, Location, Name}; -use heck::SnakeCase; -use lucet_module::bindings::Bindings; -use std::collections::HashMap; - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Package { - pub names: Vec, - pub modules: HashMap, -} - -impl Package { - fn new() -> Self { - Self { - names: Vec::new(), - modules: HashMap::new(), - } - } - - fn introduce_name( - &mut self, - name: &str, - location: &Location, - ) -> Result { - if let Some(existing) = self.id_for_name(&name) { - let prev = self - .names - .get(existing.0) - .expect("lookup told us name exists"); - Err(ValidationError::NameAlreadyExists { - name: name.to_owned(), - at_location: *location, - previous_location: prev.location, - }) - } else { - let id = self.names.len(); - self.names.push(Name { - name: name.to_owned(), - location: *location, - }); - Ok(Ident(id)) - } - } - - fn id_for_name(&self, name: &str) -> Option { - for (id, n) in self.names.iter().enumerate() { - if n.name == name { - return Some(Ident(id)); - } - } - None - } - - fn define_module(&mut self, id: Ident, mod_: Module) { - if let Some(prev_def) = self.modules.insert(id, mod_) { - panic!("id {} already defined: {:?}", id, prev_def) - } - } - - pub fn from_declarations(decls: &[SyntaxDecl]) -> Result { - let mut pkg = Self::new(); - let mut idents: Vec = Vec::new(); - for decl in decls { - match decl { - SyntaxDecl::Module { name, location, .. } => { - idents.push(pkg.introduce_name(name, location)?); - } - _ => Err(ValidationError::Syntax { - expected: "module", - location: *decl.location(), - })?, - } - } - - for (decl, id) in decls.iter().zip(&idents) { - match decl { - SyntaxDecl::Module { decls, name, .. } => { - let binding_prefix = "__".to_owned() + &name.to_snake_case(); - pkg.define_module( - *id, - Module::from_declarations(decls, name.clone(), binding_prefix)?, - ); - } - _ => unreachable!(), - } - } - - Ok(pkg) - } - - pub fn bindings(&self) -> Bindings { - let b: HashMap> = self - .modules - .iter() - .map(|(_, m)| (m.module_name.clone(), m.func_bindings())) - .collect(); - Bindings::new(b) - } -} - -#[cfg(test)] -mod test { - use super::*; - use crate::parser::Parser; - use crate::types::{AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant}; - fn pkg_(syntax: &str) -> Result { - let mut parser = Parser::new(syntax); - let decls = parser.match_decls().expect("parses"); - Package::from_declarations(&decls) - } - - #[test] - fn trivial() { - let pkg = pkg_("mod empty {}").expect("valid package"); - assert_eq!( - pkg.names, - vec![Name { - name: "empty".to_owned(), - location: Location { line: 1, column: 0 } - }] - ); - assert_eq!( - pkg.modules, - vec![( - Ident(0), - Module { - names: Vec::new(), - data_types: HashMap::new(), - data_type_ordering: Vec::new(), - funcs: HashMap::new(), - module_name: "empty".to_owned(), - binding_prefix: "__empty".to_owned(), - } - )] - .into_iter() - .collect::>() - ); - } - - #[test] - fn multiple_empty_mods() { - let pkg = pkg_("mod empty1 {} mod empty2{}mod\nempty3{//\n}").expect("valid package"); - assert_eq!( - pkg.names, - vec![ - Name { - name: "empty1".to_owned(), - location: Location { line: 1, column: 0 } - }, - Name { - name: "empty2".to_owned(), - location: Location { - line: 1, - column: 14 - } - }, - Name { - name: "empty3".to_owned(), - location: Location { - line: 1, - column: 26 - } - } - ] - ); - assert_eq!( - pkg.modules, - vec![ - ( - Ident(0), - Module { - names: Vec::new(), - data_types: HashMap::new(), - data_type_ordering: Vec::new(), - funcs: HashMap::new(), - module_name: "empty1".to_owned(), - binding_prefix: "__empty1".to_owned(), - } - ), - ( - Ident(1), - Module { - names: Vec::new(), - data_types: HashMap::new(), - data_type_ordering: Vec::new(), - funcs: HashMap::new(), - module_name: "empty2".to_owned(), - binding_prefix: "__empty2".to_owned(), - } - ), - ( - Ident(2), - Module { - names: Vec::new(), - data_types: HashMap::new(), - data_type_ordering: Vec::new(), - funcs: HashMap::new(), - module_name: "empty3".to_owned(), - binding_prefix: "__empty3".to_owned(), - } - ) - ] - .into_iter() - .collect::>() - ); - } - - #[test] - fn mod_with_a_type() { - let pkg = pkg_("mod foo { type bar = u8; }").expect("valid package"); - assert_eq!( - pkg.names, - vec![Name { - name: "foo".to_owned(), - location: Location { line: 1, column: 0 } - }] - ); - assert_eq!( - pkg.modules, - vec![( - Ident(0), - Module { - names: vec![Name { - name: "bar".to_owned(), - location: Location { - line: 1, - column: 10 - } - }], - funcs: HashMap::new(), - data_types: vec![( - Ident(0), - DataType { - variant: DataTypeVariant::Alias(AliasDataType { - to: DataTypeRef::Atom(AtomType::U8) - }), - repr_size: 1, - align: 1, - } - )] - .into_iter() - .collect::>(), - data_type_ordering: vec![Ident(0)], - module_name: "foo".to_owned(), - binding_prefix: "__foo".to_owned(), - } - )] - .into_iter() - .collect::>() - ); - } - - #[test] - fn no_mod_duplicate_name() { - pkg_("mod foo {} mod foo {}").err().expect("error package"); - } - - #[test] - fn no_mod_in_mod() { - pkg_("mod foo { mod bar { }}").err().expect("error package"); - pkg_("mod foo { enum whatever {} mod bar { }}") - .err() - .expect("error package"); - } - - #[test] - fn no_top_level_types() { - pkg_("mod foo { } enum bar {}") - .err() - .expect("error package"); - } -} diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index 4f9c3ed49..05f74e005 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -1,5 +1,5 @@ use super::lexer::{LexError, Lexer, LocatedError, LocatedToken, Token}; -use super::types::{AbiType, AtomType, Location}; +use super::{AbiType, AtomType, Location}; use std::error::Error; use std::fmt; diff --git a/lucet-idl/src/env/prelude.rs b/lucet-idl/src/prelude.rs similarity index 96% rename from lucet-idl/src/env/prelude.rs rename to lucet-idl/src/prelude.rs index 33a940a32..c6276f501 100644 --- a/lucet-idl/src/env/prelude.rs +++ b/lucet-idl/src/prelude.rs @@ -1,9 +1,9 @@ -use crate::env::atoms::AtomType; -use crate::env::repr::{ +use crate::atoms::AtomType; +use crate::repr::{ DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, ModuleDatatypesRepr, ModuleFuncsRepr, ModuleIx, ModuleRepr, }; -use crate::env::MemArea; +use crate::MemArea; use cranelift_entity::{EntityRef, PrimaryMap}; pub fn std_module() -> ModuleRepr { @@ -72,9 +72,9 @@ impl AtomType { #[cfg(test)] mod test { use super::std_module; - use crate::env::atoms::AtomType; - use crate::env::cursor::Package; - use crate::env::repr::{DatatypeIdent, PackageRepr}; + use crate::atoms::AtomType; + use crate::cursor::Package; + use crate::repr::{DatatypeIdent, PackageRepr}; use cranelift_entity::PrimaryMap; #[test] fn atom_idents() { diff --git a/lucet-idl/src/env/repr.rs b/lucet-idl/src/repr.rs similarity index 96% rename from lucet-idl/src/env/repr.rs rename to lucet-idl/src/repr.rs index 7264b2d11..f7e6f070c 100644 --- a/lucet-idl/src/env/repr.rs +++ b/lucet-idl/src/repr.rs @@ -1,4 +1,4 @@ -use crate::env::atoms::{AbiType, AtomType}; +use crate::atoms::{AbiType, AtomType}; use cranelift_entity::{entity_impl, PrimaryMap}; #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -7,8 +7,8 @@ entity_impl!(ModuleIx); #[derive(Debug, Clone)] pub struct PackageRepr { - pub names: PrimaryMap, - pub modules: PrimaryMap, + pub(crate) names: PrimaryMap, + pub(crate) modules: PrimaryMap, } #[derive(Debug, Copy, Clone, PartialEq, Eq)] diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs index 5ea7ba739..e69de29bb 100644 --- a/lucet-idl/src/types.rs +++ b/lucet-idl/src/types.rs @@ -1,112 +0,0 @@ -pub use crate::env::atoms::{AbiType, AtomType}; -pub use crate::env::MemArea; - -use std::fmt; - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] -pub struct Location { - pub line: usize, - pub column: usize, -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] -pub struct Ident(pub usize); - -impl fmt::Display for Ident { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum DataTypeRef { - Defined(Ident), - Atom(AtomType), -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct StructMember { - pub type_: DataTypeRef, - pub name: String, - pub offset: usize, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct StructDataType { - pub members: Vec, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct EnumMember { - pub name: String, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct EnumDataType { - pub members: Vec, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct AliasDataType { - pub to: DataTypeRef, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum DataTypeVariant { - Struct(StructDataType), - Enum(EnumDataType), - Alias(AliasDataType), -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct DataType { - pub variant: DataTypeVariant, - pub repr_size: usize, - pub align: usize, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Name { - pub name: String, - pub location: Location, -} - -impl MemArea for DataType { - fn mem_size(&self) -> usize { - self.repr_size - } - fn mem_align(&self) -> usize { - self.align - } -} - -impl fmt::Display for Name { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.name) - } -} - -/// A convenient structure holding a data type, its name and -/// its internal IDL representation -#[derive(Debug, Clone)] -pub struct Named<'t, E> { - pub id: Ident, - pub name: &'t Name, - pub entity: &'t E, -} - -impl<'a, T> Named<'a, T> { - pub fn using_name(&self, other: &'a U) -> Named<'a, U> { - Named { - id: self.id, - name: self.name, - entity: other, - } - } -} - -impl<'a> Named<'a, DataType> { - pub fn datatype_ref(&self) -> DataTypeRef { - DataTypeRef::Defined(self.id) - } -} diff --git a/lucet-idl/src/env/validate/datatypes.rs b/lucet-idl/src/validate/datatypes.rs similarity index 98% rename from lucet-idl/src/env/validate/datatypes.rs rename to lucet-idl/src/validate/datatypes.rs index fc86878c9..cb9e20a68 100644 --- a/lucet-idl/src/env/validate/datatypes.rs +++ b/lucet-idl/src/validate/datatypes.rs @@ -1,16 +1,12 @@ use super::names::ModNamesBuilder; -use crate::env::atoms::AtomType; -use crate::env::cursor::Package; -use crate::env::repr::{ - AliasDatatypeRepr, DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, - EnumDatatypeRepr, EnumMemberRepr, ModuleDatatypesRepr, StructDatatypeRepr, StructMemberRepr, -}; -use crate::env::MemArea; -use crate::error::ValidationError; use crate::parser::{ EnumVariant as EnumVariantSyntax, StructMember as StructMemberSyntax, SyntaxTypeRef, }; -use crate::types::Location; +use crate::repr::{ + AliasDatatypeRepr, DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, + EnumDatatypeRepr, EnumMemberRepr, ModuleDatatypesRepr, StructDatatypeRepr, StructMemberRepr, +}; +use crate::{AtomType, Location, MemArea, Package, ValidationError}; use cranelift_entity::{PrimaryMap, SecondaryMap}; use std::collections::HashMap; diff --git a/lucet-idl/src/env/validate/function.rs b/lucet-idl/src/validate/function.rs similarity index 98% rename from lucet-idl/src/env/validate/function.rs rename to lucet-idl/src/validate/function.rs index 2804419b6..281286619 100644 --- a/lucet-idl/src/env/validate/function.rs +++ b/lucet-idl/src/validate/function.rs @@ -1,13 +1,10 @@ use super::names::ModNamesBuilder; -use crate::env::atoms::{AbiType, AtomType}; -use crate::env::cursor::{Datatype, Module}; -use crate::env::repr::{ +use crate::parser::{BindingDirSyntax, BindingRefSyntax, BindingSyntax, FuncArgSyntax}; +use crate::repr::{ ArgIx, BindingDirection, BindingFromRepr, BindingIx, BindingRepr, FuncIx, FuncRepr, ModuleFuncsRepr, ParamIx, ParamRepr, RetIx, }; -use crate::error::ValidationError; -use crate::parser::{BindingDirSyntax, BindingRefSyntax, BindingSyntax, FuncArgSyntax}; -use crate::types::Location; +use crate::{AbiType, AtomType, Datatype, Location, Module, ValidationError}; use cranelift_entity::{EntityRef, PrimaryMap}; use std::collections::HashMap; use std::ops::Deref; diff --git a/lucet-idl/src/validate/mod.rs b/lucet-idl/src/validate/mod.rs new file mode 100644 index 000000000..c2762dd1b --- /dev/null +++ b/lucet-idl/src/validate/mod.rs @@ -0,0 +1,7 @@ +mod datatypes; +mod function; +mod module; +mod names; +mod package; + +pub use package::package_from_declarations; diff --git a/lucet-idl/src/env/validate/module.rs b/lucet-idl/src/validate/module.rs similarity index 98% rename from lucet-idl/src/env/validate/module.rs rename to lucet-idl/src/validate/module.rs index 90c7695a4..ec2c58e05 100644 --- a/lucet-idl/src/env/validate/module.rs +++ b/lucet-idl/src/validate/module.rs @@ -1,10 +1,9 @@ use super::datatypes::DatatypeModuleBuilder; use super::function::FunctionModuleBuilder; use super::names::ModNamesBuilder; -use crate::env::cursor::Package; -use crate::env::repr::{ModuleIx, ModuleRepr, PackageRepr}; -use crate::error::ValidationError; use crate::parser::SyntaxDecl; +use crate::repr::{ModuleIx, ModuleRepr, PackageRepr}; +use crate::{Package, ValidationError}; pub fn module_from_declarations( env: &PackageRepr, @@ -99,11 +98,9 @@ pub fn module_from_declarations( #[cfg(test)] mod tests { use super::*; - use crate::env::cursor::{BindingDirection, DatatypeVariant, ParamType}; - use crate::env::validate::package::PackageBuilder; - use crate::env::MemArea; use crate::parser::Parser; - use crate::types::Location; + use crate::validate::package::PackageBuilder; + use crate::{BindingDirection, DatatypeVariant, Location, MemArea, ParamType}; fn mod_syntax(syntax: &str) -> Result { let mut parser = Parser::new(syntax); let decls = parser.match_decls().expect("parses"); diff --git a/lucet-idl/src/env/validate/names.rs b/lucet-idl/src/validate/names.rs similarity index 96% rename from lucet-idl/src/env/validate/names.rs rename to lucet-idl/src/validate/names.rs index fab293e45..939d0b4c2 100644 --- a/lucet-idl/src/env/validate/names.rs +++ b/lucet-idl/src/validate/names.rs @@ -1,7 +1,6 @@ -use crate::env::repr::{DatatypeIdent, DatatypeIx, FuncIx, ModuleIx}; -use crate::error::ValidationError; use crate::parser::SyntaxTypeRef; -use crate::types::Location; +use crate::repr::{DatatypeIdent, DatatypeIx, FuncIx, ModuleIx}; +use crate::{Location, ValidationError}; use cranelift_entity::PrimaryMap; use std::collections::HashMap; diff --git a/lucet-idl/src/env/validate/package.rs b/lucet-idl/src/validate/package.rs similarity index 97% rename from lucet-idl/src/env/validate/package.rs rename to lucet-idl/src/validate/package.rs index 9630fc798..cf3d83f67 100644 --- a/lucet-idl/src/env/validate/package.rs +++ b/lucet-idl/src/validate/package.rs @@ -1,10 +1,10 @@ #![allow(unused)] use super::module::module_from_declarations; -use crate::env::prelude::std_module; -use crate::env::repr::{ModuleIx, ModuleRepr, PackageRepr}; use crate::error::ValidationError; use crate::parser::SyntaxDecl; -use crate::types::Location; +use crate::prelude::std_module; +use crate::repr::{ModuleIx, ModuleRepr, PackageRepr}; +use crate::Location; use cranelift_entity::PrimaryMap; use std::collections::HashMap; @@ -97,8 +97,8 @@ impl PackageBuilder { #[cfg(test)] mod test { use super::*; - use crate::env::cursor::Package; use crate::parser::Parser; + use crate::Package; fn pkg_(syntax: &str) -> Result { let mut parser = Parser::new(syntax); From 63183b6740f910815c53c16ef1dff1a5d7616c55 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 1 Aug 2019 16:57:10 -0700 Subject: [PATCH 325/512] lucet-idl: a PackageRepr is a Package now unboxing it fixed our lifetime problems --- lucet-idl/src/cursor.rs | 60 ++++++++++++----------------- lucet-idl/src/error.rs | 1 - lucet-idl/src/lib.rs | 6 +-- lucet-idl/src/prelude.rs | 5 +-- lucet-idl/src/repr.rs | 2 +- lucet-idl/src/validate/datatypes.rs | 9 +++-- lucet-idl/src/validate/module.rs | 55 +++++++++++++------------- lucet-idl/src/validate/package.rs | 26 +++++-------- 8 files changed, 70 insertions(+), 94 deletions(-) diff --git a/lucet-idl/src/cursor.rs b/lucet-idl/src/cursor.rs index 362184ec7..11736e999 100644 --- a/lucet-idl/src/cursor.rs +++ b/lucet-idl/src/cursor.rs @@ -1,48 +1,34 @@ pub use crate::atoms::{AbiType, AtomType}; use crate::parser::SyntaxTypeRef; -pub use crate::repr::BindingDirection; use crate::repr::{ AliasDatatypeRepr, BindingFromRepr, BindingIx, BindingRepr, DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, EnumDatatypeRepr, FuncIdent, FuncIx, FuncRepr, ModuleIx, - ModuleRepr, PackageRepr, ParamIx, ParamRepr, StructDatatypeRepr, StructMemberRepr, + ModuleRepr, ParamIx, ParamRepr, StructDatatypeRepr, StructMemberRepr, }; +pub use crate::repr::{BindingDirection, Package}; use crate::MemArea; -#[derive(Debug, Clone)] -pub struct Package<'a> { - repr: &'a PackageRepr, -} - -impl<'a> Package<'a> { - pub fn new(repr: &'a PackageRepr) -> Package<'a> { - Package { repr } - } - - pub fn module(&self, name: &str) -> Option> { - self.repr - .names +impl Package { + pub fn module<'a>(&'a self, name: &str) -> Option> { + self.names .iter() .find(|(_, n)| *n == name) .and_then(|(ix, _)| self.module_by_ix(ix)) } - pub fn modules(&self) -> impl Iterator> { - let pkg = self.repr; - self.repr.names.keys().map(move |ix| Module { pkg, ix }) + pub fn modules<'a>(&'a self) -> impl Iterator> + 'a { + self.names.keys().map(move |ix| Module { pkg: &self, ix }) } - pub fn module_by_ix(&self, ix: ModuleIx) -> Option> { - if self.repr.modules.is_valid(ix) { - Some(Module { - pkg: &self.repr, - ix, - }) + pub fn module_by_ix<'a>(&'a self, ix: ModuleIx) -> Option> { + if self.modules.is_valid(ix) { + Some(Module { pkg: &self, ix }) } else { None } } - pub fn datatype_by_id(&self, id: DatatypeIdent) -> Option> { + pub fn datatype_by_id<'a>(&'a self, id: DatatypeIdent) -> Option> { self.module_by_ix(id.module) .and_then(|m| m.datatype_by_ix(id.datatype)) } @@ -50,7 +36,7 @@ impl<'a> Package<'a> { #[derive(Debug, Clone)] pub struct Module<'a> { - pkg: &'a PackageRepr, + pkg: &'a Package, ix: ModuleIx, } @@ -59,8 +45,8 @@ impl<'a> Module<'a> { self.pkg.modules.get(self.ix).expect("i exist") } - pub fn package(&self) -> Package<'a> { - Package { repr: self.pkg } + pub fn package(&self) -> &'a Package { + self.pkg } pub fn name(&self) -> &str { @@ -140,7 +126,7 @@ impl<'a> Module<'a> { #[derive(Debug, Clone)] pub struct Datatype<'a> { - pkg: &'a PackageRepr, + pkg: &'a Package, id: DatatypeIdent, } @@ -252,7 +238,7 @@ impl<'a> DatatypeVariant<'a> { #[derive(Debug, Clone)] pub struct StructDatatype<'a> { - pkg: &'a PackageRepr, + pkg: &'a Package, repr: &'a StructDatatypeRepr, id: DatatypeIdent, } @@ -294,7 +280,7 @@ impl<'a> From> for Datatype<'a> { #[derive(Debug, Clone)] pub struct StructMember<'a> { - pkg: &'a PackageRepr, + pkg: &'a Package, repr: &'a StructMemberRepr, } @@ -315,7 +301,7 @@ impl<'a> StructMember<'a> { #[derive(Debug, Clone)] pub struct EnumDatatype<'a> { - pkg: &'a PackageRepr, + pkg: &'a Package, repr: &'a EnumDatatypeRepr, id: DatatypeIdent, } @@ -371,7 +357,7 @@ impl<'a> EnumMember<'a> { #[derive(Debug, Clone)] pub struct AliasDatatype<'a> { - pkg: &'a PackageRepr, + pkg: &'a Package, repr: &'a AliasDatatypeRepr, id: DatatypeIdent, } @@ -403,7 +389,7 @@ impl<'a> From> for Datatype<'a> { #[derive(Debug, Clone)] pub struct Function<'a> { - pkg: &'a PackageRepr, + pkg: &'a Package, id: FuncIdent, } @@ -508,7 +494,8 @@ impl<'a> FuncParam<'a> { self.repr().type_ } pub fn type_(&self) -> Datatype<'a> { - Package::new(self.func.pkg) + self.func + .pkg .datatype_by_id(AtomType::from(self.repr().type_).datatype_id()) .expect("valid type") } @@ -547,7 +534,8 @@ impl<'a> FuncBinding<'a> { &self.repr().name } pub fn type_(&self) -> Datatype<'a> { - Package::new(self.func.pkg) + self.func + .pkg .datatype_by_id(self.repr().type_) .expect("valid type") } diff --git a/lucet-idl/src/error.rs b/lucet-idl/src/error.rs index d28f1b41d..82bd91643 100644 --- a/lucet-idl/src/error.rs +++ b/lucet-idl/src/error.rs @@ -4,7 +4,6 @@ use std::error::Error; use std::fmt; use std::io; -#[allow(dead_code)] #[derive(Debug, Fail)] pub enum IDLError { #[fail(display = "Internal error: {}", _0)] diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 0bcd510b7..27bdec06b 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -20,7 +20,6 @@ mod pretty_writer; pub use crate::config::{Backend, Config}; pub use crate::cursor::*; pub use crate::error::{IDLError, ValidationError}; -pub use crate::repr::{BindingDirection, PackageRepr}; pub use crate::{AbiType, AtomType}; //use crate::c::CGenerator; @@ -41,7 +40,7 @@ pub trait MemArea { fn mem_align(&self) -> usize; } -pub fn parse_package(input: &str) -> Result { +pub fn parse_package(input: &str) -> Result { let mut parser = Parser::new(&input); let decls = parser.match_decls()?; let pkg = package_from_declarations(&decls)?; @@ -59,8 +58,7 @@ pub fn codegen(package: &Package, config: &Config, output: Box) -> Re } pub fn run(config: &Config, input: &str, output: Box) -> Result<(), IDLError> { - let pkg_repr = parse_package(input)?; - let pkg = Package::new(&pkg_repr); + let pkg = parse_package(input)?; codegen(&pkg, config, output) } diff --git a/lucet-idl/src/prelude.rs b/lucet-idl/src/prelude.rs index c6276f501..b9f99c725 100644 --- a/lucet-idl/src/prelude.rs +++ b/lucet-idl/src/prelude.rs @@ -74,7 +74,7 @@ mod test { use super::std_module; use crate::atoms::AtomType; use crate::cursor::Package; - use crate::repr::{DatatypeIdent, PackageRepr}; + use crate::repr::{DatatypeIdent, Package}; use cranelift_entity::PrimaryMap; #[test] fn atom_idents() { @@ -84,8 +84,7 @@ mod test { names.push("std".to_owned()); let mut modules = PrimaryMap::new(); modules.push(std_module()); - let pkg_repr = PackageRepr { names, modules }; - let prelude = Package::new(&pkg_repr); + let prelude = Package { names, modules }; fn lookup_atom_by_id(package: &Package, ident: DatatypeIdent) -> AtomType { let dt = package.datatype_by_id(ident).expect("get by id"); diff --git a/lucet-idl/src/repr.rs b/lucet-idl/src/repr.rs index f7e6f070c..d85c0bee4 100644 --- a/lucet-idl/src/repr.rs +++ b/lucet-idl/src/repr.rs @@ -6,7 +6,7 @@ pub struct ModuleIx(u32); entity_impl!(ModuleIx); #[derive(Debug, Clone)] -pub struct PackageRepr { +pub struct Package { pub(crate) names: PrimaryMap, pub(crate) modules: PrimaryMap, } diff --git a/lucet-idl/src/validate/datatypes.rs b/lucet-idl/src/validate/datatypes.rs index cb9e20a68..52e69ff66 100644 --- a/lucet-idl/src/validate/datatypes.rs +++ b/lucet-idl/src/validate/datatypes.rs @@ -4,9 +4,10 @@ use crate::parser::{ }; use crate::repr::{ AliasDatatypeRepr, DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, - EnumDatatypeRepr, EnumMemberRepr, ModuleDatatypesRepr, StructDatatypeRepr, StructMemberRepr, + EnumDatatypeRepr, EnumMemberRepr, ModuleDatatypesRepr, Package, StructDatatypeRepr, + StructMemberRepr, }; -use crate::{AtomType, Location, MemArea, Package, ValidationError}; +use crate::{AtomType, Location, MemArea, ValidationError}; use cranelift_entity::{PrimaryMap, SecondaryMap}; use std::collections::HashMap; @@ -46,13 +47,13 @@ enum VariantIR { #[derive(Clone)] pub struct DatatypeModuleBuilder<'a> { - env: Package<'a>, + env: &'a Package, names: &'a ModNamesBuilder, types: PrimaryMap, } impl<'a> DatatypeModuleBuilder<'a> { - pub fn new(env: Package<'a>, names: &'a ModNamesBuilder) -> Self { + pub fn new(env: &'a Package, names: &'a ModNamesBuilder) -> Self { Self { env, names, diff --git a/lucet-idl/src/validate/module.rs b/lucet-idl/src/validate/module.rs index ec2c58e05..105007907 100644 --- a/lucet-idl/src/validate/module.rs +++ b/lucet-idl/src/validate/module.rs @@ -2,11 +2,11 @@ use super::datatypes::DatatypeModuleBuilder; use super::function::FunctionModuleBuilder; use super::names::ModNamesBuilder; use crate::parser::SyntaxDecl; -use crate::repr::{ModuleIx, ModuleRepr, PackageRepr}; +use crate::repr::{ModuleIx, ModuleRepr}; use crate::{Package, ValidationError}; pub fn module_from_declarations( - env: &PackageRepr, + env: &Package, ix: ModuleIx, decls: &[SyntaxDecl], ) -> Result { @@ -30,8 +30,7 @@ pub fn module_from_declarations( } // Datatypes are defined in terms of the parent environment: - let data_env = Package::new(env); - let mut datatypes_builder = DatatypeModuleBuilder::new(data_env, &names); + let mut datatypes_builder = DatatypeModuleBuilder::new(env, &names); // Then, we can define each datatype for decl in decls.iter() { @@ -69,7 +68,7 @@ pub fn module_from_declarations( funcs_env_repr .modules .push(ModuleRepr::from_datatypes(datatypes_module.clone())); - let funcs_env = Package::new(&funcs_env_repr).module_by_ix(ix).unwrap(); + let funcs_env = funcs_env_repr.module_by_ix(ix).unwrap(); // Now we can define each function: let mut funcs_builder = FunctionModuleBuilder::new(funcs_env, &names); @@ -101,7 +100,7 @@ mod tests { use crate::parser::Parser; use crate::validate::package::PackageBuilder; use crate::{BindingDirection, DatatypeVariant, Location, MemArea, ParamType}; - fn mod_syntax(syntax: &str) -> Result { + fn mod_syntax(syntax: &str) -> Result { let mut parser = Parser::new(syntax); let decls = parser.match_decls().expect("parses"); @@ -123,7 +122,7 @@ mod tests { #[test] fn struct_two_atoms() { let pkg_r = mod_syntax("struct foo { a: i32, b: f32 }").expect("valid"); - let module = Package::new(&pkg_r).module("mod").unwrap(); + let module = pkg_r.module("mod").unwrap(); let foo = module.datatype("foo").expect("foo datatype defined"); assert_eq!(foo.mem_size(), 8); assert_eq!(foo.mem_align(), 4); @@ -230,8 +229,8 @@ mod tests { assert!(mod_syntax("enum foo { a, b }").is_ok()); { - let pkg_repr = mod_syntax("enum foo { a, b }").expect("valid syntax"); - let m = Package::new(&pkg_repr).module("mod").expect("get module"); + let pkg = mod_syntax("enum foo { a, b }").expect("valid syntax"); + let m = pkg.module("mod").expect("get module"); let foo = m.datatype("foo").expect("get foo"); match foo.variant() { DatatypeVariant::Enum(e) => { @@ -284,8 +283,8 @@ mod tests { assert!(mod_syntax("type foo = u8;").is_ok()); assert!(mod_syntax("type link = u32;\nstruct list { next: link, thing: i32 }").is_ok()); - let pkg_repr = mod_syntax("type foo = bar;\nenum bar { a }").expect("valid"); - let m = Package::new(&pkg_repr).module("mod").expect("get module"); + let pkg = mod_syntax("type foo = bar;\nenum bar { a }").expect("valid"); + let m = pkg.module("mod").expect("get module"); let foo = m.datatype("foo").expect("get foo"); match foo.variant() { @@ -332,8 +331,8 @@ mod tests { #[test] fn func_trivial() { - let pkg_repr = mod_syntax("fn foo();").expect("valid module"); - let m = Package::new(&pkg_repr).module("mod").expect("get module"); + let pkg = mod_syntax("fn foo();").expect("valid module"); + let m = pkg.module("mod").expect("get module"); let foo = m.function("foo").expect("get foo"); assert_eq!(foo.name(), "foo"); assert_eq!(foo.params().collect::>().len(), 0); @@ -342,8 +341,8 @@ mod tests { #[test] fn func_one_arg() { - let pkg_repr = mod_syntax("fn foo(a: i64);").expect("valid module"); - let m = Package::new(&pkg_repr).module("mod").expect("get module"); + let pkg = mod_syntax("fn foo(a: i64);").expect("valid module"); + let m = pkg.module("mod").expect("get module"); let foo = m.function("foo").expect("get foo"); assert_eq!(foo.args().collect::>().len(), 1); @@ -366,8 +365,8 @@ mod tests { #[test] fn func_one_ret() { - let pkg_repr = mod_syntax("fn foo() -> r: i64;").expect("valid module"); - let m = Package::new(&pkg_repr).module("mod").expect("get module"); + let pkg = mod_syntax("fn foo() -> r: i64;").expect("valid module"); + let m = pkg.module("mod").expect("get module"); let foo = m.function("foo").expect("get foo"); assert_eq!(foo.rets().collect::>().len(), 1); @@ -421,8 +420,8 @@ mod tests { #[test] fn func_one_arg_value_binding() { - let pkg_repr = mod_syntax("fn foo(a: i32) where\na_binding: in i8 <- a;").expect("valid"); - let m = Package::new(&pkg_repr).module("mod").expect("get module"); + let pkg = mod_syntax("fn foo(a: i32) where\na_binding: in i8 <- a;").expect("valid"); + let m = pkg.module("mod").expect("get module"); let foo = m.function("foo").expect("get foo"); assert_eq!(foo.args().collect::>().len(), 1); @@ -442,9 +441,8 @@ mod tests { #[test] fn func_one_arg_ptr_binding() { - let pkg_repr = - mod_syntax("fn foo(a: i32) where\na_binding: inout i8 <- *a;").expect("valid"); - let m = Package::new(&pkg_repr).module("mod").expect("get module"); + let pkg = mod_syntax("fn foo(a: i32) where\na_binding: inout i8 <- *a;").expect("valid"); + let m = pkg.module("mod").expect("get module"); let foo = m.function("foo").expect("get foo"); assert_eq!(foo.args().collect::>().len(), 1); @@ -531,10 +529,9 @@ mod tests { #[test] fn func_one_ret_value_binding() { - let pkg_repr = - mod_syntax("fn foo() -> a: i32 where\na_binding: out i8 <- a;").expect("valid"); + let pkg = mod_syntax("fn foo() -> a: i32 where\na_binding: out i8 <- a;").expect("valid"); - let m = Package::new(&pkg_repr).module("mod").expect("get module"); + let m = pkg.module("mod").expect("get module"); let foo = m.function("foo").expect("get foo"); assert_eq!(foo.rets().collect::>().len(), 1); @@ -580,11 +577,11 @@ mod tests { #[test] fn func_two_arg_slice_binding() { - let pkg_repr = mod_syntax( + let pkg = mod_syntax( "fn foo(a_ptr: i32, a_len: i32) where\na_binding: inout i8 <- [a_ptr, a_len];", ) .expect("valid"); - let m = Package::new(&pkg_repr).module("mod").expect("get module"); + let m = pkg.module("mod").expect("get module"); let foo = m.function("foo").expect("get foo"); assert_eq!(foo.args().collect::>().len(), 2); @@ -609,7 +606,7 @@ mod tests { #[test] fn func_buncha_bindings() { - let pkg_repr = mod_syntax( + let pkg = mod_syntax( "fn nontrivial(a: i32, b: i32, c: f32) -> d: i32 where\n\ a_binding: out u8 <- *a,\n\ b_binding: inout u16 <- *b,\n\ @@ -619,7 +616,7 @@ mod tests { ) .expect("valid"); - let m = Package::new(&pkg_repr).module("mod").expect("get module"); + let m = pkg.module("mod").expect("get module"); let nontrivial = m.function("nontrivial").expect("get nontrivial"); assert_eq!(nontrivial.args().collect::>().len(), 3); diff --git a/lucet-idl/src/validate/package.rs b/lucet-idl/src/validate/package.rs index cf3d83f67..b51b91015 100644 --- a/lucet-idl/src/validate/package.rs +++ b/lucet-idl/src/validate/package.rs @@ -1,16 +1,13 @@ -#![allow(unused)] use super::module::module_from_declarations; use crate::error::ValidationError; use crate::parser::SyntaxDecl; use crate::prelude::std_module; -use crate::repr::{ModuleIx, ModuleRepr, PackageRepr}; +use crate::repr::{ModuleIx, ModuleRepr, Package}; use crate::Location; use cranelift_entity::PrimaryMap; use std::collections::HashMap; -pub fn package_from_declarations( - package_decls: &[SyntaxDecl], -) -> Result { +pub fn package_from_declarations(package_decls: &[SyntaxDecl]) -> Result { let mut pkg = PackageBuilder::new(); for decl in package_decls { match decl { @@ -34,12 +31,12 @@ pub fn package_from_declarations( pub struct PackageBuilder { name_decls: HashMap)>, - repr: PackageRepr, + repr: Package, } impl PackageBuilder { pub fn new() -> Self { - let mut repr = PackageRepr { + let mut repr = Package { names: PrimaryMap::new(), modules: PrimaryMap::new(), }; @@ -79,7 +76,7 @@ impl PackageBuilder { Ok(ix) } - pub fn repr(&self) -> &PackageRepr { + pub fn repr(&self) -> &Package { &self.repr } @@ -89,7 +86,7 @@ impl PackageBuilder { assert_eq!(ix, pushed_ix); } - pub fn build(self) -> PackageRepr { + pub fn build(self) -> Package { self.repr } } @@ -100,7 +97,7 @@ mod test { use crate::parser::Parser; use crate::Package; - fn pkg_(syntax: &str) -> Result { + fn pkg_(syntax: &str) -> Result { let mut parser = Parser::new(syntax); let decls = parser.match_decls().expect("parses"); package_from_declarations(&decls) @@ -108,8 +105,7 @@ mod test { #[test] fn one_empty_mod() { - let repr = pkg_("mod empty {}").expect("valid package"); - let pkg = Package::new(&repr); + let pkg = pkg_("mod empty {}").expect("valid package"); let empty = pkg.module("empty").expect("mod empty exists"); assert_eq!(empty.name(), "empty"); assert_eq!(empty.datatypes().collect::>().len(), 0); @@ -118,8 +114,7 @@ mod test { #[test] fn multiple_empty_mod() { - let repr = pkg_("mod empty1 {} mod empty2{}mod\nempty3{//\n}").expect("valid package"); - let pkg = Package::new(&repr); + let pkg = pkg_("mod empty1 {} mod empty2{}mod\nempty3{//\n}").expect("valid package"); let _ = pkg.module("empty1").expect("mod empty1 exists"); let _ = pkg.module("empty2").expect("mod empty2 exists"); let _ = pkg.module("empty3").expect("mod empty3 exists"); @@ -127,8 +122,7 @@ mod test { #[test] fn mod_with_a_type() { - let repr = pkg_("mod foo { type bar = u8; }").expect("valid package"); - let pkg = Package::new(&repr); + let pkg = pkg_("mod foo { type bar = u8; }").expect("valid package"); let foo = pkg.module("foo").expect("mod foo exists"); let _bar = foo.datatype("bar").expect("foo::bar exists"); } From 58c0964cb712e47b4c30f88e185af1f81cbd7001 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 1 Aug 2019 18:03:25 -0700 Subject: [PATCH 326/512] lucet-idl: c generator turned on again and it looks SO MUCH NICER dont you think?? --- lucet-idl/src/c.rs | 234 ++++++++++++------------------- lucet-idl/src/cursor.rs | 29 +++- lucet-idl/src/lib.rs | 14 +- lucet-idl/src/parser.rs | 15 -- lucet-idl/src/prelude.rs | 1 - lucet-idl/src/validate/module.rs | 4 +- 6 files changed, 126 insertions(+), 171 deletions(-) diff --git a/lucet-idl/src/c.rs b/lucet-idl/src/c.rs index 71bd796dd..e93231cc8 100644 --- a/lucet-idl/src/c.rs +++ b/lucet-idl/src/c.rs @@ -1,16 +1,9 @@ -#![allow(dead_code)] -#![allow(unused_variables)] - -use crate::error::IDLError; -use crate::function::FuncDecl; -use crate::module::Module; -use crate::package::Package; use crate::pretty_writer::PrettyWriter; -use crate::types::{ - AbiType, AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, Named, - StructDataType, +use crate::{ + AbiType, AliasDatatype, AtomType, Datatype, DatatypeVariant, EnumDatatype, Function, IDLError, + MemArea, Package, StructDatatype, }; -use std::io::prelude::*; +use std::io::Write; /// Generator for the C backend pub struct CGenerator { @@ -33,44 +26,43 @@ impl CGenerator { } pub fn generate_guest(&mut self, package: &Package) -> Result<(), IDLError> { - for (_ident, module) in package.modules.iter() { - for ref dt in module.datatypes() { - self.gen_type_header(module, dt)?; - match &dt.entity.variant { - DataTypeVariant::Struct(s) => self.gen_struct(module, dt, s)?, - DataTypeVariant::Alias(a) => self.gen_alias(module, dt, a)?, - DataTypeVariant::Enum(e) => self.gen_enum(module, dt, e)?, + for module in package.modules() { + if module.name() == "std" { + continue; + } + for dt in module.datatypes() { + self.gen_type_header(&dt)?; + match dt.variant() { + DatatypeVariant::Struct(s) => self.gen_struct(&s)?, + DatatypeVariant::Alias(a) => self.gen_alias(&a)?, + DatatypeVariant::Enum(e) => self.gen_enum(&e)?, + DatatypeVariant::Atom(_) => unreachable!(), } } - for fdecl in module.func_decls() { - self.gen_function(module, &fdecl)?; + for func in module.functions() { + self.gen_function(&func)?; } } Ok(()) } - fn gen_type_header(&mut self, _module: &Module, dt: &Named) -> Result<(), IDLError> { + fn gen_type_header(&mut self, dt: &Datatype) -> Result<(), IDLError> { self.w .eob() - .writeln(format!("// ---------- {} ----------", dt.name.name)) + .writeln(format!("// ---------- {} ----------", dt.name())) .eob(); Ok(()) } // The most important thing in alias generation is to cache the size // and alignment rules of what it ultimately points to - fn gen_alias( - &mut self, - module: &Module, - dt: &Named, - alias: &AliasDataType, - ) -> Result<(), IDLError> { - let dtname = self.type_name(dt); + fn gen_alias(&mut self, alias: &AliasDatatype) -> Result<(), IDLError> { + let own_type_name = Datatype::from(alias.clone()).c_type_name(); self.w .writeln(format!( "typedef {} {};", - self.type_ref_name(module, &alias.to), - dtname + alias.to().c_type_name(), + own_type_name, )) .eob(); @@ -78,190 +70,142 @@ impl CGenerator { self.w .writeln(format!( "_Static_assert(sizeof({}) == {}, \"unexpected alias size\");", - dtname, dt.entity.repr_size + own_type_name, + alias.mem_size(), )) .eob(); Ok(()) } - fn gen_struct( - &mut self, - module: &Module, - dt: &Named, - struct_: &StructDataType, - ) -> Result<(), IDLError> { - let dtname = self.type_name(dt); - self.w.writeln(format!("{} {{", dtname)); + fn gen_struct(&mut self, struct_: &StructDatatype) -> Result<(), IDLError> { + let own_type_name = Datatype::from(struct_.clone()).c_type_name(); + self.w.writeln(format!("{} {{", own_type_name)); let mut w_block = self.w.new_block(); - for member in struct_.members.iter() { + for member in struct_.members() { w_block.writeln(format!( "{} {};", - self.type_ref_name(module, &member.type_), - member.name + member.type_().c_type_name(), + member.name(), )); } self.w.writeln("};").eob(); // Skip the first member, as it will always be at the beginning of the structure - for (i, member) in struct_.members.iter().enumerate().skip(1) { + for member in struct_.members().skip(1) { self.w.writeln(format!( "_Static_assert(offsetof({}, {}) == {}, \"unexpected offset\");", - dtname, member.name, member.offset + own_type_name, + member.name(), + member.offset() )); } - let struct_size = dt.entity.repr_size; self.w .writeln(format!( "_Static_assert(sizeof({}) == {}, \"unexpected structure size\");", - dtname, struct_size, + own_type_name, + struct_.mem_size(), )) .eob(); - Ok(()) } // Enums generate both a specific typedef, and a traditional C-style enum // The typedef is required to use a native type which is consistent across all architectures - fn gen_enum( - &mut self, - module: &Module, - dt: &Named, - enum_: &EnumDataType, - ) -> Result<(), IDLError> { - let dtname = self.type_name(dt); - let type_size = dt.entity.repr_size; - self.w.writeln(format!("{} {{", dtname)); - let mut pretty_writer_i1 = self.w.new_block(); - for (i, named_member) in enum_.members.iter().enumerate() { - pretty_writer_i1.writeln(format!( + fn gen_enum(&mut self, enum_: &EnumDatatype) -> Result<(), IDLError> { + let own_type_name = Datatype::from(enum_.clone()).c_type_name(); + self.w.writeln(format!("{} {{", own_type_name)); + let mut w = self.w.new_block(); + for variant in enum_.variants() { + w.writeln(format!( "{}, // {}", - macro_for(&dt.name.name, &named_member.name), - i + macro_for(enum_.name(), variant.name()), + variant.index(), )); } self.w.writeln("};").eob(); self.w .writeln(format!( "_Static_assert(sizeof({}) == {}, \"unexpected enumeration size\");", - dtname, type_size + own_type_name, + enum_.mem_size(), )) .eob(); Ok(()) } /// Currently support generating ABI level definition for C guests. Bindings not supported. - fn gen_function(&mut self, _module: &Module, func: &Named) -> Result<(), IDLError> { - let func = func.entity; - - let return_decl = match func.rets.len() { - 0 => "void", - 1 => abi_type_name(&func.rets[0].type_), + fn gen_function(&mut self, func: &Function) -> Result<(), IDLError> { + let rets = func.rets().collect::>(); + let return_decl = match rets.len() { + 0 => "void".to_owned(), + 1 => rets[0].type_().c_type_name(), _ => unreachable!("functions limited to 0 or 1 return arguments"), }; let arg_list = func - .args - .iter() - .map(|a| format!("{} {}", abi_type_name(&a.type_), a.name)) + .args() + .map(|a| format!("{} {}", a.type_().c_type_name(), a.name())) .collect::>() .join(", "); self.w.writeln(format!( "extern {} {}({});", - return_decl, func.field_name, arg_list, + return_decl, + func.name(), + arg_list, )); Ok(()) } +} - // Return `true` if the type is an atom, an emum, or an alias to one of these - pub fn is_type_eventually_an_atom_or_enum(&self, module: &Module, type_: &DataTypeRef) -> bool { - let inner_type = match type_ { - DataTypeRef::Atom(_) => return true, - DataTypeRef::Defined(inner_type) => inner_type, - }; - let inner_data_type_entry = module.get_datatype(*inner_type).expect("defined datatype"); - match inner_data_type_entry.entity.variant { - DataTypeVariant::Struct { .. } => false, - DataTypeVariant::Enum { .. } => true, - DataTypeVariant::Alias(ref a) => self.is_type_eventually_an_atom_or_enum(module, &a.to), - } - } - - /// Return the type refererence, with aliases being resolved - pub fn unalias<'t>(&self, module: &'t Module, type_: &'t DataTypeRef) -> &'t DataTypeRef { - let inner_type = match type_ { - DataTypeRef::Atom(_) => return type_, - DataTypeRef::Defined(inner_type) => inner_type, - }; - let inner_data_type_entry = module.get_datatype(*inner_type).expect("defined datatype"); - if let DataTypeVariant::Alias(ref a) = inner_data_type_entry.entity.variant { - self.unalias(module, &a.to) - } else { - type_ - } - } - - fn type_name(&self, dt: &Named) -> String { - match dt.entity.variant { - DataTypeVariant::Struct(_) => format!("struct {}", dt.name.name), - DataTypeVariant::Enum(_) => format!("enum {}", dt.name.name), - DataTypeVariant::Alias(_) => format!("{}", dt.name.name), - } - } +trait CTypeName { + fn c_type_name(&self) -> String; +} - fn type_ref_name(&self, module: &Module, type_: &DataTypeRef) -> String { - match type_ { - DataTypeRef::Atom(a) => atom_type_name(a).to_owned(), - DataTypeRef::Defined(id) => { - let dt = &module.get_datatype(*id).expect("type_name of valid ref"); - self.type_name(dt) - } +impl CTypeName for AtomType { + fn c_type_name(&self) -> String { + match self { + AtomType::Bool => "bool", + AtomType::U8 => "uint8_t", + AtomType::U16 => "uint16_t", + AtomType::U32 => "uint32_t", + AtomType::U64 => "uint64_t", + AtomType::I8 => "int8_t", + AtomType::I16 => "int16_t", + AtomType::I32 => "int32_t", + AtomType::I64 => "int64_t", + AtomType::F32 => "float", + AtomType::F64 => "double", } + .to_owned() } } -fn abi_type_name(abi_type: &AbiType) -> &'static str { - match abi_type { - AbiType::I32 => atom_type_name(&AtomType::I32), - AbiType::I64 => atom_type_name(&AtomType::I64), - AbiType::F32 => atom_type_name(&AtomType::F32), - AbiType::F64 => atom_type_name(&AtomType::F64), +impl CTypeName for AbiType { + fn c_type_name(&self) -> String { + AtomType::from(self.clone()).c_type_name() } } -fn atom_type_name(atom_type: &AtomType) -> &'static str { - match atom_type { - AtomType::Bool => "bool", - AtomType::U8 => "uint8_t", - AtomType::U16 => "uint16_t", - AtomType::U32 => "uint32_t", - AtomType::U64 => "uint64_t", - AtomType::I8 => "int8_t", - AtomType::I16 => "int16_t", - AtomType::I32 => "int32_t", - AtomType::I64 => "int64_t", - AtomType::F32 => "float", - AtomType::F64 => "double", +impl CTypeName for Datatype<'_> { + fn c_type_name(&self) -> String { + match self.variant() { + DatatypeVariant::Struct(_) => format!("struct {}", self.name()), + DatatypeVariant::Enum(_) => format!("enum {}", self.name()), + DatatypeVariant::Alias(_) => self.name().to_owned(), + DatatypeVariant::Atom(a) => a.c_type_name(), + } } } fn macro_for(prefix: &str, name: &str) -> String { + use heck::ShoutySnakeCase; let mut macro_name = String::new(); macro_name.push_str(&prefix.to_uppercase()); macro_name.push('_'); - let mut previous_was_uppercase = name.chars().nth(0).expect("Empty name").is_uppercase(); - for c in name.chars() { - let is_uppercase = c.is_uppercase(); - if is_uppercase != previous_was_uppercase { - macro_name.push('_'); - } - for uc in c.to_uppercase() { - macro_name.push(uc); - } - previous_was_uppercase = is_uppercase; - } + macro_name.push_str(&name.to_shouty_snake_case()); macro_name } diff --git a/lucet-idl/src/cursor.rs b/lucet-idl/src/cursor.rs index 11736e999..2bb83cbbd 100644 --- a/lucet-idl/src/cursor.rs +++ b/lucet-idl/src/cursor.rs @@ -278,6 +278,15 @@ impl<'a> From> for Datatype<'a> { } } +impl<'a> MemArea for StructDatatype<'a> { + fn mem_size(&self) -> usize { + Datatype::from(self.clone()).mem_size() + } + fn mem_align(&self) -> usize { + Datatype::from(self.clone()).mem_align() + } +} + #[derive(Debug, Clone)] pub struct StructMember<'a> { pkg: &'a Package, @@ -338,6 +347,15 @@ impl<'a> From> for Datatype<'a> { } } +impl<'a> MemArea for EnumDatatype<'a> { + fn mem_size(&self) -> usize { + Datatype::from(self.clone()).mem_size() + } + fn mem_align(&self) -> usize { + Datatype::from(self.clone()).mem_align() + } +} + pub struct EnumMember<'a> { repr: EnumDatatype<'a>, index: usize, @@ -350,7 +368,7 @@ impl<'a> EnumMember<'a> { pub fn name(&self) -> &str { &self.repr.repr.members[self.index].name } - pub fn value(&self) -> usize { + pub fn index(&self) -> usize { self.index } } @@ -387,6 +405,15 @@ impl<'a> From> for Datatype<'a> { } } +impl<'a> MemArea for AliasDatatype<'a> { + fn mem_size(&self) -> usize { + Datatype::from(self.clone()).mem_size() + } + fn mem_align(&self) -> usize { + Datatype::from(self.clone()).mem_align() + } +} + #[derive(Debug, Clone)] pub struct Function<'a> { pkg: &'a Package, diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 27bdec06b..37e22dd7e 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -4,17 +4,17 @@ extern crate failure; mod atoms; -mod cursor; -mod prelude; -mod repr; -mod validate; -//mod c; +mod c; mod config; +mod cursor; pub mod env; mod error; mod lexer; mod parser; +mod prelude; mod pretty_writer; +mod repr; +mod validate; //mod rust; pub use crate::config::{Backend, Config}; @@ -22,7 +22,7 @@ pub use crate::cursor::*; pub use crate::error::{IDLError, ValidationError}; pub use crate::{AbiType, AtomType}; -//use crate::c::CGenerator; +use crate::c::CGenerator; use crate::parser::Parser; //use crate::rust::RustGenerator; use crate::validate::package_from_declarations; @@ -49,7 +49,7 @@ pub fn parse_package(input: &str) -> Result { pub fn codegen(package: &Package, config: &Config, output: Box) -> Result<(), IDLError> { match config.backend { - Backend::CGuest => unimplemented!(), //CGenerator::new(output).generate_guest(package)?, + Backend::CGuest => CGenerator::new(output).generate_guest(package)?, Backend::RustGuest => unimplemented!(), //RustGenerator::new(output).generate_guest(package)?, Backend::RustHost => unimplemented!(), //RustGenerator::new(output).generate_host(package)?, Backend::Bindings => unimplemented!(), //generate_bindings(&package.bindings(), output)?, diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index 05f74e005..15101534c 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -35,15 +35,6 @@ pub enum SyntaxDecl { } impl SyntaxDecl { - pub fn name(&self) -> &str { - match self { - SyntaxDecl::Struct { name, .. } => &name, - SyntaxDecl::Enum { name, .. } => &name, - SyntaxDecl::Alias { name, .. } => &name, - SyntaxDecl::Module { name, .. } => &name, - SyntaxDecl::Function { name, .. } => &name, - } - } pub fn location(&self) -> &Location { match self { SyntaxDecl::Struct { location, .. } => &location, @@ -53,12 +44,6 @@ impl SyntaxDecl { SyntaxDecl::Function { location, .. } => &location, } } - pub fn is_datatype(&self) -> bool { - match self { - SyntaxDecl::Struct { .. } | SyntaxDecl::Enum { .. } | SyntaxDecl::Alias { .. } => true, - _ => false, - } - } } #[derive(Debug, PartialEq, Eq, Clone)] diff --git a/lucet-idl/src/prelude.rs b/lucet-idl/src/prelude.rs index b9f99c725..3348487b6 100644 --- a/lucet-idl/src/prelude.rs +++ b/lucet-idl/src/prelude.rs @@ -73,7 +73,6 @@ impl AtomType { mod test { use super::std_module; use crate::atoms::AtomType; - use crate::cursor::Package; use crate::repr::{DatatypeIdent, Package}; use cranelift_entity::PrimaryMap; #[test] diff --git a/lucet-idl/src/validate/module.rs b/lucet-idl/src/validate/module.rs index 105007907..8fcb7ea9d 100644 --- a/lucet-idl/src/validate/module.rs +++ b/lucet-idl/src/validate/module.rs @@ -237,10 +237,10 @@ mod tests { assert_eq!(e.variants().collect::>().len(), 2); let a = e.variant("a").expect("variant a exists"); assert_eq!(a.name(), "a"); - assert_eq!(a.value(), 0); + assert_eq!(a.index(), 0); let b = e.variant("b").expect("variant b exists"); assert_eq!(b.name(), "b"); - assert_eq!(b.value(), 1); + assert_eq!(b.index(), 1); } _ => panic!("foo is an enum!"), } From 42765e3eca97f029c98354a5d4d2b3012c40ab19 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 2 Aug 2019 12:50:49 -0700 Subject: [PATCH 327/512] lucet-idl: build out idiomatic func defintion in C! --- lucet-idl/src/c.rs | 140 +++++++++++++++++++++++++++++-- lucet-idl/src/cursor.rs | 7 ++ lucet-idl/src/pretty_writer.rs | 1 + lucet-idl/tests/example.idl | 6 +- lucet-idl/tests/example.rs | 24 +++--- lucet-idl/tests/example_driver.c | 16 ++++ 6 files changed, 176 insertions(+), 18 deletions(-) diff --git a/lucet-idl/src/c.rs b/lucet-idl/src/c.rs index e93231cc8..ec1003146 100644 --- a/lucet-idl/src/c.rs +++ b/lucet-idl/src/c.rs @@ -1,7 +1,7 @@ use crate::pretty_writer::PrettyWriter; use crate::{ - AbiType, AliasDatatype, AtomType, Datatype, DatatypeVariant, EnumDatatype, Function, IDLError, - MemArea, Package, StructDatatype, + AbiType, AliasDatatype, AtomType, BindingDirection, BindingParam, Datatype, DatatypeVariant, + EnumDatatype, FuncBinding, Function, IDLError, MemArea, Package, StructDatatype, }; use std::io::Write; @@ -40,7 +40,8 @@ impl CGenerator { } } for func in module.functions() { - self.gen_function(&func)?; + self.gen_abi_function(&func)?; + self.gen_idiomatic_function(&func)?; } } Ok(()) @@ -135,8 +136,7 @@ impl CGenerator { Ok(()) } - /// Currently support generating ABI level definition for C guests. Bindings not supported. - fn gen_function(&mut self, func: &Function) -> Result<(), IDLError> { + fn gen_abi_function(&mut self, func: &Function) -> Result<(), IDLError> { let rets = func.rets().collect::>(); let return_decl = match rets.len() { 0 => "void".to_owned(), @@ -151,14 +151,101 @@ impl CGenerator { .join(", "); self.w.writeln(format!( - "extern {} {}({});", + "extern {} {}({}) {};", return_decl, - func.name(), + func.c_abi_func_name(), arg_list, + func.c_abi_func_attributes(), )); Ok(()) } + + fn gen_idiomatic_function(&mut self, func: &Function) -> Result<(), IDLError> { + let ret_bindings = func.c_ret_bindings().collect::>(); + + let own_return_decl = match ret_bindings.len() { + 0 => "void".to_owned(), + 1 => ret_bindings[0].type_().c_type_name(), + _ => unreachable!("functions limited to 0 or 1 return arguments"), + }; + + let own_arg_list = func + .c_arg_bindings() + .map(|b| match b.param() { + BindingParam::Ptr(_p) => format!( + "{}{}* {}", + b.c_constness(), + b.type_().c_type_name(), + b.name() + ), + BindingParam::Slice(_ptr, _len) => format!( + "{}{}* {}_ptr, size_t {}_len", + b.c_constness(), + b.type_().c_type_name(), + b.name(), + b.name(), + ), + BindingParam::Value(_v) => format!("{} {}", b.type_().c_type_name(), b.name(),), + }) + .collect::>() + .join(", "); + + self.w.writeln(format!( + "{} {}({}) {{", + own_return_decl, + func.c_idiomatic_func_name(), + own_arg_list, + )); + { + let arg_bindings = func + .c_arg_bindings() + .map(|b| match b.param() { + BindingParam::Ptr(p) => format!("({}) {}", p.type_().c_type_name(), b.name()), + BindingParam::Slice(p, l) => format!( + "({}) {}_ptr, ({}) {}_len", + p.type_().c_type_name(), + b.name(), + l.type_().c_type_name(), + b.name() + ), + BindingParam::Value(v) => format!("({}) {}", v.type_().c_type_name(), b.name()), + }) + .collect::>() + .join(", "); + + let (ret_capture, ret_statement) = match ret_bindings.len() { + 0 => (format!(""), format!("return;")), + 1 => { + let b = &ret_bindings[0]; + match b.param() { + BindingParam::Ptr(p) => ( + format!("{} {} = ", p.type_().c_type_name(), p.name()), + format!("return (*{}) {};", b.type_().c_type_name(), p.name()), + ), + BindingParam::Value(v) => ( + format!("{} {} = ", v.type_().c_type_name(), v.name()), + format!("return ({}) {};", b.type_().c_type_name(), v.name()), + ), + BindingParam::Slice { .. } => unreachable!(), + } + } + _ => unreachable!(), + }; + + let mut w = self.w.new_block(); + w.writeln(format!( + "{}{}({});", + ret_capture, + func.c_abi_func_name(), + arg_bindings, + )); + w.writeln(ret_statement); + } + self.w.eob().writeln("}"); + + Ok(()) + } } trait CTypeName { @@ -209,3 +296,42 @@ fn macro_for(prefix: &str, name: &str) -> String { macro_name.push_str(&name.to_shouty_snake_case()); macro_name } + +impl Function<'_> { + fn c_abi_func_name(&self) -> String { + format!("_{}_{}", self.module().name(), self.name()) + } + fn c_abi_func_attributes(&self) -> String { + format!( + "__attribute__((import_module(\"{}\"),import_name(\"{}\")))", + self.module().name(), + self.name() + ) + } + fn c_idiomatic_func_name(&self) -> String { + format!("{}_{}", self.module().name(), self.name()) + } + + fn c_arg_bindings<'a>(&'a self) -> impl Iterator> { + self.bindings().filter(|b| !binding_is_ret(b)) + } + fn c_ret_bindings<'a>(&'a self) -> impl Iterator> { + self.bindings().filter(|b| binding_is_ret(b)) + } +} + +fn binding_is_ret(b: &FuncBinding) -> bool { + b.direction() == BindingDirection::Out && b.param().value().is_some() +} + +impl FuncBinding<'_> { + fn c_constness(&self) -> String { + if self.direction() == BindingDirection::In + && (self.param().ptr().is_some() || self.param().slice().is_some()) + { + "const ".to_owned() + } else { + "".to_owned() + } + } +} diff --git a/lucet-idl/src/cursor.rs b/lucet-idl/src/cursor.rs index 2bb83cbbd..a48c1f0cd 100644 --- a/lucet-idl/src/cursor.rs +++ b/lucet-idl/src/cursor.rs @@ -493,6 +493,13 @@ impl<'a> Function<'a> { ix, }) } + + pub fn module(&self) -> Module<'a> { + Module { + pkg: self.pkg, + ix: self.id.module, + } + } } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/lucet-idl/src/pretty_writer.rs b/lucet-idl/src/pretty_writer.rs index 0a6e54f23..f061b72eb 100644 --- a/lucet-idl/src/pretty_writer.rs +++ b/lucet-idl/src/pretty_writer.rs @@ -1,3 +1,4 @@ +#![allow(unused)] use std::cell::RefCell; use std::io::prelude::*; use std::rc::Rc; diff --git a/lucet-idl/tests/example.idl b/lucet-idl/tests/example.idl index d6c864272..e44f72f29 100644 --- a/lucet-idl/tests/example.idl +++ b/lucet-idl/tests/example.idl @@ -26,7 +26,11 @@ mod example { // functions // implicit bindings: in value, out value. - fn set_color(to: i32) -> r: i32; + fn set_counter(to: i32) -> r: i32; + + // explicit bindings: in value, out value. + fn set_color(to_int: i32) -> r: i32 + where to: in color <- to_int, prev: out color <- r; // binding: in pointer fn set_struct(struct_pointer: i32) diff --git a/lucet-idl/tests/example.rs b/lucet-idl/tests/example.rs index c8aa5d42e..001730d63 100644 --- a/lucet-idl/tests/example.rs +++ b/lucet-idl/tests/example.rs @@ -5,7 +5,7 @@ use std::process::Command; use tempfile::TempDir; #[test] -fn compile_and_run_c() { +fn compile_c_guest() { let mut source = String::new(); File::open("tests/example.idl") .expect("open example.idl") @@ -25,8 +25,10 @@ fn compile_and_run_c() { ) .expect("run lucet_idl"); - let cmd_cc = Command::new("cc") + let cmd_cc = Command::new("/opt/wasi-sdk/bin/clang") + .arg("--target=wasm32-wasi") .arg("--std=c99") + .arg("-Wl,--allow-undefined") .arg("-I") .arg(tempdir.path()) .arg("tests/example_driver.c") @@ -35,24 +37,26 @@ fn compile_and_run_c() { .status() .expect("run cc"); assert!(cmd_cc.success(), "failure to compile generated code"); +} - let cmd_run = Command::new(tempdir.path().join("example")) - .status() - .expect("run generated code"); - assert!(cmd_run.success(), "failure to run generated code"); +#[test] +fn compile_and_test_rust_guest() { + compile_and_test_rust(lucet_idl::Backend::RustGuest) } #[test] -fn compile_and_run_rust_guest() { +fn compile_and_test_rust_host() { + compile_and_test_rust(lucet_idl::Backend::RustHost) +} + +fn compile_and_test_rust(backend: lucet_idl::Backend) { let mut source = String::new(); File::open("tests/example.idl") .expect("open example.idl") .read_to_string(&mut source) .expect("read example.idl"); - let config = lucet_idl::Config { - backend: lucet_idl::Backend::RustGuest, - }; + let config = lucet_idl::Config { backend }; let tempdir = TempDir::new().expect("create tempdir"); diff --git a/lucet-idl/tests/example_driver.c b/lucet-idl/tests/example_driver.c index 626723b66..590ccfac5 100644 --- a/lucet-idl/tests/example_driver.c +++ b/lucet-idl/tests/example_driver.c @@ -14,5 +14,21 @@ int main (int argc, char *argv[]) { .c = COLOR_RED, }; + int32_t ctr_res = example_set_counter(666); + + enum color c4 = example_set_color(c1); + + example_set_struct(&s); + + example_get_color_to_ptr(&c1); + + example_swap_color_by_ptr(&c2); + + const uint8_t debug_str[] = "hello, world!"; + example_debug_str(debug_str, sizeof(debug_str)); + + uint8_t inout_str[] = "hello again, I guess"; + example_inout_str(inout_str, sizeof(inout_str)); + return 0; } From 58bf0268e0877f9295f2c77362699506a17a0092 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 2 Aug 2019 17:36:12 -0700 Subject: [PATCH 328/512] lucet-idl: rust datatypes are generated --- lucet-idl/src/c.rs | 3 - lucet-idl/src/cursor.rs | 150 ++-- lucet-idl/src/env/mod.rs | 1 - lucet-idl/src/lib.rs | 24 +- lucet-idl/src/rust.rs | 1168 +++++++++++++++-------------- lucet-idl/src/rust/guest_funcs.rs | 14 +- lucet-idl/src/validate/module.rs | 6 +- 7 files changed, 677 insertions(+), 689 deletions(-) delete mode 100644 lucet-idl/src/env/mod.rs diff --git a/lucet-idl/src/c.rs b/lucet-idl/src/c.rs index ec1003146..b79e263f1 100644 --- a/lucet-idl/src/c.rs +++ b/lucet-idl/src/c.rs @@ -27,9 +27,6 @@ impl CGenerator { pub fn generate_guest(&mut self, package: &Package) -> Result<(), IDLError> { for module in package.modules() { - if module.name() == "std" { - continue; - } for dt in module.datatypes() { self.gen_type_header(&dt)?; match dt.variant() { diff --git a/lucet-idl/src/cursor.rs b/lucet-idl/src/cursor.rs index a48c1f0cd..a2455e06a 100644 --- a/lucet-idl/src/cursor.rs +++ b/lucet-idl/src/cursor.rs @@ -7,6 +7,7 @@ use crate::repr::{ }; pub use crate::repr::{BindingDirection, Package}; use crate::MemArea; +use std::ops::Deref; impl Package { pub fn module<'a>(&'a self, name: &str) -> Option> { @@ -17,7 +18,10 @@ impl Package { } pub fn modules<'a>(&'a self) -> impl Iterator> + 'a { - self.names.keys().map(move |ix| Module { pkg: &self, ix }) + self.names + .keys() + .map(move |ix| Module { pkg: &self, ix }) + .filter(|m| m.name() != "std") } pub fn module_by_ix<'a>(&'a self, ix: ModuleIx) -> Option> { @@ -161,19 +165,16 @@ impl<'a> Datatype<'a> { match self.repr().variant { DatatypeVariantRepr::Atom(a) => DatatypeVariant::Atom(a), DatatypeVariantRepr::Struct(ref repr) => DatatypeVariant::Struct(StructDatatype { - pkg: self.pkg, + datatype: self.clone(), repr: &repr, - id: self.id, }), DatatypeVariantRepr::Enum(ref repr) => DatatypeVariant::Enum(EnumDatatype { - pkg: self.pkg, + datatype: self.clone(), repr: &repr, - id: self.id, }), DatatypeVariantRepr::Alias(ref repr) => DatatypeVariant::Alias(AliasDatatype { - pkg: self.pkg, + datatype: self.clone(), repr: &repr, - id: self.id, }), } } @@ -238,58 +239,40 @@ impl<'a> DatatypeVariant<'a> { #[derive(Debug, Clone)] pub struct StructDatatype<'a> { - pkg: &'a Package, + datatype: Datatype<'a>, repr: &'a StructDatatypeRepr, - id: DatatypeIdent, } impl<'a> StructDatatype<'a> { - pub fn name(&self) -> &str { - Datatype { - pkg: self.pkg, - id: self.id, - } - .name() - } pub fn member(&self, name: &str) -> Option> { - let pkg = self.pkg; - self.repr - .members - .iter() - .find(|m| m.name == name) - .map(move |repr| StructMember { pkg, repr }) + self.members().find(|m| m.name() == name) } pub fn members(&self) -> impl Iterator> { - let pkg = self.pkg; - self.repr - .members - .iter() - .map(move |repr| StructMember { pkg, repr }) + let struct_ = self.clone(); + self.repr.members.iter().map(move |repr| StructMember { + struct_: struct_.clone(), + repr, + }) } } -impl<'a> From> for Datatype<'a> { - fn from(s: StructDatatype<'a>) -> Datatype<'a> { - Datatype { - pkg: s.pkg, - id: s.id, - } +impl<'a> Deref for StructDatatype<'a> { + type Target = Datatype<'a>; + fn deref(&self) -> &Self::Target { + &self.datatype } } -impl<'a> MemArea for StructDatatype<'a> { - fn mem_size(&self) -> usize { - Datatype::from(self.clone()).mem_size() - } - fn mem_align(&self) -> usize { - Datatype::from(self.clone()).mem_align() +impl<'a> From> for Datatype<'a> { + fn from(s: StructDatatype<'a>) -> Datatype<'a> { + s.datatype.clone() } } #[derive(Debug, Clone)] pub struct StructMember<'a> { - pkg: &'a Package, + struct_: StructDatatype<'a>, repr: &'a StructMemberRepr, } @@ -302,33 +285,28 @@ impl<'a> StructMember<'a> { } pub fn type_(&self) -> Datatype<'a> { Datatype { - pkg: self.pkg, + pkg: self.struct_.datatype.pkg, id: self.repr.type_, } } + pub fn struct_(&self) -> StructDatatype<'a> { + self.struct_.clone() + } } #[derive(Debug, Clone)] pub struct EnumDatatype<'a> { - pkg: &'a Package, + datatype: Datatype<'a>, repr: &'a EnumDatatypeRepr, - id: DatatypeIdent, } impl<'a> EnumDatatype<'a> { - pub fn name(&self) -> &str { - Datatype { - pkg: self.pkg, - id: self.id, - } - .name() - } pub fn variants(&self) -> impl Iterator> { - let repr = self.clone(); + let enum_ = self.clone(); (0..self.repr.members.len()) .into_iter() .map(move |ix| EnumMember { - repr: repr.clone(), + enum_: enum_.clone(), index: ix, }) } @@ -338,35 +316,30 @@ impl<'a> EnumDatatype<'a> { } } -impl<'a> From> for Datatype<'a> { - fn from(e: EnumDatatype<'a>) -> Datatype<'a> { - Datatype { - pkg: e.pkg, - id: e.id, - } +impl<'a> Deref for EnumDatatype<'a> { + type Target = Datatype<'a>; + fn deref(&self) -> &Self::Target { + &self.datatype } } -impl<'a> MemArea for EnumDatatype<'a> { - fn mem_size(&self) -> usize { - Datatype::from(self.clone()).mem_size() - } - fn mem_align(&self) -> usize { - Datatype::from(self.clone()).mem_align() +impl<'a> From> for Datatype<'a> { + fn from(e: EnumDatatype<'a>) -> Datatype<'a> { + e.datatype } } pub struct EnumMember<'a> { - repr: EnumDatatype<'a>, + enum_: EnumDatatype<'a>, index: usize, } impl<'a> EnumMember<'a> { - pub fn parent(&self) -> EnumDatatype<'a> { - self.repr.clone() + pub fn enum_(&self) -> EnumDatatype<'a> { + self.enum_.clone() } pub fn name(&self) -> &str { - &self.repr.repr.members[self.index].name + &self.enum_.repr.members[self.index].name } pub fn index(&self) -> usize { self.index @@ -375,22 +348,14 @@ impl<'a> EnumMember<'a> { #[derive(Debug, Clone)] pub struct AliasDatatype<'a> { - pkg: &'a Package, + datatype: Datatype<'a>, repr: &'a AliasDatatypeRepr, - id: DatatypeIdent, } impl<'a> AliasDatatype<'a> { - pub fn name(&self) -> &str { - Datatype { - pkg: self.pkg, - id: self.id, - } - .name() - } pub fn to(&self) -> Datatype<'a> { Datatype { - pkg: self.pkg, + pkg: self.datatype.pkg, id: self.repr.to, } } @@ -398,19 +363,14 @@ impl<'a> AliasDatatype<'a> { impl<'a> From> for Datatype<'a> { fn from(a: AliasDatatype<'a>) -> Datatype<'a> { - Datatype { - pkg: a.pkg, - id: a.id, - } + a.datatype.clone() } } -impl<'a> MemArea for AliasDatatype<'a> { - fn mem_size(&self) -> usize { - Datatype::from(self.clone()).mem_size() - } - fn mem_align(&self) -> usize { - Datatype::from(self.clone()).mem_align() +impl<'a> Deref for AliasDatatype<'a> { + type Target = Datatype<'a>; + fn deref(&self) -> &Self::Target { + &self.datatype } } @@ -502,10 +462,10 @@ impl<'a> Function<'a> { } } -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ParamType { - Arg, - Ret, +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum ParamPosition { + Arg(usize), + Ret(usize), } #[derive(Debug, Clone)] @@ -533,10 +493,10 @@ impl<'a> FuncParam<'a> { .datatype_by_id(AtomType::from(self.repr().type_).datatype_id()) .expect("valid type") } - pub fn param_type(&self) -> ParamType { + pub fn param_position(&self) -> ParamPosition { match self.ix { - ParamIx::Arg { .. } => ParamType::Arg, - ParamIx::Ret { .. } => ParamType::Ret, + ParamIx::Arg(ix) => ParamPosition::Arg(ix.as_u32() as usize), + ParamIx::Ret(ix) => ParamPosition::Ret(ix.as_u32() as usize), } } pub fn binding(&self) -> FuncBinding<'a> { diff --git a/lucet-idl/src/env/mod.rs b/lucet-idl/src/env/mod.rs deleted file mode 100644 index 8b1378917..000000000 --- a/lucet-idl/src/env/mod.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 37e22dd7e..4bd8911d0 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -7,15 +7,14 @@ mod atoms; mod c; mod config; mod cursor; -pub mod env; mod error; mod lexer; mod parser; mod prelude; mod pretty_writer; mod repr; +mod rust; mod validate; -//mod rust; pub use crate::config::{Backend, Config}; pub use crate::cursor::*; @@ -24,9 +23,10 @@ pub use crate::{AbiType, AtomType}; use crate::c::CGenerator; use crate::parser::Parser; -//use crate::rust::RustGenerator; +use crate::rust::RustGenerator; use crate::validate::package_from_declarations; use lucet_module::bindings::Bindings; +use std::collections::HashMap; use std::io::Write; #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] @@ -50,9 +50,9 @@ pub fn parse_package(input: &str) -> Result { pub fn codegen(package: &Package, config: &Config, output: Box) -> Result<(), IDLError> { match config.backend { Backend::CGuest => CGenerator::new(output).generate_guest(package)?, - Backend::RustGuest => unimplemented!(), //RustGenerator::new(output).generate_guest(package)?, - Backend::RustHost => unimplemented!(), //RustGenerator::new(output).generate_host(package)?, - Backend::Bindings => unimplemented!(), //generate_bindings(&package.bindings(), output)?, + Backend::RustGuest => RustGenerator::new(output).generate_guest(package)?, + Backend::RustHost => RustGenerator::new(output).generate_host(package)?, + Backend::Bindings => generate_bindings(&create_bindings(package), output)?, } Ok(()) } @@ -62,6 +62,18 @@ pub fn run(config: &Config, input: &str, output: Box) -> Result<(), I codegen(&pkg, config, output) } +fn create_bindings(package: &Package) -> Bindings { + let mut bs = HashMap::new(); + for m in package.modules() { + let mut mod_bs = HashMap::new(); + for f in m.functions() { + mod_bs.insert(f.name().to_owned(), f.host_func_name()); + } + bs.insert(m.name().to_owned(), mod_bs); + } + Bindings::new(bs) +} + fn generate_bindings(bindings: &Bindings, mut output: Box) -> Result<(), IDLError> { let bindings_json = bindings .to_string() diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index edf0e731f..47144f8ff 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -2,45 +2,43 @@ #![allow(unused_variables)] use crate::error::IDLError; -use crate::function::{BindingRef, FuncDecl}; -use crate::module::Module; -use crate::package::Package; use crate::pretty_writer::PrettyWriter; -use crate::types::{ - AbiType, AliasDataType, AtomType, DataType, DataTypeRef, DataTypeVariant, EnumDataType, Ident, - Named, StructDataType, +use crate::{ + AbiType, AliasDatatype, AtomType, Datatype, DatatypeVariant, EnumDatatype, Function, MemArea, + Module, Package, StructDatatype, }; use heck::{CamelCase, SnakeCase}; -use std::collections::HashMap; use std::io::Write; mod guest_funcs; /// Generator for the Rust backend pub struct RustGenerator { - pub defined: HashMap, pub w: PrettyWriter, } impl RustGenerator { pub fn new(w: Box) -> Self { Self { - defined: HashMap::new(), w: PrettyWriter::new(w), } } pub fn generate_guest(&mut self, package: &Package) -> Result<(), IDLError> { - for (_ident, module) in package.modules.iter() { - self.generate_datatypes(module)?; + for module in package.modules() { + self.w + .writeln(format!("mod {} {{", module.rust_name())) + .indent(); + self.generate_datatypes(&module)?; + /* for fdecl in module.func_decls() { self.guest_idiomatic_def(module, &fdecl.entity)?; } self.w .writeln("mod abi {") - .indent() + ndent() .writeln(format!( "#[link(wasm_import_module=\"{}\")]", module.module_name @@ -51,683 +49,635 @@ impl RustGenerator { self.guest_abi_import(module, &fdecl.entity)?; } self.w.eob().writeln("}").eob().writeln("}"); + */ + + self.w.eob().writeln("}"); } Ok(()) } pub fn generate_host(&mut self, package: &Package) -> Result<(), IDLError> { - for (_ident, module) in package.modules.iter() { - self.generate_datatypes(module)?; - - self.host_trait_definition(module)?; - self.w.eob(); - + for module in package.modules() { self.w - .writeln("use lucet_runtime::{lucet_hostcalls, lucet_hostcall_terminate};"); - self.w.writeln("lucet_hostcalls! {").indent(); - for fdecl in module.func_decls() { - self.host_abi_definition(module, &fdecl.entity)?; - } + .writeln(format!("mod {} {{", module.rust_name())) + .indent(); + self.generate_datatypes(&module)?; + + /* + self.host_trait_definition(module)?; + self.w.eob(); + + self.w + .writeln("use lucet_runtime::{lucet_hostcalls, lucet_hostcall_terminate};"); + self.w.writeln("lucet_hostcalls! {").indent(); + for fdecl in module.func_decls() { + self.host_abi_definition(module, &fdecl.entity)?; + } + self.w.eob().writeln("}"); + + self.host_ensure_linked(module); + */ self.w.eob().writeln("}"); - - self.host_ensure_linked(module); } Ok(()) } fn generate_datatypes(&mut self, module: &Module) -> Result<(), IDLError> { - for ref dt in module.datatypes() { - match &dt.entity.variant { - DataTypeVariant::Struct(s) => self.gen_struct(module, dt, s)?, - DataTypeVariant::Alias(a) => self.gen_alias(module, dt, a)?, - DataTypeVariant::Enum(e) => self.gen_enum(module, dt, e)?, + for dt in module.datatypes() { + match dt.variant() { + DatatypeVariant::Struct(s) => self.gen_struct(&s)?, + DatatypeVariant::Alias(a) => self.gen_alias(&a)?, + DatatypeVariant::Enum(e) => self.gen_enum(&e)?, + DatatypeVariant::Atom { .. } => {} } } Ok(()) } - fn define_name(&mut self, dt: &Named) -> String { - let typename = dt.name.name.to_camel_case(); - self.defined.insert(dt.id, typename.clone()); - typename - } - - fn get_defined_typename(&self, data_type_ref: &DataTypeRef) -> String { - match data_type_ref { - DataTypeRef::Defined(id) => self.defined.get(id).expect("definition exists"), - DataTypeRef::Atom(a) => Self::atom_name(a), - } - .to_owned() - } - - fn atom_name(atom_type: &AtomType) -> &'static str { - use AtomType::*; - match atom_type { - Bool => "bool", - U8 => "u8", - U16 => "u16", - U32 => "u32", - U64 => "u64", - I8 => "i8", - I16 => "i16", - I32 => "i32", - I64 => "i64", - F32 => "f32", - F64 => "f64", - } - } - - fn abitype_name(abi_type: &AbiType) -> &'static str { - use AbiType::*; - match abi_type { - I32 => "i32", - I64 => "i64", - F32 => "f32", - F64 => "f64", - } - } - - fn gen_alias( - &mut self, - module: &Module, - dt: &Named, - alias: &AliasDataType, - ) -> Result<(), IDLError> { - let typename = self.define_name(dt); - let pointee_name = self.get_defined_typename(&alias.to); - + fn gen_alias(&mut self, alias: &AliasDatatype) -> Result<(), IDLError> { self.w - .writeln(format!("pub type {} = {};", typename, pointee_name)) + .writeln(format!( + "pub type {} = {};", + alias.rust_type_name(), + alias.to().rust_type_name() + )) .eob(); - gen_testcase(&mut self.w, &dt.name.name.to_snake_case(), move |w| { + gen_testcase(&mut self.w, &alias.name().to_snake_case(), move |w| { w.writeln(format!( "assert_eq!({}, ::std::mem::size_of::());", - dt.entity.repr_size, typename + alias.mem_size(), + alias.rust_type_name() )); Ok(()) })?; - Ok(()) } - fn gen_struct( - &mut self, - module: &Module, - dt: &Named, - struct_: &StructDataType, - ) -> Result<(), IDLError> { - let typename = self.define_name(dt); - + fn gen_struct(&mut self, struct_: &StructDatatype) -> Result<(), IDLError> { self.w .writeln("#[repr(C)]") - .writeln(format!("pub struct {} {{", typename)); + .writeln(format!("pub struct {} {{", struct_.rust_type_name())); let mut w = self.w.new_block(); - for m in struct_.members.iter() { + for m in struct_.members() { w.writeln(format!( "{}: {},", - m.name.to_snake_case(), - self.get_defined_typename(&m.type_) + m.name().to_snake_case(), + m.type_().rust_type_name(), )); } self.w.writeln("}").eob(); - gen_testcase(&mut self.w, &dt.name.name.to_snake_case(), |w| { + gen_testcase(&mut self.w, &struct_.name().to_snake_case(), |w| { w.writeln(format!( "assert_eq!({}, ::std::mem::size_of::());", - dt.entity.repr_size, typename + struct_.mem_size(), + struct_.rust_type_name(), )); - for m in struct_.members.iter() { + for m in struct_.members() { w.writeln(format!( "assert_eq!({}, {{ let base = ::std::ptr::null::(); unsafe {{ (&(*base).{}) as *const _ as usize }} }});", - m.offset, typename, m.name, + m.offset(), struct_.rust_type_name(), m.name(), )); } Ok(()) })?; - Ok(()) } // Enums generate both a specific typedef, and a traditional C-style enum // The typedef is required to use a native type which is consistent across all architectures - fn gen_enum( - &mut self, - module: &Module, - dt: &Named, - enum_: &EnumDataType, - ) -> Result<(), IDLError> { - let typename = self.define_name(dt); - + fn gen_enum(&mut self, enum_: &EnumDatatype) -> Result<(), IDLError> { self.w .writeln("#[repr(C)]") .writeln("#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]") - .writeln(format!("pub enum {} {{", typename)); + .writeln(format!("pub enum {} {{", enum_.rust_type_name())); let mut w = self.w.new_block(); - for m in enum_.members.iter() { - w.writeln(format!("{},", m.name.to_camel_case())); + for v in enum_.variants() { + w.writeln(format!("{},", v.name().to_camel_case())); } self.w.writeln("}").eob(); - gen_testcase(&mut self.w, &dt.name.name.to_snake_case(), |w| { + gen_testcase(&mut self.w, &enum_.name().to_snake_case(), |w| { w.writeln(format!( "assert_eq!({}, ::std::mem::size_of::());", - dt.entity.repr_size, typename + enum_.mem_size(), + enum_.rust_type_name(), )); Ok(()) })?; - Ok(()) } + /* + fn guest_abi_import(&mut self, module: &Module, func: &FuncDecl) -> Result<(), IDLError> { + let mut args = String::new(); + for a in func.args.iter() { + args += &format!( + "{}: {},", + a.name.to_snake_case(), + Self::abitype_name(&a.type_) + ); + } - fn guest_abi_import(&mut self, module: &Module, func: &FuncDecl) -> Result<(), IDLError> { - let mut args = String::new(); - for a in func.args.iter() { - args += &format!( - "{}: {},", - a.name.to_snake_case(), - Self::abitype_name(&a.type_) - ); - } - - let rets = if func.rets.len() == 0 { - "()" - } else { - assert_eq!(func.rets.len(), 1); - Self::abitype_name(&func.rets[0].type_) - }; - - self.w - .writeln("#[no_mangle]") - .writeln(format!("pub fn {}({}) -> {};", func.field_name, args, rets)); - - Ok(()) - } + let rets = if func.rets.len() == 0 { + "()" + } else { + assert_eq!(func.rets.len(), 1); + Self::abitype_name(&func.rets[0].type_) + }; - fn guest_idiomatic_def(&mut self, module: &Module, func: &FuncDecl) -> Result<(), IDLError> { - use guest_funcs::{AbiCallBuilder, FuncBuilder}; + self.w + .writeln("#[no_mangle]") + .writeln(format!("pub fn {}({}) -> {};", func.field_name, args, rets)); - let name = func.field_name.to_snake_case(); - let mut def = FuncBuilder::new(name, "()".to_owned()); - let mut abi_call = AbiCallBuilder::new(func); + Ok(()) + } - for input in func.in_bindings.iter() { - match &input.from { - BindingRef::Ptr(ptr_pos) => { - let ptr = func.get_param(ptr_pos).expect("valid param"); - def.arg(format!( - "{}: &{}", - input.name, - self.get_defined_typename(&input.type_) - )); - abi_call.before(format!( - "let {} = {} as *const _ as i32;", - ptr.name, input.name, - )); - abi_call.param(ptr_pos, ptr.name.clone()); + fn guest_idiomatic_def(&mut self, module: &Module, func: &FuncDecl) -> Result<(), IDLError> { + use guest_funcs::{AbiCallBuilder, FuncBuilder}; + + let name = func.field_name.to_snake_case(); + let mut def = FuncBuilder::new(name, "()".to_owned()); + let mut abi_call = AbiCallBuilder::new(func); + + for input in func.in_bindings.iter() { + match &input.from { + BindingRef::Ptr(ptr_pos) => { + let ptr = func.get_param(ptr_pos).expect("valid param"); + def.arg(format!( + "{}: &{}", + input.name, + self.get_defined_typename(&input.type_) + )); + abi_call.before(format!( + "let {} = {} as *const _ as i32;", + ptr.name, input.name, + )); + abi_call.param(ptr_pos, ptr.name.clone()); + } + BindingRef::Slice(ptr_pos, len_pos) => { + let ptr = func.get_param(ptr_pos).expect("valid param"); + let len = func.get_param(len_pos).expect("lenid param"); + def.arg(format!( + "{}: &[{}]", + input.name, + self.get_defined_typename(&input.type_) + )); + + abi_call.before(format!( + "let {} = {}.as_ptr() as i32;", + ptr.name, input.name, + )); + abi_call.param(ptr_pos, ptr.name.clone()); + + abi_call.before(format!("let {} = {}.len() as i32;", len.name, input.name,)); + abi_call.param(len_pos, len.name.clone()); + } + BindingRef::Value(val_pos) => { + let val = func.get_param(val_pos).expect("valid param"); + def.arg(format!( + "{}: {}", + input.name, + self.get_defined_typename(&input.type_) + )); + abi_call.before(format!( + "let {} = {} as {};", + val.name, + input.name, + Self::abitype_name(&val.type_) + )); + abi_call.param(val_pos, val.name.clone()); + } } - BindingRef::Slice(ptr_pos, len_pos) => { - let ptr = func.get_param(ptr_pos).expect("valid param"); - let len = func.get_param(len_pos).expect("lenid param"); - def.arg(format!( - "{}: &[{}]", - input.name, - self.get_defined_typename(&input.type_) - )); - - abi_call.before(format!( - "let {} = {}.as_ptr() as i32;", - ptr.name, input.name, - )); - abi_call.param(ptr_pos, ptr.name.clone()); + } - abi_call.before(format!("let {} = {}.len() as i32;", len.name, input.name,)); - abi_call.param(len_pos, len.name.clone()); - } - BindingRef::Value(val_pos) => { - let val = func.get_param(val_pos).expect("valid param"); - def.arg(format!( - "{}: {}", - input.name, - self.get_defined_typename(&input.type_) - )); - abi_call.before(format!( - "let {} = {} as {};", - val.name, - input.name, - Self::abitype_name(&val.type_) - )); - abi_call.param(val_pos, val.name.clone()); + for io in func.inout_bindings.iter() { + match &io.from { + BindingRef::Ptr(ptr_pos) => { + let ptr = func.get_param(ptr_pos).expect("valid param"); + def.arg(format!( + "{}: &mut {}", + io.name, + self.get_defined_typename(&io.type_) + )); + abi_call.before(format!("let {} = {} as *mut _ as i32;", ptr.name, io.name)); + abi_call.param(ptr_pos, ptr.name.clone()); + } + BindingRef::Slice(ptr_pos, len_pos) => { + let ptr = func.get_param(ptr_pos).expect("ptrid param"); + let len = func.get_param(len_pos).expect("lenid param"); + def.arg(format!( + "{}: &mut [{}]", + io.name, + self.get_defined_typename(&io.type_) + )); + abi_call.before(format!("let {} = {}.as_ptr() as i32;", ptr.name, io.name)); + abi_call.before(format!("let {} = {}.len() as i32;", len.name, io.name)); + abi_call.param(ptr_pos, ptr.name.clone()); + abi_call.param(len_pos, len.name.clone()); + } + BindingRef::Value(_val) => { + unreachable!("it should not be possible to have an inout value {:?}", io); + } } } - } - for io in func.inout_bindings.iter() { - match &io.from { - BindingRef::Ptr(ptr_pos) => { - let ptr = func.get_param(ptr_pos).expect("valid param"); - def.arg(format!( - "{}: &mut {}", - io.name, - self.get_defined_typename(&io.type_) - )); - abi_call.before(format!("let {} = {} as *mut _ as i32;", ptr.name, io.name)); - abi_call.param(ptr_pos, ptr.name.clone()); - } - BindingRef::Slice(ptr_pos, len_pos) => { - let ptr = func.get_param(ptr_pos).expect("ptrid param"); - let len = func.get_param(len_pos).expect("lenid param"); - def.arg(format!( - "{}: &mut [{}]", - io.name, - self.get_defined_typename(&io.type_) - )); - abi_call.before(format!("let {} = {}.as_ptr() as i32;", ptr.name, io.name)); - abi_call.before(format!("let {} = {}.len() as i32;", len.name, io.name)); - abi_call.param(ptr_pos, ptr.name.clone()); - abi_call.param(len_pos, len.name.clone()); - } - BindingRef::Value(_val) => { - unreachable!("it should not be possible to have an inout value {:?}", io); + for o in func.out_bindings.iter() { + match &o.from { + BindingRef::Ptr(ptr_pos) => { + let ptr = func.get_param(ptr_pos).expect("valid param"); + let otypename = self.get_defined_typename(&o.type_); + def.ok_type(otypename.clone()); + abi_call.before(format!( + "let mut {} = ::std::mem::MaybeUninit::<{}>::uninit();", + ptr.name, otypename + )); + abi_call.param(ptr_pos, format!("{}.as_mut_ptr() as i32", ptr.name)); + abi_call.after(format!( + "let {} = unsafe {{ {}.assume_init() }};", + ptr.name, ptr.name + )); + def.ok_value(ptr.name.clone()); + } + BindingRef::Value(val_pos) => { + let val = func.get_param(val_pos).expect("valid param"); + def.ok_type(self.get_defined_typename(&o.type_)); + abi_call.param(val_pos, val.name.clone()); + abi_call.after(format!( + "let {} = {} as {};", + val.name, + val.name, + self.get_defined_typename(&o.type_), + )); + def.ok_value(val.name.clone()); + } + BindingRef::Slice(_ptr, _len) => { + unreachable!("it should not be possible to have an out slice {:?}", o); + } } } + + def.render(&mut self.w, |mut w| abi_call.render(&mut w))?; + + Ok(()) } - for o in func.out_bindings.iter() { - match &o.from { - BindingRef::Ptr(ptr_pos) => { - let ptr = func.get_param(ptr_pos).expect("valid param"); - let otypename = self.get_defined_typename(&o.type_); - def.ok_type(otypename.clone()); - abi_call.before(format!( - "let mut {} = ::std::mem::MaybeUninit::<{}>::uninit();", - ptr.name, otypename - )); - abi_call.param(ptr_pos, format!("{}.as_mut_ptr() as i32", ptr.name)); - abi_call.after(format!( - "let {} = unsafe {{ {}.assume_init() }};", - ptr.name, ptr.name - )); - def.ok_value(ptr.name.clone()); - } - BindingRef::Value(val_pos) => { - let val = func.get_param(val_pos).expect("valid param"); - def.ok_type(self.get_defined_typename(&o.type_)); - abi_call.param(val_pos, val.name.clone()); - abi_call.after(format!( - "let {} = {} as {};", - val.name, - val.name, - self.get_defined_typename(&o.type_), - )); - def.ok_value(val.name.clone()); - } - BindingRef::Slice(_ptr, _len) => { - unreachable!("it should not be possible to have an out slice {:?}", o); - } + fn host_abi_definition(&mut self, module: &Module, func: &FuncDecl) -> Result<(), IDLError> { + let mut args = vec![format!("&mut vmctx")]; + for a in func.args.iter() { + args.push(format!( + "{}: {}", + a.name.to_snake_case(), + Self::abitype_name(&a.type_) + )); } - } - def.render(&mut self.w, |mut w| abi_call.render(&mut w))?; + let abi_rettype = if func.rets.len() == 0 { + "()" + } else { + assert_eq!(func.rets.len(), 1); + Self::abitype_name(&func.rets[0].type_) + }; - Ok(()) - } + self.w + .writeln("#[no_mangle]") + .writeln(format!( + "// Wasm func {}::{}", + module.module_name, func.field_name + )) + .writeln(format!( + "pub unsafe extern \"C\" fn {}({},) -> {} {{", + func.binding_name, + args.join(", "), + abi_rettype + )); - fn host_abi_definition(&mut self, module: &Module, func: &FuncDecl) -> Result<(), IDLError> { - let mut args = vec![format!("&mut vmctx")]; - for a in func.args.iter() { - args.push(format!( - "{}: {}", - a.name.to_snake_case(), - Self::abitype_name(&a.type_) - )); - } + self.w.indent(); - let abi_rettype = if func.rets.len() == 0 { - "()" - } else { - assert_eq!(func.rets.len(), 1); - Self::abitype_name(&func.rets[0].type_) - }; + let typename = module.module_name.to_camel_case(); - self.w - .writeln("#[no_mangle]") - .writeln(format!( - "// Wasm func {}::{}", - module.module_name, func.field_name - )) - .writeln(format!( - "pub unsafe extern \"C\" fn {}({},) -> {} {{", - func.binding_name, - args.join(", "), - abi_rettype + self.w.writeln(format!( + "fn inner(heap: &mut [u8], obj: &mut dyn {}, {}) -> Result<{},()> {{", + typename, + func.args + .iter() + .map(|a| format!( + "{}: {}", + a.name.to_snake_case(), + Self::abitype_name(&a.type_) + )) + .collect::>() + .join(", "), + abi_rettype, )); + self.w.indent(); + { + let (pre, post, trait_args, trait_rets, func_rets) = self.trait_dispatch(module, func); + self.w.writelns(&pre); + self.w.writeln(format!( + "let {} = obj.{}({})?;", + render_tuple(&trait_rets), + func.field_name.to_snake_case(), + trait_args.join(", ") + )); + self.w.writelns(&post); + self.w.writeln(format!("Ok({})", render_tuple(&func_rets))); + } + self.w.eob().writeln("}"); - self.w.indent(); - - let typename = module.module_name.to_camel_case(); - - self.w.writeln(format!( - "fn inner(heap: &mut [u8], obj: &mut dyn {}, {}) -> Result<{},()> {{", - typename, - func.args - .iter() - .map(|a| format!( - "{}: {}", - a.name.to_snake_case(), - Self::abitype_name(&a.type_) - )) - .collect::>() - .join(", "), - abi_rettype, - )); - self.w.indent(); - { - let (pre, post, trait_args, trait_rets, func_rets) = self.trait_dispatch(module, func); - self.w.writelns(&pre); self.w.writeln(format!( - "let {} = obj.{}({})?;", - render_tuple(&trait_rets), - func.field_name.to_snake_case(), - trait_args.join(", ") + "let mut ctx: ::std::cell::RefMut> = vmctx.get_embed_ctx_mut::>();", + typename = typename )); - self.w.writelns(&post); - self.w.writeln(format!("Ok({})", render_tuple(&func_rets))); - } - self.w.eob().writeln("}"); - - self.w.writeln(format!( - "let mut ctx: ::std::cell::RefMut> = vmctx.get_embed_ctx_mut::>();", - typename = typename - )); - self.w.writeln("let mut heap = vmctx.heap_mut();"); - self.w.writeln(format!( - "match inner(&mut *heap, &mut **ctx, {}) {{ Ok(v) => v, Err(e) => lucet_hostcall_terminate!(\"FIXME\"), }}", - func.args - .iter() - .map(|a| a.name.to_snake_case()) - .collect::>() - .join(", "), - )); - self.w.eob().writeln("}"); + self.w.writeln("let mut heap = vmctx.heap_mut();"); + self.w.writeln(format!( + "match inner(&mut *heap, &mut **ctx, {}) {{ Ok(v) => v, Err(e) => lucet_hostcall_terminate!(\"FIXME\"), }}", + func.args + .iter() + .map(|a| a.name.to_snake_case()) + .collect::>() + .join(", "), + )); + self.w.eob().writeln("}"); - Ok(()) - } + Ok(()) + } - fn trait_dispatch( - &self, - module: &Module, - func: &FuncDecl, - ) -> ( - Vec, - Vec, - Vec, - Vec, - Vec, - ) { - let mut pre = Vec::new(); - let mut post = Vec::new(); - let mut trait_args = Vec::new(); - let mut trait_rets = Vec::new(); - let mut func_rets = Vec::new(); - - for input in func.in_bindings.iter() { - let input_mem = module.get_mem_area(&input.type_); - match &input.from { - BindingRef::Ptr(ptr_pos) => { - let ptr = func.get_param(ptr_pos).expect("valid param"); - pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name)); - pre.push(format!( - "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", - ptr = ptr.name, - align = input_mem.mem_align(), - )); - pre.push(format!( - "#[allow(non_snake_case)] let {name}___MEM: &[u8] = heap.get({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", - name = input.name, - ptr = ptr.name, - len = input_mem.mem_size(), - )); - pre.push(format!( - "let {name}: &{typename} = unsafe {{ ({name}___MEM.as_ptr() as *const {typename}).as_ref().unwrap() }}; // convert pointer in linear memory to ref", - name = input.name, - typename = self.get_defined_typename(&input.type_), - )); - trait_args.push(input.name.clone()); - } - BindingRef::Slice(ptr_pos, len_pos) => { - let ptr = func.get_param(ptr_pos).expect("valid param"); - let len = func.get_param(len_pos).expect("valid param"); - - pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name)); - pre.push(format!("let {len} = {len} as usize;", len = len.name)); - pre.push(format!( - "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", - ptr = ptr.name, - align = input_mem.mem_align(), - )); - pre.push(format!( - "#[allow(non_snake_case)] let {name}___MEM: &[u8] = heap.get({ptr}..({ptr}+({len}*{elem_len}))).ok_or_else(|| () /* FIXME: bounds check failed */)?;", - name = input.name, - ptr = ptr.name, - len = len.name, - elem_len = input_mem.mem_size(), - )); - - pre.push(format!( - "let {}: &[{}] = unsafe {{ ::std::slice::from_raw_parts({name}___MEM.as_ptr() as *const {typename}, {len}) }};", - name = input.name, - typename = self.get_defined_typename(&input.type_), - len = len.name, - )); - trait_args.push(input.name.clone()); - } - BindingRef::Value(value_pos) => { - let value = func.get_param(value_pos).expect("valid param"); - pre.push(format!( - "let {name}: {typename} = {value} as {typename};", - name = input.name, - typename = self.get_defined_typename(&input.type_), - value = value.name - )); - trait_args.push(value.name.clone()); + fn trait_dispatch( + &self, + module: &Module, + func: &FuncDecl, + ) -> ( + Vec, + Vec, + Vec, + Vec, + Vec, + ) { + let mut pre = Vec::new(); + let mut post = Vec::new(); + let mut trait_args = Vec::new(); + let mut trait_rets = Vec::new(); + let mut func_rets = Vec::new(); + + for input in func.in_bindings.iter() { + let input_mem = module.get_mem_area(&input.type_); + match &input.from { + BindingRef::Ptr(ptr_pos) => { + let ptr = func.get_param(ptr_pos).expect("valid param"); + pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name)); + pre.push(format!( + "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", + ptr = ptr.name, + align = input_mem.mem_align(), + )); + pre.push(format!( + "#[allow(non_snake_case)] let {name}___MEM: &[u8] = heap.get({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", + name = input.name, + ptr = ptr.name, + len = input_mem.mem_size(), + )); + pre.push(format!( + "let {name}: &{typename} = unsafe {{ ({name}___MEM.as_ptr() as *const {typename}).as_ref().unwrap() }}; // convert pointer in linear memory to ref", + name = input.name, + typename = self.get_defined_typename(&input.type_), + )); + trait_args.push(input.name.clone()); + } + BindingRef::Slice(ptr_pos, len_pos) => { + let ptr = func.get_param(ptr_pos).expect("valid param"); + let len = func.get_param(len_pos).expect("valid param"); + + pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name)); + pre.push(format!("let {len} = {len} as usize;", len = len.name)); + pre.push(format!( + "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", + ptr = ptr.name, + align = input_mem.mem_align(), + )); + pre.push(format!( + "#[allow(non_snake_case)] let {name}___MEM: &[u8] = heap.get({ptr}..({ptr}+({len}*{elem_len}))).ok_or_else(|| () /* FIXME: bounds check failed */)?;", + name = input.name, + ptr = ptr.name, + len = len.name, + elem_len = input_mem.mem_size(), + )); + + pre.push(format!( + "let {}: &[{}] = unsafe {{ ::std::slice::from_raw_parts({name}___MEM.as_ptr() as *const {typename}, {len}) }};", + name = input.name, + typename = self.get_defined_typename(&input.type_), + len = len.name, + )); + trait_args.push(input.name.clone()); + } + BindingRef::Value(value_pos) => { + let value = func.get_param(value_pos).expect("valid param"); + pre.push(format!( + "let {name}: {typename} = {value} as {typename};", + name = input.name, + typename = self.get_defined_typename(&input.type_), + value = value.name + )); + trait_args.push(value.name.clone()); + } } } - } - for io in func.inout_bindings.iter() { - let io_mem = module.get_mem_area(&io.type_); - match &io.from { - BindingRef::Ptr(ptr_pos) => { - let ptr = func.get_param(ptr_pos).expect("valid param"); - pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name)); - pre.push(format!( - "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", - ptr = ptr.name, - align = io_mem.mem_align(), - )); - pre.push(format!( - "#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", - name = io.name, - ptr = ptr.name, - len = io_mem.mem_size(), - )); - pre.push(format!( - "let mut {name}: &mut {typename} = unsafe {{ ({name}___MEM.as_mut_ptr() as *mut {typename}).as_mut().unwrap() }}; // convert pointer in linear memory to ref", - name = io.name, - typename = self.get_defined_typename(&io.type_), - )); - trait_args.push(format!("&mut {}", io.name)); + for io in func.inout_bindings.iter() { + let io_mem = module.get_mem_area(&io.type_); + match &io.from { + BindingRef::Ptr(ptr_pos) => { + let ptr = func.get_param(ptr_pos).expect("valid param"); + pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name)); + pre.push(format!( + "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", + ptr = ptr.name, + align = io_mem.mem_align(), + )); + pre.push(format!( + "#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", + name = io.name, + ptr = ptr.name, + len = io_mem.mem_size(), + )); + pre.push(format!( + "let mut {name}: &mut {typename} = unsafe {{ ({name}___MEM.as_mut_ptr() as *mut {typename}).as_mut().unwrap() }}; // convert pointer in linear memory to ref", + name = io.name, + typename = self.get_defined_typename(&io.type_), + )); + trait_args.push(format!("&mut {}", io.name)); + } + BindingRef::Slice(ptr_pos, len_pos) => { + let ptr = func.get_param(ptr_pos).expect("valid param"); + let len = func.get_param(len_pos).expect("valid param"); + + pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name)); + pre.push(format!("let {len} = {len} as usize;", len = len.name)); + pre.push(format!( + "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", + ptr = ptr.name, + align = io_mem.mem_align(), + )); + pre.push(format!( + "#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+({len}*{elem_len}))).ok_or_else(|| () /* FIXME: bounds check failed */)?;", + name = io.name, + ptr = ptr.name, + len = len.name, + elem_len = io_mem.mem_size(), + )); + + pre.push(format!( + "let mut {}: &mut [{}] = unsafe {{ ::std::slice::from_raw_parts_mut({name}___MEM.as_mut_ptr() as *mut {typename}, {len}) }};", + name = io.name, + typename = self.get_defined_typename(&io.type_), + len = len.name, + )); + + trait_args.push(format!("&mut {}", io.name.clone())); + } + BindingRef::Value { .. } => unreachable!(), } - BindingRef::Slice(ptr_pos, len_pos) => { - let ptr = func.get_param(ptr_pos).expect("valid param"); - let len = func.get_param(len_pos).expect("valid param"); - - pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name)); - pre.push(format!("let {len} = {len} as usize;", len = len.name)); - pre.push(format!( - "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", - ptr = ptr.name, - align = io_mem.mem_align(), - )); - pre.push(format!( - "#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+({len}*{elem_len}))).ok_or_else(|| () /* FIXME: bounds check failed */)?;", - name = io.name, - ptr = ptr.name, - len = len.name, - elem_len = io_mem.mem_size(), - )); - - pre.push(format!( - "let mut {}: &mut [{}] = unsafe {{ ::std::slice::from_raw_parts_mut({name}___MEM.as_mut_ptr() as *mut {typename}, {len}) }};", - name = io.name, - typename = self.get_defined_typename(&io.type_), - len = len.name, - )); - - trait_args.push(format!("&mut {}", io.name.clone())); - } - BindingRef::Value { .. } => unreachable!(), } - } - for out in func.out_bindings.iter() { - let out_mem = module.get_mem_area(&out.type_); - match &out.from { - BindingRef::Ptr(ptr_pos) => { - let ptr = func.get_param(ptr_pos).expect("valid param"); - - pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name)); - pre.push(format!( - "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", - ptr = ptr.name, - align = out_mem.mem_align(), - )); - pre.push(format!( - "#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", - name = out.name, - ptr = ptr.name, - len = out_mem.mem_size(), - )); - pre.push(format!( - "let mut {ptr}: &mut {typename} = unsafe {{ ({name}___MEM.as_mut_ptr() as *mut {typename}).as_mut().unwrap() }}; // convert pointer in linear memory to ref", - name = out.name, - typename = self.get_defined_typename(&out.type_), - ptr = ptr.name, - )); - - trait_rets.push(out.name.clone()); - post.push(format!( - "*{} = {}; // Copy into out-pointer reference", - ptr.name, out.name, - )); - } - BindingRef::Value(value_pos) => { - let value = func.get_param(value_pos).expect("valid param"); - trait_rets.push(out.name.clone()); - post.push(format!( - "let {value}: {typename} = {arg} as {typename};", - value = value.name, - typename = Self::abitype_name(&value.type_), - arg = out.name, - )); - func_rets.push(value.name.clone()) + for out in func.out_bindings.iter() { + let out_mem = module.get_mem_area(&out.type_); + match &out.from { + BindingRef::Ptr(ptr_pos) => { + let ptr = func.get_param(ptr_pos).expect("valid param"); + + pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name)); + pre.push(format!( + "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", + ptr = ptr.name, + align = out_mem.mem_align(), + )); + pre.push(format!( + "#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", + name = out.name, + ptr = ptr.name, + len = out_mem.mem_size(), + )); + pre.push(format!( + "let mut {ptr}: &mut {typename} = unsafe {{ ({name}___MEM.as_mut_ptr() as *mut {typename}).as_mut().unwrap() }}; // convert pointer in linear memory to ref", + name = out.name, + typename = self.get_defined_typename(&out.type_), + ptr = ptr.name, + )); + + trait_rets.push(out.name.clone()); + post.push(format!( + "*{} = {}; // Copy into out-pointer reference", + ptr.name, out.name, + )); + } + BindingRef::Value(value_pos) => { + let value = func.get_param(value_pos).expect("valid param"); + trait_rets.push(out.name.clone()); + post.push(format!( + "let {value}: {typename} = {arg} as {typename};", + value = value.name, + typename = Self::abitype_name(&value.type_), + arg = out.name, + )); + func_rets.push(value.name.clone()) + } + BindingRef::Slice { .. } => unreachable!(), } - BindingRef::Slice { .. } => unreachable!(), } + (pre, post, trait_args, trait_rets, func_rets) } - (pre, post, trait_args, trait_rets, func_rets) - } - fn host_trait_definition(&mut self, module: &Module) -> Result<(), IDLError> { - self.w - .writeln(format!( - "pub trait {} {{", - module.module_name.to_camel_case() - )) - .indent(); - for fdecl in module.func_decls() { - let func_name = fdecl.entity.field_name.to_snake_case(); + fn host_trait_definition(&mut self, module: &Module) -> Result<(), IDLError> { + self.w + .writeln(format!( + "pub trait {} {{", + module.module_name.to_camel_case() + )) + .indent(); + for fdecl in module.func_decls() { + let func_name = fdecl.entity.field_name.to_snake_case(); - let (mut args, rets) = self.trait_idiomatic_params(&fdecl.entity); - args.insert(0, "&mut self".to_owned()); + let (mut args, rets) = self.trait_idiomatic_params(&fdecl.entity); + args.insert(0, "&mut self".to_owned()); - self.w.writeln(format!( - "fn {}({}) -> {};", - func_name, - args.join(", "), - format!("Result<{},()>", render_tuple(&rets)), - )); - } + self.w.writeln(format!( + "fn {}({}) -> {};", + func_name, + args.join(", "), + format!("Result<{},()>", render_tuple(&rets)), + )); + } - self.w.eob().writeln("}"); + self.w.eob().writeln("}"); - Ok(()) - } + Ok(()) + } - fn trait_idiomatic_params(&self, func: &FuncDecl) -> (Vec, Vec) { - let mut args = Vec::new(); - for input in func.in_bindings.iter() { - match &input.from { - BindingRef::Ptr { .. } => args.push(format!( - "{}: &{}", - input.name, - self.get_defined_typename(&input.type_) - )), - BindingRef::Slice { .. } => args.push(format!( - "{}: &[{}]", - input.name, - self.get_defined_typename(&input.type_) - )), - BindingRef::Value { .. } => args.push(format!( - "{}: {}", - input.name, - self.get_defined_typename(&input.type_) - )), + fn trait_idiomatic_params(&self, func: &FuncDecl) -> (Vec, Vec) { + let mut args = Vec::new(); + for input in func.in_bindings.iter() { + match &input.from { + BindingRef::Ptr { .. } => args.push(format!( + "{}: &{}", + input.name, + self.get_defined_typename(&input.type_) + )), + BindingRef::Slice { .. } => args.push(format!( + "{}: &[{}]", + input.name, + self.get_defined_typename(&input.type_) + )), + BindingRef::Value { .. } => args.push(format!( + "{}: {}", + input.name, + self.get_defined_typename(&input.type_) + )), + } } - } - for io in func.inout_bindings.iter() { - match &io.from { - BindingRef::Ptr { .. } => args.push(format!( - "{}: &mut {}", - io.name, - self.get_defined_typename(&io.type_) - )), - BindingRef::Slice { .. } => args.push(format!( - "{}: &mut [{}]", - io.name, - self.get_defined_typename(&io.type_) - )), - BindingRef::Value { .. } => unreachable!(), + for io in func.inout_bindings.iter() { + match &io.from { + BindingRef::Ptr { .. } => args.push(format!( + "{}: &mut {}", + io.name, + self.get_defined_typename(&io.type_) + )), + BindingRef::Slice { .. } => args.push(format!( + "{}: &mut [{}]", + io.name, + self.get_defined_typename(&io.type_) + )), + BindingRef::Value { .. } => unreachable!(), + } } - } - let mut rets = Vec::new(); - for out in func.out_bindings.iter() { - match &out.from { - BindingRef::Ptr { .. } | BindingRef::Value { .. } => { - rets.push(format!("{}", self.get_defined_typename(&out.type_))) + let mut rets = Vec::new(); + for out in func.out_bindings.iter() { + match &out.from { + BindingRef::Ptr { .. } | BindingRef::Value { .. } => { + rets.push(format!("{}", self.get_defined_typename(&out.type_))) + } + BindingRef::Slice { .. } => unreachable!(), } - BindingRef::Slice { .. } => unreachable!(), } + (args, rets) } - (args, rets) - } - fn host_ensure_linked(&mut self, module: &Module) { - self.w.writeln("pub fn ensure_linked() {").indent(); - self.w.writeln("unsafe {"); - for fdecl in module.func_decls() { - self.w.writeln(format!( - "::std::ptr::read_volatile({} as *const extern \"C\" fn());", - fdecl.entity.binding_name, - )); + fn host_ensure_linked(&mut self, module: &Module) { + self.w.writeln("pub fn ensure_linked() {").indent(); + self.w.writeln("unsafe {"); + for fdecl in module.func_decls() { + self.w.writeln(format!( + "::std::ptr::read_volatile({} as *const extern \"C\" fn());", + fdecl.entity.binding_name, + )); + } + self.w.eob().writeln("}"); + self.w.eob().writeln("}"); } - self.w.eob().writeln("}"); - self.w.eob().writeln("}"); - } + */ } fn gen_testcase(w: &mut PrettyWriter, name: &str, f: F) -> Result<(), IDLError> @@ -752,3 +702,73 @@ pub fn render_tuple(members: &[String]) -> String { _ => format!("({})", members.join(", ")), } } + +trait RustTypeName { + fn rust_type_name(&self) -> String; +} + +impl RustTypeName for AtomType { + fn rust_type_name(&self) -> String { + match self { + AtomType::Bool => "bool", + AtomType::U8 => "u8", + AtomType::U16 => "u16", + AtomType::U32 => "u32", + AtomType::U64 => "u64", + AtomType::I8 => "i8", + AtomType::I16 => "i16", + AtomType::I32 => "i32", + AtomType::I64 => "i64", + AtomType::F32 => "f32", + AtomType::F64 => "f64", + } + .to_owned() + } +} + +impl RustTypeName for AbiType { + fn rust_type_name(&self) -> String { + AtomType::from(self.clone()).rust_type_name() + } +} + +impl RustTypeName for Datatype<'_> { + fn rust_type_name(&self) -> String { + match self.variant() { + DatatypeVariant::Struct(_) | DatatypeVariant::Enum(_) | DatatypeVariant::Alias(_) => { + self.name().to_camel_case() + } + DatatypeVariant::Atom(a) => a.rust_type_name(), + } + } +} + +impl Function<'_> { + fn rust_name(&self) -> String { + self.name().to_snake_case() + } + + pub fn host_func_name(&self) -> String { + format!( + "__{}_{}", + self.module().name().to_snake_case(), + self.name().to_snake_case() + ) + } + /* + fn rust_idiomatic_args<'a>(&'a self) -> impl Iterator> { + unimplemented!() + //self.bindings().filter(|b| !binding_is_ret(b)) + } + fn rust_idiomatic_rets<'a>(&'a self) -> impl Iterator> { + unimplemented!() + //self.bindings().filter(|b| binding_is_ret(b)) + } + */ +} + +impl Module<'_> { + fn rust_name(&self) -> String { + self.name().to_snake_case() + } +} diff --git a/lucet-idl/src/rust/guest_funcs.rs b/lucet-idl/src/rust/guest_funcs.rs index 25a3e7107..1e8521c8c 100644 --- a/lucet-idl/src/rust/guest_funcs.rs +++ b/lucet-idl/src/rust/guest_funcs.rs @@ -1,11 +1,11 @@ use super::render_tuple; use crate::error::IDLError; -use crate::function::{FuncDecl, ParamPosition}; use crate::pretty_writer::PrettyWriter; +use crate::{Function, ParamPosition}; use heck::SnakeCase; pub struct AbiCallBuilder<'a> { - decl: &'a FuncDecl, + func: Function<'a>, before: Vec, after: Vec, args: Vec>, @@ -13,11 +13,11 @@ pub struct AbiCallBuilder<'a> { } impl<'a> AbiCallBuilder<'a> { - pub fn new(decl: &'a FuncDecl) -> Self { - let arg_len = decl.args.len(); - let ret_len = decl.rets.len(); + pub fn new(func: Function<'a>) -> Self { + let arg_len = func.args().collect::>().len(); + let ret_len = func.rets().collect::>().len(); AbiCallBuilder { - decl, + func, before: Vec::new(), after: Vec::new(), args: vec![None; arg_len], @@ -45,7 +45,7 @@ impl<'a> AbiCallBuilder<'a> { } pub fn render(&self, w: &mut PrettyWriter) -> Result<(), IDLError> { - let name = self.decl.field_name.to_snake_case(); + let name = self.func.name().to_snake_case(); let arg_syntax = self .args diff --git a/lucet-idl/src/validate/module.rs b/lucet-idl/src/validate/module.rs index 8fcb7ea9d..232ba8389 100644 --- a/lucet-idl/src/validate/module.rs +++ b/lucet-idl/src/validate/module.rs @@ -99,7 +99,7 @@ mod tests { use super::*; use crate::parser::Parser; use crate::validate::package::PackageBuilder; - use crate::{BindingDirection, DatatypeVariant, Location, MemArea, ParamType}; + use crate::{BindingDirection, DatatypeVariant, Location, MemArea, ParamPosition}; fn mod_syntax(syntax: &str) -> Result { let mut parser = Parser::new(syntax); let decls = parser.match_decls().expect("parses"); @@ -360,7 +360,7 @@ mod tests { assert_eq!(a_bind.direction(), BindingDirection::In); let a_val = a_bind.param().value().expect("binding is a value"); assert_eq!(a_val.name(), "a"); - assert_eq!(a_val.param_type(), ParamType::Arg); + assert_eq!(a_val.param_position(), ParamPosition::Arg(0)); } #[test] @@ -384,7 +384,7 @@ mod tests { assert_eq!(r_bind.direction(), BindingDirection::Out); let r_val = r_bind.param().value().expect("binding is a value"); assert_eq!(r_val.name(), "r"); - assert_eq!(r_val.param_type(), ParamType::Ret); + assert_eq!(r_val.param_position(), ParamPosition::Ret(0)); } #[test] From d56b97c6f86f13ca3f957e2b0c7750a5140b8dff Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Sun, 4 Aug 2019 16:23:24 -0700 Subject: [PATCH 329/512] lucet-idl: add rust guest abi import --- lucet-idl/src/rust.rs | 81 +++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 33 deletions(-) diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index 47144f8ff..f06184193 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -31,24 +31,22 @@ impl RustGenerator { .indent(); self.generate_datatypes(&module)?; - /* - for fdecl in module.func_decls() { - self.guest_idiomatic_def(module, &fdecl.entity)?; - } - self.w .writeln("mod abi {") - ndent() - .writeln(format!( - "#[link(wasm_import_module=\"{}\")]", - module.module_name - )) + .indent() + .writeln(format!("#[link(wasm_import_module=\"{}\")]", module.name())) .writeln("extern \"C\" {") .indent(); - for fdecl in module.func_decls() { - self.guest_abi_import(module, &fdecl.entity)?; + for f in module.functions() { + self.guest_abi_import(&f)?; } self.w.eob().writeln("}").eob().writeln("}"); + + /* + for fdecl in module.func_decls() { + self.guest_idiomatic_def(module, &fdecl.entity)?; + } + */ self.w.eob().writeln("}"); @@ -173,31 +171,28 @@ impl RustGenerator { })?; Ok(()) } - /* - fn guest_abi_import(&mut self, module: &Module, func: &FuncDecl) -> Result<(), IDLError> { - let mut args = String::new(); - for a in func.args.iter() { - args += &format!( - "{}: {},", - a.name.to_snake_case(), - Self::abitype_name(&a.type_) - ); - } + fn guest_abi_import(&mut self, func: &Function) -> Result<(), IDLError> { + let mut arg_syntax = Vec::new(); + for a in func.args() { + arg_syntax.push(format!("{}: {}", a.name(), a.type_().rust_type_name())); + } - let rets = if func.rets.len() == 0 { - "()" - } else { - assert_eq!(func.rets.len(), 1); - Self::abitype_name(&func.rets[0].type_) - }; + let ret_syntax = func + .rets() + .map(|r| r.type_().rust_type_name()) + .rust_return_signature(); - self.w - .writeln("#[no_mangle]") - .writeln(format!("pub fn {}({}) -> {};", func.field_name, args, rets)); + self.w.writeln("#[no_mangle]").writeln(format!( + "pub fn {}({}) -> {};", + func.rust_name(), + arg_syntax.join(", "), + ret_syntax + )); - Ok(()) - } + Ok(()) + } + /* fn guest_idiomatic_def(&mut self, module: &Module, func: &FuncDecl) -> Result<(), IDLError> { use guest_funcs::{AbiCallBuilder, FuncBuilder}; @@ -772,3 +767,23 @@ impl Module<'_> { self.name().to_snake_case() } } + +trait RustReturnSignature { + fn rust_return_signature(&mut self) -> String; +} + +impl RustReturnSignature for I +where + I: Iterator, +{ + fn rust_return_signature(&mut self) -> String { + let mut rets = self.collect::>(); + if rets.len() == 0 { + "()".to_owned() + } else if rets.len() == 1 { + rets.pop().unwrap() + } else { + format!("({})", rets.join(", ")) + } + } +} From 7fdbf8b6612c69b445e9f5f5b6b41a29906e9688 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 5 Aug 2019 16:45:04 -0700 Subject: [PATCH 330/512] lucet-idl: rust backend ported to new cursors --- lucet-idl/src/rust.rs | 898 +++++++++++++++--------------- lucet-idl/src/rust/guest_funcs.rs | 44 +- lucet-idl/tests/example.rs | 3 + 3 files changed, 451 insertions(+), 494 deletions(-) diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index f06184193..9cc807377 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -4,8 +4,8 @@ use crate::error::IDLError; use crate::pretty_writer::PrettyWriter; use crate::{ - AbiType, AliasDatatype, AtomType, Datatype, DatatypeVariant, EnumDatatype, Function, MemArea, - Module, Package, StructDatatype, + AbiType, AliasDatatype, AtomType, BindingDirection, BindingParam, Datatype, DatatypeVariant, + EnumDatatype, Function, MemArea, Module, Package, StructDatatype, }; use heck::{CamelCase, SnakeCase}; use std::io::Write; @@ -42,13 +42,10 @@ impl RustGenerator { } self.w.eob().writeln("}").eob().writeln("}"); - /* - for fdecl in module.func_decls() { - self.guest_idiomatic_def(module, &fdecl.entity)?; + for f in module.functions() { + self.guest_idiomatic_def(&f)?; } - */ - self.w.eob().writeln("}"); } Ok(()) @@ -61,20 +58,19 @@ impl RustGenerator { .indent(); self.generate_datatypes(&module)?; - /* - self.host_trait_definition(module)?; - self.w.eob(); + self.host_trait_definition(&module)?; + self.w.eob(); - self.w - .writeln("use lucet_runtime::{lucet_hostcalls, lucet_hostcall_terminate};"); - self.w.writeln("lucet_hostcalls! {").indent(); - for fdecl in module.func_decls() { - self.host_abi_definition(module, &fdecl.entity)?; - } - self.w.eob().writeln("}"); + self.w + .writeln("use lucet_runtime::{lucet_hostcalls, lucet_hostcall_terminate};"); + self.w.writeln("lucet_hostcalls! {").indent(); + for func in module.functions() { + self.host_abi_definition(&func)?; + } + self.w.eob().writeln("}"); + + self.host_ensure_linked(&module); - self.host_ensure_linked(module); - */ self.w.eob().writeln("}"); } Ok(()) @@ -180,7 +176,7 @@ impl RustGenerator { let ret_syntax = func .rets() .map(|r| r.type_().rust_type_name()) - .rust_return_signature(); + .rust_tuple_syntax(); self.w.writeln("#[no_mangle]").writeln(format!( "pub fn {}({}) -> {};", @@ -192,487 +188,485 @@ impl RustGenerator { Ok(()) } - /* - fn guest_idiomatic_def(&mut self, module: &Module, func: &FuncDecl) -> Result<(), IDLError> { - use guest_funcs::{AbiCallBuilder, FuncBuilder}; - - let name = func.field_name.to_snake_case(); - let mut def = FuncBuilder::new(name, "()".to_owned()); - let mut abi_call = AbiCallBuilder::new(func); - - for input in func.in_bindings.iter() { - match &input.from { - BindingRef::Ptr(ptr_pos) => { - let ptr = func.get_param(ptr_pos).expect("valid param"); - def.arg(format!( - "{}: &{}", - input.name, - self.get_defined_typename(&input.type_) - )); - abi_call.before(format!( - "let {} = {} as *const _ as i32;", - ptr.name, input.name, - )); - abi_call.param(ptr_pos, ptr.name.clone()); - } - BindingRef::Slice(ptr_pos, len_pos) => { - let ptr = func.get_param(ptr_pos).expect("valid param"); - let len = func.get_param(len_pos).expect("lenid param"); - def.arg(format!( - "{}: &[{}]", - input.name, - self.get_defined_typename(&input.type_) - )); + fn guest_idiomatic_def(&mut self, func: &Function) -> Result<(), IDLError> { + use guest_funcs::{AbiCallBuilder, FuncBuilder}; - abi_call.before(format!( - "let {} = {}.as_ptr() as i32;", - ptr.name, input.name, - )); - abi_call.param(ptr_pos, ptr.name.clone()); - - abi_call.before(format!("let {} = {}.len() as i32;", len.name, input.name,)); - abi_call.param(len_pos, len.name.clone()); - } - BindingRef::Value(val_pos) => { - let val = func.get_param(val_pos).expect("valid param"); - def.arg(format!( - "{}: {}", - input.name, - self.get_defined_typename(&input.type_) - )); - abi_call.before(format!( - "let {} = {} as {};", - val.name, - input.name, - Self::abitype_name(&val.type_) - )); - abi_call.param(val_pos, val.name.clone()); - } + let name = func.rust_name(); + let mut def = FuncBuilder::new(name, "()".to_owned()); + let mut abi_call = AbiCallBuilder::new(func.clone()); + + for input in func + .bindings() + .filter(|b| b.direction() == BindingDirection::In) + { + match &input.param() { + BindingParam::Ptr(ptr) => { + def.arg(format!( + "{}: &{}", + input.name(), + input.type_().rust_type_name(), + )); + abi_call.before(format!( + "let {} = {} as *const _ as i32;", + ptr.name(), + input.name(), + )); + } + BindingParam::Slice(ptr, len) => { + def.arg(format!( + "{}: &[{}]", + input.name(), + input.type_().rust_type_name(), + )); + + abi_call.before(format!( + "let {} = {}.as_ptr() as i32;", + ptr.name(), + input.name(), + )); + abi_call.before(format!( + "let {} = {}.len() as i32;", + len.name(), + input.name() + )); + } + BindingParam::Value(val) => { + def.arg(format!( + "{}: {}", + input.name(), + input.type_().rust_type_name(), + )); + abi_call.before(format!( + "let {} = {} as {};", + val.name(), + input.name(), + val.type_().rust_type_name(), + )); } } + } - for io in func.inout_bindings.iter() { - match &io.from { - BindingRef::Ptr(ptr_pos) => { - let ptr = func.get_param(ptr_pos).expect("valid param"); - def.arg(format!( - "{}: &mut {}", - io.name, - self.get_defined_typename(&io.type_) - )); - abi_call.before(format!("let {} = {} as *mut _ as i32;", ptr.name, io.name)); - abi_call.param(ptr_pos, ptr.name.clone()); - } - BindingRef::Slice(ptr_pos, len_pos) => { - let ptr = func.get_param(ptr_pos).expect("ptrid param"); - let len = func.get_param(len_pos).expect("lenid param"); - def.arg(format!( - "{}: &mut [{}]", - io.name, - self.get_defined_typename(&io.type_) - )); - abi_call.before(format!("let {} = {}.as_ptr() as i32;", ptr.name, io.name)); - abi_call.before(format!("let {} = {}.len() as i32;", len.name, io.name)); - abi_call.param(ptr_pos, ptr.name.clone()); - abi_call.param(len_pos, len.name.clone()); - } - BindingRef::Value(_val) => { - unreachable!("it should not be possible to have an inout value {:?}", io); - } + for io in func + .bindings() + .filter(|b| b.direction() == BindingDirection::InOut) + { + match &io.param() { + BindingParam::Ptr(ptr) => { + def.arg(format!( + "{}: &mut {}", + io.name(), + io.type_().rust_type_name(), + )); + abi_call.before(format!( + "let {} = {} as *mut _ as i32;", + ptr.name(), + io.name() + )); + } + BindingParam::Slice(ptr, len) => { + def.arg(format!( + "{}: &mut [{}]", + io.name(), + io.type_().rust_type_name(), + )); + abi_call.before(format!( + "let {} = {}.as_ptr() as i32;", + ptr.name(), + io.name() + )); + abi_call.before(format!("let {} = {}.len() as i32;", len.name(), io.name())); + } + BindingParam::Value(_val) => { + unreachable!("it should not be possible to have an inout value {:?}", io); } } + } - for o in func.out_bindings.iter() { - match &o.from { - BindingRef::Ptr(ptr_pos) => { - let ptr = func.get_param(ptr_pos).expect("valid param"); - let otypename = self.get_defined_typename(&o.type_); - def.ok_type(otypename.clone()); - abi_call.before(format!( - "let mut {} = ::std::mem::MaybeUninit::<{}>::uninit();", - ptr.name, otypename - )); - abi_call.param(ptr_pos, format!("{}.as_mut_ptr() as i32", ptr.name)); - abi_call.after(format!( - "let {} = unsafe {{ {}.assume_init() }};", - ptr.name, ptr.name - )); - def.ok_value(ptr.name.clone()); - } - BindingRef::Value(val_pos) => { - let val = func.get_param(val_pos).expect("valid param"); - def.ok_type(self.get_defined_typename(&o.type_)); - abi_call.param(val_pos, val.name.clone()); - abi_call.after(format!( - "let {} = {} as {};", - val.name, - val.name, - self.get_defined_typename(&o.type_), - )); - def.ok_value(val.name.clone()); - } - BindingRef::Slice(_ptr, _len) => { - unreachable!("it should not be possible to have an out slice {:?}", o); - } + for o in func + .bindings() + .filter(|b| b.direction() == BindingDirection::Out) + { + match &o.param() { + BindingParam::Ptr(ptr) => { + def.ok_type(o.type_().rust_type_name()); + abi_call.before(format!( + "let mut {}___MEM = ::std::mem::MaybeUninit::<{}>::uninit();", + ptr.name(), + o.type_().rust_type_name() + )); + abi_call.before(format!( + "let {} = {}___MEM.as_mut_ptr() as i32;", + ptr.name(), + ptr.name() + )); + abi_call.after(format!( + "let {} = unsafe {{ {}___MEM.assume_init() }};", + o.name(), + ptr.name() + )); + def.ok_value(o.name().to_owned()); + } + BindingParam::Value(val) => { + def.ok_type(o.type_().rust_type_name()); + abi_call.after(format!( + "let {} = {}::from({});", + o.name(), + o.type_().rust_type_name(), + val.name(), + )); + def.ok_value(o.name().to_owned()); + } + BindingParam::Slice(_ptr, _len) => { + unreachable!("it should not be possible to have an out slice {:?}", o); } } + } - def.render(&mut self.w, |mut w| abi_call.render(&mut w))?; + def.render(&mut self.w, |mut w| abi_call.render(&mut w))?; - Ok(()) - } + Ok(()) + } - fn host_abi_definition(&mut self, module: &Module, func: &FuncDecl) -> Result<(), IDLError> { - let mut args = vec![format!("&mut vmctx")]; - for a in func.args.iter() { - args.push(format!( - "{}: {}", - a.name.to_snake_case(), - Self::abitype_name(&a.type_) - )); - } + fn host_abi_definition(&mut self, func: &Function) -> Result<(), IDLError> { + let mut args = vec![format!("&mut vmctx")]; + for a in func.args() { + args.push(format!( + "{}: {}", + a.name().to_snake_case(), + a.type_().rust_type_name(), + )); + } - let abi_rettype = if func.rets.len() == 0 { - "()" - } else { - assert_eq!(func.rets.len(), 1); - Self::abitype_name(&func.rets[0].type_) - }; + let abi_rettype = func + .rets() + .map(|r| r.type_().rust_type_name()) + .rust_tuple_syntax(); - self.w - .writeln("#[no_mangle]") - .writeln(format!( - "// Wasm func {}::{}", - module.module_name, func.field_name - )) - .writeln(format!( - "pub unsafe extern \"C\" fn {}({},) -> {} {{", - func.binding_name, - args.join(", "), - abi_rettype - )); + self.w + .writeln("#[no_mangle]") + .writeln(format!( + "// Wasm func {}::{}", + func.module().name(), + func.name() + )) + .writeln(format!( + "pub unsafe extern \"C\" fn {}({},) -> {} {{", + func.host_func_name(), + args.join(", "), + abi_rettype + )); - self.w.indent(); + self.w.indent(); - let typename = module.module_name.to_camel_case(); + let trait_type_name = func.module().name().to_camel_case(); + self.w.writeln(format!( + "fn inner(heap: &mut [u8], obj: &mut dyn {}, {}) -> Result<{},()> {{", + trait_type_name, + func.args() + .map(|a| format!("{}: {}", a.name(), a.type_().rust_type_name(),)) + .collect::>() + .join(", "), + abi_rettype, + )); + self.w.indent(); + { + let (pre, post, trait_args, trait_rets, func_rets) = self.trait_dispatch(func); + self.w.writelns(&pre); self.w.writeln(format!( - "fn inner(heap: &mut [u8], obj: &mut dyn {}, {}) -> Result<{},()> {{", - typename, - func.args - .iter() - .map(|a| format!( - "{}: {}", - a.name.to_snake_case(), - Self::abitype_name(&a.type_) - )) - .collect::>() - .join(", "), - abi_rettype, + "let {} = obj.{}({})?;", + render_tuple(&trait_rets), + func.rust_name(), + trait_args.join(", ") )); - self.w.indent(); - { - let (pre, post, trait_args, trait_rets, func_rets) = self.trait_dispatch(module, func); - self.w.writelns(&pre); - self.w.writeln(format!( - "let {} = obj.{}({})?;", - render_tuple(&trait_rets), - func.field_name.to_snake_case(), - trait_args.join(", ") - )); - self.w.writelns(&post); - self.w.writeln(format!("Ok({})", render_tuple(&func_rets))); - } - self.w.eob().writeln("}"); + self.w.writelns(&post); + self.w.writeln(format!("Ok({})", render_tuple(&func_rets))); + } + self.w.eob().writeln("}"); - self.w.writeln(format!( + self.w.writeln(format!( "let mut ctx: ::std::cell::RefMut> = vmctx.get_embed_ctx_mut::>();", - typename = typename + typename =trait_type_name )); - self.w.writeln("let mut heap = vmctx.heap_mut();"); - self.w.writeln(format!( + self.w.writeln("let mut heap = vmctx.heap_mut();"); + self.w.writeln(format!( "match inner(&mut *heap, &mut **ctx, {}) {{ Ok(v) => v, Err(e) => lucet_hostcall_terminate!(\"FIXME\"), }}", - func.args - .iter() - .map(|a| a.name.to_snake_case()) + func.args() + .map(|a| a.name().to_owned()) .collect::>() .join(", "), )); - self.w.eob().writeln("}"); + self.w.eob().writeln("}"); - Ok(()) - } + Ok(()) + } - fn trait_dispatch( - &self, - module: &Module, - func: &FuncDecl, - ) -> ( - Vec, - Vec, - Vec, - Vec, - Vec, - ) { - let mut pre = Vec::new(); - let mut post = Vec::new(); - let mut trait_args = Vec::new(); - let mut trait_rets = Vec::new(); - let mut func_rets = Vec::new(); - - for input in func.in_bindings.iter() { - let input_mem = module.get_mem_area(&input.type_); - match &input.from { - BindingRef::Ptr(ptr_pos) => { - let ptr = func.get_param(ptr_pos).expect("valid param"); - pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name)); - pre.push(format!( - "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", - ptr = ptr.name, - align = input_mem.mem_align(), - )); - pre.push(format!( + fn trait_dispatch( + &self, + func: &Function, + ) -> ( + Vec, + Vec, + Vec, + Vec, + Vec, + ) { + let mut pre = Vec::new(); + let mut post = Vec::new(); + let mut trait_args = Vec::new(); + let mut trait_rets = Vec::new(); + let mut func_rets = Vec::new(); + + for input in func + .bindings() + .filter(|b| b.direction() == BindingDirection::In) + { + match input.param() { + BindingParam::Ptr(ptr) => { + pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name())); + pre.push(format!( + "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", + ptr = ptr.name(), + align = input.type_().mem_align(), + )); + pre.push(format!( "#[allow(non_snake_case)] let {name}___MEM: &[u8] = heap.get({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", - name = input.name, - ptr = ptr.name, - len = input_mem.mem_size(), + name = input.name(), + ptr = ptr.name(), + len = input.type_().mem_size(), )); - pre.push(format!( + pre.push(format!( "let {name}: &{typename} = unsafe {{ ({name}___MEM.as_ptr() as *const {typename}).as_ref().unwrap() }}; // convert pointer in linear memory to ref", - name = input.name, - typename = self.get_defined_typename(&input.type_), - )); - trait_args.push(input.name.clone()); - } - BindingRef::Slice(ptr_pos, len_pos) => { - let ptr = func.get_param(ptr_pos).expect("valid param"); - let len = func.get_param(len_pos).expect("valid param"); - - pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name)); - pre.push(format!("let {len} = {len} as usize;", len = len.name)); - pre.push(format!( - "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", - ptr = ptr.name, - align = input_mem.mem_align(), + name = input.name(), + typename = input.type_().rust_type_name(), )); - pre.push(format!( + trait_args.push(input.name().to_owned()); + } + BindingParam::Slice(ptr, len) => { + pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name())); + pre.push(format!("let {len} = {len} as usize;", len = len.name())); + pre.push(format!( + "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", + ptr = ptr.name(), + align = input.type_().mem_align(), + )); + pre.push(format!( "#[allow(non_snake_case)] let {name}___MEM: &[u8] = heap.get({ptr}..({ptr}+({len}*{elem_len}))).ok_or_else(|| () /* FIXME: bounds check failed */)?;", - name = input.name, - ptr = ptr.name, - len = len.name, - elem_len = input_mem.mem_size(), + name = input.name(), + ptr = ptr.name(), + len = len.name(), + elem_len = input.type_().mem_size(), )); - pre.push(format!( + pre.push(format!( "let {}: &[{}] = unsafe {{ ::std::slice::from_raw_parts({name}___MEM.as_ptr() as *const {typename}, {len}) }};", - name = input.name, - typename = self.get_defined_typename(&input.type_), - len = len.name, + name = input.name(), + typename = input.type_().rust_type_name(), + len = len.name(), )); - trait_args.push(input.name.clone()); - } - BindingRef::Value(value_pos) => { - let value = func.get_param(value_pos).expect("valid param"); - pre.push(format!( - "let {name}: {typename} = {value} as {typename};", - name = input.name, - typename = self.get_defined_typename(&input.type_), - value = value.name - )); - trait_args.push(value.name.clone()); - } + trait_args.push(input.name().to_owned()); + } + BindingParam::Value(value) => { + pre.push(format!( + "let {name}: {typename} = {value} as {typename};", + name = input.name(), + typename = input.type_().rust_type_name(), + value = value.name(), + )); + trait_args.push(value.name().to_owned()); } } - for io in func.inout_bindings.iter() { - let io_mem = module.get_mem_area(&io.type_); - match &io.from { - BindingRef::Ptr(ptr_pos) => { - let ptr = func.get_param(ptr_pos).expect("valid param"); - pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name)); - pre.push(format!( - "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", - ptr = ptr.name, - align = io_mem.mem_align(), - )); - pre.push(format!( + } + for io in func + .bindings() + .filter(|b| b.direction() == BindingDirection::InOut) + { + match io.param() { + BindingParam::Ptr(ptr) => { + pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name())); + pre.push(format!( + "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", + ptr = ptr.name(), + align = io.type_().mem_align(), + )); + pre.push(format!( "#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", - name = io.name, - ptr = ptr.name, - len = io_mem.mem_size(), + name = io.name(), + ptr = ptr.name(), + len = io.type_().mem_size(), )); - pre.push(format!( + pre.push(format!( "let mut {name}: &mut {typename} = unsafe {{ ({name}___MEM.as_mut_ptr() as *mut {typename}).as_mut().unwrap() }}; // convert pointer in linear memory to ref", - name = io.name, - typename = self.get_defined_typename(&io.type_), + name = io.name(), + typename = io.type_().rust_type_name(), )); - trait_args.push(format!("&mut {}", io.name)); - } - BindingRef::Slice(ptr_pos, len_pos) => { - let ptr = func.get_param(ptr_pos).expect("valid param"); - let len = func.get_param(len_pos).expect("valid param"); - - pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name)); - pre.push(format!("let {len} = {len} as usize;", len = len.name)); - pre.push(format!( - "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", - ptr = ptr.name, - align = io_mem.mem_align(), - )); - pre.push(format!( + trait_args.push(format!("&mut {}", io.name())); + } + BindingParam::Slice(ptr, len) => { + pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name())); + pre.push(format!("let {len} = {len} as usize;", len = len.name())); + pre.push(format!( + "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", + ptr = ptr.name(), + align = io.type_().mem_align(), + )); + pre.push(format!( "#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+({len}*{elem_len}))).ok_or_else(|| () /* FIXME: bounds check failed */)?;", - name = io.name, - ptr = ptr.name, - len = len.name, - elem_len = io_mem.mem_size(), + name = io.name(), + ptr = ptr.name(), + len = len.name(), + elem_len = io.type_().mem_size(), )); - pre.push(format!( + pre.push(format!( "let mut {}: &mut [{}] = unsafe {{ ::std::slice::from_raw_parts_mut({name}___MEM.as_mut_ptr() as *mut {typename}, {len}) }};", - name = io.name, - typename = self.get_defined_typename(&io.type_), - len = len.name, + name = io.name(), + typename = io.type_().rust_type_name(), + len = len.name(), )); - trait_args.push(format!("&mut {}", io.name.clone())); - } - BindingRef::Value { .. } => unreachable!(), + trait_args.push(format!("&mut {}", io.name())); } + BindingParam::Value { .. } => unreachable!(), } - for out in func.out_bindings.iter() { - let out_mem = module.get_mem_area(&out.type_); - match &out.from { - BindingRef::Ptr(ptr_pos) => { - let ptr = func.get_param(ptr_pos).expect("valid param"); - - pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name)); - pre.push(format!( - "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", - ptr = ptr.name, - align = out_mem.mem_align(), - )); - pre.push(format!( + } + for out in func + .bindings() + .filter(|b| b.direction() == BindingDirection::Out) + { + match out.param() { + BindingParam::Ptr(ptr) => { + pre.push(format!( + "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", + ptr = ptr.name(), + align = out.type_().mem_align(), + )); + pre.push(format!( "#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", - name = out.name, - ptr = ptr.name, - len = out_mem.mem_size(), + name = out.name(), + ptr = ptr.name(), + len = out.type_().mem_size(), )); - pre.push(format!( + pre.push(format!( "let mut {ptr}: &mut {typename} = unsafe {{ ({name}___MEM.as_mut_ptr() as *mut {typename}).as_mut().unwrap() }}; // convert pointer in linear memory to ref", - name = out.name, - typename = self.get_defined_typename(&out.type_), - ptr = ptr.name, + name = out.name(), + typename = out.type_().rust_type_name(), + ptr = ptr.name(), )); - trait_rets.push(out.name.clone()); - post.push(format!( - "*{} = {}; // Copy into out-pointer reference", - ptr.name, out.name, - )); - } - BindingRef::Value(value_pos) => { - let value = func.get_param(value_pos).expect("valid param"); - trait_rets.push(out.name.clone()); - post.push(format!( - "let {value}: {typename} = {arg} as {typename};", - value = value.name, - typename = Self::abitype_name(&value.type_), - arg = out.name, - )); - func_rets.push(value.name.clone()) - } - BindingRef::Slice { .. } => unreachable!(), + trait_rets.push(out.name().to_owned()); + post.push(format!( + "*{} = {}; // Copy into out-pointer reference", + ptr.name(), + out.name(), + )); } + BindingParam::Value(value) => { + trait_rets.push(out.name().to_owned()); + post.push(format!( + "let {value}: {typename} = {arg} as {typename};", + value = value.name(), + typename = value.type_().rust_type_name(), + arg = out.name(), + )); + func_rets.push(value.name().to_owned()) + } + BindingParam::Slice { .. } => unreachable!(), } - (pre, post, trait_args, trait_rets, func_rets) } + (pre, post, trait_args, trait_rets, func_rets) + } - fn host_trait_definition(&mut self, module: &Module) -> Result<(), IDLError> { - self.w - .writeln(format!( - "pub trait {} {{", - module.module_name.to_camel_case() - )) - .indent(); - for fdecl in module.func_decls() { - let func_name = fdecl.entity.field_name.to_snake_case(); - - let (mut args, rets) = self.trait_idiomatic_params(&fdecl.entity); - args.insert(0, "&mut self".to_owned()); + fn host_trait_definition(&mut self, module: &Module) -> Result<(), IDLError> { + self.w + .writeln(format!("pub trait {} {{", module.name().to_camel_case())) + .indent(); + for func in module.functions() { + let (mut args, rets) = self.trait_idiomatic_params(&func); + args.insert(0, "&mut self".to_owned()); - self.w.writeln(format!( - "fn {}({}) -> {};", - func_name, - args.join(", "), - format!("Result<{},()>", render_tuple(&rets)), - )); - } + self.w.writeln(format!( + "fn {}({}) -> {};", + func.rust_name(), + args.join(", "), + format!("Result<{},()>", render_tuple(&rets)), + )); + } - self.w.eob().writeln("}"); + self.w.eob().writeln("}"); - Ok(()) - } + Ok(()) + } - fn trait_idiomatic_params(&self, func: &FuncDecl) -> (Vec, Vec) { - let mut args = Vec::new(); - for input in func.in_bindings.iter() { - match &input.from { - BindingRef::Ptr { .. } => args.push(format!( - "{}: &{}", - input.name, - self.get_defined_typename(&input.type_) - )), - BindingRef::Slice { .. } => args.push(format!( - "{}: &[{}]", - input.name, - self.get_defined_typename(&input.type_) - )), - BindingRef::Value { .. } => args.push(format!( - "{}: {}", - input.name, - self.get_defined_typename(&input.type_) - )), - } + fn trait_idiomatic_params(&self, func: &Function) -> (Vec, Vec) { + let mut args = Vec::new(); + for input in func + .bindings() + .filter(|b| b.direction() == BindingDirection::In) + { + match &input.param() { + BindingParam::Ptr { .. } => args.push(format!( + "{}: &{}", + input.name(), + input.type_().rust_type_name(), + )), + BindingParam::Slice { .. } => args.push(format!( + "{}: &[{}]", + input.name(), + input.type_().rust_type_name(), + )), + BindingParam::Value { .. } => args.push(format!( + "{}: {}", + input.name(), + input.type_().rust_type_name(), + )), } - for io in func.inout_bindings.iter() { - match &io.from { - BindingRef::Ptr { .. } => args.push(format!( - "{}: &mut {}", - io.name, - self.get_defined_typename(&io.type_) - )), - BindingRef::Slice { .. } => args.push(format!( - "{}: &mut [{}]", - io.name, - self.get_defined_typename(&io.type_) - )), - BindingRef::Value { .. } => unreachable!(), - } + } + for io in func + .bindings() + .filter(|b| b.direction() == BindingDirection::InOut) + { + match &io.param() { + BindingParam::Ptr { .. } => args.push(format!( + "{}: &mut {}", + io.name(), + io.type_().rust_type_name(), + )), + BindingParam::Slice { .. } => args.push(format!( + "{}: &mut [{}]", + io.name(), + io.type_().rust_type_name(), + )), + BindingParam::Value { .. } => unreachable!(), } - let mut rets = Vec::new(); - for out in func.out_bindings.iter() { - match &out.from { - BindingRef::Ptr { .. } | BindingRef::Value { .. } => { - rets.push(format!("{}", self.get_defined_typename(&out.type_))) - } - BindingRef::Slice { .. } => unreachable!(), + } + let mut rets = Vec::new(); + for out in func + .bindings() + .filter(|b| b.direction() == BindingDirection::Out) + { + match &out.param() { + BindingParam::Ptr { .. } | BindingParam::Value { .. } => { + rets.push(format!("{}", out.type_().rust_type_name())) } + BindingParam::Slice { .. } => unreachable!(), } - (args, rets) } + (args, rets) + } - fn host_ensure_linked(&mut self, module: &Module) { - self.w.writeln("pub fn ensure_linked() {").indent(); - self.w.writeln("unsafe {"); - for fdecl in module.func_decls() { - self.w.writeln(format!( - "::std::ptr::read_volatile({} as *const extern \"C\" fn());", - fdecl.entity.binding_name, - )); - } - self.w.eob().writeln("}"); - self.w.eob().writeln("}"); + fn host_ensure_linked(&mut self, module: &Module) { + self.w.writeln("pub fn ensure_linked() {").indent(); + self.w.writeln("unsafe {"); + for func in module.functions() { + self.w.writeln(format!( + "::std::ptr::read_volatile({} as *const extern \"C\" fn());", + func.host_func_name(), + )); } - */ + self.w.eob().writeln("}"); + self.w.eob().writeln("}"); + } } fn gen_testcase(w: &mut PrettyWriter, name: &str, f: F) -> Result<(), IDLError> @@ -690,14 +684,6 @@ where Ok(()) } -pub fn render_tuple(members: &[String]) -> String { - match members.len() { - 0 => "()".to_owned(), - 1 => members[0].clone(), - _ => format!("({})", members.join(", ")), - } -} - trait RustTypeName { fn rust_type_name(&self) -> String; } @@ -750,16 +736,6 @@ impl Function<'_> { self.name().to_snake_case() ) } - /* - fn rust_idiomatic_args<'a>(&'a self) -> impl Iterator> { - unimplemented!() - //self.bindings().filter(|b| !binding_is_ret(b)) - } - fn rust_idiomatic_rets<'a>(&'a self) -> impl Iterator> { - unimplemented!() - //self.bindings().filter(|b| binding_is_ret(b)) - } - */ } impl Module<'_> { @@ -768,22 +744,24 @@ impl Module<'_> { } } -trait RustReturnSignature { - fn rust_return_signature(&mut self) -> String; +pub fn render_tuple(members: &[String]) -> String { + match members.len() { + 0 => "()".to_owned(), + 1 => members[0].clone(), + _ => format!("({})", members.join(", ")), + } +} + +pub trait RustTupleSyntax { + fn rust_tuple_syntax(&mut self) -> String; } -impl RustReturnSignature for I +impl RustTupleSyntax for I where I: Iterator, { - fn rust_return_signature(&mut self) -> String { - let mut rets = self.collect::>(); - if rets.len() == 0 { - "()".to_owned() - } else if rets.len() == 1 { - rets.pop().unwrap() - } else { - format!("({})", rets.join(", ")) - } + fn rust_tuple_syntax(&mut self) -> String { + let rets = self.collect::>(); + render_tuple(&rets) } } diff --git a/lucet-idl/src/rust/guest_funcs.rs b/lucet-idl/src/rust/guest_funcs.rs index 1e8521c8c..3e9199aa3 100644 --- a/lucet-idl/src/rust/guest_funcs.rs +++ b/lucet-idl/src/rust/guest_funcs.rs @@ -1,38 +1,21 @@ use super::render_tuple; use crate::error::IDLError; use crate::pretty_writer::PrettyWriter; -use crate::{Function, ParamPosition}; +use crate::Function; use heck::SnakeCase; pub struct AbiCallBuilder<'a> { func: Function<'a>, before: Vec, after: Vec, - args: Vec>, - rets: Vec>, } impl<'a> AbiCallBuilder<'a> { pub fn new(func: Function<'a>) -> Self { - let arg_len = func.args().collect::>().len(); - let ret_len = func.rets().collect::>().len(); AbiCallBuilder { func, before: Vec::new(), after: Vec::new(), - args: vec![None; arg_len], - rets: vec![None; ret_len], - } - } - - pub fn param(&mut self, position: &ParamPosition, value: String) { - match position { - ParamPosition::Arg(n) => { - self.args[*n] = Some(value); - } - ParamPosition::Ret(n) => { - self.rets[*n] = Some(value); - } } } @@ -48,27 +31,20 @@ impl<'a> AbiCallBuilder<'a> { let name = self.func.name().to_snake_case(); let arg_syntax = self - .args - .iter() - .map(|v| { - v.clone() - .ok_or(IDLError::InternalError("unconstructed abi arg")) - }) - .collect::, IDLError>>()? + .func + .args() + .map(|a| a.name().to_owned()) + .collect::>() .join(", "); let rets = self - .rets - .iter() - .map(|v| { - v.clone() - .ok_or(IDLError::InternalError("unconstructed abi ret")) - }) - .collect::, IDLError>>()?; + .func + .rets() + .map(|r| r.name().to_owned()) + .collect::>(); let ret_syntax = if rets.is_empty() { String::new() } else { - assert_eq!(rets.len(), 1); - format!("let {} = ", rets[0]) + format!("let {} = ", render_tuple(&rets)) }; w.writelns(&self.before); diff --git a/lucet-idl/tests/example.rs b/lucet-idl/tests/example.rs index 001730d63..85f22ff21 100644 --- a/lucet-idl/tests/example.rs +++ b/lucet-idl/tests/example.rs @@ -44,10 +44,13 @@ fn compile_and_test_rust_guest() { compile_and_test_rust(lucet_idl::Backend::RustGuest) } +/* DISABLED: host needs the lucet_hostcalls! macro from lucet_runtime, + * and we dont want to manage the dep here, lucet-idl-test can handle it #[test] fn compile_and_test_rust_host() { compile_and_test_rust(lucet_idl::Backend::RustHost) } +*/ fn compile_and_test_rust(backend: lucet_idl::Backend) { let mut source = String::new(); From f8e44e172137fe65795ce7a77c725b22bd52d77c Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 5 Aug 2019 21:19:43 -0700 Subject: [PATCH 331/512] lucet-idl-test: fixup most issues --- lucet-idl/lucet-idl-test/src/host.rs | 8 +- lucet-idl/lucet-idl-test/src/values.rs | 225 ++++++++++++------------- lucet-idl/src/cursor.rs | 1 + lucet-idl/src/lib.rs | 20 ++- 4 files changed, 128 insertions(+), 126 deletions(-) diff --git a/lucet-idl/lucet-idl-test/src/host.rs b/lucet-idl/lucet-idl-test/src/host.rs index 05e06c4b8..9d36c5590 100644 --- a/lucet-idl/lucet-idl-test/src/host.rs +++ b/lucet-idl/lucet-idl-test/src/host.rs @@ -17,7 +17,7 @@ pub struct HostApp { impl HostApp { pub fn new(package: &Package) -> Result { - if package.modules.len() != 1 { + if package.modules().collect::>().len() != 1 { Err(format_err!( "only one module per package supported at this time" ))? @@ -54,10 +54,12 @@ impl HostApp { )?; let harness_file = hostapp.source_file("harness.rs")?; - self.test_harness( + /* FIXME + test_harness( Box::new(harness_file), package.modules.get(0).expect("one module per package"), )?; + */ Ok(hostapp) } @@ -113,5 +115,3 @@ impl Drop for HostApp { } } } - -fn test_harness(out: Box, module: &Module) -> Result<(), Error> {} diff --git a/lucet-idl/lucet-idl-test/src/values.rs b/lucet-idl/lucet-idl-test/src/values.rs index e6789313a..55d3bb2b9 100644 --- a/lucet-idl/lucet-idl-test/src/values.rs +++ b/lucet-idl/lucet-idl-test/src/values.rs @@ -1,7 +1,7 @@ use heck::CamelCase; use lucet_idl::{ - AliasDataType, AtomType, BindingRef, DataTypeRef, DataTypeVariant, EnumDataType, FuncBinding, - FuncDecl, Module, Named, StructDataType, StructMember, + AliasDatatype, AtomType, BindingDirection, BindingParam, Datatype, DatatypeVariant, + EnumDatatype, FuncBinding, Function, Module, StructDatatype, StructMember, }; use proptest::prelude::*; @@ -60,11 +60,17 @@ pub struct EnumVal { } impl EnumVal { - pub fn strat(enum_datatype: &Named) -> impl Strategy { - let name = enum_datatype.name.name.clone(); - prop::sample::select(enum_datatype.entity.members.clone()).prop_map(move |mem| EnumVal { + pub fn strat(enum_datatype: &EnumDatatype) -> impl Strategy { + let name = enum_datatype.name().to_owned(); + prop::sample::select( + enum_datatype + .variants() + .map(|v| v.name().to_owned()) + .collect::>(), + ) + .prop_map(move |mem_name| EnumVal { enum_name: name.clone(), - member_name: mem.name, + member_name: mem_name.clone(), }) } pub fn render_rustval(&self) -> String { @@ -83,13 +89,11 @@ pub struct StructVal { } impl StructVal { - pub fn strat(struct_dt: &Named, module: &Module) -> BoxedStrategy { - let name = struct_dt.name.name.clone(); + pub fn strat(struct_dt: &StructDatatype) -> BoxedStrategy { + let name = struct_dt.name().to_owned(); let member_strats: Vec> = struct_dt - .entity - .members - .iter() - .map(|m| StructMemberVal::strat(m, module)) + .members() + .map(|m| StructMemberVal::strat(&m)) .collect(); member_strats .prop_map(move |members| StructVal { @@ -115,14 +119,15 @@ impl StructVal { #[derive(Debug, Clone, PartialEq)] pub struct StructMemberVal { pub name: String, - pub value: Box, + pub value: Box, } impl StructMemberVal { - pub fn strat(struct_member: &StructMember, module: &Module) -> BoxedStrategy { - let name = struct_member.name.clone(); - module - .datatype_strat(&struct_member.type_) + pub fn strat(struct_member: &StructMember) -> BoxedStrategy { + let name = struct_member.name().to_owned(); + struct_member + .type_() + .strat() .prop_map(move |value| StructMemberVal { name: name.clone(), value: Box::new(value), @@ -134,14 +139,15 @@ impl StructMemberVal { #[derive(Debug, Clone, PartialEq)] pub struct AliasVal { pub name: String, - pub value: Box, + pub value: Box, } impl AliasVal { - pub fn strat(alias_dt: &Named, module: &Module) -> BoxedStrategy { - let name = alias_dt.name.name.clone(); - module - .datatype_strat(&alias_dt.entity.to) + pub fn strat(alias_dt: &AliasDatatype) -> BoxedStrategy { + let name = alias_dt.name().to_owned(); + alias_dt + .to() + .strat() .prop_map(move |value| AliasVal { name: name.clone(), value: Box::new(value), @@ -154,58 +160,43 @@ impl AliasVal { } #[derive(Debug, Clone, PartialEq)] -pub enum DataTypeVal { +pub enum DatatypeVal { Enum(EnumVal), Struct(StructVal), Alias(AliasVal), Atom(AtomVal), } -impl DataTypeVal { +impl DatatypeVal { pub fn render_rustval(&self) -> String { match self { - DataTypeVal::Enum(a) => a.render_rustval(), - DataTypeVal::Struct(a) => a.render_rustval(), - DataTypeVal::Alias(a) => a.render_rustval(), - DataTypeVal::Atom(a) => a.render_rustval(), + DatatypeVal::Enum(a) => a.render_rustval(), + DatatypeVal::Struct(a) => a.render_rustval(), + DatatypeVal::Alias(a) => a.render_rustval(), + DatatypeVal::Atom(a) => a.render_rustval(), } } } -pub trait ModuleExt { - fn datatype_strat(&self, dtref: &DataTypeRef) -> BoxedStrategy; - fn function_strat(&self) -> BoxedStrategy; +pub trait DatatypeExt { + fn strat(&self) -> BoxedStrategy; } -impl ModuleExt for Module { - fn datatype_strat(&self, dtref: &DataTypeRef) -> BoxedStrategy { - match dtref { - DataTypeRef::Defined(ident) => { - let dt = self.get_datatype(*ident).expect("ref to defined datatype"); - match dt.entity.variant { - DataTypeVariant::Struct(ref struct_dt) => { - StructVal::strat(&dt.using_name(struct_dt), self) - .prop_map(DataTypeVal::Struct) - .boxed() - } - DataTypeVariant::Enum(ref enum_dt) => EnumVal::strat(&dt.using_name(enum_dt)) - .prop_map(DataTypeVal::Enum) - .boxed(), - DataTypeVariant::Alias(ref alias_dt) => { - AliasVal::strat(&dt.using_name(alias_dt), self) - .prop_map(DataTypeVal::Alias) - .boxed() - } - } +impl<'a> DatatypeExt for Datatype<'a> { + fn strat(&self) -> BoxedStrategy { + match self.variant() { + DatatypeVariant::Struct(ref struct_dt) => StructVal::strat(struct_dt) + .prop_map(DatatypeVal::Struct) + .boxed(), + DatatypeVariant::Enum(ref enum_dt) => { + EnumVal::strat(enum_dt).prop_map(DatatypeVal::Enum).boxed() } - DataTypeRef::Atom(a) => AtomVal::strat(&a).prop_map(DataTypeVal::Atom).boxed(), + DatatypeVariant::Alias(ref alias_dt) => AliasVal::strat(alias_dt) + .prop_map(DatatypeVal::Alias) + .boxed(), + DatatypeVariant::Atom(a) => AtomVal::strat(&a).prop_map(DatatypeVal::Atom).boxed(), } } - - fn function_strat(&self) -> BoxedStrategy { - let decls = self.funcs.values().cloned().collect::>(); - prop::sample::select(decls).boxed() - } } #[derive(Debug, Clone, PartialEq)] @@ -217,40 +208,40 @@ pub struct BindingVal { #[derive(Debug, Clone, PartialEq)] pub enum BindingValVariant { - Value(DataTypeVal), - Ptr(DataTypeVal), - Array(Vec), + Value(DatatypeVal), + Ptr(DatatypeVal), + Array(Vec), } impl BindingVal { - fn binding_strat(module: &Module, binding: &FuncBinding, mutable: bool) -> BoxedStrategy { - let name = binding.name.clone(); - match binding.from { - BindingRef::Value(_) => module - .datatype_strat(&binding.type_) + fn binding_strat(binding: &FuncBinding, mutable: bool) -> BoxedStrategy { + let name = binding.name().to_owned(); + match binding.param() { + BindingParam::Value(_) => binding + .type_() + .strat() .prop_map(move |v| BindingVal { name: name.clone(), mutable, variant: BindingValVariant::Value(v), }) .boxed(), - BindingRef::Ptr(_) => module - .datatype_strat(&binding.type_) + BindingParam::Ptr(_) => binding + .type_() + .strat() .prop_map(move |v| BindingVal { name: name.clone(), mutable, variant: BindingValVariant::Ptr(v), }) .boxed(), - BindingRef::Slice(_, _) => { - prop::collection::vec(module.datatype_strat(&binding.type_), 100) - .prop_map(move |v| BindingVal { - name: name.clone(), - mutable, - variant: BindingValVariant::Array(v), - }) - .boxed() - } + BindingParam::Slice(_, _) => prop::collection::vec(binding.type_().strat(), 100) + .prop_map(move |v| BindingVal { + name: name.clone(), + mutable, + variant: BindingValVariant::Array(v), + }) + .boxed(), } } fn render_rust_binding(&self) -> String { @@ -292,41 +283,39 @@ impl BindingVal { } #[derive(Debug, Clone)] -pub struct FuncCallPredicate { - func: FuncDecl, +pub struct FuncCallPredicate<'a> { + func: &'a Function<'a>, pre: Vec, post: Vec, } -impl FuncCallPredicate { - pub fn strat(module: &Module, func: &FuncDecl) -> BoxedStrategy { +impl<'a> FuncCallPredicate<'a> { + pub fn strat(func: &Function<'a>) -> BoxedStrategy> { let mut pre_strat: Vec> = func - .in_bindings - .iter() - .map(|binding| BindingVal::binding_strat(module, binding, false)) + .bindings() + .filter(|b| b.direction() == BindingDirection::In) + .map(|binding| BindingVal::binding_strat(&binding, false)) .collect(); pre_strat.append( &mut func - .inout_bindings - .iter() - .map(|binding| BindingVal::binding_strat(module, binding, true)) + .bindings() + .filter(|b| b.direction() == BindingDirection::InOut) + .map(|binding| BindingVal::binding_strat(&binding, true)) .collect(), ); let post_strat: Vec> = func - .inout_bindings - .iter() - .chain(func.out_bindings.iter()) - .map(|binding| BindingVal::binding_strat(module, binding, false)) + .bindings() + .filter(|b| b.direction() == BindingDirection::InOut) + .chain( + func.bindings() + .filter(|b| b.direction() == BindingDirection::Out), + ) + .map(|binding| BindingVal::binding_strat(&binding, false)) .collect(); - let func = func.clone(); (pre_strat, post_strat) - .prop_map(move |(pre, post)| FuncCallPredicate { - pre, - post, - func: func.clone(), - }) + .prop_map(move |(pre, post)| FuncCallPredicate { pre, post, func }) .boxed() } @@ -338,18 +327,26 @@ impl FuncCallPredicate { .collect(); let mut arg_syntax = Vec::new(); - for in_binding in self.func.in_bindings.iter() { - arg_syntax.push(match in_binding.from { - BindingRef::Ptr(_) => format!("&{}", in_binding.name), - BindingRef::Slice(_, _) => format!("&{}", in_binding.name), - BindingRef::Value(_) => in_binding.name.clone(), + for in_binding in self + .func + .bindings() + .filter(|b| b.direction() == BindingDirection::In) + { + arg_syntax.push(match in_binding.param() { + BindingParam::Ptr(_) => format!("&{}", in_binding.name()), + BindingParam::Slice(_, _) => format!("&{}", in_binding.name()), + BindingParam::Value(_) => in_binding.name().to_owned(), }) } - for io_binding in self.func.inout_bindings.iter() { - arg_syntax.push(match io_binding.from { - BindingRef::Ptr(_) => format!("&mut {}", io_binding.name), - BindingRef::Slice(_, _) => format!("&mut {}", io_binding.name), - BindingRef::Value(_) => unreachable!("should be no such thing as an io value"), + for io_binding in self + .func + .bindings() + .filter(|b| b.direction() == BindingDirection::InOut) + { + arg_syntax.push(match io_binding.param() { + BindingParam::Ptr(_) => format!("&mut {}", io_binding.name()), + BindingParam::Slice(_, _) => format!("&mut {}", io_binding.name()), + BindingParam::Value(_) => unreachable!("should be no such thing as an io value"), }) } @@ -357,13 +354,13 @@ impl FuncCallPredicate { "let {} = {}({});", render_tuple( self.func - .out_bindings - .iter() - .map(|b| b.name.clone()) + .bindings() + .filter(|b| b.direction() == BindingDirection::In) + .map(|b| b.name().to_owned()) .collect::>(), "_" ), - self.func.field_name, + self.func.name(), arg_syntax.join(",") )); lines.append( @@ -402,10 +399,11 @@ impl FuncCallPredicate { lines.push("struct TestHarness;".to_owned()); lines.push(format!( "impl {} for TesHarnesst {{", - module.module_name.to_camel_case() + module.name().to_camel_case() )); - for func in module.func_decls() { - let func = func.entity; + for func in module.functions() { + lines.push(format!("/* FIXME: method {} */", func.name())); + /* let mut args: Vec = Vec::new(); for input in func.in_bindings.iter() {} let mut rets = Vec::new(); @@ -421,6 +419,7 @@ impl FuncCallPredicate { lines.push("panic!(\"should not be called\")".to_owned()); } lines.push("}".to_owned()); + */ } lines.push("}".to_owned()); lines diff --git a/lucet-idl/src/cursor.rs b/lucet-idl/src/cursor.rs index a2455e06a..f921359b2 100644 --- a/lucet-idl/src/cursor.rs +++ b/lucet-idl/src/cursor.rs @@ -329,6 +329,7 @@ impl<'a> From> for Datatype<'a> { } } +#[derive(Debug, Clone)] pub struct EnumMember<'a> { enum_: EnumDatatype<'a>, index: usize, diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 4bd8911d0..4f8119e79 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -52,7 +52,7 @@ pub fn codegen(package: &Package, config: &Config, output: Box) -> Re Backend::CGuest => CGenerator::new(output).generate_guest(package)?, Backend::RustGuest => RustGenerator::new(output).generate_guest(package)?, Backend::RustHost => RustGenerator::new(output).generate_host(package)?, - Backend::Bindings => generate_bindings(&create_bindings(package), output)?, + Backend::Bindings => generate_bindings(&package.bindings(), output)?, } Ok(()) } @@ -62,16 +62,18 @@ pub fn run(config: &Config, input: &str, output: Box) -> Result<(), I codegen(&pkg, config, output) } -fn create_bindings(package: &Package) -> Bindings { - let mut bs = HashMap::new(); - for m in package.modules() { - let mut mod_bs = HashMap::new(); - for f in m.functions() { - mod_bs.insert(f.name().to_owned(), f.host_func_name()); +impl Package { + pub fn bindings(&self) -> Bindings { + let mut bs = HashMap::new(); + for m in self.modules() { + let mut mod_bs = HashMap::new(); + for f in m.functions() { + mod_bs.insert(f.name().to_owned(), f.host_func_name()); + } + bs.insert(m.name().to_owned(), mod_bs); } - bs.insert(m.name().to_owned(), mod_bs); + Bindings::new(bs) } - Bindings::new(bs) } fn generate_bindings(bindings: &Bindings, mut output: Box) -> Result<(), IDLError> { From 2fad163d325d50fe567e9ba9cb10f9adb748a921 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 6 Aug 2019 13:50:26 -0700 Subject: [PATCH 332/512] lucet-idl: move atomtype/abitype parsing from lexer to validator --- lucet-idl/src/atoms.rs | 54 ++++++++ lucet-idl/src/cursor.rs | 39 +++--- lucet-idl/src/lexer.rs | 37 +----- lucet-idl/src/parser.rs | 190 ++++++++++++++++------------ lucet-idl/src/prelude.rs | 27 ++-- lucet-idl/src/validate/datatypes.rs | 4 +- lucet-idl/src/validate/function.rs | 36 +++--- lucet-idl/src/validate/names.rs | 24 ++-- 8 files changed, 232 insertions(+), 179 deletions(-) diff --git a/lucet-idl/src/atoms.rs b/lucet-idl/src/atoms.rs index 420f474c3..60b696fbd 100644 --- a/lucet-idl/src/atoms.rs +++ b/lucet-idl/src/atoms.rs @@ -30,6 +30,46 @@ impl MemArea for AtomType { } } +const ATOM_TYPE_NAMES: &'static [(AtomType, &'static str)] = &[ + (AtomType::Bool, "bool"), + (AtomType::U8, "u8"), + (AtomType::U16, "u16"), + (AtomType::U32, "u32"), + (AtomType::U64, "u64"), + (AtomType::I8, "i8"), + (AtomType::I16, "i16"), + (AtomType::I32, "i32"), + (AtomType::I64, "i64"), + (AtomType::F32, "f32"), + (AtomType::F64, "f64"), +]; + +#[cfg(test)] +#[test] +fn atom_type_names_are_indexed_correctly() { + for (ix, (atom, _name)) in ATOM_TYPE_NAMES.iter().enumerate() { + assert_eq!(ix, *atom as usize); + } +} + +impl ::std::convert::TryFrom<&str> for AtomType { + type Error = (); + fn try_from(name: &str) -> Result { + ATOM_TYPE_NAMES + .iter() + .find(|(_a, n)| *n == name) + .map(|(a, _n)| a.clone()) + .ok_or(()) + } +} + +impl ::std::fmt::Display for AtomType { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + let (_a, n) = ATOM_TYPE_NAMES[*self as usize]; + write!(f, "{}", n) + } +} + #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum AbiType { I32, @@ -88,3 +128,17 @@ impl MemArea for AbiType { self.mem_size() } } + +impl ::std::convert::TryFrom<&str> for AbiType { + type Error = (); + fn try_from(name: &str) -> Result { + let atom = AtomType::try_from(name)?; + Self::of_atom(atom).ok_or(()) + } +} + +impl ::std::fmt::Display for AbiType { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + write!(f, "{}", AtomType::from(self.clone())) + } +} diff --git a/lucet-idl/src/cursor.rs b/lucet-idl/src/cursor.rs index f921359b2..8d28be679 100644 --- a/lucet-idl/src/cursor.rs +++ b/lucet-idl/src/cursor.rs @@ -1,5 +1,4 @@ pub use crate::atoms::{AbiType, AtomType}; -use crate::parser::SyntaxTypeRef; use crate::repr::{ AliasDatatypeRepr, BindingFromRepr, BindingIx, BindingRepr, DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, EnumDatatypeRepr, FuncIdent, FuncIx, FuncRepr, ModuleIx, @@ -7,6 +6,7 @@ use crate::repr::{ }; pub use crate::repr::{BindingDirection, Package}; use crate::MemArea; +use std::convert::TryFrom; use std::ops::Deref; impl Package { @@ -17,11 +17,12 @@ impl Package { .and_then(|(ix, _)| self.module_by_ix(ix)) } + fn all_modules<'a>(&'a self) -> impl Iterator> + 'a { + self.names.keys().map(move |ix| Module { pkg: &self, ix }) + } + pub fn modules<'a>(&'a self) -> impl Iterator> + 'a { - self.names - .keys() - .map(move |ix| Module { pkg: &self, ix }) - .filter(|m| m.name() != "std") + self.all_modules().filter(|m| m.name() != "std") } pub fn module_by_ix<'a>(&'a self, ix: ModuleIx) -> Option> { @@ -58,12 +59,20 @@ impl<'a> Module<'a> { } pub fn datatype(&self, name: &str) -> Option> { - self.repr() - .datatypes - .names - .iter() - .find(|(_, n)| *n == name) - .and_then(|(ix, _)| self.datatype_by_ix(ix)) + if let Ok(atom) = AtomType::try_from(name) { + Some( + self.pkg + .datatype_by_id(atom.datatype_id()) + .expect("atom from id"), + ) + } else { + self.repr() + .datatypes + .names + .iter() + .find(|(_, n)| *n == name) + .and_then(|(ix, _)| self.datatype_by_ix(ix)) + } } pub fn datatype_by_ix(&self, ix: DatatypeIx) -> Option> { @@ -90,14 +99,6 @@ impl<'a> Module<'a> { }) } - // XXX move this to a trait that we dont export, eventaully... - pub fn datatype_by_syntax(&self, tref: &SyntaxTypeRef) -> Option> { - match tref { - SyntaxTypeRef::Name { name, .. } => self.datatype(name), - SyntaxTypeRef::Atom { atom, .. } => self.package().datatype_by_id(atom.datatype_id()), - } - } - pub fn function(&self, name: &str) -> Option> { self.repr() .funcs diff --git a/lucet-idl/src/lexer.rs b/lucet-idl/src/lexer.rs index 91200ca89..59b86e60a 100644 --- a/lucet-idl/src/lexer.rs +++ b/lucet-idl/src/lexer.rs @@ -1,4 +1,4 @@ -use crate::{AtomType, Location}; +use crate::Location; use std::str::CharIndices; #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -17,7 +17,6 @@ pub enum Token<'a> { Equals, // = LArrow, // <- RArrow, // -> - Atom(AtomType), Word(&'a str), Quote(&'a str), // Found between balanced "". No escaping. } @@ -135,23 +134,7 @@ impl<'a> Lexer<'a> { } } let text = &self.source[begin..self.pos]; - token( - match text { - "bool" => Token::Atom(AtomType::Bool), - "i8" => Token::Atom(AtomType::I8), - "i16" => Token::Atom(AtomType::I16), - "i32" => Token::Atom(AtomType::I32), - "i64" => Token::Atom(AtomType::I64), - "u8" => Token::Atom(AtomType::U8), - "u16" => Token::Atom(AtomType::U16), - "u32" => Token::Atom(AtomType::U32), - "u64" => Token::Atom(AtomType::U64), - "f32" => Token::Atom(AtomType::F32), - "f64" => Token::Atom(AtomType::F64), - _ => Token::Word(text), - }, - loc, - ) + token(Token::Word(text), loc) } fn scan_comment(&mut self) -> Result<(), LocatedError> { @@ -286,22 +269,6 @@ mod tests { Some(super::error(err, Location { line, column })) } - #[test] - fn atoms() { - let mut lex = Lexer::new("i8 i16 i32 i64\nu8 u16 u32 u64\nf32 f64"); - assert_eq!(lex.next(), token(Token::Atom(AtomType::I8), 1, 0)); - assert_eq!(lex.next(), token(Token::Atom(AtomType::I16), 1, 3)); - assert_eq!(lex.next(), token(Token::Atom(AtomType::I32), 1, 7)); - assert_eq!(lex.next(), token(Token::Atom(AtomType::I64), 1, 11)); - assert_eq!(lex.next(), token(Token::Atom(AtomType::U8), 2, 0)); - assert_eq!(lex.next(), token(Token::Atom(AtomType::U16), 2, 3)); - assert_eq!(lex.next(), token(Token::Atom(AtomType::U32), 2, 7)); - assert_eq!(lex.next(), token(Token::Atom(AtomType::U64), 2, 11)); - assert_eq!(lex.next(), token(Token::Atom(AtomType::F32), 3, 0)); - assert_eq!(lex.next(), token(Token::Atom(AtomType::F64), 3, 4)); - assert_eq!(lex.next(), None); - } - #[test] fn comments() { let mut lex = Lexer::new("the quick // brown fox\njumped\n//over the three\nlazy//dogs"); diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index 15101534c..979c44837 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -1,5 +1,5 @@ use super::lexer::{LexError, Lexer, LocatedError, LocatedToken, Token}; -use super::{AbiType, AtomType, Location}; +use super::Location; use std::error::Error; use std::fmt; @@ -17,7 +17,7 @@ pub enum SyntaxDecl { }, Alias { name: String, - what: SyntaxTypeRef, + what: SyntaxIdent, location: Location, }, Module { @@ -47,15 +47,15 @@ impl SyntaxDecl { } #[derive(Debug, PartialEq, Eq, Clone)] -pub enum SyntaxTypeRef { - Atom { atom: AtomType, location: Location }, - Name { name: String, location: Location }, +pub struct SyntaxIdent { + pub name: String, + pub location: Location, } #[derive(Debug, PartialEq, Eq, Clone)] pub struct StructMember { pub name: String, - pub type_: SyntaxTypeRef, + pub type_: SyntaxIdent, pub location: Location, } @@ -68,7 +68,7 @@ pub struct EnumVariant { #[derive(Debug, PartialEq, Eq, Clone)] pub struct FuncArgSyntax { pub name: String, - pub type_: AbiType, + pub type_: SyntaxIdent, pub location: Location, } @@ -88,7 +88,7 @@ pub enum BindingDirSyntax { #[derive(Debug, PartialEq, Eq, Clone)] pub struct BindingSyntax { pub name: String, - pub type_: SyntaxTypeRef, + pub type_: SyntaxIdent, pub direction: BindingDirSyntax, pub from: BindingRefSyntax, pub location: Location, @@ -211,7 +211,7 @@ impl<'a> Parser<'a> { let location = self.location; self.consume(); self.match_token(Token::Colon, "expected :")?; - let member_ref = self.match_ref("expected member type")?; + let member_ref = self.match_ident("expected member type")?; members.push(StructMember { name: member_name.to_string(), type_: member_ref, @@ -283,7 +283,7 @@ impl<'a> Parser<'a> { let location = self.location; self.consume(); self.match_token(Token::Colon, "expected :")?; - let type_ = self.match_abitype()?; + let type_ = self.match_ident("type name")?; args.push(FuncArgSyntax { name: name.to_string(), @@ -319,7 +319,7 @@ impl<'a> Parser<'a> { let location = self.location; self.consume(); self.match_token(Token::Colon, "expected :")?; - let type_ = self.match_abitype()?; + let type_ = self.match_ident("type name")?; args.push(FuncArgSyntax { type_, name: name.to_string(), @@ -352,7 +352,7 @@ impl<'a> Parser<'a> { self.consume(); self.match_token(Token::Colon, "expected :")?; let direction = self.match_bind_direction()?; - let type_ = self.match_ref("type value")?; + let type_ = self.match_ident("type name")?; self.match_token(Token::LArrow, "expected <-")?; let from = self.match_binding_ref()?; bindings.push(BindingSyntax { @@ -458,7 +458,7 @@ impl<'a> Parser<'a> { self.consume(); let name = err_ctx!(err_msg, self.match_a_word("expected type name"))?; err_ctx!(err_msg, self.match_token(Token::Equals, "expected ="))?; - let what = self.match_ref("type value")?; + let what = self.match_ident("type value")?; err_ctx!(err_msg, self.match_token(Token::Semi, "expected ;"))?; return Ok(Some(SyntaxDecl::Alias { name: name.to_owned(), @@ -561,39 +561,17 @@ impl<'a> Parser<'a> { Ok(decls) } - fn match_ref(&mut self, err_msg: &str) -> Result { + fn match_ident(&mut self, err_msg: &str) -> Result { match self.token() { - Some(Token::Atom(atom)) => { - let location = self.location; - self.consume(); - Ok(SyntaxTypeRef::Atom { atom, location }) - } Some(Token::Word(name)) => { let location = self.location; self.consume(); - Ok(SyntaxTypeRef::Name { + Ok(SyntaxIdent { name: name.to_string(), location, }) } - _ => err_ctx!( - err_msg, - parse_err!(self.location, "expected atom, or type name") - ), - } - } - - fn match_abitype(&mut self) -> Result { - match self.token() { - Some(Token::Atom(atom)) => match AbiType::of_atom(atom) { - Some(abitype) => { - self.consume(); - Ok(abitype) - } - None => parse_err!(self.location, "expected abi type, got non-abi atom type"), - }, - Some(Token::Word(w)) => parse_err!(self.location, "expected abi type, got '{}'", w), - _ => parse_err!(self.location, "expected abi type"), + _ => err_ctx!(err_msg, parse_err!(self.location, "expected identifier")), } } } @@ -629,8 +607,8 @@ mod tests { name: "foo".to_string(), members: vec![StructMember { name: "a".to_owned(), - type_: SyntaxTypeRef::Atom { - atom: AtomType::I32, + type_: SyntaxIdent { + name: "i32".to_owned(), location: Location { line: 1, column: 15, @@ -658,8 +636,8 @@ mod tests { name: "foo".to_string(), members: vec![StructMember { name: "b".to_owned(), - type_: SyntaxTypeRef::Atom { - atom: AtomType::I32, + type_: SyntaxIdent { + name: "i32".to_owned(), location: Location { line: 1, column: 15, @@ -688,8 +666,8 @@ mod tests { members: vec![ StructMember { name: "d".to_owned(), - type_: SyntaxTypeRef::Atom { - atom: AtomType::F64, + type_: SyntaxIdent { + name: "f64".to_owned(), location: Location { line: 1, column: 14, @@ -702,8 +680,8 @@ mod tests { }, StructMember { name: "e".to_owned(), - type_: SyntaxTypeRef::Atom { - atom: AtomType::U8, + type_: SyntaxIdent { + name: "u8".to_owned(), location: Location { line: 1, column: 22, @@ -734,7 +712,7 @@ mod tests { members: vec![ StructMember { name: "a".to_owned(), - type_: SyntaxTypeRef::Name { + type_: SyntaxIdent { name: "mod".to_owned(), location: Location { line: 1, @@ -748,7 +726,7 @@ mod tests { }, StructMember { name: "struct".to_owned(), - type_: SyntaxTypeRef::Name { + type_: SyntaxIdent { name: "enum".to_owned(), location: Location { line: 1, @@ -985,40 +963,48 @@ mod tests { #[test] fn fn_return_i32() { - let canonical = vec![SyntaxDecl::Function { - name: "getch".to_owned(), - args: Vec::new(), - rets: vec![FuncArgSyntax { - type_: AbiType::I32, - name: "r".to_owned(), - location: Location { - line: 1, - column: 14, - }, - }], - bindings: Vec::new(), - location: Location { line: 1, column: 0 }, - }]; + fn canonical(column: usize) -> Vec { + vec![SyntaxDecl::Function { + name: "getch".to_owned(), + args: Vec::new(), + rets: vec![FuncArgSyntax { + type_: SyntaxIdent { + name: "i32".to_owned(), + location: Location { + line: 1, + column: column, + }, + }, + name: "r".to_owned(), + location: Location { + line: 1, + column: 14, + }, + }], + bindings: Vec::new(), + location: Location { line: 1, column: 0 }, + }] + } assert_eq!( Parser::new("fn getch() -> r:i32;") - // 0 5 10 + // 0 5 10 15 .match_decls() .expect("valid decls"), - canonical + canonical(16) ); assert_eq!( Parser::new("fn getch() -> r: i32,;") // 0 5 10 .match_decls() .expect("valid decls"), - canonical + canonical(17) ); assert_eq!( Parser::new("fn getch() -> r :i32 , ;") // 0 5 10 .match_decls() .expect("valid decls"), - canonical + canonical(17) ); } @@ -1027,7 +1013,13 @@ mod tests { let canonical = SyntaxDecl::Function { name: "foo".to_owned(), args: vec![FuncArgSyntax { - type_: AbiType::I32, + type_: SyntaxIdent { + name: "i32".to_owned(), + location: Location { + line: 1, + column: 10, + }, + }, name: "a".to_owned(), location: Location { line: 1, column: 7 }, }], @@ -1059,12 +1051,24 @@ mod tests { name: "foo".to_owned(), args: vec![ FuncArgSyntax { - type_: AbiType::I32, + type_: SyntaxIdent { + name: "i32".to_owned(), + location: Location { + line: 1, + column: 10, + }, + }, name: "a".to_owned(), location: Location { line: 1, column: 7 }, }, FuncArgSyntax { - type_: AbiType::F64, + type_: SyntaxIdent { + name: "f64".to_owned(), + location: Location { + line: 1, + column: 18, + }, + }, name: "b".to_owned(), location: Location { line: 1, @@ -1107,7 +1111,13 @@ mod tests { args: Vec::new(), rets: vec![ FuncArgSyntax { - type_: AbiType::I32, + type_: SyntaxIdent { + name: "i32".to_owned(), + location: Location { + line: 1, + column: 18, + } + }, name: "r1".to_owned(), location: Location { line: 1, @@ -1115,7 +1125,13 @@ mod tests { }, }, FuncArgSyntax { - type_: AbiType::I64, + type_: SyntaxIdent { + name: "i64".to_owned(), + location: Location { + line: 1, + column: 27 + } + }, name: "r2".to_owned(), location: Location { line: 1, @@ -1123,7 +1139,13 @@ mod tests { }, }, FuncArgSyntax { - type_: AbiType::F32, + type_: SyntaxIdent { + name: "f32".to_owned(), + location: Location { + line: 1, + column: 36 + } + }, name: "r3".to_owned(), location: Location { line: 1, @@ -1153,7 +1175,13 @@ mod tests { SyntaxDecl::Function { name: "fgetch".to_owned(), args: vec![FuncArgSyntax { - type_: AbiType::I32, + type_: SyntaxIdent { + name: "i32".to_owned(), + location: Location { + line: 1, + column: 16 + } + }, name: "fptr".to_owned(), location: Location { line: 1, @@ -1161,7 +1189,13 @@ mod tests { }, },], rets: vec![FuncArgSyntax { - type_: AbiType::I32, + type_: SyntaxIdent { + name: "i32".to_owned(), + location: Location { + line: 1, + column: 27 + } + }, name: "r".to_owned(), location: Location { line: 1, @@ -1171,7 +1205,7 @@ mod tests { bindings: vec![ BindingSyntax { name: "file".to_owned(), - type_: SyntaxTypeRef::Name { + type_: SyntaxIdent { name: "file_t".to_owned(), location: Location { line: 2, column: 9 }, }, @@ -1183,8 +1217,8 @@ mod tests { }, BindingSyntax { name: "r".to_owned(), - type_: SyntaxTypeRef::Atom { - atom: AtomType::U8, + type_: SyntaxIdent { + name: "u8".to_owned(), location: Location { line: 3, column: 7 }, }, direction: BindingDirSyntax::Out, @@ -1193,7 +1227,7 @@ mod tests { }, BindingSyntax { name: "some_slice".to_owned(), - type_: SyntaxTypeRef::Name { + type_: SyntaxIdent { name: "something".to_owned(), location: Location { line: 4, diff --git a/lucet-idl/src/prelude.rs b/lucet-idl/src/prelude.rs index 3348487b6..45925d074 100644 --- a/lucet-idl/src/prelude.rs +++ b/lucet-idl/src/prelude.rs @@ -17,8 +17,9 @@ pub fn std_module() -> ModuleRepr { } fn std_datatypes() -> ModuleDatatypesRepr { - fn create_atom(repr: &mut ModuleDatatypesRepr, name: &str, atom: AtomType) { - let ix = repr.names.push(name.to_owned()); + fn create_atom(repr: &mut ModuleDatatypesRepr, atom: AtomType) { + // Display instance takes care of name: + let ix = repr.names.push(format!("{}", atom)); let mem_size = atom.mem_size(); let mem_align = atom.mem_align(); let dix = repr.datatypes.push(DatatypeRepr { @@ -35,17 +36,17 @@ fn std_datatypes() -> ModuleDatatypesRepr { datatypes: PrimaryMap::new(), topological_order: Vec::new(), }; - create_atom(&mut repr, "bool", AtomType::Bool); - create_atom(&mut repr, "u8", AtomType::U8); - create_atom(&mut repr, "u16", AtomType::U16); - create_atom(&mut repr, "u32", AtomType::U32); - create_atom(&mut repr, "u64", AtomType::U64); - create_atom(&mut repr, "i8", AtomType::I8); - create_atom(&mut repr, "i16", AtomType::I16); - create_atom(&mut repr, "i32", AtomType::I32); - create_atom(&mut repr, "i64", AtomType::I64); - create_atom(&mut repr, "f32", AtomType::F32); - create_atom(&mut repr, "f64", AtomType::F64); + create_atom(&mut repr, AtomType::Bool); + create_atom(&mut repr, AtomType::U8); + create_atom(&mut repr, AtomType::U16); + create_atom(&mut repr, AtomType::U32); + create_atom(&mut repr, AtomType::U64); + create_atom(&mut repr, AtomType::I8); + create_atom(&mut repr, AtomType::I16); + create_atom(&mut repr, AtomType::I32); + create_atom(&mut repr, AtomType::I64); + create_atom(&mut repr, AtomType::F32); + create_atom(&mut repr, AtomType::F64); repr } diff --git a/lucet-idl/src/validate/datatypes.rs b/lucet-idl/src/validate/datatypes.rs index 52e69ff66..aef9d7711 100644 --- a/lucet-idl/src/validate/datatypes.rs +++ b/lucet-idl/src/validate/datatypes.rs @@ -1,6 +1,6 @@ use super::names::ModNamesBuilder; use crate::parser::{ - EnumVariant as EnumVariantSyntax, StructMember as StructMemberSyntax, SyntaxTypeRef, + EnumVariant as EnumVariantSyntax, StructMember as StructMemberSyntax, SyntaxIdent, }; use crate::repr::{ AliasDatatypeRepr, DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, @@ -154,7 +154,7 @@ impl<'a> DatatypeModuleBuilder<'a> { pub fn introduce_alias( &mut self, name: &str, - dest: &SyntaxTypeRef, + dest: &SyntaxIdent, location: &Location, ) -> Result<(), ValidationError> { let ix = self diff --git a/lucet-idl/src/validate/function.rs b/lucet-idl/src/validate/function.rs index 281286619..4802584cc 100644 --- a/lucet-idl/src/validate/function.rs +++ b/lucet-idl/src/validate/function.rs @@ -7,6 +7,7 @@ use crate::repr::{ use crate::{AbiType, AtomType, Datatype, Location, Module, ValidationError}; use cranelift_entity::{EntityRef, PrimaryMap}; use std::collections::HashMap; +use std::convert::TryFrom; use std::ops::Deref; pub struct FunctionModuleBuilder<'a> { @@ -109,9 +110,15 @@ impl<'a> FuncValidator<'a> { (arg_syntax.location.clone(), position), ); } + let type_ = AbiType::try_from(arg_syntax.type_.name.as_str()).map_err(|_| { + ValidationError::Syntax { + expected: "abi type", + location: arg_syntax.type_.location, + } + })?; Ok(ParamRepr { name: arg_syntax.name.clone(), - type_: arg_syntax.type_.clone(), + type_, }) } @@ -181,14 +188,13 @@ impl<'a> FuncValidator<'a> { .insert(binding.name.clone(), (binding.location.clone(), ix)); } - // 2. resolve type_ SyntaxRef to a Datatype - let type_ = self - .module - .datatype_by_syntax(&binding.type_) - .ok_or_else(|| ValidationError::NameNotFound { - name: format!("{:?}", binding.type_), // XXX FIXME + // 2. resolve type_ SyntaxIdent to a Datatype + let type_ = self.module.datatype(&binding.type_.name).ok_or_else(|| { + ValidationError::NameNotFound { + name: binding.type_.name.to_owned(), use_location: binding.location, - })?; + } + })?; // 3. typecheck the binding: let from = self.validate_binding_ref(&binding, &type_)?; @@ -352,20 +358,8 @@ impl<'a> FuncValidator<'a> { } Ok(BindingFromRepr::Slice(ptr_position, len_position)) } - ( - BindingRefSyntax::Name(ref _ptr_name), - BindingRefSyntax::Ptr(ref len_ptr_ref), - ) => match len_ptr_ref.deref() { - BindingRefSyntax::Name(_len_ptr_name) => { - unimplemented!("slice syntax [ptr, *len] for an output slice"); - } - _ => Err(ValidationError::Syntax { - expected: "slice binding must be of form [ptr, len] or [ptr, *len]", - location: binding.location.clone(), - }), - }, _ => Err(ValidationError::Syntax { - expected: "slice binding must be of form [ptr, len] or [ptr, *len]", + expected: "slice binding must be of form [ptr, len]", location: binding.location.clone(), }), } diff --git a/lucet-idl/src/validate/names.rs b/lucet-idl/src/validate/names.rs index 939d0b4c2..36bfead3e 100644 --- a/lucet-idl/src/validate/names.rs +++ b/lucet-idl/src/validate/names.rs @@ -1,8 +1,9 @@ -use crate::parser::SyntaxTypeRef; +use crate::parser::SyntaxIdent; use crate::repr::{DatatypeIdent, DatatypeIx, FuncIx, ModuleIx}; -use crate::{Location, ValidationError}; +use crate::{AtomType, Location, ValidationError}; use cranelift_entity::PrimaryMap; use std::collections::HashMap; +use std::convert::TryFrom; pub struct ModNamesBuilder { pub module: ModuleIx, @@ -59,24 +60,25 @@ impl ModNamesBuilder { pub fn datatype_id_from_syntax( &self, - syntax: &SyntaxTypeRef, + syntax: &SyntaxIdent, ) -> Result { - match syntax { - SyntaxTypeRef::Atom { atom, .. } => Ok(atom.datatype_id()), - SyntaxTypeRef::Name { name, location } => match self.names.get(name) { + if let Ok(atom) = AtomType::try_from(syntax.name.as_str()) { + Ok(atom.datatype_id()) + } else { + match self.names.get(syntax.name.as_str()) { Some((ModContentIx::Datatype(ix), _loc)) => { Ok(DatatypeIdent::new(self.module, *ix)) } Some((_, bound_loc)) => Err(ValidationError::NameSortError { - name: name.to_owned(), - use_location: *location, + name: syntax.name.clone(), + use_location: syntax.location, bound_location: *bound_loc, }), None => Err(ValidationError::NameNotFound { - name: name.to_owned(), - use_location: *location, + name: syntax.name.clone(), + use_location: syntax.location, }), - }, + } } } From 29dd8a416d0fce0101e9394751fbff363fb69a17 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 6 Aug 2019 14:14:13 -0700 Subject: [PATCH 333/512] lucet-idl: parse tree uses &'syntax str rather than String one less clone is good --- lucet-idl/src/parser.rs | 249 ++++++++++++++-------------- lucet-idl/src/validate/datatypes.rs | 10 +- lucet-idl/src/validate/function.rs | 44 ++--- lucet-idl/src/validate/names.rs | 8 +- 4 files changed, 153 insertions(+), 158 deletions(-) diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index 979c44837..5eb443682 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -4,37 +4,37 @@ use std::error::Error; use std::fmt; #[derive(Debug, PartialEq, Eq, Clone)] -pub enum SyntaxDecl { +pub enum SyntaxDecl<'a> { Struct { - name: String, - members: Vec, + name: &'a str, + members: Vec>, location: Location, }, Enum { - name: String, - variants: Vec, + name: &'a str, + variants: Vec>, location: Location, }, Alias { - name: String, - what: SyntaxIdent, + name: &'a str, + what: SyntaxIdent<'a>, location: Location, }, Module { - name: String, - decls: Vec, + name: &'a str, + decls: Vec>, location: Location, }, Function { - name: String, - args: Vec, - rets: Vec, - bindings: Vec, + name: &'a str, + args: Vec>, + rets: Vec>, + bindings: Vec>, location: Location, }, } -impl SyntaxDecl { +impl<'a> SyntaxDecl<'a> { pub fn location(&self) -> &Location { match self { SyntaxDecl::Struct { location, .. } => &location, @@ -47,28 +47,28 @@ impl SyntaxDecl { } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct SyntaxIdent { - pub name: String, +pub struct SyntaxIdent<'a> { + pub name: &'a str, pub location: Location, } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct StructMember { - pub name: String, - pub type_: SyntaxIdent, +pub struct StructMember<'a> { + pub name: &'a str, + pub type_: SyntaxIdent<'a>, pub location: Location, } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct EnumVariant { - pub name: String, +pub struct EnumVariant<'a> { + pub name: &'a str, pub location: Location, } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct FuncArgSyntax { - pub name: String, - pub type_: SyntaxIdent, +pub struct FuncArgSyntax<'a> { + pub name: &'a str, + pub type_: SyntaxIdent<'a>, pub location: Location, } @@ -86,19 +86,19 @@ pub enum BindingDirSyntax { } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct BindingSyntax { - pub name: String, - pub type_: SyntaxIdent, +pub struct BindingSyntax<'a> { + pub name: &'a str, + pub type_: SyntaxIdent<'a>, pub direction: BindingDirSyntax, - pub from: BindingRefSyntax, + pub from: BindingRefSyntax<'a>, pub location: Location, } #[derive(Debug, PartialEq, Eq, Clone)] -pub enum BindingRefSyntax { - Ptr(Box), - Slice(Box, Box), - Name(String), +pub enum BindingRefSyntax<'a> { + Ptr(Box>), + Slice(Box>, Box>), + Name(&'a str), } impl fmt::Display for ParseError { @@ -199,7 +199,7 @@ impl<'a> Parser<'a> { } } - fn match_struct_body(&mut self) -> Result, ParseError> { + fn match_struct_body(&mut self) -> Result>, ParseError> { let mut members = Vec::new(); loop { match self.token() { @@ -213,7 +213,7 @@ impl<'a> Parser<'a> { self.match_token(Token::Colon, "expected :")?; let member_ref = self.match_ident("expected member type")?; members.push(StructMember { - name: member_name.to_string(), + name: member_name, type_: member_ref, location, }); @@ -238,7 +238,7 @@ impl<'a> Parser<'a> { Ok(members) } - fn match_enum_body(&mut self) -> Result, ParseError> { + fn match_enum_body(&mut self) -> Result>, ParseError> { let mut names = Vec::new(); loop { match self.token() { @@ -250,7 +250,7 @@ impl<'a> Parser<'a> { let location = self.location; self.consume(); names.push(EnumVariant { - name: name.to_owned(), + name: name, location, }); match self.token() { @@ -271,7 +271,7 @@ impl<'a> Parser<'a> { Ok(names) } - fn match_func_args(&mut self) -> Result, ParseError> { + fn match_func_args(&mut self) -> Result>, ParseError> { let mut args = Vec::new(); loop { match self.token() { @@ -286,7 +286,7 @@ impl<'a> Parser<'a> { let type_ = self.match_ident("type name")?; args.push(FuncArgSyntax { - name: name.to_string(), + name, type_, location, }); @@ -308,7 +308,7 @@ impl<'a> Parser<'a> { Ok(args) } - fn match_func_rets(&mut self) -> Result, ParseError> { + fn match_func_rets(&mut self) -> Result>, ParseError> { let mut args = Vec::new(); loop { match self.token() { @@ -322,7 +322,7 @@ impl<'a> Parser<'a> { let type_ = self.match_ident("type name")?; args.push(FuncArgSyntax { type_, - name: name.to_string(), + name, location, }); match self.token() { @@ -342,7 +342,7 @@ impl<'a> Parser<'a> { Ok(args) } - fn match_binding_exprs(&mut self) -> Result, ParseError> { + fn match_binding_exprs(&mut self) -> Result>, ParseError> { let mut bindings = Vec::new(); loop { match self.token() { @@ -356,7 +356,7 @@ impl<'a> Parser<'a> { self.match_token(Token::LArrow, "expected <-")?; let from = self.match_binding_ref()?; bindings.push(BindingSyntax { - name: name.to_string(), + name, type_, direction, from, @@ -401,7 +401,7 @@ impl<'a> Parser<'a> { } } - fn match_binding_ref(&mut self) -> Result { + fn match_binding_ref(&mut self) -> Result, ParseError> { match self.token() { Some(Token::Star) => { self.consume(); @@ -409,7 +409,7 @@ impl<'a> Parser<'a> { } Some(Token::Word(name)) => { self.consume(); - Ok(BindingRefSyntax::Name(name.to_string())) + Ok(BindingRefSyntax::Name(name)) } Some(Token::LBracket) => { self.consume(); @@ -426,7 +426,7 @@ impl<'a> Parser<'a> { } } - pub fn match_decl(&mut self, err_msg: &str) -> Result, ParseError> { + pub fn match_decl(&mut self, err_msg: &str) -> Result>, ParseError> { loop { match self.token() { Some(Token::Word("struct")) => { @@ -436,7 +436,7 @@ impl<'a> Parser<'a> { err_ctx!(err_msg, self.match_token(Token::LBrace, "expected {"))?; let members = err_ctx!(err_msg, self.match_struct_body())?; return Ok(Some(SyntaxDecl::Struct { - name: name.to_owned(), + name, members, location, })); @@ -448,7 +448,7 @@ impl<'a> Parser<'a> { err_ctx!(err_msg, self.match_token(Token::LBrace, "expected {"))?; let variants = err_ctx!(err_msg, self.match_enum_body())?; return Ok(Some(SyntaxDecl::Enum { - name: name.to_owned(), + name, variants, location, })); @@ -461,7 +461,7 @@ impl<'a> Parser<'a> { let what = self.match_ident("type value")?; err_ctx!(err_msg, self.match_token(Token::Semi, "expected ;"))?; return Ok(Some(SyntaxDecl::Alias { - name: name.to_owned(), + name, what, location, })); @@ -487,7 +487,7 @@ impl<'a> Parser<'a> { } return Ok(Some(SyntaxDecl::Module { - name: name.to_owned(), + name, decls, location, })); @@ -528,7 +528,7 @@ impl<'a> Parser<'a> { }; return Ok(Some(SyntaxDecl::Function { - name: name.to_owned(), + name, args, rets, bindings, @@ -549,7 +549,7 @@ impl<'a> Parser<'a> { } } - pub fn match_decls(&mut self) -> Result, ParseError> { + pub fn match_decls(&mut self) -> Result>, ParseError> { let mut decls = Vec::new(); loop { match self.match_decl("declaration") { @@ -561,15 +561,12 @@ impl<'a> Parser<'a> { Ok(decls) } - fn match_ident(&mut self, err_msg: &str) -> Result { + fn match_ident(&mut self, err_msg: &str) -> Result, ParseError> { match self.token() { Some(Token::Word(name)) => { let location = self.location; self.consume(); - Ok(SyntaxIdent { - name: name.to_string(), - location, - }) + Ok(SyntaxIdent { name, location }) } _ => err_ctx!(err_msg, parse_err!(self.location, "expected identifier")), } @@ -588,7 +585,7 @@ mod tests { .expect("valid parse") .expect("valid decl"), SyntaxDecl::Struct { - name: "foo".to_string(), + name: "foo", members: Vec::new(), location: Location { line: 1, column: 0 }, } @@ -604,11 +601,11 @@ mod tests { .expect("valid parse") .expect("valid decl"), SyntaxDecl::Struct { - name: "foo".to_string(), + name: "foo", members: vec![StructMember { - name: "a".to_owned(), + name: "a", type_: SyntaxIdent { - name: "i32".to_owned(), + name: "i32", location: Location { line: 1, column: 15, @@ -633,11 +630,11 @@ mod tests { .expect("valid parse") .expect("valid decl"), SyntaxDecl::Struct { - name: "foo".to_string(), + name: "foo", members: vec![StructMember { - name: "b".to_owned(), + name: "b", type_: SyntaxIdent { - name: "i32".to_owned(), + name: "i32", location: Location { line: 1, column: 15, @@ -662,12 +659,12 @@ mod tests { .expect("valid parse") .expect("valid decl"), SyntaxDecl::Struct { - name: "c".to_string(), + name: "c", members: vec![ StructMember { - name: "d".to_owned(), + name: "d", type_: SyntaxIdent { - name: "f64".to_owned(), + name: "f64", location: Location { line: 1, column: 14, @@ -679,9 +676,9 @@ mod tests { }, }, StructMember { - name: "e".to_owned(), + name: "e", type_: SyntaxIdent { - name: "u8".to_owned(), + name: "u8", location: Location { line: 1, column: 22, @@ -708,12 +705,12 @@ mod tests { .expect("valid parse") .expect("valid decl"), SyntaxDecl::Struct { - name: "foo".to_string(), + name: "foo", members: vec![ StructMember { - name: "a".to_owned(), + name: "a", type_: SyntaxIdent { - name: "mod".to_owned(), + name: "mod", location: Location { line: 1, column: 15, @@ -725,9 +722,9 @@ mod tests { }, }, StructMember { - name: "struct".to_owned(), + name: "struct", type_: SyntaxIdent { - name: "enum".to_owned(), + name: "enum", location: Location { line: 1, column: 28, @@ -753,7 +750,7 @@ mod tests { .expect("valid parse") .expect("valid decl"), SyntaxDecl::Enum { - name: "foo".to_owned(), + name: "foo", variants: Vec::new(), location: Location { line: 1, column: 0 }, }, @@ -769,9 +766,9 @@ mod tests { .expect("valid parse") .expect("valid decl"), SyntaxDecl::Enum { - name: "foo".to_owned(), + name: "foo", variants: vec![EnumVariant { - name: "first".to_owned(), + name: "first", location: Location { line: 1, column: 10, @@ -791,9 +788,9 @@ mod tests { .expect("valid parse") .expect("valid decl"), SyntaxDecl::Enum { - name: "bar".to_owned(), + name: "bar", variants: vec![EnumVariant { - name: "first".to_owned(), + name: "first", location: Location { line: 1, column: 10, @@ -814,31 +811,31 @@ mod tests { .expect("valid parse") .expect("valid decl"), SyntaxDecl::Enum { - name: "baz".to_owned(), + name: "baz", variants: vec![ EnumVariant { - name: "one".to_owned(), + name: "one", location: Location { line: 1, column: 11, }, }, EnumVariant { - name: "two".to_owned(), + name: "two", location: Location { line: 1, column: 16, }, }, EnumVariant { - name: "three".to_owned(), + name: "three", location: Location { line: 1, column: 21, }, }, EnumVariant { - name: "four".to_owned(), + name: "four", location: Location { line: 2, column: 2 }, }, ], @@ -857,7 +854,7 @@ mod tests { .expect("valid parse") .expect("valid decl"), SyntaxDecl::Module { - name: "empty".to_owned(), + name: "empty", decls: Vec::new(), location: Location { line: 1, column: 0 }, } @@ -874,11 +871,11 @@ mod tests { .expect("valid parse") .expect("valid decl"), SyntaxDecl::Module { - name: "one".to_owned(), + name: "one", decls: vec![SyntaxDecl::Module { - name: "two".to_owned(), + name: "two", decls: vec![SyntaxDecl::Module { - name: "three".to_owned(), + name: "three", decls: Vec::new(), location: Location { line: 1, @@ -905,10 +902,10 @@ mod tests { .expect("valid parse") .expect("valid decl"), SyntaxDecl::Module { - name: "one".to_owned(), + name: "one", decls: vec![ SyntaxDecl::Enum { - name: "foo".to_owned(), + name: "foo", variants: Vec::new(), location: Location { line: 1, @@ -916,7 +913,7 @@ mod tests { }, }, SyntaxDecl::Struct { - name: "bar".to_owned(), + name: "bar", members: Vec::new(), location: Location { line: 1, @@ -932,7 +929,7 @@ mod tests { #[test] fn fn_trivial() { let canonical = vec![SyntaxDecl::Function { - name: "trivial".to_owned(), + name: "trivial", args: Vec::new(), rets: Vec::new(), bindings: Vec::new(), @@ -963,19 +960,19 @@ mod tests { #[test] fn fn_return_i32() { - fn canonical(column: usize) -> Vec { + fn canonical(column: usize) -> Vec> { vec![SyntaxDecl::Function { - name: "getch".to_owned(), + name: "getch", args: Vec::new(), rets: vec![FuncArgSyntax { type_: SyntaxIdent { - name: "i32".to_owned(), + name: "i32", location: Location { line: 1, column: column, }, }, - name: "r".to_owned(), + name: "r", location: Location { line: 1, column: 14, @@ -1011,16 +1008,16 @@ mod tests { #[test] fn fn_one_arg() { let canonical = SyntaxDecl::Function { - name: "foo".to_owned(), + name: "foo", args: vec![FuncArgSyntax { type_: SyntaxIdent { - name: "i32".to_owned(), + name: "i32", location: Location { line: 1, column: 10, }, }, - name: "a".to_owned(), + name: "a", location: Location { line: 1, column: 7 }, }], rets: Vec::new(), @@ -1048,28 +1045,28 @@ mod tests { #[test] fn fn_multi_arg() { let canonical = SyntaxDecl::Function { - name: "foo".to_owned(), + name: "foo", args: vec![ FuncArgSyntax { type_: SyntaxIdent { - name: "i32".to_owned(), + name: "i32", location: Location { line: 1, column: 10, }, }, - name: "a".to_owned(), + name: "a", location: Location { line: 1, column: 7 }, }, FuncArgSyntax { type_: SyntaxIdent { - name: "f64".to_owned(), + name: "f64", location: Location { line: 1, column: 18, }, }, - name: "b".to_owned(), + name: "b", location: Location { line: 1, column: 15, @@ -1107,18 +1104,18 @@ mod tests { .expect("valid parse") .expect("valid decl"), SyntaxDecl::Function { - name: "getch".to_owned(), + name: "getch", args: Vec::new(), rets: vec![ FuncArgSyntax { type_: SyntaxIdent { - name: "i32".to_owned(), + name: "i32", location: Location { line: 1, column: 18, } }, - name: "r1".to_owned(), + name: "r1", location: Location { line: 1, column: 14, @@ -1126,13 +1123,13 @@ mod tests { }, FuncArgSyntax { type_: SyntaxIdent { - name: "i64".to_owned(), + name: "i64", location: Location { line: 1, column: 27 } }, - name: "r2".to_owned(), + name: "r2", location: Location { line: 1, column: 23, @@ -1140,13 +1137,13 @@ mod tests { }, FuncArgSyntax { type_: SyntaxIdent { - name: "f32".to_owned(), + name: "f32", location: Location { line: 1, column: 36 } }, - name: "r3".to_owned(), + name: "r3", location: Location { line: 1, column: 32, @@ -1173,16 +1170,16 @@ mod tests { .expect("valid parse") .expect("valid decl"), SyntaxDecl::Function { - name: "fgetch".to_owned(), + name: "fgetch", args: vec![FuncArgSyntax { type_: SyntaxIdent { - name: "i32".to_owned(), + name: "i32", location: Location { line: 1, column: 16 } }, - name: "fptr".to_owned(), + name: "fptr", location: Location { line: 1, column: 10, @@ -1190,13 +1187,13 @@ mod tests { },], rets: vec![FuncArgSyntax { type_: SyntaxIdent { - name: "i32".to_owned(), + name: "i32", location: Location { line: 1, column: 27 } }, - name: "r".to_owned(), + name: "r", location: Location { line: 1, column: 24, @@ -1204,31 +1201,29 @@ mod tests { }], bindings: vec![ BindingSyntax { - name: "file".to_owned(), + name: "file", type_: SyntaxIdent { - name: "file_t".to_owned(), + name: "file_t", location: Location { line: 2, column: 9 }, }, direction: BindingDirSyntax::In, - from: BindingRefSyntax::Ptr(Box::new(BindingRefSyntax::Name( - "fptr".to_owned() - ))), + from: BindingRefSyntax::Ptr(Box::new(BindingRefSyntax::Name("fptr"))), location: Location { line: 2, column: 0 }, }, BindingSyntax { - name: "r".to_owned(), + name: "r", type_: SyntaxIdent { - name: "u8".to_owned(), + name: "u8", location: Location { line: 3, column: 7 }, }, direction: BindingDirSyntax::Out, - from: BindingRefSyntax::Name("r".to_owned()), + from: BindingRefSyntax::Name("r"), location: Location { line: 3, column: 0 }, }, BindingSyntax { - name: "some_slice".to_owned(), + name: "some_slice", type_: SyntaxIdent { - name: "something".to_owned(), + name: "something", location: Location { line: 4, column: 16 @@ -1236,8 +1231,8 @@ mod tests { }, direction: BindingDirSyntax::Out, from: BindingRefSyntax::Slice( - Box::new(BindingRefSyntax::Name("a".to_owned())), - Box::new(BindingRefSyntax::Name("b".to_owned())) + Box::new(BindingRefSyntax::Name("a")), + Box::new(BindingRefSyntax::Name("b")) ), location: Location { line: 4, column: 0 }, } diff --git a/lucet-idl/src/validate/datatypes.rs b/lucet-idl/src/validate/datatypes.rs index aef9d7711..c2009d9e6 100644 --- a/lucet-idl/src/validate/datatypes.rs +++ b/lucet-idl/src/validate/datatypes.rs @@ -82,9 +82,9 @@ impl<'a> DatatypeModuleBuilder<'a> { let mut members = Vec::new(); for mem in members_syntax { // Ensure that each member name is unique: - if let Some(existing) = uniq_membs.insert(mem.name.clone(), mem) { + if let Some(existing) = uniq_membs.insert(mem.name.to_owned(), mem) { Err(ValidationError::NameAlreadyExists { - name: mem.name.clone(), + name: mem.name.to_owned(), at_location: mem.location, previous_location: existing.location, })? @@ -95,7 +95,7 @@ impl<'a> DatatypeModuleBuilder<'a> { // build the struct with this as the member: members.push(StructMemberIR { type_, - name: mem.name.clone(), + name: mem.name.to_owned(), }); } self.define_datatype( @@ -131,14 +131,14 @@ impl<'a> DatatypeModuleBuilder<'a> { // Ensure that each member name is unique: if let Some(existing) = uniq_vars.insert(var.name.clone(), var) { Err(ValidationError::NameAlreadyExists { - name: var.name.clone(), + name: var.name.to_owned(), at_location: var.location, previous_location: existing.location, })? } // build the struct with this as the member: members.push(EnumMemberRepr { - name: var.name.clone(), + name: var.name.to_owned(), }) } self.define_datatype( diff --git a/lucet-idl/src/validate/function.rs b/lucet-idl/src/validate/function.rs index 4802584cc..9bcf649ff 100644 --- a/lucet-idl/src/validate/function.rs +++ b/lucet-idl/src/validate/function.rs @@ -72,7 +72,7 @@ struct FuncValidator<'a> { // Ret positions index into this vector: rets: PrimaryMap, // binding name to - binding_names: HashMap, + binding_names: HashMap<&'a str, (Location, BindingIx)>, // param position to binding syntax bindings: PrimaryMap, param_binding_sites: HashMap, @@ -98,26 +98,23 @@ impl<'a> FuncValidator<'a> { arg_syntax: &FuncArgSyntax, position: ParamIx, ) -> Result { - if let Some((previous_location, _)) = self.param_names.get(&arg_syntax.name) { + if let Some((previous_location, _)) = self.param_names.get(arg_syntax.name) { Err(ValidationError::NameAlreadyExists { - name: arg_syntax.name.clone(), + name: arg_syntax.name.to_owned(), at_location: arg_syntax.location, previous_location: previous_location.clone(), })?; } else { - self.param_names.insert( - arg_syntax.name.clone(), - (arg_syntax.location.clone(), position), - ); + self.param_names + .insert(arg_syntax.name.to_owned(), (arg_syntax.location, position)); } - let type_ = AbiType::try_from(arg_syntax.type_.name.as_str()).map_err(|_| { - ValidationError::Syntax { + let type_ = + AbiType::try_from(arg_syntax.type_.name).map_err(|_| ValidationError::Syntax { expected: "abi type", location: arg_syntax.type_.location, - } - })?; + })?; Ok(ParamRepr { - name: arg_syntax.name.clone(), + name: arg_syntax.name.to_owned(), type_, }) } @@ -135,7 +132,7 @@ impl<'a> FuncValidator<'a> { if rets.len() > 1 { Err(ValidationError::Syntax { expected: "at most one return value", - location: self.location.clone(), + location: *self.location, })? } for (ix, r) in rets.iter().enumerate() { @@ -147,7 +144,10 @@ impl<'a> FuncValidator<'a> { Ok(()) } - fn introduce_bindings(&mut self, bindings: &[BindingSyntax]) -> Result<(), ValidationError> { + fn introduce_bindings( + &mut self, + bindings: &[BindingSyntax<'a>], + ) -> Result<(), ValidationError> { for (ix, binding) in bindings.iter().enumerate() { let ix = BindingIx::new(ix); let b = self.introduce_binding(binding, ix)?; @@ -173,19 +173,19 @@ impl<'a> FuncValidator<'a> { fn introduce_binding( &mut self, - binding: &BindingSyntax, + binding: &BindingSyntax<'a>, ix: BindingIx, ) -> Result { // 1. make sure binding name is unique if let Some((previous_location, _)) = self.binding_names.get(&binding.name) { Err(ValidationError::NameAlreadyExists { - name: binding.name.clone(), + name: binding.name.to_owned(), at_location: binding.location, previous_location: previous_location.clone(), })?; } else { self.binding_names - .insert(binding.name.clone(), (binding.location.clone(), ix)); + .insert(binding.name, (binding.location, ix)); } // 2. resolve type_ SyntaxIdent to a Datatype @@ -207,7 +207,7 @@ impl<'a> FuncValidator<'a> { }; Ok(BindingRepr { - name: binding.name.clone(), + name: binding.name.to_owned(), type_: type_.id(), direction, from, @@ -222,7 +222,7 @@ impl<'a> FuncValidator<'a> { // 1. make sure binding name is unique. We're re-using the arg name // for the binding. If another binding overlapped with the arg name, // it is now at fault. (complicated, huh... :/) - if let Some((previous_location, _)) = self.binding_names.get(&arg.name) { + if let Some((previous_location, _)) = self.binding_names.get(arg.name.as_str()) { let (arg_location, _) = self.param_names.get(&arg.name).expect("arg introduced"); Err(ValidationError::BindingNameAlreadyBound { name: arg.name.clone(), @@ -251,7 +251,7 @@ impl<'a> FuncValidator<'a> { }) } - fn get_arg(&self, arg_name: &String) -> Option<(ParamIx, ParamRepr)> { + fn get_arg(&self, arg_name: &str) -> Option<(ParamIx, ParamRepr)> { let (_, position) = self.param_names.get(arg_name)?; match position { ParamIx::Arg(ix) => Some(( @@ -267,7 +267,7 @@ impl<'a> FuncValidator<'a> { fn validate_binding_arg_mapping( &mut self, - name: &String, + name: &str, location: &Location, ) -> Result<(ParamIx, ParamRepr), ValidationError> { // Check that it refers to a valid arg: @@ -278,7 +278,7 @@ impl<'a> FuncValidator<'a> { // Check that the arg has only been used once: if let Some(use_location) = self.param_binding_sites.get(&position) { Err(ValidationError::BindingNameAlreadyBound { - name: name.clone(), + name: name.to_owned(), at_location: location.clone(), bound_location: use_location.clone(), })?; diff --git a/lucet-idl/src/validate/names.rs b/lucet-idl/src/validate/names.rs index 36bfead3e..627c1ab31 100644 --- a/lucet-idl/src/validate/names.rs +++ b/lucet-idl/src/validate/names.rs @@ -62,20 +62,20 @@ impl ModNamesBuilder { &self, syntax: &SyntaxIdent, ) -> Result { - if let Ok(atom) = AtomType::try_from(syntax.name.as_str()) { + if let Ok(atom) = AtomType::try_from(syntax.name) { Ok(atom.datatype_id()) } else { - match self.names.get(syntax.name.as_str()) { + match self.names.get(syntax.name) { Some((ModContentIx::Datatype(ix), _loc)) => { Ok(DatatypeIdent::new(self.module, *ix)) } Some((_, bound_loc)) => Err(ValidationError::NameSortError { - name: syntax.name.clone(), + name: syntax.name.to_owned(), use_location: syntax.location, bound_location: *bound_loc, }), None => Err(ValidationError::NameNotFound { - name: syntax.name.clone(), + name: syntax.name.to_owned(), use_location: syntax.location, }), } From 5837bbc161dae13f2b0151a434a68a47dec7f775 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 6 Aug 2019 15:02:17 -0700 Subject: [PATCH 334/512] lucet-idl: reject out-slice bindings cant support these till we make an allocation protocol --- lucet-idl/src/validate/function.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lucet-idl/src/validate/function.rs b/lucet-idl/src/validate/function.rs index 9bcf649ff..d1ef59553 100644 --- a/lucet-idl/src/validate/function.rs +++ b/lucet-idl/src/validate/function.rs @@ -336,7 +336,7 @@ impl<'a> FuncValidator<'a> { if ptr_arg.type_ != AbiType::I32 { Err(ValidationError::BindingTypeError { expected: "slice pointer must be i32", - location: binding.location.clone(), + location: binding.location, })?; } let (len_position, len_arg) = @@ -344,7 +344,7 @@ impl<'a> FuncValidator<'a> { if len_arg.type_ != AbiType::I32 { Err(ValidationError::BindingTypeError { expected: "slice len must be i32", - location: binding.location.clone(), + location: binding.location, })?; } match (&ptr_position, &len_position) { @@ -352,10 +352,16 @@ impl<'a> FuncValidator<'a> { _ => { Err(ValidationError::BindingTypeError { expected: "slice bindings must be inputs", - location: binding.location.clone(), + location: binding.location, })?; } } + if binding.direction == BindingDirSyntax::Out { + Err(ValidationError::BindingTypeError { + expected: "slice bindings must be in or inout", + location: binding.location, + })?; + } Ok(BindingFromRepr::Slice(ptr_position, len_position)) } _ => Err(ValidationError::Syntax { From 445710eead514b1260073abffa5f58add472dd47 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 6 Aug 2019 18:01:17 -0700 Subject: [PATCH 335/512] lucet-idl: refactor rust backend to be more reasonable --- lucet-idl/src/c.rs | 2 +- lucet-idl/src/cursor.rs | 19 +- lucet-idl/src/lib.rs | 11 +- lucet-idl/src/rust.rs | 593 ++++++------------------------ lucet-idl/src/rust/cursor.rs | 396 ++++++++++++++++++++ lucet-idl/src/rust/guest_funcs.rs | 119 ------ 6 files changed, 529 insertions(+), 611 deletions(-) create mode 100644 lucet-idl/src/rust/cursor.rs delete mode 100644 lucet-idl/src/rust/guest_funcs.rs diff --git a/lucet-idl/src/c.rs b/lucet-idl/src/c.rs index b79e263f1..419c5f0fc 100644 --- a/lucet-idl/src/c.rs +++ b/lucet-idl/src/c.rs @@ -245,7 +245,7 @@ impl CGenerator { } } -trait CTypeName { +pub trait CTypeName { fn c_type_name(&self) -> String; } diff --git a/lucet-idl/src/cursor.rs b/lucet-idl/src/cursor.rs index 8d28be679..203028d04 100644 --- a/lucet-idl/src/cursor.rs +++ b/lucet-idl/src/cursor.rs @@ -302,17 +302,17 @@ pub struct EnumDatatype<'a> { } impl<'a> EnumDatatype<'a> { - pub fn variants(&self) -> impl Iterator> { + pub fn variants(&self) -> impl Iterator> { let enum_ = self.clone(); (0..self.repr.members.len()) .into_iter() - .map(move |ix| EnumMember { + .map(move |ix| EnumVariant { enum_: enum_.clone(), index: ix, }) } - pub fn variant(&self, name: &str) -> Option> { + pub fn variant(&self, name: &str) -> Option> { self.variants().find(|v| v.name() == name) } } @@ -331,12 +331,12 @@ impl<'a> From> for Datatype<'a> { } #[derive(Debug, Clone)] -pub struct EnumMember<'a> { +pub struct EnumVariant<'a> { enum_: EnumDatatype<'a>, index: usize, } -impl<'a> EnumMember<'a> { +impl<'a> EnumVariant<'a> { pub fn enum_(&self) -> EnumDatatype<'a> { self.enum_.clone() } @@ -462,6 +462,15 @@ impl<'a> Function<'a> { ix: self.id.module, } } + + pub fn host_func_name(&self) -> String { + use heck::SnakeCase; + format!( + "__{}_{}", + self.module().name().to_snake_case(), + self.name().to_snake_case() + ) + } } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 4f8119e79..017ab13bd 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -16,10 +16,17 @@ mod repr; mod rust; mod validate; +pub use crate::atoms::{AbiType, AtomType}; pub use crate::config::{Backend, Config}; -pub use crate::cursor::*; +pub use crate::cursor::{ + AliasDatatype, BindingDirection, BindingParam, Datatype, DatatypeVariant, EnumDatatype, + EnumVariant, FuncBinding, FuncParam, Function, Module, Package, ParamPosition, StructDatatype, + StructMember, +}; pub use crate::error::{IDLError, ValidationError}; -pub use crate::{AbiType, AtomType}; +pub use crate::rust::{ + RustFunc, RustIdiomArg, RustIdiomRet, RustName, RustTupleSyntax, RustTypeName, +}; use crate::c::CGenerator; use crate::parser::Parser; diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index 9cc807377..3fb4e9a15 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -1,17 +1,17 @@ -#![allow(dead_code)] -#![allow(unused_variables)] +mod cursor; use crate::error::IDLError; use crate::pretty_writer::PrettyWriter; use crate::{ - AbiType, AliasDatatype, AtomType, BindingDirection, BindingParam, Datatype, DatatypeVariant, - EnumDatatype, Function, MemArea, Module, Package, StructDatatype, + AliasDatatype, DatatypeVariant, EnumDatatype, Function, MemArea, Module, Package, + StructDatatype, }; -use heck::{CamelCase, SnakeCase}; +pub use cursor::{ + render_tuple, RustFunc, RustIdiomArg, RustIdiomRet, RustName, RustTupleSyntax, RustTypeName, +}; +use heck::SnakeCase; use std::io::Write; -mod guest_funcs; - /// Generator for the Rust backend pub struct RustGenerator { pub w: PrettyWriter, @@ -59,7 +59,6 @@ impl RustGenerator { self.generate_datatypes(&module)?; self.host_trait_definition(&module)?; - self.w.eob(); self.w .writeln("use lucet_runtime::{lucet_hostcalls, lucet_hostcall_terminate};"); @@ -71,7 +70,9 @@ impl RustGenerator { self.host_ensure_linked(&module); - self.w.eob().writeln("}"); + self.w + .eob() + .writeln(format!("}} // end module {}", module.rust_name())); } Ok(()) } @@ -89,13 +90,11 @@ impl RustGenerator { } fn gen_alias(&mut self, alias: &AliasDatatype) -> Result<(), IDLError> { - self.w - .writeln(format!( - "pub type {} = {};", - alias.rust_type_name(), - alias.to().rust_type_name() - )) - .eob(); + self.w.writeln(format!( + "pub type {} = {};", + alias.rust_type_name(), + alias.to().rust_type_name() + )); gen_testcase(&mut self.w, &alias.name().to_snake_case(), move |w| { w.writeln(format!( @@ -116,13 +115,13 @@ impl RustGenerator { let mut w = self.w.new_block(); for m in struct_.members() { w.writeln(format!( - "{}: {},", - m.name().to_snake_case(), + "pub {}: {},", + m.rust_name(), m.type_().rust_type_name(), )); } - self.w.writeln("}").eob(); + self.w.writeln("}"); gen_testcase(&mut self.w, &struct_.name().to_snake_case(), |w| { w.writeln(format!( @@ -134,7 +133,7 @@ impl RustGenerator { for m in struct_.members() { w.writeln(format!( "assert_eq!({}, {{ let base = ::std::ptr::null::(); unsafe {{ (&(*base).{}) as *const _ as usize }} }});", - m.offset(), struct_.rust_type_name(), m.name(), + m.offset(), struct_.rust_type_name(), m.rust_name(), )); } Ok(()) @@ -152,10 +151,10 @@ impl RustGenerator { let mut w = self.w.new_block(); for v in enum_.variants() { - w.writeln(format!("{},", v.name().to_camel_case())); + w.writeln(format!("{},", v.rust_name())); } - self.w.writeln("}").eob(); + self.w.writeln("}"); gen_testcase(&mut self.w, &enum_.name().to_snake_case(), |w| { w.writeln(format!( @@ -170,13 +169,13 @@ impl RustGenerator { fn guest_abi_import(&mut self, func: &Function) -> Result<(), IDLError> { let mut arg_syntax = Vec::new(); for a in func.args() { - arg_syntax.push(format!("{}: {}", a.name(), a.type_().rust_type_name())); + arg_syntax.push(format!("{}: {}", a.rust_name(), a.type_().rust_type_name())); } let ret_syntax = func .rets() .map(|r| r.type_().rust_type_name()) - .rust_tuple_syntax(); + .rust_tuple_syntax("()"); self.w.writeln("#[no_mangle]").writeln(format!( "pub fn {}({}) -> {};", @@ -189,141 +188,55 @@ impl RustGenerator { } fn guest_idiomatic_def(&mut self, func: &Function) -> Result<(), IDLError> { - use guest_funcs::{AbiCallBuilder, FuncBuilder}; - let name = func.rust_name(); - let mut def = FuncBuilder::new(name, "()".to_owned()); - let mut abi_call = AbiCallBuilder::new(func.clone()); + let idiom_args = func.rust_idiom_args(); + let idiom_rets = func.rust_idiom_rets(); + + let idiom_arg_syntax = idiom_args + .iter() + .map(|a| a.arg_declaration()) + .collect::>() + .join(", "); + let idiom_ret_syntax = format!( + "Result<{},()>", + idiom_rets + .iter() + .map(|r| r.ret_declaration()) + .rust_tuple_syntax("()") + ); - for input in func - .bindings() - .filter(|b| b.direction() == BindingDirection::In) - { - match &input.param() { - BindingParam::Ptr(ptr) => { - def.arg(format!( - "{}: &{}", - input.name(), - input.type_().rust_type_name(), - )); - abi_call.before(format!( - "let {} = {} as *const _ as i32;", - ptr.name(), - input.name(), - )); - } - BindingParam::Slice(ptr, len) => { - def.arg(format!( - "{}: &[{}]", - input.name(), - input.type_().rust_type_name(), - )); - - abi_call.before(format!( - "let {} = {}.as_ptr() as i32;", - ptr.name(), - input.name(), - )); - abi_call.before(format!( - "let {} = {}.len() as i32;", - len.name(), - input.name() - )); - } - BindingParam::Value(val) => { - def.arg(format!( - "{}: {}", - input.name(), - input.type_().rust_type_name(), - )); - abi_call.before(format!( - "let {} = {} as {};", - val.name(), - input.name(), - val.type_().rust_type_name(), - )); - } - } + self.w + .writeln(format!( + "pub fn {}({}) -> {} {{", + name, idiom_arg_syntax, idiom_ret_syntax + )) + .indent(); + for a in idiom_args.iter() { + self.w.writelns(&a.guest_abi_args()); } - - for io in func - .bindings() - .filter(|b| b.direction() == BindingDirection::InOut) - { - match &io.param() { - BindingParam::Ptr(ptr) => { - def.arg(format!( - "{}: &mut {}", - io.name(), - io.type_().rust_type_name(), - )); - abi_call.before(format!( - "let {} = {} as *mut _ as i32;", - ptr.name(), - io.name() - )); - } - BindingParam::Slice(ptr, len) => { - def.arg(format!( - "{}: &mut [{}]", - io.name(), - io.type_().rust_type_name(), - )); - abi_call.before(format!( - "let {} = {}.as_ptr() as i32;", - ptr.name(), - io.name() - )); - abi_call.before(format!("let {} = {}.len() as i32;", len.name(), io.name())); - } - BindingParam::Value(_val) => { - unreachable!("it should not be possible to have an inout value {:?}", io); - } - } + for r in idiom_rets.iter() { + self.w.writelns(&r.guest_abi_args()); } - for o in func - .bindings() - .filter(|b| b.direction() == BindingDirection::Out) - { - match &o.param() { - BindingParam::Ptr(ptr) => { - def.ok_type(o.type_().rust_type_name()); - abi_call.before(format!( - "let mut {}___MEM = ::std::mem::MaybeUninit::<{}>::uninit();", - ptr.name(), - o.type_().rust_type_name() - )); - abi_call.before(format!( - "let {} = {}___MEM.as_mut_ptr() as i32;", - ptr.name(), - ptr.name() - )); - abi_call.after(format!( - "let {} = unsafe {{ {}___MEM.assume_init() }};", - o.name(), - ptr.name() - )); - def.ok_value(o.name().to_owned()); - } - BindingParam::Value(val) => { - def.ok_type(o.type_().rust_type_name()); - abi_call.after(format!( - "let {} = {}::from({});", - o.name(), - o.type_().rust_type_name(), - val.name(), - )); - def.ok_value(o.name().to_owned()); - } - BindingParam::Slice(_ptr, _len) => { - unreachable!("it should not be possible to have an out slice {:?}", o); - } - } - } + self.w.writeln(format!( + "let {} = unsafe {{ abi::{}({}) }};", + func.rets().map(|r| r.rust_name()).rust_tuple_syntax("_"), + name, + func.args() + .map(|a| a.rust_name()) + .collect::>() + .join(", ") + )); - def.render(&mut self.w, |mut w| abi_call.render(&mut w))?; + for r in idiom_rets.iter() { + self.w.writeln(r.guest_from_abi_call()); + } + self.w.writeln(format!( + "Ok({})", + idiom_rets.iter().map(|r| r.name()).rust_tuple_syntax("()") + )); + self.w.eob().writeln("}"); Ok(()) } @@ -332,7 +245,7 @@ impl RustGenerator { for a in func.args() { args.push(format!( "{}: {}", - a.name().to_snake_case(), + a.rust_name().to_snake_case(), a.type_().rust_type_name(), )); } @@ -340,14 +253,14 @@ impl RustGenerator { let abi_rettype = func .rets() .map(|r| r.type_().rust_type_name()) - .rust_tuple_syntax(); + .rust_tuple_syntax("()"); self.w .writeln("#[no_mangle]") .writeln(format!( "// Wasm func {}::{}", func.module().name(), - func.name() + func.rust_name() )) .writeln(format!( "pub unsafe extern \"C\" fn {}({},) -> {} {{", @@ -358,29 +271,47 @@ impl RustGenerator { self.w.indent(); - let trait_type_name = func.module().name().to_camel_case(); + let trait_type_name = func.module().rust_type_name(); self.w.writeln(format!( "fn inner(heap: &mut [u8], obj: &mut dyn {}, {}) -> Result<{},()> {{", trait_type_name, func.args() - .map(|a| format!("{}: {}", a.name(), a.type_().rust_type_name(),)) + .map(|a| format!("{}: {}", a.rust_name(), a.type_().rust_type_name(),)) .collect::>() .join(", "), abi_rettype, )); self.w.indent(); { - let (pre, post, trait_args, trait_rets, func_rets) = self.trait_dispatch(func); - self.w.writelns(&pre); + let idiom_args = func.rust_idiom_args(); + let idiom_rets = func.rust_idiom_rets(); + + for a in idiom_args.iter() { + self.w.writelns(&a.host_unpack_to_abi()); + } + for r in idiom_rets.iter() { + self.w.writelns(&r.host_unpack_to_abi()); + } self.w.writeln(format!( "let {} = obj.{}({})?;", - render_tuple(&trait_rets), + idiom_rets.iter().map(|r| r.name()).rust_tuple_syntax("_"), func.rust_name(), - trait_args.join(", ") + idiom_args + .iter() + .map(|a| a.name()) + .collect::>() + .join(", "), + )); + for r in idiom_rets.iter() { + self.w.writeln(r.host_unpack_from_abi()); + } + self.w.writeln(format!( + "Ok({})", + func.rets() + .map(|r| r.name().to_string()) + .rust_tuple_syntax("()") )); - self.w.writelns(&post); - self.w.writeln(format!("Ok({})", render_tuple(&func_rets))); } self.w.eob().writeln("}"); @@ -401,195 +332,28 @@ impl RustGenerator { Ok(()) } - fn trait_dispatch( - &self, - func: &Function, - ) -> ( - Vec, - Vec, - Vec, - Vec, - Vec, - ) { - let mut pre = Vec::new(); - let mut post = Vec::new(); - let mut trait_args = Vec::new(); - let mut trait_rets = Vec::new(); - let mut func_rets = Vec::new(); - - for input in func - .bindings() - .filter(|b| b.direction() == BindingDirection::In) - { - match input.param() { - BindingParam::Ptr(ptr) => { - pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name())); - pre.push(format!( - "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", - ptr = ptr.name(), - align = input.type_().mem_align(), - )); - pre.push(format!( - "#[allow(non_snake_case)] let {name}___MEM: &[u8] = heap.get({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", - name = input.name(), - ptr = ptr.name(), - len = input.type_().mem_size(), - )); - pre.push(format!( - "let {name}: &{typename} = unsafe {{ ({name}___MEM.as_ptr() as *const {typename}).as_ref().unwrap() }}; // convert pointer in linear memory to ref", - name = input.name(), - typename = input.type_().rust_type_name(), - )); - trait_args.push(input.name().to_owned()); - } - BindingParam::Slice(ptr, len) => { - pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name())); - pre.push(format!("let {len} = {len} as usize;", len = len.name())); - pre.push(format!( - "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", - ptr = ptr.name(), - align = input.type_().mem_align(), - )); - pre.push(format!( - "#[allow(non_snake_case)] let {name}___MEM: &[u8] = heap.get({ptr}..({ptr}+({len}*{elem_len}))).ok_or_else(|| () /* FIXME: bounds check failed */)?;", - name = input.name(), - ptr = ptr.name(), - len = len.name(), - elem_len = input.type_().mem_size(), - )); - - pre.push(format!( - "let {}: &[{}] = unsafe {{ ::std::slice::from_raw_parts({name}___MEM.as_ptr() as *const {typename}, {len}) }};", - name = input.name(), - typename = input.type_().rust_type_name(), - len = len.name(), - )); - trait_args.push(input.name().to_owned()); - } - BindingParam::Value(value) => { - pre.push(format!( - "let {name}: {typename} = {value} as {typename};", - name = input.name(), - typename = input.type_().rust_type_name(), - value = value.name(), - )); - trait_args.push(value.name().to_owned()); - } - } - } - for io in func - .bindings() - .filter(|b| b.direction() == BindingDirection::InOut) - { - match io.param() { - BindingParam::Ptr(ptr) => { - pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name())); - pre.push(format!( - "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", - ptr = ptr.name(), - align = io.type_().mem_align(), - )); - pre.push(format!( - "#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", - name = io.name(), - ptr = ptr.name(), - len = io.type_().mem_size(), - )); - pre.push(format!( - "let mut {name}: &mut {typename} = unsafe {{ ({name}___MEM.as_mut_ptr() as *mut {typename}).as_mut().unwrap() }}; // convert pointer in linear memory to ref", - name = io.name(), - typename = io.type_().rust_type_name(), - )); - trait_args.push(format!("&mut {}", io.name())); - } - BindingParam::Slice(ptr, len) => { - pre.push(format!("let {ptr} = {ptr} as usize;", ptr = ptr.name())); - pre.push(format!("let {len} = {len} as usize;", len = len.name())); - pre.push(format!( - "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", - ptr = ptr.name(), - align = io.type_().mem_align(), - )); - pre.push(format!( - "#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+({len}*{elem_len}))).ok_or_else(|| () /* FIXME: bounds check failed */)?;", - name = io.name(), - ptr = ptr.name(), - len = len.name(), - elem_len = io.type_().mem_size(), - )); - - pre.push(format!( - "let mut {}: &mut [{}] = unsafe {{ ::std::slice::from_raw_parts_mut({name}___MEM.as_mut_ptr() as *mut {typename}, {len}) }};", - name = io.name(), - typename = io.type_().rust_type_name(), - len = len.name(), - )); - - trait_args.push(format!("&mut {}", io.name())); - } - BindingParam::Value { .. } => unreachable!(), - } - } - for out in func - .bindings() - .filter(|b| b.direction() == BindingDirection::Out) - { - match out.param() { - BindingParam::Ptr(ptr) => { - pre.push(format!( - "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", - ptr = ptr.name(), - align = out.type_().mem_align(), - )); - pre.push(format!( - "#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", - name = out.name(), - ptr = ptr.name(), - len = out.type_().mem_size(), - )); - pre.push(format!( - "let mut {ptr}: &mut {typename} = unsafe {{ ({name}___MEM.as_mut_ptr() as *mut {typename}).as_mut().unwrap() }}; // convert pointer in linear memory to ref", - name = out.name(), - typename = out.type_().rust_type_name(), - ptr = ptr.name(), - )); - - trait_rets.push(out.name().to_owned()); - post.push(format!( - "*{} = {}; // Copy into out-pointer reference", - ptr.name(), - out.name(), - )); - } - BindingParam::Value(value) => { - trait_rets.push(out.name().to_owned()); - post.push(format!( - "let {value}: {typename} = {arg} as {typename};", - value = value.name(), - typename = value.type_().rust_type_name(), - arg = out.name(), - )); - func_rets.push(value.name().to_owned()) - } - BindingParam::Slice { .. } => unreachable!(), - } - } - (pre, post, trait_args, trait_rets, func_rets) - } - fn host_trait_definition(&mut self, module: &Module) -> Result<(), IDLError> { self.w - .writeln(format!("pub trait {} {{", module.name().to_camel_case())) + .writeln(format!("pub trait {} {{", module.rust_type_name())) .indent(); for func in module.functions() { - let (mut args, rets) = self.trait_idiomatic_params(&func); + let mut args = func + .rust_idiom_args() + .iter() + .map(|a| a.arg_value()) + .collect::>(); args.insert(0, "&mut self".to_owned()); + let rets = func + .rust_idiom_rets() + .iter() + .map(|a| a.name()) + .rust_tuple_syntax("()"); self.w.writeln(format!( "fn {}({}) -> {};", func.rust_name(), args.join(", "), - format!("Result<{},()>", render_tuple(&rets)), + format!("Result<{},()>", rets), )); } @@ -598,66 +362,9 @@ impl RustGenerator { Ok(()) } - fn trait_idiomatic_params(&self, func: &Function) -> (Vec, Vec) { - let mut args = Vec::new(); - for input in func - .bindings() - .filter(|b| b.direction() == BindingDirection::In) - { - match &input.param() { - BindingParam::Ptr { .. } => args.push(format!( - "{}: &{}", - input.name(), - input.type_().rust_type_name(), - )), - BindingParam::Slice { .. } => args.push(format!( - "{}: &[{}]", - input.name(), - input.type_().rust_type_name(), - )), - BindingParam::Value { .. } => args.push(format!( - "{}: {}", - input.name(), - input.type_().rust_type_name(), - )), - } - } - for io in func - .bindings() - .filter(|b| b.direction() == BindingDirection::InOut) - { - match &io.param() { - BindingParam::Ptr { .. } => args.push(format!( - "{}: &mut {}", - io.name(), - io.type_().rust_type_name(), - )), - BindingParam::Slice { .. } => args.push(format!( - "{}: &mut [{}]", - io.name(), - io.type_().rust_type_name(), - )), - BindingParam::Value { .. } => unreachable!(), - } - } - let mut rets = Vec::new(); - for out in func - .bindings() - .filter(|b| b.direction() == BindingDirection::Out) - { - match &out.param() { - BindingParam::Ptr { .. } | BindingParam::Value { .. } => { - rets.push(format!("{}", out.type_().rust_type_name())) - } - BindingParam::Slice { .. } => unreachable!(), - } - } - (args, rets) - } - fn host_ensure_linked(&mut self, module: &Module) { self.w.writeln("pub fn ensure_linked() {").indent(); - self.w.writeln("unsafe {"); + self.w.writeln("unsafe {").indent(); for func in module.functions() { self.w.writeln(format!( "::std::ptr::read_volatile({} as *const extern \"C\" fn());", @@ -679,89 +386,7 @@ where ww.writeln("#[test]").writeln("fn test() {"); let mut www = ww.new_block(); f(&mut www)?; - ww.writeln("}").eob(); - w.writeln("}").eob(); + ww.writeln("}"); + w.writeln("}"); Ok(()) } - -trait RustTypeName { - fn rust_type_name(&self) -> String; -} - -impl RustTypeName for AtomType { - fn rust_type_name(&self) -> String { - match self { - AtomType::Bool => "bool", - AtomType::U8 => "u8", - AtomType::U16 => "u16", - AtomType::U32 => "u32", - AtomType::U64 => "u64", - AtomType::I8 => "i8", - AtomType::I16 => "i16", - AtomType::I32 => "i32", - AtomType::I64 => "i64", - AtomType::F32 => "f32", - AtomType::F64 => "f64", - } - .to_owned() - } -} - -impl RustTypeName for AbiType { - fn rust_type_name(&self) -> String { - AtomType::from(self.clone()).rust_type_name() - } -} - -impl RustTypeName for Datatype<'_> { - fn rust_type_name(&self) -> String { - match self.variant() { - DatatypeVariant::Struct(_) | DatatypeVariant::Enum(_) | DatatypeVariant::Alias(_) => { - self.name().to_camel_case() - } - DatatypeVariant::Atom(a) => a.rust_type_name(), - } - } -} - -impl Function<'_> { - fn rust_name(&self) -> String { - self.name().to_snake_case() - } - - pub fn host_func_name(&self) -> String { - format!( - "__{}_{}", - self.module().name().to_snake_case(), - self.name().to_snake_case() - ) - } -} - -impl Module<'_> { - fn rust_name(&self) -> String { - self.name().to_snake_case() - } -} - -pub fn render_tuple(members: &[String]) -> String { - match members.len() { - 0 => "()".to_owned(), - 1 => members[0].clone(), - _ => format!("({})", members.join(", ")), - } -} - -pub trait RustTupleSyntax { - fn rust_tuple_syntax(&mut self) -> String; -} - -impl RustTupleSyntax for I -where - I: Iterator, -{ - fn rust_tuple_syntax(&mut self) -> String { - let rets = self.collect::>(); - render_tuple(&rets) - } -} diff --git a/lucet-idl/src/rust/cursor.rs b/lucet-idl/src/rust/cursor.rs new file mode 100644 index 000000000..2e2a3a9d1 --- /dev/null +++ b/lucet-idl/src/rust/cursor.rs @@ -0,0 +1,396 @@ +use crate::{ + AbiType, AtomType, BindingDirection, BindingParam, Datatype, DatatypeVariant, EnumVariant, + FuncBinding, FuncParam, Function, MemArea, Module, StructMember, +}; +use heck::{CamelCase, SnakeCase}; + +pub trait RustTupleSyntax { + fn rust_tuple_syntax(&mut self, base_case: &str) -> String; +} + +impl RustTupleSyntax for I +where + I: Iterator, +{ + fn rust_tuple_syntax(&mut self, base_case: &str) -> String { + let rets = self.collect::>(); + render_tuple(&rets, base_case) + } +} + +pub trait RustTypeName { + fn rust_type_name(&self) -> String; +} + +impl RustTypeName for Module<'_> { + fn rust_type_name(&self) -> String { + self.name().to_camel_case() + } +} + +impl RustTypeName for AtomType { + fn rust_type_name(&self) -> String { + format!("{}", self) + } +} + +impl RustTypeName for AbiType { + fn rust_type_name(&self) -> String { + format!("{}", self) + } +} + +impl RustTypeName for Datatype<'_> { + fn rust_type_name(&self) -> String { + match self.variant() { + DatatypeVariant::Struct(_) | DatatypeVariant::Enum(_) | DatatypeVariant::Alias(_) => { + self.name().to_camel_case() + } + DatatypeVariant::Atom(a) => a.rust_type_name(), + } + } +} + +pub trait RustName { + fn rust_name(&self) -> String; +} + +impl RustName for Function<'_> { + fn rust_name(&self) -> String { + self.name().to_snake_case() + } +} + +impl RustName for Module<'_> { + fn rust_name(&self) -> String { + self.name().to_snake_case() + } +} + +impl RustName for EnumVariant<'_> { + fn rust_name(&self) -> String { + self.name().to_camel_case() + } +} + +impl RustName for StructMember<'_> { + fn rust_name(&self) -> String { + self.name().to_snake_case() + } +} + +impl RustName for FuncParam<'_> { + fn rust_name(&self) -> String { + self.name().to_snake_case() + } +} + +impl RustName for FuncBinding<'_> { + fn rust_name(&self) -> String { + self.name().to_snake_case() + } +} + +pub fn render_tuple(members: &[String], base_case: &str) -> String { + match members.len() { + 0 => base_case.to_owned(), + 1 => members[0].clone(), + _ => format!("({})", members.join(", ")), + } +} + +pub trait RustFunc<'a> { + fn rust_idiom_args(&self) -> Vec>; + fn rust_idiom_rets(&self) -> Vec>; +} + +impl<'a> RustFunc<'a> for Function<'a> { + fn rust_idiom_args(&self) -> Vec> { + self.bindings() + .filter(|b| b.direction() == BindingDirection::In) + .chain( + self.bindings() + .filter(|b| b.direction() == BindingDirection::InOut), + ) + .map(|b| RustIdiomArg { binding: b }) + .collect() + } + + fn rust_idiom_rets(&self) -> Vec> { + self.bindings() + .filter(|b| b.direction() == BindingDirection::Out) + .map(|binding| RustIdiomRet { binding }) + .collect() + } +} + +pub struct RustIdiomArg<'a> { + binding: FuncBinding<'a>, +} + +impl<'a> RustIdiomArg<'a> { + fn mutable(&self) -> String { + if self.binding.direction() == BindingDirection::InOut { + "mut " + } else { + "" + } + .to_owned() + } + + pub fn arg_declaration(&self) -> String { + match self.binding.param() { + BindingParam::Ptr { .. } => { + format!("{}: &{}{}", self.name(), self.mutable(), self.type_name()) + } + BindingParam::Slice { .. } => { + format!("{}: &{}[{}]", self.name(), self.mutable(), self.type_name(),) + } + BindingParam::Value { .. } => { + assert_eq!(self.binding.direction(), BindingDirection::In); + format!("{}: {}", self.name(), self.type_name()) + } + } + } + + pub fn arg_value(&self) -> String { + match self.binding.param() { + BindingParam::Ptr { .. } | BindingParam::Slice { .. } => { + format!("&{}{}", self.mutable(), self.name(),) + } + BindingParam::Value { .. } => { + assert_eq!(self.binding.direction(), BindingDirection::In); + self.name() + } + } + } + + pub fn guest_abi_args(&self) -> Vec { + match self.binding.param() { + BindingParam::Ptr(ptr) => vec![format!( + "let {} = {} as *const _ as i32;", + ptr.rust_name(), + self.name(), + )], + BindingParam::Slice(ptr, len) => vec![ + format!("let {} = {}.as_ptr() as i32;", ptr.rust_name(), self.name()), + format!("let {} = {}.len() as i32;", len.rust_name(), self.name()), + ], + BindingParam::Value(val) => vec![format!( + "let {} = {} as {};", + val.rust_name(), + self.name(), + val.type_().rust_type_name() + )], + } + } + + pub fn host_unpack_to_abi(&self) -> Vec { + if self.binding.direction() == BindingDirection::In { + match self.binding.param() { + BindingParam::Ptr(ptr) => vec![ + format!("let {ptr} = {ptr} as usize;", + ptr = ptr.rust_name() + ), + format!("if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", + ptr = ptr.rust_name(), + align = self.binding.type_().mem_align(), + ), + format!("#[allow(non_snake_case)] let {name}___MEM: &[u8] = heap.get({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", + name = self.name(), + ptr = ptr.rust_name(), + len = self.binding.type_().mem_size(), + ), + format!("let {name}: &{typename} = unsafe {{ ({name}___MEM.as_ptr() as *const {typename}).as_ref().unwrap() }}; // convert pointer in linear memory to ref", + name = self.name(), + typename = self.type_name(), + ), + ], + BindingParam::Slice(ptr, len) => vec![ + format!("let {ptr} = {ptr} as usize;", + ptr = ptr.rust_name() + ), + format!("let {len} = {len} as usize;", + len = len.rust_name() + ), + format!("if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", + ptr = ptr.rust_name(), + align = self.binding.type_().mem_align(), + ), + format!("#[allow(non_snake_case)] let {name}___MEM: &[u8] = heap.get({ptr}..({ptr}+({len}*{elem_len}))).ok_or_else(|| () /* FIXME: bounds check failed */)?;", + name = self.name(), + ptr = ptr.rust_name(), + len = len.rust_name(), + elem_len =self.binding.type_().mem_size(), + ), + format!("let {}: &[{}] = unsafe {{ ::std::slice::from_raw_parts({name}___MEM.as_ptr() as *const {typename}, {len}) }};", + name = self.name(), + typename = self.type_name(), + len = len.rust_name(), + ) + ], + BindingParam::Value(val) => vec![ + format!("let {name}: {typename} = {value} as {typename};", + name = self.name(), + typename = self.type_name(), + value = val.rust_name(), + ) + ], + } + } else { + assert_eq!(self.binding.direction(), BindingDirection::InOut); + match self.binding.param() { + BindingParam::Ptr(ptr) => vec![ + format!("let {ptr} = {ptr} as usize;", + ptr = ptr.rust_name() + ), + format!("if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", + ptr = ptr.rust_name(), + align = self.binding.type_().mem_align(), + ), + format!("#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", + name = self.name(), + ptr = ptr.rust_name(), + len = self.binding.type_().mem_size(), + ), + format!("let mut {name}: &mut {typename} = unsafe {{ ({name}___MEM.as_mut_ptr() as *mut {typename}).as_mut().unwrap() }}; // convert pointer in linear memory to ref", + name = self.name(), + typename = self.type_name(), + ), + ], + BindingParam::Slice(ptr, len) => vec![ + format!("let {ptr} = {ptr} as usize;", + ptr = ptr.rust_name() + ), + format!("let {len} = {len} as usize;", + len = len.rust_name() + ), + format!("if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", + ptr = ptr.rust_name(), + align = self.binding.type_().mem_align(), + ), + format!("#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+({len}*{elem_len}))).ok_or_else(|| () /* FIXME: bounds check failed */)?;", + name = self.name(), + ptr = ptr.rust_name(), + len = len.rust_name(), + elem_len = self.binding.type_().mem_size(), + ), + + format!("let mut {}: &mut [{}] = unsafe {{ ::std::slice::from_raw_parts_mut({name}___MEM.as_mut_ptr() as *mut {typename}, {len}) }};", + name = self.name(), + typename = self.type_name(), + len = len.rust_name(), + ), + ], + BindingParam::Value {..} => unreachable!(), + } + } + } + pub fn name(&self) -> String { + self.binding.rust_name() + } + + pub fn type_name(&self) -> String { + self.binding.type_().rust_type_name() + } +} + +pub struct RustIdiomRet<'a> { + binding: FuncBinding<'a>, +} + +impl<'a> RustIdiomRet<'a> { + pub fn ret_declaration(&self) -> String { + match self.binding.param() { + BindingParam::Ptr { .. } | BindingParam::Value { .. } => self.type_name(), + BindingParam::Slice { .. } => unreachable!(), + } + } + + pub fn guest_abi_args(&self) -> Vec { + match self.binding.param() { + BindingParam::Ptr(ptr) => vec![ + format!( + "let mut {}___MEM = ::std::mem::MaybeUninit::<{}>::uninit();", + ptr.rust_name(), + self.type_name(), + ), + format!( + "let {} = {}___MEM.as_mut_ptr() as i32;", + ptr.rust_name(), + ptr.rust_name() + ), + ], + BindingParam::Value { .. } => vec![], + BindingParam::Slice { .. } => unreachable!(), + } + } + + pub fn guest_from_abi_call(&self) -> String { + match self.binding.param() { + BindingParam::Ptr(ptr) => format!( + "let {} = unsafe {{ {}___MEM.assume_init() }};", + self.name(), + ptr.rust_name() + ), + BindingParam::Value(val) => format!( + "let {} = {}::from({});", + self.name(), + self.type_name(), + val.rust_name(), + ), + BindingParam::Slice { .. } => unreachable!(), + } + } + + pub fn host_unpack_to_abi(&self) -> Vec { + match self.binding.param() { + BindingParam::Ptr(ptr) => vec![ + format!( + "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", + ptr = ptr.name(), + align = self.binding.type_().mem_align(), + ), + format!( + "#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", + name = self.name(), + ptr = ptr.rust_name(), + len =self.binding.type_().mem_size(), + ), + format!( + "let mut {ptr}: &mut {typename} = unsafe {{ ({name}___MEM.as_mut_ptr() as *mut {typename}).as_mut().unwrap() }}; // convert pointer in linear memory to ref", + name = self.name(), + typename = self.type_name(), + ptr = ptr.rust_name(), + ), + ], + BindingParam::Value(_val) => vec![], + BindingParam::Slice { .. } => unreachable!(), + } + } + + pub fn host_unpack_from_abi(&self) -> String { + match self.binding.param() { + BindingParam::Ptr(ptr) => format!( + "*{} = {}; // Copy into out-pointer reference", + ptr.rust_name(), + self.name(), + ), + BindingParam::Value(val) => format!( + "let {value}: {typename} = {arg} as {typename};", + value = val.rust_name(), + typename = val.type_().rust_type_name(), + arg = self.name(), + ), + BindingParam::Slice { .. } => unreachable!(), + } + } + + pub fn name(&self) -> String { + self.binding.rust_name() + } + + pub fn type_name(&self) -> String { + self.binding.type_().rust_type_name() + } +} diff --git a/lucet-idl/src/rust/guest_funcs.rs b/lucet-idl/src/rust/guest_funcs.rs deleted file mode 100644 index 3e9199aa3..000000000 --- a/lucet-idl/src/rust/guest_funcs.rs +++ /dev/null @@ -1,119 +0,0 @@ -use super::render_tuple; -use crate::error::IDLError; -use crate::pretty_writer::PrettyWriter; -use crate::Function; -use heck::SnakeCase; - -pub struct AbiCallBuilder<'a> { - func: Function<'a>, - before: Vec, - after: Vec, -} - -impl<'a> AbiCallBuilder<'a> { - pub fn new(func: Function<'a>) -> Self { - AbiCallBuilder { - func, - before: Vec::new(), - after: Vec::new(), - } - } - - pub fn before(&mut self, stmt: String) { - self.before.push(stmt); - } - - pub fn after(&mut self, stmt: String) { - self.after.push(stmt); - } - - pub fn render(&self, w: &mut PrettyWriter) -> Result<(), IDLError> { - let name = self.func.name().to_snake_case(); - - let arg_syntax = self - .func - .args() - .map(|a| a.name().to_owned()) - .collect::>() - .join(", "); - let rets = self - .func - .rets() - .map(|r| r.name().to_owned()) - .collect::>(); - let ret_syntax = if rets.is_empty() { - String::new() - } else { - format!("let {} = ", render_tuple(&rets)) - }; - - w.writelns(&self.before); - - w.writeln(format!( - "{}unsafe {{ abi::{}({}) }};", - ret_syntax, name, arg_syntax - )); - - w.writelns(&self.after); - - Ok(()) - } -} - -pub struct FuncBuilder { - name: String, - error_type: String, - args: Vec, - ok_types: Vec, - ok_values: Vec, -} - -impl FuncBuilder { - pub fn new(name: String, error_type: String) -> Self { - FuncBuilder { - name, - error_type, - args: Vec::new(), - ok_types: Vec::new(), - ok_values: Vec::new(), - } - } - - pub fn arg(&mut self, arg: String) { - self.args.push(arg) - } - - pub fn ok_type(&mut self, arg: String) { - self.ok_types.push(arg); - } - - pub fn ok_value(&mut self, val: String) { - self.ok_values.push(val); - } - - pub fn render(&self, w: &mut PrettyWriter, body: F) -> Result<(), IDLError> - where - F: FnOnce(&mut PrettyWriter) -> Result<(), IDLError>, - { - if self.ok_types.len() != self.ok_values.len() { - Err(IDLError::InternalError( - "func builder ok types do not match ok values", - ))?; - } - let arg_syntax = self.args.join(", "); - let ret_syntax = format!( - "Result<{},{}>", - render_tuple(&self.ok_types), - self.error_type - ); - w.writeln(format!( - "pub fn {}({}) -> {} {{", - self.name, arg_syntax, ret_syntax - )) - .indent(); - body(w)?; - w.writeln(format!("Ok({})", render_tuple(&self.ok_values))); - w.eob().writeln("}".to_owned()); - Ok(()) - } -} From bf347880064d761cc60a9d6cac9bdff3b9a4c286 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 7 Aug 2019 17:07:16 -0700 Subject: [PATCH 336/512] lucet-idl-test: render harnesses for both rust guest and host --- lucet-idl/lucet-idl-test/Cargo.toml | 2 +- lucet-idl/lucet-idl-test/src/host.rs | 17 +- lucet-idl/lucet-idl-test/src/lib.rs | 1 + lucet-idl/lucet-idl-test/src/main.rs | 35 ++-- lucet-idl/lucet-idl-test/src/rust_guest.rs | 31 ++-- lucet-idl/lucet-idl-test/src/values.rs | 190 +++++++++++---------- lucet-idl/src/lib.rs | 2 +- lucet-idl/src/rust.rs | 2 +- 8 files changed, 155 insertions(+), 125 deletions(-) diff --git a/lucet-idl/lucet-idl-test/Cargo.toml b/lucet-idl/lucet-idl-test/Cargo.toml index 1f10f2402..8df1ce874 100644 --- a/lucet-idl/lucet-idl-test/Cargo.toml +++ b/lucet-idl/lucet-idl-test/Cargo.toml @@ -17,7 +17,7 @@ lucetc = { path = "../../lucetc" } lucet-runtime = { path = "../../lucet-runtime" } lucet-wasi = { path = "../../lucet-wasi" } lucet-wasi-sdk = { path = "../../lucet-wasi-sdk" } -proptest = "0.9.3" +proptest = "0.9.4" tempfile = "3.0" failure = "0.1" log = "0.4" diff --git a/lucet-idl/lucet-idl-test/src/host.rs b/lucet-idl/lucet-idl-test/src/host.rs index 9d36c5590..e4e633284 100644 --- a/lucet-idl/lucet-idl-test/src/host.rs +++ b/lucet-idl/lucet-idl-test/src/host.rs @@ -1,6 +1,7 @@ +use crate::ModuleTestPlan; use failure::{format_err, Error}; use fs2::FileExt; -use lucet_idl::{self, Backend, Config, Package}; +use lucet_idl::{self, pretty_writer::PrettyWriter, Backend, Config, Package}; use std::fs::{self, File}; use std::path::{Path, PathBuf}; use std::process::Command; @@ -16,8 +17,9 @@ pub struct HostApp { } impl HostApp { - pub fn new(package: &Package) -> Result { - if package.modules().collect::>().len() != 1 { + pub fn new(package: &Package, test_plan: &ModuleTestPlan) -> Result { + let modules = package.modules().collect::>(); + if modules.len() != 1 { Err(format_err!( "only one module per package supported at this time" ))? @@ -53,13 +55,8 @@ impl HostApp { Box::new(idl_file), )?; - let harness_file = hostapp.source_file("harness.rs")?; - /* FIXME - test_harness( - Box::new(harness_file), - package.modules.get(0).expect("one module per package"), - )?; - */ + let mut harness_writer = PrettyWriter::new(Box::new(hostapp.source_file("harness.rs")?)); + test_plan.render_host(&mut harness_writer); Ok(hostapp) } diff --git a/lucet-idl/lucet-idl-test/src/lib.rs b/lucet-idl/lucet-idl-test/src/lib.rs index 75efc6c6d..24e227f64 100644 --- a/lucet-idl/lucet-idl-test/src/lib.rs +++ b/lucet-idl/lucet-idl-test/src/lib.rs @@ -9,6 +9,7 @@ pub use c_guest::CGuestApp; pub use host::HostApp; pub use rust_guest::RustGuestApp; pub use syntax::Spec; +pub use values::ModuleTestPlan; pub use workspace::Workspace; #[cfg(test)] diff --git a/lucet-idl/lucet-idl-test/src/main.rs b/lucet-idl/lucet-idl-test/src/main.rs index 945126356..c1b3da407 100644 --- a/lucet-idl/lucet-idl-test/src/main.rs +++ b/lucet-idl/lucet-idl-test/src/main.rs @@ -1,8 +1,8 @@ use clap::{App, Arg}; use env_logger; use log::{debug, info}; -use lucet_idl::{parse_package, Package}; -use lucet_idl_test::{CGuestApp, HostApp, RustGuestApp, Spec, Workspace}; +use lucet_idl::{parse_package, Module, Package}; +use lucet_idl_test::{CGuestApp, HostApp, ModuleTestPlan, RustGuestApp, Spec, Workspace}; use proptest::prelude::*; use proptest::strategy::ValueTree; use proptest::test_runner::TestRunner; @@ -14,10 +14,11 @@ fn main() { env_logger::init(); let exe_config = ExeConfig::parse(); + let mut runner = TestRunner::default(); + let input_idl = match exe_config.input { Some(path) => read_to_string(path).expect("read contents of input file"), None => { - let mut runner = TestRunner::default(); let spec = Spec::strat(10).new_tree(&mut runner).unwrap().current(); let rendered = spec.render_idl(); info!("generated spec:\n{}", rendered); @@ -28,7 +29,6 @@ fn main() { let pkg = parse_package(&input_idl).expect("parse generated package"); debug!("parsed package: {:?}", pkg); - if exe_config.generate_values { generate_values(&pkg); process::exit(0); @@ -38,12 +38,25 @@ fn main() { generate_calls(&pkg); process::exit(0); } + + let module = pkg + .modules() + .collect::>() + .pop() + .expect("get generated module"); + let test_plan = ModuleTestPlan::strat(&module) + .new_tree(&mut runner) + .unwrap() + .current(); + // Workspace deleted when dropped - need to keep it alive for app to be run let mut guest_apps: Vec<(PathBuf, Workspace)> = Vec::new(); if exe_config.build_rust_guest { let mut rust_guest_app = RustGuestApp::new().expect("create rust guest app"); - let rust_guest_so = rust_guest_app.build(&pkg).expect("compile rust guest app"); + let rust_guest_so = rust_guest_app + .build(&pkg, &test_plan) + .expect("compile rust guest app"); guest_apps.push((rust_guest_so, rust_guest_app.into_workspace())); } @@ -54,7 +67,7 @@ fn main() { } if exe_config.build_host { - let mut host_app = HostApp::new(&pkg).expect("create host app"); + let mut host_app = HostApp::new(&pkg, &test_plan).expect("create host app"); if exe_config.run_guests { for (guest_app_path, _ws) in guest_apps.iter() { host_app.run(guest_app_path).expect("run guest app"); @@ -143,9 +156,9 @@ impl ExeConfig { fn generate_values(package: &Package) { use lucet_idl_test::values::*; - for (_, m) in package.modules.iter() { + for m in package.modules() { for dt in m.datatypes() { - let dt_generator = m.datatype_strat(&dt.datatype_ref()); + let dt_generator = dt.strat(); let mut runner = TestRunner::default(); let value = dt_generator .new_tree(&mut runner) @@ -159,9 +172,9 @@ fn generate_values(package: &Package) { fn generate_calls(package: &Package) { use lucet_idl_test::values::*; - for (_, m) in package.modules.iter() { - for fdecl in m.func_decls() { - let func_pred_gen = FuncCallPredicate::strat(&m, &fdecl.entity); + for m in package.modules() { + for func in m.functions() { + let func_pred_gen = FuncCallPredicate::strat(&func); let mut runner = TestRunner::default(); let value = func_pred_gen .new_tree(&mut runner) diff --git a/lucet-idl/lucet-idl-test/src/rust_guest.rs b/lucet-idl/lucet-idl-test/src/rust_guest.rs index 87e628898..0dcbffab5 100644 --- a/lucet-idl/lucet-idl-test/src/rust_guest.rs +++ b/lucet-idl/lucet-idl-test/src/rust_guest.rs @@ -1,10 +1,10 @@ use crate::workspace::Workspace; +use crate::ModuleTestPlan; use failure::{format_err, Error}; -use lucet_idl::{self, Backend, Config, Package}; +use lucet_idl::{self, pretty_writer::PrettyWriter, Backend, Config, Package}; use lucet_wasi; use lucetc::{Lucetc, LucetcOpts}; use std::fs::File; -use std::io::Write; use std::path::PathBuf; use std::process::Command; @@ -30,17 +30,16 @@ impl RustGuestApp { Ok(()) } - fn generate_main_rs(&mut self) -> Result<(), Error> { - let mut main_file = File::create(self.work.source_path("main.rs"))?; - main_file.write_all( - b" -#[allow(unused)] -mod idl; + fn generate_main_rs(&mut self, test_plan: &ModuleTestPlan) -> Result<(), Error> { + let mut w = PrettyWriter::new(Box::new(File::create(self.work.source_path("main.rs"))?)); + w.writeln("mod idl;"); + w.writeln(format!("use idl::{}::*;", test_plan.module_name)); -fn main() { - println!(\"hello, world from rust guest\"); -}", - )?; + w.writeln("fn main() {").indent(); + w.writeln("println!(\"hello, world from rust guest\");"); + test_plan.render_guest(&mut w); + w.writeln("println!(\"test complete!\");"); + w.eob().writeln("}"); Ok(()) } @@ -58,9 +57,13 @@ fn main() { Ok(()) } - pub fn build(&mut self, package: &Package) -> Result { + pub fn build( + &mut self, + package: &Package, + test_plan: &ModuleTestPlan, + ) -> Result { self.generate_idl_rs(package)?; - self.generate_main_rs()?; + self.generate_main_rs(test_plan)?; self.rustc()?; let mut bindings = lucet_wasi::bindings(); bindings.extend(&package.bindings())?; diff --git a/lucet-idl/lucet-idl-test/src/values.rs b/lucet-idl/lucet-idl-test/src/values.rs index 55d3bb2b9..982d935e8 100644 --- a/lucet-idl/lucet-idl-test/src/values.rs +++ b/lucet-idl/lucet-idl-test/src/values.rs @@ -1,7 +1,8 @@ -use heck::CamelCase; +use heck::{CamelCase, SnakeCase}; use lucet_idl::{ - AliasDatatype, AtomType, BindingDirection, BindingParam, Datatype, DatatypeVariant, - EnumDatatype, FuncBinding, Function, Module, StructDatatype, StructMember, + pretty_writer::PrettyWriter, AliasDatatype, AtomType, BindingDirection, BindingParam, Datatype, + DatatypeVariant, EnumDatatype, FuncBinding, Function, Module, RustFunc, RustName, RustTypeName, + StructDatatype, StructMember, }; use proptest::prelude::*; @@ -283,14 +284,18 @@ impl BindingVal { } #[derive(Debug, Clone)] -pub struct FuncCallPredicate<'a> { - func: &'a Function<'a>, +pub struct FuncCallPredicate { + func_name: String, + func_call_args: Vec, + func_call_rets: Vec, + func_sig_args: Vec, + func_sig_rets: Vec, pre: Vec, post: Vec, } -impl<'a> FuncCallPredicate<'a> { - pub fn strat(func: &Function<'a>) -> BoxedStrategy> { +impl FuncCallPredicate { + pub fn strat(func: &Function) -> BoxedStrategy { let mut pre_strat: Vec> = func .bindings() .filter(|b| b.direction() == BindingDirection::In) @@ -306,16 +311,37 @@ impl<'a> FuncCallPredicate<'a> { ); let post_strat: Vec> = func .bindings() - .filter(|b| b.direction() == BindingDirection::InOut) - .chain( - func.bindings() - .filter(|b| b.direction() == BindingDirection::Out), - ) + .filter(|b| { + b.direction() == BindingDirection::InOut || b.direction() == BindingDirection::Out + }) .map(|binding| BindingVal::binding_strat(&binding, false)) .collect(); + let idiom_args = func.rust_idiom_args(); + let func_name = func.rust_name(); + let func_call_args = idiom_args.iter().map(|a| a.arg_value()).collect::>(); + let func_sig_args = idiom_args + .iter() + .map(|a| a.arg_declaration()) + .collect::>(); + + let idiom_rets = func.rust_idiom_rets(); + let func_call_rets = idiom_rets.iter().map(|r| r.name()).collect::>(); + let func_sig_rets = idiom_rets + .iter() + .map(|a| a.ret_declaration()) + .collect::>(); + (pre_strat, post_strat) - .prop_map(move |(pre, post)| FuncCallPredicate { pre, post, func }) + .prop_map(move |(pre, post)| FuncCallPredicate { + func_name: func_name.clone(), + func_call_args: func_call_args.clone(), + func_call_rets: func_call_rets.clone(), + func_sig_args: func_sig_args.clone(), + func_sig_rets: func_sig_rets.clone(), + pre, + post, + }) .boxed() } @@ -326,107 +352,97 @@ impl<'a> FuncCallPredicate<'a> { .map(|val| val.render_rust_binding()) .collect(); - let mut arg_syntax = Vec::new(); - for in_binding in self - .func - .bindings() - .filter(|b| b.direction() == BindingDirection::In) - { - arg_syntax.push(match in_binding.param() { - BindingParam::Ptr(_) => format!("&{}", in_binding.name()), - BindingParam::Slice(_, _) => format!("&{}", in_binding.name()), - BindingParam::Value(_) => in_binding.name().to_owned(), - }) - } - for io_binding in self - .func - .bindings() - .filter(|b| b.direction() == BindingDirection::InOut) - { - arg_syntax.push(match io_binding.param() { - BindingParam::Ptr(_) => format!("&mut {}", io_binding.name()), - BindingParam::Slice(_, _) => format!("&mut {}", io_binding.name()), - BindingParam::Value(_) => unreachable!("should be no such thing as an io value"), - }) - } - lines.push(format!( - "let {} = {}({});", - render_tuple( - self.func - .bindings() - .filter(|b| b.direction() == BindingDirection::In) - .map(|b| b.name().to_owned()) - .collect::>(), - "_" - ), - self.func.name(), - arg_syntax.join(",") + "let {} = {}({}).unwrap();", + render_tuple(&self.func_call_rets, "_"), + self.func_name, + self.func_call_args.join(",") )); lines.append( &mut self .post .iter() - .map(|val| format!("assert_eq!({}, {});", val.name, val.render_rust_ref())) + .map(|val| { + format!( + "assert_eq!({}, {});", + val.name, + val.render_rust_constructor() + ) + }) .collect(), ); lines } - pub fn render_callee(&self) -> Vec { - let mut lines = Vec::new(); + pub fn render_callee(&self, w: &mut PrettyWriter) { + w.writeln(format!( + "fn {}(&mut self, {}) -> Result<{}, ()> {{", + self.func_name, + self.func_sig_args.join(", "), + render_tuple(&self.func_sig_rets, "()") + )) + .indent(); // Assert preconditions hold - lines.append( - &mut self + w.writelns( + &self .pre .iter() .map(|val| format!("assert_eq!({}, {};", val.name, val.render_rust_ref())) - .collect(), + .collect::>(), ); // Make postconditions hold - lines.append( - &mut self + w.writelns( + &self .post .iter() .map(|val| format!("*{} = {};", val.name, val.render_rust_constructor())) - .collect(), + .collect::>(), ); - lines + w.eob().writeln("}"); } +} - pub fn render_host_trait(&self, module: &Module) -> Vec { - let mut lines = Vec::new(); - lines.push("struct TestHarness;".to_owned()); - lines.push(format!( - "impl {} for TesHarnesst {{", - module.name().to_camel_case() - )); - for func in module.functions() { - lines.push(format!("/* FIXME: method {} */", func.name())); - /* - let mut args: Vec = Vec::new(); - for input in func.in_bindings.iter() {} - let mut rets = Vec::new(); - lines.push(format!( - "fn {}(&mut self, {}) -> Result<{}, ()>", - func.field_name, - args.join(","), - render_tuple(rets, "()") - )); - if func.field_name == self.func.field_name { - lines.append(&mut self.render_callee()); - } else { - lines.push("panic!(\"should not be called\")".to_owned()); - } - lines.push("}".to_owned()); - */ +#[derive(Debug, Clone)] +pub struct ModuleTestPlan { + pub module_name: String, + module_type_name: String, + func_predicates: Vec, +} + +impl ModuleTestPlan { + pub fn strat(module: &Module) -> BoxedStrategy { + let module_name = module.name().to_snake_case(); + let module_type_name = module.rust_type_name(); + module + .functions() + .map(|f| FuncCallPredicate::strat(&f)) + .collect::>() + .prop_map(move |func_predicates| ModuleTestPlan { + module_name: module_name.clone(), + module_type_name: module_type_name.clone(), + func_predicates, + }) + .boxed() + } + + pub fn render_guest(&self, w: &mut PrettyWriter) { + for func in self.func_predicates.iter() { + w.writelns(&func.render_caller()); } - lines.push("}".to_owned()); - lines + } + + pub fn render_host(&self, mut w: &mut PrettyWriter) { + w.writeln("struct TestHarness;"); + w.writeln(format!("impl {} for TestHarness {{", self.module_type_name,)) + .indent(); + for func in self.func_predicates.iter() { + func.render_callee(&mut w) + } + w.eob().writeln("}"); } } -fn render_tuple(vs: Vec, base_case: &str) -> String { +fn render_tuple(vs: &[String], base_case: &str) -> String { match vs.len() { 0 => base_case.to_owned(), 1 => vs[0].clone(), diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 017ab13bd..c81ef39fe 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -11,7 +11,7 @@ mod error; mod lexer; mod parser; mod prelude; -mod pretty_writer; +pub mod pretty_writer; mod repr; mod rust; mod validate; diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index 3fb4e9a15..be403094f 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -27,7 +27,7 @@ impl RustGenerator { pub fn generate_guest(&mut self, package: &Package) -> Result<(), IDLError> { for module in package.modules() { self.w - .writeln(format!("mod {} {{", module.rust_name())) + .writeln(format!("pub mod {} {{", module.rust_name())) .indent(); self.generate_datatypes(&module)?; From caf1c2bbb67ec7701380d42f374a08d319b5e6ca Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 7 Aug 2019 18:02:20 -0700 Subject: [PATCH 337/512] bump cargo.lock --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 87f28fbd0..c17c80511 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -801,7 +801,7 @@ name = "lucet-idl" version = "0.1.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-entity 0.31.0", + "cranelift-entity 0.37.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", From a8a47736c0405f5ddf6209c664c42d548b4ae072 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 7 Aug 2019 22:12:02 -0700 Subject: [PATCH 338/512] lucet-idl-test: many fixes, very nearly works --- lucet-idl/lucet-idl-test/src/values.rs | 32 +++++++---- lucet-idl/src/cursor.rs | 33 +++++++++++ lucet-idl/src/rust.rs | 80 ++++++++++++++++++++++++-- lucet-idl/src/rust/cursor.rs | 63 ++++++++++++++------ 4 files changed, 173 insertions(+), 35 deletions(-) diff --git a/lucet-idl/lucet-idl-test/src/values.rs b/lucet-idl/lucet-idl-test/src/values.rs index 982d935e8..65ce01788 100644 --- a/lucet-idl/lucet-idl-test/src/values.rs +++ b/lucet-idl/lucet-idl-test/src/values.rs @@ -273,7 +273,7 @@ impl BindingVal { BindingValVariant::Value(v) => v.render_rustval(), BindingValVariant::Ptr(v) => format!("&{}", v.render_rustval()), BindingValVariant::Array(vs) => format!( - "&[{}]", + "vec![{}].as_slice()", vs.iter() .map(|v| v.render_rustval()) .collect::>() @@ -387,17 +387,27 @@ impl FuncCallPredicate { &self .pre .iter() - .map(|val| format!("assert_eq!({}, {};", val.name, val.render_rust_ref())) + .map(|val| format!("assert_eq!({}, {});", val.name, val.render_rust_ref())) .collect::>(), ); // Make postconditions hold - w.writelns( - &self - .post - .iter() - .map(|val| format!("*{} = {};", val.name, val.render_rust_constructor())) - .collect::>(), - ); + let mut ret_vals = Vec::new(); + for post in self.post.iter() { + match post.variant { + BindingValVariant::Value(ref val) => { + ret_vals.push(val.render_rustval()); + } + BindingValVariant::Ptr(ref val) => { + w.writeln(format!("*{} = {};", post.name, val.render_rustval())); + } + BindingValVariant::Array(ref vals) => { + for (ix, val) in vals.iter().enumerate() { + w.writeln(format!("{}[{}] = {};", post.name, ix, val.render_rustval())); + } + } + } + } + w.writeln(format!("Ok({})", render_tuple(&ret_vals, "()"))); w.eob().writeln("}"); } } @@ -432,7 +442,9 @@ impl ModuleTestPlan { } pub fn render_host(&self, mut w: &mut PrettyWriter) { - w.writeln("struct TestHarness;"); + w.writeln(format!("use crate::idl::{}::*;", self.module_name)); + w.writeln("pub struct TestHarness;"); + w.writeln("pub fn ctx() -> TestHarness { TestHarness }"); w.writeln(format!("impl {} for TestHarness {{", self.module_type_name,)) .indent(); for func in self.func_predicates.iter() { diff --git a/lucet-idl/src/cursor.rs b/lucet-idl/src/cursor.rs index 203028d04..e546ae5c5 100644 --- a/lucet-idl/src/cursor.rs +++ b/lucet-idl/src/cursor.rs @@ -183,6 +183,17 @@ impl<'a> Datatype<'a> { pub fn abi_type(&self) -> Option { self.variant().abi_type() } + + pub fn anti_alias(&self) -> Datatype<'a> { + match self.repr().variant { + DatatypeVariantRepr::Alias(ref repr) => AliasDatatype { + datatype: self.clone(), + repr: &repr, + } + .anti_alias(), + _ => self.clone(), + } + } } impl<'a> MemArea for Datatype<'a> { @@ -361,6 +372,28 @@ impl<'a> AliasDatatype<'a> { id: self.repr.to, } } + + /// Find the non-alias datatype that this alias transitively refers to. + pub fn anti_alias(&self) -> Datatype<'a> { + // We can't just call this recursively because + // of the borrow checker, so we have to recurse in a loop :/ + let mut referent = Datatype { + pkg: self.datatype.pkg, + id: self.repr.to, + }; + loop { + match referent.variant() { + DatatypeVariant::Alias(a) => { + referent.id = a.datatype.id; + } + _ => break, + } + } + Datatype { + pkg: self.datatype.pkg, + id: referent.id, + } + } } impl<'a> From> for Datatype<'a> { diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index be403094f..dfd8317e5 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -54,7 +54,7 @@ impl RustGenerator { pub fn generate_host(&mut self, package: &Package) -> Result<(), IDLError> { for module in package.modules() { self.w - .writeln(format!("mod {} {{", module.rust_name())) + .writeln(format!("pub mod {} {{", module.rust_name())) .indent(); self.generate_datatypes(&module)?; @@ -68,12 +68,14 @@ impl RustGenerator { } self.w.eob().writeln("}"); - self.host_ensure_linked(&module); + self.host_module_ensure_linked(&module); self.w .eob() .writeln(format!("}} // end module {}", module.rust_name())); } + self.host_package_ensure_linked(&package); + Ok(()) } @@ -110,6 +112,7 @@ impl RustGenerator { fn gen_struct(&mut self, struct_: &StructDatatype) -> Result<(), IDLError> { self.w .writeln("#[repr(C)]") + .writeln("#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]") .writeln(format!("pub struct {} {{", struct_.rust_type_name())); let mut w = self.w.new_block(); @@ -123,6 +126,33 @@ impl RustGenerator { self.w.writeln("}"); + self.w + .writeln(format!("impl {} {{", struct_.rust_type_name())); + let mut w = self.w.new_block(); + + w.writeln("pub fn validate_bytes(repr: &[u8]) -> bool {"); + let mut ww = w.new_block(); + for m in struct_.members() { + match m.type_().anti_alias().variant() { + DatatypeVariant::Struct(_) | DatatypeVariant::Enum(_) => { + ww.writeln(format!( + "{}::validate_bytes(&repr[{}..{}]) &&", + m.type_().rust_type_name(), + m.offset(), + m.offset() + m.type_().mem_size(), + )); + } + DatatypeVariant::Atom(_) => { + ww.writeln(format!("// not validating {}", m.type_().rust_type_name())); + } + DatatypeVariant::Alias(_) => unreachable!("anti-aliased datatype"), + } + } + ww.writeln("true"); // to catch the trailing && + w.writeln("}"); + + self.w.writeln("}"); // end impl + gen_testcase(&mut self.w, &struct_.name().to_snake_case(), |w| { w.writeln(format!( "assert_eq!({}, ::std::mem::size_of::());", @@ -146,7 +176,7 @@ impl RustGenerator { fn gen_enum(&mut self, enum_: &EnumDatatype) -> Result<(), IDLError> { self.w .writeln("#[repr(C)]") - .writeln("#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]") + .writeln("#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]") .writeln(format!("pub enum {} {{", enum_.rust_type_name())); let mut w = self.w.new_block(); @@ -156,6 +186,35 @@ impl RustGenerator { self.w.writeln("}"); + self.w + .writeln(format!("impl {} {{", enum_.rust_type_name())); + let mut w = self.w.new_block(); + w.writeln("pub fn from_u32(e: u32) -> Option {"); + let mut ww = w.new_block(); + ww.writeln("match e {"); + let mut www = ww.new_block(); + for v in enum_.variants() { + www.writeln(format!( + "{} => Some({}::{}),", + v.index(), + enum_.rust_type_name(), + v.rust_name() + )); + } + www.writeln("_ => None,"); + ww.writeln("}"); + w.writeln("}"); + + w.writeln("pub fn validate_bytes(repr: &[u8]) -> bool {"); + let mut ww = w.new_block(); + ww.writeln(format!( + "((repr[0] as u32) + ((repr[1] as u32) << 8) + \ + ((repr[2] as u32) << 16) + ((repr[3] as u32) << 24)) < {}", + enum_.variants().collect::>().len() + )); + w.writeln("}"); + self.w.writeln("}"); // end impl + gen_testcase(&mut self.w, &enum_.name().to_snake_case(), |w| { w.writeln(format!( "assert_eq!({}, ::std::mem::size_of::());", @@ -340,13 +399,13 @@ impl RustGenerator { let mut args = func .rust_idiom_args() .iter() - .map(|a| a.arg_value()) + .map(|a| a.arg_declaration()) .collect::>(); args.insert(0, "&mut self".to_owned()); let rets = func .rust_idiom_rets() .iter() - .map(|a| a.name()) + .map(|a| a.ret_declaration()) .rust_tuple_syntax("()"); self.w.writeln(format!( @@ -362,7 +421,7 @@ impl RustGenerator { Ok(()) } - fn host_ensure_linked(&mut self, module: &Module) { + fn host_module_ensure_linked(&mut self, module: &Module) { self.w.writeln("pub fn ensure_linked() {").indent(); self.w.writeln("unsafe {").indent(); for func in module.functions() { @@ -374,6 +433,15 @@ impl RustGenerator { self.w.eob().writeln("}"); self.w.eob().writeln("}"); } + + fn host_package_ensure_linked(&mut self, package: &Package) { + self.w.writeln("pub fn ensure_linked() {").indent(); + for module in package.modules() { + self.w + .writeln(format!("{}::ensure_linked()", module.rust_name())); + } + self.w.eob().writeln("}"); + } } fn gen_testcase(w: &mut PrettyWriter, name: &str, f: F) -> Result<(), IDLError> diff --git a/lucet-idl/src/rust/cursor.rs b/lucet-idl/src/rust/cursor.rs index 2e2a3a9d1..833091b06 100644 --- a/lucet-idl/src/rust/cursor.rs +++ b/lucet-idl/src/rust/cursor.rs @@ -229,13 +229,7 @@ impl<'a> RustIdiomArg<'a> { len = len.rust_name(), ) ], - BindingParam::Value(val) => vec![ - format!("let {name}: {typename} = {value} as {typename};", - name = self.name(), - typename = self.type_name(), - value = val.rust_name(), - ) - ], + BindingParam::Value(_val) => vec![cast_value_to_binding(&self.binding)], } } else { assert_eq!(self.binding.direction(), BindingDirection::InOut); @@ -311,7 +305,7 @@ impl<'a> RustIdiomRet<'a> { match self.binding.param() { BindingParam::Ptr(ptr) => vec![ format!( - "let mut {}___MEM = ::std::mem::MaybeUninit::<{}>::uninit();", + "#[allow(non_snake_case)] let mut {}___MEM = ::std::mem::MaybeUninit::<{}>::uninit();", ptr.rust_name(), self.type_name(), ), @@ -333,19 +327,19 @@ impl<'a> RustIdiomRet<'a> { self.name(), ptr.rust_name() ), - BindingParam::Value(val) => format!( - "let {} = {}::from({});", - self.name(), - self.type_name(), - val.rust_name(), - ), + BindingParam::Value(_val) => cast_value_to_binding(&self.binding), BindingParam::Slice { .. } => unreachable!(), } } pub fn host_unpack_to_abi(&self) -> Vec { match self.binding.param() { - BindingParam::Ptr(ptr) => vec![ + BindingParam::Ptr(ptr) => { + let mut lines = vec![ + format!( + "let {ptr} = {ptr} as usize;", + ptr = ptr.rust_name() + ), format!( "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", ptr = ptr.name(), @@ -356,14 +350,23 @@ impl<'a> RustIdiomRet<'a> { name = self.name(), ptr = ptr.rust_name(), len =self.binding.type_().mem_size(), - ), - format!( + )]; + match self.binding.type_().anti_alias().variant() { + DatatypeVariant::Enum(_) | DatatypeVariant::Struct(_) => { + lines.push(format!("if !{}::validate_bytes(&{}___MEM) {{ Err(())?; /* FIXME invalid representation */ }}", + self.type_name(), self.name())) + } + DatatypeVariant::Atom(_) => {} // No representation validation required + DatatypeVariant::Alias(_) => unreachable!("anti-aliased"), + } + lines.push(format!( "let mut {ptr}: &mut {typename} = unsafe {{ ({name}___MEM.as_mut_ptr() as *mut {typename}).as_mut().unwrap() }}; // convert pointer in linear memory to ref", name = self.name(), typename = self.type_name(), ptr = ptr.rust_name(), - ), - ], + )); + lines + } BindingParam::Value(_val) => vec![], BindingParam::Slice { .. } => unreachable!(), } @@ -394,3 +397,25 @@ impl<'a> RustIdiomRet<'a> { self.binding.type_().rust_type_name() } } + +fn cast_value_to_binding(b: &FuncBinding) -> String { + match b.param() { + BindingParam::Value(val) => match b.type_().anti_alias().variant() { + DatatypeVariant::Enum(_) => format!( + "let {} = {}::from_u32({} as u32).ok_or(())?; // FIXME throw the right error", + b.rust_name(), + b.type_().rust_type_name(), + val.rust_name(), + ), + DatatypeVariant::Atom(_) => format!( + "let {} = {} as {};", + b.rust_name(), + val.rust_name(), + b.type_().rust_type_name(), + ), + DatatypeVariant::Alias(_) => unreachable!("anti-aliased"), + DatatypeVariant::Struct(_) => unreachable!("can't represent struct as binding value"), + }, + _ => panic!("can only cast BindingParam::Value to binding type"), + } +} From f49c59215a555e9bf15b0de74d1e5646efaa7ac9 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 8 Aug 2019 17:57:51 -0700 Subject: [PATCH 339/512] lucet-idl-test: fix testing! we can now round-trip test the example idl successfully! --- lucet-idl/lucet-idl-test/src/rust_guest.rs | 1 + lucet-idl/lucet-idl-test/src/values.rs | 85 ++++++++++++---------- lucet-idl/src/rust/cursor.rs | 47 ++++++++---- 3 files changed, 78 insertions(+), 55 deletions(-) diff --git a/lucet-idl/lucet-idl-test/src/rust_guest.rs b/lucet-idl/lucet-idl-test/src/rust_guest.rs index 0dcbffab5..c8b2fd244 100644 --- a/lucet-idl/lucet-idl-test/src/rust_guest.rs +++ b/lucet-idl/lucet-idl-test/src/rust_guest.rs @@ -32,6 +32,7 @@ impl RustGuestApp { fn generate_main_rs(&mut self, test_plan: &ModuleTestPlan) -> Result<(), Error> { let mut w = PrettyWriter::new(Box::new(File::create(self.work.source_path("main.rs"))?)); + w.writeln("#[allow(unused)]"); w.writeln("mod idl;"); w.writeln(format!("use idl::{}::*;", test_plan.module_name)); diff --git a/lucet-idl/lucet-idl-test/src/values.rs b/lucet-idl/lucet-idl-test/src/values.rs index 65ce01788..638a3ab24 100644 --- a/lucet-idl/lucet-idl-test/src/values.rs +++ b/lucet-idl/lucet-idl-test/src/values.rs @@ -1,8 +1,8 @@ use heck::{CamelCase, SnakeCase}; use lucet_idl::{ pretty_writer::PrettyWriter, AliasDatatype, AtomType, BindingDirection, BindingParam, Datatype, - DatatypeVariant, EnumDatatype, FuncBinding, Function, Module, RustFunc, RustName, RustTypeName, - StructDatatype, StructMember, + DatatypeVariant, EnumDatatype, Function, Module, RustFunc, RustIdiomArg, RustIdiomRet, + RustName, RustTypeName, StructDatatype, StructMember, }; use proptest::prelude::*; @@ -215,10 +215,11 @@ pub enum BindingValVariant { } impl BindingVal { - fn binding_strat(binding: &FuncBinding, mutable: bool) -> BoxedStrategy { - let name = binding.name().to_owned(); - match binding.param() { - BindingParam::Value(_) => binding + fn arg_strat(arg: &RustIdiomArg) -> BoxedStrategy { + let mutable = arg.direction() == BindingDirection::InOut; + let name = arg.name(); + match arg.param() { + BindingParam::Value(_) => arg .type_() .strat() .prop_map(move |v| BindingVal { @@ -227,7 +228,7 @@ impl BindingVal { variant: BindingValVariant::Value(v), }) .boxed(), - BindingParam::Ptr(_) => binding + BindingParam::Ptr(_) => arg .type_() .strat() .prop_map(move |v| BindingVal { @@ -236,7 +237,7 @@ impl BindingVal { variant: BindingValVariant::Ptr(v), }) .boxed(), - BindingParam::Slice(_, _) => prop::collection::vec(binding.type_().strat(), 100) + BindingParam::Slice(_, _) => prop::collection::vec(arg.type_().strat(), 100) .prop_map(move |v| BindingVal { name: name.clone(), mutable, @@ -245,6 +246,21 @@ impl BindingVal { .boxed(), } } + + fn ret_strat(ret: &RustIdiomRet) -> BoxedStrategy { + let name = ret.name(); + // There can only be param or value bindings on returns, + // and both are idiomatically values. + ret.type_() + .strat() + .prop_map(move |v| BindingVal { + name: name.clone(), + mutable: false, + variant: BindingValVariant::Value(v), + }) + .boxed() + } + fn render_rust_binding(&self) -> String { format!( "let {}{} = {};", @@ -296,42 +312,28 @@ pub struct FuncCallPredicate { impl FuncCallPredicate { pub fn strat(func: &Function) -> BoxedStrategy { - let mut pre_strat: Vec> = func - .bindings() - .filter(|b| b.direction() == BindingDirection::In) - .map(|binding| BindingVal::binding_strat(&binding, false)) - .collect(); + let args = func.rust_idiom_args(); + let rets = func.rust_idiom_rets(); - pre_strat.append( - &mut func - .bindings() - .filter(|b| b.direction() == BindingDirection::InOut) - .map(|binding| BindingVal::binding_strat(&binding, true)) - .collect(), - ); - let post_strat: Vec> = func - .bindings() - .filter(|b| { - b.direction() == BindingDirection::InOut || b.direction() == BindingDirection::Out - }) - .map(|binding| BindingVal::binding_strat(&binding, false)) - .collect(); + // Precondition on all arguments + let pre_strat: Vec> = + args.iter().map(|a| BindingVal::arg_strat(a)).collect(); - let idiom_args = func.rust_idiom_args(); - let func_name = func.rust_name(); - let func_call_args = idiom_args.iter().map(|a| a.arg_value()).collect::>(); - let func_sig_args = idiom_args + // Postcondition on all inout arguments, and all return values + let post_strat: Vec> = args .iter() - .map(|a| a.arg_declaration()) - .collect::>(); + .filter(|a| a.direction() == BindingDirection::InOut) + .map(|a| BindingVal::arg_strat(a)) + .chain(rets.iter().map(|r| BindingVal::ret_strat(r))) + .collect(); - let idiom_rets = func.rust_idiom_rets(); - let func_call_rets = idiom_rets.iter().map(|r| r.name()).collect::>(); - let func_sig_rets = idiom_rets - .iter() - .map(|a| a.ret_declaration()) - .collect::>(); + let func_call_args = args.iter().map(|a| a.arg_value()).collect::>(); + let func_sig_args = args.iter().map(|a| a.arg_declaration()).collect::>(); + let func_call_rets = rets.iter().map(|r| r.name()).collect::>(); + let func_sig_rets = rets.iter().map(|a| a.ret_declaration()).collect::>(); + + let func_name = func.rust_name(); (pre_strat, post_strat) .prop_map(move |(pre, post)| FuncCallPredicate { func_name: func_name.clone(), @@ -444,13 +446,16 @@ impl ModuleTestPlan { pub fn render_host(&self, mut w: &mut PrettyWriter) { w.writeln(format!("use crate::idl::{}::*;", self.module_name)); w.writeln("pub struct TestHarness;"); - w.writeln("pub fn ctx() -> TestHarness { TestHarness }"); w.writeln(format!("impl {} for TestHarness {{", self.module_type_name,)) .indent(); for func in self.func_predicates.iter() { func.render_callee(&mut w) } w.eob().writeln("}"); + w.writeln(format!( + "pub fn ctx() -> Box {{ Box::new(TestHarness) }}", + self.module_type_name + )); } } diff --git a/lucet-idl/src/rust/cursor.rs b/lucet-idl/src/rust/cursor.rs index 833091b06..a1ab95300 100644 --- a/lucet-idl/src/rust/cursor.rs +++ b/lucet-idl/src/rust/cursor.rs @@ -129,6 +129,22 @@ pub struct RustIdiomArg<'a> { } impl<'a> RustIdiomArg<'a> { + pub fn name(&self) -> String { + self.binding.rust_name() + } + pub fn direction(&self) -> BindingDirection { + self.binding.direction() + } + pub fn type_(&self) -> Datatype<'a> { + self.binding.type_() + } + pub fn type_name(&self) -> String { + self.type_().rust_type_name() + } + pub fn param(&self) -> BindingParam<'a> { + self.binding.param() + } + fn mutable(&self) -> String { if self.binding.direction() == BindingDirection::InOut { "mut " @@ -280,13 +296,6 @@ impl<'a> RustIdiomArg<'a> { } } } - pub fn name(&self) -> String { - self.binding.rust_name() - } - - pub fn type_name(&self) -> String { - self.binding.type_().rust_type_name() - } } pub struct RustIdiomRet<'a> { @@ -294,6 +303,22 @@ pub struct RustIdiomRet<'a> { } impl<'a> RustIdiomRet<'a> { + pub fn name(&self) -> String { + self.binding.rust_name() + } + pub fn direction(&self) -> BindingDirection { + self.binding.direction() + } + pub fn type_(&self) -> Datatype<'a> { + self.binding.type_() + } + pub fn type_name(&self) -> String { + self.type_().rust_type_name() + } + pub fn param(&self) -> BindingParam<'a> { + self.binding.param() + } + pub fn ret_declaration(&self) -> String { match self.binding.param() { BindingParam::Ptr { .. } | BindingParam::Value { .. } => self.type_name(), @@ -388,14 +413,6 @@ impl<'a> RustIdiomRet<'a> { BindingParam::Slice { .. } => unreachable!(), } } - - pub fn name(&self) -> String { - self.binding.rust_name() - } - - pub fn type_name(&self) -> String { - self.binding.type_().rust_type_name() - } } fn cast_value_to_binding(b: &FuncBinding) -> String { From 6877d4b25f0ebfabcb7238932fac10e2ae5578cd Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 21 Aug 2019 08:36:19 -0700 Subject: [PATCH 340/512] lucet-idl: get rid of `io` binding syntax, just support `inout` --- lucet-idl/src/parser.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index 5eb443682..14896da1a 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -386,7 +386,7 @@ impl<'a> Parser<'a> { self.consume(); Ok(BindingDirSyntax::In) } - Some(Token::Word("inout")) | Some(Token::Word("io")) => { + Some(Token::Word("inout")) => { self.consume(); Ok(BindingDirSyntax::InOut) } @@ -394,10 +394,7 @@ impl<'a> Parser<'a> { self.consume(); Ok(BindingDirSyntax::Out) } - _ => parse_err!( - self.location, - "expected binding direction (in, out, inout, io)" - ), + _ => parse_err!(self.location, "expected binding direction (in, out, inout)"), } } From 09d5f24a7be0dd5085cc11246ee467a883d834f3 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 21 Aug 2019 08:36:38 -0700 Subject: [PATCH 341/512] lucet-idl: only derive Eq and Ord on structs that do not contain floats --- lucet-idl/src/cursor.rs | 12 ++++++++++++ lucet-idl/src/rust.rs | 7 ++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lucet-idl/src/cursor.rs b/lucet-idl/src/cursor.rs index e546ae5c5..650ab59f4 100644 --- a/lucet-idl/src/cursor.rs +++ b/lucet-idl/src/cursor.rs @@ -194,6 +194,18 @@ impl<'a> Datatype<'a> { _ => self.clone(), } } + + pub fn contains_floats(&self) -> bool { + match self.variant() { + DatatypeVariant::Struct(s) => { + s.members().find(|m| m.type_().contains_floats()).is_some() + } + DatatypeVariant::Alias { .. } => self.anti_alias().contains_floats(), + DatatypeVariant::Enum { .. } => false, + DatatypeVariant::Atom(AtomType::F32) | DatatypeVariant::Atom(AtomType::F64) => true, + DatatypeVariant::Atom(_) => false, + } + } } impl<'a> MemArea for Datatype<'a> { diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index dfd8317e5..c2b26f480 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -110,9 +110,14 @@ impl RustGenerator { } fn gen_struct(&mut self, struct_: &StructDatatype) -> Result<(), IDLError> { + let mut derivations = vec!["Debug", "Clone", "PartialEq", "PartialOrd"]; + if !struct_.contains_floats() { + derivations.push("Eq"); + derivations.push("Ord"); + } self.w .writeln("#[repr(C)]") - .writeln("#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]") + .writeln(format!("#[derive({})]", derivations.join(", "))) .writeln(format!("pub struct {} {{", struct_.rust_type_name())); let mut w = self.w.new_block(); From ca665b702e18ef19d88b46cce1e09bb976fe6bc7 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 21 Aug 2019 08:48:03 -0700 Subject: [PATCH 342/512] lucet-idl: simplification in parser for func return value / whereclauses --- lucet-idl/src/parser.rs | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index 14896da1a..e3a8e6e36 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -496,17 +496,11 @@ impl<'a> Parser<'a> { err_ctx!(err_msg, self.match_token(Token::LPar, "expected ("))?; let args = err_ctx!(err_msg, self.match_func_args())?; - - let rets = match self.token() { - Some(Token::RArrow) => { - self.consume(); - err_ctx!(err_msg, self.match_func_rets())? - } - Some(Token::Semi) | Some(Token::Word("where")) => Vec::new(), - t => err_ctx!( - err_msg, - parse_err!(self.location, "expected where, -> or ;, got {:?}", t) - )?, + let rets = if let Some(Token::RArrow) = self.token() { + self.consume(); + err_ctx!(err_msg, self.match_func_rets())? + } else { + Vec::new() }; let bindings = match self.token() { @@ -518,10 +512,10 @@ impl<'a> Parser<'a> { self.consume(); err_ctx!(err_msg, self.match_binding_exprs())? } - x => unreachable!( - "match func rets didnt leave us with semi or where: {:?}", - x - ), + t => err_ctx!( + err_msg, + parse_err!(self.location, "expected where, -> or ;, got {:?}", t) + )?, }; return Ok(Some(SyntaxDecl::Function { From 07468d2a5025616bd4890e30abef7dbf235b605d Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 21 Aug 2019 08:49:50 -0700 Subject: [PATCH 343/512] lucet-idl: explain c backend unreachable --- lucet-idl/src/c.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lucet-idl/src/c.rs b/lucet-idl/src/c.rs index 419c5f0fc..be9bbf5ef 100644 --- a/lucet-idl/src/c.rs +++ b/lucet-idl/src/c.rs @@ -33,7 +33,9 @@ impl CGenerator { DatatypeVariant::Struct(s) => self.gen_struct(&s)?, DatatypeVariant::Alias(a) => self.gen_alias(&a)?, DatatypeVariant::Enum(e) => self.gen_enum(&e)?, - DatatypeVariant::Atom(_) => unreachable!(), + DatatypeVariant::Atom(_) => { + unreachable!("atoms should not be defined in package modules") + } } } for func in module.functions() { From 47d9fc9a0fef0c1574c6dfa4d2a62db71843423f Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 21 Aug 2019 09:02:11 -0700 Subject: [PATCH 344/512] lucet-idl: make all of the cursor structs Copy and eliminate a ton of clones as a result --- lucet-idl/src/cursor.rs | 85 ++++++++++++++++++++--------------------- lucet-idl/src/repr.rs | 2 +- 2 files changed, 42 insertions(+), 45 deletions(-) diff --git a/lucet-idl/src/cursor.rs b/lucet-idl/src/cursor.rs index 650ab59f4..910e87ab8 100644 --- a/lucet-idl/src/cursor.rs +++ b/lucet-idl/src/cursor.rs @@ -129,7 +129,7 @@ impl<'a> Module<'a> { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub struct Datatype<'a> { pkg: &'a Package, id: DatatypeIdent, @@ -166,15 +166,15 @@ impl<'a> Datatype<'a> { match self.repr().variant { DatatypeVariantRepr::Atom(a) => DatatypeVariant::Atom(a), DatatypeVariantRepr::Struct(ref repr) => DatatypeVariant::Struct(StructDatatype { - datatype: self.clone(), + datatype: *self, repr: &repr, }), DatatypeVariantRepr::Enum(ref repr) => DatatypeVariant::Enum(EnumDatatype { - datatype: self.clone(), + datatype: *self, repr: &repr, }), DatatypeVariantRepr::Alias(ref repr) => DatatypeVariant::Alias(AliasDatatype { - datatype: self.clone(), + datatype: *self, repr: &repr, }), } @@ -187,11 +187,11 @@ impl<'a> Datatype<'a> { pub fn anti_alias(&self) -> Datatype<'a> { match self.repr().variant { DatatypeVariantRepr::Alias(ref repr) => AliasDatatype { - datatype: self.clone(), + datatype: *self, repr: &repr, } .anti_alias(), - _ => self.clone(), + _ => *self, } } @@ -261,7 +261,7 @@ impl<'a> DatatypeVariant<'a> { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub struct StructDatatype<'a> { datatype: Datatype<'a>, repr: &'a StructDatatypeRepr, @@ -273,11 +273,11 @@ impl<'a> StructDatatype<'a> { } pub fn members(&self) -> impl Iterator> { - let struct_ = self.clone(); - self.repr.members.iter().map(move |repr| StructMember { - struct_: struct_.clone(), - repr, - }) + let struct_ = *self; + self.repr + .members + .iter() + .map(move |repr| StructMember { struct_, repr }) } } @@ -290,11 +290,11 @@ impl<'a> Deref for StructDatatype<'a> { impl<'a> From> for Datatype<'a> { fn from(s: StructDatatype<'a>) -> Datatype<'a> { - s.datatype.clone() + s.datatype } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub struct StructMember<'a> { struct_: StructDatatype<'a>, repr: &'a StructMemberRepr, @@ -314,11 +314,11 @@ impl<'a> StructMember<'a> { } } pub fn struct_(&self) -> StructDatatype<'a> { - self.struct_.clone() + self.struct_ } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub struct EnumDatatype<'a> { datatype: Datatype<'a>, repr: &'a EnumDatatypeRepr, @@ -326,13 +326,10 @@ pub struct EnumDatatype<'a> { impl<'a> EnumDatatype<'a> { pub fn variants(&self) -> impl Iterator> { - let enum_ = self.clone(); + let enum_ = *self; (0..self.repr.members.len()) .into_iter() - .map(move |ix| EnumVariant { - enum_: enum_.clone(), - index: ix, - }) + .map(move |ix| EnumVariant { enum_, index: ix }) } pub fn variant(&self, name: &str) -> Option> { @@ -353,7 +350,7 @@ impl<'a> From> for Datatype<'a> { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub struct EnumVariant<'a> { enum_: EnumDatatype<'a>, index: usize, @@ -361,7 +358,7 @@ pub struct EnumVariant<'a> { impl<'a> EnumVariant<'a> { pub fn enum_(&self) -> EnumDatatype<'a> { - self.enum_.clone() + self.enum_ } pub fn name(&self) -> &str { &self.enum_.repr.members[self.index].name @@ -410,7 +407,7 @@ impl<'a> AliasDatatype<'a> { impl<'a> From> for Datatype<'a> { fn from(a: AliasDatatype<'a>) -> Datatype<'a> { - a.datatype.clone() + a.datatype } } @@ -421,7 +418,7 @@ impl<'a> Deref for AliasDatatype<'a> { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub struct Function<'a> { pkg: &'a Package, id: FuncIdent, @@ -437,7 +434,7 @@ impl<'a> Function<'a> { } pub fn arg(&self, name: &str) -> Option> { - let func = self.clone(); + let func = *self; self.repr() .args .iter() @@ -449,15 +446,15 @@ impl<'a> Function<'a> { } pub fn args(&self) -> impl Iterator> { - let func = self.clone(); + let func = *self; self.repr().args.iter().map(move |(ix, _)| FuncParam { - func: func.clone(), + func, ix: ParamIx::Arg(ix), }) } pub fn ret(&self, name: &str) -> Option> { - let func = self.clone(); + let func = *self; self.repr() .rets .iter() @@ -469,9 +466,9 @@ impl<'a> Function<'a> { } pub fn rets(&self) -> impl Iterator> { - let func = self.clone(); + let func = *self; self.repr().rets.iter().map(move |(ix, _)| FuncParam { - func: func.clone(), + func, ix: ParamIx::Ret(ix), }) } @@ -485,7 +482,7 @@ impl<'a> Function<'a> { } pub fn binding(&self, name: &str) -> Option> { - let func = self.clone(); + let func = *self; self.repr() .bindings .iter() @@ -494,11 +491,11 @@ impl<'a> Function<'a> { } pub fn bindings(&self) -> impl Iterator> { - let func = self.clone(); - self.repr().bindings.iter().map(move |(ix, _)| FuncBinding { - func: func.clone(), - ix, - }) + let func = *self; + self.repr() + .bindings + .iter() + .map(move |(ix, _)| FuncBinding { func, ix }) } pub fn module(&self) -> Module<'a> { @@ -524,7 +521,7 @@ pub enum ParamPosition { Ret(usize), } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub struct FuncParam<'a> { func: Function<'a>, ix: ParamIx, @@ -556,7 +553,7 @@ impl<'a> FuncParam<'a> { } } pub fn binding(&self) -> FuncBinding<'a> { - let func = self.func.clone(); + let func = self.func; self.func .repr() .bindings @@ -595,28 +592,28 @@ impl<'a> FuncBinding<'a> { pub fn param(&self) -> BindingParam<'a> { match self.repr().from { BindingFromRepr::Ptr(ix) => BindingParam::Ptr(FuncParam { - func: self.func.clone(), + func: self.func, ix, }), BindingFromRepr::Slice(ptr_ix, len_ix) => BindingParam::Slice( FuncParam { - func: self.func.clone(), + func: self.func, ix: ptr_ix, }, FuncParam { - func: self.func.clone(), + func: self.func, ix: len_ix, }, ), BindingFromRepr::Value(ix) => BindingParam::Value(FuncParam { - func: self.func.clone(), + func: self.func, ix, }), } } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub enum BindingParam<'a> { Ptr(FuncParam<'a>), Slice(FuncParam<'a>, FuncParam<'a>), diff --git a/lucet-idl/src/repr.rs b/lucet-idl/src/repr.rs index d85c0bee4..d935400cb 100644 --- a/lucet-idl/src/repr.rs +++ b/lucet-idl/src/repr.rs @@ -31,7 +31,7 @@ impl DatatypeIdent { pub struct FuncIx(u32); entity_impl!(FuncIx); -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct FuncIdent { pub module: ModuleIx, pub func: FuncIx, From 0c9d2a20714c0d645ca67f24c5f070ccf1b4b1e7 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 21 Aug 2019 09:04:08 -0700 Subject: [PATCH 345/512] lucet-idl: use a while let --- lucet-idl/src/cursor.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/lucet-idl/src/cursor.rs b/lucet-idl/src/cursor.rs index 910e87ab8..0ec1f908a 100644 --- a/lucet-idl/src/cursor.rs +++ b/lucet-idl/src/cursor.rs @@ -390,13 +390,8 @@ impl<'a> AliasDatatype<'a> { pkg: self.datatype.pkg, id: self.repr.to, }; - loop { - match referent.variant() { - DatatypeVariant::Alias(a) => { - referent.id = a.datatype.id; - } - _ => break, - } + while let DatatypeVariant::Alias(a) = referent.variant() { + referent.id = a.datatype.id; } Datatype { pkg: self.datatype.pkg, From 058c629567f74c00c379a84ce8337c928a3f7c44 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 21 Aug 2019 09:08:20 -0700 Subject: [PATCH 346/512] lucet-idl: host func name is a rust-specific thing --- lucet-idl/src/cursor.rs | 9 --------- lucet-idl/src/rust/cursor.rs | 9 +++++++++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lucet-idl/src/cursor.rs b/lucet-idl/src/cursor.rs index 0ec1f908a..28a1e840e 100644 --- a/lucet-idl/src/cursor.rs +++ b/lucet-idl/src/cursor.rs @@ -499,15 +499,6 @@ impl<'a> Function<'a> { ix: self.id.module, } } - - pub fn host_func_name(&self) -> String { - use heck::SnakeCase; - format!( - "__{}_{}", - self.module().name().to_snake_case(), - self.name().to_snake_case() - ) - } } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] diff --git a/lucet-idl/src/rust/cursor.rs b/lucet-idl/src/rust/cursor.rs index a1ab95300..acfaf0786 100644 --- a/lucet-idl/src/rust/cursor.rs +++ b/lucet-idl/src/rust/cursor.rs @@ -102,6 +102,7 @@ pub fn render_tuple(members: &[String], base_case: &str) -> String { pub trait RustFunc<'a> { fn rust_idiom_args(&self) -> Vec>; fn rust_idiom_rets(&self) -> Vec>; + fn host_func_name(&self) -> String; } impl<'a> RustFunc<'a> for Function<'a> { @@ -122,6 +123,14 @@ impl<'a> RustFunc<'a> for Function<'a> { .map(|binding| RustIdiomRet { binding }) .collect() } + + fn host_func_name(&self) -> String { + format!( + "__{}_{}", + self.module().name().to_snake_case(), + self.name().to_snake_case() + ) + } } pub struct RustIdiomArg<'a> { From ecd767c84ea3f669e233d0b260cd3398476d58ce Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 21 Aug 2019 09:29:43 -0700 Subject: [PATCH 347/512] lucet-idl: validationerror derives Fail --- lucet-idl/src/error.rs | 83 ++++++------------------------------------ 1 file changed, 11 insertions(+), 72 deletions(-) diff --git a/lucet-idl/src/error.rs b/lucet-idl/src/error.rs index 82bd91643..d6ddbcb21 100644 --- a/lucet-idl/src/error.rs +++ b/lucet-idl/src/error.rs @@ -1,7 +1,5 @@ use crate::parser; use crate::Location; -use std::error::Error; -use std::fmt; use std::io; #[derive(Debug, Fail)] @@ -36,102 +34,43 @@ impl From for IDLError { } } -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, Fail)] pub enum ValidationError { + #[fail(display = "Redefinition of name `{}`", name)] NameAlreadyExists { name: String, at_location: Location, previous_location: Location, }, + #[fail(display = "Use of unknown name `{}`", name)] NameNotFound { name: String, use_location: Location, }, - Empty { - name: String, - location: Location, - }, - Infinite { - name: String, - location: Location, - }, + #[fail(display = "Empty definition for `{}`", name)] + Empty { name: String, location: Location }, + #[fail(display = "Infinite definition for `{}`", name)] + Infinite { name: String, location: Location }, + #[fail(display = "Syntax error: expected {}", expected)] Syntax { expected: &'static str, location: Location, }, + #[fail(display = "Name `{}` bound to another sort", name)] NameSortError { name: String, use_location: Location, bound_location: Location, }, + #[fail(display = "Name `{}` already bound", name)] BindingNameAlreadyBound { name: String, at_location: Location, bound_location: Location, }, + #[fail(display = "Binding type error: expected {}", expected)] BindingTypeError { expected: &'static str, location: Location, }, } - -impl fmt::Display for ValidationError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ValidationError::NameAlreadyExists { - name, - at_location, - previous_location, - } => write!( - f, - "Redefinition of name {} at line {} - previous definition was at line {}", - name, at_location.line, previous_location.line - ), - ValidationError::NameNotFound { name, use_location } => { - write!(f, "Name {} not found at line {}", name, use_location.line) - } - ValidationError::Empty { name, location } => { - write!(f, "Empty definition for {} at line {}", name, location.line) - } - ValidationError::Infinite { name, location } => write!( - f, - "Circular reference for {} at line {}", - name, location.line - ), - ValidationError::Syntax { expected, location } => write!( - f, - "Invalid syntax: expected {} at line {}", - expected, location.line - ), - ValidationError::NameSortError { - name, - use_location, - bound_location, - } => write!( - f, - "Name {} at line {} - bound to another sort at line {}", - name, use_location.line, bound_location.line - ), - ValidationError::BindingNameAlreadyBound { - name, - at_location, - bound_location, - } => write!( - f, - "Argument {} used in binding at line {} - previously bound at line {}", - name, at_location.line, bound_location.line - ), - ValidationError::BindingTypeError { expected, location } => write!( - f, - "type error: expected {} - in binding at line {}", - expected, location.line, - ), - } - } -} - -impl Error for ValidationError { - fn description(&self) -> &str { - "Validation error" - } -} From 7cdd10da6fc4a23b8b36afa21a799bf048b819ae Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 21 Aug 2019 09:37:46 -0700 Subject: [PATCH 348/512] lucet-idl: prelude tests use PackageBuilder which makes the thing being tested less obvious, but the invariant does have to hold across these two modules. not a great design tbh --- lucet-idl/src/prelude.rs | 55 ++++++++++++++++------------------- lucet-idl/src/validate/mod.rs | 2 +- 2 files changed, 26 insertions(+), 31 deletions(-) diff --git a/lucet-idl/src/prelude.rs b/lucet-idl/src/prelude.rs index 45925d074..831b4e8d5 100644 --- a/lucet-idl/src/prelude.rs +++ b/lucet-idl/src/prelude.rs @@ -72,36 +72,31 @@ impl AtomType { #[cfg(test)] mod test { - use super::std_module; use crate::atoms::AtomType; use crate::repr::{DatatypeIdent, Package}; - use cranelift_entity::PrimaryMap; + use crate::validate::PackageBuilder; #[test] fn atom_idents() { use AtomType::*; - - let mut names = PrimaryMap::new(); - names.push("std".to_owned()); - let mut modules = PrimaryMap::new(); - modules.push(std_module()); - let prelude = Package { names, modules }; + let builder = PackageBuilder::new(); // Uses `super::std_module` + let prelude = builder.repr(); fn lookup_atom_by_id(package: &Package, ident: DatatypeIdent) -> AtomType { let dt = package.datatype_by_id(ident).expect("get by id"); dt.variant().atom().expect("datatype is atom") } - assert_eq!(Bool, lookup_atom_by_id(&prelude, Bool.datatype_id())); - assert_eq!(U8, lookup_atom_by_id(&prelude, U8.datatype_id())); - assert_eq!(U16, lookup_atom_by_id(&prelude, U16.datatype_id())); - assert_eq!(U32, lookup_atom_by_id(&prelude, U32.datatype_id())); - assert_eq!(U64, lookup_atom_by_id(&prelude, U64.datatype_id())); - assert_eq!(I8, lookup_atom_by_id(&prelude, I8.datatype_id())); - assert_eq!(I16, lookup_atom_by_id(&prelude, I16.datatype_id())); - assert_eq!(I32, lookup_atom_by_id(&prelude, I32.datatype_id())); - assert_eq!(I64, lookup_atom_by_id(&prelude, I64.datatype_id())); - assert_eq!(F32, lookup_atom_by_id(&prelude, F32.datatype_id())); - assert_eq!(F64, lookup_atom_by_id(&prelude, F64.datatype_id())); + assert_eq!(Bool, lookup_atom_by_id(prelude, Bool.datatype_id())); + assert_eq!(U8, lookup_atom_by_id(prelude, U8.datatype_id())); + assert_eq!(U16, lookup_atom_by_id(prelude, U16.datatype_id())); + assert_eq!(U32, lookup_atom_by_id(prelude, U32.datatype_id())); + assert_eq!(U64, lookup_atom_by_id(prelude, U64.datatype_id())); + assert_eq!(I8, lookup_atom_by_id(prelude, I8.datatype_id())); + assert_eq!(I16, lookup_atom_by_id(prelude, I16.datatype_id())); + assert_eq!(I32, lookup_atom_by_id(prelude, I32.datatype_id())); + assert_eq!(I64, lookup_atom_by_id(prelude, I64.datatype_id())); + assert_eq!(F32, lookup_atom_by_id(prelude, F32.datatype_id())); + assert_eq!(F64, lookup_atom_by_id(prelude, F64.datatype_id())); fn lookup_atom_by_name(package: &Package, name: &str) -> AtomType { let dt = package @@ -112,16 +107,16 @@ mod test { dt.variant().atom().expect("datatype is atom") } - assert_eq!(Bool, lookup_atom_by_name(&prelude, "bool")); - assert_eq!(U8, lookup_atom_by_name(&prelude, "u8")); - assert_eq!(U16, lookup_atom_by_name(&prelude, "u16")); - assert_eq!(U32, lookup_atom_by_name(&prelude, "u32")); - assert_eq!(U64, lookup_atom_by_name(&prelude, "u64")); - assert_eq!(I8, lookup_atom_by_name(&prelude, "i8")); - assert_eq!(I16, lookup_atom_by_name(&prelude, "i16")); - assert_eq!(I32, lookup_atom_by_name(&prelude, "i32")); - assert_eq!(I64, lookup_atom_by_name(&prelude, "i64")); - assert_eq!(F32, lookup_atom_by_name(&prelude, "f32")); - assert_eq!(F64, lookup_atom_by_name(&prelude, "f64")); + assert_eq!(Bool, lookup_atom_by_name(prelude, "bool")); + assert_eq!(U8, lookup_atom_by_name(prelude, "u8")); + assert_eq!(U16, lookup_atom_by_name(prelude, "u16")); + assert_eq!(U32, lookup_atom_by_name(prelude, "u32")); + assert_eq!(U64, lookup_atom_by_name(prelude, "u64")); + assert_eq!(I8, lookup_atom_by_name(prelude, "i8")); + assert_eq!(I16, lookup_atom_by_name(prelude, "i16")); + assert_eq!(I32, lookup_atom_by_name(prelude, "i32")); + assert_eq!(I64, lookup_atom_by_name(prelude, "i64")); + assert_eq!(F32, lookup_atom_by_name(prelude, "f32")); + assert_eq!(F64, lookup_atom_by_name(prelude, "f64")); } } diff --git a/lucet-idl/src/validate/mod.rs b/lucet-idl/src/validate/mod.rs index c2762dd1b..d71f26dd6 100644 --- a/lucet-idl/src/validate/mod.rs +++ b/lucet-idl/src/validate/mod.rs @@ -4,4 +4,4 @@ mod module; mod names; mod package; -pub use package::package_from_declarations; +pub use package::{package_from_declarations, PackageBuilder}; From a3b3b807b6b040b1cf769f4bf926fd82f2c8140f Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 21 Aug 2019 10:45:22 -0700 Subject: [PATCH 349/512] lucet-idl: derive default unless contains enum --- lucet-idl/src/cursor.rs | 12 +++++++++++- lucet-idl/src/rust.rs | 10 +++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/lucet-idl/src/cursor.rs b/lucet-idl/src/cursor.rs index 28a1e840e..d61db3532 100644 --- a/lucet-idl/src/cursor.rs +++ b/lucet-idl/src/cursor.rs @@ -200,12 +200,22 @@ impl<'a> Datatype<'a> { DatatypeVariant::Struct(s) => { s.members().find(|m| m.type_().contains_floats()).is_some() } - DatatypeVariant::Alias { .. } => self.anti_alias().contains_floats(), + DatatypeVariant::Alias(a) => a.contains_floats(), DatatypeVariant::Enum { .. } => false, DatatypeVariant::Atom(AtomType::F32) | DatatypeVariant::Atom(AtomType::F64) => true, DatatypeVariant::Atom(_) => false, } } + pub fn contains_enums(&self) -> bool { + match self.variant() { + DatatypeVariant::Struct(s) => { + s.members().find(|m| m.type_().contains_enums()).is_some() + } + DatatypeVariant::Alias(a) => a.contains_enums(), + DatatypeVariant::Enum { .. } => true, + DatatypeVariant::Atom { .. } => false, + } + } } impl<'a> MemArea for Datatype<'a> { diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index c2b26f480..bc8f04f4f 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -110,10 +110,14 @@ impl RustGenerator { } fn gen_struct(&mut self, struct_: &StructDatatype) -> Result<(), IDLError> { - let mut derivations = vec!["Debug", "Clone", "PartialEq", "PartialOrd"]; + let mut derivations = vec!["Debug", "Copy", "Clone", "PartialEq", "PartialOrd"]; if !struct_.contains_floats() { derivations.push("Eq"); derivations.push("Ord"); + derivations.push("Hash"); + } + if !struct_.contains_enums() { + derivations.push("Default"); } self.w .writeln("#[repr(C)]") @@ -180,8 +184,8 @@ impl RustGenerator { // The typedef is required to use a native type which is consistent across all architectures fn gen_enum(&mut self, enum_: &EnumDatatype) -> Result<(), IDLError> { self.w - .writeln("#[repr(C)]") - .writeln("#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]") + .writeln("#[repr(u32)]") + .writeln("#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]") .writeln(format!("pub enum {} {{", enum_.rust_type_name())); let mut w = self.w.new_block(); From 29470ef88bd930d8d46f15946ff94e4ab8cd8686 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 21 Aug 2019 11:36:22 -0700 Subject: [PATCH 350/512] lucet-idl: use MaybeUninit instead of null for struct member offset assertions --- lucet-idl/src/rust.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index bc8f04f4f..374bd5de3 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -170,10 +170,21 @@ impl RustGenerator { )); for m in struct_.members() { - w.writeln(format!( - "assert_eq!({}, {{ let base = ::std::ptr::null::(); unsafe {{ (&(*base).{}) as *const _ as usize }} }});", - m.offset(), struct_.rust_type_name(), m.rust_name(), - )); + w.writeln("{"); + let mut ww = w.new_block(); + // This is essentially an inlining of the macros in the memoffset crate. + ww.writeln(format!( + "let base_uninit = ::std::mem::MaybeUninit::::uninit();", + struct_.rust_type_name(), + )) + .writeln("let base_ptr = base_uninit.as_ptr();") + .writeln(format!( + "let field_ptr = unsafe {{ &(*base_ptr).{} as *const _ }};", + m.rust_name(), + )) + .writeln("let offset = (field_ptr as usize) - (base_ptr as usize);") + .writeln(format!("assert_eq!({}, offset);", m.offset())); + w.writeln("}"); } Ok(()) })?; From 8fa1a7cd247695e798bbf37b9eb9c96fd77d0736 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 21 Aug 2019 13:40:03 -0700 Subject: [PATCH 351/512] lucet-idl: get rid of Deref impls of Datatype rust should have a non-deref way to delegate method calls to a member --- lucet-idl/src/c.rs | 14 ++--- lucet-idl/src/cursor.rs | 30 +++------ lucet-idl/src/rust.rs | 101 +++++++++++++++++-------------- lucet-idl/src/validate/module.rs | 2 +- 4 files changed, 74 insertions(+), 73 deletions(-) diff --git a/lucet-idl/src/c.rs b/lucet-idl/src/c.rs index be9bbf5ef..07ba7d78d 100644 --- a/lucet-idl/src/c.rs +++ b/lucet-idl/src/c.rs @@ -57,7 +57,7 @@ impl CGenerator { // The most important thing in alias generation is to cache the size // and alignment rules of what it ultimately points to fn gen_alias(&mut self, alias: &AliasDatatype) -> Result<(), IDLError> { - let own_type_name = Datatype::from(alias.clone()).c_type_name(); + let own_type_name = alias.datatype().c_type_name(); self.w .writeln(format!( "typedef {} {};", @@ -71,7 +71,7 @@ impl CGenerator { .writeln(format!( "_Static_assert(sizeof({}) == {}, \"unexpected alias size\");", own_type_name, - alias.mem_size(), + alias.datatype().mem_size(), )) .eob(); @@ -79,7 +79,7 @@ impl CGenerator { } fn gen_struct(&mut self, struct_: &StructDatatype) -> Result<(), IDLError> { - let own_type_name = Datatype::from(struct_.clone()).c_type_name(); + let own_type_name = struct_.datatype().c_type_name(); self.w.writeln(format!("{} {{", own_type_name)); let mut w_block = self.w.new_block(); for member in struct_.members() { @@ -105,7 +105,7 @@ impl CGenerator { .writeln(format!( "_Static_assert(sizeof({}) == {}, \"unexpected structure size\");", own_type_name, - struct_.mem_size(), + struct_.datatype().mem_size(), )) .eob(); Ok(()) @@ -114,13 +114,13 @@ impl CGenerator { // Enums generate both a specific typedef, and a traditional C-style enum // The typedef is required to use a native type which is consistent across all architectures fn gen_enum(&mut self, enum_: &EnumDatatype) -> Result<(), IDLError> { - let own_type_name = Datatype::from(enum_.clone()).c_type_name(); + let own_type_name = enum_.datatype().c_type_name(); self.w.writeln(format!("{} {{", own_type_name)); let mut w = self.w.new_block(); for variant in enum_.variants() { w.writeln(format!( "{}, // {}", - macro_for(enum_.name(), variant.name()), + macro_for(enum_.datatype().name(), variant.name()), variant.index(), )); } @@ -129,7 +129,7 @@ impl CGenerator { .writeln(format!( "_Static_assert(sizeof({}) == {}, \"unexpected enumeration size\");", own_type_name, - enum_.mem_size(), + enum_.datatype().mem_size(), )) .eob(); Ok(()) diff --git a/lucet-idl/src/cursor.rs b/lucet-idl/src/cursor.rs index d61db3532..44b9fe204 100644 --- a/lucet-idl/src/cursor.rs +++ b/lucet-idl/src/cursor.rs @@ -7,7 +7,6 @@ use crate::repr::{ pub use crate::repr::{BindingDirection, Package}; use crate::MemArea; use std::convert::TryFrom; -use std::ops::Deref; impl Package { pub fn module<'a>(&'a self, name: &str) -> Option> { @@ -200,7 +199,7 @@ impl<'a> Datatype<'a> { DatatypeVariant::Struct(s) => { s.members().find(|m| m.type_().contains_floats()).is_some() } - DatatypeVariant::Alias(a) => a.contains_floats(), + DatatypeVariant::Alias(a) => a.to().contains_floats(), DatatypeVariant::Enum { .. } => false, DatatypeVariant::Atom(AtomType::F32) | DatatypeVariant::Atom(AtomType::F64) => true, DatatypeVariant::Atom(_) => false, @@ -211,7 +210,7 @@ impl<'a> Datatype<'a> { DatatypeVariant::Struct(s) => { s.members().find(|m| m.type_().contains_enums()).is_some() } - DatatypeVariant::Alias(a) => a.contains_enums(), + DatatypeVariant::Alias(a) => a.to().contains_enums(), DatatypeVariant::Enum { .. } => true, DatatypeVariant::Atom { .. } => false, } @@ -289,12 +288,9 @@ impl<'a> StructDatatype<'a> { .iter() .map(move |repr| StructMember { struct_, repr }) } -} -impl<'a> Deref for StructDatatype<'a> { - type Target = Datatype<'a>; - fn deref(&self) -> &Self::Target { - &self.datatype + pub fn datatype(&self) -> Datatype<'a> { + self.datatype } } @@ -345,12 +341,9 @@ impl<'a> EnumDatatype<'a> { pub fn variant(&self, name: &str) -> Option> { self.variants().find(|v| v.name() == name) } -} -impl<'a> Deref for EnumDatatype<'a> { - type Target = Datatype<'a>; - fn deref(&self) -> &Self::Target { - &self.datatype + pub fn datatype(&self) -> Datatype<'a> { + self.datatype } } @@ -408,6 +401,10 @@ impl<'a> AliasDatatype<'a> { id: referent.id, } } + + pub fn datatype(&self) -> Datatype<'a> { + self.datatype + } } impl<'a> From> for Datatype<'a> { @@ -416,13 +413,6 @@ impl<'a> From> for Datatype<'a> { } } -impl<'a> Deref for AliasDatatype<'a> { - type Target = Datatype<'a>; - fn deref(&self) -> &Self::Target { - &self.datatype - } -} - #[derive(Debug, Clone, Copy)] pub struct Function<'a> { pkg: &'a Package, diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index 374bd5de3..709e5041e 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -94,35 +94,42 @@ impl RustGenerator { fn gen_alias(&mut self, alias: &AliasDatatype) -> Result<(), IDLError> { self.w.writeln(format!( "pub type {} = {};", - alias.rust_type_name(), + alias.datatype().rust_type_name(), alias.to().rust_type_name() )); - gen_testcase(&mut self.w, &alias.name().to_snake_case(), move |w| { - w.writeln(format!( - "assert_eq!({}, ::std::mem::size_of::());", - alias.mem_size(), - alias.rust_type_name() - )); - Ok(()) - })?; + gen_testcase( + &mut self.w, + &alias.datatype().name().to_snake_case(), + move |w| { + w.writeln(format!( + "assert_eq!({}, ::std::mem::size_of::());", + alias.datatype().mem_size(), + alias.datatype().rust_type_name() + )); + Ok(()) + }, + )?; Ok(()) } fn gen_struct(&mut self, struct_: &StructDatatype) -> Result<(), IDLError> { let mut derivations = vec!["Debug", "Copy", "Clone", "PartialEq", "PartialOrd"]; - if !struct_.contains_floats() { + if !struct_.datatype().contains_floats() { derivations.push("Eq"); derivations.push("Ord"); derivations.push("Hash"); } - if !struct_.contains_enums() { + if !struct_.datatype().contains_enums() { derivations.push("Default"); } self.w .writeln("#[repr(C)]") .writeln(format!("#[derive({})]", derivations.join(", "))) - .writeln(format!("pub struct {} {{", struct_.rust_type_name())); + .writeln(format!( + "pub struct {} {{", + struct_.datatype().rust_type_name() + )); let mut w = self.w.new_block(); for m in struct_.members() { @@ -136,7 +143,7 @@ impl RustGenerator { self.w.writeln("}"); self.w - .writeln(format!("impl {} {{", struct_.rust_type_name())); + .writeln(format!("impl {} {{", struct_.datatype().rust_type_name())); let mut w = self.w.new_block(); w.writeln("pub fn validate_bytes(repr: &[u8]) -> bool {"); @@ -162,32 +169,36 @@ impl RustGenerator { self.w.writeln("}"); // end impl - gen_testcase(&mut self.w, &struct_.name().to_snake_case(), |w| { - w.writeln(format!( - "assert_eq!({}, ::std::mem::size_of::());", - struct_.mem_size(), - struct_.rust_type_name(), - )); - - for m in struct_.members() { - w.writeln("{"); - let mut ww = w.new_block(); - // This is essentially an inlining of the macros in the memoffset crate. - ww.writeln(format!( - "let base_uninit = ::std::mem::MaybeUninit::::uninit();", - struct_.rust_type_name(), - )) - .writeln("let base_ptr = base_uninit.as_ptr();") - .writeln(format!( - "let field_ptr = unsafe {{ &(*base_ptr).{} as *const _ }};", - m.rust_name(), - )) - .writeln("let offset = (field_ptr as usize) - (base_ptr as usize);") - .writeln(format!("assert_eq!({}, offset);", m.offset())); - w.writeln("}"); - } - Ok(()) - })?; + gen_testcase( + &mut self.w, + &struct_.datatype().name().to_snake_case(), + |w| { + w.writeln(format!( + "assert_eq!({}, ::std::mem::size_of::());", + struct_.datatype().mem_size(), + struct_.datatype().rust_type_name(), + )); + + for m in struct_.members() { + w.writeln("{"); + let mut ww = w.new_block(); + // This is essentially an inlining of the macros in the memoffset crate. + ww.writeln(format!( + "let base_uninit = ::std::mem::MaybeUninit::::uninit();", + struct_.datatype().rust_type_name(), + )) + .writeln("let base_ptr = base_uninit.as_ptr();") + .writeln(format!( + "let field_ptr = unsafe {{ &(*base_ptr).{} as *const _ }};", + m.rust_name(), + )) + .writeln("let offset = (field_ptr as usize) - (base_ptr as usize);") + .writeln(format!("assert_eq!({}, offset);", m.offset())); + w.writeln("}"); + } + Ok(()) + }, + )?; Ok(()) } @@ -197,7 +208,7 @@ impl RustGenerator { self.w .writeln("#[repr(u32)]") .writeln("#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]") - .writeln(format!("pub enum {} {{", enum_.rust_type_name())); + .writeln(format!("pub enum {} {{", enum_.datatype().rust_type_name())); let mut w = self.w.new_block(); for v in enum_.variants() { @@ -207,7 +218,7 @@ impl RustGenerator { self.w.writeln("}"); self.w - .writeln(format!("impl {} {{", enum_.rust_type_name())); + .writeln(format!("impl {} {{", enum_.datatype().rust_type_name())); let mut w = self.w.new_block(); w.writeln("pub fn from_u32(e: u32) -> Option {"); let mut ww = w.new_block(); @@ -217,7 +228,7 @@ impl RustGenerator { www.writeln(format!( "{} => Some({}::{}),", v.index(), - enum_.rust_type_name(), + enum_.datatype().rust_type_name(), v.rust_name() )); } @@ -235,11 +246,11 @@ impl RustGenerator { w.writeln("}"); self.w.writeln("}"); // end impl - gen_testcase(&mut self.w, &enum_.name().to_snake_case(), |w| { + gen_testcase(&mut self.w, &enum_.datatype().name().to_snake_case(), |w| { w.writeln(format!( "assert_eq!({}, ::std::mem::size_of::());", - enum_.mem_size(), - enum_.rust_type_name(), + enum_.datatype().mem_size(), + enum_.datatype().rust_type_name(), )); Ok(()) })?; diff --git a/lucet-idl/src/validate/module.rs b/lucet-idl/src/validate/module.rs index 232ba8389..6f6dff19b 100644 --- a/lucet-idl/src/validate/module.rs +++ b/lucet-idl/src/validate/module.rs @@ -289,7 +289,7 @@ mod tests { match foo.variant() { DatatypeVariant::Alias(a) => { - assert_eq!(a.name(), "foo"); + assert_eq!(a.datatype().name(), "foo"); assert_eq!(a.to().name(), "bar"); } _ => panic!("foo is an alias"), From a46ada2a321ce7e02bd63b8881c97ec1fc13791f Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 21 Aug 2019 13:56:27 -0700 Subject: [PATCH 352/512] lucet-idl: many code review fixes --- lucet-idl/src/c.rs | 51 ++++++++++++++++++------------------ lucet-idl/src/cursor.rs | 6 ++--- lucet-idl/src/rust.rs | 2 +- lucet-idl/src/rust/cursor.rs | 19 +++++++------- 4 files changed, 38 insertions(+), 40 deletions(-) diff --git a/lucet-idl/src/c.rs b/lucet-idl/src/c.rs index 07ba7d78d..fd0a1abcd 100644 --- a/lucet-idl/src/c.rs +++ b/lucet-idl/src/c.rs @@ -161,14 +161,18 @@ impl CGenerator { } fn gen_idiomatic_function(&mut self, func: &Function) -> Result<(), IDLError> { - let ret_bindings = func.c_ret_bindings().collect::>(); - - let own_return_decl = match ret_bindings.len() { - 0 => "void".to_owned(), - 1 => ret_bindings[0].type_().c_type_name(), + let mut ret_bindings = func.c_ret_bindings().collect::>(); + let ret_bindings = match ret_bindings.len() { + 0 => None, + 1 => Some(ret_bindings.pop().expect("only member")), _ => unreachable!("functions limited to 0 or 1 return arguments"), }; + let own_return_decl = ret_bindings + .clone() + .map(|b| b.type_().c_type_name()) + .unwrap_or("void".to_owned()); + let own_arg_list = func .c_arg_bindings() .map(|b| match b.param() { @@ -213,24 +217,19 @@ impl CGenerator { .collect::>() .join(", "); - let (ret_capture, ret_statement) = match ret_bindings.len() { - 0 => (format!(""), format!("return;")), - 1 => { - let b = &ret_bindings[0]; - match b.param() { - BindingParam::Ptr(p) => ( - format!("{} {} = ", p.type_().c_type_name(), p.name()), - format!("return (*{}) {};", b.type_().c_type_name(), p.name()), - ), - BindingParam::Value(v) => ( - format!("{} {} = ", v.type_().c_type_name(), v.name()), - format!("return ({}) {};", b.type_().c_type_name(), v.name()), - ), - BindingParam::Slice { .. } => unreachable!(), - } - } - _ => unreachable!(), - }; + let (ret_capture, ret_statement) = ret_bindings + .map(|b| match b.param() { + BindingParam::Ptr(p) => ( + format!("{} {} = ", p.type_().c_type_name(), p.name()), + format!("return (*{}) {};", b.type_().c_type_name(), p.name()), + ), + BindingParam::Value(v) => ( + format!("{} {} = ", v.type_().c_type_name(), v.name()), + format!("return ({}) {};", b.type_().c_type_name(), v.name()), + ), + BindingParam::Slice { .. } => unreachable!("return slices are not supported"), + }) + .unwrap_or((format!(""), format!("return;"))); let mut w = self.w.new_block(); w.writeln(format!( @@ -324,13 +323,13 @@ fn binding_is_ret(b: &FuncBinding) -> bool { } impl FuncBinding<'_> { - fn c_constness(&self) -> String { + fn c_constness(&self) -> &'static str { if self.direction() == BindingDirection::In && (self.param().ptr().is_some() || self.param().slice().is_some()) { - "const ".to_owned() + "const " } else { - "".to_owned() + "" } } } diff --git a/lucet-idl/src/cursor.rs b/lucet-idl/src/cursor.rs index 44b9fe204..cbdabeaf1 100644 --- a/lucet-idl/src/cursor.rs +++ b/lucet-idl/src/cursor.rs @@ -183,13 +183,13 @@ impl<'a> Datatype<'a> { self.variant().abi_type() } - pub fn anti_alias(&self) -> Datatype<'a> { + pub fn canonicalize(&self) -> Datatype<'a> { match self.repr().variant { DatatypeVariantRepr::Alias(ref repr) => AliasDatatype { datatype: *self, repr: &repr, } - .anti_alias(), + .canonicalize(), _ => *self, } } @@ -386,7 +386,7 @@ impl<'a> AliasDatatype<'a> { } /// Find the non-alias datatype that this alias transitively refers to. - pub fn anti_alias(&self) -> Datatype<'a> { + pub fn canonicalize(&self) -> Datatype<'a> { // We can't just call this recursively because // of the borrow checker, so we have to recurse in a loop :/ let mut referent = Datatype { diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs index 709e5041e..fecdea303 100644 --- a/lucet-idl/src/rust.rs +++ b/lucet-idl/src/rust.rs @@ -149,7 +149,7 @@ impl RustGenerator { w.writeln("pub fn validate_bytes(repr: &[u8]) -> bool {"); let mut ww = w.new_block(); for m in struct_.members() { - match m.type_().anti_alias().variant() { + match m.type_().canonicalize().variant() { DatatypeVariant::Struct(_) | DatatypeVariant::Enum(_) => { ww.writeln(format!( "{}::validate_bytes(&repr[{}..{}]) &&", diff --git a/lucet-idl/src/rust/cursor.rs b/lucet-idl/src/rust/cursor.rs index acfaf0786..31f05fb66 100644 --- a/lucet-idl/src/rust/cursor.rs +++ b/lucet-idl/src/rust/cursor.rs @@ -154,13 +154,12 @@ impl<'a> RustIdiomArg<'a> { self.binding.param() } - fn mutable(&self) -> String { + fn mutable(&self) -> &'static str { if self.binding.direction() == BindingDirection::InOut { "mut " } else { "" } - .to_owned() } pub fn arg_declaration(&self) -> String { @@ -169,7 +168,7 @@ impl<'a> RustIdiomArg<'a> { format!("{}: &{}{}", self.name(), self.mutable(), self.type_name()) } BindingParam::Slice { .. } => { - format!("{}: &{}[{}]", self.name(), self.mutable(), self.type_name(),) + format!("{}: &{}[{}]", self.name(), self.mutable(), self.type_name()) } BindingParam::Value { .. } => { assert_eq!(self.binding.direction(), BindingDirection::In); @@ -226,7 +225,7 @@ impl<'a> RustIdiomArg<'a> { ptr = ptr.rust_name(), len = self.binding.type_().mem_size(), ), - format!("let {name}: &{typename} = unsafe {{ ({name}___MEM.as_ptr() as *const {typename}).as_ref().unwrap() }}; // convert pointer in linear memory to ref", + format!("let {name}: &{typename} = unsafe {{ ({name}___MEM.as_ptr() as *const {typename}).as_ref().expect(\"determined to be valid ref\") }}; // convert pointer in linear memory to ref", name = self.name(), typename = self.type_name(), ), @@ -248,7 +247,7 @@ impl<'a> RustIdiomArg<'a> { len = len.rust_name(), elem_len =self.binding.type_().mem_size(), ), - format!("let {}: &[{}] = unsafe {{ ::std::slice::from_raw_parts({name}___MEM.as_ptr() as *const {typename}, {len}) }};", + format!("let {name}: &[{typename}] = unsafe {{ ::std::slice::from_raw_parts({name}___MEM.as_ptr() as *const {typename}, {len}) }};", name = self.name(), typename = self.type_name(), len = len.rust_name(), @@ -272,7 +271,7 @@ impl<'a> RustIdiomArg<'a> { ptr = ptr.rust_name(), len = self.binding.type_().mem_size(), ), - format!("let mut {name}: &mut {typename} = unsafe {{ ({name}___MEM.as_mut_ptr() as *mut {typename}).as_mut().unwrap() }}; // convert pointer in linear memory to ref", + format!("let mut {name}: &mut {typename} = unsafe {{ ({name}___MEM.as_mut_ptr() as *mut {typename}).as_mut().expect(\"determined to be valid ref\") }}; // convert pointer in linear memory to ref", name = self.name(), typename = self.type_name(), ), @@ -295,7 +294,7 @@ impl<'a> RustIdiomArg<'a> { elem_len = self.binding.type_().mem_size(), ), - format!("let mut {}: &mut [{}] = unsafe {{ ::std::slice::from_raw_parts_mut({name}___MEM.as_mut_ptr() as *mut {typename}, {len}) }};", + format!("let mut {name}: &mut [{typename}] = unsafe {{ ::std::slice::from_raw_parts_mut({name}___MEM.as_mut_ptr() as *mut {typename}, {len}) }};", name = self.name(), typename = self.type_name(), len = len.rust_name(), @@ -385,7 +384,7 @@ impl<'a> RustIdiomRet<'a> { ptr = ptr.rust_name(), len =self.binding.type_().mem_size(), )]; - match self.binding.type_().anti_alias().variant() { + match self.binding.type_().canonicalize().variant() { DatatypeVariant::Enum(_) | DatatypeVariant::Struct(_) => { lines.push(format!("if !{}::validate_bytes(&{}___MEM) {{ Err(())?; /* FIXME invalid representation */ }}", self.type_name(), self.name())) @@ -394,7 +393,7 @@ impl<'a> RustIdiomRet<'a> { DatatypeVariant::Alias(_) => unreachable!("anti-aliased"), } lines.push(format!( - "let mut {ptr}: &mut {typename} = unsafe {{ ({name}___MEM.as_mut_ptr() as *mut {typename}).as_mut().unwrap() }}; // convert pointer in linear memory to ref", + "let mut {ptr}: &mut {typename} = unsafe {{ ({name}___MEM.as_mut_ptr() as *mut {typename}).as_mut().expect(\"determined to be valid ref\") }}; // convert pointer in linear memory to ref", name = self.name(), typename = self.type_name(), ptr = ptr.rust_name(), @@ -426,7 +425,7 @@ impl<'a> RustIdiomRet<'a> { fn cast_value_to_binding(b: &FuncBinding) -> String { match b.param() { - BindingParam::Value(val) => match b.type_().anti_alias().variant() { + BindingParam::Value(val) => match b.type_().canonicalize().variant() { DatatypeVariant::Enum(_) => format!( "let {} = {}::from_u32({} as u32).ok_or(())?; // FIXME throw the right error", b.rust_name(), From d7e54c668817c12a1535d4e1ce69c2473b91f34f Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 21 Aug 2019 14:03:43 -0700 Subject: [PATCH 353/512] delete empty file --- lucet-idl/src/types.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 lucet-idl/src/types.rs diff --git a/lucet-idl/src/types.rs b/lucet-idl/src/types.rs deleted file mode 100644 index e69de29bb..000000000 From 89852bf9363d8f05058c41795282b93032e9eb84 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 21 Aug 2019 14:10:55 -0700 Subject: [PATCH 354/512] lucet-idl: get rid of tons of unnecessary refs/clones of Location --- lucet-idl/src/validate/datatypes.rs | 18 +++++----- lucet-idl/src/validate/function.rs | 51 ++++++++++++++--------------- lucet-idl/src/validate/module.rs | 8 ++--- 3 files changed, 38 insertions(+), 39 deletions(-) diff --git a/lucet-idl/src/validate/datatypes.rs b/lucet-idl/src/validate/datatypes.rs index c2009d9e6..3da6dc661 100644 --- a/lucet-idl/src/validate/datatypes.rs +++ b/lucet-idl/src/validate/datatypes.rs @@ -65,7 +65,7 @@ impl<'a> DatatypeModuleBuilder<'a> { &mut self, name: &str, members_syntax: &[StructMemberSyntax], - location: &Location, + location: Location, ) -> Result<(), ValidationError> { let ix = self .names @@ -74,7 +74,7 @@ impl<'a> DatatypeModuleBuilder<'a> { if members_syntax.is_empty() { Err(ValidationError::Empty { name: name.to_owned(), - location: *location, + location, })? } @@ -102,7 +102,7 @@ impl<'a> DatatypeModuleBuilder<'a> { ix, DatatypeIR { variant: VariantIR::Struct(StructIR { members }), - location: *location, + location, }, ); Ok(()) @@ -112,7 +112,7 @@ impl<'a> DatatypeModuleBuilder<'a> { &mut self, name: &str, variants: &[EnumVariantSyntax], - location: &Location, + location: Location, ) -> Result<(), ValidationError> { let ix = self .names @@ -121,7 +121,7 @@ impl<'a> DatatypeModuleBuilder<'a> { if variants.is_empty() { Err(ValidationError::Empty { name: name.to_owned(), - location: *location, + location, })? } @@ -145,7 +145,7 @@ impl<'a> DatatypeModuleBuilder<'a> { ix, DatatypeIR { variant: VariantIR::Enum(EnumIR { members }), - location: *location, + location, }, ); Ok(()) @@ -155,7 +155,7 @@ impl<'a> DatatypeModuleBuilder<'a> { &mut self, name: &str, dest: &SyntaxIdent, - location: &Location, + location: Location, ) -> Result<(), ValidationError> { let ix = self .names @@ -166,7 +166,7 @@ impl<'a> DatatypeModuleBuilder<'a> { ix, DatatypeIR { variant: VariantIR::Alias(AliasIR { to }), - location: *location, + location, }, ); Ok(()) @@ -200,7 +200,7 @@ impl<'a> DatatypeModuleBuilder<'a> { self.dfs_walk(ix, &mut visited, &mut ordered, &mut finalized) .map_err(|_| ValidationError::Infinite { name: name.clone(), - location: decl.location.clone(), + location: decl.location, })?; } diff --git a/lucet-idl/src/validate/function.rs b/lucet-idl/src/validate/function.rs index d1ef59553..56a7d188d 100644 --- a/lucet-idl/src/validate/function.rs +++ b/lucet-idl/src/validate/function.rs @@ -31,7 +31,7 @@ impl<'a> FunctionModuleBuilder<'a> { args: &[FuncArgSyntax], rets: &[FuncArgSyntax], bindings: &[BindingSyntax], - location: &Location, + location: Location, ) -> Result<(), ValidationError> { let mut validator = FuncValidator::new(location, &self.env); validator.introduce_args(args)?; @@ -76,12 +76,12 @@ struct FuncValidator<'a> { // param position to binding syntax bindings: PrimaryMap, param_binding_sites: HashMap, - location: &'a Location, + location: Location, module: &'a Module<'a>, } impl<'a> FuncValidator<'a> { - fn new(location: &'a Location, module: &'a Module<'a>) -> Self { + fn new(location: Location, module: &'a Module<'a>) -> Self { Self { param_names: HashMap::new(), args: PrimaryMap::new(), @@ -102,7 +102,7 @@ impl<'a> FuncValidator<'a> { Err(ValidationError::NameAlreadyExists { name: arg_syntax.name.to_owned(), at_location: arg_syntax.location, - previous_location: previous_location.clone(), + previous_location: *previous_location, })?; } else { self.param_names @@ -132,7 +132,7 @@ impl<'a> FuncValidator<'a> { if rets.len() > 1 { Err(ValidationError::Syntax { expected: "at most one return value", - location: *self.location, + location: self.location, })? } for (ix, r) in rets.iter().enumerate() { @@ -181,7 +181,7 @@ impl<'a> FuncValidator<'a> { Err(ValidationError::NameAlreadyExists { name: binding.name.to_owned(), at_location: binding.location, - previous_location: previous_location.clone(), + previous_location: *previous_location, })?; } else { self.binding_names @@ -226,8 +226,8 @@ impl<'a> FuncValidator<'a> { let (arg_location, _) = self.param_names.get(&arg.name).expect("arg introduced"); Err(ValidationError::BindingNameAlreadyBound { name: arg.name.clone(), - at_location: previous_location.clone(), - bound_location: arg_location.clone(), + at_location: *previous_location, + bound_location: *arg_location, })?; } @@ -268,23 +268,22 @@ impl<'a> FuncValidator<'a> { fn validate_binding_arg_mapping( &mut self, name: &str, - location: &Location, + location: Location, ) -> Result<(ParamIx, ParamRepr), ValidationError> { // Check that it refers to a valid arg: let (position, arg) = self.get_arg(name).ok_or_else(|| ValidationError::Syntax { expected: "name of an argument or return value", - location: location.clone(), + location, })?; // Check that the arg has only been used once: if let Some(use_location) = self.param_binding_sites.get(&position) { Err(ValidationError::BindingNameAlreadyBound { name: name.to_owned(), - at_location: location.clone(), - bound_location: use_location.clone(), + at_location: location, + bound_location: *use_location, })?; } else { - self.param_binding_sites - .insert(position.clone(), location.clone()); + self.param_binding_sites.insert(position.clone(), location); } Ok((position, arg)) } @@ -299,11 +298,11 @@ impl<'a> FuncValidator<'a> { BindingRefSyntax::Ptr(bref) => match bref.deref() { BindingRefSyntax::Name(ref name) => { let (position, funcarg) = - self.validate_binding_arg_mapping(name, &binding.location)?; + self.validate_binding_arg_mapping(name, binding.location)?; if funcarg.type_ != AbiType::I32 { Err(ValidationError::BindingTypeError { expected: "pointer bindings to be represented as an i32", - location: binding.location.clone(), + location: binding.location, })?; } match position { @@ -313,7 +312,7 @@ impl<'a> FuncValidator<'a> { ParamIx::Ret(_) => { Err(ValidationError::BindingTypeError { expected: "return value cannot be bound to pointer", - location: binding.location.clone(), + location: binding.location, })?; } } @@ -321,7 +320,7 @@ impl<'a> FuncValidator<'a> { } _ => Err(ValidationError::Syntax { expected: "pointer binding must be of form *arg", - location: binding.location.clone(), + location: binding.location, }), }, // A slice of two names is accepted: @@ -332,7 +331,7 @@ impl<'a> FuncValidator<'a> { BindingRefSyntax::Name(ref len_name), ) => { let (ptr_position, ptr_arg) = - self.validate_binding_arg_mapping(ptr_name, &binding.location)?; + self.validate_binding_arg_mapping(ptr_name, binding.location)?; if ptr_arg.type_ != AbiType::I32 { Err(ValidationError::BindingTypeError { expected: "slice pointer must be i32", @@ -340,7 +339,7 @@ impl<'a> FuncValidator<'a> { })?; } let (len_position, len_arg) = - self.validate_binding_arg_mapping(len_name, &binding.location)?; + self.validate_binding_arg_mapping(len_name, binding.location)?; if len_arg.type_ != AbiType::I32 { Err(ValidationError::BindingTypeError { expected: "slice len must be i32", @@ -366,14 +365,14 @@ impl<'a> FuncValidator<'a> { } _ => Err(ValidationError::Syntax { expected: "slice binding must be of form [ptr, len]", - location: binding.location.clone(), + location: binding.location, }), } } // A bare name is accepted: BindingRefSyntax::Name(ref name) => { let (position, funcarg) = - self.validate_binding_arg_mapping(name, &binding.location)?; + self.validate_binding_arg_mapping(name, binding.location)?; // make sure funcarg.type_ is a valid representation of target type match target_type.abi_type() { @@ -381,14 +380,14 @@ impl<'a> FuncValidator<'a> { if target_repr != funcarg.type_ { Err(ValidationError::BindingTypeError { expected: "binding type representation to match argument type", - location: binding.location.clone(), + location: binding.location, })?; } } None => { Err(ValidationError::BindingTypeError { expected: "binding type to be representable as value (try passing by reference instead)", - location: binding.location.clone(), + location: binding.location, })?; } } @@ -398,7 +397,7 @@ impl<'a> FuncValidator<'a> { if binding.direction != BindingDirSyntax::In { Err(ValidationError::BindingTypeError { expected: "argument value must be input-only binding", - location: binding.location.clone(), + location: binding.location, })?; } } @@ -406,7 +405,7 @@ impl<'a> FuncValidator<'a> { if binding.direction != BindingDirSyntax::Out { Err(ValidationError::BindingTypeError { expected: "return value must be output-only binding", - location: binding.location.clone(), + location: binding.location, })?; } } diff --git a/lucet-idl/src/validate/module.rs b/lucet-idl/src/validate/module.rs index 6f6dff19b..fe1c09089 100644 --- a/lucet-idl/src/validate/module.rs +++ b/lucet-idl/src/validate/module.rs @@ -40,21 +40,21 @@ pub fn module_from_declarations( location, members, } => { - datatypes_builder.introduce_struct(name, members, location)?; + datatypes_builder.introduce_struct(name, members, *location)?; } SyntaxDecl::Enum { name, location, variants, } => { - datatypes_builder.introduce_enum(name, variants, location)?; + datatypes_builder.introduce_enum(name, variants, *location)?; } SyntaxDecl::Alias { name, location, what, } => { - datatypes_builder.introduce_alias(name, what, location)?; + datatypes_builder.introduce_alias(name, what, *location)?; } _ => {} } @@ -82,7 +82,7 @@ pub fn module_from_declarations( location, } = decl { - funcs_builder.introduce_func(name, args, rets, bindings, location)?; + funcs_builder.introduce_func(name, args, rets, bindings, *location)?; } } From 40f7b894441459b831bc687a6841ef7821c985a7 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 21 Aug 2019 14:26:27 -0700 Subject: [PATCH 355/512] lucet-idl: fixup atom/abi relationships allow i64 abi to represent smaller types --- lucet-idl/src/atoms.rs | 13 ++++++++++--- lucet-idl/src/cursor.rs | 2 +- lucet-idl/src/validate/function.rs | 4 ++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/lucet-idl/src/atoms.rs b/lucet-idl/src/atoms.rs index 60b696fbd..25ea32e74 100644 --- a/lucet-idl/src/atoms.rs +++ b/lucet-idl/src/atoms.rs @@ -79,7 +79,7 @@ pub enum AbiType { } impl AbiType { - pub fn from_atom(a: &AtomType) -> Self { + pub fn smallest_representation(a: &AtomType) -> Self { match a { AtomType::Bool | AtomType::U8 @@ -94,7 +94,14 @@ impl AbiType { } } - pub fn of_atom(a: AtomType) -> Option { + pub fn can_represent(&self, a: &Self) -> bool { + match self { + AbiType::I64 => *a == AbiType::I32 || *a == AbiType::I64, + _ => a == self, + } + } + + pub fn from_atom(a: AtomType) -> Option { match a { AtomType::I32 => Some(AbiType::I32), AtomType::I64 => Some(AbiType::I64), @@ -133,7 +140,7 @@ impl ::std::convert::TryFrom<&str> for AbiType { type Error = (); fn try_from(name: &str) -> Result { let atom = AtomType::try_from(name)?; - Self::of_atom(atom).ok_or(()) + Self::from_atom(atom).ok_or(()) } } diff --git a/lucet-idl/src/cursor.rs b/lucet-idl/src/cursor.rs index cbdabeaf1..64d114291 100644 --- a/lucet-idl/src/cursor.rs +++ b/lucet-idl/src/cursor.rs @@ -237,7 +237,7 @@ pub enum DatatypeVariant<'a> { impl<'a> DatatypeVariant<'a> { pub fn abi_type(&self) -> Option { match self { - DatatypeVariant::Atom(a) => Some(AbiType::from_atom(a)), + DatatypeVariant::Atom(a) => Some(AbiType::smallest_representation(a)), DatatypeVariant::Struct(_) => None, DatatypeVariant::Enum(_) => Some(AbiType::I32), DatatypeVariant::Alias(a) => a.to().abi_type(), diff --git a/lucet-idl/src/validate/function.rs b/lucet-idl/src/validate/function.rs index 56a7d188d..1ccd50dad 100644 --- a/lucet-idl/src/validate/function.rs +++ b/lucet-idl/src/validate/function.rs @@ -377,9 +377,9 @@ impl<'a> FuncValidator<'a> { // make sure funcarg.type_ is a valid representation of target type match target_type.abi_type() { Some(target_repr) => { - if target_repr != funcarg.type_ { + if !funcarg.type_.can_represent(&target_repr) { Err(ValidationError::BindingTypeError { - expected: "binding type representation to match argument type", + expected: "binding type which can represent argument type", location: binding.location, })?; } From 05ee44d942e320de77aa541d92489b920e17be4b Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 21 Aug 2019 15:27:38 -0700 Subject: [PATCH 356/512] lucet-idl: fix error messages in binding validation tests and add an extra test case or two --- lucet-idl/src/validate/module.rs | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/lucet-idl/src/validate/module.rs b/lucet-idl/src/validate/module.rs index fe1c09089..8bdcee3ab 100644 --- a/lucet-idl/src/validate/module.rs +++ b/lucet-idl/src/validate/module.rs @@ -477,37 +477,52 @@ mod tests { fn func_one_arg_binding_wrong_type() { // Cant convert int to float assert_eq!( - mod_syntax("fn trivial(a: i32) where\na_binding: out f32 <- a;") + mod_syntax("fn trivial(a: i32) where\na_binding: in f32 <- a;") .err() .unwrap(), ValidationError::BindingTypeError { - expected: "binding type representation to match argument type", + expected: "binding type which can represent argument type", location: Location { line: 2, column: 0 } }, ); // Cant convert float to int assert_eq!( - mod_syntax("fn trivial(a: f32) where\na_binding: out i32 <- a;") + mod_syntax("fn trivial(a: f32) where\na_binding: in i32 <- a;") .err() .unwrap(), ValidationError::BindingTypeError { - expected: "binding type representation to match argument type", + expected: "binding type which can represent argument type", location: Location { line: 2, column: 0 } }, ); // Cant represent i64 with i32 assert_eq!( - mod_syntax("fn trivial(a: i32) where\na_binding: out i64 <- a;") + mod_syntax("fn trivial(a: i32) where\na_binding: in i64 <- a;") .err() .unwrap(), ValidationError::BindingTypeError { - expected: "binding type representation to match argument type", + expected: "binding type which can represent argument type", location: Location { line: 2, column: 0 } }, ); - // Cant represent ptr with float + + // but, can represent i32 with i64 + mod_syntax("fn trivial(a: i64) where\na_binding: in i32 <- a;").unwrap(); + + // Cant represent f64 with f32 + assert_eq!( + mod_syntax("fn trivial(a: f32) where\na_binding: in f64 <- a;") + .err() + .unwrap(), + ValidationError::BindingTypeError { + expected: "binding type which can represent argument type", + location: Location { line: 2, column: 0 } + }, + ); + + // Cant represent ptr with f32 assert_eq!( - mod_syntax("fn trivial(a: f32) where\na_binding: out i8 <- *a;") + mod_syntax("fn trivial(a: f32) where\na_binding: in i8 <- *a;") .err() .unwrap(), ValidationError::BindingTypeError { From 35704e18b4ecd67a275acdb9d83d34d68ae63529 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 26 Aug 2019 15:46:39 -0700 Subject: [PATCH 357/512] lucet-idl-test: fix stub --- lucet-idl/lucet-idl-test/resources/rust_host/src/harness.rs | 2 +- lucet-idl/lucet-idl-test/resources/rust_host/src/idl.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lucet-idl/lucet-idl-test/resources/rust_host/src/harness.rs b/lucet-idl/lucet-idl-test/resources/rust_host/src/harness.rs index b74497767..f2d1ce9f7 100644 --- a/lucet-idl/lucet-idl-test/resources/rust_host/src/harness.rs +++ b/lucet-idl/lucet-idl-test/resources/rust_host/src/harness.rs @@ -1,6 +1,6 @@ // PLACEHOLDER FILE // this file is overwritten, and restored, by lucet-idl-test pub struct Ctx; -fn ctx() -> Box { +pub fn ctx() -> Box { Box::new(Ctx) } diff --git a/lucet-idl/lucet-idl-test/resources/rust_host/src/idl.rs b/lucet-idl/lucet-idl-test/resources/rust_host/src/idl.rs index 8228ef8d1..94f7133ac 100644 --- a/lucet-idl/lucet-idl-test/resources/rust_host/src/idl.rs +++ b/lucet-idl/lucet-idl-test/resources/rust_host/src/idl.rs @@ -1,3 +1,3 @@ // PLACEHOLDER FILE // this file is overwritten, and restored, by lucet-idl-test -fn ensure_linked() {} +pub fn ensure_linked() {} From 8110462b2863a654b55e397e6dea05eba6164d05 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 26 Aug 2019 15:51:32 -0700 Subject: [PATCH 358/512] lucet-idl-test: fixes --- lucet-idl/lucet-idl-test/src/syntax.rs | 7 +++++-- lucet-idl/lucet-idl-test/src/values.rs | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lucet-idl/lucet-idl-test/src/syntax.rs b/lucet-idl/lucet-idl-test/src/syntax.rs index 4d32b4e89..14542824d 100644 --- a/lucet-idl/lucet-idl-test/src/syntax.rs +++ b/lucet-idl/lucet-idl-test/src/syntax.rs @@ -300,7 +300,7 @@ impl FunctionSyntax { arg_syntax.push(format!( "a_{}: {}", ix, - AbiType::from_atom(&atomtype).render_idl() + AbiType::smallest_representation(atomtype).render_idl() )); binding_syntax.push(format!( "b_{}: in {} <- a_{}", @@ -353,7 +353,10 @@ impl FunctionSyntax { let mut ret_syntax = None; if let Some(b) = self.ret_binding { - ret_syntax = Some(format!("r: {}", AbiType::from_atom(&b).render_idl())); + ret_syntax = Some(format!( + "r: {}", + AbiType::smallest_representation(&b).render_idl() + )); let ix = self.arg_bindings.len(); binding_syntax.push(format!("b_{}: out {} <- r", ix, b.render_idl(),)); } diff --git a/lucet-idl/lucet-idl-test/src/values.rs b/lucet-idl/lucet-idl-test/src/values.rs index 638a3ab24..cf384244c 100644 --- a/lucet-idl/lucet-idl-test/src/values.rs +++ b/lucet-idl/lucet-idl-test/src/values.rs @@ -62,7 +62,7 @@ pub struct EnumVal { impl EnumVal { pub fn strat(enum_datatype: &EnumDatatype) -> impl Strategy { - let name = enum_datatype.name().to_owned(); + let name = enum_datatype.datatype().name().to_owned(); prop::sample::select( enum_datatype .variants() @@ -91,7 +91,7 @@ pub struct StructVal { impl StructVal { pub fn strat(struct_dt: &StructDatatype) -> BoxedStrategy { - let name = struct_dt.name().to_owned(); + let name = struct_dt.datatype().name().to_owned(); let member_strats: Vec> = struct_dt .members() .map(|m| StructMemberVal::strat(&m)) @@ -145,7 +145,7 @@ pub struct AliasVal { impl AliasVal { pub fn strat(alias_dt: &AliasDatatype) -> BoxedStrategy { - let name = alias_dt.name().to_owned(); + let name = alias_dt.datatype().name().to_owned(); alias_dt .to() .strat() From 18d67c8e1eeec7a78b2e5708de3e6005d0c17d06 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 26 Aug 2019 15:51:39 -0700 Subject: [PATCH 359/512] lucet-idl: separate parse trees for package-level and syntax-level decls rather than a recursive parse tree. --- lucet-idl/src/lib.rs | 2 +- lucet-idl/src/parser.rs | 429 +++++++++++----------------- lucet-idl/src/validate/datatypes.rs | 2 +- lucet-idl/src/validate/module.rs | 28 +- lucet-idl/src/validate/package.rs | 26 +- 5 files changed, 199 insertions(+), 288 deletions(-) diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index c81ef39fe..b77af7785 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -49,7 +49,7 @@ pub trait MemArea { pub fn parse_package(input: &str) -> Result { let mut parser = Parser::new(&input); - let decls = parser.match_decls()?; + let decls = parser.match_package_decls()?; let pkg = package_from_declarations(&decls)?; Ok(pkg) } diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index e3a8e6e36..8239cb0fa 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -4,7 +4,16 @@ use std::error::Error; use std::fmt; #[derive(Debug, PartialEq, Eq, Clone)] -pub enum SyntaxDecl<'a> { +pub enum PackageDecl<'a> { + Module { + name: &'a str, + decls: Vec>, + location: Location, + }, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum ModuleDecl<'a> { Struct { name: &'a str, members: Vec>, @@ -20,11 +29,6 @@ pub enum SyntaxDecl<'a> { what: SyntaxIdent<'a>, location: Location, }, - Module { - name: &'a str, - decls: Vec>, - location: Location, - }, Function { name: &'a str, args: Vec>, @@ -34,18 +38,6 @@ pub enum SyntaxDecl<'a> { }, } -impl<'a> SyntaxDecl<'a> { - pub fn location(&self) -> &Location { - match self { - SyntaxDecl::Struct { location, .. } => &location, - SyntaxDecl::Enum { location, .. } => &location, - SyntaxDecl::Alias { location, .. } => &location, - SyntaxDecl::Module { location, .. } => &location, - SyntaxDecl::Function { location, .. } => &location, - } - } -} - #[derive(Debug, PartialEq, Eq, Clone)] pub struct SyntaxIdent<'a> { pub name: &'a str, @@ -199,6 +191,17 @@ impl<'a> Parser<'a> { } } + fn match_ident(&mut self, err_msg: &str) -> Result, ParseError> { + match self.token() { + Some(Token::Word(name)) => { + let location = self.location; + self.consume(); + Ok(SyntaxIdent { name, location }) + } + _ => err_ctx!(err_msg, parse_err!(self.location, "expected identifier")), + } + } + fn match_struct_body(&mut self) -> Result>, ParseError> { let mut members = Vec::new(); loop { @@ -423,145 +426,129 @@ impl<'a> Parser<'a> { } } - pub fn match_decl(&mut self, err_msg: &str) -> Result>, ParseError> { - loop { - match self.token() { - Some(Token::Word("struct")) => { - let location = self.location; - self.consume(); - let name = err_ctx!(err_msg, self.match_a_word("expected struct name"))?; - err_ctx!(err_msg, self.match_token(Token::LBrace, "expected {"))?; - let members = err_ctx!(err_msg, self.match_struct_body())?; - return Ok(Some(SyntaxDecl::Struct { - name, - members, - location, - })); - } - Some(Token::Word("enum")) => { - let location = self.location; - self.consume(); - let name = err_ctx!(err_msg, self.match_a_word("expected enum name"))?; - err_ctx!(err_msg, self.match_token(Token::LBrace, "expected {"))?; - let variants = err_ctx!(err_msg, self.match_enum_body())?; - return Ok(Some(SyntaxDecl::Enum { - name, - variants, - location, - })); - } - Some(Token::Word("type")) => { - let location = self.location; - self.consume(); - let name = err_ctx!(err_msg, self.match_a_word("expected type name"))?; - err_ctx!(err_msg, self.match_token(Token::Equals, "expected ="))?; - let what = self.match_ident("type value")?; - err_ctx!(err_msg, self.match_token(Token::Semi, "expected ;"))?; - return Ok(Some(SyntaxDecl::Alias { - name, - what, - location, - })); - } - Some(Token::Word("mod")) => { - let location = self.location; - self.consume(); - let name = err_ctx!(err_msg, self.match_a_word("expected module name"))?; - err_ctx!(err_msg, self.match_token(Token::LBrace, "expected {"))?; - - let mut decls = Vec::new(); - loop { - if let Some(Token::RBrace) = self.token() { - self.consume(); - break; - } else { - match self.match_decl("declaration") { - Ok(Some(decl)) => decls.push(decl), - Ok(None) => parse_err!(self.location, "missing close brace '}'")?, - Err(e) => Err(e)?, - } - } - } + pub fn match_module_decl(&mut self) -> Result, ParseError> { + match self.token() { + Some(Token::Word("struct")) => { + let location = self.location; + self.consume(); + let name = self.match_a_word("expected struct name")?; + self.match_token(Token::LBrace, "expected {")?; + let members = self.match_struct_body()?; + Ok(ModuleDecl::Struct { + name, + members, + location, + }) + } + Some(Token::Word("enum")) => { + let location = self.location; + self.consume(); + let name = self.match_a_word("expected enum name")?; + self.match_token(Token::LBrace, "expected {")?; + let variants = self.match_enum_body()?; + Ok(ModuleDecl::Enum { + name, + variants, + location, + }) + } + Some(Token::Word("type")) => { + let location = self.location; + self.consume(); + let name = self.match_a_word("expected type name")?; + self.match_token(Token::Equals, "expected =")?; + let what = self.match_ident("type value")?; + self.match_token(Token::Semi, "expected ;")?; + Ok(ModuleDecl::Alias { + name, + what, + location, + }) + } + Some(Token::Word("fn")) => { + let location = self.location; + self.consume(); + let name = self.match_a_word("expected function name")?; - return Ok(Some(SyntaxDecl::Module { - name, - decls, - location, - })); - } - Some(Token::Word("fn")) => { - let location = self.location; + self.match_token(Token::LPar, "expected (")?; + let args = self.match_func_args()?; + let rets = if let Some(Token::RArrow) = self.token() { self.consume(); - let name = err_ctx!(err_msg, self.match_a_word("expected function name"))?; + self.match_func_rets()? + } else { + Vec::new() + }; - err_ctx!(err_msg, self.match_token(Token::LPar, "expected ("))?; - let args = err_ctx!(err_msg, self.match_func_args())?; - let rets = if let Some(Token::RArrow) = self.token() { + let bindings = match self.token() { + Some(Token::Semi) => { self.consume(); - err_ctx!(err_msg, self.match_func_rets())? - } else { Vec::new() - }; + } + Some(Token::Word("where")) => { + self.consume(); + self.match_binding_exprs()? + } + t => parse_err!(self.location, "expected where, -> or ;, got {:?}", t)?, + }; - let bindings = match self.token() { - Some(Token::Semi) => { + Ok(ModuleDecl::Function { + name, + args, + rets, + bindings, + location, + }) + } + Some(_) | None => parse_err!(self.location, "expected module declaration"), + } + } + + pub fn match_package_decl(&mut self) -> Result, ParseError> { + match self.token() { + Some(Token::Word("mod")) => { + let location = self.location; + self.consume(); + let name = self.match_a_word("expected module name")?; + self.match_token(Token::LBrace, "expected {")?; + + let mut decls = Vec::new(); + loop { + match self.token() { + Some(Token::RBrace) => { self.consume(); - Vec::new() + break; } - Some(Token::Word("where")) => { - self.consume(); - err_ctx!(err_msg, self.match_binding_exprs())? + Some(_) => { + let decl = self.match_module_decl()?; + decls.push(decl); } - t => err_ctx!( - err_msg, - parse_err!(self.location, "expected where, -> or ;, got {:?}", t) - )?, - }; - - return Ok(Some(SyntaxDecl::Function { - name, - args, - rets, - bindings, - location, - })); - } - Some(_) => { - return parse_err!( - self.location, - "in {}\nexpected keyword or attribute", - err_msg - ) - } - None => { - return Ok(None); + None => parse_err!(self.location, "expected module decl or }")?, + } } + + Ok(PackageDecl::Module { + name, + decls, + location, + }) } + Some(_) | None => parse_err!(self.location, "expected package declaration"), } } - pub fn match_decls(&mut self) -> Result>, ParseError> { + pub fn match_package_decls(&mut self) -> Result>, ParseError> { let mut decls = Vec::new(); loop { - match self.match_decl("declaration") { - Ok(Some(decl)) => decls.push(decl), - Ok(None) => break, - Err(e) => Err(e)?, + match self.token() { + Some(_) => { + let decl = self.match_package_decl()?; + decls.push(decl); + } + None => break, } } Ok(decls) } - - fn match_ident(&mut self, err_msg: &str) -> Result, ParseError> { - match self.token() { - Some(Token::Word(name)) => { - let location = self.location; - self.consume(); - Ok(SyntaxIdent { name, location }) - } - _ => err_ctx!(err_msg, parse_err!(self.location, "expected identifier")), - } - } } #[cfg(test)] @@ -571,11 +558,8 @@ mod tests { fn struct_empty() { let mut parser = Parser::new("struct foo {}"); assert_eq!( - parser - .match_decl("empty struct") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Struct { + parser.match_module_decl().expect("valid parse"), + ModuleDecl::Struct { name: "foo", members: Vec::new(), location: Location { line: 1, column: 0 }, @@ -587,11 +571,8 @@ mod tests { let mut parser = Parser::new("struct foo {a: i32 }"); // column ruler: 0 7 12 15 assert_eq!( - parser - .match_decl("foo a i32") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Struct { + parser.match_module_decl().expect("valid parse"), + ModuleDecl::Struct { name: "foo", members: vec![StructMember { name: "a", @@ -616,11 +597,8 @@ mod tests { let mut parser = Parser::new("struct foo {b: i32, }"); // 0 7 12 15 assert_eq!( - parser - .match_decl("foo b i32 with trailing comma") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Struct { + parser.match_module_decl().expect("valid parse"), + ModuleDecl::Struct { name: "foo", members: vec![StructMember { name: "b", @@ -645,11 +623,8 @@ mod tests { let mut parser = Parser::new("struct c { d: f64, e: u8 }"); // 0 7 11 14 19 22 assert_eq!( - parser - .match_decl("struct c") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Struct { + parser.match_module_decl().expect("valid parse"), + ModuleDecl::Struct { name: "c", members: vec![ StructMember { @@ -691,11 +666,8 @@ mod tests { let mut parser = Parser::new("struct foo {a: mod, struct: enum }"); // column ruler: 0 7 12 15 21 30 assert_eq!( - parser - .match_decl("foo a i32") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Struct { + parser.match_module_decl().expect("valid parse"), + ModuleDecl::Struct { name: "foo", members: vec![ StructMember { @@ -736,11 +708,8 @@ mod tests { let mut parser = Parser::new("enum foo {}"); // 0 5 assert_eq!( - parser - .match_decl("empty enum") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Enum { + parser.match_module_decl().expect("valid parse"), + ModuleDecl::Enum { name: "foo", variants: Vec::new(), location: Location { line: 1, column: 0 }, @@ -752,11 +721,8 @@ mod tests { let mut parser = Parser::new("enum foo {first,}"); // 0 5 10 assert_eq!( - parser - .match_decl("one entry enum, trailing comma") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Enum { + parser.match_module_decl().expect("valid parse"), + ModuleDecl::Enum { name: "foo", variants: vec![EnumVariant { name: "first", @@ -774,11 +740,8 @@ mod tests { let mut parser = Parser::new("enum bar {first}"); // 0 5 10 assert_eq!( - parser - .match_decl("one entry enum, no trailing comma") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Enum { + parser.match_module_decl().expect("valid parse"), + ModuleDecl::Enum { name: "bar", variants: vec![EnumVariant { name: "first", @@ -797,11 +760,8 @@ mod tests { let mut parser = Parser::new("enum baz { one, two, three\n, four, }"); // 0 5 11 16 21 0 2 assert_eq!( - parser - .match_decl("four entry enum, trailing comma") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Enum { + parser.match_module_decl().expect("valid parse"), + ModuleDecl::Enum { name: "baz", variants: vec![ EnumVariant { @@ -840,11 +800,8 @@ mod tests { let mut parser = Parser::new("mod empty {}"); // 0 5 10 assert_eq!( - parser - .match_decl("empty module") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Module { + parser.match_package_decl().expect("valid parse"), + PackageDecl::Module { name: "empty", decls: Vec::new(), location: Location { line: 1, column: 0 }, @@ -852,50 +809,16 @@ mod tests { ); } - #[test] - fn mod_nesting() { - let mut parser = Parser::new("mod one { mod two { mod three { } } }"); - // 0 5 10 15 20 - assert_eq!( - parser - .match_decl("nested modules") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Module { - name: "one", - decls: vec![SyntaxDecl::Module { - name: "two", - decls: vec![SyntaxDecl::Module { - name: "three", - decls: Vec::new(), - location: Location { - line: 1, - column: 20 - }, - }], - location: Location { - line: 1, - column: 10 - }, - }], - location: Location { line: 1, column: 0 }, - } - ); - } - #[test] fn mod_types() { let mut parser = Parser::new("mod one { enum foo {} struct bar {} }"); // 0 5 10 15 20 assert_eq!( - parser - .match_decl("module with types") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Module { + parser.match_package_decl().expect("valid parse"), + PackageDecl::Module { name: "one", decls: vec![ - SyntaxDecl::Enum { + ModuleDecl::Enum { name: "foo", variants: Vec::new(), location: Location { @@ -903,7 +826,7 @@ mod tests { column: 10 }, }, - SyntaxDecl::Struct { + ModuleDecl::Struct { name: "bar", members: Vec::new(), location: Location { @@ -919,7 +842,7 @@ mod tests { #[test] fn fn_trivial() { - let canonical = vec![SyntaxDecl::Function { + let canonical = vec![ModuleDecl::Function { name: "trivial", args: Vec::new(), rets: Vec::new(), @@ -929,21 +852,21 @@ mod tests { assert_eq!( Parser::new("fn trivial();") // 0 5 10 - .match_decls() + .match_module_decls() .expect("valid parse"), canonical, ); assert_eq!( Parser::new("fn trivial ( ) ;") // 0 5 10 - .match_decls() + .match_module_decls() .expect("valid parse"), canonical, ); assert_eq!( Parser::new("fn trivial()->;") // 0 5 10 - .match_decls() + .match_module_decls() .expect("valid parse"), canonical, ); @@ -951,8 +874,8 @@ mod tests { #[test] fn fn_return_i32() { - fn canonical(column: usize) -> Vec> { - vec![SyntaxDecl::Function { + fn canonical(column: usize) -> Vec> { + vec![ModuleDecl::Function { name: "getch", args: Vec::new(), rets: vec![FuncArgSyntax { @@ -976,21 +899,21 @@ mod tests { assert_eq!( Parser::new("fn getch() -> r:i32;") // 0 5 10 15 - .match_decls() + .match_module_decls() .expect("valid decls"), canonical(16) ); assert_eq!( Parser::new("fn getch() -> r: i32,;") // 0 5 10 - .match_decls() + .match_module_decls() .expect("valid decls"), canonical(17) ); assert_eq!( Parser::new("fn getch() -> r :i32 , ;") // 0 5 10 - .match_decls() + .match_module_decls() .expect("valid decls"), canonical(17) ); @@ -998,7 +921,7 @@ mod tests { #[test] fn fn_one_arg() { - let canonical = SyntaxDecl::Function { + let canonical = ModuleDecl::Function { name: "foo", args: vec![FuncArgSyntax { type_: SyntaxIdent { @@ -1018,24 +941,22 @@ mod tests { assert_eq!( Parser::new("fn foo(a: i32);") // 0 5 10 15 20 25 - .match_decl("returns i32") - .expect("valid parse") - .expect("valid decl"), + .match_module_decl() + .expect("valid parse"), canonical ); assert_eq!( Parser::new("fn foo(a: i32,);") // 0 5 10 15 20 25 - .match_decl("returns i32") - .expect("valid parse") - .expect("valid decl"), + .match_module_decl() + .expect("valid parse"), canonical ); } #[test] fn fn_multi_arg() { - let canonical = SyntaxDecl::Function { + let canonical = ModuleDecl::Function { name: "foo", args: vec![ FuncArgSyntax { @@ -1071,17 +992,15 @@ mod tests { assert_eq!( Parser::new("fn foo(a: i32, b: f64);") // 0 5 10 15 20 25 - .match_decl("two args") - .expect("valid parse") - .expect("valid decl"), + .match_module_decl() + .expect("valid parse"), canonical ); assert_eq!( Parser::new("fn foo(a: i32, b: f64, );") // 0 5 10 15 20 25 - .match_decl("two args with trailing comma") - .expect("valid parse") - .expect("valid decl"), + .match_module_decl() + .expect("valid parse"), canonical ); } @@ -1091,10 +1010,9 @@ mod tests { assert_eq!( Parser::new("fn getch() -> r1: i32, r2: i64, r3: f32;") // 0 5 10 15 20 25 30 - .match_decl("returns u8") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Function { + .match_module_decl() + .expect("valid parse"), + ModuleDecl::Function { name: "getch", args: Vec::new(), rets: vec![ @@ -1157,10 +1075,9 @@ mod tests { some_slice: out something <- [a, b];" ) // 0 5 10 15 20 25 30 - .match_decl("returns u8") - .expect("valid parse") - .expect("valid decl"), - SyntaxDecl::Function { + .match_module_decl() + .expect("valid parse"), + ModuleDecl::Function { name: "fgetch", args: vec![FuncArgSyntax { type_: SyntaxIdent { diff --git a/lucet-idl/src/validate/datatypes.rs b/lucet-idl/src/validate/datatypes.rs index 3da6dc661..0591ae334 100644 --- a/lucet-idl/src/validate/datatypes.rs +++ b/lucet-idl/src/validate/datatypes.rs @@ -136,7 +136,7 @@ impl<'a> DatatypeModuleBuilder<'a> { previous_location: existing.location, })? } - // build the struct with this as the member: + // build the enum with this as the member: members.push(EnumMemberRepr { name: var.name.to_owned(), }) diff --git a/lucet-idl/src/validate/module.rs b/lucet-idl/src/validate/module.rs index 8bdcee3ab..9b6d58028 100644 --- a/lucet-idl/src/validate/module.rs +++ b/lucet-idl/src/validate/module.rs @@ -1,31 +1,27 @@ use super::datatypes::DatatypeModuleBuilder; use super::function::FunctionModuleBuilder; use super::names::ModNamesBuilder; -use crate::parser::SyntaxDecl; +use crate::parser::ModuleDecl; use crate::repr::{ModuleIx, ModuleRepr}; use crate::{Package, ValidationError}; pub fn module_from_declarations( env: &Package, ix: ModuleIx, - decls: &[SyntaxDecl], + decls: &[ModuleDecl], ) -> Result { // First, we need to declare names of all the declarations let mut names = ModNamesBuilder::new(ix); for decl in decls.iter() { match decl { - SyntaxDecl::Struct { name, location, .. } - | SyntaxDecl::Enum { name, location, .. } - | SyntaxDecl::Alias { name, location, .. } => { + ModuleDecl::Struct { name, location, .. } + | ModuleDecl::Enum { name, location, .. } + | ModuleDecl::Alias { name, location, .. } => { names.introduce_datatype(name, location)?; } - SyntaxDecl::Function { name, location, .. } => { + ModuleDecl::Function { name, location, .. } => { names.introduce_function(name, location)?; } - SyntaxDecl::Module { location, .. } => Err(ValidationError::Syntax { - expected: "type or function declaration", - location: *location, - })?, } } @@ -35,21 +31,21 @@ pub fn module_from_declarations( // Then, we can define each datatype for decl in decls.iter() { match decl { - SyntaxDecl::Struct { + ModuleDecl::Struct { name, location, members, } => { datatypes_builder.introduce_struct(name, members, *location)?; } - SyntaxDecl::Enum { + ModuleDecl::Enum { name, location, variants, } => { datatypes_builder.introduce_enum(name, variants, *location)?; } - SyntaxDecl::Alias { + ModuleDecl::Alias { name, location, what, @@ -74,7 +70,7 @@ pub fn module_from_declarations( let mut funcs_builder = FunctionModuleBuilder::new(funcs_env, &names); for decl in decls { - if let SyntaxDecl::Function { + if let ModuleDecl::Function { name, args, rets, @@ -102,11 +98,11 @@ mod tests { use crate::{BindingDirection, DatatypeVariant, Location, MemArea, ParamPosition}; fn mod_syntax(syntax: &str) -> Result { let mut parser = Parser::new(syntax); - let decls = parser.match_decls().expect("parses"); + let decls = parser.match_module_decls().expect("parses"); let mut pkg_builder = PackageBuilder::new(); let mod_ix = pkg_builder - .introduce_name("mod", &Location { line: 0, column: 0 }) + .introduce_name("mod", Location { line: 0, column: 0 }) .expect("declare name ok"); let module_repr = module_from_declarations(pkg_builder.repr(), mod_ix, &decls)?; pkg_builder.define_module(mod_ix, module_repr); diff --git a/lucet-idl/src/validate/package.rs b/lucet-idl/src/validate/package.rs index b51b91015..0d0e40d24 100644 --- a/lucet-idl/src/validate/package.rs +++ b/lucet-idl/src/validate/package.rs @@ -1,29 +1,27 @@ use super::module::module_from_declarations; use crate::error::ValidationError; -use crate::parser::SyntaxDecl; +use crate::parser::PackageDecl; use crate::prelude::std_module; use crate::repr::{ModuleIx, ModuleRepr, Package}; use crate::Location; use cranelift_entity::PrimaryMap; use std::collections::HashMap; -pub fn package_from_declarations(package_decls: &[SyntaxDecl]) -> Result { +pub fn package_from_declarations( + package_decls: &[PackageDecl], +) -> Result { let mut pkg = PackageBuilder::new(); for decl in package_decls { match decl { - SyntaxDecl::Module { + PackageDecl::Module { name, location, decls, } => { - let module_ix = pkg.introduce_name(name, location)?; - let module_repr = module_from_declarations(pkg.repr(), module_ix, decls)?; + let module_ix = pkg.introduce_name(name, *location)?; + let module_repr = module_from_declarations(pkg.repr(), module_ix, &decls)?; pkg.define_module(module_ix, module_repr); } - _ => Err(ValidationError::Syntax { - expected: "module", - location: *decl.location(), - })?, } } Ok(pkg.build()) @@ -51,28 +49,28 @@ impl PackageBuilder { pub fn introduce_name( &mut self, name: &str, - location: &Location, + location: Location, ) -> Result { if let Some((_, prev_loc)) = self.name_decls.get(name) { match prev_loc { Some(prev_loc) => { Err(ValidationError::NameAlreadyExists { name: name.to_owned(), - at_location: *location, + at_location: location, previous_location: *prev_loc, })?; } None => { Err(ValidationError::Syntax { expected: "non-reserved module name", - location: *location, + location: location, })?; } } } let ix = self.repr.names.push(name.to_owned()); self.name_decls - .insert(name.to_owned(), (ix, Some(*location))); + .insert(name.to_owned(), (ix, Some(location))); Ok(ix) } @@ -99,7 +97,7 @@ mod test { fn pkg_(syntax: &str) -> Result { let mut parser = Parser::new(syntax); - let decls = parser.match_decls().expect("parses"); + let decls = parser.match_package_decls().expect("parses"); package_from_declarations(&decls) } From d482c7ef2c8993281297613272b4782613a81ddd Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 26 Aug 2019 18:00:46 -0700 Subject: [PATCH 360/512] lucet-idl: finish fixing parser split-up --- lucet-idl/src/parser.rs | 69 ++++++++++++--- lucet-idl/src/validate/datatypes.rs | 125 +++++++++++++++++----------- lucet-idl/src/validate/package.rs | 36 -------- 3 files changed, 134 insertions(+), 96 deletions(-) diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index 8239cb0fa..29fee9655 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -503,6 +503,15 @@ impl<'a> Parser<'a> { } } + #[cfg(test)] + pub fn match_module_decls(&mut self) -> Result>, ParseError> { + let mut decls = Vec::new(); + while self.token().is_some() { + decls.push(self.match_module_decl()?); + } + Ok(decls) + } + pub fn match_package_decl(&mut self) -> Result, ParseError> { match self.token() { Some(Token::Word("mod")) => { @@ -842,31 +851,31 @@ mod tests { #[test] fn fn_trivial() { - let canonical = vec![ModuleDecl::Function { + let canonical = ModuleDecl::Function { name: "trivial", args: Vec::new(), rets: Vec::new(), bindings: Vec::new(), location: Location { line: 1, column: 0 }, - }]; + }; assert_eq!( Parser::new("fn trivial();") // 0 5 10 - .match_module_decls() + .match_module_decl() .expect("valid parse"), canonical, ); assert_eq!( Parser::new("fn trivial ( ) ;") // 0 5 10 - .match_module_decls() + .match_module_decl() .expect("valid parse"), canonical, ); assert_eq!( Parser::new("fn trivial()->;") // 0 5 10 - .match_module_decls() + .match_module_decl() .expect("valid parse"), canonical, ); @@ -874,8 +883,8 @@ mod tests { #[test] fn fn_return_i32() { - fn canonical(column: usize) -> Vec> { - vec![ModuleDecl::Function { + fn canonical(column: usize) -> ModuleDecl<'static> { + ModuleDecl::Function { name: "getch", args: Vec::new(), rets: vec![FuncArgSyntax { @@ -894,26 +903,26 @@ mod tests { }], bindings: Vec::new(), location: Location { line: 1, column: 0 }, - }] + } } assert_eq!( Parser::new("fn getch() -> r:i32;") // 0 5 10 15 - .match_module_decls() + .match_module_decl() .expect("valid decls"), canonical(16) ); assert_eq!( Parser::new("fn getch() -> r: i32,;") // 0 5 10 - .match_module_decls() + .match_module_decl() .expect("valid decls"), canonical(17) ); assert_eq!( Parser::new("fn getch() -> r :i32 , ;") // 0 5 10 - .match_module_decls() + .match_module_decl() .expect("valid decls"), canonical(17) ); @@ -1149,4 +1158,42 @@ mod tests { } ); } + + #[test] + fn no_mod_in_mod() { + let err = Parser::new("mod foo { mod bar { }}").match_package_decl(); + assert_eq!( + err, + Err(ParseError { + message: "expected module declaration".to_owned(), + location: Location { + line: 1, + column: 10 + } + }) + ); + Parser::new("mod foo { enum whatever {} mod bar { }}") + .match_package_decls() + .err() + .expect("error package"); + } + + #[test] + fn no_top_level_types() { + let err = Parser::new("mod foo { } enum bar {}") + .match_package_decls() + .err() + .expect("error package"); + assert_eq!( + err, + ParseError { + message: "expected package declaration".to_owned(), + location: Location { + line: 1, + column: 12 + } + } + ); + } + } diff --git a/lucet-idl/src/validate/datatypes.rs b/lucet-idl/src/validate/datatypes.rs index 0591ae334..550dc8550 100644 --- a/lucet-idl/src/validate/datatypes.rs +++ b/lucet-idl/src/validate/datatypes.rs @@ -181,11 +181,9 @@ impl<'a> DatatypeModuleBuilder<'a> { } pub fn build(self) -> Result { - let mut finalized = SecondaryMap::new(); - finalized.resize(self.names.types.len()); + let mut finalized = FinalizedTypes::new(self.names.types.len()); + let mut ordered = Vec::new(); - // Important to iterate in name order, so error messages are consistient. - // HashMap iteration order is not stable. for (ix, name) in self.names.types.iter() { let decl = self .types @@ -193,7 +191,7 @@ impl<'a> DatatypeModuleBuilder<'a> { .expect("all datatypes declared were defined"); // Depth first search through datatypes will return an error if they - // are infinite, and insert + // are infinite, by marking all visited datatypes in this map: let mut visited = SecondaryMap::new(); visited.resize(self.names.types.len()); @@ -204,10 +202,7 @@ impl<'a> DatatypeModuleBuilder<'a> { })?; } - let mut datatypes = PrimaryMap::new(); - for dt in finalized.values() { - datatypes.push(dt.clone().expect("all datatypes finalized")); - } + let datatypes = finalized.build(); assert_eq!( self.names.types.len(), @@ -232,7 +227,7 @@ impl<'a> DatatypeModuleBuilder<'a> { ix: DatatypeIx, visited: &mut SecondaryMap, ordered: &mut Vec, - finalized_types: &mut SecondaryMap>, + finalized_types: &mut FinalizedTypes, ) -> Result<(), ()> { // Ensure that dfs terminates: if visited[ix] { @@ -253,11 +248,7 @@ impl<'a> DatatypeModuleBuilder<'a> { } } // If finalized type information has not yet been computed, we can now compute it: - if finalized_types - .get(ix) - .expect("ix exists in types") - .is_none() - { + if !finalized_types.is_defined(ix) { let mut offset = 0; let mut struct_align = 1; let mut members: Vec = Vec::new(); @@ -278,11 +269,14 @@ impl<'a> DatatypeModuleBuilder<'a> { let mem_size = align_to(offset, struct_align); - finalized_types[ix] = Some(DatatypeRepr { - variant: DatatypeVariantRepr::Struct(StructDatatypeRepr { members }), - mem_size, - mem_align: struct_align, - }); + finalized_types.define( + ix, + DatatypeRepr { + variant: DatatypeVariantRepr::Struct(StructDatatypeRepr { members }), + mem_size, + mem_align: struct_align, + }, + ); } } VariantIR::Alias(ref a) => { @@ -294,36 +288,36 @@ impl<'a> DatatypeModuleBuilder<'a> { } // If finalized type information has not yet been computed, we can now compute it: - if finalized_types - .get(ix) - .expect("ix exists in types") - .is_none() - { + if !finalized_types.is_defined(ix) { let (mem_size, mem_align) = self.datatype_size_align(a.to, finalized_types); - finalized_types[ix] = Some(DatatypeRepr { - variant: DatatypeVariantRepr::Alias(AliasDatatypeRepr { to: a.to.clone() }), - mem_size, - mem_align, - }); + finalized_types.define( + ix, + DatatypeRepr { + variant: DatatypeVariantRepr::Alias(AliasDatatypeRepr { + to: a.to.clone(), + }), + mem_size, + mem_align, + }, + ); } } VariantIR::Enum(ref e) => { // No recursion to do on the dfs. - if finalized_types - .get(ix) - .expect("ix exists in types") - .is_none() - { + if !finalized_types.is_defined(ix) { // x86_64 ABI says enum is 32 bits wide let mem_size = AtomType::U32.mem_size(); let mem_align = mem_size; - finalized_types[ix] = Some(DatatypeRepr { - variant: DatatypeVariantRepr::Enum(EnumDatatypeRepr { - members: e.members.clone(), - }), - mem_size, - mem_align, - }); + finalized_types.define( + ix, + DatatypeRepr { + variant: DatatypeVariantRepr::Enum(EnumDatatypeRepr { + members: e.members.clone(), + }), + mem_size, + mem_align, + }, + ); } } } @@ -339,15 +333,12 @@ impl<'a> DatatypeModuleBuilder<'a> { fn datatype_size_align( &self, id: DatatypeIdent, - finalized_types: &SecondaryMap>, + finalized_types: &FinalizedTypes, ) -> (usize, usize) { let (size, align) = if id.module == self.names.module { - let t = finalized_types - .get(id.datatype) - .cloned() - .expect("looking up identifier in this module") - .expect("looking up type defined in this module"); - (t.mem_size, t.mem_align) + finalized_types + .size_align(id.datatype) + .expect("looking up type defined in this module") } else { let dt = self .env @@ -361,6 +352,42 @@ impl<'a> DatatypeModuleBuilder<'a> { } } +struct FinalizedTypes { + types: SecondaryMap>, +} + +impl FinalizedTypes { + fn new(map_size: usize) -> Self { + let mut types = SecondaryMap::new(); + types.resize(map_size); + Self { types } + } + + fn is_defined(&self, ix: DatatypeIx) -> bool { + self.types.get(ix).expect("index exists in types").is_some() + } + + fn size_align(&self, ix: DatatypeIx) -> Option<(usize, usize)> { + if let Some(d) = self.types.get(ix).expect("index exists in types") { + Some((d.mem_size, d.mem_align)) + } else { + None + } + } + + fn define(&mut self, ix: DatatypeIx, repr: DatatypeRepr) { + self.types[ix] = Some(repr) + } + + fn build(self) -> PrimaryMap { + let mut datatypes = PrimaryMap::new(); + for dt in self.types.values() { + datatypes.push(dt.clone().expect("all datatypes finalized")); + } + datatypes + } +} + fn align_to(offs: usize, alignment: usize) -> usize { offs + alignment - 1 - ((offs + alignment - 1) % alignment) } diff --git a/lucet-idl/src/validate/package.rs b/lucet-idl/src/validate/package.rs index 0d0e40d24..bed4dc872 100644 --- a/lucet-idl/src/validate/package.rs +++ b/lucet-idl/src/validate/package.rs @@ -149,40 +149,4 @@ mod test { } ); } - - #[test] - fn no_mod_in_mod() { - let err = pkg_("mod foo { mod bar { }}").err().expect("error package"); - assert_eq!( - err, - ValidationError::Syntax { - expected: "type or function declaration", - location: Location { - line: 1, - column: 10 - } - } - ); - pkg_("mod foo { enum whatever {} mod bar { }}") - .err() - .expect("error package"); - } - - #[test] - fn no_top_level_types() { - let err = pkg_("mod foo { } enum bar {}") - .err() - .expect("error package"); - assert_eq!( - err, - ValidationError::Syntax { - expected: "module", - location: Location { - line: 1, - column: 12 - } - } - ); - } - } From 036352d702df01a7c258e8371e3f7eff0452499a Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 26 Aug 2019 18:01:04 -0700 Subject: [PATCH 361/512] lucet-idl-test: split test plan into separate module; fixes --- lucet-idl/lucet-idl-test/src/lib.rs | 16 +- lucet-idl/lucet-idl-test/src/main.rs | 4 +- lucet-idl/lucet-idl-test/src/test_plan.rs | 177 +++++++++++++++++++++ lucet-idl/lucet-idl-test/src/values.rs | 185 ++-------------------- 4 files changed, 202 insertions(+), 180 deletions(-) create mode 100644 lucet-idl/lucet-idl-test/src/test_plan.rs diff --git a/lucet-idl/lucet-idl-test/src/lib.rs b/lucet-idl/lucet-idl-test/src/lib.rs index 24e227f64..28011cf38 100644 --- a/lucet-idl/lucet-idl-test/src/lib.rs +++ b/lucet-idl/lucet-idl-test/src/lib.rs @@ -2,19 +2,21 @@ mod c_guest; mod host; mod rust_guest; pub mod syntax; -pub mod values; +mod test_plan; +mod values; mod workspace; pub use c_guest::CGuestApp; pub use host::HostApp; pub use rust_guest::RustGuestApp; pub use syntax::Spec; -pub use values::ModuleTestPlan; +pub use test_plan::{FuncCallPredicate, ModuleTestPlan}; +pub use values::DatatypeExt; pub use workspace::Workspace; #[cfg(test)] mod tests { - use crate::{CGuestApp, HostApp, RustGuestApp, Spec}; + use crate::{CGuestApp, HostApp, ModuleTestPlan, RustGuestApp, Spec}; use lucet_idl::parse_package; use proptest::prelude::*; @@ -23,8 +25,10 @@ mod tests { fn generate_rust_guest(spec in Spec::strat(20)) { let rendered = spec.render_idl(); let pkg = parse_package(&rendered).unwrap(); + let modules = pkg.modules().collect::>(); + let test_plan = ModuleTestPlan::empty(&modules.get(0).expect("just one module")); let mut rust_guest_app = RustGuestApp::new().expect("create rust guest app"); - let _rust_guest_so = rust_guest_app.build(&pkg).expect("compile rust guest app"); + let _rust_guest_so = rust_guest_app.build(&pkg, &test_plan).expect("compile rust guest app"); } #[test] @@ -39,7 +43,9 @@ mod tests { fn generate_host(spec in Spec::strat(20)) { let rendered = spec.render_idl(); let pkg = parse_package(&rendered).unwrap(); - let mut host_app = HostApp::new(&pkg).expect("create host app"); + let modules = pkg.modules().collect::>(); + let test_plan = ModuleTestPlan::empty(&modules.get(0).expect("just one module")); + let mut host_app = HostApp::new(&pkg, &test_plan).expect("create host app"); let _host_app = host_app.build().expect("compile host app"); } diff --git a/lucet-idl/lucet-idl-test/src/main.rs b/lucet-idl/lucet-idl-test/src/main.rs index c1b3da407..4c8a0e5e0 100644 --- a/lucet-idl/lucet-idl-test/src/main.rs +++ b/lucet-idl/lucet-idl-test/src/main.rs @@ -154,7 +154,7 @@ impl ExeConfig { } fn generate_values(package: &Package) { - use lucet_idl_test::values::*; + use lucet_idl_test::DatatypeExt; for m in package.modules() { for dt in m.datatypes() { @@ -170,7 +170,7 @@ fn generate_values(package: &Package) { } fn generate_calls(package: &Package) { - use lucet_idl_test::values::*; + use lucet_idl_test::FuncCallPredicate; for m in package.modules() { for func in m.functions() { diff --git a/lucet-idl/lucet-idl-test/src/test_plan.rs b/lucet-idl/lucet-idl-test/src/test_plan.rs new file mode 100644 index 000000000..2ea74b3f8 --- /dev/null +++ b/lucet-idl/lucet-idl-test/src/test_plan.rs @@ -0,0 +1,177 @@ +use crate::values::*; +use heck::SnakeCase; +use lucet_idl::{ + pretty_writer::PrettyWriter, BindingDirection, Function, Module, RustFunc, RustName, + RustTypeName, +}; +use proptest::prelude::*; + +#[derive(Debug, Clone)] +pub struct FuncCallPredicate { + func_name: String, + func_call_args: Vec, + func_call_rets: Vec, + func_sig_args: Vec, + func_sig_rets: Vec, + pre: Vec, + post: Vec, +} + +impl FuncCallPredicate { + pub fn strat(func: &Function) -> BoxedStrategy { + let args = func.rust_idiom_args(); + let rets = func.rust_idiom_rets(); + + // Precondition on all arguments + let pre_strat: Vec> = + args.iter().map(|a| BindingVal::arg_strat(a)).collect(); + + // Postcondition on all inout arguments, and all return values + let post_strat: Vec> = args + .iter() + .filter(|a| a.direction() == BindingDirection::InOut) + .map(|a| BindingVal::arg_strat(a)) + .chain(rets.iter().map(|r| BindingVal::ret_strat(r))) + .collect(); + + let func_call_args = args.iter().map(|a| a.arg_value()).collect::>(); + let func_sig_args = args.iter().map(|a| a.arg_declaration()).collect::>(); + + let func_call_rets = rets.iter().map(|r| r.name()).collect::>(); + let func_sig_rets = rets.iter().map(|a| a.ret_declaration()).collect::>(); + + let func_name = func.rust_name(); + (pre_strat, post_strat) + .prop_map(move |(pre, post)| FuncCallPredicate { + func_name: func_name.clone(), + func_call_args: func_call_args.clone(), + func_call_rets: func_call_rets.clone(), + func_sig_args: func_sig_args.clone(), + func_sig_rets: func_sig_rets.clone(), + pre, + post, + }) + .boxed() + } + + pub fn render_caller(&self) -> Vec { + let mut lines: Vec = self + .pre + .iter() + .map(|val| val.render_rust_binding()) + .collect(); + + lines.push(format!( + "let {} = {}({}).unwrap();", + render_tuple(&self.func_call_rets, "_"), + self.func_name, + self.func_call_args.join(",") + )); + lines.append( + &mut self + .post + .iter() + .map(|val| { + format!( + "assert_eq!({}, {});", + val.name, + val.render_rust_constructor() + ) + }) + .collect(), + ); + lines + } + + pub fn render_callee(&self, w: &mut PrettyWriter) { + w.writeln(format!( + "fn {}(&mut self, {}) -> Result<{}, ()> {{", + self.func_name, + self.func_sig_args.join(", "), + render_tuple(&self.func_sig_rets, "()") + )) + .indent(); + // Assert preconditions hold + w.writelns( + &self + .pre + .iter() + .map(|val| format!("assert_eq!({}, {});", val.name, val.render_rust_ref())) + .collect::>(), + ); + // Make postconditions hold + let mut ret_vals = Vec::new(); + for post in self.post.iter() { + match post.variant { + BindingValVariant::Value(ref val) => { + ret_vals.push(val.render_rustval()); + } + BindingValVariant::Ptr(ref val) => { + w.writeln(format!("*{} = {};", post.name, val.render_rustval())); + } + BindingValVariant::Array(ref vals) => { + for (ix, val) in vals.iter().enumerate() { + w.writeln(format!("{}[{}] = {};", post.name, ix, val.render_rustval())); + } + } + } + } + w.writeln(format!("Ok({})", render_tuple(&ret_vals, "()"))); + w.eob().writeln("}"); + } +} + +#[derive(Debug, Clone)] +pub struct ModuleTestPlan { + pub module_name: String, + module_type_name: String, + func_predicates: Vec, +} + +impl ModuleTestPlan { + pub fn empty(module: &Module) -> Self { + let module_name = module.name().to_snake_case(); + let module_type_name = module.rust_type_name(); + ModuleTestPlan { + module_name, + module_type_name, + func_predicates: Vec::new(), + } + } + + pub fn strat(module: &Module) -> BoxedStrategy { + let module_name = module.name().to_snake_case(); + let module_type_name = module.rust_type_name(); + module + .functions() + .map(|f| FuncCallPredicate::strat(&f)) + .collect::>() + .prop_map(move |func_predicates| ModuleTestPlan { + module_name: module_name.clone(), + module_type_name: module_type_name.clone(), + func_predicates, + }) + .boxed() + } + + pub fn render_guest(&self, w: &mut PrettyWriter) { + for func in self.func_predicates.iter() { + w.writelns(&func.render_caller()); + } + } + + pub fn render_host(&self, mut w: &mut PrettyWriter) { + w.writeln(format!("use crate::idl::{}::*;", self.module_name)); + w.writeln("pub struct TestHarness;"); + w.writeln(format!("impl {} for TestHarness {{", self.module_type_name,)) + .indent(); + for func in self.func_predicates.iter() { + func.render_callee(&mut w) + } + w.eob().writeln("}"); + w.writeln(format!( + "pub fn ctx() -> Box {{ Box::new(TestHarness) }}", + self.module_type_name + )); + } +} diff --git a/lucet-idl/lucet-idl-test/src/values.rs b/lucet-idl/lucet-idl-test/src/values.rs index cf384244c..82ab038d3 100644 --- a/lucet-idl/lucet-idl-test/src/values.rs +++ b/lucet-idl/lucet-idl-test/src/values.rs @@ -1,8 +1,7 @@ -use heck::{CamelCase, SnakeCase}; +use heck::CamelCase; use lucet_idl::{ - pretty_writer::PrettyWriter, AliasDatatype, AtomType, BindingDirection, BindingParam, Datatype, - DatatypeVariant, EnumDatatype, Function, Module, RustFunc, RustIdiomArg, RustIdiomRet, - RustName, RustTypeName, StructDatatype, StructMember, + AliasDatatype, AtomType, BindingDirection, BindingParam, Datatype, DatatypeVariant, + EnumDatatype, RustIdiomArg, RustIdiomRet, StructDatatype, StructMember, }; use proptest::prelude::*; @@ -202,9 +201,9 @@ impl<'a> DatatypeExt for Datatype<'a> { #[derive(Debug, Clone, PartialEq)] pub struct BindingVal { - name: String, - mutable: bool, - variant: BindingValVariant, + pub name: String, + pub mutable: bool, + pub variant: BindingValVariant, } #[derive(Debug, Clone, PartialEq)] @@ -215,7 +214,7 @@ pub enum BindingValVariant { } impl BindingVal { - fn arg_strat(arg: &RustIdiomArg) -> BoxedStrategy { + pub fn arg_strat(arg: &RustIdiomArg) -> BoxedStrategy { let mutable = arg.direction() == BindingDirection::InOut; let name = arg.name(); match arg.param() { @@ -247,7 +246,7 @@ impl BindingVal { } } - fn ret_strat(ret: &RustIdiomRet) -> BoxedStrategy { + pub fn ret_strat(ret: &RustIdiomRet) -> BoxedStrategy { let name = ret.name(); // There can only be param or value bindings on returns, // and both are idiomatically values. @@ -261,7 +260,7 @@ impl BindingVal { .boxed() } - fn render_rust_binding(&self) -> String { + pub fn render_rust_binding(&self) -> String { format!( "let {}{} = {};", if self.mutable { "mut " } else { "" }, @@ -270,7 +269,7 @@ impl BindingVal { ) } - fn render_rust_constructor(&self) -> String { + pub fn render_rust_constructor(&self) -> String { match &self.variant { BindingValVariant::Value(v) => v.render_rustval(), BindingValVariant::Ptr(v) => v.render_rustval(), @@ -284,7 +283,7 @@ impl BindingVal { } } - fn render_rust_ref(&self) -> String { + pub fn render_rust_ref(&self) -> String { match &self.variant { BindingValVariant::Value(v) => v.render_rustval(), BindingValVariant::Ptr(v) => format!("&{}", v.render_rustval()), @@ -299,167 +298,7 @@ impl BindingVal { } } -#[derive(Debug, Clone)] -pub struct FuncCallPredicate { - func_name: String, - func_call_args: Vec, - func_call_rets: Vec, - func_sig_args: Vec, - func_sig_rets: Vec, - pre: Vec, - post: Vec, -} - -impl FuncCallPredicate { - pub fn strat(func: &Function) -> BoxedStrategy { - let args = func.rust_idiom_args(); - let rets = func.rust_idiom_rets(); - - // Precondition on all arguments - let pre_strat: Vec> = - args.iter().map(|a| BindingVal::arg_strat(a)).collect(); - - // Postcondition on all inout arguments, and all return values - let post_strat: Vec> = args - .iter() - .filter(|a| a.direction() == BindingDirection::InOut) - .map(|a| BindingVal::arg_strat(a)) - .chain(rets.iter().map(|r| BindingVal::ret_strat(r))) - .collect(); - - let func_call_args = args.iter().map(|a| a.arg_value()).collect::>(); - let func_sig_args = args.iter().map(|a| a.arg_declaration()).collect::>(); - - let func_call_rets = rets.iter().map(|r| r.name()).collect::>(); - let func_sig_rets = rets.iter().map(|a| a.ret_declaration()).collect::>(); - - let func_name = func.rust_name(); - (pre_strat, post_strat) - .prop_map(move |(pre, post)| FuncCallPredicate { - func_name: func_name.clone(), - func_call_args: func_call_args.clone(), - func_call_rets: func_call_rets.clone(), - func_sig_args: func_sig_args.clone(), - func_sig_rets: func_sig_rets.clone(), - pre, - post, - }) - .boxed() - } - - pub fn render_caller(&self) -> Vec { - let mut lines: Vec = self - .pre - .iter() - .map(|val| val.render_rust_binding()) - .collect(); - - lines.push(format!( - "let {} = {}({}).unwrap();", - render_tuple(&self.func_call_rets, "_"), - self.func_name, - self.func_call_args.join(",") - )); - lines.append( - &mut self - .post - .iter() - .map(|val| { - format!( - "assert_eq!({}, {});", - val.name, - val.render_rust_constructor() - ) - }) - .collect(), - ); - lines - } - - pub fn render_callee(&self, w: &mut PrettyWriter) { - w.writeln(format!( - "fn {}(&mut self, {}) -> Result<{}, ()> {{", - self.func_name, - self.func_sig_args.join(", "), - render_tuple(&self.func_sig_rets, "()") - )) - .indent(); - // Assert preconditions hold - w.writelns( - &self - .pre - .iter() - .map(|val| format!("assert_eq!({}, {});", val.name, val.render_rust_ref())) - .collect::>(), - ); - // Make postconditions hold - let mut ret_vals = Vec::new(); - for post in self.post.iter() { - match post.variant { - BindingValVariant::Value(ref val) => { - ret_vals.push(val.render_rustval()); - } - BindingValVariant::Ptr(ref val) => { - w.writeln(format!("*{} = {};", post.name, val.render_rustval())); - } - BindingValVariant::Array(ref vals) => { - for (ix, val) in vals.iter().enumerate() { - w.writeln(format!("{}[{}] = {};", post.name, ix, val.render_rustval())); - } - } - } - } - w.writeln(format!("Ok({})", render_tuple(&ret_vals, "()"))); - w.eob().writeln("}"); - } -} - -#[derive(Debug, Clone)] -pub struct ModuleTestPlan { - pub module_name: String, - module_type_name: String, - func_predicates: Vec, -} - -impl ModuleTestPlan { - pub fn strat(module: &Module) -> BoxedStrategy { - let module_name = module.name().to_snake_case(); - let module_type_name = module.rust_type_name(); - module - .functions() - .map(|f| FuncCallPredicate::strat(&f)) - .collect::>() - .prop_map(move |func_predicates| ModuleTestPlan { - module_name: module_name.clone(), - module_type_name: module_type_name.clone(), - func_predicates, - }) - .boxed() - } - - pub fn render_guest(&self, w: &mut PrettyWriter) { - for func in self.func_predicates.iter() { - w.writelns(&func.render_caller()); - } - } - - pub fn render_host(&self, mut w: &mut PrettyWriter) { - w.writeln(format!("use crate::idl::{}::*;", self.module_name)); - w.writeln("pub struct TestHarness;"); - w.writeln(format!("impl {} for TestHarness {{", self.module_type_name,)) - .indent(); - for func in self.func_predicates.iter() { - func.render_callee(&mut w) - } - w.eob().writeln("}"); - w.writeln(format!( - "pub fn ctx() -> Box {{ Box::new(TestHarness) }}", - self.module_type_name - )); - } -} - -fn render_tuple(vs: &[String], base_case: &str) -> String { +pub fn render_tuple(vs: &[String], base_case: &str) -> String { match vs.len() { 0 => base_case.to_owned(), 1 => vs[0].clone(), From f69152a96667e82415ba46eee93838e8a35b27b0 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 26 Aug 2019 18:47:30 -0700 Subject: [PATCH 362/512] lucet-idl: render rust cast to boolean as != 0 --- lucet-idl/src/rust/cursor.rs | 41 +++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/lucet-idl/src/rust/cursor.rs b/lucet-idl/src/rust/cursor.rs index 31f05fb66..bcfd5779d 100644 --- a/lucet-idl/src/rust/cursor.rs +++ b/lucet-idl/src/rust/cursor.rs @@ -200,12 +200,17 @@ impl<'a> RustIdiomArg<'a> { format!("let {} = {}.as_ptr() as i32;", ptr.rust_name(), self.name()), format!("let {} = {}.len() as i32;", len.rust_name(), self.name()), ], - BindingParam::Value(val) => vec![format!( - "let {} = {} as {};", - val.rust_name(), - self.name(), - val.type_().rust_type_name() - )], + BindingParam::Value(val) => match val.type_().variant() { + DatatypeVariant::Atom(AtomType::Bool) => { + vec![format!("let {} = {} != 0;", val.rust_name(), self.name(),)] + } + _ => vec![format!( + "let {} = {} as {};", + val.rust_name(), + self.name(), + val.type_().rust_type_name() + )], + }, } } @@ -412,12 +417,21 @@ impl<'a> RustIdiomRet<'a> { ptr.rust_name(), self.name(), ), - BindingParam::Value(val) => format!( - "let {value}: {typename} = {arg} as {typename};", - value = val.rust_name(), - typename = val.type_().rust_type_name(), - arg = self.name(), - ), + BindingParam::Value(val) => match val.type_().variant() { + DatatypeVariant::Atom(AtomType::Bool) => format!( + "let {value}: {typename} = {arg} != 0;", + value = val.rust_name(), + typename = val.type_().rust_type_name(), + arg = self.name(), + ), + + _ => format!( + "let {value}: {typename} = {arg} as {typename};", + value = val.rust_name(), + typename = val.type_().rust_type_name(), + arg = self.name(), + ), + }, BindingParam::Slice { .. } => unreachable!(), } } @@ -432,6 +446,9 @@ fn cast_value_to_binding(b: &FuncBinding) -> String { b.type_().rust_type_name(), val.rust_name(), ), + DatatypeVariant::Atom(AtomType::Bool) => { + format!("let {} = {} != 0;", b.rust_name(), val.rust_name(),) + } DatatypeVariant::Atom(_) => format!( "let {} = {} as {};", b.rust_name(), From 8f03eb0de1c2740dc614d5751747d679b378c3c4 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 26 Aug 2019 18:47:45 -0700 Subject: [PATCH 363/512] lucet-idl-test: implement trivial test plan --- lucet-idl/lucet-idl-test/src/lib.rs | 4 +- lucet-idl/lucet-idl-test/src/test_plan.rs | 37 ++++++++- lucet-idl/lucet-idl-test/src/values.rs | 92 ++++++++++++++++++++++- 3 files changed, 125 insertions(+), 8 deletions(-) diff --git a/lucet-idl/lucet-idl-test/src/lib.rs b/lucet-idl/lucet-idl-test/src/lib.rs index 28011cf38..c2a50b71b 100644 --- a/lucet-idl/lucet-idl-test/src/lib.rs +++ b/lucet-idl/lucet-idl-test/src/lib.rs @@ -26,7 +26,7 @@ mod tests { let rendered = spec.render_idl(); let pkg = parse_package(&rendered).unwrap(); let modules = pkg.modules().collect::>(); - let test_plan = ModuleTestPlan::empty(&modules.get(0).expect("just one module")); + let test_plan = ModuleTestPlan::trivial(&modules.get(0).expect("just one module")); let mut rust_guest_app = RustGuestApp::new().expect("create rust guest app"); let _rust_guest_so = rust_guest_app.build(&pkg, &test_plan).expect("compile rust guest app"); } @@ -44,7 +44,7 @@ mod tests { let rendered = spec.render_idl(); let pkg = parse_package(&rendered).unwrap(); let modules = pkg.modules().collect::>(); - let test_plan = ModuleTestPlan::empty(&modules.get(0).expect("just one module")); + let test_plan = ModuleTestPlan::trivial(&modules.get(0).expect("just one module")); let mut host_app = HostApp::new(&pkg, &test_plan).expect("create host app"); let _host_app = host_app.build().expect("compile host app"); } diff --git a/lucet-idl/lucet-idl-test/src/test_plan.rs b/lucet-idl/lucet-idl-test/src/test_plan.rs index 2ea74b3f8..e81a7fb18 100644 --- a/lucet-idl/lucet-idl-test/src/test_plan.rs +++ b/lucet-idl/lucet-idl-test/src/test_plan.rs @@ -54,6 +54,35 @@ impl FuncCallPredicate { .boxed() } + pub fn trivial(func: &Function) -> FuncCallPredicate { + let args = func.rust_idiom_args(); + let rets = func.rust_idiom_rets(); + + let pre = args.iter().map(|a| BindingVal::arg_trivial(a)).collect(); + let post = args + .iter() + .filter(|a| a.direction() == BindingDirection::InOut) + .map(|a| BindingVal::arg_trivial(a)) + .chain(rets.iter().map(|r| BindingVal::ret_trivial(r))) + .collect(); + + let func_call_args = args.iter().map(|a| a.arg_value()).collect::>(); + let func_sig_args = args.iter().map(|a| a.arg_declaration()).collect::>(); + + let func_call_rets = rets.iter().map(|r| r.name()).collect::>(); + let func_sig_rets = rets.iter().map(|a| a.ret_declaration()).collect::>(); + + FuncCallPredicate { + func_name: func.rust_name(), + func_call_args, + func_sig_args, + func_call_rets, + func_sig_rets, + pre, + post, + } + } + pub fn render_caller(&self) -> Vec { let mut lines: Vec = self .pre @@ -129,13 +158,17 @@ pub struct ModuleTestPlan { } impl ModuleTestPlan { - pub fn empty(module: &Module) -> Self { + pub fn trivial(module: &Module) -> Self { let module_name = module.name().to_snake_case(); let module_type_name = module.rust_type_name(); + let func_predicates = module + .functions() + .map(|f| FuncCallPredicate::trivial(&f)) + .collect(); ModuleTestPlan { module_name, module_type_name, - func_predicates: Vec::new(), + func_predicates, } } diff --git a/lucet-idl/lucet-idl-test/src/values.rs b/lucet-idl/lucet-idl-test/src/values.rs index 82ab038d3..27ce780f4 100644 --- a/lucet-idl/lucet-idl-test/src/values.rs +++ b/lucet-idl/lucet-idl-test/src/values.rs @@ -36,6 +36,21 @@ impl AtomVal { AtomType::F64 => any::().prop_map(AtomVal::F64).boxed(), } } + pub fn trivial(atom_type: &AtomType) -> Self { + match atom_type { + AtomType::Bool => AtomVal::Bool(false), + AtomType::U8 => AtomVal::U8(0), + AtomType::U16 => AtomVal::U16(0), + AtomType::U32 => AtomVal::U32(0), + AtomType::U64 => AtomVal::U64(0), + AtomType::I8 => AtomVal::I8(0), + AtomType::I16 => AtomVal::I16(0), + AtomType::I32 => AtomVal::I32(0), + AtomType::I64 => AtomVal::I64(0), + AtomType::F32 => AtomVal::F32(0.0), + AtomType::F64 => AtomVal::F64(0.0), + } + } pub fn render_rustval(&self) -> String { match self { AtomVal::Bool(v) => format!("{}", v), @@ -73,6 +88,20 @@ impl EnumVal { member_name: mem_name.clone(), }) } + pub fn trivial(enum_datatype: &EnumDatatype) -> Self { + let enum_name = enum_datatype.datatype().name().to_owned(); + let member_name = enum_datatype + .variants() + .collect::>() + .get(0) + .expect("at least one variant") + .name() + .to_owned(); + EnumVal { + enum_name, + member_name, + } + } pub fn render_rustval(&self) -> String { format!( "{}::{}", @@ -102,6 +131,17 @@ impl StructVal { }) .boxed() } + pub fn trivial(struct_dt: &StructDatatype) -> Self { + let struct_name = struct_dt.datatype().name().to_owned(); + let members = struct_dt + .members() + .map(|m| StructMemberVal::trivial(&m)) + .collect(); + StructVal { + struct_name, + members, + } + } pub fn render_rustval(&self) -> String { let members = self .members @@ -134,6 +174,11 @@ impl StructMemberVal { }) .boxed() } + pub fn trivial(struct_member: &StructMember) -> Self { + let name = struct_member.name().to_owned(); + let value = Box::new(struct_member.type_().trivial_val()); + StructMemberVal { name, value } + } } #[derive(Debug, Clone, PartialEq)] @@ -154,6 +199,11 @@ impl AliasVal { }) .boxed() } + pub fn trivial(alias_dt: &AliasDatatype) -> Self { + let name = alias_dt.datatype().name().to_owned(); + let value = Box::new(alias_dt.to().trivial_val()); + AliasVal { name, value } + } pub fn render_rustval(&self) -> String { self.value.render_rustval() } @@ -180,23 +230,34 @@ impl DatatypeVal { pub trait DatatypeExt { fn strat(&self) -> BoxedStrategy; + fn trivial_val(&self) -> DatatypeVal; } impl<'a> DatatypeExt for Datatype<'a> { fn strat(&self) -> BoxedStrategy { match self.variant() { - DatatypeVariant::Struct(ref struct_dt) => StructVal::strat(struct_dt) + DatatypeVariant::Struct(struct_dt) => StructVal::strat(&struct_dt) .prop_map(DatatypeVal::Struct) .boxed(), - DatatypeVariant::Enum(ref enum_dt) => { - EnumVal::strat(enum_dt).prop_map(DatatypeVal::Enum).boxed() + DatatypeVariant::Enum(enum_dt) => { + EnumVal::strat(&enum_dt).prop_map(DatatypeVal::Enum).boxed() } - DatatypeVariant::Alias(ref alias_dt) => AliasVal::strat(alias_dt) + DatatypeVariant::Alias(alias_dt) => AliasVal::strat(&alias_dt) .prop_map(DatatypeVal::Alias) .boxed(), DatatypeVariant::Atom(a) => AtomVal::strat(&a).prop_map(DatatypeVal::Atom).boxed(), } } + fn trivial_val(&self) -> DatatypeVal { + match self.variant() { + DatatypeVariant::Struct(struct_dt) => { + DatatypeVal::Struct(StructVal::trivial(&struct_dt)) + } + DatatypeVariant::Enum(enum_dt) => DatatypeVal::Enum(EnumVal::trivial(&enum_dt)), + DatatypeVariant::Alias(alias_dt) => DatatypeVal::Alias(AliasVal::trivial(&alias_dt)), + DatatypeVariant::Atom(atom_dt) => DatatypeVal::Atom(AtomVal::trivial(&atom_dt)), + } + } } #[derive(Debug, Clone, PartialEq)] @@ -246,6 +307,20 @@ impl BindingVal { } } + pub fn arg_trivial(arg: &RustIdiomArg) -> Self { + let name = arg.name(); + let mutable = arg.direction() == BindingDirection::InOut; + let trivial_val = arg.type_().trivial_val(); + BindingVal { + name, + mutable, + variant: match arg.param() { + BindingParam::Value(_) => BindingValVariant::Value(trivial_val), + BindingParam::Ptr(_) => BindingValVariant::Ptr(trivial_val), + BindingParam::Slice(_, _) => BindingValVariant::Array(vec![trivial_val]), + }, + } + } pub fn ret_strat(ret: &RustIdiomRet) -> BoxedStrategy { let name = ret.name(); // There can only be param or value bindings on returns, @@ -259,6 +334,15 @@ impl BindingVal { }) .boxed() } + pub fn ret_trivial(ret: &RustIdiomRet) -> Self { + let name = ret.name(); + let trivial_val = ret.type_().trivial_val(); + BindingVal { + name, + mutable: false, + variant: BindingValVariant::Value(trivial_val), + } + } pub fn render_rust_binding(&self) -> String { format!( From 624ae0a2e643cb195f004494150661a27db27e69 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 26 Aug 2019 18:52:32 -0700 Subject: [PATCH 364/512] lucet-idl: func validator review comments --- lucet-idl/src/validate/function.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lucet-idl/src/validate/function.rs b/lucet-idl/src/validate/function.rs index 1ccd50dad..74d200f82 100644 --- a/lucet-idl/src/validate/function.rs +++ b/lucet-idl/src/validate/function.rs @@ -65,13 +65,13 @@ impl<'a> FunctionModuleBuilder<'a> { } struct FuncValidator<'a> { - // arg name to declaration location and argument position + // arg/return name to declaration location and argument position param_names: HashMap, // Arg positions index into this vector: args: PrimaryMap, // Ret positions index into this vector: rets: PrimaryMap, - // binding name to + // binding name to declaration location and binding position binding_names: HashMap<&'a str, (Location, BindingIx)>, // param position to binding syntax bindings: PrimaryMap, @@ -234,7 +234,7 @@ impl<'a> FuncValidator<'a> { // 2. resolve type let type_ = AtomType::from(arg.type_).datatype_id(); - // 3. no need to validate ref- we can construct it ourselves + // 3. construct the binding from-value for this position let from = BindingFromRepr::Value(position); // 4. direction depends on whether param is an arg or ret @@ -295,7 +295,7 @@ impl<'a> FuncValidator<'a> { ) -> Result { match &binding.from { // A pointer to a name is accepted: - BindingRefSyntax::Ptr(bref) => match bref.deref() { + BindingRefSyntax::Ptr(bref) => match **bref { BindingRefSyntax::Name(ref name) => { let (position, funcarg) = self.validate_binding_arg_mapping(name, binding.location)?; From 5a886dd4e98724a381287ef1fe5411e097a91e00 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 27 Aug 2019 10:24:00 -0700 Subject: [PATCH 365/512] lucet-idl: proptest found bug in parser :) --- lucet-idl/lucet-idl-test/src/lib.rs | 7 +++++++ lucet-idl/src/parser.rs | 5 ++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lucet-idl/lucet-idl-test/src/lib.rs b/lucet-idl/lucet-idl-test/src/lib.rs index c2a50b71b..3f4afea3d 100644 --- a/lucet-idl/lucet-idl-test/src/lib.rs +++ b/lucet-idl/lucet-idl-test/src/lib.rs @@ -21,6 +21,13 @@ mod tests { use proptest::prelude::*; proptest! { + #[test] + fn generate_idl(spec in Spec::strat(4)) { + let rendered = spec.render_idl(); + println!("{}", rendered); + let _ = parse_package(&rendered).unwrap(); + } + #[test] fn generate_rust_guest(spec in Spec::strat(20)) { let rendered = spec.render_idl(); diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index 29fee9655..07d4948b1 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -349,7 +349,10 @@ impl<'a> Parser<'a> { let mut bindings = Vec::new(); loop { match self.token() { - Some(Token::Semi) => break, + Some(Token::Semi) => { + self.consume(); + break; + } Some(Token::Word(name)) => { let location = self.location; self.consume(); From 9bf0ee63ed1c37f7b28dd08b8a566c4685975c93 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 27 Aug 2019 11:04:29 -0700 Subject: [PATCH 366/512] bump cargo.lock --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index c17c80511..dbb3ae170 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -801,7 +801,7 @@ name = "lucet-idl" version = "0.1.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-entity 0.37.0", + "cranelift-entity 0.40.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", From 13f4c6d0a9452f1485f2c8ac2109763f443a332a Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Wed, 4 Sep 2019 21:41:53 +0200 Subject: [PATCH 367/512] Update the bincode crate to version 1.1 (#274) Using an old version prevents applications using the lucet crate from also using bincode 1.1. --- Cargo.lock | 165 +++++++++--------- lucet-module/Cargo.toml | 2 +- .../lucet-runtime-internals/Cargo.toml | 2 +- lucetc/Cargo.toml | 2 +- 4 files changed, 86 insertions(+), 85 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dbb3ae170..ecc56325c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,7 +18,7 @@ name = "ansi_term" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -40,7 +40,7 @@ version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -50,7 +50,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.35" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", @@ -64,7 +64,7 @@ name = "backtrace-sys" version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -91,9 +91,10 @@ dependencies = [ [[package]] name = "bincode" -version = "1.0.1" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -115,7 +116,7 @@ dependencies = [ "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -163,7 +164,7 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -198,7 +199,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cc" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -258,10 +259,10 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.41" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -393,8 +394,8 @@ dependencies = [ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", @@ -414,7 +415,7 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.6.3" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -465,7 +466,7 @@ name = "csv" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bstr 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -501,7 +502,7 @@ dependencies = [ "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -512,7 +513,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -534,7 +535,7 @@ dependencies = [ "indexmap 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "string-interner 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "string-interner 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -543,7 +544,7 @@ name = "failure" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.36 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -585,7 +586,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -614,7 +615,7 @@ dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -757,8 +758,8 @@ name = "libloading" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -792,7 +793,7 @@ dependencies = [ "lucetc 0.1.1", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -845,7 +846,7 @@ dependencies = [ name = "lucet-module" version = "0.1.1" dependencies = [ - "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-codegen 0.40.0", "cranelift-entity 0.40.0", @@ -863,7 +864,7 @@ name = "lucet-runtime" version = "0.1.1" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", @@ -875,7 +876,7 @@ dependencies = [ "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -883,10 +884,10 @@ dependencies = [ name = "lucet-runtime-internals" version = "0.1.1" dependencies = [ - "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -904,7 +905,7 @@ dependencies = [ name = "lucet-runtime-tests" version = "0.1.1" dependencies = [ - "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", @@ -965,8 +966,8 @@ dependencies = [ "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -987,7 +988,7 @@ name = "lucetc" version = "0.1.1" dependencies = [ "bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-codegen 0.40.0", @@ -1046,7 +1047,7 @@ name = "miniz-sys" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1064,7 +1065,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1203,7 +1204,7 @@ name = "precision" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1223,7 +1224,7 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1251,7 +1252,7 @@ dependencies = [ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "rusty-fork 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1274,7 +1275,7 @@ name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1286,7 +1287,7 @@ dependencies = [ "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1304,7 +1305,7 @@ dependencies = [ "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1315,7 +1316,7 @@ dependencies = [ "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1334,7 +1335,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1352,7 +1353,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rand_core" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1371,7 +1372,7 @@ name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1389,7 +1390,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1402,7 +1403,7 @@ dependencies = [ "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1437,26 +1438,26 @@ version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon-core" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1478,12 +1479,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "regex" -version = "1.2.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1497,7 +1498,7 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.11" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1505,7 +1506,7 @@ name = "remove_dir_all" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1627,7 +1628,7 @@ name = "serde_derive" version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1681,7 +1682,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "string-interner" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1732,7 +1733,7 @@ name = "syn" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1768,7 +1769,7 @@ dependencies = [ "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1785,7 +1786,7 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1882,8 +1883,8 @@ name = "wabt-sys" version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "cmake 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1901,7 +1902,7 @@ version = "2.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1942,7 +1943,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1964,7 +1965,7 @@ name = "winapi-util" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1977,7 +1978,7 @@ name = "wincolor" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1989,7 +1990,7 @@ dependencies = [ "cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2005,12 +2006,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" "checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" -"checksum backtrace 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "1371048253fa3bac6704bfd6bbfc922ee9bdcee8881330d40f308b81cc5adc55" +"checksum backtrace 0.3.36 (registry+https://github.com/rust-lang/crates.io-index)" = "e43b13e6ad6177777669f60f642e26307b44676392fae3610676edb54073681d" "checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum bencher 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdb4953a096c551ce9ace855a604d702e6e62d77fac690575ae347571717f5" "checksum bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "505e45beaf0a1462f5548fe885edf2d83e62022b2ce8b10fef0f7686b48c9266" -"checksum bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f2fb9e29e72fd6bc12071533d5dc7664cb01480c59406f656d7ac25c7bd8ff7" +"checksum bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9f04a5e50dc80b3d5d35320889053637d15011aed5e66b66b37ae798c65da6f7" "checksum bindgen 0.47.3 (registry+https://github.com/rust-lang/crates.io-index)" = "df683a55b54b41d5ea8ebfaebb5aa7e6b84e3f3006a78f010dadc9ca88469260" "checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80" "checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb" @@ -2018,25 +2019,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" "checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" -"checksum bstr 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94cdf78eb7e94c566c1f5dbe2abf8fc70a548fc902942a48c4b3a98b48ca9ade" +"checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245" "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" -"checksum cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "b548a4ee81fccb95919d4e22cfea83c7693ebfd78f0495493178db20b3139da7" +"checksum cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "8dae9c4b8fedcae85592ba623c4fd08cfdab3e3b72d6df780c6ead964a69bfff" "checksum cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7fa24eb00d5ffab90eaeaf1092ac85c04c64aaf358ea6f84505b8116d24c6af" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c" "checksum clang-sys 0.26.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ef0c1bcf2e99c649104bd7a7012d8f8802684400e03db0ec0af48583c6fa0e4" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum cmake 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "3c84c596dcf125d6781f58e3f4254677ec2a6d8aa56e8501ac277100990b3229" +"checksum cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62" "checksum colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cdb90b60f2927f8d76139c72dbde7e10c3a2bc47c8594c9c7a66529f2687c03" "checksum core_affinity 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6d162c6e463c31dbf78fefa99d042156c1c74d404e299cfe3df2923cb857595b" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0363053954f3e679645fc443321ca128b7b950a6fe288cf5f9335cc22ee58394" "checksum criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76f9212ddf2f4a9eb2d401635190600656a1f88a932ef53d06e7fa4c7e02fb8e" -"checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" +"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" "checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" @@ -2104,7 +2105,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum precision 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "83f0b3de90e9edd6382604f4f28509ce25272deb065b94045fc47abcde567d55" "checksum printtable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "69967dae4cac71681361899d9905d3d2985fc989d7afb32a8dff3aed5461ecdf" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c5c2380ae88876faae57698be9e9775e3544decad214599c3a6266cca6ac802" +"checksum proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "175a40b9cf564ce9bf050654633dbf339978706b8ead1a907bb970b63185dd95" "checksum progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b820305721858696053a7fd0215cfeeee16ecaaf96b7a209945428e02f1c44" "checksum proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf147e022eacf0c8a054ab864914a7602618adba841d800a9a9868a5237a529f" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" @@ -2117,7 +2118,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" -"checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" +"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" @@ -2127,13 +2128,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03b418169fb9c46533f326efd6eed2576699c44ca92d3052a066214a8d828929" "checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d" -"checksum rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4b0186e22767d5b9738a05eab7c6ac90b15db17e5b5f9bd87976dd7d89a10a4" -"checksum rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe0df8435ac0c397d467b6cad6d25543d06e8a019ef3f6af3c384597515bd2" +"checksum rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83a27732a533a1be0a0035a111fe76db89ad312f6f0347004c220c57f209a123" +"checksum rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" -"checksum regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88c3d9193984285d544df4a30c23a4e62ead42edf70a4452ceb76dac1ce05c26" +"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" "checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9" -"checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f" +"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" "checksum rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2089e4031214d129e201f8c3c8c2fe97cd7322478a0d1cdf78e7029b0042efdb" "checksum rpassword 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34fa7bcae7fca3c8471e8417088bbc3ad9af8066b0ecf4f3c0d98a0d772716e" @@ -2154,7 +2155,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" "checksum siphasher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9913c75df657d84a03fa689c016b0bb2863ff0b497b26a8d6e9703f8d5df03a8" -"checksum string-interner 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "abb38a0d8fe673c40b10b6b75abcb076a958cc10fb894f14993d9737c4c87000" +"checksum string-interner 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "97c92fe95243b91f6c60d2a53bf33231fa43e6e239c1ee590f59fa8724938f3e" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" "checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" @@ -2186,7 +2187,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wasmparser 0.36.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a014c25b9ddb665ad952d4260413931948a0b279b3504307870a5b73051526c" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" +"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" diff --git a/lucet-module/Cargo.toml b/lucet-module/Cargo.toml index da0c76e82..e67e0b505 100644 --- a/lucet-module/Cargo.toml +++ b/lucet-module/Cargo.toml @@ -18,7 +18,7 @@ cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.40.0 failure = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -bincode = "~1.0.1" +bincode = "1.1.4" num-derive = "0.2" num-traits = "0.2" minisign = "0.5.11" diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index 0962ee9e1..4d7e0b7c2 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -13,7 +13,7 @@ edition = "2018" lucet-module = { path = "../../lucet-module", version = "0.1.1" } bitflags = "1.0" -bincode = "~1.0.1" +bincode = "1.1.4" byteorder = "1.3" failure = "0.1" lazy_static = "1.1" diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index 32466e1e2..214ba23f0 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -17,7 +17,7 @@ name = "lucetc" path = "src/main.rs" [dependencies] -bincode = "~1.0.1" +bincode = "1.1.4" cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.40.0" } cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.40.0" } cranelift-native = { path = "../cranelift/cranelift-native", version = "0.40.0" } From 1b9f0ecc28e87deb6e068a7ccfdf503b60f135be Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 4 Sep 2019 12:21:38 -0700 Subject: [PATCH 368/512] delete faerie submodule --- .gitmodules | 3 --- Cargo.toml | 3 --- faerie | 1 - 3 files changed, 7 deletions(-) delete mode 160000 faerie diff --git a/.gitmodules b/.gitmodules index f81bc9a8b..bb7be0756 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "cranelift"] path = cranelift url = https://github.com/cranestation/cranelift -[submodule "faerie"] - path = faerie - url = https://github.com/m4b/faerie [submodule "lucet-spectest/spec"] path = lucet-spectest/spec url = https://github.com/webassembly/spec diff --git a/Cargo.toml b/Cargo.toml index f3502f0e3..ae9231929 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,3 @@ exclude = ["cranelift"] [profile.test] rpath = true - -[replace] -"faerie:0.10.1" = { path = "faerie" } diff --git a/faerie b/faerie deleted file mode 160000 index 926b3765b..000000000 --- a/faerie +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 926b3765b8f3751fb17f26321626b41b30b894e2 From 6fd30669ea7774247ec68d56c64429d08c2fa152 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 5 Sep 2019 10:29:28 -0700 Subject: [PATCH 369/512] upgrade to faerie 0.11, and latest cranelift, target-lexicon, wasmparser etc --- Cargo.lock | 138 ++++++++++++++++++++-------------------- cranelift | 2 +- lucet-module/Cargo.toml | 4 +- lucetc/Cargo.toml | 20 +++--- 4 files changed, 82 insertions(+), 82 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ecc56325c..c725de40d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -50,7 +50,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", @@ -64,7 +64,7 @@ name = "backtrace-sys" version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -199,7 +199,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cc" -version = "1.0.41" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -262,7 +262,7 @@ name = "cmake" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -287,86 +287,86 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.40.0" +version = "0.41.0" dependencies = [ - "cranelift-entity 0.40.0", + "cranelift-entity 0.41.0", ] [[package]] name = "cranelift-codegen" -version = "0.40.0" +version = "0.41.0" dependencies = [ - "cranelift-bforest 0.40.0", - "cranelift-codegen-meta 0.40.0", - "cranelift-entity 0.40.0", + "cranelift-bforest 0.41.0", + "cranelift-codegen-meta 0.41.0", + "cranelift-entity 0.41.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-codegen-meta" -version = "0.40.0" +version = "0.41.0" dependencies = [ - "cranelift-entity 0.40.0", + "cranelift-entity 0.41.0", ] [[package]] name = "cranelift-entity" -version = "0.40.0" +version = "0.41.0" [[package]] name = "cranelift-faerie" -version = "0.40.0" +version = "0.41.0" dependencies = [ - "cranelift-codegen 0.40.0", - "cranelift-module 0.40.0", - "faerie 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen 0.41.0", + "cranelift-module 0.41.0", + "faerie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-frontend" -version = "0.40.0" +version = "0.41.0" dependencies = [ - "cranelift-codegen 0.40.0", + "cranelift-codegen 0.41.0", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-module" -version = "0.40.0" +version = "0.41.0" dependencies = [ - "cranelift-codegen 0.40.0", - "cranelift-entity 0.40.0", + "cranelift-codegen 0.41.0", + "cranelift-entity 0.41.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-native" -version = "0.40.0" +version = "0.41.0" dependencies = [ - "cranelift-codegen 0.40.0", + "cranelift-codegen 0.41.0", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-wasm" -version = "0.40.0" +version = "0.41.0" dependencies = [ - "cranelift-codegen 0.40.0", - "cranelift-entity 0.40.0", - "cranelift-frontend 0.40.0", + "cranelift-codegen 0.41.0", + "cranelift-entity 0.41.0", + "cranelift-frontend 0.41.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.36.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.37.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -527,16 +527,16 @@ dependencies = [ [[package]] name = "faerie" -version = "0.10.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "goblin 0.0.23 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "string-interner 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "string-interner 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -544,7 +544,7 @@ name = "failure" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.36 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -758,7 +758,7 @@ name = "libloading" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -802,7 +802,7 @@ name = "lucet-idl" version = "0.1.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-entity 0.40.0", + "cranelift-entity 0.41.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", @@ -848,8 +848,8 @@ version = "0.1.1" dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.40.0", - "cranelift-entity 0.40.0", + "cranelift-codegen 0.41.0", + "cranelift-entity 0.41.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -864,7 +864,7 @@ name = "lucet-runtime" version = "0.1.1" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", @@ -887,7 +887,7 @@ dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -905,7 +905,7 @@ dependencies = [ name = "lucet-runtime-tests" version = "0.1.1" dependencies = [ - "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", @@ -991,15 +991,15 @@ dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.40.0", - "cranelift-entity 0.40.0", - "cranelift-faerie 0.40.0", - "cranelift-frontend 0.40.0", - "cranelift-module 0.40.0", - "cranelift-native 0.40.0", - "cranelift-wasm 0.40.0", + "cranelift-codegen 0.41.0", + "cranelift-entity 0.41.0", + "cranelift-faerie 0.41.0", + "cranelift-frontend 0.41.0", + "cranelift-module 0.41.0", + "cranelift-native 0.41.0", + "cranelift-wasm 0.41.0", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "faerie 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "faerie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1008,11 +1008,11 @@ dependencies = [ "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "wasmonkey 0.1.8", - "wasmparser 0.36.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.37.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1047,7 +1047,7 @@ name = "miniz-sys" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1065,7 +1065,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1204,7 +1204,7 @@ name = "precision" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1438,7 +1438,7 @@ version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1682,7 +1682,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "string-interner" -version = "0.6.4" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1751,7 +1751,7 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.4.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1883,7 +1883,7 @@ name = "wabt-sys" version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1924,7 +1924,7 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.36.0" +version = "0.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2006,7 +2006,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" "checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" -"checksum backtrace 0.3.36 (registry+https://github.com/rust-lang/crates.io-index)" = "e43b13e6ad6177777669f60f642e26307b44676392fae3610676edb54073681d" +"checksum backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)" = "5180c5a20655b14a819b652fd2378fa5f1697b6c9ddad3e695c2f9cedf6df4e2" "checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum bencher 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdb4953a096c551ce9ace855a604d702e6e62d77fac690575ae347571717f5" @@ -2024,7 +2024,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" -"checksum cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "8dae9c4b8fedcae85592ba623c4fd08cfdab3e3b72d6df780c6ead964a69bfff" +"checksum cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)" = "a61c7bce55cd2fae6ec8cb935ebd76256c2959a1f95790f6118a441c2cd5b406" "checksum cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7fa24eb00d5ffab90eaeaf1092ac85c04c64aaf358ea6f84505b8116d24c6af" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c" @@ -2049,7 +2049,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" "checksum errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2a071601ed01b988f896ab14b95e67335d1eeb50190932a1320f7fe3cadc84e" "checksum errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067" -"checksum faerie 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1d2467155f3071b96447d53af110805cadbe9162f5be6c300792fb76c0e54051" +"checksum faerie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "875d78b92b2a4d9e1e2c7eeccfa30a327d2ee6434db3beb8fd6fd92f41898bc4" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" @@ -2155,7 +2155,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" "checksum siphasher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9913c75df657d84a03fa689c016b0bb2863ff0b497b26a8d6e9703f8d5df03a8" -"checksum string-interner 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "97c92fe95243b91f6c60d2a53bf33231fa43e6e239c1ee590f59fa8724938f3e" +"checksum string-interner 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd710eadff449a1531351b0e43eb81ea404336fa2f56c777427ab0e32a4cf183" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" "checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" @@ -2163,7 +2163,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" -"checksum target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b0ab4982b8945c35cc1c46a83a9094c414f6828a099ce5dcaa8ee2b04642dcb" +"checksum target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7975cb2c6f37d77b190bc5004a2bb015971464756fde9514651a525ada2a741a" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" "checksum terminal_size 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "023345d35850b69849741bd9a5432aa35290e3d8eb76af8717026f270d1cf133" @@ -2184,7 +2184,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a6265b25719e82598d104b3717375e37661d41753e2c84cde3f51050c7ed7e3c" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" -"checksum wasmparser 0.36.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a014c25b9ddb665ad952d4260413931948a0b279b3504307870a5b73051526c" +"checksum wasmparser 0.37.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7329e663dfa399d8ad1a31a9358fc777140cd741cea56d154abbc4c9f7edb137" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" diff --git a/cranelift b/cranelift index 5534fd2c2..6850d8e60 160000 --- a/cranelift +++ b/cranelift @@ -1 +1 @@ -Subproject commit 5534fd2c2f411dcdb981f992239fc0e96790312b +Subproject commit 6850d8e60daf128633366b8c98461b0fb1972581 diff --git a/lucet-module/Cargo.toml b/lucet-module/Cargo.toml index e67e0b505..54484a3ad 100644 --- a/lucet-module/Cargo.toml +++ b/lucet-module/Cargo.toml @@ -10,11 +10,11 @@ authors = ["Lucet team "] edition = "2018" [dependencies] -cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.40.0" } +cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.41.0" } # We only depend on the types in codegen used inside ir::Signature. TODO: make # a lucet-module version of those types, and make lucetc responsible for translating # from the cranelift-codegen::ir::Signature to a lucet-module::Signature -cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.40.0" } +cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.41.0" } failure = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index 214ba23f0..fd934ce6b 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -18,20 +18,20 @@ path = "src/main.rs" [dependencies] bincode = "1.1.4" -cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.40.0" } -cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.40.0" } -cranelift-native = { path = "../cranelift/cranelift-native", version = "0.40.0" } -cranelift-frontend = { path = "../cranelift/cranelift-frontend", version = "0.40.0" } -cranelift-module = { path = "../cranelift/cranelift-module", version = "0.40.0" } -cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.40.0" } -cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.40.0" } -target-lexicon = "0.4.0" +cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.41.0" } +cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.41.0" } +cranelift-native = { path = "../cranelift/cranelift-native", version = "0.41.0" } +cranelift-frontend = { path = "../cranelift/cranelift-frontend", version = "0.41.0" } +cranelift-module = { path = "../cranelift/cranelift-module", version = "0.41.0" } +cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.41.0" } +cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.41.0" } +target-lexicon = "0.8.0" lucet-module = { path = "../lucet-module", version = "0.1.1" } -wasmparser = "0.36.0" +wasmparser = "0.37.0" clap="2.32" log = "0.4" env_logger = "0.6" -faerie = "0.10.0" +faerie = "0.11.0" goblin = "0.0.22" failure = "0.1" byteorder = "1.2" From 043ad6f512c1febe9b00258ec5f61950d3c05ff9 Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Thu, 5 Sep 2019 15:44:53 -0700 Subject: [PATCH 370/512] cargo install with debug to avoid full release build times --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index e44be13fb..91f832727 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,7 +35,7 @@ ENV PATH=/root/.cargo/bin:$PATH RUN rustup component add rustfmt --toolchain 1.36.0-x86_64-unknown-linux-gnu RUN rustup target add wasm32-wasi -RUN cargo install cargo-audit cargo-watch rsign2 +RUN cargo install --debug cargo-audit cargo-watch rsign2 RUN curl -sS -L -O https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-6/wasi-sdk_6.0_amd64.deb \ && dpkg -i wasi-sdk_6.0_amd64.deb && rm -f wasi-sdk_6.0_amd64.deb From 0747b73ff10a2af0c284dd92b8151f07b86ce53b Mon Sep 17 00:00:00 2001 From: "shravanrn@gmail.com" Date: Mon, 9 Sep 2019 14:10:44 -0700 Subject: [PATCH 371/512] Fixes #288 - Remove cranelift-codegen from the dependencies of the lucet-runtime components such as lucet-module --- Cargo.lock | 1 - lucet-module/Cargo.toml | 4 -- lucet-module/src/types.rs | 110 -------------------------------------- lucetc/src/decls.rs | 4 +- lucetc/src/lib.rs | 1 + lucetc/src/types.rs | 103 +++++++++++++++++++++++++++++++++++ 6 files changed, 106 insertions(+), 117 deletions(-) create mode 100644 lucetc/src/types.rs diff --git a/Cargo.lock b/Cargo.lock index c725de40d..b7303214d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -848,7 +848,6 @@ version = "0.1.1" dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.41.0", "cranelift-entity 0.41.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/lucet-module/Cargo.toml b/lucet-module/Cargo.toml index 54484a3ad..16078ab0b 100644 --- a/lucet-module/Cargo.toml +++ b/lucet-module/Cargo.toml @@ -11,10 +11,6 @@ edition = "2018" [dependencies] cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.41.0" } -# We only depend on the types in codegen used inside ir::Signature. TODO: make -# a lucet-module version of those types, and make lucetc responsible for translating -# from the cranelift-codegen::ir::Signature to a lucet-module::Signature -cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.41.0" } failure = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/lucet-module/src/types.rs b/lucet-module/src/types.rs index 2b5c02e51..e2f2fe681 100644 --- a/lucet-module/src/types.rs +++ b/lucet-module/src/types.rs @@ -1,6 +1,4 @@ -use cranelift_codegen::ir; use serde::{Deserialize, Serialize}; -use std::convert::TryFrom; use std::fmt::{Display, Formatter}; #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] @@ -22,46 +20,6 @@ impl Display for ValueType { } } -#[derive(Debug)] -pub enum ValueError { - Unrepresentable, - InvalidVMContext, -} - -impl TryFrom<&ir::AbiParam> for ValueType { - type Error = ValueError; - - fn try_from(value: &ir::AbiParam) -> Result { - match value { - ir::AbiParam { - value_type: cranelift_ty, - purpose: ir::ArgumentPurpose::Normal, - extension: ir::ArgumentExtension::None, - location: ir::ArgumentLoc::Unassigned, - } => { - let size = cranelift_ty.bits(); - - if cranelift_ty.is_int() { - match size { - 32 => Ok(ValueType::I32), - 64 => Ok(ValueType::I64), - _ => Err(ValueError::Unrepresentable), - } - } else if cranelift_ty.is_float() { - match size { - 32 => Ok(ValueType::F32), - 64 => Ok(ValueType::F64), - _ => Err(ValueError::Unrepresentable), - } - } else { - Err(ValueError::Unrepresentable) - } - } - _ => Err(ValueError::Unrepresentable), - } - } -} - /// A signature for a function in a wasm module. /// /// Note that this does not explicitly name VMContext as a parameter! It is assumed that all wasm @@ -112,71 +70,3 @@ macro_rules! lucet_signature { } }; } - -#[derive(Debug)] -pub enum SignatureError { - BadElement(ir::AbiParam, ValueError), - BadSignature, -} - -impl TryFrom<&ir::Signature> for Signature { - type Error = SignatureError; - - fn try_from(value: &ir::Signature) -> Result { - let mut params: Vec = Vec::new(); - - let mut param_iter = value.params.iter(); - - // Enforce that the first parameter is VMContext, as Signature assumes. - // Even functions declared no-arg take VMContext in reality. - if let Some(param) = param_iter.next() { - match ¶m { - ir::AbiParam { - value_type: value, - purpose: ir::ArgumentPurpose::VMContext, - extension: ir::ArgumentExtension::None, - location: ir::ArgumentLoc::Unassigned, - } => { - if value.is_int() && value.bits() == 64 { - // this is VMContext, so we can move on. - } else { - return Err(SignatureError::BadElement( - param.to_owned(), - ValueError::InvalidVMContext, - )); - } - } - _ => { - return Err(SignatureError::BadElement( - param.to_owned(), - ValueError::InvalidVMContext, - )); - } - } - } else { - return Err(SignatureError::BadSignature); - } - - for param in param_iter { - let value_ty = ValueType::try_from(param) - .map_err(|e| SignatureError::BadElement(param.clone(), e))?; - - params.push(value_ty); - } - - let ret_ty: Option = match value.returns.as_slice() { - &[] => None, - &[ref ret_ty] => { - let value_ty = ValueType::try_from(ret_ty) - .map_err(|e| SignatureError::BadElement(ret_ty.clone(), e))?; - - Some(value_ty) - } - _ => { - return Err(SignatureError::BadSignature); - } - }; - - Ok(Signature { params, ret_ty }) - } -} diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index 9240271ba..b30d9a7b2 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -5,6 +5,7 @@ use crate::module::{ModuleInfo, UniqueFuncIndex}; use crate::name::Name; use crate::runtime::{Runtime, RuntimeFunc}; use crate::table::TABLE_SYM; +use crate::types::to_lucet_signature; use cranelift_codegen::entity::{EntityRef, PrimaryMap}; use cranelift_codegen::ir; use cranelift_codegen::isa::TargetFrontendConfig; @@ -21,7 +22,6 @@ use lucet_module::{ ModuleData, Signature as LucetSignature, UniqueSignatureIndex, }; use std::collections::HashMap; -use std::convert::TryFrom; #[derive(Debug)] pub struct FunctionDecl<'a> { @@ -530,7 +530,7 @@ impl<'a> ModuleDecls<'a> { .signatures .values() .map(|sig| { - LucetSignature::try_from(sig) + to_lucet_signature(sig) .map_err(|e| format_err!("error converting cranelift sig to wasm sig: {:?}", e)) .context(LucetcErrorKind::TranslatingModule) }) diff --git a/lucetc/src/lib.rs b/lucetc/src/lib.rs index d11a095a2..10b48b871 100644 --- a/lucetc/src/lib.rs +++ b/lucetc/src/lib.rs @@ -18,6 +18,7 @@ mod sparsedata; mod stack_probe; mod table; mod traps; +mod types; use crate::load::read_bytes; pub use crate::{ diff --git a/lucetc/src/types.rs b/lucetc/src/types.rs new file mode 100644 index 000000000..cb2023a0a --- /dev/null +++ b/lucetc/src/types.rs @@ -0,0 +1,103 @@ +use cranelift_codegen::ir; +use lucet_module::Signature; +use lucet_module::ValueType; + +#[derive(Debug)] +pub enum ValueError { + Unrepresentable, + InvalidVMContext, +} + +fn to_lucet_value(value: &ir::AbiParam) -> Result { + match value { + ir::AbiParam { + value_type: cranelift_ty, + purpose: ir::ArgumentPurpose::Normal, + extension: ir::ArgumentExtension::None, + location: ir::ArgumentLoc::Unassigned, + } => { + let size = cranelift_ty.bits(); + + if cranelift_ty.is_int() { + match size { + 32 => Ok(ValueType::I32), + 64 => Ok(ValueType::I64), + _ => Err(ValueError::Unrepresentable), + } + } else if cranelift_ty.is_float() { + match size { + 32 => Ok(ValueType::F32), + 64 => Ok(ValueType::F64), + _ => Err(ValueError::Unrepresentable), + } + } else { + Err(ValueError::Unrepresentable) + } + } + _ => Err(ValueError::Unrepresentable), + } +} + +#[derive(Debug)] +pub enum SignatureError { + BadElement(ir::AbiParam, ValueError), + BadSignature, +} + +pub fn to_lucet_signature(value: &ir::Signature) -> Result { + let mut params: Vec = Vec::new(); + + let mut param_iter = value.params.iter(); + + // Enforce that the first parameter is VMContext, as Signature assumes. + // Even functions declared no-arg take VMContext in reality. + if let Some(param) = param_iter.next() { + match ¶m { + ir::AbiParam { + value_type: value, + purpose: ir::ArgumentPurpose::VMContext, + extension: ir::ArgumentExtension::None, + location: ir::ArgumentLoc::Unassigned, + } => { + if value.is_int() && value.bits() == 64 { + // this is VMContext, so we can move on. + } else { + return Err(SignatureError::BadElement( + param.to_owned(), + ValueError::InvalidVMContext, + )); + } + } + _ => { + return Err(SignatureError::BadElement( + param.to_owned(), + ValueError::InvalidVMContext, + )); + } + } + } else { + return Err(SignatureError::BadSignature); + } + + for param in param_iter { + let value_ty = + to_lucet_value(param).map_err(|e| SignatureError::BadElement(param.clone(), e))?; + + params.push(value_ty); + } + + let ret_ty: Option = match value.returns.as_slice() { + &[] => None, + &[ref ret_ty] => { + let value_ty = to_lucet_value(ret_ty) + .map_err(|e| SignatureError::BadElement(ret_ty.clone(), e))?; + + Some(value_ty) + } + _ => { + return Err(SignatureError::BadSignature); + } + }; + + Ok(Signature { params, ret_ty }) +} From 17ba0ae1b1fff1d1f373ad9c05c0218af4532632 Mon Sep 17 00:00:00 2001 From: Gabor Greif Date: Tue, 10 Sep 2019 23:19:48 +0200 Subject: [PATCH 372/512] Fix a few typos --- lucet-builtins/wasmonkey/README.md | 2 +- lucet-wasi/tests/guests/duplicate_import.wat | 2 +- lucetc/tests/wasm/duplicate_imports.wat | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lucet-builtins/wasmonkey/README.md b/lucet-builtins/wasmonkey/README.md index 00887e644..ae588b3d9 100644 --- a/lucet-builtins/wasmonkey/README.md +++ b/lucet-builtins/wasmonkey/README.md @@ -23,7 +23,7 @@ OPTIONS: ``` `builtins_file` is an object containing alternative implementations to -funcitons called in the wasm code. +functions called in the wasm code. Symbols starting with a `builtin_` prefix will be used for substitution. diff --git a/lucet-wasi/tests/guests/duplicate_import.wat b/lucet-wasi/tests/guests/duplicate_import.wat index 6bd7c1eec..dc8c43f1d 100644 --- a/lucet-wasi/tests/guests/duplicate_import.wat +++ b/lucet-wasi/tests/guests/duplicate_import.wat @@ -25,7 +25,7 @@ ;; declare that, actually, one of the imported functions is exported (export "read_2" (func $read_2)) - ;; and delcare that the *other* read function is also exported, by a + ;; and declare that the *other* read function is also exported, by a ;; different name. This lets us check that when we merge the functions, ;; we also merge their export names properly. (export "read" (func $read)) diff --git a/lucetc/tests/wasm/duplicate_imports.wat b/lucetc/tests/wasm/duplicate_imports.wat index b85726bfa..ac2b3fb5b 100644 --- a/lucetc/tests/wasm/duplicate_imports.wat +++ b/lucetc/tests/wasm/duplicate_imports.wat @@ -21,7 +21,7 @@ ;; declare that, actually, one of the imported functions is exported (export "read_2" (func $read_2)) - ;; and delcare that the *other* read function is also exported, by a + ;; and declare that the *other* read function is also exported, by a ;; different name. This lets us check that when we merge the functions, ;; we also merge their export names properly. (export "read" (func $read)) From 5215f8a1f4f0ec4088b4e3d780eab525c024728a Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 11 Sep 2019 15:24:56 -0700 Subject: [PATCH 373/512] lucet-idl: parse and validate `witx` format (#275) * lucet-idl: competent sexpr parser * lucet-idl: start implementing grammar from https://github.com/WebAssembly/WASI/pull/74/files * lucet-idl: add dan's wasi_unstable.wati as a test case original commit, from https://github.com/sunfishcode/wasi: commit 383385700a13acc2bc4ad2ac7e78a445d9053d21 (HEAD, refs/remotes/sunfishcode/moduletype) Author: Dan Gohman Date: Wed Aug 14 22:42:24 2019 -0700 A wasi_unstable description based on module types. This sketches out a description of the current wasi_unstable API, using a syntax which anticipates the "module types" syntax [recently proposed to the CG](https://github.com/WebAssembly/meetings/blob/master/2019/CG-08-06.md#discuss-new-proposal-that-introduces-types-for-modules-and-instances-and-text-format-thereof-as-initially-discussed-in-design1289), though it does use a few extensions which can be easily lowered, and which mostly anticipate the [Interface Types](https://github.com/WebAssembly/webidl-bindings/issues/47#issuecomment-519717553) proposal. This is derived from [the WatIDL proposal](https://github.com/WebAssembly/WASI/pull/64), though it differs in a few ways: - It doesn't yet do anything special for capabilities, for now. File descriptors are just integers, for now. But the idea is that we could add OCAP concepts later. - It uses a new `(flags ...)` construct in place of structs of Bool fields, to describe flags values. This allows us to explicitly declare the underlying wasm type for flags values. - Types used by the API are declared outside of the moduletype, because we're using wat syntax as much as possible, and there, `(type ...)` inside a module declares an entry in the type section, which isn't what's intended here. The extensions to module types are: - It uses `string`, `array`, and `{s,u}{8,16,32,64}` types, which are expected to be provided in some form by the Interface Types proposal. For now though, they can all be lowered in straightforward ways, by assuming that `string` is always just UTF-8. - It adds `typename` declarations, which can name any wasm type, and of the extra types mentioned in the previous item, or `struct`, `enum`, or `flags`. - It declares functions with multiple return values, which for now will need to be lowered to output (pointer) parameters. * lucet-idl: enough infra to feed wasi_unstable.wati through parser * lucet-idl: fix typo in wasi_unstable lexer found it! cheers * lucet-idl: better error reporting * lucet-idl: parse a bunch more of wati * lucet-idl: @interface is an Annot("interface") * lucet-idl: switch from wasi_unstable.wati to multiple .witx * lucet-idl: interface-types idl files are now called .witx webassembly interface types has claimed the `.wit` file extension for describing just module interfaces. this idl is currently the `.wit` syntax, plus extensions. in lieu of a better name, dan and I decided `.witx` will work for the time being. * lucet-idl: renames of stuff in witx, plus use stmts * lucet-idl: typenames.witx had an extra close paren * lucet-idl: correct path to typenames in wasi_unstable.witx * lucet-idl: change parser to own everything. start implementing use * lucet-idl: witx use directive works! * lucet-idl: better error messages in parser through lookahead * lucet-idl: parser makes it through wasi_unstable * lucet-idl: wasi_unstable.witx: fix two syntax errors in * lucet-idl: witx use decls are now like #pragma once so we dont have to care about cycles, and diamond dependencies will be handled correctly * lucet-idl: witx use resolution moved to toplevel.rs * lucet-idl: make an AST for witx * lucet-idl: rename interfacetypes to witx * lucet-idl witx: file name goes in location, location throughout parse tree * lucet-idl witx: validator is filling out * lucet-idl witx: typenames.witx reorg so names are defined before use this restriction makes it possible to perform validation linearly, which is in line with validation elsewhere in wasm * lucet-idl witx: validation of all datatypes complete * lucet-idl witx: finish validation * lucet-idl witx: fix tests * lucet-idl: fix tests * lucet-idl witx: syntax derives Eq. mock the filesystem to test use more tests required * lucet-idl witx: some fixups, plenty of toplevel tests * lucet-idl witx: add docs, refactor error name, resolve warnings * lucet-idl: add test case to load wasi_unstable.witx * lucet-idl: rustfmt * lucet-idl witx: review comments * lucet-idl witx: really fix the path thing this time * lucet-idl witx: simplify paths one more time not my favorite corner of std!! --- lucet-idl/src/config.rs | 5 +- lucet-idl/src/error.rs | 9 + lucet-idl/src/lib.rs | 17 +- lucet-idl/src/main.rs | 14 +- lucet-idl/src/witx/ast.rs | 161 +++++++ lucet-idl/src/witx/lexer.rs | 353 ++++++++++++++ lucet-idl/src/witx/mod.rs | 46 ++ lucet-idl/src/witx/parser.rs | 557 ++++++++++++++++++++++ lucet-idl/src/witx/sexpr.rs | 224 +++++++++ lucet-idl/src/witx/toplevel.rs | 244 ++++++++++ lucet-idl/src/witx/validate.rs | 362 +++++++++++++++ lucet-idl/tests/example.rs | 24 +- lucet-idl/tests/typenames.witx | 719 +++++++++++++++++++++++++++++ lucet-idl/tests/wasi_unstable.rs | 8 + lucet-idl/tests/wasi_unstable.witx | 516 +++++++++++++++++++++ 15 files changed, 3236 insertions(+), 23 deletions(-) create mode 100644 lucet-idl/src/witx/ast.rs create mode 100644 lucet-idl/src/witx/lexer.rs create mode 100644 lucet-idl/src/witx/mod.rs create mode 100644 lucet-idl/src/witx/parser.rs create mode 100644 lucet-idl/src/witx/sexpr.rs create mode 100644 lucet-idl/src/witx/toplevel.rs create mode 100644 lucet-idl/src/witx/validate.rs create mode 100644 lucet-idl/tests/typenames.witx create mode 100644 lucet-idl/tests/wasi_unstable.rs create mode 100644 lucet-idl/tests/wasi_unstable.witx diff --git a/lucet-idl/src/config.rs b/lucet-idl/src/config.rs index d42a05803..177005066 100644 --- a/lucet-idl/src/config.rs +++ b/lucet-idl/src/config.rs @@ -2,11 +2,12 @@ use crate::error::IDLError; #[derive(Clone, Debug)] pub struct Config { + pub witx: bool, pub backend: Backend, } impl Config { - pub fn parse(backend_opt: &str) -> Result { + pub fn parse(witx: bool, backend_opt: &str) -> Result { let backend = Backend::from_str(backend_opt).ok_or_else(|| { IDLError::UsageError(format!( "Invalid backend: {}\nValid options are: {:?}", @@ -14,7 +15,7 @@ impl Config { Backend::options() )) })?; - Ok(Self { backend }) + Ok(Self { witx, backend }) } } diff --git a/lucet-idl/src/error.rs b/lucet-idl/src/error.rs index d6ddbcb21..d2fe337cf 100644 --- a/lucet-idl/src/error.rs +++ b/lucet-idl/src/error.rs @@ -1,4 +1,5 @@ use crate::parser; +use crate::witx::WitxError; use crate::Location; use std::io; @@ -14,6 +15,8 @@ pub enum IDLError { ValidationError(#[cause] ValidationError), #[fail(display = "{}", _0)] Io(#[cause] io::Error), + #[fail(display = "{}", _0)] + Witx(#[cause] WitxError), } impl From for IDLError { @@ -34,6 +37,12 @@ impl From for IDLError { } } +impl From for IDLError { + fn from(e: WitxError) -> Self { + IDLError::Witx(e) + } +} + #[derive(Debug, PartialEq, Eq, Clone, Fail)] pub enum ValidationError { #[fail(display = "Redefinition of name `{}`", name)] diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index b77af7785..47aa96b1e 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -15,6 +15,7 @@ pub mod pretty_writer; mod repr; mod rust; mod validate; +mod witx; pub use crate::atoms::{AbiType, AtomType}; pub use crate::config::{Backend, Config}; @@ -32,9 +33,12 @@ use crate::c::CGenerator; use crate::parser::Parser; use crate::rust::RustGenerator; use crate::validate::package_from_declarations; +pub use crate::witx::load_witx; use lucet_module::bindings::Bindings; use std::collections::HashMap; +use std::fs; use std::io::Write; +use std::path::Path; #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] pub struct Location { @@ -64,9 +68,16 @@ pub fn codegen(package: &Package, config: &Config, output: Box) -> Re Ok(()) } -pub fn run(config: &Config, input: &str, output: Box) -> Result<(), IDLError> { - let pkg = parse_package(input)?; - codegen(&pkg, config, output) +pub fn run(config: &Config, input_path: &Path, output: Box) -> Result<(), IDLError> { + if config.witx { + let doc = load_witx(input_path).map_err(IDLError::Witx)?; + println!("{:?}", doc); + Ok(()) + } else { + let input = fs::read_to_string(input_path)?; + let pkg = parse_package(&input)?; + codegen(&pkg, config, output) + } } impl Package { diff --git a/lucet-idl/src/main.rs b/lucet-idl/src/main.rs index 2cf4f7e2d..a4bed0428 100644 --- a/lucet-idl/src/main.rs +++ b/lucet-idl/src/main.rs @@ -39,6 +39,13 @@ impl ExeConfig { .required(false) .help("output path"), ) + .arg( + Arg::with_name("witx") + .long("witx") + .takes_value(false) + .required(false) + .help("witx (interface-types, with extensions) mode"), + ) .get_matches(); let input_path = PathBuf::from( matches @@ -46,7 +53,10 @@ impl ExeConfig { .ok_or(IDLError::UsageError("Input file required".to_owned()))?, ); let output_path = matches.value_of("output").map(PathBuf::from); - let config = Config::parse(matches.value_of("backend").unwrap())?; + let config = Config::parse( + matches.is_present("witx"), + matches.value_of("backend").unwrap(), + )?; Ok(ExeConfig { input_path, output_path, @@ -64,7 +74,7 @@ fn doit() -> Result<(), IDLError> { None => Box::new(io::stdout()), }; - run(&exe_config.config, &source, output)?; + run(&exe_config.config, &exe_config.input_path, output)?; Ok(()) } diff --git a/lucet-idl/src/witx/ast.rs b/lucet-idl/src/witx/ast.rs new file mode 100644 index 000000000..2e5d65954 --- /dev/null +++ b/lucet-idl/src/witx/ast.rs @@ -0,0 +1,161 @@ +#![allow(dead_code)] +use std::collections::HashMap; +use std::rc::{Rc, Weak}; + +pub use super::parser::BuiltinType; + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Id(String); + +impl Id { + pub fn new>(s: S) -> Self { + Id(s.as_ref().to_string()) + } + pub fn as_str(&self) -> &str { + self.0.as_str() + } +} + +#[derive(Debug, Clone)] +pub struct Document { + pub definitions: Vec, + pub entries: HashMap, +} + +#[derive(Debug, Clone)] +pub enum Definition { + Datatype(Rc), + Module(Rc), +} + +#[derive(Debug, Clone)] +pub enum Entry { + Datatype(Weak), + Module(Weak), +} + +impl Entry { + pub fn kind(&self) -> &'static str { + match self { + Entry::Datatype { .. } => "datatype", + Entry::Module { .. } => "module", + } + } +} + +#[derive(Debug, Clone)] +pub enum DatatypeIdent { + Builtin(BuiltinType), + Array(Box), + Ident(Rc), +} + +#[derive(Debug, Clone)] +pub struct Datatype { + pub name: Id, + pub variant: DatatypeVariant, +} + +#[derive(Debug, Clone)] +pub enum DatatypeVariant { + Alias(AliasDatatype), + Enum(EnumDatatype), + Flags(FlagsDatatype), + Struct(StructDatatype), + Union(UnionDatatype), +} + +#[derive(Debug, Clone)] +pub struct AliasDatatype { + pub name: Id, + pub to: DatatypeIdent, +} + +#[derive(Debug, Clone)] +pub enum IntRepr { + I8, + I16, + I32, + I64, +} + +#[derive(Debug, Clone)] +pub struct EnumDatatype { + pub name: Id, + pub repr: IntRepr, + pub variants: Vec, +} + +#[derive(Debug, Clone)] +pub struct FlagsDatatype { + pub name: Id, + pub repr: IntRepr, + pub flags: Vec, +} + +#[derive(Debug, Clone)] +pub struct StructDatatype { + pub name: Id, + pub members: Vec, +} + +#[derive(Debug, Clone)] +pub struct StructMember { + pub name: Id, + pub type_: DatatypeIdent, +} + +#[derive(Debug, Clone)] +pub struct UnionDatatype { + pub name: Id, + pub variants: Vec, +} + +#[derive(Debug, Clone)] +pub struct UnionVariant { + pub name: Id, + pub type_: DatatypeIdent, +} + +#[derive(Debug, Clone)] +pub struct Module { + pub name: Id, + pub definitions: Vec, + pub entries: HashMap, +} + +#[derive(Debug, Clone)] +pub enum ModuleDefinition { + Import(Rc), + Func(Rc), +} + +#[derive(Debug, Clone)] +pub enum ModuleEntry { + Import(Weak), + Func(Weak), +} + +#[derive(Debug, Clone)] +pub struct ModuleImport { + pub name: Id, + pub variant: ModuleImportVariant, +} + +#[derive(Debug, Clone)] +pub enum ModuleImportVariant { + Memory, +} + +#[derive(Debug, Clone)] +pub struct InterfaceFunc { + pub name: Id, + pub params: Vec, + pub results: Vec, +} + +#[derive(Debug, Clone)] +pub struct InterfaceFuncParam { + pub name: Id, + pub type_: DatatypeIdent, +} diff --git a/lucet-idl/src/witx/lexer.rs b/lucet-idl/src/witx/lexer.rs new file mode 100644 index 000000000..1dac8fe34 --- /dev/null +++ b/lucet-idl/src/witx/lexer.rs @@ -0,0 +1,353 @@ +use super::Location; +use std::path::{Path, PathBuf}; +use std::str::CharIndices; + +///! The lexer turns a string into a stream of located tokens. +///! The tokens are meant for consumption by the s-expression parser. +///! +///! Comments in source text look like `;; rest of line ...`. +///! Words look like `abcde_` +///! Idents look like `$abcde_` +///! Annotations look like `@abcde_` +///! Quotes look like `"a b cde 123 @#$%^&*() _"` +///! +///! This implementation was heavily influenced by `cranelift-reader` + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum Token<'a> { + LPar, // ( + RPar, // ) + Word(&'a str), // Bare word + Ident(&'a str), // Starts with $ + Annot(&'a str), // Starts with @. short for annotation. + Quote(&'a str), // Found between balanced "". No escaping. +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct LocatedToken<'a> { + pub token: Token<'a>, + pub location: Location, +} + +fn token(token: Token<'_>, location: Location) -> Result, LocatedError> { + Ok(LocatedToken { token, location }) +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy, Fail)] +pub enum LexError { + #[fail(display = "Invalid character '{}'", _0)] + InvalidChar(char), + #[fail(display = "Empty identifier '$'")] + EmptyIdentifier, + #[fail(display = "Empty annotation '@'")] + EmptyAnnotation, + #[fail(display = "Unterminated quote")] + UnterminatedQuote, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct LocatedError { + pub error: LexError, + pub location: Location, +} + +fn error<'a>(error: LexError, location: Location) -> Result, LocatedError> { + Err(LocatedError { error, location }) +} + +pub struct Lexer<'a> { + source: &'a str, + chars: CharIndices<'a>, + lookahead: Option, + pos: usize, + line_number: usize, + column_start: usize, + tab_compensation: usize, + path: PathBuf, +} + +impl<'a> Lexer<'a> { + pub fn new>(s: &'a str, path: P) -> Lexer<'_> { + let mut lex = Lexer { + source: s, + chars: s.char_indices(), + lookahead: None, + pos: 0, + line_number: 1, + column_start: 0, + tab_compensation: 0, + path: path.as_ref().into(), + }; + lex.next_ch(); + lex + } + + fn next_ch(&mut self) -> Option { + if self.lookahead == Some('\n') { + self.line_number += 1; + self.column_start = self.pos + 1; // Next column starts a fresh line + self.tab_compensation = 0; + } else if self.lookahead == Some('\t') { + self.tab_compensation += 7; // One column for the position of the char itself, add 7 more for a tabwidth of 8 + } + match self.chars.next() { + Some((idx, ch)) => { + self.pos = idx; + self.lookahead = Some(ch); + } + None => { + self.pos = self.source.len(); + self.lookahead = None; + } + } + self.lookahead + } + + fn loc(&self) -> Location { + Location { + path: self.path.clone(), + line: self.line_number, + column: self.pos - self.column_start + self.tab_compensation, + } + } + + fn looking_at(&self, prefix: &str) -> bool { + self.source[self.pos..].starts_with(prefix) + } + + fn scan_char(&mut self, tok: Token<'a>) -> Result, LocatedError> { + assert!(self.lookahead.is_some()); + let loc = self.loc(); + self.next_ch(); + token(tok, loc) + } + + pub fn rest_of_line(&mut self) -> &'a str { + let begin = self.pos; + loop { + match self.next_ch() { + None | Some('\n') => return &self.source[begin..self.pos], + _ => {} + } + } + } + + fn scan_word(&mut self) -> Result, LocatedError> { + let begin = self.pos; + let loc = self.loc(); + assert!(self.lookahead == Some('_') || self.lookahead.unwrap().is_alphabetic()); + loop { + match self.next_ch() { + Some('_') | Some('-') => {} + Some(ch) if ch.is_alphanumeric() => {} + _ => break, + } + } + let text = &self.source[begin..self.pos]; + token(Token::Word(text), loc) + } + + fn scan_ident(&mut self) -> Result, LocatedError> { + let loc = self.loc(); + assert!(self.lookahead == Some('$')); + match self.next_ch() { + Some(ch) if ch.is_alphanumeric() || ch == '_' => {} + _ => Err(LocatedError { + error: LexError::EmptyIdentifier, + location: loc.clone(), + })?, + } + let begin = self.pos; + + loop { + match self.next_ch() { + Some('_') | Some('-') => {} + Some(ch) if ch.is_alphanumeric() => {} + _ => break, + } + } + + let text = &self.source[begin..self.pos]; + token(Token::Ident(text), loc) + } + + fn scan_annotation(&mut self) -> Result, LocatedError> { + let loc = self.loc(); + assert!(self.lookahead == Some('@')); + match self.next_ch() { + Some(ch) if ch.is_alphanumeric() || ch == '_' => {} + _ => Err(LocatedError { + error: LexError::EmptyAnnotation, + location: loc.clone(), + })?, + } + let begin = self.pos; + + loop { + match self.next_ch() { + Some('_') | Some('-') => {} + Some(ch) if ch.is_alphanumeric() => {} + _ => break, + } + } + + let text = &self.source[begin..self.pos]; + token(Token::Annot(text), loc) + } + + fn scan_quote(&mut self) -> Result, LocatedError> { + let begin = self.pos; + let loc = self.loc(); + assert!(self.lookahead == Some('"')); + loop { + match self.next_ch() { + None => Err(LocatedError { + error: LexError::UnterminatedQuote, + location: loc.clone(), + })?, + Some('"') => { + self.next_ch(); + break; + } + _ => {} + } + } + let text = &self.source[(begin + 1)..(self.pos - 1)]; + token(Token::Quote(text), loc) + } + + #[allow(clippy::should_implement_trait)] + pub fn next(&mut self) -> Option, LocatedError>> { + loop { + let loc = self.loc(); + return match self.lookahead { + None => None, + Some(c) => Some(match c { + '(' => self.scan_char(Token::LPar), + ')' => self.scan_char(Token::RPar), + '$' => self.scan_ident(), + '@' => self.scan_annotation(), + ';' => { + if self.looking_at(";;") { + self.rest_of_line(); + continue; + } else { + self.next_ch(); + error(LexError::InvalidChar(';'), loc) + } + } + '"' => self.scan_quote(), + '_' => self.scan_word(), + ch if ch.is_alphabetic() => self.scan_word(), + ch if ch.is_whitespace() => { + self.next_ch(); + continue; + } + _ => { + self.next_ch(); + error(LexError::InvalidChar(c), loc) + } + }), + }; + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use std::path::{Path, PathBuf}; + + fn testlexer(input: &str) -> Lexer { + Lexer::new(input, Path::new("/test")) + } + + fn token( + token: Token<'_>, + line: usize, + column: usize, + ) -> Option, LocatedError>> { + Some(super::token( + token, + Location { + path: PathBuf::from("/test"), + line, + column, + }, + )) + } + + fn error<'a>( + err: LexError, + line: usize, + column: usize, + ) -> Option, LocatedError>> { + Some(super::error( + err, + Location { + path: PathBuf::from("/test"), + line, + column, + }, + )) + } + #[test] + fn words_and_idents() { + let mut lex = testlexer("$gussie is a good $dog"); + // ruler 0 5 10 15 20 + assert_eq!(lex.next(), token(Token::Ident("gussie"), 1, 0)); + assert_eq!(lex.next(), token(Token::Word("is"), 1, 8)); + assert_eq!(lex.next(), token(Token::Word("a"), 1, 11)); + assert_eq!(lex.next(), token(Token::Word("good"), 1, 13)); + assert_eq!(lex.next(), token(Token::Ident("dog"), 1, 18)); + assert_eq!(lex.next(), None); + + let mut lex = + testlexer("$ok $a $_ $ _\nkebab-case\nsnake_case\n$kebab-ident\n$snake_ident"); + assert_eq!(lex.next(), token(Token::Ident("ok"), 1, 0)); + assert_eq!(lex.next(), token(Token::Ident("a"), 1, 4)); + assert_eq!(lex.next(), token(Token::Ident("_"), 1, 7)); + assert_eq!(lex.next(), error(LexError::EmptyIdentifier, 1, 10)); + assert_eq!(lex.next(), token(Token::Word("_"), 1, 12)); + assert_eq!(lex.next(), token(Token::Word("kebab-case"), 2, 0)); + assert_eq!(lex.next(), token(Token::Word("snake_case"), 3, 0)); + assert_eq!(lex.next(), token(Token::Ident("kebab-ident"), 4, 0)); + assert_eq!(lex.next(), token(Token::Ident("snake_ident"), 5, 0)); + assert_eq!(lex.next(), None); + } + + #[test] + fn comments() { + let mut lex = testlexer("the quick ;; brown fox\njumped\n;;over the three\nlazy;;dogs"); + assert_eq!(lex.next(), token(Token::Word("the"), 1, 0)); + assert_eq!(lex.next(), token(Token::Word("quick"), 1, 4)); + assert_eq!(lex.next(), token(Token::Word("jumped"), 2, 0)); + assert_eq!(lex.next(), token(Token::Word("lazy"), 4, 0)); + assert_eq!(lex.next(), None); + + let mut lex = testlexer("line1 ;;\n$sym_2;\n\t\tl3;;;333"); + assert_eq!(lex.next(), token(Token::Word("line1"), 1, 0)); + assert_eq!(lex.next(), token(Token::Ident("sym_2"), 2, 0)); + assert_eq!(lex.next(), error(LexError::InvalidChar(';'), 2, 6)); + assert_eq!(lex.next(), token(Token::Word("l3"), 3, 16)); // Two tabs = 16 columns + assert_eq!(lex.next(), None); + } + + #[test] + fn quotes() { + let mut lex = testlexer("a \"bc\" d"); + assert_eq!(lex.next(), token(Token::Word("a"), 1, 0)); + assert_eq!(lex.next(), token(Token::Quote("bc"), 1, 2)); + assert_eq!(lex.next(), token(Token::Word("d"), 1, 7)); + + let mut lex = testlexer("a \"b\nc\" d"); + assert_eq!(lex.next(), token(Token::Word("a"), 1, 0)); + assert_eq!(lex.next(), token(Token::Quote("b\nc"), 1, 2)); + assert_eq!(lex.next(), token(Token::Word("d"), 2, 3)); + + let mut lex = testlexer("a \"b"); + assert_eq!(lex.next(), token(Token::Word("a"), 1, 0)); + assert_eq!(lex.next(), error(LexError::UnterminatedQuote, 1, 2)); + } +} diff --git a/lucet-idl/src/witx/mod.rs b/lucet-idl/src/witx/mod.rs new file mode 100644 index 000000000..72eb2441c --- /dev/null +++ b/lucet-idl/src/witx/mod.rs @@ -0,0 +1,46 @@ +/// Types describing a validated witx document +pub mod ast; +/// Lexer text into tokens +mod lexer; +/// Witx syntax parsing from SExprs +mod parser; +/// SExpr parsing from tokens +mod sexpr; +/// Resolve toplevel `use` declarations across files +mod toplevel; +/// Validate declarations into ast +mod validate; + +pub use ast::Document; +pub use parser::{DeclSyntax, ParseError}; +pub use sexpr::SExprParseError; +pub use toplevel::parse_witx; +pub use validate::{validate_document, ValidationError}; + +use std::io; +use std::path::{Path, PathBuf}; + +/// Location in the source text +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct Location { + pub path: PathBuf, + pub line: usize, + pub column: usize, +} + +#[derive(Debug, Fail)] +pub enum WitxError { + #[fail(display = "{}", _0)] + SExpr(#[cause] SExprParseError), + #[fail(display = "when resolving use declaration for {:?}: {}", _0, _1)] + UseResolution(PathBuf, #[cause] io::Error), + #[fail(display = "{}", _0)] + Parse(#[cause] ParseError), + #[fail(display = "{}", _0)] + Validation(#[cause] ValidationError), +} + +pub fn load_witx>(path: P) -> Result { + let parsed_decls = parse_witx(path)?; + validate_document(&parsed_decls).map_err(WitxError::Validation) +} diff --git a/lucet-idl/src/witx/parser.rs b/lucet-idl/src/witx/parser.rs new file mode 100644 index 000000000..0e595e10b --- /dev/null +++ b/lucet-idl/src/witx/parser.rs @@ -0,0 +1,557 @@ +use super::sexpr::SExpr; +use super::Location; + +///! Parser turns s-expressions into unvalidated syntax constructs. +///! conventions: +///! `Type::starts_parsing(s-expr) -> bool` is for look-ahead: we use +///! this predicate to combine parsers for different `Type`s where both +///! alternatives are accepted. +///! `Type::parse(sexpr: &SExpr) -> Result` takes a single +///! s-expression and parses it into a `Self`. +///! for parsers that take a subset of a vector s-expression, the signature +///! `Type::parse(sexprs: &[SExpr], location: Location) -> Result` +///! has an additional `Location` argument, which should point to the parent SExpr::Vec. +///! This is used for error reporting in case the slice doesn't have the number of elements +///! expected. + +#[derive(Debug, Fail)] +#[fail(display = "{} at {:?}", _0, _1)] +pub struct ParseError { + pub message: String, + pub location: Location, +} + +macro_rules! parse_err { + ($loc:expr, $msg:expr) => { + ParseError { message: $msg.to_string(), location: $loc.clone() } + }; + ($loc:expr, $fmt:expr, $( $arg:expr ),+ ) => { + ParseError { message: format!($fmt, $( $arg ),+), location: $loc.clone() } + }; +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IdentSyntax { + pub name: String, + pub location: Location, +} + +macro_rules! id { + ($s:expr, $loc: expr) => { + IdentSyntax { + name: $s.to_string(), + location: $loc.clone(), + } + }; +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum BuiltinType { + String, + Data, + U8, + U16, + U32, + U64, + S8, + S16, + S32, + S64, + F32, + F64, +} + +impl BuiltinType { + pub fn starts_parsing(sexpr: &SExpr) -> bool { + match sexpr { + SExpr::Word("string", _) + | SExpr::Word("data", _) + | SExpr::Word("u8", _) + | SExpr::Word("u16", _) + | SExpr::Word("u32", _) + | SExpr::Word("u64", _) + | SExpr::Word("s8", _) + | SExpr::Word("s16", _) + | SExpr::Word("s32", _) + | SExpr::Word("s64", _) + | SExpr::Word("f32", _) + | SExpr::Word("f64", _) => true, + _ => false, + } + } + pub fn parse(sexpr: &SExpr) -> Result { + match sexpr { + SExpr::Word("string", _loc) => Ok(BuiltinType::String), + SExpr::Word("data", _loc) => Ok(BuiltinType::Data), + SExpr::Word("u8", _loc) => Ok(BuiltinType::U8), + SExpr::Word("u16", _loc) => Ok(BuiltinType::U16), + SExpr::Word("u32", _loc) => Ok(BuiltinType::U32), + SExpr::Word("u64", _loc) => Ok(BuiltinType::U64), + SExpr::Word("s8", _loc) => Ok(BuiltinType::S8), + SExpr::Word("s16", _loc) => Ok(BuiltinType::S16), + SExpr::Word("s32", _loc) => Ok(BuiltinType::S32), + SExpr::Word("s64", _loc) => Ok(BuiltinType::S64), + SExpr::Word("f32", _loc) => Ok(BuiltinType::F32), + SExpr::Word("f64", _loc) => Ok(BuiltinType::F64), + _ => Err(parse_err!(sexpr.location(), "invalid builtin type")), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum DatatypeIdentSyntax { + Builtin(BuiltinType), + Array(Box), + Ident(IdentSyntax), +} + +impl DatatypeIdentSyntax { + pub fn starts_parsing(sexpr: &SExpr) -> bool { + BuiltinType::starts_parsing(sexpr) + || match sexpr { + SExpr::Ident(_, _) => true, + SExpr::Vec(v, _) => match (v.get(0), v.get(1)) { + (Some(SExpr::Word("array", _)), Some(_)) => true, + _ => false, + }, + _ => false, + } + } + pub fn parse(sexpr: &SExpr) -> Result { + if BuiltinType::starts_parsing(sexpr) { + let builtin = BuiltinType::parse(sexpr)?; + Ok(DatatypeIdentSyntax::Builtin(builtin)) + } else { + match sexpr { + SExpr::Ident(i, loc) => Ok(DatatypeIdentSyntax::Ident(id!(i, loc))), + SExpr::Vec(v, loc) => match (v.get(0), v.get(1)) { + (Some(SExpr::Word("array", _loc)), Some(expr)) => Ok( + DatatypeIdentSyntax::Array(Box::new(DatatypeIdentSyntax::parse(expr)?)), + ), + _ => Err(parse_err!(loc, "expected type identifier")), + }, + _ => Err(parse_err!(sexpr.location(), "expected type identifier")), + } + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum TopLevelSyntax { + Decl(DeclSyntax), + Use(IdentSyntax), +} + +impl TopLevelSyntax { + pub fn parse(sexpr: &SExpr) -> Result { + if DeclSyntax::starts_parsing(sexpr) { + let decl = DeclSyntax::parse(sexpr)?; + Ok(TopLevelSyntax::Decl(decl)) + } else { + match sexpr { + SExpr::Vec(v, vec_loc) => match v.get(0) { + Some(SExpr::Word("use", loc)) => match v.get(1) { + Some(SExpr::Quote(u, loc)) => Ok(TopLevelSyntax::Use(id!(u, loc))), + _ => Err(parse_err!(loc, "invalid use declaration")), + }, + _ => Err(parse_err!(vec_loc, "expected top level declaration")), + }, + _ => Err(parse_err!( + sexpr.location(), + "expected top level declaration" + )), + } + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum DeclSyntax { + Typename(TypenameSyntax), + Module(ModuleSyntax), +} + +impl DeclSyntax { + pub fn starts_parsing(sexpr: &SExpr) -> bool { + match sexpr { + SExpr::Vec(v, _) => match v.get(0) { + Some(SExpr::Word("typename", _)) => true, + Some(SExpr::Word("module", _)) => true, + _ => false, + }, + _ => false, + } + } + pub fn parse(sexpr: &SExpr) -> Result { + match sexpr { + SExpr::Vec(v, loc) => match v.get(0) { + Some(SExpr::Word("typename", loc)) => { + Ok(DeclSyntax::Typename(TypenameSyntax::parse(&v[1..], loc)?)) + } + Some(SExpr::Word("module", loc)) => { + Ok(DeclSyntax::Module(ModuleSyntax::parse(&v[1..], loc)?)) + } + _ => Err(parse_err!(loc, "invalid declaration")), + }, + _ => Err(parse_err!(sexpr.location(), "expected vec")), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TypenameSyntax { + pub ident: IdentSyntax, + pub def: TypedefSyntax, +} + +impl TypenameSyntax { + pub fn parse(sexpr: &[SExpr], loc: &Location) -> Result { + let ident = match sexpr.get(0) { + Some(SExpr::Ident(i, loc)) => id!(i, loc), + _ => Err(parse_err!(loc, "expected typename identifier"))?, + }; + let def = match sexpr.get(1) { + Some(expr) => TypedefSyntax::parse(expr)?, + _ => Err(parse_err!(loc, "expected type definition"))?, + }; + Ok(TypenameSyntax { ident, def }) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum TypedefSyntax { + Ident(DatatypeIdentSyntax), + Enum(EnumSyntax), + Flags(FlagsSyntax), + Struct(StructSyntax), + Union(UnionSyntax), +} + +impl TypedefSyntax { + pub fn parse(sexpr: &SExpr) -> Result { + if DatatypeIdentSyntax::starts_parsing(sexpr) { + let ident = DatatypeIdentSyntax::parse(sexpr)?; + Ok(TypedefSyntax::Ident(ident)) + } else { + match sexpr { + SExpr::Vec(vs, loc) => match vs.get(0) { + Some(SExpr::Word("enum", loc)) => { + Ok(TypedefSyntax::Enum(EnumSyntax::parse(&vs[1..], loc)?)) + } + Some(SExpr::Word("flags", loc)) => { + Ok(TypedefSyntax::Flags(FlagsSyntax::parse(&vs[1..], loc)?)) + } + Some(SExpr::Word("struct", loc)) => { + Ok(TypedefSyntax::Struct(StructSyntax::parse(&vs[1..], loc)?)) + } + Some(SExpr::Word("union", loc)) => { + Ok(TypedefSyntax::Union(UnionSyntax::parse(&vs[1..], loc)?)) + } + _ => Err(parse_err!( + loc, + "expected type identifier or type definition" + )), + }, + _ => Err(parse_err!( + sexpr.location(), + "expected type identifier or type definition" + )), + } + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct EnumSyntax { + pub repr: BuiltinType, + pub members: Vec, +} + +impl EnumSyntax { + pub fn parse(sexpr: &[SExpr], loc: &Location) -> Result { + let repr = match sexpr.get(0) { + Some(e) => BuiltinType::parse(e)?, + _ => Err(parse_err!(loc, "no enum repr"))?, + }; + let members = sexpr[1..] + .iter() + .map(|m| match m { + SExpr::Ident(i, loc) => Ok(id!(i, loc)), + s => Err(parse_err!(s.location(), "expected enum member identifier")), + }) + .collect::, ParseError>>()?; + if members.is_empty() { + Err(parse_err!(loc, "expected at least one enum member"))? + } + Ok(EnumSyntax { repr, members }) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct FlagsSyntax { + pub repr: BuiltinType, + pub flags: Vec, +} + +impl FlagsSyntax { + pub fn parse(sexpr: &[SExpr], loc: &Location) -> Result { + let repr = BuiltinType::parse( + sexpr + .get(0) + .ok_or_else(|| parse_err!(loc, "expected flag repr type"))?, + )?; + let flags = sexpr[1..] + .iter() + .map(|f| match f { + SExpr::Vec(vs, loc) => match (vs.get(0), vs.get(1)) { + (Some(SExpr::Word("flag", _)), Some(SExpr::Ident(i, loc))) => Ok(id!(i, loc)), + _ => Err(parse_err!(loc, "expected flag specifier")), + }, + s => Err(parse_err!(s.location(), "expected flag specifier")), + }) + .collect::, ParseError>>()?; + Ok(FlagsSyntax { repr, flags }) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StructSyntax { + pub fields: Vec, +} + +impl StructSyntax { + pub fn parse(sexpr: &[SExpr], loc: &Location) -> Result { + if sexpr.is_empty() { + Err(parse_err!(loc, "expected at least one struct member"))? + } + let fields = sexpr + .iter() + .map(|f| FieldSyntax::parse(f, "field")) + .collect::, ParseError>>()?; + Ok(StructSyntax { fields }) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct FieldSyntax { + pub name: IdentSyntax, + pub type_: DatatypeIdentSyntax, +} + +impl FieldSyntax { + pub fn starts_parsing(sexpr: &SExpr, constructor: &str) -> bool { + match sexpr { + SExpr::Vec(v, _) => match v.get(0) { + Some(SExpr::Word(c, _)) => *c == constructor, + _ => false, + }, + _ => false, + } + } + pub fn parse(sexpr: &SExpr, constructor: &str) -> Result { + match sexpr { + SExpr::Vec(v, loc) => match v.get(0) { + Some(SExpr::Word(c, _)) if *c == constructor => { + let name = match v.get(1) { + Some(SExpr::Ident(i, loc)) => id!(i, loc), + _ => Err(parse_err!(loc, "expected {} name identifier", constructor))?, + }; + let type_ = DatatypeIdentSyntax::parse(v.get(2).ok_or_else(|| { + parse_err!(loc, "expected {} type identifier", constructor) + })?)?; + Ok(FieldSyntax { name, type_ }) + } + _ => Err(parse_err!(loc, "expected {}", constructor)), + }, + _ => Err(parse_err!(sexpr.location(), "expected {}", constructor)), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct UnionSyntax { + pub fields: Vec, +} + +impl UnionSyntax { + pub fn parse(sexpr: &[SExpr], loc: &Location) -> Result { + if sexpr.is_empty() { + Err(parse_err!(loc, "expected at least one union member"))? + } + let fields = sexpr + .iter() + .map(|f| FieldSyntax::parse(f, "field")) + .collect::, ParseError>>()?; + Ok(UnionSyntax { fields }) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ModuleSyntax { + pub name: IdentSyntax, + pub decls: Vec, +} + +impl ModuleSyntax { + pub fn parse(sexprs: &[SExpr], loc: &Location) -> Result { + let name = match sexprs.get(0) { + Some(SExpr::Ident(i, loc)) => id!(i, loc), + _ => Err(parse_err!(loc, "expected module name"))?, + }; + let decls = sexprs[1..] + .iter() + .map(|s| ModuleDeclSyntax::parse(s)) + .collect::, _>>()?; + Ok(ModuleSyntax { name, decls }) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ModuleDeclSyntax { + Import(ModuleImportSyntax), + Func(InterfaceFuncSyntax), +} + +impl ModuleDeclSyntax { + pub fn parse(sexpr: &SExpr) -> Result { + if ModuleImportSyntax::starts_parsing(sexpr) { + Ok(ModuleDeclSyntax::Import(ModuleImportSyntax::parse(sexpr)?)) + } else if InterfaceFuncSyntax::starts_parsing(sexpr) { + Ok(ModuleDeclSyntax::Func(InterfaceFuncSyntax::parse(sexpr)?)) + } else { + Err(parse_err!(sexpr.location(), "expected import or function")) + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ModuleImportSyntax { + pub name: IdentSyntax, + pub type_: ImportTypeSyntax, +} + +impl ModuleImportSyntax { + pub fn starts_parsing(sexpr: &SExpr) -> bool { + match sexpr { + SExpr::Vec(vs, _) => match vs.get(0) { + Some(SExpr::Word("import", _)) => true, + _ => false, + }, + _ => false, + } + } + pub fn parse(sexpr: &SExpr) -> Result { + match sexpr { + SExpr::Vec(vs, vec_loc) => match (vs.get(0), vs.get(1)) { + (Some(SExpr::Word("import", _)), Some(SExpr::Quote(name, loc))) => { + let name = id!(name, loc); + let type_ = ImportTypeSyntax::parse(&vs[2..], vec_loc)?; + Ok(ModuleImportSyntax { name, type_ }) + } + _ => Err(parse_err!(vec_loc, "expected module import")), + }, + _ => Err(parse_err!(sexpr.location(), "expected module import")), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ImportTypeSyntax { + Memory, +} + +impl ImportTypeSyntax { + pub fn parse(sexpr: &[SExpr], loc: &Location) -> Result { + if sexpr.len() > 1 { + Err(parse_err!(loc, "too many elements for an import type"))?; + } + match sexpr.get(0) { + Some(SExpr::Vec(vs, loc)) => match vs.get(0) { + Some(SExpr::Word("memory", _)) => { + if vs.len() == 1 { + Ok(ImportTypeSyntax::Memory) + } else { + Err(parse_err!(loc, "too many elements for memory declaration")) + } + } + _ => Err(parse_err!(loc, "expected import type")), + }, + _ => Err(parse_err!(loc, "expected import type")), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct InterfaceFuncSyntax { + pub export: IdentSyntax, + pub params: Vec, + pub results: Vec, +} + +impl InterfaceFuncSyntax { + pub fn starts_parsing(sexpr: &SExpr) -> bool { + match sexpr { + SExpr::Vec(vs, _) => match (vs.get(0), vs.get(1)) { + (Some(SExpr::Annot("interface", _)), Some(SExpr::Word("func", _))) => true, + _ => false, + }, + _ => false, + } + } + pub fn parse(sexpr: &SExpr) -> Result { + match sexpr { + SExpr::Vec(vs, loc) => match (vs.get(0), vs.get(1)) { + (Some(SExpr::Annot("interface", _)), Some(SExpr::Word("func", _))) => { + let export = match vs.get(2) { + Some(SExpr::Vec(es, loc)) => match (es.get(0), es.get(1)) { + ( + Some(SExpr::Word("export", _)), + Some(SExpr::Quote(name, name_loc)), + ) => { + if es.len() == 2 { + id!(name, name_loc) + } else { + Err(parse_err!( + loc, + "too many elements for export declaration" + ))? + } + } + _ => Err(parse_err!(loc, "expected export declaration"))?, + }, + _ => Err(parse_err!(loc, "expected export declaration"))?, + }; + let mut params = Vec::new(); + let mut results = Vec::new(); + + for sexpr in &vs[3..] { + if FieldSyntax::starts_parsing(sexpr, "param") { + let param = FieldSyntax::parse(sexpr, "param")?; + params.push(param); + } else if FieldSyntax::starts_parsing(sexpr, "result") { + let result = FieldSyntax::parse(sexpr, "result")?; + results.push(result); + } else { + Err(parse_err!( + sexpr.location(), + "expected param or result field" + ))?; + } + } + + Ok(InterfaceFuncSyntax { + export, + params, + results, + }) + } + _ => Err(parse_err!(loc, "expected interface func declaration")), + }, + + _ => Err(parse_err!( + sexpr.location(), + "expected interface func declaration" + )), + } + } +} diff --git a/lucet-idl/src/witx/sexpr.rs b/lucet-idl/src/witx/sexpr.rs new file mode 100644 index 000000000..c01c83516 --- /dev/null +++ b/lucet-idl/src/witx/sexpr.rs @@ -0,0 +1,224 @@ +pub use super::lexer::LexError; +use super::lexer::{Lexer, LocatedError, LocatedToken, Token}; +use super::Location; +use std::path::{Path, PathBuf}; + +///! The s-expression parser turns a string into a stream of SExprs. +///! It uses the `Lexer` under the hood. +///! This implementation was heavily influenced by `cranelift-reader` + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum SExpr<'a> { + Vec(Vec>, Location), + Word(&'a str, Location), + Ident(&'a str, Location), + Quote(&'a str, Location), + /// Short for Annotation + Annot(&'a str, Location), +} + +impl<'a> SExpr<'a> { + pub fn location(&self) -> Location { + match self { + SExpr::Vec(_, loc) => loc.clone(), + SExpr::Word(_, loc) => loc.clone(), + SExpr::Ident(_, loc) => loc.clone(), + SExpr::Quote(_, loc) => loc.clone(), + SExpr::Annot(_, loc) => loc.clone(), + } + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Fail)] +pub enum SExprParseError { + #[fail(display = "Lexical error at {:?}: {}", _1, _0)] + Lex(LexError, Location), + #[fail(display = "Unexpected ')' at {:?}", _0)] + UnexpectedCloseParen(Location), + #[fail(display = "Unexpected end of input in {:?}", _0)] + UnexpectedEof(PathBuf), +} + +pub struct SExprParser<'a> { + lex: Lexer<'a>, + lookahead: Option>, + location: Location, +} + +impl<'a> SExprParser<'a> { + pub fn new>(text: &'a str, path: P) -> SExprParser<'_> { + SExprParser { + lex: Lexer::new(text, path.as_ref()), + lookahead: None, + location: Location { + path: path.as_ref().into(), + line: 0, + column: 0, + }, + } + } + fn consume(&mut self) -> Token<'a> { + self.lookahead.take().expect("no token to consume") + } + fn token(&mut self) -> Result>, SExprParseError> { + while self.lookahead == None { + match self.lex.next() { + Some(Ok(LocatedToken { token, location })) => { + self.location = location; + self.lookahead = Some(token) + } + Some(Err(LocatedError { error, location })) => { + self.location = location.clone(); + Err(SExprParseError::Lex(error, location))?; + } + None => break, + } + } + Ok(self.lookahead) + } + + pub fn match_sexpr(&mut self) -> Result, SExprParseError> { + let location = self.location.clone(); + match self.token()? { + Some(Token::LPar) => { + self.consume(); + let mut members = Vec::new(); + loop { + match self.token()? { + Some(Token::RPar) => { + self.consume(); + break; + } + _ => { + members.push(self.match_sexpr()?); + } + } + } + Ok(SExpr::Vec(members, location)) + } + Some(Token::Word(word)) => { + self.consume(); + Ok(SExpr::Word(word, location)) + } + Some(Token::Ident(id)) => { + self.consume(); + Ok(SExpr::Ident(id, location)) + } + Some(Token::Annot(id)) => { + self.consume(); + Ok(SExpr::Annot(id, location)) + } + Some(Token::Quote(q)) => { + self.consume(); + Ok(SExpr::Quote(q, location)) + } + Some(Token::RPar) => Err(SExprParseError::UnexpectedCloseParen(location)), + None => Err(SExprParseError::UnexpectedEof(self.location.path.clone())), + } + } + + pub fn match_sexprs(&mut self) -> Result>, SExprParseError> { + let mut sexprs = Vec::new(); + while self.token()?.is_some() { + sexprs.push(self.match_sexpr()?); + } + Ok(sexprs) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::path::PathBuf; + + fn loc(line: usize, col: usize) -> Location { + Location { + path: PathBuf::from("/test"), + line: line, + column: col, + } + } + + fn testparser(input: &str) -> SExprParser { + SExprParser::new(input, Path::new("/test")) + } + + #[test] + fn empty() { + let mut parser = testparser(""); + assert_eq!(parser.match_sexprs().expect("valid parse"), Vec::new()); + let mut parser = testparser(" ;; just a comment\n;;another"); + assert_eq!(parser.match_sexprs().expect("valid parse"), Vec::new()); + } + + #[test] + fn atoms() { + let mut parser = testparser("hello\n$world\n\"a quotation\""); + assert_eq!( + parser.match_sexprs().expect("valid parse"), + vec![ + SExpr::Word("hello", loc(1, 0)), + SExpr::Ident("world", loc(2, 0)), + SExpr::Quote("a quotation", loc(3, 0)), + ] + ); + } + + #[test] + fn lists() { + let mut parser = testparser("()"); + assert_eq!( + parser.match_sexprs().expect("valid parse"), + vec![SExpr::Vec(vec![], loc(1, 0))] + ); + + let mut parser = testparser("(hello\n$world\n\"a quotation\")"); + assert_eq!( + parser.match_sexprs().expect("valid parse"), + vec![SExpr::Vec( + vec![ + SExpr::Word("hello", loc(1, 1)), + SExpr::Ident("world", loc(2, 0)), + SExpr::Quote("a quotation", loc(3, 0)), + ], + loc(1, 0) + )] + ); + + let mut parser = testparser("((($deep)))"); + assert_eq!( + parser.match_sexprs().expect("valid parse"), + vec![SExpr::Vec( + vec![SExpr::Vec( + vec![SExpr::Vec(vec![SExpr::Ident("deep", loc(1, 3))], loc(1, 2))], + loc(1, 1) + )], + loc(1, 0) + )] + ); + } + + #[test] + fn errors() { + let mut parser = testparser("("); + assert_eq!( + parser.match_sexprs().err().expect("dies"), + SExprParseError::UnexpectedEof(PathBuf::from("/test")) + ); + let mut parser = testparser(")"); + assert_eq!( + parser.match_sexprs().err().expect("dies"), + SExprParseError::UnexpectedCloseParen(loc(1, 0)) + ); + let mut parser = testparser("())"); + assert_eq!( + parser.match_sexprs().err().expect("dies"), + SExprParseError::UnexpectedCloseParen(loc(1, 2)) + ); + let mut parser = testparser("$ ;; should be a lex error"); + assert_eq!( + parser.match_sexprs().err().expect("dies"), + SExprParseError::Lex(LexError::EmptyIdentifier, loc(1, 0),), + ); + } +} diff --git a/lucet-idl/src/witx/toplevel.rs b/lucet-idl/src/witx/toplevel.rs new file mode 100644 index 000000000..6af5bacf8 --- /dev/null +++ b/lucet-idl/src/witx/toplevel.rs @@ -0,0 +1,244 @@ +use super::parser::{DeclSyntax, ParseError, TopLevelSyntax}; +use super::sexpr::SExprParser; +use super::WitxError; +use std::collections::HashSet; +use std::fs; +use std::path::{Path, PathBuf}; + +trait WitxIo { + fn fgets(&self, path: &Path) -> Result; + fn canonicalize(&self, path: &Path) -> Result; +} + +struct Filesystem; + +impl WitxIo for Filesystem { + fn fgets(&self, path: &Path) -> Result { + fs::read_to_string(path).map_err(|e| WitxError::UseResolution(path.to_path_buf(), e)) + } + fn canonicalize(&self, path: &Path) -> Result { + path.canonicalize() + .map_err(|e| WitxError::UseResolution(path.to_path_buf(), e)) + } +} + +pub fn parse_witx>(i: P) -> Result, WitxError> { + parse_witx_with(i, &Filesystem) +} + +fn parse_witx_with>( + i: P, + witxio: &dyn WitxIo, +) -> Result, WitxError> { + let input_path = witxio.canonicalize(&i.as_ref())?; + + let input = witxio.fgets(&input_path)?; + + let toplevel = parse_toplevel(&input, &input_path)?; + let mut resolved = HashSet::new(); + resolved.insert(input_path.clone()); + let search_path = input_path.parent().unwrap_or(Path::new(".")); + resolve_uses(toplevel, &search_path, &mut resolved, witxio) +} + +fn parse_toplevel(source_text: &str, file_path: &Path) -> Result, WitxError> { + let mut sexpr_parser = SExprParser::new(source_text, file_path); + let sexprs = sexpr_parser.match_sexprs().map_err(WitxError::SExpr)?; + let top_levels = sexprs + .iter() + .map(|s| TopLevelSyntax::parse(s)) + .collect::, ParseError>>() + .map_err(WitxError::Parse)?; + Ok(top_levels) +} + +fn resolve_uses( + toplevel: Vec, + search_path: &Path, + used: &mut HashSet, + witxio: &dyn WitxIo, +) -> Result, WitxError> { + let mut decls = Vec::new(); + + for t in toplevel { + match t { + TopLevelSyntax::Decl(d) => decls.push(d), + TopLevelSyntax::Use(u) => { + let abs_path = witxio.canonicalize(&search_path.join(u.name))?; + // Include the decls from a use declaration only once + // in a given toplevel. Same idea as #pragma once. + if !used.contains(&abs_path) { + used.insert(abs_path.clone()); + + let source_text = witxio.fgets(&abs_path)?; + let inner_toplevels = parse_toplevel(&source_text, &abs_path)?; + + let inner_decls = resolve_uses(inner_toplevels, search_path, used, witxio)?; + decls.extend(inner_decls) + } + } + } + } + + Ok(decls) +} + +#[cfg(test)] +mod test { + use super::*; + use crate::witx::Location; + use std::collections::HashMap; + + struct MockFs { + map: HashMap<&'static str, &'static str>, + } + + impl MockFs { + pub fn new(strings: Vec<(&'static str, &'static str)>) -> Self { + MockFs { + map: strings.into_iter().collect(), + } + } + } + + impl WitxIo for MockFs { + fn fgets(&self, path: &Path) -> Result { + if let Some(entry) = self.map.get(path.to_str().unwrap()) { + Ok(entry.to_string()) + } else { + use std::io::{Error, ErrorKind}; + Err(WitxError::UseResolution( + path.to_path_buf(), + Error::new(ErrorKind::Other, "mock fs: file not found"), + )) + } + } + fn canonicalize(&self, path: &Path) -> Result { + Ok(PathBuf::from(path)) + } + } + + #[test] + fn empty() { + assert_eq!( + parse_witx_with(&Path::new("/a"), &MockFs::new(vec![("/a", ";; empty")])) + .expect("parse"), + Vec::new(), + ); + } + + #[test] + fn one_use() { + assert_eq!( + parse_witx_with( + &Path::new("/a"), + &MockFs::new(vec![("/a", "(use \"b\")"), ("/b", ";; empty")]) + ) + .expect("parse"), + Vec::new(), + ); + } + + #[test] + fn multi_use() { + use crate::witx::parser::*; + assert_eq!( + parse_witx_with( + &Path::new("/a"), + &MockFs::new(vec![ + ("/a", "(use \"b\")"), + ("/b", "(use \"c\")\n(typename $b_float f64)"), + ("/c", "(typename $c_int u32)") + ]) + ) + .expect("parse"), + vec![ + DeclSyntax::Typename(TypenameSyntax { + ident: IdentSyntax { + name: "c_int".to_owned(), + location: Location { + path: PathBuf::from("/c"), + line: 1, + column: 10, + } + }, + def: TypedefSyntax::Ident(DatatypeIdentSyntax::Builtin(BuiltinType::U32)) + }), + DeclSyntax::Typename(TypenameSyntax { + ident: IdentSyntax { + name: "b_float".to_owned(), + location: Location { + path: PathBuf::from("/b"), + line: 2, + column: 10, + } + }, + def: TypedefSyntax::Ident(DatatypeIdentSyntax::Builtin(BuiltinType::F64)) + }) + ], + ); + } + + #[test] + fn diamond_dependency() { + use crate::witx::parser::*; + assert_eq!( + parse_witx_with( + &Path::new("/a"), + &MockFs::new(vec![ + ("/a", "(use \"b\")\n(use \"c\")"), + ("/b", "(use \"d\")"), + ("/c", "(use \"d\")"), + ("/d", "(typename $d_char u8)") + ]) + ) + .expect("parse"), + vec![DeclSyntax::Typename(TypenameSyntax { + ident: IdentSyntax { + name: "d_char".to_owned(), + location: Location { + path: PathBuf::from("/d"), + line: 1, + column: 10, + } + }, + def: TypedefSyntax::Ident(DatatypeIdentSyntax::Builtin(BuiltinType::U8)) + })], + ); + } + + #[test] + fn use_not_found() { + match parse_witx_with(&Path::new("/a"), &MockFs::new(vec![("/a", "(use \"b\")")])) + .err() + .unwrap() + { + WitxError::UseResolution(path, _error) => assert_eq!(path, PathBuf::from("/b")), + e => panic!("wrong error: {:?}", e), + } + } + + #[test] + fn use_invalid() { + match parse_witx_with( + &Path::new("/a"), + &MockFs::new(vec![("/a", "(use bbbbbbb)")]), + ) + .err() + .unwrap() + { + WitxError::Parse(e) => { + assert_eq!(e.message, "invalid use declaration"); + assert_eq!( + e.location, + Location { + path: PathBuf::from("/a"), + line: 1, + column: 1 + } + ); + } + e => panic!("wrong error: {:?}", e), + } + } +} diff --git a/lucet-idl/src/witx/validate.rs b/lucet-idl/src/witx/validate.rs new file mode 100644 index 000000000..c285a8229 --- /dev/null +++ b/lucet-idl/src/witx/validate.rs @@ -0,0 +1,362 @@ +use super::ast::{ + AliasDatatype, BuiltinType, Datatype, DatatypeIdent, DatatypeVariant, Definition, Document, + Entry, EnumDatatype, FlagsDatatype, Id, IntRepr, InterfaceFunc, InterfaceFuncParam, Module, + ModuleDefinition, ModuleEntry, ModuleImport, ModuleImportVariant, StructDatatype, StructMember, + UnionDatatype, UnionVariant, +}; +use super::parser::{ + DatatypeIdentSyntax, DeclSyntax, EnumSyntax, FlagsSyntax, IdentSyntax, ImportTypeSyntax, + ModuleDeclSyntax, StructSyntax, TypedefSyntax, UnionSyntax, +}; +use super::Location; +use std::collections::HashMap; +use std::rc::Rc; + +#[derive(Debug, Fail)] +pub enum ValidationError { + #[fail(display = "Unknown name `{}`", name)] + UnknownName { name: String, location: Location }, + #[fail(display = "Redefinition of name `{}`", name)] + NameAlreadyExists { + name: String, + at_location: Location, + previous_location: Location, + }, + #[fail( + display = "Wrong kind of name `{}`: expected {}, got {}", + name, expected, got + )] + WrongKindName { + name: String, + location: Location, + expected: &'static str, + got: &'static str, + }, + #[fail(display = "Recursive definition of name `{}`", name)] + Recursive { name: String, location: Location }, + #[fail(display = "Invalid representation `{:?}`", repr)] + InvalidRepr { + repr: BuiltinType, + location: Location, + }, +} + +pub fn validate_document(decls: &[DeclSyntax]) -> Result { + let mut validator = DocValidation::new(); + let mut definitions = Vec::new(); + for d in decls { + definitions.push(validator.validate_decl(&d)?); + } + + Ok(Document { + entries: validator.entries, + definitions, + }) +} + +struct IdentValidation { + names: HashMap, +} + +impl IdentValidation { + fn new() -> Self { + Self { + names: HashMap::new(), + } + } + fn introduce(&mut self, syntax: &IdentSyntax) -> Result { + if let Some(introduced) = self.names.get(&syntax.name) { + Err(ValidationError::NameAlreadyExists { + name: syntax.name.clone(), + at_location: syntax.location.clone(), + previous_location: introduced.clone(), + }) + } else { + self.names + .insert(syntax.name.clone(), syntax.location.clone()); + Ok(Id::new(&syntax.name)) + } + } + + fn get(&self, syntax: &IdentSyntax) -> Result { + if self.names.get(&syntax.name).is_some() { + Ok(Id::new(&syntax.name)) + } else { + Err(ValidationError::UnknownName { + name: syntax.name.clone(), + location: syntax.location.clone(), + }) + } + } +} + +struct DocValidation { + scope: IdentValidation, + pub entries: HashMap, +} + +impl DocValidation { + fn new() -> Self { + Self { + scope: IdentValidation::new(), + entries: HashMap::new(), + } + } + + fn validate_decl(&mut self, decl: &DeclSyntax) -> Result { + match decl { + DeclSyntax::Typename(decl) => { + let name = self.scope.introduce(&decl.ident)?; + let variant = + match &decl.def { + TypedefSyntax::Ident(syntax) => DatatypeVariant::Alias(AliasDatatype { + name: name.clone(), + to: self.validate_datatype_ident(&syntax)?, + }), + TypedefSyntax::Enum(syntax) => DatatypeVariant::Enum(self.validate_enum( + &name, + &syntax, + &decl.ident.location, + )?), + TypedefSyntax::Flags(syntax) => DatatypeVariant::Flags( + self.validate_flags(&name, &syntax, &decl.ident.location)?, + ), + TypedefSyntax::Struct(syntax) => DatatypeVariant::Struct( + self.validate_struct(&name, &syntax, &decl.ident.location)?, + ), + TypedefSyntax::Union(syntax) => DatatypeVariant::Union( + self.validate_union(&name, &syntax, &decl.ident.location)?, + ), + }; + let rc_datatype = Rc::new(Datatype { + name: name.clone(), + variant, + }); + self.entries + .insert(name, Entry::Datatype(Rc::downgrade(&rc_datatype))); + Ok(Definition::Datatype(rc_datatype)) + } + DeclSyntax::Module(syntax) => { + let name = self.scope.introduce(&syntax.name)?; + let mut module_validator = ModuleValidation::new(self); + let definitions = syntax + .decls + .iter() + .map(|d| module_validator.validate_decl(&d)) + .collect::, _>>()?; + + let rc_module = Rc::new(Module { + name: name.clone(), + definitions, + entries: module_validator.entries, + }); + self.entries + .insert(name, Entry::Module(Rc::downgrade(&rc_module))); + Ok(Definition::Module(rc_module)) + } + } + } + + fn validate_datatype_ident( + &self, + syntax: &DatatypeIdentSyntax, + ) -> Result { + match syntax { + DatatypeIdentSyntax::Builtin(b) => Ok(DatatypeIdent::Builtin(*b)), + DatatypeIdentSyntax::Array(a) => Ok(DatatypeIdent::Array(Box::new( + self.validate_datatype_ident(&a)?, + ))), + DatatypeIdentSyntax::Ident(i) => { + let id = self.scope.get(i)?; + match self.entries.get(&id) { + Some(Entry::Datatype(weak_d)) => Ok(DatatypeIdent::Ident( + weak_d.upgrade().expect("weak backref to defined type"), + )), + Some(e) => Err(ValidationError::WrongKindName { + name: i.name.clone(), + location: i.location.clone(), + expected: "datatype", + got: e.kind(), + }), + None => Err(ValidationError::Recursive { + name: i.name.clone(), + location: i.location.clone(), + }), + } + } + } + } + + fn validate_enum( + &self, + name: &Id, + syntax: &EnumSyntax, + location: &Location, + ) -> Result { + let mut enum_scope = IdentValidation::new(); + let repr = validate_int_repr(&syntax.repr, location)?; + let variants = syntax + .members + .iter() + .map(|i| enum_scope.introduce(i)) + .collect::, _>>()?; + + Ok(EnumDatatype { + name: name.clone(), + repr, + variants, + }) + } + + fn validate_flags( + &self, + name: &Id, + syntax: &FlagsSyntax, + location: &Location, + ) -> Result { + let mut flags_scope = IdentValidation::new(); + let repr = validate_int_repr(&syntax.repr, location)?; + let flags = syntax + .flags + .iter() + .map(|i| flags_scope.introduce(i)) + .collect::, _>>()?; + + Ok(FlagsDatatype { + name: name.clone(), + repr, + flags, + }) + } + + fn validate_struct( + &self, + name: &Id, + syntax: &StructSyntax, + _location: &Location, + ) -> Result { + let mut member_scope = IdentValidation::new(); + let members = syntax + .fields + .iter() + .map(|f| { + Ok(StructMember { + name: member_scope.introduce(&f.name)?, + type_: self.validate_datatype_ident(&f.type_)?, + }) + }) + .collect::, _>>()?; + + Ok(StructDatatype { + name: name.clone(), + members, + }) + } + + fn validate_union( + &self, + name: &Id, + syntax: &UnionSyntax, + _location: &Location, + ) -> Result { + let mut variant_scope = IdentValidation::new(); + let variants = syntax + .fields + .iter() + .map(|f| { + Ok(UnionVariant { + name: variant_scope.introduce(&f.name)?, + type_: self.validate_datatype_ident(&f.type_)?, + }) + }) + .collect::, _>>()?; + + Ok(UnionDatatype { + name: name.clone(), + variants, + }) + } +} + +fn validate_int_repr(type_: &BuiltinType, location: &Location) -> Result { + match type_ { + BuiltinType::U8 => Ok(IntRepr::I8), + BuiltinType::U16 => Ok(IntRepr::I16), + BuiltinType::U32 => Ok(IntRepr::I32), + BuiltinType::U64 => Ok(IntRepr::I64), + _ => Err(ValidationError::InvalidRepr { + repr: type_.clone(), + location: location.clone(), + }), + } +} + +struct ModuleValidation<'a> { + doc: &'a DocValidation, + scope: IdentValidation, + pub entries: HashMap, +} + +impl<'a> ModuleValidation<'a> { + fn new(doc: &'a DocValidation) -> Self { + Self { + doc, + scope: IdentValidation::new(), + entries: HashMap::new(), + } + } + + fn validate_decl( + &mut self, + decl: &ModuleDeclSyntax, + ) -> Result { + match decl { + ModuleDeclSyntax::Import(syntax) => { + let name = self.scope.introduce(&syntax.name)?; + let variant = match syntax.type_ { + ImportTypeSyntax::Memory => ModuleImportVariant::Memory, + }; + let rc_import = Rc::new(ModuleImport { + name: name.clone(), + variant, + }); + self.entries + .insert(name, ModuleEntry::Import(Rc::downgrade(&rc_import))); + Ok(ModuleDefinition::Import(rc_import)) + } + ModuleDeclSyntax::Func(syntax) => { + let name = self.scope.introduce(&syntax.export)?; + let mut argnames = IdentValidation::new(); + let params = syntax + .params + .iter() + .map(|f| { + Ok(InterfaceFuncParam { + name: argnames.introduce(&f.name)?, + type_: self.doc.validate_datatype_ident(&f.type_)?, + }) + }) + .collect::, _>>()?; + let results = syntax + .results + .iter() + .map(|f| { + Ok(InterfaceFuncParam { + name: argnames.introduce(&f.name)?, + type_: self.doc.validate_datatype_ident(&f.type_)?, + }) + }) + .collect::, _>>()?; + + let rc_func = Rc::new(InterfaceFunc { + name: name.clone(), + params, + results, + }); + self.entries + .insert(name, ModuleEntry::Func(Rc::downgrade(&rc_func))); + Ok(ModuleDefinition::Func(rc_func)) + } + } + } +} diff --git a/lucet-idl/tests/example.rs b/lucet-idl/tests/example.rs index 85f22ff21..4451eff05 100644 --- a/lucet-idl/tests/example.rs +++ b/lucet-idl/tests/example.rs @@ -1,26 +1,21 @@ use lucet_idl; use std::fs::File; -use std::io::prelude::*; +use std::path::Path; use std::process::Command; use tempfile::TempDir; #[test] fn compile_c_guest() { - let mut source = String::new(); - File::open("tests/example.idl") - .expect("open example.idl") - .read_to_string(&mut source) - .expect("read example.idl"); - let config = lucet_idl::Config { backend: lucet_idl::Backend::CGuest, + witx: false, }; let tempdir = TempDir::new().expect("create tempdir"); lucet_idl::run( &config, - &source, + Path::new("tests/example.idl"), Box::new(File::create(tempdir.path().join("example.h")).expect("create file")), ) .expect("run lucet_idl"); @@ -53,13 +48,10 @@ fn compile_and_test_rust_host() { */ fn compile_and_test_rust(backend: lucet_idl::Backend) { - let mut source = String::new(); - File::open("tests/example.idl") - .expect("open example.idl") - .read_to_string(&mut source) - .expect("read example.idl"); - - let config = lucet_idl::Config { backend }; + let config = lucet_idl::Config { + backend, + witx: false, + }; let tempdir = TempDir::new().expect("create tempdir"); @@ -67,7 +59,7 @@ fn compile_and_test_rust(backend: lucet_idl::Backend) { lucet_idl::run( &config, - &source, + Path::new("tests/example.idl"), Box::new(File::create(gen_file.clone()).expect("create file")), ) .expect("run lucet_idl"); diff --git a/lucet-idl/tests/typenames.witx b/lucet-idl/tests/typenames.witx new file mode 100644 index 000000000..e322b66a6 --- /dev/null +++ b/lucet-idl/tests/typenames.witx @@ -0,0 +1,719 @@ +;; Type names used by the wasi_unstable module type. +;; +;; Some content here is derived from [CloudABI](https://github.com/NuxiNL/cloudabi). + +(typename $size_t u32) +(typename $uintptr_t u32) +(typename $string_array (array string)) + +;; Non-negative file size or length of a region within a file. +(typename $filesize_t u64) + +;; Timestamp in nanoseconds. +(typename $timestamp_t u64) + +;; Identifiers for clocks. +(typename $clockid_t + (enum u32 + ;; The store-wide monotonic clock, which is defined as a clock measuring + ;; real time, whose value cannot be adjusted and which cannot have negative + ;; clock jumps. The epoch of this clock is undefined. The absolute time + ;; value of this clock therefore has no meaning. + $CLOCK_MONOTONIC + ;; The CPU-time clock associated with the current process. + $CLOCK_PROCESS_CPUTIME_ID + ;; The clock measuring real time. Time value zero corresponds with + ;; 1970-01-01T00:00:00Z. + $CLOCK_REALTIME + ;; The CPU-time clock associated with the current thread. + $CLOCK_THREAD_CPUTIME_ID + ) +) + +;; Error codes returned by functions. +;; Not all of these error codes are returned by the functions provided by this +;; API; some are used in higher-level library layers, and others are provided +;; merely for alignment with POSIX. +(typename $errno_t + (enum u16 + ;; No error occurred. System call completed successfully. + $ESUCCESS + ;; Argument list too long. + $E2BIG + ;; Permission denied. + $EACCES + ;; Address in use. + $EADDRINUSE + ;; Address not available. + $EADDRNOTAVAIL + ;; Address family not supported. + $EAFNOSUPPORT + ;; Resource unavailable, or operation would block. + $EAGAIN + ;; Connection already in progress. + $EALREADY + ;; Bad file descriptor. + $EBADF + ;; Bad message. + $EBADMSG + ;; Device or resource busy. + $EBUSY + ;; Operation canceled. + $ECANCELED + ;; No child processes. + $ECHILD + ;; Connection aborted. + $ECONNABORTED + ;; Connection refused. + $ECONNREFUSED + ;; Connection reset. + $ECONNRESET + ;; Resource deadlock would occur. + $EDEADLK + ;; Destination address required. + $EDESTADDRREQ + ;; Mathematics argument out of domain of function. + $EDOM + ;; Reserved. + $EDQUOT + ;; File exists. + $EEXIST + ;; Bad address. + $EFAULT + ;; File too large. + $EFBIG + ;; Host is unreachable. + $EHOSTUNREACH + ;; Identifier removed. + $EIDRM + ;; Illegal byte sequence. + $EILSEQ + ;; Operation in progress. + $EINPROGRESS + ;; Interrupted function. + $EINTR + ;; Invalid argument. + $EINVAL + ;; I/O error. + $EIO + ;; Socket is connected. + $EISCONN + ;; Is a directory. + $EISDIR + ;; Too many levels of symbolic links. + $ELOOP + ;; File descriptor value too large. + $EMFILE + ;; Too many links. + $EMLINK + ;; Message too large. + $EMSGSIZE + ;; Reserved. + $EMULTIHOP + ;; Filename too long. + $ENAMETOOLONG + ;; Network is down. + $ENETDOWN + ;; Connection aborted by network. + $ENETRESET + ;; Network unreachable. + $ENETUNREACH + ;; Too many files open in system. + $ENFILE + ;; No buffer space available. + $ENOBUFS + ;; No such device. + $ENODEV + ;; No such file or directory. + $ENOENT + ;; Executable file format error. + $ENOEXEC + ;; No locks available. + $ENOLCK + ;; Reserved. + $ENOLINK + ;; Not enough space. + $ENOMEM + ;; No message of the desired type. + $ENOMSG + ;; Protocol not available. + $ENOPROTOOPT + ;; No space left on device. + $ENOSPC + ;; Function not supported. + $ENOSYS + ;; The socket is not connected. + $ENOTCONN + ;; Not a directory or a symbolic link to a directory. + $ENOTDIR + ;; Directory not empty. + $ENOTEMPTY + ;; State not recoverable. + $ENOTRECOVERABLE + ;; Not a socket. + $ENOTSOCK + ;; Not supported, or operation not supported on socket. + $ENOTSUP + ;; Inappropriate I/O control operation. + $ENOTTY + ;; No such device or address. + $ENXIO + ;; Value too large to be stored in data type. + $EOVERFLOW + ;; Previous owner died. + $EOWNERDEAD + ;; Operation not permitted. + $EPERM + ;; Broken pipe. + $EPIPE + ;; Protocol error. + $EPROTO + ;; Protocol not supported. + $EPROTONOSUPPORT + ;; Protocol wrong type for socket. + $EPROTOTYPE + ;; Result too large. + $ERANGE + ;; Read-only file system. + $EROFS + ;; Invalid seek. + $ESPIPE + ;; No such process. + $ESRCH + ;; Reserved. + $ESTALE + ;; Connection timed out. + $ETIMEDOUT + ;; Text file busy. + $ETXTBSY + ;; Cross-device link. + $EXDEV + ;; Extension: Capabilities insufficient. + $ENOTCAPABLE + ) +) + +;; File descriptor rights, determining which actions may be performed. +(typename $rights_t + (flags u64 + ;; The right to invoke `__wasi_fd_datasync()`. + ;; + ;; If `__WASI_RIGHT_PATH_OPEN` is set, includes the right to invoke + ;; `__wasi_path_open()` with `__WASI_FDFLAG_DSYNC`. + (flag $RIGHT_FD_DATASYNC) + ;; The right to invoke `__wasi_fd_read()` and `__wasi_sock_recv()`. + ;; + ;; If `__WASI_RIGHT_FD_SEEK` is set, includes the right to invoke + ;; `__wasi_fd_pread()`. + (flag $RIGHT_FD_READ) + ;; The right to invoke `__wasi_fd_seek()`. This flag implies `__WASI_RIGHT_FD_TELL`. + (flag $RIGHT_FD_SEEK) + ;; The right to invoke `__wasi_fd_fdstat_set_flags()`. + (flag $RIGHT_FD_FDSTAT_SET_FLAGS) + ;; The right to invoke `__wasi_fd_sync()`. + ;; + ;; If `__WASI_RIGHT_PATH_OPEN` is set, includes the right to invoke + ;; `__wasi_path_open()` with `__WASI_FDFLAG_RSYNC` and `__WASI_FDFLAG_DSYNC`. + (flag $RIGHT_FD_SYNC) + ;; The right to invoke `__wasi_fd_seek()` in such a way that the file offset + ;; remains unaltered (i.e., `__WASI_WHENCE_CUR` with offset zero), or to + ;; invoke `__wasi_fd_tell()`. + (flag $RIGHT_FD_TELL) + ;; The right to invoke `__wasi_fd_write()` and `__wasi_sock_send()`. + ;; If `__WASI_RIGHT_FD_SEEK` is set, includes the right to invoke `__wasi_fd_pwrite()`. + (flag $RIGHT_FD_WRITE) + ;; The right to invoke `__wasi_fd_advise()`. + (flag $RIGHT_FD_ADVISE) + ;; The right to invoke `__wasi_fd_allocate()`. + (flag $RIGHT_FD_ALLOCATE) + ;; The right to invoke `__wasi_path_create_directory()`. + (flag $RIGHT_PATH_CREATE_DIRECTORY) + ;; If `__WASI_RIGHT_PATH_OPEN` is set, the right to invoke `__wasi_path_open()` with `__WASI_O_CREAT`. + (flag $RIGHT_PATH_CREATE_FILE) + ;; The right to invoke `__wasi_path_link()` with the file descriptor as the + ;; source directory. + (flag $RIGHT_PATH_LINK_SOURCE) + ;; The right to invoke `__wasi_path_link()` with the file descriptor as the + ;; target directory. + (flag $RIGHT_PATH_LINK_TARGET) + ;; The right to invoke `__wasi_path_open()`. + (flag $RIGHT_PATH_OPEN) + ;; The right to invoke `__wasi_fd_readdir()`. + (flag $RIGHT_FD_READDIR) + ;; The right to invoke `__wasi_path_readlink()`. + (flag $RIGHT_PATH_READLINK) + ;; The right to invoke `__wasi_path_rename()` with the file descriptor as the source directory. + (flag $RIGHT_PATH_RENAME_SOURCE) + ;; The right to invoke `__wasi_path_rename()` with the file descriptor as the target directory. + (flag $RIGHT_PATH_RENAME_TARGET) + ;; The right to invoke `__wasi_path_filestat_get()`. + (flag $RIGHT_PATH_FILESTAT_GET) + ;; The right to change a file's size (there is no `__wasi_path_filestat_set_size()`). + ;; If `__WASI_RIGHT_PATH_OPEN` is set, includes the right to invoke `__wasi_path_open()` with `__WASI_O_TRUNC`. + (flag $RIGHT_PATH_FILESTAT_SET_SIZE) + ;; The right to invoke `__wasi_path_filestat_set_times()`. + (flag $RIGHT_PATH_FILESTAT_SET_TIMES) + ;; The right to invoke `__wasi_fd_filestat_get()`. + (flag $RIGHT_FD_FILESTAT_GET) + ;; The right to invoke `__wasi_fd_filestat_set_size()`. + (flag $RIGHT_FD_FILESTAT_SET_SIZE) + ;; The right to invoke `__wasi_fd_filestat_set_times()`. + (flag $RIGHT_FD_FILESTAT_SET_TIMES) + ;; The right to invoke `__wasi_path_symlink()`. + (flag $RIGHT_PATH_SYMLINK) + ;; The right to invoke `__wasi_path_unlink_file()`. + (flag $RIGHT_PATH_UNLINK_FILE) + ;; The right to invoke `__wasi_path_remove_directory()`. + (flag $RIGHT_PATH_REMOVE_DIRECTORY) + ;; If `__WASI_RIGHT_FD_READ` is set, includes the right to invoke `__wasi_poll_oneoff()` to subscribe to `__WASI_EVENTTYPE_FD_READ`. + ;; If `__WASI_RIGHT_FD_WRITE` is set, includes the right to invoke `__wasi_poll_oneoff()` to subscribe to `__WASI_EVENTTYPE_FD_WRITE`. + (flag $RIGHT_POLL_FD_READWRITE) + ;; The right to invoke `__wasi_sock_shutdown()`. + (flag $RIGHT_SOCK_SHUTDOWN) + ) +) + +;; A file descriptor index. +(typename $fd_t u32) + +;; A region of memory for scatter/gather reads. +(typename $iovec_t + (struct + ;; The address and length of the buffer to be filled. + (field $buf $uintptr_t) + (field $buf_len $size_t) + ) +) + +;; A region of memory for scatter/gather writes. +(typename $ciovec_t + (struct + ;; The address and length of the buffer to be written. + (field $buf $uintptr_t) + (field $buf_len $size_t) + ) +) + +(typename $iovec_t_array (array $iovec_t)) +(typename $ciovec_t_array (array $ciovec_t)) + +;; Relative offset within a file. +(typename $filedelta_t s64) + +;; The position relative to which to set the offset of the file descriptor. +(typename $whence_t + (enum u8 + ;; Seek relative to current position. + $WHENCE_CUR + ;; Seek relative to end-of-file. + $WHENCE_END + ;; Seek relative to start-of-file. + $WHENCE_SET + ) +) + +;; A reference to the offset of a directory entry. +(typename $dircookie_t u64) + +;; The type for the $d_namelen field of $dirent_t. +(typename $dirnamelen_t u32) + +;; File serial number that is unique within its file system. +(typename $inode_t u64) + +;; The type of a file descriptor or file. +(typename $filetype_t + (enum u8 + ;; The type of the file descriptor or file is unknown or is different from any of the other types specified. + $FILETYPE_UNKNOWN + ;; The file descriptor or file refers to a block device inode. + $FILETYPE_BLOCK_DEVICE + ;; The file descriptor or file refers to a character device inode. + $FILETYPE_CHARACTER_DEVICE + ;; The file descriptor or file refers to a directory inode. + $FILETYPE_DIRECTORY + ;; The file descriptor or file refers to a regular file inode. + $FILETYPE_REGULAR_FILE + ;; The file descriptor or file refers to a datagram socket. + $FILETYPE_SOCKET_DGRAM + ;; The file descriptor or file refers to a byte-stream socket. + $FILETYPE_SOCKET_STREAM + ;; The file refers to a symbolic link inode. + $FILETYPE_SYMBOLIC_LINK + ) +) + +;; A directory entry. +(typename $dirent_t + (struct + ;; The offset of the next directory entry stored in this directory. + (field $d_next $dircookie_t) + ;; The serial number of the file referred to by this directory entry. + (field $d_ino $inode_t) + ;; The length of the name of the directory entry. + (field $d_namlen $dirnamelen_t) + ;; The type of the file referred to by this directory entry. + (field $d_type $filetype_t) + ) +) + +;; File or memory access pattern advisory information. +(typename $advice_t + (enum u8 + ;; The application expects that it will not access the specified data in the near future. + $ADVICE_DONTNEED + ;; The application expects to access the specified data once and then not reuse it thereafter. + $ADVICE_NOREUSE + ;; The application has no advice to give on its behavior with respect to the specified data. + $ADVICE_NORMAL + ;; The application expects to access the specified data in a random order. + $ADVICE_RANDOM + ;; The application expects to access the specified data sequentially from lower offsets to higher offsets. + $ADVICE_SEQUENTIAL + ;; The application expects to access the specified data in the near future. + $ADVICE_WILLNEED + ) +) + +;; File descriptor flags. +(typename $fdflags_t + (flags u16 + ;; Append mode: Data written to the file is always appended to the file's end. + (flag $FDFLAG_APPEND) + ;; Write according to synchronized I/O data integrity completion. Only the data stored in the file is synchronized. + (flag $FDFLAG_DSYNC) + ;; Non-blocking mode. + (flag $FDFLAG_NONBLOCK) + ;; Synchronized read I/O operations. + (flag $FDFLAG_RSYNC) + ;; Write according to synchronized I/O file integrity completion. In + ;; addition to synchronizing the data stored in the file, the implementation + ;; may also synchronously update the file's metadata. + (flag $FDFLAG_SYNC) + ) +) + +;; File descriptor attributes. +(typename $fdstat_t + (struct + ;; File type. + (field $fs_filetype $filetype_t) + ;; File descriptor flags. + (field $fs_flags $fdflags_t) + ;; Rights that apply to this file descriptor. + (field $fs_rights_base $rights_t) + ;; Maximum set of rights that may be installed on new file descriptors that + ;; are created through this file descriptor, e.g., through + ;; `__wasi_path_open()`. + (field $fs_rights_inheriting $rights_t) + ) +) + +;; Identifier for a device containing a file system. Can be used in combination +;; with __wasi_inode_t to uniquely identify a file or directory in the +;; filesystem. +(typename $device_t u64) + + +;; Which file time attributes to adjust. +(typename $fstflags_t + (flags u16 + ;; Adjust the last data access timestamp to the value stored in __wasi_filestat_t::st_atim. + (flag $FILESTAT_SET_ATIM) + ;; Adjust the last data access timestamp to the time of clock `__WASI_CLOCK_REALTIME`. + (flag $FILESTAT_SET_ATIM_NOW) + ;; Adjust the last data modification timestamp to the value stored in __wasi_filestat_t::st_mtim. + (flag $FILESTAT_SET_MTIM) + ;; Adjust the last data modification timestamp to the time of clock `__WASI_CLOCK_REALTIME`. + (flag $FILESTAT_SET_MTIM_NOW) + ) +) + +;; Flags determining the method of how paths are resolved. +(typename $lookupflags_t + (flags u32 + ;; As long as the resolved path corresponds to a symbolic link, it is expanded. + (flag $LOOKUP_SYMLINK_FOLLOW) + ) +) + +;; Open flags used by `__wasi_path_open()`. +(typename $oflags_t + (flags u16 + ;; Create file if it does not exist. + (flag $O_CREAT) + ;; Fail if not a directory. + (flag $O_DIRECTORY) + ;; Fail if file already exists. + (flag $O_EXCL) + ;; Truncate file to size 0. + (flag $O_TRUNC) + ) +) + +;; Number of hard links to an inode. +(typename $linkcount_t u32) + +;; File attributes. +(typename $filestat_t + (struct + ;; Device ID of device containing the file. + (field $st_dev $device_t) + ;; File serial number. + (field $st_ino $inode_t) + ;; File type. + (field $st_filetype $filetype_t) + ;; Number of hard links to the file. + (field $st_nlink $linkcount_t) + ;; For regular files, the file size in bytes. For symbolic links, the length in bytes of the pathname contained in the symbolic link. + (field $st_size $filesize_t) + ;; Last data access timestamp. + (field $st_atim $timestamp_t) + ;; Last data modification timestamp. + (field $st_mtim $timestamp_t) + ;; Last file status change timestamp. + (field $st_ctim $timestamp_t) + ) +) + +;; User-provided value that may be attached to objects that is retained when +;; extracted from the implementation. +(typename $userdata_t u64) + +;; Type of a subscription to an event or its occurrence. +(typename $eventtype_t + (flags u8 + ;; The time value of clock __wasi_subscription_t::u.clock.clock_id has + ;; reached timestamp __wasi_subscription_t::u.clock.timeout. + (flag $EVENTTYPE_CLOCK) + ;; File descriptor __wasi_subscription_t::u.fd_readwrite.fd has data + ;; available for reading. This event always triggers for regular files. + (flag $EVENTTYPE_FD_READ) + ;; File descriptor __wasi_subscription_t::u.fd_readwrite.fd has capacity + ;; available for writing. This event always triggers for regular files. + (flag $EVENTTYPE_FD_WRITE) + ) +) + +;; The state of the file descriptor subscribed to with +;; `__WASI_EVENTTYPE_FD_READ` or `__WASI_EVENTTYPE_FD_WRITE`. +(typename $eventrwflags_t + (flags u16 + ;; The peer of this socket has closed or disconnected. + (flag $EVENT_FD_READWRITE_HANGUP) + ) +) + +;; The contents of an $event_t when type is `__WASI_EVENTTYPE_FD_READ` or +;; `__WASI_EVENTTYPE_FD_WRITE`. +(typename $event_fd_readwrite_t + (struct + ;; The number of bytes available for reading or writing. + (field $nbytes $filesize_t) + ;; The state of the file descriptor. + (field $flags $eventrwflags_t) + ) +) + +;; The contents of an $event_t. +(typename $event_u + (union + ;; When type is `__WASI_EVENTTYPE_FD_READ` or `__WASI_EVENTTYPE_FD_WRITE`: + (field $fd_readwrite $event_fd_readwrite_t) + ) +) + +;; An event that occurred. +(typename $event_t + (struct + ;; User-provided value that got attached to __wasi_subscription_t::userdata. + (field $userdata $userdata_t) + ;; If non-zero, an error that occurred while processing the subscription request. + (field $error $errno_t) + ;; The type of the event that occurred. + (field $type $eventtype_t) + ;; The contents of the event. + (field $u $event_u) + ) +) + +;; Flags determining how to interpret the timestamp provided in +;; __wasi_subscription_t::u.clock.timeout. +(typename $subclockflags_t + (flags u16 + ;; If set, treat the timestamp provided in + ;; __wasi_subscription_t::u.clock.timeout as an absolute timestamp of clock + ;; __wasi_subscription_t::u.clock.clock_id. If clear, treat the timestamp + ;; provided in __wasi_subscription_t::u.clock.timeout relative to the + ;; current time value of clock __wasi_subscription_t::u.clock.clock_id. + (flag $SUBSCRIPTION_CLOCK_ABSTIME) + ) +) + +;; The contents of a $subscription_t when type is `__WASI_EVENTTYPE_CLOCK`. +(typename $subscription_clock_t + (struct + ;; The user-defined unique identifier of the clock. + (field $identifier $userdata_t) + ;; The clock against which to compare the timestamp. + (field $clock_id $clockid_t) + ;; The absolute or relative timestamp. + (field $timeout $timestamp_t) + ;; The amount of time that the implementation may wait additionally + ;; to coalesce with other events. + ;; + ;; Flags specifying whether the timeout is absolute or relative + (field $precision $timestamp_t) + ) +) + +;; The contents of a $subscription_t when type is type is +;; `__WASI_EVENTTYPE_FD_READ` or `__WASI_EVENTTYPE_FD_WRITE`. +(typename $subscription_fd_readwrite_t + (struct + ;; The file descriptor on which to wait for it to become ready for reading or writing. + (field $file_descriptor $fd_t) + ) +) + +;; The contents of a $subscription_t. +(typename $subscription_u + (union + ;; When type is `__WASI_EVENTTYPE_CLOCK`: + (field $clock $subscription_clock_t) + ;; When type is `__WASI_EVENTTYPE_FD_READ` or `__WASI_EVENTTYPE_FD_WRITE`: + (field $fd_readwrite $subscription_fd_readwrite_t) + ) +) + +;; Subscription to an event. +(typename $subscription_t + (struct + ;; User-provided value that is attached to the subscription in the + ;; implementation and returned through __wasi_event_t::userdata. + (field $userdata $userdata_t) + ;; The type of the event to which to subscribe. + (field $type $eventtype_t) + ;; The contents of the subscription. + (field $u $subscription_u) + ) +) + +;; Exit code generated by a process when exiting. +(typename $exitcode_t u32) + +;; Signal condition. +(typename $signal_t + (enum u8 + ;; Process abort signal. + ;; Action: Terminates the process. + $SIGABRT + ;; Alarm clock. + ;; Action: Terminates the process. + $SIGALRM + ;; Access to an undefined portion of a memory object. + ;; Action: Terminates the process. + $SIGBUS + ;; Child process terminated, stopped, or continued. + ;; Action: Ignored. + $SIGCHLD + ;; Continue executing, if stopped. + ;; Action: Continues executing, if stopped. + $SIGCONT + ;; Erroneous arithmetic operation. + ;; Action: Terminates the process. + $SIGFPE + ;; Hangup. + ;; Action: Terminates the process. + $SIGHUP + ;; Illegal instruction. + ;; Action: Terminates the process. + $SIGILL + ;; Terminate interrupt signal. + ;; Action: Terminates the process. + $SIGINT + ;; Kill. + ;; Action: Terminates the process. + $SIGKILL + ;; Write on a pipe with no one to read it. + ;; Action: Ignored. + $SIGPIPE + ;; Terminal quit signal. + ;; Action: Terminates the process. + $SIGQUIT + ;; Invalid memory reference. + ;; Action: Terminates the process. + $SIGSEGV + ;; Stop executing. + ;; Action: Stops executing. + $SIGSTOP + ;; Bad system call. + ;; Action: Terminates the process. + $SIGSYS + ;; Termination signal. + ;; Action: Terminates the process. + $SIGTERM + ;; Trace/breakpoint trap. + ;; Action: Terminates the process. + $SIGTRAP + ;; Terminal stop signal. + ;; Action: Stops executing. + $SIGTSTP + ;; Background process attempting read. + ;; Action: Stops executing. + $SIGTTIN + ;; Background process attempting write. + ;; Action: Stops executing. + $SIGTTOU + ;; High bandwidth data is available at a socket. + ;; Action: Ignored. + $SIGURG + ;; User-defined signal 1. + ;; Action: Terminates the process. + $SIGUSR1 + ;; User-defined signal 2. + ;; Action: Terminates the process. + $SIGUSR2 + ;; Virtual timer expired. + ;; Action: Terminates the process. + $SIGVTALRM + ;; CPU time limit exceeded. + ;; Action: Terminates the process. + $SIGXCPU + ;; File size limit exceeded. + ;; Action: Terminates the process. + $SIGXFSZ + ) +) + +;; Flags provided to `__wasi_sock_recv()`. +(typename $riflags_t + (flags u16 + ;; Returns the message without removing it from the socket's receive queue. + (flag $SOCK_RECV_PEEK) + ;; On byte-stream sockets, block until the full amount of data can be returned. + (flag $SOCK_RECV_WAITALL) + ) +) + +;; Flags returned by `__wasi_sock_recv()`. +(typename $roflags_t + (flags u16 + ;; Returned by `__wasi_sock_recv()`: Message data has been truncated. + (flag $SOCK_RECV_DATA_TRUNCATED) + ) +) + +;; Flags provided to `__wasi_sock_send()`. As there are currently no flags +;; defined, it must be set to zero. +(typename $siflags_t u16) + +;; Which channels on a socket to shut down. +(typename $sdflags_t + (flags u8 + ;; Disables further receive operations. + (flag $SHUT_RD) + ;; Disables further send operations. + (flag $SHUT_WR) + ) +) diff --git a/lucet-idl/tests/wasi_unstable.rs b/lucet-idl/tests/wasi_unstable.rs new file mode 100644 index 000000000..59af0ba55 --- /dev/null +++ b/lucet-idl/tests/wasi_unstable.rs @@ -0,0 +1,8 @@ +use lucet_idl; +use std::path::Path; + +#[test] +fn validate_wasi_unstable() { + lucet_idl::load_witx(Path::new("tests/wasi_unstable.witx")) + .expect("parse and validate wasi_unstable.witx"); +} diff --git a/lucet-idl/tests/wasi_unstable.witx b/lucet-idl/tests/wasi_unstable.witx new file mode 100644 index 000000000..ace70fcfc --- /dev/null +++ b/lucet-idl/tests/wasi_unstable.witx @@ -0,0 +1,516 @@ +;; The wasi_unstable module type. +;; +;; Some content here is derived from [CloudABI](https://github.com/NuxiNL/cloudabi). + +(use "typenames.witx") + +(module $wasi_unstable + ;; Linear memory to be accessed by WASI functions that need it. + (import "memory" (memory)) + + ;; Read command-line argument data. + ;; The size of the array should match that returned by `wasi_args_sizes_get()` + (@interface func (export "args_get") + (result $error $errno_t) + (result $argv $string_array) + ) + ;; Return command-line argument data sizes. + (@interface func (export "args_sizes_get") + (result $error $errno_t) + ;; The number of arguments. + (result $argc $size_t) + ;; The size of the argument string data. + (result $argv_buf_size $size_t) + ) + + ;; Read environment variable data. + ;; The sizes of the buffers should match that returned by `environ.sizes_get()`. + (@interface func (export "environ_get") + (result $error $errno_t) + (result $argv $string_array) + ) + ;; Return command-line argument data sizes. + (@interface func (export "environ_sizes_get") + ;; The number of arguments. + (result $argc $size_t) + ;; The size of the argument string data. + (result $argv_buf_size $size_t) + ) + + ;; Return the resolution of a clock. + ;; Implementations are required to provide a non-zero value for supported clocks. For unsupported clocks, return `WASI_EINVAL` + ;; Note: This is similar to `clock_getres` in POSIX. + (@interface func (export "clock_res_get") + (result $error $errno_t) + ;; The clock for which to return the resolution. + (param $clock_id $clockid_t) + ;; The resolution of the clock. + (result $resolution $timestamp_t) + ) + ;; Return the time value of a clock. + ;; Note: This is similar to `clock_gettime` in POSIX. + (@interface func (export "clock_time_get") + ;; The clock for which to return the time. + (param $clock_id $clockid_t) + ;; The maximum lag (exclusive) that the returned time value may have, compared to its actual value. + (param $precision $timestamp_t) + (result $error $errno_t) + ;; The time value of the clock. + (result $time $timestamp_t) + ) + + ;; Provide file advisory information on a file descriptor. + ;; Note: This is similar to `posix_fadvise` in POSIX. + (@interface func (export "fd_advise") + (param $fd $fd_t) + (param $offset $filesize_t) ;; The offset within the file to which the advisory applies. + (param $len $filesize_t) ;; The length of the region to which the advisory applies. + (param $advice $advice_t) ;; The advice. + (result $error $errno_t) + ) + + ;; Force the allocation of space in a file. + ;; Note: This is similar to `posix_fallocate` in POSIX. + (@interface func (export "fd_allocate") + (param $fd $fd_t) + ;; The offset at which to start the allocation. + (param $offset $filesize_t) + ;; The length of the area that is allocated. + (param $len $filesize_t) + (result $error $errno_t) + ) + + ;; Close a file descriptor. + ;; Note: This is similar to `close` in POSIX. + (@interface func (export "fd_close") + (param $fd $fd_t) + (result $error $errno_t) + ) + + ;; Synchronize the data of a file to disk. + ;; Note: This is similar to `fdatasync` in POSIX. + (@interface func (export "fd_datasync") + (param $fd $fd_t) + (result $error $errno_t) + ) + + ;; Get the attributes of a file descriptor. + ;; Note: This returns similar flags to `fsync(fd, F_GETFL)` in POSIX, as well as additional fields. + (@interface func (export "fd_fdstat_get") + (param $fd $fd_t) + (result $error $errno_t) + ;; The buffer where the file descriptor's attributes are stored. + (result $stat $fdstat_t) + ) + + ;; Adjust the flags associated with a file descriptor. + ;; Note: This is similar to `fcntl(fd, F_SETFL, flags)` in POSIX. + (@interface func (export "fd_fdstat_set_flags") + (param $fd $fd_t) + ;; The desired values of the file descriptor flags. + (param $flags $fdflags_t) + (result $error $errno_t) + ) + + ;; Adjust the rights associated with a file descriptor. + ;; This can only be used to remove rights, and returns `ENOTCAPABLE` if called in a way that would attempt to add rights + (@interface func (export "fd_fdstat_set_rights") + (param $fd $fd_t) + ;; The desired rights of the file descriptor. + (param $fs_rights_base $rights_t) + (param $fs_rights_inheriting $rights_t) + (result $error $errno_t) + ) + + ;; Return the attributes of an open file. + (@interface func (export "fd_filestat_get") + (param $fd $fd_t) + (result $error $errno_t) + ;; The buffer where the file's attributes are stored. + (result $fs_rights_base $rights_t) + ) + + ;; Adjust the size of an open file. If this increases the file's size, the extra bytes are filled with zeros. + ;; Note: This is similar to `ftruncate` in POSIX. + (@interface func (export "fd_filestat_set_size") + (param $fd $fd_t) + ;; The desired file size. + (param $st_size $filesize_t) + (result $error $errno_t) + ) + + ;; Adjust the timestamps of an open file or directory. + ;; Note: This is similar to `futimens` in POSIX. + (@interface func (export "fd_filestat_set_times") + (param $fd $fd_t) + ;; The desired values of the data access timestamp. + (param $st_atim $timestamp_t) + ;; The desired values of the data modification timestamp. + (param $st_mtim $timestamp_t) + ;; A bitmask indicating which timestamps to adjust. + (param $fst_flags $fstflags_t) + (result $error $errno_t) + ) + + ;; Read from a file descriptor, without using and updating the file descriptor's offset. + ;; Note: This is similar to `preadv` in POSIX. + (@interface func (export "fd_pread") + (param $fd $fd_t) + ;; List of scatter/gather vectors in which to store data. + (param $iovs $iovec_t_array) + ;; The offset within the file at which to read. + (param $offset $filesize_t) + (result $error $errno_t) + ;; The number of bytes read. + (result $nread $size_t) + ) + + ;; Return a description of the given preopened file descriptor. + (@interface func (export "fd_prestat_get") + (param $fd $fd_t) + (result $error $errno_t) + ;; The buffer where the description is stored. + (result $buf data) + ) + + ;; Return a description of the given preopened file descriptor. + (@interface func (export "fd_prestat_dir_name") + (param $fd $fd_t) + ;; A buffer into which to write the preopened directory name. + (param $path string) + (result $error $errno_t) + ) + + ;; Write to a file descriptor, without using and updating the file descriptor's offset. + ;; Note: This is similar to `pwritev` in POSIX. + (@interface func (export "fd_pwrite") + (param $fd $fd_t) + ;; List of scatter/gather vectors from which to retrieve data. + (param $iovs $iovec_t_array) + ;; The offset within the file at which to write. + (param $offset $filesize_t) + (result $error $errno_t) + ;; The number of bytes written. + (result $nwritten $size_t) + ) + + ;; Read from a file descriptor. + ;; Note: This is similar to `readv` in POSIX. + (@interface func (export "fd_read") + (param $fd $fd_t) + ;; List of scatter/gather vectors to which to store data. + (param $iovs $iovec_t_array) + (result $error $errno_t) + ;; The number of bytes read. + (result $nread $size_t) + ) + + ;; Read directory entries from a directory. + ;; When successful, the contents of the output buffer consist of a sequence of + ;; directory entries. Each directory entry consists of a dirent_t object, + ;; followed by dirent_t::d_namlen bytes holding the name of the directory + ;; entry. + ;; + ;; This function fills the output buffer as much as possible, potentially + ;; truncating the last directory entry. This allows the caller to grow its + ;; read buffer size in case it's too small to fit a single large directory + ;; entry, or skip the oversized directory entry. + (@interface func (export "fd_readdir") + (param $fd $fd_t) + ;; The buffer where directory entries are stored + (param $buf data) + ;; The location within the directory to start reading + (param $cookie $dircookie_t) + (result $error $errno_t) + ;; The number of bytes stored in the read buffer. If less than the size of the read buffer, the end of the directory has been reached. + (result $bufused $size_t) + ) + + ;; Atomically replace a file descriptor by renumbering another file descriptor. + ;; + ;; Due to the strong focus on thread safety, this environment does not provide + ;; a mechanism to duplicate or renumber a file descriptor to an arbitrary + ;; number, like `dup2()`. This would be prone to race conditions, as an actual + ;; file descriptor with the same number could be allocated by a different + ;; thread at the same time. + ;; + ;; This function provides a way to atomically renumber file descriptors, which + ;; would disappear if `dup2()` were to be removed entirely. + (@interface func (export "fd_renumber") + (param $fd $fd_t) + ;; The file descriptor to overwrite. + (param $to $fd_t) + (result $error $errno_t) + ) + + ;; Move the offset of a file descriptor. + ;; Note: This is similar to `lseek` in POSIX. + (@interface func (export "fd_seek") + (param $fd $fd_t) + ;; The number of bytes to move. + (param $offset $filedelta_t) + ;; The base from which the offset is relative. + (param $whence $whence_t) + (result $error $errno_t) + ;; The new offset of the file descriptor, relative to the start of the file. + (result $newoffset $filesize_t) + ) + + ;; Synchronize the data and metadata of a file to disk. + ;; Note: This is similar to `fsync` in POSIX. + (@interface func (export "fd_sync") + (param $fd $fd_t) + (result $error $errno_t) + ) + + ;; Return the current offset of a file descriptor. + ;; Note: This is similar to `lseek(fd, 0, SEEK_CUR)` in POSIX. + (@interface func (export "fd_tell") + (param $fd $fd_t) + (result $error $errno_t) + ;; The current offset of the file descriptor, relative to the start of the file. + (result $offset $filesize_t) + ) + + ;; Write to a file descriptor. + ;; Note: This is similar to `writev` in POSIX. + (@interface func (export "fd_write") + (param $fd $fd_t) + ;; List of scatter/gather vectors from which to retrieve data. + (param $iovs $iovec_t_array) + (result $error $errno_t) + ;; The number of bytes written. + (result $nwritten $size_t) + ) + + ;; Create a directory. + ;; Note: This is similar to `mkdirat` in POSIX. + (@interface func (export "path_create_directory") + (param $fd $fd_t) + ;; The path at which to create the directory. + (param $path string) + (result $error $errno_t) + ) + + ;; Return the attributes of a file or directory. + ;; Note: This is similar to `stat` in POSIX. + (@interface func (export "path_filestat_get") + (param $fd $fd_t) + ;; Flags determining the method of how the path is resolved. + (param $flags $lookupflags_t) + ;; The path of the file or directory to inspect. + (param $path string) + (result $error $errno_t) + ;; The buffer where the file's attributes are stored. + (result $buf $filestat_t) + ) + + ;; Adjust the timestamps of a file or directory. + ;; Note: This is similar to `utimensat` in POSIX. + (@interface func (export "path_filestat_set_times") + (param $fd $fd_t) + ;; Flags determining the method of how the path is resolved. + (param $flags $lookupflags_t) + ;; The path of the file or directory to operate on. + (param $path string) + ;; The desired values of the data access timestamp. + (param $st_atim $timestamp_t) + ;; The desired values of the data modification timestamp. + (param $st_mtim $timestamp_t) + ;; A bitmask indicating which timestamps to adjust. + (param $fst_flags $fstflags_t) + (result $error $errno_t) + ) + + ;; Create a hard link. + ;; Note: This is similar to `linkat` in POSIX. + (@interface func (export "path_link") + (param $fd $fd_t) + ;; Flags determining the method of how the path is resolved. + (param $old_flags $lookupflags_t) + ;; The source path from which to link. + (param $old_path string) + ;; The working directory at which the resolution of the new path starts. + (param $new_fd string) + ;; The destination path at which to create the hard link. + (param $new_path string) + (result $error $errno_t) + ) + + ;; Open a file or directory. + ;; + ;; The returned file descriptor is not guaranteed to be the lowest-numbered + ;; file descriptor not currently open; it is randomized to prevent + ;; applications from depending on making assumptions about indexes, since this + ;; is error-prone in multi-threaded contexts. The returned file descriptor is + ;; guaranteed to be less than 2**31. + ;; + ;; Note: This is similar to `openat` in POSIX. + (@interface func (export "path_open") + (param $fd $fd_t) + ;; Flags determining the method of how the path is resolved. + (param $dirflags $lookupflags_t) + ;; The relative path of the file or directory to open, relative to the + ;; `dirfd` directory. + (param $path string) + ;; The method by which to open the file. + (param $o_flags $oflags_t) + ;; The initial rights of the newly created file descriptor. The + ;; implementation is allowed to return a file descriptor with fewer rights + ;; than specified, if and only if those rights do not apply to the type of + ;; file being opened. + ;; + ;; The base rights are rights that will apply to operations using the file + ;; descriptor itself, while the inheriting rights are rights that apply to + ;; file descriptors derived from it. + (param $fs_rights_base $rights_t) + (param $fs_rights_inherting $rights_t) + (result $error $errno_t) + ;; The file descriptor of the file that has been opened. + (result $opened_fd $fd_t) + ) + + ;; Read the contents of a symbolic link. + ;; Note: This is similar to `readlinkat` in POSIX. + (@interface func (export "path_readlink") + (param $fd $fd_t) + ;; The path of the symbolic link from which to read. + (param $path string) + ;; The buffer to which to write the contents of the symbolic link. + (param $buf string) + (result $error $errno_t) + ;; The number of bytes placed in the buffer. + (result $bufused $size_t) + ) + + ;; Remove a directory. + ;; Return `__WASI_ENOTEMPTY` if the directory is not empty. + ;; Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX. + (@interface func (export "path_remove_directory") + (param $fd $fd_t) + ;; The path to a directory to remove. + (param $path string) + (result $error $errno_t) + ) + + ;; Rename a file or directory. + ;; Note: This is similar to `renameat` in POSIX. + (@interface func (export "path_rename") + (param $fd $fd_t) + ;; The source path of the file or directory to rename. + (param $old_path string) + ;; The working directory at which the resolution of the new path starts. + (param $new_fd $fd_t) + ;; The destination path to which to rename the file or directory. + (param $new_path string) + (result $error $errno_t) + ) + + ;; Create a symbolic link. + ;; Note: This is similar to `symlinkat` in POSIX. + (@interface func (export "path_symlink") + (param $fd $fd_t) + ;; The contents of the symbolic link. + (param $old_path string) + ;; The destination path at which to create the symbolic link. + (param $new_path string) + (result $error $errno_t) + ) + + + ;; Unlink a file. + ;; Return `__WASI_EISDIR` if the path refers to a directory. + ;; Note: This is similar to `unlinkat(fd, path, 0)` in POSIX. + (@interface func (export "path_unlink_file") + (param $fd $fd_t) + ;; The path to a file to unlink. + (param $path string) + (result $error $errno_t) + ) + + ;; Concurrently poll for the occurrence of a set of events. + (@interface func (export "poll_oneoff") + ;; The events to which to subscribe. + (param $in $subscription_t) + ;; The events that have occurred. + (param $out $event_t) + ;; Both the number of subscriptions and events. + (param $nsubscriptions $size_t) + (result $error $errno_t) + ;; The number of events stored. + (result $nevents $size_t) + ) + + ;; Terminate the process normally. An exit code of 0 indicates successful + ;; termination of the program. The meanings of other values is dependent on + ;; the environment. + (@interface func (export "proc_exit") + ;; The exit code returned by the process. + (param $rval $exitcode_t) + ) + + ;; Send a signal to the process of the calling thread. + ;; Note: This is similar to `raise` in POSIX. + (@interface func (export "proc_raise") + ;; The signal condition to trigger. + (param $sig $signal_t) + (result $error $errno_t) + ) + + ;; Temporarily yield execution of the calling thread. + ;; Note: This is similar to `sched_yield` in POSIX. + (@interface func (export "proc_sched_yield") + (result $error $errno_t) + ) + + ;; Write high-quality random data into a buffer. + ;; This function blocks when the implementation is unable to immediately + ;; provide sufficient high-quality random data. + ;; This function may execute slowly, so when large mounts of random data are + ;; required, it's advisable to use this function to seed a pseudo-random + ;; number generator, rather than to provide the random data directly. + (@interface func (export "random_get") + ;; The buffer to fill with random data. + (param $buf data) + (result $error $errno_t) + ) + + ;; Receive a message from a socket. + ;; Note: This is similar to `recv` in POSIX, though it also supports reading + ;; the data into multiple buffers in the manner of `readv`. + (@interface func (export "sock_recv") + (param $fd $fd_t) + ;; List of scatter/gather vectors to which to store data. + (param $ri_data $iovec_t_array) + ;; Message flags. + (param $ri_flags $riflags_t) + (result $error $errno_t) + ;; Number of bytes stored in ri_data. + (result $ro_datalen $size_t) + ;; Message flags. + (result $ro_flags $roflags_t) + ) + + ;; Send a message on a socket. + ;; Note: This is similar to `send` in POSIX, though it also supports writing + ;; the data from multiple buffers in the manner of `writev`. + (@interface func (export "sock_send") + (param $fd $fd_t) + ;; List of scatter/gather vectors to which to retrieve data + (param $si_data $ciovec_t_array) + ;; Message flags. + (param $si_flags $siflags_t) + (result $error $errno_t) + ;; Number of bytes transmitted. + (result $so_datalen $size_t) + ) + + ;; Shut down socket send and receive channels. + ;; Note: This is similar to `shutdown` in POSIX. + (@interface func (export "sock_shutdown") + (param $fd $fd_t) + ;; Which channels on the socket to shut down. + (param $how $sdflags_t) + (result $error $errno_t) + ) +) From 0d73d2917b8d9626217d7c48c9ccd6826a88e06f Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 12 Sep 2019 11:34:50 -0700 Subject: [PATCH 374/512] split lucet-idl and witx-frontend into two separate crates --- Cargo.lock | 8 ++++ Cargo.toml | 1 + lucet-idl/src/config.rs | 5 +-- lucet-idl/src/error.rs | 9 ----- lucet-idl/src/lib.rs | 14 ++----- lucet-idl/src/main.rs | 14 +------ lucet-idl/tests/example.rs | 6 +-- lucet-idl/tests/wasi_unstable.rs | 8 ---- lucet-idl/witx-frontend/Cargo.toml | 21 ++++++++++ .../{src/witx => witx-frontend/src}/ast.rs | 2 +- .../{src/witx => witx-frontend/src}/lexer.rs | 3 +- .../witx/mod.rs => witx-frontend/src/lib.rs} | 18 ++++++--- lucet-idl/witx-frontend/src/main.rs | 38 +++++++++++++++++++ .../{src/witx => witx-frontend/src}/parser.rs | 5 ++- .../{src/witx => witx-frontend/src}/sexpr.rs | 7 ++-- .../witx => witx-frontend/src}/toplevel.rs | 6 +-- .../witx => witx-frontend/src}/validate.rs | 18 ++++----- 17 files changed, 111 insertions(+), 72 deletions(-) delete mode 100644 lucet-idl/tests/wasi_unstable.rs create mode 100644 lucet-idl/witx-frontend/Cargo.toml rename lucet-idl/{src/witx => witx-frontend/src}/ast.rs (98%) rename lucet-idl/{src/witx => witx-frontend/src}/lexer.rs (99%) rename lucet-idl/{src/witx/mod.rs => witx-frontend/src/lib.rs} (65%) create mode 100644 lucet-idl/witx-frontend/src/main.rs rename lucet-idl/{src/witx => witx-frontend/src}/parser.rs (99%) rename lucet-idl/{src/witx => witx-frontend/src}/sexpr.rs (98%) rename lucet-idl/{src/witx => witx-frontend/src}/toplevel.rs (98%) rename lucet-idl/{src/witx => witx-frontend/src}/validate.rs (96%) diff --git a/Cargo.lock b/Cargo.lock index b7303214d..f0ded9527 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1992,6 +1992,14 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "witx-frontend" +version = "0.1.0" +dependencies = [ + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "xfailure" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index ae9231929..88e0923f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "lucet-analyze", "lucet-idl", + "lucet-idl/witx-frontend", "lucet-idl/lucet-idl-test", "lucet-idl/lucet-idl-test/resources/rust_host", "lucet-module", diff --git a/lucet-idl/src/config.rs b/lucet-idl/src/config.rs index 177005066..d42a05803 100644 --- a/lucet-idl/src/config.rs +++ b/lucet-idl/src/config.rs @@ -2,12 +2,11 @@ use crate::error::IDLError; #[derive(Clone, Debug)] pub struct Config { - pub witx: bool, pub backend: Backend, } impl Config { - pub fn parse(witx: bool, backend_opt: &str) -> Result { + pub fn parse(backend_opt: &str) -> Result { let backend = Backend::from_str(backend_opt).ok_or_else(|| { IDLError::UsageError(format!( "Invalid backend: {}\nValid options are: {:?}", @@ -15,7 +14,7 @@ impl Config { Backend::options() )) })?; - Ok(Self { witx, backend }) + Ok(Self { backend }) } } diff --git a/lucet-idl/src/error.rs b/lucet-idl/src/error.rs index d2fe337cf..d6ddbcb21 100644 --- a/lucet-idl/src/error.rs +++ b/lucet-idl/src/error.rs @@ -1,5 +1,4 @@ use crate::parser; -use crate::witx::WitxError; use crate::Location; use std::io; @@ -15,8 +14,6 @@ pub enum IDLError { ValidationError(#[cause] ValidationError), #[fail(display = "{}", _0)] Io(#[cause] io::Error), - #[fail(display = "{}", _0)] - Witx(#[cause] WitxError), } impl From for IDLError { @@ -37,12 +34,6 @@ impl From for IDLError { } } -impl From for IDLError { - fn from(e: WitxError) -> Self { - IDLError::Witx(e) - } -} - #[derive(Debug, PartialEq, Eq, Clone, Fail)] pub enum ValidationError { #[fail(display = "Redefinition of name `{}`", name)] diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs index 47aa96b1e..d2ffbfe6a 100644 --- a/lucet-idl/src/lib.rs +++ b/lucet-idl/src/lib.rs @@ -15,7 +15,6 @@ pub mod pretty_writer; mod repr; mod rust; mod validate; -mod witx; pub use crate::atoms::{AbiType, AtomType}; pub use crate::config::{Backend, Config}; @@ -33,7 +32,6 @@ use crate::c::CGenerator; use crate::parser::Parser; use crate::rust::RustGenerator; use crate::validate::package_from_declarations; -pub use crate::witx::load_witx; use lucet_module::bindings::Bindings; use std::collections::HashMap; use std::fs; @@ -69,15 +67,9 @@ pub fn codegen(package: &Package, config: &Config, output: Box) -> Re } pub fn run(config: &Config, input_path: &Path, output: Box) -> Result<(), IDLError> { - if config.witx { - let doc = load_witx(input_path).map_err(IDLError::Witx)?; - println!("{:?}", doc); - Ok(()) - } else { - let input = fs::read_to_string(input_path)?; - let pkg = parse_package(&input)?; - codegen(&pkg, config, output) - } + let input = fs::read_to_string(input_path)?; + let pkg = parse_package(&input)?; + codegen(&pkg, config, output) } impl Package { diff --git a/lucet-idl/src/main.rs b/lucet-idl/src/main.rs index a4bed0428..c642a3ab9 100644 --- a/lucet-idl/src/main.rs +++ b/lucet-idl/src/main.rs @@ -16,7 +16,7 @@ pub struct ExeConfig { impl ExeConfig { pub fn parse() -> Result { let matches = App::new("lucet-idl") - .version("0.1.0") + .version(env!("CARGO_PKG_VERSION")) .about("lucet_idl code generator") .arg( Arg::with_name("input") @@ -39,13 +39,6 @@ impl ExeConfig { .required(false) .help("output path"), ) - .arg( - Arg::with_name("witx") - .long("witx") - .takes_value(false) - .required(false) - .help("witx (interface-types, with extensions) mode"), - ) .get_matches(); let input_path = PathBuf::from( matches @@ -53,10 +46,7 @@ impl ExeConfig { .ok_or(IDLError::UsageError("Input file required".to_owned()))?, ); let output_path = matches.value_of("output").map(PathBuf::from); - let config = Config::parse( - matches.is_present("witx"), - matches.value_of("backend").unwrap(), - )?; + let config = Config::parse(matches.value_of("backend").unwrap())?; Ok(ExeConfig { input_path, output_path, diff --git a/lucet-idl/tests/example.rs b/lucet-idl/tests/example.rs index 4451eff05..fa62f8c24 100644 --- a/lucet-idl/tests/example.rs +++ b/lucet-idl/tests/example.rs @@ -8,7 +8,6 @@ use tempfile::TempDir; fn compile_c_guest() { let config = lucet_idl::Config { backend: lucet_idl::Backend::CGuest, - witx: false, }; let tempdir = TempDir::new().expect("create tempdir"); @@ -48,10 +47,7 @@ fn compile_and_test_rust_host() { */ fn compile_and_test_rust(backend: lucet_idl::Backend) { - let config = lucet_idl::Config { - backend, - witx: false, - }; + let config = lucet_idl::Config { backend }; let tempdir = TempDir::new().expect("create tempdir"); diff --git a/lucet-idl/tests/wasi_unstable.rs b/lucet-idl/tests/wasi_unstable.rs deleted file mode 100644 index 59af0ba55..000000000 --- a/lucet-idl/tests/wasi_unstable.rs +++ /dev/null @@ -1,8 +0,0 @@ -use lucet_idl; -use std::path::Path; - -#[test] -fn validate_wasi_unstable() { - lucet_idl::load_witx(Path::new("tests/wasi_unstable.witx")) - .expect("parse and validate wasi_unstable.witx"); -} diff --git a/lucet-idl/witx-frontend/Cargo.toml b/lucet-idl/witx-frontend/Cargo.toml new file mode 100644 index 000000000..b41399312 --- /dev/null +++ b/lucet-idl/witx-frontend/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "witx-frontend" +version = "0.1.0" +description = "Parse and validate witx file format" +homepage = "https://github.com/fastly/lucet" +repository = "https://github.com/fastly/lucet" +license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +authors = ["Pat Hickey "] +edition = "2018" + +[lib] +crate-type=["rlib"] + +[[bin]] +name = "witx-validate" +path = "src/main.rs" + +[dependencies] +clap = "2" +failure = "0.1" diff --git a/lucet-idl/src/witx/ast.rs b/lucet-idl/witx-frontend/src/ast.rs similarity index 98% rename from lucet-idl/src/witx/ast.rs rename to lucet-idl/witx-frontend/src/ast.rs index 2e5d65954..7f583732d 100644 --- a/lucet-idl/src/witx/ast.rs +++ b/lucet-idl/witx-frontend/src/ast.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::rc::{Rc, Weak}; -pub use super::parser::BuiltinType; +pub use crate::parser::BuiltinType; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Id(String); diff --git a/lucet-idl/src/witx/lexer.rs b/lucet-idl/witx-frontend/src/lexer.rs similarity index 99% rename from lucet-idl/src/witx/lexer.rs rename to lucet-idl/witx-frontend/src/lexer.rs index 1dac8fe34..b004acf07 100644 --- a/lucet-idl/src/witx/lexer.rs +++ b/lucet-idl/witx-frontend/src/lexer.rs @@ -1,4 +1,5 @@ -use super::Location; +use crate::Location; +use failure::Fail; use std::path::{Path, PathBuf}; use std::str::CharIndices; diff --git a/lucet-idl/src/witx/mod.rs b/lucet-idl/witx-frontend/src/lib.rs similarity index 65% rename from lucet-idl/src/witx/mod.rs rename to lucet-idl/witx-frontend/src/lib.rs index 72eb2441c..bb0e3a6b9 100644 --- a/lucet-idl/src/witx/mod.rs +++ b/lucet-idl/witx-frontend/src/lib.rs @@ -1,5 +1,5 @@ /// Types describing a validated witx document -pub mod ast; +mod ast; /// Lexer text into tokens mod lexer; /// Witx syntax parsing from SExprs @@ -11,12 +11,18 @@ mod toplevel; /// Validate declarations into ast mod validate; -pub use ast::Document; +pub use ast::{ + AliasDatatype, BuiltinType, Datatype, DatatypeIdent, DatatypeVariant, Definition, Document, + Entry, EnumDatatype, FlagsDatatype, Id, IntRepr, InterfaceFunc, InterfaceFuncParam, Module, + ModuleDefinition, ModuleEntry, ModuleImport, ModuleImportVariant, StructDatatype, StructMember, + UnionDatatype, UnionVariant, +}; +pub use lexer::LexError; pub use parser::{DeclSyntax, ParseError}; pub use sexpr::SExprParseError; -pub use toplevel::parse_witx; -pub use validate::{validate_document, ValidationError}; +pub use validate::ValidationError; +use failure::Fail; use std::io; use std::path::{Path, PathBuf}; @@ -40,7 +46,9 @@ pub enum WitxError { Validation(#[cause] ValidationError), } -pub fn load_witx>(path: P) -> Result { +pub fn load>(path: P) -> Result { + use toplevel::parse_witx; + use validate::validate_document; let parsed_decls = parse_witx(path)?; validate_document(&parsed_decls).map_err(WitxError::Validation) } diff --git a/lucet-idl/witx-frontend/src/main.rs b/lucet-idl/witx-frontend/src/main.rs new file mode 100644 index 000000000..d8ae69d9e --- /dev/null +++ b/lucet-idl/witx-frontend/src/main.rs @@ -0,0 +1,38 @@ +use clap::{App, Arg}; +use std::path::Path; +use std::process; +use witx_frontend::load; + +pub fn main() { + let app = App::new("witx-validate") + .version(env!("CARGO_PKG_VERSION")) + .about("Validate witx file format") + .arg( + Arg::with_name("input") + .required(true) + .help("path to root of witx document"), + ) + .arg( + Arg::with_name("verbose") + .short("v") + .long("verbose") + .takes_value(false) + .required(false), + ) + .get_matches(); + + match load(Path::new(app.value_of("input").expect("required arg"))) { + Ok(doc) => { + if app.is_present("verbose") { + println!("{:?}", doc) + } + } + Err(e) => { + eprintln!("{}", e); + if app.is_present("verbose") { + eprintln!("{:?}", e); + } + process::exit(1); + } + } +} diff --git a/lucet-idl/src/witx/parser.rs b/lucet-idl/witx-frontend/src/parser.rs similarity index 99% rename from lucet-idl/src/witx/parser.rs rename to lucet-idl/witx-frontend/src/parser.rs index 0e595e10b..e319d0c22 100644 --- a/lucet-idl/src/witx/parser.rs +++ b/lucet-idl/witx-frontend/src/parser.rs @@ -1,5 +1,6 @@ -use super::sexpr::SExpr; -use super::Location; +use crate::sexpr::SExpr; +use crate::Location; +use failure::Fail; ///! Parser turns s-expressions into unvalidated syntax constructs. ///! conventions: diff --git a/lucet-idl/src/witx/sexpr.rs b/lucet-idl/witx-frontend/src/sexpr.rs similarity index 98% rename from lucet-idl/src/witx/sexpr.rs rename to lucet-idl/witx-frontend/src/sexpr.rs index c01c83516..dfb124611 100644 --- a/lucet-idl/src/witx/sexpr.rs +++ b/lucet-idl/witx-frontend/src/sexpr.rs @@ -1,6 +1,7 @@ -pub use super::lexer::LexError; -use super::lexer::{Lexer, LocatedError, LocatedToken, Token}; -use super::Location; +pub use crate::lexer::LexError; +use crate::lexer::{Lexer, LocatedError, LocatedToken, Token}; +use crate::Location; +use failure::Fail; use std::path::{Path, PathBuf}; ///! The s-expression parser turns a string into a stream of SExprs. diff --git a/lucet-idl/src/witx/toplevel.rs b/lucet-idl/witx-frontend/src/toplevel.rs similarity index 98% rename from lucet-idl/src/witx/toplevel.rs rename to lucet-idl/witx-frontend/src/toplevel.rs index 6af5bacf8..5f3f7145b 100644 --- a/lucet-idl/src/witx/toplevel.rs +++ b/lucet-idl/witx-frontend/src/toplevel.rs @@ -1,6 +1,6 @@ -use super::parser::{DeclSyntax, ParseError, TopLevelSyntax}; -use super::sexpr::SExprParser; -use super::WitxError; +use crate::parser::{DeclSyntax, ParseError, TopLevelSyntax}; +use crate::sexpr::SExprParser; +use crate::WitxError; use std::collections::HashSet; use std::fs; use std::path::{Path, PathBuf}; diff --git a/lucet-idl/src/witx/validate.rs b/lucet-idl/witx-frontend/src/validate.rs similarity index 96% rename from lucet-idl/src/witx/validate.rs rename to lucet-idl/witx-frontend/src/validate.rs index c285a8229..c2f0f6270 100644 --- a/lucet-idl/src/witx/validate.rs +++ b/lucet-idl/witx-frontend/src/validate.rs @@ -1,14 +1,14 @@ -use super::ast::{ +use crate::{ + parser::{ + DatatypeIdentSyntax, DeclSyntax, EnumSyntax, FlagsSyntax, IdentSyntax, ImportTypeSyntax, + ModuleDeclSyntax, StructSyntax, TypedefSyntax, UnionSyntax, + }, AliasDatatype, BuiltinType, Datatype, DatatypeIdent, DatatypeVariant, Definition, Document, - Entry, EnumDatatype, FlagsDatatype, Id, IntRepr, InterfaceFunc, InterfaceFuncParam, Module, - ModuleDefinition, ModuleEntry, ModuleImport, ModuleImportVariant, StructDatatype, StructMember, - UnionDatatype, UnionVariant, -}; -use super::parser::{ - DatatypeIdentSyntax, DeclSyntax, EnumSyntax, FlagsSyntax, IdentSyntax, ImportTypeSyntax, - ModuleDeclSyntax, StructSyntax, TypedefSyntax, UnionSyntax, + Entry, EnumDatatype, FlagsDatatype, Id, IntRepr, InterfaceFunc, InterfaceFuncParam, Location, + Module, ModuleDefinition, ModuleEntry, ModuleImport, ModuleImportVariant, StructDatatype, + StructMember, UnionDatatype, UnionVariant, }; -use super::Location; +use failure::Fail; use std::collections::HashMap; use std::rc::Rc; From f2bc6653c2abc926cc9f1f36420696cfcc469dc6 Mon Sep 17 00:00:00 2001 From: Eric Kilmer Date: Sat, 14 Sep 2019 12:59:08 -0400 Subject: [PATCH 375/512] Exit dev shell scripts on first command exiting with non-zero return (#298) * Exit dev shell scripts on first command exiting with non-zero return Fixes issue #297 * Create stages for Travis * Remove set -e from devenv scripts --- .travis.yml | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index d8a5a0a85..b0f4e6f2c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,33 @@ dist: xenial +# Same as version in Dockerfile(s) +rust: 1.36.0 + env: - UNOPTIMIZED_BUILD=true services: - docker -script: - - ./devenv_run.sh make indent-check test audit - - ./devenv_stop.sh - - git diff --exit-code - - ./devenv_build_toolchain_only.sh +stages: + - lint + - build_and_test + +jobs: + include: + - stage: lint + language: rust + install: + - rustup component add rustfmt + script: + - make indent-check + - git diff --exit-code + - stage: build_and_test + script: + - ./devenv_run.sh make test || travis_terminate 1 + - ./devenv_run.sh make audit || travis_terminate 1 + - ./devenv_stop.sh + - ./devenv_build_toolchain_only.sh notifications: email: false From 0ad737c16c9d0cb54d12237503d6605eb674de09 Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Wed, 11 Sep 2019 15:48:21 -0700 Subject: [PATCH 376/512] add version info to modules version information is comprised of both the current crate version and the current git commit hash (if available). the current git commit hash is only used in release builds to avoid too much furstration in typical development workflows using tools like "git commit --amend" or "git rebase", or just making non-conflicting spot changes to only one of lucetc or lucet-runtime --- Cargo.lock | 1 + lucet-analyze/src/main.rs | 5 + lucet-module/Cargo.toml | 1 + lucet-module/src/lib.rs | 2 + lucet-module/src/module.rs | 3 + lucet-module/src/signature.rs | 9 +- lucet-module/src/version_info.rs | 92 ++++++++++++++++++ .../lucet-runtime-internals/build.rs | 28 ++++++ .../lucet-runtime-internals/src/module/dl.rs | 18 +++- lucet-runtime/tests/version_checks.rs | 16 +++ .../tests/version_checks/old_module.so | Bin 0 -> 9424 bytes lucetc/build.rs | 29 ++++++ lucetc/src/output.rs | 9 +- 13 files changed, 207 insertions(+), 6 deletions(-) create mode 100644 lucet-module/src/version_info.rs create mode 100644 lucet-runtime/tests/version_checks.rs create mode 100755 lucet-runtime/tests/version_checks/old_module.so create mode 100644 lucetc/build.rs diff --git a/Cargo.lock b/Cargo.lock index f0ded9527..0bb2d1e59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -850,6 +850,7 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.41.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/lucet-analyze/src/main.rs b/lucet-analyze/src/main.rs index 2c20655e8..e1bd17d3b 100644 --- a/lucet-analyze/src/main.rs +++ b/lucet-analyze/src/main.rs @@ -2,6 +2,7 @@ use lucet_module::{ FunctionSpec, Module, ModuleData, SerializedModule, TableElement, TrapManifest, TrapSite, + VersionInfo, }; use byteorder::{LittleEndian, ReadBytesExt}; @@ -102,7 +103,10 @@ impl<'a> ArtifactSummary<'a> { .unwrap(); let mut rdr = Cursor::new(buffer); + let version = VersionInfo::read_from(&mut rdr).unwrap(); + SerializedModule { + version, module_data_ptr: rdr.read_u64::().unwrap(), module_data_len: rdr.read_u64::().unwrap(), tables_ptr: rdr.read_u64::().unwrap(), @@ -211,6 +215,7 @@ fn load_module<'b, 'a: 'b>( ) }; Module { + version: serialized_module.version.clone(), module_data, tables, function_manifest, diff --git a/lucet-module/Cargo.toml b/lucet-module/Cargo.toml index 16078ab0b..41fc62748 100644 --- a/lucet-module/Cargo.toml +++ b/lucet-module/Cargo.toml @@ -20,3 +20,4 @@ num-traits = "0.2" minisign = "0.5.11" object = "0.12" byteorder = "1.3" +memoffset = "0.5.1" diff --git a/lucet-module/src/lib.rs b/lucet-module/src/lib.rs index 8be0f1797..b1259024e 100644 --- a/lucet-module/src/lib.rs +++ b/lucet-module/src/lib.rs @@ -17,6 +17,7 @@ mod signature; mod tables; mod traps; mod types; +mod version_info; pub use crate::error::Error; pub use crate::functions::{ @@ -32,6 +33,7 @@ pub use crate::signature::{ModuleSignature, PublicKey}; pub use crate::tables::TableElement; pub use crate::traps::{TrapCode, TrapManifest, TrapSite}; pub use crate::types::{Signature, ValueType}; +pub use crate::version_info::VersionInfo; /// Owned variants of the module data types, useful for serialization and testing. pub mod owned { diff --git a/lucet-module/src/module.rs b/lucet-module/src/module.rs index 793a94382..238e2bcb0 100644 --- a/lucet-module/src/module.rs +++ b/lucet-module/src/module.rs @@ -1,12 +1,14 @@ use crate::functions::FunctionSpec; use crate::module_data::ModuleData; use crate::tables::TableElement; +use crate::version_info::VersionInfo; pub const LUCET_MODULE_SYM: &str = "lucet_module"; /// Module is the exposed structure that contains all the data backing a Lucet-compiled object. #[derive(Debug)] pub struct Module<'a> { + pub version: VersionInfo, pub module_data: ModuleData<'a>, pub tables: &'a [&'a [TableElement]], pub function_manifest: &'a [FunctionSpec], @@ -18,6 +20,7 @@ pub struct Module<'a> { #[repr(C)] #[derive(Debug)] pub struct SerializedModule { + pub version: VersionInfo, pub module_data_ptr: u64, pub module_data_len: u64, pub tables_ptr: u64, diff --git a/lucet-module/src/signature.rs b/lucet-module/src/signature.rs index 5e6e52b4f..134bd7256 100644 --- a/lucet-module/src/signature.rs +++ b/lucet-module/src/signature.rs @@ -1,8 +1,9 @@ use crate::error::Error::{self, IOError, ModuleSignatureError}; -use crate::module::LUCET_MODULE_SYM; +use crate::module::{SerializedModule, LUCET_MODULE_SYM}; use crate::module_data::MODULE_DATA_SYM; use crate::ModuleData; use byteorder::{ByteOrder, LittleEndian}; +use memoffset::offset_of; pub use minisign::{PublicKey, SecretKey}; use minisign::{SignatureBones, SignatureBox}; use object::*; @@ -94,8 +95,10 @@ impl RawModuleAndData { format!("`{}` symbol not present", MODULE_DATA_SYM), ))?; - let module_data_len = - LittleEndian::read_u64(&obj_bin[(native_data_symbol_data.offset + 8)..]) as usize; + let module_data_len = LittleEndian::read_u64( + &obj_bin[(native_data_symbol_data.offset + + offset_of!(SerializedModule, module_data_len))..], + ) as usize; Ok(RawModuleAndData { obj_bin, diff --git a/lucet-module/src/version_info.rs b/lucet-module/src/version_info.rs new file mode 100644 index 000000000..e0cd70578 --- /dev/null +++ b/lucet-module/src/version_info.rs @@ -0,0 +1,92 @@ +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; +use std::cmp::min; +use std::fmt; +use std::io; + +/// VersionInfo is information about a Lucet module to allow the Lucet runtime to determine if or +/// how the module can be loaded, if so requested. The information here describes implementation +/// details in runtime support for `lucetc`-produced modules, and nothing higher level. +#[repr(C)] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct VersionInfo { + major: u16, + minor: u16, + patch: u16, + reserved: u16, + version_hash: [u8; 8], +} + +impl fmt::Display for VersionInfo { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{}.{}.{}", self.major, self.minor, self.patch)?; + if u64::from_ne_bytes(self.version_hash) != 0 { + write!( + fmt, + "-{}", + std::str::from_utf8(&self.version_hash).unwrap_or("INVALID") + )?; + } + Ok(()) + } +} + +impl VersionInfo { + pub fn write_to(&self, w: &mut W) -> io::Result<()> { + w.write_u16::(self.major)?; + w.write_u16::(self.minor)?; + w.write_u16::(self.patch)?; + w.write_u16::(self.reserved)?; + w.write(&self.version_hash).and_then(|written| { + if written != self.version_hash.len() { + Err(io::Error::new( + io::ErrorKind::Other, + "unable to write full version hash", + )) + } else { + Ok(()) + } + }) + } + + pub fn read_from(r: &mut R) -> io::Result { + let mut version_hash = [0u8; 8]; + Ok(VersionInfo { + major: r.read_u16::()?, + minor: r.read_u16::()?, + patch: r.read_u16::()?, + reserved: r.read_u16::()?, + version_hash: { + r.read_exact(&mut version_hash)?; + version_hash + }, + }) + } + + pub fn valid(&self) -> bool { + self.reserved == 0x8000 + } + + pub fn current(current_hash: &'static [u8]) -> Self { + let mut version_hash = [0u8; 8]; + + for i in 0..min(version_hash.len(), current_hash.len()) { + version_hash[i] = current_hash[i]; + } + + // The reasoning for this is as follows: + // `SerializedModule`, in version before version information was introduced, began with a + // pointer - `module_data_ptr`. This pointer would be relocated to somewhere in user space + // for the embedder of `lucet-runtime`. On x86_64, hopefully, that's userland code in some + // OS, meaning the pointer will be a pointer to user memory, and will be below + // 0x8000_0000_0000_0000. By setting `reserved` to `0x8000`, we set what would be the + // highest bit in `module_data_ptr` in an old `lucet-runtime` and guarantee a segmentation + // fault when loading these newer modules with version information. + VersionInfo { + major: env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap(), + minor: env!("CARGO_PKG_VERSION_MINOR").parse().unwrap(), + patch: env!("CARGO_PKG_VERSION_PATCH").parse().unwrap(), + reserved: 0x8000u16, + version_hash, + } + } +} diff --git a/lucet-runtime/lucet-runtime-internals/build.rs b/lucet-runtime/lucet-runtime-internals/build.rs index 41323408c..9c5e5418a 100644 --- a/lucet-runtime/lucet-runtime-internals/build.rs +++ b/lucet-runtime/lucet-runtime-internals/build.rs @@ -1,3 +1,7 @@ +use std::env; +use std::fs::File; +use std::path::Path; + use cc; fn main() { @@ -14,4 +18,28 @@ fn main() { cc::Build::new() .file("src/context/tests/c_child.c") .compile("context_tests_c_child"); + + let commit_file_path = Path::new(&env::var("OUT_DIR").unwrap()).join("commit_hash"); + // in debug builds we only need the file to exist, but in release builds this will be used and + // requires mutability. + #[allow(unused_variables, unused_mut)] + let mut f = File::create(&commit_file_path).unwrap(); + + // This is about the closest not-additional-feature-flag way to detect release builds. + // In debug builds, leave the `commit_hash` file empty to allow looser version checking and + // avoid impacting development workflows too much. + #[cfg(not(debug_assertions))] + { + use std::io::Write; + use std::process::Command; + + let last_commit_hash = Command::new("git") + .args(&["log", "-n", "1", "--pretty=format:%H"]) + .output() + .ok(); + + if let Some(last_commit_hash) = last_commit_hash { + f.write_all(&last_commit_hash.stdout).unwrap(); + } + } } diff --git a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs index 350a08640..98fb5bba6 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs @@ -4,7 +4,7 @@ use libc::c_void; use libloading::Library; use lucet_module::{ FunctionHandle, FunctionIndex, FunctionPointer, FunctionSpec, ModuleData, ModuleSignature, - PublicKey, SerializedModule, Signature, LUCET_MODULE_SYM, + PublicKey, SerializedModule, Signature, VersionInfo, LUCET_MODULE_SYM, }; use std::ffi::CStr; use std::mem::MaybeUninit; @@ -61,6 +61,21 @@ impl DlModule { let serialized_module: &SerializedModule = unsafe { serialized_module_ptr.as_ref().unwrap() }; + let version = serialized_module.version.clone(); + + let runtime_version = + VersionInfo::current(include_str!(concat!(env!("OUT_DIR"), "/commit_hash")).as_bytes()); + + if !version.valid() { + return Err(lucet_incorrect_module!("reserved bit is not set. This module is likely too old for this lucet-runtime to load.")); + } else if version != runtime_version { + return Err(lucet_incorrect_module!( + "version mismatch. module has version {}, while this runtime is version {}", + version, + runtime_version, + )); + } + // Deserialize the slice into ModuleData, which will hold refs into the loaded // shared object file in `module_data_slice`. Both of these get a 'static lifetime because // Rust doesn't have a safe way to describe that their lifetime matches the containing @@ -115,6 +130,7 @@ impl DlModule { lib, fbase, module: lucet_module::Module { + version, module_data, tables, function_manifest, diff --git a/lucet-runtime/tests/version_checks.rs b/lucet-runtime/tests/version_checks.rs new file mode 100644 index 000000000..fa5c9a30c --- /dev/null +++ b/lucet-runtime/tests/version_checks.rs @@ -0,0 +1,16 @@ +use lucet_runtime::{DlModule, Error}; + +#[test] +pub fn reject_old_modules() { + let err = DlModule::load("./tests/version_checks/old_module.so") + .err() + .unwrap(); + + if let Error::ModuleError(e) = err { + let msg = format!("{}", e); + assert!(msg.contains("reserved bit is not set")); + assert!(msg.contains("module is likely too old")); + } else { + panic!("unexpected error loading module: {}", err); + } +} diff --git a/lucet-runtime/tests/version_checks/old_module.so b/lucet-runtime/tests/version_checks/old_module.so new file mode 100755 index 0000000000000000000000000000000000000000..cf04b77a76ec93614780f072ddedf1258e4ec802 GIT binary patch literal 9424 zcmeHN&1(};5Pzvws}-9Tzp0uQJ@`S?gXlqJ6t+b*$up5ZkY!OJLXjtOHJWtj<`XNwu?%{n)m<_O5+qb*nnj^?K^b`@7e!?zngQ z&CvPwr{53mrRfE!kF=<*-r&$8`rV{&r4i7X2mSajLx9kq}MD zt`lSZa7Q9k$nQ4d9DkR@2TntzUnov%#9qQEHBfQ=!0xY5*^DsvpkmdaL!R*z@t0?I-Df$Jx}_r1glS zS+}0eSfkH^hL&dQ!Z;RMM*{!h@Ws>_vUv|00IW|^O#g}j_&wqcz!4un1K27*i9`T2 z94Q4L1uv)#HwYL63<3rLgMdN6AYc&qHwa)`c3w8IpTGYob0+s?EZbuBLiT-lXPl6E zY)fxS`pv>O3CBBK55K4pVLv_{4)uE*i?H7ydN6(;VnUu@e}wrVPB^=Czf_hb(ZHor z+P`ax@lKw}$z*eG|3E$*nO}o|LBJqj5HJWB1PlTO0fT@+z#w1{FbEg~{v!m?so;`h zEmC;oG?rTmu`Mzep3E+E=E^;n*v19S>ds$vDD)=6P=j7MLx;ak_OiI@Q}d{dJo$83 znlmt&<+}GF4G^u>^66QFrIM0<-VZ!Fo>s|$QYD#p{Jcu$Y9+r`40+(Gq~{hKR;py+ z4hJ+Y>!atSo45Ntr|4=+r+6_-0-s4Q0r3sw9+RG`b zeKl}v5r0vu^(1f%_)o~q07oB<*W)RykAB)#(s6F^M;{OTCe788g#V@5NfO6~Kl*s! zSU*}n*560I920#*94mvTX|A5|Btv(Q1op@JIOYbQfT8ec{zoJJ`0fTg;{FRi=ueTr zxuZUOkAv@D@SO|pH}FRtJ><(d!5_!vXd>d+oJ=&qALBW`P!g|pgoAT+Iu@h#{{#z5 B=8XUV literal 0 HcmV?d00001 diff --git a/lucetc/build.rs b/lucetc/build.rs new file mode 100644 index 000000000..96299ec26 --- /dev/null +++ b/lucetc/build.rs @@ -0,0 +1,29 @@ +use std::env; +use std::fs::File; +use std::path::Path; + +fn main() { + let commit_file_path = Path::new(&env::var("OUT_DIR").unwrap()).join("commit_hash"); + // in debug builds we only need the file to exist, but in release builds this will be used and + // requires mutability. + #[allow(unused_variables, unused_mut)] + let mut f = File::create(&commit_file_path).unwrap(); + + // This is about the closest not-additional-feature-flag way to detect release builds. + // In debug builds, leave the `commit_hash` file empty to allow looser version checking and + // avoid impacting development workflows too much. + #[cfg(not(debug_assertions))] + { + use std::io::Write; + use std::process::Command; + + let last_commit_hash = Command::new("git") + .args(&["log", "-n", "1", "--pretty=format:%H"]) + .output() + .ok(); + + if let Some(last_commit_hash) = last_commit_hash { + f.write_all(&last_commit_hash.stdout).unwrap(); + } + } +} diff --git a/lucetc/src/output.rs b/lucetc/src/output.rs index 08d65f997..5e49b6bfa 100644 --- a/lucetc/src/output.rs +++ b/lucetc/src/output.rs @@ -10,7 +10,7 @@ use cranelift_codegen::{ir, isa}; use cranelift_faerie::FaerieProduct; use faerie::{Artifact, Decl, Link}; use failure::{format_err, Error, ResultExt}; -use lucet_module::{FunctionSpec, LUCET_MODULE_SYM, MODULE_DATA_SYM}; +use lucet_module::{FunctionSpec, VersionInfo, LUCET_MODULE_SYM, MODULE_DATA_SYM}; use std::collections::HashMap; use std::fs::File; use std::io::{Cursor, Write}; @@ -136,10 +136,15 @@ fn write_module( function_manifest_len: usize, obj: &mut Artifact, ) -> Result<(), Error> { - let mut native_data = Cursor::new(Vec::with_capacity(NATIVE_POINTER_SIZE * 4)); + let mut native_data = Cursor::new(Vec::with_capacity(16 + NATIVE_POINTER_SIZE * 4)); obj.declare(LUCET_MODULE_SYM, Decl::data().global()) .context(format!("declaring {}", LUCET_MODULE_SYM))?; + let version = + VersionInfo::current(include_str!(concat!(env!("OUT_DIR"), "/commit_hash")).as_bytes()); + + version.write_to(&mut native_data)?; + write_relocated_slice( obj, &mut native_data, From eca48fb545cdaa2e90c6f451072dc351a89c66d3 Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Fri, 13 Sep 2019 12:45:38 -0700 Subject: [PATCH 377/512] review comments --- lucet-module/src/version_info.rs | 8 ++++++++ lucetc/src/output.rs | 7 ++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lucet-module/src/version_info.rs b/lucet-module/src/version_info.rs index e0cd70578..2914a9d69 100644 --- a/lucet-module/src/version_info.rs +++ b/lucet-module/src/version_info.rs @@ -13,6 +13,14 @@ pub struct VersionInfo { minor: u16, patch: u16, reserved: u16, + /// `version_hash` is either all nulls or the first eight ascii characters of the git commit + /// hash of wherever this Version is coming from. In the case of a compiled lucet module, this + /// hash will come from the git commit that the lucetc producing it came from. In a runtime + /// context, it will be the git commit of lucet-runtime built into the embedder. + /// + /// The version hash will typically populated only in release builds, but may blank even in + /// that case: if building from a packagd crate, or in a build environment that does not have + /// "git" installed, `lucetc` and `lucet-runtime` will fall back to an empty hash. version_hash: [u8; 8], } diff --git a/lucetc/src/output.rs b/lucetc/src/output.rs index 5e49b6bfa..66b706171 100644 --- a/lucetc/src/output.rs +++ b/lucetc/src/output.rs @@ -1,7 +1,6 @@ use crate::error::LucetcErrorKind; use crate::function_manifest::{write_function_manifest, FUNCTION_MANIFEST_SYM}; use crate::name::Name; -use crate::pointer::NATIVE_POINTER_SIZE; use crate::stack_probe; use crate::table::{link_tables, TABLE_SYM}; use crate::traps::write_trap_tables; @@ -10,7 +9,9 @@ use cranelift_codegen::{ir, isa}; use cranelift_faerie::FaerieProduct; use faerie::{Artifact, Decl, Link}; use failure::{format_err, Error, ResultExt}; -use lucet_module::{FunctionSpec, VersionInfo, LUCET_MODULE_SYM, MODULE_DATA_SYM}; +use lucet_module::{ + FunctionSpec, SerializedModule, VersionInfo, LUCET_MODULE_SYM, MODULE_DATA_SYM, +}; use std::collections::HashMap; use std::fs::File; use std::io::{Cursor, Write}; @@ -136,7 +137,7 @@ fn write_module( function_manifest_len: usize, obj: &mut Artifact, ) -> Result<(), Error> { - let mut native_data = Cursor::new(Vec::with_capacity(16 + NATIVE_POINTER_SIZE * 4)); + let mut native_data = Cursor::new(Vec::with_capacity(std::mem::size_of::())); obj.declare(LUCET_MODULE_SYM, Decl::data().global()) .context(format!("declaring {}", LUCET_MODULE_SYM))?; From b905c4448308d89fe600f314c14932644985f877 Mon Sep 17 00:00:00 2001 From: Shravan Narayan Date: Tue, 17 Sep 2019 14:02:11 -0700 Subject: [PATCH 378/512] Fixes #299 - WasiCtx should open dev/null read write (#302) --- lucet-wasi/src/ctx.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lucet-wasi/src/ctx.rs b/lucet-wasi/src/ctx.rs index 889ecfc99..f32acb64a 100644 --- a/lucet-wasi/src/ctx.rs +++ b/lucet-wasi/src/ctx.rs @@ -4,7 +4,7 @@ use failure::{bail, format_err, Error}; use nix::unistd::dup; use std::collections::HashMap; use std::ffi::{CStr, CString}; -use std::fs::File; +use std::fs::{File, OpenOptions}; use std::io::{stderr, stdin, stdout}; use std::os::unix::prelude::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use std::path::{Path, PathBuf}; @@ -240,5 +240,9 @@ impl WasiCtx { } fn dev_null() -> File { - File::open("/dev/null").expect("failed to open /dev/null") + OpenOptions::new() + .read(true) + .write(true) + .open("/dev/null") + .expect("failed to open /dev/null") } From bb5b1d1a1430a9e26d9eaaa7b523380059a4447d Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Thu, 19 Sep 2019 12:12:10 -0700 Subject: [PATCH 379/512] need to go through the ELF view to read the tables slice too we were going through the mapper to read each table, but incorrectly assumed the pointer in the artifact to look at didn't need translation too --- lucet-analyze/src/main.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lucet-analyze/src/main.rs b/lucet-analyze/src/main.rs index e1bd17d3b..f1253e263 100644 --- a/lucet-analyze/src/main.rs +++ b/lucet-analyze/src/main.rs @@ -487,15 +487,21 @@ fn print_summary(summary: ArtifactSummary<'_>) { "function_manifest_len", serialized_module.function_manifest_len ); + let tables_bytes = summary + .read_memory( + serialized_module.tables_ptr, + serialized_module.tables_len * mem::size_of::<&[TableElement]>() as u64, + ) + .unwrap(); let tables = unsafe { std::slice::from_raw_parts( - serialized_module.tables_ptr as *const &[TableElement], + tables_bytes.as_ptr() as *const &[TableElement], serialized_module.tables_len as usize, ) }; let mut reconstructed_tables = Vec::new(); // same situation as trap tables - these slices are valid as if the module was - // dlopen'd, but we jsut read it as a flat file. So read through the ELF view and use + // dlopen'd, but we just read it as a flat file. So read through the ELF view and use // pointers to that for the real slices. for table in tables { From 0b7598bf3fa24fbea5d7012331d9115cc3e5f55a Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Thu, 19 Sep 2019 11:07:12 -0700 Subject: [PATCH 380/512] add a CallStackBuilder abstraction to tease apart Context::init also adds documentation on what the guest stack looks like when initialized --- .../src/context/context_asm.S | 6 +- .../src/context/mod.rs | 170 +++++++++++++----- 2 files changed, 128 insertions(+), 48 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/context/context_asm.S b/lucet-runtime/lucet-runtime-internals/src/context/context_asm.S index 7f409ffca..47b5bd6f5 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/context_asm.S +++ b/lucet-runtime/lucet-runtime-internals/src/context/context_asm.S @@ -62,8 +62,10 @@ _lucet_context_bootstrap: .align 16 lucet_context_backstop: _lucet_context_backstop: - mov -16(%rbp), %rdi /* parent context to arg 1 */ - mov -8(%rbp), %rsi /* own context to arg 2 */ + // Note that `rbp` here really has no relation to any stack! + // it happens to be an available pointer we can hang the contexts to swap off of. + mov (%rbp), %rdi /* parent context to arg 1 */ + mov 8(%rbp), %rsi /* own context to arg 2 */ mov %rax, (8*8 + 8*16 + 8*0)(%rdi) /* store return values before swapping back -- offset is offsetof(struct lucet_context, retvals) */ mov %rdx, (8*8 + 8*16 + 8*1)(%rdi) movdqu %xmm0, (8*8 + 8*16 + 8*2)(%rdi) /* floating-point return value */ diff --git a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs index da957d636..58fba548a 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs @@ -202,6 +202,49 @@ impl ContextHandle { } } +struct CallStackBuilder<'a> { + offset: usize, + stack: &'a mut [u64], +} + +impl<'a> CallStackBuilder<'a> { + pub fn new(stack: &'a mut [u64]) -> Self { + CallStackBuilder { offset: 0, stack } + } + + fn push(&mut self, val: u64) { + self.offset += 1; + self.stack[self.stack.len() - self.offset] = val; + } + + /// Stores `args` onto the stack such that when a return address is written after, the + /// complete unit will be 16-byte aligned, as the x86_64 ABI requires. + /// + /// That is to say, `args` will be padded such that the current top of stack is 8-byte + /// aligned. + fn store_args(&mut self, args: &[u64]) { + let items_end = args.len() + self.offset; + + if items_end % 2 == 1 { + // we need to add one entry just before the arguments so that the arguments start on an + // aligned address. + self.push(0); + } + + for arg in args.iter().rev() { + self.push(*arg); + } + } + + fn offset(&self) -> usize { + self.offset + } + + fn into_inner(self) -> (&'a mut [u64], usize) { + (self.stack, self.offset) + } +} + impl Context { /// Initialize a new child context. /// @@ -281,6 +324,41 @@ impl Context { /// ); /// assert!(res.is_ok()); /// ``` + /// + /// # Implementation details + /// + /// This prepares a stack for the child context structured as follows, assuming an 0x1000 byte + /// stack: + /// ```text + /// 0x1000: +-------------------------+ + /// 0x0ff8: | &child | + /// 0x0ff0: | &parent | <-- `backstop_args`, which is stored to `rbp`. + /// 0x0fe8: | NULL | // Null added if necessary for alignment. + /// 0x0fe0: | spilled_arg_1 | // Guest arguments follow. + /// 0x0fd8: | spilled_arg_2 | + /// 0x0fd0: ~ spilled_arg_3 ~ // The three arguments here are just for show. + /// 0x0fc8: | lucet_context_backstop | <-- This forms an ABI-matching call frame for fptr. + /// 0x0fc0: | fptr | <-- The actual guest code we want to run. + /// 0x0fb8: | lucet_context_bootstrap | <-- The guest stack pointer starts here. + /// 0x0fb0: | | + /// 0x0XXX: ~ ~ // Rest of the stack needs no preparation. + /// 0x0000: | | + /// +-------------------------+ + /// ``` + /// + /// This packing of data on the stack is interwoven with noteworthy constraints on what the + /// backstop may do: + /// * The backstop must not return on the guest stack. + /// - The next value will be a spilled argument or NULL. Neither are an intended address. + /// * The backstop cannot have ABI-conforming spilled arguments. + /// - No code runs between `fptr` and `lucet_context_backstop`, so nothing exists to + /// clean up `fptr`'s arguments. `lucet_context_backstop` would have to adjust the + /// stack pointer by a variable amount, and it does not, so `rsp` will continue to + /// point to guest arguments. + /// - This is why bootstrap recieves arguments via rbp, pointing elsewhere on the stack. + /// + /// The bootstrap function must be careful, but is less constrained since it can clean up + /// and prepare a context for `fptr`. pub fn init( stack: &mut [u64], parent: &mut Context, @@ -301,7 +379,7 @@ impl Context { match val_to_reg(arg) { RegVal::GpReg(v) => { if gp_args_ix >= 6 { - spilled_args.push(arg); + spilled_args.push(val_to_stack(arg)); } else { child.bootstrap_gp_ix_arg(gp_args_ix, v); gp_args_ix += 1; @@ -309,7 +387,7 @@ impl Context { } RegVal::FpReg(v) => { if fp_args_ix >= 8 { - spilled_args.push(arg); + spilled_args.push(val_to_stack(arg)); } else { child.bootstrap_fp_ix_arg(fp_args_ix, v); fp_args_ix += 1; @@ -318,52 +396,52 @@ impl Context { } } - // the top of the stack; should not be used as an index, always subtracted from - let sp = stack.len(); - - let stack_start = 3 // the bootstrap ret addr, then guest func ret addr, then the backstop ret addr - + spilled_args.len() // then any args to guest func that don't fit in registers - + spilled_args.len() % 2 // padding to keep the stack 16-byte aligned when we spill an odd number of spilled arguments - + 4; // then the backstop args and terminator - - // stack-saved arguments start 3 below the top of the stack - // (TODO: a diagram would be great here) - let mut stack_args_ix = 3; - - // If there are more additional args to the guest function than available registers, they - // have to be pushed on the stack underneath the return address. - for arg in spilled_args { - let v = val_to_stack(arg); - stack[sp + stack_args_ix - stack_start] = v; - stack_args_ix += 1; - } - - // Prepare the stack for a swap context that lands in the bootstrap function swap will ret - // into the bootstrap function - stack[sp + 0 - stack_start] = lucet_context_bootstrap as u64; - - // The bootstrap function returns into the guest function, fptr - stack[sp + 1 - stack_start] = fptr as u64; - - // the guest function returns into lucet_context_backstop. - stack[sp + 2 - stack_start] = lucet_context_backstop as u64; - - // if fptr ever returns, it returns to the backstop func. backstop needs two arguments in - // its frame - first the context we are switching *out of* (which is also the one we are - // creating right now) and the ctx we switch back into. Note *parent might not be a valid - // ctx now, but it should be when this ctx is started. - stack[sp - 4] = child as *mut Context as u64; - stack[sp - 3] = parent as *mut Context as u64; - // Terminate the call chain. - stack[sp - 2] = 0; - stack[sp - 1] = 0; + // set up an initial call stack for guests to bootstrap into and execute + let mut stack_builder = CallStackBuilder::new(stack); + + // store arguments we'll pass to `lucet_context_swap` on the stack, above where the guest + // might scribble over them. + stack_builder.push(parent as *mut Context as u64); + stack_builder.push(child as *mut Context as u64); + + // we'll pass a pointer to them via `rbp` in the guest's Context we switch to. + let backstop_args = stack_builder.offset(); + + // we actually don't want to put an explicit pointer to these arguments anywhere. we'll + // line up the rest of the stack such that these are in argument position when we jump to + // `fptr`. + stack_builder.store_args(spilled_args.as_slice()); + + // the stack must be aligned in the environment we'll execute `fptr` from - this is an ABI + // requirement and can cause segfaults if not upheld. + assert_eq!( + stack_builder.offset() % 2, + 0, + "incorrect alignment for guest call frame" + ); + + // we execute the guest code via returns, so we make a "call stack" of routines like: + // -> lucet_context_backstop() + // -> fptr() + // -> lucet_context_bootstrap() + // + // with each address the start of the named function, so when the inner function + // completes it returns to begin the next function up. + stack_builder.push(lucet_context_backstop as u64); + stack_builder.push(fptr as u64); + stack_builder.push(lucet_context_bootstrap as u64); + + let (stack, stack_start) = stack_builder.into_inner(); // RSP, RBP, and sigset still remain to be initialized. - // Stack pointer: this has the return address of the first function to be run on the swap. - child.gpr.rsp = &mut stack[sp - stack_start] as *mut u64 as u64; - // Frame pointer: this is only used by the backstop code. It uses it to locate the ctx and - // parent arguments set above. - child.gpr.rbp = &mut stack[sp - 2] as *mut u64 as u64; + // Stack pointer: this points to the return address that will be used by `swap`, in place + // of the original (eg, in the host) return address. The return address this points to is + // the address of the first function to run on `swap`: `lucet_context_bootstrap`. + child.gpr.rsp = &mut stack[stack.len() - stack_start] as *mut u64 as u64; + + // This value in rbp is only used in `lucet_context_backstop`, where we use it to locate + // the parent and child contexts to `Context::swap` with. + child.gpr.rbp = &mut stack[stack.len() - backstop_args] as *mut u64 as u64; // Read the sigprocmask to be restored if we ever need to jump out of a signal handler. If // this isn't possible, die. From 6f29071eea2b00b50300b280ba0424521808199d Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 20 Sep 2019 15:21:29 -0700 Subject: [PATCH 381/512] upgrade to cranelift 0.43.1, wasmparser 0.39.1 --- Cargo.lock | 80 ++++++++++++---------- benchmarks/lucet-benchmarks/src/compile.rs | 2 +- benchmarks/lucet-benchmarks/src/par.rs | 2 +- benchmarks/lucet-benchmarks/src/seq.rs | 8 +-- cranelift | 2 +- lucet-module/Cargo.toml | 2 +- lucet-spectest/src/script.rs | 2 +- lucet-wasi-sdk/tests/lucetc.rs | 8 +-- lucetc/Cargo.toml | 16 ++--- lucetc/src/compiler.rs | 28 ++++---- lucetc/src/decls.rs | 5 ++ lucetc/src/options.rs | 10 +-- lucetc/tests/wasm.rs | 43 +++++++----- 13 files changed, 116 insertions(+), 92 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0bb2d1e59..181254141 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -287,41 +287,42 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.41.0" +version = "0.43.1" dependencies = [ - "cranelift-entity 0.41.0", + "cranelift-entity 0.43.1", ] [[package]] name = "cranelift-codegen" -version = "0.41.0" +version = "0.43.1" dependencies = [ - "cranelift-bforest 0.41.0", - "cranelift-codegen-meta 0.41.0", - "cranelift-entity 0.41.0", + "cranelift-bforest 0.43.1", + "cranelift-codegen-meta 0.43.1", + "cranelift-entity 0.43.1", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-codegen-meta" -version = "0.41.0" +version = "0.43.1" dependencies = [ - "cranelift-entity 0.41.0", + "cranelift-entity 0.43.1", ] [[package]] name = "cranelift-entity" -version = "0.41.0" +version = "0.43.1" [[package]] name = "cranelift-faerie" -version = "0.41.0" +version = "0.43.1" dependencies = [ - "cranelift-codegen 0.41.0", - "cranelift-module 0.41.0", + "cranelift-codegen 0.43.1", + "cranelift-module 0.43.1", "faerie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -330,43 +331,44 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.41.0" +version = "0.43.1" dependencies = [ - "cranelift-codegen 0.41.0", + "cranelift-codegen 0.43.1", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-module" -version = "0.41.0" +version = "0.43.1" dependencies = [ - "cranelift-codegen 0.41.0", - "cranelift-entity 0.41.0", + "cranelift-codegen 0.43.1", + "cranelift-entity 0.43.1", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-native" -version = "0.41.0" +version = "0.43.1" dependencies = [ - "cranelift-codegen 0.41.0", + "cranelift-codegen 0.43.1", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-wasm" -version = "0.41.0" +version = "0.43.1" dependencies = [ - "cranelift-codegen 0.41.0", - "cranelift-entity 0.41.0", - "cranelift-frontend 0.41.0", + "cranelift-codegen 0.43.1", + "cranelift-entity 0.43.1", + "cranelift-frontend 0.43.1", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.37.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -802,7 +804,7 @@ name = "lucet-idl" version = "0.1.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-entity 0.41.0", + "cranelift-entity 0.43.1", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", @@ -848,7 +850,7 @@ version = "0.1.1" dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-entity 0.41.0", + "cranelift-entity 0.43.1", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -991,13 +993,13 @@ dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.41.0", - "cranelift-entity 0.41.0", - "cranelift-faerie 0.41.0", - "cranelift-frontend 0.41.0", - "cranelift-module 0.41.0", - "cranelift-native 0.41.0", - "cranelift-wasm 0.41.0", + "cranelift-codegen 0.43.1", + "cranelift-entity 0.43.1", + "cranelift-faerie 0.43.1", + "cranelift-frontend 0.43.1", + "cranelift-module 0.43.1", + "cranelift-native 0.43.1", + "cranelift-wasm 0.43.1", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "faerie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1012,7 +1014,7 @@ dependencies = [ "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "wasmonkey 0.1.8", - "wasmparser 0.37.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1680,6 +1682,11 @@ name = "siphasher" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "smallvec" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "string-interner" version = "0.7.1" @@ -1924,7 +1931,7 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.37.1" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2163,6 +2170,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" "checksum siphasher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9913c75df657d84a03fa689c016b0bb2863ff0b497b26a8d6e9703f8d5df03a8" +"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" "checksum string-interner 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd710eadff449a1531351b0e43eb81ea404336fa2f56c777427ab0e32a4cf183" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" @@ -2192,7 +2200,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a6265b25719e82598d104b3717375e37661d41753e2c84cde3f51050c7ed7e3c" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" -"checksum wasmparser 0.37.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7329e663dfa399d8ad1a31a9358fc777140cd741cea56d154abbc4c9f7edb137" +"checksum wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a026c1436af49d5537c7561c7474f81f7a754e36445fe52e6e88795a9747291c" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" diff --git a/benchmarks/lucet-benchmarks/src/compile.rs b/benchmarks/lucet-benchmarks/src/compile.rs index 85fd65920..92a1efcbf 100644 --- a/benchmarks/lucet-benchmarks/src/compile.rs +++ b/benchmarks/lucet-benchmarks/src/compile.rs @@ -19,7 +19,7 @@ fn compile_hello_all(c: &mut Criterion) { criterion::BatchSize::SmallInput, ) }, - &[OptLevel::None, OptLevel::Standard, OptLevel::Fast], + &[OptLevel::None, OptLevel::Speed, OptLevel::SpeedAndSize], ) .sample_size(10); diff --git a/benchmarks/lucet-benchmarks/src/par.rs b/benchmarks/lucet-benchmarks/src/par.rs index ac595f3d5..61fdf77f5 100644 --- a/benchmarks/lucet-benchmarks/src/par.rs +++ b/benchmarks/lucet-benchmarks/src/par.rs @@ -42,7 +42,7 @@ fn par_instantiate(c: &mut Criterion) { let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); - compile_hello(&so_file, OptLevel::Fast); + compile_hello(&so_file, OptLevel::default()); let module = DlModule::load(&so_file).unwrap(); diff --git a/benchmarks/lucet-benchmarks/src/seq.rs b/benchmarks/lucet-benchmarks/src/seq.rs index 77651de5f..1fa946007 100644 --- a/benchmarks/lucet-benchmarks/src/seq.rs +++ b/benchmarks/lucet-benchmarks/src/seq.rs @@ -30,7 +30,7 @@ fn hello_load_mkregion_and_instantiate(c: &mut Criter let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); - compile_hello(&so_file, OptLevel::Fast); + compile_hello(&so_file, OptLevel::default()); c.bench_function( &format!("hello_load_mkregion_and_instantiate ({})", R::TYPE_NAME), @@ -58,7 +58,7 @@ fn hello_instantiate(c: &mut Criterion) { let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); - compile_hello(&so_file, OptLevel::Fast); + compile_hello(&so_file, OptLevel::default()); let module = DlModule::load(&so_file).unwrap(); let region = R::create(1, &Limits::default()).unwrap(); @@ -126,7 +126,7 @@ fn hello_drop_instance(c: &mut Criterion) { let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); - compile_hello(&so_file, OptLevel::Fast); + compile_hello(&so_file, OptLevel::default()); let module = DlModule::load(&so_file).unwrap(); let region = R::create(1, &Limits::default()).unwrap(); @@ -247,7 +247,7 @@ fn run_hello(c: &mut Criterion) { let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); - compile_hello(&so_file, OptLevel::Fast); + compile_hello(&so_file, OptLevel::default()); let module = DlModule::load(&so_file).unwrap(); let region = R::create(1, &Limits::default()).unwrap(); diff --git a/cranelift b/cranelift index 6850d8e60..5738526de 160000 --- a/cranelift +++ b/cranelift @@ -1 +1 @@ -Subproject commit 6850d8e60daf128633366b8c98461b0fb1972581 +Subproject commit 5738526de291188317ff6c93a207c5c877055f41 diff --git a/lucet-module/Cargo.toml b/lucet-module/Cargo.toml index 41fc62748..a9fa3f705 100644 --- a/lucet-module/Cargo.toml +++ b/lucet-module/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Lucet team "] edition = "2018" [dependencies] -cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.41.0" } +cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.43.1" } failure = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/lucet-spectest/src/script.rs b/lucet-spectest/src/script.rs index 7afbf755f..555065b0c 100644 --- a/lucet-spectest/src/script.rs +++ b/lucet-spectest/src/script.rs @@ -69,7 +69,7 @@ impl ScriptEnv { let bindings = bindings::spec_test_bindings(); let compiler = Compiler::new( module, - OptLevel::Fast, + OptLevel::default(), &bindings, HeapSettings::default(), true, diff --git a/lucet-wasi-sdk/tests/lucetc.rs b/lucet-wasi-sdk/tests/lucetc.rs index a1186509f..c7e270449 100644 --- a/lucet-wasi-sdk/tests/lucetc.rs +++ b/lucet-wasi-sdk/tests/lucetc.rs @@ -39,7 +39,7 @@ mod lucetc_tests { let m = module_from_c(&["empty"], &[]).expect("build module for empty"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile empty"); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compile empty"); let mdata = c.module_data().unwrap(); assert!(mdata.heap_spec().is_some()); // clang creates 3 globals: @@ -74,7 +74,7 @@ mod lucetc_tests { let m = module_from_c(&["c"], &["c"]).expect("build module for c"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile c"); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compile c"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 0, "import functions"); assert_eq!(mdata.export_functions().len(), 1, "export functions"); @@ -91,7 +91,7 @@ mod lucetc_tests { let m = module_from_c(&["d"], &["d"]).expect("build module for d"); let b = d_only_test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile d"); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compile d"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 1, "import functions"); assert_eq!(mdata.export_functions().len(), 1, "export functions"); @@ -107,7 +107,7 @@ mod lucetc_tests { let m = module_from_c(&["c", "d"], &["c", "d"]).expect("build module for c & d"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile c & d"); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compile c & d"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 0, "import functions"); assert_eq!(mdata.export_functions().len(), 2, "export functions"); diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index fd934ce6b..b621edfd8 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -18,16 +18,16 @@ path = "src/main.rs" [dependencies] bincode = "1.1.4" -cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.41.0" } -cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.41.0" } -cranelift-native = { path = "../cranelift/cranelift-native", version = "0.41.0" } -cranelift-frontend = { path = "../cranelift/cranelift-frontend", version = "0.41.0" } -cranelift-module = { path = "../cranelift/cranelift-module", version = "0.41.0" } -cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.41.0" } -cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.41.0" } +cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.43.1" } +cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.43.1" } +cranelift-native = { path = "../cranelift/cranelift-native", version = "0.43.1" } +cranelift-frontend = { path = "../cranelift/cranelift-frontend", version = "0.43.1" } +cranelift-module = { path = "../cranelift/cranelift-module", version = "0.43.1" } +cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.43.1" } +cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.43.1" } target-lexicon = "0.8.0" lucet-module = { path = "../lucet-module", version = "0.1.1" } -wasmparser = "0.37.0" +wasmparser = "0.39.1" clap="2.32" log = "0.4" env_logger = "0.6" diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index 954cc3a12..c6c3e228d 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -24,22 +24,22 @@ use lucet_module::{FunctionSpec, ModuleData, MODULE_DATA_SYM}; #[derive(Debug, Clone, Copy)] pub enum OptLevel { None, - Standard, - Fast, + Speed, + SpeedAndSize, } impl Default for OptLevel { fn default() -> OptLevel { - OptLevel::Standard + OptLevel::SpeedAndSize } } impl OptLevel { pub fn to_flag(&self) -> &str { match self { - OptLevel::None => "fastest", - OptLevel::Standard => "default", - OptLevel::Fast => "best", + OptLevel::None => "none", + OptLevel::Speed => "speed", + OptLevel::SpeedAndSize => "speed_and_size", } } } @@ -64,14 +64,18 @@ impl<'a> Compiler<'a> { let frontend_config = isa.frontend_config(); let mut module_info = ModuleInfo::new(frontend_config.clone()); - // As of cranelift-wasm 0.29, which uses wasmparser 0.23, the parser used inside + // As of cranelift-wasm 0.43 which uses wasmparser 0.40, the parser used inside // cranelift-wasm does not validate. We need to run the validating parser on the binary // first. The InvalidWebAssembly error below will never trigger. - use wasmparser::validate; - if !validate(wasm_binary, None) { - Err(format_err!("wasmparser validation rejected module")) - .context(LucetcErrorKind::Validation)?; - } + wasmparser::validate(wasm_binary, None) + .map_err(|e| { + format_err!( + "invalid WebAssembly module, at offset {}: {}", + e.offset, + e.message + ) + }) + .context(LucetcErrorKind::Validation)?; translate_module(wasm_binary, &mut module_info).map_err(|e| match e { WasmError::User(_) => e.context(LucetcErrorKind::Input), diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index b30d9a7b2..936515335 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -342,6 +342,11 @@ impl<'a> ModuleDecls<'a> { .context(LucetcErrorKind::TranslatingModule) } } + GlobalInit::V128Const(_) => Err(format_err!( + "invalid declaration of global {}: v128const type", + ix.as_u32() + )) + .context(LucetcErrorKind::Unsupported), }?; globals.push(GlobalSpec::new(global, g_decl.export_names.clone())); diff --git a/lucetc/src/options.rs b/lucetc/src/options.rs index e9fad6433..f8d6ee099 100644 --- a/lucetc/src/options.rs +++ b/lucetc/src/options.rs @@ -100,10 +100,10 @@ impl Options { }; let opt_level = match m.value_of("opt_level") { - None => OptLevel::default(), + None => OptLevel::SpeedAndSize, Some("0") => OptLevel::None, - Some("1") => OptLevel::Standard, - Some("2") | Some("fast") => OptLevel::Fast, + Some("1") => OptLevel::Speed, + Some("2") => OptLevel::SpeedAndSize, Some(_) => panic!("unknown value for opt-level"), }; @@ -214,8 +214,8 @@ impl Options { Arg::with_name("opt_level") .long("--opt-level") .takes_value(true) - .possible_values(&["0", "1", "2", "fast"]) - .help("optimization level (default: '1')"), + .possible_values(&["0", "1", "2", "none", "speed", "speed_and_size"]) + .help("optimization level (default: 'speed_and_size'). 0 is alias to 'none', 1 to 'speed', 2 to 'speed_and_size'"), ) .arg( Arg::with_name("keygen") diff --git a/lucetc/tests/wasm.rs b/lucetc/tests/wasm.rs index 46e820edc..5c8254176 100644 --- a/lucetc/tests/wasm.rs +++ b/lucetc/tests/wasm.rs @@ -42,7 +42,8 @@ mod module_data { let m = load_wat_module("exported_import"); let b = super::test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compiling exported_import"); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false) + .expect("compiling exported_import"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.globals_spec().len(), 0); @@ -61,7 +62,8 @@ mod module_data { let m = load_wat_module("multiple_import"); let b = super::test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compiling multiple_import"); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false) + .expect("compiling multiple_import"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.globals_spec().len(), 0); @@ -76,7 +78,8 @@ mod module_data { let m = load_wat_module("globals_export"); let b = super::test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compiling globals_export"); + let c = + Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compiling globals_export"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.globals_spec().len(), 1); @@ -92,7 +95,7 @@ mod module_data { let m = load_wat_module("fibonacci"); let b = super::test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compiling fibonacci"); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compiling fibonacci"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.globals_spec().len(), 0); @@ -106,7 +109,7 @@ mod module_data { let m = load_wat_module("arith"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compiling arith"); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compiling arith"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.globals_spec().len(), 0); @@ -123,7 +126,8 @@ mod module_data { )) .unwrap(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile duplicate_imports"); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false) + .expect("compile duplicate_imports"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 2); @@ -149,7 +153,7 @@ mod module_data { )) .unwrap(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile icall"); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compile icall"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 1); @@ -185,7 +189,7 @@ mod module_data { let m = load_wat_module("icall"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile icall"); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compile icall"); let _module_data = c.module_data().unwrap(); /* TODO can't express these with module data @@ -210,7 +214,7 @@ mod module_data { let m = load_wat_module("icall_sparse"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile icall_sparse"); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compile icall_sparse"); let _module_data = c.module_data().unwrap(); /* TODO can't express these with module data @@ -249,7 +253,8 @@ mod module_data { let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile globals_import"); + let c = + Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compile globals_import"); let module_data = c.module_data().unwrap(); let gspec = module_data.globals_spec(); @@ -270,7 +275,7 @@ mod module_data { let m = load_wat_module("heap_spec_import"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h.clone(), false) + let c = Compiler::new(&m, OptLevel::default(), &b, h.clone(), false) .expect("compiling heap_spec_import"); assert_eq!( @@ -293,7 +298,7 @@ mod module_data { let m = load_wat_module("heap_spec_definition"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h.clone(), false) + let c = Compiler::new(&m, OptLevel::default(), &b, h.clone(), false) .expect("compiling heap_spec_definition"); assert_eq!( @@ -315,7 +320,8 @@ mod module_data { let m = load_wat_module("heap_spec_none"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compiling heap_spec_none"); + let c = + Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compiling heap_spec_none"); assert_eq!(c.module_data().unwrap().heap_spec(), None,); } @@ -324,7 +330,7 @@ mod module_data { let m = load_wat_module("oversize_data_segment"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h, false); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false); assert!( c.is_err(), "compilation error because data initializers are oversized" @@ -347,7 +353,7 @@ mod module_data { let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::Fast, &b, h, false); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false); assert!( c.is_err(), "compilation error because wasm module is invalid" @@ -360,7 +366,8 @@ mod module_data { let m = load_wat_module("start_section"); let b = Bindings::empty(); let h = HeapSettings::default(); - let _c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile start_section"); + let _c = + Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compile start_section"); /* assert!( p.module().start_section().is_some(), @@ -378,8 +385,8 @@ mod compile { let m = load_wat_module(file); let b = super::test_bindings(); let h = HeapSettings::default(); - let c = - Compiler::new(&m, OptLevel::Fast, &b, h, false).expect(&format!("compile {}", file)); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false) + .expect(&format!("compile {}", file)); let _obj = c.object_file().expect(&format!("codegen {}", file)); } macro_rules! compile_test { From 8bab844ff7c4c2a7863b4eeacf01bb0788a92869 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 25 Sep 2019 11:21:15 -0700 Subject: [PATCH 382/512] cranelift 0.44.0 --- Cargo.lock | 70 ++++++++++++++++++++++------------------- cranelift | 2 +- lucet-module/Cargo.toml | 2 +- lucetc/Cargo.toml | 14 ++++----- 4 files changed, 47 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 181254141..7e293a4e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -287,18 +287,19 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.43.1" +version = "0.44.0" dependencies = [ - "cranelift-entity 0.43.1", + "cranelift-entity 0.44.0", ] [[package]] name = "cranelift-codegen" -version = "0.43.1" +version = "0.44.0" dependencies = [ - "cranelift-bforest 0.43.1", - "cranelift-codegen-meta 0.43.1", - "cranelift-entity 0.43.1", + "cranelift-bforest 0.44.0", + "cranelift-codegen-meta 0.44.0", + "cranelift-codegen-shared 0.44.0", + "cranelift-entity 0.44.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -308,21 +309,26 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.43.1" +version = "0.44.0" dependencies = [ - "cranelift-entity 0.43.1", + "cranelift-codegen-shared 0.44.0", + "cranelift-entity 0.44.0", ] +[[package]] +name = "cranelift-codegen-shared" +version = "0.44.0" + [[package]] name = "cranelift-entity" -version = "0.43.1" +version = "0.44.0" [[package]] name = "cranelift-faerie" -version = "0.43.1" +version = "0.44.0" dependencies = [ - "cranelift-codegen 0.43.1", - "cranelift-module 0.43.1", + "cranelift-codegen 0.44.0", + "cranelift-module 0.44.0", "faerie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -331,9 +337,9 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.43.1" +version = "0.44.0" dependencies = [ - "cranelift-codegen 0.43.1", + "cranelift-codegen 0.44.0", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -341,30 +347,30 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.43.1" +version = "0.44.0" dependencies = [ - "cranelift-codegen 0.43.1", - "cranelift-entity 0.43.1", + "cranelift-codegen 0.44.0", + "cranelift-entity 0.44.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-native" -version = "0.43.1" +version = "0.44.0" dependencies = [ - "cranelift-codegen 0.43.1", + "cranelift-codegen 0.44.0", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-wasm" -version = "0.43.1" +version = "0.44.0" dependencies = [ - "cranelift-codegen 0.43.1", - "cranelift-entity 0.43.1", - "cranelift-frontend 0.43.1", + "cranelift-codegen 0.44.0", + "cranelift-entity 0.44.0", + "cranelift-frontend 0.44.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -804,7 +810,7 @@ name = "lucet-idl" version = "0.1.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-entity 0.43.1", + "cranelift-entity 0.44.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", @@ -850,7 +856,7 @@ version = "0.1.1" dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-entity 0.43.1", + "cranelift-entity 0.44.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -993,13 +999,13 @@ dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.43.1", - "cranelift-entity 0.43.1", - "cranelift-faerie 0.43.1", - "cranelift-frontend 0.43.1", - "cranelift-module 0.43.1", - "cranelift-native 0.43.1", - "cranelift-wasm 0.43.1", + "cranelift-codegen 0.44.0", + "cranelift-entity 0.44.0", + "cranelift-faerie 0.44.0", + "cranelift-frontend 0.44.0", + "cranelift-module 0.44.0", + "cranelift-native 0.44.0", + "cranelift-wasm 0.44.0", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "faerie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/cranelift b/cranelift index 5738526de..d5c34954d 160000 --- a/cranelift +++ b/cranelift @@ -1 +1 @@ -Subproject commit 5738526de291188317ff6c93a207c5c877055f41 +Subproject commit d5c34954d9ea94732a1711542c2e42790870adb0 diff --git a/lucet-module/Cargo.toml b/lucet-module/Cargo.toml index a9fa3f705..a046d810f 100644 --- a/lucet-module/Cargo.toml +++ b/lucet-module/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Lucet team "] edition = "2018" [dependencies] -cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.43.1" } +cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.44.0" } failure = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index b621edfd8..b60be4b7b 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -18,13 +18,13 @@ path = "src/main.rs" [dependencies] bincode = "1.1.4" -cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.43.1" } -cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.43.1" } -cranelift-native = { path = "../cranelift/cranelift-native", version = "0.43.1" } -cranelift-frontend = { path = "../cranelift/cranelift-frontend", version = "0.43.1" } -cranelift-module = { path = "../cranelift/cranelift-module", version = "0.43.1" } -cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.43.1" } -cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.43.1" } +cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.44.0" } +cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.44.0" } +cranelift-native = { path = "../cranelift/cranelift-native", version = "0.44.0" } +cranelift-frontend = { path = "../cranelift/cranelift-frontend", version = "0.44.0" } +cranelift-module = { path = "../cranelift/cranelift-module", version = "0.44.0" } +cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.44.0" } +cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.44.0" } target-lexicon = "0.8.0" lucet-module = { path = "../lucet-module", version = "0.1.1" } wasmparser = "0.39.1" From f50f934397ecdd901dd2e65ad4a5ef36d0133293 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 25 Sep 2019 14:12:21 -0700 Subject: [PATCH 383/512] lucet-benchmarks: use module-level constant to explicitly pin OptLevel --- benchmarks/lucet-benchmarks/src/par.rs | 5 ++++- benchmarks/lucet-benchmarks/src/seq.rs | 11 +++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/benchmarks/lucet-benchmarks/src/par.rs b/benchmarks/lucet-benchmarks/src/par.rs index 61fdf77f5..be017d39c 100644 --- a/benchmarks/lucet-benchmarks/src/par.rs +++ b/benchmarks/lucet-benchmarks/src/par.rs @@ -6,6 +6,9 @@ use rayon::prelude::*; use std::sync::Arc; use tempfile::TempDir; +/// Common definiton of OptLevel +const BENCHMARK_OPT_LEVEL: OptLevel = OptLevel::SpeedAndSize; + /// Parallel instantiation. /// /// This measures how well the region handles concurrent instantiations from multiple @@ -42,7 +45,7 @@ fn par_instantiate(c: &mut Criterion) { let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); - compile_hello(&so_file, OptLevel::default()); + compile_hello(&so_file, BENCHMARK_OPT_LEVEL); let module = DlModule::load(&so_file).unwrap(); diff --git a/benchmarks/lucet-benchmarks/src/seq.rs b/benchmarks/lucet-benchmarks/src/seq.rs index 1fa946007..28983d552 100644 --- a/benchmarks/lucet-benchmarks/src/seq.rs +++ b/benchmarks/lucet-benchmarks/src/seq.rs @@ -7,6 +7,9 @@ use std::path::Path; use std::sync::Arc; use tempfile::TempDir; +/// Common definiton of OptLevel +const BENCHMARK_OPT_LEVEL: OptLevel = OptLevel::SpeedAndSize; + const DENSE_HEAP_SIZES_KB: &'static [usize] = &[0, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2 * 1024, 4 * 1024]; @@ -30,7 +33,7 @@ fn hello_load_mkregion_and_instantiate(c: &mut Criter let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); - compile_hello(&so_file, OptLevel::default()); + compile_hello(&so_file, BENCHMARK_OPT_LEVEL); c.bench_function( &format!("hello_load_mkregion_and_instantiate ({})", R::TYPE_NAME), @@ -58,7 +61,7 @@ fn hello_instantiate(c: &mut Criterion) { let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); - compile_hello(&so_file, OptLevel::default()); + compile_hello(&so_file, BENCHMARK_OPT_LEVEL); let module = DlModule::load(&so_file).unwrap(); let region = R::create(1, &Limits::default()).unwrap(); @@ -126,7 +129,7 @@ fn hello_drop_instance(c: &mut Criterion) { let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); - compile_hello(&so_file, OptLevel::default()); + compile_hello(&so_file, BENCHMARK_OPT_LEVEL); let module = DlModule::load(&so_file).unwrap(); let region = R::create(1, &Limits::default()).unwrap(); @@ -247,7 +250,7 @@ fn run_hello(c: &mut Criterion) { let workdir = TempDir::new().expect("create working directory"); let so_file = workdir.path().join("out.so"); - compile_hello(&so_file, OptLevel::default()); + compile_hello(&so_file, BENCHMARK_OPT_LEVEL); let module = DlModule::load(&so_file).unwrap(); let region = R::create(1, &Limits::default()).unwrap(); From cffa6caee88e677c65149378f81d8fb214a47de1 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 20 Sep 2019 15:21:29 -0700 Subject: [PATCH 384/512] upgrade to cranelift 0.43.1, wasmparser 0.39.1 --- Cargo.lock | 130 ++++++++++++++++++++++++++--------------------------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7e293a4e8..9396c4c4b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,7 +2,7 @@ # It is not intended for manual editing. [[package]] name = "adler32" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -50,7 +50,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.37" +version = "0.3.38" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", @@ -64,7 +64,7 @@ name = "backtrace-sys" version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -96,7 +96,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -170,7 +170,7 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -199,7 +199,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cc" -version = "1.0.42" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -262,7 +262,7 @@ name = "cmake" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -404,8 +404,8 @@ dependencies = [ "rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -478,7 +478,7 @@ dependencies = [ "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -499,7 +499,7 @@ dependencies = [ [[package]] name = "either" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -508,7 +508,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -540,7 +540,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "indexmap 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "string-interner 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -552,7 +552,7 @@ name = "failure" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -704,7 +704,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "humantime" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -720,13 +720,13 @@ dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "indexmap" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -734,7 +734,7 @@ name = "itertools" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -766,7 +766,7 @@ name = "libloading" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -863,7 +863,7 @@ dependencies = [ "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "object 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -872,7 +872,7 @@ name = "lucet-runtime" version = "0.1.1" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", @@ -895,7 +895,7 @@ dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -913,7 +913,7 @@ dependencies = [ name = "lucet-runtime-tests" version = "0.1.1" dependencies = [ - "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", @@ -932,7 +932,7 @@ dependencies = [ "lucet-module 0.1.1", "lucet-runtime 0.1.1", "lucetc 0.1.1", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1055,7 +1055,7 @@ name = "miniz-sys" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1064,7 +1064,7 @@ name = "miniz_oxide" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1073,7 +1073,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1194,7 +1194,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "pkg-config" -version = "0.3.15" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1212,7 +1212,7 @@ name = "precision" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1232,7 +1232,7 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1283,7 +1283,7 @@ name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1318,7 +1318,7 @@ dependencies = [ [[package]] name = "rand" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1446,7 +1446,7 @@ version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1456,7 +1456,7 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1625,18 +1625,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.99" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.99" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1648,7 +1648,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1676,8 +1676,8 @@ dependencies = [ "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "precision 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "printtable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1685,7 +1685,7 @@ dependencies = [ [[package]] name = "siphasher" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1698,7 +1698,7 @@ name = "string-interner" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1746,7 +1746,7 @@ name = "syn" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1779,7 +1779,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1823,7 +1823,7 @@ name = "tinytemplate" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1832,7 +1832,7 @@ name = "toml" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1885,8 +1885,8 @@ name = "wabt" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1896,7 +1896,7 @@ name = "wabt-sys" version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1928,10 +1928,10 @@ dependencies = [ "goblin 0.0.23 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "siphasher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "siphasher 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2020,14 +2020,14 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" +"checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94" "checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" "checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" -"checksum backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)" = "5180c5a20655b14a819b652fd2378fa5f1697b6c9ddad3e695c2f9cedf6df4e2" +"checksum backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "690a62be8920ccf773ee00ef0968649b0e724cda8bd5b12286302b4ae955fdf5" "checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum bencher 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdb4953a096c551ce9ace855a604d702e6e62d77fac690575ae347571717f5" @@ -2045,7 +2045,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" -"checksum cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)" = "a61c7bce55cd2fae6ec8cb935ebd76256c2959a1f95790f6118a441c2cd5b406" +"checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be" "checksum cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7fa24eb00d5ffab90eaeaf1092ac85c04c64aaf358ea6f84505b8116d24c6af" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c" @@ -2066,7 +2066,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d" "checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" "checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" +"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" "checksum errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2a071601ed01b988f896ab14b95e67335d1eeb50190932a1320f7fe3cadc84e" "checksum errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067" @@ -2090,9 +2090,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" "checksum human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bec6e801ef7367625bd94ad7e2965e6027189f3e9deef422388d993af2814a0" -"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" +"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" "checksum hwloc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2934f84993b8b4bcae9b6a4e5f0aca638462dda9c7b4f26a570241494f21e0f4" -"checksum indexmap 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4d6d89e0948bf10c08b9ecc8ac5b83f07f857ebe2c0cbe38de15b4e4f510356" +"checksum indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a61202fbe46c4a951e9404a720a0180bcf3212c750d735cb5c4ba4dc551299f3" "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" @@ -2120,13 +2120,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)" = "20d7e522a7f994cc4ae32970b1ce0d99ecf91b8e1df080517a26faa6d2e2ee62" "checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" "checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" -"checksum pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c1d2cfa5a714db3b5f24f0915e74fcdf91d09d496ba61329705dda7774d2af" +"checksum pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "72d5370d90f49f70bd033c3d75e87fc529fbfff9d6f7cccef07d6170079d91ea" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum precision 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "83f0b3de90e9edd6382604f4f28509ce25272deb065b94045fc47abcde567d55" "checksum printtable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "69967dae4cac71681361899d9905d3d2985fc989d7afb32a8dff3aed5461ecdf" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "175a40b9cf564ce9bf050654633dbf339978706b8ead1a907bb970b63185dd95" +"checksum proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afdc77cc74ec70ed262262942ebb7dac3d479e9e5cfa2da1841c0806f6cdabcc" "checksum progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b820305721858696053a7fd0215cfeeee16ecaaf96b7a209945428e02f1c44" "checksum proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf147e022eacf0c8a054ab864914a7602618adba841d800a9a9868a5237a529f" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" @@ -2134,7 +2134,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" +"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" @@ -2171,11 +2171,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum scrypt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "656c79d0e90d0ab28ac86bf3c3d10bfbbac91450d3f190113b4e76d9fec3cfdd" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" -"checksum serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "cb4dc18c61206b08dc98216c98faa0232f4337e1e1b8574551d5bad29ea1b425" +"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" +"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e" "checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" -"checksum siphasher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9913c75df657d84a03fa689c016b0bb2863ff0b497b26a8d6e9703f8d5df03a8" +"checksum siphasher 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "83da420ee8d1a89e640d0948c646c1c088758d3a3c538f943bfa97bdac17929d" "checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" "checksum string-interner 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd710eadff449a1531351b0e43eb81ea404336fa2f56c777427ab0e32a4cf183" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" From e8b5438c922f9da2a467ec3f834e1d37f44d6670 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 19 Sep 2019 15:29:25 -0700 Subject: [PATCH 385/512] lucet-validate: initial commit --- Cargo.lock | 20 ++++++++++ Cargo.toml | 1 + lucet-validate/Cargo.toml | 23 +++++++++++ lucet-validate/src/lib.rs | 12 ++++++ lucet-validate/src/main.rs | 80 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 136 insertions(+) create mode 100644 lucet-validate/Cargo.toml create mode 100644 lucet-validate/src/lib.rs create mode 100644 lucet-validate/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 9396c4c4b..ebe97f81e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -938,6 +938,16 @@ dependencies = [ "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lucet-validate" +version = "0.1.0" +dependencies = [ + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.37.1 (registry+https://github.com/rust-lang/crates.io-index)", + "witx 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "lucet-wasi" version = "0.1.1" @@ -2006,6 +2016,15 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "witx" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "witx-frontend" version = "0.1.0" @@ -2216,4 +2235,5 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" "checksum winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef84b96d10db72dd980056666d7f1e7663ce93d82fa33b63e71c966f4cf5032" +"checksum witx 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "604cc621e6dbe18e5229955b0b3abfbeb95b27b413e8fcac367ecf2f0e3d10c2" "checksum xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da90eac47bf1d7871b75004b9b631d107df15f37669383b23f0b5297bc7516b6" diff --git a/Cargo.toml b/Cargo.toml index 88e0923f0..d15abe273 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ members = [ "lucet-runtime/lucet-runtime-internals", "lucet-runtime/lucet-runtime-tests", "lucet-spectest", + "lucet-validate", "lucet-wasi", "lucet-wasi-fuzz", "lucet-wasi-sdk", diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml new file mode 100644 index 000000000..97a75aa4d --- /dev/null +++ b/lucet-validate/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "lucet-validate" +version = "0.1.0" +description = "Parse and validate webassembly files against witx interface" +homepage = "https://github.com/fastly/lucet" +repository = "https://github.com/fastly/lucet" +license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +authors = ["Pat Hickey "] +edition = "2018" + +[lib] +crate-type=["rlib"] + +[[bin]] +name = "lucet-validate" +path = "src/main.rs" + +[dependencies] +clap = "2" +failure = "0.1" +witx = "0.1" +wasmparser = "0.37" diff --git a/lucet-validate/src/lib.rs b/lucet-validate/src/lib.rs new file mode 100644 index 000000000..26ecd02fd --- /dev/null +++ b/lucet-validate/src/lib.rs @@ -0,0 +1,12 @@ +use failure::Fail; +use witx; + +#[derive(Debug, Fail)] +pub enum Error { + #[fail(display = "Idk")] + Idk, +} + +pub fn validate(interface: &witx::Document, module_contents: &[u8]) -> Result<(), Error> { + Err(Error::Idk) +} diff --git a/lucet-validate/src/main.rs b/lucet-validate/src/main.rs new file mode 100644 index 000000000..ea827bfb9 --- /dev/null +++ b/lucet-validate/src/main.rs @@ -0,0 +1,80 @@ +#[macro_use] +extern crate clap; +use clap::Arg; +use failure::Fail; +use lucet_validate; +use std::fs::File; +use std::io::{self, Read}; +use std::path::{Path, PathBuf}; +use std::process; +use witx; + +pub fn main() { + // rebuild if env vars used by app_from_crate! change: + let _ = include_str!("../Cargo.toml"); + + let matches = app_from_crate!() + .arg(Arg::with_name("interface").takes_value(true).required(true)) + .arg(Arg::with_name("module").takes_value(true).required(true)) + .arg( + Arg::with_name("verbose") + .short("v") + .takes_value(false) + .required(false), + ) + .get_matches(); + + let interface_path = PathBuf::from( + matches + .value_of("interface") + .expect("interface arg required"), + ); + let input_path = PathBuf::from(matches.value_of("module").expect("module arg required")); + + match run(&interface_path, &input_path) { + Ok(()) => {} + Err(e) => { + if matches.is_present("verbose") { + println!("{:?}", e); + } else { + println!("{}", e); + } + process::exit(-1); + } + } +} + +fn run(interface: &Path, module: &Path) -> Result<(), Error> { + let interface_doc = witx::load(interface)?; + + let mut module_contents = Vec::new(); + let mut file = File::open(module).map_err(|e| Error::Io(module.into(), e))?; + file.read_to_end(&mut module_contents) + .map_err(|e| Error::Io(module.into(), e))?; + + lucet_validate::validate(&interface_doc, &module_contents)?; + + Ok(()) +} + +#[derive(Debug, Fail)] +enum Error { + #[fail(display = "{}", _0)] + Witx(#[cause] witx::WitxError), + #[fail(display = "With file {:?}: {}", _0, _1)] + Io(PathBuf, #[cause] io::Error), + #[fail(display = "{}", _0)] + Validate(#[cause] lucet_validate::Error), +} + +impl From for Error { + fn from(e: witx::WitxError) -> Error { + Error::Witx(e) + } +} + +impl From for Error { + fn from(e: lucet_validate::Error) -> Error { + Error::Validate(e) + } +} From fc0ff999bc598688a67106b3e60f6f34614636be Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 19 Sep 2019 18:46:46 -0700 Subject: [PATCH 386/512] lucet-validate: build up moduletype from parser --- Cargo.lock | 9 ++- lucet-validate/Cargo.toml | 3 +- lucet-validate/src/lib.rs | 130 +++++++++++++++++++++++++++++++++++++- 3 files changed, 137 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ebe97f81e..d7bb30414 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -943,8 +943,9 @@ name = "lucet-validate" version = "0.1.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-entity 0.43.1", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.37.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.39.1 (git+https://github.com/pchickey/wasmparser.rs?branch=pch/correct_section_content_api)", "witx 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1945,6 +1946,11 @@ dependencies = [ "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "wasmparser" +version = "0.39.1" +source = "git+https://github.com/pchickey/wasmparser.rs?branch=pch/correct_section_content_api#a4fc03884f52c78e65c898ef22094dfe5e166e6d" + [[package]] name = "wasmparser" version = "0.39.1" @@ -2225,6 +2231,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a6265b25719e82598d104b3717375e37661d41753e2c84cde3f51050c7ed7e3c" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" +"checksum wasmparser 0.39.1 (git+https://github.com/pchickey/wasmparser.rs?branch=pch/correct_section_content_api)" = "" "checksum wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a026c1436af49d5537c7561c7474f81f7a754e36445fe52e6e88795a9747291c" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index 97a75aa4d..0e54d1067 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -20,4 +20,5 @@ path = "src/main.rs" clap = "2" failure = "0.1" witx = "0.1" -wasmparser = "0.37" +cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.43.1" } +wasmparser = { git = "https://github.com/pchickey/wasmparser.rs", branch = "pch/correct_section_content_api" } diff --git a/lucet-validate/src/lib.rs b/lucet-validate/src/lib.rs index 26ecd02fd..a93e45df1 100644 --- a/lucet-validate/src/lib.rs +++ b/lucet-validate/src/lib.rs @@ -1,12 +1,136 @@ +use cranelift_entity::{entity_impl, PrimaryMap}; use failure::Fail; +use std::collections::HashMap; +use wasmparser::{ + self, ExternalKind, FuncType, ImportSectionEntryType, ModuleReader, SectionContent, Type, +}; use witx; #[derive(Debug, Fail)] pub enum Error { - #[fail(display = "Idk")] - Idk, + #[fail(display = "WebAssembly validation error at offset {}: {}", _1, 0)] + WasmValidation(&'static str, usize), + #[fail(display = "Unsupported: {}", _0)] + Unsupported(String), +} + +impl From for Error { + fn from(e: wasmparser::BinaryReaderError) -> Error { + Error::WasmValidation(e.message, e.offset) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] +struct TypeIndex(u32); +entity_impl!(TypeIndex); + +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] +struct FuncIndex(u32); +entity_impl!(FuncIndex); + +#[derive(Clone, Debug, PartialEq, Eq)] +struct FuncSignature { + params: Vec, + returns: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +struct Func { + ty: TypeIndex, + import: Option<(String, String)>, +} + +#[derive(Clone, Debug)] +struct ModuleType { + types: PrimaryMap, + funcs: PrimaryMap, + exports: HashMap, } pub fn validate(interface: &witx::Document, module_contents: &[u8]) -> Result<(), Error> { - Err(Error::Idk) + wasmparser::validate(module_contents, None)?; + + let mut module = ModuleType { + types: PrimaryMap::new(), + funcs: PrimaryMap::new(), + exports: HashMap::new(), + }; + + let mut module_reader = ModuleReader::new(module_contents)?; + while !module_reader.eof() { + let section = module_reader.read()?; + match section.content()? { + SectionContent::Type(types) => { + for entry in types { + match entry? { + FuncType { + form: wasmparser::Type::Func, + params, + returns, + } => { + module.types.push(FuncSignature { + params: params.to_vec(), + returns: returns.to_vec(), + }); + } + _ => Err(Error::Unsupported("type section entry".to_string()))?, + } + } + } + SectionContent::Import(imports) => { + for import in imports { + let import = import?; + match import.ty { + ImportSectionEntryType::Function(ftype) => { + module.funcs.push(Func { + ty: TypeIndex::from_u32(ftype), + import: Some((import.module.to_owned(), import.field.to_owned())), + }); + } + ImportSectionEntryType::Memory(_) => { + Err(Error::Unsupported(format!( + "memory import {}:{}", + import.module, import.field + )))?; + } + ImportSectionEntryType::Table(_) => { + Err(Error::Unsupported(format!( + "table import {}:{}", + import.module, import.field + )))?; + } + ImportSectionEntryType::Global(_) => { + Err(Error::Unsupported(format!( + "global import {}:{}", + import.module, import.field + )))?; + } + } + } + } + SectionContent::Export(exports) => { + for export in exports { + let export = export?; + match export.kind { + ExternalKind::Function => { + module.exports.insert( + export.field.to_string(), + FuncIndex::from_u32(export.index), + ); + } + _ => {} // Dont care about other exports + } + } + } + SectionContent::Function(functions) => { + for function_ty in functions { + let ty = TypeIndex::from_u32(function_ty?); + module.funcs.push(Func { ty, import: None }); + } + } + _ => {} // Dont care about other sections + } + } + + Ok(()) } From 964be269b0168deb1e1af713576e08663623c940 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 19 Sep 2019 19:24:42 -0700 Subject: [PATCH 387/512] lucet-validate: print out type sig of all imports, start func sig --- lucet-validate/src/lib.rs | 128 ++++---------------------- lucet-validate/src/moduletype.rs | 150 +++++++++++++++++++++++++++++++ 2 files changed, 167 insertions(+), 111 deletions(-) create mode 100644 lucet-validate/src/moduletype.rs diff --git a/lucet-validate/src/lib.rs b/lucet-validate/src/lib.rs index a93e45df1..7b21d6151 100644 --- a/lucet-validate/src/lib.rs +++ b/lucet-validate/src/lib.rs @@ -1,11 +1,11 @@ -use cranelift_entity::{entity_impl, PrimaryMap}; +mod moduletype; + use failure::Fail; -use std::collections::HashMap; -use wasmparser::{ - self, ExternalKind, FuncType, ImportSectionEntryType, ModuleReader, SectionContent, Type, -}; +use wasmparser; use witx; +pub use self::moduletype::{FuncSignature, ImportFunc, ModuleType}; + #[derive(Debug, Fail)] pub enum Error { #[fail(display = "WebAssembly validation error at offset {}: {}", _1, 0)] @@ -20,116 +20,22 @@ impl From for Error { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] -struct TypeIndex(u32); -entity_impl!(TypeIndex); - -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] -struct FuncIndex(u32); -entity_impl!(FuncIndex); - -#[derive(Clone, Debug, PartialEq, Eq)] -struct FuncSignature { - params: Vec, - returns: Vec, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -struct Func { - ty: TypeIndex, - import: Option<(String, String)>, -} - -#[derive(Clone, Debug)] -struct ModuleType { - types: PrimaryMap, - funcs: PrimaryMap, - exports: HashMap, -} - pub fn validate(interface: &witx::Document, module_contents: &[u8]) -> Result<(), Error> { wasmparser::validate(module_contents, None)?; - let mut module = ModuleType { - types: PrimaryMap::new(), - funcs: PrimaryMap::new(), - exports: HashMap::new(), - }; + let moduletype = ModuleType::parse(module_contents)?; + + for import in moduletype.imports() { + println!( + "import {}::{} has type {:?}", + import.module, import.field, import.ty + ); + } - let mut module_reader = ModuleReader::new(module_contents)?; - while !module_reader.eof() { - let section = module_reader.read()?; - match section.content()? { - SectionContent::Type(types) => { - for entry in types { - match entry? { - FuncType { - form: wasmparser::Type::Func, - params, - returns, - } => { - module.types.push(FuncSignature { - params: params.to_vec(), - returns: returns.to_vec(), - }); - } - _ => Err(Error::Unsupported("type section entry".to_string()))?, - } - } - } - SectionContent::Import(imports) => { - for import in imports { - let import = import?; - match import.ty { - ImportSectionEntryType::Function(ftype) => { - module.funcs.push(Func { - ty: TypeIndex::from_u32(ftype), - import: Some((import.module.to_owned(), import.field.to_owned())), - }); - } - ImportSectionEntryType::Memory(_) => { - Err(Error::Unsupported(format!( - "memory import {}:{}", - import.module, import.field - )))?; - } - ImportSectionEntryType::Table(_) => { - Err(Error::Unsupported(format!( - "table import {}:{}", - import.module, import.field - )))?; - } - ImportSectionEntryType::Global(_) => { - Err(Error::Unsupported(format!( - "global import {}:{}", - import.module, import.field - )))?; - } - } - } - } - SectionContent::Export(exports) => { - for export in exports { - let export = export?; - match export.kind { - ExternalKind::Function => { - module.exports.insert( - export.field.to_string(), - FuncIndex::from_u32(export.index), - ); - } - _ => {} // Dont care about other exports - } - } - } - SectionContent::Function(functions) => { - for function_ty in functions { - let ty = TypeIndex::from_u32(function_ty?); - module.funcs.push(Func { ty, import: None }); - } - } - _ => {} // Dont care about other sections - } + if let Some(startfunc) = moduletype.export("_start") { + println!("wasi start func has type {:?}", startfunc); + } else { + println!("no wasi start func"); } Ok(()) diff --git a/lucet-validate/src/moduletype.rs b/lucet-validate/src/moduletype.rs new file mode 100644 index 000000000..5bd1034df --- /dev/null +++ b/lucet-validate/src/moduletype.rs @@ -0,0 +1,150 @@ +use crate::Error; +use cranelift_entity::{entity_impl, PrimaryMap}; +use std::collections::HashMap; +pub use wasmparser::Type; +use wasmparser::{ExternalKind, FuncType, ImportSectionEntryType, ModuleReader, SectionContent}; + +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] +struct TypeIndex(u32); +entity_impl!(TypeIndex); + +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] +struct FuncIndex(u32); +entity_impl!(FuncIndex); + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct FuncSignature { + pub params: Vec, + pub returns: Vec, +} + +#[derive(Clone)] +struct Func { + pub ty: TypeIndex, + pub import: Option<(String, String)>, +} + +#[derive(Clone)] +pub struct ModuleType { + types: PrimaryMap, + funcs: PrimaryMap, + exports: HashMap, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ImportFunc { + pub module: String, + pub field: String, + pub ty: FuncSignature, +} + +impl ModuleType { + pub fn imports(&self) -> Vec { + self.funcs + .iter() + .filter_map(|(_, f)| { + f.import.clone().map(|(module, field)| ImportFunc { + module, + field, + ty: self.types.get(f.ty).expect("get type").clone(), + }) + }) + .collect() + } + + pub fn export(&self, name: &str) -> Option<&FuncSignature> { + self.exports.get(name).map(|funcix| { + let func = self.funcs.get(*funcix).expect("valid funcix"); + self.types.get(func.ty).expect("valid typeix") + }) + } + + pub fn parse(module_contents: &[u8]) -> Result { + let mut module = ModuleType { + types: PrimaryMap::new(), + funcs: PrimaryMap::new(), + exports: HashMap::new(), + }; + + let mut module_reader = ModuleReader::new(module_contents)?; + while !module_reader.eof() { + let section = module_reader.read()?; + match section.content()? { + SectionContent::Type(types) => { + for entry in types { + match entry? { + FuncType { + form: wasmparser::Type::Func, + params, + returns, + } => { + module.types.push(FuncSignature { + params: params.to_vec(), + returns: returns.to_vec(), + }); + } + _ => Err(Error::Unsupported("type section entry".to_string()))?, + } + } + } + SectionContent::Import(imports) => { + for import in imports { + let import = import?; + match import.ty { + ImportSectionEntryType::Function(ftype) => { + module.funcs.push(Func { + ty: TypeIndex::from_u32(ftype), + import: Some(( + import.module.to_owned(), + import.field.to_owned(), + )), + }); + } + ImportSectionEntryType::Memory(_) => { + Err(Error::Unsupported(format!( + "memory import {}:{}", + import.module, import.field + )))?; + } + ImportSectionEntryType::Table(_) => { + Err(Error::Unsupported(format!( + "table import {}:{}", + import.module, import.field + )))?; + } + ImportSectionEntryType::Global(_) => { + Err(Error::Unsupported(format!( + "global import {}:{}", + import.module, import.field + )))?; + } + } + } + } + SectionContent::Export(exports) => { + for export in exports { + let export = export?; + match export.kind { + ExternalKind::Function => { + module.exports.insert( + export.field.to_string(), + FuncIndex::from_u32(export.index), + ); + } + _ => {} // Dont care about other exports + } + } + } + SectionContent::Function(functions) => { + for function_ty in functions { + let ty = TypeIndex::from_u32(function_ty?); + module.funcs.push(Func { ty, import: None }); + } + } + _ => {} // Dont care about other sections + } + } + + Ok(module) + } +} From 915dcb8694d32c7220de7716717b54f00c5fc596 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 19 Sep 2019 20:14:09 -0700 Subject: [PATCH 388/512] lucet-validate: better api to witx crate is in a branch --- Cargo.lock | 6 +++--- lucet-validate/Cargo.toml | 2 +- lucet-validate/src/lib.rs | 2 +- lucet-validate/src/moduletype.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d7bb30414..cacff0bb6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -946,7 +946,7 @@ dependencies = [ "cranelift-entity 0.43.1", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "wasmparser 0.39.1 (git+https://github.com/pchickey/wasmparser.rs?branch=pch/correct_section_content_api)", - "witx 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "witx 0.1.0 (git+https://github.com/webassembly/wasi?branch=pch/witx_better_api)", ] [[package]] @@ -2025,7 +2025,7 @@ dependencies = [ [[package]] name = "witx" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/webassembly/wasi?branch=pch/witx_better_api#c6620677d8a41e3e4a330e23a042ca244f5f859a" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2242,5 +2242,5 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" "checksum winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef84b96d10db72dd980056666d7f1e7663ce93d82fa33b63e71c966f4cf5032" -"checksum witx 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "604cc621e6dbe18e5229955b0b3abfbeb95b27b413e8fcac367ecf2f0e3d10c2" +"checksum witx 0.1.0 (git+https://github.com/webassembly/wasi?branch=pch/witx_better_api)" = "" "checksum xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da90eac47bf1d7871b75004b9b631d107df15f37669383b23f0b5297bc7516b6" diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index 0e54d1067..2d6137e9f 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -19,6 +19,6 @@ path = "src/main.rs" [dependencies] clap = "2" failure = "0.1" -witx = "0.1" +witx = { git = "https://github.com/webassembly/wasi", branch = "pch/witx_better_api" } cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.43.1" } wasmparser = { git = "https://github.com/pchickey/wasmparser.rs", branch = "pch/correct_section_content_api" } diff --git a/lucet-validate/src/lib.rs b/lucet-validate/src/lib.rs index 7b21d6151..64141b083 100644 --- a/lucet-validate/src/lib.rs +++ b/lucet-validate/src/lib.rs @@ -23,7 +23,7 @@ impl From for Error { pub fn validate(interface: &witx::Document, module_contents: &[u8]) -> Result<(), Error> { wasmparser::validate(module_contents, None)?; - let moduletype = ModuleType::parse(module_contents)?; + let moduletype = ModuleType::parse_wasm(module_contents)?; for import in moduletype.imports() { println!( diff --git a/lucet-validate/src/moduletype.rs b/lucet-validate/src/moduletype.rs index 5bd1034df..74d161b06 100644 --- a/lucet-validate/src/moduletype.rs +++ b/lucet-validate/src/moduletype.rs @@ -59,7 +59,7 @@ impl ModuleType { }) } - pub fn parse(module_contents: &[u8]) -> Result { + pub fn parse_wasm(module_contents: &[u8]) -> Result { let mut module = ModuleType { types: PrimaryMap::new(), funcs: PrimaryMap::new(), From 4db9d49090faa0c9f9e2ea23e354fbde9c1dcad1 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 23 Sep 2019 15:22:28 -0700 Subject: [PATCH 389/512] lucet-validate: calculate module type of InterfaceFunc --- lucet-validate/src/lib.rs | 5 +- lucet-validate/src/moduletype.rs | 17 +------ lucet-validate/src/types.rs | 14 ++++++ lucet-validate/src/witx_moduletype.rs | 71 +++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 16 deletions(-) create mode 100644 lucet-validate/src/types.rs create mode 100644 lucet-validate/src/witx_moduletype.rs diff --git a/lucet-validate/src/lib.rs b/lucet-validate/src/lib.rs index 64141b083..eb58eb7eb 100644 --- a/lucet-validate/src/lib.rs +++ b/lucet-validate/src/lib.rs @@ -1,10 +1,13 @@ mod moduletype; +mod types; +mod witx_moduletype; use failure::Fail; use wasmparser; use witx; -pub use self::moduletype::{FuncSignature, ImportFunc, ModuleType}; +pub use self::moduletype::ModuleType; +pub use self::types::{AtomType, FuncSignature, ImportFunc}; #[derive(Debug, Fail)] pub enum Error { diff --git a/lucet-validate/src/moduletype.rs b/lucet-validate/src/moduletype.rs index 74d161b06..162f9710e 100644 --- a/lucet-validate/src/moduletype.rs +++ b/lucet-validate/src/moduletype.rs @@ -1,4 +1,4 @@ -use crate::Error; +use crate::{Error, FuncSignature, ImportFunc}; use cranelift_entity::{entity_impl, PrimaryMap}; use std::collections::HashMap; pub use wasmparser::Type; @@ -12,12 +12,6 @@ entity_impl!(TypeIndex); struct FuncIndex(u32); entity_impl!(FuncIndex); -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct FuncSignature { - pub params: Vec, - pub returns: Vec, -} - #[derive(Clone)] struct Func { pub ty: TypeIndex, @@ -31,13 +25,6 @@ pub struct ModuleType { exports: HashMap, } -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct ImportFunc { - pub module: String, - pub field: String, - pub ty: FuncSignature, -} - impl ModuleType { pub fn imports(&self) -> Vec { self.funcs @@ -80,7 +67,7 @@ impl ModuleType { } => { module.types.push(FuncSignature { params: params.to_vec(), - returns: returns.to_vec(), + results: returns.to_vec(), }); } _ => Err(Error::Unsupported("type section entry".to_string()))?, diff --git a/lucet-validate/src/types.rs b/lucet-validate/src/types.rs new file mode 100644 index 000000000..a4c05d10e --- /dev/null +++ b/lucet-validate/src/types.rs @@ -0,0 +1,14 @@ +pub use wasmparser::Type as AtomType; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct FuncSignature { + pub params: Vec, + pub results: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ImportFunc { + pub module: String, + pub field: String, + pub ty: FuncSignature, +} diff --git a/lucet-validate/src/witx_moduletype.rs b/lucet-validate/src/witx_moduletype.rs new file mode 100644 index 000000000..113962c3c --- /dev/null +++ b/lucet-validate/src/witx_moduletype.rs @@ -0,0 +1,71 @@ +#![allow(unused)] // WIP + +use crate::{AtomType, FuncSignature}; +use witx::{ + BuiltinType, Datatype, DatatypeIdent, DatatypeVariant, Document, IntRepr, InterfaceFunc, +}; + +pub trait HasFuncSignature { + fn func_signature(&self) -> FuncSignature; +} + +impl HasFuncSignature for InterfaceFunc { + fn func_signature(&self) -> FuncSignature { + let params = self + .params + .iter() + .flat_map(|p| p.type_.module_types()) + .collect(); + let results = self + .results + .iter() + .flat_map(|p| p.type_.module_types()) + .collect(); + FuncSignature { params, results } + } +} + +pub trait ModuleTypeParams { + fn module_types(&self) -> Vec; +} + +impl ModuleTypeParams for DatatypeIdent { + fn module_types(&self) -> Vec { + match self { + DatatypeIdent::Builtin(builtin_type) => match builtin_type { + BuiltinType::String | BuiltinType::Data => vec![AtomType::I32, AtomType::I32], + BuiltinType::U8 + | BuiltinType::U16 + | BuiltinType::U32 + | BuiltinType::S8 + | BuiltinType::S16 + | BuiltinType::S32 => vec![AtomType::I32], + BuiltinType::U64 | BuiltinType::S64 => vec![AtomType::I64], + BuiltinType::F32 => vec![AtomType::F32], + BuiltinType::F64 => vec![AtomType::F64], + }, + DatatypeIdent::Array(_) => vec![AtomType::I32, AtomType::I32], + DatatypeIdent::Pointer(_) | DatatypeIdent::ConstPointer(_) => vec![AtomType::I32], + DatatypeIdent::Ident(datatype) => datatype.module_types(), + } + } +} +impl ModuleTypeParams for Datatype { + fn module_types(&self) -> Vec { + match &self.variant { + DatatypeVariant::Alias(a) => a.to.module_types(), + DatatypeVariant::Enum(e) => e.repr.module_types(), + DatatypeVariant::Flags(f) => f.repr.module_types(), + DatatypeVariant::Struct(_) | DatatypeVariant::Union(_) => vec![AtomType::I32], + } + } +} + +impl ModuleTypeParams for IntRepr { + fn module_types(&self) -> Vec { + match self { + IntRepr::I8 | IntRepr::I16 | IntRepr::I32 => vec![AtomType::I32], + IntRepr::I64 => vec![AtomType::I64], + } + } +} From 029e89ec3a5e453b9e0e2a7e9c0e7cce3fe3ca0b Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 24 Sep 2019 12:24:46 -0700 Subject: [PATCH 390/512] lucet-validate: use release of wasmparser 0.39.1 --- Cargo.lock | 8 +------- lucet-validate/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cacff0bb6..324891b37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -945,7 +945,7 @@ dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.43.1", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.39.1 (git+https://github.com/pchickey/wasmparser.rs?branch=pch/correct_section_content_api)", + "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", "witx 0.1.0 (git+https://github.com/webassembly/wasi?branch=pch/witx_better_api)", ] @@ -1946,11 +1946,6 @@ dependencies = [ "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "wasmparser" -version = "0.39.1" -source = "git+https://github.com/pchickey/wasmparser.rs?branch=pch/correct_section_content_api#a4fc03884f52c78e65c898ef22094dfe5e166e6d" - [[package]] name = "wasmparser" version = "0.39.1" @@ -2231,7 +2226,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a6265b25719e82598d104b3717375e37661d41753e2c84cde3f51050c7ed7e3c" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" -"checksum wasmparser 0.39.1 (git+https://github.com/pchickey/wasmparser.rs?branch=pch/correct_section_content_api)" = "" "checksum wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a026c1436af49d5537c7561c7474f81f7a754e36445fe52e6e88795a9747291c" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index 2d6137e9f..8a856f5ec 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -21,4 +21,4 @@ clap = "2" failure = "0.1" witx = { git = "https://github.com/webassembly/wasi", branch = "pch/witx_better_api" } cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.43.1" } -wasmparser = { git = "https://github.com/pchickey/wasmparser.rs", branch = "pch/correct_section_content_api" } +wasmparser = "0.39.1" From d9a91f75938c84d659d9c38d924d4a84475437c3 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 24 Sep 2019 12:49:53 -0700 Subject: [PATCH 391/512] lucet-validate: parse module type of wasi sdk test program --- Cargo.lock | 2 ++ lucet-validate/Cargo.toml | 6 +++++ lucet-validate/tests/wasisdk.rs | 45 +++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 lucet-validate/tests/wasisdk.rs diff --git a/Cargo.lock b/Cargo.lock index 324891b37..ab81a57be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -945,6 +945,8 @@ dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.43.1", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lucet-wasi-sdk 0.1.1", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", "witx 0.1.0 (git+https://github.com/webassembly/wasi?branch=pch/witx_better_api)", ] diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index 8a856f5ec..634d6a0e4 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -22,3 +22,9 @@ failure = "0.1" witx = { git = "https://github.com/webassembly/wasi", branch = "pch/witx_better_api" } cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.43.1" } wasmparser = "0.39.1" + + +[dev-dependencies] +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.1.1" } +tempfile = "3.0" + diff --git a/lucet-validate/tests/wasisdk.rs b/lucet-validate/tests/wasisdk.rs new file mode 100644 index 000000000..602ac3f51 --- /dev/null +++ b/lucet-validate/tests/wasisdk.rs @@ -0,0 +1,45 @@ +#[cfg(test)] +mod wasi_sdk_tests { + use lucet_validate::ModuleType; + use std::path::PathBuf; + + fn wasi_sdk_test_source_file(name: &str) -> PathBuf { + let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + p.push(".."); + p.push("lucet-wasi-sdk"); + p.push("tests"); + p.push(name); + assert!(p.exists(), "test file does not exist"); + p + } + + fn compile_to_wasm(filename: &str) -> Vec { + use lucet_wasi_sdk::{CompileOpts, Link, LinkOpt, LinkOpts}; + use std::fs::File; + use std::io::Read; + use tempfile::TempDir; + + let tmp = TempDir::new().expect("create temporary directory"); + + let mut linker = Link::new(&[wasi_sdk_test_source_file(filename)]); + linker.cflag("-nostartfiles"); + linker.link_opt(LinkOpt::NoDefaultEntryPoint); + + let wasmfile = tmp.path().join("out.wasm"); + + linker.link(wasmfile.clone()).expect("link out.wasm"); + + let mut module_contents = Vec::new(); + let mut file = File::open(wasmfile).expect("open out.wasm"); + file.read_to_end(&mut module_contents) + .expect("read out.wasm"); + + module_contents + } + + #[test] + fn moduletype_of_compiled() { + let main_wasm = compile_to_wasm("main_returns.c"); + let moduletype = ModuleType::parse_wasm(&main_wasm).expect("main_returns has module type"); + } +} From ff6cf4e2bf364d71a4be8af78ec0db8a27a55256 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 24 Sep 2019 20:17:53 -0700 Subject: [PATCH 392/512] lucet-validate: use wasi crate to validate against spec --- Cargo.lock | 16 ++++++-- lucet-validate/Cargo.toml | 3 +- lucet-validate/src/main.rs | 57 +++++++++++++++++++++------ lucet-validate/src/witx_moduletype.rs | 6 +-- lucet-validate/tests/wasisdk.rs | 12 +++++- 5 files changed, 70 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ab81a57be..07b4b88d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -947,8 +947,9 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-wasi-sdk 0.1.1", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.1.0 (git+https://github.com/webassembly/wasi?branch=pch/wasi_crate)", "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", - "witx 0.1.0 (git+https://github.com/webassembly/wasi?branch=pch/witx_better_api)", + "witx 0.1.0 (git+https://github.com/webassembly/wasi?branch=pch/wasi_crate)", ] [[package]] @@ -1932,6 +1933,14 @@ dependencies = [ "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "wasi" +version = "0.1.0" +source = "git+https://github.com/webassembly/wasi?branch=pch/wasi_crate#da8eecd2548db520f215c0d25209163b45320490" +dependencies = [ + "witx 0.1.0 (git+https://github.com/webassembly/wasi?branch=pch/wasi_crate)", +] + [[package]] name = "wasmonkey" version = "0.1.8" @@ -2022,7 +2031,7 @@ dependencies = [ [[package]] name = "witx" version = "0.1.0" -source = "git+https://github.com/webassembly/wasi?branch=pch/witx_better_api#c6620677d8a41e3e4a330e23a042ca244f5f859a" +source = "git+https://github.com/webassembly/wasi?branch=pch/wasi_crate#da8eecd2548db520f215c0d25209163b45320490" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2228,6 +2237,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a6265b25719e82598d104b3717375e37661d41753e2c84cde3f51050c7ed7e3c" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" +"checksum wasi 0.1.0 (git+https://github.com/webassembly/wasi?branch=pch/wasi_crate)" = "" "checksum wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a026c1436af49d5537c7561c7474f81f7a754e36445fe52e6e88795a9747291c" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" @@ -2238,5 +2248,5 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" "checksum winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef84b96d10db72dd980056666d7f1e7663ce93d82fa33b63e71c966f4cf5032" -"checksum witx 0.1.0 (git+https://github.com/webassembly/wasi?branch=pch/witx_better_api)" = "" +"checksum witx 0.1.0 (git+https://github.com/webassembly/wasi?branch=pch/wasi_crate)" = "" "checksum xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da90eac47bf1d7871b75004b9b631d107df15f37669383b23f0b5297bc7516b6" diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index 634d6a0e4..cbf4ee462 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -19,7 +19,8 @@ path = "src/main.rs" [dependencies] clap = "2" failure = "0.1" -witx = { git = "https://github.com/webassembly/wasi", branch = "pch/witx_better_api" } +witx = { git = "https://github.com/webassembly/wasi", branch = "pch/wasi_crate" } +wasi = { git = "https://github.com/webassembly/wasi", branch = "pch/wasi_crate" } cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.43.1" } wasmparser = "0.39.1" diff --git a/lucet-validate/src/main.rs b/lucet-validate/src/main.rs index ea827bfb9..ab9418504 100644 --- a/lucet-validate/src/main.rs +++ b/lucet-validate/src/main.rs @@ -14,8 +14,21 @@ pub fn main() { let _ = include_str!("../Cargo.toml"); let matches = app_from_crate!() - .arg(Arg::with_name("interface").takes_value(true).required(true)) .arg(Arg::with_name("module").takes_value(true).required(true)) + .arg( + Arg::with_name("witx") + .takes_value(true) + .required(false) + .long("witx") + .help("validate against interface in this witx file"), + ) + .arg( + Arg::with_name("wasi") + .takes_value(false) + .required(false) + .long("wasi") + .help("validate against wasi interface"), + ) .arg( Arg::with_name("verbose") .short("v") @@ -24,18 +37,27 @@ pub fn main() { ) .get_matches(); - let interface_path = PathBuf::from( - matches - .value_of("interface") - .expect("interface arg required"), - ); - let input_path = PathBuf::from(matches.value_of("module").expect("module arg required")); + let module_path = matches + .value_of("module") + .map(Path::new) + .expect("module arg required"); - match run(&interface_path, &input_path) { + match run( + &module_path, + matches.value_of("witx"), + matches.is_present("wasi"), + ) { Ok(()) => {} Err(e) => { if matches.is_present("verbose") { - println!("{:?}", e); + match e { + Error::Witx(e) => { + println!("{}", e.report()); + } + _ => { + println!("{:?}", e); + } + } } else { println!("{}", e); } @@ -44,13 +66,20 @@ pub fn main() { } } -fn run(interface: &Path, module: &Path) -> Result<(), Error> { - let interface_doc = witx::load(interface)?; +fn run(module_path: &Path, witx_path: Option<&str>, wasi_spec: bool) -> Result<(), Error> { + let interface_doc = match (witx_path, wasi_spec) { + (Some(witx_path), false) => witx::load(Path::new(witx_path))?, + (None, true) => wasi::unstable::preview0(), + (Some(_), true) => Err(Error::Usage( + "Cannot validate against both witx and wasi spec", + ))?, + (None, false) => Err(Error::Usage("must provide at least one spec"))?, + }; let mut module_contents = Vec::new(); - let mut file = File::open(module).map_err(|e| Error::Io(module.into(), e))?; + let mut file = File::open(module_path).map_err(|e| Error::Io(module_path.into(), e))?; file.read_to_end(&mut module_contents) - .map_err(|e| Error::Io(module.into(), e))?; + .map_err(|e| Error::Io(module_path.into(), e))?; lucet_validate::validate(&interface_doc, &module_contents)?; @@ -59,6 +88,8 @@ fn run(interface: &Path, module: &Path) -> Result<(), Error> { #[derive(Debug, Fail)] enum Error { + #[fail(display = "Usage error: {}", _0)] + Usage(&'static str), #[fail(display = "{}", _0)] Witx(#[cause] witx::WitxError), #[fail(display = "With file {:?}: {}", _0, _1)] diff --git a/lucet-validate/src/witx_moduletype.rs b/lucet-validate/src/witx_moduletype.rs index 113962c3c..1539a03c0 100644 --- a/lucet-validate/src/witx_moduletype.rs +++ b/lucet-validate/src/witx_moduletype.rs @@ -1,9 +1,5 @@ -#![allow(unused)] // WIP - use crate::{AtomType, FuncSignature}; -use witx::{ - BuiltinType, Datatype, DatatypeIdent, DatatypeVariant, Document, IntRepr, InterfaceFunc, -}; +use witx::{BuiltinType, Datatype, DatatypeIdent, DatatypeVariant, IntRepr, InterfaceFunc}; pub trait HasFuncSignature { fn func_signature(&self) -> FuncSignature; diff --git a/lucet-validate/tests/wasisdk.rs b/lucet-validate/tests/wasisdk.rs index 602ac3f51..5cff081c5 100644 --- a/lucet-validate/tests/wasisdk.rs +++ b/lucet-validate/tests/wasisdk.rs @@ -1,7 +1,8 @@ #[cfg(test)] mod wasi_sdk_tests { - use lucet_validate::ModuleType; + use lucet_validate::{self, ModuleType}; use std::path::PathBuf; + use wasi; fn wasi_sdk_test_source_file(name: &str) -> PathBuf { let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR")); @@ -40,6 +41,13 @@ mod wasi_sdk_tests { #[test] fn moduletype_of_compiled() { let main_wasm = compile_to_wasm("main_returns.c"); - let moduletype = ModuleType::parse_wasm(&main_wasm).expect("main_returns has module type"); + let _moduletype = ModuleType::parse_wasm(&main_wasm).expect("main_returns has module type"); + } + + #[test] + fn validate_compiled() { + let main_wasm = compile_to_wasm("main_returns.c"); + let wasi_spec = wasi::unstable::preview0(); + lucet_validate::validate(&wasi_spec, &main_wasm).expect("validates"); } } From 2532f949af601465a322c8f1557235c440ebe595 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 25 Sep 2019 13:26:00 -0700 Subject: [PATCH 393/512] lucet-validate: cranelift 0.44.0 --- Cargo.lock | 2 +- lucet-validate/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 07b4b88d0..67265581b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -943,7 +943,7 @@ name = "lucet-validate" version = "0.1.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-entity 0.43.1", + "cranelift-entity 0.44.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-wasi-sdk 0.1.1", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index cbf4ee462..e88feaf89 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -21,7 +21,7 @@ clap = "2" failure = "0.1" witx = { git = "https://github.com/webassembly/wasi", branch = "pch/wasi_crate" } wasi = { git = "https://github.com/webassembly/wasi", branch = "pch/wasi_crate" } -cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.43.1" } +cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.44.0" } wasmparser = "0.39.1" From 8f449832e730b376e455418e9ffc04048a51fc2f Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 25 Sep 2019 14:08:40 -0700 Subject: [PATCH 394/512] lucet-wasi-sdk: correct signature of `main` in test c code --- lucet-wasi-sdk/tests/main_returns.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lucet-wasi-sdk/tests/main_returns.c b/lucet-wasi-sdk/tests/main_returns.c index 0bbc1f069..c63a8dfd2 100644 --- a/lucet-wasi-sdk/tests/main_returns.c +++ b/lucet-wasi-sdk/tests/main_returns.c @@ -1,5 +1,5 @@ -void main(void) +int main(int argc, char *argv[]) { - return; + return 0; } From 0ee27be387d945b9829e2e576344706239db310b Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 25 Sep 2019 14:09:07 -0700 Subject: [PATCH 395/512] lucet-validate: use witx spec from WASI repo as a submodule --- .gitmodules | 3 +++ Cargo.lock | 14 +------------ lucet-validate/Cargo.toml | 3 +-- lucet-validate/src/lib.rs | 31 +++++++++++++++++++++++----- lucet-validate/src/main.rs | 36 +++++++++++++++------------------ lucet-validate/tests/wasisdk.rs | 15 ++++++-------- wasi | 1 + 7 files changed, 54 insertions(+), 49 deletions(-) create mode 160000 wasi diff --git a/.gitmodules b/.gitmodules index bb7be0756..aa307e5b0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "sightglass"] path = sightglass url = https://github.com/fastly/sightglass +[submodule "wasi"] + path = wasi + url = https://github.com/webassembly/wasi diff --git a/Cargo.lock b/Cargo.lock index 67265581b..7b76ee759 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -947,9 +947,8 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-wasi-sdk 0.1.1", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.1.0 (git+https://github.com/webassembly/wasi?branch=pch/wasi_crate)", "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", - "witx 0.1.0 (git+https://github.com/webassembly/wasi?branch=pch/wasi_crate)", + "witx 0.1.0", ] [[package]] @@ -1933,14 +1932,6 @@ dependencies = [ "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "wasi" -version = "0.1.0" -source = "git+https://github.com/webassembly/wasi?branch=pch/wasi_crate#da8eecd2548db520f215c0d25209163b45320490" -dependencies = [ - "witx 0.1.0 (git+https://github.com/webassembly/wasi?branch=pch/wasi_crate)", -] - [[package]] name = "wasmonkey" version = "0.1.8" @@ -2031,7 +2022,6 @@ dependencies = [ [[package]] name = "witx" version = "0.1.0" -source = "git+https://github.com/webassembly/wasi?branch=pch/wasi_crate#da8eecd2548db520f215c0d25209163b45320490" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2237,7 +2227,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a6265b25719e82598d104b3717375e37661d41753e2c84cde3f51050c7ed7e3c" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" -"checksum wasi 0.1.0 (git+https://github.com/webassembly/wasi?branch=pch/wasi_crate)" = "" "checksum wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a026c1436af49d5537c7561c7474f81f7a754e36445fe52e6e88795a9747291c" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" @@ -2248,5 +2237,4 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" "checksum winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef84b96d10db72dd980056666d7f1e7663ce93d82fa33b63e71c966f4cf5032" -"checksum witx 0.1.0 (git+https://github.com/webassembly/wasi?branch=pch/wasi_crate)" = "" "checksum xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da90eac47bf1d7871b75004b9b631d107df15f37669383b23f0b5297bc7516b6" diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index e88feaf89..428ea4910 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -19,8 +19,7 @@ path = "src/main.rs" [dependencies] clap = "2" failure = "0.1" -witx = { git = "https://github.com/webassembly/wasi", branch = "pch/wasi_crate" } -wasi = { git = "https://github.com/webassembly/wasi", branch = "pch/wasi_crate" } +witx = { path = "../wasi/tools/witx", version = "0.1.0" } cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.44.0" } wasmparser = "0.39.1" diff --git a/lucet-validate/src/lib.rs b/lucet-validate/src/lib.rs index eb58eb7eb..69bc20b43 100644 --- a/lucet-validate/src/lib.rs +++ b/lucet-validate/src/lib.rs @@ -15,6 +15,8 @@ pub enum Error { WasmValidation(&'static str, usize), #[fail(display = "Unsupported: {}", _0)] Unsupported(String), + #[fail(display = "Uncategorized error: {}", _0)] + Uncategorized(String), } impl From for Error { @@ -23,7 +25,11 @@ impl From for Error { } } -pub fn validate(interface: &witx::Document, module_contents: &[u8]) -> Result<(), Error> { +pub fn validate( + witx_doc: &witx::Document, + module_contents: &[u8], + wasi_exe: bool, +) -> Result<(), Error> { wasmparser::validate(module_contents, None)?; let moduletype = ModuleType::parse_wasm(module_contents)?; @@ -35,11 +41,26 @@ pub fn validate(interface: &witx::Document, module_contents: &[u8]) -> Result<() ); } - if let Some(startfunc) = moduletype.export("_start") { - println!("wasi start func has type {:?}", startfunc); - } else { - println!("no wasi start func"); + if wasi_exe { + check_wasi_start_func(&moduletype)?; } Ok(()) } + +pub fn check_wasi_start_func(moduletype: &ModuleType) -> Result<(), Error> { + if let Some(startfunc) = moduletype.export("_start") { + if !(startfunc.params.is_empty() && startfunc.results.is_empty()) { + Err(Error::Uncategorized(format!( + "bad type signature on _start: {:?}", + startfunc + ))) + } else { + Ok(()) + } + } else { + Err(Error::Uncategorized( + "missing WASI executable start function (\"_start\")".to_string(), + )) + } +} diff --git a/lucet-validate/src/main.rs b/lucet-validate/src/main.rs index ab9418504..8513d2cdd 100644 --- a/lucet-validate/src/main.rs +++ b/lucet-validate/src/main.rs @@ -14,20 +14,25 @@ pub fn main() { let _ = include_str!("../Cargo.toml"); let matches = app_from_crate!() - .arg(Arg::with_name("module").takes_value(true).required(true)) + .arg( + Arg::with_name("module") + .takes_value(true) + .required(true) + .help("WebAssembly module"), + ) .arg( Arg::with_name("witx") .takes_value(true) - .required(false) - .long("witx") + .required(true) .help("validate against interface in this witx file"), ) .arg( - Arg::with_name("wasi") + Arg::with_name("wasi-exe") .takes_value(false) .required(false) - .long("wasi") - .help("validate against wasi interface"), + .short("w") + .long("wasi-exe") + .help("validate exports of WASI executable"), ) .arg( Arg::with_name("verbose") @@ -44,8 +49,8 @@ pub fn main() { match run( &module_path, - matches.value_of("witx"), - matches.is_present("wasi"), + Path::new(matches.value_of("witx").expect("witx path required")), + matches.is_present("wasi-exe"), ) { Ok(()) => {} Err(e) => { @@ -66,30 +71,21 @@ pub fn main() { } } -fn run(module_path: &Path, witx_path: Option<&str>, wasi_spec: bool) -> Result<(), Error> { - let interface_doc = match (witx_path, wasi_spec) { - (Some(witx_path), false) => witx::load(Path::new(witx_path))?, - (None, true) => wasi::unstable::preview0(), - (Some(_), true) => Err(Error::Usage( - "Cannot validate against both witx and wasi spec", - ))?, - (None, false) => Err(Error::Usage("must provide at least one spec"))?, - }; +fn run(module_path: &Path, witx_path: &Path, wasi_exe: bool) -> Result<(), Error> { + let witx_doc = witx::load(witx_path)?; let mut module_contents = Vec::new(); let mut file = File::open(module_path).map_err(|e| Error::Io(module_path.into(), e))?; file.read_to_end(&mut module_contents) .map_err(|e| Error::Io(module_path.into(), e))?; - lucet_validate::validate(&interface_doc, &module_contents)?; + lucet_validate::validate(&witx_doc, &module_contents, wasi_exe)?; Ok(()) } #[derive(Debug, Fail)] enum Error { - #[fail(display = "Usage error: {}", _0)] - Usage(&'static str), #[fail(display = "{}", _0)] Witx(#[cause] witx::WitxError), #[fail(display = "With file {:?}: {}", _0, _1)] diff --git a/lucet-validate/tests/wasisdk.rs b/lucet-validate/tests/wasisdk.rs index 5cff081c5..c2faf7c62 100644 --- a/lucet-validate/tests/wasisdk.rs +++ b/lucet-validate/tests/wasisdk.rs @@ -2,7 +2,7 @@ mod wasi_sdk_tests { use lucet_validate::{self, ModuleType}; use std::path::PathBuf; - use wasi; + use witx; fn wasi_sdk_test_source_file(name: &str) -> PathBuf { let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR")); @@ -15,19 +15,15 @@ mod wasi_sdk_tests { } fn compile_to_wasm(filename: &str) -> Vec { - use lucet_wasi_sdk::{CompileOpts, Link, LinkOpt, LinkOpts}; + use lucet_wasi_sdk::Link; use std::fs::File; use std::io::Read; use tempfile::TempDir; let tmp = TempDir::new().expect("create temporary directory"); - let mut linker = Link::new(&[wasi_sdk_test_source_file(filename)]); - linker.cflag("-nostartfiles"); - linker.link_opt(LinkOpt::NoDefaultEntryPoint); - let wasmfile = tmp.path().join("out.wasm"); - + let linker = Link::new(&[wasi_sdk_test_source_file(filename)]); linker.link(wasmfile.clone()).expect("link out.wasm"); let mut module_contents = Vec::new(); @@ -47,7 +43,8 @@ mod wasi_sdk_tests { #[test] fn validate_compiled() { let main_wasm = compile_to_wasm("main_returns.c"); - let wasi_spec = wasi::unstable::preview0(); - lucet_validate::validate(&wasi_spec, &main_wasm).expect("validates"); + let wasi_spec = witx::load("../wasi/phases/unstable/witx/wasi_unstable_preview0.witx") + .expect("load wasi_unstable_preview0"); + lucet_validate::validate(&wasi_spec, &main_wasm, true).expect("validation"); } } diff --git a/wasi b/wasi new file mode 160000 index 000000000..4536ea88d --- /dev/null +++ b/wasi @@ -0,0 +1 @@ +Subproject commit 4536ea88dc18e90737829410d766bd620375ca43 From 5f282e35cc9bf1af83c4fd6f749744107e1e83f8 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 25 Sep 2019 17:53:04 -0700 Subject: [PATCH 396/512] lucet-validate: wip... starting to validate sigs against witx --- lucet-validate/src/lib.rs | 46 +++++++++++++++++++------ lucet-validate/src/witx_moduletype.rs | 49 +++++++++++++++++++++------ wasi | 2 +- 3 files changed, 76 insertions(+), 21 deletions(-) diff --git a/lucet-validate/src/lib.rs b/lucet-validate/src/lib.rs index 69bc20b43..1c7633138 100644 --- a/lucet-validate/src/lib.rs +++ b/lucet-validate/src/lib.rs @@ -3,11 +3,13 @@ mod types; mod witx_moduletype; use failure::Fail; +use std::rc::Rc; use wasmparser; -use witx; +use witx::{Document, Id, Module}; pub use self::moduletype::ModuleType; pub use self::types::{AtomType, FuncSignature, ImportFunc}; +pub use self::witx_moduletype::{HasFuncSignature, ModuleTypeParams, SignatureError}; #[derive(Debug, Fail)] pub enum Error { @@ -15,30 +17,46 @@ pub enum Error { WasmValidation(&'static str, usize), #[fail(display = "Unsupported: {}", _0)] Unsupported(String), + #[fail(display = "{}", _0)] + Signature(SignatureError), #[fail(display = "Uncategorized error: {}", _0)] Uncategorized(String), } +impl From for Error { + fn from(e: SignatureError) -> Error { + Error::Signature(e) + } +} impl From for Error { fn from(e: wasmparser::BinaryReaderError) -> Error { Error::WasmValidation(e.message, e.offset) } } -pub fn validate( - witx_doc: &witx::Document, - module_contents: &[u8], - wasi_exe: bool, -) -> Result<(), Error> { +pub fn validate(witx_doc: &Document, module_contents: &[u8], wasi_exe: bool) -> Result<(), Error> { wasmparser::validate(module_contents, None)?; let moduletype = ModuleType::parse_wasm(module_contents)?; for import in moduletype.imports() { - println!( - "import {}::{} has type {:?}", - import.module, import.field, import.ty - ); + let func = witx_module(witx_doc, &import.module)? + .func(&Id::new(&import.field)) + .ok_or_else(|| { + Error::Uncategorized(format!( + "func {}::{} not found", + import.module, import.field + )) + })?; + if func.func_signature()? != import.ty { + Err(Error::Uncategorized(format!( + "type mismatch in {}::{}: module has {:?}, spec has {:?}", + import.module, + import.field, + import.ty, + func.func_signature(), + )))?; + } } if wasi_exe { @@ -48,6 +66,14 @@ pub fn validate( Ok(()) } +pub fn witx_module(doc: &Document, module: &str) -> Result, Error> { + match module { + "wasi_unstable" => doc.module(&Id::new("wasi_unstable_preview0")), + _ => doc.module(&Id::new(module)), + } + .ok_or_else(|| Error::Uncategorized(format!("module {} not found", module))) +} + pub fn check_wasi_start_func(moduletype: &ModuleType) -> Result<(), Error> { if let Some(startfunc) = moduletype.export("_start") { if !(startfunc.params.is_empty() && startfunc.results.is_empty()) { diff --git a/lucet-validate/src/witx_moduletype.rs b/lucet-validate/src/witx_moduletype.rs index 1539a03c0..fab3c7baf 100644 --- a/lucet-validate/src/witx_moduletype.rs +++ b/lucet-validate/src/witx_moduletype.rs @@ -1,23 +1,52 @@ use crate::{AtomType, FuncSignature}; +use failure::Fail; use witx::{BuiltinType, Datatype, DatatypeIdent, DatatypeVariant, IntRepr, InterfaceFunc}; +#[derive(Debug, Fail)] +pub enum SignatureError { + #[fail(display = "invalid result type: {}", _0)] + InvalidResultType(String), +} + pub trait HasFuncSignature { - fn func_signature(&self) -> FuncSignature; + fn func_signature(&self) -> Result; } impl HasFuncSignature for InterfaceFunc { - fn func_signature(&self) -> FuncSignature { - let params = self + fn func_signature(&self) -> Result { + let mut params = self .params .iter() .flat_map(|p| p.type_.module_types()) - .collect(); - let results = self + .collect::>(); + + let first_result = self.results.iter().next().map(|p| { + let mut ts = p.type_.module_types(); + if ts.len() > 1 { + Err(SignatureError::InvalidResultType(format!( + "in {}: result {}: {:?} represented as module types {:?}", + self.name.as_str(), + p.name.as_str(), + p.type_, + ts + ))) + } else { + Ok(ts.pop().unwrap()) + } + }); + let results = if let Some(r) = first_result { + vec![r?.clone()] + } else { + vec![] + }; + + let subsequent_results = self .results .iter() - .flat_map(|p| p.type_.module_types()) - .collect(); - FuncSignature { params, results } + .skip(1) + .flat_map(|p| p.type_.module_types()); + params.extend(subsequent_results); + Ok(FuncSignature { params, results }) } } @@ -60,8 +89,8 @@ impl ModuleTypeParams for Datatype { impl ModuleTypeParams for IntRepr { fn module_types(&self) -> Vec { match self { - IntRepr::I8 | IntRepr::I16 | IntRepr::I32 => vec![AtomType::I32], - IntRepr::I64 => vec![AtomType::I64], + IntRepr::U8 | IntRepr::U16 | IntRepr::U32 => vec![AtomType::I32], + IntRepr::U64 => vec![AtomType::I64], } } } diff --git a/wasi b/wasi index 4536ea88d..bd75cdf69 160000 --- a/wasi +++ b/wasi @@ -1 +1 @@ -Subproject commit 4536ea88dc18e90737829410d766bd620375ca43 +Subproject commit bd75cdf69f943b075ac209959570efc9e2e90de1 From 7f99ccfdcf68e420308d191a96da757e89adc6c4 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 26 Sep 2019 16:32:58 -0700 Subject: [PATCH 397/512] lucet-validate: all lucet-wasi test cases now validate --- Cargo.lock | 5 +- lucet-validate/Cargo.toml | 4 +- lucet-validate/src/lib.rs | 8 +-- lucet-validate/src/witx_moduletype.rs | 75 ++++++++++++-------- lucet-validate/tests/wasitests.rs | 60 ++++++++++++++++ lucet-wasi/tests/guests/duplicate_import.wat | 4 +- wasi | 2 +- 7 files changed, 117 insertions(+), 41 deletions(-) create mode 100644 lucet-validate/tests/wasitests.rs diff --git a/Cargo.lock b/Cargo.lock index 7b76ee759..a87c53862 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -947,8 +947,9 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-wasi-sdk 0.1.1", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", - "witx 0.1.0", + "witx 0.2.0", ] [[package]] @@ -2021,7 +2022,7 @@ dependencies = [ [[package]] name = "witx" -version = "0.1.0" +version = "0.2.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index 428ea4910..4537ba5b8 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -19,7 +19,7 @@ path = "src/main.rs" [dependencies] clap = "2" failure = "0.1" -witx = { path = "../wasi/tools/witx", version = "0.1.0" } +witx = { path = "../wasi/tools/witx", version = "0.2.0" } cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.44.0" } wasmparser = "0.39.1" @@ -27,4 +27,4 @@ wasmparser = "0.39.1" [dev-dependencies] lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.1.1" } tempfile = "3.0" - +wabt = "0.7" diff --git a/lucet-validate/src/lib.rs b/lucet-validate/src/lib.rs index 1c7633138..de7d136cc 100644 --- a/lucet-validate/src/lib.rs +++ b/lucet-validate/src/lib.rs @@ -48,13 +48,11 @@ pub fn validate(witx_doc: &Document, module_contents: &[u8], wasi_exe: bool) -> import.module, import.field )) })?; - if func.func_signature()? != import.ty { + let sig = func.func_signature()?; + if sig != import.ty { Err(Error::Uncategorized(format!( "type mismatch in {}::{}: module has {:?}, spec has {:?}", - import.module, - import.field, - import.ty, - func.func_signature(), + import.module, import.field, import.ty, sig, )))?; } } diff --git a/lucet-validate/src/witx_moduletype.rs b/lucet-validate/src/witx_moduletype.rs index fab3c7baf..3eb4f0c26 100644 --- a/lucet-validate/src/witx_moduletype.rs +++ b/lucet-validate/src/witx_moduletype.rs @@ -17,25 +17,13 @@ impl HasFuncSignature for InterfaceFunc { let mut params = self .params .iter() - .flat_map(|p| p.type_.module_types()) + .flat_map(|p| p.type_.param_by_value_type()) .collect::>(); - let first_result = self.results.iter().next().map(|p| { - let mut ts = p.type_.module_types(); - if ts.len() > 1 { - Err(SignatureError::InvalidResultType(format!( - "in {}: result {}: {:?} represented as module types {:?}", - self.name.as_str(), - p.name.as_str(), - p.type_, - ts - ))) - } else { - Ok(ts.pop().unwrap()) - } - }); - let results = if let Some(r) = first_result { - vec![r?.clone()] + let results = if let Some(first_result) = self.results.iter().next() { + vec![first_result.type_.result_type().ok_or_else(|| { + SignatureError::InvalidResultType(format!("no result type for {:?}", first_result)) + })?] } else { vec![] }; @@ -44,20 +32,29 @@ impl HasFuncSignature for InterfaceFunc { .results .iter() .skip(1) - .flat_map(|p| p.type_.module_types()); + .flat_map(|p| p.type_.param_by_reference_type()); params.extend(subsequent_results); Ok(FuncSignature { params, results }) } } pub trait ModuleTypeParams { - fn module_types(&self) -> Vec; + fn param_by_value_type(&self) -> Vec; + fn param_by_reference_type(&self) -> Vec; + fn result_type(&self) -> Option { + let mut param_types = self.param_by_value_type(); + match param_types.len() { + 1 => Some(param_types.pop().unwrap()), + _ => None, + } + } } impl ModuleTypeParams for DatatypeIdent { - fn module_types(&self) -> Vec { + fn param_by_value_type(&self) -> Vec { + use DatatypeIdent::*; match self { - DatatypeIdent::Builtin(builtin_type) => match builtin_type { + Builtin(builtin_type) => match builtin_type { BuiltinType::String | BuiltinType::Data => vec![AtomType::I32, AtomType::I32], BuiltinType::U8 | BuiltinType::U16 @@ -69,28 +66,48 @@ impl ModuleTypeParams for DatatypeIdent { BuiltinType::F32 => vec![AtomType::F32], BuiltinType::F64 => vec![AtomType::F64], }, - DatatypeIdent::Array(_) => vec![AtomType::I32, AtomType::I32], - DatatypeIdent::Pointer(_) | DatatypeIdent::ConstPointer(_) => vec![AtomType::I32], - DatatypeIdent::Ident(datatype) => datatype.module_types(), + Array(_) => vec![AtomType::I32, AtomType::I32], + Pointer(_) | ConstPointer(_) => vec![AtomType::I32], + Ident(datatype) => datatype.param_by_value_type(), + } + } + fn param_by_reference_type(&self) -> Vec { + use DatatypeIdent::*; + match self { + Builtin(builtin) => match builtin { + BuiltinType::String | BuiltinType::Data => self.param_by_value_type(), + _ => vec![AtomType::I32], + }, + Array(_) | Pointer(_) | ConstPointer(_) => self.param_by_value_type(), + Ident(datatype) => datatype.param_by_reference_type(), } } } impl ModuleTypeParams for Datatype { - fn module_types(&self) -> Vec { + fn param_by_value_type(&self) -> Vec { match &self.variant { - DatatypeVariant::Alias(a) => a.to.module_types(), - DatatypeVariant::Enum(e) => e.repr.module_types(), - DatatypeVariant::Flags(f) => f.repr.module_types(), + DatatypeVariant::Alias(a) => a.to.param_by_value_type(), + DatatypeVariant::Enum(e) => e.repr.param_by_value_type(), + DatatypeVariant::Flags(f) => f.repr.param_by_value_type(), DatatypeVariant::Struct(_) | DatatypeVariant::Union(_) => vec![AtomType::I32], } } + fn param_by_reference_type(&self) -> Vec { + match &self.variant { + DatatypeVariant::Alias(a) => a.to.param_by_reference_type(), + _ => vec![AtomType::I32], + } + } } impl ModuleTypeParams for IntRepr { - fn module_types(&self) -> Vec { + fn param_by_value_type(&self) -> Vec { match self { IntRepr::U8 | IntRepr::U16 | IntRepr::U32 => vec![AtomType::I32], IntRepr::U64 => vec![AtomType::I64], } } + fn param_by_reference_type(&self) -> Vec { + vec![AtomType::I32] + } } diff --git a/lucet-validate/tests/wasitests.rs b/lucet-validate/tests/wasitests.rs new file mode 100644 index 000000000..51a2bddb3 --- /dev/null +++ b/lucet-validate/tests/wasitests.rs @@ -0,0 +1,60 @@ +#[cfg(test)] +mod lucet_wasi_tests { + use lucet_validate; + use std::fs; + use std::path::Path; + use wabt; + use witx; + + fn c_to_wasm(c_path: &Path) -> Vec { + use lucet_wasi_sdk::Link; + use std::fs::File; + use std::io::Read; + use tempfile::TempDir; + + let tmp = TempDir::new().expect("create temporary directory"); + + let wasmfile = tmp.path().join("out.wasm"); + let linker = Link::new(&[c_path]); + linker.link(wasmfile.clone()).expect("link out.wasm"); + + let mut module_contents = Vec::new(); + let mut file = File::open(wasmfile).expect("open out.wasm"); + file.read_to_end(&mut module_contents) + .expect("read out.wasm"); + + module_contents + } + + fn wat_to_wasm(wat_path: &Path) -> Vec { + use std::fs::File; + use std::io::Read; + + let mut wat_contents = Vec::new(); + let mut file = File::open(wat_path).expect("open wat"); + file.read_to_end(&mut wat_contents).expect("read wat"); + wabt::wat2wasm(wat_contents).expect("wat2wasm") + } + + #[test] + fn validate_lucet_wasi_test_guests() { + let wasi_spec = witx::load("../wasi/phases/unstable/witx/wasi_unstable_preview0.witx") + .expect("load wasi_unstable_preview0"); + + for entry in + fs::read_dir("../lucet-wasi/tests/guests").expect("read lucet_wasi test guests dir") + { + let entry_path = entry.expect("file from lucet_wasi test guests dir").path(); + let entry_wasm = match entry_path + .extension() + .map(|s| s.to_str().expect("extension is str")) + { + Some("c") => c_to_wasm(&entry_path), + Some("wat") => wat_to_wasm(&entry_path), + _ => panic!("unsupported extension: {:?}", entry_path), + }; + lucet_validate::validate(&wasi_spec, &entry_wasm, true) + .expect(&format!("validate {:?}", entry_path)); + } + } +} diff --git a/lucet-wasi/tests/guests/duplicate_import.wat b/lucet-wasi/tests/guests/duplicate_import.wat index dc8c43f1d..987286f33 100644 --- a/lucet-wasi/tests/guests/duplicate_import.wat +++ b/lucet-wasi/tests/guests/duplicate_import.wat @@ -1,6 +1,6 @@ (module (type (func (param i32 i32 i32 i32) (result i32))) - (type (func (result i32))) + (type (func)) ;; import fd_read, this is fine. (func $read (import "wasi_unstable" "fd_read") (type 0)) @@ -21,7 +21,7 @@ (data (i32.const 64) "\00\00\00\00\18\00\00\00") (func $_setup (type 1) - (call $write (i32.const 1) (i32.const 64) (i32.const 1) (i32.const 0))) + (drop (call $write (i32.const 1) (i32.const 64) (i32.const 1) (i32.const 0)))) ;; declare that, actually, one of the imported functions is exported (export "read_2" (func $read_2)) diff --git a/wasi b/wasi index bd75cdf69..14d2ac38c 160000 --- a/wasi +++ b/wasi @@ -1 +1 @@ -Subproject commit bd75cdf69f943b075ac209959570efc9e2e90de1 +Subproject commit 14d2ac38c11d98e6e87fbeeb86fcee5e3b8b80d3 From 2320b5bbc23dac778a44a99af04a556e57411c91 Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Thu, 26 Sep 2019 16:35:05 -0700 Subject: [PATCH 398/512] move the stack guard page between the stack and heap where it was protecting against stack underflow into globals, which are extremely unlikely. Far more likely, are stack overflows into the instance's heap, where we accidentally caught those via heap guard space instead. If an instance's `Limits` had the number of heap guard pages as 0, which is permissible, an instance with full utilization would then map a page that had been acting as a stack guard page as read/write and remove the guard-ness of that page. This commit moves a page to be an outside-of-heap dedicated stack guard page. --- .../lucet-runtime-internals/src/alloc/mod.rs | 14 ++++++++++++-- .../src/instance/signals.rs | 2 +- .../lucet-runtime-internals/src/region/mmap.rs | 6 +++--- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs b/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs index 8cd8378f3..165cd0cdb 100644 --- a/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs @@ -113,7 +113,8 @@ impl Drop for Alloc { } impl Alloc { - pub fn addr_in_heap_guard(&self, addr: *const c_void) -> bool { + pub fn addr_in_guard_page(&self, addr: *const c_void) -> bool { + let addr = addr as usize; let heap = self.slot().heap as usize; let guard_start = heap + self.heap_accessible_size; let guard_end = heap + self.slot().limits.heap_address_space_size; @@ -121,7 +122,16 @@ impl Alloc { // "addr = {:p}, guard_start = {:p}, guard_end = {:p}", // addr, guard_start as *mut c_void, guard_end as *mut c_void // ); - (addr as usize >= guard_start) && ((addr as usize) < guard_end) + let stack_guard_end = self.slot().stack as usize; + let stack_guard_start = stack_guard_end - host_page_size(); + // eprintln!( + // "addr = {:p}, stack_guard_start = {:p}, stack_guard_end = {:p}", + // addr, stack_guard_start as *mut c_void, stack_guard_end as *mut c_void + // ); + let in_heap_guard = (addr >= guard_start) && (addr < guard_end); + let in_stack_guard = (addr >= stack_guard_start) && (addr < stack_guard_end); + + in_heap_guard || in_stack_guard } pub fn expand_heap(&mut self, expand_bytes: u32, module: &dyn Module) -> Result { diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs index 72a0fa4fe..6b396b8ff 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs @@ -190,7 +190,7 @@ extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext // If the trap was a segv or bus fault and the addressed memory was outside the // guard pages, it is also a fatal error let outside_guard = (siginfo.si_signo == SIGSEGV || siginfo.si_signo == SIGBUS) - && !inst.alloc.addr_in_heap_guard(siginfo.si_addr_ext()); + && !inst.alloc.addr_in_guard_page(siginfo.si_addr_ext()); // record the fault and jump back to the host context inst.state = State::Faulted { diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs index 2a3cc5e07..d1579eed9 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs @@ -39,10 +39,10 @@ use std::sync::{Arc, Mutex, Weak}; /// 0xXXXX: ~ .......heap....... ~ // heap size is governed by limits.heap_address_space_size /// 0xXXXX: | | /// 0xN000: +-----------------------| <-- Stack (at heap_start + limits.heap_address_space_size) +/// 0xNXXX: --- stack guard page ---- /// 0xNXXX: | | /// 0xXXXX: ~ .......stack...... ~ // stack size is governed by limits.stack_size /// 0xXXXX: | | -/// 0xXXXx: --- stack guard page ---- /// 0xM000: +-----------------------| <-- Globals (at stack_start + limits.stack_size + PAGE_SIZE) /// 0xMXXX: | | /// 0xXXXX: ~ ......globals..... ~ @@ -317,8 +317,8 @@ impl MmapRegion { // lay out the other sections in memory let heap = mem as usize + instance_heap_offset(); - let stack = heap + region.limits.heap_address_space_size; - let globals = stack + region.limits.stack_size + host_page_size(); + let stack = heap + region.limits.heap_address_space_size + host_page_size(); + let globals = stack + region.limits.stack_size; let sigstack = globals + host_page_size(); Ok(Slot { From 18b4c4217e32a1a3b7f65e1f5acac6633f25e813 Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Thu, 26 Sep 2019 14:56:40 -0700 Subject: [PATCH 399/512] adjust signal handler to not always be so stack-hungry Because the Lucet signal handler is run on any arbitrary thread that recives a signal, if the signal handler is installed anywhere in the process, it may be run on a signal stack we didn't set up. This means we are still bound to be careful about how much stack is present, which will often be SIGSTKSZ (observed to be ~8kb on Debian-likes, at least). `handle_signal` is the entrypoint for any signal in the process, so its call frame, locals, etc, are active for any path through the signal handler. For other paths through the signal handler that may involve subsequent calls, and in debug builds of lucet-runtime, the body of the `SignalBehavior::Default` arm would include several `UContext` local variables, as well as a `State` local which itself contains another `UContext`. x86_64 `UContext` are large, resulting in this match arm being responsible for ~5kb of stack usage in `handle_signal`, that is only _actually_ used in this match arm. So, by moving the arm to a closure and immediately calling it, we force Rust to defer that stack usage in debug builds to only be used when the closure is called. In release builds, the closure is likely inlined, but all intermediate copies of UContext _probably_ go away and the entire issue is _probably_ avoided. A subsequent commit will introduce tests around signal handler stack use for these various paths. --- .../src/instance/signals.rs | 65 ++++++++++++------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs index 6b396b8ff..068de1bd1 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs @@ -180,31 +180,48 @@ extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext true } SignalBehavior::Default => { - // safety: pointer is checked for null at the top of the function, and the - // manpage guarantees that a siginfo_t will be passed as the second argument - let siginfo = unsafe { *siginfo_ptr }; - let rip_addr = rip as usize; - // If the trap table lookup returned unknown, it is a fatal error - let unknown_fault = trapcode.is_none(); - - // If the trap was a segv or bus fault and the addressed memory was outside the - // guard pages, it is also a fatal error - let outside_guard = (siginfo.si_signo == SIGSEGV || siginfo.si_signo == SIGBUS) - && !inst.alloc.addr_in_guard_page(siginfo.si_addr_ext()); - - // record the fault and jump back to the host context - inst.state = State::Faulted { - details: FaultDetails { - fatal: unknown_fault || outside_guard, - trapcode: trapcode, - rip_addr, - // Details set to `None` here: have to wait until `verify_trap_safety` to - // fill in these details, because access may not be signal safe. - rip_addr_details: None, - }, - siginfo, - context: ctx.into(), + /* + * /!\ WARNING: LOAD-BEARING THUNK /!\ + * + * This thunk, in debug builds, introduces multiple copies of UContext in the local + * stack frame. This also includes a local `State`, which is quite large as well. + * In total, this thunk accounts for roughly 5kb of stack use, where default signal + * stack sizes are typically 8kb total. + * + * In code paths that do not pass through this (such as immediately reraising as a + * host signal), the code in this thunk would force an exhaustion of more than half + * the stack, significantly increasing the likelihood the Lucet signal handler may + * overflow some other thread with a minimal stack size. + */ + let mut thunk = || { + // safety: pointer is checked for null at the top of the function, and the + // manpage guarantees that a siginfo_t will be passed as the second argument + let siginfo = unsafe { *siginfo_ptr }; + let rip_addr = rip as usize; + // If the trap table lookup returned unknown, it is a fatal error + let unknown_fault = trapcode.is_none(); + + // If the trap was a segv or bus fault and the addressed memory was outside the + // guard pages, it is also a fatal error + let outside_guard = (siginfo.si_signo == SIGSEGV || siginfo.si_signo == SIGBUS) + && !inst.alloc.addr_in_guard_page(siginfo.si_addr_ext()); + + // record the fault and jump back to the host context + inst.state = State::Faulted { + details: FaultDetails { + fatal: unknown_fault || outside_guard, + trapcode: trapcode, + rip_addr, + // Details set to `None` here: have to wait until `verify_trap_safety` to + // fill in these details, because access may not be signal safe. + rip_addr_details: None, + }, + siginfo, + context: ctx.into(), + }; }; + + thunk(); true } } From e8a442edfc91eca059ffb4e2fd832eee490c92d3 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Fri, 27 Sep 2019 15:39:42 -0700 Subject: [PATCH 400/512] switch sigprocmask to pthread_sigmask `pthread_sigmask` is the safe choice for a multithreaded environment. Per `sigprocmask(2)`: > The use of sigprocmask() is unspecified in a multithreaded process; see pthread_sigmask(3). --- benchmarks/lucet-benchmarks/src/context.rs | 10 +++++----- .../lucet-runtime-internals/src/context/mod.rs | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/benchmarks/lucet-benchmarks/src/context.rs b/benchmarks/lucet-benchmarks/src/context.rs index ac14ee5ed..3a4836932 100644 --- a/benchmarks/lucet-benchmarks/src/context.rs +++ b/benchmarks/lucet-benchmarks/src/context.rs @@ -347,14 +347,14 @@ fn context_init_swap_return_many_args(c: &mut Criterion) { }); } -/// Time the call to sigprocmask as used in `Context::init()`. -fn context_sigprocmask(c: &mut Criterion) { +/// Time the call to pthread_sigmask as used in `Context::init()`. +fn context_pthread_sigmask(c: &mut Criterion) { use nix::sys::signal; - c.bench_function("context_sigprocmask", |b| { + c.bench_function("context_pthread_sigmask", |b| { b.iter_batched( || signal::SigSet::empty(), |mut sigset| { - signal::sigprocmask(signal::SigmaskHow::SIG_SETMASK, None, Some(&mut sigset)) + signal::pthread_sigmask(signal::SigmaskHow::SIG_SETMASK, None, Some(&mut sigset)) .unwrap() }, criterion::BatchSize::PerIteration, @@ -367,5 +367,5 @@ pub fn context_benches(c: &mut Criterion) { context_swap_return(c); context_init_swap_return(c); context_init_swap_return_many_args(c); - context_sigprocmask(c); + context_pthread_sigmask(c); } diff --git a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs index 58fba548a..82e0ecc08 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs @@ -443,14 +443,14 @@ impl Context { // the parent and child contexts to `Context::swap` with. child.gpr.rbp = &mut stack[stack.len() - backstop_args] as *mut u64 as u64; - // Read the sigprocmask to be restored if we ever need to jump out of a signal handler. If - // this isn't possible, die. - signal::sigprocmask( + // Read the mask to be restored if we ever need to jump out of a signal handler. If this + // isn't possible, die. + signal::pthread_sigmask( signal::SigmaskHow::SIG_SETMASK, None, Some(&mut child.sigset), ) - .expect("sigprocmask could not be retrieved"); + .expect("pthread_sigmask could not be retrieved"); Ok(()) } @@ -593,7 +593,7 @@ impl Context { /// `!` as a type like that is currently experimental. #[inline] pub unsafe fn set_from_signal(to: &Context) -> Result<(), nix::Error> { - signal::sigprocmask(signal::SigmaskHow::SIG_SETMASK, Some(&to.sigset), None)?; + signal::pthread_sigmask(signal::SigmaskHow::SIG_SETMASK, Some(&to.sigset), None)?; Context::set(to) } From 724bf3231783a659b75037174991630b45f6e799 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Wed, 18 Sep 2019 16:27:02 -0700 Subject: [PATCH 401/512] switch to nightly-2019-09-25, the most recent with all components --- Dockerfile | 4 ++-- helpers/indent.sh | 6 ++++-- lucet-idl/src/parser.rs | 1 - lucetc/src/module.rs | 3 ++- rust-toolchain | 2 +- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index 91f832727..5cf8e6e49 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,11 +28,11 @@ RUN update-alternatives --install /usr/bin/clang clang /usr/bin/clang-6.0 100 ENV LD_LIBRARY_PATH=/usr/local/lib RUN curl https://sh.rustup.rs -sSf | \ - sh -s -- --default-toolchain 1.36.0 -y && \ + sh -s -- --default-toolchain nightly-2019-09-25 -y && \ /root/.cargo/bin/rustup update nightly ENV PATH=/root/.cargo/bin:$PATH -RUN rustup component add rustfmt --toolchain 1.36.0-x86_64-unknown-linux-gnu +RUN rustup component add rustfmt --toolchain nightly-2019-09-25-x86_64-unknown-linux-gnu RUN rustup target add wasm32-wasi RUN cargo install --debug cargo-audit cargo-watch rsign2 diff --git a/helpers/indent.sh b/helpers/indent.sh index 654755184..2c0d8dc80 100755 --- a/helpers/indent.sh +++ b/helpers/indent.sh @@ -10,8 +10,10 @@ cleanup() { } trap cleanup 1 2 3 6 15 -if ! rustfmt --version | grep -q "rustfmt 1.2.2-stable"; then - echo "indent requires rustfmt 1.2.2-stable" +RUSTFMT_VERSION=1.4.8-nightly + +if ! rustfmt --version | grep -q "rustfmt $RUSTFMT_VERSION"; then + echo "indent requires rustfmt $RUSTFMT_VERSION" exit 1 fi diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs index 07d4948b1..e076e5230 100644 --- a/lucet-idl/src/parser.rs +++ b/lucet-idl/src/parser.rs @@ -1198,5 +1198,4 @@ mod tests { } ); } - } diff --git a/lucetc/src/module.rs b/lucetc/src/module.rs index 9a1e995bd..a72ef1b9f 100644 --- a/lucetc/src/module.rs +++ b/lucetc/src/module.rs @@ -369,7 +369,8 @@ impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { self.tables.push(Exportable::new(table)); vac.insert(vec![table_elems]); } else { - panic!("creation of elements for undeclared table! only table 0 is implicitly declared") // Do we implicitly declare them all???? i sure hope not + panic!("creation of elements for undeclared table! only table 0 is implicitly declared") + // Do we implicitly declare them all???? i sure hope not } } } diff --git a/rust-toolchain b/rust-toolchain index 39fc130ef..9e495a9f7 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -1.36.0 +nightly-2019-09-25 From a7dee890ab248a2e732bdb43e96a6d4b14981da0 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 27 Sep 2019 17:24:34 -0700 Subject: [PATCH 402/512] lucet-validate: witx_moduletype is now part of witx crate --- lucet-validate/src/lib.rs | 20 ++--- lucet-validate/src/moduletype.rs | 36 ++++++-- lucet-validate/src/types.rs | 16 +++- lucet-validate/src/witx_moduletype.rs | 113 -------------------------- wasi | 2 +- 5 files changed, 48 insertions(+), 139 deletions(-) delete mode 100644 lucet-validate/src/witx_moduletype.rs diff --git a/lucet-validate/src/lib.rs b/lucet-validate/src/lib.rs index de7d136cc..c6a8b81f6 100644 --- a/lucet-validate/src/lib.rs +++ b/lucet-validate/src/lib.rs @@ -1,6 +1,5 @@ mod moduletype; mod types; -mod witx_moduletype; use failure::Fail; use std::rc::Rc; @@ -8,8 +7,8 @@ use wasmparser; use witx::{Document, Id, Module}; pub use self::moduletype::ModuleType; -pub use self::types::{AtomType, FuncSignature, ImportFunc}; -pub use self::witx_moduletype::{HasFuncSignature, ModuleTypeParams, SignatureError}; +pub use self::types::{FuncSignature, ImportFunc}; +pub use witx::AtomType; #[derive(Debug, Fail)] pub enum Error { @@ -17,17 +16,10 @@ pub enum Error { WasmValidation(&'static str, usize), #[fail(display = "Unsupported: {}", _0)] Unsupported(String), - #[fail(display = "{}", _0)] - Signature(SignatureError), #[fail(display = "Uncategorized error: {}", _0)] Uncategorized(String), } -impl From for Error { - fn from(e: SignatureError) -> Error { - Error::Signature(e) - } -} impl From for Error { fn from(e: wasmparser::BinaryReaderError) -> Error { Error::WasmValidation(e.message, e.offset) @@ -48,11 +40,11 @@ pub fn validate(witx_doc: &Document, module_contents: &[u8], wasi_exe: bool) -> import.module, import.field )) })?; - let sig = func.func_signature()?; - if sig != import.ty { + let spec_type = FuncSignature::from(func.module_type()); + if spec_type != import.ty { Err(Error::Uncategorized(format!( "type mismatch in {}::{}: module has {:?}, spec has {:?}", - import.module, import.field, import.ty, sig, + import.module, import.field, import.ty, spec_type, )))?; } } @@ -74,7 +66,7 @@ pub fn witx_module(doc: &Document, module: &str) -> Result, Error> { pub fn check_wasi_start_func(moduletype: &ModuleType) -> Result<(), Error> { if let Some(startfunc) = moduletype.export("_start") { - if !(startfunc.params.is_empty() && startfunc.results.is_empty()) { + if !(startfunc.args.is_empty() && startfunc.ret.is_none()) { Err(Error::Uncategorized(format!( "bad type signature on _start: {:?}", startfunc diff --git a/lucet-validate/src/moduletype.rs b/lucet-validate/src/moduletype.rs index 162f9710e..e9d216547 100644 --- a/lucet-validate/src/moduletype.rs +++ b/lucet-validate/src/moduletype.rs @@ -1,8 +1,9 @@ -use crate::{Error, FuncSignature, ImportFunc}; +use crate::{AtomType, Error, FuncSignature, ImportFunc}; use cranelift_entity::{entity_impl, PrimaryMap}; use std::collections::HashMap; -pub use wasmparser::Type; -use wasmparser::{ExternalKind, FuncType, ImportSectionEntryType, ModuleReader, SectionContent}; +use wasmparser::{ + ExternalKind, FuncType, ImportSectionEntryType, ModuleReader, SectionContent, Type as WType, +}; #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] struct TypeIndex(u32); @@ -61,14 +62,23 @@ impl ModuleType { for entry in types { match entry? { FuncType { - form: wasmparser::Type::Func, + form: WType::Func, params, returns, } => { - module.types.push(FuncSignature { - params: params.to_vec(), - results: returns.to_vec(), - }); + let ret = match returns.len() { + 0 => None, + 1 => Some(wasmparser_to_atomtype(&returns[0])?), + _ => Err(Error::Unsupported(format!( + "more than 1 return value: {:?}", + returns, + )))?, + }; + let args = params + .iter() + .map(|a| wasmparser_to_atomtype(a)) + .collect::, _>>()?; + module.types.push(FuncSignature { args, ret }); } _ => Err(Error::Unsupported("type section entry".to_string()))?, } @@ -135,3 +145,13 @@ impl ModuleType { Ok(module) } } + +fn wasmparser_to_atomtype(a: &WType) -> Result { + match a { + WType::I32 => Ok(AtomType::I32), + WType::I64 => Ok(AtomType::I64), + WType::F32 => Ok(AtomType::F32), + WType::F64 => Ok(AtomType::F64), + _ => Err(Error::Unsupported(format!("wasmparser type {:?}", a))), + } +} diff --git a/lucet-validate/src/types.rs b/lucet-validate/src/types.rs index a4c05d10e..a3cafc38f 100644 --- a/lucet-validate/src/types.rs +++ b/lucet-validate/src/types.rs @@ -1,9 +1,19 @@ -pub use wasmparser::Type as AtomType; +use crate::AtomType; +use witx::ModuleFuncType; #[derive(Clone, Debug, PartialEq, Eq)] pub struct FuncSignature { - pub params: Vec, - pub results: Vec, + pub args: Vec, + pub ret: Option, +} + +impl From for FuncSignature { + fn from(m: ModuleFuncType) -> FuncSignature { + FuncSignature { + args: m.args.iter().map(|a| a.repr()).collect(), + ret: m.ret.map(|r| r.repr()), + } + } } #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/lucet-validate/src/witx_moduletype.rs b/lucet-validate/src/witx_moduletype.rs deleted file mode 100644 index 3eb4f0c26..000000000 --- a/lucet-validate/src/witx_moduletype.rs +++ /dev/null @@ -1,113 +0,0 @@ -use crate::{AtomType, FuncSignature}; -use failure::Fail; -use witx::{BuiltinType, Datatype, DatatypeIdent, DatatypeVariant, IntRepr, InterfaceFunc}; - -#[derive(Debug, Fail)] -pub enum SignatureError { - #[fail(display = "invalid result type: {}", _0)] - InvalidResultType(String), -} - -pub trait HasFuncSignature { - fn func_signature(&self) -> Result; -} - -impl HasFuncSignature for InterfaceFunc { - fn func_signature(&self) -> Result { - let mut params = self - .params - .iter() - .flat_map(|p| p.type_.param_by_value_type()) - .collect::>(); - - let results = if let Some(first_result) = self.results.iter().next() { - vec![first_result.type_.result_type().ok_or_else(|| { - SignatureError::InvalidResultType(format!("no result type for {:?}", first_result)) - })?] - } else { - vec![] - }; - - let subsequent_results = self - .results - .iter() - .skip(1) - .flat_map(|p| p.type_.param_by_reference_type()); - params.extend(subsequent_results); - Ok(FuncSignature { params, results }) - } -} - -pub trait ModuleTypeParams { - fn param_by_value_type(&self) -> Vec; - fn param_by_reference_type(&self) -> Vec; - fn result_type(&self) -> Option { - let mut param_types = self.param_by_value_type(); - match param_types.len() { - 1 => Some(param_types.pop().unwrap()), - _ => None, - } - } -} - -impl ModuleTypeParams for DatatypeIdent { - fn param_by_value_type(&self) -> Vec { - use DatatypeIdent::*; - match self { - Builtin(builtin_type) => match builtin_type { - BuiltinType::String | BuiltinType::Data => vec![AtomType::I32, AtomType::I32], - BuiltinType::U8 - | BuiltinType::U16 - | BuiltinType::U32 - | BuiltinType::S8 - | BuiltinType::S16 - | BuiltinType::S32 => vec![AtomType::I32], - BuiltinType::U64 | BuiltinType::S64 => vec![AtomType::I64], - BuiltinType::F32 => vec![AtomType::F32], - BuiltinType::F64 => vec![AtomType::F64], - }, - Array(_) => vec![AtomType::I32, AtomType::I32], - Pointer(_) | ConstPointer(_) => vec![AtomType::I32], - Ident(datatype) => datatype.param_by_value_type(), - } - } - fn param_by_reference_type(&self) -> Vec { - use DatatypeIdent::*; - match self { - Builtin(builtin) => match builtin { - BuiltinType::String | BuiltinType::Data => self.param_by_value_type(), - _ => vec![AtomType::I32], - }, - Array(_) | Pointer(_) | ConstPointer(_) => self.param_by_value_type(), - Ident(datatype) => datatype.param_by_reference_type(), - } - } -} -impl ModuleTypeParams for Datatype { - fn param_by_value_type(&self) -> Vec { - match &self.variant { - DatatypeVariant::Alias(a) => a.to.param_by_value_type(), - DatatypeVariant::Enum(e) => e.repr.param_by_value_type(), - DatatypeVariant::Flags(f) => f.repr.param_by_value_type(), - DatatypeVariant::Struct(_) | DatatypeVariant::Union(_) => vec![AtomType::I32], - } - } - fn param_by_reference_type(&self) -> Vec { - match &self.variant { - DatatypeVariant::Alias(a) => a.to.param_by_reference_type(), - _ => vec![AtomType::I32], - } - } -} - -impl ModuleTypeParams for IntRepr { - fn param_by_value_type(&self) -> Vec { - match self { - IntRepr::U8 | IntRepr::U16 | IntRepr::U32 => vec![AtomType::I32], - IntRepr::U64 => vec![AtomType::I64], - } - } - fn param_by_reference_type(&self) -> Vec { - vec![AtomType::I32] - } -} diff --git a/wasi b/wasi index 14d2ac38c..eebac803a 160000 --- a/wasi +++ b/wasi @@ -1 +1 @@ -Subproject commit 14d2ac38c11d98e6e87fbeeb86fcee5e3b8b80d3 +Subproject commit eebac803ad69b8f2d1973b85d99814358ee639a2 From b812e0f4ed0087f878ba0b9952376ff7b58df10a Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 27 Sep 2019 17:32:17 -0700 Subject: [PATCH 403/512] makefile: add lucet-validate to tests --- Makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 9a57bda72..987c13352 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,8 @@ test: indent-check -p lucet-idl \ -p lucet-wasi-sdk \ -p lucet-wasi \ - -p lucet-benchmarks + -p lucet-benchmarks \ + -p lucet-validate # run a single seed through the fuzzer to stave off bitrot cargo run -p lucet-wasi-fuzz -- test-seed 410757864950 helpers/lucet-toolchain-tests/signature.sh @@ -73,4 +74,5 @@ watch: -p lucet-idl \ -p lucet-wasi-sdk \ -p lucet-wasi \ - -p lucet-benchmarks" + -p lucet-benchmarks \ + -p lucet-validate" From 9ca8de9a343b273c0e927ea4b850f5d27cec0237 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 30 Sep 2019 14:36:42 -0700 Subject: [PATCH 404/512] lucet-validate: latest witx branch, where module types renamed core types --- lucet-validate/src/lib.rs | 2 +- lucet-validate/src/types.rs | 6 +++--- wasi | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lucet-validate/src/lib.rs b/lucet-validate/src/lib.rs index c6a8b81f6..1eb706eaa 100644 --- a/lucet-validate/src/lib.rs +++ b/lucet-validate/src/lib.rs @@ -40,7 +40,7 @@ pub fn validate(witx_doc: &Document, module_contents: &[u8], wasi_exe: bool) -> import.module, import.field )) })?; - let spec_type = FuncSignature::from(func.module_type()); + let spec_type = FuncSignature::from(func.core_type()); if spec_type != import.ty { Err(Error::Uncategorized(format!( "type mismatch in {}::{}: module has {:?}, spec has {:?}", diff --git a/lucet-validate/src/types.rs b/lucet-validate/src/types.rs index a3cafc38f..426974e45 100644 --- a/lucet-validate/src/types.rs +++ b/lucet-validate/src/types.rs @@ -1,5 +1,5 @@ use crate::AtomType; -use witx::ModuleFuncType; +use witx::CoreFuncType; #[derive(Clone, Debug, PartialEq, Eq)] pub struct FuncSignature { @@ -7,8 +7,8 @@ pub struct FuncSignature { pub ret: Option, } -impl From for FuncSignature { - fn from(m: ModuleFuncType) -> FuncSignature { +impl From for FuncSignature { + fn from(m: CoreFuncType) -> FuncSignature { FuncSignature { args: m.args.iter().map(|a| a.repr()).collect(), ret: m.ret.map(|r| r.repr()), diff --git a/wasi b/wasi index eebac803a..b0a753c97 160000 --- a/wasi +++ b/wasi @@ -1 +1 @@ -Subproject commit eebac803ad69b8f2d1973b85d99814358ee639a2 +Subproject commit b0a753c97c4e4e15cbfc11e553d899761d895690 From a991bb1c5c2444dfef1d5e7e82e83d5982c2b36c Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 30 Sep 2019 15:48:54 -0700 Subject: [PATCH 405/512] use goblin 0.0.24 everywhere --- Cargo.lock | 28 +++------------------------- lucet-analyze/Cargo.toml | 2 +- lucet-builtins/wasmonkey/Cargo.toml | 2 +- lucetc/Cargo.toml | 2 +- 4 files changed, 6 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7e293a4e8..30e2f0e67 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -631,16 +631,6 @@ name = "glob" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "goblin" -version = "0.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "goblin" version = "0.0.22" @@ -651,16 +641,6 @@ dependencies = [ "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "goblin" -version = "0.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "goblin" version = "0.0.24" @@ -784,7 +764,7 @@ version = "0.1.1" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", ] @@ -1009,7 +989,7 @@ dependencies = [ "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "faerie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", @@ -1925,7 +1905,7 @@ version = "0.1.8" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "goblin 0.0.23 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2082,9 +2062,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" "checksum getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8d1dffef07351aafe6ef177e4dd2b8dcf503e6bc765dea3b0de9ed149a3db1ec" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" -"checksum goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6a4013e9182f2345c6b7829b9ef6e670bce0dfca12c6f974457ed2160c2c7fe9" "checksum goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "7f55d53401eb2fd30afd025c570b1946b6966344acf21b42e31286f3bf89e6a8" -"checksum goblin 0.0.23 (registry+https://github.com/rust-lang/crates.io-index)" = "ac56b4753b6b8c2e052ca30717e5a09acf1b02a2c1681bf3d883bd660e5d22bd" "checksum goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "e3fa261d919c1ae9d1e4533c4a2f99e10938603c4208d56c05bec7a872b661b0" "checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" diff --git a/lucet-analyze/Cargo.toml b/lucet-analyze/Cargo.toml index 41cabaa49..cf0886f07 100644 --- a/lucet-analyze/Cargo.toml +++ b/lucet-analyze/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Lucet team "] edition = "2018" [dependencies] -goblin="0.0.21" +goblin="0.0.24" byteorder="1.2.1" colored="1.6.1" lucet-module = { path = "../lucet-module", version = "0.1.1" } diff --git a/lucet-builtins/wasmonkey/Cargo.toml b/lucet-builtins/wasmonkey/Cargo.toml index c1abb5fa8..1513f9496 100644 --- a/lucet-builtins/wasmonkey/Cargo.toml +++ b/lucet-builtins/wasmonkey/Cargo.toml @@ -12,7 +12,7 @@ edition = "2018" [dependencies] clap = "2.33" failure = "0.1" -goblin = "0.0.23" +goblin = "0.0.24" lazy_static = "1.3" parity-wasm = "0.38" serde = "1.0" diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index b60be4b7b..5d1c51b37 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -32,7 +32,7 @@ clap="2.32" log = "0.4" env_logger = "0.6" faerie = "0.11.0" -goblin = "0.0.22" +goblin = "0.0.24" failure = "0.1" byteorder = "1.2" wasmonkey = { path = "../lucet-builtins/wasmonkey", version = "0.1.7" } From 8b17568aaf4a8ab99f51b7de145a2250c17a3d2c Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 1 Oct 2019 10:26:21 -0700 Subject: [PATCH 406/512] [lucet-idl] parameterize C test with `WASI_SDK` env var --- lucet-idl/tests/example.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lucet-idl/tests/example.rs b/lucet-idl/tests/example.rs index fa62f8c24..cc6167244 100644 --- a/lucet-idl/tests/example.rs +++ b/lucet-idl/tests/example.rs @@ -1,9 +1,19 @@ use lucet_idl; +use std::env; use std::fs::File; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::process::Command; use tempfile::TempDir; +/// Get the base path of the installed WASI SDK. +/// +/// This logic is adapted from `lucet-wasi-sdk` so that we do not incur its additional dependencies. +fn wasi_sdk_clang() -> PathBuf { + PathBuf::from(&env::var("WASI_SDK").unwrap_or("/opt/wasi-sdk".to_owned())) + .join("bin") + .join("clang") +} + #[test] fn compile_c_guest() { let config = lucet_idl::Config { @@ -19,7 +29,7 @@ fn compile_c_guest() { ) .expect("run lucet_idl"); - let cmd_cc = Command::new("/opt/wasi-sdk/bin/clang") + let cmd_cc = Command::new(wasi_sdk_clang()) .arg("--target=wasm32-wasi") .arg("--std=c99") .arg("-Wl,--allow-undefined") From 512996853b7fc0f12eeacab85cd535df65285c85 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 1 Oct 2019 10:57:53 -0700 Subject: [PATCH 407/512] use lucet-validate in lucetc --- Cargo.lock | 4 +++- lucet-validate/Cargo.toml | 2 +- lucet-validate/src/lib.rs | 8 ++++---- lucetc/Cargo.toml | 2 ++ lucetc/src/compiler.rs | 31 +++++++++++++++++++------------ lucetc/src/lib.rs | 18 ++++++++++++++++++ lucetc/src/main.rs | 10 ++++++++++ lucetc/src/options.rs | 16 ++++++++++++++++ 8 files changed, 73 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a87c53862..477421d81 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -940,7 +940,7 @@ dependencies = [ [[package]] name = "lucet-validate" -version = "0.1.0" +version = "0.1.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.44.0", @@ -1027,6 +1027,7 @@ dependencies = [ "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", + "lucet-validate 0.1.1", "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1035,6 +1036,7 @@ dependencies = [ "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "wasmonkey 0.1.8", "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", + "witx 0.2.0", ] [[package]] diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index 4537ba5b8..589b7ca61 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-validate" -version = "0.1.0" +version = "0.1.1" description = "Parse and validate webassembly files against witx interface" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" diff --git a/lucet-validate/src/lib.rs b/lucet-validate/src/lib.rs index 1eb706eaa..32c1b127b 100644 --- a/lucet-validate/src/lib.rs +++ b/lucet-validate/src/lib.rs @@ -4,11 +4,11 @@ mod types; use failure::Fail; use std::rc::Rc; use wasmparser; -use witx::{Document, Id, Module}; +use witx::{Id, Module}; pub use self::moduletype::ModuleType; pub use self::types::{FuncSignature, ImportFunc}; -pub use witx::AtomType; +pub use witx::{AtomType, Document}; #[derive(Debug, Fail)] pub enum Error { @@ -56,7 +56,7 @@ pub fn validate(witx_doc: &Document, module_contents: &[u8], wasi_exe: bool) -> Ok(()) } -pub fn witx_module(doc: &Document, module: &str) -> Result, Error> { +fn witx_module(doc: &Document, module: &str) -> Result, Error> { match module { "wasi_unstable" => doc.module(&Id::new("wasi_unstable_preview0")), _ => doc.module(&Id::new(module)), @@ -64,7 +64,7 @@ pub fn witx_module(doc: &Document, module: &str) -> Result, Error> { .ok_or_else(|| Error::Uncategorized(format!("module {} not found", module))) } -pub fn check_wasi_start_func(moduletype: &ModuleType) -> Result<(), Error> { +fn check_wasi_start_func(moduletype: &ModuleType) -> Result<(), Error> { if let Some(startfunc) = moduletype.export("_start") { if !(startfunc.args.is_empty() && startfunc.ret.is_none()) { Err(Error::Uncategorized(format!( diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index b60be4b7b..d0ccb7844 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -27,6 +27,8 @@ cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.44.0" cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.44.0" } target-lexicon = "0.8.0" lucet-module = { path = "../lucet-module", version = "0.1.1" } +lucet-validate = { path = "../lucet-validate", version = "0.1.1" } +witx = { path = "../wasi/tools/witx", version = "0.2.0" } wasmparser = "0.39.1" clap="2.32" log = "0.4" diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index c6c3e228d..dc5f159bd 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -20,6 +20,7 @@ use cranelift_wasm::{translate_module, FuncTranslator, WasmError}; use failure::{format_err, Fail, ResultExt}; use lucet_module::bindings::Bindings; use lucet_module::{FunctionSpec, ModuleData, MODULE_DATA_SYM}; +use lucet_validate::{self, Document}; #[derive(Debug, Clone, Copy)] pub enum OptLevel { @@ -58,24 +59,30 @@ impl<'a> Compiler<'a> { bindings: &'a Bindings, heap_settings: HeapSettings, count_instructions: bool, + spec: &Option, ) -> Result { let isa = Self::target_isa(opt_level); let frontend_config = isa.frontend_config(); let mut module_info = ModuleInfo::new(frontend_config.clone()); - // As of cranelift-wasm 0.43 which uses wasmparser 0.40, the parser used inside - // cranelift-wasm does not validate. We need to run the validating parser on the binary - // first. The InvalidWebAssembly error below will never trigger. - wasmparser::validate(wasm_binary, None) - .map_err(|e| { - format_err!( - "invalid WebAssembly module, at offset {}: {}", - e.offset, - e.message - ) - }) - .context(LucetcErrorKind::Validation)?; + if let Some(spec) = spec { + lucet_validate::validate(spec, wasm_binary, true) + .context(LucetcErrorKind::Validation)?; + } else { + // As of cranelift-wasm 0.43 which uses wasmparser 0.40, the parser used inside + // cranelift-wasm does not validate. We need to run the validating parser on the binary + // first. The InvalidWebAssembly error below will never trigger. + wasmparser::validate(wasm_binary, None) + .map_err(|e| { + format_err!( + "invalid WebAssembly module, at offset {}: {}", + e.offset, + e.message + ) + }) + .context(LucetcErrorKind::Validation)?; + } translate_module(wasm_binary, &mut module_info).map_err(|e| match e { WasmError::User(_) => e.context(LucetcErrorKind::Input), diff --git a/lucetc/src/lib.rs b/lucetc/src/lib.rs index 10b48b871..7f880acd4 100644 --- a/lucetc/src/lib.rs +++ b/lucetc/src/lib.rs @@ -31,6 +31,7 @@ pub use crate::{ }; use failure::{format_err, Error, ResultExt}; pub use lucet_module::bindings::Bindings; +pub use lucet_validate::Document; use signature::{PublicKey, SecretKey}; use std::env; use std::path::{Path, PathBuf}; @@ -47,6 +48,7 @@ pub struct Lucetc { opt_level: OptLevel, heap: HeapSettings, builtins_paths: Vec, + witx_spec: Option, sk: Option, pk: Option, sign: bool, @@ -74,6 +76,9 @@ pub trait LucetcOpts { fn builtins>(&mut self, builtins_path: P); fn with_builtins>(self, builtins_path: P) -> Self; + fn witx_spec(&mut self, witx_spec: Document); + fn with_witx_spec(self, witx_spec: Document) -> Self; + fn min_reserved_size(&mut self, min_reserved_size: u64); fn with_min_reserved_size(self, min_reserved_size: u64) -> Self; @@ -134,6 +139,15 @@ impl LucetcOpts for T { self } + fn witx_spec(&mut self, witx_spec: Document) { + self.as_lucetc().witx_spec = Some(witx_spec); + } + + fn with_witx_spec(mut self, witx_spec: Document) -> Self { + self.witx_spec(witx_spec); + self + } + fn min_reserved_size(&mut self, min_reserved_size: u64) { self.as_lucetc().heap.min_reserved_size = min_reserved_size; } @@ -226,6 +240,7 @@ impl Lucetc { opt_level: OptLevel::default(), heap: HeapSettings::default(), builtins_paths: vec![], + witx_spec: None, pk: None, sk: None, sign: false, @@ -242,6 +257,7 @@ impl Lucetc { opt_level: OptLevel::default(), heap: HeapSettings::default(), builtins_paths: vec![], + witx_spec: None, pk: None, sk: None, sign: false, @@ -287,6 +303,7 @@ impl Lucetc { &bindings, self.heap.clone(), self.count_instructions, + &self.witx_spec, )?; let obj = compiler.object_file()?; @@ -303,6 +320,7 @@ impl Lucetc { &bindings, self.heap.clone(), self.count_instructions, + &self.witx_spec, )?; compiler diff --git a/lucetc/src/main.rs b/lucetc/src/main.rs index d1b89cbd1..5ae1505dc 100644 --- a/lucetc/src/main.rs +++ b/lucetc/src/main.rs @@ -11,6 +11,7 @@ use lucetc::{ use std::io::{self, Write}; use std::path::PathBuf; use std::process; +use witx; fn main() { env_logger::init(); @@ -54,6 +55,15 @@ pub fn run(opts: &Options) -> Result<(), Error> { .with_bindings(bindings) .with_opt_level(opts.opt_level); + match opts.witx_specs.len() { + 0 => {} + 1 => { + let spec = witx::load(&opts.witx_specs[0])?; + c.witx_spec(spec); + } + _ => Err(format_err!("multiple witx specs not yet supported"))?, + } + if let Some(ref builtins) = opts.builtins_path { c.builtins(builtins); } diff --git a/lucetc/src/options.rs b/lucetc/src/options.rs index f8d6ee099..af604b760 100644 --- a/lucetc/src/options.rs +++ b/lucetc/src/options.rs @@ -35,6 +35,7 @@ pub struct Options { pub input: Vec, pub codegen: CodegenOutput, pub binding_files: Vec, + pub witx_specs: Vec, pub builtins_path: Option, pub min_reserved_size: Option, pub max_reserved_size: Option, @@ -65,6 +66,12 @@ impl Options { .map(PathBuf::from) .collect(); + let witx_specs: Vec = m + .values_of("witx") + .unwrap_or_default() + .map(PathBuf::from) + .collect(); + let codegen = match m.value_of("emit") { None => CodegenOutput::SharedObj, Some("clif") => CodegenOutput::Clif, @@ -119,6 +126,7 @@ impl Options { input, codegen, binding_files, + witx_specs, builtins_path, min_reserved_size, max_reserved_size, @@ -164,6 +172,14 @@ impl Options { .number_of_values(1) .help("path to bindings json file"), ) + .arg( + Arg::with_name("witx") + .long("--witx") + .takes_value(true) + .multiple(true) + .number_of_values(1) + .help("path to witx spec to validate against"), + ) .arg( Arg::with_name("min_reserved_size") .long("--min-reserved-size") From bbc19a655500eacbce32e5f27b13b37dd4799c52 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 1 Oct 2019 16:29:54 -0700 Subject: [PATCH 408/512] lucetc: use lucet-validate Validator --- lucet-validate/src/lib.rs | 161 ++++++++++++++++++++--------- lucet-validate/src/main.rs | 7 +- lucetc/src/compiler.rs | 8 +- lucetc/src/lib.rs | 24 ++--- lucetc/src/main.rs | 6 +- lucetc/src/options.rs | 14 ++- lucetc/tests/wasm.rs | 180 ++++++++++++++++++++++++++++----- lucetc/tests/wasm/wasi_exe.wat | 12 +++ 8 files changed, 317 insertions(+), 95 deletions(-) create mode 100644 lucetc/tests/wasm/wasi_exe.wat diff --git a/lucet-validate/src/lib.rs b/lucet-validate/src/lib.rs index 32c1b127b..bb226fd4f 100644 --- a/lucet-validate/src/lib.rs +++ b/lucet-validate/src/lib.rs @@ -2,13 +2,14 @@ mod moduletype; mod types; use failure::Fail; +use std::path::Path; use std::rc::Rc; use wasmparser; -use witx::{Id, Module}; +use witx::{self, Id, Module}; pub use self::moduletype::ModuleType; pub use self::types::{FuncSignature, ImportFunc}; -pub use witx::{AtomType, Document}; +pub use witx::{AtomType, Document, WitxError}; #[derive(Debug, Fail)] pub enum Error { @@ -16,8 +17,31 @@ pub enum Error { WasmValidation(&'static str, usize), #[fail(display = "Unsupported: {}", _0)] Unsupported(String), - #[fail(display = "Uncategorized error: {}", _0)] - Uncategorized(String), + #[fail(display = "Module not found: {}", _0)] + ModuleNotFound(String), + #[fail(display = "Import not found: {}::{}", module, field)] + ImportNotFound { module: String, field: String }, + #[fail(display = "Export not found: {}", field)] + ExportNotFound { field: String }, + #[fail( + display = "Import type error: for {}::{}, expected {:?}, got {:?}", + module, field, expected, got + )] + ImportTypeError { + module: String, + field: String, + expected: FuncSignature, + got: FuncSignature, + }, + #[fail( + display = "Export type error: for {}, expected {:?}, got {:?}", + field, expected, got + )] + ExportTypeError { + field: String, + expected: FuncSignature, + got: FuncSignature, + }, } impl From for Error { @@ -26,57 +50,100 @@ impl From for Error { } } -pub fn validate(witx_doc: &Document, module_contents: &[u8], wasi_exe: bool) -> Result<(), Error> { - wasmparser::validate(module_contents, None)?; - - let moduletype = ModuleType::parse_wasm(module_contents)?; - - for import in moduletype.imports() { - let func = witx_module(witx_doc, &import.module)? - .func(&Id::new(&import.field)) - .ok_or_else(|| { - Error::Uncategorized(format!( - "func {}::{} not found", - import.module, import.field - )) - })?; - let spec_type = FuncSignature::from(func.core_type()); - if spec_type != import.ty { - Err(Error::Uncategorized(format!( - "type mismatch in {}::{}: module has {:?}, spec has {:?}", - import.module, import.field, import.ty, spec_type, - )))?; - } +pub struct Validator { + witx: Document, + wasi_exe: bool, +} + +impl Validator { + pub fn new(witx: Document, wasi_exe: bool) -> Self { + Self { witx, wasi_exe } } - if wasi_exe { - check_wasi_start_func(&moduletype)?; + pub fn parse(source: &str) -> Result { + let witx = witx::parse(source)?; + Ok(Self { + witx, + wasi_exe: false, + }) } - Ok(()) -} + pub fn load(source_path: &Path) -> Result { + let witx = witx::load(source_path)?; + Ok(Self { + witx, + wasi_exe: false, + }) + } -fn witx_module(doc: &Document, module: &str) -> Result, Error> { - match module { - "wasi_unstable" => doc.module(&Id::new("wasi_unstable_preview0")), - _ => doc.module(&Id::new(module)), + pub fn wasi_exe(&mut self, check: bool) { + self.wasi_exe = check; + } + + pub fn with_wasi_exe(mut self, check: bool) -> Self { + self.wasi_exe(check); + self + } + + pub fn validate(&self, module_contents: &[u8]) -> Result<(), Error> { + wasmparser::validate(module_contents, None)?; + + let moduletype = ModuleType::parse_wasm(module_contents)?; + + for import in moduletype.imports() { + let func = self + .witx_module(&import.module)? + .func(&Id::new(&import.field)) + .ok_or_else(|| Error::ImportNotFound { + module: import.module.clone(), + field: import.field.clone(), + })?; + let spec_type = FuncSignature::from(func.core_type()); + if spec_type != import.ty { + Err(Error::ImportTypeError { + module: import.module, + field: import.field, + got: import.ty, + expected: spec_type, + })?; + } + } + + if self.wasi_exe { + self.check_wasi_start_func(&moduletype)?; + } + + Ok(()) + } + + fn witx_module(&self, module: &str) -> Result, Error> { + match module { + "wasi_unstable" => self.witx.module(&Id::new("wasi_unstable_preview0")), + _ => self.witx.module(&Id::new(module)), + } + .ok_or_else(|| Error::ModuleNotFound(module.to_string())) } - .ok_or_else(|| Error::Uncategorized(format!("module {} not found", module))) -} -fn check_wasi_start_func(moduletype: &ModuleType) -> Result<(), Error> { - if let Some(startfunc) = moduletype.export("_start") { - if !(startfunc.args.is_empty() && startfunc.ret.is_none()) { - Err(Error::Uncategorized(format!( - "bad type signature on _start: {:?}", - startfunc - ))) + fn check_wasi_start_func(&self, moduletype: &ModuleType) -> Result<(), Error> { + let start_name = "_start"; + let expected = FuncSignature { + args: vec![], + ret: None, + }; + if let Some(startfunc) = moduletype.export(start_name) { + if startfunc != &expected { + Err(Error::ExportTypeError { + field: start_name.to_string(), + expected, + got: startfunc.clone(), + }) + } else { + Ok(()) + } } else { - Ok(()) + Err(Error::ExportNotFound { + field: start_name.to_string(), + }) } - } else { - Err(Error::Uncategorized( - "missing WASI executable start function (\"_start\")".to_string(), - )) } } diff --git a/lucet-validate/src/main.rs b/lucet-validate/src/main.rs index 8513d2cdd..6dadb3dce 100644 --- a/lucet-validate/src/main.rs +++ b/lucet-validate/src/main.rs @@ -2,7 +2,7 @@ extern crate clap; use clap::Arg; use failure::Fail; -use lucet_validate; +use lucet_validate::{self, Validator}; use std::fs::File; use std::io::{self, Read}; use std::path::{Path, PathBuf}; @@ -72,14 +72,13 @@ pub fn main() { } fn run(module_path: &Path, witx_path: &Path, wasi_exe: bool) -> Result<(), Error> { - let witx_doc = witx::load(witx_path)?; - let mut module_contents = Vec::new(); let mut file = File::open(module_path).map_err(|e| Error::Io(module_path.into(), e))?; file.read_to_end(&mut module_contents) .map_err(|e| Error::Io(module_path.into(), e))?; - lucet_validate::validate(&witx_doc, &module_contents, wasi_exe)?; + let validator = Validator::load(witx_path)?.with_wasi_exe(wasi_exe); + validator.validate(&module_contents)?; Ok(()) } diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index dc5f159bd..fe4155f34 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -20,7 +20,7 @@ use cranelift_wasm::{translate_module, FuncTranslator, WasmError}; use failure::{format_err, Fail, ResultExt}; use lucet_module::bindings::Bindings; use lucet_module::{FunctionSpec, ModuleData, MODULE_DATA_SYM}; -use lucet_validate::{self, Document}; +use lucet_validate::Validator; #[derive(Debug, Clone, Copy)] pub enum OptLevel { @@ -59,15 +59,15 @@ impl<'a> Compiler<'a> { bindings: &'a Bindings, heap_settings: HeapSettings, count_instructions: bool, - spec: &Option, + validator: &Option, ) -> Result { let isa = Self::target_isa(opt_level); let frontend_config = isa.frontend_config(); let mut module_info = ModuleInfo::new(frontend_config.clone()); - if let Some(spec) = spec { - lucet_validate::validate(spec, wasm_binary, true) + if let Some(v) = validator { + v.validate(wasm_binary) .context(LucetcErrorKind::Validation)?; } else { // As of cranelift-wasm 0.43 which uses wasmparser 0.40, the parser used inside diff --git a/lucetc/src/lib.rs b/lucetc/src/lib.rs index 7f880acd4..c3170c3f8 100644 --- a/lucetc/src/lib.rs +++ b/lucetc/src/lib.rs @@ -31,7 +31,7 @@ pub use crate::{ }; use failure::{format_err, Error, ResultExt}; pub use lucet_module::bindings::Bindings; -pub use lucet_validate::Document; +pub use lucet_validate::Validator; use signature::{PublicKey, SecretKey}; use std::env; use std::path::{Path, PathBuf}; @@ -48,7 +48,7 @@ pub struct Lucetc { opt_level: OptLevel, heap: HeapSettings, builtins_paths: Vec, - witx_spec: Option, + validator: Option, sk: Option, pk: Option, sign: bool, @@ -76,8 +76,8 @@ pub trait LucetcOpts { fn builtins>(&mut self, builtins_path: P); fn with_builtins>(self, builtins_path: P) -> Self; - fn witx_spec(&mut self, witx_spec: Document); - fn with_witx_spec(self, witx_spec: Document) -> Self; + fn validator(&mut self, validator: Validator); + fn with_validator(self, validator: Validator) -> Self; fn min_reserved_size(&mut self, min_reserved_size: u64); fn with_min_reserved_size(self, min_reserved_size: u64) -> Self; @@ -139,12 +139,12 @@ impl LucetcOpts for T { self } - fn witx_spec(&mut self, witx_spec: Document) { - self.as_lucetc().witx_spec = Some(witx_spec); + fn validator(&mut self, validator: Validator) { + self.as_lucetc().validator = Some(validator); } - fn with_witx_spec(mut self, witx_spec: Document) -> Self { - self.witx_spec(witx_spec); + fn with_validator(mut self, validator: Validator) -> Self { + self.validator(validator); self } @@ -240,7 +240,7 @@ impl Lucetc { opt_level: OptLevel::default(), heap: HeapSettings::default(), builtins_paths: vec![], - witx_spec: None, + validator: None, pk: None, sk: None, sign: false, @@ -257,7 +257,7 @@ impl Lucetc { opt_level: OptLevel::default(), heap: HeapSettings::default(), builtins_paths: vec![], - witx_spec: None, + validator: None, pk: None, sk: None, sign: false, @@ -303,7 +303,7 @@ impl Lucetc { &bindings, self.heap.clone(), self.count_instructions, - &self.witx_spec, + &self.validator, )?; let obj = compiler.object_file()?; @@ -320,7 +320,7 @@ impl Lucetc { &bindings, self.heap.clone(), self.count_instructions, - &self.witx_spec, + &self.validator, )?; compiler diff --git a/lucetc/src/main.rs b/lucetc/src/main.rs index 5ae1505dc..29e763974 100644 --- a/lucetc/src/main.rs +++ b/lucetc/src/main.rs @@ -4,6 +4,7 @@ use crate::options::{CodegenOutput, Options}; use failure::{format_err, Error, ResultExt}; use log::info; use lucet_module::bindings::Bindings; +use lucet_validate::Validator; use lucetc::{ signature::{self, PublicKey}, Lucetc, LucetcOpts, @@ -11,7 +12,6 @@ use lucetc::{ use std::io::{self, Write}; use std::path::PathBuf; use std::process; -use witx; fn main() { env_logger::init(); @@ -58,8 +58,8 @@ pub fn run(opts: &Options) -> Result<(), Error> { match opts.witx_specs.len() { 0 => {} 1 => { - let spec = witx::load(&opts.witx_specs[0])?; - c.witx_spec(spec); + let validator = Validator::load(&opts.witx_specs[0])?.with_wasi_exe(opts.wasi_exe); + c.validator(validator); } _ => Err(format_err!("multiple witx specs not yet supported"))?, } diff --git a/lucetc/src/options.rs b/lucetc/src/options.rs index af604b760..b8114bced 100644 --- a/lucetc/src/options.rs +++ b/lucetc/src/options.rs @@ -36,6 +36,7 @@ pub struct Options { pub codegen: CodegenOutput, pub binding_files: Vec, pub witx_specs: Vec, + pub wasi_exe: bool, pub builtins_path: Option, pub min_reserved_size: Option, pub max_reserved_size: Option, @@ -67,10 +68,11 @@ impl Options { .collect(); let witx_specs: Vec = m - .values_of("witx") + .values_of("witx_specs") .unwrap_or_default() .map(PathBuf::from) .collect(); + let wasi_exe = m.is_present("wasi_exe"); let codegen = match m.value_of("emit") { None => CodegenOutput::SharedObj, @@ -127,6 +129,7 @@ impl Options { codegen, binding_files, witx_specs, + wasi_exe, builtins_path, min_reserved_size, max_reserved_size, @@ -173,13 +176,20 @@ impl Options { .help("path to bindings json file"), ) .arg( - Arg::with_name("witx") + Arg::with_name("witx_specs") .long("--witx") .takes_value(true) .multiple(true) .number_of_values(1) .help("path to witx spec to validate against"), ) + .arg( + Arg::with_name("wasi_exe") + .long("--wasi_exe") + .takes_value(false) + .multiple(false) + .help("validate as a wasi executable"), + ) .arg( Arg::with_name("min_reserved_size") .long("--min-reserved-size") diff --git a/lucetc/tests/wasm.rs b/lucetc/tests/wasm.rs index 5c8254176..bf17429e4 100644 --- a/lucetc/tests/wasm.rs +++ b/lucetc/tests/wasm.rs @@ -2,7 +2,7 @@ use lucet_module::bindings::Bindings; use std::collections::HashMap; use std::path::PathBuf; -fn load_wat_module(name: &str) -> Vec { +pub fn load_wat_module(name: &str) -> Vec { use std::fs::File; use std::io::Read; use wabt::wat2wasm; @@ -13,7 +13,7 @@ fn load_wat_module(name: &str) -> Vec { wat2wasm(contents).expect("convert module to wasm binary format") } -fn test_bindings() -> Bindings { +pub fn test_bindings() -> Bindings { let imports: HashMap = [ ("icalltarget".into(), "icalltarget".into()), // icall_import ("inc".into(), "inc".into()), // import @@ -42,7 +42,7 @@ mod module_data { let m = load_wat_module("exported_import"); let b = super::test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false) + let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None) .expect("compiling exported_import"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.globals_spec().len(), 0); @@ -62,7 +62,7 @@ mod module_data { let m = load_wat_module("multiple_import"); let b = super::test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false) + let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None) .expect("compiling multiple_import"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.globals_spec().len(), 0); @@ -78,8 +78,8 @@ mod module_data { let m = load_wat_module("globals_export"); let b = super::test_bindings(); let h = HeapSettings::default(); - let c = - Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compiling globals_export"); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None) + .expect("compiling globals_export"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.globals_spec().len(), 1); @@ -95,7 +95,8 @@ mod module_data { let m = load_wat_module("fibonacci"); let b = super::test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compiling fibonacci"); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None) + .expect("compiling fibonacci"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.globals_spec().len(), 0); @@ -109,7 +110,8 @@ mod module_data { let m = load_wat_module("arith"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compiling arith"); + let c = + Compiler::new(&m, OptLevel::default(), &b, h, false, &None).expect("compiling arith"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.globals_spec().len(), 0); @@ -126,7 +128,7 @@ mod module_data { )) .unwrap(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false) + let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None) .expect("compile duplicate_imports"); let mdata = c.module_data().unwrap(); @@ -153,7 +155,7 @@ mod module_data { )) .unwrap(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compile icall"); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None).expect("compile icall"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 1); @@ -189,7 +191,7 @@ mod module_data { let m = load_wat_module("icall"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compile icall"); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None).expect("compile icall"); let _module_data = c.module_data().unwrap(); /* TODO can't express these with module data @@ -214,7 +216,8 @@ mod module_data { let m = load_wat_module("icall_sparse"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compile icall_sparse"); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None) + .expect("compile icall_sparse"); let _module_data = c.module_data().unwrap(); /* TODO can't express these with module data @@ -253,8 +256,8 @@ mod module_data { let b = Bindings::empty(); let h = HeapSettings::default(); - let c = - Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compile globals_import"); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None) + .expect("compile globals_import"); let module_data = c.module_data().unwrap(); let gspec = module_data.globals_spec(); @@ -275,7 +278,7 @@ mod module_data { let m = load_wat_module("heap_spec_import"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h.clone(), false) + let c = Compiler::new(&m, OptLevel::default(), &b, h.clone(), false, &None) .expect("compiling heap_spec_import"); assert_eq!( @@ -298,7 +301,7 @@ mod module_data { let m = load_wat_module("heap_spec_definition"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h.clone(), false) + let c = Compiler::new(&m, OptLevel::default(), &b, h.clone(), false, &None) .expect("compiling heap_spec_definition"); assert_eq!( @@ -320,8 +323,8 @@ mod module_data { let m = load_wat_module("heap_spec_none"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = - Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compiling heap_spec_none"); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None) + .expect("compiling heap_spec_none"); assert_eq!(c.module_data().unwrap().heap_spec(), None,); } @@ -330,7 +333,7 @@ mod module_data { let m = load_wat_module("oversize_data_segment"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None); assert!( c.is_err(), "compilation error because data initializers are oversized" @@ -353,7 +356,7 @@ mod module_data { let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None); assert!( c.is_err(), "compilation error because wasm module is invalid" @@ -366,8 +369,8 @@ mod module_data { let m = load_wat_module("start_section"); let b = Bindings::empty(); let h = HeapSettings::default(); - let _c = - Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compile start_section"); + let _c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None) + .expect("compile start_section"); /* assert!( p.module().start_section().is_some(), @@ -385,7 +388,7 @@ mod compile { let m = load_wat_module(file); let b = super::test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false) + let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None) .expect(&format!("compile {}", file)); let _obj = c.object_file().expect(&format!("codegen {}", file)); } @@ -418,3 +421,134 @@ mod compile { compile_test!(unreachable_code); compile_test!(start_section); } + +mod validate { + + use super::load_wat_module; + use lucet_validate::Validator; + use lucetc::{Compiler, HeapSettings, OptLevel}; + + #[test] + fn validate_arith() { + let m = load_wat_module("arith"); + let b = super::test_bindings(); + let h = HeapSettings::default(); + + // Empty witx: arith module has no imports + let v = Validator::parse("") + .expect("empty witx validates") + .with_wasi_exe(false); + + let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile"); + let _obj = c.object_file().expect("codegen"); + } + + #[test] + fn validate_import() { + let m = load_wat_module("import"); + let b = super::test_bindings(); + let h = HeapSettings::default(); + + let witx = " + (module $env + (@interface func (export \"inc\") + (result $r s32)))"; + let v = Validator::parse(witx) + .expect("witx validates") + .with_wasi_exe(false); + + let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile"); + let _obj = c.object_file().expect("codegen"); + } + + #[test] + fn validate_icall_import() { + let m = load_wat_module("icall_import"); + let b = super::test_bindings(); + let h = HeapSettings::default(); + + let witx = " + (module $env + (@interface func (export \"icalltarget\") + (param $a1 u32) + (param $a2 u32) + (result $r s32)))"; + let v = Validator::parse(witx) + .expect("witx validates") + .with_wasi_exe(false); + + let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile"); + let _obj = c.object_file().expect("codegen"); + } + + #[test] + fn validate_exported_import() { + let m = load_wat_module("exported_import"); + let b = super::test_bindings(); + let h = HeapSettings::default(); + + let witx = " + (module $env + (@interface func (export \"imported_main\")) + (@interface func (export \"inc\")))"; + let v = Validator::parse(witx) + .expect("witx validates") + .with_wasi_exe(false); + + let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile"); + let _obj = c.object_file().expect("codegen"); + } + + #[test] + fn validate_multiple_import() { + let m = load_wat_module("multiple_import"); + let b = super::test_bindings(); + let h = HeapSettings::default(); + + let witx = " + (module $env + (@interface func (export \"imported_main\")) + (@interface func (export \"inc\")))"; + let v = Validator::parse(witx) + .expect("witx validates") + .with_wasi_exe(false); + + let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile"); + let _obj = c.object_file().expect("codegen"); + } + + #[test] + fn validate_import_many() { + let m = load_wat_module("import_many"); + let b = super::test_bindings(); + let h = HeapSettings::default(); + + let witx = " + (module $env + (@interface func (export \"imp_0\") (result $r u32)) + (@interface func (export \"imp_1\") (result $r u32)) + (@interface func (export \"imp_2\") (result $r u32)) + (@interface func (export \"imp_3\") (result $r u32)))"; + let v = Validator::parse(witx) + .expect("witx validates") + .with_wasi_exe(false); + + let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile"); + let _obj = c.object_file().expect("codegen"); + } + + #[test] + fn validate_wasi_exe() { + let m = load_wat_module("wasi_exe"); + let b = super::test_bindings(); + let h = HeapSettings::default(); + + let witx = ""; + let v = Validator::parse(witx) + .expect("witx validates") + .with_wasi_exe(true); + + let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile"); + let _obj = c.object_file().expect("codegen"); + } +} diff --git a/lucetc/tests/wasm/wasi_exe.wat b/lucetc/tests/wasm/wasi_exe.wat new file mode 100644 index 000000000..0410646da --- /dev/null +++ b/lucetc/tests/wasm/wasi_exe.wat @@ -0,0 +1,12 @@ +(module + (memory 1) + (func $start (export "_start") (local i32) + (set_local 0 (i32.sub (i32.const 4) (i32.const 4))) + (if + (get_local 0) + (then unreachable) + (else (i32.store (i32.const 0) (i32.mul (i32.const 6) (get_local 0)))) + ) + ) + (data (i32.const 0) "abcdefgh") +) From d4804f7923b929f4102a45c41f9f42ab161e1003 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 1 Oct 2019 17:36:32 -0700 Subject: [PATCH 409/512] changes to lucetc threaded throughout repo and lucet-wasi-sdk validates that imports work according to witx! --- Cargo.lock | 1 + lucet-spectest/src/script.rs | 1 + lucet-validate/src/lib.rs | 4 +-- lucet-wasi-sdk/Cargo.toml | 3 ++ lucet-wasi-sdk/tests/hello.c | 8 +++++ lucet-wasi-sdk/tests/lucetc.rs | 54 ++++++++++++++++++++++++++--- lucet-wasi-sdk/tests/main_returns.c | 5 --- 7 files changed, 65 insertions(+), 11 deletions(-) create mode 100644 lucet-wasi-sdk/tests/hello.c delete mode 100644 lucet-wasi-sdk/tests/main_returns.c diff --git a/Cargo.lock b/Cargo.lock index 477421d81..2544d8db1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1001,6 +1001,7 @@ version = "0.1.1" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.1.1", + "lucet-validate 0.1.1", "lucetc 0.1.1", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/lucet-spectest/src/script.rs b/lucet-spectest/src/script.rs index 555065b0c..70fe4bfae 100644 --- a/lucet-spectest/src/script.rs +++ b/lucet-spectest/src/script.rs @@ -73,6 +73,7 @@ impl ScriptEnv { &bindings, HeapSettings::default(), true, + &None, ) .map_err(program_error)?; diff --git a/lucet-validate/src/lib.rs b/lucet-validate/src/lib.rs index bb226fd4f..e1471f35f 100644 --- a/lucet-validate/src/lib.rs +++ b/lucet-validate/src/lib.rs @@ -68,8 +68,8 @@ impl Validator { }) } - pub fn load(source_path: &Path) -> Result { - let witx = witx::load(source_path)?; + pub fn load>(source_path: P) -> Result { + let witx = witx::load(source_path.as_ref())?; Ok(Self { witx, wasi_exe: false, diff --git a/lucet-wasi-sdk/Cargo.toml b/lucet-wasi-sdk/Cargo.toml index 870cf437b..bee820b2d 100644 --- a/lucet-wasi-sdk/Cargo.toml +++ b/lucet-wasi-sdk/Cargo.toml @@ -14,3 +14,6 @@ failure = "0.1" lucetc = { path = "../lucetc", version = "0.1.1" } lucet-module = { path = "../lucet-module", version = "0.1.1" } tempfile = "3.0" + +[dev-dependencies] +lucet-validate = { path = "../lucet-validate", version = "0.1.1" } diff --git a/lucet-wasi-sdk/tests/hello.c b/lucet-wasi-sdk/tests/hello.c new file mode 100644 index 000000000..02f86c083 --- /dev/null +++ b/lucet-wasi-sdk/tests/hello.c @@ -0,0 +1,8 @@ + +#include + +int main(int argc, char *argv[]) +{ + printf("hello, world! i am %s\n", argv[0]); + return 0; +} diff --git a/lucet-wasi-sdk/tests/lucetc.rs b/lucet-wasi-sdk/tests/lucetc.rs index c7e270449..6df32e49e 100644 --- a/lucet-wasi-sdk/tests/lucetc.rs +++ b/lucet-wasi-sdk/tests/lucetc.rs @@ -2,6 +2,7 @@ mod lucetc_tests { use failure::Error; use lucet_module::bindings::Bindings; + use lucet_validate::Validator; use lucet_wasi_sdk::*; use lucetc::{Compiler, HeapSettings, OptLevel}; use std::collections::HashMap; @@ -39,7 +40,9 @@ mod lucetc_tests { let m = module_from_c(&["empty"], &[]).expect("build module for empty"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compile empty"); + let v = Validator::parse("").expect("empty validation environment"); + let c = + Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile empty"); let mdata = c.module_data().unwrap(); assert!(mdata.heap_spec().is_some()); // clang creates 3 globals: @@ -74,7 +77,9 @@ mod lucetc_tests { let m = module_from_c(&["c"], &["c"]).expect("build module for c"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compile c"); + let v = Validator::parse("").expect("empty validation environment"); + + let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile c"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 0, "import functions"); assert_eq!(mdata.export_functions().len(), 1, "export functions"); @@ -91,7 +96,11 @@ mod lucetc_tests { let m = module_from_c(&["d"], &["d"]).expect("build module for d"); let b = d_only_test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compile d"); + let v = Validator::parse( + "(module $env (@interface func (export \"c\") (param $a1 s32) (result $r1 s32)))", + ) + .expect("empty validation environment"); + let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile d"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 1, "import functions"); assert_eq!(mdata.export_functions().len(), 1, "export functions"); @@ -107,7 +116,9 @@ mod lucetc_tests { let m = module_from_c(&["c", "d"], &["c", "d"]).expect("build module for c & d"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false).expect("compile c & d"); + let v = Validator::parse("").expect("empty validation environment"); + let c = + Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile c & d"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 0, "import functions"); assert_eq!(mdata.export_functions().len(), 2, "export functions"); @@ -117,4 +128,39 @@ mod lucetc_tests { */ let _obj = c.object_file().expect("generate code from c & d"); } + + #[test] + fn hello() { + let m = { + // This is like module_from_c, except missing the bits that have it leave out the wasi + // stdlib and tentry points: + let tempdir = tempfile::Builder::new() + .prefix("wasi-sdk-test") + .tempdir() + .expect("create tempdir"); + let mut wasm = PathBuf::from(tempdir.path()); + wasm.push("out.wasm"); + + let linker = Link::new(&[PathBuf::from("tests/hello.c")]); + linker.link(wasm.clone()).expect("link"); + + let mut wasm_file = File::open(wasm).expect("open wasm"); + let mut wasm_contents = Vec::new(); + wasm_file + .read_to_end(&mut wasm_contents) + .expect("read wasm"); + wasm_contents + }; + + let b = + Bindings::from_file("../lucet-wasi/bindings.json").expect("load lucet-wasi bindings"); + let h = HeapSettings::default(); + let v = Validator::load("../wasi/phases/unstable/witx/wasi_unstable_preview0.witx") + .expect("wasi spec validation") + .with_wasi_exe(true); + let c = + Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile empty"); + let mdata = c.module_data().unwrap(); + assert!(mdata.heap_spec().is_some()); + } } diff --git a/lucet-wasi-sdk/tests/main_returns.c b/lucet-wasi-sdk/tests/main_returns.c deleted file mode 100644 index c63a8dfd2..000000000 --- a/lucet-wasi-sdk/tests/main_returns.c +++ /dev/null @@ -1,5 +0,0 @@ - -int main(int argc, char *argv[]) -{ - return 0; -} From d8dbd8598de92b4ee7499305d497637bca7c00b8 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 2 Oct 2019 12:23:12 -0700 Subject: [PATCH 410/512] delete witx-frontend: subsumed by wasi repo --- lucet-idl/tests/typenames.witx | 719 ------------------------ lucet-idl/tests/wasi_unstable.witx | 516 ----------------- lucet-idl/witx-frontend/Cargo.toml | 21 - lucet-idl/witx-frontend/src/ast.rs | 161 ------ lucet-idl/witx-frontend/src/lexer.rs | 354 ------------ lucet-idl/witx-frontend/src/lib.rs | 54 -- lucet-idl/witx-frontend/src/main.rs | 38 -- lucet-idl/witx-frontend/src/parser.rs | 558 ------------------ lucet-idl/witx-frontend/src/sexpr.rs | 225 -------- lucet-idl/witx-frontend/src/toplevel.rs | 244 -------- lucet-idl/witx-frontend/src/validate.rs | 362 ------------ 11 files changed, 3252 deletions(-) delete mode 100644 lucet-idl/tests/typenames.witx delete mode 100644 lucet-idl/tests/wasi_unstable.witx delete mode 100644 lucet-idl/witx-frontend/Cargo.toml delete mode 100644 lucet-idl/witx-frontend/src/ast.rs delete mode 100644 lucet-idl/witx-frontend/src/lexer.rs delete mode 100644 lucet-idl/witx-frontend/src/lib.rs delete mode 100644 lucet-idl/witx-frontend/src/main.rs delete mode 100644 lucet-idl/witx-frontend/src/parser.rs delete mode 100644 lucet-idl/witx-frontend/src/sexpr.rs delete mode 100644 lucet-idl/witx-frontend/src/toplevel.rs delete mode 100644 lucet-idl/witx-frontend/src/validate.rs diff --git a/lucet-idl/tests/typenames.witx b/lucet-idl/tests/typenames.witx deleted file mode 100644 index e322b66a6..000000000 --- a/lucet-idl/tests/typenames.witx +++ /dev/null @@ -1,719 +0,0 @@ -;; Type names used by the wasi_unstable module type. -;; -;; Some content here is derived from [CloudABI](https://github.com/NuxiNL/cloudabi). - -(typename $size_t u32) -(typename $uintptr_t u32) -(typename $string_array (array string)) - -;; Non-negative file size or length of a region within a file. -(typename $filesize_t u64) - -;; Timestamp in nanoseconds. -(typename $timestamp_t u64) - -;; Identifiers for clocks. -(typename $clockid_t - (enum u32 - ;; The store-wide monotonic clock, which is defined as a clock measuring - ;; real time, whose value cannot be adjusted and which cannot have negative - ;; clock jumps. The epoch of this clock is undefined. The absolute time - ;; value of this clock therefore has no meaning. - $CLOCK_MONOTONIC - ;; The CPU-time clock associated with the current process. - $CLOCK_PROCESS_CPUTIME_ID - ;; The clock measuring real time. Time value zero corresponds with - ;; 1970-01-01T00:00:00Z. - $CLOCK_REALTIME - ;; The CPU-time clock associated with the current thread. - $CLOCK_THREAD_CPUTIME_ID - ) -) - -;; Error codes returned by functions. -;; Not all of these error codes are returned by the functions provided by this -;; API; some are used in higher-level library layers, and others are provided -;; merely for alignment with POSIX. -(typename $errno_t - (enum u16 - ;; No error occurred. System call completed successfully. - $ESUCCESS - ;; Argument list too long. - $E2BIG - ;; Permission denied. - $EACCES - ;; Address in use. - $EADDRINUSE - ;; Address not available. - $EADDRNOTAVAIL - ;; Address family not supported. - $EAFNOSUPPORT - ;; Resource unavailable, or operation would block. - $EAGAIN - ;; Connection already in progress. - $EALREADY - ;; Bad file descriptor. - $EBADF - ;; Bad message. - $EBADMSG - ;; Device or resource busy. - $EBUSY - ;; Operation canceled. - $ECANCELED - ;; No child processes. - $ECHILD - ;; Connection aborted. - $ECONNABORTED - ;; Connection refused. - $ECONNREFUSED - ;; Connection reset. - $ECONNRESET - ;; Resource deadlock would occur. - $EDEADLK - ;; Destination address required. - $EDESTADDRREQ - ;; Mathematics argument out of domain of function. - $EDOM - ;; Reserved. - $EDQUOT - ;; File exists. - $EEXIST - ;; Bad address. - $EFAULT - ;; File too large. - $EFBIG - ;; Host is unreachable. - $EHOSTUNREACH - ;; Identifier removed. - $EIDRM - ;; Illegal byte sequence. - $EILSEQ - ;; Operation in progress. - $EINPROGRESS - ;; Interrupted function. - $EINTR - ;; Invalid argument. - $EINVAL - ;; I/O error. - $EIO - ;; Socket is connected. - $EISCONN - ;; Is a directory. - $EISDIR - ;; Too many levels of symbolic links. - $ELOOP - ;; File descriptor value too large. - $EMFILE - ;; Too many links. - $EMLINK - ;; Message too large. - $EMSGSIZE - ;; Reserved. - $EMULTIHOP - ;; Filename too long. - $ENAMETOOLONG - ;; Network is down. - $ENETDOWN - ;; Connection aborted by network. - $ENETRESET - ;; Network unreachable. - $ENETUNREACH - ;; Too many files open in system. - $ENFILE - ;; No buffer space available. - $ENOBUFS - ;; No such device. - $ENODEV - ;; No such file or directory. - $ENOENT - ;; Executable file format error. - $ENOEXEC - ;; No locks available. - $ENOLCK - ;; Reserved. - $ENOLINK - ;; Not enough space. - $ENOMEM - ;; No message of the desired type. - $ENOMSG - ;; Protocol not available. - $ENOPROTOOPT - ;; No space left on device. - $ENOSPC - ;; Function not supported. - $ENOSYS - ;; The socket is not connected. - $ENOTCONN - ;; Not a directory or a symbolic link to a directory. - $ENOTDIR - ;; Directory not empty. - $ENOTEMPTY - ;; State not recoverable. - $ENOTRECOVERABLE - ;; Not a socket. - $ENOTSOCK - ;; Not supported, or operation not supported on socket. - $ENOTSUP - ;; Inappropriate I/O control operation. - $ENOTTY - ;; No such device or address. - $ENXIO - ;; Value too large to be stored in data type. - $EOVERFLOW - ;; Previous owner died. - $EOWNERDEAD - ;; Operation not permitted. - $EPERM - ;; Broken pipe. - $EPIPE - ;; Protocol error. - $EPROTO - ;; Protocol not supported. - $EPROTONOSUPPORT - ;; Protocol wrong type for socket. - $EPROTOTYPE - ;; Result too large. - $ERANGE - ;; Read-only file system. - $EROFS - ;; Invalid seek. - $ESPIPE - ;; No such process. - $ESRCH - ;; Reserved. - $ESTALE - ;; Connection timed out. - $ETIMEDOUT - ;; Text file busy. - $ETXTBSY - ;; Cross-device link. - $EXDEV - ;; Extension: Capabilities insufficient. - $ENOTCAPABLE - ) -) - -;; File descriptor rights, determining which actions may be performed. -(typename $rights_t - (flags u64 - ;; The right to invoke `__wasi_fd_datasync()`. - ;; - ;; If `__WASI_RIGHT_PATH_OPEN` is set, includes the right to invoke - ;; `__wasi_path_open()` with `__WASI_FDFLAG_DSYNC`. - (flag $RIGHT_FD_DATASYNC) - ;; The right to invoke `__wasi_fd_read()` and `__wasi_sock_recv()`. - ;; - ;; If `__WASI_RIGHT_FD_SEEK` is set, includes the right to invoke - ;; `__wasi_fd_pread()`. - (flag $RIGHT_FD_READ) - ;; The right to invoke `__wasi_fd_seek()`. This flag implies `__WASI_RIGHT_FD_TELL`. - (flag $RIGHT_FD_SEEK) - ;; The right to invoke `__wasi_fd_fdstat_set_flags()`. - (flag $RIGHT_FD_FDSTAT_SET_FLAGS) - ;; The right to invoke `__wasi_fd_sync()`. - ;; - ;; If `__WASI_RIGHT_PATH_OPEN` is set, includes the right to invoke - ;; `__wasi_path_open()` with `__WASI_FDFLAG_RSYNC` and `__WASI_FDFLAG_DSYNC`. - (flag $RIGHT_FD_SYNC) - ;; The right to invoke `__wasi_fd_seek()` in such a way that the file offset - ;; remains unaltered (i.e., `__WASI_WHENCE_CUR` with offset zero), or to - ;; invoke `__wasi_fd_tell()`. - (flag $RIGHT_FD_TELL) - ;; The right to invoke `__wasi_fd_write()` and `__wasi_sock_send()`. - ;; If `__WASI_RIGHT_FD_SEEK` is set, includes the right to invoke `__wasi_fd_pwrite()`. - (flag $RIGHT_FD_WRITE) - ;; The right to invoke `__wasi_fd_advise()`. - (flag $RIGHT_FD_ADVISE) - ;; The right to invoke `__wasi_fd_allocate()`. - (flag $RIGHT_FD_ALLOCATE) - ;; The right to invoke `__wasi_path_create_directory()`. - (flag $RIGHT_PATH_CREATE_DIRECTORY) - ;; If `__WASI_RIGHT_PATH_OPEN` is set, the right to invoke `__wasi_path_open()` with `__WASI_O_CREAT`. - (flag $RIGHT_PATH_CREATE_FILE) - ;; The right to invoke `__wasi_path_link()` with the file descriptor as the - ;; source directory. - (flag $RIGHT_PATH_LINK_SOURCE) - ;; The right to invoke `__wasi_path_link()` with the file descriptor as the - ;; target directory. - (flag $RIGHT_PATH_LINK_TARGET) - ;; The right to invoke `__wasi_path_open()`. - (flag $RIGHT_PATH_OPEN) - ;; The right to invoke `__wasi_fd_readdir()`. - (flag $RIGHT_FD_READDIR) - ;; The right to invoke `__wasi_path_readlink()`. - (flag $RIGHT_PATH_READLINK) - ;; The right to invoke `__wasi_path_rename()` with the file descriptor as the source directory. - (flag $RIGHT_PATH_RENAME_SOURCE) - ;; The right to invoke `__wasi_path_rename()` with the file descriptor as the target directory. - (flag $RIGHT_PATH_RENAME_TARGET) - ;; The right to invoke `__wasi_path_filestat_get()`. - (flag $RIGHT_PATH_FILESTAT_GET) - ;; The right to change a file's size (there is no `__wasi_path_filestat_set_size()`). - ;; If `__WASI_RIGHT_PATH_OPEN` is set, includes the right to invoke `__wasi_path_open()` with `__WASI_O_TRUNC`. - (flag $RIGHT_PATH_FILESTAT_SET_SIZE) - ;; The right to invoke `__wasi_path_filestat_set_times()`. - (flag $RIGHT_PATH_FILESTAT_SET_TIMES) - ;; The right to invoke `__wasi_fd_filestat_get()`. - (flag $RIGHT_FD_FILESTAT_GET) - ;; The right to invoke `__wasi_fd_filestat_set_size()`. - (flag $RIGHT_FD_FILESTAT_SET_SIZE) - ;; The right to invoke `__wasi_fd_filestat_set_times()`. - (flag $RIGHT_FD_FILESTAT_SET_TIMES) - ;; The right to invoke `__wasi_path_symlink()`. - (flag $RIGHT_PATH_SYMLINK) - ;; The right to invoke `__wasi_path_unlink_file()`. - (flag $RIGHT_PATH_UNLINK_FILE) - ;; The right to invoke `__wasi_path_remove_directory()`. - (flag $RIGHT_PATH_REMOVE_DIRECTORY) - ;; If `__WASI_RIGHT_FD_READ` is set, includes the right to invoke `__wasi_poll_oneoff()` to subscribe to `__WASI_EVENTTYPE_FD_READ`. - ;; If `__WASI_RIGHT_FD_WRITE` is set, includes the right to invoke `__wasi_poll_oneoff()` to subscribe to `__WASI_EVENTTYPE_FD_WRITE`. - (flag $RIGHT_POLL_FD_READWRITE) - ;; The right to invoke `__wasi_sock_shutdown()`. - (flag $RIGHT_SOCK_SHUTDOWN) - ) -) - -;; A file descriptor index. -(typename $fd_t u32) - -;; A region of memory for scatter/gather reads. -(typename $iovec_t - (struct - ;; The address and length of the buffer to be filled. - (field $buf $uintptr_t) - (field $buf_len $size_t) - ) -) - -;; A region of memory for scatter/gather writes. -(typename $ciovec_t - (struct - ;; The address and length of the buffer to be written. - (field $buf $uintptr_t) - (field $buf_len $size_t) - ) -) - -(typename $iovec_t_array (array $iovec_t)) -(typename $ciovec_t_array (array $ciovec_t)) - -;; Relative offset within a file. -(typename $filedelta_t s64) - -;; The position relative to which to set the offset of the file descriptor. -(typename $whence_t - (enum u8 - ;; Seek relative to current position. - $WHENCE_CUR - ;; Seek relative to end-of-file. - $WHENCE_END - ;; Seek relative to start-of-file. - $WHENCE_SET - ) -) - -;; A reference to the offset of a directory entry. -(typename $dircookie_t u64) - -;; The type for the $d_namelen field of $dirent_t. -(typename $dirnamelen_t u32) - -;; File serial number that is unique within its file system. -(typename $inode_t u64) - -;; The type of a file descriptor or file. -(typename $filetype_t - (enum u8 - ;; The type of the file descriptor or file is unknown or is different from any of the other types specified. - $FILETYPE_UNKNOWN - ;; The file descriptor or file refers to a block device inode. - $FILETYPE_BLOCK_DEVICE - ;; The file descriptor or file refers to a character device inode. - $FILETYPE_CHARACTER_DEVICE - ;; The file descriptor or file refers to a directory inode. - $FILETYPE_DIRECTORY - ;; The file descriptor or file refers to a regular file inode. - $FILETYPE_REGULAR_FILE - ;; The file descriptor or file refers to a datagram socket. - $FILETYPE_SOCKET_DGRAM - ;; The file descriptor or file refers to a byte-stream socket. - $FILETYPE_SOCKET_STREAM - ;; The file refers to a symbolic link inode. - $FILETYPE_SYMBOLIC_LINK - ) -) - -;; A directory entry. -(typename $dirent_t - (struct - ;; The offset of the next directory entry stored in this directory. - (field $d_next $dircookie_t) - ;; The serial number of the file referred to by this directory entry. - (field $d_ino $inode_t) - ;; The length of the name of the directory entry. - (field $d_namlen $dirnamelen_t) - ;; The type of the file referred to by this directory entry. - (field $d_type $filetype_t) - ) -) - -;; File or memory access pattern advisory information. -(typename $advice_t - (enum u8 - ;; The application expects that it will not access the specified data in the near future. - $ADVICE_DONTNEED - ;; The application expects to access the specified data once and then not reuse it thereafter. - $ADVICE_NOREUSE - ;; The application has no advice to give on its behavior with respect to the specified data. - $ADVICE_NORMAL - ;; The application expects to access the specified data in a random order. - $ADVICE_RANDOM - ;; The application expects to access the specified data sequentially from lower offsets to higher offsets. - $ADVICE_SEQUENTIAL - ;; The application expects to access the specified data in the near future. - $ADVICE_WILLNEED - ) -) - -;; File descriptor flags. -(typename $fdflags_t - (flags u16 - ;; Append mode: Data written to the file is always appended to the file's end. - (flag $FDFLAG_APPEND) - ;; Write according to synchronized I/O data integrity completion. Only the data stored in the file is synchronized. - (flag $FDFLAG_DSYNC) - ;; Non-blocking mode. - (flag $FDFLAG_NONBLOCK) - ;; Synchronized read I/O operations. - (flag $FDFLAG_RSYNC) - ;; Write according to synchronized I/O file integrity completion. In - ;; addition to synchronizing the data stored in the file, the implementation - ;; may also synchronously update the file's metadata. - (flag $FDFLAG_SYNC) - ) -) - -;; File descriptor attributes. -(typename $fdstat_t - (struct - ;; File type. - (field $fs_filetype $filetype_t) - ;; File descriptor flags. - (field $fs_flags $fdflags_t) - ;; Rights that apply to this file descriptor. - (field $fs_rights_base $rights_t) - ;; Maximum set of rights that may be installed on new file descriptors that - ;; are created through this file descriptor, e.g., through - ;; `__wasi_path_open()`. - (field $fs_rights_inheriting $rights_t) - ) -) - -;; Identifier for a device containing a file system. Can be used in combination -;; with __wasi_inode_t to uniquely identify a file or directory in the -;; filesystem. -(typename $device_t u64) - - -;; Which file time attributes to adjust. -(typename $fstflags_t - (flags u16 - ;; Adjust the last data access timestamp to the value stored in __wasi_filestat_t::st_atim. - (flag $FILESTAT_SET_ATIM) - ;; Adjust the last data access timestamp to the time of clock `__WASI_CLOCK_REALTIME`. - (flag $FILESTAT_SET_ATIM_NOW) - ;; Adjust the last data modification timestamp to the value stored in __wasi_filestat_t::st_mtim. - (flag $FILESTAT_SET_MTIM) - ;; Adjust the last data modification timestamp to the time of clock `__WASI_CLOCK_REALTIME`. - (flag $FILESTAT_SET_MTIM_NOW) - ) -) - -;; Flags determining the method of how paths are resolved. -(typename $lookupflags_t - (flags u32 - ;; As long as the resolved path corresponds to a symbolic link, it is expanded. - (flag $LOOKUP_SYMLINK_FOLLOW) - ) -) - -;; Open flags used by `__wasi_path_open()`. -(typename $oflags_t - (flags u16 - ;; Create file if it does not exist. - (flag $O_CREAT) - ;; Fail if not a directory. - (flag $O_DIRECTORY) - ;; Fail if file already exists. - (flag $O_EXCL) - ;; Truncate file to size 0. - (flag $O_TRUNC) - ) -) - -;; Number of hard links to an inode. -(typename $linkcount_t u32) - -;; File attributes. -(typename $filestat_t - (struct - ;; Device ID of device containing the file. - (field $st_dev $device_t) - ;; File serial number. - (field $st_ino $inode_t) - ;; File type. - (field $st_filetype $filetype_t) - ;; Number of hard links to the file. - (field $st_nlink $linkcount_t) - ;; For regular files, the file size in bytes. For symbolic links, the length in bytes of the pathname contained in the symbolic link. - (field $st_size $filesize_t) - ;; Last data access timestamp. - (field $st_atim $timestamp_t) - ;; Last data modification timestamp. - (field $st_mtim $timestamp_t) - ;; Last file status change timestamp. - (field $st_ctim $timestamp_t) - ) -) - -;; User-provided value that may be attached to objects that is retained when -;; extracted from the implementation. -(typename $userdata_t u64) - -;; Type of a subscription to an event or its occurrence. -(typename $eventtype_t - (flags u8 - ;; The time value of clock __wasi_subscription_t::u.clock.clock_id has - ;; reached timestamp __wasi_subscription_t::u.clock.timeout. - (flag $EVENTTYPE_CLOCK) - ;; File descriptor __wasi_subscription_t::u.fd_readwrite.fd has data - ;; available for reading. This event always triggers for regular files. - (flag $EVENTTYPE_FD_READ) - ;; File descriptor __wasi_subscription_t::u.fd_readwrite.fd has capacity - ;; available for writing. This event always triggers for regular files. - (flag $EVENTTYPE_FD_WRITE) - ) -) - -;; The state of the file descriptor subscribed to with -;; `__WASI_EVENTTYPE_FD_READ` or `__WASI_EVENTTYPE_FD_WRITE`. -(typename $eventrwflags_t - (flags u16 - ;; The peer of this socket has closed or disconnected. - (flag $EVENT_FD_READWRITE_HANGUP) - ) -) - -;; The contents of an $event_t when type is `__WASI_EVENTTYPE_FD_READ` or -;; `__WASI_EVENTTYPE_FD_WRITE`. -(typename $event_fd_readwrite_t - (struct - ;; The number of bytes available for reading or writing. - (field $nbytes $filesize_t) - ;; The state of the file descriptor. - (field $flags $eventrwflags_t) - ) -) - -;; The contents of an $event_t. -(typename $event_u - (union - ;; When type is `__WASI_EVENTTYPE_FD_READ` or `__WASI_EVENTTYPE_FD_WRITE`: - (field $fd_readwrite $event_fd_readwrite_t) - ) -) - -;; An event that occurred. -(typename $event_t - (struct - ;; User-provided value that got attached to __wasi_subscription_t::userdata. - (field $userdata $userdata_t) - ;; If non-zero, an error that occurred while processing the subscription request. - (field $error $errno_t) - ;; The type of the event that occurred. - (field $type $eventtype_t) - ;; The contents of the event. - (field $u $event_u) - ) -) - -;; Flags determining how to interpret the timestamp provided in -;; __wasi_subscription_t::u.clock.timeout. -(typename $subclockflags_t - (flags u16 - ;; If set, treat the timestamp provided in - ;; __wasi_subscription_t::u.clock.timeout as an absolute timestamp of clock - ;; __wasi_subscription_t::u.clock.clock_id. If clear, treat the timestamp - ;; provided in __wasi_subscription_t::u.clock.timeout relative to the - ;; current time value of clock __wasi_subscription_t::u.clock.clock_id. - (flag $SUBSCRIPTION_CLOCK_ABSTIME) - ) -) - -;; The contents of a $subscription_t when type is `__WASI_EVENTTYPE_CLOCK`. -(typename $subscription_clock_t - (struct - ;; The user-defined unique identifier of the clock. - (field $identifier $userdata_t) - ;; The clock against which to compare the timestamp. - (field $clock_id $clockid_t) - ;; The absolute or relative timestamp. - (field $timeout $timestamp_t) - ;; The amount of time that the implementation may wait additionally - ;; to coalesce with other events. - ;; - ;; Flags specifying whether the timeout is absolute or relative - (field $precision $timestamp_t) - ) -) - -;; The contents of a $subscription_t when type is type is -;; `__WASI_EVENTTYPE_FD_READ` or `__WASI_EVENTTYPE_FD_WRITE`. -(typename $subscription_fd_readwrite_t - (struct - ;; The file descriptor on which to wait for it to become ready for reading or writing. - (field $file_descriptor $fd_t) - ) -) - -;; The contents of a $subscription_t. -(typename $subscription_u - (union - ;; When type is `__WASI_EVENTTYPE_CLOCK`: - (field $clock $subscription_clock_t) - ;; When type is `__WASI_EVENTTYPE_FD_READ` or `__WASI_EVENTTYPE_FD_WRITE`: - (field $fd_readwrite $subscription_fd_readwrite_t) - ) -) - -;; Subscription to an event. -(typename $subscription_t - (struct - ;; User-provided value that is attached to the subscription in the - ;; implementation and returned through __wasi_event_t::userdata. - (field $userdata $userdata_t) - ;; The type of the event to which to subscribe. - (field $type $eventtype_t) - ;; The contents of the subscription. - (field $u $subscription_u) - ) -) - -;; Exit code generated by a process when exiting. -(typename $exitcode_t u32) - -;; Signal condition. -(typename $signal_t - (enum u8 - ;; Process abort signal. - ;; Action: Terminates the process. - $SIGABRT - ;; Alarm clock. - ;; Action: Terminates the process. - $SIGALRM - ;; Access to an undefined portion of a memory object. - ;; Action: Terminates the process. - $SIGBUS - ;; Child process terminated, stopped, or continued. - ;; Action: Ignored. - $SIGCHLD - ;; Continue executing, if stopped. - ;; Action: Continues executing, if stopped. - $SIGCONT - ;; Erroneous arithmetic operation. - ;; Action: Terminates the process. - $SIGFPE - ;; Hangup. - ;; Action: Terminates the process. - $SIGHUP - ;; Illegal instruction. - ;; Action: Terminates the process. - $SIGILL - ;; Terminate interrupt signal. - ;; Action: Terminates the process. - $SIGINT - ;; Kill. - ;; Action: Terminates the process. - $SIGKILL - ;; Write on a pipe with no one to read it. - ;; Action: Ignored. - $SIGPIPE - ;; Terminal quit signal. - ;; Action: Terminates the process. - $SIGQUIT - ;; Invalid memory reference. - ;; Action: Terminates the process. - $SIGSEGV - ;; Stop executing. - ;; Action: Stops executing. - $SIGSTOP - ;; Bad system call. - ;; Action: Terminates the process. - $SIGSYS - ;; Termination signal. - ;; Action: Terminates the process. - $SIGTERM - ;; Trace/breakpoint trap. - ;; Action: Terminates the process. - $SIGTRAP - ;; Terminal stop signal. - ;; Action: Stops executing. - $SIGTSTP - ;; Background process attempting read. - ;; Action: Stops executing. - $SIGTTIN - ;; Background process attempting write. - ;; Action: Stops executing. - $SIGTTOU - ;; High bandwidth data is available at a socket. - ;; Action: Ignored. - $SIGURG - ;; User-defined signal 1. - ;; Action: Terminates the process. - $SIGUSR1 - ;; User-defined signal 2. - ;; Action: Terminates the process. - $SIGUSR2 - ;; Virtual timer expired. - ;; Action: Terminates the process. - $SIGVTALRM - ;; CPU time limit exceeded. - ;; Action: Terminates the process. - $SIGXCPU - ;; File size limit exceeded. - ;; Action: Terminates the process. - $SIGXFSZ - ) -) - -;; Flags provided to `__wasi_sock_recv()`. -(typename $riflags_t - (flags u16 - ;; Returns the message without removing it from the socket's receive queue. - (flag $SOCK_RECV_PEEK) - ;; On byte-stream sockets, block until the full amount of data can be returned. - (flag $SOCK_RECV_WAITALL) - ) -) - -;; Flags returned by `__wasi_sock_recv()`. -(typename $roflags_t - (flags u16 - ;; Returned by `__wasi_sock_recv()`: Message data has been truncated. - (flag $SOCK_RECV_DATA_TRUNCATED) - ) -) - -;; Flags provided to `__wasi_sock_send()`. As there are currently no flags -;; defined, it must be set to zero. -(typename $siflags_t u16) - -;; Which channels on a socket to shut down. -(typename $sdflags_t - (flags u8 - ;; Disables further receive operations. - (flag $SHUT_RD) - ;; Disables further send operations. - (flag $SHUT_WR) - ) -) diff --git a/lucet-idl/tests/wasi_unstable.witx b/lucet-idl/tests/wasi_unstable.witx deleted file mode 100644 index ace70fcfc..000000000 --- a/lucet-idl/tests/wasi_unstable.witx +++ /dev/null @@ -1,516 +0,0 @@ -;; The wasi_unstable module type. -;; -;; Some content here is derived from [CloudABI](https://github.com/NuxiNL/cloudabi). - -(use "typenames.witx") - -(module $wasi_unstable - ;; Linear memory to be accessed by WASI functions that need it. - (import "memory" (memory)) - - ;; Read command-line argument data. - ;; The size of the array should match that returned by `wasi_args_sizes_get()` - (@interface func (export "args_get") - (result $error $errno_t) - (result $argv $string_array) - ) - ;; Return command-line argument data sizes. - (@interface func (export "args_sizes_get") - (result $error $errno_t) - ;; The number of arguments. - (result $argc $size_t) - ;; The size of the argument string data. - (result $argv_buf_size $size_t) - ) - - ;; Read environment variable data. - ;; The sizes of the buffers should match that returned by `environ.sizes_get()`. - (@interface func (export "environ_get") - (result $error $errno_t) - (result $argv $string_array) - ) - ;; Return command-line argument data sizes. - (@interface func (export "environ_sizes_get") - ;; The number of arguments. - (result $argc $size_t) - ;; The size of the argument string data. - (result $argv_buf_size $size_t) - ) - - ;; Return the resolution of a clock. - ;; Implementations are required to provide a non-zero value for supported clocks. For unsupported clocks, return `WASI_EINVAL` - ;; Note: This is similar to `clock_getres` in POSIX. - (@interface func (export "clock_res_get") - (result $error $errno_t) - ;; The clock for which to return the resolution. - (param $clock_id $clockid_t) - ;; The resolution of the clock. - (result $resolution $timestamp_t) - ) - ;; Return the time value of a clock. - ;; Note: This is similar to `clock_gettime` in POSIX. - (@interface func (export "clock_time_get") - ;; The clock for which to return the time. - (param $clock_id $clockid_t) - ;; The maximum lag (exclusive) that the returned time value may have, compared to its actual value. - (param $precision $timestamp_t) - (result $error $errno_t) - ;; The time value of the clock. - (result $time $timestamp_t) - ) - - ;; Provide file advisory information on a file descriptor. - ;; Note: This is similar to `posix_fadvise` in POSIX. - (@interface func (export "fd_advise") - (param $fd $fd_t) - (param $offset $filesize_t) ;; The offset within the file to which the advisory applies. - (param $len $filesize_t) ;; The length of the region to which the advisory applies. - (param $advice $advice_t) ;; The advice. - (result $error $errno_t) - ) - - ;; Force the allocation of space in a file. - ;; Note: This is similar to `posix_fallocate` in POSIX. - (@interface func (export "fd_allocate") - (param $fd $fd_t) - ;; The offset at which to start the allocation. - (param $offset $filesize_t) - ;; The length of the area that is allocated. - (param $len $filesize_t) - (result $error $errno_t) - ) - - ;; Close a file descriptor. - ;; Note: This is similar to `close` in POSIX. - (@interface func (export "fd_close") - (param $fd $fd_t) - (result $error $errno_t) - ) - - ;; Synchronize the data of a file to disk. - ;; Note: This is similar to `fdatasync` in POSIX. - (@interface func (export "fd_datasync") - (param $fd $fd_t) - (result $error $errno_t) - ) - - ;; Get the attributes of a file descriptor. - ;; Note: This returns similar flags to `fsync(fd, F_GETFL)` in POSIX, as well as additional fields. - (@interface func (export "fd_fdstat_get") - (param $fd $fd_t) - (result $error $errno_t) - ;; The buffer where the file descriptor's attributes are stored. - (result $stat $fdstat_t) - ) - - ;; Adjust the flags associated with a file descriptor. - ;; Note: This is similar to `fcntl(fd, F_SETFL, flags)` in POSIX. - (@interface func (export "fd_fdstat_set_flags") - (param $fd $fd_t) - ;; The desired values of the file descriptor flags. - (param $flags $fdflags_t) - (result $error $errno_t) - ) - - ;; Adjust the rights associated with a file descriptor. - ;; This can only be used to remove rights, and returns `ENOTCAPABLE` if called in a way that would attempt to add rights - (@interface func (export "fd_fdstat_set_rights") - (param $fd $fd_t) - ;; The desired rights of the file descriptor. - (param $fs_rights_base $rights_t) - (param $fs_rights_inheriting $rights_t) - (result $error $errno_t) - ) - - ;; Return the attributes of an open file. - (@interface func (export "fd_filestat_get") - (param $fd $fd_t) - (result $error $errno_t) - ;; The buffer where the file's attributes are stored. - (result $fs_rights_base $rights_t) - ) - - ;; Adjust the size of an open file. If this increases the file's size, the extra bytes are filled with zeros. - ;; Note: This is similar to `ftruncate` in POSIX. - (@interface func (export "fd_filestat_set_size") - (param $fd $fd_t) - ;; The desired file size. - (param $st_size $filesize_t) - (result $error $errno_t) - ) - - ;; Adjust the timestamps of an open file or directory. - ;; Note: This is similar to `futimens` in POSIX. - (@interface func (export "fd_filestat_set_times") - (param $fd $fd_t) - ;; The desired values of the data access timestamp. - (param $st_atim $timestamp_t) - ;; The desired values of the data modification timestamp. - (param $st_mtim $timestamp_t) - ;; A bitmask indicating which timestamps to adjust. - (param $fst_flags $fstflags_t) - (result $error $errno_t) - ) - - ;; Read from a file descriptor, without using and updating the file descriptor's offset. - ;; Note: This is similar to `preadv` in POSIX. - (@interface func (export "fd_pread") - (param $fd $fd_t) - ;; List of scatter/gather vectors in which to store data. - (param $iovs $iovec_t_array) - ;; The offset within the file at which to read. - (param $offset $filesize_t) - (result $error $errno_t) - ;; The number of bytes read. - (result $nread $size_t) - ) - - ;; Return a description of the given preopened file descriptor. - (@interface func (export "fd_prestat_get") - (param $fd $fd_t) - (result $error $errno_t) - ;; The buffer where the description is stored. - (result $buf data) - ) - - ;; Return a description of the given preopened file descriptor. - (@interface func (export "fd_prestat_dir_name") - (param $fd $fd_t) - ;; A buffer into which to write the preopened directory name. - (param $path string) - (result $error $errno_t) - ) - - ;; Write to a file descriptor, without using and updating the file descriptor's offset. - ;; Note: This is similar to `pwritev` in POSIX. - (@interface func (export "fd_pwrite") - (param $fd $fd_t) - ;; List of scatter/gather vectors from which to retrieve data. - (param $iovs $iovec_t_array) - ;; The offset within the file at which to write. - (param $offset $filesize_t) - (result $error $errno_t) - ;; The number of bytes written. - (result $nwritten $size_t) - ) - - ;; Read from a file descriptor. - ;; Note: This is similar to `readv` in POSIX. - (@interface func (export "fd_read") - (param $fd $fd_t) - ;; List of scatter/gather vectors to which to store data. - (param $iovs $iovec_t_array) - (result $error $errno_t) - ;; The number of bytes read. - (result $nread $size_t) - ) - - ;; Read directory entries from a directory. - ;; When successful, the contents of the output buffer consist of a sequence of - ;; directory entries. Each directory entry consists of a dirent_t object, - ;; followed by dirent_t::d_namlen bytes holding the name of the directory - ;; entry. - ;; - ;; This function fills the output buffer as much as possible, potentially - ;; truncating the last directory entry. This allows the caller to grow its - ;; read buffer size in case it's too small to fit a single large directory - ;; entry, or skip the oversized directory entry. - (@interface func (export "fd_readdir") - (param $fd $fd_t) - ;; The buffer where directory entries are stored - (param $buf data) - ;; The location within the directory to start reading - (param $cookie $dircookie_t) - (result $error $errno_t) - ;; The number of bytes stored in the read buffer. If less than the size of the read buffer, the end of the directory has been reached. - (result $bufused $size_t) - ) - - ;; Atomically replace a file descriptor by renumbering another file descriptor. - ;; - ;; Due to the strong focus on thread safety, this environment does not provide - ;; a mechanism to duplicate or renumber a file descriptor to an arbitrary - ;; number, like `dup2()`. This would be prone to race conditions, as an actual - ;; file descriptor with the same number could be allocated by a different - ;; thread at the same time. - ;; - ;; This function provides a way to atomically renumber file descriptors, which - ;; would disappear if `dup2()` were to be removed entirely. - (@interface func (export "fd_renumber") - (param $fd $fd_t) - ;; The file descriptor to overwrite. - (param $to $fd_t) - (result $error $errno_t) - ) - - ;; Move the offset of a file descriptor. - ;; Note: This is similar to `lseek` in POSIX. - (@interface func (export "fd_seek") - (param $fd $fd_t) - ;; The number of bytes to move. - (param $offset $filedelta_t) - ;; The base from which the offset is relative. - (param $whence $whence_t) - (result $error $errno_t) - ;; The new offset of the file descriptor, relative to the start of the file. - (result $newoffset $filesize_t) - ) - - ;; Synchronize the data and metadata of a file to disk. - ;; Note: This is similar to `fsync` in POSIX. - (@interface func (export "fd_sync") - (param $fd $fd_t) - (result $error $errno_t) - ) - - ;; Return the current offset of a file descriptor. - ;; Note: This is similar to `lseek(fd, 0, SEEK_CUR)` in POSIX. - (@interface func (export "fd_tell") - (param $fd $fd_t) - (result $error $errno_t) - ;; The current offset of the file descriptor, relative to the start of the file. - (result $offset $filesize_t) - ) - - ;; Write to a file descriptor. - ;; Note: This is similar to `writev` in POSIX. - (@interface func (export "fd_write") - (param $fd $fd_t) - ;; List of scatter/gather vectors from which to retrieve data. - (param $iovs $iovec_t_array) - (result $error $errno_t) - ;; The number of bytes written. - (result $nwritten $size_t) - ) - - ;; Create a directory. - ;; Note: This is similar to `mkdirat` in POSIX. - (@interface func (export "path_create_directory") - (param $fd $fd_t) - ;; The path at which to create the directory. - (param $path string) - (result $error $errno_t) - ) - - ;; Return the attributes of a file or directory. - ;; Note: This is similar to `stat` in POSIX. - (@interface func (export "path_filestat_get") - (param $fd $fd_t) - ;; Flags determining the method of how the path is resolved. - (param $flags $lookupflags_t) - ;; The path of the file or directory to inspect. - (param $path string) - (result $error $errno_t) - ;; The buffer where the file's attributes are stored. - (result $buf $filestat_t) - ) - - ;; Adjust the timestamps of a file or directory. - ;; Note: This is similar to `utimensat` in POSIX. - (@interface func (export "path_filestat_set_times") - (param $fd $fd_t) - ;; Flags determining the method of how the path is resolved. - (param $flags $lookupflags_t) - ;; The path of the file or directory to operate on. - (param $path string) - ;; The desired values of the data access timestamp. - (param $st_atim $timestamp_t) - ;; The desired values of the data modification timestamp. - (param $st_mtim $timestamp_t) - ;; A bitmask indicating which timestamps to adjust. - (param $fst_flags $fstflags_t) - (result $error $errno_t) - ) - - ;; Create a hard link. - ;; Note: This is similar to `linkat` in POSIX. - (@interface func (export "path_link") - (param $fd $fd_t) - ;; Flags determining the method of how the path is resolved. - (param $old_flags $lookupflags_t) - ;; The source path from which to link. - (param $old_path string) - ;; The working directory at which the resolution of the new path starts. - (param $new_fd string) - ;; The destination path at which to create the hard link. - (param $new_path string) - (result $error $errno_t) - ) - - ;; Open a file or directory. - ;; - ;; The returned file descriptor is not guaranteed to be the lowest-numbered - ;; file descriptor not currently open; it is randomized to prevent - ;; applications from depending on making assumptions about indexes, since this - ;; is error-prone in multi-threaded contexts. The returned file descriptor is - ;; guaranteed to be less than 2**31. - ;; - ;; Note: This is similar to `openat` in POSIX. - (@interface func (export "path_open") - (param $fd $fd_t) - ;; Flags determining the method of how the path is resolved. - (param $dirflags $lookupflags_t) - ;; The relative path of the file or directory to open, relative to the - ;; `dirfd` directory. - (param $path string) - ;; The method by which to open the file. - (param $o_flags $oflags_t) - ;; The initial rights of the newly created file descriptor. The - ;; implementation is allowed to return a file descriptor with fewer rights - ;; than specified, if and only if those rights do not apply to the type of - ;; file being opened. - ;; - ;; The base rights are rights that will apply to operations using the file - ;; descriptor itself, while the inheriting rights are rights that apply to - ;; file descriptors derived from it. - (param $fs_rights_base $rights_t) - (param $fs_rights_inherting $rights_t) - (result $error $errno_t) - ;; The file descriptor of the file that has been opened. - (result $opened_fd $fd_t) - ) - - ;; Read the contents of a symbolic link. - ;; Note: This is similar to `readlinkat` in POSIX. - (@interface func (export "path_readlink") - (param $fd $fd_t) - ;; The path of the symbolic link from which to read. - (param $path string) - ;; The buffer to which to write the contents of the symbolic link. - (param $buf string) - (result $error $errno_t) - ;; The number of bytes placed in the buffer. - (result $bufused $size_t) - ) - - ;; Remove a directory. - ;; Return `__WASI_ENOTEMPTY` if the directory is not empty. - ;; Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX. - (@interface func (export "path_remove_directory") - (param $fd $fd_t) - ;; The path to a directory to remove. - (param $path string) - (result $error $errno_t) - ) - - ;; Rename a file or directory. - ;; Note: This is similar to `renameat` in POSIX. - (@interface func (export "path_rename") - (param $fd $fd_t) - ;; The source path of the file or directory to rename. - (param $old_path string) - ;; The working directory at which the resolution of the new path starts. - (param $new_fd $fd_t) - ;; The destination path to which to rename the file or directory. - (param $new_path string) - (result $error $errno_t) - ) - - ;; Create a symbolic link. - ;; Note: This is similar to `symlinkat` in POSIX. - (@interface func (export "path_symlink") - (param $fd $fd_t) - ;; The contents of the symbolic link. - (param $old_path string) - ;; The destination path at which to create the symbolic link. - (param $new_path string) - (result $error $errno_t) - ) - - - ;; Unlink a file. - ;; Return `__WASI_EISDIR` if the path refers to a directory. - ;; Note: This is similar to `unlinkat(fd, path, 0)` in POSIX. - (@interface func (export "path_unlink_file") - (param $fd $fd_t) - ;; The path to a file to unlink. - (param $path string) - (result $error $errno_t) - ) - - ;; Concurrently poll for the occurrence of a set of events. - (@interface func (export "poll_oneoff") - ;; The events to which to subscribe. - (param $in $subscription_t) - ;; The events that have occurred. - (param $out $event_t) - ;; Both the number of subscriptions and events. - (param $nsubscriptions $size_t) - (result $error $errno_t) - ;; The number of events stored. - (result $nevents $size_t) - ) - - ;; Terminate the process normally. An exit code of 0 indicates successful - ;; termination of the program. The meanings of other values is dependent on - ;; the environment. - (@interface func (export "proc_exit") - ;; The exit code returned by the process. - (param $rval $exitcode_t) - ) - - ;; Send a signal to the process of the calling thread. - ;; Note: This is similar to `raise` in POSIX. - (@interface func (export "proc_raise") - ;; The signal condition to trigger. - (param $sig $signal_t) - (result $error $errno_t) - ) - - ;; Temporarily yield execution of the calling thread. - ;; Note: This is similar to `sched_yield` in POSIX. - (@interface func (export "proc_sched_yield") - (result $error $errno_t) - ) - - ;; Write high-quality random data into a buffer. - ;; This function blocks when the implementation is unable to immediately - ;; provide sufficient high-quality random data. - ;; This function may execute slowly, so when large mounts of random data are - ;; required, it's advisable to use this function to seed a pseudo-random - ;; number generator, rather than to provide the random data directly. - (@interface func (export "random_get") - ;; The buffer to fill with random data. - (param $buf data) - (result $error $errno_t) - ) - - ;; Receive a message from a socket. - ;; Note: This is similar to `recv` in POSIX, though it also supports reading - ;; the data into multiple buffers in the manner of `readv`. - (@interface func (export "sock_recv") - (param $fd $fd_t) - ;; List of scatter/gather vectors to which to store data. - (param $ri_data $iovec_t_array) - ;; Message flags. - (param $ri_flags $riflags_t) - (result $error $errno_t) - ;; Number of bytes stored in ri_data. - (result $ro_datalen $size_t) - ;; Message flags. - (result $ro_flags $roflags_t) - ) - - ;; Send a message on a socket. - ;; Note: This is similar to `send` in POSIX, though it also supports writing - ;; the data from multiple buffers in the manner of `writev`. - (@interface func (export "sock_send") - (param $fd $fd_t) - ;; List of scatter/gather vectors to which to retrieve data - (param $si_data $ciovec_t_array) - ;; Message flags. - (param $si_flags $siflags_t) - (result $error $errno_t) - ;; Number of bytes transmitted. - (result $so_datalen $size_t) - ) - - ;; Shut down socket send and receive channels. - ;; Note: This is similar to `shutdown` in POSIX. - (@interface func (export "sock_shutdown") - (param $fd $fd_t) - ;; Which channels on the socket to shut down. - (param $how $sdflags_t) - (result $error $errno_t) - ) -) diff --git a/lucet-idl/witx-frontend/Cargo.toml b/lucet-idl/witx-frontend/Cargo.toml deleted file mode 100644 index b41399312..000000000 --- a/lucet-idl/witx-frontend/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "witx-frontend" -version = "0.1.0" -description = "Parse and validate witx file format" -homepage = "https://github.com/fastly/lucet" -repository = "https://github.com/fastly/lucet" -license = "Apache-2.0 WITH LLVM-exception" -categories = ["wasm"] -authors = ["Pat Hickey "] -edition = "2018" - -[lib] -crate-type=["rlib"] - -[[bin]] -name = "witx-validate" -path = "src/main.rs" - -[dependencies] -clap = "2" -failure = "0.1" diff --git a/lucet-idl/witx-frontend/src/ast.rs b/lucet-idl/witx-frontend/src/ast.rs deleted file mode 100644 index 7f583732d..000000000 --- a/lucet-idl/witx-frontend/src/ast.rs +++ /dev/null @@ -1,161 +0,0 @@ -#![allow(dead_code)] -use std::collections::HashMap; -use std::rc::{Rc, Weak}; - -pub use crate::parser::BuiltinType; - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Id(String); - -impl Id { - pub fn new>(s: S) -> Self { - Id(s.as_ref().to_string()) - } - pub fn as_str(&self) -> &str { - self.0.as_str() - } -} - -#[derive(Debug, Clone)] -pub struct Document { - pub definitions: Vec, - pub entries: HashMap, -} - -#[derive(Debug, Clone)] -pub enum Definition { - Datatype(Rc), - Module(Rc), -} - -#[derive(Debug, Clone)] -pub enum Entry { - Datatype(Weak), - Module(Weak), -} - -impl Entry { - pub fn kind(&self) -> &'static str { - match self { - Entry::Datatype { .. } => "datatype", - Entry::Module { .. } => "module", - } - } -} - -#[derive(Debug, Clone)] -pub enum DatatypeIdent { - Builtin(BuiltinType), - Array(Box), - Ident(Rc), -} - -#[derive(Debug, Clone)] -pub struct Datatype { - pub name: Id, - pub variant: DatatypeVariant, -} - -#[derive(Debug, Clone)] -pub enum DatatypeVariant { - Alias(AliasDatatype), - Enum(EnumDatatype), - Flags(FlagsDatatype), - Struct(StructDatatype), - Union(UnionDatatype), -} - -#[derive(Debug, Clone)] -pub struct AliasDatatype { - pub name: Id, - pub to: DatatypeIdent, -} - -#[derive(Debug, Clone)] -pub enum IntRepr { - I8, - I16, - I32, - I64, -} - -#[derive(Debug, Clone)] -pub struct EnumDatatype { - pub name: Id, - pub repr: IntRepr, - pub variants: Vec, -} - -#[derive(Debug, Clone)] -pub struct FlagsDatatype { - pub name: Id, - pub repr: IntRepr, - pub flags: Vec, -} - -#[derive(Debug, Clone)] -pub struct StructDatatype { - pub name: Id, - pub members: Vec, -} - -#[derive(Debug, Clone)] -pub struct StructMember { - pub name: Id, - pub type_: DatatypeIdent, -} - -#[derive(Debug, Clone)] -pub struct UnionDatatype { - pub name: Id, - pub variants: Vec, -} - -#[derive(Debug, Clone)] -pub struct UnionVariant { - pub name: Id, - pub type_: DatatypeIdent, -} - -#[derive(Debug, Clone)] -pub struct Module { - pub name: Id, - pub definitions: Vec, - pub entries: HashMap, -} - -#[derive(Debug, Clone)] -pub enum ModuleDefinition { - Import(Rc), - Func(Rc), -} - -#[derive(Debug, Clone)] -pub enum ModuleEntry { - Import(Weak), - Func(Weak), -} - -#[derive(Debug, Clone)] -pub struct ModuleImport { - pub name: Id, - pub variant: ModuleImportVariant, -} - -#[derive(Debug, Clone)] -pub enum ModuleImportVariant { - Memory, -} - -#[derive(Debug, Clone)] -pub struct InterfaceFunc { - pub name: Id, - pub params: Vec, - pub results: Vec, -} - -#[derive(Debug, Clone)] -pub struct InterfaceFuncParam { - pub name: Id, - pub type_: DatatypeIdent, -} diff --git a/lucet-idl/witx-frontend/src/lexer.rs b/lucet-idl/witx-frontend/src/lexer.rs deleted file mode 100644 index b004acf07..000000000 --- a/lucet-idl/witx-frontend/src/lexer.rs +++ /dev/null @@ -1,354 +0,0 @@ -use crate::Location; -use failure::Fail; -use std::path::{Path, PathBuf}; -use std::str::CharIndices; - -///! The lexer turns a string into a stream of located tokens. -///! The tokens are meant for consumption by the s-expression parser. -///! -///! Comments in source text look like `;; rest of line ...`. -///! Words look like `abcde_` -///! Idents look like `$abcde_` -///! Annotations look like `@abcde_` -///! Quotes look like `"a b cde 123 @#$%^&*() _"` -///! -///! This implementation was heavily influenced by `cranelift-reader` - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum Token<'a> { - LPar, // ( - RPar, // ) - Word(&'a str), // Bare word - Ident(&'a str), // Starts with $ - Annot(&'a str), // Starts with @. short for annotation. - Quote(&'a str), // Found between balanced "". No escaping. -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct LocatedToken<'a> { - pub token: Token<'a>, - pub location: Location, -} - -fn token(token: Token<'_>, location: Location) -> Result, LocatedError> { - Ok(LocatedToken { token, location }) -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Fail)] -pub enum LexError { - #[fail(display = "Invalid character '{}'", _0)] - InvalidChar(char), - #[fail(display = "Empty identifier '$'")] - EmptyIdentifier, - #[fail(display = "Empty annotation '@'")] - EmptyAnnotation, - #[fail(display = "Unterminated quote")] - UnterminatedQuote, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct LocatedError { - pub error: LexError, - pub location: Location, -} - -fn error<'a>(error: LexError, location: Location) -> Result, LocatedError> { - Err(LocatedError { error, location }) -} - -pub struct Lexer<'a> { - source: &'a str, - chars: CharIndices<'a>, - lookahead: Option, - pos: usize, - line_number: usize, - column_start: usize, - tab_compensation: usize, - path: PathBuf, -} - -impl<'a> Lexer<'a> { - pub fn new>(s: &'a str, path: P) -> Lexer<'_> { - let mut lex = Lexer { - source: s, - chars: s.char_indices(), - lookahead: None, - pos: 0, - line_number: 1, - column_start: 0, - tab_compensation: 0, - path: path.as_ref().into(), - }; - lex.next_ch(); - lex - } - - fn next_ch(&mut self) -> Option { - if self.lookahead == Some('\n') { - self.line_number += 1; - self.column_start = self.pos + 1; // Next column starts a fresh line - self.tab_compensation = 0; - } else if self.lookahead == Some('\t') { - self.tab_compensation += 7; // One column for the position of the char itself, add 7 more for a tabwidth of 8 - } - match self.chars.next() { - Some((idx, ch)) => { - self.pos = idx; - self.lookahead = Some(ch); - } - None => { - self.pos = self.source.len(); - self.lookahead = None; - } - } - self.lookahead - } - - fn loc(&self) -> Location { - Location { - path: self.path.clone(), - line: self.line_number, - column: self.pos - self.column_start + self.tab_compensation, - } - } - - fn looking_at(&self, prefix: &str) -> bool { - self.source[self.pos..].starts_with(prefix) - } - - fn scan_char(&mut self, tok: Token<'a>) -> Result, LocatedError> { - assert!(self.lookahead.is_some()); - let loc = self.loc(); - self.next_ch(); - token(tok, loc) - } - - pub fn rest_of_line(&mut self) -> &'a str { - let begin = self.pos; - loop { - match self.next_ch() { - None | Some('\n') => return &self.source[begin..self.pos], - _ => {} - } - } - } - - fn scan_word(&mut self) -> Result, LocatedError> { - let begin = self.pos; - let loc = self.loc(); - assert!(self.lookahead == Some('_') || self.lookahead.unwrap().is_alphabetic()); - loop { - match self.next_ch() { - Some('_') | Some('-') => {} - Some(ch) if ch.is_alphanumeric() => {} - _ => break, - } - } - let text = &self.source[begin..self.pos]; - token(Token::Word(text), loc) - } - - fn scan_ident(&mut self) -> Result, LocatedError> { - let loc = self.loc(); - assert!(self.lookahead == Some('$')); - match self.next_ch() { - Some(ch) if ch.is_alphanumeric() || ch == '_' => {} - _ => Err(LocatedError { - error: LexError::EmptyIdentifier, - location: loc.clone(), - })?, - } - let begin = self.pos; - - loop { - match self.next_ch() { - Some('_') | Some('-') => {} - Some(ch) if ch.is_alphanumeric() => {} - _ => break, - } - } - - let text = &self.source[begin..self.pos]; - token(Token::Ident(text), loc) - } - - fn scan_annotation(&mut self) -> Result, LocatedError> { - let loc = self.loc(); - assert!(self.lookahead == Some('@')); - match self.next_ch() { - Some(ch) if ch.is_alphanumeric() || ch == '_' => {} - _ => Err(LocatedError { - error: LexError::EmptyAnnotation, - location: loc.clone(), - })?, - } - let begin = self.pos; - - loop { - match self.next_ch() { - Some('_') | Some('-') => {} - Some(ch) if ch.is_alphanumeric() => {} - _ => break, - } - } - - let text = &self.source[begin..self.pos]; - token(Token::Annot(text), loc) - } - - fn scan_quote(&mut self) -> Result, LocatedError> { - let begin = self.pos; - let loc = self.loc(); - assert!(self.lookahead == Some('"')); - loop { - match self.next_ch() { - None => Err(LocatedError { - error: LexError::UnterminatedQuote, - location: loc.clone(), - })?, - Some('"') => { - self.next_ch(); - break; - } - _ => {} - } - } - let text = &self.source[(begin + 1)..(self.pos - 1)]; - token(Token::Quote(text), loc) - } - - #[allow(clippy::should_implement_trait)] - pub fn next(&mut self) -> Option, LocatedError>> { - loop { - let loc = self.loc(); - return match self.lookahead { - None => None, - Some(c) => Some(match c { - '(' => self.scan_char(Token::LPar), - ')' => self.scan_char(Token::RPar), - '$' => self.scan_ident(), - '@' => self.scan_annotation(), - ';' => { - if self.looking_at(";;") { - self.rest_of_line(); - continue; - } else { - self.next_ch(); - error(LexError::InvalidChar(';'), loc) - } - } - '"' => self.scan_quote(), - '_' => self.scan_word(), - ch if ch.is_alphabetic() => self.scan_word(), - ch if ch.is_whitespace() => { - self.next_ch(); - continue; - } - _ => { - self.next_ch(); - error(LexError::InvalidChar(c), loc) - } - }), - }; - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - use std::path::{Path, PathBuf}; - - fn testlexer(input: &str) -> Lexer { - Lexer::new(input, Path::new("/test")) - } - - fn token( - token: Token<'_>, - line: usize, - column: usize, - ) -> Option, LocatedError>> { - Some(super::token( - token, - Location { - path: PathBuf::from("/test"), - line, - column, - }, - )) - } - - fn error<'a>( - err: LexError, - line: usize, - column: usize, - ) -> Option, LocatedError>> { - Some(super::error( - err, - Location { - path: PathBuf::from("/test"), - line, - column, - }, - )) - } - #[test] - fn words_and_idents() { - let mut lex = testlexer("$gussie is a good $dog"); - // ruler 0 5 10 15 20 - assert_eq!(lex.next(), token(Token::Ident("gussie"), 1, 0)); - assert_eq!(lex.next(), token(Token::Word("is"), 1, 8)); - assert_eq!(lex.next(), token(Token::Word("a"), 1, 11)); - assert_eq!(lex.next(), token(Token::Word("good"), 1, 13)); - assert_eq!(lex.next(), token(Token::Ident("dog"), 1, 18)); - assert_eq!(lex.next(), None); - - let mut lex = - testlexer("$ok $a $_ $ _\nkebab-case\nsnake_case\n$kebab-ident\n$snake_ident"); - assert_eq!(lex.next(), token(Token::Ident("ok"), 1, 0)); - assert_eq!(lex.next(), token(Token::Ident("a"), 1, 4)); - assert_eq!(lex.next(), token(Token::Ident("_"), 1, 7)); - assert_eq!(lex.next(), error(LexError::EmptyIdentifier, 1, 10)); - assert_eq!(lex.next(), token(Token::Word("_"), 1, 12)); - assert_eq!(lex.next(), token(Token::Word("kebab-case"), 2, 0)); - assert_eq!(lex.next(), token(Token::Word("snake_case"), 3, 0)); - assert_eq!(lex.next(), token(Token::Ident("kebab-ident"), 4, 0)); - assert_eq!(lex.next(), token(Token::Ident("snake_ident"), 5, 0)); - assert_eq!(lex.next(), None); - } - - #[test] - fn comments() { - let mut lex = testlexer("the quick ;; brown fox\njumped\n;;over the three\nlazy;;dogs"); - assert_eq!(lex.next(), token(Token::Word("the"), 1, 0)); - assert_eq!(lex.next(), token(Token::Word("quick"), 1, 4)); - assert_eq!(lex.next(), token(Token::Word("jumped"), 2, 0)); - assert_eq!(lex.next(), token(Token::Word("lazy"), 4, 0)); - assert_eq!(lex.next(), None); - - let mut lex = testlexer("line1 ;;\n$sym_2;\n\t\tl3;;;333"); - assert_eq!(lex.next(), token(Token::Word("line1"), 1, 0)); - assert_eq!(lex.next(), token(Token::Ident("sym_2"), 2, 0)); - assert_eq!(lex.next(), error(LexError::InvalidChar(';'), 2, 6)); - assert_eq!(lex.next(), token(Token::Word("l3"), 3, 16)); // Two tabs = 16 columns - assert_eq!(lex.next(), None); - } - - #[test] - fn quotes() { - let mut lex = testlexer("a \"bc\" d"); - assert_eq!(lex.next(), token(Token::Word("a"), 1, 0)); - assert_eq!(lex.next(), token(Token::Quote("bc"), 1, 2)); - assert_eq!(lex.next(), token(Token::Word("d"), 1, 7)); - - let mut lex = testlexer("a \"b\nc\" d"); - assert_eq!(lex.next(), token(Token::Word("a"), 1, 0)); - assert_eq!(lex.next(), token(Token::Quote("b\nc"), 1, 2)); - assert_eq!(lex.next(), token(Token::Word("d"), 2, 3)); - - let mut lex = testlexer("a \"b"); - assert_eq!(lex.next(), token(Token::Word("a"), 1, 0)); - assert_eq!(lex.next(), error(LexError::UnterminatedQuote, 1, 2)); - } -} diff --git a/lucet-idl/witx-frontend/src/lib.rs b/lucet-idl/witx-frontend/src/lib.rs deleted file mode 100644 index bb0e3a6b9..000000000 --- a/lucet-idl/witx-frontend/src/lib.rs +++ /dev/null @@ -1,54 +0,0 @@ -/// Types describing a validated witx document -mod ast; -/// Lexer text into tokens -mod lexer; -/// Witx syntax parsing from SExprs -mod parser; -/// SExpr parsing from tokens -mod sexpr; -/// Resolve toplevel `use` declarations across files -mod toplevel; -/// Validate declarations into ast -mod validate; - -pub use ast::{ - AliasDatatype, BuiltinType, Datatype, DatatypeIdent, DatatypeVariant, Definition, Document, - Entry, EnumDatatype, FlagsDatatype, Id, IntRepr, InterfaceFunc, InterfaceFuncParam, Module, - ModuleDefinition, ModuleEntry, ModuleImport, ModuleImportVariant, StructDatatype, StructMember, - UnionDatatype, UnionVariant, -}; -pub use lexer::LexError; -pub use parser::{DeclSyntax, ParseError}; -pub use sexpr::SExprParseError; -pub use validate::ValidationError; - -use failure::Fail; -use std::io; -use std::path::{Path, PathBuf}; - -/// Location in the source text -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Location { - pub path: PathBuf, - pub line: usize, - pub column: usize, -} - -#[derive(Debug, Fail)] -pub enum WitxError { - #[fail(display = "{}", _0)] - SExpr(#[cause] SExprParseError), - #[fail(display = "when resolving use declaration for {:?}: {}", _0, _1)] - UseResolution(PathBuf, #[cause] io::Error), - #[fail(display = "{}", _0)] - Parse(#[cause] ParseError), - #[fail(display = "{}", _0)] - Validation(#[cause] ValidationError), -} - -pub fn load>(path: P) -> Result { - use toplevel::parse_witx; - use validate::validate_document; - let parsed_decls = parse_witx(path)?; - validate_document(&parsed_decls).map_err(WitxError::Validation) -} diff --git a/lucet-idl/witx-frontend/src/main.rs b/lucet-idl/witx-frontend/src/main.rs deleted file mode 100644 index d8ae69d9e..000000000 --- a/lucet-idl/witx-frontend/src/main.rs +++ /dev/null @@ -1,38 +0,0 @@ -use clap::{App, Arg}; -use std::path::Path; -use std::process; -use witx_frontend::load; - -pub fn main() { - let app = App::new("witx-validate") - .version(env!("CARGO_PKG_VERSION")) - .about("Validate witx file format") - .arg( - Arg::with_name("input") - .required(true) - .help("path to root of witx document"), - ) - .arg( - Arg::with_name("verbose") - .short("v") - .long("verbose") - .takes_value(false) - .required(false), - ) - .get_matches(); - - match load(Path::new(app.value_of("input").expect("required arg"))) { - Ok(doc) => { - if app.is_present("verbose") { - println!("{:?}", doc) - } - } - Err(e) => { - eprintln!("{}", e); - if app.is_present("verbose") { - eprintln!("{:?}", e); - } - process::exit(1); - } - } -} diff --git a/lucet-idl/witx-frontend/src/parser.rs b/lucet-idl/witx-frontend/src/parser.rs deleted file mode 100644 index e319d0c22..000000000 --- a/lucet-idl/witx-frontend/src/parser.rs +++ /dev/null @@ -1,558 +0,0 @@ -use crate::sexpr::SExpr; -use crate::Location; -use failure::Fail; - -///! Parser turns s-expressions into unvalidated syntax constructs. -///! conventions: -///! `Type::starts_parsing(s-expr) -> bool` is for look-ahead: we use -///! this predicate to combine parsers for different `Type`s where both -///! alternatives are accepted. -///! `Type::parse(sexpr: &SExpr) -> Result` takes a single -///! s-expression and parses it into a `Self`. -///! for parsers that take a subset of a vector s-expression, the signature -///! `Type::parse(sexprs: &[SExpr], location: Location) -> Result` -///! has an additional `Location` argument, which should point to the parent SExpr::Vec. -///! This is used for error reporting in case the slice doesn't have the number of elements -///! expected. - -#[derive(Debug, Fail)] -#[fail(display = "{} at {:?}", _0, _1)] -pub struct ParseError { - pub message: String, - pub location: Location, -} - -macro_rules! parse_err { - ($loc:expr, $msg:expr) => { - ParseError { message: $msg.to_string(), location: $loc.clone() } - }; - ($loc:expr, $fmt:expr, $( $arg:expr ),+ ) => { - ParseError { message: format!($fmt, $( $arg ),+), location: $loc.clone() } - }; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct IdentSyntax { - pub name: String, - pub location: Location, -} - -macro_rules! id { - ($s:expr, $loc: expr) => { - IdentSyntax { - name: $s.to_string(), - location: $loc.clone(), - } - }; -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum BuiltinType { - String, - Data, - U8, - U16, - U32, - U64, - S8, - S16, - S32, - S64, - F32, - F64, -} - -impl BuiltinType { - pub fn starts_parsing(sexpr: &SExpr) -> bool { - match sexpr { - SExpr::Word("string", _) - | SExpr::Word("data", _) - | SExpr::Word("u8", _) - | SExpr::Word("u16", _) - | SExpr::Word("u32", _) - | SExpr::Word("u64", _) - | SExpr::Word("s8", _) - | SExpr::Word("s16", _) - | SExpr::Word("s32", _) - | SExpr::Word("s64", _) - | SExpr::Word("f32", _) - | SExpr::Word("f64", _) => true, - _ => false, - } - } - pub fn parse(sexpr: &SExpr) -> Result { - match sexpr { - SExpr::Word("string", _loc) => Ok(BuiltinType::String), - SExpr::Word("data", _loc) => Ok(BuiltinType::Data), - SExpr::Word("u8", _loc) => Ok(BuiltinType::U8), - SExpr::Word("u16", _loc) => Ok(BuiltinType::U16), - SExpr::Word("u32", _loc) => Ok(BuiltinType::U32), - SExpr::Word("u64", _loc) => Ok(BuiltinType::U64), - SExpr::Word("s8", _loc) => Ok(BuiltinType::S8), - SExpr::Word("s16", _loc) => Ok(BuiltinType::S16), - SExpr::Word("s32", _loc) => Ok(BuiltinType::S32), - SExpr::Word("s64", _loc) => Ok(BuiltinType::S64), - SExpr::Word("f32", _loc) => Ok(BuiltinType::F32), - SExpr::Word("f64", _loc) => Ok(BuiltinType::F64), - _ => Err(parse_err!(sexpr.location(), "invalid builtin type")), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum DatatypeIdentSyntax { - Builtin(BuiltinType), - Array(Box), - Ident(IdentSyntax), -} - -impl DatatypeIdentSyntax { - pub fn starts_parsing(sexpr: &SExpr) -> bool { - BuiltinType::starts_parsing(sexpr) - || match sexpr { - SExpr::Ident(_, _) => true, - SExpr::Vec(v, _) => match (v.get(0), v.get(1)) { - (Some(SExpr::Word("array", _)), Some(_)) => true, - _ => false, - }, - _ => false, - } - } - pub fn parse(sexpr: &SExpr) -> Result { - if BuiltinType::starts_parsing(sexpr) { - let builtin = BuiltinType::parse(sexpr)?; - Ok(DatatypeIdentSyntax::Builtin(builtin)) - } else { - match sexpr { - SExpr::Ident(i, loc) => Ok(DatatypeIdentSyntax::Ident(id!(i, loc))), - SExpr::Vec(v, loc) => match (v.get(0), v.get(1)) { - (Some(SExpr::Word("array", _loc)), Some(expr)) => Ok( - DatatypeIdentSyntax::Array(Box::new(DatatypeIdentSyntax::parse(expr)?)), - ), - _ => Err(parse_err!(loc, "expected type identifier")), - }, - _ => Err(parse_err!(sexpr.location(), "expected type identifier")), - } - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum TopLevelSyntax { - Decl(DeclSyntax), - Use(IdentSyntax), -} - -impl TopLevelSyntax { - pub fn parse(sexpr: &SExpr) -> Result { - if DeclSyntax::starts_parsing(sexpr) { - let decl = DeclSyntax::parse(sexpr)?; - Ok(TopLevelSyntax::Decl(decl)) - } else { - match sexpr { - SExpr::Vec(v, vec_loc) => match v.get(0) { - Some(SExpr::Word("use", loc)) => match v.get(1) { - Some(SExpr::Quote(u, loc)) => Ok(TopLevelSyntax::Use(id!(u, loc))), - _ => Err(parse_err!(loc, "invalid use declaration")), - }, - _ => Err(parse_err!(vec_loc, "expected top level declaration")), - }, - _ => Err(parse_err!( - sexpr.location(), - "expected top level declaration" - )), - } - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum DeclSyntax { - Typename(TypenameSyntax), - Module(ModuleSyntax), -} - -impl DeclSyntax { - pub fn starts_parsing(sexpr: &SExpr) -> bool { - match sexpr { - SExpr::Vec(v, _) => match v.get(0) { - Some(SExpr::Word("typename", _)) => true, - Some(SExpr::Word("module", _)) => true, - _ => false, - }, - _ => false, - } - } - pub fn parse(sexpr: &SExpr) -> Result { - match sexpr { - SExpr::Vec(v, loc) => match v.get(0) { - Some(SExpr::Word("typename", loc)) => { - Ok(DeclSyntax::Typename(TypenameSyntax::parse(&v[1..], loc)?)) - } - Some(SExpr::Word("module", loc)) => { - Ok(DeclSyntax::Module(ModuleSyntax::parse(&v[1..], loc)?)) - } - _ => Err(parse_err!(loc, "invalid declaration")), - }, - _ => Err(parse_err!(sexpr.location(), "expected vec")), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct TypenameSyntax { - pub ident: IdentSyntax, - pub def: TypedefSyntax, -} - -impl TypenameSyntax { - pub fn parse(sexpr: &[SExpr], loc: &Location) -> Result { - let ident = match sexpr.get(0) { - Some(SExpr::Ident(i, loc)) => id!(i, loc), - _ => Err(parse_err!(loc, "expected typename identifier"))?, - }; - let def = match sexpr.get(1) { - Some(expr) => TypedefSyntax::parse(expr)?, - _ => Err(parse_err!(loc, "expected type definition"))?, - }; - Ok(TypenameSyntax { ident, def }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum TypedefSyntax { - Ident(DatatypeIdentSyntax), - Enum(EnumSyntax), - Flags(FlagsSyntax), - Struct(StructSyntax), - Union(UnionSyntax), -} - -impl TypedefSyntax { - pub fn parse(sexpr: &SExpr) -> Result { - if DatatypeIdentSyntax::starts_parsing(sexpr) { - let ident = DatatypeIdentSyntax::parse(sexpr)?; - Ok(TypedefSyntax::Ident(ident)) - } else { - match sexpr { - SExpr::Vec(vs, loc) => match vs.get(0) { - Some(SExpr::Word("enum", loc)) => { - Ok(TypedefSyntax::Enum(EnumSyntax::parse(&vs[1..], loc)?)) - } - Some(SExpr::Word("flags", loc)) => { - Ok(TypedefSyntax::Flags(FlagsSyntax::parse(&vs[1..], loc)?)) - } - Some(SExpr::Word("struct", loc)) => { - Ok(TypedefSyntax::Struct(StructSyntax::parse(&vs[1..], loc)?)) - } - Some(SExpr::Word("union", loc)) => { - Ok(TypedefSyntax::Union(UnionSyntax::parse(&vs[1..], loc)?)) - } - _ => Err(parse_err!( - loc, - "expected type identifier or type definition" - )), - }, - _ => Err(parse_err!( - sexpr.location(), - "expected type identifier or type definition" - )), - } - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct EnumSyntax { - pub repr: BuiltinType, - pub members: Vec, -} - -impl EnumSyntax { - pub fn parse(sexpr: &[SExpr], loc: &Location) -> Result { - let repr = match sexpr.get(0) { - Some(e) => BuiltinType::parse(e)?, - _ => Err(parse_err!(loc, "no enum repr"))?, - }; - let members = sexpr[1..] - .iter() - .map(|m| match m { - SExpr::Ident(i, loc) => Ok(id!(i, loc)), - s => Err(parse_err!(s.location(), "expected enum member identifier")), - }) - .collect::, ParseError>>()?; - if members.is_empty() { - Err(parse_err!(loc, "expected at least one enum member"))? - } - Ok(EnumSyntax { repr, members }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FlagsSyntax { - pub repr: BuiltinType, - pub flags: Vec, -} - -impl FlagsSyntax { - pub fn parse(sexpr: &[SExpr], loc: &Location) -> Result { - let repr = BuiltinType::parse( - sexpr - .get(0) - .ok_or_else(|| parse_err!(loc, "expected flag repr type"))?, - )?; - let flags = sexpr[1..] - .iter() - .map(|f| match f { - SExpr::Vec(vs, loc) => match (vs.get(0), vs.get(1)) { - (Some(SExpr::Word("flag", _)), Some(SExpr::Ident(i, loc))) => Ok(id!(i, loc)), - _ => Err(parse_err!(loc, "expected flag specifier")), - }, - s => Err(parse_err!(s.location(), "expected flag specifier")), - }) - .collect::, ParseError>>()?; - Ok(FlagsSyntax { repr, flags }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StructSyntax { - pub fields: Vec, -} - -impl StructSyntax { - pub fn parse(sexpr: &[SExpr], loc: &Location) -> Result { - if sexpr.is_empty() { - Err(parse_err!(loc, "expected at least one struct member"))? - } - let fields = sexpr - .iter() - .map(|f| FieldSyntax::parse(f, "field")) - .collect::, ParseError>>()?; - Ok(StructSyntax { fields }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FieldSyntax { - pub name: IdentSyntax, - pub type_: DatatypeIdentSyntax, -} - -impl FieldSyntax { - pub fn starts_parsing(sexpr: &SExpr, constructor: &str) -> bool { - match sexpr { - SExpr::Vec(v, _) => match v.get(0) { - Some(SExpr::Word(c, _)) => *c == constructor, - _ => false, - }, - _ => false, - } - } - pub fn parse(sexpr: &SExpr, constructor: &str) -> Result { - match sexpr { - SExpr::Vec(v, loc) => match v.get(0) { - Some(SExpr::Word(c, _)) if *c == constructor => { - let name = match v.get(1) { - Some(SExpr::Ident(i, loc)) => id!(i, loc), - _ => Err(parse_err!(loc, "expected {} name identifier", constructor))?, - }; - let type_ = DatatypeIdentSyntax::parse(v.get(2).ok_or_else(|| { - parse_err!(loc, "expected {} type identifier", constructor) - })?)?; - Ok(FieldSyntax { name, type_ }) - } - _ => Err(parse_err!(loc, "expected {}", constructor)), - }, - _ => Err(parse_err!(sexpr.location(), "expected {}", constructor)), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct UnionSyntax { - pub fields: Vec, -} - -impl UnionSyntax { - pub fn parse(sexpr: &[SExpr], loc: &Location) -> Result { - if sexpr.is_empty() { - Err(parse_err!(loc, "expected at least one union member"))? - } - let fields = sexpr - .iter() - .map(|f| FieldSyntax::parse(f, "field")) - .collect::, ParseError>>()?; - Ok(UnionSyntax { fields }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ModuleSyntax { - pub name: IdentSyntax, - pub decls: Vec, -} - -impl ModuleSyntax { - pub fn parse(sexprs: &[SExpr], loc: &Location) -> Result { - let name = match sexprs.get(0) { - Some(SExpr::Ident(i, loc)) => id!(i, loc), - _ => Err(parse_err!(loc, "expected module name"))?, - }; - let decls = sexprs[1..] - .iter() - .map(|s| ModuleDeclSyntax::parse(s)) - .collect::, _>>()?; - Ok(ModuleSyntax { name, decls }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ModuleDeclSyntax { - Import(ModuleImportSyntax), - Func(InterfaceFuncSyntax), -} - -impl ModuleDeclSyntax { - pub fn parse(sexpr: &SExpr) -> Result { - if ModuleImportSyntax::starts_parsing(sexpr) { - Ok(ModuleDeclSyntax::Import(ModuleImportSyntax::parse(sexpr)?)) - } else if InterfaceFuncSyntax::starts_parsing(sexpr) { - Ok(ModuleDeclSyntax::Func(InterfaceFuncSyntax::parse(sexpr)?)) - } else { - Err(parse_err!(sexpr.location(), "expected import or function")) - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ModuleImportSyntax { - pub name: IdentSyntax, - pub type_: ImportTypeSyntax, -} - -impl ModuleImportSyntax { - pub fn starts_parsing(sexpr: &SExpr) -> bool { - match sexpr { - SExpr::Vec(vs, _) => match vs.get(0) { - Some(SExpr::Word("import", _)) => true, - _ => false, - }, - _ => false, - } - } - pub fn parse(sexpr: &SExpr) -> Result { - match sexpr { - SExpr::Vec(vs, vec_loc) => match (vs.get(0), vs.get(1)) { - (Some(SExpr::Word("import", _)), Some(SExpr::Quote(name, loc))) => { - let name = id!(name, loc); - let type_ = ImportTypeSyntax::parse(&vs[2..], vec_loc)?; - Ok(ModuleImportSyntax { name, type_ }) - } - _ => Err(parse_err!(vec_loc, "expected module import")), - }, - _ => Err(parse_err!(sexpr.location(), "expected module import")), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ImportTypeSyntax { - Memory, -} - -impl ImportTypeSyntax { - pub fn parse(sexpr: &[SExpr], loc: &Location) -> Result { - if sexpr.len() > 1 { - Err(parse_err!(loc, "too many elements for an import type"))?; - } - match sexpr.get(0) { - Some(SExpr::Vec(vs, loc)) => match vs.get(0) { - Some(SExpr::Word("memory", _)) => { - if vs.len() == 1 { - Ok(ImportTypeSyntax::Memory) - } else { - Err(parse_err!(loc, "too many elements for memory declaration")) - } - } - _ => Err(parse_err!(loc, "expected import type")), - }, - _ => Err(parse_err!(loc, "expected import type")), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct InterfaceFuncSyntax { - pub export: IdentSyntax, - pub params: Vec, - pub results: Vec, -} - -impl InterfaceFuncSyntax { - pub fn starts_parsing(sexpr: &SExpr) -> bool { - match sexpr { - SExpr::Vec(vs, _) => match (vs.get(0), vs.get(1)) { - (Some(SExpr::Annot("interface", _)), Some(SExpr::Word("func", _))) => true, - _ => false, - }, - _ => false, - } - } - pub fn parse(sexpr: &SExpr) -> Result { - match sexpr { - SExpr::Vec(vs, loc) => match (vs.get(0), vs.get(1)) { - (Some(SExpr::Annot("interface", _)), Some(SExpr::Word("func", _))) => { - let export = match vs.get(2) { - Some(SExpr::Vec(es, loc)) => match (es.get(0), es.get(1)) { - ( - Some(SExpr::Word("export", _)), - Some(SExpr::Quote(name, name_loc)), - ) => { - if es.len() == 2 { - id!(name, name_loc) - } else { - Err(parse_err!( - loc, - "too many elements for export declaration" - ))? - } - } - _ => Err(parse_err!(loc, "expected export declaration"))?, - }, - _ => Err(parse_err!(loc, "expected export declaration"))?, - }; - let mut params = Vec::new(); - let mut results = Vec::new(); - - for sexpr in &vs[3..] { - if FieldSyntax::starts_parsing(sexpr, "param") { - let param = FieldSyntax::parse(sexpr, "param")?; - params.push(param); - } else if FieldSyntax::starts_parsing(sexpr, "result") { - let result = FieldSyntax::parse(sexpr, "result")?; - results.push(result); - } else { - Err(parse_err!( - sexpr.location(), - "expected param or result field" - ))?; - } - } - - Ok(InterfaceFuncSyntax { - export, - params, - results, - }) - } - _ => Err(parse_err!(loc, "expected interface func declaration")), - }, - - _ => Err(parse_err!( - sexpr.location(), - "expected interface func declaration" - )), - } - } -} diff --git a/lucet-idl/witx-frontend/src/sexpr.rs b/lucet-idl/witx-frontend/src/sexpr.rs deleted file mode 100644 index dfb124611..000000000 --- a/lucet-idl/witx-frontend/src/sexpr.rs +++ /dev/null @@ -1,225 +0,0 @@ -pub use crate::lexer::LexError; -use crate::lexer::{Lexer, LocatedError, LocatedToken, Token}; -use crate::Location; -use failure::Fail; -use std::path::{Path, PathBuf}; - -///! The s-expression parser turns a string into a stream of SExprs. -///! It uses the `Lexer` under the hood. -///! This implementation was heavily influenced by `cranelift-reader` - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum SExpr<'a> { - Vec(Vec>, Location), - Word(&'a str, Location), - Ident(&'a str, Location), - Quote(&'a str, Location), - /// Short for Annotation - Annot(&'a str, Location), -} - -impl<'a> SExpr<'a> { - pub fn location(&self) -> Location { - match self { - SExpr::Vec(_, loc) => loc.clone(), - SExpr::Word(_, loc) => loc.clone(), - SExpr::Ident(_, loc) => loc.clone(), - SExpr::Quote(_, loc) => loc.clone(), - SExpr::Annot(_, loc) => loc.clone(), - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Fail)] -pub enum SExprParseError { - #[fail(display = "Lexical error at {:?}: {}", _1, _0)] - Lex(LexError, Location), - #[fail(display = "Unexpected ')' at {:?}", _0)] - UnexpectedCloseParen(Location), - #[fail(display = "Unexpected end of input in {:?}", _0)] - UnexpectedEof(PathBuf), -} - -pub struct SExprParser<'a> { - lex: Lexer<'a>, - lookahead: Option>, - location: Location, -} - -impl<'a> SExprParser<'a> { - pub fn new>(text: &'a str, path: P) -> SExprParser<'_> { - SExprParser { - lex: Lexer::new(text, path.as_ref()), - lookahead: None, - location: Location { - path: path.as_ref().into(), - line: 0, - column: 0, - }, - } - } - fn consume(&mut self) -> Token<'a> { - self.lookahead.take().expect("no token to consume") - } - fn token(&mut self) -> Result>, SExprParseError> { - while self.lookahead == None { - match self.lex.next() { - Some(Ok(LocatedToken { token, location })) => { - self.location = location; - self.lookahead = Some(token) - } - Some(Err(LocatedError { error, location })) => { - self.location = location.clone(); - Err(SExprParseError::Lex(error, location))?; - } - None => break, - } - } - Ok(self.lookahead) - } - - pub fn match_sexpr(&mut self) -> Result, SExprParseError> { - let location = self.location.clone(); - match self.token()? { - Some(Token::LPar) => { - self.consume(); - let mut members = Vec::new(); - loop { - match self.token()? { - Some(Token::RPar) => { - self.consume(); - break; - } - _ => { - members.push(self.match_sexpr()?); - } - } - } - Ok(SExpr::Vec(members, location)) - } - Some(Token::Word(word)) => { - self.consume(); - Ok(SExpr::Word(word, location)) - } - Some(Token::Ident(id)) => { - self.consume(); - Ok(SExpr::Ident(id, location)) - } - Some(Token::Annot(id)) => { - self.consume(); - Ok(SExpr::Annot(id, location)) - } - Some(Token::Quote(q)) => { - self.consume(); - Ok(SExpr::Quote(q, location)) - } - Some(Token::RPar) => Err(SExprParseError::UnexpectedCloseParen(location)), - None => Err(SExprParseError::UnexpectedEof(self.location.path.clone())), - } - } - - pub fn match_sexprs(&mut self) -> Result>, SExprParseError> { - let mut sexprs = Vec::new(); - while self.token()?.is_some() { - sexprs.push(self.match_sexpr()?); - } - Ok(sexprs) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::path::PathBuf; - - fn loc(line: usize, col: usize) -> Location { - Location { - path: PathBuf::from("/test"), - line: line, - column: col, - } - } - - fn testparser(input: &str) -> SExprParser { - SExprParser::new(input, Path::new("/test")) - } - - #[test] - fn empty() { - let mut parser = testparser(""); - assert_eq!(parser.match_sexprs().expect("valid parse"), Vec::new()); - let mut parser = testparser(" ;; just a comment\n;;another"); - assert_eq!(parser.match_sexprs().expect("valid parse"), Vec::new()); - } - - #[test] - fn atoms() { - let mut parser = testparser("hello\n$world\n\"a quotation\""); - assert_eq!( - parser.match_sexprs().expect("valid parse"), - vec![ - SExpr::Word("hello", loc(1, 0)), - SExpr::Ident("world", loc(2, 0)), - SExpr::Quote("a quotation", loc(3, 0)), - ] - ); - } - - #[test] - fn lists() { - let mut parser = testparser("()"); - assert_eq!( - parser.match_sexprs().expect("valid parse"), - vec![SExpr::Vec(vec![], loc(1, 0))] - ); - - let mut parser = testparser("(hello\n$world\n\"a quotation\")"); - assert_eq!( - parser.match_sexprs().expect("valid parse"), - vec![SExpr::Vec( - vec![ - SExpr::Word("hello", loc(1, 1)), - SExpr::Ident("world", loc(2, 0)), - SExpr::Quote("a quotation", loc(3, 0)), - ], - loc(1, 0) - )] - ); - - let mut parser = testparser("((($deep)))"); - assert_eq!( - parser.match_sexprs().expect("valid parse"), - vec![SExpr::Vec( - vec![SExpr::Vec( - vec![SExpr::Vec(vec![SExpr::Ident("deep", loc(1, 3))], loc(1, 2))], - loc(1, 1) - )], - loc(1, 0) - )] - ); - } - - #[test] - fn errors() { - let mut parser = testparser("("); - assert_eq!( - parser.match_sexprs().err().expect("dies"), - SExprParseError::UnexpectedEof(PathBuf::from("/test")) - ); - let mut parser = testparser(")"); - assert_eq!( - parser.match_sexprs().err().expect("dies"), - SExprParseError::UnexpectedCloseParen(loc(1, 0)) - ); - let mut parser = testparser("())"); - assert_eq!( - parser.match_sexprs().err().expect("dies"), - SExprParseError::UnexpectedCloseParen(loc(1, 2)) - ); - let mut parser = testparser("$ ;; should be a lex error"); - assert_eq!( - parser.match_sexprs().err().expect("dies"), - SExprParseError::Lex(LexError::EmptyIdentifier, loc(1, 0),), - ); - } -} diff --git a/lucet-idl/witx-frontend/src/toplevel.rs b/lucet-idl/witx-frontend/src/toplevel.rs deleted file mode 100644 index 5f3f7145b..000000000 --- a/lucet-idl/witx-frontend/src/toplevel.rs +++ /dev/null @@ -1,244 +0,0 @@ -use crate::parser::{DeclSyntax, ParseError, TopLevelSyntax}; -use crate::sexpr::SExprParser; -use crate::WitxError; -use std::collections::HashSet; -use std::fs; -use std::path::{Path, PathBuf}; - -trait WitxIo { - fn fgets(&self, path: &Path) -> Result; - fn canonicalize(&self, path: &Path) -> Result; -} - -struct Filesystem; - -impl WitxIo for Filesystem { - fn fgets(&self, path: &Path) -> Result { - fs::read_to_string(path).map_err(|e| WitxError::UseResolution(path.to_path_buf(), e)) - } - fn canonicalize(&self, path: &Path) -> Result { - path.canonicalize() - .map_err(|e| WitxError::UseResolution(path.to_path_buf(), e)) - } -} - -pub fn parse_witx>(i: P) -> Result, WitxError> { - parse_witx_with(i, &Filesystem) -} - -fn parse_witx_with>( - i: P, - witxio: &dyn WitxIo, -) -> Result, WitxError> { - let input_path = witxio.canonicalize(&i.as_ref())?; - - let input = witxio.fgets(&input_path)?; - - let toplevel = parse_toplevel(&input, &input_path)?; - let mut resolved = HashSet::new(); - resolved.insert(input_path.clone()); - let search_path = input_path.parent().unwrap_or(Path::new(".")); - resolve_uses(toplevel, &search_path, &mut resolved, witxio) -} - -fn parse_toplevel(source_text: &str, file_path: &Path) -> Result, WitxError> { - let mut sexpr_parser = SExprParser::new(source_text, file_path); - let sexprs = sexpr_parser.match_sexprs().map_err(WitxError::SExpr)?; - let top_levels = sexprs - .iter() - .map(|s| TopLevelSyntax::parse(s)) - .collect::, ParseError>>() - .map_err(WitxError::Parse)?; - Ok(top_levels) -} - -fn resolve_uses( - toplevel: Vec, - search_path: &Path, - used: &mut HashSet, - witxio: &dyn WitxIo, -) -> Result, WitxError> { - let mut decls = Vec::new(); - - for t in toplevel { - match t { - TopLevelSyntax::Decl(d) => decls.push(d), - TopLevelSyntax::Use(u) => { - let abs_path = witxio.canonicalize(&search_path.join(u.name))?; - // Include the decls from a use declaration only once - // in a given toplevel. Same idea as #pragma once. - if !used.contains(&abs_path) { - used.insert(abs_path.clone()); - - let source_text = witxio.fgets(&abs_path)?; - let inner_toplevels = parse_toplevel(&source_text, &abs_path)?; - - let inner_decls = resolve_uses(inner_toplevels, search_path, used, witxio)?; - decls.extend(inner_decls) - } - } - } - } - - Ok(decls) -} - -#[cfg(test)] -mod test { - use super::*; - use crate::witx::Location; - use std::collections::HashMap; - - struct MockFs { - map: HashMap<&'static str, &'static str>, - } - - impl MockFs { - pub fn new(strings: Vec<(&'static str, &'static str)>) -> Self { - MockFs { - map: strings.into_iter().collect(), - } - } - } - - impl WitxIo for MockFs { - fn fgets(&self, path: &Path) -> Result { - if let Some(entry) = self.map.get(path.to_str().unwrap()) { - Ok(entry.to_string()) - } else { - use std::io::{Error, ErrorKind}; - Err(WitxError::UseResolution( - path.to_path_buf(), - Error::new(ErrorKind::Other, "mock fs: file not found"), - )) - } - } - fn canonicalize(&self, path: &Path) -> Result { - Ok(PathBuf::from(path)) - } - } - - #[test] - fn empty() { - assert_eq!( - parse_witx_with(&Path::new("/a"), &MockFs::new(vec![("/a", ";; empty")])) - .expect("parse"), - Vec::new(), - ); - } - - #[test] - fn one_use() { - assert_eq!( - parse_witx_with( - &Path::new("/a"), - &MockFs::new(vec![("/a", "(use \"b\")"), ("/b", ";; empty")]) - ) - .expect("parse"), - Vec::new(), - ); - } - - #[test] - fn multi_use() { - use crate::witx::parser::*; - assert_eq!( - parse_witx_with( - &Path::new("/a"), - &MockFs::new(vec![ - ("/a", "(use \"b\")"), - ("/b", "(use \"c\")\n(typename $b_float f64)"), - ("/c", "(typename $c_int u32)") - ]) - ) - .expect("parse"), - vec![ - DeclSyntax::Typename(TypenameSyntax { - ident: IdentSyntax { - name: "c_int".to_owned(), - location: Location { - path: PathBuf::from("/c"), - line: 1, - column: 10, - } - }, - def: TypedefSyntax::Ident(DatatypeIdentSyntax::Builtin(BuiltinType::U32)) - }), - DeclSyntax::Typename(TypenameSyntax { - ident: IdentSyntax { - name: "b_float".to_owned(), - location: Location { - path: PathBuf::from("/b"), - line: 2, - column: 10, - } - }, - def: TypedefSyntax::Ident(DatatypeIdentSyntax::Builtin(BuiltinType::F64)) - }) - ], - ); - } - - #[test] - fn diamond_dependency() { - use crate::witx::parser::*; - assert_eq!( - parse_witx_with( - &Path::new("/a"), - &MockFs::new(vec![ - ("/a", "(use \"b\")\n(use \"c\")"), - ("/b", "(use \"d\")"), - ("/c", "(use \"d\")"), - ("/d", "(typename $d_char u8)") - ]) - ) - .expect("parse"), - vec![DeclSyntax::Typename(TypenameSyntax { - ident: IdentSyntax { - name: "d_char".to_owned(), - location: Location { - path: PathBuf::from("/d"), - line: 1, - column: 10, - } - }, - def: TypedefSyntax::Ident(DatatypeIdentSyntax::Builtin(BuiltinType::U8)) - })], - ); - } - - #[test] - fn use_not_found() { - match parse_witx_with(&Path::new("/a"), &MockFs::new(vec![("/a", "(use \"b\")")])) - .err() - .unwrap() - { - WitxError::UseResolution(path, _error) => assert_eq!(path, PathBuf::from("/b")), - e => panic!("wrong error: {:?}", e), - } - } - - #[test] - fn use_invalid() { - match parse_witx_with( - &Path::new("/a"), - &MockFs::new(vec![("/a", "(use bbbbbbb)")]), - ) - .err() - .unwrap() - { - WitxError::Parse(e) => { - assert_eq!(e.message, "invalid use declaration"); - assert_eq!( - e.location, - Location { - path: PathBuf::from("/a"), - line: 1, - column: 1 - } - ); - } - e => panic!("wrong error: {:?}", e), - } - } -} diff --git a/lucet-idl/witx-frontend/src/validate.rs b/lucet-idl/witx-frontend/src/validate.rs deleted file mode 100644 index c2f0f6270..000000000 --- a/lucet-idl/witx-frontend/src/validate.rs +++ /dev/null @@ -1,362 +0,0 @@ -use crate::{ - parser::{ - DatatypeIdentSyntax, DeclSyntax, EnumSyntax, FlagsSyntax, IdentSyntax, ImportTypeSyntax, - ModuleDeclSyntax, StructSyntax, TypedefSyntax, UnionSyntax, - }, - AliasDatatype, BuiltinType, Datatype, DatatypeIdent, DatatypeVariant, Definition, Document, - Entry, EnumDatatype, FlagsDatatype, Id, IntRepr, InterfaceFunc, InterfaceFuncParam, Location, - Module, ModuleDefinition, ModuleEntry, ModuleImport, ModuleImportVariant, StructDatatype, - StructMember, UnionDatatype, UnionVariant, -}; -use failure::Fail; -use std::collections::HashMap; -use std::rc::Rc; - -#[derive(Debug, Fail)] -pub enum ValidationError { - #[fail(display = "Unknown name `{}`", name)] - UnknownName { name: String, location: Location }, - #[fail(display = "Redefinition of name `{}`", name)] - NameAlreadyExists { - name: String, - at_location: Location, - previous_location: Location, - }, - #[fail( - display = "Wrong kind of name `{}`: expected {}, got {}", - name, expected, got - )] - WrongKindName { - name: String, - location: Location, - expected: &'static str, - got: &'static str, - }, - #[fail(display = "Recursive definition of name `{}`", name)] - Recursive { name: String, location: Location }, - #[fail(display = "Invalid representation `{:?}`", repr)] - InvalidRepr { - repr: BuiltinType, - location: Location, - }, -} - -pub fn validate_document(decls: &[DeclSyntax]) -> Result { - let mut validator = DocValidation::new(); - let mut definitions = Vec::new(); - for d in decls { - definitions.push(validator.validate_decl(&d)?); - } - - Ok(Document { - entries: validator.entries, - definitions, - }) -} - -struct IdentValidation { - names: HashMap, -} - -impl IdentValidation { - fn new() -> Self { - Self { - names: HashMap::new(), - } - } - fn introduce(&mut self, syntax: &IdentSyntax) -> Result { - if let Some(introduced) = self.names.get(&syntax.name) { - Err(ValidationError::NameAlreadyExists { - name: syntax.name.clone(), - at_location: syntax.location.clone(), - previous_location: introduced.clone(), - }) - } else { - self.names - .insert(syntax.name.clone(), syntax.location.clone()); - Ok(Id::new(&syntax.name)) - } - } - - fn get(&self, syntax: &IdentSyntax) -> Result { - if self.names.get(&syntax.name).is_some() { - Ok(Id::new(&syntax.name)) - } else { - Err(ValidationError::UnknownName { - name: syntax.name.clone(), - location: syntax.location.clone(), - }) - } - } -} - -struct DocValidation { - scope: IdentValidation, - pub entries: HashMap, -} - -impl DocValidation { - fn new() -> Self { - Self { - scope: IdentValidation::new(), - entries: HashMap::new(), - } - } - - fn validate_decl(&mut self, decl: &DeclSyntax) -> Result { - match decl { - DeclSyntax::Typename(decl) => { - let name = self.scope.introduce(&decl.ident)?; - let variant = - match &decl.def { - TypedefSyntax::Ident(syntax) => DatatypeVariant::Alias(AliasDatatype { - name: name.clone(), - to: self.validate_datatype_ident(&syntax)?, - }), - TypedefSyntax::Enum(syntax) => DatatypeVariant::Enum(self.validate_enum( - &name, - &syntax, - &decl.ident.location, - )?), - TypedefSyntax::Flags(syntax) => DatatypeVariant::Flags( - self.validate_flags(&name, &syntax, &decl.ident.location)?, - ), - TypedefSyntax::Struct(syntax) => DatatypeVariant::Struct( - self.validate_struct(&name, &syntax, &decl.ident.location)?, - ), - TypedefSyntax::Union(syntax) => DatatypeVariant::Union( - self.validate_union(&name, &syntax, &decl.ident.location)?, - ), - }; - let rc_datatype = Rc::new(Datatype { - name: name.clone(), - variant, - }); - self.entries - .insert(name, Entry::Datatype(Rc::downgrade(&rc_datatype))); - Ok(Definition::Datatype(rc_datatype)) - } - DeclSyntax::Module(syntax) => { - let name = self.scope.introduce(&syntax.name)?; - let mut module_validator = ModuleValidation::new(self); - let definitions = syntax - .decls - .iter() - .map(|d| module_validator.validate_decl(&d)) - .collect::, _>>()?; - - let rc_module = Rc::new(Module { - name: name.clone(), - definitions, - entries: module_validator.entries, - }); - self.entries - .insert(name, Entry::Module(Rc::downgrade(&rc_module))); - Ok(Definition::Module(rc_module)) - } - } - } - - fn validate_datatype_ident( - &self, - syntax: &DatatypeIdentSyntax, - ) -> Result { - match syntax { - DatatypeIdentSyntax::Builtin(b) => Ok(DatatypeIdent::Builtin(*b)), - DatatypeIdentSyntax::Array(a) => Ok(DatatypeIdent::Array(Box::new( - self.validate_datatype_ident(&a)?, - ))), - DatatypeIdentSyntax::Ident(i) => { - let id = self.scope.get(i)?; - match self.entries.get(&id) { - Some(Entry::Datatype(weak_d)) => Ok(DatatypeIdent::Ident( - weak_d.upgrade().expect("weak backref to defined type"), - )), - Some(e) => Err(ValidationError::WrongKindName { - name: i.name.clone(), - location: i.location.clone(), - expected: "datatype", - got: e.kind(), - }), - None => Err(ValidationError::Recursive { - name: i.name.clone(), - location: i.location.clone(), - }), - } - } - } - } - - fn validate_enum( - &self, - name: &Id, - syntax: &EnumSyntax, - location: &Location, - ) -> Result { - let mut enum_scope = IdentValidation::new(); - let repr = validate_int_repr(&syntax.repr, location)?; - let variants = syntax - .members - .iter() - .map(|i| enum_scope.introduce(i)) - .collect::, _>>()?; - - Ok(EnumDatatype { - name: name.clone(), - repr, - variants, - }) - } - - fn validate_flags( - &self, - name: &Id, - syntax: &FlagsSyntax, - location: &Location, - ) -> Result { - let mut flags_scope = IdentValidation::new(); - let repr = validate_int_repr(&syntax.repr, location)?; - let flags = syntax - .flags - .iter() - .map(|i| flags_scope.introduce(i)) - .collect::, _>>()?; - - Ok(FlagsDatatype { - name: name.clone(), - repr, - flags, - }) - } - - fn validate_struct( - &self, - name: &Id, - syntax: &StructSyntax, - _location: &Location, - ) -> Result { - let mut member_scope = IdentValidation::new(); - let members = syntax - .fields - .iter() - .map(|f| { - Ok(StructMember { - name: member_scope.introduce(&f.name)?, - type_: self.validate_datatype_ident(&f.type_)?, - }) - }) - .collect::, _>>()?; - - Ok(StructDatatype { - name: name.clone(), - members, - }) - } - - fn validate_union( - &self, - name: &Id, - syntax: &UnionSyntax, - _location: &Location, - ) -> Result { - let mut variant_scope = IdentValidation::new(); - let variants = syntax - .fields - .iter() - .map(|f| { - Ok(UnionVariant { - name: variant_scope.introduce(&f.name)?, - type_: self.validate_datatype_ident(&f.type_)?, - }) - }) - .collect::, _>>()?; - - Ok(UnionDatatype { - name: name.clone(), - variants, - }) - } -} - -fn validate_int_repr(type_: &BuiltinType, location: &Location) -> Result { - match type_ { - BuiltinType::U8 => Ok(IntRepr::I8), - BuiltinType::U16 => Ok(IntRepr::I16), - BuiltinType::U32 => Ok(IntRepr::I32), - BuiltinType::U64 => Ok(IntRepr::I64), - _ => Err(ValidationError::InvalidRepr { - repr: type_.clone(), - location: location.clone(), - }), - } -} - -struct ModuleValidation<'a> { - doc: &'a DocValidation, - scope: IdentValidation, - pub entries: HashMap, -} - -impl<'a> ModuleValidation<'a> { - fn new(doc: &'a DocValidation) -> Self { - Self { - doc, - scope: IdentValidation::new(), - entries: HashMap::new(), - } - } - - fn validate_decl( - &mut self, - decl: &ModuleDeclSyntax, - ) -> Result { - match decl { - ModuleDeclSyntax::Import(syntax) => { - let name = self.scope.introduce(&syntax.name)?; - let variant = match syntax.type_ { - ImportTypeSyntax::Memory => ModuleImportVariant::Memory, - }; - let rc_import = Rc::new(ModuleImport { - name: name.clone(), - variant, - }); - self.entries - .insert(name, ModuleEntry::Import(Rc::downgrade(&rc_import))); - Ok(ModuleDefinition::Import(rc_import)) - } - ModuleDeclSyntax::Func(syntax) => { - let name = self.scope.introduce(&syntax.export)?; - let mut argnames = IdentValidation::new(); - let params = syntax - .params - .iter() - .map(|f| { - Ok(InterfaceFuncParam { - name: argnames.introduce(&f.name)?, - type_: self.doc.validate_datatype_ident(&f.type_)?, - }) - }) - .collect::, _>>()?; - let results = syntax - .results - .iter() - .map(|f| { - Ok(InterfaceFuncParam { - name: argnames.introduce(&f.name)?, - type_: self.doc.validate_datatype_ident(&f.type_)?, - }) - }) - .collect::, _>>()?; - - let rc_func = Rc::new(InterfaceFunc { - name: name.clone(), - params, - results, - }); - self.entries - .insert(name, ModuleEntry::Func(Rc::downgrade(&rc_func))); - Ok(ModuleDefinition::Func(rc_func)) - } - } - } -} From bfd88834baafe66fe04f14dbd2dbac5f53b53789 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 2 Oct 2019 12:24:17 -0700 Subject: [PATCH 411/512] upgrade to witx 0.3.0 --- Cargo.lock | 14 +++----------- Cargo.toml | 1 - lucet-validate/Cargo.toml | 2 +- lucetc/Cargo.toml | 2 +- wasi | 2 +- 5 files changed, 6 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2544d8db1..54b1e8dbd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -949,7 +949,7 @@ dependencies = [ "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", - "witx 0.2.0", + "witx 0.3.0", ] [[package]] @@ -1037,7 +1037,7 @@ dependencies = [ "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "wasmonkey 0.1.8", "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", - "witx 0.2.0", + "witx 0.3.0", ] [[package]] @@ -2025,15 +2025,7 @@ dependencies = [ [[package]] name = "witx" -version = "0.2.0" -dependencies = [ - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "witx-frontend" -version = "0.1.0" +version = "0.3.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index d15abe273..37f16cf48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,6 @@ members = [ "lucet-analyze", "lucet-idl", - "lucet-idl/witx-frontend", "lucet-idl/lucet-idl-test", "lucet-idl/lucet-idl-test/resources/rust_host", "lucet-module", diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index 589b7ca61..9dcded04a 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -19,7 +19,7 @@ path = "src/main.rs" [dependencies] clap = "2" failure = "0.1" -witx = { path = "../wasi/tools/witx", version = "0.2.0" } +witx = { path = "../wasi/tools/witx", version = "0.3.0" } cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.44.0" } wasmparser = "0.39.1" diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index d0ccb7844..f3ea70792 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -28,7 +28,7 @@ cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.44.0" } target-lexicon = "0.8.0" lucet-module = { path = "../lucet-module", version = "0.1.1" } lucet-validate = { path = "../lucet-validate", version = "0.1.1" } -witx = { path = "../wasi/tools/witx", version = "0.2.0" } +witx = { path = "../wasi/tools/witx", version = "0.3.0" } wasmparser = "0.39.1" clap="2.32" log = "0.4" diff --git a/wasi b/wasi index b0a753c97..a50853b96 160000 --- a/wasi +++ b/wasi @@ -1 +1 @@ -Subproject commit b0a753c97c4e4e15cbfc11e553d899761d895690 +Subproject commit a50853b962ce7e1386b29e79a6f8884978f16834 From 75b83e9550e70e03df692d6df80f68c8d452440a Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 2 Oct 2019 12:46:29 -0700 Subject: [PATCH 412/512] delete lucet-validate's wasi-sdk test: that testis now inside lucet-wasi-sdk --- lucet-validate/tests/wasisdk.rs | 50 --------------------------------- 1 file changed, 50 deletions(-) delete mode 100644 lucet-validate/tests/wasisdk.rs diff --git a/lucet-validate/tests/wasisdk.rs b/lucet-validate/tests/wasisdk.rs deleted file mode 100644 index c2faf7c62..000000000 --- a/lucet-validate/tests/wasisdk.rs +++ /dev/null @@ -1,50 +0,0 @@ -#[cfg(test)] -mod wasi_sdk_tests { - use lucet_validate::{self, ModuleType}; - use std::path::PathBuf; - use witx; - - fn wasi_sdk_test_source_file(name: &str) -> PathBuf { - let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - p.push(".."); - p.push("lucet-wasi-sdk"); - p.push("tests"); - p.push(name); - assert!(p.exists(), "test file does not exist"); - p - } - - fn compile_to_wasm(filename: &str) -> Vec { - use lucet_wasi_sdk::Link; - use std::fs::File; - use std::io::Read; - use tempfile::TempDir; - - let tmp = TempDir::new().expect("create temporary directory"); - - let wasmfile = tmp.path().join("out.wasm"); - let linker = Link::new(&[wasi_sdk_test_source_file(filename)]); - linker.link(wasmfile.clone()).expect("link out.wasm"); - - let mut module_contents = Vec::new(); - let mut file = File::open(wasmfile).expect("open out.wasm"); - file.read_to_end(&mut module_contents) - .expect("read out.wasm"); - - module_contents - } - - #[test] - fn moduletype_of_compiled() { - let main_wasm = compile_to_wasm("main_returns.c"); - let _moduletype = ModuleType::parse_wasm(&main_wasm).expect("main_returns has module type"); - } - - #[test] - fn validate_compiled() { - let main_wasm = compile_to_wasm("main_returns.c"); - let wasi_spec = witx::load("../wasi/phases/unstable/witx/wasi_unstable_preview0.witx") - .expect("load wasi_unstable_preview0"); - lucet_validate::validate(&wasi_spec, &main_wasm, true).expect("validation"); - } -} From a0f51f3ca3f0d69fce2d3cb8e77482dafe824ccf Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 2 Oct 2019 12:48:19 -0700 Subject: [PATCH 413/512] lucet-validate: test harness uses new api --- lucet-validate/tests/wasitests.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lucet-validate/tests/wasitests.rs b/lucet-validate/tests/wasitests.rs index 51a2bddb3..587395b3f 100644 --- a/lucet-validate/tests/wasitests.rs +++ b/lucet-validate/tests/wasitests.rs @@ -1,10 +1,9 @@ #[cfg(test)] mod lucet_wasi_tests { - use lucet_validate; + use lucet_validate::Validator; use std::fs; use std::path::Path; use wabt; - use witx; fn c_to_wasm(c_path: &Path) -> Vec { use lucet_wasi_sdk::Link; @@ -38,7 +37,7 @@ mod lucet_wasi_tests { #[test] fn validate_lucet_wasi_test_guests() { - let wasi_spec = witx::load("../wasi/phases/unstable/witx/wasi_unstable_preview0.witx") + let validator = Validator::load("../wasi/phases/unstable/witx/wasi_unstable_preview0.witx") .expect("load wasi_unstable_preview0"); for entry in @@ -53,7 +52,8 @@ mod lucet_wasi_tests { Some("wat") => wat_to_wasm(&entry_path), _ => panic!("unsupported extension: {:?}", entry_path), }; - lucet_validate::validate(&wasi_spec, &entry_wasm, true) + validator + .validate(&entry_wasm) .expect(&format!("validate {:?}", entry_path)); } } From 5e2b60122ee7e16b6b656e4da44ae38186da1f6d Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Thu, 3 Oct 2019 13:43:03 -0700 Subject: [PATCH 414/512] Make WASI `poll` test more deterministic, but disable pending debugging (#320) - Removes a sleep that wasn't relevant for testing poll - Timeout step waits on an in-process pipe rather than stdin, which should make its behavior more consistent across environments - Temporarily ignores the test while we debug its behavior in certain CI environments --- lucet-wasi/tests/guests/poll.c | 6 +----- lucet-wasi/tests/test_helpers/mod.rs | 15 +++++++++++++++ lucet-wasi/tests/tests.rs | 9 ++++++--- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/lucet-wasi/tests/guests/poll.c b/lucet-wasi/tests/guests/poll.c index d8f9a8c1d..bec0688e8 100644 --- a/lucet-wasi/tests/guests/poll.c +++ b/lucet-wasi/tests/guests/poll.c @@ -22,11 +22,7 @@ int main(void) ret = poll(fds, 1, 2000); time(&now); assert(ret == 0); - assert(now - before >= 2); - - sleep(1); - time(&now); - assert(now - before >= 3); + assert(now - before >= 1); return 0; } diff --git a/lucet-wasi/tests/test_helpers/mod.rs b/lucet-wasi/tests/test_helpers/mod.rs index 455928a92..5793ad4dc 100644 --- a/lucet-wasi/tests/test_helpers/mod.rs +++ b/lucet-wasi/tests/test_helpers/mod.rs @@ -116,6 +116,21 @@ pub fn run_with_stdout>( Ok((exitcode, stdout)) } +pub fn run_with_null_stdin>( + path: P, + ctx: WasiCtxBuilder, +) -> Result<__wasi_exitcode_t, Error> { + let (pipe_out, pipe_in) = nix::unistd::pipe()?; + + let ctx = unsafe { ctx.raw_fd(0, pipe_out) }.build()?; + + let exitcode = run(path, ctx)?; + + nix::unistd::close(pipe_in)?; + + Ok(exitcode) +} + /// Call this if you're having trouble with `__wasi_*` symbols not being exported. /// /// This is pretty hackish; we will hopefully be able to avoid this altogether once [this diff --git a/lucet-wasi/tests/tests.rs b/lucet-wasi/tests/tests.rs index 18cdf386d..fbde24b5d 100644 --- a/lucet-wasi/tests/tests.rs +++ b/lucet-wasi/tests/tests.rs @@ -1,6 +1,6 @@ mod test_helpers; -use crate::test_helpers::{run, run_with_stdout, LUCET_WASI_ROOT}; +use crate::test_helpers::{run, run_with_null_stdin, run_with_stdout, LUCET_WASI_ROOT}; use lucet_wasi::{WasiCtx, WasiCtxBuilder}; use std::fs::File; use std::path::Path; @@ -367,10 +367,13 @@ fn pseudoquine() { assert_eq!(stdout, expected); } +// ACF 2019-10-03: temporarily disabled until we figure out why it's behaving differently only in +// one CI environment +#[ignore] #[test] fn poll() { - let ctx = WasiCtxBuilder::new().args(&["poll"]).build().unwrap(); - let exitcode = run("poll.c", ctx).unwrap(); + let ctx = WasiCtxBuilder::new().args(&["poll"]); + let exitcode = run_with_null_stdin("poll.c", ctx).unwrap(); assert_eq!(exitcode, 0); } From 90ee1d39389ea123af92d2084ca8a8690b20d72f Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 3 Oct 2019 15:39:43 -0700 Subject: [PATCH 415/512] address review comments --- Cargo.lock | 1 - lucet-validate/src/main.rs | 6 +++++- lucet-wasi-sdk/tests/lucetc.rs | 8 ++++++-- lucetc/Cargo.toml | 1 - lucetc/src/compiler.rs | 2 +- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 54b1e8dbd..e1212e964 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1037,7 +1037,6 @@ dependencies = [ "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "wasmonkey 0.1.8", "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", - "witx 0.3.0", ] [[package]] diff --git a/lucet-validate/src/main.rs b/lucet-validate/src/main.rs index 6dadb3dce..9f14a05c1 100644 --- a/lucet-validate/src/main.rs +++ b/lucet-validate/src/main.rs @@ -52,7 +52,11 @@ pub fn main() { Path::new(matches.value_of("witx").expect("witx path required")), matches.is_present("wasi-exe"), ) { - Ok(()) => {} + Ok(()) => { + if matches.is_present("verbose") { + println!("validated successfully") + } + } Err(e) => { if matches.is_present("verbose") { match e { diff --git a/lucet-wasi-sdk/tests/lucetc.rs b/lucet-wasi-sdk/tests/lucetc.rs index 6df32e49e..5918e320e 100644 --- a/lucet-wasi-sdk/tests/lucetc.rs +++ b/lucet-wasi-sdk/tests/lucetc.rs @@ -10,6 +10,9 @@ mod lucetc_tests { use std::io::Read; use std::path::PathBuf; + /// Compile C -> WebAssembly using wasi-sdk's clang. Does not use the wasi-sdk + /// libc, and does not produce a wasi executable, just a wasm module with the given set of + /// export functions. fn module_from_c(cfiles: &[&str], exports: &[&str]) -> Result, Error> { let cfiles: Vec = cfiles .iter() @@ -132,8 +135,8 @@ mod lucetc_tests { #[test] fn hello() { let m = { - // This is like module_from_c, except missing the bits that have it leave out the wasi - // stdlib and tentry points: + // Unlike in module_from_c, use wasi-sdk to compile a C file to a wasi executable, + // linking in wasi-libc and exposing the wasi _start entry point only: let tempdir = tempfile::Builder::new() .prefix("wasi-sdk-test") .tempdir() @@ -158,6 +161,7 @@ mod lucetc_tests { let v = Validator::load("../wasi/phases/unstable/witx/wasi_unstable_preview0.witx") .expect("wasi spec validation") .with_wasi_exe(true); + // Compiler will only unwrap if the Validator defined above accepts the module let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile empty"); let mdata = c.module_data().unwrap(); diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index f3ea70792..da28f4dba 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -28,7 +28,6 @@ cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.44.0" } target-lexicon = "0.8.0" lucet-module = { path = "../lucet-module", version = "0.1.1" } lucet-validate = { path = "../lucet-validate", version = "0.1.1" } -witx = { path = "../wasi/tools/witx", version = "0.3.0" } wasmparser = "0.39.1" clap="2.32" log = "0.4" diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index fe4155f34..6aacc6e54 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -70,7 +70,7 @@ impl<'a> Compiler<'a> { v.validate(wasm_binary) .context(LucetcErrorKind::Validation)?; } else { - // As of cranelift-wasm 0.43 which uses wasmparser 0.40, the parser used inside + // As of cranelift-wasm 0.43 which uses wasmparser 0.39.1, the parser used inside // cranelift-wasm does not validate. We need to run the validating parser on the binary // first. The InvalidWebAssembly error below will never trigger. wasmparser::validate(wasm_binary, None) From 263c8980f5489efeaeb1d290d0d6348f1d04547c Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 3 Oct 2019 17:17:30 -0700 Subject: [PATCH 416/512] lucet-validate: add readme --- lucet-validate/README.md | 50 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 lucet-validate/README.md diff --git a/lucet-validate/README.md b/lucet-validate/README.md new file mode 100644 index 000000000..42b260ca2 --- /dev/null +++ b/lucet-validate/README.md @@ -0,0 +1,50 @@ +# lucet-validate + +Validates a WebAssembly module against a witx spec. + +## What is witx? + +* Witx is a specification languaged developed as part of the + [WASI](https://github.com/WebAssembly/WASI) effort. The `witx` crate lives in + that repository, as well as `.witx` files that describe the WASI standard. + +* A Witx specification is parsed and validated from `.witx` files by the `witx` + crate. The set of types and modules defined by these files is called a Witx document. + +* A Witx specification contains modules, and modules contain interface functions. + These are functions defined in terms of parameters (inputs) and results + (outputs), all of which can have complex types like pointers, arrays, strings, + structs etc. + +* Each interface function has a method to calculate its type signature in terms + of the "core" WebAssembly types (i32, i64, f32, f64 used in WebAssembly 1.0 + function types). This calculation takes into account that some complex types + are passed as pointers into linear memory, or a pointer-length pair, while + others (smaller ints like u8 or s16) can be represented by atomic values + (i32, in this example). + + +## What is validated? + +* The WebAssembly module itself is validated to be WebAssembly 1.0. We don't + support validating extensions to the spec yet but ought to be able to without + any issues. + +* Each import of the WebAssembly module is validated to be present, and have + the expected core type signature, given by the Witx document. + +* If the Validator is set to validate an `wasi-exe`, it additionally checks + that the module exports a function named `_start` with the type signature `[] + -> ()`. (This is not to be confused with having a `start` section, which is a + different concept from the WASI executable entrypoint `_start`.) + + +## What is not? + +* The WebAssembly module does not contain enough information to determine that + the core types found in the type signature are used by the WebAssembly + program in a way that matches the complex types (strings arrays structs etc) + in the witx document. This property could only be validated in the source + language before it is compiled to WebAssembly. + + From 30fe754ed3918506cee3f734509410076277e444 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Fri, 4 Oct 2019 14:57:08 -0700 Subject: [PATCH 417/512] [lucet-validate] ignore non-c/wat files rather than failing test Ephemeral files left around by editors were causing a panic. --- lucet-validate/tests/wasitests.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lucet-validate/tests/wasitests.rs b/lucet-validate/tests/wasitests.rs index 587395b3f..95ac9c0ac 100644 --- a/lucet-validate/tests/wasitests.rs +++ b/lucet-validate/tests/wasitests.rs @@ -50,7 +50,10 @@ mod lucet_wasi_tests { { Some("c") => c_to_wasm(&entry_path), Some("wat") => wat_to_wasm(&entry_path), - _ => panic!("unsupported extension: {:?}", entry_path), + _ => { + eprintln!("unsupported extension: {:?}", entry_path); + continue; + } }; validator .validate(&entry_wasm) From e0922fea145f81d5b311a1be6346836c25aae37f Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 8 Oct 2019 10:38:40 -0700 Subject: [PATCH 418/512] package lucet-validate, including wasi unstable witx --- lucet-validate/Cargo.toml | 16 ++- lucet-validate/LICENSE | 219 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 lucet-validate/LICENSE diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index 9dcded04a..95fb2a17d 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -23,8 +23,22 @@ witx = { path = "../wasi/tools/witx", version = "0.3.0" } cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.44.0" } wasmparser = "0.39.1" - [dev-dependencies] lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.1.1" } tempfile = "3.0" wabt = "0.7" + +[package.metadata.deb] +name = "fst-lucet-validate" +maintainer = "Lucet team " +depends = "$auto" +priority = "optional" +assets = [ + ["target/release/lucet-validate", "/opt/fst-lucet-validate/bin/lucet-validate", "755"], + ["target/release/liblucet_validate.rlib", "/opt/fst-lucet-validate/lib/", "644"], + ["LICENSE", "/opt/fst-lucet-validate/share/doc/lucet-validate/", "644"], + ["../wasi/phases/unstable/witx/typenames.witx", + "/opt/fst-lucet-validate/share/wasi/unstable/typenames.witx", "644"], + ["../wasi/phases/unstable/witx/wasi_unstable_preview0.witx", + "/opt/fst-lucet-validate/share/wasi/unstable/wasi_unstable_preview0.witx", "644"], +] diff --git a/lucet-validate/LICENSE b/lucet-validate/LICENSE new file mode 100644 index 000000000..be1d7c438 --- /dev/null +++ b/lucet-validate/LICENSE @@ -0,0 +1,219 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. From 4da92924f16def1c0694662cafa7614dae92a110 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 8 Oct 2019 13:32:49 -0700 Subject: [PATCH 419/512] rename `lucet-analyze->lucet-objdump`; add debs for it and `lucetc` --- Cargo.lock | 20 ++++++++++---------- Cargo.toml | 4 ++-- helpers/install.sh | 2 +- {lucet-analyze => lucet-objdump}/.gitignore | 0 {lucet-analyze => lucet-objdump}/Cargo.toml | 12 +++++++++++- {lucet-analyze => lucet-objdump}/LICENSE | 0 {lucet-analyze => lucet-objdump}/src/main.rs | 4 ++-- lucetc/Cargo.toml | 15 +++++++++++++++ 8 files changed, 41 insertions(+), 16 deletions(-) rename {lucet-analyze => lucet-objdump}/.gitignore (100%) rename {lucet-analyze => lucet-objdump}/Cargo.toml (56%) rename {lucet-analyze => lucet-objdump}/LICENSE (100%) rename {lucet-analyze => lucet-objdump}/src/main.rs (98%) diff --git a/Cargo.lock b/Cargo.lock index 61d6a6bc8..3900214c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -758,16 +758,6 @@ dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "lucet-analyze" -version = "0.1.1" -dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.1.1", -] - [[package]] name = "lucet-benchmarks" version = "0.1.1" @@ -847,6 +837,16 @@ dependencies = [ "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lucet-objdump" +version = "0.1.1" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", + "lucet-module 0.1.1", +] + [[package]] name = "lucet-runtime" version = "0.1.1" diff --git a/Cargo.toml b/Cargo.toml index 37f16cf48..77b153281 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,11 +2,12 @@ [workspace] members = [ - "lucet-analyze", + "benchmarks/lucet-benchmarks", "lucet-idl", "lucet-idl/lucet-idl-test", "lucet-idl/lucet-idl-test/resources/rust_host", "lucet-module", + "lucet-objdump", "lucet-runtime", "lucet-runtime/lucet-runtime-internals", "lucet-runtime/lucet-runtime-tests", @@ -17,7 +18,6 @@ members = [ "lucet-wasi-sdk", "lucetc", "sightglass", - "benchmarks/lucet-benchmarks", ] exclude = ["cranelift"] diff --git a/helpers/install.sh b/helpers/install.sh index 9fc6ca840..49fb22e3d 100755 --- a/helpers/install.sh +++ b/helpers/install.sh @@ -38,7 +38,7 @@ else DYLIB_SUFFIX="so" fi -BINS="lucet-analyze lucet-wasi lucetc sightglass spec-test wasmonkey" +BINS="lucet-objdump lucet-validate lucet-wasi lucetc sightglass spec-test wasmonkey" LIBS="liblucet_runtime.${DYLIB_SUFFIX}" DOCS="lucet-wasi/README.md sightglass/README.md" BUNDLE_DOCS="README.md" diff --git a/lucet-analyze/.gitignore b/lucet-objdump/.gitignore similarity index 100% rename from lucet-analyze/.gitignore rename to lucet-objdump/.gitignore diff --git a/lucet-analyze/Cargo.toml b/lucet-objdump/Cargo.toml similarity index 56% rename from lucet-analyze/Cargo.toml rename to lucet-objdump/Cargo.toml index cf0886f07..a5fe151ec 100644 --- a/lucet-analyze/Cargo.toml +++ b/lucet-objdump/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "lucet-analyze" +name = "lucet-objdump" version = "0.1.1" description = "Analyze object files emitted by the Lucet compiler" homepage = "https://github.com/fastly/lucet" @@ -14,3 +14,13 @@ goblin="0.0.24" byteorder="1.2.1" colored="1.6.1" lucet-module = { path = "../lucet-module", version = "0.1.1" } + +[package.metadata.deb] +name = "fst-lucet-objdump" +maintainer = "Lucet team " +depends = "$auto" +priority = "optional" +assets = [ + ["target/release/lucet-objdump", "/opt/fst-lucet-objdump/bin/lucet-objdump", "755"], + ["LICENSE", "/opt/fst-lucet-objdump/share/doc/lucet-objdump/", "644"], +] diff --git a/lucet-analyze/LICENSE b/lucet-objdump/LICENSE similarity index 100% rename from lucet-analyze/LICENSE rename to lucet-objdump/LICENSE diff --git a/lucet-analyze/src/main.rs b/lucet-objdump/src/main.rs similarity index 98% rename from lucet-analyze/src/main.rs rename to lucet-objdump/src/main.rs index f1253e263..58350c136 100644 --- a/lucet-analyze/src/main.rs +++ b/lucet-objdump/src/main.rs @@ -153,7 +153,7 @@ fn main() { /// Parse a trap manifest for function `f`, if it has one. /// /// `parse_trap_manifest` may very understandably be confusing. Why not use `f.traps()`? In -/// `lucet-analyze` the module has been accessed by reading the file and following structures as +/// `lucet-objdump` the module has been accessed by reading the file and following structures as /// they exist at rest. This means pointers are not relocated, so slices that would be valid when /// loaded through the platform's loader currently have pointers that are not valid for memory /// access. @@ -523,7 +523,7 @@ fn print_summary(summary: ArtifactSummary<'_>) { println!("\nModule:"); summarize_module(&summary, &module); } else { - println!("The symbol `lucet_module` is {}, so lucet-analyze cannot look at most of the interesting parts.", "MISSING".red().bold()); + println!("The symbol `lucet_module` is {}, so lucet-objdump cannot look at most of the interesting parts.", "MISSING".red().bold()); } println!(""); diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index 0026baf6c..948facc89 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -44,3 +44,18 @@ human-size = "0.4" parity-wasm = "0.38" minisign = "0.5.11" memoffset = "0.5.1" + +[package.metadata.deb] +name = "fst-lucetc" +maintainer = "Lucet team " +depends = "$auto" +priority = "optional" +assets = [ + ["target/release/lucetc", "/opt/fst-lucetc/bin/lucetc", "755"], + ["target/release/liblucetc.rlib", "/opt/fst-lucetc/lib/", "644"], + ["LICENSE", "/opt/fst-lucetc/share/doc/lucetc/", "644"], + ["../wasi/phases/unstable/witx/typenames.witx", + "/opt/fst-lucetc/share/wasi/unstable/typenames.witx", "644"], + ["../wasi/phases/unstable/witx/wasi_unstable_preview0.witx", + "/opt/fst-lucetc/share/wasi/unstable/wasi_unstable_preview0.witx", "644"], +] From 79bd885f4fe1b22e2771554ffb450f57c55270f7 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Thu, 10 Oct 2019 12:49:00 -0700 Subject: [PATCH 420/512] skip Lucet build in the container step on travis --- .travis.yml | 2 +- devenv_build_container.sh | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b0f4e6f2c..bb34f0496 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ dist: xenial rust: 1.36.0 env: - - UNOPTIMIZED_BUILD=true + - UNOPTIMIZED_BUILD=true DEVENV_SKIP_LUCET_BUILD=true services: - docker diff --git a/devenv_build_container.sh b/devenv_build_container.sh index 4c8d51bfa..9bd8fec05 100755 --- a/devenv_build_container.sh +++ b/devenv_build_container.sh @@ -19,6 +19,11 @@ docker build -t lucet-dev:latest . docker tag lucet-dev:latest lucet:latest +if [ ! -z "$DEVENV_SKIP_LUCET_BUILD" ]; then + echo "Done" + exit 0 +fi + if docker image inspect lucet:latest > /dev/null; then if [ -z "$DEVENV_FORCE_REBUILD" ]; then echo "A lucet image is already present" From e85695c8af1da2d43d78ce693ae2e6596aef9976 Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Wed, 9 Oct 2019 13:25:33 -0700 Subject: [PATCH 421/512] 0.2.0 --- Cargo.lock | 118 +++++++++--------- Cargo.toml | 2 +- benchmarks/lucet-benchmarks/Cargo.toml | 2 +- lucet-idl/Cargo.toml | 2 +- lucet-module/Cargo.toml | 2 +- lucet-objdump/Cargo.toml | 4 +- lucet-runtime/Cargo.toml | 8 +- .../lucet-runtime-internals/Cargo.toml | 4 +- lucet-runtime/lucet-runtime-tests/Cargo.toml | 10 +- lucet-spectest/Cargo.toml | 8 +- lucet-validate/Cargo.toml | 4 +- lucet-wasi-fuzz/Cargo.toml | 2 +- lucet-wasi-sdk/Cargo.toml | 8 +- lucet-wasi/Cargo.toml | 12 +- lucetc/Cargo.toml | 6 +- 15 files changed, 96 insertions(+), 96 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3900214c5..a4858ca29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -760,15 +760,15 @@ dependencies = [ [[package]] name = "lucet-benchmarks" -version = "0.1.1" +version = "0.2.0" dependencies = [ "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.1.1", - "lucet-runtime 0.1.1", - "lucet-runtime-internals 0.1.1", - "lucet-wasi 0.1.1", - "lucet-wasi-sdk 0.1.1", - "lucetc 0.1.1", + "lucet-module 0.2.0", + "lucet-runtime 0.2.0", + "lucet-runtime-internals 0.2.0", + "lucet-wasi 0.2.0", + "lucet-wasi-sdk 0.2.0", + "lucetc 0.2.0", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -777,14 +777,14 @@ dependencies = [ [[package]] name = "lucet-idl" -version = "0.1.1" +version = "0.2.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.44.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.1.1", - "lucetc 0.1.1", + "lucet-module 0.2.0", + "lucetc 0.2.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -799,11 +799,11 @@ dependencies = [ "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-idl 0.1.1", - "lucet-runtime 0.1.1", - "lucet-wasi 0.1.1", - "lucet-wasi-sdk 0.1.1", - "lucetc 0.1.1", + "lucet-idl 0.2.0", + "lucet-runtime 0.2.0", + "lucet-wasi 0.2.0", + "lucet-wasi-sdk 0.2.0", + "lucetc 0.2.0", "proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -815,14 +815,14 @@ dependencies = [ "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-idl 0.1.1", - "lucet-runtime 0.1.1", - "lucet-wasi 0.1.1", + "lucet-idl 0.2.0", + "lucet-runtime 0.2.0", + "lucet-wasi 0.2.0", ] [[package]] name = "lucet-module" -version = "0.1.1" +version = "0.2.0" dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -839,28 +839,28 @@ dependencies = [ [[package]] name = "lucet-objdump" -version = "0.1.1" +version = "0.2.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.1.1", + "lucet-module 0.2.0", ] [[package]] name = "lucet-runtime" -version = "0.1.1" +version = "0.2.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.1.1", - "lucet-runtime-internals 0.1.1", - "lucet-runtime-tests 0.1.1", - "lucet-wasi-sdk 0.1.1", - "lucetc 0.1.1", + "lucet-module 0.2.0", + "lucet-runtime-internals 0.2.0", + "lucet-runtime-tests 0.2.0", + "lucet-wasi-sdk 0.2.0", + "lucetc 0.2.0", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -870,7 +870,7 @@ dependencies = [ [[package]] name = "lucet-runtime-internals" -version = "0.1.1" +version = "0.2.0" dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -881,7 +881,7 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.1.1", + "lucet-module 0.2.0", "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -891,27 +891,27 @@ dependencies = [ [[package]] name = "lucet-runtime-tests" -version = "0.1.1" +version = "0.2.0" dependencies = [ "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.1.1", - "lucet-runtime-internals 0.1.1", - "lucet-wasi-sdk 0.1.1", - "lucetc 0.1.1", + "lucet-module 0.2.0", + "lucet-runtime-internals 0.2.0", + "lucet-wasi-sdk 0.2.0", + "lucetc 0.2.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucet-spectest" -version = "0.1.1" +version = "0.2.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.1.1", - "lucet-runtime 0.1.1", - "lucetc 0.1.1", + "lucet-module 0.2.0", + "lucet-runtime 0.2.0", + "lucetc 0.2.0", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -920,12 +920,12 @@ dependencies = [ [[package]] name = "lucet-validate" -version = "0.1.1" +version = "0.2.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.44.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-wasi-sdk 0.1.1", + "lucet-wasi-sdk 0.2.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -934,7 +934,7 @@ dependencies = [ [[package]] name = "lucet-wasi" -version = "0.1.1" +version = "0.2.0" dependencies = [ "bindgen 0.47.3 (registry+https://github.com/rust-lang/crates.io-index)", "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -942,11 +942,11 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.1.1", - "lucet-runtime 0.1.1", - "lucet-runtime-internals 0.1.1", - "lucet-wasi-sdk 0.1.1", - "lucetc 0.1.1", + "lucet-module 0.2.0", + "lucet-runtime 0.2.0", + "lucet-runtime-internals 0.2.0", + "lucet-wasi-sdk 0.2.0", + "lucetc 0.2.0", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -954,16 +954,16 @@ dependencies = [ [[package]] name = "lucet-wasi-fuzz" -version = "0.1.1" +version = "0.2.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.1.1", - "lucet-runtime 0.1.1", - "lucet-wasi 0.1.1", - "lucet-wasi-sdk 0.1.1", - "lucetc 0.1.1", + "lucet-module 0.2.0", + "lucet-runtime 0.2.0", + "lucet-wasi 0.2.0", + "lucet-wasi-sdk 0.2.0", + "lucetc 0.2.0", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -977,18 +977,18 @@ dependencies = [ [[package]] name = "lucet-wasi-sdk" -version = "0.1.1" +version = "0.2.0" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.1.1", - "lucet-validate 0.1.1", - "lucetc 0.1.1", + "lucet-module 0.2.0", + "lucet-validate 0.2.0", + "lucetc 0.2.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucetc" -version = "0.1.1" +version = "0.2.0" dependencies = [ "bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1007,8 +1007,8 @@ dependencies = [ "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.1.1", - "lucet-validate 0.1.1", + "lucet-module 0.2.0", + "lucet-validate 0.2.0", "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 77b153281..a3322ed1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,4 @@ -# Lucet version 0.1.1 +# Lucet version 0.2.0 [workspace] members = [ diff --git a/benchmarks/lucet-benchmarks/Cargo.toml b/benchmarks/lucet-benchmarks/Cargo.toml index 0eb323e62..4c014080f 100644 --- a/benchmarks/lucet-benchmarks/Cargo.toml +++ b/benchmarks/lucet-benchmarks/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-benchmarks" -version = "0.1.1" +version = "0.2.0" description = "Benchmarks for the Lucet runtime" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" diff --git a/lucet-idl/Cargo.toml b/lucet-idl/Cargo.toml index ac86769b8..01359c88f 100644 --- a/lucet-idl/Cargo.toml +++ b/lucet-idl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-idl" -version = "0.1.1" +version = "0.2.0" description = "Describe interfaces between WebAssembly guest programs and lucet-runtime hosts" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" diff --git a/lucet-module/Cargo.toml b/lucet-module/Cargo.toml index a046d810f..4e73d754b 100644 --- a/lucet-module/Cargo.toml +++ b/lucet-module/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-module" -version = "0.1.1" +version = "0.2.0" description = "A structured interface for Lucet modules" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" diff --git a/lucet-objdump/Cargo.toml b/lucet-objdump/Cargo.toml index a5fe151ec..457b1a8be 100644 --- a/lucet-objdump/Cargo.toml +++ b/lucet-objdump/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-objdump" -version = "0.1.1" +version = "0.2.0" description = "Analyze object files emitted by the Lucet compiler" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -13,7 +13,7 @@ edition = "2018" goblin="0.0.24" byteorder="1.2.1" colored="1.6.1" -lucet-module = { path = "../lucet-module", version = "0.1.1" } +lucet-module = { path = "../lucet-module", version = "0.2.0" } [package.metadata.deb] name = "fst-lucet-objdump" diff --git a/lucet-runtime/Cargo.toml b/lucet-runtime/Cargo.toml index 7f021f79d..b6f74f052 100644 --- a/lucet-runtime/Cargo.toml +++ b/lucet-runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime" -version = "0.1.1" +version = "0.2.0" description = "Pure Rust runtime for Lucet WebAssembly toolchain" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -11,8 +11,8 @@ edition = "2018" [dependencies] libc = "=0.2.59" -lucet-runtime-internals = { path = "lucet-runtime-internals", version = "0.1.1" } -lucet-module = { path = "../lucet-module", version = "0.1.1" } +lucet-runtime-internals = { path = "lucet-runtime-internals", version = "0.2.0" } +lucet-module = { path = "../lucet-module", version = "0.2.0" } num-traits = "0.2" num-derive = "0.2" @@ -21,7 +21,7 @@ byteorder = "1.2" failure = "0.1" lazy_static = "1.1" lucetc = { path = "../lucetc" } -lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.1.1" } +lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.2.0" } lucet-wasi-sdk = { path = "../lucet-wasi-sdk" } nix = "0.13" rayon = "1.0" diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index 4d7e0b7c2..eb75fe169 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime-internals" -version = "0.1.1" +version = "0.2.0" description = "Pure Rust runtime for Lucet WebAssembly toolchain (internals)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -10,7 +10,7 @@ authors = ["Lucet team "] edition = "2018" [dependencies] -lucet-module = { path = "../../lucet-module", version = "0.1.1" } +lucet-module = { path = "../../lucet-module", version = "0.2.0" } bitflags = "1.0" bincode = "1.1.4" diff --git a/lucet-runtime/lucet-runtime-tests/Cargo.toml b/lucet-runtime/lucet-runtime-tests/Cargo.toml index 8d8b39246..a2dc3f66e 100644 --- a/lucet-runtime/lucet-runtime-tests/Cargo.toml +++ b/lucet-runtime/lucet-runtime-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime-tests" -version = "0.1.1" +version = "0.2.0" description = "Pure Rust runtime for Lucet WebAssembly toolchain (tests)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -18,10 +18,10 @@ test = false failure = "0.1" lazy_static = "1.1" tempfile = "3.0" -lucet-module = { path = "../../lucet-module", version = "0.1.1" } -lucet-runtime-internals = { path = "../lucet-runtime-internals", version = "0.1.1" } -lucet-wasi-sdk = { path = "../../lucet-wasi-sdk", version = "0.1.1" } -lucetc = { path = "../../lucetc", version = "0.1.1" } +lucet-module = { path = "../../lucet-module", version = "0.2.0" } +lucet-runtime-internals = { path = "../lucet-runtime-internals", version = "0.2.0" } +lucet-wasi-sdk = { path = "../../lucet-wasi-sdk", version = "0.2.0" } +lucetc = { path = "../../lucetc", version = "0.2.0" } [build-dependencies] cc = "1.0" diff --git a/lucet-spectest/Cargo.toml b/lucet-spectest/Cargo.toml index 3cc808a22..9a6da3dfd 100644 --- a/lucet-spectest/Cargo.toml +++ b/lucet-spectest/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-spectest" -version = "0.1.1" +version = "0.2.0" description = "Test harness to run WebAssembly spec tests (.wast) against the Lucet toolchain" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -17,9 +17,9 @@ name = "spec-test" path = "src/main.rs" [dependencies] -lucetc = { path = "../lucetc", version = "0.1.1" } -lucet-module = { path = "../lucet-module", version = "0.1.1" } -lucet-runtime = { path = "../lucet-runtime", version = "0.1.1" } +lucetc = { path = "../lucetc", version = "0.2.0" } +lucet-module = { path = "../lucet-module", version = "0.2.0" } +lucet-runtime = { path = "../lucet-runtime", version = "0.2.0" } wabt = "0.7" serde = "1.0" serde_json = "1.0" diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index 95fb2a17d..464e7c506 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-validate" -version = "0.1.1" +version = "0.2.0" description = "Parse and validate webassembly files against witx interface" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -24,7 +24,7 @@ cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.44.0" wasmparser = "0.39.1" [dev-dependencies] -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.1.1" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.2.0" } tempfile = "3.0" wabt = "0.7" diff --git a/lucet-wasi-fuzz/Cargo.toml b/lucet-wasi-fuzz/Cargo.toml index 0ef37b1b1..eee7a1292 100644 --- a/lucet-wasi-fuzz/Cargo.toml +++ b/lucet-wasi-fuzz/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi-fuzz" -version = "0.1.1" +version = "0.2.0" description = "Test the Lucet toolchain against native code execution using Csmith" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" diff --git a/lucet-wasi-sdk/Cargo.toml b/lucet-wasi-sdk/Cargo.toml index bee820b2d..0ec97da41 100644 --- a/lucet-wasi-sdk/Cargo.toml +++ b/lucet-wasi-sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi-sdk" -version = "0.1.1" +version = "0.2.0" description = "A Rust interface to the wasi-sdk compiler and linker" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -11,9 +11,9 @@ edition = "2018" [dependencies] failure = "0.1" -lucetc = { path = "../lucetc", version = "0.1.1" } -lucet-module = { path = "../lucet-module", version = "0.1.1" } +lucetc = { path = "../lucetc", version = "0.2.0" } +lucet-module = { path = "../lucet-module", version = "0.2.0" } tempfile = "3.0" [dev-dependencies] -lucet-validate = { path = "../lucet-validate", version = "0.1.1" } +lucet-validate = { path = "../lucet-validate", version = "0.2.0" } diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index 19a239bb1..c95e706c1 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi" -version = "0.1.1" +version = "0.2.0" description = "Fastly's runtime for the WebAssembly System Interface (WASI)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -29,15 +29,15 @@ clap = "2.23" failure = "0.1" human-size = "0.4" libc = "=0.2.59" -lucet-runtime = { path = "../lucet-runtime", version = "0.1.1" } -lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.1.1" } -lucet-module = { path = "../lucet-module", version = "0.1.1" } +lucet-runtime = { path = "../lucet-runtime", version = "0.2.0" } +lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.2.0" } +lucet-module = { path = "../lucet-module", version = "0.2.0" } nix = "0.13" rand = "0.6" [dev-dependencies] -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.1.1" } -lucetc = { path = "../lucetc", version = "0.1.1" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.2.0" } +lucetc = { path = "../lucetc", version = "0.2.0" } tempfile = "3.0" [build-dependencies.bindgen] diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index 948facc89..bd55edfdc 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucetc" -version = "0.1.1" +version = "0.2.0" description = "Fastly's WebAssembly to native code compiler" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -26,8 +26,8 @@ cranelift-module = { path = "../cranelift/cranelift-module", version = "0.44.0" cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.44.0" } cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.44.0" } target-lexicon = "0.8.0" -lucet-module = { path = "../lucet-module", version = "0.1.1" } -lucet-validate = { path = "../lucet-validate", version = "0.1.1" } +lucet-module = { path = "../lucet-module", version = "0.2.0" } +lucet-validate = { path = "../lucet-validate", version = "0.2.0" } wasmparser = "0.39.1" clap="2.32" log = "0.4" From 05f7a334385dcef63deda460f3ef265b3c2add61 Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Wed, 9 Oct 2019 13:40:39 -0700 Subject: [PATCH 422/512] make bump-global-version.sh gnu sed-friendly -i.previous should be usable on either linux sed or macos sed, but the space leads to linux sed interpreting it as `-i`, which is a valid flag on its own, and `.previous`, as a sed command. --- helpers/bump-global-version.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers/bump-global-version.sh b/helpers/bump-global-version.sh index 7a9783dc1..e2ad9acc5 100755 --- a/helpers/bump-global-version.sh +++ b/helpers/bump-global-version.sh @@ -19,7 +19,7 @@ version_bump() { echo echo "Setting the global Lucet version number to: [$VERSION]" find lucetc lucet-* benchmarks/lucet-* -type f -maxdepth 1 -name 'Cargo.toml' -print | while read -r file; do - sed -i '.previous' "s/^ *version *=.*/version = \"${VERSION}\"/" "$file" && rm -f "${file}.previous" + sed -i'.previous' "s/^ *version *=.*/version = \"${VERSION}\"/" "$file" && rm -f "${file}.previous" done echo "Done." } From b2e4c4e0860254011ce93bbd5a0781fec9cce38e Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Fri, 11 Oct 2019 18:43:05 +0200 Subject: [PATCH 423/512] lucetc: fix --opt-level {none, speed, speed_and_size} (#328) --- lucetc/src/options.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lucetc/src/options.rs b/lucetc/src/options.rs index b8114bced..85401e99d 100644 --- a/lucetc/src/options.rs +++ b/lucetc/src/options.rs @@ -110,9 +110,9 @@ impl Options { let opt_level = match m.value_of("opt_level") { None => OptLevel::SpeedAndSize, - Some("0") => OptLevel::None, - Some("1") => OptLevel::Speed, - Some("2") => OptLevel::SpeedAndSize, + Some("0") | Some("none") => OptLevel::None, + Some("1") | Some("speed") => OptLevel::Speed, + Some("2") | Some("speed_and_size") => OptLevel::SpeedAndSize, Some(_) => panic!("unknown value for opt-level"), }; From 5782846ffab185efcbd187277dc469fad327daf7 Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Fri, 11 Oct 2019 09:50:12 -0700 Subject: [PATCH 424/512] cargo publish requires versions on dev dependencies to publish --- lucet-runtime/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lucet-runtime/Cargo.toml b/lucet-runtime/Cargo.toml index b6f74f052..485c011cd 100644 --- a/lucet-runtime/Cargo.toml +++ b/lucet-runtime/Cargo.toml @@ -20,9 +20,9 @@ num-derive = "0.2" byteorder = "1.2" failure = "0.1" lazy_static = "1.1" -lucetc = { path = "../lucetc" } +lucetc = { path = "../lucetc", version = "0.2.0" } lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.2.0" } -lucet-wasi-sdk = { path = "../lucet-wasi-sdk" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.2.0" } nix = "0.13" rayon = "1.0" tempfile = "3.0" From 241f2322add3167dba73720cad5eee10ff546726 Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Fri, 11 Oct 2019 19:55:21 +0200 Subject: [PATCH 425/512] lucet-wasi/README.md doesn't exist any more, don't try to install it (#330) --- helpers/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers/install.sh b/helpers/install.sh index 49fb22e3d..9ef65925b 100755 --- a/helpers/install.sh +++ b/helpers/install.sh @@ -40,7 +40,7 @@ fi BINS="lucet-objdump lucet-validate lucet-wasi lucetc sightglass spec-test wasmonkey" LIBS="liblucet_runtime.${DYLIB_SUFFIX}" -DOCS="lucet-wasi/README.md sightglass/README.md" +DOCS="sightglass/README.md" BUNDLE_DOCS="README.md" if test -t 0; then From f9e13e0f17dbfdaa2fd529876cddb12a0fe29d43 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 11 Oct 2019 12:45:17 -0700 Subject: [PATCH 426/512] dockerfile: use wask-sdk 7 --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5cf8e6e49..5af3166f1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,8 +37,8 @@ RUN rustup target add wasm32-wasi RUN cargo install --debug cargo-audit cargo-watch rsign2 -RUN curl -sS -L -O https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-6/wasi-sdk_6.0_amd64.deb \ - && dpkg -i wasi-sdk_6.0_amd64.deb && rm -f wasi-sdk_6.0_amd64.deb +RUN curl -sS -L -O https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-7/wasi-sdk_7.0_amd64.deb \ + && dpkg -i wasi-sdk_7.0_amd64.deb && rm -f wasi-sdk_7.0_amd64.deb ENV WASI_SDK=/opt/wasi-sdk From df2932d85688b26df24310b487a7044a3096e4f0 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 11 Oct 2019 13:50:58 -0700 Subject: [PATCH 427/512] lucet-wasi-sdk: fix test to reflect behavior of clang-9 --- lucet-wasi-sdk/tests/lucetc.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lucet-wasi-sdk/tests/lucetc.rs b/lucet-wasi-sdk/tests/lucetc.rs index 5918e320e..9c94f52a7 100644 --- a/lucet-wasi-sdk/tests/lucetc.rs +++ b/lucet-wasi-sdk/tests/lucetc.rs @@ -48,11 +48,9 @@ mod lucetc_tests { Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile empty"); let mdata = c.module_data().unwrap(); assert!(mdata.heap_spec().is_some()); - // clang creates 3 globals: - assert_eq!(mdata.globals_spec().len(), 3); + // clang creates 1 global, which is not exported.: + assert_eq!(mdata.globals_spec().len(), 1); assert!(mdata.globals_spec()[0].is_internal()); - assert_eq!(mdata.globals_spec()[1].export_names(), &["__heap_base"]); - assert_eq!(mdata.globals_spec()[2].export_names(), &["__data_end"]); assert_eq!(mdata.import_functions().len(), 0, "import functions"); assert_eq!(mdata.export_functions().len(), 0, "export functions"); From dce0ae48527c031b3c4092e4981544c0cde2d50f Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Fri, 11 Oct 2019 13:47:36 -0700 Subject: [PATCH 428/512] the runtime's module version check was restrictive enough to be annoying In the case that the runtime is a debug or from-cargo version, there's no commit hash, so a build from any lucetc that can include a commit hash would immediately fail the version check. Since lucetc may be installed by `cargo install`, which will build release binaries, this is more likely than initially expected. --- lucet-module/src/version_info.rs | 38 +++++++++++++++---- lucet-module/tests/version.rs | 28 ++++++++++++++ .../lucet-runtime-internals/src/module/dl.rs | 10 ++--- 3 files changed, 64 insertions(+), 12 deletions(-) create mode 100644 lucet-module/tests/version.rs diff --git a/lucet-module/src/version_info.rs b/lucet-module/src/version_info.rs index 2914a9d69..6c4587686 100644 --- a/lucet-module/src/version_info.rs +++ b/lucet-module/src/version_info.rs @@ -19,7 +19,7 @@ pub struct VersionInfo { /// context, it will be the git commit of lucet-runtime built into the embedder. /// /// The version hash will typically populated only in release builds, but may blank even in - /// that case: if building from a packagd crate, or in a build environment that does not have + /// that case: if building from a packaged crate, or in a build environment that does not have /// "git" installed, `lucetc` and `lucet-runtime` will fall back to an empty hash. version_hash: [u8; 8], } @@ -39,6 +39,31 @@ impl fmt::Display for VersionInfo { } impl VersionInfo { + pub fn new(major: u16, minor: u16, patch: u16, version_hash: [u8; 8]) -> VersionInfo { + VersionInfo { + major, minor, patch, reserved: 0x8000, version_hash + } + } + + /// A more permissive version check than for version equality. This check will allow a more + /// precise `other` + pub fn compatible_with(&self, other: &VersionInfo) -> bool { + if !(self.valid() || other.valid()) { + return false; + } + + if self.major == other.major && self.minor == other.minor && self.patch == other.patch { + if self.version_hash == [0u8; 8] { + // we aren't bound to a specific git commit, so anything goes. + true + } else { + self.version_hash == other.version_hash + } + } else { + false + } + } + pub fn write_to(&self, w: &mut W) -> io::Result<()> { w.write_u16::(self.major)?; w.write_u16::(self.minor)?; @@ -89,12 +114,11 @@ impl VersionInfo { // 0x8000_0000_0000_0000. By setting `reserved` to `0x8000`, we set what would be the // highest bit in `module_data_ptr` in an old `lucet-runtime` and guarantee a segmentation // fault when loading these newer modules with version information. - VersionInfo { - major: env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap(), - minor: env!("CARGO_PKG_VERSION_MINOR").parse().unwrap(), - patch: env!("CARGO_PKG_VERSION_PATCH").parse().unwrap(), - reserved: 0x8000u16, + VersionInfo::new( + env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap(), + env!("CARGO_PKG_VERSION_MINOR").parse().unwrap(), + env!("CARGO_PKG_VERSION_PATCH").parse().unwrap(), version_hash, - } + ) } } diff --git a/lucet-module/tests/version.rs b/lucet-module/tests/version.rs new file mode 100644 index 000000000..52a35d2f9 --- /dev/null +++ b/lucet-module/tests/version.rs @@ -0,0 +1,28 @@ +use lucet_module::VersionInfo; + +#[test] +fn version_equality() { + let precise = VersionInfo::new( + 0, + 1, + 2, + [0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61] + ); + + let imprecise = VersionInfo::new( + 0, + 1, + 2, + [0, 0, 0, 0, 0, 0, 0, 0] + ); + + // first, these are two different versions. + assert_ne!(precise, imprecise); + + // something running a version only as detailed as `major.minor.patch` can run a matching + // version that may include a commit hash + assert!(imprecise.compatible_with(&precise)); + + // something running a version `major.minor.patch-commit` rejects a version less specific + assert!(!precise.compatible_with(&imprecise)); +} diff --git a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs index 98fb5bba6..ac22c5e4f 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs @@ -61,17 +61,17 @@ impl DlModule { let serialized_module: &SerializedModule = unsafe { serialized_module_ptr.as_ref().unwrap() }; - let version = serialized_module.version.clone(); + let module_version = serialized_module.version.clone(); let runtime_version = VersionInfo::current(include_str!(concat!(env!("OUT_DIR"), "/commit_hash")).as_bytes()); - if !version.valid() { + if !module_version.valid() { return Err(lucet_incorrect_module!("reserved bit is not set. This module is likely too old for this lucet-runtime to load.")); - } else if version != runtime_version { + } else if !runtime_version.compatible_with(&module_version) { return Err(lucet_incorrect_module!( "version mismatch. module has version {}, while this runtime is version {}", - version, + module_version, runtime_version, )); } @@ -130,7 +130,7 @@ impl DlModule { lib, fbase, module: lucet_module::Module { - version, + version: module_version, module_data, tables, function_manifest, From 63cd5d48f60beb8e69cebde9c12044c4bc8ee5b2 Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Fri, 11 Oct 2019 13:53:49 -0700 Subject: [PATCH 429/512] grammar --- lucet-module/src/version_info.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lucet-module/src/version_info.rs b/lucet-module/src/version_info.rs index 6c4587686..ccb837707 100644 --- a/lucet-module/src/version_info.rs +++ b/lucet-module/src/version_info.rs @@ -45,8 +45,8 @@ impl VersionInfo { } } - /// A more permissive version check than for version equality. This check will allow a more - /// precise `other` + /// A more permissive version check than for version equality. This check will allow an `other` + /// version that is more specific than `self`, but matches for data that is available. pub fn compatible_with(&self, other: &VersionInfo) -> bool { if !(self.valid() || other.valid()) { return false; From b429b6704eb74259bc91d80f5ebc1f47e1d5fcd6 Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Fri, 11 Oct 2019 13:55:31 -0700 Subject: [PATCH 430/512] rustfmt --- lucet-module/src/version_info.rs | 6 +++++- lucet-module/tests/version.rs | 14 ++------------ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/lucet-module/src/version_info.rs b/lucet-module/src/version_info.rs index ccb837707..94ec4112b 100644 --- a/lucet-module/src/version_info.rs +++ b/lucet-module/src/version_info.rs @@ -41,7 +41,11 @@ impl fmt::Display for VersionInfo { impl VersionInfo { pub fn new(major: u16, minor: u16, patch: u16, version_hash: [u8; 8]) -> VersionInfo { VersionInfo { - major, minor, patch, reserved: 0x8000, version_hash + major, + minor, + patch, + reserved: 0x8000, + version_hash, } } diff --git a/lucet-module/tests/version.rs b/lucet-module/tests/version.rs index 52a35d2f9..3480c74c3 100644 --- a/lucet-module/tests/version.rs +++ b/lucet-module/tests/version.rs @@ -2,19 +2,9 @@ use lucet_module::VersionInfo; #[test] fn version_equality() { - let precise = VersionInfo::new( - 0, - 1, - 2, - [0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61] - ); + let precise = VersionInfo::new(0, 1, 2, [0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61]); - let imprecise = VersionInfo::new( - 0, - 1, - 2, - [0, 0, 0, 0, 0, 0, 0, 0] - ); + let imprecise = VersionInfo::new(0, 1, 2, [0, 0, 0, 0, 0, 0, 0, 0]); // first, these are two different versions. assert_ne!(precise, imprecise); From 91caead89457208439fa09949e21513f3fd29c3a Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 11 Oct 2019 11:34:33 -0700 Subject: [PATCH 431/512] configure CI using Github Actions there are two workflows: * workflows/main.yml defines the Test and Lint jobs, which run in parallel on each push and PR. * Test takes about 19 minutes to complete. * Lint takes about 45 seconds to run `make indent-check`. * workflows/fuzz.yml defines the Fuzz job, which runs nightly at midnight. It only runs on the master branch, so we need to merge this PR to test it. The fuzz smoke-test passes, so I expect that this will work. We will probably have to add some system to report failures it discovers. We may want to run it more often, as well. there is one disabled workflow: * workflows/mac-ci.yml.disabled will run the CI, except for fuzzing, under Mac OS. It is disabled because tests fail on Mac OS at the moment. It should be enabled as part of fixing Mac OS. there is one Action: * actions/test specifies (in action.yml) a job that builds the Dockerfile at the repo root and runs `make test` in the container. The Test job uses the Dockerfile in the repo, but not the devenv scripts to run it. Actions only runs Docker via the This means the devenv scripts themselves have no CI under Actions. Once we have Mac OS support enabled again, there is a lot less reason to maintain the complex set of devenv scripts, which do a lot of fancy and difficult-to-understand stuff to allow using `lucetc`, `lucet-wasi` and other executables on the Mac (or windows, I guess). We could instead document the one-liner invocations of Docker to reproduce our standard developer environment locally. --- .dockerignore | 2 +- .github/actions/test/action.yml | 14 ++++++++ .github/workflows/fuzz.yml | 48 +++++++++++++++++++++++++++ .github/workflows/mac-ci.yml.disabled | 29 ++++++++++++++++ .github/workflows/main.yml | 31 +++++++++++++++++ Makefile | 15 ++++++--- lucet-wasi-fuzz/src/main.rs | 9 +++-- 7 files changed, 141 insertions(+), 7 deletions(-) create mode 100644 .github/actions/test/action.yml create mode 100644 .github/workflows/fuzz.yml create mode 100644 .github/workflows/mac-ci.yml.disabled create mode 100644 .github/workflows/main.yml diff --git a/.dockerignore b/.dockerignore index eb5a316cb..72e8ffc0d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1 +1 @@ -target +* diff --git a/.github/actions/test/action.yml b/.github/actions/test/action.yml new file mode 100644 index 000000000..bd111c486 --- /dev/null +++ b/.github/actions/test/action.yml @@ -0,0 +1,14 @@ +name: 'Test Lucet' +description: 'run tests using standardized lucet development environment' +runs: + using: 'docker' + image: '../../../Dockerfile' + # The Dockerfile does not specify an entrypoint. + entrypoint: "/bin/sh" + args: + # Next arg is a command for sh to execute. + - '-c' + # rustup expects $HOME to be set to /root during `docker run` because thats what + # it was set to during container creation. Actions clears $HOME so we set it here. + # The test target of the Makefile is our standard CI. + - 'export HOME=/root; make test' diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml new file mode 100644 index 000000000..ffcd46327 --- /dev/null +++ b/.github/workflows/fuzz.yml @@ -0,0 +1,48 @@ +name: Fuzz +on: + schedule: + - cron: "0 0 * * *" + +jobs: + fuzz: + name: Fuzz lucet-wasi + + runs-on: ubuntu-16.04 + steps: + - uses: actions/checkout@master + with: + submodules: true + + - name: Install Rust (rustup) + run: rustup update + + - name: Install wasi-sdk (ubuntu) + run: | + curl -sS -L -O https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-7/wasi-sdk_7.0_amd64.deb + sudo dpkg -i wasi-sdk_7.0_amd64.deb + + - name: Install native clang, csmith tools + run: | + sudo apt-get install -y --no-install-recommends \ + software-properties-common \ + clang-6.0 \ + gcc-multilib \ + csmith \ + libcsmith-dev \ + creduce + sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-6.0 100 + + - name: Build Binaryen tools + run: | + curl -sS -L "https://github.com/WebAssembly/binaryen/archive/version_${BINARYEN_VERSION}.tar.gz" | tar xzf - + mkdir -p binaryen-build + cd binaryen-build && cmake "../binaryen-version_${BINARYEN_VERSION}" && make wasm-opt wasm-reduce + echo "##[add-path]$PWD/binaryen-build/bin" + env: + BINARYEN_VERSION: 86 + + - name: Test lucet-wasi-fuzz with known seed + run: make test-fuzz + + - name: Fuzz + run: make fuzz diff --git a/.github/workflows/mac-ci.yml.disabled b/.github/workflows/mac-ci.yml.disabled new file mode 100644 index 000000000..fee6f873d --- /dev/null +++ b/.github/workflows/mac-ci.yml.disabled @@ -0,0 +1,29 @@ +name: Mac OS CI +on: [push, pull_request] + +jobs: + test: + name: Test + runs-on: macos-latest + steps: + - uses: actions/checkout@master + with: + submodules: true + + - name: Install Rust (macos) + run: | + curl https://sh.rustup.rs | sh -s -- -y + rustup update + echo "##[add-path]$HOME/.cargo/bin" + + - name: Install wasi-sdk (macos) + run: | + curl -sS -L -O https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-7/wasi-sdk-7.0-macos.tar.gz + tar xf wasi-sdk-7.0-macos.tar.gz + sudo mv wasi-sdk-7.0/opt /opt + + - name: Test Lucet + run: make test-except-fuzz + + - name: Ensure testing did not change sources + run: git diff --exit-code diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 000000000..2b4c03fc8 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,31 @@ +name: CI +on: [push, pull_request] + +jobs: + test: + name: Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + with: + submodules: true + + # Testing uses the development environment Docker container. + # This action builds the container and executes the test suite inside it. + - uses: ./.github/actions/test + + - name: Ensure testing did not change sources + run: git diff --exit-code + + rustfmt: + name: Rustfmt + runs-on: ubuntu-16.04 + steps: + - uses: actions/checkout@master + with: + submodules: true + - name: Install Rust (rustup) + run: | + rustup update + rustup component add rustfmt + - run: make indent-check diff --git a/Makefile b/Makefile index 987c13352..565e650f6 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,10 @@ install-dev: build-dev @helpers/install.sh --unoptimized .PHONY: test -test: indent-check +test: indent-check test-except-fuzz test-fuzz + +.PHONY: test-except-fuzz +test-except-fuzz: cargo test --no-fail-fast \ -p lucet-runtime-internals \ -p lucet-runtime \ @@ -30,12 +33,16 @@ test: indent-check -p lucet-idl \ -p lucet-wasi-sdk \ -p lucet-wasi \ + -p lucet-wasi-fuzz \ -p lucet-benchmarks \ - -p lucet-validate - # run a single seed through the fuzzer to stave off bitrot - cargo run -p lucet-wasi-fuzz -- test-seed 410757864950 + -p lucet-validate \ helpers/lucet-toolchain-tests/signature.sh +# run a single seed through the fuzzer to stave off bitrot +.PHONY: test-fuzz +test-fuzz: + cargo run -p lucet-wasi-fuzz -- test-seed 410757864950 + .PHONY: fuzz fuzz: cargo run --release -p lucet-wasi-fuzz -- fuzz --num-tests=1000 diff --git a/lucet-wasi-fuzz/src/main.rs b/lucet-wasi-fuzz/src/main.rs index ae90cd13f..9417aa16c 100644 --- a/lucet-wasi-fuzz/src/main.rs +++ b/lucet-wasi-fuzz/src/main.rs @@ -1,6 +1,6 @@ #![deny(bare_trait_objects)] -use failure::{bail, ensure, format_err, Error}; +use failure::{bail, format_err, Error}; use libc::c_ulong; use lucet_module::bindings::Bindings; use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region}; @@ -299,7 +299,12 @@ fn run_native>(tmpdir: &TempDir, gen_c_path: P) -> Result Date: Fri, 11 Oct 2019 17:04:39 -0700 Subject: [PATCH 432/512] bump lucet crates to 0.2.1 --- Cargo.lock | 112 +++++++++--------- Cargo.toml | 2 +- benchmarks/lucet-benchmarks/Cargo.toml | 2 +- lucet-module/Cargo.toml | 2 +- lucet-objdump/Cargo.toml | 4 +- lucet-runtime/Cargo.toml | 12 +- .../lucet-runtime-internals/Cargo.toml | 4 +- lucet-runtime/lucet-runtime-tests/Cargo.toml | 10 +- lucet-spectest/Cargo.toml | 8 +- lucet-validate/Cargo.toml | 4 +- lucet-wasi-fuzz/Cargo.toml | 2 +- lucet-wasi-sdk/Cargo.toml | 8 +- lucet-wasi/Cargo.toml | 12 +- lucetc/Cargo.toml | 6 +- 14 files changed, 94 insertions(+), 94 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a4858ca29..881fe1423 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -760,15 +760,15 @@ dependencies = [ [[package]] name = "lucet-benchmarks" -version = "0.2.0" +version = "0.2.1" dependencies = [ "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.2.0", - "lucet-runtime 0.2.0", - "lucet-runtime-internals 0.2.0", - "lucet-wasi 0.2.0", - "lucet-wasi-sdk 0.2.0", - "lucetc 0.2.0", + "lucet-module 0.2.1", + "lucet-runtime 0.2.1", + "lucet-runtime-internals 0.2.1", + "lucet-wasi 0.2.1", + "lucet-wasi-sdk 0.2.1", + "lucetc 0.2.1", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -783,8 +783,8 @@ dependencies = [ "cranelift-entity 0.44.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.2.0", - "lucetc 0.2.0", + "lucet-module 0.2.1", + "lucetc 0.2.1", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -800,10 +800,10 @@ dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-idl 0.2.0", - "lucet-runtime 0.2.0", - "lucet-wasi 0.2.0", - "lucet-wasi-sdk 0.2.0", - "lucetc 0.2.0", + "lucet-runtime 0.2.1", + "lucet-wasi 0.2.1", + "lucet-wasi-sdk 0.2.1", + "lucetc 0.2.1", "proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -816,13 +816,13 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-idl 0.2.0", - "lucet-runtime 0.2.0", - "lucet-wasi 0.2.0", + "lucet-runtime 0.2.1", + "lucet-wasi 0.2.1", ] [[package]] name = "lucet-module" -version = "0.2.0" +version = "0.2.1" dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -839,28 +839,28 @@ dependencies = [ [[package]] name = "lucet-objdump" -version = "0.2.0" +version = "0.2.1" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.2.0", + "lucet-module 0.2.1", ] [[package]] name = "lucet-runtime" -version = "0.2.0" +version = "0.2.1" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.2.0", - "lucet-runtime-internals 0.2.0", - "lucet-runtime-tests 0.2.0", - "lucet-wasi-sdk 0.2.0", - "lucetc 0.2.0", + "lucet-module 0.2.1", + "lucet-runtime-internals 0.2.1", + "lucet-runtime-tests 0.2.1", + "lucet-wasi-sdk 0.2.1", + "lucetc 0.2.1", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -870,7 +870,7 @@ dependencies = [ [[package]] name = "lucet-runtime-internals" -version = "0.2.0" +version = "0.2.1" dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -881,7 +881,7 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.2.0", + "lucet-module 0.2.1", "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -891,27 +891,27 @@ dependencies = [ [[package]] name = "lucet-runtime-tests" -version = "0.2.0" +version = "0.2.1" dependencies = [ "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.2.0", - "lucet-runtime-internals 0.2.0", - "lucet-wasi-sdk 0.2.0", - "lucetc 0.2.0", + "lucet-module 0.2.1", + "lucet-runtime-internals 0.2.1", + "lucet-wasi-sdk 0.2.1", + "lucetc 0.2.1", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucet-spectest" -version = "0.2.0" +version = "0.2.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.2.0", - "lucet-runtime 0.2.0", - "lucetc 0.2.0", + "lucet-module 0.2.1", + "lucet-runtime 0.2.1", + "lucetc 0.2.1", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -920,12 +920,12 @@ dependencies = [ [[package]] name = "lucet-validate" -version = "0.2.0" +version = "0.2.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.44.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-wasi-sdk 0.2.0", + "lucet-wasi-sdk 0.2.1", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -934,7 +934,7 @@ dependencies = [ [[package]] name = "lucet-wasi" -version = "0.2.0" +version = "0.2.1" dependencies = [ "bindgen 0.47.3 (registry+https://github.com/rust-lang/crates.io-index)", "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -942,11 +942,11 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.2.0", - "lucet-runtime 0.2.0", - "lucet-runtime-internals 0.2.0", - "lucet-wasi-sdk 0.2.0", - "lucetc 0.2.0", + "lucet-module 0.2.1", + "lucet-runtime 0.2.1", + "lucet-runtime-internals 0.2.1", + "lucet-wasi-sdk 0.2.1", + "lucetc 0.2.1", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -954,16 +954,16 @@ dependencies = [ [[package]] name = "lucet-wasi-fuzz" -version = "0.2.0" +version = "0.2.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.2.0", - "lucet-runtime 0.2.0", - "lucet-wasi 0.2.0", - "lucet-wasi-sdk 0.2.0", - "lucetc 0.2.0", + "lucet-module 0.2.1", + "lucet-runtime 0.2.1", + "lucet-wasi 0.2.1", + "lucet-wasi-sdk 0.2.1", + "lucetc 0.2.1", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -977,18 +977,18 @@ dependencies = [ [[package]] name = "lucet-wasi-sdk" -version = "0.2.0" +version = "0.2.1" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.2.0", - "lucet-validate 0.2.0", - "lucetc 0.2.0", + "lucet-module 0.2.1", + "lucet-validate 0.2.1", + "lucetc 0.2.1", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucetc" -version = "0.2.0" +version = "0.2.1" dependencies = [ "bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1007,8 +1007,8 @@ dependencies = [ "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.2.0", - "lucet-validate 0.2.0", + "lucet-module 0.2.1", + "lucet-validate 0.2.1", "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index a3322ed1a..ab9de2b37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,4 @@ -# Lucet version 0.2.0 +# Lucet version 0.2.1 [workspace] members = [ diff --git a/benchmarks/lucet-benchmarks/Cargo.toml b/benchmarks/lucet-benchmarks/Cargo.toml index 4c014080f..9bfb75d2f 100644 --- a/benchmarks/lucet-benchmarks/Cargo.toml +++ b/benchmarks/lucet-benchmarks/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-benchmarks" -version = "0.2.0" +version = "0.2.1" description = "Benchmarks for the Lucet runtime" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" diff --git a/lucet-module/Cargo.toml b/lucet-module/Cargo.toml index 4e73d754b..36e8f1bb2 100644 --- a/lucet-module/Cargo.toml +++ b/lucet-module/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-module" -version = "0.2.0" +version = "0.2.1" description = "A structured interface for Lucet modules" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" diff --git a/lucet-objdump/Cargo.toml b/lucet-objdump/Cargo.toml index 457b1a8be..df25d41bc 100644 --- a/lucet-objdump/Cargo.toml +++ b/lucet-objdump/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-objdump" -version = "0.2.0" +version = "0.2.1" description = "Analyze object files emitted by the Lucet compiler" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -13,7 +13,7 @@ edition = "2018" goblin="0.0.24" byteorder="1.2.1" colored="1.6.1" -lucet-module = { path = "../lucet-module", version = "0.2.0" } +lucet-module = { path = "../lucet-module", version = "0.2.1" } [package.metadata.deb] name = "fst-lucet-objdump" diff --git a/lucet-runtime/Cargo.toml b/lucet-runtime/Cargo.toml index 485c011cd..11621f07e 100644 --- a/lucet-runtime/Cargo.toml +++ b/lucet-runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime" -version = "0.2.0" +version = "0.2.1" description = "Pure Rust runtime for Lucet WebAssembly toolchain" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -11,8 +11,8 @@ edition = "2018" [dependencies] libc = "=0.2.59" -lucet-runtime-internals = { path = "lucet-runtime-internals", version = "0.2.0" } -lucet-module = { path = "../lucet-module", version = "0.2.0" } +lucet-runtime-internals = { path = "lucet-runtime-internals", version = "0.2.1" } +lucet-module = { path = "../lucet-module", version = "0.2.1" } num-traits = "0.2" num-derive = "0.2" @@ -20,9 +20,9 @@ num-derive = "0.2" byteorder = "1.2" failure = "0.1" lazy_static = "1.1" -lucetc = { path = "../lucetc", version = "0.2.0" } -lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.2.0" } -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.2.0" } +lucetc = { path = "../lucetc", version = "0.2.1" } +lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.2.1" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.2.1" } nix = "0.13" rayon = "1.0" tempfile = "3.0" diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index eb75fe169..69168524b 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime-internals" -version = "0.2.0" +version = "0.2.1" description = "Pure Rust runtime for Lucet WebAssembly toolchain (internals)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -10,7 +10,7 @@ authors = ["Lucet team "] edition = "2018" [dependencies] -lucet-module = { path = "../../lucet-module", version = "0.2.0" } +lucet-module = { path = "../../lucet-module", version = "0.2.1" } bitflags = "1.0" bincode = "1.1.4" diff --git a/lucet-runtime/lucet-runtime-tests/Cargo.toml b/lucet-runtime/lucet-runtime-tests/Cargo.toml index a2dc3f66e..522f6b14d 100644 --- a/lucet-runtime/lucet-runtime-tests/Cargo.toml +++ b/lucet-runtime/lucet-runtime-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime-tests" -version = "0.2.0" +version = "0.2.1" description = "Pure Rust runtime for Lucet WebAssembly toolchain (tests)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -18,10 +18,10 @@ test = false failure = "0.1" lazy_static = "1.1" tempfile = "3.0" -lucet-module = { path = "../../lucet-module", version = "0.2.0" } -lucet-runtime-internals = { path = "../lucet-runtime-internals", version = "0.2.0" } -lucet-wasi-sdk = { path = "../../lucet-wasi-sdk", version = "0.2.0" } -lucetc = { path = "../../lucetc", version = "0.2.0" } +lucet-module = { path = "../../lucet-module", version = "0.2.1" } +lucet-runtime-internals = { path = "../lucet-runtime-internals", version = "0.2.1" } +lucet-wasi-sdk = { path = "../../lucet-wasi-sdk", version = "0.2.1" } +lucetc = { path = "../../lucetc", version = "0.2.1" } [build-dependencies] cc = "1.0" diff --git a/lucet-spectest/Cargo.toml b/lucet-spectest/Cargo.toml index 9a6da3dfd..128c3cca4 100644 --- a/lucet-spectest/Cargo.toml +++ b/lucet-spectest/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-spectest" -version = "0.2.0" +version = "0.2.1" description = "Test harness to run WebAssembly spec tests (.wast) against the Lucet toolchain" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -17,9 +17,9 @@ name = "spec-test" path = "src/main.rs" [dependencies] -lucetc = { path = "../lucetc", version = "0.2.0" } -lucet-module = { path = "../lucet-module", version = "0.2.0" } -lucet-runtime = { path = "../lucet-runtime", version = "0.2.0" } +lucetc = { path = "../lucetc", version = "0.2.1" } +lucet-module = { path = "../lucet-module", version = "0.2.1" } +lucet-runtime = { path = "../lucet-runtime", version = "0.2.1" } wabt = "0.7" serde = "1.0" serde_json = "1.0" diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index 464e7c506..19ab69085 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-validate" -version = "0.2.0" +version = "0.2.1" description = "Parse and validate webassembly files against witx interface" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -24,7 +24,7 @@ cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.44.0" wasmparser = "0.39.1" [dev-dependencies] -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.2.0" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.2.1" } tempfile = "3.0" wabt = "0.7" diff --git a/lucet-wasi-fuzz/Cargo.toml b/lucet-wasi-fuzz/Cargo.toml index eee7a1292..d297f3758 100644 --- a/lucet-wasi-fuzz/Cargo.toml +++ b/lucet-wasi-fuzz/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi-fuzz" -version = "0.2.0" +version = "0.2.1" description = "Test the Lucet toolchain against native code execution using Csmith" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" diff --git a/lucet-wasi-sdk/Cargo.toml b/lucet-wasi-sdk/Cargo.toml index 0ec97da41..ba2d24216 100644 --- a/lucet-wasi-sdk/Cargo.toml +++ b/lucet-wasi-sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi-sdk" -version = "0.2.0" +version = "0.2.1" description = "A Rust interface to the wasi-sdk compiler and linker" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -11,9 +11,9 @@ edition = "2018" [dependencies] failure = "0.1" -lucetc = { path = "../lucetc", version = "0.2.0" } -lucet-module = { path = "../lucet-module", version = "0.2.0" } +lucetc = { path = "../lucetc", version = "0.2.1" } +lucet-module = { path = "../lucet-module", version = "0.2.1" } tempfile = "3.0" [dev-dependencies] -lucet-validate = { path = "../lucet-validate", version = "0.2.0" } +lucet-validate = { path = "../lucet-validate", version = "0.2.1" } diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index c95e706c1..422dfda4d 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi" -version = "0.2.0" +version = "0.2.1" description = "Fastly's runtime for the WebAssembly System Interface (WASI)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -29,15 +29,15 @@ clap = "2.23" failure = "0.1" human-size = "0.4" libc = "=0.2.59" -lucet-runtime = { path = "../lucet-runtime", version = "0.2.0" } -lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.2.0" } -lucet-module = { path = "../lucet-module", version = "0.2.0" } +lucet-runtime = { path = "../lucet-runtime", version = "0.2.1" } +lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.2.1" } +lucet-module = { path = "../lucet-module", version = "0.2.1" } nix = "0.13" rand = "0.6" [dev-dependencies] -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.2.0" } -lucetc = { path = "../lucetc", version = "0.2.0" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.2.1" } +lucetc = { path = "../lucetc", version = "0.2.1" } tempfile = "3.0" [build-dependencies.bindgen] diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index bd55edfdc..bb3168aae 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucetc" -version = "0.2.0" +version = "0.2.1" description = "Fastly's WebAssembly to native code compiler" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -26,8 +26,8 @@ cranelift-module = { path = "../cranelift/cranelift-module", version = "0.44.0" cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.44.0" } cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.44.0" } target-lexicon = "0.8.0" -lucet-module = { path = "../lucet-module", version = "0.2.0" } -lucet-validate = { path = "../lucet-validate", version = "0.2.0" } +lucet-module = { path = "../lucet-module", version = "0.2.1" } +lucet-validate = { path = "../lucet-validate", version = "0.2.1" } wasmparser = "0.39.1" clap="2.32" log = "0.4" From d08f83e8c053b262ee7b1602c8c1ce1cbad21795 Mon Sep 17 00:00:00 2001 From: awortman-fastly <49215183+awortman-fastly@users.noreply.github.com> Date: Wed, 16 Oct 2019 14:57:08 -0700 Subject: [PATCH 433/512] Improve lucetc error messages (#269) * move off debug repr for error reporting this still prints the underlying error, like a wabt error in the case of invalid webassembly text, but does so in a more readable way --- Cargo.lock | 25 ++++++++++++++++++++++++- lucetc/Cargo.toml | 2 +- lucetc/src/load.rs | 20 +++++++++++++++++--- lucetc/src/main.rs | 6 +++++- 4 files changed, 47 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 881fe1423..60679b28e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1014,7 +1014,7 @@ dependencies = [ "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "wabt 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "wasmonkey 0.1.8", "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1887,6 +1887,17 @@ dependencies = [ "wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "wabt" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "wabt-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "wabt-sys" version = "0.5.4" @@ -1897,6 +1908,16 @@ dependencies = [ "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "wabt-sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "wait-timeout" version = "0.2.0" @@ -2197,7 +2218,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "74e463a508e390cc7447e70f640fbf44ad52e1bd095314ace1fdf99516d32add" +"checksum wabt 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "94b5f5d6984ca42df66280baa8a15ac188a173ddaf4580b574a98931c01920e7" "checksum wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a6265b25719e82598d104b3717375e37661d41753e2c84cde3f51050c7ed7e3c" +"checksum wabt-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b064c81821100adb4b71923cecfc67fef083db21c3bbd454b0162c7ffe63eeaa" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" "checksum wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a026c1436af49d5537c7561c7474f81f7a754e36445fe52e6e88795a9747291c" diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index bb3168aae..daa77aabd 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -37,7 +37,7 @@ goblin = "0.0.24" failure = "0.1" byteorder = "1.2" wasmonkey = { path = "../lucet-builtins/wasmonkey", version = "0.1.7" } -wabt = "0.7" +wabt = "0.9.1" tempfile = "3.0" bimap = "0.2" human-size = "0.4" diff --git a/lucetc/src/load.rs b/lucetc/src/load.rs index 97b449ed4..d756e28e2 100644 --- a/lucetc/src/load.rs +++ b/lucetc/src/load.rs @@ -4,7 +4,7 @@ use failure::*; use std::fs::File; use std::io::Read; use std::path::Path; -use wabt::wat2wasm; +use wabt::{wat2wasm, ErrorKind}; pub fn read_module>( path: P, @@ -32,8 +32,22 @@ pub fn read_bytes(bytes: Vec) -> Result, Error> { let converted = if wasm_preamble(&bytes) { bytes } else { - wat2wasm(bytes).map_err(|_| { - format_err!("Input is neither valid WASM nor WAT").context(LucetcErrorKind::Input) + wat2wasm(bytes).map_err(|err| { + use std::error::Error; + let mut result = err.description().to_string(); + match unsafe { std::mem::transmute::(err) } { + ErrorKind::Parse(msg) | + // this shouldn't be reachable - we're going the other way + ErrorKind::Deserialize(msg) | + // not sure how this error comes up + ErrorKind::ResolveNames(msg) | + ErrorKind::Validate(msg) => { + result.push_str(":\n"); + result.push_str(&msg); + }, + _ => { } + }; + format_err!("{}", result).context(LucetcErrorKind::Input) })? }; Ok(converted) diff --git a/lucetc/src/main.rs b/lucetc/src/main.rs index 29e763974..f44dc9f3b 100644 --- a/lucetc/src/main.rs +++ b/lucetc/src/main.rs @@ -19,7 +19,11 @@ fn main() { let opts = Options::get().unwrap(); if let Err(err) = run(&opts) { - let mut msg = format!("{:?}", err); + let mut msg = format!("Error: {}.", err); + if let Some(cause) = err.as_fail().cause() { + msg.push(' '); + msg.push_str(&format!("{}", cause)); + } if !msg.ends_with('\n') { msg.push('\n'); } From 28c5d3a599770186c804b51cf4300e2306ea6ba0 Mon Sep 17 00:00:00 2001 From: Tyler McMullen Date: Wed, 16 Oct 2019 18:33:29 -0700 Subject: [PATCH 434/512] Timeouts (#150) * add termination mechanism and use it to implement timeouts The termination model is described in the `execution` module-level docs, but to reiterate: when in guest code, terminate with a SIGALRM sent immediately, and when in host code, terminate by setting a flag (setting `execution_domain` to `Terminated`) and checking that flag when exiting a hostcall. Hostcalls currently have their safety, with respect to termination, implemented by running the whole hostcall in `uninterruptable`, which effectively makes all hostcalls critical sections. In the future, we may want to expose the idea of interruptable hostcalls, both to avoid overhead of synchronizing `KillState` when entering an exiting hostcalls, and to avoid delayed termination. In the extreme, even though this adds a tool for timeout-style logic, it is at worst a request to stop execution, which requires hostcalls to complete in a reasonable amount of time to guarantee that timeouts are always witnessed promptly. --- benchmarks/lucet-benchmarks/src/context.rs | 42 ++- lucet-runtime/include/lucet_types.h | 1 + .../src/alloc/tests.rs | 16 +- .../lucet-runtime-internals/src/c_api.rs | 5 + .../src/context/context_asm.S | 105 ++++-- .../src/context/mod.rs | 63 ++-- .../src/context/tests/c_child.rs | 3 + .../src/context/tests/mod.rs | 18 +- .../src/context/tests/rust_child.rs | 8 +- .../src/hostcall_macros.rs | 33 +- .../lucet-runtime-internals/src/instance.rs | 63 +++- .../src/instance/execution.rs | 319 +++++++++++++++++ .../src/instance/signals.rs | 34 +- .../lucet-runtime-internals/src/vmctx.rs | 3 +- .../guests/timeout/bindings.json | 4 + .../guests/timeout/fault.c | 8 + .../guests/timeout/inf_loop.c | 4 + .../lucet-runtime-tests/src/guest_fault.rs | 55 +-- lucet-runtime/lucet-runtime-tests/src/lib.rs | 1 + .../lucet-runtime-tests/src/timeout.rs | 324 ++++++++++++++++++ lucet-runtime/src/c_api.rs | 1 - lucet-runtime/src/lib.rs | 4 +- lucet-runtime/tests/timeout.rs | 3 + lucet-wasi/src/main.rs | 27 ++ 24 files changed, 988 insertions(+), 156 deletions(-) create mode 100644 lucet-runtime/lucet-runtime-internals/src/instance/execution.rs create mode 100644 lucet-runtime/lucet-runtime-tests/guests/timeout/bindings.json create mode 100644 lucet-runtime/lucet-runtime-tests/guests/timeout/fault.c create mode 100644 lucet-runtime/lucet-runtime-tests/guests/timeout/inf_loop.c create mode 100644 lucet-runtime/lucet-runtime-tests/src/timeout.rs create mode 100644 lucet-runtime/tests/timeout.rs diff --git a/benchmarks/lucet-benchmarks/src/context.rs b/benchmarks/lucet-benchmarks/src/context.rs index 3a4836932..5b2fede39 100644 --- a/benchmarks/lucet-benchmarks/src/context.rs +++ b/benchmarks/lucet-benchmarks/src/context.rs @@ -10,7 +10,14 @@ fn context_init(c: &mut Criterion) { c.bench_function("context_init", move |b| { b.iter(|| { let mut parent = ContextHandle::new(); - ContextHandle::create_and_init(&mut *stack, &mut parent, f as usize, &[]).unwrap(); + ContextHandle::create_and_init( + &mut *stack, + &mut parent, + std::ptr::null(), + f as usize, + &[], + ) + .unwrap(); }) }); } @@ -24,9 +31,14 @@ fn context_swap_return(c: &mut Criterion) { || { let mut stack = vec![0u64; 1024].into_boxed_slice(); let mut parent = ContextHandle::new(); - let child = - ContextHandle::create_and_init(&mut *stack, &mut parent, f as usize, &[]) - .unwrap(); + let child = ContextHandle::create_and_init( + &mut *stack, + &mut parent, + std::ptr::null(), + f as usize, + &[], + ) + .unwrap(); (stack, parent, child) }, |(stack, mut parent, child)| unsafe { @@ -47,9 +59,14 @@ fn context_init_swap_return(c: &mut Criterion) { || vec![0u64; 1024].into_boxed_slice(), |mut stack| { let mut parent = ContextHandle::new(); - let child = - ContextHandle::create_and_init(&mut *stack, &mut parent, f as usize, &[]) - .unwrap(); + let child = ContextHandle::create_and_init( + &mut *stack, + &mut parent, + std::ptr::null(), + f as usize, + &[], + ) + .unwrap(); unsafe { Context::swap(&mut parent, &child) }; stack }, @@ -336,9 +353,14 @@ fn context_init_swap_return_many_args(c: &mut Criterion) { || vec![0u64; 1024].into_boxed_slice(), |mut stack| { let mut parent = ContextHandle::new(); - let child = - ContextHandle::create_and_init(&mut *stack, &mut parent, f as usize, &args) - .unwrap(); + let child = ContextHandle::create_and_init( + &mut *stack, + &mut parent, + std::ptr::null(), + f as usize, + &args, + ) + .unwrap(); unsafe { Context::swap(&mut parent, &child) }; stack }, diff --git a/lucet-runtime/include/lucet_types.h b/lucet-runtime/include/lucet_types.h index 820f943ce..ec4b3365d 100644 --- a/lucet-runtime/include/lucet_types.h +++ b/lucet-runtime/include/lucet_types.h @@ -47,6 +47,7 @@ enum lucet_terminated_reason { lucet_terminated_reason_yield_type_mismatch, lucet_terminated_reason_borrow_error, lucet_terminated_reason_provided, + lucet_terminated_reason_remote, }; enum lucet_trapcode { diff --git a/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs b/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs index c4d8823a6..0c557490c 100644 --- a/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs +++ b/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs @@ -6,7 +6,7 @@ macro_rules! alloc_tests { use $TestRegion as TestRegion; use $crate::alloc::Limits; use $crate::context::{Context, ContextHandle}; - use $crate::instance::InstanceInternal; + use $crate::instance::{InstanceInternal, KillState}; use $crate::module::{GlobalValue, HeapSpec, MockModuleBuilder}; use $crate::region::Region; use $crate::val::Val; @@ -602,9 +602,12 @@ macro_rules! alloc_tests { let mut parent = ContextHandle::new(); unsafe { let heap_ptr = inst.alloc_mut().heap_mut().as_ptr() as *mut c_void; + let kill_state = KillState::new(); + kill_state.enable_termination(); let child = ContextHandle::create_and_init( inst.alloc_mut().stack_u64_mut(), &mut parent, + &kill_state as *const KillState, heap_touching_child as usize, &[Val::CPtr(heap_ptr)], ) @@ -626,7 +629,15 @@ macro_rules! alloc_tests { std::slice::from_raw_parts_mut(heap, CONTEXT_TEST_INITIAL_SIZE as usize / 8) }; let mut onthestack = [0u8; STACK_PATTERN_LENGTH]; + // While not used, this array is load-bearing! A function that executes after the + // guest completes, `instance_kill_state_exit_guest_region`, may end up using + // sufficient stack space to trample over values in this function's call frame. + // + // Padding it out with a duplicate pattern makes enough space for `onthestack` to + // not be clobbered. + let mut ignored = [0u8; STACK_PATTERN_LENGTH]; for i in 0..STACK_PATTERN_LENGTH { + ignored[i] = (i % 256) as u8; onthestack[i] = (i % 256) as u8; } heap[0] = onthestack.as_ptr() as u64; @@ -644,9 +655,12 @@ macro_rules! alloc_tests { let mut parent = ContextHandle::new(); unsafe { let heap_ptr = inst.alloc_mut().heap_mut().as_ptr() as *mut c_void; + let kill_state = KillState::new(); + kill_state.enable_termination(); let child = ContextHandle::create_and_init( inst.alloc_mut().stack_u64_mut(), &mut parent, + &kill_state as *const KillState, stack_pattern_child as usize, &[Val::CPtr(heap_ptr)], ) diff --git a/lucet-runtime/lucet-runtime-internals/src/c_api.rs b/lucet-runtime/lucet-runtime-internals/src/c_api.rs index 02aa0a156..576cf8c12 100644 --- a/lucet-runtime/lucet-runtime-internals/src/c_api.rs +++ b/lucet-runtime/lucet-runtime-internals/src/c_api.rs @@ -295,6 +295,10 @@ pub mod lucet_result { .map(|CTerminationDetails { details }| *details) .unwrap_or(ptr::null_mut()), }, + TerminationDetails::Remote => lucet_terminated { + reason: lucet_terminated_reason::Remote, + provided: std::ptr::null_mut(), + }, }, }, }, @@ -348,6 +352,7 @@ pub mod lucet_result { YieldTypeMismatch, BorrowError, Provided, + Remote, } #[repr(C)] diff --git a/lucet-runtime/lucet-runtime-internals/src/context/context_asm.S b/lucet-runtime/lucet-runtime-internals/src/context/context_asm.S index 47b5bd6f5..287b03d6a 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/context_asm.S +++ b/lucet-runtime/lucet-runtime-internals/src/context/context_asm.S @@ -39,13 +39,15 @@ .align 16 lucet_context_bootstrap: _lucet_context_bootstrap: - /* Move each of the context-saved registers into the corresponding call - * argument register. See lucet_register enum for docs */ - mov %r12, %rsi - mov %r13, %rdx - mov %r14, %rcx - mov %r15, %r8 - mov %rbx, %r9 + // Move each of the argument values into the corresponding call + // argument register. + pop %r9 + pop %r8 + pop %rcx + pop %rdx + pop %rsi + pop %rdi + /* the next thing on the stack is the guest function - return to it */ ret #ifdef __ELF__ @@ -64,11 +66,22 @@ lucet_context_backstop: _lucet_context_backstop: // Note that `rbp` here really has no relation to any stack! // it happens to be an available pointer we can hang the contexts to swap off of. + mov (%rbp), %rdi // load the parent context to forward values in return value registers + mov %rax, (10*8 + 8*16 + 8*0)(%rdi) /* store return values before swapping back -- offset is offsetof(struct lucet_context, retvals) */ + mov %rdx, (10*8 + 8*16 + 8*1)(%rdi) + movdqu %xmm0, (10*8 + 8*16 + 8*2)(%rdi) /* floating-point return value */ + + // load instance pointer, arg 1 + mov 16(%rbp), %rdi +#ifdef __ELF__ + call instance_kill_state_exit_guest_region@PLT +#else + call instance_kill_state_exit_guest_region +#endif + mov (%rbp), %rdi /* parent context to arg 1 */ mov 8(%rbp), %rsi /* own context to arg 2 */ - mov %rax, (8*8 + 8*16 + 8*0)(%rdi) /* store return values before swapping back -- offset is offsetof(struct lucet_context, retvals) */ - mov %rdx, (8*8 + 8*16 + 8*1)(%rdi) - movdqu %xmm0, (8*8 + 8*16 + 8*2)(%rdi) /* floating-point return value */ + #ifdef __ELF__ jmp lucet_context_swap@PLT #else @@ -97,15 +110,16 @@ _lucet_context_swap: mov %r13, (5*8)(%rdi) mov %r14, (6*8)(%rdi) mov %r15, (7*8)(%rdi) + mov %rsi, (8*8)(%rdi) - movdqu %xmm0, (8*8 + 0*16)(%rdi) - movdqu %xmm1, (8*8 + 1*16)(%rdi) - movdqu %xmm2, (8*8 + 2*16)(%rdi) - movdqu %xmm3, (8*8 + 3*16)(%rdi) - movdqu %xmm4, (8*8 + 4*16)(%rdi) - movdqu %xmm5, (8*8 + 5*16)(%rdi) - movdqu %xmm6, (8*8 + 6*16)(%rdi) - movdqu %xmm7, (8*8 + 7*16)(%rdi) + movdqu %xmm0, (10*8 + 0*16)(%rdi) + movdqu %xmm1, (10*8 + 1*16)(%rdi) + movdqu %xmm2, (10*8 + 2*16)(%rdi) + movdqu %xmm3, (10*8 + 3*16)(%rdi) + movdqu %xmm4, (10*8 + 4*16)(%rdi) + movdqu %xmm5, (10*8 + 5*16)(%rdi) + movdqu %xmm6, (10*8 + 6*16)(%rdi) + movdqu %xmm7, (10*8 + 7*16)(%rdi) // load everything from offsets from rsi (2nd arg) mov (0*8)(%rsi), %rbx @@ -117,14 +131,17 @@ _lucet_context_swap: mov (6*8)(%rsi), %r14 mov (7*8)(%rsi), %r15 - movdqu (8*8 + 0*16)(%rsi), %xmm0 - movdqu (8*8 + 1*16)(%rsi), %xmm1 - movdqu (8*8 + 2*16)(%rsi), %xmm2 - movdqu (8*8 + 3*16)(%rsi), %xmm3 - movdqu (8*8 + 4*16)(%rsi), %xmm4 - movdqu (8*8 + 5*16)(%rsi), %xmm5 - movdqu (8*8 + 6*16)(%rsi), %xmm6 - movdqu (8*8 + 7*16)(%rsi), %xmm7 + movdqu (10*8 + 0*16)(%rsi), %xmm0 + movdqu (10*8 + 1*16)(%rsi), %xmm1 + movdqu (10*8 + 2*16)(%rsi), %xmm2 + movdqu (10*8 + 3*16)(%rsi), %xmm3 + movdqu (10*8 + 4*16)(%rsi), %xmm4 + movdqu (10*8 + 5*16)(%rsi), %xmm5 + movdqu (10*8 + 6*16)(%rsi), %xmm6 + movdqu (10*8 + 7*16)(%rsi), %xmm7 + + // restore rsi when we're done with the context pointer + mov (8*8)(%rsi), %rsi ret #ifdef __ELF__ @@ -149,15 +166,16 @@ _lucet_context_set: mov (5*8)(%rdi), %r13 mov (6*8)(%rdi), %r14 mov (7*8)(%rdi), %r15 + mov (8*8)(%rdi), %rsi - movdqu (8*8 + 0*16)(%rdi), %xmm0 - movdqu (8*8 + 1*16)(%rdi), %xmm1 - movdqu (8*8 + 2*16)(%rdi), %xmm2 - movdqu (8*8 + 3*16)(%rdi), %xmm3 - movdqu (8*8 + 4*16)(%rdi), %xmm4 - movdqu (8*8 + 5*16)(%rdi), %xmm5 - movdqu (8*8 + 6*16)(%rdi), %xmm6 - movdqu (8*8 + 7*16)(%rdi), %xmm7 + movdqu (10*8 + 0*16)(%rdi), %xmm0 + movdqu (10*8 + 1*16)(%rdi), %xmm1 + movdqu (10*8 + 2*16)(%rdi), %xmm2 + movdqu (10*8 + 3*16)(%rdi), %xmm3 + movdqu (10*8 + 4*16)(%rdi), %xmm4 + movdqu (10*8 + 5*16)(%rdi), %xmm5 + movdqu (10*8 + 6*16)(%rdi), %xmm6 + movdqu (10*8 + 7*16)(%rdi), %xmm7 // load rdi from itself last mov (3*8)(%rdi), %rdi @@ -166,6 +184,25 @@ _lucet_context_set: .size lucet_context_set,.-lucet_context_set #endif +.text +.globl lucet_context_activate +#ifdef __ELF__ +.type lucet_context_activate,@function +#else +.globl _lucet_context_activate +#endif +.align 16 +// lucet_context_activate is essentially a function with two arguments: +// in rdi, the address of this guest's "running" flag. +// in rsi, the address of the guest code to resume at. +lucet_context_activate: +_lucet_context_activate: + movb $1, (%rdi) + jmp *%rsi +#ifdef __ELF__ +.size lucet_context_activate,.-lucet_context_activate +#endif + /* Mark that we don't need executable stack. */ #if defined(__linux__) && defined(__ELF__) .section .note.GNU-stack,"",%progbits diff --git a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs index 82e0ecc08..88bc24cf5 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs @@ -3,6 +3,7 @@ #[cfg(test)] mod tests; +use crate::instance::execution::KillState; use crate::val::{val_to_reg, val_to_stack, RegVal, UntypedRetVal, Val}; use failure::Fail; use nix; @@ -25,15 +26,16 @@ use xfailure::xbail; /// . Since the members are all /// `u64`, this should be fine? #[repr(C)] -struct GpRegs { +pub(crate) struct GpRegs { rbx: u64, - rsp: u64, + pub(crate) rsp: u64, rbp: u64, - rdi: u64, + pub(crate) rdi: u64, r12: u64, r13: u64, r14: u64, r15: u64, + pub(crate) rsi: u64, } impl GpRegs { @@ -47,6 +49,7 @@ impl GpRegs { r13: 0, r14: 0, r15: 0, + rsi: 0, } } } @@ -110,7 +113,7 @@ impl FpRegs { /// that pointer becomes invalid, and the behavior of returning from that context becomes undefined. #[repr(C, align(64))] pub struct Context { - gpr: GpRegs, + pub(crate) gpr: GpRegs, fpr: FpRegs, retvals_gp: [u64; 2], retval_fp: __m128, @@ -193,11 +196,12 @@ impl ContextHandle { pub fn create_and_init( stack: &mut [u64], parent: &mut ContextHandle, + kill_state: *const KillState, fptr: usize, args: &[Val], ) -> Result { let mut child = ContextHandle::new(); - Context::init(stack, parent, &mut child, fptr, args)?; + Context::init(stack, parent, &mut child, kill_state, fptr, args)?; Ok(child) } } @@ -294,6 +298,7 @@ impl Context { /// &mut *stack, /// &mut parent, /// &mut child, + /// std::ptr::null(), /// entrypoint as usize, /// &[Val::U64(120), Val::F32(3.14)], /// ); @@ -319,6 +324,7 @@ impl Context { /// &mut *stack, /// &mut parent, /// &mut child, + /// std::ptr::null(), /// entrypoint as usize, /// &[Val::U64(120), Val::F32(3.14)], /// ); @@ -363,6 +369,7 @@ impl Context { stack: &mut [u64], parent: &mut Context, child: &mut Context, + kill_state: *const KillState, fptr: usize, args: &[Val], ) -> Result<(), Error> { @@ -372,6 +379,7 @@ impl Context { let mut gp_args_ix = 0; let mut fp_args_ix = 0; + let mut gp_regs_values = [0u64; 6]; let mut spilled_args = vec![]; @@ -381,7 +389,7 @@ impl Context { if gp_args_ix >= 6 { spilled_args.push(val_to_stack(arg)); } else { - child.bootstrap_gp_ix_arg(gp_args_ix, v); + gp_regs_values[gp_args_ix] = v; gp_args_ix += 1; } } @@ -399,12 +407,15 @@ impl Context { // set up an initial call stack for guests to bootstrap into and execute let mut stack_builder = CallStackBuilder::new(stack); + // store a pointer to the context swap completion flag, to signal the guest has activated + stack_builder.push(kill_state as u64); + // store arguments we'll pass to `lucet_context_swap` on the stack, above where the guest // might scribble over them. stack_builder.push(parent as *mut Context as u64); stack_builder.push(child as *mut Context as u64); - // we'll pass a pointer to them via `rbp` in the guest's Context we switch to. + // we'll pass a pointer to these values via `rbp` in the guest's Context we switch to. let backstop_args = stack_builder.offset(); // we actually don't want to put an explicit pointer to these arguments anywhere. we'll @@ -429,6 +440,12 @@ impl Context { // completes it returns to begin the next function up. stack_builder.push(lucet_context_backstop as u64); stack_builder.push(fptr as u64); + + // add all general purpose arguments for the guest to be bootstrapped + for arg in gp_regs_values.iter() { + stack_builder.push(*arg); + } + stack_builder.push(lucet_context_bootstrap as u64); let (stack, stack_start) = stack_builder.into_inner(); @@ -515,6 +532,7 @@ impl Context { /// &mut stack, /// &mut parent, /// &mut child, + /// std::ptr::null(), /// entrypoint as usize, /// &[], /// ).unwrap(); @@ -629,31 +647,6 @@ impl Context { UntypedRetVal::new(gp, fp) } - /// Put one of the first 6 general-purpose arguments into a `Context` register. - /// - /// Although these registers are callee-saved registers rather than argument registers, they get - /// moved into argument registers by `lucet_context_bootstrap`. - /// - /// - `ix`: ABI general-purpose argument number - /// - `arg`: argument value - fn bootstrap_gp_ix_arg(&mut self, ix: usize, arg: u64) { - match ix { - // rdi lives across bootstrap - 0 => self.gpr.rdi = arg, - // bootstraps into rsi - 1 => self.gpr.r12 = arg, - // bootstraps into rdx - 2 => self.gpr.r13 = arg, - // bootstraps into rcx - 3 => self.gpr.r14 = arg, - // bootstraps into r8 - 4 => self.gpr.r15 = arg, - // bootstraps into r9 - 5 => self.gpr.rbx = arg, - _ => panic!("unexpected gp register index {}", ix), - } - } - /// Put one of the first 8 floating-point arguments into a `Context` register. /// /// - `ix`: ABI floating-point argument number @@ -710,4 +703,10 @@ extern "C" { /// /// Never returns because the current context is discarded. fn lucet_context_set(to: *const Context) -> !; + + /// Enables termination for the instance, after performing a context switch. + /// + /// Takes the guest return address as an argument as a consequence of implementation details, + /// see `Instance::swap_and_return` for more. + pub(crate) fn lucet_context_activate(); } diff --git a/lucet-runtime/lucet-runtime-internals/src/context/tests/c_child.rs b/lucet-runtime/lucet-runtime-internals/src/context/tests/c_child.rs index 4bdb3bd14..b9945b39c 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/tests/c_child.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/tests/c_child.rs @@ -51,9 +51,12 @@ macro_rules! test_body { macro_rules! init_and_swap { ( $stack:ident, $fn:ident, [ $( $args:expr ),* ] ) => { unsafe { + let kill_state = $crate::instance::KillState::new(); + kill_state.enable_termination(); let child = Box::into_raw(Box::new(ContextHandle::create_and_init( &mut *$stack, parent_regs.as_mut().unwrap(), + &kill_state as *const $crate::instance::KillState, $fn as usize, &[$( $args ),*], ).unwrap())); diff --git a/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs b/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs index 14bc5312c..9709d6ac7 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs @@ -1,15 +1,16 @@ mod c_child; mod rust_child; use crate::context::{Context, ContextHandle, Error}; +use crate::instance::execution::KillState; use memoffset::offset_of; use std::slice; #[test] fn context_offsets_correct() { assert_eq!(offset_of!(Context, gpr), 0); - assert_eq!(offset_of!(Context, fpr), 8 * 8); - assert_eq!(offset_of!(Context, retvals_gp), 8 * 8 + 8 * 16); - assert_eq!(offset_of!(Context, retval_fp), 8 * 8 + 8 * 16 + 8 * 2); + assert_eq!(offset_of!(Context, fpr), 10 * 8); + assert_eq!(offset_of!(Context, retvals_gp), 10 * 8 + 8 * 16); + assert_eq!(offset_of!(Context, retval_fp), 10 * 8 + 8 * 16 + 8 * 2); } #[test] @@ -32,8 +33,15 @@ fn init_rejects_unaligned() { // now we have the unaligned stack, let's make sure it blows up right let mut parent = ContextHandle::new(); - let res = - ContextHandle::create_and_init(&mut stack_unaligned, &mut parent, dummy as usize, &[]); + let kill_state = KillState::new(); + kill_state.enable_termination(); + let res = ContextHandle::create_and_init( + &mut stack_unaligned, + &mut parent, + &kill_state as *const KillState, + dummy as usize, + &[], + ); if let Err(Error::UnalignedStack) = res { assert!(true); diff --git a/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs b/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs index 7292114b9..6747a00f4 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs @@ -47,15 +47,21 @@ macro_rules! test_body { macro_rules! init_and_swap { ( $stack:ident, $fn:ident, [ $( $args:expr ),* ] ) => { unsafe { + let kill_state = $crate::instance::KillState::new(); + kill_state.enable_termination(); let child = ContextHandle::create_and_init( &mut *$stack, PARENT.as_mut().unwrap(), + &kill_state as *const $crate::instance::KillState, $fn as usize, &[$( $args ),*], ).unwrap(); CHILD = Some(child); - Context::swap(PARENT.as_mut().unwrap(), CHILD.as_ref().unwrap()); + Context::swap( + PARENT.as_mut().unwrap(), + CHILD.as_ref().unwrap(), + ); } } } diff --git a/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs b/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs index 3c11f8807..64690fbb3 100644 --- a/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs +++ b/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs @@ -45,21 +45,28 @@ macro_rules! lucet_hostcalls { ) -> $ret_ty { $($body)* } - let res = std::panic::catch_unwind(move || { - hostcall_impl(&mut $crate::vmctx::Vmctx::from_raw(vmctx_raw), $( $arg ),*) - }); - match res { - Ok(res) => res, - Err(e) => { - match e.downcast::<$crate::instance::TerminationDetails>() { - Ok(details) => { - let mut vmctx = $crate::vmctx::Vmctx::from_raw(vmctx_raw); - vmctx.terminate_no_unwind(*details) - }, - Err(e) => std::panic::resume_unwind(e), + // don't warn if this macro happens to expand in a context where `VmctxInternal` + // was already imported + #[allow(unused_imports)] + use $crate::vmctx::VmctxInternal; + + $crate::vmctx::Vmctx::from_raw(vmctx_raw).instance_mut().uninterruptable(|| { + let res = std::panic::catch_unwind(move || { + hostcall_impl(&mut $crate::vmctx::Vmctx::from_raw(vmctx_raw), $( $arg ),*) + }); + match res { + Ok(res) => res, + Err(e) => { + match e.downcast::<$crate::instance::TerminationDetails>() { + Ok(details) => { + let mut vmctx = $crate::vmctx::Vmctx::from_raw(vmctx_raw); + vmctx.terminate_no_unwind(*details) + }, + Err(e) => std::panic::resume_unwind(e), + } } } - } + }) } )* } diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index f9c8a4987..08d8dc119 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -1,7 +1,9 @@ +pub mod execution; mod siginfo_ext; pub mod signals; pub mod state; +pub use crate::instance::execution::{KillError, KillState, KillSuccess, KillSwitch}; pub use crate::instance::signals::{signal_handler_none, SignalBehavior, SignalHandler}; pub use crate::instance::state::State; @@ -13,7 +15,7 @@ use crate::module::{self, FunctionHandle, FunctionPointer, Global, GlobalValue, use crate::region::RegionInternal; use crate::val::{UntypedRetVal, Val}; use crate::WASM_PAGE_SIZE; -use libc::{c_void, siginfo_t, uintptr_t}; +use libc::{c_void, pthread_self, siginfo_t, uintptr_t}; use lucet_module::InstanceRuntimeData; use memoffset::offset_of; use std::any::Any; @@ -224,6 +226,9 @@ pub struct Instance { /// Instance state and error information pub(crate) state: State, + /// Small mutexed state used for remote kill switch functionality + pub(crate) kill_state: Arc, + /// The memory allocated for this instance alloc: Alloc, @@ -688,6 +693,29 @@ impl Instance { self.c_fatal_handler = Some(handler); } + pub fn kill_switch(&self) -> KillSwitch { + KillSwitch::new(Arc::downgrade(&self.kill_state)) + } + + // This needs to be public as it's used in the expansion of `lucet_hostcalls`, available for + // external use. But you *really* shouldn't have to call this yourself, so we're going to keep + // it out of rustdoc. + #[doc(hidden)] + pub fn uninterruptable T>(&mut self, f: F) -> T { + self.kill_state.begin_hostcall(); + let res = f(); + let stop_reason = self.kill_state.end_hostcall(); + + if let Some(termination_details) = stop_reason { + // TODO: once we have unwinding, panic here instead so we unwind host frames + unsafe { + self.terminate(termination_details); + } + } + + res + } + #[inline] pub fn get_instruction_count(&self) -> u64 { self.get_instance_implicits().instruction_count @@ -709,6 +737,7 @@ impl Instance { module, ctx: Context::new(), state: State::Ready, + kill_state: Arc::new(KillState::new()), alloc, fatal_handler: default_fatal_handler, c_fatal_handler: None, @@ -800,16 +829,42 @@ impl Instance { let mut args_with_vmctx = vec![Val::from(self.alloc.slot().heap)]; args_with_vmctx.extend_from_slice(args); + let kill_state_ptr: *const KillState = &*self.kill_state; + HOST_CTX.with(|host_ctx| { Context::init( unsafe { self.alloc.stack_u64_mut() }, unsafe { &mut *host_ctx.get() }, &mut self.ctx, + kill_state_ptr, func.ptr.as_usize(), &args_with_vmctx, ) })?; + // Set up the guest to set itself as terminable, then continue to + // whatever guest code we want to run. + // + // `lucet_context_activate` takes two arguments: + // rsi: address of guest code to execute + // rdi: pointer to a bool that indicates the guest can be terminated + // + // The appropriate value for `rsi` is the top of the guest stack, which + // we would otherwise return to and start executing immediately. For + // `rdi`, we want to pass a pointer to the instance's `terminable` flag. + // + // once we've set up arguments, swap out the guest return address with + // `lucet_context_activate` so we start execution there. + unsafe { + let top_of_stack = self.ctx.gpr.rsp as *mut u64; + // move the guest code address to rsi + self.ctx.gpr.rsi = *top_of_stack; + // replace it with the activation thunk + *top_of_stack = crate::context::lucet_context_activate as u64; + // and store a pointer to indicate we're active + self.ctx.gpr.rdi = self.kill_state.terminable_ptr() as u64; + } + self.swap_and_return() } @@ -825,6 +880,8 @@ impl Instance { ); self.state = State::Running; + self.kill_state.schedule(unsafe { pthread_self() }); + // there should never be another instance running on this thread when we enter this function CURRENT_INSTANCE.with(|current_instance| { let mut current_instance = current_instance.borrow_mut(); @@ -859,6 +916,8 @@ impl Instance { // // The state should never be `Ready`, `Terminated`, `Yielded`, or `Transitioning` at this point + self.kill_state.deschedule(); + // Set transitioning state temporarily so that we can move values out of the current state let st = mem::replace(&mut self.state, State::Transitioning); @@ -1006,6 +1065,7 @@ pub enum TerminationDetails { BorrowError(&'static str), /// Calls to `lucet_hostcall_terminate` provide a payload for use by the embedder. Provided(Box), + Remote, } impl TerminationDetails { @@ -1055,6 +1115,7 @@ impl std::fmt::Debug for TerminationDetails { TerminationDetails::CtxNotFound => write!(f, "CtxNotFound"), TerminationDetails::YieldTypeMismatch => write!(f, "YieldTypeMismatch"), TerminationDetails::Provided(_) => write!(f, "Provided(Any)"), + TerminationDetails::Remote => write!(f, "Remote"), } } } diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/execution.rs b/lucet-runtime/lucet-runtime-internals/src/instance/execution.rs new file mode 100644 index 000000000..da21c0092 --- /dev/null +++ b/lucet-runtime/lucet-runtime-internals/src/instance/execution.rs @@ -0,0 +1,319 @@ +//! The `execution` module contains state for an instance's execution, and exposes functions +//! building that state into something appropriate for safe use externally. +//! +//! So far as state tracked in this module is concerned, there are two key items: "terminability" +//! and "execution domain". +//! +//! ## Terminability +//! This specifically answers the question "is it safe to initiate termination of this instance +//! right now?". An instance becomes terminable when it begins executing, and stops being +//! terminable when it is terminated, or when it stops executing. Termination does not directly map +//! to the idea of guest code currently executing on a processor, because termination can occur +//! during host code, or while a guest has yielded execution. As a result, termination can only be +//! treated as a best-effort to deschedule a guest, and is typically quick when it occurs during +//! guest code execution, or immediately upon resuming execution of guest code (exiting host code, +//! or resuming a yielded instance). +//! +//! ## Execution Domain +//! Execution domains allow us to distinguish what an appropriate mechanism to signal termination +//! is. This means that changing of an execution domain must be atomic - it would be an error to +//! read the current execution domain, continue with that domain to determine temination, and +//! simultaneously for execution to continue possibly into a different execution domain. For +//! example, beginning termination directly at the start of a hostcall, where sending `SIGALRM` may +//! be appropriate, while the domain switches to `Hostcall` and is no longer appropriate for +//! signalling, would be an error. +//! +//! ## Instance Lifecycle and `KillState` +//! +//! And now we can enumerate interleavings of execution and timeout, to see the expected state at +//! possible points of interest in an instance's lifecycle: +//! +//! * `Instance created` +//! - terminable: `false` +//! - execution_domain: `Guest` +//! * `Instance::run called` +//! - terminable: `true` +//! - execution_domain: `Guest` +//! * `Instance::run executing` +//! - terminable: `true, or false` +//! - execution_domain: `Guest, Hostcall, or Terminated` +//! - `execution_domain` will only be `Guest` when executing guest code, only be `Hostcall` when +//! executing a hostcall, but may also be `Terminated` while in a hostcall to indicate that it +//! should exit when the hostcall completes. +//! - `terminable` will be false if and only if `execution_domain` is `Terminated`. +//! * `Instance::run returns` +//! - terminable: `false` +//! - execution_domain: `Guest, Hostcall, or Terminated` +//! - `execution_domain` will be `Guest` when the initial guest function returns, `Hostcall` when +//! terminated by `lucet_hostcall_terminate!`, and `Terminated` when exiting due to a termination +//! request. +//! * `Guest function executing` +//! - terminable: `true` +//! - execution_domain: `Guest` +//! * `Guest function returns` +//! - terminable: `true` +//! - execution_domain: `Guest` +//! * `Hostcall called` +//! - terminable: `true` +//! - execution_domain: `Hostcall` +//! * `Hostcall executing` +//! - terminable: `true` +//! - execution_domain: `Hostcall, or Terminated` +//! - `execution_domain` will typically be `Hostcall`, but may be `Terminated` if termination of +//! the instance is requested during the hostcall. +//! - `terminable` will be false if and only if `execution_domain` is `Terminated`. +//! * `Hostcall yields` +//! - This is a specific point in "Hostcall executing" and has no further semantics. +//! * `Hostcall resumes` +//! - This is a specific point in "Hostcall executing" and has no further semantics. +//! * `Hostcall returns` +//! - terminable: `true` +//! - execution_domain: `Guest` +//! - `execution_domain` may be `Terminated` before returning, in which case `terminable` will be +//! false, but the hostcall would then exit. If a hostcall successfully returns to its caller it +//! was not terminated, so the only state an instance will have after returning from a hostcall +//! will be that it's executing terminable guest code. + +use libc::{pthread_kill, pthread_t, SIGALRM}; +use std::mem; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{Condvar, Mutex, Weak}; + +use crate::instance::TerminationDetails; + +/// All instance state a remote kill switch needs to determine if and how to signal that execution +/// should stop. +/// +/// Some definitions for reference in this struct's documentation: +/// * "stopped" means "stop executing at some point before reaching the end of the entrypoint +/// wasm function". +/// * "critical section" means what it typically means - an uninterruptable region of code. The +/// detail here is that currently "critical section" and "hostcall" are interchangeable, but in +/// the future this may change. Hostcalls may one day be able to opt out of criticalness, or +/// perhaps guest code may include critical sections. +/// +/// "Stopped" is a particularly loose word here because it encompasses the worst case: trying to +/// stop a guest that is currently in a critical section. Because the signal will only be checked +/// when exiting the critical section, the latency is bounded by whatever embedder guarantees are +/// made. In fact, it is possible for a kill signal to be successfully sent and still never +/// impactful, if a hostcall itself invokes `lucet_hostcall_terminate!`. In this circumstance, the +/// hostcall would terminate the instance if it returned, but `lucet_hostcall_terminate!` will +/// terminate the guest before the termination request would even be checked. +pub struct KillState { + /// Can the instance be terminated? This must be `true` only when the instance can be stopped. + /// This may be false while the instance can safely be stopped, such as immediately after + /// completing a host->guest context swap. Regions such as this should be minimized, but are + /// not a problem of correctness. + /// + /// Typically, this is true while in any guest code, or hostcalls made from guest code. + terminable: AtomicBool, + /// The kind of code is currently executing in the instance this `KillState` describes. + /// + /// This allows a `KillSwitch` to determine what the appropriate signalling mechanism is in + /// `terminate`. Locks on `execution_domain` prohibit modification while signalling, ensuring + /// both that: + /// * we don't enter a hostcall while someone may decide it is safe to signal, and + /// * no one may try to signal in a hostcall-safe manner after exiting a hostcall, where it + /// may never again be checked by the guest. + execution_domain: Mutex, + /// The current `thread_id` the associated instance is running on. This is the TID where + /// `SIGALRM` will be sent if the instance is killed via `KillSwitch::terminate` and a signal + /// is an appropriate mechanism. + thread_id: Mutex>, + /// `tid_change_notifier` allows functions that may cause a change in `thread_id` to wait, + /// without spinning, for the signal to be processed. + tid_change_notifier: Condvar, +} + +#[no_mangle] +pub unsafe extern "C" fn instance_kill_state_exit_guest_region(kill_state: *mut KillState) { + let terminable = (*kill_state).terminable.swap(false, Ordering::SeqCst); + if !terminable { + // Something else has taken the terminable flag, so it's not safe to actually exit a + // guest context yet. Because this is called when exiting a guest context, the + // termination mechanism will be a signal, delivered at some point (hopefully soon!). + // Further, because the termination mechanism will be a signal, we are constrained to + // only signal-safe behavior. + // + // For now, hang indefinitely, waiting for the sigalrm to arrive. + + loop {} + } +} + +impl KillState { + pub fn new() -> KillState { + KillState { + terminable: AtomicBool::new(false), + tid_change_notifier: Condvar::new(), + execution_domain: Mutex::new(Domain::Guest), + thread_id: Mutex::new(None), + } + } + + pub fn is_terminable(&self) -> bool { + self.terminable.load(Ordering::SeqCst) + } + + pub fn enable_termination(&self) { + self.terminable.store(true, Ordering::SeqCst); + } + + pub fn disable_termination(&self) { + self.terminable.store(false, Ordering::SeqCst); + } + + pub fn terminable_ptr(&self) -> *const AtomicBool { + &self.terminable as *const AtomicBool + } + + pub fn begin_hostcall(&self) { + // Lock the current execution domain, so we can update to `Hostcall`. + let mut current_domain = self.execution_domain.lock().unwrap(); + match *current_domain { + Domain::Guest => { + // Guest is the expected domain until this point. Switch to the Hostcall + // domain so we know to not interrupt this instance. + *current_domain = Domain::Hostcall; + } + Domain::Hostcall => { + panic!( + "Invalid state: Instance marked as in a hostcall while entering a hostcall." + ); + } + Domain::Terminated => { + panic!("Invalid state: Instance marked as terminated while in guest code. This should be an error."); + } + } + } + + pub fn end_hostcall(&self) -> Option { + let mut current_domain = self.execution_domain.lock().unwrap(); + match *current_domain { + Domain::Guest => { + panic!("Invalid state: Instance marked as in guest code while exiting a hostcall."); + } + Domain::Hostcall => { + *current_domain = Domain::Guest; + None + } + Domain::Terminated => { + // The instance was stopped in the hostcall we were executing. + debug_assert!(!self.terminable.load(Ordering::SeqCst)); + std::mem::drop(current_domain); + Some(TerminationDetails::Remote) + } + } + } + + pub fn schedule(&self, tid: pthread_t) { + *self.thread_id.lock().unwrap() = Some(tid); + self.tid_change_notifier.notify_all(); + } + + pub fn deschedule(&self) { + *self.thread_id.lock().unwrap() = None; + self.tid_change_notifier.notify_all(); + } +} + +pub enum Domain { + Guest, + Hostcall, + Terminated, +} + +pub struct KillSwitch { + state: Weak, +} + +#[derive(Debug, PartialEq)] +pub enum KillSuccess { + Signalled, + Pending, +} + +#[derive(Debug, PartialEq)] +pub enum KillError { + NotTerminable, +} + +type KillResult = Result; + +/// An object that can be used to terminate an instance's execution from a separate thread. +impl KillSwitch { + pub(crate) fn new(state: Weak) -> Self { + KillSwitch { state } + } + + /// Signal the instance associated with this `KillSwitch` to stop, if possible. + /// + /// The returned `Result` only describes the behavior taken by this function, not necessarily + /// what caused the associated instance to stop. + /// + /// As an example, if a `KillSwitch` fires, sending a SIGALRM to an instance at the same + /// moment it begins handling a SIGSEGV which is determined to be fatal, the instance may + /// stop with `State::Faulted` before actually _handling_ the SIGALRM we'd send here. So the + /// host code will see `State::Faulted` as an instance state, where `KillSwitch::terminate` + /// would return `Ok(KillSuccess::Signalled)`. + pub fn terminate(&self) -> KillResult { + // Get the underlying kill state. If this fails, it means the instance exited and was + // discarded, so we can't terminate. + let state = self.state.upgrade().ok_or(KillError::NotTerminable)?; + + // Attempt to take the flag indicating the instance may terminate + let terminable = state.terminable.swap(false, Ordering::SeqCst); + if !terminable { + return Err(KillError::NotTerminable); + } + + // we got it! we can signal the instance. + + // Now check what domain the instance is in. We can signal in guest code, but want + // to avoid signalling in host code lest we interrupt some function operating on + // guest/host shared memory, and invalidate invariants. For example, interrupting + // in the middle of a resize operation on a `Vec` could be extremely dangerous. + // + // Hold this lock through all signalling logic to prevent the instance from + // switching domains (and invalidating safety of whichever mechanism we choose here) + let mut execution_domain = state.execution_domain.lock().unwrap(); + + let result = match *execution_domain { + Domain::Guest => { + let mut curr_tid = state.thread_id.lock().unwrap(); + // we're in guest code, so we can just send a signal. + if let Some(thread_id) = *curr_tid { + unsafe { + pthread_kill(thread_id, SIGALRM); + } + + // wait for the SIGALRM handler to deschedule the instance + // + // this should never actually loop, which would indicate the instance + // was moved to another thread, or we got spuriously notified. + while curr_tid.is_some() { + curr_tid = state.tid_change_notifier.wait(curr_tid).unwrap(); + } + Ok(KillSuccess::Signalled) + } else { + panic!("logic error: instance is terminable but not actually running."); + } + } + Domain::Hostcall => { + // the guest is in a hostcall, so the only thing we can do is indicate it + // should terminate and wait. + *execution_domain = Domain::Terminated; + Ok(KillSuccess::Pending) + } + Domain::Terminated => { + // Something else (another KillSwitch?) has already signalled this instance + // to exit when it has completed its hostcall. Nothing to do here. + Err(KillError::NotTerminable) + } + }; + // explicitly drop the lock to be clear about how long we want to hold this lock, which is + // until all signalling is complete. + mem::drop(execution_domain); + result + } +} diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs index 068de1bd1..1ca1af942 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs @@ -128,7 +128,8 @@ extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext if !(signal == Signal::SIGBUS || signal == Signal::SIGSEGV || signal == Signal::SIGILL - || signal == Signal::SIGFPE) + || signal == Signal::SIGFPE + || signal == Signal::SIGALRM) { panic!("unexpected signal in guest signal handler: {:?}", signal); } @@ -164,10 +165,25 @@ extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext .as_mut() }; + if signal == Signal::SIGALRM { + // if have gotten a SIGALRM, the killswitch that sent this signal must have also + // disabled the `terminable` flag. If this assert fails, the SIGALRM came from some + // other source, or we have a bug that allows SIGALRM to be sent when they should not. + // + // TODO: once we have a notion of logging in `lucet-runtime`, this should be a logged + // error. + debug_assert!(!inst.kill_state.is_terminable()); + + inst.state = State::Terminating { + details: TerminationDetails::Remote, + }; + return true; + } + let trapcode = inst.module.lookup_trapcode(rip); let behavior = (inst.signal_handler)(inst, &trapcode, signum, siginfo_ptr, ucontext_ptr); - match behavior { + let switch_to_host = match behavior { SignalBehavior::Continue => { // return to the guest context without making any modifications to the instance false @@ -177,6 +193,7 @@ extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext inst.state = State::Terminating { details: TerminationDetails::Signal, }; + true } SignalBehavior::Default => { @@ -224,7 +241,14 @@ extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext thunk(); true } + }; + + if switch_to_host { + // we must disable termination so no KillSwitch may fire in host code. + inst.kill_state.disable_termination(); } + + switch_to_host }); if switch_to_host { @@ -242,6 +266,7 @@ struct SignalState { saved_sigfpe: SigAction, saved_sigill: SigAction, saved_sigsegv: SigAction, + saved_sigalrm: SigAction, saved_panic_hook: Option) + Sync + Send + 'static>>>, } @@ -254,6 +279,7 @@ unsafe fn setup_guest_signal_state(ostate: &mut Option) { masked_signals.add(Signal::SIGFPE); masked_signals.add(Signal::SIGILL); masked_signals.add(Signal::SIGSEGV); + masked_signals.add(Signal::SIGALRM); // setup signal handlers let sa = SigAction::new( @@ -265,6 +291,7 @@ unsafe fn setup_guest_signal_state(ostate: &mut Option) { let saved_sigfpe = sigaction(Signal::SIGFPE, &sa).expect("sigaction succeeds"); let saved_sigill = sigaction(Signal::SIGILL, &sa).expect("sigaction succeeds"); let saved_sigsegv = sigaction(Signal::SIGSEGV, &sa).expect("sigaction succeeds"); + let saved_sigalrm = sigaction(Signal::SIGALRM, &sa).expect("sigaction succeeds"); let saved_panic_hook = Some(setup_guest_panic_hook()); @@ -274,6 +301,7 @@ unsafe fn setup_guest_signal_state(ostate: &mut Option) { saved_sigfpe, saved_sigill, saved_sigsegv, + saved_sigalrm, saved_panic_hook, }); } @@ -303,6 +331,7 @@ unsafe fn restore_host_signal_state(state: &mut SignalState) { sigaction(Signal::SIGFPE, &state.saved_sigfpe).expect("sigaction succeeds"); sigaction(Signal::SIGILL, &state.saved_sigill).expect("sigaction succeeds"); sigaction(Signal::SIGSEGV, &state.saved_sigsegv).expect("sigaction succeeds"); + sigaction(Signal::SIGALRM, &state.saved_sigalrm).expect("sigaction succeeds"); // restore panic hook drop(panic::take_hook()); @@ -327,6 +356,7 @@ unsafe fn reraise_host_signal_in_handler( Signal::SIGFPE => state.saved_sigfpe.clone(), Signal::SIGILL => state.saved_sigill.clone(), Signal::SIGSEGV => state.saved_sigsegv.clone(), + Signal::SIGALRM => state.saved_sigalrm.clone(), sig => panic!( "unexpected signal in reraise_host_signal_in_handler: {:?}", sig diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index 61897a38e..3949ad3a9 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -363,6 +363,7 @@ impl Vmctx { val: YieldedVal::new(val), expecting: expecting as Box, }; + HOST_CTX.with(|host_ctx| unsafe { Context::swap(&mut inst.ctx, &mut *host_ctx.get()) }); } @@ -411,7 +412,7 @@ impl Instance { /// /// This is almost certainly not what you want to use to terminate from a hostcall; use panics /// with `TerminationDetails` instead. - unsafe fn terminate(&mut self, details: TerminationDetails) -> ! { + pub(crate) unsafe fn terminate(&mut self, details: TerminationDetails) -> ! { self.state = State::Terminating { details }; #[allow(unused_unsafe)] // The following unsafe will be incorrectly warned as unused HOST_CTX.with(|host_ctx| unsafe { Context::set(&*host_ctx.get()) }) diff --git a/lucet-runtime/lucet-runtime-tests/guests/timeout/bindings.json b/lucet-runtime/lucet-runtime-tests/guests/timeout/bindings.json new file mode 100644 index 000000000..5f45274a8 --- /dev/null +++ b/lucet-runtime/lucet-runtime-tests/guests/timeout/bindings.json @@ -0,0 +1,4 @@ +{ + "env": { + } +} diff --git a/lucet-runtime/lucet-runtime-tests/guests/timeout/fault.c b/lucet-runtime/lucet-runtime-tests/guests/timeout/fault.c new file mode 100644 index 000000000..948072dec --- /dev/null +++ b/lucet-runtime/lucet-runtime-tests/guests/timeout/fault.c @@ -0,0 +1,8 @@ +int main() { + char* invalid = (char*)0x12345678; + char c = *invalid; +} + +int onetwothree() { + return 123; +} diff --git a/lucet-runtime/lucet-runtime-tests/guests/timeout/inf_loop.c b/lucet-runtime/lucet-runtime-tests/guests/timeout/inf_loop.c new file mode 100644 index 000000000..3fca49c6d --- /dev/null +++ b/lucet-runtime/lucet-runtime-tests/guests/timeout/inf_loop.c @@ -0,0 +1,4 @@ +int main() { + while(1) {} + return 0; +} diff --git a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs index ff898eff6..3615f04eb 100644 --- a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs +++ b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs @@ -124,11 +124,11 @@ pub fn mock_traps_module() -> Arc { macro_rules! guest_fault_tests { ( $TestRegion:path ) => { use lazy_static::lazy_static; - use libc::{c_void, siginfo_t, SIGSEGV}; + use libc::{c_void, pthread_kill, pthread_self, siginfo_t, SIGALRM, SIGSEGV}; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime::{ lucet_hostcall_terminate, lucet_hostcalls, DlModule, Error, FaultDetails, Instance, - Limits, Region, SignalBehavior, TrapCode, + Limits, Region, SignalBehavior, TerminationDetails, TrapCode, }; use nix::sys::mman::{mmap, MapFlags, ProtFlags}; use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal}; @@ -455,57 +455,6 @@ macro_rules! guest_fault_tests { }) } - #[test] - fn alarm() { - extern "C" fn timeout_handler(signum: libc::c_int) { - assert!(signum == libc::SIGALRM); - std::process::exit(3); - } - test_ex(|| { - let module = mock_traps_module(); - let region = - TestRegion::create(1, &Limits::default()).expect("region can be created"); - let mut inst = region - .new_instance(module) - .expect("instance can be created"); - - inst.set_fatal_handler(fatal_handler_exit); - - match fork().expect("can fork") { - ForkResult::Child => { - // set up alarm handler and pend an alarm in 1 second - unsafe { - // child process doesn't have any contention for installed signal handlers, so - // we don't need to grab the lock exclusively here - sigaction( - Signal::SIGALRM, - &SigAction::new( - SigHandler::Handler(timeout_handler), - SaFlags::empty(), - SigSet::empty(), - ), - ) - .expect("sigaction succeeds"); - } - nix::unistd::alarm::set(1); - - // run guest code that loops forever - inst.run("infinite_loop", &[]).expect("instance runs"); - // show that we never get here - std::process::exit(1); - } - ForkResult::Parent { child } => { - match waitpid(Some(child), None).expect("can wait on child") { - WaitStatus::Exited(_, code) => { - assert_eq!(code, 3); - } - ws => panic!("unexpected wait status: {:?}", ws), - } - } - } - }) - } - #[test] fn sigsegv_handler_during_guest() { lazy_static! { diff --git a/lucet-runtime/lucet-runtime-tests/src/lib.rs b/lucet-runtime/lucet-runtime-tests/src/lib.rs index 9d2d11feb..a9c3da653 100644 --- a/lucet-runtime/lucet-runtime-tests/src/lib.rs +++ b/lucet-runtime/lucet-runtime-tests/src/lib.rs @@ -8,3 +8,4 @@ pub mod memory; pub mod stack; pub mod start; pub mod strcmp; +pub mod timeout; diff --git a/lucet-runtime/lucet-runtime-tests/src/timeout.rs b/lucet-runtime/lucet-runtime-tests/src/timeout.rs new file mode 100644 index 000000000..88fa04cce --- /dev/null +++ b/lucet-runtime/lucet-runtime-tests/src/timeout.rs @@ -0,0 +1,324 @@ +use crate::helpers::{MockExportBuilder, MockModuleBuilder}; +use lucet_module::FunctionPointer; +use lucet_runtime_internals::module::Module; +use lucet_runtime_internals::vmctx::lucet_vmctx; +use std::sync::Arc; + +pub fn mock_timeout_module() -> Arc { + extern "C" fn onetwothree(_vmctx: *mut lucet_vmctx) -> std::os::raw::c_int { + 123 + } + + extern "C" fn infinite_loop(_vmctx: *mut lucet_vmctx) -> () { + loop {} + } + + extern "C" fn do_nothing(_vmctx: *mut lucet_vmctx) -> () {} + + extern "C" fn run_slow_hostcall(vmctx: *mut lucet_vmctx) -> bool { + extern "C" { + fn slow_hostcall(vmctx: *mut lucet_vmctx) -> bool; + } + unsafe { slow_hostcall(vmctx) } + } + + extern "C" fn run_yielding_hostcall(vmctx: *mut lucet_vmctx) -> () { + extern "C" { + fn yielding_hostcall(vmctx: *mut lucet_vmctx) -> (); + } + unsafe { yielding_hostcall(vmctx) } + } + + MockModuleBuilder::new() + .with_export_func(MockExportBuilder::new( + "infinite_loop", + FunctionPointer::from_usize(infinite_loop as usize), + )) + .with_export_func(MockExportBuilder::new( + "do_nothing", + FunctionPointer::from_usize(do_nothing as usize), + )) + .with_export_func(MockExportBuilder::new( + "onetwothree", + FunctionPointer::from_usize(onetwothree as usize), + )) + .with_export_func(MockExportBuilder::new( + "run_slow_hostcall", + FunctionPointer::from_usize(run_slow_hostcall as usize), + )) + .with_export_func(MockExportBuilder::new( + "run_yielding_hostcall", + FunctionPointer::from_usize(run_yielding_hostcall as usize), + )) + .build() +} + +#[macro_export] +macro_rules! timeout_tests { + ( $TestRegion:path ) => { + use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; + use lucet_runtime::{ + lucet_hostcall_terminate, lucet_hostcalls, DlModule, Error, FaultDetails, Instance, + KillError, KillSuccess, Limits, Region, RunResult, SignalBehavior, TerminationDetails, + TrapCode, YieldedVal, + }; + use nix::sys::mman::{mmap, MapFlags, ProtFlags}; + use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal}; + use nix::sys::wait::{waitpid, WaitStatus}; + use nix::unistd::{fork, ForkResult}; + use std::ptr; + use std::sync::{Arc, Mutex}; + use std::thread; + use std::time::Duration; + use $TestRegion as TestRegion; + use $crate::build::test_module_c; + use $crate::helpers::{FunctionPointer, MockExportBuilder, MockModuleBuilder}; + use $crate::timeout::mock_timeout_module; + + lucet_hostcalls! { + #[no_mangle] + pub unsafe extern "C" fn slow_hostcall( + &mut vmctx, + ) -> bool { + // make a window of time so we can timeout in a hostcall + thread::sleep(Duration::from_millis(200)); + true + } + + #[no_mangle] + pub unsafe extern "C" fn yielding_hostcall( + &mut vmctx, + ) -> () { + vmctx.yield_(); + } + } + + fn run_onetwothree(inst: &mut Instance) { + let retval = inst + .run("onetwothree", &[]) + .expect("instance runs") + .unwrap_returned(); + assert_eq!(libc::c_int::from(retval), 123); + } + + #[test] + fn timeout_in_guest() { + let module = mock_timeout_module(); + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + let kill_switch = inst.kill_switch(); + + thread::spawn(move || { + thread::sleep(Duration::from_millis(100)); + assert_eq!(kill_switch.terminate(), Ok(KillSuccess::Signalled)); + }); + + match inst.run("infinite_loop", &[]) { + Err(Error::RuntimeTerminated(TerminationDetails::Remote)) => { + // this is what we want to see + } + res => panic!("unexpected result: {:?}", res), + } + + // after a timeout, can reset and run a normal function + inst.reset().expect("instance resets"); + + run_onetwothree(&mut inst); + } + + #[test] + fn timeout_before_guest() { + let module = mock_timeout_module(); + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + let kill_switch = inst.kill_switch(); + assert_eq!(kill_switch.terminate(), Err(KillError::NotTerminable)); + + // not being terminable, the instance still runs and is unaffected + run_onetwothree(&mut inst); + } + + #[test] + fn timeout_after_guest() { + let module = mock_timeout_module(); + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + match inst.run("do_nothing", &[]) { + Ok(_) => {} + res => panic!("unexpected result: {:?}", res), + } + + let kill_switch = inst.kill_switch(); + assert_eq!(kill_switch.terminate(), Err(KillError::NotTerminable)); + + // after a timeout, can reset and run a normal function + inst.reset().expect("instance resets"); + + run_onetwothree(&mut inst); + } + + #[test] + fn timeout_after_guest_fault() { + let module = test_module_c("timeout", "fault.c").expect("build and load module"); + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + match inst.run("main", &[0u32.into(), 0u32.into()]) { + Err(Error::RuntimeFault(details)) => { + assert_eq!(details.trapcode, Some(TrapCode::HeapOutOfBounds)); + } + res => panic!("unexpected result: {:?}", res), + } + + let kill_switch = inst.kill_switch(); + assert_eq!(kill_switch.terminate(), Err(KillError::NotTerminable)); + + // after a timeout, can reset and run a normal function + inst.reset().expect("instance resets"); + + run_onetwothree(&mut inst); + } + + #[test] + fn timeout_in_hostcall() { + let module = mock_timeout_module(); + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + let kill_switch = inst.kill_switch(); + + thread::spawn(move || { + thread::sleep(Duration::from_millis(100)); + assert_eq!(kill_switch.terminate(), Ok(KillSuccess::Pending)); + }); + + match inst.run("run_slow_hostcall", &[]) { + Err(Error::RuntimeTerminated(TerminationDetails::Remote)) => {} + res => panic!("unexpected result: {:?}", res), + } + + // after a timeout, can reset and run a normal function + inst.reset().expect("instance resets"); + + run_onetwothree(&mut inst); + } + + #[test] + fn timeout_while_yielded() { + let module = mock_timeout_module(); + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + let kill_switch = inst.kill_switch(); + + thread::spawn(move || { + thread::sleep(Duration::from_millis(100)); + assert_eq!(kill_switch.terminate(), Ok(KillSuccess::Pending)); + }); + + match inst.run("run_yielding_hostcall", &[]) { + Ok(RunResult::Yielded(EmptyYieldVal)) => {} + res => panic!("unexpected result: {:?}", res), + } + + println!("waiting......"); + + // wait for the timeout to expire + thread::sleep(Duration::from_millis(200)); + + match inst.resume() { + Err(Error::RuntimeTerminated(TerminationDetails::Remote)) => {} + res => panic!("unexpected result: {:?}", res), + } + + // after a timeout, can reset and run a normal function + inst.reset().expect("instance resets"); + + run_onetwothree(&mut inst); + } + + #[test] + fn timeout_killswitch_reuse() { + let module = test_module_c("timeout", "inf_loop.c").expect("build and load module"); + + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + let kill_switch = inst.kill_switch(); + + let t = thread::spawn(move || { + assert!(kill_switch.terminate().is_err()); // fails too soon + thread::sleep(Duration::from_millis(100)); + assert!(kill_switch.terminate().is_ok()); // works + thread::sleep(Duration::from_millis(100)); + assert!(kill_switch.terminate().is_err()); // fails too soon + }); + + thread::sleep(Duration::from_millis(10)); + + match inst.run("main", &[0u32.into(), 0u32.into()]) { + // the result we're expecting - the guest has been terminated! + Err(Error::RuntimeTerminated(TerminationDetails::Remote)) => {} + res => { + panic!("unexpected result: {:?}", res); + } + }; + + t.join().unwrap(); + } + + #[test] + fn double_timeout() { + let module = mock_timeout_module(); + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + let kill_switch = inst.kill_switch(); + let second_kill_switch = inst.kill_switch(); + + thread::spawn(move || { + thread::sleep(Duration::from_millis(100)); + assert_eq!(kill_switch.terminate(), Ok(KillSuccess::Signalled)); + }); + + thread::spawn(move || { + thread::sleep(Duration::from_millis(200)); + assert_eq!( + second_kill_switch.terminate(), + Err(KillError::NotTerminable) + ); + }); + + match inst.run("infinite_loop", &[]) { + Err(Error::RuntimeTerminated(TerminationDetails::Remote)) => { + // this is what we want to see + } + res => panic!("unexpected result: {:?}", res), + } + + // after a timeout, can reset and run a normal function + inst.reset().expect("instance resets"); + + run_onetwothree(&mut inst); + } + }; +} diff --git a/lucet-runtime/src/c_api.rs b/lucet-runtime/src/c_api.rs index d8ab48187..c1886c223 100644 --- a/lucet-runtime/src/c_api.rs +++ b/lucet-runtime/src/c_api.rs @@ -5,7 +5,6 @@ use lucet_runtime_internals::c_api::*; use lucet_runtime_internals::instance::{ instance_handle_from_raw, instance_handle_to_raw, InstanceInternal, }; -use lucet_runtime_internals::vmctx::VmctxInternal; use lucet_runtime_internals::WASM_PAGE_SIZE; use lucet_runtime_internals::{ assert_nonnull, lucet_hostcall_terminate, lucet_hostcalls, with_ffi_arcs, diff --git a/lucet-runtime/src/lib.rs b/lucet-runtime/src/lib.rs index fd5511773..df5bbc450 100644 --- a/lucet-runtime/src/lib.rs +++ b/lucet-runtime/src/lib.rs @@ -346,8 +346,8 @@ pub use lucet_module::{PublicKey, TrapCode}; pub use lucet_runtime_internals::alloc::Limits; pub use lucet_runtime_internals::error::Error; pub use lucet_runtime_internals::instance::{ - FaultDetails, Instance, InstanceHandle, RunResult, SignalBehavior, TerminationDetails, - YieldedVal, + FaultDetails, Instance, InstanceHandle, KillError, KillSuccess, RunResult, SignalBehavior, + TerminationDetails, YieldedVal, }; pub use lucet_runtime_internals::module::{DlModule, Module}; pub use lucet_runtime_internals::region::mmap::MmapRegion; diff --git a/lucet-runtime/tests/timeout.rs b/lucet-runtime/tests/timeout.rs new file mode 100644 index 000000000..9c2f044ed --- /dev/null +++ b/lucet-runtime/tests/timeout.rs @@ -0,0 +1,3 @@ +use lucet_runtime_tests::timeout_tests; + +timeout_tests!(lucet_runtime::MmapRegion); diff --git a/lucet-wasi/src/main.rs b/lucet-wasi/src/main.rs index 7919e3662..f074d1255 100644 --- a/lucet-wasi/src/main.rs +++ b/lucet-wasi/src/main.rs @@ -10,6 +10,8 @@ use lucet_wasi::{hostcalls, WasiCtxBuilder}; use std::fs::File; use std::path::PathBuf; use std::sync::Arc; +use std::thread; +use std::time::Duration; struct Config<'a> { lucet_module: &'a str, @@ -17,6 +19,7 @@ struct Config<'a> { entrypoint: &'a str, preopen_dirs: Vec<(File, &'a str)>, limits: Limits, + timeout: Option, verify: bool, pk_path: Option, } @@ -96,6 +99,9 @@ fn main() { .default_value("8 MiB") .help("Maximum stack size (must be a multiple of 4 KiB)"), ) + .arg( + Arg::with_name("timeout").long("timeout").takes_value(true).help("Number of milliseconds the instance will be allowed to run") + ) .arg( Arg::with_name("guest_args") .required(false) @@ -163,6 +169,10 @@ fn main() { .and_then(|v| parse_humansized(v)) .unwrap() as usize; + let timeout = matches + .value_of("timeout") + .map(|t| Duration::from_millis(t.parse::().unwrap())); + let limits = Limits { heap_memory_size, heap_address_space_size, @@ -184,6 +194,7 @@ fn main() { entrypoint, preopen_dirs, limits, + timeout, verify, pk_path, }; @@ -237,6 +248,16 @@ fn run(config: Config<'_>) { .build() .expect("instance can be created"); + if let Some(timeout) = config.timeout { + let kill_switch = inst.kill_switch(); + thread::spawn(move || { + thread::sleep(timeout); + // We may hit this line exactly when the guest exits, so sometimes `terminate` can + // fail. That's still acceptable, so just ignore the result. + kill_switch.terminate().ok(); + }); + } + match inst.run(config.entrypoint, &[]) { // normal termination implies 0 exit code Ok(RunResult::Returned(_)) => 0, @@ -247,6 +268,12 @@ fn run(config: Config<'_>) { )) => *any .downcast_ref::() .expect("termination yields an exitcode"), + Err(lucet_runtime::Error::RuntimeTerminated( + lucet_runtime::TerminationDetails::Remote, + )) => { + println!("Terminated via remote kill switch (likely a timeout)"); + std::u32::MAX + } Err(e) => panic!("lucet-wasi runtime error: {}", e), } }; From d8e52f1009a19b7bd4e2fce9a97ea34fa72bfe4d Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Thu, 17 Oct 2019 12:47:19 -0700 Subject: [PATCH 435/512] [lucetc] add very basic JSON formatting for errors This is meant to be a starting point for more semantic error reporting, but in order to get there we'll need to do a broader refactor of our error types --- Cargo.lock | 2 ++ lucetc/Cargo.toml | 2 ++ lucetc/src/main.rs | 33 +++++++++++++++++++++++---------- lucetc/src/options.rs | 28 ++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 60679b28e..dbec9d664 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1012,6 +1012,8 @@ dependencies = [ "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index daa77aabd..8ac477710 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -44,6 +44,8 @@ human-size = "0.4" parity-wasm = "0.38" minisign = "0.5.11" memoffset = "0.5.1" +serde = "1.0" +serde_json = "1.0" [package.metadata.deb] name = "fst-lucetc" diff --git a/lucetc/src/main.rs b/lucetc/src/main.rs index f44dc9f3b..2832815c6 100644 --- a/lucetc/src/main.rs +++ b/lucetc/src/main.rs @@ -1,6 +1,6 @@ mod options; -use crate::options::{CodegenOutput, Options}; +use crate::options::{CodegenOutput, ErrorStyle, Options}; use failure::{format_err, Error, ResultExt}; use log::info; use lucet_module::bindings::Bindings; @@ -9,25 +9,38 @@ use lucetc::{ signature::{self, PublicKey}, Lucetc, LucetcOpts, }; -use std::io::{self, Write}; +use serde::Serialize; +use serde_json; use std::path::PathBuf; use std::process; +#[derive(Clone, Debug, Serialize)] +pub struct SerializedLucetcError { + error: String, +} + +impl From for SerializedLucetcError { + fn from(e: Error) -> Self { + SerializedLucetcError { + error: format!("{}", e), + } + } +} + fn main() { env_logger::init(); let opts = Options::get().unwrap(); if let Err(err) = run(&opts) { - let mut msg = format!("Error: {}.", err); - if let Some(cause) = err.as_fail().cause() { - msg.push(' '); - msg.push_str(&format!("{}", cause)); - } - if !msg.ends_with('\n') { - msg.push('\n'); + match opts.error_style { + ErrorStyle::Human => eprintln!("Error: {}\n", err), + ErrorStyle::Json => { + let s: SerializedLucetcError = err.into(); + let json = serde_json::to_string(&s).unwrap(); + eprintln!("{}", json); + } } - io::stderr().write_all(msg.as_bytes()).unwrap(); process::exit(1); } } diff --git a/lucetc/src/options.rs b/lucetc/src/options.rs index 85401e99d..d6b4da72d 100644 --- a/lucetc/src/options.rs +++ b/lucetc/src/options.rs @@ -10,6 +10,18 @@ pub enum CodegenOutput { SharedObj, } +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ErrorStyle { + Human, + Json, +} + +impl Default for ErrorStyle { + fn default() -> Self { + ErrorStyle::Human + } +} + fn parse_humansized(desc: &str) -> Result { use human_size::{Byte, ParsingError, Size, SpecificSize}; match desc.parse::() { @@ -49,6 +61,7 @@ pub struct Options { pub pk_path: Option, pub sk_path: Option, pub count_instructions: bool, + pub error_style: ErrorStyle, } impl Options { @@ -123,6 +136,13 @@ impl Options { let pk_path = m.value_of("pk_path").map(PathBuf::from); let count_instructions = m.is_present("count_instructions"); + let error_style = match m.value_of("error_style") { + None => ErrorStyle::default(), + Some("human") => ErrorStyle::Human, + Some("json") => ErrorStyle::Json, + Some(_) => panic!("unknown value for error-style"), + }; + Ok(Options { output, input, @@ -142,6 +162,7 @@ impl Options { sk_path, pk_path, count_instructions, + error_style, }) } pub fn get() -> Result { @@ -279,6 +300,13 @@ impl Options { .takes_value(false) .help("Instrument the produced binary to count the number of wasm operations the translated program executes") ) + .arg( + Arg::with_name("error_style") + .long("error-style") + .takes_value(true) + .possible_values(&["human", "json"]) + .help("Style of error reporting (default: human)"), + ) .get_matches(); Self::from_args(&m) From 34c4bcc2f334b33e1404f4b5658f12bbb726021f Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Thu, 17 Oct 2019 14:59:27 -0700 Subject: [PATCH 436/512] [lucet-runtime] relax unnecessary restrictions on some functions - The `Send + Sync` restriction on the downcast methods was leftover from before the `State` refactor lifted those restrictions from `YieldedVal`s - The mutable borrow on `Instance::get_embed_ctx_mut()` is checked at runtime by the `RefCell`s inside the underlying map. This patch gives us fewer compile-time guarantees, but holding a mutable borrow on the entire instance just to get at an embedding context is way too strict --- lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs | 4 ++-- lucet-runtime/lucet-runtime-internals/src/instance.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs b/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs index 808390545..55147dea2 100644 --- a/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs @@ -30,8 +30,8 @@ impl CtxMap { }) } - pub fn try_get_mut(&mut self) -> Option, BorrowMutError>> { - self.map.get_mut(&TypeId::of::()).map(|x| { + pub fn try_get_mut(&self) -> Option, BorrowMutError>> { + self.map.get(&TypeId::of::()).map(|x| { x.try_borrow_mut().map(|r| { RefMut::map(r, |b| { b.downcast_mut::() diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index 08d8dc119..536a10fba 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -623,7 +623,7 @@ impl Instance { } /// Get a mutable reference to a context value of a particular type, if it exists. - pub fn get_embed_ctx_mut(&mut self) -> Option, BorrowMutError>> { + pub fn get_embed_ctx_mut(&self) -> Option, BorrowMutError>> { self.embed_ctx.try_get_mut::() } @@ -1156,7 +1156,7 @@ impl YieldedVal { /// Attempt to downcast the yielded value to a concrete type, returning the original /// `YieldedVal` if unsuccessful. - pub fn downcast(self) -> Result, YieldedVal> { + pub fn downcast(self) -> Result, YieldedVal> { match self.val.downcast() { Ok(val) => Ok(val), Err(val) => Err(YieldedVal { val }), @@ -1165,7 +1165,7 @@ impl YieldedVal { /// Returns a reference to the yielded value if it is present and of type `A`, or `None` if it /// isn't. - pub fn downcast_ref(&self) -> Option<&A> { + pub fn downcast_ref(&self) -> Option<&A> { self.val.downcast_ref() } } From abdd42bc43bfa1b9ea9fc1b124199b3c6f5f81c8 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Thu, 17 Oct 2019 15:16:12 -0700 Subject: [PATCH 437/512] tests run again --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 565e650f6..9eec9bb4d 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ test-except-fuzz: -p lucet-wasi \ -p lucet-wasi-fuzz \ -p lucet-benchmarks \ - -p lucet-validate \ + -p lucet-validate helpers/lucet-toolchain-tests/signature.sh # run a single seed through the fuzzer to stave off bitrot From 82bcc682754841f9e398207074c7ac27577d2ff0 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Thu, 17 Oct 2019 15:23:58 -0700 Subject: [PATCH 438/512] fix the number of magic globals that wasi-sdk clang creates --- lucet-wasi-sdk/tests/lucetc.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lucet-wasi-sdk/tests/lucetc.rs b/lucet-wasi-sdk/tests/lucetc.rs index 9c94f52a7..1714f0fce 100644 --- a/lucet-wasi-sdk/tests/lucetc.rs +++ b/lucet-wasi-sdk/tests/lucetc.rs @@ -48,8 +48,8 @@ mod lucetc_tests { Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile empty"); let mdata = c.module_data().unwrap(); assert!(mdata.heap_spec().is_some()); - // clang creates 1 global, which is not exported.: - assert_eq!(mdata.globals_spec().len(), 1); + // clang creates 3 globals, which are not exported.: + assert_eq!(mdata.globals_spec().len(), 3); assert!(mdata.globals_spec()[0].is_internal()); assert_eq!(mdata.import_functions().len(), 0, "import functions"); From 69a86ef635ac15cfa7cbd448417c7ae090132c61 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 17 Oct 2019 16:00:01 -0700 Subject: [PATCH 439/512] fix lucet-wasi-sdk test for wask-sdk-7 --- lucet-wasi-sdk/tests/lucetc.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lucet-wasi-sdk/tests/lucetc.rs b/lucet-wasi-sdk/tests/lucetc.rs index 1714f0fce..e54212f75 100644 --- a/lucet-wasi-sdk/tests/lucetc.rs +++ b/lucet-wasi-sdk/tests/lucetc.rs @@ -48,8 +48,8 @@ mod lucetc_tests { Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile empty"); let mdata = c.module_data().unwrap(); assert!(mdata.heap_spec().is_some()); - // clang creates 3 globals, which are not exported.: - assert_eq!(mdata.globals_spec().len(), 3); + // clang creates just 1 global: + assert_eq!(mdata.globals_spec().len(), 1); assert!(mdata.globals_spec()[0].is_internal()); assert_eq!(mdata.import_functions().len(), 0, "import functions"); From fac8ee596846847ce24e06da987378440c8ba7e6 Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Fri, 18 Oct 2019 11:00:11 -0700 Subject: [PATCH 440/512] allow KillState's `exit_guest_region` to be name-mangled --- .../lucet-runtime-internals/src/context/context_asm.S | 7 ++----- lucet-runtime/lucet-runtime-internals/src/context/mod.rs | 7 ++++++- .../lucet-runtime-internals/src/instance/execution.rs | 3 +-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/context/context_asm.S b/lucet-runtime/lucet-runtime-internals/src/context/context_asm.S index 287b03d6a..6feb06e01 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/context_asm.S +++ b/lucet-runtime/lucet-runtime-internals/src/context/context_asm.S @@ -73,11 +73,8 @@ _lucet_context_backstop: // load instance pointer, arg 1 mov 16(%rbp), %rdi -#ifdef __ELF__ - call instance_kill_state_exit_guest_region@PLT -#else - call instance_kill_state_exit_guest_region -#endif + // call `lucet_runtime_internals::instance::execution::exit_guest_region` + call *24(%rbp) mov (%rbp), %rdi /* parent context to arg 1 */ mov 8(%rbp), %rsi /* own context to arg 2 */ diff --git a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs index 88bc24cf5..995a09440 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs @@ -407,7 +407,12 @@ impl Context { // set up an initial call stack for guests to bootstrap into and execute let mut stack_builder = CallStackBuilder::new(stack); - // store a pointer to the context swap completion flag, to signal the guest has activated + // pass this crate's `exit_guest_region` function pointer, so we can allow + // `exit_guest_function` to be name mangled. Mangling is beneficial as it allows multiple + // crates to depend on `lucet-runtime-internals` without linker conflicts. + stack_builder.push(crate::instance::execution::exit_guest_region as u64); + + // store a pointer to kill state, which the guest interacts with to safely exit stack_builder.push(kill_state as u64); // store arguments we'll pass to `lucet_context_swap` on the stack, above where the guest diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/execution.rs b/lucet-runtime/lucet-runtime-internals/src/instance/execution.rs index da21c0092..fe8e32074 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/execution.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/execution.rs @@ -125,8 +125,7 @@ pub struct KillState { tid_change_notifier: Condvar, } -#[no_mangle] -pub unsafe extern "C" fn instance_kill_state_exit_guest_region(kill_state: *mut KillState) { +pub unsafe extern "C" fn exit_guest_region(kill_state: *mut KillState) { let terminable = (*kill_state).terminable.swap(false, Ordering::SeqCst); if !terminable { // Something else has taken the terminable flag, so it's not safe to actually exit a From ebf4f5138a44941aaa0a1011c3da967264c6978e Mon Sep 17 00:00:00 2001 From: awortman-fastly <49215183+awortman-fastly@users.noreply.github.com> Date: Fri, 18 Oct 2019 16:13:31 -0700 Subject: [PATCH 441/512] Bump versions to 0.3.0 (#340) * 0.3.0 * lucetc error messages include the underlying error from wabt * lucet-runtime supports timeouts * lucetc can emit errors as json * lucet-runtime removes unnecessary restrictions on some functions wabt update is necessary to avoid linker issues with multiple wabt in use at once --- Cargo.lock | 151 ++++++++---------- Cargo.toml | 2 +- benchmarks/lucet-benchmarks/Cargo.toml | 2 +- lucet-module/Cargo.toml | 2 +- lucet-objdump/Cargo.toml | 4 +- lucet-runtime/Cargo.toml | 12 +- .../lucet-runtime-internals/Cargo.toml | 4 +- lucet-runtime/lucet-runtime-tests/Cargo.toml | 10 +- lucet-spectest/Cargo.toml | 10 +- lucet-spectest/src/lib.rs | 11 +- lucet-validate/Cargo.toml | 6 +- lucet-wasi-fuzz/Cargo.toml | 2 +- lucet-wasi-sdk/Cargo.toml | 8 +- lucet-wasi/Cargo.toml | 12 +- lucetc/Cargo.toml | 8 +- 15 files changed, 115 insertions(+), 129 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dbec9d664..c2a0e3817 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -760,15 +760,15 @@ dependencies = [ [[package]] name = "lucet-benchmarks" -version = "0.2.1" +version = "0.3.0" dependencies = [ "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.2.1", - "lucet-runtime 0.2.1", - "lucet-runtime-internals 0.2.1", - "lucet-wasi 0.2.1", - "lucet-wasi-sdk 0.2.1", - "lucetc 0.2.1", + "lucet-module 0.3.0", + "lucet-runtime 0.3.0", + "lucet-runtime-internals 0.3.0", + "lucet-wasi 0.3.0", + "lucet-wasi-sdk 0.3.0", + "lucetc 0.3.0", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -783,8 +783,8 @@ dependencies = [ "cranelift-entity 0.44.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.2.1", - "lucetc 0.2.1", + "lucet-module 0.3.0", + "lucetc 0.3.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -800,10 +800,10 @@ dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-idl 0.2.0", - "lucet-runtime 0.2.1", - "lucet-wasi 0.2.1", - "lucet-wasi-sdk 0.2.1", - "lucetc 0.2.1", + "lucet-runtime 0.3.0", + "lucet-wasi 0.3.0", + "lucet-wasi-sdk 0.3.0", + "lucetc 0.3.0", "proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -816,13 +816,13 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-idl 0.2.0", - "lucet-runtime 0.2.1", - "lucet-wasi 0.2.1", + "lucet-runtime 0.3.0", + "lucet-wasi 0.3.0", ] [[package]] name = "lucet-module" -version = "0.2.1" +version = "0.3.0" dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -839,28 +839,28 @@ dependencies = [ [[package]] name = "lucet-objdump" -version = "0.2.1" +version = "0.3.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.2.1", + "lucet-module 0.3.0", ] [[package]] name = "lucet-runtime" -version = "0.2.1" +version = "0.3.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.2.1", - "lucet-runtime-internals 0.2.1", - "lucet-runtime-tests 0.2.1", - "lucet-wasi-sdk 0.2.1", - "lucetc 0.2.1", + "lucet-module 0.3.0", + "lucet-runtime-internals 0.3.0", + "lucet-runtime-tests 0.3.0", + "lucet-wasi-sdk 0.3.0", + "lucetc 0.3.0", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -870,7 +870,7 @@ dependencies = [ [[package]] name = "lucet-runtime-internals" -version = "0.2.1" +version = "0.3.0" dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -881,7 +881,7 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.2.1", + "lucet-module 0.3.0", "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -891,50 +891,50 @@ dependencies = [ [[package]] name = "lucet-runtime-tests" -version = "0.2.1" +version = "0.3.0" dependencies = [ "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.2.1", - "lucet-runtime-internals 0.2.1", - "lucet-wasi-sdk 0.2.1", - "lucetc 0.2.1", + "lucet-module 0.3.0", + "lucet-runtime-internals 0.3.0", + "lucet-wasi-sdk 0.3.0", + "lucetc 0.3.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucet-spectest" -version = "0.2.1" +version = "0.3.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.2.1", - "lucet-runtime 0.2.1", - "lucetc 0.2.1", + "lucet-module 0.3.0", + "lucet-runtime 0.3.0", + "lucetc 0.3.0", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucet-validate" -version = "0.2.1" +version = "0.3.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.44.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-wasi-sdk 0.2.1", + "lucet-wasi-sdk 0.3.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", "witx 0.3.0", ] [[package]] name = "lucet-wasi" -version = "0.2.1" +version = "0.3.0" dependencies = [ "bindgen 0.47.3 (registry+https://github.com/rust-lang/crates.io-index)", "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -942,11 +942,11 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.2.1", - "lucet-runtime 0.2.1", - "lucet-runtime-internals 0.2.1", - "lucet-wasi-sdk 0.2.1", - "lucetc 0.2.1", + "lucet-module 0.3.0", + "lucet-runtime 0.3.0", + "lucet-runtime-internals 0.3.0", + "lucet-wasi-sdk 0.3.0", + "lucetc 0.3.0", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -954,16 +954,16 @@ dependencies = [ [[package]] name = "lucet-wasi-fuzz" -version = "0.2.1" +version = "0.3.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.2.1", - "lucet-runtime 0.2.1", - "lucet-wasi 0.2.1", - "lucet-wasi-sdk 0.2.1", - "lucetc 0.2.1", + "lucet-module 0.3.0", + "lucet-runtime 0.3.0", + "lucet-wasi 0.3.0", + "lucet-wasi-sdk 0.3.0", + "lucetc 0.3.0", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -977,18 +977,18 @@ dependencies = [ [[package]] name = "lucet-wasi-sdk" -version = "0.2.1" +version = "0.3.0" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.2.1", - "lucet-validate 0.2.1", - "lucetc 0.2.1", + "lucet-module 0.3.0", + "lucet-validate 0.3.0", + "lucetc 0.3.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucetc" -version = "0.2.1" +version = "0.3.0" dependencies = [ "bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1007,8 +1007,8 @@ dependencies = [ "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.2.1", - "lucet-validate 0.2.1", + "lucet-module 0.3.0", + "lucet-validate 0.3.0", "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1016,7 +1016,7 @@ dependencies = [ "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wabt 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasmonkey 0.1.8", "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1880,39 +1880,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "wabt" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wabt" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "wabt-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wabt-sys" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", - "cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wabt-sys" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2219,10 +2198,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "74e463a508e390cc7447e70f640fbf44ad52e1bd095314ace1fdf99516d32add" -"checksum wabt 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "94b5f5d6984ca42df66280baa8a15ac188a173ddaf4580b574a98931c01920e7" -"checksum wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a6265b25719e82598d104b3717375e37661d41753e2c84cde3f51050c7ed7e3c" -"checksum wabt-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b064c81821100adb4b71923cecfc67fef083db21c3bbd454b0162c7ffe63eeaa" +"checksum wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3c5c5c1286c6e578416982609f47594265f9d489f9b836157d403ad605a46693" +"checksum wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af5d153dc96aad7dc13ab90835b892c69867948112d95299e522d370c4e13a08" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" "checksum wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a026c1436af49d5537c7561c7474f81f7a754e36445fe52e6e88795a9747291c" diff --git a/Cargo.toml b/Cargo.toml index ab9de2b37..d1eb02de1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,4 @@ -# Lucet version 0.2.1 +# Lucet version 0.3.0 [workspace] members = [ diff --git a/benchmarks/lucet-benchmarks/Cargo.toml b/benchmarks/lucet-benchmarks/Cargo.toml index 9bfb75d2f..4fc38e88e 100644 --- a/benchmarks/lucet-benchmarks/Cargo.toml +++ b/benchmarks/lucet-benchmarks/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-benchmarks" -version = "0.2.1" +version = "0.3.0" description = "Benchmarks for the Lucet runtime" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" diff --git a/lucet-module/Cargo.toml b/lucet-module/Cargo.toml index 36e8f1bb2..93a8b51b2 100644 --- a/lucet-module/Cargo.toml +++ b/lucet-module/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-module" -version = "0.2.1" +version = "0.3.0" description = "A structured interface for Lucet modules" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" diff --git a/lucet-objdump/Cargo.toml b/lucet-objdump/Cargo.toml index df25d41bc..85e954af2 100644 --- a/lucet-objdump/Cargo.toml +++ b/lucet-objdump/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-objdump" -version = "0.2.1" +version = "0.3.0" description = "Analyze object files emitted by the Lucet compiler" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -13,7 +13,7 @@ edition = "2018" goblin="0.0.24" byteorder="1.2.1" colored="1.6.1" -lucet-module = { path = "../lucet-module", version = "0.2.1" } +lucet-module = { path = "../lucet-module", version = "0.3.0" } [package.metadata.deb] name = "fst-lucet-objdump" diff --git a/lucet-runtime/Cargo.toml b/lucet-runtime/Cargo.toml index 11621f07e..b6e08d197 100644 --- a/lucet-runtime/Cargo.toml +++ b/lucet-runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime" -version = "0.2.1" +version = "0.3.0" description = "Pure Rust runtime for Lucet WebAssembly toolchain" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -11,8 +11,8 @@ edition = "2018" [dependencies] libc = "=0.2.59" -lucet-runtime-internals = { path = "lucet-runtime-internals", version = "0.2.1" } -lucet-module = { path = "../lucet-module", version = "0.2.1" } +lucet-runtime-internals = { path = "lucet-runtime-internals", version = "0.3.0" } +lucet-module = { path = "../lucet-module", version = "0.3.0" } num-traits = "0.2" num-derive = "0.2" @@ -20,9 +20,9 @@ num-derive = "0.2" byteorder = "1.2" failure = "0.1" lazy_static = "1.1" -lucetc = { path = "../lucetc", version = "0.2.1" } -lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.2.1" } -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.2.1" } +lucetc = { path = "../lucetc", version = "0.3.0" } +lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.3.0" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.3.0" } nix = "0.13" rayon = "1.0" tempfile = "3.0" diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index 69168524b..f619e41f7 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime-internals" -version = "0.2.1" +version = "0.3.0" description = "Pure Rust runtime for Lucet WebAssembly toolchain (internals)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -10,7 +10,7 @@ authors = ["Lucet team "] edition = "2018" [dependencies] -lucet-module = { path = "../../lucet-module", version = "0.2.1" } +lucet-module = { path = "../../lucet-module", version = "0.3.0" } bitflags = "1.0" bincode = "1.1.4" diff --git a/lucet-runtime/lucet-runtime-tests/Cargo.toml b/lucet-runtime/lucet-runtime-tests/Cargo.toml index 522f6b14d..22a92181e 100644 --- a/lucet-runtime/lucet-runtime-tests/Cargo.toml +++ b/lucet-runtime/lucet-runtime-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime-tests" -version = "0.2.1" +version = "0.3.0" description = "Pure Rust runtime for Lucet WebAssembly toolchain (tests)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -18,10 +18,10 @@ test = false failure = "0.1" lazy_static = "1.1" tempfile = "3.0" -lucet-module = { path = "../../lucet-module", version = "0.2.1" } -lucet-runtime-internals = { path = "../lucet-runtime-internals", version = "0.2.1" } -lucet-wasi-sdk = { path = "../../lucet-wasi-sdk", version = "0.2.1" } -lucetc = { path = "../../lucetc", version = "0.2.1" } +lucet-module = { path = "../../lucet-module", version = "0.3.0" } +lucet-runtime-internals = { path = "../lucet-runtime-internals", version = "0.3.0" } +lucet-wasi-sdk = { path = "../../lucet-wasi-sdk", version = "0.3.0" } +lucetc = { path = "../../lucetc", version = "0.3.0" } [build-dependencies] cc = "1.0" diff --git a/lucet-spectest/Cargo.toml b/lucet-spectest/Cargo.toml index 128c3cca4..67bdbd43f 100644 --- a/lucet-spectest/Cargo.toml +++ b/lucet-spectest/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-spectest" -version = "0.2.1" +version = "0.3.0" description = "Test harness to run WebAssembly spec tests (.wast) against the Lucet toolchain" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -17,10 +17,10 @@ name = "spec-test" path = "src/main.rs" [dependencies] -lucetc = { path = "../lucetc", version = "0.2.1" } -lucet-module = { path = "../lucet-module", version = "0.2.1" } -lucet-runtime = { path = "../lucet-runtime", version = "0.2.1" } -wabt = "0.7" +lucetc = { path = "../lucetc", version = "0.3.0" } +lucet-module = { path = "../lucet-module", version = "0.3.0" } +lucet-runtime = { path = "../lucet-runtime", version = "0.3.0" } +wabt = "0.9.2" serde = "1.0" serde_json = "1.0" failure = "0.1" diff --git a/lucet-spectest/src/lib.rs b/lucet-spectest/src/lib.rs index 15fbbd4d2..c32d74983 100644 --- a/lucet-spectest/src/lib.rs +++ b/lucet-spectest/src/lib.rs @@ -136,7 +136,11 @@ fn step(script: &mut ScriptEnv, cmd: &CommandKind) -> Result<(), SpecTestError> _ => Err(SpecTestErrorKind::UnsupportedCommand)?, }, - CommandKind::AssertExhaustion { ref action } => match action { + // TODO: verify the exhaustion message is what we expected + CommandKind::AssertExhaustion { + ref action, + message: _, + } => match action { Action::Invoke { ref module, ref field, @@ -258,6 +262,10 @@ fn check_retval(expected: &[Value], got: UntypedRetVal) -> Result<(), SpecTestEr .context(SpecTestErrorKind::IncorrectResult)? } } + Value::V128(_) => { + Err(format_err!("got unsupported SIMD V128 value")) + .context(SpecTestErrorKind::UnsupportedCommand)?; + } }, n => Err(format_err!("{} expected return values not supported", n)) .context(SpecTestErrorKind::UnsupportedCommand)?, @@ -273,6 +281,7 @@ fn translate_args(args: &[Value]) -> Vec { Value::I64(ref i) => Val::U64(*i as u64), Value::F32(ref f) => Val::F32(*f), Value::F64(ref f) => Val::F64(*f), + Value::V128(_) => panic!("unsupported SIMD argument size: v128"), }; out.push(v); } diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index 19ab69085..12879507c 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-validate" -version = "0.2.1" +version = "0.3.0" description = "Parse and validate webassembly files against witx interface" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -24,9 +24,9 @@ cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.44.0" wasmparser = "0.39.1" [dev-dependencies] -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.2.1" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.3.0" } tempfile = "3.0" -wabt = "0.7" +wabt = "0.9.2" [package.metadata.deb] name = "fst-lucet-validate" diff --git a/lucet-wasi-fuzz/Cargo.toml b/lucet-wasi-fuzz/Cargo.toml index d297f3758..25b393fb9 100644 --- a/lucet-wasi-fuzz/Cargo.toml +++ b/lucet-wasi-fuzz/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi-fuzz" -version = "0.2.1" +version = "0.3.0" description = "Test the Lucet toolchain against native code execution using Csmith" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" diff --git a/lucet-wasi-sdk/Cargo.toml b/lucet-wasi-sdk/Cargo.toml index ba2d24216..3f7ba24a1 100644 --- a/lucet-wasi-sdk/Cargo.toml +++ b/lucet-wasi-sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi-sdk" -version = "0.2.1" +version = "0.3.0" description = "A Rust interface to the wasi-sdk compiler and linker" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -11,9 +11,9 @@ edition = "2018" [dependencies] failure = "0.1" -lucetc = { path = "../lucetc", version = "0.2.1" } -lucet-module = { path = "../lucet-module", version = "0.2.1" } +lucetc = { path = "../lucetc", version = "0.3.0" } +lucet-module = { path = "../lucet-module", version = "0.3.0" } tempfile = "3.0" [dev-dependencies] -lucet-validate = { path = "../lucet-validate", version = "0.2.1" } +lucet-validate = { path = "../lucet-validate", version = "0.3.0" } diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index 422dfda4d..a0104174c 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi" -version = "0.2.1" +version = "0.3.0" description = "Fastly's runtime for the WebAssembly System Interface (WASI)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -29,15 +29,15 @@ clap = "2.23" failure = "0.1" human-size = "0.4" libc = "=0.2.59" -lucet-runtime = { path = "../lucet-runtime", version = "0.2.1" } -lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.2.1" } -lucet-module = { path = "../lucet-module", version = "0.2.1" } +lucet-runtime = { path = "../lucet-runtime", version = "0.3.0" } +lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.3.0" } +lucet-module = { path = "../lucet-module", version = "0.3.0" } nix = "0.13" rand = "0.6" [dev-dependencies] -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.2.1" } -lucetc = { path = "../lucetc", version = "0.2.1" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.3.0" } +lucetc = { path = "../lucetc", version = "0.3.0" } tempfile = "3.0" [build-dependencies.bindgen] diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index 8ac477710..7f6c5cbcc 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucetc" -version = "0.2.1" +version = "0.3.0" description = "Fastly's WebAssembly to native code compiler" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -26,8 +26,8 @@ cranelift-module = { path = "../cranelift/cranelift-module", version = "0.44.0" cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.44.0" } cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.44.0" } target-lexicon = "0.8.0" -lucet-module = { path = "../lucet-module", version = "0.2.1" } -lucet-validate = { path = "../lucet-validate", version = "0.2.1" } +lucet-module = { path = "../lucet-module", version = "0.3.0" } +lucet-validate = { path = "../lucet-validate", version = "0.3.0" } wasmparser = "0.39.1" clap="2.32" log = "0.4" @@ -37,7 +37,7 @@ goblin = "0.0.24" failure = "0.1" byteorder = "1.2" wasmonkey = { path = "../lucet-builtins/wasmonkey", version = "0.1.7" } -wabt = "0.9.1" +wabt = "0.9.2" tempfile = "3.0" bimap = "0.2" human-size = "0.4" From d445687bfe08296579cfe6b4aa3f7c4d6c84b537 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 21 Oct 2019 10:21:34 -0700 Subject: [PATCH 442/512] [lucet-runtime] add `is_yielded`, etc methods for instances Previously a client would have to keep around the `RunResult` to know which state an instance is in. --- .../lucet-runtime-internals/src/instance.rs | 20 +++++++++++++++++-- .../src/instance/state.rs | 2 +- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index 536a10fba..da8793652 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -697,6 +697,22 @@ impl Instance { KillSwitch::new(Arc::downgrade(&self.kill_state)) } + pub fn is_ready(&self) -> bool { + self.state.is_ready() + } + + pub fn is_yielded(&self) -> bool { + self.state.is_yielded() + } + + pub fn is_faulted(&self) -> bool { + self.state.is_faulted() + } + + pub fn is_terminated(&self) -> bool { + self.state.is_terminated() + } + // This needs to be public as it's used in the expansion of `lucet_hostcalls`, available for // external use. But you *really* shouldn't have to call this yourself, so we're going to keep // it out of rustdoc. @@ -794,7 +810,7 @@ impl Instance { /// Run a function in guest context at the given entrypoint. fn run_func(&mut self, func: FunctionHandle, args: &[Val]) -> Result { - if !(self.state.is_ready() || (self.state.is_fault() && !self.state.is_fatal())) { + if !(self.state.is_ready() || (self.state.is_faulted() && !self.state.is_fatal())) { return Err(Error::InvalidArgument( "instance must be ready or non-fatally faulted", )); @@ -875,7 +891,7 @@ impl Instance { fn swap_and_return(&mut self) -> Result { debug_assert!( self.state.is_ready() - || (self.state.is_fault() && !self.state.is_fatal()) + || (self.state.is_faulted() && !self.state.is_fatal()) || self.state.is_yielded() ); self.state = State::Running; diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/state.rs b/lucet-runtime/lucet-runtime-internals/src/instance/state.rs index 1be034667..8426d520b 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/state.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/state.rs @@ -129,7 +129,7 @@ impl State { } } - pub fn is_fault(&self) -> bool { + pub fn is_faulted(&self) -> bool { if let State::Faulted { .. } = self { true } else { From 3a47eb42f693b00a09a9d817c9a66b9e45ff355a Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 21 Oct 2019 10:33:43 -0700 Subject: [PATCH 443/512] [lucetc] json errors report as an array to support multiple errors We don't have the capability to produce multiple errors yet, so this only returns an array of a single element. Returning multiple errors will require refactoring of our code as well as upstream dependencies. --- lucetc/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lucetc/src/main.rs b/lucetc/src/main.rs index 2832815c6..e1b5e1191 100644 --- a/lucetc/src/main.rs +++ b/lucetc/src/main.rs @@ -36,8 +36,8 @@ fn main() { match opts.error_style { ErrorStyle::Human => eprintln!("Error: {}\n", err), ErrorStyle::Json => { - let s: SerializedLucetcError = err.into(); - let json = serde_json::to_string(&s).unwrap(); + let errs: Vec = vec![err.into()]; + let json = serde_json::to_string(&errs).unwrap(); eprintln!("{}", json); } } From 1da70d2249bcad9838260e192d2ac802c209035f Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 22 Oct 2019 12:52:09 -0700 Subject: [PATCH 444/512] add (currently-failing) test for moving yielded instances --- lucet-runtime/lucet-runtime-tests/src/host.rs | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/lucet-runtime/lucet-runtime-tests/src/host.rs b/lucet-runtime/lucet-runtime-tests/src/host.rs index f71de1cf3..dd8ad21b8 100644 --- a/lucet-runtime/lucet-runtime-tests/src/host.rs +++ b/lucet-runtime/lucet-runtime-tests/src/host.rs @@ -609,5 +609,53 @@ macro_rules! host_tests { Ok(_) => panic!("unexpected success"), } } + + /// This test shows that we can send an `InstanceHandle` to another thread while a guest is + /// yielded, and it resumes successfully. + #[test] + fn switch_threads_resume() { + extern "C" { + fn hostcall_yields_5(vmctx: *mut lucet_vmctx); + } + + unsafe extern "C" fn f(vmctx: *mut lucet_vmctx) -> u64 { + hostcall_yields_5(vmctx); + 42 + } + + let module = MockModuleBuilder::new() + .with_export_func(MockExportBuilder::new( + "f", + FunctionPointer::from_usize(f as usize), + )) + .build(); + + let region = TestRegion::create(1, &Limits::default()).expect("region can be created"); + let mut inst = region + .new_instance(module) + .expect("instance can be created"); + + // make sure we yield with 5 on the original thread + assert_eq!( + *inst + .run("f", &[]) + .unwrap() + .unwrap_yielded() + .downcast::() + .unwrap(), + 5u64 + ); + + let res = std::thread::spawn(move || { + // but then move the instance to another thread and resume it from there + inst.resume() + .expect("instance resumes") + .returned() + .expect("returns 42") + }) + .join() + .unwrap(); + assert_eq!(u64::from(res), 42u64); + } }; } From de717d5fcd4f8e19a33cbc40620738d39b7cfe07 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 22 Oct 2019 13:00:31 -0700 Subject: [PATCH 445/512] fix the sending-yielded-instances bug in horrendous fashion --- lucet-runtime/lucet-runtime-internals/src/instance.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index da8793652..b0da72548 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -911,6 +911,11 @@ impl Instance { self.with_signals_on(|i| { HOST_CTX.with(|host_ctx| { + unsafe { + let new_host_ctx = &mut *host_ctx.get() as *const _ as u64; + let stack = i.alloc.stack_u64_mut(); + stack[stack.len() - 3] = new_host_ctx; + }; // Save the current context into `host_ctx`, and jump to the guest context. The // lucet context is linked to host_ctx, so it will return here after it finishes, // successfully or otherwise. From 5c4d5b2e180f7433e68cd2b28d455390bcd0bf94 Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Tue, 22 Oct 2019 17:46:15 -0700 Subject: [PATCH 446/512] move guest data from the guest stack to Instance --- benchmarks/lucet-benchmarks/src/context.rs | 59 +++++++++---------- .../src/alloc/tests.rs | 24 +++++--- .../src/context/mod.rs | 47 +++++---------- .../src/context/tests/c_child.rs | 10 +++- .../src/context/tests/mod.rs | 15 ++--- .../src/context/tests/rust_child.rs | 10 +++- .../lucet-runtime-internals/src/instance.rs | 44 +++++++++++--- 7 files changed, 113 insertions(+), 96 deletions(-) diff --git a/benchmarks/lucet-benchmarks/src/context.rs b/benchmarks/lucet-benchmarks/src/context.rs index 5b2fede39..b8106dffd 100644 --- a/benchmarks/lucet-benchmarks/src/context.rs +++ b/benchmarks/lucet-benchmarks/src/context.rs @@ -1,5 +1,6 @@ use criterion::Criterion; use lucet_runtime_internals::context::{Context, ContextHandle}; +use lucet_runtime_internals::instance::GuestData; /// Time the initialization of a context. fn context_init(c: &mut Criterion) { @@ -10,14 +11,8 @@ fn context_init(c: &mut Criterion) { c.bench_function("context_init", move |b| { b.iter(|| { let mut parent = ContextHandle::new(); - ContextHandle::create_and_init( - &mut *stack, - &mut parent, - std::ptr::null(), - f as usize, - &[], - ) - .unwrap(); + let mut guest_data = GuestData::default(); + ContextHandle::create_and_init(&mut *stack, &mut guest_data, f as usize, &[]).unwrap(); }) }); } @@ -31,14 +26,14 @@ fn context_swap_return(c: &mut Criterion) { || { let mut stack = vec![0u64; 1024].into_boxed_slice(); let mut parent = ContextHandle::new(); - let child = ContextHandle::create_and_init( - &mut *stack, - &mut parent, - std::ptr::null(), - f as usize, - &[], - ) - .unwrap(); + let mut guest_data = GuestData::default(); + let mut child = + ContextHandle::create_and_init(&mut *stack, &mut guest_data, f as usize, &[]) + .unwrap(); + let child_ref: &mut Context = &mut *child; + guest_data.child_ctx = child_ref as *mut Context; + let parent_ref: &mut Context = &mut *parent; + guest_data.parent_ctx = parent_ref as *mut Context; (stack, parent, child) }, |(stack, mut parent, child)| unsafe { @@ -59,14 +54,14 @@ fn context_init_swap_return(c: &mut Criterion) { || vec![0u64; 1024].into_boxed_slice(), |mut stack| { let mut parent = ContextHandle::new(); - let child = ContextHandle::create_and_init( - &mut *stack, - &mut parent, - std::ptr::null(), - f as usize, - &[], - ) - .unwrap(); + let mut guest_data = GuestData::default(); + let mut child = + ContextHandle::create_and_init(&mut *stack, &mut guest_data, f as usize, &[]) + .unwrap(); + let child_ref: &mut Context = &mut *child; + guest_data.child_ctx = child_ref as *mut Context; + let parent_ref: &mut Context = &mut *parent; + guest_data.parent_ctx = parent_ref as *mut Context; unsafe { Context::swap(&mut parent, &child) }; stack }, @@ -353,14 +348,14 @@ fn context_init_swap_return_many_args(c: &mut Criterion) { || vec![0u64; 1024].into_boxed_slice(), |mut stack| { let mut parent = ContextHandle::new(); - let child = ContextHandle::create_and_init( - &mut *stack, - &mut parent, - std::ptr::null(), - f as usize, - &args, - ) - .unwrap(); + let mut guest_data = GuestData::default(); + let mut child = + ContextHandle::create_and_init(&mut *stack, &mut guest_data, f as usize, &args) + .unwrap(); + let child_ref: &mut Context = &mut *child; + guest_data.child_ctx = child_ref as *mut Context; + let parent_ref: &mut Context = &mut *parent; + guest_data.parent_ctx = parent_ref as *mut Context; unsafe { Context::swap(&mut parent, &child) }; stack }, diff --git a/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs b/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs index 0c557490c..67417da23 100644 --- a/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs +++ b/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs @@ -6,7 +6,7 @@ macro_rules! alloc_tests { use $TestRegion as TestRegion; use $crate::alloc::Limits; use $crate::context::{Context, ContextHandle}; - use $crate::instance::{InstanceInternal, KillState}; + use $crate::instance::{GuestData, InstanceInternal, KillState}; use $crate::module::{GlobalValue, HeapSpec, MockModuleBuilder}; use $crate::region::Region; use $crate::val::Val; @@ -604,14 +604,19 @@ macro_rules! alloc_tests { let heap_ptr = inst.alloc_mut().heap_mut().as_ptr() as *mut c_void; let kill_state = KillState::new(); kill_state.enable_termination(); - let child = ContextHandle::create_and_init( + let mut guest_data = GuestData::default(); + guest_data.kill_state = &kill_state as *const KillState; + let mut child = ContextHandle::create_and_init( inst.alloc_mut().stack_u64_mut(), - &mut parent, - &kill_state as *const KillState, + &mut guest_data, heap_touching_child as usize, &[Val::CPtr(heap_ptr)], ) .expect("context init succeeds"); + let child_ref: &mut Context = &mut *child; + guest_data.child_ctx = child_ref as *mut Context; + let parent_ref: &mut Context = &mut *parent; + guest_data.parent_ctx = parent_ref as *mut Context; Context::swap(&mut parent, &child); assert_eq!(inst.alloc().heap()[0], 123); assert_eq!(inst.alloc().heap()[4095], 45); @@ -657,14 +662,19 @@ macro_rules! alloc_tests { let heap_ptr = inst.alloc_mut().heap_mut().as_ptr() as *mut c_void; let kill_state = KillState::new(); kill_state.enable_termination(); - let child = ContextHandle::create_and_init( + let mut guest_data = GuestData::default(); + guest_data.kill_state = &kill_state as *const KillState; + let mut child = ContextHandle::create_and_init( inst.alloc_mut().stack_u64_mut(), - &mut parent, - &kill_state as *const KillState, + &mut guest_data, stack_pattern_child as usize, &[Val::CPtr(heap_ptr)], ) .expect("context init succeeds"); + let child_ref: &mut Context = &mut *child; + guest_data.child_ctx = child_ref as *mut Context; + let parent_ref: &mut Context = &mut *parent; + guest_data.parent_ctx = parent_ref as *mut Context; Context::swap(&mut parent, &child); let stack_pattern = inst.alloc().heap_u64()[0] as usize; diff --git a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs index 995a09440..80e76c88f 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs @@ -3,7 +3,7 @@ #[cfg(test)] mod tests; -use crate::instance::execution::KillState; +use crate::instance::GuestData; use crate::val::{val_to_reg, val_to_stack, RegVal, UntypedRetVal, Val}; use failure::Fail; use nix; @@ -195,13 +195,12 @@ impl ContextHandle { pub fn create_and_init( stack: &mut [u64], - parent: &mut ContextHandle, - kill_state: *const KillState, + guest_data: &mut GuestData, fptr: usize, args: &[Val], ) -> Result { let mut child = ContextHandle::new(); - Context::init(stack, parent, &mut child, kill_state, fptr, args)?; + Context::init(stack, &mut child, guest_data, fptr, args)?; Ok(child) } } @@ -287,18 +286,18 @@ impl Context { /// /// ```no_run /// # use lucet_runtime_internals::context::Context; + /// # use lucet_runtime_internals::instance::GuestData; /// # use lucet_runtime_internals::val::Val; /// extern "C" { fn entrypoint(x: u64, y: f32); } /// // allocating an even number of `u64`s seems to reliably yield /// // properly aligned stacks, but TODO do better /// let mut stack = vec![0u64; 1024].into_boxed_slice(); - /// let mut parent = Context::new(); + /// let mut guest_data = GuestData::default(); /// let mut child = Context::new(); /// let res = Context::init( /// &mut *stack, - /// &mut parent, /// &mut child, - /// std::ptr::null(), + /// &mut guest_data, /// entrypoint as usize, /// &[Val::U64(120), Val::F32(3.14)], /// ); @@ -313,18 +312,18 @@ impl Context { /// /// ```no_run /// # use lucet_runtime_internals::context::{Context, ContextHandle}; + /// # use lucet_runtime_internals::instance::GuestData; /// # use lucet_runtime_internals::val::Val; /// extern "C" fn entrypoint(x: u64, y: f32) { } /// // allocating an even number of `u64`s seems to reliably yield /// // properly aligned stacks, but TODO do better /// let mut stack = vec![0u64; 1024].into_boxed_slice(); - /// let mut parent = ContextHandle::new(); + /// let mut guest_data = GuestData::default(); /// let mut child = Context::new(); /// let res = Context::init( /// &mut *stack, - /// &mut parent, /// &mut child, - /// std::ptr::null(), + /// &mut guest_data, /// entrypoint as usize, /// &[Val::U64(120), Val::F32(3.14)], /// ); @@ -367,9 +366,8 @@ impl Context { /// and prepare a context for `fptr`. pub fn init( stack: &mut [u64], - parent: &mut Context, child: &mut Context, - kill_state: *const KillState, + guest_data: &GuestData, fptr: usize, args: &[Val], ) -> Result<(), Error> { @@ -407,22 +405,6 @@ impl Context { // set up an initial call stack for guests to bootstrap into and execute let mut stack_builder = CallStackBuilder::new(stack); - // pass this crate's `exit_guest_region` function pointer, so we can allow - // `exit_guest_function` to be name mangled. Mangling is beneficial as it allows multiple - // crates to depend on `lucet-runtime-internals` without linker conflicts. - stack_builder.push(crate::instance::execution::exit_guest_region as u64); - - // store a pointer to kill state, which the guest interacts with to safely exit - stack_builder.push(kill_state as u64); - - // store arguments we'll pass to `lucet_context_swap` on the stack, above where the guest - // might scribble over them. - stack_builder.push(parent as *mut Context as u64); - stack_builder.push(child as *mut Context as u64); - - // we'll pass a pointer to these values via `rbp` in the guest's Context we switch to. - let backstop_args = stack_builder.offset(); - // we actually don't want to put an explicit pointer to these arguments anywhere. we'll // line up the rest of the stack such that these are in argument position when we jump to // `fptr`. @@ -461,9 +443,7 @@ impl Context { // the address of the first function to run on `swap`: `lucet_context_bootstrap`. child.gpr.rsp = &mut stack[stack.len() - stack_start] as *mut u64 as u64; - // This value in rbp is only used in `lucet_context_backstop`, where we use it to locate - // the parent and child contexts to `Context::swap` with. - child.gpr.rbp = &mut stack[stack.len() - backstop_args] as *mut u64 as u64; + child.gpr.rbp = guest_data as *const GuestData as u64; // Read the mask to be restored if we ever need to jump out of a signal handler. If this // isn't possible, die. @@ -529,15 +509,16 @@ impl Context { /// /// ```no_run /// # use lucet_runtime_internals::context::Context; + /// # use lucet_runtime_internals::instance::GuestData; /// # extern "C" fn entrypoint() {} /// # let mut stack = vec![0u64; 1024].into_boxed_slice(); + /// let mut guest_data = GuestData::default(); /// let mut parent = Context::new(); /// let mut child = Context::new(); /// Context::init( /// &mut stack, - /// &mut parent, /// &mut child, - /// std::ptr::null(), + /// &mut guest_data, /// entrypoint as usize, /// &[], /// ).unwrap(); diff --git a/lucet-runtime/lucet-runtime-internals/src/context/tests/c_child.rs b/lucet-runtime/lucet-runtime-internals/src/context/tests/c_child.rs index b9945b39c..17d765941 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/tests/c_child.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/tests/c_child.rs @@ -53,16 +53,22 @@ macro_rules! init_and_swap { unsafe { let kill_state = $crate::instance::KillState::new(); kill_state.enable_termination(); + let mut guest_data = $crate::instance::GuestData::default(); + guest_data.kill_state = &kill_state as *const $crate::instance::KillState; let child = Box::into_raw(Box::new(ContextHandle::create_and_init( &mut *$stack, - parent_regs.as_mut().unwrap(), - &kill_state as *const $crate::instance::KillState, + &mut guest_data, $fn as usize, &[$( $args ),*], ).unwrap())); child_regs = child; + let parent_ctx: &mut Context = parent_regs.as_mut().unwrap(); + guest_data.parent_ctx = parent_ctx as *mut Context; + let child_ctx: &mut Context = child_regs.as_mut().unwrap(); + guest_data.child_ctx = child_ctx as *mut Context; + Context::swap(parent_regs.as_mut().unwrap(), child_regs.as_ref().unwrap()); } } diff --git a/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs b/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs index 9709d6ac7..1f2ef26c9 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs @@ -1,7 +1,7 @@ mod c_child; mod rust_child; use crate::context::{Context, ContextHandle, Error}; -use crate::instance::execution::KillState; +use crate::instance::GuestData; use memoffset::offset_of; use std::slice; @@ -32,16 +32,9 @@ fn init_rejects_unaligned() { let mut stack_unaligned = unsafe { slice::from_raw_parts_mut(ptr, len) }; // now we have the unaligned stack, let's make sure it blows up right - let mut parent = ContextHandle::new(); - let kill_state = KillState::new(); - kill_state.enable_termination(); - let res = ContextHandle::create_and_init( - &mut stack_unaligned, - &mut parent, - &kill_state as *const KillState, - dummy as usize, - &[], - ); + let mut guest_data = GuestData::default(); + let res = + ContextHandle::create_and_init(&mut stack_unaligned, &mut guest_data, dummy as usize, &[]); if let Err(Error::UnalignedStack) = res { assert!(true); diff --git a/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs b/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs index 6747a00f4..bd5263030 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs @@ -49,15 +49,21 @@ macro_rules! init_and_swap { unsafe { let kill_state = $crate::instance::KillState::new(); kill_state.enable_termination(); + let mut guest_data = $crate::instance::GuestData::default(); + guest_data.kill_state = &kill_state as *const $crate::instance::KillState; let child = ContextHandle::create_and_init( &mut *$stack, - PARENT.as_mut().unwrap(), - &kill_state as *const $crate::instance::KillState, + &mut guest_data, $fn as usize, &[$( $args ),*], ).unwrap(); CHILD = Some(child); + let child_ref: &mut Context = CHILD.as_mut().unwrap(); + guest_data.child_ctx = child_ref as *mut Context; + let parent_ref: &mut Context = PARENT.as_mut().unwrap(); + guest_data.parent_ctx = parent_ref as *mut Context; + Context::swap( PARENT.as_mut().unwrap(), CHILD.as_ref().unwrap(), diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index b0da72548..a246fecee 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -60,6 +60,29 @@ pub struct InstanceHandle { needs_inst_drop: bool, } +/// `GuestData` contains host data that must be shared with guests. These are necesary to implement +/// operations that interact with the host context, such as context switching and some parts of +/// instance termination. +#[repr(C)] +pub struct GuestData { + pub child_ctx: *mut Context, + pub parent_ctx: *mut Context, + pub kill_state: *const KillState, + pub exit_guest_region: *const extern "C" fn(*mut execution::KillState), +} + +impl Default for GuestData { + fn default() -> Self { + GuestData { + child_ctx: std::ptr::null_mut(), + parent_ctx: std::ptr::null_mut(), + kill_state: std::ptr::null(), + exit_guest_region: execution::exit_guest_region + as *const extern "C" fn(*mut execution::KillState), + } + } +} + // raw pointer lint unsafe impl Send for InstanceHandle {} @@ -256,6 +279,10 @@ pub struct Instance { /// The value passed back to the guest when resuming a yielded instance. pub(crate) resumed_val: Option>, + /// Information shared with the guest to implement guest primitives like + /// `lucet_context_backstop`. + guest_data: GuestData, + /// `_padding` must be the last member of the structure. /// This marks where the padding starts to make the structure exactly 4096 bytes long. /// It is also used to compute the size of the structure up to that point, i.e. without padding. @@ -747,6 +774,7 @@ impl Instance { impl Instance { fn new(alloc: Alloc, module: Arc, embed_ctx: CtxMap) -> Self { let globals_ptr = alloc.slot().globals as *mut i64; + let mut inst = Instance { magic: LUCET_INSTANCE_MAGIC, embed_ctx: embed_ctx, @@ -760,6 +788,7 @@ impl Instance { signal_handler: Box::new(signal_handler_none) as Box, entrypoint: None, resumed_val: None, + guest_data: GuestData::default(), _padding: (), }; inst.set_globals_ptr(globals_ptr); @@ -845,14 +874,15 @@ impl Instance { let mut args_with_vmctx = vec![Val::from(self.alloc.slot().heap)]; args_with_vmctx.extend_from_slice(args); - let kill_state_ptr: *const KillState = &*self.kill_state; - HOST_CTX.with(|host_ctx| { + self.guest_data.child_ctx = &mut self.ctx as *mut Context; + self.guest_data.kill_state = &*self.kill_state; + self.guest_data.parent_ctx = unsafe { &mut *host_ctx.get() }; + Context::init( unsafe { self.alloc.stack_u64_mut() }, - unsafe { &mut *host_ctx.get() }, &mut self.ctx, - kill_state_ptr, + &self.guest_data, func.ptr.as_usize(), &args_with_vmctx, ) @@ -911,11 +941,7 @@ impl Instance { self.with_signals_on(|i| { HOST_CTX.with(|host_ctx| { - unsafe { - let new_host_ctx = &mut *host_ctx.get() as *const _ as u64; - let stack = i.alloc.stack_u64_mut(); - stack[stack.len() - 3] = new_host_ctx; - }; + i.guest_data.parent_ctx = host_ctx.get(); // Save the current context into `host_ctx`, and jump to the guest context. The // lucet context is linked to host_ctx, so it will return here after it finishes, // successfully or otherwise. From 9c6a65f538f14f89c6adc7d4d21078482e3672a0 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 22 Oct 2019 21:13:36 -0400 Subject: [PATCH 447/512] run the benchmarks in debug mode for `make test` --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9eec9bb4d..f47ca403a 100644 --- a/Makefile +++ b/Makefile @@ -34,8 +34,8 @@ test-except-fuzz: -p lucet-wasi-sdk \ -p lucet-wasi \ -p lucet-wasi-fuzz \ - -p lucet-benchmarks \ -p lucet-validate + cargo test --benches -p lucet-benchmarks -- --test # run the benchmarks in debug mode helpers/lucet-toolchain-tests/signature.sh # run a single seed through the fuzzer to stave off bitrot From 5cb17c7fafc26883819630411e66aeee0d01e66a Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Wed, 23 Oct 2019 16:09:04 -0400 Subject: [PATCH 448/512] [lucet-runtime-internals] refactor guest-specific context data This ended up changing around the interface to initializing and swapping contexts in some important ways. Notably, a pointer to the parent context that `lucet_context_bootstrap` swaps into when the entrypoint function returns is no longer written into the guest stack, but rather is a field on `Context`. This field gets updated in the `to` context when calling `Context::swap()`, so that we can swap `to` a context from different `from` contexts without trying to always swap back to the original context. This also gets us ready to abstract away instance/timeout-specific data from the `Context` struct by making the use of a backstop callback function explicit but optional. --- benchmarks/lucet-benchmarks/src/context.rs | 40 ++---- benchmarks/lucet-benchmarks/src/seq.rs | 1 + .../src/alloc/tests.rs | 24 +--- .../src/context/context_asm.S | 36 ++++-- .../src/context/mod.rs | 116 +++++++++++------- .../src/context/tests/c_child.rs | 14 +-- .../src/context/tests/mod.rs | 5 +- .../src/context/tests/rust_child.rs | 22 +--- .../lucet-runtime-internals/src/instance.rs | 51 ++------ .../src/instance/execution.rs | 9 +- 10 files changed, 135 insertions(+), 183 deletions(-) diff --git a/benchmarks/lucet-benchmarks/src/context.rs b/benchmarks/lucet-benchmarks/src/context.rs index b8106dffd..c0fb67879 100644 --- a/benchmarks/lucet-benchmarks/src/context.rs +++ b/benchmarks/lucet-benchmarks/src/context.rs @@ -1,6 +1,5 @@ use criterion::Criterion; use lucet_runtime_internals::context::{Context, ContextHandle}; -use lucet_runtime_internals::instance::GuestData; /// Time the initialization of a context. fn context_init(c: &mut Criterion) { @@ -10,9 +9,7 @@ fn context_init(c: &mut Criterion) { c.bench_function("context_init", move |b| { b.iter(|| { - let mut parent = ContextHandle::new(); - let mut guest_data = GuestData::default(); - ContextHandle::create_and_init(&mut *stack, &mut guest_data, f as usize, &[]).unwrap(); + ContextHandle::create_and_init(&mut *stack, f as usize, &[]).unwrap(); }) }); } @@ -25,19 +22,12 @@ fn context_swap_return(c: &mut Criterion) { b.iter_batched( || { let mut stack = vec![0u64; 1024].into_boxed_slice(); - let mut parent = ContextHandle::new(); - let mut guest_data = GuestData::default(); - let mut child = - ContextHandle::create_and_init(&mut *stack, &mut guest_data, f as usize, &[]) - .unwrap(); - let child_ref: &mut Context = &mut *child; - guest_data.child_ctx = child_ref as *mut Context; - let parent_ref: &mut Context = &mut *parent; - guest_data.parent_ctx = parent_ref as *mut Context; + let parent = ContextHandle::new(); + let child = ContextHandle::create_and_init(&mut *stack, f as usize, &[]).unwrap(); (stack, parent, child) }, - |(stack, mut parent, child)| unsafe { - Context::swap(&mut parent, &child); + |(stack, mut parent, mut child)| unsafe { + Context::swap(&mut parent, &mut child); stack }, criterion::BatchSize::PerIteration, @@ -54,15 +44,9 @@ fn context_init_swap_return(c: &mut Criterion) { || vec![0u64; 1024].into_boxed_slice(), |mut stack| { let mut parent = ContextHandle::new(); - let mut guest_data = GuestData::default(); let mut child = - ContextHandle::create_and_init(&mut *stack, &mut guest_data, f as usize, &[]) - .unwrap(); - let child_ref: &mut Context = &mut *child; - guest_data.child_ctx = child_ref as *mut Context; - let parent_ref: &mut Context = &mut *parent; - guest_data.parent_ctx = parent_ref as *mut Context; - unsafe { Context::swap(&mut parent, &child) }; + ContextHandle::create_and_init(&mut *stack, f as usize, &[]).unwrap(); + unsafe { Context::swap(&mut parent, &mut child) }; stack }, criterion::BatchSize::PerIteration, @@ -348,15 +332,9 @@ fn context_init_swap_return_many_args(c: &mut Criterion) { || vec![0u64; 1024].into_boxed_slice(), |mut stack| { let mut parent = ContextHandle::new(); - let mut guest_data = GuestData::default(); let mut child = - ContextHandle::create_and_init(&mut *stack, &mut guest_data, f as usize, &args) - .unwrap(); - let child_ref: &mut Context = &mut *child; - guest_data.child_ctx = child_ref as *mut Context; - let parent_ref: &mut Context = &mut *parent; - guest_data.parent_ctx = parent_ref as *mut Context; - unsafe { Context::swap(&mut parent, &child) }; + ContextHandle::create_and_init(&mut *stack, f as usize, &args).unwrap(); + unsafe { Context::swap(&mut parent, &mut child) }; stack }, criterion::BatchSize::PerIteration, diff --git a/benchmarks/lucet-benchmarks/src/seq.rs b/benchmarks/lucet-benchmarks/src/seq.rs index 28983d552..e0afa79b1 100644 --- a/benchmarks/lucet-benchmarks/src/seq.rs +++ b/benchmarks/lucet-benchmarks/src/seq.rs @@ -24,6 +24,7 @@ const SPARSE_HEAP_SIZES_KB: &'static [usize] = &[0, 256, 512, 1024, 2 * 1024, 4 /// To minimize the effects of filesystem cache on the `DlModule::load()`, this runs `sync` between /// each iteration. fn hello_load_mkregion_and_instantiate(c: &mut Criterion) { + lucet_wasi::hostcalls::ensure_linked(); fn body(so_file: &Path) -> InstanceHandle { let module = DlModule::load(so_file).unwrap(); let region = R::create(1, &Limits::default()).unwrap(); diff --git a/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs b/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs index 67417da23..76da9952b 100644 --- a/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs +++ b/lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs @@ -6,7 +6,7 @@ macro_rules! alloc_tests { use $TestRegion as TestRegion; use $crate::alloc::Limits; use $crate::context::{Context, ContextHandle}; - use $crate::instance::{GuestData, InstanceInternal, KillState}; + use $crate::instance::InstanceInternal; use $crate::module::{GlobalValue, HeapSpec, MockModuleBuilder}; use $crate::region::Region; use $crate::val::Val; @@ -602,22 +602,13 @@ macro_rules! alloc_tests { let mut parent = ContextHandle::new(); unsafe { let heap_ptr = inst.alloc_mut().heap_mut().as_ptr() as *mut c_void; - let kill_state = KillState::new(); - kill_state.enable_termination(); - let mut guest_data = GuestData::default(); - guest_data.kill_state = &kill_state as *const KillState; let mut child = ContextHandle::create_and_init( inst.alloc_mut().stack_u64_mut(), - &mut guest_data, heap_touching_child as usize, &[Val::CPtr(heap_ptr)], ) .expect("context init succeeds"); - let child_ref: &mut Context = &mut *child; - guest_data.child_ctx = child_ref as *mut Context; - let parent_ref: &mut Context = &mut *parent; - guest_data.parent_ctx = parent_ref as *mut Context; - Context::swap(&mut parent, &child); + Context::swap(&mut parent, &mut child); assert_eq!(inst.alloc().heap()[0], 123); assert_eq!(inst.alloc().heap()[4095], 45); } @@ -660,22 +651,13 @@ macro_rules! alloc_tests { let mut parent = ContextHandle::new(); unsafe { let heap_ptr = inst.alloc_mut().heap_mut().as_ptr() as *mut c_void; - let kill_state = KillState::new(); - kill_state.enable_termination(); - let mut guest_data = GuestData::default(); - guest_data.kill_state = &kill_state as *const KillState; let mut child = ContextHandle::create_and_init( inst.alloc_mut().stack_u64_mut(), - &mut guest_data, stack_pattern_child as usize, &[Val::CPtr(heap_ptr)], ) .expect("context init succeeds"); - let child_ref: &mut Context = &mut *child; - guest_data.child_ctx = child_ref as *mut Context; - let parent_ref: &mut Context = &mut *parent; - guest_data.parent_ctx = parent_ref as *mut Context; - Context::swap(&mut parent, &child); + Context::swap(&mut parent, &mut child); let stack_pattern = inst.alloc().heap_u64()[0] as usize; assert!(stack_pattern > inst.alloc().slot().stack as usize); diff --git a/lucet-runtime/lucet-runtime-internals/src/context/context_asm.S b/lucet-runtime/lucet-runtime-internals/src/context/context_asm.S index 6feb06e01..c844516ad 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/context_asm.S +++ b/lucet-runtime/lucet-runtime-internals/src/context/context_asm.S @@ -65,19 +65,29 @@ _lucet_context_bootstrap: lucet_context_backstop: _lucet_context_backstop: // Note that `rbp` here really has no relation to any stack! - // it happens to be an available pointer we can hang the contexts to swap off of. - mov (%rbp), %rdi // load the parent context to forward values in return value registers - mov %rax, (10*8 + 8*16 + 8*0)(%rdi) /* store return values before swapping back -- offset is offsetof(struct lucet_context, retvals) */ - mov %rdx, (10*8 + 8*16 + 8*1)(%rdi) - movdqu %xmm0, (10*8 + 8*16 + 8*2)(%rdi) /* floating-point return value */ - - // load instance pointer, arg 1 - mov 16(%rbp), %rdi - // call `lucet_runtime_internals::instance::execution::exit_guest_region` - call *24(%rbp) - - mov (%rbp), %rdi /* parent context to arg 1 */ - mov 8(%rbp), %rsi /* own context to arg 2 */ + // Instead, it's a pointer to the guest context. + mov (10*8 + 8*16 + 8*2 + 16)(%rbp), %rdi // load the parent context to forward values in return value registers + mov %rax, (10*8 + 8*16 + 8*0)(%rbp) /* store return values before swapping back -- offset is offsetof(struct lucet_context, retvals) */ + mov %rdx, (10*8 + 8*16 + 8*1)(%rbp) + movdqu %xmm0, (10*8 + 8*16 + 8*2)(%rbp) /* floating-point return value */ + + // load `backstop_callback`, but skip calling it if it's null + mov (10*8 + 8*16 + 8*2 + 16 + 8)(%rbp), %rsi + test %rsi, %rsi +#ifdef __ELF__ + jz no_backstop_callback@PLT +#else + jz no_backstop_callback +#endif + + // load `backstop_data`, arg 1 + mov (10*8 + 8*16 + 8*2 + 16 + 8 + 8)(%rbp), %rdi + // call `backstop_callback` + call *%rsi + +no_backstop_callback: + mov %rbp, %rdi // load the guest context to the "from" argument + mov (10*8 + 8*16 + 8*2 + 16)(%rbp), %rsi // load the parent context to the "to" argument #ifdef __ELF__ jmp lucet_context_swap@PLT diff --git a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs index 80e76c88f..b89b945c3 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs @@ -3,14 +3,14 @@ #[cfg(test)] mod tests; -use crate::instance::GuestData; +use crate::instance::Instance; use crate::val::{val_to_reg, val_to_stack, RegVal, UntypedRetVal, Val}; use failure::Fail; use nix; use nix::sys::signal; use std::arch::x86_64::{__m128, _mm_setzero_ps}; -use std::mem; use std::ptr::NonNull; +use std::{mem, ptr}; use xfailure::xbail; /// Callee-saved general-purpose registers in the AMD64 ABI. @@ -97,6 +97,9 @@ impl FpRegs { /// Everything we need to make a context switch: a signal mask, and the registers and return values /// that are manipulated directly by assembly code. /// +/// A context also tracks which other context to swap back to if a child context's entrypoint function +/// returns, and can optionally contain a callback function to be run just before that swap occurs. +/// /// # Layout /// /// The `repr(C)` and order of fields in this struct are very important, as the assembly code reads @@ -117,6 +120,10 @@ pub struct Context { fpr: FpRegs, retvals_gp: [u64; 2], retval_fp: __m128, + parent_ctx: *mut Context, + // TODO ACF 2019-10-23: make Instance into a generic parameter? + backstop_callback: *const unsafe extern "C" fn(*mut Instance), + backstop_data: *mut Instance, sigset: signal::SigSet, } @@ -128,6 +135,9 @@ impl Context { fpr: FpRegs::new(), retvals_gp: [0; 2], retval_fp: unsafe { _mm_setzero_ps() }, + parent_ctx: ptr::null_mut(), + backstop_callback: Context::default_backstop_callback as *const _, + backstop_data: ptr::null_mut(), sigset: signal::SigSet::empty(), } } @@ -195,12 +205,11 @@ impl ContextHandle { pub fn create_and_init( stack: &mut [u64], - guest_data: &mut GuestData, fptr: usize, args: &[Val], ) -> Result { let mut child = ContextHandle::new(); - Context::init(stack, &mut child, guest_data, fptr, args)?; + Context::init(stack, &mut child, fptr, args)?; Ok(child) } } @@ -253,10 +262,6 @@ impl Context { /// /// - `stack`: The stack for the child; *must be 16-byte aligned*. /// - /// - `parent`: The context that the child will return to. Since `swap` initializes the fields - /// in its `from` argument, this will typically be an empty context from `ContextHandle::zero()` - /// that will later be passed to `swap`. - /// /// - `child`: The context for the child. The fields of this structure will be overwritten by /// `init`. /// @@ -286,18 +291,15 @@ impl Context { /// /// ```no_run /// # use lucet_runtime_internals::context::Context; - /// # use lucet_runtime_internals::instance::GuestData; /// # use lucet_runtime_internals::val::Val; /// extern "C" { fn entrypoint(x: u64, y: f32); } /// // allocating an even number of `u64`s seems to reliably yield /// // properly aligned stacks, but TODO do better /// let mut stack = vec![0u64; 1024].into_boxed_slice(); - /// let mut guest_data = GuestData::default(); /// let mut child = Context::new(); /// let res = Context::init( /// &mut *stack, /// &mut child, - /// &mut guest_data, /// entrypoint as usize, /// &[Val::U64(120), Val::F32(3.14)], /// ); @@ -312,18 +314,15 @@ impl Context { /// /// ```no_run /// # use lucet_runtime_internals::context::{Context, ContextHandle}; - /// # use lucet_runtime_internals::instance::GuestData; /// # use lucet_runtime_internals::val::Val; /// extern "C" fn entrypoint(x: u64, y: f32) { } /// // allocating an even number of `u64`s seems to reliably yield /// // properly aligned stacks, but TODO do better /// let mut stack = vec![0u64; 1024].into_boxed_slice(); - /// let mut guest_data = GuestData::default(); /// let mut child = Context::new(); /// let res = Context::init( /// &mut *stack, /// &mut child, - /// &mut guest_data, /// entrypoint as usize, /// &[Val::U64(120), Val::F32(3.14)], /// ); @@ -336,16 +335,14 @@ impl Context { /// stack: /// ```text /// 0x1000: +-------------------------+ - /// 0x0ff8: | &child | - /// 0x0ff0: | &parent | <-- `backstop_args`, which is stored to `rbp`. - /// 0x0fe8: | NULL | // Null added if necessary for alignment. - /// 0x0fe0: | spilled_arg_1 | // Guest arguments follow. - /// 0x0fd8: | spilled_arg_2 | - /// 0x0fd0: ~ spilled_arg_3 ~ // The three arguments here are just for show. - /// 0x0fc8: | lucet_context_backstop | <-- This forms an ABI-matching call frame for fptr. - /// 0x0fc0: | fptr | <-- The actual guest code we want to run. - /// 0x0fb8: | lucet_context_bootstrap | <-- The guest stack pointer starts here. - /// 0x0fb0: | | + /// 0x0ff8: | NULL | // Null added if necessary for alignment. + /// 0x0ff0: | spilled_arg_1 | // Guest arguments follow. + /// 0x0fe8: | spilled_arg_2 | + /// 0x0fe0: ~ spilled_arg_3 ~ // The three arguments here are just for show. + /// 0x0fd8: | lucet_context_backstop | <-- This forms an ABI-matching call frame for fptr. + /// 0x0fd0: | fptr | <-- The actual guest code we want to run. + /// 0x0fc8: | lucet_context_bootstrap | <-- The guest stack pointer starts here. + /// 0x0fc0: | | /// 0x0XXX: ~ ~ // Rest of the stack needs no preparation. /// 0x0000: | | /// +-------------------------+ @@ -367,7 +364,32 @@ impl Context { pub fn init( stack: &mut [u64], child: &mut Context, - guest_data: &GuestData, + fptr: usize, + args: &[Val], + ) -> Result<(), Error> { + Context::init_with_callback( + stack, + child, + Context::default_backstop_callback, + ptr::null_mut(), + fptr, + args, + ) + } + + /// The default backstop callback does nothing, and is just a marker. + extern "C" fn default_backstop_callback(_: *mut Instance) {} + + /// Similar to `Context::init()`, but allows setting a callback function to be run when the + /// guest entrypoint returns. + /// + /// After the entrypoint function returns, but before swapping back to the parent context, + /// `backstop_callback` will be run with the single argument `backstop_data`. + pub fn init_with_callback( + stack: &mut [u64], + child: &mut Context, + backstop_callback: unsafe extern "C" fn(*mut Instance), + backstop_data: *mut Instance, fptr: usize, args: &[Val], ) -> Result<(), Error> { @@ -375,6 +397,11 @@ impl Context { xbail!(Error::UnalignedStack); } + if backstop_callback != Context::default_backstop_callback { + child.backstop_callback = backstop_callback as *const _; + child.backstop_data = backstop_data; + } + let mut gp_args_ix = 0; let mut fp_args_ix = 0; let mut gp_regs_values = [0u64; 6]; @@ -443,7 +470,7 @@ impl Context { // the address of the first function to run on `swap`: `lucet_context_bootstrap`. child.gpr.rsp = &mut stack[stack.len() - stack_start] as *mut u64 as u64; - child.gpr.rbp = guest_data as *const GuestData as u64; + child.gpr.rbp = child as *const Context as u64; // Read the mask to be restored if we ever need to jump out of a signal handler. If this // isn't possible, die. @@ -466,13 +493,17 @@ impl Context { /// pointer is then replaced by the value saved in `to.gpr.rsp`, so when `swap` returns, it will /// return to the pointer saved in `to`'s stack. /// - /// If `to` was freshly initialized by passing it as the child to `init`, `swap` will return to - /// the function that bootstraps arguments and then calls the entrypoint that was passed to - /// `init`. + /// If `to` was freshly initialized by passing it as the `child` argument to `init`, `swap` will + /// return to the function that bootstraps arguments and then calls the entrypoint that was + /// passed to `init`. /// /// If `to` was previously passed as the `from` argument to another call to `swap`, the program /// will return as if from that _first_ call to `swap`. /// + /// The address of `from` will be saved as `to.parent_ctx`. If `to` was initialized by `init`, + /// it will swap back to the `from` context when the entrypoint function returns via + /// `lucet_context_backstop`. + /// /// # Safety /// /// The value in `to.gpr.rsp` must be a valid pointer into the stack that was originally passed @@ -483,12 +514,16 @@ impl Context { /// of the function passed to `init`, or be unaltered from when they were previously written by /// `swap`. /// + /// If `to` was initialized by `init`, the `from` context must not be moved, dropped, or + /// otherwise invalidated while in the `to` context unless `to`'s entrypoint function never + /// returns. + /// /// If `from` is never returned to, `swap`ped to, or `set` to, resources could leak due to /// implicit `drop`s never being called: /// /// ```no_run /// # use lucet_runtime_internals::context::Context; - /// fn f(x: Box, child: &Context) { + /// fn f(x: Box, child: &mut Context) { /// let mut xs = vec![187; 410757864530]; /// xs[0] += *x; /// @@ -509,25 +544,23 @@ impl Context { /// /// ```no_run /// # use lucet_runtime_internals::context::Context; - /// # use lucet_runtime_internals::instance::GuestData; /// # extern "C" fn entrypoint() {} /// # let mut stack = vec![0u64; 1024].into_boxed_slice(); - /// let mut guest_data = GuestData::default(); /// let mut parent = Context::new(); /// let mut child = Context::new(); /// Context::init( /// &mut stack, /// &mut child, - /// &mut guest_data, /// entrypoint as usize, /// &[], /// ).unwrap(); /// - /// unsafe { Context::swap(&mut parent, &child); } + /// unsafe { Context::swap(&mut parent, &mut child); } /// ``` #[inline] - pub unsafe fn swap(from: &mut Context, to: &Context) { - lucet_context_swap(from as *mut Context, to as *const Context); + pub unsafe fn swap(from: &mut Context, to: &mut Context) { + to.parent_ctx = from; + lucet_context_swap(from as *mut _, to as *mut _); } /// Swap to another context without saving the current context. @@ -558,13 +591,14 @@ impl Context { /// /// ## Returning /// - /// If `to` is a context freshly initialized by `init`, at least one of the following must be - /// true, otherwise the program will return to a context with uninitialized registers: + /// If `to` is a context freshly initialized by `init` (as opposed to a context populated only + /// by `swap`, such as a host context), at least one of the following must be true, otherwise + /// the program will return to a context with uninitialized registers: /// /// - The `fptr` argument to `init` is a function that never returns /// - /// - The `parent` argument to `init` was passed as the `from` argument to `swap` before this - /// call to `set` + /// - A valid context must have been passed as the `from` argument to `swap` when entering the + /// current context before this call to `set` /// /// ## Resource leaks /// @@ -683,7 +717,7 @@ extern "C" { fn lucet_context_backstop(); /// Saves the current context and performs the context switch. Implemented in assembly. - fn lucet_context_swap(from: *mut Context, to: *const Context); + fn lucet_context_swap(from: *mut Context, to: *mut Context); /// Performs the context switch; implemented in assembly. /// diff --git a/lucet-runtime/lucet-runtime-internals/src/context/tests/c_child.rs b/lucet-runtime/lucet-runtime-internals/src/context/tests/c_child.rs index 17d765941..6c881c02c 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/tests/c_child.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/tests/c_child.rs @@ -51,25 +51,15 @@ macro_rules! test_body { macro_rules! init_and_swap { ( $stack:ident, $fn:ident, [ $( $args:expr ),* ] ) => { unsafe { - let kill_state = $crate::instance::KillState::new(); - kill_state.enable_termination(); - let mut guest_data = $crate::instance::GuestData::default(); - guest_data.kill_state = &kill_state as *const $crate::instance::KillState; let child = Box::into_raw(Box::new(ContextHandle::create_and_init( &mut *$stack, - &mut guest_data, $fn as usize, &[$( $args ),*], ).unwrap())); child_regs = child; - let parent_ctx: &mut Context = parent_regs.as_mut().unwrap(); - guest_data.parent_ctx = parent_ctx as *mut Context; - let child_ctx: &mut Context = child_regs.as_mut().unwrap(); - guest_data.child_ctx = child_ctx as *mut Context; - - Context::swap(parent_regs.as_mut().unwrap(), child_regs.as_ref().unwrap()); + Context::swap(parent_regs.as_mut().unwrap(), child_regs.as_mut().unwrap()); } } } @@ -119,7 +109,7 @@ fn call_child_twice() { arg1_val = 10; unsafe { - Context::swap(parent_regs.as_mut().unwrap(), child_regs.as_ref().unwrap()); + Context::swap(parent_regs.as_mut().unwrap(), child_regs.as_mut().unwrap()); } assert_eq!( diff --git a/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs b/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs index 1f2ef26c9..c98930b16 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs @@ -1,7 +1,6 @@ mod c_child; mod rust_child; use crate::context::{Context, ContextHandle, Error}; -use crate::instance::GuestData; use memoffset::offset_of; use std::slice; @@ -32,9 +31,7 @@ fn init_rejects_unaligned() { let mut stack_unaligned = unsafe { slice::from_raw_parts_mut(ptr, len) }; // now we have the unaligned stack, let's make sure it blows up right - let mut guest_data = GuestData::default(); - let res = - ContextHandle::create_and_init(&mut stack_unaligned, &mut guest_data, dummy as usize, &[]); + let res = ContextHandle::create_and_init(&mut stack_unaligned, dummy as usize, &[]); if let Err(Error::UnalignedStack) = res { assert!(true); diff --git a/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs b/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs index bd5263030..5c44053dc 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs @@ -47,26 +47,16 @@ macro_rules! test_body { macro_rules! init_and_swap { ( $stack:ident, $fn:ident, [ $( $args:expr ),* ] ) => { unsafe { - let kill_state = $crate::instance::KillState::new(); - kill_state.enable_termination(); - let mut guest_data = $crate::instance::GuestData::default(); - guest_data.kill_state = &kill_state as *const $crate::instance::KillState; let child = ContextHandle::create_and_init( &mut *$stack, - &mut guest_data, $fn as usize, &[$( $args ),*], ).unwrap(); CHILD = Some(child); - let child_ref: &mut Context = CHILD.as_mut().unwrap(); - guest_data.child_ctx = child_ref as *mut Context; - let parent_ref: &mut Context = PARENT.as_mut().unwrap(); - guest_data.parent_ctx = parent_ref as *mut Context; - Context::swap( PARENT.as_mut().unwrap(), - CHILD.as_ref().unwrap(), + CHILD.as_mut().unwrap(), ); } } @@ -84,7 +74,7 @@ extern "C" fn arg_printing_child(arg0: *mut c_void, arg1: *mut c_void) { ) .unwrap(); - unsafe { Context::swap(CHILD.as_mut().unwrap(), PARENT.as_ref().unwrap()) }; + unsafe { Context::swap(CHILD.as_mut().unwrap(), PARENT.as_mut().unwrap()) }; // Read the arguments again let arg0_val = unsafe { *(arg0 as *mut c_int) }; @@ -98,7 +88,7 @@ extern "C" fn arg_printing_child(arg0: *mut c_void, arg1: *mut c_void) { ) .unwrap(); - unsafe { Context::swap(CHILD.as_mut().unwrap(), PARENT.as_ref().unwrap()) }; + unsafe { Context::swap(CHILD.as_mut().unwrap(), PARENT.as_mut().unwrap()) }; } #[test] @@ -132,7 +122,7 @@ fn call_child_twice() { arg1_val = 10; unsafe { - Context::swap(PARENT.as_mut().unwrap(), CHILD.as_ref().unwrap()); + Context::swap(PARENT.as_mut().unwrap(), CHILD.as_mut().unwrap()); } assert_output_eq!( @@ -269,7 +259,7 @@ macro_rules! child_n_args { write!(out, $prefix).unwrap(); $( write!(out, " {}", $arg).unwrap(); - );* + )* write!(out, "\n").unwrap(); } @@ -369,7 +359,7 @@ macro_rules! child_n_fp_args { write!(out, $prefix).unwrap(); $( write!(out, " {:.1}", $arg).unwrap(); - );* + )* write!(out, "\n").unwrap(); } diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index a246fecee..b2d8dd473 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -60,29 +60,6 @@ pub struct InstanceHandle { needs_inst_drop: bool, } -/// `GuestData` contains host data that must be shared with guests. These are necesary to implement -/// operations that interact with the host context, such as context switching and some parts of -/// instance termination. -#[repr(C)] -pub struct GuestData { - pub child_ctx: *mut Context, - pub parent_ctx: *mut Context, - pub kill_state: *const KillState, - pub exit_guest_region: *const extern "C" fn(*mut execution::KillState), -} - -impl Default for GuestData { - fn default() -> Self { - GuestData { - child_ctx: std::ptr::null_mut(), - parent_ctx: std::ptr::null_mut(), - kill_state: std::ptr::null(), - exit_guest_region: execution::exit_guest_region - as *const extern "C" fn(*mut execution::KillState), - } - } -} - // raw pointer lint unsafe impl Send for InstanceHandle {} @@ -279,10 +256,6 @@ pub struct Instance { /// The value passed back to the guest when resuming a yielded instance. pub(crate) resumed_val: Option>, - /// Information shared with the guest to implement guest primitives like - /// `lucet_context_backstop`. - guest_data: GuestData, - /// `_padding` must be the last member of the structure. /// This marks where the padding starts to make the structure exactly 4096 bytes long. /// It is also used to compute the size of the structure up to that point, i.e. without padding. @@ -788,7 +761,6 @@ impl Instance { signal_handler: Box::new(signal_handler_none) as Box, entrypoint: None, resumed_val: None, - guest_data: GuestData::default(), _padding: (), }; inst.set_globals_ptr(globals_ptr); @@ -874,19 +846,15 @@ impl Instance { let mut args_with_vmctx = vec![Val::from(self.alloc.slot().heap)]; args_with_vmctx.extend_from_slice(args); - HOST_CTX.with(|host_ctx| { - self.guest_data.child_ctx = &mut self.ctx as *mut Context; - self.guest_data.kill_state = &*self.kill_state; - self.guest_data.parent_ctx = unsafe { &mut *host_ctx.get() }; - - Context::init( - unsafe { self.alloc.stack_u64_mut() }, - &mut self.ctx, - &self.guest_data, - func.ptr.as_usize(), - &args_with_vmctx, - ) - })?; + let self_ptr = self as *mut _; + Context::init_with_callback( + unsafe { self.alloc.stack_u64_mut() }, + &mut self.ctx, + execution::exit_guest_region, + self_ptr, + func.ptr.as_usize(), + &args_with_vmctx, + )?; // Set up the guest to set itself as terminable, then continue to // whatever guest code we want to run. @@ -941,7 +909,6 @@ impl Instance { self.with_signals_on(|i| { HOST_CTX.with(|host_ctx| { - i.guest_data.parent_ctx = host_ctx.get(); // Save the current context into `host_ctx`, and jump to the guest context. The // lucet context is linked to host_ctx, so it will return here after it finishes, // successfully or otherwise. diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/execution.rs b/lucet-runtime/lucet-runtime-internals/src/instance/execution.rs index fe8e32074..26ee4310c 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/execution.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/execution.rs @@ -79,7 +79,7 @@ use std::mem; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Condvar, Mutex, Weak}; -use crate::instance::TerminationDetails; +use crate::instance::{Instance, TerminationDetails}; /// All instance state a remote kill switch needs to determine if and how to signal that execution /// should stop. @@ -125,8 +125,11 @@ pub struct KillState { tid_change_notifier: Condvar, } -pub unsafe extern "C" fn exit_guest_region(kill_state: *mut KillState) { - let terminable = (*kill_state).terminable.swap(false, Ordering::SeqCst); +pub unsafe extern "C" fn exit_guest_region(instance: *mut Instance) { + let terminable = (*instance) + .kill_state + .terminable + .swap(false, Ordering::SeqCst); if !terminable { // Something else has taken the terminable flag, so it's not safe to actually exit a // guest context yet. Because this is called when exiting a guest context, the From 7b02d08578d320fa11ce8520ef4163942beb1d89 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Wed, 23 Oct 2019 16:17:12 -0400 Subject: [PATCH 449/512] [lucet-benchmarks] slightly simplify a setup iter --- benchmarks/lucet-benchmarks/src/context.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/benchmarks/lucet-benchmarks/src/context.rs b/benchmarks/lucet-benchmarks/src/context.rs index c0fb67879..1803e6735 100644 --- a/benchmarks/lucet-benchmarks/src/context.rs +++ b/benchmarks/lucet-benchmarks/src/context.rs @@ -22,11 +22,11 @@ fn context_swap_return(c: &mut Criterion) { b.iter_batched( || { let mut stack = vec![0u64; 1024].into_boxed_slice(); - let parent = ContextHandle::new(); let child = ContextHandle::create_and_init(&mut *stack, f as usize, &[]).unwrap(); - (stack, parent, child) + (stack, child) }, - |(stack, mut parent, mut child)| unsafe { + |(stack, mut child)| unsafe { + let mut parent = ContextHandle::new(); Context::swap(&mut parent, &mut child); stack }, From 30970e40348ddcf875837c84305cd5bd44aee0f5 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Wed, 23 Oct 2019 18:44:33 -0400 Subject: [PATCH 450/512] bump crate versions to 0.3.1 Keeping this as a minor semver because API changes were restricted to `lucet-runtime-internals` functions that are not exported via `lucet-runtime`. --- Cargo.lock | 112 +++++++++--------- Cargo.toml | 2 +- benchmarks/lucet-benchmarks/Cargo.toml | 2 +- lucet-module/Cargo.toml | 2 +- lucet-objdump/Cargo.toml | 4 +- lucet-runtime/Cargo.toml | 12 +- .../lucet-runtime-internals/Cargo.toml | 4 +- lucet-runtime/lucet-runtime-tests/Cargo.toml | 10 +- lucet-spectest/Cargo.toml | 8 +- lucet-validate/Cargo.toml | 4 +- lucet-wasi-fuzz/Cargo.toml | 2 +- lucet-wasi-sdk/Cargo.toml | 8 +- lucet-wasi/Cargo.toml | 12 +- lucetc/Cargo.toml | 6 +- 14 files changed, 94 insertions(+), 94 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c2a0e3817..f3a706184 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -760,15 +760,15 @@ dependencies = [ [[package]] name = "lucet-benchmarks" -version = "0.3.0" +version = "0.3.1" dependencies = [ "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.3.0", - "lucet-runtime 0.3.0", - "lucet-runtime-internals 0.3.0", - "lucet-wasi 0.3.0", - "lucet-wasi-sdk 0.3.0", - "lucetc 0.3.0", + "lucet-module 0.3.1", + "lucet-runtime 0.3.1", + "lucet-runtime-internals 0.3.1", + "lucet-wasi 0.3.1", + "lucet-wasi-sdk 0.3.1", + "lucetc 0.3.1", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -783,8 +783,8 @@ dependencies = [ "cranelift-entity 0.44.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.3.0", - "lucetc 0.3.0", + "lucet-module 0.3.1", + "lucetc 0.3.1", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -800,10 +800,10 @@ dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-idl 0.2.0", - "lucet-runtime 0.3.0", - "lucet-wasi 0.3.0", - "lucet-wasi-sdk 0.3.0", - "lucetc 0.3.0", + "lucet-runtime 0.3.1", + "lucet-wasi 0.3.1", + "lucet-wasi-sdk 0.3.1", + "lucetc 0.3.1", "proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -816,13 +816,13 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-idl 0.2.0", - "lucet-runtime 0.3.0", - "lucet-wasi 0.3.0", + "lucet-runtime 0.3.1", + "lucet-wasi 0.3.1", ] [[package]] name = "lucet-module" -version = "0.3.0" +version = "0.3.1" dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -839,28 +839,28 @@ dependencies = [ [[package]] name = "lucet-objdump" -version = "0.3.0" +version = "0.3.1" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.3.0", + "lucet-module 0.3.1", ] [[package]] name = "lucet-runtime" -version = "0.3.0" +version = "0.3.1" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.3.0", - "lucet-runtime-internals 0.3.0", - "lucet-runtime-tests 0.3.0", - "lucet-wasi-sdk 0.3.0", - "lucetc 0.3.0", + "lucet-module 0.3.1", + "lucet-runtime-internals 0.3.1", + "lucet-runtime-tests 0.3.1", + "lucet-wasi-sdk 0.3.1", + "lucetc 0.3.1", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -870,7 +870,7 @@ dependencies = [ [[package]] name = "lucet-runtime-internals" -version = "0.3.0" +version = "0.3.1" dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -881,7 +881,7 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.3.0", + "lucet-module 0.3.1", "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -891,27 +891,27 @@ dependencies = [ [[package]] name = "lucet-runtime-tests" -version = "0.3.0" +version = "0.3.1" dependencies = [ "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.3.0", - "lucet-runtime-internals 0.3.0", - "lucet-wasi-sdk 0.3.0", - "lucetc 0.3.0", + "lucet-module 0.3.1", + "lucet-runtime-internals 0.3.1", + "lucet-wasi-sdk 0.3.1", + "lucetc 0.3.1", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucet-spectest" -version = "0.3.0" +version = "0.3.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.3.0", - "lucet-runtime 0.3.0", - "lucetc 0.3.0", + "lucet-module 0.3.1", + "lucet-runtime 0.3.1", + "lucetc 0.3.1", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -920,12 +920,12 @@ dependencies = [ [[package]] name = "lucet-validate" -version = "0.3.0" +version = "0.3.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.44.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-wasi-sdk 0.3.0", + "lucet-wasi-sdk 0.3.1", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -934,7 +934,7 @@ dependencies = [ [[package]] name = "lucet-wasi" -version = "0.3.0" +version = "0.3.1" dependencies = [ "bindgen 0.47.3 (registry+https://github.com/rust-lang/crates.io-index)", "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -942,11 +942,11 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.3.0", - "lucet-runtime 0.3.0", - "lucet-runtime-internals 0.3.0", - "lucet-wasi-sdk 0.3.0", - "lucetc 0.3.0", + "lucet-module 0.3.1", + "lucet-runtime 0.3.1", + "lucet-runtime-internals 0.3.1", + "lucet-wasi-sdk 0.3.1", + "lucetc 0.3.1", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -954,16 +954,16 @@ dependencies = [ [[package]] name = "lucet-wasi-fuzz" -version = "0.3.0" +version = "0.3.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.3.0", - "lucet-runtime 0.3.0", - "lucet-wasi 0.3.0", - "lucet-wasi-sdk 0.3.0", - "lucetc 0.3.0", + "lucet-module 0.3.1", + "lucet-runtime 0.3.1", + "lucet-wasi 0.3.1", + "lucet-wasi-sdk 0.3.1", + "lucetc 0.3.1", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -977,18 +977,18 @@ dependencies = [ [[package]] name = "lucet-wasi-sdk" -version = "0.3.0" +version = "0.3.1" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.3.0", - "lucet-validate 0.3.0", - "lucetc 0.3.0", + "lucet-module 0.3.1", + "lucet-validate 0.3.1", + "lucetc 0.3.1", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucetc" -version = "0.3.0" +version = "0.3.1" dependencies = [ "bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1007,8 +1007,8 @@ dependencies = [ "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.3.0", - "lucet-validate 0.3.0", + "lucet-module 0.3.1", + "lucet-validate 0.3.1", "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index d1eb02de1..7d5b8860c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,4 @@ -# Lucet version 0.3.0 +# Lucet version 0.3.1 [workspace] members = [ diff --git a/benchmarks/lucet-benchmarks/Cargo.toml b/benchmarks/lucet-benchmarks/Cargo.toml index 4fc38e88e..8af99a722 100644 --- a/benchmarks/lucet-benchmarks/Cargo.toml +++ b/benchmarks/lucet-benchmarks/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-benchmarks" -version = "0.3.0" +version = "0.3.1" description = "Benchmarks for the Lucet runtime" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" diff --git a/lucet-module/Cargo.toml b/lucet-module/Cargo.toml index 93a8b51b2..300a53792 100644 --- a/lucet-module/Cargo.toml +++ b/lucet-module/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-module" -version = "0.3.0" +version = "0.3.1" description = "A structured interface for Lucet modules" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" diff --git a/lucet-objdump/Cargo.toml b/lucet-objdump/Cargo.toml index 85e954af2..6b0018813 100644 --- a/lucet-objdump/Cargo.toml +++ b/lucet-objdump/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-objdump" -version = "0.3.0" +version = "0.3.1" description = "Analyze object files emitted by the Lucet compiler" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -13,7 +13,7 @@ edition = "2018" goblin="0.0.24" byteorder="1.2.1" colored="1.6.1" -lucet-module = { path = "../lucet-module", version = "0.3.0" } +lucet-module = { path = "../lucet-module", version = "0.3.1" } [package.metadata.deb] name = "fst-lucet-objdump" diff --git a/lucet-runtime/Cargo.toml b/lucet-runtime/Cargo.toml index b6e08d197..ad05062e8 100644 --- a/lucet-runtime/Cargo.toml +++ b/lucet-runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime" -version = "0.3.0" +version = "0.3.1" description = "Pure Rust runtime for Lucet WebAssembly toolchain" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -11,8 +11,8 @@ edition = "2018" [dependencies] libc = "=0.2.59" -lucet-runtime-internals = { path = "lucet-runtime-internals", version = "0.3.0" } -lucet-module = { path = "../lucet-module", version = "0.3.0" } +lucet-runtime-internals = { path = "lucet-runtime-internals", version = "0.3.1" } +lucet-module = { path = "../lucet-module", version = "0.3.1" } num-traits = "0.2" num-derive = "0.2" @@ -20,9 +20,9 @@ num-derive = "0.2" byteorder = "1.2" failure = "0.1" lazy_static = "1.1" -lucetc = { path = "../lucetc", version = "0.3.0" } -lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.3.0" } -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.3.0" } +lucetc = { path = "../lucetc", version = "0.3.1" } +lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.3.1" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.3.1" } nix = "0.13" rayon = "1.0" tempfile = "3.0" diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index f619e41f7..c61966c98 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime-internals" -version = "0.3.0" +version = "0.3.1" description = "Pure Rust runtime for Lucet WebAssembly toolchain (internals)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -10,7 +10,7 @@ authors = ["Lucet team "] edition = "2018" [dependencies] -lucet-module = { path = "../../lucet-module", version = "0.3.0" } +lucet-module = { path = "../../lucet-module", version = "0.3.1" } bitflags = "1.0" bincode = "1.1.4" diff --git a/lucet-runtime/lucet-runtime-tests/Cargo.toml b/lucet-runtime/lucet-runtime-tests/Cargo.toml index 22a92181e..379ad8260 100644 --- a/lucet-runtime/lucet-runtime-tests/Cargo.toml +++ b/lucet-runtime/lucet-runtime-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime-tests" -version = "0.3.0" +version = "0.3.1" description = "Pure Rust runtime for Lucet WebAssembly toolchain (tests)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -18,10 +18,10 @@ test = false failure = "0.1" lazy_static = "1.1" tempfile = "3.0" -lucet-module = { path = "../../lucet-module", version = "0.3.0" } -lucet-runtime-internals = { path = "../lucet-runtime-internals", version = "0.3.0" } -lucet-wasi-sdk = { path = "../../lucet-wasi-sdk", version = "0.3.0" } -lucetc = { path = "../../lucetc", version = "0.3.0" } +lucet-module = { path = "../../lucet-module", version = "0.3.1" } +lucet-runtime-internals = { path = "../lucet-runtime-internals", version = "0.3.1" } +lucet-wasi-sdk = { path = "../../lucet-wasi-sdk", version = "0.3.1" } +lucetc = { path = "../../lucetc", version = "0.3.1" } [build-dependencies] cc = "1.0" diff --git a/lucet-spectest/Cargo.toml b/lucet-spectest/Cargo.toml index 67bdbd43f..521dd04c1 100644 --- a/lucet-spectest/Cargo.toml +++ b/lucet-spectest/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-spectest" -version = "0.3.0" +version = "0.3.1" description = "Test harness to run WebAssembly spec tests (.wast) against the Lucet toolchain" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -17,9 +17,9 @@ name = "spec-test" path = "src/main.rs" [dependencies] -lucetc = { path = "../lucetc", version = "0.3.0" } -lucet-module = { path = "../lucet-module", version = "0.3.0" } -lucet-runtime = { path = "../lucet-runtime", version = "0.3.0" } +lucetc = { path = "../lucetc", version = "0.3.1" } +lucet-module = { path = "../lucet-module", version = "0.3.1" } +lucet-runtime = { path = "../lucet-runtime", version = "0.3.1" } wabt = "0.9.2" serde = "1.0" serde_json = "1.0" diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index 12879507c..8c3b6a8e9 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-validate" -version = "0.3.0" +version = "0.3.1" description = "Parse and validate webassembly files against witx interface" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -24,7 +24,7 @@ cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.44.0" wasmparser = "0.39.1" [dev-dependencies] -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.3.0" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.3.1" } tempfile = "3.0" wabt = "0.9.2" diff --git a/lucet-wasi-fuzz/Cargo.toml b/lucet-wasi-fuzz/Cargo.toml index 25b393fb9..b36ee2256 100644 --- a/lucet-wasi-fuzz/Cargo.toml +++ b/lucet-wasi-fuzz/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi-fuzz" -version = "0.3.0" +version = "0.3.1" description = "Test the Lucet toolchain against native code execution using Csmith" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" diff --git a/lucet-wasi-sdk/Cargo.toml b/lucet-wasi-sdk/Cargo.toml index 3f7ba24a1..140c533b2 100644 --- a/lucet-wasi-sdk/Cargo.toml +++ b/lucet-wasi-sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi-sdk" -version = "0.3.0" +version = "0.3.1" description = "A Rust interface to the wasi-sdk compiler and linker" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -11,9 +11,9 @@ edition = "2018" [dependencies] failure = "0.1" -lucetc = { path = "../lucetc", version = "0.3.0" } -lucet-module = { path = "../lucet-module", version = "0.3.0" } +lucetc = { path = "../lucetc", version = "0.3.1" } +lucet-module = { path = "../lucet-module", version = "0.3.1" } tempfile = "3.0" [dev-dependencies] -lucet-validate = { path = "../lucet-validate", version = "0.3.0" } +lucet-validate = { path = "../lucet-validate", version = "0.3.1" } diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index a0104174c..f8ca0055d 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi" -version = "0.3.0" +version = "0.3.1" description = "Fastly's runtime for the WebAssembly System Interface (WASI)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -29,15 +29,15 @@ clap = "2.23" failure = "0.1" human-size = "0.4" libc = "=0.2.59" -lucet-runtime = { path = "../lucet-runtime", version = "0.3.0" } -lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.3.0" } -lucet-module = { path = "../lucet-module", version = "0.3.0" } +lucet-runtime = { path = "../lucet-runtime", version = "0.3.1" } +lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.3.1" } +lucet-module = { path = "../lucet-module", version = "0.3.1" } nix = "0.13" rand = "0.6" [dev-dependencies] -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.3.0" } -lucetc = { path = "../lucetc", version = "0.3.0" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.3.1" } +lucetc = { path = "../lucetc", version = "0.3.1" } tempfile = "3.0" [build-dependencies.bindgen] diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index 7f6c5cbcc..511f80340 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucetc" -version = "0.3.0" +version = "0.3.1" description = "Fastly's WebAssembly to native code compiler" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -26,8 +26,8 @@ cranelift-module = { path = "../cranelift/cranelift-module", version = "0.44.0" cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.44.0" } cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.44.0" } target-lexicon = "0.8.0" -lucet-module = { path = "../lucet-module", version = "0.3.0" } -lucet-validate = { path = "../lucet-validate", version = "0.3.0" } +lucet-module = { path = "../lucet-module", version = "0.3.1" } +lucet-validate = { path = "../lucet-validate", version = "0.3.1" } wasmparser = "0.39.1" clap="2.32" log = "0.4" From e1aa4e1ec204471c30ebfc962a7af1067d058166 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Tue, 29 Oct 2019 11:34:34 -0700 Subject: [PATCH 451/512] [lucetc] restore output for the underlying cause of `lucetc::Error`s --- lucetc/src/main.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lucetc/src/main.rs b/lucetc/src/main.rs index e1b5e1191..4d22b4012 100644 --- a/lucetc/src/main.rs +++ b/lucetc/src/main.rs @@ -22,7 +22,11 @@ pub struct SerializedLucetcError { impl From for SerializedLucetcError { fn from(e: Error) -> Self { SerializedLucetcError { - error: format!("{}", e), + error: if let Some(cause) = e.as_fail().cause() { + format!("{}: {}", e, cause) + } else { + format!("{}", e) + }, } } } @@ -34,7 +38,12 @@ fn main() { if let Err(err) = run(&opts) { match opts.error_style { - ErrorStyle::Human => eprintln!("Error: {}\n", err), + ErrorStyle::Human => { + eprintln!("Error: {}\n", err); + if let Some(cause) = err.as_fail().cause() { + eprintln!("{}", cause); + } + } ErrorStyle::Json => { let errs: Vec = vec![err.into()]; let json = serde_json::to_string(&errs).unwrap(); From 1337ed6b3cdf8d26d82cee8393f14f442e62786d Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Wed, 30 Oct 2019 10:01:48 -0700 Subject: [PATCH 452/512] update cranelift to current master (0.46.1) This is in preparation for adding an interface to customize machine-dependent features in cranelift's codegen --- Cargo.lock | 88 +++++++++++++++++++-------------------- cranelift | 2 +- lucet-module/Cargo.toml | 2 +- lucet-validate/Cargo.toml | 2 +- lucetc/Cargo.toml | 14 +++---- lucetc/src/compiler.rs | 35 ++++++++++++---- lucetc/src/function.rs | 6 +-- lucetc/src/module.rs | 11 +++-- 8 files changed, 91 insertions(+), 69 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f3a706184..9c3283595 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -287,19 +287,19 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.44.0" +version = "0.46.1" dependencies = [ - "cranelift-entity 0.44.0", + "cranelift-entity 0.46.1", ] [[package]] name = "cranelift-codegen" -version = "0.44.0" +version = "0.46.1" dependencies = [ - "cranelift-bforest 0.44.0", - "cranelift-codegen-meta 0.44.0", - "cranelift-codegen-shared 0.44.0", - "cranelift-entity 0.44.0", + "cranelift-bforest 0.46.1", + "cranelift-codegen-meta 0.46.1", + "cranelift-codegen-shared 0.46.1", + "cranelift-entity 0.46.1", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -309,26 +309,26 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.44.0" +version = "0.46.1" dependencies = [ - "cranelift-codegen-shared 0.44.0", - "cranelift-entity 0.44.0", + "cranelift-codegen-shared 0.46.1", + "cranelift-entity 0.46.1", ] [[package]] name = "cranelift-codegen-shared" -version = "0.44.0" +version = "0.46.1" [[package]] name = "cranelift-entity" -version = "0.44.0" +version = "0.46.1" [[package]] name = "cranelift-faerie" -version = "0.44.0" +version = "0.46.1" dependencies = [ - "cranelift-codegen 0.44.0", - "cranelift-module 0.44.0", + "cranelift-codegen 0.46.1", + "cranelift-module 0.46.1", "faerie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -337,9 +337,9 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.44.0" +version = "0.46.1" dependencies = [ - "cranelift-codegen 0.44.0", + "cranelift-codegen 0.46.1", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -347,34 +347,34 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.44.0" +version = "0.46.1" dependencies = [ - "cranelift-codegen 0.44.0", - "cranelift-entity 0.44.0", + "cranelift-codegen 0.46.1", + "cranelift-entity 0.46.1", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-native" -version = "0.44.0" +version = "0.46.1" dependencies = [ - "cranelift-codegen 0.44.0", - "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen 0.46.1", + "raw-cpuid 7.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-wasm" -version = "0.44.0" +version = "0.46.1" dependencies = [ - "cranelift-codegen 0.44.0", - "cranelift-entity 0.44.0", - "cranelift-frontend 0.44.0", + "cranelift-codegen 0.46.1", + "cranelift-entity 0.46.1", + "cranelift-frontend 0.46.1", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -780,7 +780,7 @@ name = "lucet-idl" version = "0.2.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-entity 0.44.0", + "cranelift-entity 0.46.1", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.3.1", @@ -826,7 +826,7 @@ version = "0.3.1" dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-entity 0.44.0", + "cranelift-entity 0.46.1", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -923,12 +923,12 @@ name = "lucet-validate" version = "0.3.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-entity 0.44.0", + "cranelift-entity 0.46.1", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-wasi-sdk 0.3.1", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", "witx 0.3.0", ] @@ -994,13 +994,13 @@ dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.44.0", - "cranelift-entity 0.44.0", - "cranelift-faerie 0.44.0", - "cranelift-frontend 0.44.0", - "cranelift-module 0.44.0", - "cranelift-native 0.44.0", - "cranelift-wasm 0.44.0", + "cranelift-codegen 0.46.1", + "cranelift-entity 0.46.1", + "cranelift-faerie 0.46.1", + "cranelift-frontend 0.46.1", + "cranelift-module 0.46.1", + "cranelift-native 0.46.1", + "cranelift-wasm 0.46.1", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "faerie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1018,7 +1018,7 @@ dependencies = [ "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasmonkey 0.1.8", - "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1440,7 +1440,7 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "6.1.0" +version = "7.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1935,7 +1935,7 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.39.1" +version = "0.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2144,7 +2144,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03b418169fb9c46533f326efd6eed2576699c44ca92d3052a066214a8d828929" -"checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d" +"checksum raw-cpuid 7.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4a349ca83373cfa5d6dbb66fd76e58b2cca08da71a5f6400de0a0a6a9bceeaf" "checksum rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83a27732a533a1be0a0035a111fe76db89ad312f6f0347004c220c57f209a123" "checksum rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" @@ -2202,7 +2202,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af5d153dc96aad7dc13ab90835b892c69867948112d95299e522d370c4e13a08" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" -"checksum wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a026c1436af49d5537c7561c7474f81f7a754e36445fe52e6e88795a9747291c" +"checksum wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5083b449454f7de0b15f131eee17de54b5a71dcb9adcf11df2b2f78fad0cd82" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" diff --git a/cranelift b/cranelift index d5c34954d..f93589856 160000 --- a/cranelift +++ b/cranelift @@ -1 +1 @@ -Subproject commit d5c34954d9ea94732a1711542c2e42790870adb0 +Subproject commit f935898563aababf1fe06d2d6830b37a0b05e85f diff --git a/lucet-module/Cargo.toml b/lucet-module/Cargo.toml index 300a53792..8f28d5f80 100644 --- a/lucet-module/Cargo.toml +++ b/lucet-module/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Lucet team "] edition = "2018" [dependencies] -cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.44.0" } +cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.46.1" } failure = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index 8c3b6a8e9..7a3f86968 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -20,7 +20,7 @@ path = "src/main.rs" clap = "2" failure = "0.1" witx = { path = "../wasi/tools/witx", version = "0.3.0" } -cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.44.0" } +cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.46.1" } wasmparser = "0.39.1" [dev-dependencies] diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index 511f80340..0babbea4f 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -18,13 +18,13 @@ path = "src/main.rs" [dependencies] bincode = "1.1.4" -cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.44.0" } -cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.44.0" } -cranelift-native = { path = "../cranelift/cranelift-native", version = "0.44.0" } -cranelift-frontend = { path = "../cranelift/cranelift-frontend", version = "0.44.0" } -cranelift-module = { path = "../cranelift/cranelift-module", version = "0.44.0" } -cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.44.0" } -cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.44.0" } +cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.46.1" } +cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.46.1" } +cranelift-native = { path = "../cranelift/cranelift-native", version = "0.46.1" } +cranelift-frontend = { path = "../cranelift/cranelift-frontend", version = "0.46.1" } +cranelift-module = { path = "../cranelift/cranelift-module", version = "0.46.1" } +cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.46.1" } +cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.46.1" } target-lexicon = "0.8.0" lucet-module = { path = "../lucet-module", version = "0.3.1" } lucet-validate = { path = "../lucet-validate", version = "0.3.1" } diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index 6aacc6e54..85dee31f2 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -16,7 +16,7 @@ use cranelift_codegen::{ use cranelift_faerie::{FaerieBackend, FaerieBuilder, FaerieTrapCollection}; use cranelift_module::{Backend as ClifBackend, Module as ClifModule}; use cranelift_native; -use cranelift_wasm::{translate_module, FuncTranslator, WasmError}; +use cranelift_wasm::{translate_module, FuncTranslator, ModuleTranslationState, WasmError}; use failure::{format_err, Fail, ResultExt}; use lucet_module::bindings::Bindings; use lucet_module::{FunctionSpec, ModuleData, MODULE_DATA_SYM}; @@ -50,6 +50,7 @@ pub struct Compiler<'a> { clif_module: ClifModule, opt_level: OptLevel, count_instructions: bool, + module_translation_state: ModuleTranslationState, } impl<'a> Compiler<'a> { @@ -84,12 +85,15 @@ impl<'a> Compiler<'a> { .context(LucetcErrorKind::Validation)?; } - translate_module(wasm_binary, &mut module_info).map_err(|e| match e { - WasmError::User(_) => e.context(LucetcErrorKind::Input), - WasmError::InvalidWebAssembly { .. } => e.context(LucetcErrorKind::Validation), // This will trigger once cranelift-wasm upgrades to a validating wasm parser. - WasmError::Unsupported { .. } => e.context(LucetcErrorKind::Unsupported), - WasmError::ImplLimitExceeded { .. } => e.context(LucetcErrorKind::TranslatingModule), - })?; + let module_translation_state = + translate_module(wasm_binary, &mut module_info).map_err(|e| match e { + WasmError::User(_) => e.context(LucetcErrorKind::Input), + WasmError::InvalidWebAssembly { .. } => e.context(LucetcErrorKind::Validation), // This will trigger once cranelift-wasm upgrades to a validating wasm parser. + WasmError::Unsupported { .. } => e.context(LucetcErrorKind::Unsupported), + WasmError::ImplLimitExceeded { .. } => { + e.context(LucetcErrorKind::TranslatingModule) + } + })?; let libcalls = Box::new(move |libcall| match libcall { ir::LibCall::Probestack => stack_probe::STACK_PROBE_SYM.to_owned(), @@ -120,6 +124,7 @@ impl<'a> Compiler<'a> { clif_module, opt_level, count_instructions, + module_translation_state, }) } @@ -137,7 +142,13 @@ impl<'a> Compiler<'a> { clif_context.func.signature = func.signature.clone(); func_translator - .translate(code, *code_offset, &mut clif_context.func, &mut func_info) + .translate( + &self.module_translation_state, + code, + *code_offset, + &mut clif_context.func, + &mut func_info, + ) .map_err(|e| format_err!("in {}: {:?}", func.name.symbol(), e)) .context(LucetcErrorKind::FunctionTranslation)?; @@ -192,7 +203,13 @@ impl<'a> Compiler<'a> { clif_context.func.signature = func.signature.clone(); func_translator - .translate(code, *code_offset, &mut clif_context.func, &mut func_info) + .translate( + &self.module_translation_state, + code, + *code_offset, + &mut clif_context.func, + &mut func_info, + ) .map_err(|e| format_err!("in {}: {:?}", func.name.symbol(), e)) .context(LucetcErrorKind::FunctionTranslation)?; diff --git a/lucetc/src/function.rs b/lucetc/src/function.rs index 2c953039d..74e929501 100644 --- a/lucetc/src/function.rs +++ b/lucetc/src/function.rs @@ -8,8 +8,8 @@ use cranelift_codegen::ir::{self, InstBuilder}; use cranelift_codegen::isa::TargetFrontendConfig; use cranelift_frontend::FunctionBuilder; use cranelift_wasm::{ - FuncEnvironment, FuncIndex, GlobalIndex, GlobalVariable, MemoryIndex, SignatureIndex, - TableIndex, VisibleTranslationState, WasmError, WasmResult, + FuncEnvironment, FuncIndex, FuncTranslationState, GlobalIndex, GlobalVariable, MemoryIndex, + SignatureIndex, TableIndex, WasmError, WasmResult, }; use lucet_module::InstanceRuntimeData; use memoffset::offset_of; @@ -496,7 +496,7 @@ impl<'a> FuncEnvironment for FuncInfo<'a> { &mut self, op: &Operator, builder: &mut FunctionBuilder, - state: &VisibleTranslationState, + state: &FuncTranslationState, ) -> WasmResult<()> { if self.count_instructions { self.update_instruction_count_instrumentation(op, builder, state.reachable())?; diff --git a/lucetc/src/module.rs b/lucetc/src/module.rs index a72ef1b9f..982c53290 100644 --- a/lucetc/src/module.rs +++ b/lucetc/src/module.rs @@ -5,8 +5,8 @@ use cranelift_codegen::entity::{entity_impl, EntityRef, PrimaryMap}; use cranelift_codegen::ir; use cranelift_codegen::isa::TargetFrontendConfig; use cranelift_wasm::{ - FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, ModuleEnvironment, SignatureIndex, Table, - TableElementType, TableIndex, WasmResult, + FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, ModuleEnvironment, ModuleTranslationState, + SignatureIndex, Table, TableElementType, TableIndex, WasmResult, }; use failure::ResultExt; use lucet_module::UniqueSignatureIndex; @@ -327,7 +327,12 @@ impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { Ok(()) } - fn define_function_body(&mut self, body_bytes: &'a [u8], body_offset: usize) -> WasmResult<()> { + fn define_function_body( + &mut self, + _module_translation_state: &ModuleTranslationState, + body_bytes: &'a [u8], + body_offset: usize, + ) -> WasmResult<()> { let func_index = UniqueFuncIndex::new(self.imported_funcs.len() + self.function_bodies.len()); self.function_bodies From 6f093ac16382458772210e1c8fd7d6bde785287f Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 30 Oct 2019 11:46:45 -0700 Subject: [PATCH 453/512] delete .travis.yml --- .travis.yml | 33 --------------------------------- 1 file changed, 33 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index bb34f0496..000000000 --- a/.travis.yml +++ /dev/null @@ -1,33 +0,0 @@ -dist: xenial - -# Same as version in Dockerfile(s) -rust: 1.36.0 - -env: - - UNOPTIMIZED_BUILD=true DEVENV_SKIP_LUCET_BUILD=true - -services: - - docker - -stages: - - lint - - build_and_test - -jobs: - include: - - stage: lint - language: rust - install: - - rustup component add rustfmt - script: - - make indent-check - - git diff --exit-code - - stage: build_and_test - script: - - ./devenv_run.sh make test || travis_terminate 1 - - ./devenv_run.sh make audit || travis_terminate 1 - - ./devenv_stop.sh - - ./devenv_build_toolchain_only.sh - -notifications: - email: false From 67f0ec00f5ab7c3f0a0def9d6b8285d03221eff8 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Wed, 30 Oct 2019 14:31:23 -0700 Subject: [PATCH 454/512] [lucetc] add CPU feature flags for code generation This introduces a couple new command-line arguments and the associated programmatic APIs for selecting optional CPU features at compile time. Previously, we used `cranelift-native` to automatically detect and use the features available on the host, but this can cause problems when compiling for a different CPU, even if the target triple is constant. Now, we can enable or disable individual features using `--target-feature=+sse3,+avx,-popcnt`, for example. For convenience, we can also specify `--target-cpu=haswell`, for example, which enables a fixed set of individual features. The default behavior of auto-detection and use of features remains the same for now. --- cranelift | 2 +- lucet-wasi-sdk/tests/lucetc.rs | 60 +++++- lucetc/Cargo.toml | 5 +- lucetc/{src => lucetc}/main.rs | 3 +- lucetc/{src => lucetc}/options.rs | 119 +++++++++++- lucetc/src/compiler.rs | 24 ++- lucetc/src/compiler/cpu_features.rs | 159 ++++++++++++++++ lucetc/src/lib.rs | 20 +- lucetc/tests/wasm.rs | 281 ++++++++++++++++++++++++---- 9 files changed, 606 insertions(+), 67 deletions(-) rename lucetc/{src => lucetc}/main.rs (97%) rename lucetc/{src => lucetc}/options.rs (70%) create mode 100644 lucetc/src/compiler/cpu_features.rs diff --git a/cranelift b/cranelift index f93589856..91a90e4cb 160000 --- a/cranelift +++ b/cranelift @@ -1 +1 @@ -Subproject commit f935898563aababf1fe06d2d6830b37a0b05e85f +Subproject commit 91a90e4cb649a94187b22b94c8020913e8d3137e diff --git a/lucet-wasi-sdk/tests/lucetc.rs b/lucet-wasi-sdk/tests/lucetc.rs index e54212f75..0260e9528 100644 --- a/lucet-wasi-sdk/tests/lucetc.rs +++ b/lucet-wasi-sdk/tests/lucetc.rs @@ -4,7 +4,7 @@ mod lucetc_tests { use lucet_module::bindings::Bindings; use lucet_validate::Validator; use lucet_wasi_sdk::*; - use lucetc::{Compiler, HeapSettings, OptLevel}; + use lucetc::{Compiler, CpuFeatures, HeapSettings, OptLevel}; use std::collections::HashMap; use std::fs::File; use std::io::Read; @@ -44,8 +44,16 @@ mod lucetc_tests { let b = Bindings::empty(); let h = HeapSettings::default(); let v = Validator::parse("").expect("empty validation environment"); - let c = - Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile empty"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &Some(v), + ) + .expect("compile empty"); let mdata = c.module_data().unwrap(); assert!(mdata.heap_spec().is_some()); // clang creates just 1 global: @@ -80,7 +88,16 @@ mod lucetc_tests { let h = HeapSettings::default(); let v = Validator::parse("").expect("empty validation environment"); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile c"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &Some(v), + ) + .expect("compile c"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 0, "import functions"); assert_eq!(mdata.export_functions().len(), 1, "export functions"); @@ -101,7 +118,16 @@ mod lucetc_tests { "(module $env (@interface func (export \"c\") (param $a1 s32) (result $r1 s32)))", ) .expect("empty validation environment"); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile d"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &Some(v), + ) + .expect("compile d"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 1, "import functions"); assert_eq!(mdata.export_functions().len(), 1, "export functions"); @@ -118,8 +144,16 @@ mod lucetc_tests { let b = Bindings::empty(); let h = HeapSettings::default(); let v = Validator::parse("").expect("empty validation environment"); - let c = - Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile c & d"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &Some(v), + ) + .expect("compile c & d"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 0, "import functions"); assert_eq!(mdata.export_functions().len(), 2, "export functions"); @@ -160,8 +194,16 @@ mod lucetc_tests { .expect("wasi spec validation") .with_wasi_exe(true); // Compiler will only unwrap if the Validator defined above accepts the module - let c = - Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile empty"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &Some(v), + ) + .expect("compile empty"); let mdata = c.module_data().unwrap(); assert!(mdata.heap_spec().is_some()); } diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index 0babbea4f..8b58ad86e 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -9,12 +9,9 @@ categories = ["wasm"] authors = ["Lucet team "] edition = "2018" -[lib] -crate-type=["rlib"] - [[bin]] name = "lucetc" -path = "src/main.rs" +path = "lucetc/main.rs" [dependencies] bincode = "1.1.4" diff --git a/lucetc/src/main.rs b/lucetc/lucetc/main.rs similarity index 97% rename from lucetc/src/main.rs rename to lucetc/lucetc/main.rs index 4d22b4012..2984ff27e 100644 --- a/lucetc/src/main.rs +++ b/lucetc/lucetc/main.rs @@ -79,7 +79,8 @@ pub fn run(opts: &Options) -> Result<(), Error> { let mut c = Lucetc::new(PathBuf::from(input)) .with_bindings(bindings) - .with_opt_level(opts.opt_level); + .with_opt_level(opts.opt_level) + .with_cpu_features(opts.cpu_features); match opts.witx_specs.len() { 0 => {} diff --git a/lucetc/src/options.rs b/lucetc/lucetc/options.rs similarity index 70% rename from lucetc/src/options.rs rename to lucetc/lucetc/options.rs index d6b4da72d..b0b87b00d 100644 --- a/lucetc/src/options.rs +++ b/lucetc/lucetc/options.rs @@ -1,6 +1,6 @@ -use clap::{App, Arg, ArgMatches}; -use failure::Error; -use lucetc::{HeapSettings, OptLevel}; +use clap::{App, Arg, ArgMatches, Values}; +use failure::{format_err, Error}; +use lucetc::{CpuFeatures, HeapSettings, OptLevel, SpecificFeatures, TargetCpu}; use std::path::PathBuf; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -41,6 +41,50 @@ fn humansized(bytes: u64) -> String { mb.to_string() } +fn cpu_features_from_args(cpu: Option<&str>, features: Values) -> Result { + if cpu.is_none() && features.len() == 0 { + Ok(CpuFeatures::DetectCpuid) + } else { + let mut sfs: SpecificFeatures = match cpu { + None => TargetCpu::Baseline, + Some(s) => match s.to_lowercase().as_str() { + "baseline" => TargetCpu::Baseline, + "nehalem" => TargetCpu::Nehalem, + "haswell" => TargetCpu::Haswell, + "broadwell" => TargetCpu::Broadwell, + "skylake" => TargetCpu::Skylake, + "cannonlake" => TargetCpu::Cannonlake, + "icelake" => TargetCpu::Icelake, + "znver1" => TargetCpu::Znver1, + _ => Err(format_err!("unsupported CPU: {}", s))?, + }, + } + .into(); + for f in features { + let b = match f.chars().nth(0) { + Some('+') => true, + Some('-') => false, + _ => unreachable!("invalid feature string despite passing validation: {}", f), + }; + // the only valid starting characters are single-byte '+' and '-', so this indexing + // ought not to fail + match &f[1..] { + "sse3" => sfs.has_sse3 = b, + "ssse3" => sfs.has_ssse3 = b, + "sse41" => sfs.has_sse41 = b, + "sse42" => sfs.has_sse42 = b, + "popcnt" => sfs.has_popcnt = b, + "avx" => sfs.has_avx = b, + "bmi1" => sfs.has_bmi1 = b, + "bmi2" => sfs.has_bmi2 = b, + "lzcnt" => sfs.has_lzcnt = b, + _ => unreachable!("invalid feature string despite passing validation: {}", f), + } + } + Ok(CpuFeatures::Specify(sfs)) + } +} + #[derive(Debug)] pub struct Options { pub output: PathBuf, @@ -55,6 +99,7 @@ pub struct Options { pub reserved_size: Option, pub guard_size: Option, pub opt_level: OptLevel, + pub cpu_features: CpuFeatures, pub keygen: bool, pub sign: bool, pub verify: bool, @@ -128,6 +173,10 @@ impl Options { Some("2") | Some("speed_and_size") => OptLevel::SpeedAndSize, Some(_) => panic!("unknown value for opt-level"), }; + let cpu_features = cpu_features_from_args( + m.value_of("target-cpu"), + m.values_of("target-feature").unwrap_or_default(), + )?; let keygen = m.is_present("keygen"); let sign = m.is_present("sign"); @@ -156,6 +205,7 @@ impl Options { reserved_size, guard_size, opt_level, + cpu_features, keygen, sign, verify, @@ -188,6 +238,69 @@ impl Options { .multiple(false) .help("output destination, defaults to a.out if unspecified"), ) + .arg( + Arg::with_name("target-cpu") + .long("--target-cpu") + .takes_value(true) + .multiple(false) + .number_of_values(1) + .possible_values(&[ + "baseline", + "nehalem", + "haswell", + "broadwell", + "skylake", + "cannonlake", + "icelake", + "znver1", + ]) + .help("Generate code for a particular type of CPU.") + .long_help( +"Generate code for a particular type of CPU. + +If neither `--target-cpu` nor `--target-feature` is provided, `lucetc` +will automatically detect and use the features available on the host CPU. + +" + ) + ) + .arg( + Arg::with_name("target-feature") + .long("--target-feature") + .takes_value(true) + .multiple(true) + .use_delimiter(true) + .possible_values(&[ + "+sse3", "-sse3", + "+ssse3", "-ssse3", + "+sse41", "-sse41", + "+sse42", "-sse42", + "+popcnt", "-popcnt", + "+avx", "-avx", + "+bmi1", "-bmi1", + "+bmi2", "-bmi2", + "+lzcnt", "-lzcnt", + ]) + .help("Enable (+) or disable (-) specific CPU features.") + .long_help( +"Enable (+) or disable (-) specific CPU features. + +If neither `--target-cpu` nor `--target-feature` is provided, `lucetc` +will automatically detect and use the features available on the host CPU. + +This option is additive with, but takes precedence over `--target-cpu`. +For example, `--target-cpu=haswell --target-feature=-avx` will disable +AVX, but leave all other default Haswell features enabled. + +Multiple `--target-feature` groups may be specified, with precedence +increasing from left to right. For example, these arguments will enable +SSE3 but not AVX: + + --target-feature=+sse3,+avx --target-feature=-avx + +" + ) + ) .arg( Arg::with_name("bindings") .long("--bindings") diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index 85dee31f2..c99d24ce9 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -1,3 +1,6 @@ +mod cpu_features; + +pub use self::cpu_features::{CpuFeatures, SpecificFeatures, TargetCpu}; use crate::decls::ModuleDecls; use crate::error::{LucetcError, LucetcErrorKind}; use crate::function::FuncInfo; @@ -15,7 +18,6 @@ use cranelift_codegen::{ }; use cranelift_faerie::{FaerieBackend, FaerieBuilder, FaerieTrapCollection}; use cranelift_module::{Backend as ClifBackend, Module as ClifModule}; -use cranelift_native; use cranelift_wasm::{translate_module, FuncTranslator, ModuleTranslationState, WasmError}; use failure::{format_err, Fail, ResultExt}; use lucet_module::bindings::Bindings; @@ -49,6 +51,7 @@ pub struct Compiler<'a> { decls: ModuleDecls<'a>, clif_module: ClifModule, opt_level: OptLevel, + cpu_features: CpuFeatures, count_instructions: bool, module_translation_state: ModuleTranslationState, } @@ -57,12 +60,13 @@ impl<'a> Compiler<'a> { pub fn new( wasm_binary: &'a [u8], opt_level: OptLevel, + cpu_features: CpuFeatures, bindings: &'a Bindings, heap_settings: HeapSettings, count_instructions: bool, validator: &Option, ) -> Result { - let isa = Self::target_isa(opt_level); + let isa = Self::target_isa(opt_level, cpu_features)?; let frontend_config = isa.frontend_config(); let mut module_info = ModuleInfo::new(frontend_config.clone()); @@ -123,6 +127,7 @@ impl<'a> Compiler<'a> { decls, clif_module, opt_level, + cpu_features, count_instructions, module_translation_state, }) @@ -215,17 +220,22 @@ impl<'a> Compiler<'a> { funcs.insert(func.name.clone(), clif_context.func); } - Ok(CraneliftFuncs::new(funcs, Self::target_isa(self.opt_level))) + Ok(CraneliftFuncs::new( + funcs, + Self::target_isa(self.opt_level, self.cpu_features)?, + )) } - fn target_isa(opt_level: OptLevel) -> Box { + fn target_isa( + opt_level: OptLevel, + cpu_features: CpuFeatures, + ) -> Result, LucetcError> { let mut flags_builder = settings::builder(); - let isa_builder = - cranelift_native::builder().expect("host machine is not a supported target"); + let isa_builder = cpu_features.isa_builder()?; flags_builder.enable("enable_verifier").unwrap(); flags_builder.enable("is_pic").unwrap(); flags_builder.set("opt_level", opt_level.to_flag()).unwrap(); - isa_builder.finish(settings::Flags::new(flags_builder)) + Ok(isa_builder.finish(settings::Flags::new(flags_builder))) } } diff --git a/lucetc/src/compiler/cpu_features.rs b/lucetc/src/compiler/cpu_features.rs new file mode 100644 index 000000000..4caff8435 --- /dev/null +++ b/lucetc/src/compiler/cpu_features.rs @@ -0,0 +1,159 @@ +use crate::error::{LucetcError, LucetcErrorKind}; +use cranelift_codegen::{isa, settings::Configurable}; +use failure::{format_err, ResultExt}; +use target_lexicon::Triple; + +/// x86 CPU families used as shorthand for different CPU feature configurations. +/// +/// Matches the definitions from `cranelift-codegen`'s x86 settings definition. +#[derive(Debug, Clone, Copy)] +pub enum TargetCpu { + Baseline, + Nehalem, + Haswell, + Broadwell, + Skylake, + Cannonlake, + Icelake, + Znver1, +} + +/// A manual specification of the CPU features to use during codegen. +#[derive(Debug, Clone, Copy)] +pub struct SpecificFeatures { + pub has_sse3: bool, + pub has_ssse3: bool, + pub has_sse41: bool, + pub has_sse42: bool, + pub has_popcnt: bool, + pub has_avx: bool, + pub has_bmi1: bool, + pub has_bmi2: bool, + pub has_lzcnt: bool, +} + +impl SpecificFeatures { + /// Return a `CpuFeatures` with all optional features disabled. + pub fn all_disabled() -> Self { + Self { + has_sse3: false, + has_ssse3: false, + has_sse41: false, + has_sse42: false, + has_popcnt: false, + has_avx: false, + has_bmi1: false, + has_bmi2: false, + has_lzcnt: false, + } + } +} + +impl From for SpecificFeatures { + fn from(cpu: TargetCpu) -> Self { + use TargetCpu::*; + match cpu { + Baseline => Self::all_disabled(), + Nehalem => Self { + has_sse3: true, + has_ssse3: true, + has_sse41: true, + has_sse42: true, + has_popcnt: true, + ..Baseline.into() + }, + Haswell => Self { + // Note: this is not part of the Cranelift profile for Haswell, which only uses + // CPUID detection to enable AVX. If we want to bypass CPUID when compiling, we need + // to set it manually, and Haswell is the first of the CPUs with profiles to have + // AVX. + has_avx: true, + has_bmi1: true, + has_bmi2: true, + has_lzcnt: true, + ..Nehalem.into() + }, + Broadwell => Haswell.into(), + Skylake => Broadwell.into(), + Cannonlake => Skylake.into(), + Icelake => Cannonlake.into(), + Znver1 => Self { + has_sse3: true, + has_ssse3: true, + has_sse41: true, + has_sse42: true, + has_popcnt: true, + // Note: similarly to the Haswell AVX flag, we don't want to rely on CPUID detection + // here, but Ryzen does support AVX. + has_avx: true, + has_bmi1: true, + has_bmi2: true, + has_lzcnt: true, + }, + } + } +} + +/// x86-specific CPU features that affect code generation. +#[derive(Debug, Clone, Copy)] +pub enum CpuFeatures { + /// Detect and use the CPU features available on the host at compile-time. + DetectCpuid, + /// Use specific CPU features rather than relying on CPUID detection. + Specify(SpecificFeatures), +} + +impl Default for CpuFeatures { + fn default() -> Self { + Self::detect_cpuid() + } +} + +impl CpuFeatures { + /// Return a `CpuFeatures` that uses the CPUID instruction to determine which features to enable. + pub fn detect_cpuid() -> Self { + CpuFeatures::DetectCpuid + } + + /// Return a `CpuFeatures` with no optional features enabled. + pub fn all_disabled() -> Self { + CpuFeatures::Specify(SpecificFeatures::all_disabled()) + } + + /// Return a `cranelift_codegen::isa::Builder` configured with these CPU features. + pub fn isa_builder(&self) -> Result { + match self { + CpuFeatures::DetectCpuid => cranelift_native::builder() + .map_err(|_| format_err!("host machine is not a supported target")) + .context(LucetcErrorKind::Unsupported) + .map_err(|e| e.into()), + CpuFeatures::Specify(features) => { + let mut isa_builder = isa::lookup(Triple::host()) + .map_err(|_| format_err!("host machine is not a supported target")) + .context(LucetcErrorKind::Unsupported)?; + + macro_rules! enable_feature { + ( $feature:ident ) => { + if features.$feature { + isa_builder + .enable(stringify!($feature)) + .context(LucetcErrorKind::Unsupported)?; + } + }; + } + + enable_feature!(has_sse3); + enable_feature!(has_ssse3); + enable_feature!(has_sse41); + enable_feature!(has_sse42); + enable_feature!(has_popcnt); + enable_feature!(has_avx); + enable_feature!(has_bmi1); + enable_feature!(has_bmi2); + enable_feature!(has_lzcnt); + + Ok(isa_builder) + } + } + } +} diff --git a/lucetc/src/lib.rs b/lucetc/src/lib.rs index c3170c3f8..e6ff88e98 100644 --- a/lucetc/src/lib.rs +++ b/lucetc/src/lib.rs @@ -22,8 +22,7 @@ mod types; use crate::load::read_bytes; pub use crate::{ - compiler::Compiler, - compiler::OptLevel, + compiler::{Compiler, CpuFeatures, OptLevel, SpecificFeatures, TargetCpu}, error::{LucetcError, LucetcErrorKind}, heap::HeapSettings, load::read_module, @@ -46,6 +45,7 @@ pub struct Lucetc { input: LucetcInput, bindings: Vec, opt_level: OptLevel, + cpu_features: CpuFeatures, heap: HeapSettings, builtins_paths: Vec, validator: Option, @@ -73,6 +73,9 @@ pub trait LucetcOpts { fn opt_level(&mut self, opt_level: OptLevel); fn with_opt_level(self, opt_level: OptLevel) -> Self; + fn cpu_features(&mut self, cpu_features: CpuFeatures); + fn with_cpu_features(self, cpu_features: CpuFeatures) -> Self; + fn builtins>(&mut self, builtins_path: P); fn with_builtins>(self, builtins_path: P) -> Self; @@ -128,6 +131,15 @@ impl LucetcOpts for T { self } + fn cpu_features(&mut self, cpu_features: CpuFeatures) { + self.as_lucetc().cpu_features = cpu_features; + } + + fn with_cpu_features(mut self, cpu_features: CpuFeatures) -> Self { + self.cpu_features(cpu_features); + self + } + fn builtins>(&mut self, builtins_path: P) { self.as_lucetc() .builtins_paths @@ -238,6 +250,7 @@ impl Lucetc { input: LucetcInput::Path(input.to_owned()), bindings: vec![], opt_level: OptLevel::default(), + cpu_features: CpuFeatures::default(), heap: HeapSettings::default(), builtins_paths: vec![], validator: None, @@ -255,6 +268,7 @@ impl Lucetc { input: LucetcInput::Bytes(input), bindings: vec![], opt_level: OptLevel::default(), + cpu_features: CpuFeatures::default(), heap: HeapSettings::default(), builtins_paths: vec![], validator: None, @@ -300,6 +314,7 @@ impl Lucetc { let compiler = Compiler::new( &module_contents, self.opt_level, + self.cpu_features, &bindings, self.heap.clone(), self.count_instructions, @@ -317,6 +332,7 @@ impl Lucetc { let compiler = Compiler::new( &module_contents, self.opt_level, + self.cpu_features, &bindings, self.heap.clone(), self.count_instructions, diff --git a/lucetc/tests/wasm.rs b/lucetc/tests/wasm.rs index bf17429e4..08579b265 100644 --- a/lucetc/tests/wasm.rs +++ b/lucetc/tests/wasm.rs @@ -34,7 +34,7 @@ mod module_data { /// Tests of the `ModuleData` generated by the lucetc Compiler use super::load_wat_module; use lucet_module::bindings::Bindings; - use lucetc::{Compiler, HeapSettings, LucetcErrorKind, OptLevel}; + use lucetc::{Compiler, CpuFeatures, HeapSettings, LucetcErrorKind, OptLevel}; use std::path::PathBuf; #[test] @@ -42,8 +42,16 @@ mod module_data { let m = load_wat_module("exported_import"); let b = super::test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None) - .expect("compiling exported_import"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &None, + ) + .expect("compiling exported_import"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.globals_spec().len(), 0); @@ -62,8 +70,16 @@ mod module_data { let m = load_wat_module("multiple_import"); let b = super::test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None) - .expect("compiling multiple_import"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &None, + ) + .expect("compiling multiple_import"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.globals_spec().len(), 0); @@ -78,8 +94,16 @@ mod module_data { let m = load_wat_module("globals_export"); let b = super::test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None) - .expect("compiling globals_export"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &None, + ) + .expect("compiling globals_export"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.globals_spec().len(), 1); @@ -95,8 +119,16 @@ mod module_data { let m = load_wat_module("fibonacci"); let b = super::test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None) - .expect("compiling fibonacci"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &None, + ) + .expect("compiling fibonacci"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.globals_spec().len(), 0); @@ -110,8 +142,16 @@ mod module_data { let m = load_wat_module("arith"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = - Compiler::new(&m, OptLevel::default(), &b, h, false, &None).expect("compiling arith"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &None, + ) + .expect("compiling arith"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.globals_spec().len(), 0); @@ -128,8 +168,16 @@ mod module_data { )) .unwrap(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None) - .expect("compile duplicate_imports"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &None, + ) + .expect("compile duplicate_imports"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 2); @@ -155,7 +203,16 @@ mod module_data { )) .unwrap(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None).expect("compile icall"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &None, + ) + .expect("compile icall"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 1); @@ -191,7 +248,16 @@ mod module_data { let m = load_wat_module("icall"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None).expect("compile icall"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &None, + ) + .expect("compile icall"); let _module_data = c.module_data().unwrap(); /* TODO can't express these with module data @@ -216,8 +282,16 @@ mod module_data { let m = load_wat_module("icall_sparse"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None) - .expect("compile icall_sparse"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &None, + ) + .expect("compile icall_sparse"); let _module_data = c.module_data().unwrap(); /* TODO can't express these with module data @@ -256,8 +330,16 @@ mod module_data { let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None) - .expect("compile globals_import"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &None, + ) + .expect("compile globals_import"); let module_data = c.module_data().unwrap(); let gspec = module_data.globals_spec(); @@ -278,8 +360,16 @@ mod module_data { let m = load_wat_module("heap_spec_import"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h.clone(), false, &None) - .expect("compiling heap_spec_import"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h.clone(), + false, + &None, + ) + .expect("compiling heap_spec_import"); assert_eq!( c.module_data().unwrap().heap_spec(), @@ -301,8 +391,16 @@ mod module_data { let m = load_wat_module("heap_spec_definition"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h.clone(), false, &None) - .expect("compiling heap_spec_definition"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h.clone(), + false, + &None, + ) + .expect("compiling heap_spec_definition"); assert_eq!( c.module_data().unwrap().heap_spec(), @@ -323,8 +421,16 @@ mod module_data { let m = load_wat_module("heap_spec_none"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None) - .expect("compiling heap_spec_none"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &None, + ) + .expect("compiling heap_spec_none"); assert_eq!(c.module_data().unwrap().heap_spec(), None,); } @@ -333,7 +439,15 @@ mod module_data { let m = load_wat_module("oversize_data_segment"); let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &None, + ); assert!( c.is_err(), "compilation error because data initializers are oversized" @@ -356,7 +470,15 @@ mod module_data { let b = Bindings::empty(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &None, + ); assert!( c.is_err(), "compilation error because wasm module is invalid" @@ -369,8 +491,16 @@ mod module_data { let m = load_wat_module("start_section"); let b = Bindings::empty(); let h = HeapSettings::default(); - let _c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None) - .expect("compile start_section"); + let _c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &None, + ) + .expect("compile start_section"); /* assert!( p.module().start_section().is_some(), @@ -383,13 +513,21 @@ mod module_data { mod compile { // Tests for compilation completion use super::load_wat_module; - use lucetc::{Compiler, HeapSettings, OptLevel}; + use lucetc::{Compiler, CpuFeatures, HeapSettings, OptLevel}; fn run_compile_test(file: &str) { let m = load_wat_module(file); let b = super::test_bindings(); let h = HeapSettings::default(); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &None) - .expect(&format!("compile {}", file)); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &None, + ) + .expect(&format!("compile {}", file)); let _obj = c.object_file().expect(&format!("codegen {}", file)); } macro_rules! compile_test { @@ -426,7 +564,7 @@ mod validate { use super::load_wat_module; use lucet_validate::Validator; - use lucetc::{Compiler, HeapSettings, OptLevel}; + use lucetc::{Compiler, CpuFeatures, HeapSettings, OptLevel}; #[test] fn validate_arith() { @@ -439,7 +577,16 @@ mod validate { .expect("empty witx validates") .with_wasi_exe(false); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &Some(v), + ) + .expect("compile"); let _obj = c.object_file().expect("codegen"); } @@ -457,7 +604,16 @@ mod validate { .expect("witx validates") .with_wasi_exe(false); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &Some(v), + ) + .expect("compile"); let _obj = c.object_file().expect("codegen"); } @@ -477,7 +633,16 @@ mod validate { .expect("witx validates") .with_wasi_exe(false); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &Some(v), + ) + .expect("compile"); let _obj = c.object_file().expect("codegen"); } @@ -495,7 +660,16 @@ mod validate { .expect("witx validates") .with_wasi_exe(false); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &Some(v), + ) + .expect("compile"); let _obj = c.object_file().expect("codegen"); } @@ -513,7 +687,16 @@ mod validate { .expect("witx validates") .with_wasi_exe(false); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &Some(v), + ) + .expect("compile"); let _obj = c.object_file().expect("codegen"); } @@ -533,7 +716,16 @@ mod validate { .expect("witx validates") .with_wasi_exe(false); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &Some(v), + ) + .expect("compile"); let _obj = c.object_file().expect("codegen"); } @@ -548,7 +740,16 @@ mod validate { .expect("witx validates") .with_wasi_exe(true); - let c = Compiler::new(&m, OptLevel::default(), &b, h, false, &Some(v)).expect("compile"); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &Some(v), + ) + .expect("compile"); let _obj = c.object_file().expect("codegen"); } } From 2fd2236e05b31eaa8d6dbe75b15cffe70c39d503 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Wed, 30 Oct 2019 16:45:28 -0700 Subject: [PATCH 455/512] [lucetc] add `native` and `sandybridge` CPU profiles This required some reworking of how `CpuFeatures` is represented. --- lucetc/lucetc/main.rs | 2 +- lucetc/lucetc/options.rs | 91 +++++++------ lucetc/src/compiler.rs | 8 +- lucetc/src/compiler/cpu_features.rs | 203 +++++++++++++--------------- lucetc/src/lib.rs | 6 +- 5 files changed, 154 insertions(+), 156 deletions(-) diff --git a/lucetc/lucetc/main.rs b/lucetc/lucetc/main.rs index 2984ff27e..2154edf25 100644 --- a/lucetc/lucetc/main.rs +++ b/lucetc/lucetc/main.rs @@ -80,7 +80,7 @@ pub fn run(opts: &Options) -> Result<(), Error> { let mut c = Lucetc::new(PathBuf::from(input)) .with_bindings(bindings) .with_opt_level(opts.opt_level) - .with_cpu_features(opts.cpu_features); + .with_cpu_features(opts.cpu_features.clone()); match opts.witx_specs.len() { 0 => {} diff --git a/lucetc/lucetc/options.rs b/lucetc/lucetc/options.rs index b0b87b00d..aa5dfff06 100644 --- a/lucetc/lucetc/options.rs +++ b/lucetc/lucetc/options.rs @@ -1,6 +1,6 @@ use clap::{App, Arg, ArgMatches, Values}; -use failure::{format_err, Error}; -use lucetc::{CpuFeatures, HeapSettings, OptLevel, SpecificFeatures, TargetCpu}; +use failure::Error; +use lucetc::{CpuFeatures, HeapSettings, OptLevel, SpecificFeature, TargetCpu}; use std::path::PathBuf; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -42,46 +42,58 @@ fn humansized(bytes: u64) -> String { } fn cpu_features_from_args(cpu: Option<&str>, features: Values) -> Result { + use SpecificFeature::*; + use TargetCpu::*; if cpu.is_none() && features.len() == 0 { - Ok(CpuFeatures::DetectCpuid) + Ok(CpuFeatures::detect_cpuid()) } else { - let mut sfs: SpecificFeatures = match cpu { - None => TargetCpu::Baseline, + let cpu: TargetCpu = match cpu { + None => Baseline, Some(s) => match s.to_lowercase().as_str() { - "baseline" => TargetCpu::Baseline, - "nehalem" => TargetCpu::Nehalem, - "haswell" => TargetCpu::Haswell, - "broadwell" => TargetCpu::Broadwell, - "skylake" => TargetCpu::Skylake, - "cannonlake" => TargetCpu::Cannonlake, - "icelake" => TargetCpu::Icelake, - "znver1" => TargetCpu::Znver1, - _ => Err(format_err!("unsupported CPU: {}", s))?, + "native" => Native, + "baseline" => Baseline, + "nehalem" => Nehalem, + "sandybridge" => Sandybridge, + "haswell" => Haswell, + "broadwell" => Broadwell, + "skylake" => Skylake, + "cannonlake" => Cannonlake, + "icelake" => Icelake, + "znver1" => Znver1, + _ => unreachable!("invalid CPU string despite passing validation: {}", s), }, - } - .into(); - for f in features { - let b = match f.chars().nth(0) { - Some('+') => true, - Some('-') => false, - _ => unreachable!("invalid feature string despite passing validation: {}", f), - }; - // the only valid starting characters are single-byte '+' and '-', so this indexing - // ought not to fail - match &f[1..] { - "sse3" => sfs.has_sse3 = b, - "ssse3" => sfs.has_ssse3 = b, - "sse41" => sfs.has_sse41 = b, - "sse42" => sfs.has_sse42 = b, - "popcnt" => sfs.has_popcnt = b, - "avx" => sfs.has_avx = b, - "bmi1" => sfs.has_bmi1 = b, - "bmi2" => sfs.has_bmi2 = b, - "lzcnt" => sfs.has_lzcnt = b, - _ => unreachable!("invalid feature string despite passing validation: {}", f), - } - } - Ok(CpuFeatures::Specify(sfs)) + }; + let specific_features = features + .map(|fstr| { + let b = match fstr.chars().nth(0) { + Some('+') => true, + Some('-') => false, + _ => unreachable!( + "invalid feature string despite passing validation: {}", + fstr + ), + }; + // the only valid starting characters are single-byte '+' and '-', so this indexing + // ought not to fail + let f = match &fstr[1..] { + "sse3" => SSE3, + "ssse3" => SSSE3, + "sse41" => SSE41, + "sse42" => SSE42, + "popcnt" => Popcnt, + "avx" => AVX, + "bmi1" => BMI1, + "bmi2" => BMI2, + "lzcnt" => Lzcnt, + _ => unreachable!( + "invalid feature string despite passing validation: {}", + fstr + ), + }; + (f, b) + }) + .collect(); + Ok(CpuFeatures::new(cpu, specific_features)) } } @@ -245,8 +257,10 @@ impl Options { .multiple(false) .number_of_values(1) .possible_values(&[ + "native", "baseline", "nehalem", + "sandybridge", "haswell", "broadwell", "skylake", @@ -260,6 +274,7 @@ impl Options { If neither `--target-cpu` nor `--target-feature` is provided, `lucetc` will automatically detect and use the features available on the host CPU. +This is equivalent to choosing `--target-cpu=native`. " ) diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index c99d24ce9..2a5695234 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -1,6 +1,6 @@ mod cpu_features; -pub use self::cpu_features::{CpuFeatures, SpecificFeatures, TargetCpu}; +pub use self::cpu_features::{CpuFeatures, SpecificFeature, TargetCpu}; use crate::decls::ModuleDecls; use crate::error::{LucetcError, LucetcErrorKind}; use crate::function::FuncInfo; @@ -66,7 +66,7 @@ impl<'a> Compiler<'a> { count_instructions: bool, validator: &Option, ) -> Result { - let isa = Self::target_isa(opt_level, cpu_features)?; + let isa = Self::target_isa(opt_level, &cpu_features)?; let frontend_config = isa.frontend_config(); let mut module_info = ModuleInfo::new(frontend_config.clone()); @@ -222,13 +222,13 @@ impl<'a> Compiler<'a> { } Ok(CraneliftFuncs::new( funcs, - Self::target_isa(self.opt_level, self.cpu_features)?, + Self::target_isa(self.opt_level, &self.cpu_features)?, )) } fn target_isa( opt_level: OptLevel, - cpu_features: CpuFeatures, + cpu_features: &CpuFeatures, ) -> Result, LucetcError> { let mut flags_builder = settings::builder(); let isa_builder = cpu_features.isa_builder()?; diff --git a/lucetc/src/compiler/cpu_features.rs b/lucetc/src/compiler/cpu_features.rs index 4caff8435..98ed4290f 100644 --- a/lucetc/src/compiler/cpu_features.rs +++ b/lucetc/src/compiler/cpu_features.rs @@ -1,6 +1,7 @@ use crate::error::{LucetcError, LucetcErrorKind}; use cranelift_codegen::{isa, settings::Configurable}; use failure::{format_err, ResultExt}; +use std::collections::HashMap; use target_lexicon::Triple; /// x86 CPU families used as shorthand for different CPU feature configurations. @@ -8,8 +9,10 @@ use target_lexicon::Triple; /// Matches the definitions from `cranelift-codegen`'s x86 settings definition. #[derive(Debug, Clone, Copy)] pub enum TargetCpu { + Native, Baseline, Nehalem, + Sandybridge, Haswell, Broadwell, Skylake, @@ -18,89 +21,49 @@ pub enum TargetCpu { Znver1, } -/// A manual specification of the CPU features to use during codegen. -#[derive(Debug, Clone, Copy)] -pub struct SpecificFeatures { - pub has_sse3: bool, - pub has_ssse3: bool, - pub has_sse41: bool, - pub has_sse42: bool, - pub has_popcnt: bool, - pub has_avx: bool, - pub has_bmi1: bool, - pub has_bmi2: bool, - pub has_lzcnt: bool, -} - -impl SpecificFeatures { - /// Return a `CpuFeatures` with all optional features disabled. - pub fn all_disabled() -> Self { - Self { - has_sse3: false, - has_ssse3: false, - has_sse41: false, - has_sse42: false, - has_popcnt: false, - has_avx: false, - has_bmi1: false, - has_bmi2: false, - has_lzcnt: false, +impl TargetCpu { + fn features(&self) -> Vec { + use SpecificFeature::*; + use TargetCpu::*; + match self { + Native | Baseline => vec![], + Nehalem => vec![SSE3, SSSE3, SSE41, SSE42, Popcnt], + // Note: this is not part of the Cranelift profile for Haswell, and there is no Sandy + // Bridge profile. Instead, Cranelift only uses CPUID detection to enable AVX. If we + // want to bypass CPUID when compiling, we need to set AVX manually, and Sandy Bridge is + // the first family of Intel CPUs with AVX. + Sandybridge => [Nehalem.features().as_slice(), &[AVX]].concat(), + Haswell => [Sandybridge.features().as_slice(), &[BMI1, BMI2, Lzcnt]].concat(), + Broadwell => Haswell.features(), + Skylake => Broadwell.features(), + Cannonlake => Skylake.features(), + Icelake => Cannonlake.features(), + Znver1 => vec![SSE3, SSSE3, SSE41, SSE42, Popcnt, AVX, BMI1, BMI2, Lzcnt], } } } -impl From for SpecificFeatures { - fn from(cpu: TargetCpu) -> Self { - use TargetCpu::*; - match cpu { - Baseline => Self::all_disabled(), - Nehalem => Self { - has_sse3: true, - has_ssse3: true, - has_sse41: true, - has_sse42: true, - has_popcnt: true, - ..Baseline.into() - }, - Haswell => Self { - // Note: this is not part of the Cranelift profile for Haswell, which only uses - // CPUID detection to enable AVX. If we want to bypass CPUID when compiling, we need - // to set it manually, and Haswell is the first of the CPUs with profiles to have - // AVX. - has_avx: true, - has_bmi1: true, - has_bmi2: true, - has_lzcnt: true, - ..Nehalem.into() - }, - Broadwell => Haswell.into(), - Skylake => Broadwell.into(), - Cannonlake => Skylake.into(), - Icelake => Cannonlake.into(), - Znver1 => Self { - has_sse3: true, - has_ssse3: true, - has_sse41: true, - has_sse42: true, - has_popcnt: true, - // Note: similarly to the Haswell AVX flag, we don't want to rely on CPUID detection - // here, but Ryzen does support AVX. - has_avx: true, - has_bmi1: true, - has_bmi2: true, - has_lzcnt: true, - }, - } - } +/// Individual CPU features that may be used during codegen. +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum SpecificFeature { + SSE3, + SSSE3, + SSE41, + SSE42, + Popcnt, + AVX, + BMI1, + BMI2, + Lzcnt, } -/// x86-specific CPU features that affect code generation. -#[derive(Debug, Clone, Copy)] -pub enum CpuFeatures { - /// Detect and use the CPU features available on the host at compile-time. - DetectCpuid, - /// Use specific CPU features rather than relying on CPUID detection. - Specify(SpecificFeatures), +/// An x86-specific configuration of CPU features that affect code generation. +#[derive(Debug, Clone)] +pub struct CpuFeatures { + /// Base CPU profile to use + cpu: TargetCpu, + /// Specific CPU features to add or remove from the profile + specific_features: HashMap, } impl Default for CpuFeatures { @@ -110,50 +73,70 @@ impl Default for CpuFeatures { } impl CpuFeatures { + pub fn new(cpu: TargetCpu, specific_features: HashMap) -> Self { + Self { + cpu, + specific_features, + } + } + /// Return a `CpuFeatures` that uses the CPUID instruction to determine which features to enable. pub fn detect_cpuid() -> Self { - CpuFeatures::DetectCpuid + CpuFeatures { + cpu: TargetCpu::Native, + specific_features: HashMap::new(), + } } /// Return a `CpuFeatures` with no optional features enabled. - pub fn all_disabled() -> Self { - CpuFeatures::Specify(SpecificFeatures::all_disabled()) + pub fn baseline() -> Self { + CpuFeatures { + cpu: TargetCpu::Baseline, + specific_features: HashMap::new(), + } + } + + pub fn set(&mut self, sf: SpecificFeature, enabled: bool) { + self.specific_features.insert(sf, enabled); } /// Return a `cranelift_codegen::isa::Builder` configured with these CPU features. pub fn isa_builder(&self) -> Result { - match self { - CpuFeatures::DetectCpuid => cranelift_native::builder() + use SpecificFeature::*; + use TargetCpu::*; + + let mut isa_builder = if let Native = self.cpu { + cranelift_native::builder() + .map_err(|_| format_err!("host machine is not a supported target")) + } else { + isa::lookup(Triple::host()) .map_err(|_| format_err!("host machine is not a supported target")) - .context(LucetcErrorKind::Unsupported) - .map_err(|e| e.into()), - CpuFeatures::Specify(features) => { - let mut isa_builder = isa::lookup(Triple::host()) - .map_err(|_| format_err!("host machine is not a supported target")) - .context(LucetcErrorKind::Unsupported)?; - - macro_rules! enable_feature { - ( $feature:ident ) => { - if features.$feature { - isa_builder - .enable(stringify!($feature)) - .context(LucetcErrorKind::Unsupported)?; - } - }; - } - - enable_feature!(has_sse3); - enable_feature!(has_ssse3); - enable_feature!(has_sse41); - enable_feature!(has_sse42); - enable_feature!(has_popcnt); - enable_feature!(has_avx); - enable_feature!(has_bmi1); - enable_feature!(has_bmi2); - enable_feature!(has_lzcnt); - - Ok(isa_builder) + } + .context(LucetcErrorKind::Unsupported)?; + + let mut specific_features = self.specific_features.clone(); + + // add any features from the CPU profile if they are not already individually specified + for cpu_feature in self.cpu.features() { + specific_features.entry(cpu_feature).or_insert(true); + } + + for (feature, enabled) in specific_features.into_iter() { + let enabled = if enabled { "true" } else { "false" }; + match feature { + SSE3 => isa_builder.set("has_sse3", enabled).unwrap(), + SSSE3 => isa_builder.set("has_ssse3", enabled).unwrap(), + SSE41 => isa_builder.set("has_sse41", enabled).unwrap(), + SSE42 => isa_builder.set("has_sse42", enabled).unwrap(), + Popcnt => isa_builder.set("has_popcnt", enabled).unwrap(), + AVX => isa_builder.set("has_avx", enabled).unwrap(), + BMI1 => isa_builder.set("has_bmi1", enabled).unwrap(), + BMI2 => isa_builder.set("has_bmi2", enabled).unwrap(), + Lzcnt => isa_builder.set("has_lzcnt", enabled).unwrap(), } } + + + Ok(isa_builder) } } diff --git a/lucetc/src/lib.rs b/lucetc/src/lib.rs index e6ff88e98..a37cf8c9c 100644 --- a/lucetc/src/lib.rs +++ b/lucetc/src/lib.rs @@ -22,7 +22,7 @@ mod types; use crate::load::read_bytes; pub use crate::{ - compiler::{Compiler, CpuFeatures, OptLevel, SpecificFeatures, TargetCpu}, + compiler::{Compiler, CpuFeatures, OptLevel, SpecificFeature, TargetCpu}, error::{LucetcError, LucetcErrorKind}, heap::HeapSettings, load::read_module, @@ -314,7 +314,7 @@ impl Lucetc { let compiler = Compiler::new( &module_contents, self.opt_level, - self.cpu_features, + self.cpu_features.clone(), &bindings, self.heap.clone(), self.count_instructions, @@ -332,7 +332,7 @@ impl Lucetc { let compiler = Compiler::new( &module_contents, self.opt_level, - self.cpu_features, + self.cpu_features.clone(), &bindings, self.heap.clone(), self.count_instructions, From d459b70fb0e0e48a48548a06afed1fc80c5f2914 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Wed, 30 Oct 2019 17:00:19 -0700 Subject: [PATCH 456/512] fix rustfmt --- lucetc/src/compiler/cpu_features.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/lucetc/src/compiler/cpu_features.rs b/lucetc/src/compiler/cpu_features.rs index 98ed4290f..cd3319ab7 100644 --- a/lucetc/src/compiler/cpu_features.rs +++ b/lucetc/src/compiler/cpu_features.rs @@ -136,7 +136,6 @@ impl CpuFeatures { } } - Ok(isa_builder) } } From d0ddb48624273151c91e6bdf02913cff76bb5824 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Wed, 30 Oct 2019 18:04:31 -0700 Subject: [PATCH 457/512] crank up the fuzz --- .github/workflows/fuzz.yml | 2 ++ Makefile | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index ffcd46327..da8e4a664 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -45,4 +45,6 @@ jobs: run: make test-fuzz - name: Fuzz + env: + FUZZ_NUM_TESTS: 100000 run: make fuzz diff --git a/Makefile b/Makefile index f47ca403a..9291fbfcb 100644 --- a/Makefile +++ b/Makefile @@ -43,9 +43,10 @@ test-except-fuzz: test-fuzz: cargo run -p lucet-wasi-fuzz -- test-seed 410757864950 +FUZZ_NUM_TESTS?=1000 .PHONY: fuzz fuzz: - cargo run --release -p lucet-wasi-fuzz -- fuzz --num-tests=1000 + cargo run --release -p lucet-wasi-fuzz -- fuzz --num-tests=$(FUZZ_NUM_TESTS) .PHONY: bench bench: From b9b27d32e96c8a179abd04d652a0108ebf05bea1 Mon Sep 17 00:00:00 2001 From: awortman-fastly <49215183+awortman-fastly@users.noreply.github.com> Date: Thu, 31 Oct 2019 10:50:16 -0700 Subject: [PATCH 458/512] Include CPU features in module data (#351) * write cpu features into modules and verify compatibility when loading * build spectests to ward away evil bit gremlins --- Cargo.lock | 2 + Makefile | 1 + lucet-module/src/lib.rs | 2 +- lucet-module/src/module_data.rs | 52 +++++++++++- .../lucet-runtime-internals/Cargo.toml | 1 + .../lucet-runtime-internals/src/module/dl.rs | 65 +++++++++++++- .../src/module/mock.rs | 5 +- lucet-spectest/src/script.rs | 3 +- lucetc/Cargo.toml | 1 + lucetc/src/compiler.rs | 32 ++++--- lucetc/src/compiler/cpu_features.rs | 85 ++++++++++++++++++- lucetc/src/decls.rs | 4 +- 12 files changed, 230 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c3283595..f4de5ebb4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -886,6 +886,7 @@ dependencies = [ "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "raw-cpuid 7.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1012,6 +1013,7 @@ dependencies = [ "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", + "raw-cpuid 7.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Makefile b/Makefile index 9291fbfcb..2ed2a6172 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,7 @@ test: indent-check test-except-fuzz test-fuzz .PHONY: test-except-fuzz test-except-fuzz: + cargo build -p lucet-spectest # build but *not* run spectests to mitigate bitrot while spectests don't pass cargo test --no-fail-fast \ -p lucet-runtime-internals \ -p lucet-runtime \ diff --git a/lucet-module/src/lib.rs b/lucet-module/src/lib.rs index b1259024e..f53344bc2 100644 --- a/lucet-module/src/lib.rs +++ b/lucet-module/src/lib.rs @@ -27,7 +27,7 @@ pub use crate::functions::{ pub use crate::globals::{Global, GlobalDef, GlobalSpec, GlobalValue}; pub use crate::linear_memory::{HeapSpec, LinearMemorySpec, SparseData}; pub use crate::module::{Module, SerializedModule, LUCET_MODULE_SYM}; -pub use crate::module_data::{ModuleData, MODULE_DATA_SYM}; +pub use crate::module_data::{ModuleData, ModuleFeatures, MODULE_DATA_SYM}; pub use crate::runtime::InstanceRuntimeData; pub use crate::signature::{ModuleSignature, PublicKey}; pub use crate::tables::TableElement; diff --git a/lucet-module/src/module_data.rs b/lucet-module/src/module_data.rs index 9baaeeeb7..44f77daab 100644 --- a/lucet-module/src/module_data.rs +++ b/lucet-module/src/module_data.rs @@ -34,6 +34,38 @@ pub struct ModuleData<'a> { export_functions: Vec>, signatures: Vec, module_signature: Vec, + features: ModuleFeatures, +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +pub struct ModuleFeatures { + pub sse3: bool, + pub ssse3: bool, + pub sse41: bool, + pub sse42: bool, + pub avx: bool, + pub bmi1: bool, + pub bmi2: bool, + pub lzcnt: bool, + pub popcnt: bool, + _hidden: (), +} + +impl ModuleFeatures { + pub fn none() -> Self { + Self { + sse3: false, + ssse3: false, + sse41: false, + sse42: false, + avx: false, + bmi1: false, + bmi2: false, + lzcnt: false, + popcnt: false, + _hidden: (), + } + } } impl<'a> ModuleData<'a> { @@ -44,6 +76,7 @@ impl<'a> ModuleData<'a> { import_functions: Vec>, export_functions: Vec>, signatures: Vec, + features: ModuleFeatures, ) -> Self { let module_signature = vec![0u8; SignatureBones::BYTES]; Self { @@ -54,6 +87,7 @@ impl<'a> ModuleData<'a> { export_functions, signatures, module_signature, + features, } } @@ -113,6 +147,10 @@ impl<'a> ModuleData<'a> { &self.module_signature } + pub fn features(&self) -> &ModuleFeatures { + &self.features + } + pub fn patch_module_signature( module_data_bin: &'a [u8], module_signature: &[u8], @@ -161,6 +199,7 @@ pub struct OwnedModuleData { imports: Vec, exports: Vec, signatures: Vec, + features: ModuleFeatures, } impl OwnedModuleData { @@ -171,6 +210,7 @@ impl OwnedModuleData { imports: Vec, exports: Vec, signatures: Vec, + features: ModuleFeatures, ) -> Self { Self { linear_memory, @@ -179,6 +219,7 @@ impl OwnedModuleData { imports, exports, signatures, + features, } } @@ -199,11 +240,20 @@ impl OwnedModuleData { self.imports.iter().map(|imp| imp.to_ref()).collect(), self.exports.iter().map(|exp| exp.to_ref()).collect(), self.signatures.clone(), + self.features.clone(), ) } pub fn empty() -> Self { - Self::new(None, vec![], vec![], vec![], vec![], vec![]) + Self::new( + None, + vec![], + vec![], + vec![], + vec![], + vec![], + ModuleFeatures::none(), + ) } pub fn with_heap_spec(mut self, heap_spec: HeapSpec) -> Self { diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index c61966c98..9884ac14c 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -24,6 +24,7 @@ nix = "0.13" num-derive = "0.2" num-traits = "0.2" xfailure = "0.1" +raw-cpuid = "7.0.3" # This is only a dependency to ensure that other crates don't pick a newer version as a transitive # dependency. `0.1.3 < getrandom <= 0.1.6` cause `lazy_static` to pull in spinlock implementations diff --git a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs index ac22c5e4f..36b070989 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/dl.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/dl.rs @@ -3,8 +3,8 @@ use crate::module::{AddrDetails, GlobalSpec, HeapSpec, Module, ModuleInternal, T use libc::c_void; use libloading::Library; use lucet_module::{ - FunctionHandle, FunctionIndex, FunctionPointer, FunctionSpec, ModuleData, ModuleSignature, - PublicKey, SerializedModule, Signature, VersionInfo, LUCET_MODULE_SYM, + FunctionHandle, FunctionIndex, FunctionPointer, FunctionSpec, ModuleData, ModuleFeatures, + ModuleSignature, PublicKey, SerializedModule, Signature, VersionInfo, LUCET_MODULE_SYM, }; use std::ffi::CStr; use std::mem::MaybeUninit; @@ -13,6 +13,65 @@ use std::slice; use std::slice::from_raw_parts; use std::sync::Arc; +use raw_cpuid::CpuId; + +fn check_feature_support(module_features: &ModuleFeatures) -> Result<(), Error> { + let cpuid = CpuId::new(); + + fn missing_feature(feature: &str) -> Error { + Error::Unsupported(format!( + "Module requires feature host does not support: {}", + feature + )) + } + + let info = cpuid + .get_feature_info() + .ok_or_else(|| Error::Unsupported("Unable to obtain host CPU feature info!".to_string()))?; + + if module_features.sse3 && !info.has_sse3() { + return Err(missing_feature("SSE3")); + } + if module_features.ssse3 && !info.has_ssse3() { + return Err(missing_feature("SSS3")); + } + if module_features.sse41 && !info.has_sse41() { + return Err(missing_feature("SSE4.1")); + } + if module_features.sse42 && !info.has_sse42() { + return Err(missing_feature("SSE4.2")); + } + if module_features.avx && !info.has_avx() { + return Err(missing_feature("AVX")); + } + if module_features.popcnt && !info.has_popcnt() { + return Err(missing_feature("POPCNT")); + } + + let info = cpuid.get_extended_feature_info().ok_or_else(|| { + Error::Unsupported("Unable to obtain host CPU extended feature info!".to_string()) + })?; + + if module_features.bmi1 && !info.has_bmi1() { + return Err(missing_feature("BMI1")); + } + + if module_features.bmi2 && !info.has_bmi2() { + return Err(missing_feature("BMI2")); + } + + let info = cpuid.get_extended_function_info().ok_or_else(|| { + Error::Unsupported("Unable to obtain host CPU extended function info!".to_string()) + })?; + + if module_features.lzcnt && !info.has_lzcnt() { + return Err(missing_feature("LZCNT")); + } + + // Features are fine, we're compatible! + Ok(()) +} + /// A Lucet module backed by a dynamically-loaded shared object. pub struct DlModule { lib: Library, @@ -91,6 +150,8 @@ impl DlModule { }; let module_data = ModuleData::deserialize(module_data_slice)?; + check_feature_support(module_data.features())?; + // If a public key has been provided, verify the module signature // The TOCTOU issue is unavoidable without reimplenting `dlopen(3)` if let Some(pk) = pk { diff --git a/lucet-runtime/lucet-runtime-internals/src/module/mock.rs b/lucet-runtime/lucet-runtime-internals/src/module/mock.rs index 80ff9bbab..0602bd388 100644 --- a/lucet-runtime/lucet-runtime-internals/src/module/mock.rs +++ b/lucet-runtime/lucet-runtime-internals/src/module/mock.rs @@ -6,8 +6,8 @@ use lucet_module::owned::{ OwnedLinearMemorySpec, OwnedModuleData, OwnedSparseData, }; use lucet_module::{ - FunctionHandle, FunctionIndex, FunctionPointer, FunctionSpec, ModuleData, Signature, TrapSite, - UniqueSignatureIndex, + FunctionHandle, FunctionIndex, FunctionPointer, FunctionSpec, ModuleData, ModuleFeatures, + Signature, TrapSite, UniqueSignatureIndex, }; use std::collections::{BTreeMap, HashMap}; use std::sync::Arc; @@ -221,6 +221,7 @@ impl MockModuleBuilder { self.imports, self.exports, self.signatures, + ModuleFeatures::none(), ); let serialized_module_data = owned_module_data .to_ref() diff --git a/lucet-spectest/src/script.rs b/lucet-spectest/src/script.rs index 70fe4bfae..41880b9dd 100644 --- a/lucet-spectest/src/script.rs +++ b/lucet-spectest/src/script.rs @@ -1,7 +1,7 @@ use crate::bindings; use failure::{format_err, Error, Fail}; use lucet_runtime::{self, MmapRegion, Module as LucetModule, Region, UntypedRetVal, Val}; -use lucetc::{Compiler, HeapSettings, LucetcError, LucetcErrorKind, OptLevel}; +use lucetc::{Compiler, CpuFeatures, HeapSettings, LucetcError, LucetcErrorKind, OptLevel}; use std::io; use std::process::Command; use std::sync::Arc; @@ -70,6 +70,7 @@ impl ScriptEnv { let compiler = Compiler::new( module, OptLevel::default(), + CpuFeatures::baseline(), &bindings, HeapSettings::default(), true, diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index 8b58ad86e..c31216994 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -43,6 +43,7 @@ minisign = "0.5.11" memoffset = "0.5.1" serde = "1.0" serde_json = "1.0" +raw-cpuid = "7.0.3" [package.metadata.deb] name = "fst-lucetc" diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index 2a5695234..b5f80c4ce 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -21,7 +21,7 @@ use cranelift_module::{Backend as ClifBackend, Module as ClifModule}; use cranelift_wasm::{translate_module, FuncTranslator, ModuleTranslationState, WasmError}; use failure::{format_err, Fail, ResultExt}; use lucet_module::bindings::Bindings; -use lucet_module::{FunctionSpec, ModuleData, MODULE_DATA_SYM}; +use lucet_module::{FunctionSpec, ModuleData, ModuleFeatures, MODULE_DATA_SYM}; use lucet_validate::Validator; #[derive(Debug, Clone, Copy)] @@ -133,8 +133,13 @@ impl<'a> Compiler<'a> { }) } + pub fn module_features(&self) -> ModuleFeatures { + // This will grow in the future to encompass other options describing the compiled module. + (&self.cpu_features).into() + } + pub fn module_data(&self) -> Result, LucetcError> { - self.decls.get_module_data() + self.decls.get_module_data(self.module_features()) } pub fn object_file(mut self) -> Result { @@ -165,7 +170,13 @@ impl<'a> Compiler<'a> { stack_probe::declare_metadata(&mut self.decls, &mut self.clif_module).unwrap(); - let module_data_len = write_module_data(&mut self.clif_module, &self.decls)?; + let module_data_bytes = self + .module_data()? + .serialize() + .context(LucetcErrorKind::ModuleData)?; + let module_data_len = module_data_bytes.len(); + + write_module_data(&mut self.clif_module, module_data_bytes)?; write_startfunc_data(&mut self.clif_module, &self.decls)?; let table_names = write_table_data(&mut self.clif_module, &self.decls)?; @@ -241,19 +252,12 @@ impl<'a> Compiler<'a> { fn write_module_data( clif_module: &mut ClifModule, - decls: &ModuleDecls<'_>, -) -> Result { + module_data_bytes: Vec, +) -> Result<(), LucetcError> { use cranelift_module::{DataContext, Linkage}; - let module_data_serialized: Vec = decls - .get_module_data()? - .serialize() - .context(LucetcErrorKind::ModuleData)?; - - let module_data_len = module_data_serialized.len(); - let mut module_data_ctx = DataContext::new(); - module_data_ctx.define(module_data_serialized.into_boxed_slice()); + module_data_ctx.define(module_data_bytes.into_boxed_slice()); let module_data_decl = clif_module .declare_data(MODULE_DATA_SYM, Linkage::Local, true, None) @@ -262,7 +266,7 @@ fn write_module_data( .define_data(module_data_decl, &module_data_ctx) .context(LucetcErrorKind::ModuleData)?; - Ok(module_data_len) + Ok(()) } fn write_startfunc_data( diff --git a/lucetc/src/compiler/cpu_features.rs b/lucetc/src/compiler/cpu_features.rs index cd3319ab7..e6104c113 100644 --- a/lucetc/src/compiler/cpu_features.rs +++ b/lucetc/src/compiler/cpu_features.rs @@ -1,9 +1,12 @@ use crate::error::{LucetcError, LucetcErrorKind}; use cranelift_codegen::{isa, settings::Configurable}; use failure::{format_err, ResultExt}; -use std::collections::HashMap; +use lucet_module::ModuleFeatures; +use std::collections::{HashMap, HashSet}; use target_lexicon::Triple; +use raw_cpuid::CpuId; + /// x86 CPU families used as shorthand for different CPU feature configurations. /// /// Matches the definitions from `cranelift-codegen`'s x86 settings definition. @@ -66,6 +69,86 @@ pub struct CpuFeatures { specific_features: HashMap, } +fn detect_features(features: &mut ModuleFeatures) { + let cpuid = CpuId::new(); + + if let Some(info) = cpuid.get_feature_info() { + features.sse3 = info.has_sse3(); + features.ssse3 = info.has_ssse3(); + features.sse41 = info.has_sse41(); + features.sse42 = info.has_sse42(); + features.avx = info.has_avx(); + features.popcnt = info.has_popcnt(); + } + + if let Some(info) = cpuid.get_extended_feature_info() { + features.bmi1 = info.has_bmi1(); + features.bmi2 = info.has_bmi2(); + } + + if let Some(info) = cpuid.get_extended_function_info() { + features.lzcnt = info.has_lzcnt(); + } +} + +impl From<&CpuFeatures> for ModuleFeatures { + fn from(cpu_features: &CpuFeatures) -> ModuleFeatures { + let mut module_features = ModuleFeatures::none(); + + let mut feature_set: HashSet = HashSet::new(); + + if let TargetCpu::Native = cpu_features.cpu { + // If the target is `Native`, start with the current set of cpu features.. + detect_features(&mut module_features); + } else { + // otherwise, start with the target cpu's default feature set + feature_set = cpu_features.cpu.features().into_iter().collect(); + } + + for (feature, enabled) in cpu_features.specific_features.iter() { + if *enabled { + feature_set.insert(*feature); + } else { + feature_set.remove(feature); + } + } + + for feature in feature_set { + use SpecificFeature::*; + match feature { + SSE3 => { + module_features.sse3 = true; + } + SSSE3 => { + module_features.ssse3 = true; + } + SSE41 => { + module_features.sse41 = true; + } + SSE42 => { + module_features.sse42 = true; + } + AVX => { + module_features.avx = true; + } + BMI1 => { + module_features.bmi1 = true; + } + BMI2 => { + module_features.bmi2 = true; + } + Popcnt => { + module_features.popcnt = true; + } + Lzcnt => { + module_features.lzcnt = true; + } + } + } + module_features + } +} + impl Default for CpuFeatures { fn default() -> Self { Self::detect_cpuid() diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index 936515335..3a6c4b2fa 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -16,6 +16,7 @@ use cranelift_wasm::{ }; use failure::{format_err, Error, ResultExt}; use lucet_module::bindings::Bindings; +use lucet_module::ModuleFeatures; use lucet_module::{ owned::OwnedLinearMemorySpec, ExportFunction, FunctionIndex as LucetFunctionIndex, FunctionMetadata, Global as GlobalVariant, GlobalDef, GlobalSpec, HeapSpec, ImportFunction, @@ -502,7 +503,7 @@ impl<'a> ModuleDecls<'a> { } } - pub fn get_module_data(&self) -> Result, LucetcError> { + pub fn get_module_data(&self, features: ModuleFeatures) -> Result, LucetcError> { let linear_memory = if let Some(ref spec) = self.linear_memory_spec { Some(spec.to_ref()) } else { @@ -548,6 +549,7 @@ impl<'a> ModuleDecls<'a> { self.imports.clone(), self.exports.clone(), signatures, + features, )) } } From 588b8991199365b69e05012e41b516541314cd28 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Thu, 31 Oct 2019 13:08:30 -0700 Subject: [PATCH 459/512] bump to 0.4.0 --- Cargo.lock | 112 +++++++++--------- benchmarks/lucet-benchmarks/Cargo.toml | 2 +- lucet-module/Cargo.toml | 2 +- lucet-objdump/Cargo.toml | 4 +- lucet-runtime/Cargo.toml | 12 +- .../lucet-runtime-internals/Cargo.toml | 4 +- lucet-runtime/lucet-runtime-tests/Cargo.toml | 10 +- lucet-spectest/Cargo.toml | 8 +- lucet-validate/Cargo.toml | 4 +- lucet-wasi-fuzz/Cargo.toml | 2 +- lucet-wasi-sdk/Cargo.toml | 8 +- lucet-wasi/Cargo.toml | 12 +- lucetc/Cargo.toml | 6 +- 13 files changed, 93 insertions(+), 93 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f4de5ebb4..c9aaa7770 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -760,15 +760,15 @@ dependencies = [ [[package]] name = "lucet-benchmarks" -version = "0.3.1" +version = "0.4.0" dependencies = [ "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.3.1", - "lucet-runtime 0.3.1", - "lucet-runtime-internals 0.3.1", - "lucet-wasi 0.3.1", - "lucet-wasi-sdk 0.3.1", - "lucetc 0.3.1", + "lucet-module 0.4.0", + "lucet-runtime 0.4.0", + "lucet-runtime-internals 0.4.0", + "lucet-wasi 0.4.0", + "lucet-wasi-sdk 0.4.0", + "lucetc 0.4.0", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -783,8 +783,8 @@ dependencies = [ "cranelift-entity 0.46.1", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.3.1", - "lucetc 0.3.1", + "lucet-module 0.4.0", + "lucetc 0.4.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -800,10 +800,10 @@ dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-idl 0.2.0", - "lucet-runtime 0.3.1", - "lucet-wasi 0.3.1", - "lucet-wasi-sdk 0.3.1", - "lucetc 0.3.1", + "lucet-runtime 0.4.0", + "lucet-wasi 0.4.0", + "lucet-wasi-sdk 0.4.0", + "lucetc 0.4.0", "proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -816,13 +816,13 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-idl 0.2.0", - "lucet-runtime 0.3.1", - "lucet-wasi 0.3.1", + "lucet-runtime 0.4.0", + "lucet-wasi 0.4.0", ] [[package]] name = "lucet-module" -version = "0.3.1" +version = "0.4.0" dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -839,28 +839,28 @@ dependencies = [ [[package]] name = "lucet-objdump" -version = "0.3.1" +version = "0.4.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.3.1", + "lucet-module 0.4.0", ] [[package]] name = "lucet-runtime" -version = "0.3.1" +version = "0.4.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.3.1", - "lucet-runtime-internals 0.3.1", - "lucet-runtime-tests 0.3.1", - "lucet-wasi-sdk 0.3.1", - "lucetc 0.3.1", + "lucet-module 0.4.0", + "lucet-runtime-internals 0.4.0", + "lucet-runtime-tests 0.4.0", + "lucet-wasi-sdk 0.4.0", + "lucetc 0.4.0", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -870,7 +870,7 @@ dependencies = [ [[package]] name = "lucet-runtime-internals" -version = "0.3.1" +version = "0.4.0" dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -881,7 +881,7 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.3.1", + "lucet-module 0.4.0", "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -892,27 +892,27 @@ dependencies = [ [[package]] name = "lucet-runtime-tests" -version = "0.3.1" +version = "0.4.0" dependencies = [ "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.3.1", - "lucet-runtime-internals 0.3.1", - "lucet-wasi-sdk 0.3.1", - "lucetc 0.3.1", + "lucet-module 0.4.0", + "lucet-runtime-internals 0.4.0", + "lucet-wasi-sdk 0.4.0", + "lucetc 0.4.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucet-spectest" -version = "0.3.1" +version = "0.4.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.3.1", - "lucet-runtime 0.3.1", - "lucetc 0.3.1", + "lucet-module 0.4.0", + "lucet-runtime 0.4.0", + "lucetc 0.4.0", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -921,12 +921,12 @@ dependencies = [ [[package]] name = "lucet-validate" -version = "0.3.1" +version = "0.4.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.46.1", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-wasi-sdk 0.3.1", + "lucet-wasi-sdk 0.4.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -935,7 +935,7 @@ dependencies = [ [[package]] name = "lucet-wasi" -version = "0.3.1" +version = "0.4.0" dependencies = [ "bindgen 0.47.3 (registry+https://github.com/rust-lang/crates.io-index)", "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -943,11 +943,11 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.3.1", - "lucet-runtime 0.3.1", - "lucet-runtime-internals 0.3.1", - "lucet-wasi-sdk 0.3.1", - "lucetc 0.3.1", + "lucet-module 0.4.0", + "lucet-runtime 0.4.0", + "lucet-runtime-internals 0.4.0", + "lucet-wasi-sdk 0.4.0", + "lucetc 0.4.0", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -955,16 +955,16 @@ dependencies = [ [[package]] name = "lucet-wasi-fuzz" -version = "0.3.1" +version = "0.4.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.3.1", - "lucet-runtime 0.3.1", - "lucet-wasi 0.3.1", - "lucet-wasi-sdk 0.3.1", - "lucetc 0.3.1", + "lucet-module 0.4.0", + "lucet-runtime 0.4.0", + "lucet-wasi 0.4.0", + "lucet-wasi-sdk 0.4.0", + "lucetc 0.4.0", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -978,18 +978,18 @@ dependencies = [ [[package]] name = "lucet-wasi-sdk" -version = "0.3.1" +version = "0.4.0" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.3.1", - "lucet-validate 0.3.1", - "lucetc 0.3.1", + "lucet-module 0.4.0", + "lucet-validate 0.4.0", + "lucetc 0.4.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucetc" -version = "0.3.1" +version = "0.4.0" dependencies = [ "bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1008,8 +1008,8 @@ dependencies = [ "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.3.1", - "lucet-validate 0.3.1", + "lucet-module 0.4.0", + "lucet-validate 0.4.0", "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/benchmarks/lucet-benchmarks/Cargo.toml b/benchmarks/lucet-benchmarks/Cargo.toml index 8af99a722..8bee031f3 100644 --- a/benchmarks/lucet-benchmarks/Cargo.toml +++ b/benchmarks/lucet-benchmarks/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-benchmarks" -version = "0.3.1" +version = "0.4.0" description = "Benchmarks for the Lucet runtime" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" diff --git a/lucet-module/Cargo.toml b/lucet-module/Cargo.toml index 8f28d5f80..54bac1c20 100644 --- a/lucet-module/Cargo.toml +++ b/lucet-module/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-module" -version = "0.3.1" +version = "0.4.0" description = "A structured interface for Lucet modules" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" diff --git a/lucet-objdump/Cargo.toml b/lucet-objdump/Cargo.toml index 6b0018813..b5327d533 100644 --- a/lucet-objdump/Cargo.toml +++ b/lucet-objdump/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-objdump" -version = "0.3.1" +version = "0.4.0" description = "Analyze object files emitted by the Lucet compiler" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -13,7 +13,7 @@ edition = "2018" goblin="0.0.24" byteorder="1.2.1" colored="1.6.1" -lucet-module = { path = "../lucet-module", version = "0.3.1" } +lucet-module = { path = "../lucet-module", version = "0.4.0" } [package.metadata.deb] name = "fst-lucet-objdump" diff --git a/lucet-runtime/Cargo.toml b/lucet-runtime/Cargo.toml index ad05062e8..45fe5f1af 100644 --- a/lucet-runtime/Cargo.toml +++ b/lucet-runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime" -version = "0.3.1" +version = "0.4.0" description = "Pure Rust runtime for Lucet WebAssembly toolchain" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -11,8 +11,8 @@ edition = "2018" [dependencies] libc = "=0.2.59" -lucet-runtime-internals = { path = "lucet-runtime-internals", version = "0.3.1" } -lucet-module = { path = "../lucet-module", version = "0.3.1" } +lucet-runtime-internals = { path = "lucet-runtime-internals", version = "0.4.0" } +lucet-module = { path = "../lucet-module", version = "0.4.0" } num-traits = "0.2" num-derive = "0.2" @@ -20,9 +20,9 @@ num-derive = "0.2" byteorder = "1.2" failure = "0.1" lazy_static = "1.1" -lucetc = { path = "../lucetc", version = "0.3.1" } -lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.3.1" } -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.3.1" } +lucetc = { path = "../lucetc", version = "0.4.0" } +lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.4.0" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.0" } nix = "0.13" rayon = "1.0" tempfile = "3.0" diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index 9884ac14c..f1fcdc968 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime-internals" -version = "0.3.1" +version = "0.4.0" description = "Pure Rust runtime for Lucet WebAssembly toolchain (internals)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -10,7 +10,7 @@ authors = ["Lucet team "] edition = "2018" [dependencies] -lucet-module = { path = "../../lucet-module", version = "0.3.1" } +lucet-module = { path = "../../lucet-module", version = "0.4.0" } bitflags = "1.0" bincode = "1.1.4" diff --git a/lucet-runtime/lucet-runtime-tests/Cargo.toml b/lucet-runtime/lucet-runtime-tests/Cargo.toml index 379ad8260..4a599cef0 100644 --- a/lucet-runtime/lucet-runtime-tests/Cargo.toml +++ b/lucet-runtime/lucet-runtime-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime-tests" -version = "0.3.1" +version = "0.4.0" description = "Pure Rust runtime for Lucet WebAssembly toolchain (tests)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -18,10 +18,10 @@ test = false failure = "0.1" lazy_static = "1.1" tempfile = "3.0" -lucet-module = { path = "../../lucet-module", version = "0.3.1" } -lucet-runtime-internals = { path = "../lucet-runtime-internals", version = "0.3.1" } -lucet-wasi-sdk = { path = "../../lucet-wasi-sdk", version = "0.3.1" } -lucetc = { path = "../../lucetc", version = "0.3.1" } +lucet-module = { path = "../../lucet-module", version = "0.4.0" } +lucet-runtime-internals = { path = "../lucet-runtime-internals", version = "0.4.0" } +lucet-wasi-sdk = { path = "../../lucet-wasi-sdk", version = "0.4.0" } +lucetc = { path = "../../lucetc", version = "0.4.0" } [build-dependencies] cc = "1.0" diff --git a/lucet-spectest/Cargo.toml b/lucet-spectest/Cargo.toml index 521dd04c1..4948d6b1c 100644 --- a/lucet-spectest/Cargo.toml +++ b/lucet-spectest/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-spectest" -version = "0.3.1" +version = "0.4.0" description = "Test harness to run WebAssembly spec tests (.wast) against the Lucet toolchain" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -17,9 +17,9 @@ name = "spec-test" path = "src/main.rs" [dependencies] -lucetc = { path = "../lucetc", version = "0.3.1" } -lucet-module = { path = "../lucet-module", version = "0.3.1" } -lucet-runtime = { path = "../lucet-runtime", version = "0.3.1" } +lucetc = { path = "../lucetc", version = "0.4.0" } +lucet-module = { path = "../lucet-module", version = "0.4.0" } +lucet-runtime = { path = "../lucet-runtime", version = "0.4.0" } wabt = "0.9.2" serde = "1.0" serde_json = "1.0" diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index 7a3f86968..5900a6fb4 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-validate" -version = "0.3.1" +version = "0.4.0" description = "Parse and validate webassembly files against witx interface" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -24,7 +24,7 @@ cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.46.1" wasmparser = "0.39.1" [dev-dependencies] -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.3.1" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.0" } tempfile = "3.0" wabt = "0.9.2" diff --git a/lucet-wasi-fuzz/Cargo.toml b/lucet-wasi-fuzz/Cargo.toml index b36ee2256..971c7a2aa 100644 --- a/lucet-wasi-fuzz/Cargo.toml +++ b/lucet-wasi-fuzz/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi-fuzz" -version = "0.3.1" +version = "0.4.0" description = "Test the Lucet toolchain against native code execution using Csmith" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" diff --git a/lucet-wasi-sdk/Cargo.toml b/lucet-wasi-sdk/Cargo.toml index 140c533b2..c85e4b557 100644 --- a/lucet-wasi-sdk/Cargo.toml +++ b/lucet-wasi-sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi-sdk" -version = "0.3.1" +version = "0.4.0" description = "A Rust interface to the wasi-sdk compiler and linker" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -11,9 +11,9 @@ edition = "2018" [dependencies] failure = "0.1" -lucetc = { path = "../lucetc", version = "0.3.1" } -lucet-module = { path = "../lucet-module", version = "0.3.1" } +lucetc = { path = "../lucetc", version = "0.4.0" } +lucet-module = { path = "../lucet-module", version = "0.4.0" } tempfile = "3.0" [dev-dependencies] -lucet-validate = { path = "../lucet-validate", version = "0.3.1" } +lucet-validate = { path = "../lucet-validate", version = "0.4.0" } diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index f8ca0055d..de9e631fc 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi" -version = "0.3.1" +version = "0.4.0" description = "Fastly's runtime for the WebAssembly System Interface (WASI)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -29,15 +29,15 @@ clap = "2.23" failure = "0.1" human-size = "0.4" libc = "=0.2.59" -lucet-runtime = { path = "../lucet-runtime", version = "0.3.1" } -lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.3.1" } -lucet-module = { path = "../lucet-module", version = "0.3.1" } +lucet-runtime = { path = "../lucet-runtime", version = "0.4.0" } +lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.4.0" } +lucet-module = { path = "../lucet-module", version = "0.4.0" } nix = "0.13" rand = "0.6" [dev-dependencies] -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.3.1" } -lucetc = { path = "../lucetc", version = "0.3.1" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.0" } +lucetc = { path = "../lucetc", version = "0.4.0" } tempfile = "3.0" [build-dependencies.bindgen] diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index c31216994..cf92dab72 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucetc" -version = "0.3.1" +version = "0.4.0" description = "Fastly's WebAssembly to native code compiler" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -23,8 +23,8 @@ cranelift-module = { path = "../cranelift/cranelift-module", version = "0.46.1" cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.46.1" } cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.46.1" } target-lexicon = "0.8.0" -lucet-module = { path = "../lucet-module", version = "0.3.1" } -lucet-validate = { path = "../lucet-validate", version = "0.3.1" } +lucet-module = { path = "../lucet-module", version = "0.4.0" } +lucet-validate = { path = "../lucet-validate", version = "0.4.0" } wasmparser = "0.39.1" clap="2.32" log = "0.4" From 72a691e1997303274d136f7c10a56303b22a4f7c Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 31 Oct 2019 23:04:33 +0100 Subject: [PATCH 460/512] Use app_from_crate!() instead of hardcoding clap base parameters --- lucet-builtins/wasmonkey/src/bin/config/mod.rs | 6 ++---- lucet-builtins/wasmonkey/src/bin/wasmonkey.rs | 3 +++ lucet-idl/lucet-idl-test/src/main.rs | 9 +++++---- lucet-idl/src/main.rs | 9 +++++---- lucet-spectest/src/main.rs | 7 +++++-- lucetc/lucetc/main.rs | 3 +++ lucetc/lucetc/options.rs | 4 ++-- 7 files changed, 25 insertions(+), 16 deletions(-) diff --git a/lucet-builtins/wasmonkey/src/bin/config/mod.rs b/lucet-builtins/wasmonkey/src/bin/config/mod.rs index 3b2b60f51..5c2fbd758 100644 --- a/lucet-builtins/wasmonkey/src/bin/config/mod.rs +++ b/lucet-builtins/wasmonkey/src/bin/config/mod.rs @@ -1,5 +1,5 @@ use crate::{PatcherConfig, WError}; -use clap::{App, Arg}; +use clap::Arg; use std::path::PathBuf; #[derive(Default, Clone, Debug)] @@ -11,9 +11,7 @@ pub struct Config { impl Config { pub fn parse_cmdline() -> Result { - let matches = App::new("wasmonkey") - .version("1.0") - .about("Transforms WASM exports to imports") + let matches = app_from_crate!() .arg( Arg::with_name("input_file") .short("i") diff --git a/lucet-builtins/wasmonkey/src/bin/wasmonkey.rs b/lucet-builtins/wasmonkey/src/bin/wasmonkey.rs index d90c6cbe0..5ed604369 100644 --- a/lucet-builtins/wasmonkey/src/bin/wasmonkey.rs +++ b/lucet-builtins/wasmonkey/src/bin/wasmonkey.rs @@ -1,5 +1,8 @@ mod config; +#[macro_use] +extern crate clap; + use crate::config::*; use wasmonkey::*; diff --git a/lucet-idl/lucet-idl-test/src/main.rs b/lucet-idl/lucet-idl-test/src/main.rs index 4c8a0e5e0..97b7450cd 100644 --- a/lucet-idl/lucet-idl-test/src/main.rs +++ b/lucet-idl/lucet-idl-test/src/main.rs @@ -1,4 +1,7 @@ -use clap::{App, Arg}; +#[macro_use] +extern crate clap; + +use clap::Arg; use env_logger; use log::{debug, info}; use lucet_idl::{parse_package, Module, Package}; @@ -89,9 +92,7 @@ struct ExeConfig { impl ExeConfig { pub fn parse() -> Self { - let matches = App::new("lucet-idl-test") - .version("0.1.0") - .about("lucet-idl testing tool") + let matches = app_from_crate!() .arg( Arg::with_name("input") .required(false) diff --git a/lucet-idl/src/main.rs b/lucet-idl/src/main.rs index c642a3ab9..b0609a970 100644 --- a/lucet-idl/src/main.rs +++ b/lucet-idl/src/main.rs @@ -1,4 +1,7 @@ -use clap::{App, Arg}; +#[macro_use] +extern crate clap; + +use clap::Arg; use lucet_idl::{run, Config, IDLError}; use std::fs::File; use std::io; @@ -15,9 +18,7 @@ pub struct ExeConfig { impl ExeConfig { pub fn parse() -> Result { - let matches = App::new("lucet-idl") - .version(env!("CARGO_PKG_VERSION")) - .about("lucet_idl code generator") + let matches = app_from_crate!() .arg( Arg::with_name("input") .required(true) diff --git a/lucet-spectest/src/main.rs b/lucet-spectest/src/main.rs index ff8a923c2..3f32d34ef 100644 --- a/lucet-spectest/src/main.rs +++ b/lucet-spectest/src/main.rs @@ -1,10 +1,13 @@ -use clap::{App, Arg}; +#[macro_use] +extern crate clap; + +use clap::Arg; use failure::{format_err, Error}; use lucet_spectest; use std::path::PathBuf; fn main() -> Result<(), Error> { - let matches = App::new("lucet-spectest") + let matches = app_from_crate!() .arg( Arg::with_name("input") .multiple(false) diff --git a/lucetc/lucetc/main.rs b/lucetc/lucetc/main.rs index 2154edf25..55ddbb67d 100644 --- a/lucetc/lucetc/main.rs +++ b/lucetc/lucetc/main.rs @@ -1,5 +1,8 @@ mod options; +#[macro_use] +extern crate clap; + use crate::options::{CodegenOutput, ErrorStyle, Options}; use failure::{format_err, Error, ResultExt}; use log::info; diff --git a/lucetc/lucetc/options.rs b/lucetc/lucetc/options.rs index aa5dfff06..60f9cce29 100644 --- a/lucetc/lucetc/options.rs +++ b/lucetc/lucetc/options.rs @@ -1,4 +1,4 @@ -use clap::{App, Arg, ArgMatches, Values}; +use clap::{Arg, ArgMatches, Values}; use failure::Error; use lucetc::{CpuFeatures, HeapSettings, OptLevel, SpecificFeature, TargetCpu}; use std::path::PathBuf; @@ -228,7 +228,7 @@ impl Options { }) } pub fn get() -> Result { - let m = App::new("lucetc") + let m = app_from_crate!() .arg( Arg::with_name("precious") .long("--precious") From 28d7cd9b61ac25216c148ab7c987def04bfe564d Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 31 Oct 2019 23:30:02 +0100 Subject: [PATCH 461/512] Add include_str!("Cargo.toml") to update macros if Cargo.toml changes --- lucet-builtins/wasmonkey/src/bin/config/mod.rs | 1 + lucet-idl/lucet-idl-test/src/main.rs | 1 + lucet-idl/src/main.rs | 1 + lucet-spectest/src/main.rs | 1 + lucetc/lucetc/options.rs | 1 + 5 files changed, 5 insertions(+) diff --git a/lucet-builtins/wasmonkey/src/bin/config/mod.rs b/lucet-builtins/wasmonkey/src/bin/config/mod.rs index 5c2fbd758..ccd29b985 100644 --- a/lucet-builtins/wasmonkey/src/bin/config/mod.rs +++ b/lucet-builtins/wasmonkey/src/bin/config/mod.rs @@ -11,6 +11,7 @@ pub struct Config { impl Config { pub fn parse_cmdline() -> Result { + let _ = include_str!("../../../Cargo.toml"); let matches = app_from_crate!() .arg( Arg::with_name("input_file") diff --git a/lucet-idl/lucet-idl-test/src/main.rs b/lucet-idl/lucet-idl-test/src/main.rs index 97b7450cd..e1d907f58 100644 --- a/lucet-idl/lucet-idl-test/src/main.rs +++ b/lucet-idl/lucet-idl-test/src/main.rs @@ -92,6 +92,7 @@ struct ExeConfig { impl ExeConfig { pub fn parse() -> Self { + let _ = include_str!("../Cargo.toml"); let matches = app_from_crate!() .arg( Arg::with_name("input") diff --git a/lucet-idl/src/main.rs b/lucet-idl/src/main.rs index b0609a970..6e30ac8d2 100644 --- a/lucet-idl/src/main.rs +++ b/lucet-idl/src/main.rs @@ -18,6 +18,7 @@ pub struct ExeConfig { impl ExeConfig { pub fn parse() -> Result { + let _ = include_str!("../Cargo.toml"); let matches = app_from_crate!() .arg( Arg::with_name("input") diff --git a/lucet-spectest/src/main.rs b/lucet-spectest/src/main.rs index 3f32d34ef..3dffa542f 100644 --- a/lucet-spectest/src/main.rs +++ b/lucet-spectest/src/main.rs @@ -7,6 +7,7 @@ use lucet_spectest; use std::path::PathBuf; fn main() -> Result<(), Error> { + let _ = include_str!("../Cargo.toml"); let matches = app_from_crate!() .arg( Arg::with_name("input") diff --git a/lucetc/lucetc/options.rs b/lucetc/lucetc/options.rs index 60f9cce29..332dbbb36 100644 --- a/lucetc/lucetc/options.rs +++ b/lucetc/lucetc/options.rs @@ -228,6 +228,7 @@ impl Options { }) } pub fn get() -> Result { + let _ = include_str!("../Cargo.toml"); let m = app_from_crate!() .arg( Arg::with_name("precious") From 4d12bc6da6adbbf62b0c2639819baefac84e9320 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Thu, 31 Oct 2019 16:46:53 -0700 Subject: [PATCH 462/512] bump to 0.4.1 and refine some dependencies There were some problems when trying to publish the crates due to parity-wasm versions differing in our crates and Cranelift's. I went through and updated and/or fixed the versions of some crates that look like they could've caused trouble. --- Cargo.lock | 687 +++++++++--------- benchmarks/lucet-benchmarks/Cargo.toml | 4 +- cranelift | 2 +- lucet-builtins/wasmonkey/Cargo.toml | 2 +- lucet-module/Cargo.toml | 8 +- lucet-objdump/Cargo.toml | 6 +- lucet-runtime/Cargo.toml | 14 +- .../lucet-runtime-internals/Cargo.toml | 8 +- lucet-runtime/lucet-runtime-tests/Cargo.toml | 10 +- lucet-spectest/Cargo.toml | 8 +- lucet-validate/Cargo.toml | 4 +- lucet-wasi-fuzz/Cargo.toml | 4 +- lucet-wasi-sdk/Cargo.toml | 8 +- lucet-wasi/Cargo.toml | 17 +- lucetc/Cargo.toml | 10 +- 15 files changed, 403 insertions(+), 389 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c9aaa7770..294f5f430 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,10 +28,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "arrayvec" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -45,26 +45,26 @@ dependencies = [ [[package]] name = "autocfg" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.38" +version = "0.3.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "backtrace-sys" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -86,38 +86,39 @@ name = "bimap" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bincode" -version = "1.1.4" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bindgen" -version = "0.47.3" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "clang-sys 0.26.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "clang-sys 0.28.1 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "which 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -140,7 +141,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -170,7 +171,7 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -185,11 +186,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "c2-chacha" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -199,7 +199,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cc" -version = "1.0.45" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -212,7 +212,7 @@ dependencies = [ [[package]] name = "cfg-if" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -227,10 +227,10 @@ dependencies = [ [[package]] name = "clang-sys" -version = "0.26.4" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -242,7 +242,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -254,7 +254,7 @@ name = "cloudabi" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -262,7 +262,7 @@ name = "cmake" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -281,7 +281,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -300,10 +300,10 @@ dependencies = [ "cranelift-codegen-meta 0.46.1", "cranelift-codegen-shared 0.46.1", "cranelift-entity 0.46.1", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -330,7 +330,7 @@ dependencies = [ "cranelift-codegen 0.46.1", "cranelift-module 0.46.1", "faerie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -341,7 +341,7 @@ version = "0.46.1" dependencies = [ "cranelift-codegen 0.46.1", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -351,7 +351,7 @@ version = "0.46.1" dependencies = [ "cranelift-codegen 0.46.1", "cranelift-entity 0.46.1", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -360,7 +360,7 @@ name = "cranelift-native" version = "0.46.1" dependencies = [ "cranelift-codegen 0.46.1", - "raw-cpuid 7.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -371,8 +371,8 @@ dependencies = [ "cranelift-codegen 0.46.1", "cranelift-entity 0.46.1", "cranelift-frontend 0.46.1", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -382,43 +382,40 @@ name = "crc32fast" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "criterion" -version = "0.2.11" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "criterion-plot" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -435,11 +432,11 @@ name = "crossbeam-epoch" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -456,7 +453,7 @@ name = "crossbeam-utils" version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -477,8 +474,8 @@ dependencies = [ "bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -538,9 +535,9 @@ name = "faerie" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "string-interner 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -549,22 +546,22 @@ dependencies = [ [[package]] name = "failure" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "failure_derive" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -574,13 +571,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "flate2" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -632,14 +629,9 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "goblin" -version = "0.0.22" +name = "glob" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "goblin" @@ -652,20 +644,19 @@ dependencies = [ ] [[package]] -name = "hashbrown" -version = "0.1.8" +name = "heck" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "heck" -version = "0.3.1" +name = "hermit-abi" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -706,12 +697,15 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "itertools" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -746,7 +740,7 @@ name = "libloading" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -755,22 +749,22 @@ name = "log" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucet-benchmarks" -version = "0.4.0" -dependencies = [ - "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.0", - "lucet-runtime 0.4.0", - "lucet-runtime-internals 0.4.0", - "lucet-wasi 0.4.0", - "lucet-wasi-sdk 0.4.0", - "lucetc 0.4.0", +version = "0.4.1" +dependencies = [ + "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lucet-module 0.4.1", + "lucet-runtime 0.4.1", + "lucet-runtime-internals 0.4.1", + "lucet-wasi 0.4.1", + "lucet-wasi-sdk 0.4.1", + "lucetc 0.4.1", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -781,10 +775,10 @@ version = "0.2.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.46.1", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.0", - "lucetc 0.4.0", + "lucet-module 0.4.1", + "lucetc 0.4.1", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -795,15 +789,15 @@ version = "0.1.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-idl 0.2.0", - "lucet-runtime 0.4.0", - "lucet-wasi 0.4.0", - "lucet-wasi-sdk 0.4.0", - "lucetc 0.4.0", + "lucet-runtime 0.4.1", + "lucet-wasi 0.4.1", + "lucet-wasi-sdk 0.4.1", + "lucetc 0.4.1", "proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -813,56 +807,56 @@ name = "lucet-idl-test-rust-host" version = "0.1.0" dependencies = [ "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-idl 0.2.0", - "lucet-runtime 0.4.0", - "lucet-wasi 0.4.0", + "lucet-runtime 0.4.1", + "lucet-wasi 0.4.1", ] [[package]] name = "lucet-module" -version = "0.4.0" +version = "0.4.1" dependencies = [ - "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.46.1", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", - "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "object 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "object 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucet-objdump" -version = "0.4.0" +version = "0.4.1" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.0", + "lucet-module 0.4.1", ] [[package]] name = "lucet-runtime" -version = "0.4.0" +version = "0.4.1" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.0", - "lucet-runtime-internals 0.4.0", - "lucet-runtime-tests 0.4.0", - "lucet-wasi-sdk 0.4.0", - "lucetc 0.4.0", + "lucet-module 0.4.1", + "lucet-runtime-internals 0.4.1", + "lucet-runtime-tests 0.4.1", + "lucet-wasi-sdk 0.4.1", + "lucetc 0.4.1", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -870,63 +864,63 @@ dependencies = [ [[package]] name = "lucet-runtime-internals" -version = "0.4.0" +version = "0.4.1" dependencies = [ - "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.0", - "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lucet-module 0.4.1", + "memoffset 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "raw-cpuid 7.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucet-runtime-tests" -version = "0.4.0" +version = "0.4.1" dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.0", - "lucet-runtime-internals 0.4.0", - "lucet-wasi-sdk 0.4.0", - "lucetc 0.4.0", + "lucet-module 0.4.1", + "lucet-runtime-internals 0.4.1", + "lucet-wasi-sdk 0.4.1", + "lucetc 0.4.1", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucet-spectest" -version = "0.4.0" +version = "0.4.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.0", - "lucet-runtime 0.4.0", - "lucetc 0.4.0", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lucet-module 0.4.1", + "lucet-runtime 0.4.1", + "lucetc 0.4.1", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucet-validate" -version = "0.4.0" +version = "0.4.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.46.1", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-wasi-sdk 0.4.0", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lucet-wasi-sdk 0.4.1", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -935,19 +929,19 @@ dependencies = [ [[package]] name = "lucet-wasi" -version = "0.4.0" +version = "0.4.1" dependencies = [ - "bindgen 0.47.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)", "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.0", - "lucet-runtime 0.4.0", - "lucet-runtime-internals 0.4.0", - "lucet-wasi-sdk 0.4.0", - "lucetc 0.4.0", + "lucet-module 0.4.1", + "lucet-runtime 0.4.1", + "lucet-runtime-internals 0.4.1", + "lucet-wasi-sdk 0.4.1", + "lucetc 0.4.1", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -955,44 +949,44 @@ dependencies = [ [[package]] name = "lucet-wasi-fuzz" -version = "0.4.0" +version = "0.4.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.0", - "lucet-runtime 0.4.0", - "lucet-wasi 0.4.0", - "lucet-wasi-sdk 0.4.0", - "lucetc 0.4.0", + "lucet-module 0.4.1", + "lucet-runtime 0.4.1", + "lucet-wasi 0.4.1", + "lucet-wasi-sdk 0.4.1", + "lucetc 0.4.1", "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucet-wasi-sdk" -version = "0.4.0" +version = "0.4.1" dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.0", - "lucet-validate 0.4.0", - "lucetc 0.4.0", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lucet-module 0.4.1", + "lucet-validate 0.4.1", + "lucetc 0.4.1", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucetc" -version = "0.4.0" +version = "0.4.1" dependencies = [ "bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-codegen 0.46.1", @@ -1004,18 +998,18 @@ dependencies = [ "cranelift-wasm 0.46.1", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "faerie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.0", - "lucet-validate 0.4.0", - "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lucet-module 0.4.1", + "lucet-validate 0.4.1", + "memoffset 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", - "raw-cpuid 7.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wasm 0.40.3 (registry+https://github.com/rust-lang/crates.io-index)", + "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1033,7 +1027,7 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1050,18 +1044,9 @@ dependencies = [ "scrypt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "miniz-sys" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "miniz_oxide" -version = "0.3.2" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1072,16 +1057,16 @@ name = "nix" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "nodrop" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1105,12 +1090,12 @@ dependencies = [ [[package]] name = "num-derive" -version = "0.2.5" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1118,7 +1103,7 @@ name = "num-integer" version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1127,7 +1112,7 @@ name = "num-iter" version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1145,26 +1130,28 @@ name = "num-traits" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num_cpus" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "object" -version = "0.12.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "flate2 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", - "goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wasm 0.40.3 (registry+https://github.com/rust-lang/crates.io-index)", "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1175,7 +1162,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "parity-wasm" -version = "0.38.0" +version = "0.40.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1204,7 +1191,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ppv-lite86" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1212,7 +1199,7 @@ name = "precision" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1222,6 +1209,16 @@ name = "printtable" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "proc-macro-error" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "proc-macro2" version = "0.4.30" @@ -1232,7 +1229,7 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1252,7 +1249,7 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1283,7 +1280,7 @@ name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1303,7 +1300,7 @@ name = "rand" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1333,7 +1330,7 @@ name = "rand_chacha" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1342,7 +1339,7 @@ name = "rand_chacha" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1414,12 +1411,21 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_os" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_pcg" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1433,20 +1439,19 @@ dependencies = [ [[package]] name = "rand_xoshiro" -version = "0.1.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "raw-cpuid" -version = "7.0.3" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1469,7 +1474,7 @@ dependencies = [ "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1537,6 +1542,14 @@ name = "rustc-demangle" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rustc-hash" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc_version" version = "0.2.3" @@ -1558,7 +1571,7 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1569,11 +1582,6 @@ dependencies = [ "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "scopeguard" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "scopeguard" version = "1.0.0" @@ -1625,30 +1633,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.101" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.101" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1662,6 +1670,11 @@ dependencies = [ "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "shlex" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "sightglass" version = "0.1.0" @@ -1669,17 +1682,17 @@ dependencies = [ "bencher 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "core_affinity 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "hwloc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "precision 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "printtable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1690,7 +1703,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallvec" -version = "0.6.10" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1698,7 +1711,7 @@ name = "string-interner" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1708,22 +1721,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "structopt" -version = "0.2.18" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "structopt-derive" -version = "0.2.18" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1743,23 +1757,23 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "synstructure" -version = "0.10.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1767,9 +1781,9 @@ name = "target-lexicon" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1777,7 +1791,7 @@ name = "tempfile" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1823,16 +1837,16 @@ name = "tinytemplate" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "toml" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1842,7 +1856,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-segmentation" -version = "1.3.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1885,9 +1899,9 @@ name = "wabt" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1896,7 +1910,7 @@ name = "wabt-sys" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1924,13 +1938,13 @@ name = "wasmonkey" version = "0.1.8" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wasm 0.40.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "siphasher 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1942,10 +1956,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "which" -version = "2.0.1" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2011,7 +2024,7 @@ name = "witx" version = "0.3.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2024,40 +2037,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94" -"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" +"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" -"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" -"checksum backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "690a62be8920ccf773ee00ef0968649b0e724cda8bd5b12286302b4ae955fdf5" -"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b" +"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" +"checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea" +"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum bencher 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdb4953a096c551ce9ace855a604d702e6e62d77fac690575ae347571717f5" "checksum bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "505e45beaf0a1462f5548fe885edf2d83e62022b2ce8b10fef0f7686b48c9266" -"checksum bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9f04a5e50dc80b3d5d35320889053637d15011aed5e66b66b37ae798c65da6f7" -"checksum bindgen 0.47.3 (registry+https://github.com/rust-lang/crates.io-index)" = "df683a55b54b41d5ea8ebfaebb5aa7e6b84e3f3006a78f010dadc9ca88469260" +"checksum bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ab639324e3ee8774d296864fbc0dbbb256cf1a41c490b94cba90c082915f92" +"checksum bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebd71393f1ec0509b553aa012b9b58e81dadbdff7130bd3b8cba576e69b32f75" "checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80" "checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" "checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" "checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245" "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" -"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" +"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" -"checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be" +"checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c" "checksum cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7fa24eb00d5ffab90eaeaf1092ac85c04c64aaf358ea6f84505b8116d24c6af" -"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c" -"checksum clang-sys 0.26.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ef0c1bcf2e99c649104bd7a7012d8f8802684400e03db0ec0af48583c6fa0e4" +"checksum clang-sys 0.28.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81de550971c976f176130da4b2978d3b524eaa0fd9ac31f3ceb5ae1231fb4853" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62" "checksum colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cdb90b60f2927f8d76139c72dbde7e10c3a2bc47c8594c9c7a66529f2687c03" "checksum core_affinity 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6d162c6e463c31dbf78fefa99d042156c1c74d404e299cfe3df2923cb857595b" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" -"checksum criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0363053954f3e679645fc443321ca128b7b950a6fe288cf5f9335cc22ee58394" -"checksum criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76f9212ddf2f4a9eb2d401635190600656a1f88a932ef53d06e7fa4c7e02fb8e" +"checksum criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "938703e165481c8d612ea3479ac8342e5615185db37765162e762ec3523e2fc6" +"checksum criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eccdc6ce8bbe352ca89025bee672aa6d24f4eb8c53e3a8b5d1bc58011da072a2" "checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" "checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" @@ -2071,10 +2084,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2a071601ed01b988f896ab14b95e67335d1eeb50190932a1320f7fe3cadc84e" "checksum errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067" "checksum faerie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "875d78b92b2a4d9e1e2c7eeccfa30a327d2ee6434db3beb8fd6fd92f41898bc4" -"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" -"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" +"checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" +"checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" -"checksum flate2 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "2adaffba6388640136149e18ed080b77a78611c1e1d6de75aedcdf78df5d4682" +"checksum flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ad3c5233c9a940c8719031b423d7e6c16af66e031cb0420b0896f5245bf181d3" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" @@ -2082,16 +2095,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" "checksum getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8d1dffef07351aafe6ef177e4dd2b8dcf503e6bc765dea3b0de9ed149a3db1ec" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" -"checksum goblin 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "7f55d53401eb2fd30afd025c570b1946b6966344acf21b42e31286f3bf89e6a8" +"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" "checksum goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "e3fa261d919c1ae9d1e4533c4a2f99e10938603c4208d56c05bec7a872b661b0" -"checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +"checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120" "checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" "checksum human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bec6e801ef7367625bd94ad7e2965e6027189f3e9deef422388d993af2814a0" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" "checksum hwloc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2934f84993b8b4bcae9b6a4e5f0aca638462dda9c7b4f26a570241494f21e0f4" -"checksum indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a61202fbe46c4a951e9404a720a0180bcf3212c750d735cb5c4ba4dc551299f3" -"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" +"checksum indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d7b3ea5827fcb9d4fda14bf4da5f136f0db2ae9c8f4bd4e2d1c6fde4e6db2" +"checksum itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "87fa75c9dea7b07be3138c49abbb83fd4bea199b5cdc76f9804458edc5da0d6e" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" @@ -2099,32 +2112,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" -"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" +"checksum memoffset 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a85c1a8c329f11437034d7313dca647c79096523533a1c79e86f1d0f657c7cc" "checksum minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "185d3531e38475163c1652a0915ac612be3f2655756af43f10789d6145f527c2" -"checksum miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9e3ae51cea1576ceba0dde3d484d30e6e5b86dee0b2d412fe3a16a15c98202" -"checksum miniz_oxide 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7108aff85b876d06f22503dcce091e29f76733b2bfdd91eebce81f5e68203a10" +"checksum miniz_oxide 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6f3f74f726ae935c3f514300cc6773a0c9492abc5e972d42ba0c0ebb88757625" "checksum nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4dbdc256eaac2e3bd236d93ad999d3479ef775c863dbda3068c4006a92eec51b" -"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" +"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" "checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" -"checksum num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2" +"checksum num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c8b15b261814f992e33760b1fca9fe8b693d8a65299f20c9901688636cfb746" "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" "checksum num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e" "checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" -"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" -"checksum object 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df4af347f5ac3d0e83e78c26be33cd10e8e874dcb68517a909ad802ba50a90b5" +"checksum num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "155394f924cdddf08149da25bfb932d226b4a593ca7468b08191ff6335941af5" +"checksum object 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a411a7fd46b7ebc9849c80513c84280f41cbc3159f489cd77fb30ecefdd1218a" "checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" -"checksum parity-wasm 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)" = "20d7e522a7f994cc4ae32970b1ce0d99ecf91b8e1df080517a26faa6d2e2ee62" +"checksum parity-wasm 0.40.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1e39faaa292a687ea15120b1ac31899b13586446521df6c149e46f1584671e0f" "checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" "checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" "checksum pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "72d5370d90f49f70bd033c3d75e87fc529fbfff9d6f7cccef07d6170079d91ea" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" +"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" "checksum precision 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "83f0b3de90e9edd6382604f4f28509ce25272deb065b94045fc47abcde567d55" "checksum printtable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "69967dae4cac71681361899d9905d3d2985fc989d7afb32a8dff3aed5461ecdf" +"checksum proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aeccfe4d5d8ea175d5f0e4a2ad0637e0f4121d63bd99d356fb1f39ab2e7c6097" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afdc77cc74ec70ed262262942ebb7dac3d479e9e5cfa2da1841c0806f6cdabcc" +"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" "checksum progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b820305721858696053a7fd0215cfeeee16ecaaf96b7a209945428e02f1c44" "checksum proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf147e022eacf0c8a054ab864914a7602618adba841d800a9a9868a5237a529f" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" @@ -2143,10 +2156,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" "checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +"checksum rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a788ae3edb696cfcba1c19bfd388cc4b8c21f8a408432b199c072825084da58a" "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -"checksum rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03b418169fb9c46533f326efd6eed2576699c44ca92d3052a066214a8d828929" -"checksum raw-cpuid 7.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4a349ca83373cfa5d6dbb66fd76e58b2cca08da71a5f6400de0a0a6a9bceeaf" +"checksum rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e18c91676f670f6f0312764c759405f13afb98d5d73819840cf72a518487bff" +"checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d" "checksum rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83a27732a533a1be0a0035a111fe76db89ad312f6f0347004c220c57f209a123" "checksum rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" @@ -2158,31 +2172,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2089e4031214d129e201f8c3c8c2fe97cd7322478a0d1cdf78e7029b0042efdb" "checksum rpassword 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34fa7bcae7fca3c8471e8417088bbc3ad9af8066b0ecf4f3c0d98a0d772716e" "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" +"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rusty-fork 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd93264e10c577503e926bd1430193eeb5d21b059148910082245309b424fae" -"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" +"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" "checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" -"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" "checksum scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f84d114ef17fd144153d608fba7c446b0145d038985e7a8cc5d08bb0ce20383" "checksum scroll_derive 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1aa96c45e7f5a91cb7fabe7b279f02fea7126239fc40b732316e8b6a2d0fcb" "checksum scrypt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "656c79d0e90d0ab28ac86bf3c3d10bfbbac91450d3f190113b4e76d9fec3cfdd" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" -"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e" -"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" +"checksum serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4b39bd9b0b087684013a792c59e3e07a46a01d2322518d8a1104641a0b1be0" +"checksum serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "ca13fc1a832f793322228923fbb3aba9f3f44444898f835d31ad1b74fa0a2bf8" +"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" +"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" "checksum siphasher 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "83da420ee8d1a89e640d0948c646c1c088758d3a3c538f943bfa97bdac17929d" -"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" +"checksum smallvec 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "533e29e15d0748f28afbaf4ff7cab44d73e483a8e50b38c40bd13b7f3d48f542" "checksum string-interner 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd710eadff449a1531351b0e43eb81ea404336fa2f56c777427ab0e32a4cf183" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" -"checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" +"checksum structopt 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4f66a4c0ddf7aee4677995697366de0749b0139057342eccbb609b12d0affc" +"checksum structopt-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8fe0c13e476b4e21ff7f5c4ace3818b6d7bdc16897c31c73862471bc1663acae" "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" -"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" +"checksum syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7bedb3320d0f3035594b0b723c8a28d7d336a3eda3881db79e61d676fb644c" +"checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203" "checksum target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7975cb2c6f37d77b190bc5004a2bb015971464756fde9514651a525ada2a741a" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" @@ -2190,9 +2205,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4574b75faccaacddb9b284faecdf0b544b80b6b294f3d062d325c5726a209c20" -"checksum toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c7aabe75941d914b72bf3e5d3932ed92ce0664d49d8432305a8b547c37227724" +"checksum toml 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c04dffffeac90885436d23c692517bb5b8b3f8863e4afc15023628d067d667b7" "checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" -"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9" +"checksum unicode-segmentation 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49f5526225fd8b77342d5986ab5f6055552e9c0776193b5b63fd53b46debfad7" "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" @@ -2205,7 +2220,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" "checksum wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5083b449454f7de0b15f131eee17de54b5a71dcb9adcf11df2b2f78fad0cd82" -"checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" +"checksum which 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "240a31163872f7e8e49f35b42b58485e35355b07eb009d9f3686733541339a69" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/benchmarks/lucet-benchmarks/Cargo.toml b/benchmarks/lucet-benchmarks/Cargo.toml index 8bee031f3..c73c9aeb7 100644 --- a/benchmarks/lucet-benchmarks/Cargo.toml +++ b/benchmarks/lucet-benchmarks/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-benchmarks" -version = "0.4.0" +version = "0.4.1" description = "Benchmarks for the Lucet runtime" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -10,7 +10,7 @@ authors = ["Lucet team "] edition = "2018" [dependencies] -criterion = "0.2" +criterion = "0.3.0" lucetc = { path = "../../lucetc" } lucet-module = { path = "../../lucet-module" } lucet-runtime = { path = "../../lucet-runtime" } diff --git a/cranelift b/cranelift index 91a90e4cb..3217e4e32 160000 --- a/cranelift +++ b/cranelift @@ -1 +1 @@ -Subproject commit 91a90e4cb649a94187b22b94c8020913e8d3137e +Subproject commit 3217e4e3253bd15a93f1a191345c5e3a0dab31de diff --git a/lucet-builtins/wasmonkey/Cargo.toml b/lucet-builtins/wasmonkey/Cargo.toml index 1513f9496..0c18dd000 100644 --- a/lucet-builtins/wasmonkey/Cargo.toml +++ b/lucet-builtins/wasmonkey/Cargo.toml @@ -14,7 +14,7 @@ clap = "2.33" failure = "0.1" goblin = "0.0.24" lazy_static = "1.3" -parity-wasm = "0.38" +parity-wasm = "0.40.3" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" diff --git a/lucet-module/Cargo.toml b/lucet-module/Cargo.toml index 54bac1c20..e82095b7b 100644 --- a/lucet-module/Cargo.toml +++ b/lucet-module/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-module" -version = "0.4.0" +version = "0.4.1" description = "A structured interface for Lucet modules" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -15,9 +15,9 @@ failure = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" bincode = "1.1.4" -num-derive = "0.2" -num-traits = "0.2" +num-derive = "0.3.0" +num-traits = "0.2.8" minisign = "0.5.11" -object = "0.12" +object = "0.14.0" byteorder = "1.3" memoffset = "0.5.1" diff --git a/lucet-objdump/Cargo.toml b/lucet-objdump/Cargo.toml index b5327d533..d5dab36aa 100644 --- a/lucet-objdump/Cargo.toml +++ b/lucet-objdump/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-objdump" -version = "0.4.0" +version = "0.4.1" description = "Analyze object files emitted by the Lucet compiler" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -12,8 +12,8 @@ edition = "2018" [dependencies] goblin="0.0.24" byteorder="1.2.1" -colored="1.6.1" -lucet-module = { path = "../lucet-module", version = "0.4.0" } +colored="1.8.0" +lucet-module = { path = "../lucet-module", version = "0.4.1" } [package.metadata.deb] name = "fst-lucet-objdump" diff --git a/lucet-runtime/Cargo.toml b/lucet-runtime/Cargo.toml index 45fe5f1af..377349a45 100644 --- a/lucet-runtime/Cargo.toml +++ b/lucet-runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime" -version = "0.4.0" +version = "0.4.1" description = "Pure Rust runtime for Lucet WebAssembly toolchain" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -11,18 +11,18 @@ edition = "2018" [dependencies] libc = "=0.2.59" -lucet-runtime-internals = { path = "lucet-runtime-internals", version = "0.4.0" } -lucet-module = { path = "../lucet-module", version = "0.4.0" } +lucet-runtime-internals = { path = "lucet-runtime-internals", version = "0.4.1" } +lucet-module = { path = "../lucet-module", version = "0.4.1" } num-traits = "0.2" -num-derive = "0.2" +num-derive = "0.3.0" [dev-dependencies] byteorder = "1.2" failure = "0.1" lazy_static = "1.1" -lucetc = { path = "../lucetc", version = "0.4.0" } -lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.4.0" } -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.0" } +lucetc = { path = "../lucetc", version = "0.4.1" } +lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.4.1" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.1" } nix = "0.13" rayon = "1.0" tempfile = "3.0" diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index f1fcdc968..24f6f4374 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime-internals" -version = "0.4.0" +version = "0.4.1" description = "Pure Rust runtime for Lucet WebAssembly toolchain (internals)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -10,7 +10,7 @@ authors = ["Lucet team "] edition = "2018" [dependencies] -lucet-module = { path = "../../lucet-module", version = "0.4.0" } +lucet-module = { path = "../../lucet-module", version = "0.4.1" } bitflags = "1.0" bincode = "1.1.4" @@ -21,10 +21,10 @@ libc = "=0.2.59" libloading = "0.5" memoffset = "0.5.1" nix = "0.13" -num-derive = "0.2" +num-derive = "0.3.0" num-traits = "0.2" xfailure = "0.1" -raw-cpuid = "7.0.3" +raw-cpuid = "6.0.0" # This is only a dependency to ensure that other crates don't pick a newer version as a transitive # dependency. `0.1.3 < getrandom <= 0.1.6` cause `lazy_static` to pull in spinlock implementations diff --git a/lucet-runtime/lucet-runtime-tests/Cargo.toml b/lucet-runtime/lucet-runtime-tests/Cargo.toml index 4a599cef0..c0236096c 100644 --- a/lucet-runtime/lucet-runtime-tests/Cargo.toml +++ b/lucet-runtime/lucet-runtime-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime-tests" -version = "0.4.0" +version = "0.4.1" description = "Pure Rust runtime for Lucet WebAssembly toolchain (tests)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -18,10 +18,10 @@ test = false failure = "0.1" lazy_static = "1.1" tempfile = "3.0" -lucet-module = { path = "../../lucet-module", version = "0.4.0" } -lucet-runtime-internals = { path = "../lucet-runtime-internals", version = "0.4.0" } -lucet-wasi-sdk = { path = "../../lucet-wasi-sdk", version = "0.4.0" } -lucetc = { path = "../../lucetc", version = "0.4.0" } +lucet-module = { path = "../../lucet-module", version = "0.4.1" } +lucet-runtime-internals = { path = "../lucet-runtime-internals", version = "0.4.1" } +lucet-wasi-sdk = { path = "../../lucet-wasi-sdk", version = "0.4.1" } +lucetc = { path = "../../lucetc", version = "0.4.1" } [build-dependencies] cc = "1.0" diff --git a/lucet-spectest/Cargo.toml b/lucet-spectest/Cargo.toml index 4948d6b1c..7f8df4160 100644 --- a/lucet-spectest/Cargo.toml +++ b/lucet-spectest/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-spectest" -version = "0.4.0" +version = "0.4.1" description = "Test harness to run WebAssembly spec tests (.wast) against the Lucet toolchain" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -17,9 +17,9 @@ name = "spec-test" path = "src/main.rs" [dependencies] -lucetc = { path = "../lucetc", version = "0.4.0" } -lucet-module = { path = "../lucet-module", version = "0.4.0" } -lucet-runtime = { path = "../lucet-runtime", version = "0.4.0" } +lucetc = { path = "../lucetc", version = "0.4.1" } +lucet-module = { path = "../lucet-module", version = "0.4.1" } +lucet-runtime = { path = "../lucet-runtime", version = "0.4.1" } wabt = "0.9.2" serde = "1.0" serde_json = "1.0" diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index 5900a6fb4..430378d83 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-validate" -version = "0.4.0" +version = "0.4.1" description = "Parse and validate webassembly files against witx interface" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -24,7 +24,7 @@ cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.46.1" wasmparser = "0.39.1" [dev-dependencies] -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.0" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.1" } tempfile = "3.0" wabt = "0.9.2" diff --git a/lucet-wasi-fuzz/Cargo.toml b/lucet-wasi-fuzz/Cargo.toml index 971c7a2aa..6c8d280cd 100644 --- a/lucet-wasi-fuzz/Cargo.toml +++ b/lucet-wasi-fuzz/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi-fuzz" -version = "0.4.0" +version = "0.4.1" description = "Test the Lucet toolchain against native code execution using Csmith" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -24,6 +24,6 @@ progress = "0.2" rand = "0.6" regex = "1.1" rayon = "1.0" -structopt = "0.2" +structopt = "0.3.3" tempfile = "3.0" wait-timeout = "0.2" diff --git a/lucet-wasi-sdk/Cargo.toml b/lucet-wasi-sdk/Cargo.toml index c85e4b557..f73d9895e 100644 --- a/lucet-wasi-sdk/Cargo.toml +++ b/lucet-wasi-sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi-sdk" -version = "0.4.0" +version = "0.4.1" description = "A Rust interface to the wasi-sdk compiler and linker" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -11,9 +11,9 @@ edition = "2018" [dependencies] failure = "0.1" -lucetc = { path = "../lucetc", version = "0.4.0" } -lucet-module = { path = "../lucet-module", version = "0.4.0" } +lucetc = { path = "../lucetc", version = "0.4.1" } +lucet-module = { path = "../lucet-module", version = "0.4.1" } tempfile = "3.0" [dev-dependencies] -lucet-validate = { path = "../lucet-validate", version = "0.4.0" } +lucet-validate = { path = "../lucet-validate", version = "0.4.1" } diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index de9e631fc..7021cd0e1 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi" -version = "0.4.0" +version = "0.4.1" description = "Fastly's runtime for the WebAssembly System Interface (WASI)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -29,20 +29,19 @@ clap = "2.23" failure = "0.1" human-size = "0.4" libc = "=0.2.59" -lucet-runtime = { path = "../lucet-runtime", version = "0.4.0" } -lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.4.0" } -lucet-module = { path = "../lucet-module", version = "0.4.0" } +lucet-runtime = { path = "../lucet-runtime", version = "0.4.1" } +lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.4.1" } +lucet-module = { path = "../lucet-module", version = "0.4.1" } nix = "0.13" rand = "0.6" [dev-dependencies] -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.0" } -lucetc = { path = "../lucetc", version = "0.4.0" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.1" } +lucetc = { path = "../lucetc", version = "0.4.1" } tempfile = "3.0" -[build-dependencies.bindgen] -version = "0.47" -optional = true +[build-dependencies] +bindgen = { version = "0.51.1", optional = true } [lib] name = "lucet_wasi" diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index cf92dab72..bb0e73db9 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucetc" -version = "0.4.0" +version = "0.4.1" description = "Fastly's WebAssembly to native code compiler" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -23,8 +23,8 @@ cranelift-module = { path = "../cranelift/cranelift-module", version = "0.46.1" cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.46.1" } cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.46.1" } target-lexicon = "0.8.0" -lucet-module = { path = "../lucet-module", version = "0.4.0" } -lucet-validate = { path = "../lucet-validate", version = "0.4.0" } +lucet-module = { path = "../lucet-module", version = "0.4.1" } +lucet-validate = { path = "../lucet-validate", version = "0.4.1" } wasmparser = "0.39.1" clap="2.32" log = "0.4" @@ -38,12 +38,12 @@ wabt = "0.9.2" tempfile = "3.0" bimap = "0.2" human-size = "0.4" -parity-wasm = "0.38" +parity-wasm = "0.40.3" minisign = "0.5.11" memoffset = "0.5.1" serde = "1.0" serde_json = "1.0" -raw-cpuid = "7.0.3" +raw-cpuid = "6.0.0" [package.metadata.deb] name = "fst-lucetc" From ed1bb39edd95a5e3ed461fa0d7cb5b07143b4fa0 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Thu, 31 Oct 2019 17:46:33 -0700 Subject: [PATCH 463/512] use crates.io version of wasmonkey, and fix parity-wasm version --- Cargo.lock | 16 +- lucet-builtins/wasmonkey/.gitignore | 2 - lucet-builtins/wasmonkey/.travis.yml | 4 - lucet-builtins/wasmonkey/Cargo.toml | 22 -- lucet-builtins/wasmonkey/README.md | 35 --- .../wasmonkey/src/bin/config/mod.rs | 96 -------- lucet-builtins/wasmonkey/src/bin/wasmonkey.rs | 14 -- lucet-builtins/wasmonkey/src/errors.rs | 31 --- lucet-builtins/wasmonkey/src/functions_ids.rs | 104 -------- .../wasmonkey/src/functions_names.rs | 15 -- lucet-builtins/wasmonkey/src/lib.rs | 27 --- lucet-builtins/wasmonkey/src/map.rs | 63 ----- lucet-builtins/wasmonkey/src/patcher.rs | 225 ------------------ lucet-builtins/wasmonkey/src/sections.rs | 8 - lucet-builtins/wasmonkey/src/symbols.rs | 133 ----------- lucet-builtins/wasmonkey/src/tests/mod.rs | 46 ---- .../wasmonkey/src/tests/test_1.wasm | Bin 2372 -> 0 bytes lucetc/Cargo.toml | 6 +- 18 files changed, 16 insertions(+), 831 deletions(-) delete mode 100644 lucet-builtins/wasmonkey/.gitignore delete mode 100644 lucet-builtins/wasmonkey/.travis.yml delete mode 100644 lucet-builtins/wasmonkey/Cargo.toml delete mode 100644 lucet-builtins/wasmonkey/README.md delete mode 100644 lucet-builtins/wasmonkey/src/bin/config/mod.rs delete mode 100644 lucet-builtins/wasmonkey/src/bin/wasmonkey.rs delete mode 100644 lucet-builtins/wasmonkey/src/errors.rs delete mode 100644 lucet-builtins/wasmonkey/src/functions_ids.rs delete mode 100644 lucet-builtins/wasmonkey/src/functions_names.rs delete mode 100644 lucet-builtins/wasmonkey/src/lib.rs delete mode 100644 lucet-builtins/wasmonkey/src/map.rs delete mode 100644 lucet-builtins/wasmonkey/src/patcher.rs delete mode 100644 lucet-builtins/wasmonkey/src/sections.rs delete mode 100644 lucet-builtins/wasmonkey/src/symbols.rs delete mode 100644 lucet-builtins/wasmonkey/src/tests/mod.rs delete mode 100644 lucet-builtins/wasmonkey/src/tests/test_1.wasm diff --git a/Cargo.lock b/Cargo.lock index 294f5f430..020ce3628 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1006,14 +1006,14 @@ dependencies = [ "lucet-validate 0.4.1", "memoffset 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-wasm 0.40.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wasm 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmonkey 0.1.8", + "wasmonkey 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1165,6 +1165,11 @@ name = "parity-wasm" version = "0.40.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "parity-wasm" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "pbkdf2" version = "0.3.0" @@ -1935,13 +1940,14 @@ dependencies = [ [[package]] name = "wasmonkey" -version = "0.1.8" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-wasm 0.40.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wasm 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2128,6 +2134,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum object 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a411a7fd46b7ebc9849c80513c84280f41cbc3159f489cd77fb30ecefdd1218a" "checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" "checksum parity-wasm 0.40.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1e39faaa292a687ea15120b1ac31899b13586446521df6c149e46f1584671e0f" +"checksum parity-wasm 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc878dac00da22f8f61e7af3157988424567ab01d9920b962ef7dcbd7cd865" "checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" "checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" "checksum pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "72d5370d90f49f70bd033c3d75e87fc529fbfff9d6f7cccef07d6170079d91ea" @@ -2219,6 +2226,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af5d153dc96aad7dc13ab90835b892c69867948112d95299e522d370c4e13a08" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" +"checksum wasmonkey 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "af7c4bc80224427965ba21d87982cfc07d12e859824f303272056fb19f571ef9" "checksum wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5083b449454f7de0b15f131eee17de54b5a71dcb9adcf11df2b2f78fad0cd82" "checksum which 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "240a31163872f7e8e49f35b42b58485e35355b07eb009d9f3686733541339a69" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" diff --git a/lucet-builtins/wasmonkey/.gitignore b/lucet-builtins/wasmonkey/.gitignore deleted file mode 100644 index 53eaa2196..000000000 --- a/lucet-builtins/wasmonkey/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -**/*.rs.bk diff --git a/lucet-builtins/wasmonkey/.travis.yml b/lucet-builtins/wasmonkey/.travis.yml deleted file mode 100644 index 32905a519..000000000 --- a/lucet-builtins/wasmonkey/.travis.yml +++ /dev/null @@ -1,4 +0,0 @@ -language: rust -rust: - - nightly - - stable diff --git a/lucet-builtins/wasmonkey/Cargo.toml b/lucet-builtins/wasmonkey/Cargo.toml deleted file mode 100644 index 0c18dd000..000000000 --- a/lucet-builtins/wasmonkey/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "wasmonkey" -version = "0.1.8" -authors = ["Lucet team "] -description = "Patch a WASM object file to replace a set of exported functions with imported functions from another library" -license = "Apache-2.0 WITH LLVM-exception" -homepage = "https://github.com/fastly/lucet" -repository = "https://github.com/fastly/lucet" -categories = ["wasm"] -edition = "2018" - -[dependencies] -clap = "2.33" -failure = "0.1" -goblin = "0.0.24" -lazy_static = "1.3" -parity-wasm = "0.40.3" -serde = "1.0" -serde_derive = "1.0" -serde_json = "1.0" -siphasher = "0.3" -xfailure = "0.1" diff --git a/lucet-builtins/wasmonkey/README.md b/lucet-builtins/wasmonkey/README.md deleted file mode 100644 index ae588b3d9..000000000 --- a/lucet-builtins/wasmonkey/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# WASMonkey - -The WASMonkey patches a WASM object file to replace a set of exported -functions with imported functions from another library. - -## Usage - -```text -USAGE: - wasmonkey [FLAGS] [OPTIONS] --input --output - -FLAGS: - -n, --original-names Use the original name as a key in the builtins map - -h, --help Prints help information - -V, --version Prints version information - -OPTIONS: - -B, --builtins-additional ... Additional builtins function names to replace - -b, --builtins Path to the builtins library - -m, --builtins-map Path to the builtins map file - -i, --input Path to the input file - -o, --output Path to the output file -``` - -`builtins_file` is an object containing alternative implementations to -functions called in the wasm code. - -Symbols starting with a `builtin_` prefix will be used for substitution. - -For example, a `memmove()` function defined as an external in the WASM -object will be replaced by calls to an imported `builtin_memmove()` -function, if `builtin_memmove()` is present in the builtins file. - -A JSON-encoded map of the performed substitutions can be optionally written -into `builtins_map_file`. diff --git a/lucet-builtins/wasmonkey/src/bin/config/mod.rs b/lucet-builtins/wasmonkey/src/bin/config/mod.rs deleted file mode 100644 index ccd29b985..000000000 --- a/lucet-builtins/wasmonkey/src/bin/config/mod.rs +++ /dev/null @@ -1,96 +0,0 @@ -use crate::{PatcherConfig, WError}; -use clap::Arg; -use std::path::PathBuf; - -#[derive(Default, Clone, Debug)] -pub struct Config { - pub input_path: PathBuf, - pub output_path: PathBuf, - pub patcher_config: PatcherConfig, -} - -impl Config { - pub fn parse_cmdline() -> Result { - let _ = include_str!("../../../Cargo.toml"); - let matches = app_from_crate!() - .arg( - Arg::with_name("input_file") - .short("i") - .long("input") - .takes_value(true) - .required(true) - .help("Path to the input file"), - ) - .arg( - Arg::with_name("output_file") - .short("o") - .long("output") - .takes_value(true) - .required(true) - .help("Path to the output file"), - ) - .arg( - Arg::with_name("builtins_file") - .short("b") - .long("builtins") - .takes_value(true) - .required(false) - .help("Path to the builtins library"), - ) - .arg( - Arg::with_name("builtins_additional") - .short("B") - .long("builtins-additional") - .takes_value(true) - .required(false) - .multiple(true) - .help("Additional builtins function names to replace"), - ) - .arg( - Arg::with_name("builtins_map_file") - .short("m") - .long("builtins-map") - .takes_value(true) - .required(false) - .help("Path to the builtins map file"), - ) - .arg( - Arg::with_name("builtins_map_original_names") - .short("n") - .long("original-names") - .takes_value(false) - .required(false) - .help("Use the original name as a key in the builtins map"), - ) - .get_matches(); - let input_path = PathBuf::from( - matches - .value_of("input_file") - .ok_or(WError::UsageError("Input file required"))?, - ); - let output_path = PathBuf::from( - matches - .value_of("output_file") - .ok_or(WError::UsageError("Output file required"))?, - ); - let builtins_path = matches.value_of("builtins_file").map(PathBuf::from); - let builtins_map_path = matches.value_of("builtins_map_file").map(PathBuf::from); - let builtins_map_original_names = matches.is_present("builtins_map_original_names"); - let builtins_additional = matches - .values_of("builtins_additional") - .unwrap_or_default() - .map(|name| name.to_string()) - .collect(); - let config = Config { - input_path, - output_path, - patcher_config: PatcherConfig { - builtins_path, - builtins_map_path, - builtins_map_original_names, - builtins_additional, - }, - }; - Ok(config) - } -} diff --git a/lucet-builtins/wasmonkey/src/bin/wasmonkey.rs b/lucet-builtins/wasmonkey/src/bin/wasmonkey.rs deleted file mode 100644 index 5ed604369..000000000 --- a/lucet-builtins/wasmonkey/src/bin/wasmonkey.rs +++ /dev/null @@ -1,14 +0,0 @@ -mod config; - -#[macro_use] -extern crate clap; - -use crate::config::*; -use wasmonkey::*; - -fn main() -> Result<(), WError> { - let config = Config::parse_cmdline()?; - let patcher = Patcher::from_file(config.patcher_config, config.input_path)?; - patcher.store_to_file(config.output_path)?; - Ok(()) -} diff --git a/lucet-builtins/wasmonkey/src/errors.rs b/lucet-builtins/wasmonkey/src/errors.rs deleted file mode 100644 index 70e0998f8..000000000 --- a/lucet-builtins/wasmonkey/src/errors.rs +++ /dev/null @@ -1,31 +0,0 @@ -use parity_wasm::elements; -use std::io; - -#[allow(dead_code)] -#[derive(Debug, Fail)] -pub enum WError { - #[fail(display = "Internal error: {}", _0)] - InternalError(&'static str), - #[fail(display = "Incorrect usage: {}", _0)] - UsageError(&'static str), - #[fail(display = "{}", _0)] - Io(#[cause] io::Error), - #[fail(display = "{}", _0)] - WAsmError(#[cause] elements::Error), - #[fail(display = "Parse error")] - ParseError, - #[fail(display = "Unsupported")] - Unsupported, -} - -impl From for WError { - fn from(e: io::Error) -> WError { - WError::Io(e) - } -} - -impl From for WError { - fn from(e: elements::Error) -> WError { - WError::WAsmError(e) - } -} diff --git a/lucet-builtins/wasmonkey/src/functions_ids.rs b/lucet-builtins/wasmonkey/src/functions_ids.rs deleted file mode 100644 index 64850d85a..000000000 --- a/lucet-builtins/wasmonkey/src/functions_ids.rs +++ /dev/null @@ -1,104 +0,0 @@ -use crate::errors::*; -use parity_wasm::elements::{ - CodeSection, ElementSection, ExportSection, FuncBody, Instruction, Instructions, Internal, - Module, -}; - -fn shift_function_ids_in_code_section( - code_section: &mut CodeSection, - shift: u32, -) -> Result<(), WError> { - let code_bodies = code_section.bodies_mut(); - for code_body in code_bodies.iter_mut() { - let opcodes = code_body.code_mut().elements_mut(); - for opcode in opcodes.iter_mut() { - if let Instruction::Call(function_id) = *opcode { - *opcode = Instruction::Call(function_id + shift) - } - } - } - Ok(()) -} - -fn shift_function_ids_in_exports_section(export_section: &mut ExportSection, shift: u32) { - for entry in export_section.entries_mut() { - let internal = entry.internal_mut(); - if let Internal::Function(function_id) = *internal { - *internal = Internal::Function(function_id + shift) - } - } -} - -fn shift_function_ids_in_elements_section(elements_section: &mut ElementSection, shift: u32) { - for elements_segment in elements_section.entries_mut() { - for function_id in elements_segment.members_mut() { - *function_id += shift; - } - } -} - -pub fn shift_function_ids(module: &mut Module, shift: u32) -> Result<(), WError> { - shift_function_ids_in_code_section(module.code_section_mut().expect("No code section"), shift)?; - if let Some(export_section) = module.export_section_mut() { - shift_function_ids_in_exports_section(export_section, shift) - } - if let Some(elements_section) = module.elements_section_mut() { - shift_function_ids_in_elements_section(elements_section, shift) - } - Ok(()) -} - -fn replace_function_id_in_code_section(code_section: &mut CodeSection, before: u32, after: u32) { - let code_bodies = code_section.bodies_mut(); - for code_body in code_bodies.iter_mut() { - let opcodes = code_body.code_mut().elements_mut(); - for opcode in opcodes.iter_mut() { - match *opcode { - Instruction::Call(function_id) if function_id == before => { - *opcode = Instruction::Call(after) - } - _ => {} - } - } - } -} - -fn replace_function_id_in_elements_section( - elements_section: &mut ElementSection, - before: u32, - after: u32, -) { - for elements_segment in elements_section.entries_mut() { - for function_id in elements_segment.members_mut() { - if *function_id == before { - *function_id = after; - } - } - } -} - -pub fn replace_function_id(module: &mut Module, before: u32, after: u32) -> Result<(), WError> { - if let Some(code_section) = module.code_section_mut() { - replace_function_id_in_code_section(code_section, before, after) - } - - if let Some(elements_section) = module.elements_section_mut() { - replace_function_id_in_elements_section(elements_section, before, after) - }; - - Ok(()) -} - -#[allow(dead_code)] -pub fn disable_function_id(module: &mut Module, function_id: u32) -> Result<(), WError> { - let base_id = match module.import_section() { - None => 0, - Some(import_section) => import_section.entries().len() as u32, - }; - let code_section = module.code_section_mut().expect("No code section"); - let code_bodies = code_section.bodies_mut(); - let opcodes = Instructions::new(vec![Instruction::Unreachable, Instruction::End]); - let func_body = FuncBody::new(vec![], opcodes); - code_bodies[(function_id - base_id) as usize] = func_body; - Ok(()) -} diff --git a/lucet-builtins/wasmonkey/src/functions_names.rs b/lucet-builtins/wasmonkey/src/functions_names.rs deleted file mode 100644 index 25ba00b9c..000000000 --- a/lucet-builtins/wasmonkey/src/functions_names.rs +++ /dev/null @@ -1,15 +0,0 @@ -use crate::errors::*; -use parity_wasm::elements::{FunctionNameSubsection, IndexMap}; - -pub fn prepend_function_name( - function_names_subsection: &mut FunctionNameSubsection, - name: String, -) -> Result<(), WError> { - let mut map_new = IndexMap::with_capacity(function_names_subsection.names().len() + 1 as usize); - for (idx, name) in function_names_subsection.names() { - map_new.insert(idx + 1, name.clone()); - } - map_new.insert(0, name); - *function_names_subsection.names_mut() = map_new; - Ok(()) -} diff --git a/lucet-builtins/wasmonkey/src/lib.rs b/lucet-builtins/wasmonkey/src/lib.rs deleted file mode 100644 index fa3966bc7..000000000 --- a/lucet-builtins/wasmonkey/src/lib.rs +++ /dev/null @@ -1,27 +0,0 @@ -#[macro_use] -extern crate failure; - -#[cfg_attr(test, macro_use)] -extern crate lazy_static; - -#[macro_use] -extern crate serde_derive; - -#[cfg(test)] -extern crate siphasher; -#[macro_use] -extern crate xfailure; - -mod errors; -mod functions_ids; -mod functions_names; -mod map; -mod patcher; -mod sections; -mod symbols; - -#[cfg(test)] -mod tests; - -pub use crate::errors::*; -pub use crate::patcher::*; diff --git a/lucet-builtins/wasmonkey/src/map.rs b/lucet-builtins/wasmonkey/src/map.rs deleted file mode 100644 index ae50353ff..000000000 --- a/lucet-builtins/wasmonkey/src/map.rs +++ /dev/null @@ -1,63 +0,0 @@ -use crate::errors::*; -use serde_json; -use std::collections::HashMap; -use std::fs::File; -use std::io::prelude::*; -use std::path::Path; - -#[derive(Clone, Debug, Default, Serialize)] -pub struct PatchedBuiltinsMap { - pub env: HashMap, -} - -impl PatchedBuiltinsMap { - pub fn with_capacity(capacity: usize) -> Self { - PatchedBuiltinsMap { - env: HashMap::with_capacity(capacity), - } - } - - pub fn insert(&mut self, name: String, imported_name: String) -> Option { - self.env.insert(name, imported_name) - } - - pub fn write_to_file>( - &self, - builtins_map_path: P, - original_names: bool, - ) -> Result<(), WError> { - let mut map_with_original_names; - let map = if original_names { - self - } else { - map_with_original_names = PatchedBuiltinsMap::default(); - for imported_name in self.env.values() { - map_with_original_names - .env - .insert(imported_name.clone(), imported_name.clone()); - } - &map_with_original_names - }; - let json = serde_json::to_string_pretty(map).map_err(|_| WError::ParseError)?; - File::create(builtins_map_path)?.write_all(json.as_bytes())?; - Ok(()) - } - - pub fn builtins_map( - &self, - module: &str, - original_names: bool, - ) -> Result, WError> { - if module != "env" { - xbail!(WError::UsageError("Empty module")) - } - if original_names { - return Ok(self.env.clone()); - } - let mut env_map_with_original_names = HashMap::new(); - for imported_name in self.env.values() { - env_map_with_original_names.insert(imported_name.clone(), imported_name.clone()); - } - Ok(env_map_with_original_names) - } -} diff --git a/lucet-builtins/wasmonkey/src/patcher.rs b/lucet-builtins/wasmonkey/src/patcher.rs deleted file mode 100644 index 8e018060e..000000000 --- a/lucet-builtins/wasmonkey/src/patcher.rs +++ /dev/null @@ -1,225 +0,0 @@ -use crate::errors::*; -use crate::functions_ids::*; -use crate::functions_names::*; -use crate::map::*; -use crate::sections::*; -use crate::symbols::{self, ExtractedSymbols}; -use parity_wasm; -use parity_wasm::elements::{ - self, External, FunctionNameSubsection, ImportEntry, ImportSection, Internal, Module, - NameSection, Section, -}; -use std::collections::HashMap; -use std::path::{Path, PathBuf}; - -pub const BUILTIN_PREFIX: &str = "builtin_"; - -#[derive(Default, Clone, Debug)] -pub struct PatcherConfig { - pub builtins_path: Option, - pub builtins_map_path: Option, - pub builtins_map_original_names: bool, - pub builtins_additional: Vec, -} - -pub struct Patcher { - pub config: PatcherConfig, - patched_module: Module, - patched_builtins_map: PatchedBuiltinsMap, -} - -impl Patcher { - pub fn new(config: PatcherConfig, module: Module) -> Result { - let symbols = match &config.builtins_path { - None => ExtractedSymbols::from(vec![]), - Some(builtins_path) => symbols::extract_symbols(&builtins_path)?, - } - .merge_additional(&config.builtins_additional); - let builtins_names = symbols.builtins_names(); - let (patched_module, patched_builtins_map) = patch_module(module, &builtins_names)?; - let patcher = Patcher { - config, - patched_module, - patched_builtins_map, - }; - Ok(patcher) - } - - pub fn from_bytes(config: PatcherConfig, bytes: &[u8]) -> Result { - let module = parity_wasm::deserialize_buffer(bytes)?; - Self::new(config, module) - } - - pub fn from_file>(config: PatcherConfig, path_in: P) -> Result { - let module = parity_wasm::deserialize_file(path_in)?; - Self::new(config, module) - } - - pub fn into_bytes(self) -> Result, WError> { - let bytes = elements::serialize(self.patched_module)?; - Ok(bytes) - } - - pub fn store_to_file>(self, path_out: P) -> Result<(), WError> { - elements::serialize_to_file(path_out, self.patched_module)?; - if let Some(builtins_map_path) = self.config.builtins_map_path { - self.patched_builtins_map - .write_to_file(builtins_map_path, self.config.builtins_map_original_names)?; - } - Ok(()) - } - - pub fn patched_builtins_map(&self, module: &str) -> Result, WError> { - self.patched_builtins_map - .builtins_map(module, self.config.builtins_map_original_names) - } - - pub fn patched_module(self) -> Module { - self.patched_module - } -} - -#[derive(Debug)] -pub struct Builtin { - pub name: String, - pub original_function_id: Option, - pub function_type_id: Option, -} - -impl Builtin { - pub fn new(name: String) -> Self { - Builtin { - name, - original_function_id: None, - function_type_id: None, - } - } - - pub fn import_name(&self) -> String { - format!("{}{}", BUILTIN_PREFIX, self.name) - } -} - -fn function_type_id_for_function_id(module: &Module, function_id: u32) -> Option { - let offset = module - .import_section() - .map(|import_section| import_section.entries().len() as u32) - .unwrap_or(0); - if function_id < offset { - return None; - } - let functions_section_type_ids = module.function_section().unwrap().entries(); - Some(functions_section_type_ids[(function_id - offset) as usize].type_ref()) -} - -fn add_function_type_id_to_builtins( - module: &Module, - builtins: &mut Vec, -) -> Result<(), WError> { - for builtin in builtins.iter_mut() { - let function_type_id = - function_type_id_for_function_id(module, builtin.original_function_id.unwrap()) - .expect("Function ID not found"); - builtin.function_type_id = Some(function_type_id); - } - Ok(()) -} - -fn retain_only_used_builtins(module: &Module, builtins: &mut Vec) -> Result<(), WError> { - let export_section = module.export_section().expect("No export section"); - - for entry in export_section.entries() { - let internal = entry.internal(); - let function_id = match internal { - Internal::Function(function_id) => *function_id, - _ => continue, - }; - let field = entry.field(); - for builtin in builtins.iter_mut() { - if field == builtin.name { - assert!(builtin.original_function_id.is_none()); - builtin.original_function_id = Some(function_id); - break; - } - } - } - - builtins.retain(|builtin| builtin.original_function_id.is_some()); - Ok(()) -} - -fn add_import_section_if_missing(module: &mut Module) -> Result<(), WError> { - if module.import_section().is_some() { - return Ok(()); - } - let import_section = ImportSection::with_entries(vec![]); - let import_section_idx = find_type_section_idx(&module).unwrap() + 1; - module - .sections_mut() - .insert(import_section_idx, Section::Import(import_section)); - Ok(()) -} - -fn prepend_builtin_to_import_section(module: &mut Module, builtin: &Builtin) -> Result<(), WError> { - let import_name = builtin.import_name(); - let external = External::Function(builtin.function_type_id.unwrap()); - let import_entry = ImportEntry::new("env".to_string(), import_name, external); - module - .import_section_mut() - .unwrap() - .entries_mut() - .insert(0, import_entry); - Ok(()) -} - -fn prepend_builtin_to_names_section(module: &mut Module, builtin: &Builtin) -> Result<(), WError> { - let import_name = builtin.import_name(); - if module.names_section().is_none() { - let sections = module.sections_mut(); - let function_names_subsection = FunctionNameSubsection::default(); - let name_section = NameSection::new(None, Some(function_names_subsection), None); - sections.push(Section::Name(name_section)); - } - let names_section = module - .names_section_mut() - .expect("Names section not present"); - let function_names_subsection = match names_section.functions_mut() { - Some(function_names_subsection) => function_names_subsection, - _ => xbail!(WError::InternalError("Unexpected names section")), - }; - prepend_function_name(function_names_subsection, import_name)?; - Ok(()) -} - -fn patch_module( - module: Module, - builtins_names: &[&str], -) -> Result<(Module, PatchedBuiltinsMap), WError> { - let mut module = module - .parse_names() - .map_err(|_| WError::InternalError("Unable to parse names"))?; - - let mut builtins: Vec<_> = builtins_names - .iter() - .map(|x| Builtin::new(x.to_string())) - .collect(); - - retain_only_used_builtins(&module, &mut builtins)?; - add_function_type_id_to_builtins(&module, &mut builtins)?; - - add_import_section_if_missing(&mut module)?; - for (builtin_idx, builtin) in builtins.iter_mut().enumerate() { - prepend_builtin_to_import_section(&mut module, &builtin)?; - prepend_builtin_to_names_section(&mut module, &builtin)?; - shift_function_ids(&mut module, 1)?; - let original_function_id = builtin.original_function_id.unwrap() + builtin_idx as u32 + 1; - let new_function_id = 0; - replace_function_id(&mut module, original_function_id, new_function_id)?; - } - - let mut patched_builtins_map = PatchedBuiltinsMap::with_capacity(builtins.len()); - for builtin in builtins { - patched_builtins_map.insert(builtin.name.clone(), builtin.import_name()); - } - Ok((module, patched_builtins_map)) -} diff --git a/lucet-builtins/wasmonkey/src/sections.rs b/lucet-builtins/wasmonkey/src/sections.rs deleted file mode 100644 index 8d984463c..000000000 --- a/lucet-builtins/wasmonkey/src/sections.rs +++ /dev/null @@ -1,8 +0,0 @@ -use parity_wasm::elements::{Module, Section}; - -pub fn find_type_section_idx(module: &Module) -> Option { - module.sections().iter().position(|section| match section { - Section::Type(_) => true, - _ => false, - }) -} diff --git a/lucet-builtins/wasmonkey/src/symbols.rs b/lucet-builtins/wasmonkey/src/symbols.rs deleted file mode 100644 index 0ab7d4ce1..000000000 --- a/lucet-builtins/wasmonkey/src/symbols.rs +++ /dev/null @@ -1,133 +0,0 @@ -use crate::errors::*; -use crate::patcher::BUILTIN_PREFIX; -use goblin::elf::Elf; -use goblin::mach::{self, Mach, MachO}; -use goblin::Object; -use std::fs::File; -use std::io::Read; -use std::path::Path; - -#[derive(Clone, Debug, Default)] -pub struct ExtractedSymbol { - pub name: String, -} - -#[derive(Clone, Debug, Default)] -pub struct ExtractedSymbols { - pub symbols: Vec, -} - -impl From> for ExtractedSymbols { - fn from(symbols: Vec) -> Self { - ExtractedSymbols { symbols } - } -} - -impl ExtractedSymbols { - pub fn builtins_names(&self) -> Vec<&str> { - let builtins_names: Vec<&str> = self - .symbols - .iter() - .filter(|symbol| symbol.name.starts_with(BUILTIN_PREFIX)) - .map(|symbol| &symbol.name[BUILTIN_PREFIX.len()..]) - .collect(); - builtins_names - } - - pub fn merge_additional(mut self, additional_names: &[String]) -> Self { - let mut additional_symbols: Vec<_> = additional_names - .iter() - .map(|name| ExtractedSymbol { - name: name.to_string(), - }) - .collect(); - self.symbols.append(&mut additional_symbols); - self.symbols.dedup_by(|a, b| a.name == b.name); - self - } -} - -fn parse_elf(elf: &Elf<'_>) -> Result { - let mut symbols = vec![]; - - for symbol in elf - .dynsyms - .iter() - .filter(|symbol| symbol.st_info == 0x12 || symbol.st_info == 0x22) - { - let name = elf - .dynstrtab - .get(symbol.st_name) - .ok_or(WError::ParseError)? - .map_err(|_| WError::ParseError)? - .to_string(); - let extracted_symbol = ExtractedSymbol { name }; - symbols.push(extracted_symbol); - } - Ok(symbols.into()) -} - -fn parse_macho(macho: &MachO<'_>) -> Result { - let mut symbols = vec![]; - - // Start by finding the boundaries of the text section - let mut text_offset = None; - let mut text_size = None; - for section in macho.segments.sections() { - for segment in section { - if let Ok(( - mach::segment::Section { - sectname: [b'_', b'_', b't', b'e', b'x', b't', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - segname: [b'_', b'_', b'T', b'E', b'X', b'T', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - size, - offset, - .. - }, - _, - )) = segment - { - text_offset = Some(offset as usize); - text_size = Some(size as usize); - } - } - } - let text_offset = text_offset.ok_or(WError::ParseError)?; - let text_size = text_size.ok_or(WError::ParseError)?; - - // Extract the symbols we are interested in - for symbol in macho.symbols.as_ref().ok_or(WError::ParseError)?.iter() { - match symbol { - Ok(( - name, - mach::symbols::Nlist { - n_type: 0xf, - n_sect: 1, - n_value, - .. - }, - )) if name.len() > 1 && name.starts_with('_') => { - let extracted_symbol = ExtractedSymbol { - name: name[1..].to_string(), - }; - let offset = n_value as usize; - if offset < text_offset || offset >= text_offset + text_size { - continue; - } - symbols.push(extracted_symbol); - } - _ => {} - } - } - Ok(symbols.into()) -} - -pub fn extract_symbols>(path: P) -> Result { - let mut buffer = Vec::new(); - File::open(path)?.read_to_end(&mut buffer)?; - let symbols = match Object::parse(&buffer).map_err(|_| WError::ParseError)? { - Object::Mach(Mach::Binary(macho)) => parse_macho(&macho), - Object::Elf(elf) => parse_elf(&elf), - _ => xbail!(WError::Unsupported), - }?; - Ok(symbols) -} diff --git a/lucet-builtins/wasmonkey/src/tests/mod.rs b/lucet-builtins/wasmonkey/src/tests/mod.rs deleted file mode 100644 index 63ed2bae8..000000000 --- a/lucet-builtins/wasmonkey/src/tests/mod.rs +++ /dev/null @@ -1,46 +0,0 @@ -use super::*; -use siphasher::sip::SipHasher13; -use std::hash::Hasher; -use std::path::{Path, PathBuf}; - -lazy_static! { - static ref TESTS_DIR: PathBuf = Path::new(file!()).parent().unwrap().canonicalize().unwrap(); -} - -#[test] -fn patch_nothing() { - let path_in = TESTS_DIR.join("test_1.wasm"); - let config = PatcherConfig::default(); - let patcher = Patcher::from_file(config, path_in).unwrap(); - let mut hasher = SipHasher13::new(); - hasher.write(&patcher.into_bytes().unwrap()); - assert_eq!(hasher.finish(), 1401932366200566186); -} - -#[test] -fn patch_one() { - let path_in = TESTS_DIR.join("test_1.wasm"); - let mut config = PatcherConfig::default(); - config.builtins_additional = ["builtin_memmove", "builtin_nonexistent", "not_a_builtin"] - .into_iter() - .map(|s| s.to_string()) - .collect(); - let patcher = Patcher::from_file(config, path_in).unwrap(); - let mut hasher = SipHasher13::new(); - hasher.write(&patcher.into_bytes().unwrap()); - assert_eq!(hasher.finish(), 12884721342785729260); -} - -#[test] -fn patch_some() { - let path_in = TESTS_DIR.join("test_1.wasm"); - let mut config = PatcherConfig::default(); - config.builtins_additional = ["builtin_memmove", "builtin_memcpy", "builtin_strcmp"] - .into_iter() - .map(|s| s.to_string()) - .collect(); - let patcher = Patcher::from_file(config, path_in).unwrap(); - let mut hasher = SipHasher13::new(); - hasher.write(&patcher.into_bytes().unwrap()); - assert_eq!(hasher.finish(), 13205801729184435761); -} diff --git a/lucet-builtins/wasmonkey/src/tests/test_1.wasm b/lucet-builtins/wasmonkey/src/tests/test_1.wasm deleted file mode 100644 index 1bac61b0e551b196a8a81465fe572b0d312b1bd3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2372 zcmbtWU27Xh6uoz5_Cs22tfViYP?+7P639zw^RV>6QyK>oO8-JaFu`j}mTWb|;97>H z(BIj&_D{6u%V*mXRVvfk>g%~G+> zsBwudR5h_GCe5J_cfY$L`!P#rC$o#oYa{8^>hj%eAuhw4*~NzwvE!5Z>hgMVaXMd# zB(q=6zx_ru{n!bHp6?ddl8pbFrj_d2ipFW#$JN4v_P3xPvzIZl@K zw=Q21V!91LATFZGbP>*1%rmh zJ0zuF*Pu7(s2e`R#?S*7T=2)GMHIpm>`|%c#xRBn`idGhp^YddfKn%oMTMP;!J`kutRl`N}8Z>4!_QhfqWHF{%=( z+(wmCb+gxN0#z*RfeY$ls#snY79d!dM&hJ?bcTsokAf_?5(nbK^f-d)XqvES*tc~W z8>tKmCkYYop6)ips`7#UK(J@64J-=(?w?Tw0q$po3@#kRViKRR81+b`6D5apZV6@+ zmlad&gG9-_Fl1*==I10`gHNkVA4|^@p@$QU}Bd%Pyu!Trr5#AU&75# z&^G+{pkH*Ld$PB)DLb1E!g#?M$%5o8tH#u@<#9xrroHKQ74TX8Fy0A;By?clSU?; zR5ns}(xXNmbyED5igpK$9Dp!!E8@s?oAc3RWBmVH;G!UCT$?UYw=e%W5!Z+TxK!KQ zv^N0Ph{oI7)PFMB6n{&k$j(paXQ%V`xXQ@)ZvJ+5qTi*mbyv~us$%+^iXARAuD{|W H{mtbcawJQ# diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index bb0e73db9..f152eccc5 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -33,12 +33,14 @@ faerie = "0.11.0" goblin = "0.0.24" failure = "0.1" byteorder = "1.2" -wasmonkey = { path = "../lucet-builtins/wasmonkey", version = "0.1.7" } +# precisely pin wasmonkey, because the shared dependency on parity-wasm is very sensitive +wasmonkey = "=0.1.9" wabt = "0.9.2" tempfile = "3.0" bimap = "0.2" human-size = "0.4" -parity-wasm = "0.40.3" +# must match wasmonkey's version specifier +parity-wasm = "0.41" minisign = "0.5.11" memoffset = "0.5.1" serde = "1.0" From 42f6015b3aa72f28178308160aabf8f13757eb05 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 12 Sep 2019 07:27:22 +0200 Subject: [PATCH 464/512] Replace lucet-wasi with wasi-common + lucet wrappers --- Cargo.lock | 162 +- benchmarks/lucet-benchmarks/src/lib.rs | 2 +- benchmarks/lucet-benchmarks/src/seq.rs | 8 +- .../resources/rust_host/src/run.rs | 4 +- lucet-runtime/Cargo.toml | 2 +- .../lucet-runtime-internals/Cargo.toml | 4 +- lucet-wasi-fuzz/Cargo.toml | 2 +- lucet-wasi-fuzz/src/main.rs | 9 +- lucet-wasi/Cargo.toml | 5 +- lucet-wasi/src/c_api.rs | 32 +- lucet-wasi/src/ctx.rs | 248 --- lucet-wasi/src/fdentry.rs | 143 -- lucet-wasi/src/host.rs | 346 ----- lucet-wasi/src/hostcalls/fs.rs | 1357 ---------------- lucet-wasi/src/hostcalls/fs_helpers.rs | 306 ---- lucet-wasi/src/hostcalls/misc.rs | 455 ------ lucet-wasi/src/hostcalls/mod.rs | 447 ------ lucet-wasi/src/lib.rs | 11 +- lucet-wasi/src/main.rs | 19 +- lucet-wasi/src/memory.rs | 620 -------- lucet-wasi/src/wasi.rs | 597 +++++++ lucet-wasi/src/wasi_host.rs | 1035 ------------- lucet-wasi/src/wasm32.rs | 1367 ----------------- lucet-wasi/tests/test_helpers/mod.rs | 12 +- lucet-wasi/tests/tests.rs | 89 +- 25 files changed, 849 insertions(+), 6433 deletions(-) delete mode 100644 lucet-wasi/src/ctx.rs delete mode 100644 lucet-wasi/src/fdentry.rs delete mode 100644 lucet-wasi/src/host.rs delete mode 100644 lucet-wasi/src/hostcalls/fs.rs delete mode 100644 lucet-wasi/src/hostcalls/fs_helpers.rs delete mode 100644 lucet-wasi/src/hostcalls/misc.rs delete mode 100644 lucet-wasi/src/hostcalls/mod.rs delete mode 100644 lucet-wasi/src/memory.rs create mode 100644 lucet-wasi/src/wasi.rs delete mode 100644 lucet-wasi/src/wasi_host.rs delete mode 100644 lucet-wasi/src/wasm32.rs diff --git a/Cargo.lock b/Cargo.lock index 020ce3628..a04573770 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,7 +39,7 @@ name = "atty" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -55,7 +55,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -65,7 +65,7 @@ version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -118,7 +118,7 @@ dependencies = [ "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "which 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "which 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -231,7 +231,7 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -280,7 +280,7 @@ version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -486,6 +486,14 @@ dependencies = [ "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cvt" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "digest" version = "0.8.1" @@ -517,7 +525,7 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -527,7 +535,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -569,6 +577,17 @@ name = "fake-simd" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "filetime" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "flate2" version = "1.0.12" @@ -576,7 +595,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "miniz_oxide 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -590,7 +609,7 @@ name = "fs2" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -619,7 +638,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -656,7 +675,7 @@ name = "hermit-abi" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -689,9 +708,9 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -732,7 +751,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.59" +version = "0.2.65" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -849,7 +868,7 @@ dependencies = [ "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.4.1", "lucet-runtime-internals 0.4.1", "lucet-runtime-tests 0.4.1", @@ -873,11 +892,11 @@ dependencies = [ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.4.1", "memoffset 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -936,15 +955,16 @@ dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.4.1", "lucet-runtime 0.4.1", "lucet-runtime-internals 0.4.1", "lucet-wasi-sdk 0.4.1", "lucetc 0.4.1", - "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi-common 0.4.0 (git+https://github.com/fastly/wasi-common?branch=pch/stdio_files)", ] [[package]] @@ -953,7 +973,7 @@ version = "0.4.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.4.1", "lucet-runtime 0.4.1", "lucet-wasi 0.4.1", @@ -1022,7 +1042,7 @@ name = "memchr" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1060,7 +1080,19 @@ dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "nix" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1139,7 +1171,7 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1186,7 +1218,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "pkg-config" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1205,7 +1237,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1294,7 +1326,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1306,7 +1338,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1324,7 +1356,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1398,7 +1430,7 @@ name = "rand_jitter" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1410,7 +1442,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1538,7 +1570,7 @@ version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1690,14 +1722,14 @@ dependencies = [ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "hwloc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "precision 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "printtable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1797,7 +1829,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1817,7 +1849,7 @@ name = "terminal_size" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1848,7 +1880,7 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1925,7 +1957,7 @@ name = "wait-timeout" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1938,6 +1970,32 @@ dependencies = [ "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "wasi-common" +version = "0.4.0" +source = "git+https://github.com/fastly/wasi-common?branch=pch/stdio_files#16288298b92f7d6d02a5b47b338874a5c0db39e0" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi-common-cbindgen 0.4.0 (git+https://github.com/fastly/wasi-common?branch=pch/stdio_files)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winx 0.4.0 (git+https://github.com/fastly/wasi-common?branch=pch/stdio_files)", +] + +[[package]] +name = "wasi-common-cbindgen" +version = "0.4.0" +source = "git+https://github.com/fastly/wasi-common?branch=pch/stdio_files#16288298b92f7d6d02a5b47b338874a5c0db39e0" +dependencies = [ + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "wasmonkey" version = "0.1.9" @@ -1962,10 +2020,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "which" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2025,6 +2083,16 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "winx" +version = "0.4.0" +source = "git+https://github.com/fastly/wasi-common?branch=pch/stdio_files#16288298b92f7d6d02a5b47b338874a5c0db39e0" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cvt 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "witx" version = "0.3.0" @@ -2084,6 +2152,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" "checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d" "checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" +"checksum cvt 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34ac344c7efccb80cd25bc61b2170aec26f2f693fd40e765a539a1243db48c71" "checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" "checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" @@ -2093,6 +2162,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" "checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +"checksum filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd7380b54ced79dda72ecc35cc4fbbd1da6bba54afaa37e96fd1c2a308cd469" "checksum flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ad3c5233c9a940c8719031b423d7e6c16af66e031cb0420b0896f5245bf181d3" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" @@ -2114,7 +2184,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)" = "3262021842bf00fe07dbd6cf34ff25c99d7a7ebef8deea84db72be3ea3bb0aff" +"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" "checksum libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" @@ -2122,6 +2192,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "185d3531e38475163c1652a0915ac612be3f2655756af43f10789d6145f527c2" "checksum miniz_oxide 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6f3f74f726ae935c3f514300cc6773a0c9492abc5e972d42ba0c0ebb88757625" "checksum nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4dbdc256eaac2e3bd236d93ad999d3479ef775c863dbda3068c4006a92eec51b" +"checksum nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229" "checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" "checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" @@ -2137,7 +2208,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum parity-wasm 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc878dac00da22f8f61e7af3157988424567ab01d9920b962ef7dcbd7cd865" "checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" "checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" -"checksum pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "72d5370d90f49f70bd033c3d75e87fc529fbfff9d6f7cccef07d6170079d91ea" +"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" "checksum precision 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "83f0b3de90e9edd6382604f4f28509ce25272deb065b94045fc47abcde567d55" @@ -2212,7 +2283,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4574b75faccaacddb9b284faecdf0b544b80b6b294f3d062d325c5726a209c20" -"checksum toml 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c04dffffeac90885436d23c692517bb5b8b3f8863e4afc15023628d067d667b7" +"checksum toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01d1404644c8b12b16bfcffa4322403a91a451584daaaa7c28d3152e6cbc98cf" "checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" "checksum unicode-segmentation 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49f5526225fd8b77342d5986ab5f6055552e9c0776193b5b63fd53b46debfad7" "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" @@ -2226,9 +2297,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af5d153dc96aad7dc13ab90835b892c69867948112d95299e522d370c4e13a08" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" +"checksum wasi-common 0.4.0 (git+https://github.com/fastly/wasi-common?branch=pch/stdio_files)" = "" +"checksum wasi-common-cbindgen 0.4.0 (git+https://github.com/fastly/wasi-common?branch=pch/stdio_files)" = "" "checksum wasmonkey 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "af7c4bc80224427965ba21d87982cfc07d12e859824f303272056fb19f571ef9" "checksum wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5083b449454f7de0b15f131eee17de54b5a71dcb9adcf11df2b2f78fad0cd82" -"checksum which 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "240a31163872f7e8e49f35b42b58485e35355b07eb009d9f3686733541339a69" +"checksum which 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5475d47078209a02e60614f7ba5e645ef3ed60f771920ac1906d7c1cc65024c8" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" @@ -2237,4 +2310,5 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" "checksum winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef84b96d10db72dd980056666d7f1e7663ce93d82fa33b63e71c966f4cf5032" +"checksum winx 0.4.0 (git+https://github.com/fastly/wasi-common?branch=pch/stdio_files)" = "" "checksum xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da90eac47bf1d7871b75004b9b631d107df15f37669383b23f0b5297bc7516b6" diff --git a/benchmarks/lucet-benchmarks/src/lib.rs b/benchmarks/lucet-benchmarks/src/lib.rs index e6f436bba..989b582af 100644 --- a/benchmarks/lucet-benchmarks/src/lib.rs +++ b/benchmarks/lucet-benchmarks/src/lib.rs @@ -12,5 +12,5 @@ pub use seq::seq_benches; #[no_mangle] extern "C" fn lucet_benchmarks_ensure_linked() { lucet_runtime::lucet_internal_ensure_linked(); - lucet_wasi::hostcalls::ensure_linked(); + lucet_wasi::export_wasi_funcs(); } diff --git a/benchmarks/lucet-benchmarks/src/seq.rs b/benchmarks/lucet-benchmarks/src/seq.rs index e0afa79b1..85d28262b 100644 --- a/benchmarks/lucet-benchmarks/src/seq.rs +++ b/benchmarks/lucet-benchmarks/src/seq.rs @@ -24,7 +24,7 @@ const SPARSE_HEAP_SIZES_KB: &'static [usize] = &[0, 256, 512, 1024, 2 * 1024, 4 /// To minimize the effects of filesystem cache on the `DlModule::load()`, this runs `sync` between /// each iteration. fn hello_load_mkregion_and_instantiate(c: &mut Criterion) { - lucet_wasi::hostcalls::ensure_linked(); + lucet_wasi::export_wasi_funcs(); fn body(so_file: &Path) -> InstanceHandle { let module = DlModule::load(so_file).unwrap(); let region = R::create(1, &Limits::default()).unwrap(); @@ -259,10 +259,10 @@ fn run_hello(c: &mut Criterion) { c.bench_function(&format!("run_hello ({})", R::TYPE_NAME), move |b| { b.iter_batched_ref( || { - let null = std::fs::File::open("/dev/null").unwrap(); let ctx = WasiCtxBuilder::new() - .args(&["hello"]) - .fd(1, null) + .expect("create a new WASI context") + .args(["hello"].iter()) + .expect("WASI arguments") .build() .unwrap(); region diff --git a/lucet-idl/lucet-idl-test/resources/rust_host/src/run.rs b/lucet-idl/lucet-idl-test/resources/rust_host/src/run.rs index 86d9d0f60..569a0f161 100644 --- a/lucet-idl/lucet-idl-test/resources/rust_host/src/run.rs +++ b/lucet-idl/lucet-idl-test/resources/rust_host/src/run.rs @@ -6,7 +6,7 @@ use std::path::PathBuf; use std::sync::Arc; pub fn run(module_path: PathBuf) -> Result<(), Error> { - lucet_wasi::hostcalls::ensure_linked(); + lucet_wasi::export_wasi_funcs(); idl::ensure_linked(); let module = DlModule::load(&module_path)?; @@ -22,7 +22,9 @@ pub fn run(module_path: PathBuf) -> Result<(), Error> { )?; let ctx = WasiCtxBuilder::new() + .expect("create new wasi context") .inherit_stdio() + .expect("inherit stdio") .build() .expect("create empty wasi ctx"); diff --git a/lucet-runtime/Cargo.toml b/lucet-runtime/Cargo.toml index 377349a45..cd8c62cb8 100644 --- a/lucet-runtime/Cargo.toml +++ b/lucet-runtime/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Lucet team "] edition = "2018" [dependencies] -libc = "=0.2.59" +libc = "0.2.65" lucet-runtime-internals = { path = "lucet-runtime-internals", version = "0.4.1" } lucet-module = { path = "../lucet-module", version = "0.4.1" } num-traits = "0.2" diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index 24f6f4374..14db48848 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -17,10 +17,10 @@ bincode = "1.1.4" byteorder = "1.3" failure = "0.1" lazy_static = "1.1" -libc = "=0.2.59" +libc = "0.2.65" libloading = "0.5" memoffset = "0.5.1" -nix = "0.13" +nix = "0.15" num-derive = "0.3.0" num-traits = "0.2" xfailure = "0.1" diff --git a/lucet-wasi-fuzz/Cargo.toml b/lucet-wasi-fuzz/Cargo.toml index 6c8d280cd..dddd103c8 100644 --- a/lucet-wasi-fuzz/Cargo.toml +++ b/lucet-wasi-fuzz/Cargo.toml @@ -12,7 +12,7 @@ edition = "2018" [dependencies] clap = "2.32" failure = "0.1" -libc = "=0.2.59" +libc = "0.2.65" lucetc = { path = "../lucetc" } lucet-runtime = { path = "../lucet-runtime" } lucet-module = { path = "../lucet-module" } diff --git a/lucet-wasi-fuzz/src/main.rs b/lucet-wasi-fuzz/src/main.rs index 9417aa16c..0a7ec2386 100644 --- a/lucet-wasi-fuzz/src/main.rs +++ b/lucet-wasi-fuzz/src/main.rs @@ -52,7 +52,7 @@ enum Config { fn main() { lucet_runtime::lucet_internal_ensure_linked(); - lucet_wasi::hostcalls::ensure_linked(); + lucet_wasi::export_wasi_funcs(); match Config::from_args() { Config::Fuzz { num_tests } => run_many(num_tests), @@ -369,11 +369,14 @@ fn run_with_stdout>( tmpdir: &TempDir, path: P, ) -> Result<(__wasi_exitcode_t, Vec), Error> { - let ctx = WasiCtxBuilder::new().args(&["gen"]); + let ctx = WasiCtxBuilder::new() + .map_err(|_| format_err!("WasiCtxBuilder"))? + .args(["gen"].iter()) + .map_err(|_| format_err!("args"))?; let (pipe_out, pipe_in) = nix::unistd::pipe()?; - let ctx = unsafe { ctx.raw_fd(1, pipe_in) }.build()?; + let ctx = ctx.stdout(unsafe { File::from_raw_fd(pipe_in) })?.build()?; let exitcode = run(tmpdir, path, ctx)?; diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index 7021cd0e1..e6147021d 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -28,12 +28,13 @@ cast = "0.2" clap = "2.23" failure = "0.1" human-size = "0.4" -libc = "=0.2.59" lucet-runtime = { path = "../lucet-runtime", version = "0.4.1" } lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.4.1" } lucet-module = { path = "../lucet-module", version = "0.4.1" } -nix = "0.13" +libc = "0.2.65" +nix = "0.15" rand = "0.6" +wasi-common = { git = "https://github.com/fastly/wasi-common", branch = "pch/stdio_files" } [dev-dependencies] lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.1" } diff --git a/lucet-wasi/src/c_api.rs b/lucet-wasi/src/c_api.rs index be8dc9416..2b7d7f6ea 100644 --- a/lucet-wasi/src/c_api.rs +++ b/lucet-wasi/src/c_api.rs @@ -1,4 +1,6 @@ -use crate::ctx::WasiCtxBuilder; +use crate::WasiCtxBuilder; + +use libc; use lucet_runtime::{DlModule, Module, Region}; use lucet_runtime_internals::c_api::{lucet_dl_module, lucet_error, lucet_instance, lucet_region}; use lucet_runtime_internals::instance::instance_handle_to_raw; @@ -26,12 +28,18 @@ pub unsafe extern "C" fn lucet_wasi_ctx_args( assert_nonnull!(wasi_ctx); let mut b = Box::from_raw(wasi_ctx as *mut WasiCtxBuilder); let args_raw = std::slice::from_raw_parts(argv, argc); - // TODO: error handling - let args = args_raw + let args: Result, _> = args_raw .into_iter() - .map(|arg| CStr::from_ptr(*arg)) - .collect::>(); - *b = b.c_args(&args); + .map(|arg| CStr::from_ptr(*arg).to_str()) + .collect(); + let args = match args { + Ok(args) => args, + Err(_) => return lucet_error::Unsupported, + }; + *b = match b.args(args.iter()) { + Ok(b) => b, + Err(_) => return lucet_error::Unsupported, + }; Box::into_raw(b); lucet_error::Ok } @@ -40,7 +48,10 @@ pub unsafe extern "C" fn lucet_wasi_ctx_args( pub unsafe extern "C" fn lucet_wasi_ctx_inherit_env(wasi_ctx: *mut lucet_wasi_ctx) -> lucet_error { assert_nonnull!(wasi_ctx); let mut b = Box::from_raw(wasi_ctx as *mut WasiCtxBuilder); - *b = b.inherit_env(); + *b = match b.inherit_env() { + Ok(b) => b, + Err(_) => return lucet_error::Unsupported, + }; Box::into_raw(b); lucet_error::Ok } @@ -51,7 +62,10 @@ pub unsafe extern "C" fn lucet_wasi_ctx_inherit_stdio( ) -> lucet_error { assert_nonnull!(wasi_ctx); let mut b = Box::from_raw(wasi_ctx as *mut WasiCtxBuilder); - *b = b.inherit_stdio(); + *b = match b.inherit_stdio() { + Ok(b) => b, + Err(_) => return lucet_error::Unsupported, + }; Box::into_raw(b); lucet_error::Ok } @@ -94,5 +108,5 @@ pub unsafe extern "C" fn lucet_region_new_instance_with_wasi_ctx( #[no_mangle] #[doc(hidden)] pub extern "C" fn lucet_wasi_internal_ensure_linked() { - crate::hostcalls::ensure_linked(); + crate::wasi::export_wasi_funcs(); } diff --git a/lucet-wasi/src/ctx.rs b/lucet-wasi/src/ctx.rs deleted file mode 100644 index f32acb64a..000000000 --- a/lucet-wasi/src/ctx.rs +++ /dev/null @@ -1,248 +0,0 @@ -use crate::fdentry::FdEntry; -use crate::host; -use failure::{bail, format_err, Error}; -use nix::unistd::dup; -use std::collections::HashMap; -use std::ffi::{CStr, CString}; -use std::fs::{File, OpenOptions}; -use std::io::{stderr, stdin, stdout}; -use std::os::unix::prelude::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; -use std::path::{Path, PathBuf}; - -pub struct WasiCtxBuilder { - fds: HashMap, - preopens: HashMap, - args: Vec, - env: HashMap, -} - -impl WasiCtxBuilder { - /// Builder for a new `WasiCtx`. - pub fn new() -> Self { - let null = dev_null(); - WasiCtxBuilder { - fds: HashMap::new(), - preopens: HashMap::new(), - args: vec![], - env: HashMap::new(), - } - .fd_dup(0, &null) - .fd_dup(1, &null) - .fd_dup(2, &null) - } - - pub fn args(mut self, args: &[&str]) -> Self { - self.args = args - .into_iter() - .map(|arg| CString::new(*arg).expect("argument can be converted to a CString")) - .collect(); - self - } - - pub fn arg(mut self, arg: &str) -> Self { - self.args - .push(CString::new(arg).expect("argument can be converted to a CString")); - self - } - - pub fn c_args>(mut self, args: &[S]) -> Self { - self.args = args - .into_iter() - .map(|arg| arg.as_ref().to_owned()) - .collect(); - self - } - - pub fn c_arg>(mut self, arg: S) -> Self { - self.args.push(arg.as_ref().to_owned()); - self - } - - pub fn inherit_stdio(self) -> Self { - self.fd_dup(0, &stdin()) - .fd_dup(1, &stdout()) - .fd_dup(2, &stderr()) - } - - pub fn inherit_env(mut self) -> Self { - self.env = std::env::vars() - .map(|(k, v)| { - // TODO: handle errors, and possibly assert that the key is valid per POSIX - ( - CString::new(k).expect("environment key can be converted to a CString"), - CString::new(v).expect("environment value can be converted to a CString"), - ) - }) - .collect(); - self - } - - pub fn env(mut self, k: &str, v: &str) -> Self { - self.env.insert( - // TODO: handle errors, and possibly assert that the key is valid per POSIX - CString::new(k).expect("environment key can be converted to a CString"), - CString::new(v).expect("environment value can be converted to a CString"), - ); - self - } - - pub fn c_env(mut self, k: S, v: T) -> Self - where - S: AsRef, - T: AsRef, - { - self.env - .insert(k.as_ref().to_owned(), v.as_ref().to_owned()); - self - } - - /// Add an existing file-like object as a file descriptor in the context. - /// - /// When the `WasiCtx` is dropped, all of its associated file descriptors are `close`d. If you - /// do not want this to close the existing object, use `WasiCtxBuilder::fd_dup()`. - pub fn fd(self, wasm_fd: host::__wasi_fd_t, fd: F) -> Self { - // safe because we're getting a valid RawFd from the F directly - unsafe { self.raw_fd(wasm_fd, fd.into_raw_fd()) } - } - - /// Add an existing file-like object as a duplicate file descriptor in the context. - /// - /// The underlying file descriptor of this object will be duplicated before being added to the - /// context, so it will not be closed when the `WasiCtx` is dropped. - /// - /// TODO: handle `dup` errors - pub fn fd_dup(self, wasm_fd: host::__wasi_fd_t, fd: &F) -> Self { - // safe because we're getting a valid RawFd from the F directly - unsafe { self.raw_fd(wasm_fd, dup(fd.as_raw_fd()).unwrap()) } - } - - /// Add an existing file descriptor to the context. - /// - /// When the `WasiCtx` is dropped, this file descriptor will be `close`d. If you do not want to - /// close the existing descriptor, use `WasiCtxBuilder::raw_fd_dup()`. - pub unsafe fn raw_fd(mut self, wasm_fd: host::__wasi_fd_t, fd: RawFd) -> Self { - self.fds.insert(wasm_fd, FdEntry::from_raw_fd(fd)); - self - } - - /// Add a duplicate of an existing file descriptor to the context. - /// - /// The file descriptor will be duplicated before being added to the context, so it will not be - /// closed when the `WasiCtx` is dropped. - /// - /// TODO: handle `dup` errors - pub unsafe fn raw_fd_dup(self, wasm_fd: host::__wasi_fd_t, fd: RawFd) -> Self { - self.raw_fd(wasm_fd, dup(fd).unwrap()) - } - - pub fn preopened_dir>(mut self, dir: File, guest_path: P) -> Self { - self.preopens.insert(guest_path.as_ref().to_owned(), dir); - self - } - - pub fn build(mut self) -> Result { - // startup code starts looking at fd 3 for preopens - let mut preopen_fd = 3; - for (guest_path, dir) in self.preopens { - if !dir.metadata()?.is_dir() { - bail!("preopened file is not a directory"); - } - while self.fds.contains_key(&preopen_fd) { - preopen_fd = preopen_fd - .checked_add(1) - .ok_or(format_err!("not enough file handles"))?; - } - let mut fe = FdEntry::from_file(dir); - fe.preopen_path = Some(guest_path); - self.fds.insert(preopen_fd, fe); - preopen_fd += 1; - } - - let env = self - .env - .into_iter() - .map(|(k, v)| { - let mut pair = k.into_bytes(); - pair.extend_from_slice(b"="); - pair.extend_from_slice(v.to_bytes_with_nul()); - // constructing a new CString from existing CStrings is safe - unsafe { CString::from_vec_unchecked(pair) } - }) - .collect(); - - Ok(WasiCtx { - fds: self.fds, - args: self.args, - env, - }) - } -} - -#[derive(Debug)] -pub struct WasiCtx { - pub fds: HashMap, - pub args: Vec, - pub env: Vec, -} - -impl WasiCtx { - /// Make a new `WasiCtx` with some default settings. - /// - /// - File descriptors 0, 1, and 2 inherit stdin, stdout, and stderr from the host process. - /// - /// - Environment variables are inherited from the host process. - /// - /// To override these behaviors, use `WasiCtxBuilder`. - pub fn new(args: &[&str]) -> WasiCtx { - WasiCtxBuilder::new() - .args(args) - .inherit_stdio() - .inherit_env() - .build() - .expect("default options don't fail") - } - - pub fn get_fd_entry( - &self, - fd: host::__wasi_fd_t, - rights_base: host::__wasi_rights_t, - rights_inheriting: host::__wasi_rights_t, - ) -> Result<&FdEntry, host::__wasi_errno_t> { - if let Some(fe) = self.fds.get(&fd) { - // validate rights - if !fe.rights_base & rights_base != 0 || !fe.rights_inheriting & rights_inheriting != 0 - { - Err(host::__WASI_ENOTCAPABLE as host::__wasi_errno_t) - } else { - Ok(fe) - } - } else { - Err(host::__WASI_EBADF as host::__wasi_errno_t) - } - } - - pub fn insert_fd_entry( - &mut self, - fe: FdEntry, - ) -> Result { - // never insert where stdio handles usually are - let mut fd = 3; - while self.fds.contains_key(&fd) { - if let Some(next_fd) = fd.checked_add(1) { - fd = next_fd; - } else { - return Err(host::__WASI_EMFILE as host::__wasi_errno_t); - } - } - self.fds.insert(fd, fe); - Ok(fd) - } -} - -fn dev_null() -> File { - OpenOptions::new() - .read(true) - .write(true) - .open("/dev/null") - .expect("failed to open /dev/null") -} diff --git a/lucet-wasi/src/fdentry.rs b/lucet-wasi/src/fdentry.rs deleted file mode 100644 index 84d4a793c..000000000 --- a/lucet-wasi/src/fdentry.rs +++ /dev/null @@ -1,143 +0,0 @@ -use crate::host; -use std::fs::File; -use std::os::unix::prelude::{FileTypeExt, FromRawFd, IntoRawFd, RawFd}; -use std::path::PathBuf; - -#[derive(Debug)] -pub struct FdEntry { - pub fd_object: FdObject, - pub rights_base: host::__wasi_rights_t, - pub rights_inheriting: host::__wasi_rights_t, - pub preopen_path: Option, -} - -impl FdEntry { - pub fn from_file(file: File) -> FdEntry { - unsafe { FdEntry::from_raw_fd(file.into_raw_fd()) } - } -} - -impl FromRawFd for FdEntry { - // TODO: make this a different function with error handling, rather than using the trait method - unsafe fn from_raw_fd(rawfd: RawFd) -> FdEntry { - let (ty, mut rights_base, rights_inheriting) = - determine_type_rights(rawfd).expect("can determine file rights"); - - use nix::fcntl::{fcntl, OFlag, F_GETFL}; - let flags_bits = fcntl(rawfd, F_GETFL).expect("fcntl succeeds"); - let flags = OFlag::from_bits_truncate(flags_bits); - let accmode = flags & OFlag::O_ACCMODE; - if accmode == OFlag::O_RDONLY { - rights_base &= !host::__WASI_RIGHT_FD_WRITE as host::__wasi_rights_t; - } else if accmode == OFlag::O_WRONLY { - rights_base &= !host::__WASI_RIGHT_FD_READ as host::__wasi_rights_t; - } - - FdEntry { - fd_object: FdObject { - ty: ty as u8, - rawfd, - needs_close: true, - }, - rights_base, - rights_inheriting, - preopen_path: None, - } - } -} - -// TODO: can probably make this safe by using fcntl directly rather than going through `File` -pub unsafe fn determine_type_rights( - rawfd: RawFd, -) -> Result< - ( - host::__wasi_filetype_t, - host::__wasi_rights_t, - host::__wasi_rights_t, - ), - host::__wasi_errno_t, -> { - let (ty, rights_base, rights_inheriting) = { - let file = File::from_raw_fd(rawfd); - let ft = file.metadata().unwrap().file_type(); - // we just make a `File` here for convenience; we don't want it to close when it drops - std::mem::forget(file); - if ft.is_block_device() { - ( - host::__WASI_FILETYPE_BLOCK_DEVICE, - host::RIGHTS_BLOCK_DEVICE_BASE, - host::RIGHTS_BLOCK_DEVICE_INHERITING, - ) - } else if ft.is_char_device() { - if nix::unistd::isatty(rawfd).unwrap() { - ( - host::__WASI_FILETYPE_CHARACTER_DEVICE, - host::RIGHTS_TTY_BASE, - host::RIGHTS_TTY_BASE, - ) - } else { - ( - host::__WASI_FILETYPE_CHARACTER_DEVICE, - host::RIGHTS_CHARACTER_DEVICE_BASE, - host::RIGHTS_CHARACTER_DEVICE_INHERITING, - ) - } - } else if ft.is_dir() { - ( - host::__WASI_FILETYPE_DIRECTORY, - host::RIGHTS_DIRECTORY_BASE, - host::RIGHTS_DIRECTORY_INHERITING, - ) - } else if ft.is_file() { - ( - host::__WASI_FILETYPE_REGULAR_FILE, - host::RIGHTS_REGULAR_FILE_BASE, - host::RIGHTS_REGULAR_FILE_INHERITING, - ) - } else if ft.is_socket() { - use nix::sys::socket; - match socket::getsockopt(rawfd, socket::sockopt::SockType).unwrap() { - socket::SockType::Datagram => ( - host::__WASI_FILETYPE_SOCKET_DGRAM, - host::RIGHTS_SOCKET_BASE, - host::RIGHTS_SOCKET_INHERITING, - ), - socket::SockType::Stream => ( - host::__WASI_FILETYPE_SOCKET_STREAM, - host::RIGHTS_SOCKET_BASE, - host::RIGHTS_SOCKET_INHERITING, - ), - _ => return Err(host::__WASI_EINVAL as host::__wasi_errno_t), - } - } else if ft.is_fifo() { - ( - host::__WASI_FILETYPE_SOCKET_STREAM, - host::RIGHTS_SOCKET_BASE, - host::RIGHTS_SOCKET_INHERITING, - ) - } else { - return Err(host::__WASI_EINVAL as host::__wasi_errno_t); - } - }; - Ok(( - ty as host::__wasi_filetype_t, - rights_base, - rights_inheriting, - )) -} - -#[derive(Debug)] -pub struct FdObject { - pub ty: host::__wasi_filetype_t, - pub rawfd: RawFd, - pub needs_close: bool, - // TODO: directories -} - -impl Drop for FdObject { - fn drop(&mut self) { - if self.needs_close { - nix::unistd::close(self.rawfd).unwrap_or_else(|e| eprintln!("FdObject::drop(): {}", e)); - } - } -} diff --git a/lucet-wasi/src/host.rs b/lucet-wasi/src/host.rs deleted file mode 100644 index e1a6027d0..000000000 --- a/lucet-wasi/src/host.rs +++ /dev/null @@ -1,346 +0,0 @@ -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] - -include!("wasi_host.rs"); - -pub type void = ::std::os::raw::c_void; - -pub unsafe fn ciovec_to_nix<'a>(ciovec: &'a __wasi_ciovec_t) -> nix::sys::uio::IoVec<&'a [u8]> { - let slice = std::slice::from_raw_parts(ciovec.buf as *const u8, ciovec.buf_len); - nix::sys::uio::IoVec::from_slice(slice) -} - -pub unsafe fn ciovec_to_nix_mut<'a>( - ciovec: &'a mut __wasi_ciovec_t, -) -> nix::sys::uio::IoVec<&'a mut [u8]> { - let slice = std::slice::from_raw_parts_mut(ciovec.buf as *mut u8, ciovec.buf_len); - nix::sys::uio::IoVec::from_mut_slice(slice) -} - -pub unsafe fn iovec_to_nix<'a>(iovec: &'a __wasi_iovec_t) -> nix::sys::uio::IoVec<&'a [u8]> { - let slice = std::slice::from_raw_parts(iovec.buf as *const u8, iovec.buf_len); - nix::sys::uio::IoVec::from_slice(slice) -} - -pub unsafe fn iovec_to_nix_mut<'a>( - iovec: &'a mut __wasi_iovec_t, -) -> nix::sys::uio::IoVec<&'a mut [u8]> { - let slice = std::slice::from_raw_parts_mut(iovec.buf as *mut u8, iovec.buf_len); - nix::sys::uio::IoVec::from_mut_slice(slice) -} - -pub fn errno_from_nix(errno: nix::errno::Errno) -> __wasi_errno_t { - let e = match errno { - nix::errno::Errno::EPERM => __WASI_EPERM, - nix::errno::Errno::ENOENT => __WASI_ENOENT, - nix::errno::Errno::ESRCH => __WASI_ESRCH, - nix::errno::Errno::EINTR => __WASI_EINTR, - nix::errno::Errno::EIO => __WASI_EIO, - nix::errno::Errno::ENXIO => __WASI_ENXIO, - nix::errno::Errno::E2BIG => __WASI_E2BIG, - nix::errno::Errno::ENOEXEC => __WASI_ENOEXEC, - nix::errno::Errno::EBADF => __WASI_EBADF, - nix::errno::Errno::ECHILD => __WASI_ECHILD, - nix::errno::Errno::EAGAIN => __WASI_EAGAIN, - nix::errno::Errno::ENOMEM => __WASI_ENOMEM, - nix::errno::Errno::EACCES => __WASI_EACCES, - nix::errno::Errno::EFAULT => __WASI_EFAULT, - nix::errno::Errno::EBUSY => __WASI_EBUSY, - nix::errno::Errno::EEXIST => __WASI_EEXIST, - nix::errno::Errno::EXDEV => __WASI_EXDEV, - nix::errno::Errno::ENODEV => __WASI_ENODEV, - nix::errno::Errno::ENOTDIR => __WASI_ENOTDIR, - nix::errno::Errno::EISDIR => __WASI_EISDIR, - nix::errno::Errno::EINVAL => __WASI_EINVAL, - nix::errno::Errno::ENFILE => __WASI_ENFILE, - nix::errno::Errno::EMFILE => __WASI_EMFILE, - nix::errno::Errno::ENOTTY => __WASI_ENOTTY, - nix::errno::Errno::ETXTBSY => __WASI_ETXTBSY, - nix::errno::Errno::EFBIG => __WASI_EFBIG, - nix::errno::Errno::ENOSPC => __WASI_ENOSPC, - nix::errno::Errno::ESPIPE => __WASI_ESPIPE, - nix::errno::Errno::EROFS => __WASI_EROFS, - nix::errno::Errno::EMLINK => __WASI_EMLINK, - nix::errno::Errno::EPIPE => __WASI_EPIPE, - nix::errno::Errno::EDOM => __WASI_EDOM, - nix::errno::Errno::ERANGE => __WASI_ERANGE, - nix::errno::Errno::EDEADLK => __WASI_EDEADLK, - nix::errno::Errno::ENAMETOOLONG => __WASI_ENAMETOOLONG, - nix::errno::Errno::ENOLCK => __WASI_ENOLCK, - nix::errno::Errno::ENOSYS => __WASI_ENOSYS, - nix::errno::Errno::ENOTEMPTY => __WASI_ENOTEMPTY, - nix::errno::Errno::ELOOP => __WASI_ELOOP, - nix::errno::Errno::ENOMSG => __WASI_ENOMSG, - nix::errno::Errno::EIDRM => __WASI_EIDRM, - nix::errno::Errno::ENOLINK => __WASI_ENOLINK, - nix::errno::Errno::EPROTO => __WASI_EPROTO, - nix::errno::Errno::EMULTIHOP => __WASI_EMULTIHOP, - nix::errno::Errno::EBADMSG => __WASI_EBADMSG, - nix::errno::Errno::EOVERFLOW => __WASI_EOVERFLOW, - nix::errno::Errno::EILSEQ => __WASI_EILSEQ, - nix::errno::Errno::ENOTSOCK => __WASI_ENOTSOCK, - nix::errno::Errno::EDESTADDRREQ => __WASI_EDESTADDRREQ, - nix::errno::Errno::EMSGSIZE => __WASI_EMSGSIZE, - nix::errno::Errno::EPROTOTYPE => __WASI_EPROTOTYPE, - nix::errno::Errno::ENOPROTOOPT => __WASI_ENOPROTOOPT, - nix::errno::Errno::EPROTONOSUPPORT => __WASI_EPROTONOSUPPORT, - nix::errno::Errno::EAFNOSUPPORT => __WASI_EAFNOSUPPORT, - nix::errno::Errno::EADDRINUSE => __WASI_EADDRINUSE, - nix::errno::Errno::EADDRNOTAVAIL => __WASI_EADDRNOTAVAIL, - nix::errno::Errno::ENETDOWN => __WASI_ENETDOWN, - nix::errno::Errno::ENETUNREACH => __WASI_ENETUNREACH, - nix::errno::Errno::ENETRESET => __WASI_ENETRESET, - nix::errno::Errno::ECONNABORTED => __WASI_ECONNABORTED, - nix::errno::Errno::ECONNRESET => __WASI_ECONNRESET, - nix::errno::Errno::ENOBUFS => __WASI_ENOBUFS, - nix::errno::Errno::EISCONN => __WASI_EISCONN, - nix::errno::Errno::ENOTCONN => __WASI_ENOTCONN, - nix::errno::Errno::ETIMEDOUT => __WASI_ETIMEDOUT, - nix::errno::Errno::ECONNREFUSED => __WASI_ECONNREFUSED, - nix::errno::Errno::EHOSTUNREACH => __WASI_EHOSTUNREACH, - nix::errno::Errno::EALREADY => __WASI_EALREADY, - nix::errno::Errno::EINPROGRESS => __WASI_EINPROGRESS, - nix::errno::Errno::ESTALE => __WASI_ESTALE, - nix::errno::Errno::EDQUOT => __WASI_EDQUOT, - nix::errno::Errno::ECANCELED => __WASI_ECANCELED, - nix::errno::Errno::EOWNERDEAD => __WASI_EOWNERDEAD, - nix::errno::Errno::ENOTRECOVERABLE => __WASI_ENOTRECOVERABLE, - _ => __WASI_ENOSYS, - }; - e as __wasi_errno_t -} - -#[cfg(target_os = "linux")] -const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_RSYNC; - -#[cfg(not(target_os = "linux"))] -const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_SYNC; - -pub fn nix_from_fdflags(fdflags: __wasi_fdflags_t) -> nix::fcntl::OFlag { - use nix::fcntl::OFlag; - let mut nix_flags = OFlag::empty(); - if fdflags & (__WASI_FDFLAG_APPEND as __wasi_fdflags_t) != 0 { - nix_flags.insert(OFlag::O_APPEND); - } - if fdflags & (__WASI_FDFLAG_DSYNC as __wasi_fdflags_t) != 0 { - nix_flags.insert(OFlag::O_DSYNC); - } - if fdflags & (__WASI_FDFLAG_NONBLOCK as __wasi_fdflags_t) != 0 { - nix_flags.insert(OFlag::O_NONBLOCK); - } - if fdflags & (__WASI_FDFLAG_RSYNC as __wasi_fdflags_t) != 0 { - nix_flags.insert(O_RSYNC); - } - if fdflags & (__WASI_FDFLAG_SYNC as __wasi_fdflags_t) != 0 { - nix_flags.insert(OFlag::O_SYNC); - } - nix_flags -} - -pub fn fdflags_from_nix(oflags: nix::fcntl::OFlag) -> __wasi_fdflags_t { - use nix::fcntl::OFlag; - let mut fdflags = 0; - if oflags.contains(OFlag::O_APPEND) { - fdflags |= __WASI_FDFLAG_APPEND; - } - if oflags.contains(OFlag::O_DSYNC) { - fdflags |= __WASI_FDFLAG_DSYNC; - } - if oflags.contains(OFlag::O_NONBLOCK) { - fdflags |= __WASI_FDFLAG_NONBLOCK; - } - if oflags.contains(O_RSYNC) { - fdflags |= __WASI_FDFLAG_RSYNC; - } - if oflags.contains(OFlag::O_SYNC) { - fdflags |= __WASI_FDFLAG_SYNC; - } - fdflags as __wasi_fdflags_t -} - -pub fn nix_from_oflags(oflags: __wasi_oflags_t) -> nix::fcntl::OFlag { - use nix::fcntl::OFlag; - let mut nix_flags = OFlag::empty(); - if oflags & (__WASI_O_CREAT as __wasi_oflags_t) != 0 { - nix_flags.insert(OFlag::O_CREAT); - } - if oflags & (__WASI_O_DIRECTORY as __wasi_oflags_t) != 0 { - nix_flags.insert(OFlag::O_DIRECTORY); - } - if oflags & (__WASI_O_EXCL as __wasi_oflags_t) != 0 { - nix_flags.insert(OFlag::O_EXCL); - } - if oflags & (__WASI_O_TRUNC as __wasi_oflags_t) != 0 { - nix_flags.insert(OFlag::O_TRUNC); - } - nix_flags -} - -pub fn filetype_from_nix(sflags: nix::sys::stat::SFlag) -> __wasi_filetype_t { - use nix::sys::stat::SFlag; - if sflags.contains(SFlag::S_IFCHR) { - __WASI_FILETYPE_CHARACTER_DEVICE as __wasi_filetype_t - } else if sflags.contains(SFlag::S_IFBLK) { - __WASI_FILETYPE_BLOCK_DEVICE as __wasi_filetype_t - } else if sflags.contains(SFlag::S_IFIFO) | sflags.contains(SFlag::S_IFSOCK) { - __WASI_FILETYPE_SOCKET_STREAM as __wasi_filetype_t - } else if sflags.contains(SFlag::S_IFDIR) { - __WASI_FILETYPE_DIRECTORY as __wasi_filetype_t - } else if sflags.contains(SFlag::S_IFREG) { - __WASI_FILETYPE_REGULAR_FILE as __wasi_filetype_t - } else if sflags.contains(SFlag::S_IFLNK) { - __WASI_FILETYPE_SYMBOLIC_LINK as __wasi_filetype_t - } else { - __WASI_FILETYPE_UNKNOWN as __wasi_filetype_t - } -} - -pub fn nix_from_filetype(sflags: __wasi_filetype_t) -> nix::sys::stat::SFlag { - use nix::sys::stat::SFlag; - let mut nix_sflags = SFlag::empty(); - if sflags & (__WASI_FILETYPE_CHARACTER_DEVICE as __wasi_filetype_t) != 0 { - nix_sflags.insert(SFlag::S_IFCHR); - } - if sflags & (__WASI_FILETYPE_BLOCK_DEVICE as __wasi_filetype_t) != 0 { - nix_sflags.insert(SFlag::S_IFBLK); - } - if sflags & (__WASI_FILETYPE_SOCKET_STREAM as __wasi_filetype_t) != 0 { - nix_sflags.insert(SFlag::S_IFIFO); - nix_sflags.insert(SFlag::S_IFSOCK); - } - if sflags & (__WASI_FILETYPE_DIRECTORY as __wasi_filetype_t) != 0 { - nix_sflags.insert(SFlag::S_IFDIR); - } - if sflags & (__WASI_FILETYPE_REGULAR_FILE as __wasi_filetype_t) != 0 { - nix_sflags.insert(SFlag::S_IFREG); - } - if sflags & (__WASI_FILETYPE_SYMBOLIC_LINK as __wasi_filetype_t) != 0 { - nix_sflags.insert(SFlag::S_IFLNK); - } - nix_sflags -} - -pub fn filestat_from_nix(filestat: nix::sys::stat::FileStat) -> __wasi_filestat_t { - let filetype = nix::sys::stat::SFlag::from_bits_truncate(filestat.st_mode); - __wasi_filestat_t { - st_dev: filestat.st_dev as __wasi_device_t, - st_ino: filestat.st_ino as __wasi_inode_t, - st_nlink: filestat.st_nlink as __wasi_linkcount_t, - st_size: filestat.st_size as __wasi_filesize_t, - st_atim: filestat.st_atime as __wasi_timestamp_t * 1_000_000_000, - st_ctim: filestat.st_ctime as __wasi_timestamp_t * 1_000_000_000, - st_mtim: filestat.st_mtime as __wasi_timestamp_t * 1_000_000_000, - st_filetype: filetype_from_nix(filetype), - } -} - -// Rights sets from wasmtime-wasi sandboxed system primitives. Transcribed because bindgen can't -// parse the #defines. - -pub const RIGHTS_ALL: __wasi_rights_t = (__WASI_RIGHT_FD_DATASYNC - | __WASI_RIGHT_FD_READ - | __WASI_RIGHT_FD_SEEK - | __WASI_RIGHT_FD_FDSTAT_SET_FLAGS - | __WASI_RIGHT_FD_SYNC - | __WASI_RIGHT_FD_TELL - | __WASI_RIGHT_FD_WRITE - | __WASI_RIGHT_FD_ADVISE - | __WASI_RIGHT_FD_ALLOCATE - | __WASI_RIGHT_PATH_CREATE_DIRECTORY - | __WASI_RIGHT_PATH_CREATE_FILE - | __WASI_RIGHT_PATH_LINK_SOURCE - | __WASI_RIGHT_PATH_LINK_TARGET - | __WASI_RIGHT_PATH_OPEN - | __WASI_RIGHT_FD_READDIR - | __WASI_RIGHT_PATH_READLINK - | __WASI_RIGHT_PATH_RENAME_SOURCE - | __WASI_RIGHT_PATH_RENAME_TARGET - | __WASI_RIGHT_PATH_FILESTAT_GET - | __WASI_RIGHT_PATH_FILESTAT_SET_SIZE - | __WASI_RIGHT_PATH_FILESTAT_SET_TIMES - | __WASI_RIGHT_FD_FILESTAT_GET - | __WASI_RIGHT_FD_FILESTAT_SET_SIZE - | __WASI_RIGHT_FD_FILESTAT_SET_TIMES - | __WASI_RIGHT_PATH_SYMLINK - | __WASI_RIGHT_PATH_UNLINK_FILE - | __WASI_RIGHT_PATH_REMOVE_DIRECTORY - | __WASI_RIGHT_POLL_FD_READWRITE - | __WASI_RIGHT_SOCK_SHUTDOWN) as __wasi_rights_t; - -// Block and character device interaction is outside the scope of -// CloudABI. Simply allow everything. -pub const RIGHTS_BLOCK_DEVICE_BASE: __wasi_rights_t = RIGHTS_ALL; -pub const RIGHTS_BLOCK_DEVICE_INHERITING: __wasi_rights_t = RIGHTS_ALL; -pub const RIGHTS_CHARACTER_DEVICE_BASE: __wasi_rights_t = RIGHTS_ALL; -pub const RIGHTS_CHARACTER_DEVICE_INHERITING: __wasi_rights_t = RIGHTS_ALL; - -// Only allow directory operations on directories. Directories can only -// yield file descriptors to other directories and files. -pub const RIGHTS_DIRECTORY_BASE: __wasi_rights_t = (__WASI_RIGHT_FD_FDSTAT_SET_FLAGS - | __WASI_RIGHT_FD_SYNC - | __WASI_RIGHT_FD_ADVISE - | __WASI_RIGHT_PATH_CREATE_DIRECTORY - | __WASI_RIGHT_PATH_CREATE_FILE - | __WASI_RIGHT_PATH_LINK_SOURCE - | __WASI_RIGHT_PATH_LINK_TARGET - | __WASI_RIGHT_PATH_OPEN - | __WASI_RIGHT_FD_READDIR - | __WASI_RIGHT_PATH_READLINK - | __WASI_RIGHT_PATH_RENAME_SOURCE - | __WASI_RIGHT_PATH_RENAME_TARGET - | __WASI_RIGHT_PATH_FILESTAT_GET - | __WASI_RIGHT_PATH_FILESTAT_SET_SIZE - | __WASI_RIGHT_PATH_FILESTAT_SET_TIMES - | __WASI_RIGHT_FD_FILESTAT_GET - | __WASI_RIGHT_FD_FILESTAT_SET_TIMES - | __WASI_RIGHT_PATH_SYMLINK - | __WASI_RIGHT_PATH_UNLINK_FILE - | __WASI_RIGHT_PATH_REMOVE_DIRECTORY - | __WASI_RIGHT_POLL_FD_READWRITE) - as __wasi_rights_t; -pub const RIGHTS_DIRECTORY_INHERITING: __wasi_rights_t = - (RIGHTS_DIRECTORY_BASE | RIGHTS_REGULAR_FILE_BASE); - -// Operations that apply to regular files. -pub const RIGHTS_REGULAR_FILE_BASE: __wasi_rights_t = (__WASI_RIGHT_FD_DATASYNC - | __WASI_RIGHT_FD_READ - | __WASI_RIGHT_FD_SEEK - | __WASI_RIGHT_FD_FDSTAT_SET_FLAGS - | __WASI_RIGHT_FD_SYNC - | __WASI_RIGHT_FD_TELL - | __WASI_RIGHT_FD_WRITE - | __WASI_RIGHT_FD_ADVISE - | __WASI_RIGHT_FD_ALLOCATE - | __WASI_RIGHT_FD_FILESTAT_GET - | __WASI_RIGHT_FD_FILESTAT_SET_SIZE - | __WASI_RIGHT_FD_FILESTAT_SET_TIMES - | __WASI_RIGHT_POLL_FD_READWRITE) - as __wasi_rights_t; -pub const RIGHTS_REGULAR_FILE_INHERITING: __wasi_rights_t = 0; - -// Operations that apply to shared memory objects. -pub const RIGHTS_SHARED_MEMORY_BASE: __wasi_rights_t = (__WASI_RIGHT_FD_READ - | __WASI_RIGHT_FD_WRITE - | __WASI_RIGHT_FD_FILESTAT_GET - | __WASI_RIGHT_FD_FILESTAT_SET_SIZE) - as __wasi_rights_t; -pub const RIGHTS_SHARED_MEMORY_INHERITING: __wasi_rights_t = 0; - -// Operations that apply to sockets and socket pairs. -pub const RIGHTS_SOCKET_BASE: __wasi_rights_t = (__WASI_RIGHT_FD_READ - | __WASI_RIGHT_FD_FDSTAT_SET_FLAGS - | __WASI_RIGHT_FD_WRITE - | __WASI_RIGHT_FD_FILESTAT_GET - | __WASI_RIGHT_POLL_FD_READWRITE - | __WASI_RIGHT_SOCK_SHUTDOWN) - as __wasi_rights_t; -pub const RIGHTS_SOCKET_INHERITING: __wasi_rights_t = RIGHTS_ALL; - -// Operations that apply to TTYs. -pub const RIGHTS_TTY_BASE: __wasi_rights_t = (__WASI_RIGHT_FD_READ - | __WASI_RIGHT_FD_FDSTAT_SET_FLAGS - | __WASI_RIGHT_FD_WRITE - | __WASI_RIGHT_FD_FILESTAT_GET - | __WASI_RIGHT_POLL_FD_READWRITE) - as __wasi_rights_t; -pub const RIGHTS_TTY_INHERITING: __wasi_rights_t = 0; diff --git a/lucet-wasi/src/hostcalls/fs.rs b/lucet-wasi/src/hostcalls/fs.rs deleted file mode 100644 index 7eaee5352..000000000 --- a/lucet-wasi/src/hostcalls/fs.rs +++ /dev/null @@ -1,1357 +0,0 @@ -#![allow(non_camel_case_types)] -#![allow(unused_unsafe)] - -use crate::ctx::WasiCtx; -use crate::fdentry::{determine_type_rights, FdEntry}; -use crate::memory::*; -use crate::{host, wasm32}; - -use super::fs_helpers::*; -use lucet_runtime::vmctx::Vmctx; - -use nix::libc::{self, c_long, c_void, off_t}; -use std::ffi::OsStr; -use std::mem::MaybeUninit; -use std::os::unix::prelude::{FromRawFd, OsStrExt}; - -pub fn wasi_fd_close(vmctx: &mut Vmctx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t { - let mut ctx = vmctx.get_embed_ctx_mut::(); - let fd = dec_fd(fd); - if let Some(fdent) = ctx.fds.get(&fd) { - // can't close preopened files - if fdent.preopen_path.is_some() { - return wasm32::__WASI_ENOTSUP; - } - } - if let Some(mut fdent) = ctx.fds.remove(&fd) { - fdent.fd_object.needs_close = false; - match nix::unistd::close(fdent.fd_object.rawfd) { - Ok(_) => wasm32::__WASI_ESUCCESS, - Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()), - } - } else { - wasm32::__WASI_EBADF - } -} - -pub fn wasi_fd_fdstat_get( - vmctx: &mut Vmctx, - fd: wasm32::__wasi_fd_t, - fdstat_ptr: wasm32::uintptr_t, // *mut wasm32::__wasi_fdstat_t -) -> wasm32::__wasi_errno_t { - let host_fd = dec_fd(fd); - let mut host_fdstat = match dec_fdstat_byref(vmctx, fdstat_ptr) { - Ok(host_fdstat) => host_fdstat, - Err(e) => return enc_errno(e), - }; - - let ctx = vmctx.get_embed_ctx::(); - let errno = if let Some(fe) = ctx.fds.get(&host_fd) { - host_fdstat.fs_filetype = fe.fd_object.ty; - host_fdstat.fs_rights_base = fe.rights_base; - host_fdstat.fs_rights_inheriting = fe.rights_inheriting; - use nix::fcntl::{fcntl, OFlag, F_GETFL}; - match fcntl(fe.fd_object.rawfd, F_GETFL).map(OFlag::from_bits_truncate) { - Ok(flags) => { - host_fdstat.fs_flags = host::fdflags_from_nix(flags); - wasm32::__WASI_ESUCCESS - } - Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()), - } - } else { - wasm32::__WASI_EBADF - }; - enc_fdstat_byref(vmctx, fdstat_ptr, host_fdstat) - .expect("can write back into the pointer we read from"); - errno -} - -pub fn wasi_fd_fdstat_set_flags( - vmctx: &mut Vmctx, - fd: wasm32::__wasi_fd_t, - fdflags: wasm32::__wasi_fdflags_t, -) -> wasm32::__wasi_errno_t { - let host_fd = dec_fd(fd); - let host_fdflags = dec_fdflags(fdflags); - let nix_flags = host::nix_from_fdflags(host_fdflags); - - let ctx = vmctx.get_embed_ctx::(); - if let Some(fe) = ctx.fds.get(&host_fd) { - match nix::fcntl::fcntl(fe.fd_object.rawfd, nix::fcntl::F_SETFL(nix_flags)) { - Ok(_) => wasm32::__WASI_ESUCCESS, - Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()), - } - } else { - wasm32::__WASI_EBADF - } -} - -pub fn wasi_fd_tell( - vmctx: &mut Vmctx, - fd: wasm32::__wasi_fd_t, - offset: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - let ctx = vmctx.get_embed_ctx::(); - let fd = dec_fd(fd); - - let host_offset = { - use nix::unistd::{lseek, Whence}; - - let rights = host::__WASI_RIGHT_FD_TELL; - match ctx.get_fd_entry(fd, rights.into(), 0) { - Ok(fe) => match lseek(fe.fd_object.rawfd, 0, Whence::SeekCur) { - Ok(newoffset) => newoffset, - Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), - }, - Err(e) => return enc_errno(e), - } - }; - enc_filesize_byref(vmctx, offset, host_offset as u64) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) -} - -pub fn wasi_fd_seek( - vmctx: &mut Vmctx, - fd: wasm32::__wasi_fd_t, - offset: wasm32::__wasi_filedelta_t, - whence: wasm32::__wasi_whence_t, - newoffset: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - let ctx = vmctx.get_embed_ctx::(); - let fd = dec_fd(fd); - let offset = dec_filedelta(offset); - let whence = dec_whence(whence); - - let host_newoffset = { - use nix::unistd::{lseek, Whence}; - let nwhence = match u32::from(whence) { - host::__WASI_WHENCE_CUR => Whence::SeekCur, - host::__WASI_WHENCE_END => Whence::SeekEnd, - host::__WASI_WHENCE_SET => Whence::SeekSet, - _ => return wasm32::__WASI_EINVAL, - }; - - let rights = if offset == 0 && whence as u32 == host::__WASI_WHENCE_CUR { - host::__WASI_RIGHT_FD_TELL - } else { - host::__WASI_RIGHT_FD_SEEK | host::__WASI_RIGHT_FD_TELL - }; - match ctx.get_fd_entry(fd, rights.into(), 0) { - Ok(fe) => match lseek(fe.fd_object.rawfd, offset, nwhence) { - Ok(newoffset) => newoffset, - Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), - }, - Err(e) => return enc_errno(e), - } - }; - enc_filesize_byref(vmctx, newoffset, host_newoffset as u64) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) -} - -pub fn wasi_fd_prestat_get( - vmctx: &mut Vmctx, - fd: wasm32::__wasi_fd_t, - prestat_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - let ctx = vmctx.get_embed_ctx::(); - let fd = dec_fd(fd); - - let rights = host::__WASI_RIGHT_PATH_OPEN; - match ctx.get_fd_entry(fd, rights.into(), 0) { - Ok(fe) => { - if let Some(po_path) = &fe.preopen_path { - if fe.fd_object.ty != host::__WASI_FILETYPE_DIRECTORY as host::__wasi_filetype_t { - return wasm32::__WASI_ENOTDIR; - } - enc_prestat_byref( - vmctx, - prestat_ptr, - host::__wasi_prestat_t { - pr_type: host::__WASI_PREOPENTYPE_DIR as host::__wasi_preopentype_t, - u: host::__wasi_prestat_t___wasi_prestat_u { - dir: host::__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t { - pr_name_len: po_path.as_os_str().as_bytes().len(), - }, - }, - }, - ) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } else { - wasm32::__WASI_ENOTSUP - } - } - Err(e) => enc_errno(e), - } -} - -pub fn wasi_fd_prestat_dir_name( - vmctx: &mut Vmctx, - fd: wasm32::__wasi_fd_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, -) -> wasm32::__wasi_errno_t { - let ctx = vmctx.get_embed_ctx::(); - let fd = dec_fd(fd); - let rights = host::__WASI_RIGHT_PATH_OPEN; - match ctx.get_fd_entry(fd, rights.into(), 0) { - Ok(fe) => { - if let Some(po_path) = &fe.preopen_path { - if fe.fd_object.ty != host::__WASI_FILETYPE_DIRECTORY as host::__wasi_filetype_t { - return wasm32::__WASI_ENOTDIR; - } - let path_bytes = po_path.as_os_str().as_bytes(); - if path_bytes.len() > dec_usize(path_len) { - return wasm32::__WASI_ENAMETOOLONG; - } - enc_slice_of(vmctx, path_bytes, path_ptr) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } else { - wasm32::__WASI_ENOTSUP - } - } - Err(e) => enc_errno(e), - } -} - -pub fn wasi_fd_read( - vmctx: &mut Vmctx, - fd: wasm32::__wasi_fd_t, - iovs_ptr: wasm32::uintptr_t, - iovs_len: wasm32::size_t, - nread: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - use nix::sys::uio::{readv, IoVec}; - - let fd = dec_fd(fd); - let mut iovs = match dec_iovec_slice(vmctx, iovs_ptr, iovs_len) { - Ok(iovs) => iovs, - Err(e) => return enc_errno(e), - }; - - let mut ctx = vmctx.get_embed_ctx_mut::(); - let rights = host::__WASI_RIGHT_FD_READ; - let fe = match ctx.get_fd_entry(fd, rights.into(), 0) { - Ok(fe) => fe, - Err(e) => return enc_errno(e), - }; - - let mut iovs: Vec> = iovs - .iter_mut() - .map(|iov| unsafe { host::iovec_to_nix_mut(iov) }) - .collect(); - - let host_nread = match readv(fe.fd_object.rawfd, &mut iovs) { - Ok(len) => len, - Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), - }; - - if host_nread == 0 { - // we hit eof, so remove the fdentry from the context - let mut fe = ctx.fds.remove(&fd).expect("file entry is still there"); - fe.fd_object.needs_close = false; - } - enc_usize_byref(vmctx, nread, host_nread) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) -} - -pub fn wasi_fd_write( - vmctx: &mut Vmctx, - fd: wasm32::__wasi_fd_t, - iovs_ptr: wasm32::uintptr_t, - iovs_len: wasm32::size_t, - nwritten: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - use nix::sys::uio::{writev, IoVec}; - - let fd = dec_fd(fd); - let iovs = match dec_ciovec_slice(vmctx, iovs_ptr, iovs_len) { - Ok(iovs) => iovs, - Err(e) => return enc_errno(e), - }; - - let ctx = vmctx.get_embed_ctx::(); - let rights = host::__WASI_RIGHT_FD_WRITE; - let fe = match ctx.get_fd_entry(fd, rights.into(), 0) { - Ok(fe) => fe, - Err(e) => return enc_errno(e), - }; - - let iovs: Vec> = iovs - .iter() - .map(|iov| unsafe { host::ciovec_to_nix(iov) }) - .collect(); - - let host_nwritten = match writev(fe.fd_object.rawfd, &iovs) { - Ok(len) => len, - Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), - }; - enc_usize_byref(vmctx, nwritten, host_nwritten) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) -} - -pub fn wasi_path_open( - vmctx: &mut Vmctx, - dirfd: wasm32::__wasi_fd_t, - dirflags: wasm32::__wasi_lookupflags_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, - oflags: wasm32::__wasi_oflags_t, - fs_rights_base: wasm32::__wasi_rights_t, - fs_rights_inheriting: wasm32::__wasi_rights_t, - fs_flags: wasm32::__wasi_fdflags_t, - fd_out_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - use nix::errno::Errno; - use nix::fcntl::{openat, AtFlags, OFlag}; - use nix::sys::stat::{fstatat, Mode, SFlag}; - - let dirfd = dec_fd(dirfd); - let dirflags = dec_lookupflags(dirflags); - let oflags = dec_oflags(oflags); - let fs_rights_base = dec_rights(fs_rights_base); - let fs_rights_inheriting = dec_rights(fs_rights_inheriting); - let fs_flags = dec_fdflags(fs_flags); - - // which open mode do we need? - let read = fs_rights_base - & ((host::__WASI_RIGHT_FD_READ | host::__WASI_RIGHT_FD_READDIR) as host::__wasi_rights_t) - != 0; - let write = fs_rights_base - & ((host::__WASI_RIGHT_FD_DATASYNC - | host::__WASI_RIGHT_FD_WRITE - | host::__WASI_RIGHT_FD_ALLOCATE - | host::__WASI_RIGHT_FD_FILESTAT_SET_SIZE) as host::__wasi_rights_t) - != 0; - - let mut nix_all_oflags = if read && write { - OFlag::O_RDWR - } else if read { - OFlag::O_RDONLY - } else { - OFlag::O_WRONLY - }; - - // on non-Capsicum systems, we always want nofollow - nix_all_oflags.insert(OFlag::O_NOFOLLOW); - - // which rights are needed on the dirfd? - let mut needed_base = host::__WASI_RIGHT_PATH_OPEN as host::__wasi_rights_t; - let mut needed_inheriting = fs_rights_base | fs_rights_inheriting; - - // convert open flags - let nix_oflags = host::nix_from_oflags(oflags); - nix_all_oflags.insert(nix_oflags); - if nix_all_oflags.contains(OFlag::O_CREAT) { - needed_base |= host::__WASI_RIGHT_PATH_CREATE_FILE as host::__wasi_rights_t; - } - if nix_all_oflags.contains(OFlag::O_TRUNC) { - needed_base |= host::__WASI_RIGHT_PATH_FILESTAT_SET_SIZE as host::__wasi_rights_t; - } - - // convert file descriptor flags - nix_all_oflags.insert(host::nix_from_fdflags(fs_flags)); - if nix_all_oflags.contains(OFlag::O_DSYNC) { - needed_inheriting |= host::__WASI_RIGHT_FD_DATASYNC as host::__wasi_rights_t; - } - if nix_all_oflags.intersects(O_RSYNC | OFlag::O_SYNC) { - needed_inheriting |= host::__WASI_RIGHT_FD_SYNC as host::__wasi_rights_t; - } - if nix_all_oflags.contains(OFlag::O_DIRECTORY) { - nix_all_oflags.remove(OFlag::O_RDWR); - nix_all_oflags.remove(OFlag::O_WRONLY); - nix_all_oflags.insert(OFlag::O_RDONLY); - } - let path = match dec_slice_of::(vmctx, path_ptr, path_len) { - Ok(path_bytes) => OsStr::from_bytes(path_bytes), - Err(e) => return enc_errno(e), - }; - - let (dir, path) = match path_get( - &vmctx, - dirfd, - dirflags, - path, - needed_base, - needed_inheriting, - nix_oflags.contains(OFlag::O_CREAT), - ) { - Ok((dir, path)) => (dir, path), - Err(e) => return enc_errno(e), - }; - - // Call openat. Use mode 0o666 so that we follow whatever the user's - // umask is, but don't set the executable flag, because it isn't yet - // meaningful for WASI programs to create executable files. - let new_fd = match openat( - dir, - path.as_os_str(), - nix_all_oflags, - Mode::from_bits_truncate(0o666), - ) { - Ok(fd) => fd, - Err(e) => { - match e.as_errno() { - // Linux returns ENXIO instead of EOPNOTSUPP when opening a socket - Some(Errno::ENXIO) => { - if let Ok(stat) = fstatat(dir, path.as_os_str(), AtFlags::AT_SYMLINK_NOFOLLOW) { - if SFlag::from_bits_truncate(stat.st_mode).contains(SFlag::S_IFSOCK) { - return wasm32::__WASI_ENOTSUP; - } else { - return wasm32::__WASI_ENXIO; - } - } else { - return wasm32::__WASI_ENXIO; - } - } - // Linux returns ENOTDIR instead of ELOOP when using O_NOFOLLOW|O_DIRECTORY - // on a symlink. - Some(Errno::ENOTDIR) - if !(nix_all_oflags & (OFlag::O_NOFOLLOW | OFlag::O_DIRECTORY)).is_empty() => - { - if let Ok(stat) = fstatat(dir, path.as_os_str(), AtFlags::AT_SYMLINK_NOFOLLOW) { - if SFlag::from_bits_truncate(stat.st_mode).contains(SFlag::S_IFLNK) { - return wasm32::__WASI_ELOOP; - } - } - return wasm32::__WASI_ENOTDIR; - } - // FreeBSD returns EMLINK instead of ELOOP when using O_NOFOLLOW on - // a symlink. - Some(Errno::EMLINK) if !(nix_all_oflags & OFlag::O_NOFOLLOW).is_empty() => { - return wasm32::__WASI_ELOOP; - } - Some(e) => return wasm32::errno_from_nix(e), - None => return wasm32::__WASI_ENOSYS, - } - } - }; - - // Determine the type of the new file descriptor and which rights contradict with this type - let guest_fd = match unsafe { determine_type_rights(new_fd) } { - Err(e) => { - // if `close` fails, note it but do not override the underlying errno - nix::unistd::close(new_fd).unwrap_or_else(|e| { - dbg!(e); - }); - if let Err(e) = enc_fd_byref(vmctx, fd_out_ptr, wasm32::__wasi_fd_t::max_value()) { - return enc_errno(e); - } - return enc_errno(e); - } - Ok((_ty, max_base, max_inheriting)) => { - let mut fe = unsafe { FdEntry::from_raw_fd(new_fd) }; - fe.rights_base &= max_base; - fe.rights_inheriting &= max_inheriting; - match vmctx.get_embed_ctx_mut::().insert_fd_entry(fe) { - Ok(fd) => fd, - Err(e) => return enc_errno(e), - } - } - }; - enc_fd_byref(vmctx, fd_out_ptr, guest_fd) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) -} - -pub fn wasi_fd_filestat_get( - vmctx: &mut Vmctx, - fd: wasm32::__wasi_fd_t, - filestat_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - use nix::sys::stat::fstat; - - let host_fd = dec_fd(fd); - let ctx = vmctx.get_embed_ctx::(); - - let rights = host::__WASI_RIGHT_FD_FILESTAT_GET; - match ctx.get_fd_entry(host_fd, rights.into(), 0) { - Ok(fe) => match fstat(fe.fd_object.rawfd) { - Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), - Ok(filestat) => { - let host_filestat = host::filestat_from_nix(filestat); - enc_filestat_byref(vmctx, filestat_ptr, host_filestat) - .expect("can write into the pointer"); - } - }, - Err(e) => return enc_errno(e), - } - wasm32::__WASI_ESUCCESS -} - -pub fn wasi_path_filestat_get( - vmctx: &mut Vmctx, - dirfd: wasm32::__wasi_fd_t, - dirflags: wasm32::__wasi_lookupflags_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, - filestat_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - use nix::fcntl::AtFlags; - use nix::sys::stat::fstatat; - - let dirfd = dec_fd(dirfd); - let dirflags = dec_lookupflags(dirflags); - let path = match dec_slice_of::(vmctx, path_ptr, path_len) { - Ok(path_bytes) => OsStr::from_bytes(path_bytes), - Err(e) => return enc_errno(e), - }; - let rights = host::__WASI_RIGHT_PATH_FILESTAT_GET; - let (dir, path) = match path_get(&vmctx, dirfd, dirflags, path, rights.into(), 0, false) { - Ok((dir, path)) => (dir, path), - Err(e) => return enc_errno(e), - }; - let atflags = match dirflags { - wasm32::__WASI_LOOKUP_SYMLINK_FOLLOW => AtFlags::empty(), - _ => AtFlags::AT_SYMLINK_NOFOLLOW, - }; - match fstatat(dir, path.as_os_str(), atflags) { - Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()), - Ok(filestat) => { - let host_filestat = host::filestat_from_nix(filestat); - enc_filestat_byref(vmctx, filestat_ptr, host_filestat) - .expect("can write into the pointer"); - wasm32::__WASI_ESUCCESS - } - } -} - -pub fn wasi_path_create_directory( - vmctx: &mut Vmctx, - dirfd: wasm32::__wasi_fd_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, -) -> wasm32::__wasi_errno_t { - use nix::errno; - use nix::libc::mkdirat; - - let dirfd = dec_fd(dirfd); - let path = match dec_slice_of::(vmctx, path_ptr, path_len) { - Ok(path_bytes) => OsStr::from_bytes(path_bytes), - Err(e) => return enc_errno(e), - }; - let rights = host::__WASI_RIGHT_PATH_CREATE_DIRECTORY; - let (dir, path) = match path_get(&vmctx, dirfd, 0, path, rights.into(), 0, false) { - Ok((dir, path)) => (dir, path), - Err(e) => return enc_errno(e), - }; - let path_cstr = match std::ffi::CString::new(path.as_os_str().as_bytes()) { - Ok(path_cstr) => path_cstr, - Err(_) => return wasm32::__WASI_EINVAL, - }; - // nix doesn't expose mkdirat() yet - match unsafe { mkdirat(dir, path_cstr.as_ptr(), 0o777) } { - 0 => wasm32::__WASI_ESUCCESS, - _ => wasm32::errno_from_nix(errno::Errno::last()), - } -} - -pub fn wasi_path_unlink_file( - vmctx: &mut Vmctx, - dirfd: wasm32::__wasi_fd_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, -) -> wasm32::__wasi_errno_t { - use nix::errno; - use nix::libc::unlinkat; - - let dirfd = dec_fd(dirfd); - let path = match dec_slice_of::(vmctx, path_ptr, path_len) { - Ok(path_bytes) => OsStr::from_bytes(path_bytes), - Err(e) => return enc_errno(e), - }; - let rights = host::__WASI_RIGHT_PATH_UNLINK_FILE; - let (dir, path) = match path_get(&vmctx, dirfd, 0, path, rights.into(), 0, false) { - Ok((dir, path)) => (dir, path), - Err(e) => return enc_errno(e), - }; - let path_cstr = match std::ffi::CString::new(path.as_os_str().as_bytes()) { - Ok(path_cstr) => path_cstr, - Err(_) => return wasm32::__WASI_EINVAL, - }; - // nix doesn't expose unlinkat() yet - match unsafe { unlinkat(dir, path_cstr.as_ptr(), 0) } { - 0 => wasm32::__WASI_ESUCCESS, - _ => { - let mut e = errno::Errno::last(); - // Non-Linux implementations may return EPERM when attempting to remove a - // directory without `REMOVEDIR`. For WASI, adjust this to `EISDIR`. - #[cfg(not(linux))] - { - use nix::fcntl::AtFlags; - use nix::sys::stat::{fstatat, SFlag}; - if e == errno::Errno::EPERM { - if let Ok(stat) = fstatat(dir, path.as_os_str(), AtFlags::AT_SYMLINK_NOFOLLOW) { - if SFlag::from_bits_truncate(stat.st_mode).contains(SFlag::S_IFDIR) { - e = errno::Errno::EISDIR; - } - } else { - e = errno::Errno::last(); - } - } - } - wasm32::errno_from_nix(e) - } - } -} - -pub fn wasi_fd_allocate( - vmctx: &mut Vmctx, - fd: wasm32::__wasi_fd_t, - offset: wasm32::__wasi_filesize_t, - len: wasm32::__wasi_filesize_t, -) -> wasm32::__wasi_errno_t { - let host_fd = dec_fd(fd); - let ctx = vmctx.get_embed_ctx::(); - let rights = host::__WASI_RIGHT_FD_ALLOCATE; - let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) { - Ok(fe) => fe, - Err(e) => return enc_errno(e), - }; - let offset = dec_filesize(offset); - let len = dec_filesize(len); - - #[cfg(target_os = "linux")] - { - let res = - unsafe { libc::posix_fallocate(fe.fd_object.rawfd, offset as off_t, len as off_t) }; - if res != 0 { - return wasm32::errno_from_nix(nix::errno::Errno::last()); - } - } - - #[cfg(not(target_os = "linux"))] - { - use nix::sys::stat::fstat; - use nix::unistd::ftruncate; - - match fstat(fe.fd_object.rawfd) { - Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), - Ok(st) => { - let current_size = st.st_size as u64; - let wanted_size = match offset.checked_add(len) { - Some(wanted_size) => wanted_size, - None => return wasm32::__WASI_E2BIG, - }; - if wanted_size > i64::max_value() as u64 { - return wasm32::__WASI_E2BIG; - } - if wanted_size > current_size { - if let Err(e) = ftruncate(fe.fd_object.rawfd, wanted_size as off_t) { - return wasm32::errno_from_nix(e.as_errno().unwrap()); - } - } - } - } - } - - wasm32::__WASI_ESUCCESS -} - -pub fn wasi_fd_advise( - vmctx: &mut Vmctx, - fd: wasm32::__wasi_fd_t, - offset: wasm32::__wasi_filesize_t, - len: wasm32::__wasi_filesize_t, - advice: wasm32::__wasi_advice_t, -) -> wasm32::__wasi_errno_t { - let host_fd = dec_fd(fd); - let ctx = vmctx.get_embed_ctx::(); - let rights = host::__WASI_RIGHT_FD_ADVISE; - let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) { - Ok(fe) => fe, - Err(e) => return enc_errno(e), - }; - let advice = dec_advice(advice); - - #[cfg(target_os = "linux")] - { - let host_advice = match advice as u32 { - host::__WASI_ADVICE_DONTNEED => libc::POSIX_FADV_DONTNEED, - host::__WASI_ADVICE_SEQUENTIAL => libc::POSIX_FADV_SEQUENTIAL, - host::__WASI_ADVICE_WILLNEED => libc::POSIX_FADV_DONTNEED, - host::__WASI_ADVICE_NOREUSE => libc::POSIX_FADV_NOREUSE, - host::__WASI_ADVICE_RANDOM => libc::POSIX_FADV_RANDOM, - host::__WASI_ADVICE_NORMAL => libc::POSIX_FADV_NORMAL, - _ => return wasm32::__WASI_EINVAL, - }; - let offset = dec_filesize(offset); - let len = dec_filesize(len); - let res = unsafe { - libc::posix_fadvise( - fe.fd_object.rawfd, - offset as off_t, - len as off_t, - host_advice, - ) - }; - if res != 0 { - return wasm32::errno_from_nix(nix::errno::Errno::last()); - } - } - - #[cfg(not(target_os = "linux"))] - { - let _ = (fe, offset, len); - match advice as u32 { - host::__WASI_ADVICE_DONTNEED - | host::__WASI_ADVICE_SEQUENTIAL - | host::__WASI_ADVICE_WILLNEED - | host::__WASI_ADVICE_NOREUSE - | host::__WASI_ADVICE_RANDOM - | host::__WASI_ADVICE_NORMAL => {} - _ => return wasm32::__WASI_EINVAL, - } - } - - wasm32::__WASI_ESUCCESS -} - -pub fn wasi_fd_datasync(vmctx: &mut Vmctx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t { - let host_fd = dec_fd(fd); - let ctx = vmctx.get_embed_ctx::(); - let rights = host::__WASI_RIGHT_FD_DATASYNC; - let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) { - Ok(fe) => fe, - Err(e) => return enc_errno(e), - }; - let res; - - #[cfg(target_os = "linux")] - { - res = nix::unistd::fdatasync(fe.fd_object.rawfd); - } - - #[cfg(not(target_os = "linux"))] - { - res = nix::unistd::fsync(fe.fd_object.rawfd); - } - - if let Err(e) = res { - return wasm32::errno_from_nix(e.as_errno().unwrap()); - } - wasm32::__WASI_ESUCCESS -} - -pub fn wasi_fd_sync(vmctx: &mut Vmctx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t { - let host_fd = dec_fd(fd); - let ctx = vmctx.get_embed_ctx::(); - let rights = host::__WASI_RIGHT_FD_SYNC; - let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) { - Ok(fe) => fe, - Err(e) => return enc_errno(e), - }; - let res = nix::unistd::fsync(fe.fd_object.rawfd); - if let Err(e) = res { - return wasm32::errno_from_nix(e.as_errno().unwrap()); - } - wasm32::__WASI_ESUCCESS -} - -pub fn wasi_fd_fdstat_set_rights( - vmctx: &mut Vmctx, - fd: wasm32::__wasi_fd_t, - fs_rights_base: wasm32::__wasi_rights_t, - fs_rights_inheriting: wasm32::__wasi_rights_t, -) -> wasm32::__wasi_errno_t { - let host_fd = dec_fd(fd); - let mut ctx = vmctx.get_embed_ctx_mut::(); - let fe = match ctx.fds.get_mut(&host_fd) { - Some(fe) => fe, - None => return wasm32::__WASI_EBADF, - }; - if fe.rights_base & fs_rights_base != fs_rights_base - || fe.rights_inheriting & fs_rights_inheriting != fs_rights_inheriting - { - return wasm32::__WASI_ENOTCAPABLE; - } - fe.rights_base = fs_rights_base; - fe.rights_inheriting = fs_rights_inheriting; - wasm32::__WASI_ESUCCESS -} - -pub fn wasi_fd_filestat_set_size( - vmctx: &mut Vmctx, - fd: wasm32::__wasi_fd_t, - st_size: wasm32::__wasi_filesize_t, -) -> wasm32::__wasi_errno_t { - use nix::unistd::ftruncate; - - let host_fd = dec_fd(fd); - let ctx = vmctx.get_embed_ctx::(); - let rights = host::__WASI_RIGHT_FD_FILESTAT_SET_SIZE; - let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) { - Ok(fe) => fe, - Err(e) => return enc_errno(e), - }; - let st_size = dec_filesize(st_size); - if st_size > i64::max_value() as u64 { - return wasm32::__WASI_E2BIG; - } - if let Err(e) = ftruncate(fe.fd_object.rawfd, st_size as off_t) { - return wasm32::errno_from_nix(e.as_errno().unwrap()); - } - wasm32::__WASI_ESUCCESS -} - -pub fn wasi_fd_filestat_set_times( - vmctx: &mut Vmctx, - fd: wasm32::__wasi_fd_t, - st_atim: wasm32::__wasi_timestamp_t, - st_mtim: wasm32::__wasi_timestamp_t, - fst_flags: wasm32::__wasi_fstflags_t, -) -> wasm32::__wasi_errno_t { - use nix::sys::time::{TimeSpec, TimeValLike}; - - let host_fd = dec_fd(fd); - let ctx = vmctx.get_embed_ctx::(); - let rights = host::__WASI_RIGHT_FD_FILESTAT_SET_TIMES; - let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) { - Ok(fe) => fe, - Err(e) => return enc_errno(e), - }; - let st_atim = dec_timestamp(st_atim); - let mut st_mtim = dec_timestamp(st_mtim); - let fst_flags = dec_fstflags(fst_flags); - if fst_flags & (host::__WASI_FILESTAT_SET_MTIM_NOW as host::__wasi_fstflags_t) != 0 { - let clock_id = libc::CLOCK_REALTIME; - let mut timespec = MaybeUninit::::uninit(); - let res = unsafe { libc::clock_gettime(clock_id, timespec.as_mut_ptr()) }; - if res != 0 { - return wasm32::errno_from_nix(nix::errno::Errno::last()); - } - let timespec = unsafe { timespec.assume_init() }; - let time_ns = match (timespec.tv_sec as host::__wasi_timestamp_t) - .checked_mul(1_000_000_000) - .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t)) - { - Some(time_ns) => time_ns, - None => return wasm32::__WASI_EOVERFLOW, - }; - st_mtim = time_ns; - } - let ts_atime = match fst_flags as u32 { - f if f & host::__WASI_FILESTAT_SET_ATIM_NOW != 0 => libc::timespec { - tv_sec: 0, - tv_nsec: utime_now(), - }, - f if f & host::__WASI_FILESTAT_SET_ATIM != 0 => { - *TimeSpec::nanoseconds(st_atim as i64).as_ref() - } - _ => libc::timespec { - tv_sec: 0, - tv_nsec: utime_omit(), - }, - }; - let ts_mtime = *TimeSpec::nanoseconds(st_mtim as i64).as_ref(); - let times = [ts_atime, ts_mtime]; - let res = unsafe { libc::futimens(fe.fd_object.rawfd, times.as_ptr()) }; - if res != 0 { - return wasm32::errno_from_nix(nix::errno::Errno::last()); - } - wasm32::__WASI_ESUCCESS -} - -pub fn wasi_path_filestat_set_times( - vmctx: &mut Vmctx, - dirfd: wasm32::__wasi_fd_t, - dirflags: wasm32::__wasi_lookupflags_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, - st_atim: wasm32::__wasi_timestamp_t, - st_mtim: wasm32::__wasi_timestamp_t, - fst_flags: wasm32::__wasi_fstflags_t, -) -> wasm32::__wasi_errno_t { - use nix::sys::time::{TimeSpec, TimeValLike}; - - let dirfd = dec_fd(dirfd); - let dirflags = dec_lookupflags(dirflags); - let path = match dec_slice_of::(vmctx, path_ptr, path_len) { - Ok(path_bytes) => OsStr::from_bytes(path_bytes), - Err(e) => return enc_errno(e), - }; - let rights = host::__WASI_RIGHT_PATH_FILESTAT_SET_TIMES; - let (dir, path) = match path_get(&vmctx, dirfd, dirflags, path, rights.into(), 0, false) { - Ok((dir, path)) => (dir, path), - Err(e) => return enc_errno(e), - }; - let atflags = match dirflags { - wasm32::__WASI_LOOKUP_SYMLINK_FOLLOW => 0, - _ => libc::AT_SYMLINK_NOFOLLOW, - }; - let st_atim = dec_timestamp(st_atim); - let mut st_mtim = dec_timestamp(st_mtim); - let fst_flags = dec_fstflags(fst_flags); - if fst_flags & (host::__WASI_FILESTAT_SET_MTIM_NOW as host::__wasi_fstflags_t) != 0 { - let clock_id = libc::CLOCK_REALTIME; - let mut timespec = MaybeUninit::::uninit(); - let res = unsafe { libc::clock_gettime(clock_id, timespec.as_mut_ptr()) }; - if res != 0 { - return wasm32::errno_from_nix(nix::errno::Errno::last()); - } - let timespec = unsafe { timespec.assume_init() }; - let time_ns = match (timespec.tv_sec as host::__wasi_timestamp_t) - .checked_mul(1_000_000_000) - .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t)) - { - Some(time_ns) => time_ns, - None => return wasm32::__WASI_EOVERFLOW, - }; - st_mtim = time_ns; - } - let ts_atime = match fst_flags as u32 { - f if f & host::__WASI_FILESTAT_SET_ATIM_NOW != 0 => libc::timespec { - tv_sec: 0, - tv_nsec: utime_now(), - }, - f if f & host::__WASI_FILESTAT_SET_ATIM != 0 => { - *TimeSpec::nanoseconds(st_atim as i64).as_ref() - } - _ => libc::timespec { - tv_sec: 0, - tv_nsec: utime_omit(), - }, - }; - let ts_mtime = *TimeSpec::nanoseconds(st_mtim as i64).as_ref(); - let times = [ts_atime, ts_mtime]; - let path_cstr = match std::ffi::CString::new(path.as_os_str().as_bytes()) { - Ok(path_cstr) => path_cstr, - Err(_) => return wasm32::__WASI_EINVAL, - }; - let res = unsafe { libc::utimensat(dir, path_cstr.as_ptr(), times.as_ptr(), atflags) }; - if res != 0 { - return wasm32::errno_from_nix(nix::errno::Errno::last()); - } - wasm32::__WASI_ESUCCESS -} - -pub fn wasi_fd_pread( - vmctx: &mut Vmctx, - fd: wasm32::__wasi_fd_t, - iovs_ptr: wasm32::uintptr_t, - iovs_len: wasm32::size_t, - offset: wasm32::__wasi_filesize_t, - nread: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - use nix::sys::uio::pread; - use std::cmp; - - let fd = dec_fd(fd); - let iovs = match dec_iovec_slice(vmctx, iovs_ptr, iovs_len) { - Ok(iovs) => iovs, - Err(e) => return enc_errno(e), - }; - let ctx = vmctx.get_embed_ctx::(); - let rights = host::__WASI_RIGHT_FD_READ; - let fe = match ctx.get_fd_entry(fd, rights.into(), 0) { - Ok(fe) => fe, - Err(e) => return enc_errno(e), - }; - let offset = dec_filesize(offset); - if offset > i64::max_value() as u64 { - return wasm32::__WASI_EIO; - } - let buf_size = iovs.iter().map(|v| v.buf_len).sum(); - let mut buf = vec![0; buf_size]; - let host_nread = match pread(fe.fd_object.rawfd, &mut buf, offset as off_t) { - Ok(len) => len, - Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), - }; - let mut buf_offset = 0; - let mut left = host_nread; - for iov in &iovs { - if left == 0 { - break; - } - let vec_len = cmp::min(iov.buf_len, left); - unsafe { std::slice::from_raw_parts_mut(iov.buf as *mut u8, vec_len) } - .copy_from_slice(&buf[buf_offset..buf_offset + vec_len]); - buf_offset += vec_len; - left -= vec_len; - } - enc_usize_byref(vmctx, nread, host_nread) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) -} - -pub fn wasi_fd_pwrite( - vmctx: &mut Vmctx, - fd: wasm32::__wasi_fd_t, - iovs_ptr: wasm32::uintptr_t, - iovs_len: wasm32::size_t, - offset: wasm32::__wasi_filesize_t, - nwritten: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - use nix::sys::uio::pwrite; - - let fd = dec_fd(fd); - let iovs = match dec_iovec_slice(vmctx, iovs_ptr, iovs_len) { - Ok(iovs) => iovs, - Err(e) => return enc_errno(e), - }; - let ctx = vmctx.get_embed_ctx::(); - let rights = host::__WASI_RIGHT_FD_READ; - let fe = match ctx.get_fd_entry(fd, rights.into(), 0) { - Ok(fe) => fe, - Err(e) => return enc_errno(e), - }; - let offset = dec_filesize(offset); - if offset > i64::max_value() as u64 { - return wasm32::__WASI_EIO; - } - let buf_size = iovs.iter().map(|v| v.buf_len).sum(); - let mut buf = Vec::with_capacity(buf_size); - for iov in &iovs { - buf.extend_from_slice(unsafe { - std::slice::from_raw_parts(iov.buf as *const u8, iov.buf_len) - }); - } - let host_nwritten = match pwrite(fe.fd_object.rawfd, &buf, offset as off_t) { - Ok(len) => len, - Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), - }; - enc_usize_byref(vmctx, nwritten, host_nwritten) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) -} - -pub fn wasi_fd_readdir( - vmctx: &mut Vmctx, - fd: wasm32::__wasi_fd_t, - buf: wasm32::uintptr_t, - buf_len: wasm32::size_t, - cookie: wasm32::__wasi_dircookie_t, - bufused: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - use libc::{dirent, fdopendir, readdir_r, seekdir}; - - match enc_usize_byref(vmctx, bufused, 0) { - Ok(_) => {} - Err(e) => return enc_errno(e), - }; - let fd = dec_fd(fd); - let ctx = vmctx.get_embed_ctx::(); - let rights = host::__WASI_RIGHT_FD_READDIR; - let fe = match ctx.get_fd_entry(fd, rights.into(), 0) { - Ok(fe) => fe, - Err(e) => return enc_errno(e), - }; - let host_buf = match dec_slice_of::(vmctx, buf, buf_len) { - Ok(host_buf) => host_buf, - Err(e) => return enc_errno(e), - }; - let host_buf_ptr = host_buf.as_ptr(); - let host_buf_len = host_buf.len(); - let dir = unsafe { fdopendir(fe.fd_object.rawfd) }; - if dir.is_null() { - return wasm32::errno_from_nix(nix::errno::Errno::last()); - } - let cookie = dec_dircookie(cookie); - if cookie != wasm32::__WASI_DIRCOOKIE_START { - unsafe { seekdir(dir, cookie as c_long) }; - } - let mut entry_buf = MaybeUninit::::uninit(); - let mut left = host_buf_len; - let mut host_buf_offset: usize = 0; - while left > 0 { - let mut host_entry: *mut dirent = std::ptr::null_mut(); - let res = unsafe { readdir_r(dir, entry_buf.as_mut_ptr(), &mut host_entry) }; - if res == -1 { - return wasm32::errno_from_nix(nix::errno::Errno::last()); - } - if host_entry.is_null() { - break; - } - unsafe { entry_buf.assume_init() }; - let entry: wasm32::__wasi_dirent_t = match dirent_from_host(&unsafe { *host_entry }) { - Ok(entry) => entry, - Err(e) => return enc_errno(e), - }; - let name_len = entry.d_namlen as usize; - let required_space = std::mem::size_of_val(&entry) + name_len; - if required_space > left { - break; - } - unsafe { - let ptr = host_buf_ptr.offset(host_buf_offset as isize) as *mut c_void - as *mut wasm32::__wasi_dirent_t; - *ptr = entry; - } - host_buf_offset += std::mem::size_of_val(&entry); - let name_ptr = unsafe { *host_entry }.d_name.as_ptr(); - unsafe { - std::ptr::copy_nonoverlapping( - name_ptr as *const _, - host_buf_ptr.offset(host_buf_offset as isize) as *mut _, - name_len, - ) - }; - host_buf_offset += name_len; - left -= required_space; - } - let host_bufused = host_buf_len - left; - enc_usize_byref(vmctx, bufused, host_bufused) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) -} - -pub fn wasi_fd_renumber( - vmctx: &mut Vmctx, - from: wasm32::__wasi_fd_t, - to: wasm32::__wasi_fd_t, -) -> wasm32::__wasi_errno_t { - let from = dec_fd(from); - let to = dec_fd(to); - let mut ctx = vmctx.get_embed_ctx_mut::(); - let fe_from = match ctx.fds.get(&from) { - Some(fe_from) => fe_from, - None => return wasm32::__WASI_EBADF, - }; - let fe_to = match ctx.fds.get(&to) { - Some(fe_to) => fe_to, - None => return wasm32::__WASI_EBADF, - }; - if let Err(e) = nix::unistd::dup2(fe_from.fd_object.rawfd, fe_to.fd_object.rawfd) { - return wasm32::errno_from_nix(e.as_errno().unwrap()); - } - let fe_from_rawfd = fe_from.fd_object.rawfd; - ctx.fds.remove(&(fe_from_rawfd as host::__wasi_fd_t)); - - wasm32::__WASI_ESUCCESS -} - -pub fn wasi_path_link( - vmctx: &mut Vmctx, - old_dirfd: wasm32::__wasi_fd_t, - _old_flags: wasm32::__wasi_lookupflags_t, - old_path_ptr: wasm32::uintptr_t, - old_path_len: wasm32::size_t, - new_dirfd: wasm32::__wasi_fd_t, - new_path_ptr: wasm32::uintptr_t, - new_path_len: wasm32::size_t, -) -> wasm32::__wasi_errno_t { - use nix::libc::linkat; - - let old_dirfd = dec_fd(old_dirfd); - let new_dirfd = dec_fd(new_dirfd); - let old_path = match dec_slice_of::(vmctx, old_path_ptr, old_path_len) { - Ok(old_path_bytes) => OsStr::from_bytes(old_path_bytes), - Err(e) => return enc_errno(e), - }; - let new_path = match dec_slice_of::(vmctx, new_path_ptr, new_path_len) { - Ok(new_path_bytes) => OsStr::from_bytes(new_path_bytes), - Err(e) => return enc_errno(e), - }; - let rights = host::__WASI_RIGHT_PATH_LINK_SOURCE; - let (old_dir, old_path) = - match path_get(&vmctx, old_dirfd, 0, old_path, rights.into(), 0, false) { - Ok((dir, path)) => (dir, path), - Err(e) => return enc_errno(e), - }; - let rights = host::__WASI_RIGHT_PATH_LINK_TARGET; - let (new_dir, new_path) = - match path_get(&vmctx, new_dirfd, 0, new_path, rights.into(), 0, false) { - Ok((dir, path)) => (dir, path), - Err(e) => return enc_errno(e), - }; - let old_path_cstr = match std::ffi::CString::new(old_path.as_bytes()) { - Ok(old_path_cstr) => old_path_cstr, - Err(_) => return wasm32::__WASI_EINVAL, - }; - let new_path_cstr = match std::ffi::CString::new(new_path.as_bytes()) { - Ok(new_path_cstr) => new_path_cstr, - Err(_) => return wasm32::__WASI_EINVAL, - }; - - // Not setting AT_SYMLINK_FOLLOW fails on most filesystems - let atflags = libc::AT_SYMLINK_FOLLOW; - let res = unsafe { - linkat( - old_dir, - old_path_cstr.as_ptr(), - new_dir, - new_path_cstr.as_ptr(), - atflags, - ) - }; - if res != 0 { - return wasm32::errno_from_nix(nix::errno::Errno::last()); - } - wasm32::__WASI_ESUCCESS -} - -pub fn wasi_path_readlink( - vmctx: &mut Vmctx, - dirfd: wasm32::__wasi_fd_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, - buf_ptr: wasm32::uintptr_t, - buf_len: wasm32::size_t, - bufused: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - use nix::fcntl::readlinkat; - use std::cmp; - - match enc_usize_byref(vmctx, bufused, 0) { - Ok(_) => {} - Err(e) => return enc_errno(e), - }; - let dirfd = dec_fd(dirfd); - let path = match dec_slice_of::(vmctx, path_ptr, path_len) { - Ok(path_bytes) => OsStr::from_bytes(path_bytes), - Err(e) => return enc_errno(e), - }; - let rights = host::__WASI_RIGHT_PATH_READLINK; - let (dir, path) = match path_get(&vmctx, dirfd, 0, path, rights.into(), 0, false) { - Ok((dir, path)) => (dir, path), - Err(e) => return enc_errno(e), - }; - let dummy_buf = &mut [0u8]; - let mut buf = if buf_len > 0 { - match dec_slice_of_mut::(vmctx, buf_ptr, buf_len) { - Ok(buf) => buf, - Err(e) => return enc_errno(e), - } - } else { - dummy_buf - }; - let target_path = match readlinkat(dir, path.as_os_str(), &mut buf) { - Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()), - Ok(target_path) => target_path, - }; - let host_bufused = cmp::min(buf_len as usize, target_path.len()); - match enc_usize_byref(vmctx, bufused, host_bufused) { - Ok(_) => {} - Err(e) => return enc_errno(e), - }; - wasm32::__WASI_ESUCCESS -} - -pub fn wasi_path_remove_directory( - vmctx: &mut Vmctx, - dirfd: wasm32::__wasi_fd_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, -) -> wasm32::__wasi_errno_t { - use nix::errno; - use nix::libc::{unlinkat, AT_REMOVEDIR}; - - let dirfd = dec_fd(dirfd); - let path = match dec_slice_of::(vmctx, path_ptr, path_len) { - Ok(path_bytes) => OsStr::from_bytes(path_bytes), - Err(e) => return enc_errno(e), - }; - let rights = host::__WASI_RIGHT_PATH_REMOVE_DIRECTORY; - let (dir, path) = match path_get(&vmctx, dirfd, 0, path, rights.into(), 0, false) { - Ok((dir, path)) => (dir, path), - Err(e) => return enc_errno(e), - }; - let path_cstr = match std::ffi::CString::new(path.as_os_str().as_bytes()) { - Ok(path_cstr) => path_cstr, - Err(_) => return wasm32::__WASI_EINVAL, - }; - // nix doesn't expose unlinkat() yet - match unsafe { unlinkat(dir, path_cstr.as_ptr(), AT_REMOVEDIR) } { - 0 => wasm32::__WASI_ESUCCESS, - _ => wasm32::errno_from_nix(errno::Errno::last()), - } -} - -pub fn wasi_path_rename( - vmctx: &mut Vmctx, - old_dirfd: wasm32::__wasi_fd_t, - old_path_ptr: wasm32::uintptr_t, - old_path_len: wasm32::size_t, - new_dirfd: wasm32::__wasi_fd_t, - new_path_ptr: wasm32::uintptr_t, - new_path_len: wasm32::size_t, -) -> wasm32::__wasi_errno_t { - use nix::libc::renameat; - - let old_dirfd = dec_fd(old_dirfd); - let new_dirfd = dec_fd(new_dirfd); - let old_path = match dec_slice_of::(vmctx, old_path_ptr, old_path_len) { - Ok(old_path_bytes) => OsStr::from_bytes(old_path_bytes), - Err(e) => return enc_errno(e), - }; - let new_path = match dec_slice_of::(vmctx, new_path_ptr, new_path_len) { - Ok(new_path_bytes) => OsStr::from_bytes(new_path_bytes), - Err(e) => return enc_errno(e), - }; - let rights = host::__WASI_RIGHT_PATH_RENAME_SOURCE; - let (old_dir, old_path) = - match path_get(&vmctx, old_dirfd, 0, old_path, rights.into(), 0, false) { - Ok((dir, path)) => (dir, path), - Err(e) => return enc_errno(e), - }; - let rights = host::__WASI_RIGHT_PATH_RENAME_TARGET; - let (new_dir, new_path) = - match path_get(&vmctx, new_dirfd, 0, new_path, rights.into(), 0, false) { - Ok((dir, path)) => (dir, path), - Err(e) => return enc_errno(e), - }; - let old_path_cstr = match std::ffi::CString::new(old_path.as_bytes()) { - Ok(old_path_cstr) => old_path_cstr, - Err(_) => return wasm32::__WASI_EINVAL, - }; - let new_path_cstr = match std::ffi::CString::new(new_path.as_bytes()) { - Ok(new_path_cstr) => new_path_cstr, - Err(_) => return wasm32::__WASI_EINVAL, - }; - let res = unsafe { - renameat( - old_dir, - old_path_cstr.as_ptr(), - new_dir, - new_path_cstr.as_ptr(), - ) - }; - if res != 0 { - return wasm32::errno_from_nix(nix::errno::Errno::last()); - } - wasm32::__WASI_ESUCCESS -} - -pub fn wasi_path_symlink( - vmctx: &mut Vmctx, - old_path_ptr: wasm32::uintptr_t, - old_path_len: wasm32::size_t, - dirfd: wasm32::__wasi_fd_t, - new_path_ptr: wasm32::uintptr_t, - new_path_len: wasm32::size_t, -) -> wasm32::__wasi_errno_t { - use nix::libc::symlinkat; - - let dirfd = dec_fd(dirfd); - let old_path = match dec_slice_of::(vmctx, old_path_ptr, old_path_len) { - Ok(old_path_bytes) => OsStr::from_bytes(old_path_bytes), - Err(e) => return enc_errno(e), - }; - let new_path = match dec_slice_of::(vmctx, new_path_ptr, new_path_len) { - Ok(new_path_bytes) => OsStr::from_bytes(new_path_bytes), - Err(e) => return enc_errno(e), - }; - let rights = host::__WASI_RIGHT_PATH_SYMLINK; - let (dir, new_path) = match path_get(&vmctx, dirfd, 0, new_path, rights.into(), 0, false) { - Ok((dir, path)) => (dir, path), - Err(e) => return enc_errno(e), - }; - let old_path_cstr = match std::ffi::CString::new(old_path.as_bytes()) { - Ok(old_path_cstr) => old_path_cstr, - Err(_) => return wasm32::__WASI_EINVAL, - }; - let new_path_cstr = match std::ffi::CString::new(new_path.as_bytes()) { - Ok(new_path_cstr) => new_path_cstr, - Err(_) => return wasm32::__WASI_EINVAL, - }; - let res = unsafe { symlinkat(old_path_cstr.as_ptr(), dir, new_path_cstr.as_ptr()) }; - if res != 0 { - return wasm32::errno_from_nix(nix::errno::Errno::last()); - } - wasm32::__WASI_ESUCCESS -} diff --git a/lucet-wasi/src/hostcalls/fs_helpers.rs b/lucet-wasi/src/hostcalls/fs_helpers.rs deleted file mode 100644 index a82924e48..000000000 --- a/lucet-wasi/src/hostcalls/fs_helpers.rs +++ /dev/null @@ -1,306 +0,0 @@ -#![allow(non_camel_case_types)] -#![allow(unused_unsafe)] -use crate::ctx::WasiCtx; -use crate::host; - -use lucet_runtime::vmctx::Vmctx; - -use nix::libc::{self, c_long}; -use std::ffi::{OsStr, OsString}; -use std::os::unix::prelude::{OsStrExt, OsStringExt, RawFd}; - -#[cfg(target_os = "linux")] -pub const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_RSYNC; - -#[cfg(not(target_os = "linux"))] -pub const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_SYNC; - -/// Normalizes a path to ensure that the target path is located under the directory provided. -/// -/// This is a workaround for not having Capsicum support in the OS. -pub fn path_get>( - vmctx: &Vmctx, - dirfd: host::__wasi_fd_t, - dirflags: host::__wasi_lookupflags_t, - path: P, - needed_base: host::__wasi_rights_t, - needed_inheriting: host::__wasi_rights_t, - needs_final_component: bool, -) -> Result<(RawFd, OsString), host::__wasi_errno_t> { - use nix::errno::Errno; - use nix::fcntl::{openat, readlinkat, OFlag}; - use nix::sys::stat::Mode; - - const MAX_SYMLINK_EXPANSIONS: usize = 128; - - /// close all the intermediate file descriptors, but make sure not to drop either the original - /// dirfd or the one we return (which may be the same dirfd) - fn ret_dir_success(dir_stack: &mut Vec) -> RawFd { - let ret_dir = dir_stack.pop().expect("there is always a dirfd to return"); - if let Some(dirfds) = dir_stack.get(1..) { - for dirfd in dirfds { - nix::unistd::close(*dirfd).unwrap_or_else(|e| { - dbg!(e); - }); - } - } - ret_dir - } - - /// close all file descriptors other than the base directory, and return the errno for - /// convenience with `return` - fn ret_error( - dir_stack: &mut Vec, - errno: host::__wasi_errno_t, - ) -> Result<(RawFd, OsString), host::__wasi_errno_t> { - if let Some(dirfds) = dir_stack.get(1..) { - for dirfd in dirfds { - nix::unistd::close(*dirfd).unwrap_or_else(|e| { - dbg!(e); - }); - } - } - Err(errno) - } - - let ctx = vmctx.get_embed_ctx::(); - - let dirfe = ctx.get_fd_entry(dirfd, needed_base, needed_inheriting)?; - - // Stack of directory file descriptors. Index 0 always corresponds with the directory provided - // to this function. Entering a directory causes a file descriptor to be pushed, while handling - // ".." entries causes an entry to be popped. Index 0 cannot be popped, as this would imply - // escaping the base directory. - let mut dir_stack = vec![dirfe.fd_object.rawfd]; - - // Stack of paths left to process. This is initially the `path` argument to this function, but - // any symlinks we encounter are processed by pushing them on the stack. - let mut path_stack = vec![path.as_ref().to_owned().into_vec()]; - - // Track the number of symlinks we've expanded, so we can return `ELOOP` after too many. - let mut symlink_expansions = 0; - - // Buffer to read links into; defined outside of the loop so we don't reallocate it constantly. - let mut readlink_buf = vec![0u8; libc::PATH_MAX as usize + 1]; - - // TODO: rewrite this using a custom posix path type, with a component iterator that respects - // trailing slashes. This version does way too much allocation, and is way too fiddly. - loop { - let component = if let Some(cur_path) = path_stack.pop() { - // eprintln!( - // "cur_path = {:?}", - // std::str::from_utf8(cur_path.as_slice()).unwrap() - // ); - let mut split = cur_path.splitn(2, |&c| c == b'/'); - let head = split.next(); - let tail = split.next(); - match (head, tail) { - (None, _) => { - // split always returns at least a singleton iterator with an empty slice - panic!("unreachable"); - } - // path is empty - (Some([]), None) => { - return ret_error(&mut dir_stack, host::__WASI_ENOENT as host::__wasi_errno_t); - } - // path starts with `/`, is absolute - (Some([]), Some(_)) => { - return ret_error( - &mut dir_stack, - host::__WASI_ENOTCAPABLE as host::__wasi_errno_t, - ); - } - // the final component of the path with no trailing slash - (Some(component), None) => component.to_vec(), - (Some(component), Some(rest)) => { - if rest.iter().all(|&c| c == b'/') { - // the final component of the path with trailing slashes; put one trailing - // slash back on - let mut component = component.to_vec(); - component.push('/' as u8); - component - } else { - // non-final component; push the rest back on the stack - path_stack.push(rest.to_vec()); - component.to_vec() - } - } - } - } else { - // if the path stack is ever empty, we return rather than going through the loop again - panic!("unreachable"); - }; - - // eprintln!( - // "component = {:?}", - // std::str::from_utf8(component.as_slice()).unwrap() - // ); - - match component.as_slice() { - b"." => { - // skip component - } - b".." => { - // pop a directory - let dirfd = dir_stack.pop().expect("dir_stack is never empty"); - - // we're not allowed to pop past the original directory - if dir_stack.is_empty() { - return ret_error( - &mut dir_stack, - host::__WASI_ENOTCAPABLE as host::__wasi_errno_t, - ); - } else { - nix::unistd::close(dirfd).unwrap_or_else(|e| { - dbg!(e); - }); - } - } - // should the component be a directory? it should if there is more path left to process, or - // if it has a trailing slash and `needs_final_component` is not set - component - if !path_stack.is_empty() - || (component.ends_with(b"/") && !needs_final_component) => - { - match openat( - *dir_stack.last().expect("dir_stack is never empty"), - component, - OFlag::O_RDONLY | OFlag::O_DIRECTORY | OFlag::O_NOFOLLOW, - Mode::empty(), - ) { - Ok(new_dir) => { - dir_stack.push(new_dir); - continue; - } - Err(e) - // Check to see if it was a symlink. Linux indicates - // this with ENOTDIR because of the O_DIRECTORY flag. - if e.as_errno() == Some(Errno::ELOOP) - || e.as_errno() == Some(Errno::EMLINK) - || e.as_errno() == Some(Errno::ENOTDIR) => - { - // attempt symlink expansion - match readlinkat( - *dir_stack.last().expect("dir_stack is never empty"), - component, - readlink_buf.as_mut_slice(), - ) { - Ok(link_path) => { - symlink_expansions += 1; - if symlink_expansions > MAX_SYMLINK_EXPANSIONS { - return ret_error( - &mut dir_stack, - host::__WASI_ELOOP as host::__wasi_errno_t, - ); - } - - let mut link_path = link_path.as_bytes().to_vec(); - - // append a trailing slash if the component leading to it has one, so - // that we preserve any ENOTDIR that might come from trying to open a - // non-directory - if component.ends_with(b"/") { - link_path.push(b'/'); - } - - path_stack.push(link_path); - continue; - } - Err(e) => { - return ret_error( - &mut dir_stack, - host::errno_from_nix(e.as_errno().unwrap()), - ); - } - } - } - Err(e) => { - return ret_error( - &mut dir_stack, - host::errno_from_nix(e.as_errno().unwrap()), - ); - } - } - } - // the final component - component => { - // if there's a trailing slash, or if `LOOKUP_SYMLINK_FOLLOW` is set, attempt - // symlink expansion - if component.ends_with(b"/") || (dirflags & host::__WASI_LOOKUP_SYMLINK_FOLLOW) != 0 - { - match readlinkat( - *dir_stack.last().expect("dir_stack is never empty"), - component, - readlink_buf.as_mut_slice(), - ) { - Ok(link_path) => { - symlink_expansions += 1; - if symlink_expansions > MAX_SYMLINK_EXPANSIONS { - return ret_error( - &mut dir_stack, - host::__WASI_ELOOP as host::__wasi_errno_t, - ); - } - - let mut link_path = link_path.as_bytes().to_vec(); - - // append a trailing slash if the component leading to it has one, so - // that we preserve any ENOTDIR that might come from trying to open a - // non-directory - if component.ends_with(b"/") { - link_path.push(b'/'); - } - - path_stack.push(link_path); - continue; - } - Err(e) => { - let errno = e.as_errno().unwrap(); - if errno != Errno::EINVAL && errno != Errno::ENOENT { - // only return an error if this path is not actually a symlink - return ret_error(&mut dir_stack, host::errno_from_nix(errno)); - } - } - } - } - - // not a symlink, so we're done; - return Ok(( - ret_dir_success(&mut dir_stack), - OsStr::from_bytes(component).to_os_string(), - )); - } - } - - if path_stack.is_empty() { - // no further components to process. means we've hit a case like "." or "a/..", or if the - // input path has trailing slashes and `needs_final_component` is not set - return Ok(( - ret_dir_success(&mut dir_stack), - OsStr::new(".").to_os_string(), - )); - } else { - continue; - } - } -} - -#[cfg(not(target_os = "macos"))] -pub fn utime_now() -> c_long { - libc::UTIME_NOW -} - -#[cfg(target_os = "macos")] -pub fn utime_now() -> c_long { - -1 -} - -#[cfg(not(target_os = "macos"))] -pub fn utime_omit() -> c_long { - libc::UTIME_OMIT -} - -#[cfg(target_os = "macos")] -pub fn utime_omit() -> c_long { - -2 -} diff --git a/lucet-wasi/src/hostcalls/misc.rs b/lucet-wasi/src/hostcalls/misc.rs deleted file mode 100644 index 75f060009..000000000 --- a/lucet-wasi/src/hostcalls/misc.rs +++ /dev/null @@ -1,455 +0,0 @@ -#![allow(non_camel_case_types)] -#![allow(unused_unsafe)] - -use crate::ctx::WasiCtx; -use crate::memory::*; -use crate::{host, wasm32}; - -use cast::From as _0; -use lucet_runtime::lucet_hostcall_terminate; -use lucet_runtime::vmctx::Vmctx; - -use nix::convert_ioctl_res; -use nix::libc::{self, c_int}; -use std::cmp; -use std::mem::MaybeUninit; -use std::time::SystemTime; - -// define the `fionread()` function, equivalent to `ioctl(fd, FIONREAD, *bytes)` -nix::ioctl_read_bad!(fionread, nix::libc::FIONREAD, c_int); - -fn wasi_clock_to_relative_ns_delay( - wasi_clock: host::__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, -) -> u128 { - if wasi_clock.flags != wasm32::__WASI_SUBSCRIPTION_CLOCK_ABSTIME { - return wasi_clock.timeout as u128; - } - let now: u128 = SystemTime::now() - .duration_since(SystemTime::UNIX_EPOCH) - .expect("Current date is before the epoch") - .as_nanos(); - let deadline = wasi_clock.timeout as u128; - deadline.saturating_sub(now) -} - -#[derive(Debug, Copy, Clone)] -struct ClockEventData { - delay: u128, - userdata: host::__wasi_userdata_t, -} -#[derive(Debug, Copy, Clone)] -struct FdEventData { - fd: c_int, - type_: host::__wasi_eventtype_t, - userdata: host::__wasi_userdata_t, -} - -pub fn wasi_proc_exit(_vmctx: &mut Vmctx, rval: wasm32::__wasi_exitcode_t) -> ! { - lucet_hostcall_terminate!(dec_exitcode(rval)); -} - -pub fn wasi_args_get( - vmctx: &mut Vmctx, - argv_ptr: wasm32::uintptr_t, - argv_buf: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - let ctx = vmctx.get_embed_ctx::(); - - let mut argv_buf_offset = 0; - let mut argv = vec![]; - - for arg in ctx.args.iter() { - let arg_bytes = arg.as_bytes_with_nul(); - let arg_ptr = argv_buf + argv_buf_offset; - - if let Err(e) = enc_slice_of(vmctx, arg_bytes, arg_ptr) { - return enc_errno(e); - } - - argv.push(arg_ptr); - - argv_buf_offset = if let Some(new_offset) = argv_buf_offset.checked_add( - wasm32::uintptr_t::cast(arg_bytes.len()) - .expect("cast overflow would have been caught by `enc_slice_of` above"), - ) { - new_offset - } else { - return wasm32::__WASI_EOVERFLOW; - } - } - enc_slice_of(vmctx, argv.as_slice(), argv_ptr) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) -} - -pub fn wasi_args_sizes_get( - vmctx: &mut Vmctx, - argc_ptr: wasm32::uintptr_t, - argv_buf_size_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - let ctx = vmctx.get_embed_ctx::(); - - let argc = ctx.args.len(); - let argv_size = ctx - .args - .iter() - .map(|arg| arg.as_bytes_with_nul().len()) - .sum(); - if let Err(e) = enc_usize_byref(vmctx, argc_ptr, argc) { - return enc_errno(e); - } - if let Err(e) = enc_usize_byref(vmctx, argv_buf_size_ptr, argv_size) { - return enc_errno(e); - } - wasm32::__WASI_ESUCCESS -} - -pub fn wasi_sched_yield(_vmctx: &mut Vmctx) -> wasm32::__wasi_errno_t { - unsafe { libc::sched_yield() }; - wasm32::__WASI_ESUCCESS -} - -pub fn wasi_clock_res_get( - vmctx: &mut Vmctx, - clock_id: wasm32::__wasi_clockid_t, - resolution_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - // convert the supported clocks to the libc types, or return EINVAL - let clock_id = match dec_clockid(clock_id) { - host::__WASI_CLOCK_REALTIME => libc::CLOCK_REALTIME, - host::__WASI_CLOCK_MONOTONIC => libc::CLOCK_MONOTONIC, - host::__WASI_CLOCK_PROCESS_CPUTIME_ID => libc::CLOCK_PROCESS_CPUTIME_ID, - host::__WASI_CLOCK_THREAD_CPUTIME_ID => libc::CLOCK_THREAD_CPUTIME_ID, - _ => return wasm32::__WASI_EINVAL, - }; - - // no `nix` wrapper for clock_getres, so we do it ourselves - let mut timespec = MaybeUninit::::uninit(); - let res = unsafe { libc::clock_getres(clock_id, timespec.as_mut_ptr()) }; - if res != 0 { - return wasm32::errno_from_nix(nix::errno::Errno::last()); - } - let timespec = unsafe { timespec.assume_init() }; - - // convert to nanoseconds, returning EOVERFLOW in case of overflow; this is freelancing a bit - // from the spec but seems like it'll be an unusual situation to hit - (timespec.tv_sec as host::__wasi_timestamp_t) - .checked_mul(1_000_000_000) - .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t)) - .map(|resolution| { - // a supported clock can never return zero; this case will probably never get hit, but - // make sure we follow the spec - if resolution == 0 { - wasm32::__WASI_EINVAL - } else { - enc_timestamp_byref(vmctx, resolution_ptr, resolution) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - } - }) - .unwrap_or(wasm32::__WASI_EOVERFLOW) -} - -pub fn wasi_clock_time_get( - vmctx: &mut Vmctx, - clock_id: wasm32::__wasi_clockid_t, - // ignored for now, but will be useful once we put optional limits on precision to reduce side - // channels - _precision: wasm32::__wasi_timestamp_t, - time_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - // convert the supported clocks to the libc types, or return EINVAL - let clock_id = match dec_clockid(clock_id) { - host::__WASI_CLOCK_REALTIME => libc::CLOCK_REALTIME, - host::__WASI_CLOCK_MONOTONIC => libc::CLOCK_MONOTONIC, - host::__WASI_CLOCK_PROCESS_CPUTIME_ID => libc::CLOCK_PROCESS_CPUTIME_ID, - host::__WASI_CLOCK_THREAD_CPUTIME_ID => libc::CLOCK_THREAD_CPUTIME_ID, - _ => return wasm32::__WASI_EINVAL, - }; - - // no `nix` wrapper for clock_getres, so we do it ourselves - let mut timespec = MaybeUninit::::uninit(); - let res = unsafe { libc::clock_gettime(clock_id, timespec.as_mut_ptr()) }; - if res != 0 { - return wasm32::errno_from_nix(nix::errno::Errno::last()); - } - let timespec = unsafe { timespec.assume_init() }; - // convert to nanoseconds, returning EOVERFLOW in case of overflow; this is freelancing a bit - // from the spec but seems like it'll be an unusual situation to hit - (timespec.tv_sec as host::__wasi_timestamp_t) - .checked_mul(1_000_000_000) - .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t)) - .map(|time| { - enc_timestamp_byref(vmctx, time_ptr, time) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) - }) - .unwrap_or(wasm32::__WASI_EOVERFLOW) -} - -pub fn wasi_environ_get( - vmctx: &mut Vmctx, - environ_ptr: wasm32::uintptr_t, - environ_buf: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - let ctx = vmctx.get_embed_ctx::(); - - let mut environ_buf_offset = 0; - let mut environ = vec![]; - - for pair in ctx.env.iter() { - let env_bytes = pair.as_bytes_with_nul(); - let env_ptr = environ_buf + environ_buf_offset; - - if let Err(e) = enc_slice_of(vmctx, env_bytes, env_ptr) { - return enc_errno(e); - } - - environ.push(env_ptr); - - environ_buf_offset = if let Some(new_offset) = environ_buf_offset.checked_add( - wasm32::uintptr_t::cast(env_bytes.len()) - .expect("cast overflow would have been caught by `enc_slice_of` above"), - ) { - new_offset - } else { - return wasm32::__WASI_EOVERFLOW; - } - } - enc_slice_of(vmctx, environ.as_slice(), environ_ptr) - .map(|_| wasm32::__WASI_ESUCCESS) - .unwrap_or_else(|e| e) -} - -pub fn wasi_environ_sizes_get( - vmctx: &mut Vmctx, - environ_count_ptr: wasm32::uintptr_t, - environ_size_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - let ctx = vmctx.get_embed_ctx::(); - - let environ_count = ctx.env.len(); - if let Some(environ_size) = ctx.env.iter().try_fold(0, |acc: u32, pair| { - acc.checked_add(pair.as_bytes_with_nul().len() as u32) - }) { - if let Err(e) = enc_usize_byref(vmctx, environ_count_ptr, environ_count) { - return enc_errno(e); - } - if let Err(e) = enc_usize_byref(vmctx, environ_size_ptr, environ_size as usize) { - return enc_errno(e); - } - wasm32::__WASI_ESUCCESS - } else { - wasm32::__WASI_EOVERFLOW - } -} - -pub fn wasi_random_get( - vmctx: &mut Vmctx, - buf_ptr: wasm32::uintptr_t, - buf_len: wasm32::size_t, -) -> wasm32::__wasi_errno_t { - use rand::{thread_rng, RngCore}; - - let buf = match dec_slice_of_mut::(vmctx, buf_ptr, buf_len) { - Ok(buf) => buf, - Err(e) => return enc_errno(e), - }; - thread_rng().fill_bytes(buf); - - return wasm32::__WASI_ESUCCESS; -} - -fn _wasi_poll_oneoff_handle_timeout_event( - output_slice: &mut [wasm32::__wasi_event_t], - timeout: Option, -) -> wasm32::size_t { - if let Some(ClockEventData { userdata, .. }) = timeout { - let output_event = host::__wasi_event_t { - userdata, - type_: wasm32::__WASI_EVENTTYPE_CLOCK, - error: wasm32::__WASI_ESUCCESS, - u: host::__wasi_event_t___wasi_event_u { - fd_readwrite: host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { - nbytes: 0, - flags: 0, - }, - }, - }; - output_slice[0] = enc_event(output_event); - 1 - } else { - // shouldn't happen - 0 - } -} - -fn _wasi_poll_oneoff_handle_fd_event<'t>( - output_slice: &mut [wasm32::__wasi_event_t], - events: impl Iterator, -) -> wasm32::size_t { - let mut output_slice_cur = output_slice.iter_mut(); - let mut revents_count = 0; - for (fd_event, poll_fd) in events { - let revents = match poll_fd.revents() { - Some(revents) => revents, - None => continue, - }; - let mut nbytes = 0; - if fd_event.type_ == wasm32::__WASI_EVENTTYPE_FD_READ { - let _ = unsafe { fionread(fd_event.fd, &mut nbytes) }; - } - let output_event = if revents.contains(nix::poll::EventFlags::POLLNVAL) { - host::__wasi_event_t { - userdata: fd_event.userdata, - type_: fd_event.type_, - error: wasm32::__WASI_EBADF, - u: host::__wasi_event_t___wasi_event_u { - fd_readwrite: - host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { - nbytes: 0, - flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP, - }, - }, - } - } else if revents.contains(nix::poll::EventFlags::POLLERR) { - host::__wasi_event_t { - userdata: fd_event.userdata, - type_: fd_event.type_, - error: wasm32::__WASI_EIO, - u: host::__wasi_event_t___wasi_event_u { - fd_readwrite: - host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { - nbytes: 0, - flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP, - }, - }, - } - } else if revents.contains(nix::poll::EventFlags::POLLHUP) { - host::__wasi_event_t { - userdata: fd_event.userdata, - type_: fd_event.type_, - error: wasm32::__WASI_ESUCCESS, - u: host::__wasi_event_t___wasi_event_u { - fd_readwrite: - host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { - nbytes: 0, - flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP, - }, - }, - } - } else if revents.contains(nix::poll::EventFlags::POLLIN) - | revents.contains(nix::poll::EventFlags::POLLOUT) - { - host::__wasi_event_t { - userdata: fd_event.userdata, - type_: fd_event.type_, - error: wasm32::__WASI_ESUCCESS, - u: host::__wasi_event_t___wasi_event_u { - fd_readwrite: - host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { - nbytes: nbytes as host::__wasi_filesize_t, - flags: 0, - }, - }, - } - } else { - continue; - }; - *output_slice_cur.next().unwrap() = enc_event(output_event); - revents_count += 1; - } - revents_count -} - -pub fn wasi_poll_oneoff( - vmctx: &mut Vmctx, - input: wasm32::uintptr_t, - output: wasm32::uintptr_t, - nsubscriptions: wasm32::size_t, - nevents: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { - if nsubscriptions as u64 > wasm32::__wasi_filesize_t::max_value() { - return wasm32::__WASI_EINVAL; - } - enc_pointee(vmctx, nevents, 0).unwrap(); - - let input_slice = - dec_slice_of::(vmctx, input, nsubscriptions).unwrap(); - - let output_slice = - dec_slice_of_mut::(vmctx, output, nsubscriptions).unwrap(); - - let input: Vec<_> = input_slice.iter().map(|x| dec_subscription(x)).collect(); - - let timeout = input - .iter() - .filter_map(|event| match event { - Ok(event) if event.type_ == wasm32::__WASI_EVENTTYPE_CLOCK => Some(ClockEventData { - delay: wasi_clock_to_relative_ns_delay(unsafe { event.u.clock }) / 1_000_000, - userdata: event.userdata, - }), - _ => None, - }) - .min_by_key(|event| event.delay); - let fd_events: Vec<_> = input - .iter() - .filter_map(|event| match event { - Ok(event) - if event.type_ == wasm32::__WASI_EVENTTYPE_FD_READ - || event.type_ == wasm32::__WASI_EVENTTYPE_FD_WRITE => - { - Some(FdEventData { - fd: unsafe { event.u.fd_readwrite.fd } as c_int, - type_: event.type_, - userdata: event.userdata, - }) - } - _ => None, - }) - .collect(); - if fd_events.is_empty() && timeout.is_none() { - return wasm32::__WASI_ESUCCESS; - } - let mut poll_fds: Vec<_> = fd_events - .iter() - .map(|event| { - let mut flags = nix::poll::EventFlags::empty(); - match event.type_ { - wasm32::__WASI_EVENTTYPE_FD_READ => flags.insert(nix::poll::EventFlags::POLLIN), - wasm32::__WASI_EVENTTYPE_FD_WRITE => flags.insert(nix::poll::EventFlags::POLLOUT), - // An event on a file descriptor can currently only be of type FD_READ or FD_WRITE - // Nothing else has been defined in the specification, and these are also the only two - // events we filtered before. If we get something else here, the code has a serious bug. - _ => unreachable!(), - }; - nix::poll::PollFd::new(event.fd, flags) - }) - .collect(); - let timeout = timeout.map(|ClockEventData { delay, userdata }| ClockEventData { - delay: cmp::min(delay, c_int::max_value() as u128), - userdata, - }); - let poll_timeout = timeout.map(|timeout| timeout.delay as c_int).unwrap_or(-1); - let ready = loop { - match nix::poll::poll(&mut poll_fds, poll_timeout) { - Err(_) => { - if nix::errno::Errno::last() == nix::errno::Errno::EINTR { - continue; - } - return wasm32::errno_from_nix(nix::errno::Errno::last()); - } - Ok(ready) => break ready as usize, - } - }; - let events_count = if ready == 0 { - _wasi_poll_oneoff_handle_timeout_event(output_slice, timeout) - } else { - let events = fd_events.iter().zip(poll_fds.iter()).take(ready); - _wasi_poll_oneoff_handle_fd_event(output_slice, events) - }; - if let Err(e) = enc_pointee(vmctx, nevents, events_count) { - return enc_errno(e); - } - wasm32::__WASI_ESUCCESS -} diff --git a/lucet-wasi/src/hostcalls/mod.rs b/lucet-wasi/src/hostcalls/mod.rs deleted file mode 100644 index 450468176..000000000 --- a/lucet-wasi/src/hostcalls/mod.rs +++ /dev/null @@ -1,447 +0,0 @@ -//! Hostcalls that implement -//! [WASI](https://github.com/CraneStation/wasmtime-wasi/blob/wasi/docs/WASI-overview.md). -//! -//! This code borrows heavily from [wasmtime-wasi](https://github.com/CraneStation/wasmtime-wasi), -//! which in turn borrows from cloudabi-utils. See `LICENSE.wasmtime-wasi` for license information. - -#![allow(non_camel_case_types)] -#![allow(unused_unsafe)] - -mod fs; -mod fs_helpers; -mod misc; - -use crate::wasm32; - -use fs::*; -use lucet_runtime::lucet_hostcalls; -use misc::*; - -lucet_hostcalls! { - #[no_mangle] pub unsafe extern "C" - fn __wasi_proc_exit(&mut vmctx, rval: wasm32::__wasi_exitcode_t,) -> ! { - wasi_proc_exit(vmctx, rval) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_args_get( - &mut vmctx, - argv_ptr: wasm32::uintptr_t, - argv_buf: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - wasi_args_get(vmctx, argv_ptr, argv_buf) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_args_sizes_get(&mut vmctx, - argc_ptr: wasm32::uintptr_t, - argv_buf_size_ptr: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - wasi_args_sizes_get(vmctx, argc_ptr, argv_buf_size_ptr) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_sched_yield(&mut vmctx,) -> wasm32::__wasi_errno_t { - wasi_sched_yield(vmctx) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_clock_res_get( - &mut vmctx, - clock_id: wasm32::__wasi_clockid_t, - resolution_ptr: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - wasi_clock_res_get(vmctx, clock_id, resolution_ptr) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_clock_time_get( - &mut vmctx, - clock_id: wasm32::__wasi_clockid_t, - precision: wasm32::__wasi_timestamp_t, - time_ptr: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - wasi_clock_time_get(vmctx, clock_id, precision, time_ptr) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_environ_get( - &mut vmctx, - environ_ptr: wasm32::uintptr_t, - environ_buf: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - wasi_environ_get(vmctx, environ_ptr, environ_buf) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_environ_sizes_get( - &mut vmctx, - environ_count_ptr: wasm32::uintptr_t, - environ_size_ptr: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - wasi_environ_sizes_get(vmctx, environ_count_ptr, environ_size_ptr) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_fd_close( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - ) -> wasm32::__wasi_errno_t { - wasi_fd_close(vmctx, fd) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_fd_fdstat_get( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - fdstat_ptr: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - wasi_fd_fdstat_get(vmctx, fd, fdstat_ptr) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_fd_fdstat_set_flags( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - fdflags: wasm32::__wasi_fdflags_t, - ) -> wasm32::__wasi_errno_t { - wasi_fd_fdstat_set_flags(vmctx, fd, fdflags) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_fd_tell(&mut vmctx, - fd: wasm32::__wasi_fd_t, - offset: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - wasi_fd_tell(vmctx, fd, offset) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_fd_seek(&mut vmctx, - fd: wasm32::__wasi_fd_t, - offset: wasm32::__wasi_filedelta_t, - whence: wasm32::__wasi_whence_t, - newoffset: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - wasi_fd_seek(vmctx, fd, offset, whence, newoffset) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_fd_prestat_get( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - prestat_ptr: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - wasi_fd_prestat_get(vmctx, fd, prestat_ptr) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_fd_prestat_dir_name( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, - ) -> wasm32::__wasi_errno_t { - wasi_fd_prestat_dir_name(vmctx, fd, path_ptr, path_len) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_fd_read( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - iovs_ptr: wasm32::uintptr_t, - iovs_len: wasm32::size_t, - nread: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - wasi_fd_read(vmctx, fd, iovs_ptr, iovs_len, nread) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_fd_write( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - iovs_ptr: wasm32::uintptr_t, - iovs_len: wasm32::size_t, - nwritten: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - wasi_fd_write(vmctx, fd, iovs_ptr, iovs_len, nwritten) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_path_open( - &mut vmctx, - dirfd: wasm32::__wasi_fd_t, - dirflags: wasm32::__wasi_lookupflags_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, - oflags: wasm32::__wasi_oflags_t, - fs_rights_base: wasm32::__wasi_rights_t, - fs_rights_inheriting: wasm32::__wasi_rights_t, - fs_flags: wasm32::__wasi_fdflags_t, - fd_out_ptr: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - wasi_path_open(vmctx, dirfd, dirflags, path_ptr, path_len, - oflags, fs_rights_base, fs_rights_inheriting, fs_flags, - fd_out_ptr) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_random_get( - &mut vmctx, - buf_ptr: wasm32::uintptr_t, - buf_len: wasm32::size_t, - ) -> wasm32::__wasi_errno_t { - wasi_random_get(vmctx, buf_ptr, buf_len) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_poll_oneoff( - &mut vmctx, - input: wasm32::uintptr_t, - output: wasm32::uintptr_t, - nsubscriptions: wasm32::size_t, - nevents: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - wasi_poll_oneoff(vmctx, input, output, nsubscriptions, nevents) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_fd_filestat_get( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - filestat_ptr: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - wasi_fd_filestat_get(vmctx, fd, filestat_ptr) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_path_filestat_get( - &mut vmctx, - dirfd: wasm32::__wasi_fd_t, - dirflags: wasm32::__wasi_lookupflags_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, - filestat_ptr: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - wasi_path_filestat_get(vmctx, dirfd, dirflags, path_ptr, - path_len, filestat_ptr) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_path_create_directory( - &mut vmctx, - dirfd: wasm32::__wasi_fd_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, - ) -> wasm32::__wasi_errno_t { - wasi_path_create_directory(vmctx, dirfd, path_ptr, path_len) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_path_unlink_file( - &mut vmctx, - dirfd: wasm32::__wasi_fd_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, - ) -> wasm32::__wasi_errno_t { - wasi_path_unlink_file(vmctx, dirfd, path_ptr, path_len) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_fd_allocate( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - offset: wasm32::__wasi_filesize_t, - len: wasm32::__wasi_filesize_t, - ) -> wasm32::__wasi_errno_t { - wasi_fd_allocate(vmctx, fd, offset, len) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_fd_advise( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - offset: wasm32::__wasi_filesize_t, - len: wasm32::__wasi_filesize_t, - advice: wasm32::__wasi_advice_t, - ) -> wasm32::__wasi_errno_t { - wasi_fd_advise(vmctx, fd, offset, len, advice) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_fd_datasync( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - ) -> wasm32::__wasi_errno_t { - wasi_fd_datasync(vmctx, fd) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_fd_sync( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - ) -> wasm32::__wasi_errno_t { - wasi_fd_sync(vmctx, fd) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_fd_fdstat_set_rights( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - fs_rights_base: wasm32::__wasi_rights_t, - fs_rights_inheriting: wasm32::__wasi_rights_t, - ) -> wasm32::__wasi_errno_t { - wasi_fd_fdstat_set_rights(vmctx, fd, fs_rights_base, fs_rights_inheriting) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_fd_filestat_set_size( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - st_size: wasm32::__wasi_filesize_t, - ) -> wasm32::__wasi_errno_t { - wasi_fd_filestat_set_size(vmctx, fd, st_size) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_fd_filestat_set_times( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - st_atim: wasm32::__wasi_timestamp_t, - st_mtim: wasm32::__wasi_timestamp_t, - fst_flags: wasm32::__wasi_fstflags_t, - ) -> wasm32::__wasi_errno_t { - wasi_fd_filestat_set_times(vmctx, fd, st_atim, st_mtim, fst_flags) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_fd_pread( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - iovs_ptr: wasm32::uintptr_t, - iovs_len: wasm32::size_t, - offset: wasm32::__wasi_filesize_t, - nread: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - wasi_fd_pread(vmctx, fd, iovs_ptr, iovs_len, offset, nread) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_fd_pwrite( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - iovs_ptr: wasm32::uintptr_t, - iovs_len: wasm32::size_t, - offset: wasm32::__wasi_filesize_t, - nwritten: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - wasi_fd_pwrite(vmctx, fd, iovs_ptr, iovs_len, offset, nwritten) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_fd_readdir( - &mut vmctx, - fd: wasm32::__wasi_fd_t, - buf: wasm32::uintptr_t, - buf_len: wasm32::size_t, - cookie: wasm32::__wasi_dircookie_t, - bufused: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - wasi_fd_readdir(vmctx, fd, buf, buf_len, cookie, bufused) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_fd_renumber( - &mut vmctx, - from: wasm32::__wasi_fd_t, - to: wasm32::__wasi_fd_t, - ) -> wasm32::__wasi_errno_t { - wasi_fd_renumber(vmctx, from, to) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_path_filestat_set_times( - &mut vmctx, - dirfd: wasm32::__wasi_fd_t, - dirflags: wasm32::__wasi_lookupflags_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, - st_atim: wasm32::__wasi_timestamp_t, - st_mtim: wasm32::__wasi_timestamp_t, - fst_flags: wasm32::__wasi_fstflags_t, - ) -> wasm32::__wasi_errno_t { - wasi_path_filestat_set_times(vmctx, dirfd, dirflags, path_ptr, path_len, st_atim, st_mtim, fst_flags) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_path_link( - &mut vmctx, - old_fd: wasm32::__wasi_fd_t, - old_flags: wasm32::__wasi_lookupflags_t, - old_path_ptr: wasm32::uintptr_t, - old_path_len: wasm32::size_t, - new_fd: wasm32::__wasi_fd_t, - new_path_ptr: wasm32::uintptr_t, - new_path_len: wasm32::size_t, - ) -> wasm32::__wasi_errno_t { - wasi_path_link(vmctx, old_fd, old_flags, old_path_ptr, old_path_len, - new_fd, new_path_ptr, new_path_len) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_path_readlink( - &mut vmctx, - dirfd: wasm32::__wasi_fd_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, - buf_ptr: wasm32::uintptr_t, - buf_len: wasm32::size_t, - bufused: wasm32::uintptr_t, - ) -> wasm32::__wasi_errno_t { - wasi_path_readlink(vmctx, dirfd, path_ptr, path_len, buf_ptr, buf_len, bufused) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_path_remove_directory( - &mut vmctx, - dirfd: wasm32::__wasi_fd_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, - ) -> wasm32::__wasi_errno_t { - wasi_path_remove_directory(vmctx, dirfd, path_ptr, path_len) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_path_rename( - &mut vmctx, - old_dirfd: wasm32::__wasi_fd_t, - old_path_ptr: wasm32::uintptr_t, - old_path_len: wasm32::size_t, - new_dirfd: wasm32::__wasi_fd_t, - new_path_ptr: wasm32::uintptr_t, - new_path_len: wasm32::size_t, - ) -> wasm32::__wasi_errno_t { - wasi_path_rename(vmctx, old_dirfd, old_path_ptr, old_path_len, - new_dirfd, new_path_ptr, new_path_len) - } - - #[no_mangle] pub unsafe extern "C" - fn __wasi_path_symlink( - &mut vmctx, - old_path_ptr: wasm32::uintptr_t, - old_path_len: wasm32::size_t, - dir_fd: wasm32::__wasi_fd_t, - new_path_ptr: wasm32::uintptr_t, - new_path_len: wasm32::size_t, - ) -> wasm32::__wasi_errno_t { - wasi_path_symlink(vmctx, old_path_ptr, old_path_len, - dir_fd, new_path_ptr, new_path_len) - } -} - -#[doc(hidden)] -pub fn ensure_linked() { - unsafe { - std::ptr::read_volatile(__wasi_proc_exit as *const extern "C" fn()); - } -} diff --git a/lucet-wasi/src/lib.rs b/lucet-wasi/src/lib.rs index 70e133cfd..321ae23b9 100644 --- a/lucet-wasi/src/lib.rs +++ b/lucet-wasi/src/lib.rs @@ -2,12 +2,9 @@ mod bindings; pub mod c_api; -pub mod ctx; -pub mod fdentry; -pub mod host; -pub mod hostcalls; -pub mod memory; -pub mod wasm32; +pub mod wasi; pub use bindings::bindings; -pub use ctx::{WasiCtx, WasiCtxBuilder}; +pub use wasi::{export_wasi_funcs, WasiCtx, WasiCtxBuilder}; + +pub use wasi_common::host; diff --git a/lucet-wasi/src/main.rs b/lucet-wasi/src/main.rs index f074d1255..e00f7107b 100644 --- a/lucet-wasi/src/main.rs +++ b/lucet-wasi/src/main.rs @@ -3,15 +3,17 @@ #[macro_use] extern crate clap; +mod wasi; + use clap::Arg; use failure::{format_err, Error}; use lucet_runtime::{self, DlModule, Limits, MmapRegion, Module, PublicKey, Region, RunResult}; -use lucet_wasi::{hostcalls, WasiCtxBuilder}; use std::fs::File; use std::path::PathBuf; use std::sync::Arc; use std::thread; use std::time::Duration; +use wasi::WasiCtxBuilder; struct Config<'a> { lucet_module: &'a str, @@ -39,8 +41,7 @@ fn parse_humansized(desc: &str) -> Result { fn main() { // No-ops, but makes sure the linker doesn't throw away parts // of the runtime: - lucet_runtime::lucet_internal_ensure_linked(); - hostcalls::ensure_linked(); + wasi::export_wasi_funcs(); let matches = app_from_crate!() .arg( @@ -203,7 +204,7 @@ fn main() { } fn run(config: Config<'_>) { - lucet_wasi::hostcalls::ensure_linked(); + wasi::export_wasi_funcs(); let exitcode = { // doing all of this in a block makes sure everything gets dropped before exiting let pk = match (config.verify, config.pk_path) { @@ -236,9 +237,13 @@ fn run(config: Config<'_>) { .chain(config.guest_args.into_iter()) .collect::>(); let mut ctx = WasiCtxBuilder::new() - .args(&args) + .expect("wasi context can be built") + .args(args.iter()) + .expect("arguments can be stored") .inherit_stdio() - .inherit_env(); + .expect("stdio can be inherited") + .inherit_env() + .expect("environment can be inherited"); for (dir, guest_path) in config.preopen_dirs { ctx = ctx.preopened_dir(dir, guest_path); } @@ -266,7 +271,7 @@ fn run(config: Config<'_>) { Err(lucet_runtime::Error::RuntimeTerminated( lucet_runtime::TerminationDetails::Provided(any), )) => *any - .downcast_ref::() + .downcast_ref::() .expect("termination yields an exitcode"), Err(lucet_runtime::Error::RuntimeTerminated( lucet_runtime::TerminationDetails::Remote, diff --git a/lucet-wasi/src/memory.rs b/lucet-wasi/src/memory.rs deleted file mode 100644 index 3ecfd51b1..000000000 --- a/lucet-wasi/src/memory.rs +++ /dev/null @@ -1,620 +0,0 @@ -//! Functions to go back and forth between WASI types in host and wasm32 representations. -//! -//! This module is an adaptation of the `wasmtime-wasi` module -//! [`translate.rs`](https://github.com/CraneStation/wasmtime-wasi/blob/1a6ecf3a0378d71f3fc1ba25ce76a2b43e4166b8/lib/wasi/src/translate.rs); -//! its license file `LICENSE.wasmtime-wasi` is included in this project. -//! -//! Any of these functions that take a `Vmctx` argument are only meant to be called from within a -//! hostcall. -//! -//! This sort of manual encoding will hopefully be obsolete once the IDL is developed. - -use crate::{host, wasm32}; -use cast; -use cast::From as _0; -use lucet_runtime::vmctx::Vmctx; -use std::mem::{align_of, size_of}; -use std::slice; - -macro_rules! bail_errno { - ( $errno:ident ) => { - return Err(host::$errno as host::__wasi_errno_t); - }; -} - -pub fn dec_ptr( - vmctx: &Vmctx, - ptr: wasm32::uintptr_t, - len: usize, -) -> Result<*const u8, host::__wasi_errno_t> { - let heap = vmctx.heap(); - - // check for overflow - let checked_len = (ptr as usize) - .checked_add(len) - .ok_or(host::__WASI_EFAULT as host::__wasi_errno_t)?; - if checked_len > heap.len() { - bail_errno!(__WASI_EFAULT); - } - // translate the pointer - Ok(unsafe { heap.as_ptr().offset(ptr as isize) }) -} - -pub fn dec_ptr_mut( - vmctx: &Vmctx, - ptr: wasm32::uintptr_t, - len: usize, -) -> Result<*mut u8, host::__wasi_errno_t> { - let mut heap = vmctx.heap_mut(); - - // check for overflow - let checked_len = (ptr as usize) - .checked_add(len) - .ok_or(host::__WASI_EFAULT as host::__wasi_errno_t)?; - if checked_len > heap.len() { - bail_errno!(__WASI_EFAULT); - } - // translate the pointer - Ok(unsafe { heap.as_mut_ptr().offset(ptr as isize) }) -} - -pub fn dec_ptr_to( - vmctx: &Vmctx, - ptr: wasm32::uintptr_t, -) -> Result<*const T, host::__wasi_errno_t> { - // check that the ptr is aligned - if ptr as usize % align_of::() != 0 { - bail_errno!(__WASI_EINVAL); - } - dec_ptr(vmctx, ptr, size_of::()).map(|p| p as *const T) -} - -pub fn dec_ptr_to_mut( - vmctx: &Vmctx, - ptr: wasm32::uintptr_t, -) -> Result<*mut T, host::__wasi_errno_t> { - // check that the ptr is aligned - if ptr as usize % align_of::() != 0 { - bail_errno!(__WASI_EINVAL); - } - dec_ptr_mut(vmctx, ptr, size_of::()).map(|p| p as *mut T) -} - -pub fn dec_pointee(vmctx: &Vmctx, ptr: wasm32::uintptr_t) -> Result { - dec_ptr_to::(vmctx, ptr).map(|p| unsafe { p.read() }) -} - -pub fn enc_pointee( - vmctx: &Vmctx, - ptr: wasm32::uintptr_t, - t: T, -) -> Result<(), host::__wasi_errno_t> { - dec_ptr_to_mut::(vmctx, ptr).map(|p| unsafe { p.write(t) }) -} - -fn check_slice_of( - ptr: wasm32::uintptr_t, - len: wasm32::size_t, -) -> Result<(usize, usize), host::__wasi_errno_t> { - // check alignment, and that length doesn't overflow - if ptr as usize % align_of::() != 0 { - bail_errno!(__WASI_EINVAL); - } - let len = dec_usize(len); - let len_bytes = if let Some(len) = size_of::().checked_mul(len) { - len - } else { - bail_errno!(__WASI_EOVERFLOW); - }; - Ok((len, len_bytes)) -} - -pub fn dec_slice_of<'vmctx, T>( - vmctx: &'vmctx Vmctx, - ptr: wasm32::uintptr_t, - len: wasm32::size_t, -) -> Result<&'vmctx [T], host::__wasi_errno_t> { - let (len, len_bytes) = check_slice_of::(ptr, len)?; - let ptr = dec_ptr(vmctx, ptr, len_bytes)? as *const T; - Ok(unsafe { slice::from_raw_parts(ptr, len) }) -} - -pub fn dec_slice_of_mut<'vmctx, T>( - vmctx: &'vmctx Vmctx, - ptr: wasm32::uintptr_t, - len: wasm32::size_t, -) -> Result<&'vmctx mut [T], host::__wasi_errno_t> { - let (len, len_bytes) = check_slice_of::(ptr, len)?; - let ptr = dec_ptr_mut(vmctx, ptr, len_bytes)? as *mut T; - Ok(unsafe { slice::from_raw_parts_mut(ptr, len) }) -} - -pub fn enc_slice_of( - vmctx: &Vmctx, - slice: &[T], - ptr: wasm32::uintptr_t, -) -> Result<(), host::__wasi_errno_t> { - // check alignment - if ptr as usize % align_of::() != 0 { - return Err(host::__WASI_EINVAL as host::__wasi_errno_t); - } - // check that length doesn't overflow - let len_bytes = if let Some(len) = size_of::().checked_mul(slice.len()) { - len - } else { - return Err(host::__WASI_EOVERFLOW as host::__wasi_errno_t); - }; - - // get the pointer into guest memory, and copy the bytes - let ptr = dec_ptr(vmctx, ptr, len_bytes)? as *mut libc::c_void; - unsafe { std::ptr::copy_nonoverlapping(slice.as_ptr() as *const libc::c_void, ptr, len_bytes) }; - - Ok(()) -} - -macro_rules! dec_enc_scalar { - ( $ty:ident, $dec:ident, $dec_byref:ident, $enc:ident, $enc_byref:ident) => { - pub fn $dec(x: wasm32::$ty) -> host::$ty { - host::$ty::from_le(x) - } - - pub fn $dec_byref( - vmctx: &Vmctx, - ptr: wasm32::uintptr_t, - ) -> Result { - dec_pointee::(vmctx, ptr).map($dec) - } - - pub fn $enc(x: host::$ty) -> wasm32::$ty { - x.to_le() - } - - pub fn $enc_byref( - vmctx: &Vmctx, - ptr: wasm32::uintptr_t, - x: host::$ty, - ) -> Result<(), host::__wasi_errno_t> { - enc_pointee::(vmctx, ptr, $enc(x)) - } - }; -} - -pub fn dec_ciovec( - vmctx: &Vmctx, - ciovec: &wasm32::__wasi_ciovec_t, -) -> Result { - let len = dec_usize(ciovec.buf_len); - Ok(host::__wasi_ciovec_t { - buf: dec_ptr(vmctx, ciovec.buf, len)? as *const host::void, - buf_len: len, - }) -} - -pub fn dec_ciovec_slice( - vmctx: &Vmctx, - ptr: wasm32::uintptr_t, - len: wasm32::size_t, -) -> Result, host::__wasi_errno_t> { - let slice = dec_slice_of::(vmctx, ptr, len)?; - slice.iter().map(|iov| dec_ciovec(vmctx, iov)).collect() -} - -pub fn dec_iovec( - vmctx: &Vmctx, - iovec: &wasm32::__wasi_iovec_t, -) -> Result { - let len = dec_usize(iovec.buf_len); - Ok(host::__wasi_iovec_t { - buf: dec_ptr(vmctx, iovec.buf, len)? as *mut host::void, - buf_len: len, - }) -} - -pub fn dec_iovec_slice( - vmctx: &Vmctx, - ptr: wasm32::uintptr_t, - len: wasm32::size_t, -) -> Result, host::__wasi_errno_t> { - let slice = dec_slice_of::(vmctx, ptr, len)?; - slice.iter().map(|iov| dec_iovec(vmctx, iov)).collect() -} - -dec_enc_scalar!( - __wasi_clockid_t, - dec_clockid, - dec_clockid_byref, - enc_clockid, - enc_clockid_byref -); -dec_enc_scalar!( - __wasi_errno_t, - dec_errno, - dec_errno_byref, - enc_errno, - enc_errno_byref -); -dec_enc_scalar!( - __wasi_exitcode_t, - dec_exitcode, - dec_exitcode_byref, - enc_exitcode, - enc_exitcode_byref -); -dec_enc_scalar!(__wasi_fd_t, dec_fd, dec_fd_byref, enc_fd, enc_fd_byref); -dec_enc_scalar!( - __wasi_fdflags_t, - dec_fdflags, - dec_fdflags_byref, - enc_fdflags, - enc_fdflags_byref -); -dec_enc_scalar!( - __wasi_device_t, - dec_device, - dev_device_byref, - enc_device, - enc_device_byref -); -dec_enc_scalar!( - __wasi_inode_t, - dec_inode, - dev_inode_byref, - enc_inode, - enc_inode_byref -); -dec_enc_scalar!( - __wasi_linkcount_t, - dec_linkcount, - dev_linkcount_byref, - enc_linkcount, - enc_linkcount_byref -); - -pub fn dec_filestat(filestat: wasm32::__wasi_filestat_t) -> host::__wasi_filestat_t { - host::__wasi_filestat_t { - st_dev: dec_device(filestat.st_dev), - st_ino: dec_inode(filestat.st_ino), - st_filetype: dec_filetype(filestat.st_filetype), - st_nlink: dec_linkcount(filestat.st_nlink), - st_size: dec_filesize(filestat.st_size), - st_atim: dec_timestamp(filestat.st_atim), - st_mtim: dec_timestamp(filestat.st_mtim), - st_ctim: dec_timestamp(filestat.st_ctim), - } -} - -pub fn dec_filestat_byref( - vmctx: &Vmctx, - filestat_ptr: wasm32::uintptr_t, -) -> Result { - dec_pointee::(vmctx, filestat_ptr).map(dec_filestat) -} - -pub fn enc_filestat(filestat: host::__wasi_filestat_t) -> wasm32::__wasi_filestat_t { - wasm32::__wasi_filestat_t { - st_dev: enc_device(filestat.st_dev), - st_ino: enc_inode(filestat.st_ino), - st_filetype: enc_filetype(filestat.st_filetype), - st_nlink: enc_linkcount(filestat.st_nlink), - st_size: enc_filesize(filestat.st_size), - st_atim: enc_timestamp(filestat.st_atim), - st_mtim: enc_timestamp(filestat.st_mtim), - st_ctim: enc_timestamp(filestat.st_ctim), - } -} - -pub fn enc_filestat_byref( - vmctx: &Vmctx, - filestat_ptr: wasm32::uintptr_t, - host_filestat: host::__wasi_filestat_t, -) -> Result<(), host::__wasi_errno_t> { - let filestat = enc_filestat(host_filestat); - enc_pointee::(vmctx, filestat_ptr, filestat) -} - -pub fn dec_fdstat(fdstat: wasm32::__wasi_fdstat_t) -> host::__wasi_fdstat_t { - host::__wasi_fdstat_t { - fs_filetype: dec_filetype(fdstat.fs_filetype), - fs_flags: dec_fdflags(fdstat.fs_flags), - fs_rights_base: dec_rights(fdstat.fs_rights_base), - fs_rights_inheriting: dec_rights(fdstat.fs_rights_inheriting), - } -} - -pub fn dec_fdstat_byref( - vmctx: &Vmctx, - fdstat_ptr: wasm32::uintptr_t, -) -> Result { - dec_pointee::(vmctx, fdstat_ptr).map(dec_fdstat) -} - -pub fn enc_fdstat(fdstat: host::__wasi_fdstat_t) -> wasm32::__wasi_fdstat_t { - wasm32::__wasi_fdstat_t { - fs_filetype: enc_filetype(fdstat.fs_filetype), - fs_flags: enc_fdflags(fdstat.fs_flags), - __bindgen_padding_0: 0, - fs_rights_base: enc_rights(fdstat.fs_rights_base), - fs_rights_inheriting: enc_rights(fdstat.fs_rights_inheriting), - } -} - -pub fn enc_fdstat_byref( - vmctx: &Vmctx, - fdstat_ptr: wasm32::uintptr_t, - host_fdstat: host::__wasi_fdstat_t, -) -> Result<(), host::__wasi_errno_t> { - let fdstat = enc_fdstat(host_fdstat); - enc_pointee::(vmctx, fdstat_ptr, fdstat) -} - -dec_enc_scalar!( - __wasi_filedelta_t, - dec_filedelta, - dec_filedelta_byref, - enc_filedelta, - enc_filedelta_byref -); -dec_enc_scalar!( - __wasi_filesize_t, - dec_filesize, - dec_filesize_byref, - enc_filesize, - enc_filesize_byref -); - -dec_enc_scalar!( - __wasi_filetype_t, - dec_filetype, - dec_filetype_byref, - enc_filetype, - enc_filetype_byref -); - -dec_enc_scalar!( - __wasi_lookupflags_t, - dec_lookupflags, - dec_lookupflags_byref, - enc_lookupflags, - enc_lookupflags_byref -); - -dec_enc_scalar!( - __wasi_oflags_t, - dec_oflags, - dec_oflags_byref, - enc_oflags, - enc_oflags_byref -); - -pub fn dec_prestat( - prestat: wasm32::__wasi_prestat_t, -) -> Result { - match prestat.pr_type { - wasm32::__WASI_PREOPENTYPE_DIR => { - let u = host::__wasi_prestat_t___wasi_prestat_u { - dir: host::__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t { - pr_name_len: dec_usize(unsafe { prestat.u.dir.pr_name_len }), - }, - }; - Ok(host::__wasi_prestat_t { - pr_type: host::__WASI_PREOPENTYPE_DIR as host::__wasi_preopentype_t, - u, - }) - } - _ => Err(host::__WASI_EINVAL as host::__wasi_errno_t), - } -} - -pub fn dec_prestat_byref( - vmctx: &Vmctx, - prestat_ptr: wasm32::uintptr_t, -) -> Result { - dec_pointee::(vmctx, prestat_ptr).and_then(dec_prestat) -} - -pub fn enc_prestat( - prestat: host::__wasi_prestat_t, -) -> Result { - match u32::from(prestat.pr_type) { - host::__WASI_PREOPENTYPE_DIR => { - let u = wasm32::__wasi_prestat_t___wasi_prestat_u { - dir: wasm32::__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t { - pr_name_len: enc_usize(unsafe { prestat.u.dir.pr_name_len }), - }, - }; - Ok(wasm32::__wasi_prestat_t { - pr_type: wasm32::__WASI_PREOPENTYPE_DIR as wasm32::__wasi_preopentype_t, - u, - }) - } - _ => Err(host::__WASI_EINVAL as host::__wasi_errno_t), - } -} - -pub fn enc_prestat_byref( - vmctx: &Vmctx, - prestat_ptr: wasm32::uintptr_t, - host_prestat: host::__wasi_prestat_t, -) -> Result<(), host::__wasi_errno_t> { - let prestat = enc_prestat(host_prestat)?; - enc_pointee::(vmctx, prestat_ptr, prestat) -} - -dec_enc_scalar!( - __wasi_rights_t, - dec_rights, - dec_rights_byref, - enc_rights, - enc_rights_byref -); - -dec_enc_scalar!( - __wasi_timestamp_t, - dec_timestamp, - dec_timestamp_byref, - enc_timestamp, - enc_timestamp_byref -); - -pub fn dec_u32(x: u32) -> u32 { - u32::from_le(x) -} - -pub fn enc_u32(x: u32) -> u32 { - x.to_le() -} - -pub fn dec_usize(size: wasm32::size_t) -> usize { - cast::usize(u32::from_le(size)) -} - -pub fn enc_usize(size: usize) -> wasm32::size_t { - wasm32::size_t::cast(size).unwrap() -} - -pub fn enc_usize_byref( - vmctx: &Vmctx, - usize_ptr: wasm32::uintptr_t, - host_usize: usize, -) -> Result<(), host::__wasi_errno_t> { - enc_pointee::(vmctx, usize_ptr, enc_usize(host_usize)) -} - -dec_enc_scalar!( - __wasi_whence_t, - dec_whence, - dec_whence_byref, - enc_whence, - enc_whence_byref -); - -dec_enc_scalar!( - __wasi_subclockflags_t, - dec_subclockflags, - dec_subclockflags_byref, - enc_subclockflags, - enc_subclockflags_byref -); - -dec_enc_scalar!( - __wasi_eventrwflags_t, - dec_eventrwflags, - dec_eventrwflags_byref, - enc_eventrwflags, - enc_eventrwflags_byref -); - -dec_enc_scalar!( - __wasi_eventtype_t, - dec_eventtype, - dec_eventtype_byref, - enc_eventtype, - enc_eventtype_byref -); - -dec_enc_scalar!( - __wasi_userdata_t, - dec_userdata, - dec_userdata_byref, - enc_userdata, - enc_userdata_byref -); - -pub fn dec_subscription( - subscription: &wasm32::__wasi_subscription_t, -) -> Result { - let userdata = dec_userdata(subscription.userdata); - let type_ = dec_eventtype(subscription.type_); - let u_orig = subscription.__bindgen_anon_1; - let u = match type_ { - wasm32::__WASI_EVENTTYPE_CLOCK => host::__wasi_subscription_t___wasi_subscription_u { - clock: unsafe { - host::__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t { - identifier: dec_userdata(u_orig.clock.identifier), - clock_id: dec_clockid(u_orig.clock.clock_id), - timeout: dec_timestamp(u_orig.clock.timeout), - precision: dec_timestamp(u_orig.clock.precision), - flags: dec_subclockflags(u_orig.clock.flags), - } - }, - }, - wasm32::__WASI_EVENTTYPE_FD_READ | wasm32::__WASI_EVENTTYPE_FD_WRITE => host::__wasi_subscription_t___wasi_subscription_u { - fd_readwrite: host::__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t { - fd: dec_fd(unsafe{u_orig.fd_readwrite.fd}) - } - }, - _ => return Err(wasm32::__WASI_EINVAL) - }; - Ok(host::__wasi_subscription_t { userdata, type_, u }) -} - -pub fn enc_event(event: host::__wasi_event_t) -> wasm32::__wasi_event_t { - let fd_readwrite = unsafe { event.u.fd_readwrite }; - wasm32::__wasi_event_t { - userdata: enc_userdata(event.userdata), - type_: enc_eventtype(event.type_), - error: enc_errno(event.error), - __bindgen_anon_1: wasm32::__wasi_event_t__bindgen_ty_1 { - fd_readwrite: wasm32::__wasi_event_t__bindgen_ty_1__bindgen_ty_1 { - nbytes: enc_filesize(fd_readwrite.nbytes), - flags: enc_eventrwflags(fd_readwrite.flags), - __bindgen_padding_0: [0; 3], - }, - }, - __bindgen_padding_0: 0, - } -} - -dec_enc_scalar!( - __wasi_advice_t, - dec_advice, - dec_advice_byref, - enc_advice, - enc_advice_byref -); - -dec_enc_scalar!( - __wasi_fstflags_t, - dec_fstflags, - dec_fstflags_byref, - enc_fstflags, - enc_fstflags_byref -); - -dec_enc_scalar!( - __wasi_dircookie_t, - dec_dircookie, - dec_dircookie_byref, - enc_dircookie, - enc_dircookie_byref -); - -#[cfg(target_os = "linux")] -pub fn dirent_from_host( - host_entry: &nix::libc::dirent, -) -> Result { - let mut entry = unsafe { std::mem::zeroed::() }; - let d_namlen = unsafe { std::ffi::CStr::from_ptr(host_entry.d_name.as_ptr()) } - .to_bytes() - .len(); - if d_namlen > u32::max_value() as usize { - return Err(host::__WASI_EIO as host::__wasi_errno_t); - } - entry.d_ino = enc_inode(host_entry.d_ino); - entry.d_next = enc_dircookie(host_entry.d_off as u64); - entry.d_namlen = enc_u32(d_namlen as u32); - entry.d_type = enc_filetype(host_entry.d_type); - Ok(entry) -} - -#[cfg(not(target_os = "linux"))] -pub fn dirent_from_host( - host_entry: &nix::libc::dirent, -) -> Result { - let mut entry = unsafe { std::mem::zeroed::() }; - entry.d_ino = enc_inode(host_entry.d_ino); - entry.d_next = enc_dircookie(host_entry.d_seekoff); - entry.d_namlen = enc_u32(u32::from(host_entry.d_namlen)); - entry.d_type = enc_filetype(host_entry.d_type); - Ok(entry) -} diff --git a/lucet-wasi/src/wasi.rs b/lucet-wasi/src/wasi.rs new file mode 100644 index 000000000..21d9cbcac --- /dev/null +++ b/lucet-wasi/src/wasi.rs @@ -0,0 +1,597 @@ +#![allow(clippy::too_many_arguments)] + +pub use lucet_runtime::{self, vmctx::lucet_vmctx}; +pub use wasi_common::*; + +use lucet_runtime::lucet_hostcall_terminate; +use std::mem; +use std::rc::Rc; +use wasi_common::hostcalls::*; + +lucet_runtime::lucet_hostcalls! { + +#[no_mangle] +pub unsafe extern "C" fn __wasi_proc_exit( + &mut _lucet_vmctx, + rval: wasm32::__wasi_exitcode_t, +) -> ! { + export_wasi_funcs(); + lucet_hostcall_terminate!(rval); +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_args_get( + &mut lucet_ctx, + argv_ptr: wasm32::uintptr_t, + argv_buf: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + let heap = &mut lucet_ctx.heap_mut(); + args_get(wasi_ctx, heap, argv_ptr, argv_buf) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_args_sizes_get( + &mut lucet_ctx, + argc_ptr: wasm32::uintptr_t, + argv_buf_size_ptr: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + let heap = &mut lucet_ctx.heap_mut(); + args_sizes_get(wasi_ctx, heap, argc_ptr, argv_buf_size_ptr) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_sched_yield(&mut _lucet_ctx,) -> wasm32::__wasi_errno_t { + sched_yield() +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_clock_res_get( + &mut lucet_ctx, + clock_id: wasm32::__wasi_clockid_t, + resolution_ptr: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let heap = &mut lucet_ctx.heap_mut(); + clock_res_get(heap, clock_id, resolution_ptr) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_clock_time_get( + &mut lucet_ctx, + clock_id: wasm32::__wasi_clockid_t, + precision: wasm32::__wasi_timestamp_t, + time_ptr: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let heap = &mut lucet_ctx.heap_mut(); + clock_time_get(heap, clock_id, precision, time_ptr) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_environ_get( + &mut lucet_ctx, + environ_ptr: wasm32::uintptr_t, + environ_buf: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + let heap = &mut lucet_ctx.heap_mut(); + environ_get(wasi_ctx, heap, environ_ptr, environ_buf) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_environ_sizes_get( + &mut lucet_ctx, + environ_count_ptr: wasm32::uintptr_t, + environ_size_ptr: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + let heap = &mut lucet_ctx.heap_mut(); + environ_sizes_get(wasi_ctx, heap, environ_count_ptr, environ_size_ptr) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_fd_close( + &mut lucet_ctx, + fd: wasm32::__wasi_fd_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &mut lucet_ctx.get_embed_ctx_mut::(); + fd_close(wasi_ctx, fd) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_fd_fdstat_get( + &mut lucet_ctx, + fd: wasm32::__wasi_fd_t, + fdstat_ptr: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + let heap = &mut lucet_ctx.heap_mut(); + fd_fdstat_get(wasi_ctx, heap, fd, fdstat_ptr) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_fd_fdstat_set_flags( + &mut lucet_ctx, + fd: wasm32::__wasi_fd_t, + fdflags: wasm32::__wasi_fdflags_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + fd_fdstat_set_flags(wasi_ctx, fd, fdflags) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_fd_tell( + &mut lucet_ctx, + fd: wasm32::__wasi_fd_t, + offset: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &mut lucet_ctx.get_embed_ctx_mut::(); + let heap = &mut lucet_ctx.heap_mut(); + fd_tell(wasi_ctx, heap, fd, offset) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_fd_seek( + &mut lucet_ctx, + fd: wasm32::__wasi_fd_t, + offset: wasm32::__wasi_filedelta_t, + whence: wasm32::__wasi_whence_t, + newoffset: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &mut lucet_ctx.get_embed_ctx_mut::(); + let heap = &mut lucet_ctx.heap_mut(); + fd_seek(wasi_ctx, heap, fd, offset, whence, newoffset) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_fd_prestat_get( + &mut lucet_ctx, + fd: wasm32::__wasi_fd_t, + prestat_ptr: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + let heap = &mut lucet_ctx.heap_mut(); + fd_prestat_get(wasi_ctx, heap, fd, prestat_ptr) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_fd_prestat_dir_name( + &mut lucet_ctx, + fd: wasm32::__wasi_fd_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + let heap = &mut lucet_ctx.heap_mut(); + fd_prestat_dir_name(wasi_ctx, heap, fd, path_ptr, path_len) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_fd_read( + &mut lucet_ctx, + fd: wasm32::__wasi_fd_t, + iovs_ptr: wasm32::uintptr_t, + iovs_len: wasm32::size_t, + nread: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &mut lucet_ctx.get_embed_ctx_mut::(); + let heap = &mut lucet_ctx.heap_mut(); + fd_read(wasi_ctx, heap, fd, iovs_ptr, iovs_len, nread) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_fd_write( + &mut lucet_ctx, + fd: wasm32::__wasi_fd_t, + iovs_ptr: wasm32::uintptr_t, + iovs_len: wasm32::size_t, + nwritten: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &mut lucet_ctx.get_embed_ctx_mut::(); + let heap = &mut lucet_ctx.heap_mut(); + fd_write(wasi_ctx, heap, fd, iovs_ptr, iovs_len, nwritten) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_path_open( + &mut lucet_ctx, + dirfd: wasm32::__wasi_fd_t, + dirflags: wasm32::__wasi_lookupflags_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, + oflags: wasm32::__wasi_oflags_t, + fs_rights_base: wasm32::__wasi_rights_t, + fs_rights_inheriting: wasm32::__wasi_rights_t, + fs_flags: wasm32::__wasi_fdflags_t, + fd_out_ptr: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &mut lucet_ctx.get_embed_ctx_mut::(); + let heap = &mut lucet_ctx.heap_mut(); + path_open( + wasi_ctx, + heap, + dirfd, + dirflags, + path_ptr, + path_len, + oflags, + fs_rights_base, + fs_rights_inheriting, + fs_flags, + fd_out_ptr, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_random_get( + &mut lucet_ctx, + buf_ptr: wasm32::uintptr_t, + buf_len: wasm32::size_t, +) -> wasm32::__wasi_errno_t { + let heap = &mut lucet_ctx.heap_mut(); + random_get(heap, buf_ptr, buf_len) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_poll_oneoff( + &mut lucet_ctx, + input: wasm32::uintptr_t, + output: wasm32::uintptr_t, + nsubscriptions: wasm32::size_t, + nevents: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + let heap = &mut lucet_ctx.heap_mut(); + poll_oneoff(wasi_ctx, heap, input, output, nsubscriptions, nevents) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_fd_filestat_get( + &mut lucet_ctx, + fd: wasm32::__wasi_fd_t, + filestat_ptr: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + let heap = &mut lucet_ctx.heap_mut(); + fd_filestat_get(wasi_ctx, heap, fd, filestat_ptr) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_path_filestat_get( + &mut lucet_ctx, + dirfd: wasm32::__wasi_fd_t, + dirflags: wasm32::__wasi_lookupflags_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, + filestat_ptr: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + let heap = &mut lucet_ctx.heap_mut(); + path_filestat_get( + wasi_ctx, + heap, + dirfd, + dirflags, + path_ptr, + path_len, + filestat_ptr, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_path_create_directory( + &mut lucet_ctx, + dirfd: wasm32::__wasi_fd_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + let heap = &mut lucet_ctx.heap_mut(); + path_create_directory(wasi_ctx, heap, dirfd, path_ptr, path_len) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_path_unlink_file( + &mut lucet_ctx, + dirfd: wasm32::__wasi_fd_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + let heap = &mut lucet_ctx.heap_mut(); + path_unlink_file(wasi_ctx, heap, dirfd, path_ptr, path_len) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_fd_allocate( + &mut lucet_ctx, + fd: wasm32::__wasi_fd_t, + offset: wasm32::__wasi_filesize_t, + len: wasm32::__wasi_filesize_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + fd_allocate(wasi_ctx, fd, offset, len) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_fd_advise( + &mut lucet_ctx, + fd: wasm32::__wasi_fd_t, + offset: wasm32::__wasi_filesize_t, + len: wasm32::__wasi_filesize_t, + advice: wasm32::__wasi_advice_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + fd_advise(wasi_ctx, fd, offset, len, advice) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_fd_datasync( + &mut lucet_ctx, + fd: wasm32::__wasi_fd_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + fd_datasync(wasi_ctx, fd) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_fd_sync( + &mut lucet_ctx, + fd: wasm32::__wasi_fd_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + fd_sync(wasi_ctx, fd) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_fd_fdstat_set_rights( + &mut lucet_ctx, + fd: wasm32::__wasi_fd_t, + fs_rights_base: wasm32::__wasi_rights_t, + fs_rights_inheriting: wasm32::__wasi_rights_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &mut lucet_ctx.get_embed_ctx_mut::(); + fd_fdstat_set_rights(wasi_ctx, fd, fs_rights_base, fs_rights_inheriting) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_fd_filestat_set_size( + &mut lucet_ctx, + fd: wasm32::__wasi_fd_t, + st_size: wasm32::__wasi_filesize_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + fd_filestat_set_size(wasi_ctx, fd, st_size) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_fd_filestat_set_times( + &mut lucet_ctx, + fd: wasm32::__wasi_fd_t, + st_atim: wasm32::__wasi_timestamp_t, + st_mtim: wasm32::__wasi_timestamp_t, + fst_flags: wasm32::__wasi_fstflags_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + fd_filestat_set_times(wasi_ctx, fd, st_atim, st_mtim, fst_flags) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_fd_pread( + &mut lucet_ctx, + fd: wasm32::__wasi_fd_t, + iovs_ptr: wasm32::uintptr_t, + iovs_len: wasm32::size_t, + offset: wasm32::__wasi_filesize_t, + nread: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + let heap = &mut lucet_ctx.heap_mut(); + fd_pread(wasi_ctx, heap, fd, iovs_ptr, iovs_len, offset, nread) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_fd_pwrite( + &mut lucet_ctx, + fd: wasm32::__wasi_fd_t, + iovs_ptr: wasm32::uintptr_t, + iovs_len: wasm32::size_t, + offset: wasm32::__wasi_filesize_t, + nwritten: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + let heap = &mut lucet_ctx.heap_mut(); + fd_pwrite(wasi_ctx, heap, fd, iovs_ptr, iovs_len, offset, nwritten) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_fd_readdir( + &mut lucet_ctx, + fd: wasm32::__wasi_fd_t, + buf: wasm32::uintptr_t, + buf_len: wasm32::size_t, + cookie: wasm32::__wasi_dircookie_t, + bufused: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &mut lucet_ctx.get_embed_ctx_mut::(); + let heap = &mut lucet_ctx.heap_mut(); + fd_readdir(wasi_ctx, heap, fd, buf, buf_len, cookie, bufused) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_fd_renumber( + &mut lucet_ctx, + from: wasm32::__wasi_fd_t, + to: wasm32::__wasi_fd_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &mut lucet_ctx.get_embed_ctx_mut::(); + fd_renumber(wasi_ctx, from, to) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_path_filestat_set_times( + &mut lucet_ctx, + dirfd: wasm32::__wasi_fd_t, + dirflags: wasm32::__wasi_lookupflags_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, + st_atim: wasm32::__wasi_timestamp_t, + st_mtim: wasm32::__wasi_timestamp_t, + fst_flags: wasm32::__wasi_fstflags_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + let heap = &mut lucet_ctx.heap_mut(); + path_filestat_set_times( + wasi_ctx, heap, dirfd, dirflags, path_ptr, path_len, st_atim, st_mtim, fst_flags, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_path_link( + &mut lucet_ctx, + old_fd: wasm32::__wasi_fd_t, + old_flags: wasm32::__wasi_lookupflags_t, + old_path_ptr: wasm32::uintptr_t, + old_path_len: wasm32::size_t, + new_fd: wasm32::__wasi_fd_t, + new_path_ptr: wasm32::uintptr_t, + new_path_len: wasm32::size_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + let heap = &mut lucet_ctx.heap_mut(); + path_link( + wasi_ctx, + heap, + old_fd, + old_flags, + old_path_ptr, + old_path_len, + new_fd, + new_path_ptr, + new_path_len, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_path_readlink( + &mut lucet_ctx, + dirfd: wasm32::__wasi_fd_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, + buf_ptr: wasm32::uintptr_t, + buf_len: wasm32::size_t, + bufused: wasm32::uintptr_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + let heap = &mut lucet_ctx.heap_mut(); + path_readlink( + wasi_ctx, heap, dirfd, path_ptr, path_len, buf_ptr, buf_len, bufused, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_path_remove_directory( + &mut lucet_ctx, + dirfd: wasm32::__wasi_fd_t, + path_ptr: wasm32::uintptr_t, + path_len: wasm32::size_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + let heap = &mut lucet_ctx.heap_mut(); + path_remove_directory(wasi_ctx, heap, dirfd, path_ptr, path_len) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_path_rename( + &mut lucet_ctx, + old_dirfd: wasm32::__wasi_fd_t, + old_path_ptr: wasm32::uintptr_t, + old_path_len: wasm32::size_t, + new_dirfd: wasm32::__wasi_fd_t, + new_path_ptr: wasm32::uintptr_t, + new_path_len: wasm32::size_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + let heap = &mut lucet_ctx.heap_mut(); + path_rename( + wasi_ctx, + heap, + old_dirfd, + old_path_ptr, + old_path_len, + new_dirfd, + new_path_ptr, + new_path_len, + ) +} + +#[no_mangle] +pub unsafe extern "C" fn __wasi_path_symlink( + &mut lucet_ctx, + old_path_ptr: wasm32::uintptr_t, + old_path_len: wasm32::size_t, + dir_fd: wasm32::__wasi_fd_t, + new_path_ptr: wasm32::uintptr_t, + new_path_len: wasm32::size_t, +) -> wasm32::__wasi_errno_t { + let wasi_ctx = &lucet_ctx.get_embed_ctx::(); + let heap = &mut lucet_ctx.heap_mut(); + path_symlink( + wasi_ctx, + heap, + old_path_ptr, + old_path_len, + dir_fd, + new_path_ptr, + new_path_len, + ) +} + +} + +pub fn export_wasi_funcs() { + let funcs: &[*const extern "C" fn()] = &[ + __wasi_args_get as _, + __wasi_args_sizes_get as _, + __wasi_sched_yield as _, + __wasi_clock_res_get as _, + __wasi_clock_time_get as _, + __wasi_environ_get as _, + __wasi_environ_sizes_get as _, + __wasi_fd_close as _, + __wasi_fd_fdstat_get as _, + __wasi_fd_fdstat_set_flags as _, + __wasi_fd_tell as _, + __wasi_fd_seek as _, + __wasi_fd_prestat_get as _, + __wasi_fd_prestat_dir_name as _, + __wasi_fd_read as _, + __wasi_fd_write as _, + __wasi_path_open as _, + __wasi_random_get as _, + __wasi_poll_oneoff as _, + __wasi_fd_filestat_get as _, + __wasi_path_filestat_get as _, + __wasi_path_create_directory as _, + __wasi_path_unlink_file as _, + __wasi_fd_allocate as _, + __wasi_fd_advise as _, + __wasi_fd_datasync as _, + __wasi_fd_sync as _, + __wasi_fd_fdstat_set_rights as _, + __wasi_fd_filestat_set_size as _, + __wasi_fd_filestat_set_times as _, + __wasi_fd_pread as _, + __wasi_fd_pwrite as _, + __wasi_fd_readdir as _, + __wasi_fd_renumber as _, + __wasi_path_filestat_set_times as _, + __wasi_path_link as _, + __wasi_path_readlink as _, + __wasi_path_remove_directory as _, + __wasi_path_rename as _, + __wasi_path_symlink as _, + __wasi_proc_exit as _, + ]; + mem::forget(Rc::new(funcs)); +} diff --git a/lucet-wasi/src/wasi_host.rs b/lucet-wasi/src/wasi_host.rs deleted file mode 100644 index 08ae16363..000000000 --- a/lucet-wasi/src/wasi_host.rs +++ /dev/null @@ -1,1035 +0,0 @@ -/* automatically generated by rust-bindgen */ - -pub const __WASI_ADVICE_NORMAL: u32 = 0; -pub const __WASI_ADVICE_SEQUENTIAL: u32 = 1; -pub const __WASI_ADVICE_RANDOM: u32 = 2; -pub const __WASI_ADVICE_WILLNEED: u32 = 3; -pub const __WASI_ADVICE_DONTNEED: u32 = 4; -pub const __WASI_ADVICE_NOREUSE: u32 = 5; -pub const __WASI_CLOCK_REALTIME: u32 = 0; -pub const __WASI_CLOCK_MONOTONIC: u32 = 1; -pub const __WASI_CLOCK_PROCESS_CPUTIME_ID: u32 = 2; -pub const __WASI_CLOCK_THREAD_CPUTIME_ID: u32 = 3; -pub const __WASI_DIRCOOKIE_START: u32 = 0; -pub const __WASI_ESUCCESS: u32 = 0; -pub const __WASI_E2BIG: u32 = 1; -pub const __WASI_EACCES: u32 = 2; -pub const __WASI_EADDRINUSE: u32 = 3; -pub const __WASI_EADDRNOTAVAIL: u32 = 4; -pub const __WASI_EAFNOSUPPORT: u32 = 5; -pub const __WASI_EAGAIN: u32 = 6; -pub const __WASI_EALREADY: u32 = 7; -pub const __WASI_EBADF: u32 = 8; -pub const __WASI_EBADMSG: u32 = 9; -pub const __WASI_EBUSY: u32 = 10; -pub const __WASI_ECANCELED: u32 = 11; -pub const __WASI_ECHILD: u32 = 12; -pub const __WASI_ECONNABORTED: u32 = 13; -pub const __WASI_ECONNREFUSED: u32 = 14; -pub const __WASI_ECONNRESET: u32 = 15; -pub const __WASI_EDEADLK: u32 = 16; -pub const __WASI_EDESTADDRREQ: u32 = 17; -pub const __WASI_EDOM: u32 = 18; -pub const __WASI_EDQUOT: u32 = 19; -pub const __WASI_EEXIST: u32 = 20; -pub const __WASI_EFAULT: u32 = 21; -pub const __WASI_EFBIG: u32 = 22; -pub const __WASI_EHOSTUNREACH: u32 = 23; -pub const __WASI_EIDRM: u32 = 24; -pub const __WASI_EILSEQ: u32 = 25; -pub const __WASI_EINPROGRESS: u32 = 26; -pub const __WASI_EINTR: u32 = 27; -pub const __WASI_EINVAL: u32 = 28; -pub const __WASI_EIO: u32 = 29; -pub const __WASI_EISCONN: u32 = 30; -pub const __WASI_EISDIR: u32 = 31; -pub const __WASI_ELOOP: u32 = 32; -pub const __WASI_EMFILE: u32 = 33; -pub const __WASI_EMLINK: u32 = 34; -pub const __WASI_EMSGSIZE: u32 = 35; -pub const __WASI_EMULTIHOP: u32 = 36; -pub const __WASI_ENAMETOOLONG: u32 = 37; -pub const __WASI_ENETDOWN: u32 = 38; -pub const __WASI_ENETRESET: u32 = 39; -pub const __WASI_ENETUNREACH: u32 = 40; -pub const __WASI_ENFILE: u32 = 41; -pub const __WASI_ENOBUFS: u32 = 42; -pub const __WASI_ENODEV: u32 = 43; -pub const __WASI_ENOENT: u32 = 44; -pub const __WASI_ENOEXEC: u32 = 45; -pub const __WASI_ENOLCK: u32 = 46; -pub const __WASI_ENOLINK: u32 = 47; -pub const __WASI_ENOMEM: u32 = 48; -pub const __WASI_ENOMSG: u32 = 49; -pub const __WASI_ENOPROTOOPT: u32 = 50; -pub const __WASI_ENOSPC: u32 = 51; -pub const __WASI_ENOSYS: u32 = 52; -pub const __WASI_ENOTCONN: u32 = 53; -pub const __WASI_ENOTDIR: u32 = 54; -pub const __WASI_ENOTEMPTY: u32 = 55; -pub const __WASI_ENOTRECOVERABLE: u32 = 56; -pub const __WASI_ENOTSOCK: u32 = 57; -pub const __WASI_ENOTSUP: u32 = 58; -pub const __WASI_ENOTTY: u32 = 59; -pub const __WASI_ENXIO: u32 = 60; -pub const __WASI_EOVERFLOW: u32 = 61; -pub const __WASI_EOWNERDEAD: u32 = 62; -pub const __WASI_EPERM: u32 = 63; -pub const __WASI_EPIPE: u32 = 64; -pub const __WASI_EPROTO: u32 = 65; -pub const __WASI_EPROTONOSUPPORT: u32 = 66; -pub const __WASI_EPROTOTYPE: u32 = 67; -pub const __WASI_ERANGE: u32 = 68; -pub const __WASI_EROFS: u32 = 69; -pub const __WASI_ESPIPE: u32 = 70; -pub const __WASI_ESRCH: u32 = 71; -pub const __WASI_ESTALE: u32 = 72; -pub const __WASI_ETIMEDOUT: u32 = 73; -pub const __WASI_ETXTBSY: u32 = 74; -pub const __WASI_EXDEV: u32 = 75; -pub const __WASI_ENOTCAPABLE: u32 = 76; -pub const __WASI_EVENT_FD_READWRITE_HANGUP: u32 = 1; -pub const __WASI_EVENTTYPE_CLOCK: u32 = 0; -pub const __WASI_EVENTTYPE_FD_READ: u32 = 1; -pub const __WASI_EVENTTYPE_FD_WRITE: u32 = 2; -pub const __WASI_FDFLAG_APPEND: u32 = 1; -pub const __WASI_FDFLAG_DSYNC: u32 = 2; -pub const __WASI_FDFLAG_NONBLOCK: u32 = 4; -pub const __WASI_FDFLAG_RSYNC: u32 = 8; -pub const __WASI_FDFLAG_SYNC: u32 = 16; -pub const __WASI_FILETYPE_UNKNOWN: u32 = 0; -pub const __WASI_FILETYPE_BLOCK_DEVICE: u32 = 1; -pub const __WASI_FILETYPE_CHARACTER_DEVICE: u32 = 2; -pub const __WASI_FILETYPE_DIRECTORY: u32 = 3; -pub const __WASI_FILETYPE_REGULAR_FILE: u32 = 4; -pub const __WASI_FILETYPE_SOCKET_DGRAM: u32 = 5; -pub const __WASI_FILETYPE_SOCKET_STREAM: u32 = 6; -pub const __WASI_FILETYPE_SYMBOLIC_LINK: u32 = 7; -pub const __WASI_FILESTAT_SET_ATIM: u32 = 1; -pub const __WASI_FILESTAT_SET_ATIM_NOW: u32 = 2; -pub const __WASI_FILESTAT_SET_MTIM: u32 = 4; -pub const __WASI_FILESTAT_SET_MTIM_NOW: u32 = 8; -pub const __WASI_LOOKUP_SYMLINK_FOLLOW: u32 = 1; -pub const __WASI_O_CREAT: u32 = 1; -pub const __WASI_O_DIRECTORY: u32 = 2; -pub const __WASI_O_EXCL: u32 = 4; -pub const __WASI_O_TRUNC: u32 = 8; -pub const __WASI_SOCK_RECV_PEEK: u32 = 1; -pub const __WASI_SOCK_RECV_WAITALL: u32 = 2; -pub const __WASI_RIGHT_FD_DATASYNC: u32 = 1; -pub const __WASI_RIGHT_FD_READ: u32 = 2; -pub const __WASI_RIGHT_FD_SEEK: u32 = 4; -pub const __WASI_RIGHT_FD_FDSTAT_SET_FLAGS: u32 = 8; -pub const __WASI_RIGHT_FD_SYNC: u32 = 16; -pub const __WASI_RIGHT_FD_TELL: u32 = 32; -pub const __WASI_RIGHT_FD_WRITE: u32 = 64; -pub const __WASI_RIGHT_FD_ADVISE: u32 = 128; -pub const __WASI_RIGHT_FD_ALLOCATE: u32 = 256; -pub const __WASI_RIGHT_PATH_CREATE_DIRECTORY: u32 = 512; -pub const __WASI_RIGHT_PATH_CREATE_FILE: u32 = 1024; -pub const __WASI_RIGHT_PATH_LINK_SOURCE: u32 = 2048; -pub const __WASI_RIGHT_PATH_LINK_TARGET: u32 = 4096; -pub const __WASI_RIGHT_PATH_OPEN: u32 = 8192; -pub const __WASI_RIGHT_FD_READDIR: u32 = 16384; -pub const __WASI_RIGHT_PATH_READLINK: u32 = 32768; -pub const __WASI_RIGHT_PATH_RENAME_SOURCE: u32 = 65536; -pub const __WASI_RIGHT_PATH_RENAME_TARGET: u32 = 131072; -pub const __WASI_RIGHT_PATH_FILESTAT_GET: u32 = 262144; -pub const __WASI_RIGHT_PATH_FILESTAT_SET_SIZE: u32 = 524288; -pub const __WASI_RIGHT_PATH_FILESTAT_SET_TIMES: u32 = 1048576; -pub const __WASI_RIGHT_FD_FILESTAT_GET: u32 = 2097152; -pub const __WASI_RIGHT_FD_FILESTAT_SET_SIZE: u32 = 4194304; -pub const __WASI_RIGHT_FD_FILESTAT_SET_TIMES: u32 = 8388608; -pub const __WASI_RIGHT_PATH_SYMLINK: u32 = 16777216; -pub const __WASI_RIGHT_PATH_REMOVE_DIRECTORY: u32 = 33554432; -pub const __WASI_RIGHT_PATH_UNLINK_FILE: u32 = 67108864; -pub const __WASI_RIGHT_POLL_FD_READWRITE: u32 = 134217728; -pub const __WASI_RIGHT_SOCK_SHUTDOWN: u32 = 268435456; -pub const __WASI_SOCK_RECV_DATA_TRUNCATED: u32 = 1; -pub const __WASI_SHUT_RD: u32 = 1; -pub const __WASI_SHUT_WR: u32 = 2; -pub const __WASI_SIGHUP: u32 = 1; -pub const __WASI_SIGINT: u32 = 2; -pub const __WASI_SIGQUIT: u32 = 3; -pub const __WASI_SIGILL: u32 = 4; -pub const __WASI_SIGTRAP: u32 = 5; -pub const __WASI_SIGABRT: u32 = 6; -pub const __WASI_SIGBUS: u32 = 7; -pub const __WASI_SIGFPE: u32 = 8; -pub const __WASI_SIGKILL: u32 = 9; -pub const __WASI_SIGUSR1: u32 = 10; -pub const __WASI_SIGSEGV: u32 = 11; -pub const __WASI_SIGUSR2: u32 = 12; -pub const __WASI_SIGPIPE: u32 = 13; -pub const __WASI_SIGALRM: u32 = 14; -pub const __WASI_SIGTERM: u32 = 15; -pub const __WASI_SIGCHLD: u32 = 16; -pub const __WASI_SIGCONT: u32 = 17; -pub const __WASI_SIGSTOP: u32 = 18; -pub const __WASI_SIGTSTP: u32 = 19; -pub const __WASI_SIGTTIN: u32 = 20; -pub const __WASI_SIGTTOU: u32 = 21; -pub const __WASI_SIGURG: u32 = 22; -pub const __WASI_SIGXCPU: u32 = 23; -pub const __WASI_SIGXFSZ: u32 = 24; -pub const __WASI_SIGVTALRM: u32 = 25; -pub const __WASI_SIGPROF: u32 = 26; -pub const __WASI_SIGWINCH: u32 = 27; -pub const __WASI_SIGPOLL: u32 = 28; -pub const __WASI_SIGPWR: u32 = 29; -pub const __WASI_SIGSYS: u32 = 30; -pub const __WASI_SUBSCRIPTION_CLOCK_ABSTIME: u32 = 1; -pub const __WASI_WHENCE_CUR: u32 = 0; -pub const __WASI_WHENCE_END: u32 = 1; -pub const __WASI_WHENCE_SET: u32 = 2; -pub const __WASI_PREOPENTYPE_DIR: u32 = 0; -pub type __wasi_advice_t = u8; -pub type __wasi_clockid_t = u32; -pub type __wasi_device_t = u64; -pub type __wasi_dircookie_t = u64; -pub type __wasi_errno_t = u16; -pub type __wasi_eventrwflags_t = u16; -pub type __wasi_eventtype_t = u8; -pub type __wasi_exitcode_t = u32; -pub type __wasi_fd_t = u32; -pub type __wasi_fdflags_t = u16; -pub type __wasi_filedelta_t = i64; -pub type __wasi_filesize_t = u64; -pub type __wasi_filetype_t = u8; -pub type __wasi_fstflags_t = u16; -pub type __wasi_inode_t = u64; -pub type __wasi_linkcount_t = u32; -pub type __wasi_lookupflags_t = u32; -pub type __wasi_oflags_t = u16; -pub type __wasi_riflags_t = u16; -pub type __wasi_rights_t = u64; -pub type __wasi_roflags_t = u16; -pub type __wasi_sdflags_t = u8; -pub type __wasi_siflags_t = u16; -pub type __wasi_signal_t = u8; -pub type __wasi_subclockflags_t = u16; -pub type __wasi_timestamp_t = u64; -pub type __wasi_userdata_t = u64; -pub type __wasi_whence_t = u8; -pub type __wasi_preopentype_t = u8; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __wasi_dirent_t { - pub d_next: __wasi_dircookie_t, - pub d_ino: __wasi_inode_t, - pub d_namlen: u32, - pub d_type: __wasi_filetype_t, -} -#[test] -fn bindgen_test_layout___wasi_dirent_t() { - assert_eq!( - ::std::mem::size_of::<__wasi_dirent_t>(), - 24usize, - concat!("Size of: ", stringify!(__wasi_dirent_t)) - ); - assert_eq!( - ::std::mem::align_of::<__wasi_dirent_t>(), - 8usize, - concat!("Alignment of ", stringify!(__wasi_dirent_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_next as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_dirent_t), - "::", - stringify!(d_next) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_ino as *const _ as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(__wasi_dirent_t), - "::", - stringify!(d_ino) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_namlen as *const _ as usize }, - 16usize, - concat!( - "Offset of field: ", - stringify!(__wasi_dirent_t), - "::", - stringify!(d_namlen) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_type as *const _ as usize }, - 20usize, - concat!( - "Offset of field: ", - stringify!(__wasi_dirent_t), - "::", - stringify!(d_type) - ) - ); -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct __wasi_event_t { - pub userdata: __wasi_userdata_t, - pub error: __wasi_errno_t, - pub type_: __wasi_eventtype_t, - pub u: __wasi_event_t___wasi_event_u, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub union __wasi_event_t___wasi_event_u { - pub fd_readwrite: __wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t, - _bindgen_union_align: [u64; 2usize], -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t { - pub nbytes: __wasi_filesize_t, - pub flags: __wasi_eventrwflags_t, -} -#[test] -fn bindgen_test_layout___wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t() { - assert_eq!( - ::std::mem::size_of::<__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t>(), - 16usize, - concat!( - "Size of: ", - stringify!(__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t) - ) - ); - assert_eq!( - ::std::mem::align_of::<__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t>(), - 8usize, - concat!( - "Alignment of ", - stringify!(__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t>())) - .nbytes as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t), - "::", - stringify!(nbytes) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t>())) - .flags as *const _ as usize - }, - 8usize, - concat!( - "Offset of field: ", - stringify!(__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t), - "::", - stringify!(flags) - ) - ); -} -#[test] -fn bindgen_test_layout___wasi_event_t___wasi_event_u() { - assert_eq!( - ::std::mem::size_of::<__wasi_event_t___wasi_event_u>(), - 16usize, - concat!("Size of: ", stringify!(__wasi_event_t___wasi_event_u)) - ); - assert_eq!( - ::std::mem::align_of::<__wasi_event_t___wasi_event_u>(), - 8usize, - concat!("Alignment of ", stringify!(__wasi_event_t___wasi_event_u)) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_event_t___wasi_event_u>())).fd_readwrite as *const _ - as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_event_t___wasi_event_u), - "::", - stringify!(fd_readwrite) - ) - ); -} -#[test] -fn bindgen_test_layout___wasi_event_t() { - assert_eq!( - ::std::mem::size_of::<__wasi_event_t>(), - 32usize, - concat!("Size of: ", stringify!(__wasi_event_t)) - ); - assert_eq!( - ::std::mem::align_of::<__wasi_event_t>(), - 8usize, - concat!("Alignment of ", stringify!(__wasi_event_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).userdata as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_event_t), - "::", - stringify!(userdata) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).error as *const _ as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(__wasi_event_t), - "::", - stringify!(error) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).type_ as *const _ as usize }, - 10usize, - concat!( - "Offset of field: ", - stringify!(__wasi_event_t), - "::", - stringify!(type_) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).u as *const _ as usize }, - 16usize, - concat!( - "Offset of field: ", - stringify!(__wasi_event_t), - "::", - stringify!(u) - ) - ); -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct __wasi_prestat_t { - pub pr_type: __wasi_preopentype_t, - pub u: __wasi_prestat_t___wasi_prestat_u, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub union __wasi_prestat_t___wasi_prestat_u { - pub dir: __wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t, - _bindgen_union_align: u64, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t { - pub pr_name_len: usize, -} -#[test] -fn bindgen_test_layout___wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t() { - assert_eq!( - ::std::mem::size_of::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>(), - 8usize, - concat!( - "Size of: ", - stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t) - ) - ); - assert_eq!( - ::std::mem::align_of::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>(), - 8usize, - concat!( - "Alignment of ", - stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>())) - .pr_name_len as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t), - "::", - stringify!(pr_name_len) - ) - ); -} -#[test] -fn bindgen_test_layout___wasi_prestat_t___wasi_prestat_u() { - assert_eq!( - ::std::mem::size_of::<__wasi_prestat_t___wasi_prestat_u>(), - 8usize, - concat!("Size of: ", stringify!(__wasi_prestat_t___wasi_prestat_u)) - ); - assert_eq!( - ::std::mem::align_of::<__wasi_prestat_t___wasi_prestat_u>(), - 8usize, - concat!( - "Alignment of ", - stringify!(__wasi_prestat_t___wasi_prestat_u) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_prestat_t___wasi_prestat_u>())).dir as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_prestat_t___wasi_prestat_u), - "::", - stringify!(dir) - ) - ); -} -#[test] -fn bindgen_test_layout___wasi_prestat_t() { - assert_eq!( - ::std::mem::size_of::<__wasi_prestat_t>(), - 16usize, - concat!("Size of: ", stringify!(__wasi_prestat_t)) - ); - assert_eq!( - ::std::mem::align_of::<__wasi_prestat_t>(), - 8usize, - concat!("Alignment of ", stringify!(__wasi_prestat_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_prestat_t>())).pr_type as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_prestat_t), - "::", - stringify!(pr_type) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_prestat_t>())).u as *const _ as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(__wasi_prestat_t), - "::", - stringify!(u) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __wasi_fdstat_t { - pub fs_filetype: __wasi_filetype_t, - pub fs_flags: __wasi_fdflags_t, - pub fs_rights_base: __wasi_rights_t, - pub fs_rights_inheriting: __wasi_rights_t, -} -#[test] -fn bindgen_test_layout___wasi_fdstat_t() { - assert_eq!( - ::std::mem::size_of::<__wasi_fdstat_t>(), - 24usize, - concat!("Size of: ", stringify!(__wasi_fdstat_t)) - ); - assert_eq!( - ::std::mem::align_of::<__wasi_fdstat_t>(), - 8usize, - concat!("Alignment of ", stringify!(__wasi_fdstat_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_filetype as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_fdstat_t), - "::", - stringify!(fs_filetype) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_flags as *const _ as usize }, - 2usize, - concat!( - "Offset of field: ", - stringify!(__wasi_fdstat_t), - "::", - stringify!(fs_flags) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_rights_base as *const _ as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(__wasi_fdstat_t), - "::", - stringify!(fs_rights_base) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_rights_inheriting as *const _ as usize - }, - 16usize, - concat!( - "Offset of field: ", - stringify!(__wasi_fdstat_t), - "::", - stringify!(fs_rights_inheriting) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __wasi_filestat_t { - pub st_dev: __wasi_device_t, - pub st_ino: __wasi_inode_t, - pub st_filetype: __wasi_filetype_t, - pub st_nlink: __wasi_linkcount_t, - pub st_size: __wasi_filesize_t, - pub st_atim: __wasi_timestamp_t, - pub st_mtim: __wasi_timestamp_t, - pub st_ctim: __wasi_timestamp_t, -} -#[test] -fn bindgen_test_layout___wasi_filestat_t() { - assert_eq!( - ::std::mem::size_of::<__wasi_filestat_t>(), - 56usize, - concat!("Size of: ", stringify!(__wasi_filestat_t)) - ); - assert_eq!( - ::std::mem::align_of::<__wasi_filestat_t>(), - 8usize, - concat!("Alignment of ", stringify!(__wasi_filestat_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_dev as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_filestat_t), - "::", - stringify!(st_dev) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_ino as *const _ as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(__wasi_filestat_t), - "::", - stringify!(st_ino) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_filetype as *const _ as usize }, - 16usize, - concat!( - "Offset of field: ", - stringify!(__wasi_filestat_t), - "::", - stringify!(st_filetype) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_nlink as *const _ as usize }, - 20usize, - concat!( - "Offset of field: ", - stringify!(__wasi_filestat_t), - "::", - stringify!(st_nlink) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_size as *const _ as usize }, - 24usize, - concat!( - "Offset of field: ", - stringify!(__wasi_filestat_t), - "::", - stringify!(st_size) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_atim as *const _ as usize }, - 32usize, - concat!( - "Offset of field: ", - stringify!(__wasi_filestat_t), - "::", - stringify!(st_atim) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_mtim as *const _ as usize }, - 40usize, - concat!( - "Offset of field: ", - stringify!(__wasi_filestat_t), - "::", - stringify!(st_mtim) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_ctim as *const _ as usize }, - 48usize, - concat!( - "Offset of field: ", - stringify!(__wasi_filestat_t), - "::", - stringify!(st_ctim) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __wasi_ciovec_t { - pub buf: *const ::std::os::raw::c_void, - pub buf_len: usize, -} -#[test] -fn bindgen_test_layout___wasi_ciovec_t() { - assert_eq!( - ::std::mem::size_of::<__wasi_ciovec_t>(), - 16usize, - concat!("Size of: ", stringify!(__wasi_ciovec_t)) - ); - assert_eq!( - ::std::mem::align_of::<__wasi_ciovec_t>(), - 8usize, - concat!("Alignment of ", stringify!(__wasi_ciovec_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_ciovec_t>())).buf as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_ciovec_t), - "::", - stringify!(buf) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_ciovec_t>())).buf_len as *const _ as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(__wasi_ciovec_t), - "::", - stringify!(buf_len) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __wasi_iovec_t { - pub buf: *mut ::std::os::raw::c_void, - pub buf_len: usize, -} -#[test] -fn bindgen_test_layout___wasi_iovec_t() { - assert_eq!( - ::std::mem::size_of::<__wasi_iovec_t>(), - 16usize, - concat!("Size of: ", stringify!(__wasi_iovec_t)) - ); - assert_eq!( - ::std::mem::align_of::<__wasi_iovec_t>(), - 8usize, - concat!("Alignment of ", stringify!(__wasi_iovec_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_iovec_t>())).buf as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_iovec_t), - "::", - stringify!(buf) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_iovec_t>())).buf_len as *const _ as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(__wasi_iovec_t), - "::", - stringify!(buf_len) - ) - ); -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct __wasi_subscription_t { - pub userdata: __wasi_userdata_t, - pub type_: __wasi_eventtype_t, - pub u: __wasi_subscription_t___wasi_subscription_u, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub union __wasi_subscription_t___wasi_subscription_u { - pub clock: __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, - pub fd_readwrite: - __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t, - _bindgen_union_align: [u64; 5usize], -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t { - pub identifier: __wasi_userdata_t, - pub clock_id: __wasi_clockid_t, - pub timeout: __wasi_timestamp_t, - pub precision: __wasi_timestamp_t, - pub flags: __wasi_subclockflags_t, -} -#[test] -fn bindgen_test_layout___wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t() { - assert_eq!( - ::std::mem::size_of::< - __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, - >(), - 40usize, - concat!( - "Size of: ", - stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t) - ) - ); - assert_eq!( - ::std::mem::align_of::< - __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, - >(), - 8usize, - concat!( - "Alignment of ", - stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::< - __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, - >())) - .identifier as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t), - "::", - stringify!(identifier) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::< - __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, - >())) - .clock_id as *const _ as usize - }, - 8usize, - concat!( - "Offset of field: ", - stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t), - "::", - stringify!(clock_id) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::< - __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, - >())) - .timeout as *const _ as usize - }, - 16usize, - concat!( - "Offset of field: ", - stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t), - "::", - stringify!(timeout) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::< - __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, - >())) - .precision as *const _ as usize - }, - 24usize, - concat!( - "Offset of field: ", - stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t), - "::", - stringify!(precision) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::< - __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t, - >())) - .flags as *const _ as usize - }, - 32usize, - concat!( - "Offset of field: ", - stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t), - "::", - stringify!(flags) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t { - pub fd: __wasi_fd_t, -} -#[test] -fn bindgen_test_layout___wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t( -) { - assert_eq!( - ::std::mem::size_of::< - __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t, - >(), - 4usize, - concat!( - "Size of: ", - stringify!( - __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t - ) - ) - ); - assert_eq!( - ::std::mem::align_of::< - __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t, - >(), - 4usize, - concat!( - "Alignment of ", - stringify!( - __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t - ) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::< - __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t, - >())) - .fd as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!( - __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t - ), - "::", - stringify!(fd) - ) - ); -} -#[test] -fn bindgen_test_layout___wasi_subscription_t___wasi_subscription_u() { - assert_eq!( - ::std::mem::size_of::<__wasi_subscription_t___wasi_subscription_u>(), - 40usize, - concat!( - "Size of: ", - stringify!(__wasi_subscription_t___wasi_subscription_u) - ) - ); - assert_eq!( - ::std::mem::align_of::<__wasi_subscription_t___wasi_subscription_u>(), - 8usize, - concat!( - "Alignment of ", - stringify!(__wasi_subscription_t___wasi_subscription_u) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_subscription_t___wasi_subscription_u>())).clock - as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_subscription_t___wasi_subscription_u), - "::", - stringify!(clock) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_subscription_t___wasi_subscription_u>())).fd_readwrite - as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_subscription_t___wasi_subscription_u), - "::", - stringify!(fd_readwrite) - ) - ); -} -#[test] -fn bindgen_test_layout___wasi_subscription_t() { - assert_eq!( - ::std::mem::size_of::<__wasi_subscription_t>(), - 56usize, - concat!("Size of: ", stringify!(__wasi_subscription_t)) - ); - assert_eq!( - ::std::mem::align_of::<__wasi_subscription_t>(), - 8usize, - concat!("Alignment of ", stringify!(__wasi_subscription_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_subscription_t>())).userdata as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_subscription_t), - "::", - stringify!(userdata) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_subscription_t>())).type_ as *const _ as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(__wasi_subscription_t), - "::", - stringify!(type_) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_subscription_t>())).u as *const _ as usize }, - 16usize, - concat!( - "Offset of field: ", - stringify!(__wasi_subscription_t), - "::", - stringify!(u) - ) - ); -} diff --git a/lucet-wasi/src/wasm32.rs b/lucet-wasi/src/wasm32.rs deleted file mode 100644 index 9983b3790..000000000 --- a/lucet-wasi/src/wasm32.rs +++ /dev/null @@ -1,1367 +0,0 @@ -//! WASI types as defined in wasm32. This file was originally generated -//! by running bindgen over wasi/core.h with a wasm32 target, and the content -//! still largely reflects that, however it's been heavily modified, to -//! be host-independent, to avoid exposing libc implementation details, -//! to clean up cases where the headers use complex preprocessor macros, -//! and to - -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] -#![allow(dead_code)] - -// C types -pub type char = i8; -pub type schar = i8; -pub type uchar = u8; -pub type short = i16; -pub type ushort = u16; -pub type int = i32; -pub type uint = u32; -pub type long = i32; -pub type ulong = u32; -pub type longlong = i64; -pub type ulonglong = u64; - -// libc stdint types -pub type int8_t = i8; -pub type uint8_t = u8; -pub type int16_t = i16; -pub type uint16_t = u16; -pub type int32_t = i32; -pub type uint32_t = u32; -pub type int64_t = i64; -pub type uint64_t = u64; -pub type intmax_t = i64; -pub type uintmax_t = u64; -pub type int_least8_t = i8; -pub type int_least16_t = i16; -pub type int_least32_t = i32; -pub type int_least64_t = i64; -pub type uint_least8_t = u8; -pub type uint_least16_t = u16; -pub type uint_least32_t = u32; -pub type uint_least64_t = u64; -pub type int_fast8_t = i8; -pub type int_fast16_t = i32; -pub type int_fast32_t = i32; -pub type int_fast64_t = i64; -pub type uint_fast8_t = u8; -pub type uint_fast16_t = u32; -pub type uint_fast32_t = u32; -pub type uint_fast64_t = u64; -pub type size_t = ulong; -pub type intptr_t = long; -pub type uintptr_t = ulong; -pub type wchar_t = i32; - -// libc types -pub type dev_t = u64; -pub type uid_t = u32; -pub type gid_t = u32; -pub type ino_t = u64; -pub type ino64_t = u64; -pub type mode_t = u32; -pub type nlink_t = u64; -pub type off_t = i64; -pub type off64_t = i64; -pub type pid_t = i32; -pub type clock_t = i64; -pub type rlim_t = u64; -pub type rlim64_t = u64; -pub type id_t = u32; -pub type time_t = i64; -pub type useconds_t = u32; -pub type suseconds_t = i64; -pub type daddr_t = i32; -pub type key_t = i32; -pub type clockid_t = i32; -pub type timer_t = uintptr_t; // *mut ::std::os::raw::c_void -pub type blksize_t = i64; -pub type blkcnt_t = i64; -pub type blkcnt64_t = i64; -pub type fsblkcnt_t = u64; -pub type fsblkcnt64_t = u64; -pub type fsfilcnt_t = u64; -pub type fsfilcnt64_t = u64; -pub type fsword_t = i64; -pub type ssize_t = i32; -pub type loff_t = off64_t; -pub type caddr_t = uintptr_t; // *mut i8 -pub type socklen_t = u32; -pub type sig_atomic_t = i32; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct fsid_t { - pub __val: [i32; 2usize], -} -#[allow(non_snake_case)] -#[test] -fn bindgen_test_layout_fsid_t() { - assert_eq!( - ::std::mem::size_of::(), - 8usize, - concat!("Size of: ", stringify!(fsid_t)) - ); - assert_eq!( - ::std::mem::align_of::(), - 4usize, - concat!("Alignment of ", stringify!(fsid_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::())).__val as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(fsid_t), - "::", - stringify!(__val) - ) - ); -} - -// WASI types -pub type __wasi_advice_t = u8; -pub type __wasi_clockid_t = u32; -pub type __wasi_device_t = u64; -pub type __wasi_dircookie_t = u64; -pub type __wasi_errno_t = u16; -pub type __wasi_eventrwflags_t = u16; -pub type __wasi_eventtype_t = u8; -pub type __wasi_exitcode_t = u32; -pub type __wasi_fd_t = u32; -pub type __wasi_fdflags_t = u16; -pub type __wasi_fdsflags_t = u16; -pub type __wasi_filedelta_t = i64; -pub type __wasi_filesize_t = u64; -pub type __wasi_filetype_t = u8; -pub type __wasi_preopentype_t = u8; -pub type __wasi_fstflags_t = u16; -pub type __wasi_inode_t = u64; -pub type __wasi_linkcount_t = u32; -pub type __wasi_lookupflags_t = u32; -pub type __wasi_oflags_t = u16; -pub type __wasi_riflags_t = u16; -pub type __wasi_rights_t = u64; -pub type __wasi_roflags_t = u16; -pub type __wasi_sdflags_t = u8; -pub type __wasi_siflags_t = u16; -pub type __wasi_signal_t = u8; -pub type __wasi_subclockflags_t = u16; -pub type __wasi_timestamp_t = u64; -pub type __wasi_userdata_t = u64; -pub type __wasi_whence_t = u8; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __wasi_dirent_t { - pub d_next: __wasi_dircookie_t, - pub d_ino: __wasi_inode_t, - pub d_namlen: u32, - pub d_type: __wasi_filetype_t, - pub __bindgen_padding_0: [u8; 3usize], -} -#[test] -fn bindgen_test_layout_wasi_dirent_t() { - assert_eq!( - ::std::mem::size_of::<__wasi_dirent_t>(), - 24usize, - concat!("Size of: ", stringify!(__wasi_dirent_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_next as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_dirent_t), - "::", - stringify!(d_next) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_ino as *const _ as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(__wasi_dirent_t), - "::", - stringify!(d_ino) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_namlen as *const _ as usize }, - 16usize, - concat!( - "Offset of field: ", - stringify!(__wasi_dirent_t), - "::", - stringify!(d_namlen) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_type as *const _ as usize }, - 20usize, - concat!( - "Offset of field: ", - stringify!(__wasi_dirent_t), - "::", - stringify!(d_type) - ) - ); -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct __wasi_event_t { - pub userdata: __wasi_userdata_t, - pub error: __wasi_errno_t, - pub type_: __wasi_eventtype_t, - pub __bindgen_padding_0: u32, - pub __bindgen_anon_1: __wasi_event_t__bindgen_ty_1, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct __wasi_prestat_t { - pub pr_type: __wasi_preopentype_t, - pub u: __wasi_prestat_t___wasi_prestat_u, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub union __wasi_prestat_t___wasi_prestat_u { - pub dir: __wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t { - pub pr_name_len: size_t, -} -#[test] -fn bindgen_test_layout___wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t() { - assert_eq!( - ::std::mem::size_of::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>(), - 4usize, - concat!( - "Size of: ", - stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t) - ) - ); - assert_eq!( - ::std::mem::align_of::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>(), - 4usize, - concat!( - "Alignment of ", - stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>())) - .pr_name_len as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t), - "::", - stringify!(pr_name_len) - ) - ); -} -#[test] -fn bindgen_test_layout___wasi_prestat_t___wasi_prestat_u() { - assert_eq!( - ::std::mem::size_of::<__wasi_prestat_t___wasi_prestat_u>(), - 4usize, - concat!("Size of: ", stringify!(__wasi_prestat_t___wasi_prestat_u)) - ); - assert_eq!( - ::std::mem::align_of::<__wasi_prestat_t___wasi_prestat_u>(), - 4usize, - concat!( - "Alignment of ", - stringify!(__wasi_prestat_t___wasi_prestat_u) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_prestat_t___wasi_prestat_u>())).dir as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_prestat_t___wasi_prestat_u), - "::", - stringify!(dir) - ) - ); -} -#[test] -fn bindgen_test_layout___wasi_prestat_t() { - assert_eq!( - ::std::mem::size_of::<__wasi_prestat_t>(), - 8usize, - concat!("Size of: ", stringify!(__wasi_prestat_t)) - ); - assert_eq!( - ::std::mem::align_of::<__wasi_prestat_t>(), - 4usize, - concat!("Alignment of ", stringify!(__wasi_prestat_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_prestat_t>())).pr_type as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_prestat_t), - "::", - stringify!(pr_type) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_prestat_t>())).u as *const _ as usize }, - 4usize, - concat!( - "Offset of field: ", - stringify!(__wasi_prestat_t), - "::", - stringify!(u) - ) - ); -} -#[allow(non_snake_case)] -#[repr(C)] -#[derive(Copy, Clone)] -pub union __wasi_event_t__bindgen_ty_1 { - pub fd_readwrite: __wasi_event_t__bindgen_ty_1__bindgen_ty_1, - _bindgen_union_align: [u64; 2usize], -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __wasi_event_t__bindgen_ty_1__bindgen_ty_1 { - pub nbytes: __wasi_filesize_t, - pub flags: __wasi_eventrwflags_t, - pub __bindgen_padding_0: [u16; 3usize], -} -#[allow(non_snake_case)] -#[test] -fn bindgen_test_layout_wasi_event_t__bindgen_ty_1__bindgen_ty_1() { - assert_eq!( - ::std::mem::size_of::<__wasi_event_t__bindgen_ty_1__bindgen_ty_1>(), - 16usize, - concat!( - "Size of: ", - stringify!(__wasi_event_t__bindgen_ty_1__bindgen_ty_1) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_event_t__bindgen_ty_1__bindgen_ty_1>())).nbytes - as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_event_t__bindgen_ty_1__bindgen_ty_1), - "::", - stringify!(nbytes) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_event_t__bindgen_ty_1__bindgen_ty_1>())).flags as *const _ - as usize - }, - 8usize, - concat!( - "Offset of field: ", - stringify!(__wasi_event_t__bindgen_ty_1__bindgen_ty_1), - "::", - stringify!(flags) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __wasi_event_t__bindgen_ty_1__bindgen_ty_2 { - pub signal: __wasi_signal_t, - pub exitcode: __wasi_exitcode_t, -} -#[allow(non_snake_case)] -#[test] -fn bindgen_test_layout_wasi_event_t__bindgen_ty_1__bindgen_ty_2() { - assert_eq!( - ::std::mem::size_of::<__wasi_event_t__bindgen_ty_1__bindgen_ty_2>(), - 8usize, - concat!( - "Size of: ", - stringify!(__wasi_event_t__bindgen_ty_1__bindgen_ty_2) - ) - ); - assert_eq!( - ::std::mem::align_of::<__wasi_event_t__bindgen_ty_1__bindgen_ty_2>(), - 4usize, - concat!( - "Alignment of ", - stringify!(__wasi_event_t__bindgen_ty_1__bindgen_ty_2) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_event_t__bindgen_ty_1__bindgen_ty_2>())).signal - as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_event_t__bindgen_ty_1__bindgen_ty_2), - "::", - stringify!(signal) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_event_t__bindgen_ty_1__bindgen_ty_2>())).exitcode - as *const _ as usize - }, - 4usize, - concat!( - "Offset of field: ", - stringify!(__wasi_event_t__bindgen_ty_1__bindgen_ty_2), - "::", - stringify!(exitcode) - ) - ); -} -#[allow(non_snake_case)] -#[test] -fn bindgen_test_layout_wasi_event_t__bindgen_ty_1() { - assert_eq!( - ::std::mem::size_of::<__wasi_event_t__bindgen_ty_1>(), - 16usize, - concat!("Size of: ", stringify!(__wasi_event_t__bindgen_ty_1)) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_event_t__bindgen_ty_1>())).fd_readwrite as *const _ - as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_event_t__bindgen_ty_1), - "::", - stringify!(fd_readwrite) - ) - ); -} -#[test] -fn bindgen_test_layout_wasi_event_t() { - assert_eq!( - ::std::mem::size_of::<__wasi_event_t>(), - 32usize, - concat!("Size of: ", stringify!(__wasi_event_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).userdata as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_event_t), - "::", - stringify!(userdata) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).error as *const _ as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(__wasi_event_t), - "::", - stringify!(error) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).type_ as *const _ as usize }, - 10usize, - concat!( - "Offset of field: ", - stringify!(__wasi_event_t), - "::", - stringify!(type_) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __wasi_fdstat_t { - pub fs_filetype: __wasi_filetype_t, - pub fs_flags: __wasi_fdflags_t, - pub __bindgen_padding_0: u32, - pub fs_rights_base: __wasi_rights_t, - pub fs_rights_inheriting: __wasi_rights_t, -} -#[test] -fn bindgen_test_layout_wasi_fdstat_t() { - assert_eq!( - ::std::mem::size_of::<__wasi_fdstat_t>(), - 24usize, - concat!("Size of: ", stringify!(__wasi_fdstat_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_filetype as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_fdstat_t), - "::", - stringify!(fs_filetype) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_flags as *const _ as usize }, - 2usize, - concat!( - "Offset of field: ", - stringify!(__wasi_fdstat_t), - "::", - stringify!(fs_flags) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_rights_base as *const _ as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(__wasi_fdstat_t), - "::", - stringify!(fs_rights_base) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_rights_inheriting as *const _ as usize - }, - 16usize, - concat!( - "Offset of field: ", - stringify!(__wasi_fdstat_t), - "::", - stringify!(fs_rights_inheriting) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __wasi_filestat_t { - pub st_dev: __wasi_device_t, - pub st_ino: __wasi_inode_t, - pub st_filetype: __wasi_filetype_t, - pub st_nlink: __wasi_linkcount_t, - pub st_size: __wasi_filesize_t, - pub st_atim: __wasi_timestamp_t, - pub st_mtim: __wasi_timestamp_t, - pub st_ctim: __wasi_timestamp_t, -} -#[test] -fn bindgen_test_layout_wasi_filestat_t() { - assert_eq!( - ::std::mem::size_of::<__wasi_filestat_t>(), - 56usize, - concat!("Size of: ", stringify!(__wasi_filestat_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_dev as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_filestat_t), - "::", - stringify!(st_dev) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_ino as *const _ as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(__wasi_filestat_t), - "::", - stringify!(st_ino) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_filetype as *const _ as usize }, - 16usize, - concat!( - "Offset of field: ", - stringify!(__wasi_filestat_t), - "::", - stringify!(st_filetype) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_nlink as *const _ as usize }, - 20usize, - concat!( - "Offset of field: ", - stringify!(__wasi_filestat_t), - "::", - stringify!(st_nlink) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_size as *const _ as usize }, - 24usize, - concat!( - "Offset of field: ", - stringify!(__wasi_filestat_t), - "::", - stringify!(st_size) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_atim as *const _ as usize }, - 32usize, - concat!( - "Offset of field: ", - stringify!(__wasi_filestat_t), - "::", - stringify!(st_atim) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_mtim as *const _ as usize }, - 40usize, - concat!( - "Offset of field: ", - stringify!(__wasi_filestat_t), - "::", - stringify!(st_mtim) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_ctim as *const _ as usize }, - 48usize, - concat!( - "Offset of field: ", - stringify!(__wasi_filestat_t), - "::", - stringify!(st_ctim) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __wasi_ciovec_t { - pub buf: uintptr_t, // *const ::std::os::raw::c_void - pub buf_len: size_t, -} -#[test] -fn bindgen_test_layout_wasi_ciovec_t() { - assert_eq!( - ::std::mem::size_of::<__wasi_ciovec_t>(), - 8usize, - concat!("Size of: ", stringify!(__wasi_ciovec_t)) - ); - assert_eq!( - ::std::mem::align_of::<__wasi_ciovec_t>(), - 4usize, - concat!("Alignment of ", stringify!(__wasi_ciovec_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_ciovec_t>())).buf as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_ciovec_t), - "::", - stringify!(buf) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_ciovec_t>())).buf_len as *const _ as usize }, - 4usize, - concat!( - "Offset of field: ", - stringify!(__wasi_ciovec_t), - "::", - stringify!(buf_len) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __wasi_iovec_t { - pub buf: uintptr_t, // *mut ::std::os::raw::c_void - pub buf_len: size_t, -} -#[test] -fn bindgen_test_layout_wasi_iovec_t() { - assert_eq!( - ::std::mem::size_of::<__wasi_iovec_t>(), - 8usize, - concat!("Size of: ", stringify!(__wasi_iovec_t)) - ); - assert_eq!( - ::std::mem::align_of::<__wasi_iovec_t>(), - 4usize, - concat!("Alignment of ", stringify!(__wasi_iovec_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_iovec_t>())).buf as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_iovec_t), - "::", - stringify!(buf) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_iovec_t>())).buf_len as *const _ as usize }, - 4usize, - concat!( - "Offset of field: ", - stringify!(__wasi_iovec_t), - "::", - stringify!(buf_len) - ) - ); -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct __wasi_subscription_t { - pub userdata: __wasi_userdata_t, - pub type_: __wasi_eventtype_t, - pub __bindgen_padding_0: u32, - pub __bindgen_anon_1: __wasi_subscription_t__bindgen_ty_1, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub union __wasi_subscription_t__bindgen_ty_1 { - pub clock: __wasi_subscription_t__bindgen_ty_1__bindgen_ty_1, - pub fd_readwrite: __wasi_subscription_t__bindgen_ty_1__bindgen_ty_3, - _bindgen_union_align: [u64; 5usize], -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __wasi_subscription_t__bindgen_ty_1__bindgen_ty_1 { - pub identifier: __wasi_userdata_t, - pub clock_id: __wasi_clockid_t, - pub __bindgen_padding_0: u32, - pub timeout: __wasi_timestamp_t, - pub precision: __wasi_timestamp_t, - pub flags: __wasi_subclockflags_t, - pub __bindgen_padding_1: [u16; 3usize], -} -#[allow(non_snake_case)] -#[test] -fn bindgen_test_layout_wasi_subscription_t__bindgen_ty_1__bindgen_ty_1() { - assert_eq!( - ::std::mem::size_of::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1>(), - 40usize, - concat!( - "Size of: ", - stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1>())).identifier - as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1), - "::", - stringify!(identifier) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1>())).clock_id - as *const _ as usize - }, - 8usize, - concat!( - "Offset of field: ", - stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1), - "::", - stringify!(clock_id) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1>())).timeout - as *const _ as usize - }, - 16usize, - concat!( - "Offset of field: ", - stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1), - "::", - stringify!(timeout) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1>())).precision - as *const _ as usize - }, - 24usize, - concat!( - "Offset of field: ", - stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1), - "::", - stringify!(precision) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1>())).flags - as *const _ as usize - }, - 32usize, - concat!( - "Offset of field: ", - stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1), - "::", - stringify!(flags) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __wasi_subscription_t__bindgen_ty_1__bindgen_ty_3 { - pub fd: __wasi_fd_t, -} -#[allow(non_snake_case)] -#[test] -fn bindgen_test_layout_wasi_subscription_t__bindgen_ty_1__bindgen_ty_3() { - assert_eq!( - ::std::mem::size_of::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_3>(), - 4usize, - concat!( - "Size of: ", - stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_3) - ) - ); - assert_eq!( - ::std::mem::align_of::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_3>(), - 4usize, - concat!( - "Alignment of ", - stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_3) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_3>())).fd - as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_3), - "::", - stringify!(fd) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __wasi_subscription_t__bindgen_ty_1__bindgen_ty_5 { - pub fd: __wasi_fd_t, -} -#[allow(non_snake_case)] -#[test] -fn bindgen_test_layout_wasi_subscription_t__bindgen_ty_1__bindgen_ty_5() { - assert_eq!( - ::std::mem::size_of::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_5>(), - 4usize, - concat!( - "Size of: ", - stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_5) - ) - ); - assert_eq!( - ::std::mem::align_of::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_5>(), - 4usize, - concat!( - "Alignment of ", - stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_5) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_5>())).fd - as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_5), - "::", - stringify!(fd) - ) - ); -} -#[allow(non_snake_case)] -#[test] -fn bindgen_test_layout_wasi_subscription_t__bindgen_ty_1() { - assert_eq!( - ::std::mem::size_of::<__wasi_subscription_t__bindgen_ty_1>(), - 40usize, - concat!("Size of: ", stringify!(__wasi_subscription_t__bindgen_ty_1)) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1>())).clock as *const _ - as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_subscription_t__bindgen_ty_1), - "::", - stringify!(clock) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1>())).fd_readwrite as *const _ - as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_subscription_t__bindgen_ty_1), - "::", - stringify!(fd_readwrite) - ) - ); -} -#[allow(non_snake_case)] -#[test] -fn bindgen_test_layout_wasi_subscription_t() { - assert_eq!( - ::std::mem::size_of::<__wasi_subscription_t>(), - 56usize, - concat!("Size of: ", stringify!(__wasi_subscription_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_subscription_t>())).userdata as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__wasi_subscription_t), - "::", - stringify!(userdata) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__wasi_subscription_t>())).type_ as *const _ as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(__wasi_subscription_t), - "::", - stringify!(type_) - ) - ); -} - -pub fn strerror(errno: __wasi_errno_t) -> &'static str { - match errno { - __WASI_ESUCCESS => "__WASI_ESUCCESS", - __WASI_E2BIG => "__WASI_E2BIG", - __WASI_EACCES => "__WASI_EACCES", - __WASI_EADDRINUSE => "__WASI_EADDRINUSE", - __WASI_EADDRNOTAVAIL => "__WASI_EADDRNOTAVAIL", - __WASI_EAFNOSUPPORT => "__WASI_EAFNOSUPPORT", - __WASI_EAGAIN => "__WASI_EAGAIN", - __WASI_EALREADY => "__WASI_EALREADY", - __WASI_EBADF => "__WASI_EBADF", - __WASI_EBADMSG => "__WASI_EBADMSG", - __WASI_EBUSY => "__WASI_EBUSY", - __WASI_ECANCELED => "__WASI_ECANCELED", - __WASI_ECHILD => "__WASI_ECHILD", - __WASI_ECONNABORTED => "__WASI_ECONNABORTED", - __WASI_ECONNREFUSED => "__WASI_ECONNREFUSED", - __WASI_ECONNRESET => "__WASI_ECONNRESET", - __WASI_EDEADLK => "__WASI_EDEADLK", - __WASI_EDESTADDRREQ => "__WASI_EDESTADDRREQ", - __WASI_EDOM => "__WASI_EDOM", - __WASI_EDQUOT => "__WASI_EDQUOT", - __WASI_EEXIST => "__WASI_EEXIST", - __WASI_EFAULT => "__WASI_EFAULT", - __WASI_EFBIG => "__WASI_EFBIG", - __WASI_EHOSTUNREACH => "__WASI_EHOSTUNREACH", - __WASI_EIDRM => "__WASI_EIDRM", - __WASI_EILSEQ => "__WASI_EILSEQ", - __WASI_EINPROGRESS => "__WASI_EINPROGRESS", - __WASI_EINTR => "__WASI_EINTR", - __WASI_EINVAL => "__WASI_EINVAL", - __WASI_EIO => "__WASI_EIO", - __WASI_EISCONN => "__WASI_EISCONN", - __WASI_EISDIR => "__WASI_EISDIR", - __WASI_ELOOP => "__WASI_ELOOP", - __WASI_EMFILE => "__WASI_EMFILE", - __WASI_EMLINK => "__WASI_EMLINK", - __WASI_EMSGSIZE => "__WASI_EMSGSIZE", - __WASI_EMULTIHOP => "__WASI_EMULTIHOP", - __WASI_ENAMETOOLONG => "__WASI_ENAMETOOLONG", - __WASI_ENETDOWN => "__WASI_ENETDOWN", - __WASI_ENETRESET => "__WASI_ENETRESET", - __WASI_ENETUNREACH => "__WASI_ENETUNREACH", - __WASI_ENFILE => "__WASI_ENFILE", - __WASI_ENOBUFS => "__WASI_ENOBUFS", - __WASI_ENODEV => "__WASI_ENODEV", - __WASI_ENOENT => "__WASI_ENOENT", - __WASI_ENOEXEC => "__WASI_ENOEXEC", - __WASI_ENOLCK => "__WASI_ENOLCK", - __WASI_ENOLINK => "__WASI_ENOLINK", - __WASI_ENOMEM => "__WASI_ENOMEM", - __WASI_ENOMSG => "__WASI_ENOMSG", - __WASI_ENOPROTOOPT => "__WASI_ENOPROTOOPT", - __WASI_ENOSPC => "__WASI_ENOSPC", - __WASI_ENOSYS => "__WASI_ENOSYS", - __WASI_ENOTCONN => "__WASI_ENOTCONN", - __WASI_ENOTDIR => "__WASI_ENOTDIR", - __WASI_ENOTEMPTY => "__WASI_ENOTEMPTY", - __WASI_ENOTRECOVERABLE => "__WASI_ENOTRECOVERABLE", - __WASI_ENOTSOCK => "__WASI_ENOTSOCK", - __WASI_ENOTSUP => "__WASI_ENOTSUP", - __WASI_ENOTTY => "__WASI_ENOTTY", - __WASI_ENXIO => "__WASI_ENXIO", - __WASI_EOVERFLOW => "__WASI_EOVERFLOW", - __WASI_EOWNERDEAD => "__WASI_EOWNERDEAD", - __WASI_EPERM => "__WASI_EPERM", - __WASI_EPIPE => "__WASI_EPIPE", - __WASI_EPROTO => "__WASI_EPROTO", - __WASI_EPROTONOSUPPORT => "__WASI_EPROTONOSUPPORT", - __WASI_EPROTOTYPE => "__WASI_EPROTOTYPE", - __WASI_ERANGE => "__WASI_ERANGE", - __WASI_EROFS => "__WASI_EROFS", - __WASI_ESPIPE => "__WASI_ESPIPE", - __WASI_ESRCH => "__WASI_ESRCH", - __WASI_ESTALE => "__WASI_ESTALE", - __WASI_ETIMEDOUT => "__WASI_ETIMEDOUT", - __WASI_ETXTBSY => "__WASI_ETXTBSY", - __WASI_EXDEV => "__WASI_EXDEV", - __WASI_ENOTCAPABLE => "__WASI_ENOTCAPABLE", - other => panic!("Undefined errno value {:?}", other), - } -} - -pub fn whence_to_str(whence: __wasi_whence_t) -> &'static str { - match whence { - __WASI_WHENCE_CUR => "__WASI_WHENCE_CUR", - __WASI_WHENCE_END => "__WASI_WHENCE_END", - __WASI_WHENCE_SET => "__WASI_WHENCE_SET", - other => panic!("Undefined whence value {:?}", other), - } -} - -// libc constants -pub const INT8_MIN: i32 = -128; -pub const INT16_MIN: i32 = -32768; -pub const INT32_MIN: i32 = -2147483648; -pub const INT8_MAX: u32 = 127; -pub const INT16_MAX: u32 = 32767; -pub const INT32_MAX: u32 = 2147483647; -pub const UINT8_MAX: u32 = 255; -pub const UINT16_MAX: u32 = 65535; -pub const UINT32_MAX: u32 = 4294967295; -pub const INT_LEAST8_MIN: i32 = -128; -pub const INT_LEAST16_MIN: i32 = -32768; -pub const INT_LEAST32_MIN: i32 = -2147483648; -pub const INT_LEAST8_MAX: u32 = 127; -pub const INT_LEAST16_MAX: u32 = 32767; -pub const INT_LEAST32_MAX: u32 = 2147483647; -pub const UINT_LEAST8_MAX: u32 = 255; -pub const UINT_LEAST16_MAX: u32 = 65535; -pub const UINT_LEAST32_MAX: u32 = 4294967295; -pub const INT_FAST8_MIN: i32 = -128; -pub const INT_FAST16_MIN: i32 = -2147483648; -pub const INT_FAST32_MIN: i32 = -2147483648; -pub const INT_FAST8_MAX: u32 = 127; -pub const INT_FAST16_MAX: u32 = 2147483647; -pub const INT_FAST32_MAX: u32 = 2147483647; -pub const UINT_FAST8_MAX: u32 = 255; -pub const UINT_FAST16_MAX: u32 = 4294967295; -pub const UINT_FAST32_MAX: u32 = 4294967295; -pub const INTPTR_MIN: i32 = -2147483648; -pub const INTPTR_MAX: u32 = 2147483647; -pub const UINTPTR_MAX: u32 = 4294967295; -pub const PTRDIFF_MIN: i32 = -2147483648; -pub const PTRDIFF_MAX: u32 = 2147483647; -pub const SIG_ATOMIC_MIN: i32 = -2147483648; -pub const SIG_ATOMIC_MAX: u32 = 2147483647; -pub const SIZE_MAX: u32 = 4294967295; -pub const WINT_MIN: i32 = -2147483648; -pub const WINT_MAX: i32 = 2147483647; - -// WASI constants -pub const __WASI_ADVICE_NORMAL: __wasi_advice_t = 0; -pub const __WASI_ADVICE_SEQUENTIAL: __wasi_advice_t = 1; -pub const __WASI_ADVICE_RANDOM: __wasi_advice_t = 2; -pub const __WASI_ADVICE_WILLNEED: __wasi_advice_t = 3; -pub const __WASI_ADVICE_DONTNEED: __wasi_advice_t = 4; -pub const __WASI_ADVICE_NOREUSE: __wasi_advice_t = 5; -pub const __WASI_CLOCK_REALTIME: __wasi_clockid_t = 0; -pub const __WASI_CLOCK_MONOTONIC: __wasi_clockid_t = 1; -pub const __WASI_CLOCK_PROCESS_CPUTIME_ID: __wasi_clockid_t = 2; -pub const __WASI_CLOCK_THREAD_CPUTIME_ID: __wasi_clockid_t = 3; -pub const __WASI_DIRCOOKIE_START: __wasi_dircookie_t = 0; -pub const __WASI_ESUCCESS: __wasi_errno_t = 0; -pub const __WASI_E2BIG: __wasi_errno_t = 1; -pub const __WASI_EACCES: __wasi_errno_t = 2; -pub const __WASI_EADDRINUSE: __wasi_errno_t = 3; -pub const __WASI_EADDRNOTAVAIL: __wasi_errno_t = 4; -pub const __WASI_EAFNOSUPPORT: __wasi_errno_t = 5; -pub const __WASI_EAGAIN: __wasi_errno_t = 6; -pub const __WASI_EALREADY: __wasi_errno_t = 7; -pub const __WASI_EBADF: __wasi_errno_t = 8; -pub const __WASI_EBADMSG: __wasi_errno_t = 9; -pub const __WASI_EBUSY: __wasi_errno_t = 10; -pub const __WASI_ECANCELED: __wasi_errno_t = 11; -pub const __WASI_ECHILD: __wasi_errno_t = 12; -pub const __WASI_ECONNABORTED: __wasi_errno_t = 13; -pub const __WASI_ECONNREFUSED: __wasi_errno_t = 14; -pub const __WASI_ECONNRESET: __wasi_errno_t = 15; -pub const __WASI_EDEADLK: __wasi_errno_t = 16; -pub const __WASI_EDESTADDRREQ: __wasi_errno_t = 17; -pub const __WASI_EDOM: __wasi_errno_t = 18; -pub const __WASI_EDQUOT: __wasi_errno_t = 19; -pub const __WASI_EEXIST: __wasi_errno_t = 20; -pub const __WASI_EFAULT: __wasi_errno_t = 21; -pub const __WASI_EFBIG: __wasi_errno_t = 22; -pub const __WASI_EHOSTUNREACH: __wasi_errno_t = 23; -pub const __WASI_EIDRM: __wasi_errno_t = 24; -pub const __WASI_EILSEQ: __wasi_errno_t = 25; -pub const __WASI_EINPROGRESS: __wasi_errno_t = 26; -pub const __WASI_EINTR: __wasi_errno_t = 27; -pub const __WASI_EINVAL: __wasi_errno_t = 28; -pub const __WASI_EIO: __wasi_errno_t = 29; -pub const __WASI_EISCONN: __wasi_errno_t = 30; -pub const __WASI_EISDIR: __wasi_errno_t = 31; -pub const __WASI_ELOOP: __wasi_errno_t = 32; -pub const __WASI_EMFILE: __wasi_errno_t = 33; -pub const __WASI_EMLINK: __wasi_errno_t = 34; -pub const __WASI_EMSGSIZE: __wasi_errno_t = 35; -pub const __WASI_EMULTIHOP: __wasi_errno_t = 36; -pub const __WASI_ENAMETOOLONG: __wasi_errno_t = 37; -pub const __WASI_ENETDOWN: __wasi_errno_t = 38; -pub const __WASI_ENETRESET: __wasi_errno_t = 39; -pub const __WASI_ENETUNREACH: __wasi_errno_t = 40; -pub const __WASI_ENFILE: __wasi_errno_t = 41; -pub const __WASI_ENOBUFS: __wasi_errno_t = 42; -pub const __WASI_ENODEV: __wasi_errno_t = 43; -pub const __WASI_ENOENT: __wasi_errno_t = 44; -pub const __WASI_ENOEXEC: __wasi_errno_t = 45; -pub const __WASI_ENOLCK: __wasi_errno_t = 46; -pub const __WASI_ENOLINK: __wasi_errno_t = 47; -pub const __WASI_ENOMEM: __wasi_errno_t = 48; -pub const __WASI_ENOMSG: __wasi_errno_t = 49; -pub const __WASI_ENOPROTOOPT: __wasi_errno_t = 50; -pub const __WASI_ENOSPC: __wasi_errno_t = 51; -pub const __WASI_ENOSYS: __wasi_errno_t = 52; -pub const __WASI_ENOTCONN: __wasi_errno_t = 53; -pub const __WASI_ENOTDIR: __wasi_errno_t = 54; -pub const __WASI_ENOTEMPTY: __wasi_errno_t = 55; -pub const __WASI_ENOTRECOVERABLE: __wasi_errno_t = 56; -pub const __WASI_ENOTSOCK: __wasi_errno_t = 57; -pub const __WASI_ENOTSUP: __wasi_errno_t = 58; -pub const __WASI_ENOTTY: __wasi_errno_t = 59; -pub const __WASI_ENXIO: __wasi_errno_t = 60; -pub const __WASI_EOVERFLOW: __wasi_errno_t = 61; -pub const __WASI_EOWNERDEAD: __wasi_errno_t = 62; -pub const __WASI_EPERM: __wasi_errno_t = 63; -pub const __WASI_EPIPE: __wasi_errno_t = 64; -pub const __WASI_EPROTO: __wasi_errno_t = 65; -pub const __WASI_EPROTONOSUPPORT: __wasi_errno_t = 66; -pub const __WASI_EPROTOTYPE: __wasi_errno_t = 67; -pub const __WASI_ERANGE: __wasi_errno_t = 68; -pub const __WASI_EROFS: __wasi_errno_t = 69; -pub const __WASI_ESPIPE: __wasi_errno_t = 70; -pub const __WASI_ESRCH: __wasi_errno_t = 71; -pub const __WASI_ESTALE: __wasi_errno_t = 72; -pub const __WASI_ETIMEDOUT: __wasi_errno_t = 73; -pub const __WASI_ETXTBSY: __wasi_errno_t = 74; -pub const __WASI_EXDEV: __wasi_errno_t = 75; -pub const __WASI_ENOTCAPABLE: __wasi_errno_t = 76; -pub const __WASI_EVENT_FD_READWRITE_HANGUP: __wasi_eventrwflags_t = 1; -pub const __WASI_EVENTTYPE_CLOCK: __wasi_eventtype_t = 0; -pub const __WASI_EVENTTYPE_FD_READ: __wasi_eventtype_t = 1; -pub const __WASI_EVENTTYPE_FD_WRITE: __wasi_eventtype_t = 2; -pub const __WASI_FDFLAG_APPEND: __wasi_fdflags_t = 1; -pub const __WASI_FDFLAG_DSYNC: __wasi_fdflags_t = 2; -pub const __WASI_FDFLAG_NONBLOCK: __wasi_fdflags_t = 4; -pub const __WASI_FDFLAG_RSYNC: __wasi_fdflags_t = 8; -pub const __WASI_FDFLAG_SYNC: __wasi_fdflags_t = 16; -pub const __WASI_PREOPENTYPE_DIR: __wasi_preopentype_t = 0; -pub const __WASI_FILETYPE_UNKNOWN: __wasi_filetype_t = 0; -pub const __WASI_FILETYPE_BLOCK_DEVICE: __wasi_filetype_t = 1; -pub const __WASI_FILETYPE_CHARACTER_DEVICE: __wasi_filetype_t = 2; -pub const __WASI_FILETYPE_DIRECTORY: __wasi_filetype_t = 3; -pub const __WASI_FILETYPE_REGULAR_FILE: __wasi_filetype_t = 4; -pub const __WASI_FILETYPE_SOCKET_DGRAM: __wasi_filetype_t = 5; -pub const __WASI_FILETYPE_SOCKET_STREAM: __wasi_filetype_t = 6; -pub const __WASI_FILETYPE_SYMBOLIC_LINK: __wasi_filetype_t = 7; -pub const __WASI_FILESTAT_SET_ATIM: __wasi_fstflags_t = 1; -pub const __WASI_FILESTAT_SET_ATIM_NOW: __wasi_fstflags_t = 2; -pub const __WASI_FILESTAT_SET_MTIM: __wasi_fstflags_t = 4; -pub const __WASI_FILESTAT_SET_MTIM_NOW: __wasi_fstflags_t = 8; -pub const __WASI_LOOKUP_SYMLINK_FOLLOW: __wasi_lookupflags_t = 1; -pub const __WASI_O_CREAT: __wasi_oflags_t = 1; -pub const __WASI_O_DIRECTORY: __wasi_oflags_t = 2; -pub const __WASI_O_EXCL: __wasi_oflags_t = 4; -pub const __WASI_O_TRUNC: __wasi_oflags_t = 8; -pub const __WASI_SOCK_RECV_PEEK: __wasi_riflags_t = 1; -pub const __WASI_SOCK_RECV_WAITALL: __wasi_riflags_t = 2; -pub const __WASI_RIGHT_FD_DATASYNC: __wasi_rights_t = 1; -pub const __WASI_RIGHT_FD_READ: __wasi_rights_t = 2; -pub const __WASI_RIGHT_FD_SEEK: __wasi_rights_t = 4; -pub const __WASI_RIGHT_FD_FDSTAT_SET_FLAGS: __wasi_rights_t = 8; -pub const __WASI_RIGHT_FD_SYNC: __wasi_rights_t = 16; -pub const __WASI_RIGHT_FD_TELL: __wasi_rights_t = 32; -pub const __WASI_RIGHT_FD_WRITE: __wasi_rights_t = 64; -pub const __WASI_RIGHT_FD_ADVISE: __wasi_rights_t = 128; -pub const __WASI_RIGHT_FD_ALLOCATE: __wasi_rights_t = 256; -pub const __WASI_RIGHT_PATH_CREATE_DIRECTORY: __wasi_rights_t = 512; -pub const __WASI_RIGHT_PATH_CREATE_FILE: __wasi_rights_t = 1024; -pub const __WASI_RIGHT_PATH_LINK_SOURCE: __wasi_rights_t = 2048; -pub const __WASI_RIGHT_PATH_LINK_TARGET: __wasi_rights_t = 4096; -pub const __WASI_RIGHT_PATH_OPEN: __wasi_rights_t = 8192; -pub const __WASI_RIGHT_FD_READDIR: __wasi_rights_t = 16384; -pub const __WASI_RIGHT_PATH_READLINK: __wasi_rights_t = 32768; -pub const __WASI_RIGHT_PATH_RENAME_SOURCE: __wasi_rights_t = 65536; -pub const __WASI_RIGHT_PATH_RENAME_TARGET: __wasi_rights_t = 131072; -pub const __WASI_RIGHT_PATH_FILESTAT_GET: __wasi_rights_t = 262144; -pub const __WASI_RIGHT_PATH_FILESTAT_SET_SIZE: __wasi_rights_t = 524288; -pub const __WASI_RIGHT_PATH_FILESTAT_SET_TIMES: __wasi_rights_t = 1048576; -pub const __WASI_RIGHT_FD_FILESTAT_GET: __wasi_rights_t = 2097152; -pub const __WASI_RIGHT_FD_FILESTAT_SET_SIZE: __wasi_rights_t = 4194304; -pub const __WASI_RIGHT_FD_FILESTAT_SET_TIMES: __wasi_rights_t = 8388608; -pub const __WASI_RIGHT_PATH_SYMLINK: __wasi_rights_t = 16777216; -pub const __WASI_RIGHT_PATH_REMOVE_DIRECTORY: __wasi_rights_t = 33554432; -pub const __WASI_RIGHT_PATH_UNLINK_FILE: __wasi_rights_t = 67108864; -pub const __WASI_RIGHT_POLL_FD_READWRITE: __wasi_rights_t = 134217728; -pub const __WASI_RIGHT_SOCK_SHUTDOWN: __wasi_rights_t = 268435456; -pub const __WASI_SOCK_RECV_DATA_TRUNCATED: __wasi_roflags_t = 1; -pub const __WASI_SHUT_RD: __wasi_sdflags_t = 1; -pub const __WASI_SHUT_WR: __wasi_sdflags_t = 2; -pub const __WASI_SIGHUP: __wasi_signal_t = 1; -pub const __WASI_SIGINT: __wasi_signal_t = 2; -pub const __WASI_SIGQUIT: __wasi_signal_t = 3; -pub const __WASI_SIGILL: __wasi_signal_t = 4; -pub const __WASI_SIGTRAP: __wasi_signal_t = 5; -pub const __WASI_SIGABRT: __wasi_signal_t = 6; -pub const __WASI_SIGBUS: __wasi_signal_t = 7; -pub const __WASI_SIGFPE: __wasi_signal_t = 8; -pub const __WASI_SIGKILL: __wasi_signal_t = 9; -pub const __WASI_SIGUSR1: __wasi_signal_t = 10; -pub const __WASI_SIGSEGV: __wasi_signal_t = 11; -pub const __WASI_SIGUSR2: __wasi_signal_t = 12; -pub const __WASI_SIGPIPE: __wasi_signal_t = 13; -pub const __WASI_SIGALRM: __wasi_signal_t = 14; -pub const __WASI_SIGTERM: __wasi_signal_t = 15; -pub const __WASI_SIGCHLD: __wasi_signal_t = 16; -pub const __WASI_SIGCONT: __wasi_signal_t = 17; -pub const __WASI_SIGSTOP: __wasi_signal_t = 18; -pub const __WASI_SIGTSTP: __wasi_signal_t = 19; -pub const __WASI_SIGTTIN: __wasi_signal_t = 20; -pub const __WASI_SIGTTOU: __wasi_signal_t = 21; -pub const __WASI_SIGURG: __wasi_signal_t = 22; -pub const __WASI_SIGXCPU: __wasi_signal_t = 23; -pub const __WASI_SIGXFSZ: __wasi_signal_t = 24; -pub const __WASI_SIGVTALRM: __wasi_signal_t = 25; -pub const __WASI_SIGPROF: __wasi_signal_t = 26; -pub const __WASI_SIGWINCH: __wasi_signal_t = 27; -pub const __WASI_SIGPOLL: __wasi_signal_t = 28; -pub const __WASI_SIGPWR: __wasi_signal_t = 29; -pub const __WASI_SIGSYS: __wasi_signal_t = 30; -pub const __WASI_SUBSCRIPTION_CLOCK_ABSTIME: __wasi_subclockflags_t = 1; -pub const __WASI_WHENCE_CUR: __wasi_whence_t = 0; -pub const __WASI_WHENCE_END: __wasi_whence_t = 1; -pub const __WASI_WHENCE_SET: __wasi_whence_t = 2; - -pub fn errno_from_nix(errno: nix::errno::Errno) -> __wasi_errno_t { - match errno { - nix::errno::Errno::EPERM => __WASI_EPERM, - nix::errno::Errno::ENOENT => __WASI_ENOENT, - nix::errno::Errno::ESRCH => __WASI_ESRCH, - nix::errno::Errno::EINTR => __WASI_EINTR, - nix::errno::Errno::EIO => __WASI_EIO, - nix::errno::Errno::ENXIO => __WASI_ENXIO, - nix::errno::Errno::E2BIG => __WASI_E2BIG, - nix::errno::Errno::ENOEXEC => __WASI_ENOEXEC, - nix::errno::Errno::EBADF => __WASI_EBADF, - nix::errno::Errno::ECHILD => __WASI_ECHILD, - nix::errno::Errno::EAGAIN => __WASI_EAGAIN, - nix::errno::Errno::ENOMEM => __WASI_ENOMEM, - nix::errno::Errno::EACCES => __WASI_EACCES, - nix::errno::Errno::EFAULT => __WASI_EFAULT, - nix::errno::Errno::EBUSY => __WASI_EBUSY, - nix::errno::Errno::EEXIST => __WASI_EEXIST, - nix::errno::Errno::EXDEV => __WASI_EXDEV, - nix::errno::Errno::ENODEV => __WASI_ENODEV, - nix::errno::Errno::ENOTDIR => __WASI_ENOTDIR, - nix::errno::Errno::EISDIR => __WASI_EISDIR, - nix::errno::Errno::EINVAL => __WASI_EINVAL, - nix::errno::Errno::ENFILE => __WASI_ENFILE, - nix::errno::Errno::EMFILE => __WASI_EMFILE, - nix::errno::Errno::ENOTTY => __WASI_ENOTTY, - nix::errno::Errno::ETXTBSY => __WASI_ETXTBSY, - nix::errno::Errno::EFBIG => __WASI_EFBIG, - nix::errno::Errno::ENOSPC => __WASI_ENOSPC, - nix::errno::Errno::ESPIPE => __WASI_ESPIPE, - nix::errno::Errno::EROFS => __WASI_EROFS, - nix::errno::Errno::EMLINK => __WASI_EMLINK, - nix::errno::Errno::EPIPE => __WASI_EPIPE, - nix::errno::Errno::EDOM => __WASI_EDOM, - nix::errno::Errno::ERANGE => __WASI_ERANGE, - nix::errno::Errno::EDEADLK => __WASI_EDEADLK, - nix::errno::Errno::ENAMETOOLONG => __WASI_ENAMETOOLONG, - nix::errno::Errno::ENOLCK => __WASI_ENOLCK, - nix::errno::Errno::ENOSYS => __WASI_ENOSYS, - nix::errno::Errno::ENOTEMPTY => __WASI_ENOTEMPTY, - nix::errno::Errno::ELOOP => __WASI_ELOOP, - nix::errno::Errno::ENOMSG => __WASI_ENOMSG, - nix::errno::Errno::EIDRM => __WASI_EIDRM, - nix::errno::Errno::ENOLINK => __WASI_ENOLINK, - nix::errno::Errno::EPROTO => __WASI_EPROTO, - nix::errno::Errno::EMULTIHOP => __WASI_EMULTIHOP, - nix::errno::Errno::EBADMSG => __WASI_EBADMSG, - nix::errno::Errno::EOVERFLOW => __WASI_EOVERFLOW, - nix::errno::Errno::EILSEQ => __WASI_EILSEQ, - nix::errno::Errno::ENOTSOCK => __WASI_ENOTSOCK, - nix::errno::Errno::EDESTADDRREQ => __WASI_EDESTADDRREQ, - nix::errno::Errno::EMSGSIZE => __WASI_EMSGSIZE, - nix::errno::Errno::EPROTOTYPE => __WASI_EPROTOTYPE, - nix::errno::Errno::ENOPROTOOPT => __WASI_ENOPROTOOPT, - nix::errno::Errno::EPROTONOSUPPORT => __WASI_EPROTONOSUPPORT, - nix::errno::Errno::EAFNOSUPPORT => __WASI_EAFNOSUPPORT, - nix::errno::Errno::EADDRINUSE => __WASI_EADDRINUSE, - nix::errno::Errno::EADDRNOTAVAIL => __WASI_EADDRNOTAVAIL, - nix::errno::Errno::ENETDOWN => __WASI_ENETDOWN, - nix::errno::Errno::ENETUNREACH => __WASI_ENETUNREACH, - nix::errno::Errno::ENETRESET => __WASI_ENETRESET, - nix::errno::Errno::ECONNABORTED => __WASI_ECONNABORTED, - nix::errno::Errno::ECONNRESET => __WASI_ECONNRESET, - nix::errno::Errno::ENOBUFS => __WASI_ENOBUFS, - nix::errno::Errno::EISCONN => __WASI_EISCONN, - nix::errno::Errno::ENOTCONN => __WASI_ENOTCONN, - nix::errno::Errno::ETIMEDOUT => __WASI_ETIMEDOUT, - nix::errno::Errno::ECONNREFUSED => __WASI_ECONNREFUSED, - nix::errno::Errno::EHOSTUNREACH => __WASI_EHOSTUNREACH, - nix::errno::Errno::EALREADY => __WASI_EALREADY, - nix::errno::Errno::EINPROGRESS => __WASI_EINPROGRESS, - nix::errno::Errno::ESTALE => __WASI_ESTALE, - nix::errno::Errno::EDQUOT => __WASI_EDQUOT, - nix::errno::Errno::ECANCELED => __WASI_ECANCELED, - nix::errno::Errno::EOWNERDEAD => __WASI_EOWNERDEAD, - nix::errno::Errno::ENOTRECOVERABLE => __WASI_ENOTRECOVERABLE, - _ => __WASI_ENOSYS, - } -} diff --git a/lucet-wasi/tests/test_helpers/mod.rs b/lucet-wasi/tests/test_helpers/mod.rs index 5793ad4dc..1ca986609 100644 --- a/lucet-wasi/tests/test_helpers/mod.rs +++ b/lucet-wasi/tests/test_helpers/mod.rs @@ -104,7 +104,10 @@ pub fn run_with_stdout>( ) -> Result<(__wasi_exitcode_t, String), Error> { let (pipe_out, pipe_in) = nix::unistd::pipe()?; - let ctx = unsafe { ctx.raw_fd(1, pipe_in) }.build()?; + let ctx = ctx + .stdout(unsafe { File::from_raw_fd(pipe_in) }) + .unwrap() + .build()?; let exitcode = run(path, ctx)?; @@ -122,7 +125,10 @@ pub fn run_with_null_stdin>( ) -> Result<__wasi_exitcode_t, Error> { let (pipe_out, pipe_in) = nix::unistd::pipe()?; - let ctx = unsafe { ctx.raw_fd(0, pipe_out) }.build()?; + let ctx = ctx + .stdin(unsafe { File::from_raw_fd(pipe_out) }) + .unwrap() + .build()?; let exitcode = run(path, ctx)?; @@ -138,5 +144,5 @@ pub fn run_with_null_stdin>( #[no_mangle] #[doc(hidden)] pub extern "C" fn lucet_wasi_tests_internal_ensure_linked() { - lucet_wasi::hostcalls::ensure_linked(); + lucet_wasi::export_wasi_funcs(); } diff --git a/lucet-wasi/tests/tests.rs b/lucet-wasi/tests/tests.rs index fbde24b5d..41ba67926 100644 --- a/lucet-wasi/tests/tests.rs +++ b/lucet-wasi/tests/tests.rs @@ -8,7 +8,7 @@ use tempfile::TempDir; #[test] fn double_import() { - let ctx = WasiCtxBuilder::new(); + let ctx = WasiCtxBuilder::new().unwrap(); let (exitcode, stdout) = run_with_stdout("duplicate_import.wat", ctx).unwrap(); @@ -18,7 +18,10 @@ fn double_import() { #[test] fn hello() { - let ctx = WasiCtxBuilder::new().args(&["hello"]); + let ctx = WasiCtxBuilder::new() + .unwrap() + .args(["hello"].into_iter()) + .unwrap(); let (exitcode, stdout) = run_with_stdout( Path::new(LUCET_WASI_ROOT).join("examples").join("hello.c"), @@ -32,7 +35,10 @@ fn hello() { #[test] fn hello_args() { - let ctx = WasiCtxBuilder::new().args(&["hello", "test suite"]); + let ctx = WasiCtxBuilder::new() + .unwrap() + .args(["hello", "test suite"].into_iter()) + .unwrap(); let (exitcode, stdout) = run_with_stdout( Path::new(LUCET_WASI_ROOT).join("examples").join("hello.c"), @@ -47,8 +53,11 @@ fn hello_args() { #[test] fn hello_env() { let ctx = WasiCtxBuilder::new() - .args(&["hello", "test suite"]) - .env("GREETING", "goodbye"); + .unwrap() + .args(["hello", "test suite"].into_iter()) + .unwrap() + .env("GREETING", "goodbye") + .unwrap(); let (exitcode, stdout) = run_with_stdout( Path::new(LUCET_WASI_ROOT).join("examples").join("hello.c"), @@ -62,7 +71,7 @@ fn hello_env() { #[test] fn exitcode() { - let ctx = WasiCtx::new(&["exitcode"]); + let ctx = WasiCtx::new(["exitcode"].into_iter()).unwrap(); let exitcode = run("exitcode.c", ctx).unwrap(); @@ -71,7 +80,7 @@ fn exitcode() { #[test] fn clock_getres() { - let ctx = WasiCtx::new(&["clock_getres"]); + let ctx = WasiCtx::new(["clock_getres"].into_iter()).unwrap(); let exitcode = run("clock_getres.c", ctx).unwrap(); @@ -80,7 +89,7 @@ fn clock_getres() { #[test] fn getrusage() { - let ctx = WasiCtx::new(&["getrusage"]); + let ctx = WasiCtx::new(["getrusage"].into_iter()).unwrap(); let exitcode = run("getrusage.c", ctx).unwrap(); @@ -89,7 +98,7 @@ fn getrusage() { #[test] fn gettimeofday() { - let ctx = WasiCtx::new(&["gettimeofday"]); + let ctx = WasiCtx::new(["gettimeofday"].into_iter()).unwrap(); let exitcode = run("gettimeofday.c", ctx).unwrap(); @@ -98,7 +107,7 @@ fn gettimeofday() { #[test] fn getentropy() { - let ctx = WasiCtx::new(&["getentropy"]); + let ctx = WasiCtx::new(["getentropy"].into_iter()).unwrap(); let exitcode = run("getentropy.c", ctx).unwrap(); @@ -116,7 +125,12 @@ fn stdin() { write!(stdin_file, "hello from stdin!").expect("pipe write succeeds"); drop(stdin_file); - let ctx = unsafe { WasiCtxBuilder::new().args(&["stdin"]).raw_fd(0, pipe_out) }; + let ctx = WasiCtxBuilder::new() + .unwrap() + .args(["stdin"].into_iter()) + .unwrap() + .stdin(unsafe { File::from_raw_fd(pipe_out) }) + .unwrap(); let (exitcode, stdout) = run_with_stdout("stdin.c", ctx).unwrap(); @@ -132,7 +146,9 @@ fn preopen_populates() { let preopen_dir = File::open(preopen_host_path).unwrap(); let ctx = WasiCtxBuilder::new() - .args(&["preopen_populates"]) + .unwrap() + .args(["preopen_populates"].into_iter()) + .unwrap() .preopened_dir(preopen_dir, "/preopen") .build() .expect("can build WasiCtx"); @@ -152,7 +168,9 @@ fn write_file() { let preopen_dir = File::open(&preopen_host_path).unwrap(); let ctx = WasiCtxBuilder::new() - .args(&["write_file"]) + .unwrap() + .args(["write_file"].into_iter()) + .unwrap() .preopened_dir(preopen_dir, "/sandbox") .build() .expect("can build WasiCtx"); @@ -179,7 +197,9 @@ fn read_file() { let preopen_dir = File::open(&preopen_host_path).unwrap(); let ctx = WasiCtxBuilder::new() - .args(&["read_file"]) + .unwrap() + .args(["read_file"].into_iter()) + .unwrap() .preopened_dir(preopen_dir, "/sandbox"); let (exitcode, stdout) = run_with_stdout("read_file.c", ctx).unwrap(); @@ -202,7 +222,9 @@ fn read_file_twice() { let preopen_dir = File::open(&preopen_host_path).unwrap(); let ctx = WasiCtxBuilder::new() - .args(&["read_file_twice"]) + .unwrap() + .args(["read_file_twice"].into_iter()) + .unwrap() .preopened_dir(preopen_dir, "/sandbox"); let (exitcode, stdout) = run_with_stdout("read_file_twice.c", ctx).unwrap(); @@ -230,7 +252,9 @@ fn cant_dotdot() { let preopen_dir = File::open(&preopen_host_path).unwrap(); let ctx = WasiCtxBuilder::new() - .args(&["cant_dotdot"]) + .unwrap() + .args(["cant_dotdot"].into_iter()) + .unwrap() .preopened_dir(preopen_dir, "/sandbox") .build() .unwrap(); @@ -254,7 +278,9 @@ fn notdir() { let preopen_dir = File::open(&preopen_host_path).unwrap(); let ctx = WasiCtxBuilder::new() - .args(&["notdir"]) + .unwrap() + .args(["notdir"].into_iter()) + .unwrap() .preopened_dir(preopen_dir, "/sandbox") .build() .unwrap(); @@ -283,7 +309,9 @@ fn follow_symlink() { let preopen_dir = File::open(&preopen_host_path).unwrap(); let ctx = WasiCtxBuilder::new() - .args(&["follow_symlink"]) + .unwrap() + .args(["follow_symlink"].into_iter()) + .unwrap() .preopened_dir(preopen_dir, "/sandbox"); let (exitcode, stdout) = run_with_stdout("follow_symlink.c", ctx).unwrap(); @@ -308,7 +336,9 @@ fn symlink_loop() { let preopen_dir = File::open(&preopen_host_path).unwrap(); let ctx = WasiCtxBuilder::new() - .args(&["symlink_loop"]) + .unwrap() + .args(["symlink_loop"].into_iter()) + .unwrap() .preopened_dir(preopen_dir, "/sandbox") .build() .unwrap(); @@ -338,7 +368,9 @@ fn symlink_escape() { let preopen_dir = File::open(&preopen_host_path).unwrap(); let ctx = WasiCtxBuilder::new() - .args(&["symlink_escape"]) + .unwrap() + .args(["symlink_escape"].into_iter()) + .unwrap() .preopened_dir(preopen_dir, "/sandbox") .build() .unwrap(); @@ -355,7 +387,9 @@ fn pseudoquine() { let pseudoquine_c = examples_dir.join("pseudoquine.c"); let ctx = WasiCtxBuilder::new() - .args(&["pseudoquine"]) + .unwrap() + .args(["pseudoquine"].into_iter()) + .unwrap() .preopened_dir(File::open(examples_dir).unwrap(), "/examples"); let (exitcode, stdout) = run_with_stdout(&pseudoquine_c, ctx).unwrap(); @@ -372,7 +406,10 @@ fn pseudoquine() { #[ignore] #[test] fn poll() { - let ctx = WasiCtxBuilder::new().args(&["poll"]); + let ctx = WasiCtxBuilder::new() + .unwrap() + .args(["poll"].into_iter()) + .unwrap(); let exitcode = run_with_null_stdin("poll.c", ctx).unwrap(); assert_eq!(exitcode, 0); } @@ -384,7 +421,9 @@ fn stat() { std::fs::create_dir(&preopen_host_path).unwrap(); let preopen_dir = File::open(&preopen_host_path).unwrap(); let ctx = WasiCtxBuilder::new() - .args(&["stat"]) + .unwrap() + .args(["stat"].into_iter()) + .unwrap() .preopened_dir(preopen_dir, "/sandbox") .build() .expect("can build WasiCtx"); @@ -399,7 +438,9 @@ fn fs() { std::fs::create_dir(&preopen_host_path).unwrap(); let preopen_dir = File::open(&preopen_host_path).unwrap(); let ctx = WasiCtxBuilder::new() - .args(&["stat"]) + .unwrap() + .args(["stat"].into_iter()) + .unwrap() .preopened_dir(preopen_dir, "/sandbox") .build() .expect("can build WasiCtx"); From e43d2472f42a5576d1dd9f1f31d332649c009bda Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 24 Oct 2019 17:30:21 -0700 Subject: [PATCH 465/512] lucet-wasi: use pch/working branch of wasi-common --- lucet-wasi/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index e6147021d..ca731fc10 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -34,7 +34,7 @@ lucet-module = { path = "../lucet-module", version = "0.4.1" } libc = "0.2.65" nix = "0.15" rand = "0.6" -wasi-common = { git = "https://github.com/fastly/wasi-common", branch = "pch/stdio_files" } +wasi-common = { git = "https://github.com/fastly/wasi-common", branch = "pch/working" } [dev-dependencies] lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.1" } From 74f6a618d06425febb9a5a06ff199f85c58c9a12 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 29 Oct 2019 15:01:24 -0700 Subject: [PATCH 466/512] lucet-wasi: export our own __wasi_exitcode_t alias, use master upstream --- Cargo.lock | 65 ++++++++++++++++++++++++---- lucet-wasi-fuzz/src/main.rs | 3 +- lucet-wasi/Cargo.toml | 2 +- lucet-wasi/src/lib.rs | 9 +++- lucet-wasi/src/main.rs | 9 ++-- lucet-wasi/tests/test_helpers/mod.rs | 3 +- 6 files changed, 70 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a04573770..7884a9239 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -285,6 +285,15 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cpu-time" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cranelift-bforest" version = "0.46.1" @@ -964,7 +973,7 @@ dependencies = [ "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi-common 0.4.0 (git+https://github.com/fastly/wasi-common?branch=pch/stdio_files)", + "wasi-common 0.4.0 (git+https://github.com/cranestation/wasi-common)", ] [[package]] @@ -1120,6 +1129,27 @@ dependencies = [ "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-complex" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-derive" version = "0.3.0" @@ -1149,6 +1179,16 @@ dependencies = [ "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num-rational" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-traits" version = "0.1.43" @@ -1973,24 +2013,27 @@ dependencies = [ [[package]] name = "wasi-common" version = "0.4.0" -source = "git+https://github.com/fastly/wasi-common?branch=pch/stdio_files#16288298b92f7d6d02a5b47b338874a5c0db39e0" +source = "git+https://github.com/cranestation/wasi-common#74757fdd65ef6f8950e94bd2e7a8a7ed46530e46" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cpu-time 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi-common-cbindgen 0.4.0 (git+https://github.com/fastly/wasi-common?branch=pch/stdio_files)", + "wasi-common-cbindgen 0.4.0 (git+https://github.com/cranestation/wasi-common)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winx 0.4.0 (git+https://github.com/fastly/wasi-common?branch=pch/stdio_files)", + "winx 0.4.0 (git+https://github.com/cranestation/wasi-common)", ] [[package]] name = "wasi-common-cbindgen" version = "0.4.0" -source = "git+https://github.com/fastly/wasi-common?branch=pch/stdio_files#16288298b92f7d6d02a5b47b338874a5c0db39e0" +source = "git+https://github.com/cranestation/wasi-common#74757fdd65ef6f8950e94bd2e7a8a7ed46530e46" dependencies = [ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2086,7 +2129,7 @@ dependencies = [ [[package]] name = "winx" version = "0.4.0" -source = "git+https://github.com/fastly/wasi-common?branch=pch/stdio_files#16288298b92f7d6d02a5b47b338874a5c0db39e0" +source = "git+https://github.com/cranestation/wasi-common#74757fdd65ef6f8950e94bd2e7a8a7ed46530e46" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "cvt 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2142,6 +2185,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62" "checksum colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cdb90b60f2927f8d76139c72dbde7e10c3a2bc47c8594c9c7a66529f2687c03" "checksum core_affinity 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6d162c6e463c31dbf78fefa99d042156c1c74d404e299cfe3df2923cb857595b" +"checksum cpu-time 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e9e393a7668fe1fad3075085b86c781883000b4ede868f43627b34a87c8b7ded" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "938703e165481c8d612ea3479ac8342e5615185db37765162e762ec3523e2fc6" "checksum criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eccdc6ce8bbe352ca89025bee672aa6d24f4eb8c53e3a8b5d1bc58011da072a2" @@ -2196,9 +2240,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" "checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" +"checksum num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf4825417e1e1406b3782a8ce92f4d53f26ec055e3622e1881ca8e9f5f9e08db" +"checksum num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fcb0cf31fb3ff77e6d2a6ebd6800df7fdcd106f2ad89113c9130bcd07f93dffc" "checksum num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c8b15b261814f992e33760b1fca9fe8b693d8a65299f20c9901688636cfb746" "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" "checksum num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e" +"checksum num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2885278d5fe2adc2f75ced642d52d879bffaceb5a2e0b1d4309ffdfb239b454" "checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" "checksum num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "155394f924cdddf08149da25bfb932d226b4a593ca7468b08191ff6335941af5" @@ -2297,8 +2344,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af5d153dc96aad7dc13ab90835b892c69867948112d95299e522d370c4e13a08" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" -"checksum wasi-common 0.4.0 (git+https://github.com/fastly/wasi-common?branch=pch/stdio_files)" = "" -"checksum wasi-common-cbindgen 0.4.0 (git+https://github.com/fastly/wasi-common?branch=pch/stdio_files)" = "" +"checksum wasi-common 0.4.0 (git+https://github.com/cranestation/wasi-common)" = "" +"checksum wasi-common-cbindgen 0.4.0 (git+https://github.com/cranestation/wasi-common)" = "" "checksum wasmonkey 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "af7c4bc80224427965ba21d87982cfc07d12e859824f303272056fb19f571ef9" "checksum wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5083b449454f7de0b15f131eee17de54b5a71dcb9adcf11df2b2f78fad0cd82" "checksum which 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5475d47078209a02e60614f7ba5e645ef3ed60f771920ac1906d7c1cc65024c8" @@ -2310,5 +2357,5 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" "checksum winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef84b96d10db72dd980056666d7f1e7663ce93d82fa33b63e71c966f4cf5032" -"checksum winx 0.4.0 (git+https://github.com/fastly/wasi-common?branch=pch/stdio_files)" = "" +"checksum winx 0.4.0 (git+https://github.com/cranestation/wasi-common)" = "" "checksum xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da90eac47bf1d7871b75004b9b631d107df15f37669383b23f0b5297bc7516b6" diff --git a/lucet-wasi-fuzz/src/main.rs b/lucet-wasi-fuzz/src/main.rs index 0a7ec2386..b4023001f 100644 --- a/lucet-wasi-fuzz/src/main.rs +++ b/lucet-wasi-fuzz/src/main.rs @@ -4,8 +4,7 @@ use failure::{bail, format_err, Error}; use libc::c_ulong; use lucet_module::bindings::Bindings; use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region}; -use lucet_wasi::host::__wasi_exitcode_t; -use lucet_wasi::{WasiCtx, WasiCtxBuilder}; +use lucet_wasi::{WasiCtx, WasiCtxBuilder, __wasi_exitcode_t}; use lucet_wasi_sdk::{CompileOpts, Link}; use lucetc::{Lucetc, LucetcOpts}; use rand::prelude::random; diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index ca731fc10..9126695d7 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -34,7 +34,7 @@ lucet-module = { path = "../lucet-module", version = "0.4.1" } libc = "0.2.65" nix = "0.15" rand = "0.6" -wasi-common = { git = "https://github.com/fastly/wasi-common", branch = "pch/working" } +wasi-common = { git = "https://github.com/cranestation/wasi-common", branch = "master" } [dev-dependencies] lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.1" } diff --git a/lucet-wasi/src/lib.rs b/lucet-wasi/src/lib.rs index 321ae23b9..efd56f393 100644 --- a/lucet-wasi/src/lib.rs +++ b/lucet-wasi/src/lib.rs @@ -7,4 +7,11 @@ pub mod wasi; pub use bindings::bindings; pub use wasi::{export_wasi_funcs, WasiCtx, WasiCtxBuilder}; -pub use wasi_common::host; +// Exporting this type alias as a stop-gap: wasi-common should really provide a pub Rust enum type +// for the return values from _start, but it does not yet. We're going to pursue that path via witx +// and friends rather than export the type definition and constants from wasi-common right now. +// +// In the meantime, we're providing this alias because it is more descriptive to use (compared to +// `u32` in our code that uses the exitcode. +#[allow(non_camel_case_types)] +pub type __wasi_exitcode_t = u32; diff --git a/lucet-wasi/src/main.rs b/lucet-wasi/src/main.rs index e00f7107b..df2dba522 100644 --- a/lucet-wasi/src/main.rs +++ b/lucet-wasi/src/main.rs @@ -3,17 +3,15 @@ #[macro_use] extern crate clap; -mod wasi; - use clap::Arg; use failure::{format_err, Error}; use lucet_runtime::{self, DlModule, Limits, MmapRegion, Module, PublicKey, Region, RunResult}; +use lucet_wasi::{self, WasiCtxBuilder, __wasi_exitcode_t}; use std::fs::File; use std::path::PathBuf; use std::sync::Arc; use std::thread; use std::time::Duration; -use wasi::WasiCtxBuilder; struct Config<'a> { lucet_module: &'a str, @@ -41,7 +39,7 @@ fn parse_humansized(desc: &str) -> Result { fn main() { // No-ops, but makes sure the linker doesn't throw away parts // of the runtime: - wasi::export_wasi_funcs(); + lucet_wasi::export_wasi_funcs(); let matches = app_from_crate!() .arg( @@ -204,7 +202,6 @@ fn main() { } fn run(config: Config<'_>) { - wasi::export_wasi_funcs(); let exitcode = { // doing all of this in a block makes sure everything gets dropped before exiting let pk = match (config.verify, config.pk_path) { @@ -271,7 +268,7 @@ fn run(config: Config<'_>) { Err(lucet_runtime::Error::RuntimeTerminated( lucet_runtime::TerminationDetails::Provided(any), )) => *any - .downcast_ref::() + .downcast_ref::<__wasi_exitcode_t>() .expect("termination yields an exitcode"), Err(lucet_runtime::Error::RuntimeTerminated( lucet_runtime::TerminationDetails::Remote, diff --git a/lucet-wasi/tests/test_helpers/mod.rs b/lucet-wasi/tests/test_helpers/mod.rs index 1ca986609..c6ac5df97 100644 --- a/lucet-wasi/tests/test_helpers/mod.rs +++ b/lucet-wasi/tests/test_helpers/mod.rs @@ -1,7 +1,6 @@ use failure::{bail, Error}; use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region}; -use lucet_wasi::host::__wasi_exitcode_t; -use lucet_wasi::{self, WasiCtx, WasiCtxBuilder}; +use lucet_wasi::{self, WasiCtx, WasiCtxBuilder, __wasi_exitcode_t}; use lucet_wasi_sdk::{CompileOpts, Link}; use lucetc::{Lucetc, LucetcOpts}; use std::fs::File; From 5d31c38664d361531d8408ba9f3f61a00c613bcb Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 29 Oct 2019 16:59:56 -0700 Subject: [PATCH 467/512] lucet-wasi: re-export wasi-common's error --- lucet-wasi/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lucet-wasi/src/lib.rs b/lucet-wasi/src/lib.rs index efd56f393..f6ba4671d 100644 --- a/lucet-wasi/src/lib.rs +++ b/lucet-wasi/src/lib.rs @@ -15,3 +15,6 @@ pub use wasi::{export_wasi_funcs, WasiCtx, WasiCtxBuilder}; // `u32` in our code that uses the exitcode. #[allow(non_camel_case_types)] pub type __wasi_exitcode_t = u32; + +// Re-export wasi-common's error type +pub use wasi_common::Error; From 5b0265a5b4e6001593ede16d3e1f24de71ee031b Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 1 Nov 2019 15:46:32 -0700 Subject: [PATCH 468/512] lucet-wasi: export start symbol --- lucet-wasi/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lucet-wasi/src/lib.rs b/lucet-wasi/src/lib.rs index f6ba4671d..dbf3e35f9 100644 --- a/lucet-wasi/src/lib.rs +++ b/lucet-wasi/src/lib.rs @@ -18,3 +18,5 @@ pub type __wasi_exitcode_t = u32; // Re-export wasi-common's error type pub use wasi_common::Error; + +pub const START_SYMBOL: &'static str = "_start"; From 07cbd0302095583fe491972f7cf6eef908354803 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 1 Nov 2019 15:46:53 -0700 Subject: [PATCH 469/512] use nix 0.15 everywhere wasi-common depends on nix 0.15, so upgrade everywhere using 0.13.1 --- Cargo.lock | 19 +++---------------- benchmarks/lucet-benchmarks/Cargo.toml | 2 +- lucet-runtime/Cargo.toml | 2 +- lucet-wasi-fuzz/Cargo.toml | 2 +- 4 files changed, 6 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7884a9239..e34fe8b0f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -791,7 +791,7 @@ dependencies = [ "lucet-wasi 0.4.1", "lucet-wasi-sdk 0.4.1", "lucetc 0.4.1", - "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -883,7 +883,7 @@ dependencies = [ "lucet-runtime-tests 0.4.1", "lucet-wasi-sdk 0.4.1", "lucetc 0.4.1", - "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -988,7 +988,7 @@ dependencies = [ "lucet-wasi 0.4.1", "lucet-wasi-sdk 0.4.1", "lucetc 0.4.1", - "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1081,18 +1081,6 @@ dependencies = [ "adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "nix" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "nix" version = "0.15.0" @@ -2235,7 +2223,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum memoffset 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a85c1a8c329f11437034d7313dca647c79096523533a1c79e86f1d0f657c7cc" "checksum minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "185d3531e38475163c1652a0915ac612be3f2655756af43f10789d6145f527c2" "checksum miniz_oxide 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6f3f74f726ae935c3f514300cc6773a0c9492abc5e972d42ba0c0ebb88757625" -"checksum nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4dbdc256eaac2e3bd236d93ad999d3479ef775c863dbda3068c4006a92eec51b" "checksum nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229" "checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" "checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" diff --git a/benchmarks/lucet-benchmarks/Cargo.toml b/benchmarks/lucet-benchmarks/Cargo.toml index c73c9aeb7..63045b953 100644 --- a/benchmarks/lucet-benchmarks/Cargo.toml +++ b/benchmarks/lucet-benchmarks/Cargo.toml @@ -17,7 +17,7 @@ lucet-runtime = { path = "../../lucet-runtime" } lucet-runtime-internals = { path = "../../lucet-runtime/lucet-runtime-internals" } lucet-wasi = { path = "../../lucet-wasi" } lucet-wasi-sdk = { path = "../../lucet-wasi-sdk" } -nix = "0.13" +nix = "0.15" num_cpus = "1.0" rayon = "1.0" tempfile = "3.0" diff --git a/lucet-runtime/Cargo.toml b/lucet-runtime/Cargo.toml index cd8c62cb8..f60fcdbd9 100644 --- a/lucet-runtime/Cargo.toml +++ b/lucet-runtime/Cargo.toml @@ -23,7 +23,7 @@ lazy_static = "1.1" lucetc = { path = "../lucetc", version = "0.4.1" } lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.4.1" } lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.1" } -nix = "0.13" +nix = "0.15" rayon = "1.0" tempfile = "3.0" diff --git a/lucet-wasi-fuzz/Cargo.toml b/lucet-wasi-fuzz/Cargo.toml index dddd103c8..5fb368ad0 100644 --- a/lucet-wasi-fuzz/Cargo.toml +++ b/lucet-wasi-fuzz/Cargo.toml @@ -18,7 +18,7 @@ lucet-runtime = { path = "../lucet-runtime" } lucet-module = { path = "../lucet-module" } lucet-wasi = { path = "../lucet-wasi" } lucet-wasi-sdk = { path = "../lucet-wasi-sdk" } -nix = "0.13" +nix = "0.15" num_cpus = "1.10" progress = "0.2" rand = "0.6" From 5a4d8cd217236a8b4d83ee85efd939cdcb610739 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 4 Nov 2019 11:09:06 -0800 Subject: [PATCH 470/512] latest wasi-common master --- lucet-wasi/src/lib.rs | 17 +- lucet-wasi/src/wasi.rs | 352 ++++++++++++++++++++--------------------- 2 files changed, 181 insertions(+), 188 deletions(-) diff --git a/lucet-wasi/src/lib.rs b/lucet-wasi/src/lib.rs index dbf3e35f9..4fc3e1cc2 100644 --- a/lucet-wasi/src/lib.rs +++ b/lucet-wasi/src/lib.rs @@ -4,19 +4,12 @@ mod bindings; pub mod c_api; pub mod wasi; +// Lucet-specific wrappers of wasi-common: pub use bindings::bindings; -pub use wasi::{export_wasi_funcs, WasiCtx, WasiCtxBuilder}; +pub use wasi::export_wasi_funcs; -// Exporting this type alias as a stop-gap: wasi-common should really provide a pub Rust enum type -// for the return values from _start, but it does not yet. We're going to pursue that path via witx -// and friends rather than export the type definition and constants from wasi-common right now. -// -// In the meantime, we're providing this alias because it is more descriptive to use (compared to -// `u32` in our code that uses the exitcode. -#[allow(non_camel_case_types)] -pub type __wasi_exitcode_t = u32; - -// Re-export wasi-common's error type -pub use wasi_common::Error; +// Wasi-common re-exports: +pub use wasi_common::{wasi::__wasi_exitcode_t, Error, WasiCtx, WasiCtxBuilder}; +// Wasi executables export the following symbol for the entry point: pub const START_SYMBOL: &'static str = "_start"; diff --git a/lucet-wasi/src/wasi.rs b/lucet-wasi/src/wasi.rs index 21d9cbcac..1469ab898 100644 --- a/lucet-wasi/src/wasi.rs +++ b/lucet-wasi/src/wasi.rs @@ -1,7 +1,7 @@ #![allow(clippy::too_many_arguments)] pub use lucet_runtime::{self, vmctx::lucet_vmctx}; -pub use wasi_common::*; +pub use wasi_common::{wasi, wasi32, WasiCtx}; use lucet_runtime::lucet_hostcall_terminate; use std::mem; @@ -13,7 +13,7 @@ lucet_runtime::lucet_hostcalls! { #[no_mangle] pub unsafe extern "C" fn __wasi_proc_exit( &mut _lucet_vmctx, - rval: wasm32::__wasi_exitcode_t, + rval: wasi::__wasi_exitcode_t, ) -> ! { export_wasi_funcs(); lucet_hostcall_terminate!(rval); @@ -22,9 +22,9 @@ pub unsafe extern "C" fn __wasi_proc_exit( #[no_mangle] pub unsafe extern "C" fn __wasi_args_get( &mut lucet_ctx, - argv_ptr: wasm32::uintptr_t, - argv_buf: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { + argv_ptr: wasi32::uintptr_t, + argv_buf: wasi32::uintptr_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); let heap = &mut lucet_ctx.heap_mut(); args_get(wasi_ctx, heap, argv_ptr, argv_buf) @@ -33,25 +33,25 @@ pub unsafe extern "C" fn __wasi_args_get( #[no_mangle] pub unsafe extern "C" fn __wasi_args_sizes_get( &mut lucet_ctx, - argc_ptr: wasm32::uintptr_t, - argv_buf_size_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { + argc_ptr: wasi32::uintptr_t, + argv_buf_size_ptr: wasi32::uintptr_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); let heap = &mut lucet_ctx.heap_mut(); args_sizes_get(wasi_ctx, heap, argc_ptr, argv_buf_size_ptr) } #[no_mangle] -pub unsafe extern "C" fn __wasi_sched_yield(&mut _lucet_ctx,) -> wasm32::__wasi_errno_t { +pub unsafe extern "C" fn __wasi_sched_yield(&mut _lucet_ctx,) -> wasi::__wasi_errno_t { sched_yield() } #[no_mangle] pub unsafe extern "C" fn __wasi_clock_res_get( &mut lucet_ctx, - clock_id: wasm32::__wasi_clockid_t, - resolution_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { + clock_id: wasi::__wasi_clockid_t, + resolution_ptr: wasi32::uintptr_t, +) -> wasi::__wasi_errno_t { let heap = &mut lucet_ctx.heap_mut(); clock_res_get(heap, clock_id, resolution_ptr) } @@ -59,10 +59,10 @@ pub unsafe extern "C" fn __wasi_clock_res_get( #[no_mangle] pub unsafe extern "C" fn __wasi_clock_time_get( &mut lucet_ctx, - clock_id: wasm32::__wasi_clockid_t, - precision: wasm32::__wasi_timestamp_t, - time_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { + clock_id: wasi::__wasi_clockid_t, + precision: wasi::__wasi_timestamp_t, + time_ptr: wasi32::uintptr_t, +) -> wasi::__wasi_errno_t { let heap = &mut lucet_ctx.heap_mut(); clock_time_get(heap, clock_id, precision, time_ptr) } @@ -70,9 +70,9 @@ pub unsafe extern "C" fn __wasi_clock_time_get( #[no_mangle] pub unsafe extern "C" fn __wasi_environ_get( &mut lucet_ctx, - environ_ptr: wasm32::uintptr_t, - environ_buf: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { + environ_ptr: wasi32::uintptr_t, + environ_buf: wasi32::uintptr_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); let heap = &mut lucet_ctx.heap_mut(); environ_get(wasi_ctx, heap, environ_ptr, environ_buf) @@ -81,9 +81,9 @@ pub unsafe extern "C" fn __wasi_environ_get( #[no_mangle] pub unsafe extern "C" fn __wasi_environ_sizes_get( &mut lucet_ctx, - environ_count_ptr: wasm32::uintptr_t, - environ_size_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { + environ_count_ptr: wasi32::uintptr_t, + environ_size_ptr: wasi32::uintptr_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); let heap = &mut lucet_ctx.heap_mut(); environ_sizes_get(wasi_ctx, heap, environ_count_ptr, environ_size_ptr) @@ -92,8 +92,8 @@ pub unsafe extern "C" fn __wasi_environ_sizes_get( #[no_mangle] pub unsafe extern "C" fn __wasi_fd_close( &mut lucet_ctx, - fd: wasm32::__wasi_fd_t, -) -> wasm32::__wasi_errno_t { + fd: wasi::__wasi_fd_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &mut lucet_ctx.get_embed_ctx_mut::(); fd_close(wasi_ctx, fd) } @@ -101,9 +101,9 @@ pub unsafe extern "C" fn __wasi_fd_close( #[no_mangle] pub unsafe extern "C" fn __wasi_fd_fdstat_get( &mut lucet_ctx, - fd: wasm32::__wasi_fd_t, - fdstat_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { + fd: wasi::__wasi_fd_t, + fdstat_ptr: wasi32::uintptr_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); let heap = &mut lucet_ctx.heap_mut(); fd_fdstat_get(wasi_ctx, heap, fd, fdstat_ptr) @@ -112,9 +112,9 @@ pub unsafe extern "C" fn __wasi_fd_fdstat_get( #[no_mangle] pub unsafe extern "C" fn __wasi_fd_fdstat_set_flags( &mut lucet_ctx, - fd: wasm32::__wasi_fd_t, - fdflags: wasm32::__wasi_fdflags_t, -) -> wasm32::__wasi_errno_t { + fd: wasi::__wasi_fd_t, + fdflags: wasi::__wasi_fdflags_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); fd_fdstat_set_flags(wasi_ctx, fd, fdflags) } @@ -122,9 +122,9 @@ pub unsafe extern "C" fn __wasi_fd_fdstat_set_flags( #[no_mangle] pub unsafe extern "C" fn __wasi_fd_tell( &mut lucet_ctx, - fd: wasm32::__wasi_fd_t, - offset: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { + fd: wasi::__wasi_fd_t, + offset: wasi32::uintptr_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &mut lucet_ctx.get_embed_ctx_mut::(); let heap = &mut lucet_ctx.heap_mut(); fd_tell(wasi_ctx, heap, fd, offset) @@ -133,11 +133,11 @@ pub unsafe extern "C" fn __wasi_fd_tell( #[no_mangle] pub unsafe extern "C" fn __wasi_fd_seek( &mut lucet_ctx, - fd: wasm32::__wasi_fd_t, - offset: wasm32::__wasi_filedelta_t, - whence: wasm32::__wasi_whence_t, - newoffset: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { + fd: wasi::__wasi_fd_t, + offset: wasi::__wasi_filedelta_t, + whence: wasi::__wasi_whence_t, + newoffset: wasi32::uintptr_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &mut lucet_ctx.get_embed_ctx_mut::(); let heap = &mut lucet_ctx.heap_mut(); fd_seek(wasi_ctx, heap, fd, offset, whence, newoffset) @@ -146,9 +146,9 @@ pub unsafe extern "C" fn __wasi_fd_seek( #[no_mangle] pub unsafe extern "C" fn __wasi_fd_prestat_get( &mut lucet_ctx, - fd: wasm32::__wasi_fd_t, - prestat_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { + fd: wasi::__wasi_fd_t, + prestat_ptr: wasi32::uintptr_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); let heap = &mut lucet_ctx.heap_mut(); fd_prestat_get(wasi_ctx, heap, fd, prestat_ptr) @@ -157,10 +157,10 @@ pub unsafe extern "C" fn __wasi_fd_prestat_get( #[no_mangle] pub unsafe extern "C" fn __wasi_fd_prestat_dir_name( &mut lucet_ctx, - fd: wasm32::__wasi_fd_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, -) -> wasm32::__wasi_errno_t { + fd: wasi::__wasi_fd_t, + path_ptr: wasi32::uintptr_t, + path_len: wasi32::size_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); let heap = &mut lucet_ctx.heap_mut(); fd_prestat_dir_name(wasi_ctx, heap, fd, path_ptr, path_len) @@ -169,11 +169,11 @@ pub unsafe extern "C" fn __wasi_fd_prestat_dir_name( #[no_mangle] pub unsafe extern "C" fn __wasi_fd_read( &mut lucet_ctx, - fd: wasm32::__wasi_fd_t, - iovs_ptr: wasm32::uintptr_t, - iovs_len: wasm32::size_t, - nread: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { + fd: wasi::__wasi_fd_t, + iovs_ptr: wasi32::uintptr_t, + iovs_len: wasi32::size_t, + nread: wasi32::uintptr_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &mut lucet_ctx.get_embed_ctx_mut::(); let heap = &mut lucet_ctx.heap_mut(); fd_read(wasi_ctx, heap, fd, iovs_ptr, iovs_len, nread) @@ -182,11 +182,11 @@ pub unsafe extern "C" fn __wasi_fd_read( #[no_mangle] pub unsafe extern "C" fn __wasi_fd_write( &mut lucet_ctx, - fd: wasm32::__wasi_fd_t, - iovs_ptr: wasm32::uintptr_t, - iovs_len: wasm32::size_t, - nwritten: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { + fd: wasi::__wasi_fd_t, + iovs_ptr: wasi32::uintptr_t, + iovs_len: wasi32::size_t, + nwritten: wasi32::uintptr_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &mut lucet_ctx.get_embed_ctx_mut::(); let heap = &mut lucet_ctx.heap_mut(); fd_write(wasi_ctx, heap, fd, iovs_ptr, iovs_len, nwritten) @@ -195,16 +195,16 @@ pub unsafe extern "C" fn __wasi_fd_write( #[no_mangle] pub unsafe extern "C" fn __wasi_path_open( &mut lucet_ctx, - dirfd: wasm32::__wasi_fd_t, - dirflags: wasm32::__wasi_lookupflags_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, - oflags: wasm32::__wasi_oflags_t, - fs_rights_base: wasm32::__wasi_rights_t, - fs_rights_inheriting: wasm32::__wasi_rights_t, - fs_flags: wasm32::__wasi_fdflags_t, - fd_out_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { + dirfd: wasi::__wasi_fd_t, + dirflags: wasi::__wasi_lookupflags_t, + path_ptr: wasi32::uintptr_t, + path_len: wasi32::size_t, + oflags: wasi::__wasi_oflags_t, + fs_rights_base: wasi::__wasi_rights_t, + fs_rights_inheriting: wasi::__wasi_rights_t, + fs_flags: wasi::__wasi_fdflags_t, + fd_out_ptr: wasi32::uintptr_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &mut lucet_ctx.get_embed_ctx_mut::(); let heap = &mut lucet_ctx.heap_mut(); path_open( @@ -225,9 +225,9 @@ pub unsafe extern "C" fn __wasi_path_open( #[no_mangle] pub unsafe extern "C" fn __wasi_random_get( &mut lucet_ctx, - buf_ptr: wasm32::uintptr_t, - buf_len: wasm32::size_t, -) -> wasm32::__wasi_errno_t { + buf_ptr: wasi32::uintptr_t, + buf_len: wasi32::size_t, +) -> wasi::__wasi_errno_t { let heap = &mut lucet_ctx.heap_mut(); random_get(heap, buf_ptr, buf_len) } @@ -235,11 +235,11 @@ pub unsafe extern "C" fn __wasi_random_get( #[no_mangle] pub unsafe extern "C" fn __wasi_poll_oneoff( &mut lucet_ctx, - input: wasm32::uintptr_t, - output: wasm32::uintptr_t, - nsubscriptions: wasm32::size_t, - nevents: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { + input: wasi32::uintptr_t, + output: wasi32::uintptr_t, + nsubscriptions: wasi32::size_t, + nevents: wasi32::uintptr_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); let heap = &mut lucet_ctx.heap_mut(); poll_oneoff(wasi_ctx, heap, input, output, nsubscriptions, nevents) @@ -248,9 +248,9 @@ pub unsafe extern "C" fn __wasi_poll_oneoff( #[no_mangle] pub unsafe extern "C" fn __wasi_fd_filestat_get( &mut lucet_ctx, - fd: wasm32::__wasi_fd_t, - filestat_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { + fd: wasi::__wasi_fd_t, + filestat_ptr: wasi32::uintptr_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); let heap = &mut lucet_ctx.heap_mut(); fd_filestat_get(wasi_ctx, heap, fd, filestat_ptr) @@ -259,12 +259,12 @@ pub unsafe extern "C" fn __wasi_fd_filestat_get( #[no_mangle] pub unsafe extern "C" fn __wasi_path_filestat_get( &mut lucet_ctx, - dirfd: wasm32::__wasi_fd_t, - dirflags: wasm32::__wasi_lookupflags_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, - filestat_ptr: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { + dirfd: wasi::__wasi_fd_t, + dirflags: wasi::__wasi_lookupflags_t, + path_ptr: wasi32::uintptr_t, + path_len: wasi32::size_t, + filestat_ptr: wasi32::uintptr_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); let heap = &mut lucet_ctx.heap_mut(); path_filestat_get( @@ -281,10 +281,10 @@ pub unsafe extern "C" fn __wasi_path_filestat_get( #[no_mangle] pub unsafe extern "C" fn __wasi_path_create_directory( &mut lucet_ctx, - dirfd: wasm32::__wasi_fd_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, -) -> wasm32::__wasi_errno_t { + dirfd: wasi::__wasi_fd_t, + path_ptr: wasi32::uintptr_t, + path_len: wasi32::size_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); let heap = &mut lucet_ctx.heap_mut(); path_create_directory(wasi_ctx, heap, dirfd, path_ptr, path_len) @@ -293,10 +293,10 @@ pub unsafe extern "C" fn __wasi_path_create_directory( #[no_mangle] pub unsafe extern "C" fn __wasi_path_unlink_file( &mut lucet_ctx, - dirfd: wasm32::__wasi_fd_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, -) -> wasm32::__wasi_errno_t { + dirfd: wasi::__wasi_fd_t, + path_ptr: wasi32::uintptr_t, + path_len: wasi32::size_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); let heap = &mut lucet_ctx.heap_mut(); path_unlink_file(wasi_ctx, heap, dirfd, path_ptr, path_len) @@ -305,10 +305,10 @@ pub unsafe extern "C" fn __wasi_path_unlink_file( #[no_mangle] pub unsafe extern "C" fn __wasi_fd_allocate( &mut lucet_ctx, - fd: wasm32::__wasi_fd_t, - offset: wasm32::__wasi_filesize_t, - len: wasm32::__wasi_filesize_t, -) -> wasm32::__wasi_errno_t { + fd: wasi::__wasi_fd_t, + offset: wasi::__wasi_filesize_t, + len: wasi::__wasi_filesize_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); fd_allocate(wasi_ctx, fd, offset, len) } @@ -316,11 +316,11 @@ pub unsafe extern "C" fn __wasi_fd_allocate( #[no_mangle] pub unsafe extern "C" fn __wasi_fd_advise( &mut lucet_ctx, - fd: wasm32::__wasi_fd_t, - offset: wasm32::__wasi_filesize_t, - len: wasm32::__wasi_filesize_t, - advice: wasm32::__wasi_advice_t, -) -> wasm32::__wasi_errno_t { + fd: wasi::__wasi_fd_t, + offset: wasi::__wasi_filesize_t, + len: wasi::__wasi_filesize_t, + advice: wasi::__wasi_advice_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); fd_advise(wasi_ctx, fd, offset, len, advice) } @@ -328,8 +328,8 @@ pub unsafe extern "C" fn __wasi_fd_advise( #[no_mangle] pub unsafe extern "C" fn __wasi_fd_datasync( &mut lucet_ctx, - fd: wasm32::__wasi_fd_t, -) -> wasm32::__wasi_errno_t { + fd: wasi::__wasi_fd_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); fd_datasync(wasi_ctx, fd) } @@ -337,8 +337,8 @@ pub unsafe extern "C" fn __wasi_fd_datasync( #[no_mangle] pub unsafe extern "C" fn __wasi_fd_sync( &mut lucet_ctx, - fd: wasm32::__wasi_fd_t, -) -> wasm32::__wasi_errno_t { + fd: wasi::__wasi_fd_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); fd_sync(wasi_ctx, fd) } @@ -346,10 +346,10 @@ pub unsafe extern "C" fn __wasi_fd_sync( #[no_mangle] pub unsafe extern "C" fn __wasi_fd_fdstat_set_rights( &mut lucet_ctx, - fd: wasm32::__wasi_fd_t, - fs_rights_base: wasm32::__wasi_rights_t, - fs_rights_inheriting: wasm32::__wasi_rights_t, -) -> wasm32::__wasi_errno_t { + fd: wasi::__wasi_fd_t, + fs_rights_base: wasi::__wasi_rights_t, + fs_rights_inheriting: wasi::__wasi_rights_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &mut lucet_ctx.get_embed_ctx_mut::(); fd_fdstat_set_rights(wasi_ctx, fd, fs_rights_base, fs_rights_inheriting) } @@ -357,9 +357,9 @@ pub unsafe extern "C" fn __wasi_fd_fdstat_set_rights( #[no_mangle] pub unsafe extern "C" fn __wasi_fd_filestat_set_size( &mut lucet_ctx, - fd: wasm32::__wasi_fd_t, - st_size: wasm32::__wasi_filesize_t, -) -> wasm32::__wasi_errno_t { + fd: wasi::__wasi_fd_t, + st_size: wasi::__wasi_filesize_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); fd_filestat_set_size(wasi_ctx, fd, st_size) } @@ -367,11 +367,11 @@ pub unsafe extern "C" fn __wasi_fd_filestat_set_size( #[no_mangle] pub unsafe extern "C" fn __wasi_fd_filestat_set_times( &mut lucet_ctx, - fd: wasm32::__wasi_fd_t, - st_atim: wasm32::__wasi_timestamp_t, - st_mtim: wasm32::__wasi_timestamp_t, - fst_flags: wasm32::__wasi_fstflags_t, -) -> wasm32::__wasi_errno_t { + fd: wasi::__wasi_fd_t, + st_atim: wasi::__wasi_timestamp_t, + st_mtim: wasi::__wasi_timestamp_t, + fst_flags: wasi::__wasi_fstflags_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); fd_filestat_set_times(wasi_ctx, fd, st_atim, st_mtim, fst_flags) } @@ -379,12 +379,12 @@ pub unsafe extern "C" fn __wasi_fd_filestat_set_times( #[no_mangle] pub unsafe extern "C" fn __wasi_fd_pread( &mut lucet_ctx, - fd: wasm32::__wasi_fd_t, - iovs_ptr: wasm32::uintptr_t, - iovs_len: wasm32::size_t, - offset: wasm32::__wasi_filesize_t, - nread: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { + fd: wasi::__wasi_fd_t, + iovs_ptr: wasi32::uintptr_t, + iovs_len: wasi32::size_t, + offset: wasi::__wasi_filesize_t, + nread: wasi32::uintptr_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); let heap = &mut lucet_ctx.heap_mut(); fd_pread(wasi_ctx, heap, fd, iovs_ptr, iovs_len, offset, nread) @@ -393,12 +393,12 @@ pub unsafe extern "C" fn __wasi_fd_pread( #[no_mangle] pub unsafe extern "C" fn __wasi_fd_pwrite( &mut lucet_ctx, - fd: wasm32::__wasi_fd_t, - iovs_ptr: wasm32::uintptr_t, - iovs_len: wasm32::size_t, - offset: wasm32::__wasi_filesize_t, - nwritten: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { + fd: wasi::__wasi_fd_t, + iovs_ptr: wasi32::uintptr_t, + iovs_len: wasi32::size_t, + offset: wasi::__wasi_filesize_t, + nwritten: wasi32::uintptr_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); let heap = &mut lucet_ctx.heap_mut(); fd_pwrite(wasi_ctx, heap, fd, iovs_ptr, iovs_len, offset, nwritten) @@ -407,12 +407,12 @@ pub unsafe extern "C" fn __wasi_fd_pwrite( #[no_mangle] pub unsafe extern "C" fn __wasi_fd_readdir( &mut lucet_ctx, - fd: wasm32::__wasi_fd_t, - buf: wasm32::uintptr_t, - buf_len: wasm32::size_t, - cookie: wasm32::__wasi_dircookie_t, - bufused: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { + fd: wasi::__wasi_fd_t, + buf: wasi32::uintptr_t, + buf_len: wasi32::size_t, + cookie: wasi::__wasi_dircookie_t, + bufused: wasi32::uintptr_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &mut lucet_ctx.get_embed_ctx_mut::(); let heap = &mut lucet_ctx.heap_mut(); fd_readdir(wasi_ctx, heap, fd, buf, buf_len, cookie, bufused) @@ -421,9 +421,9 @@ pub unsafe extern "C" fn __wasi_fd_readdir( #[no_mangle] pub unsafe extern "C" fn __wasi_fd_renumber( &mut lucet_ctx, - from: wasm32::__wasi_fd_t, - to: wasm32::__wasi_fd_t, -) -> wasm32::__wasi_errno_t { + from: wasi::__wasi_fd_t, + to: wasi::__wasi_fd_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &mut lucet_ctx.get_embed_ctx_mut::(); fd_renumber(wasi_ctx, from, to) } @@ -431,14 +431,14 @@ pub unsafe extern "C" fn __wasi_fd_renumber( #[no_mangle] pub unsafe extern "C" fn __wasi_path_filestat_set_times( &mut lucet_ctx, - dirfd: wasm32::__wasi_fd_t, - dirflags: wasm32::__wasi_lookupflags_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, - st_atim: wasm32::__wasi_timestamp_t, - st_mtim: wasm32::__wasi_timestamp_t, - fst_flags: wasm32::__wasi_fstflags_t, -) -> wasm32::__wasi_errno_t { + dirfd: wasi::__wasi_fd_t, + dirflags: wasi::__wasi_lookupflags_t, + path_ptr: wasi32::uintptr_t, + path_len: wasi32::size_t, + st_atim: wasi::__wasi_timestamp_t, + st_mtim: wasi::__wasi_timestamp_t, + fst_flags: wasi::__wasi_fstflags_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); let heap = &mut lucet_ctx.heap_mut(); path_filestat_set_times( @@ -449,14 +449,14 @@ pub unsafe extern "C" fn __wasi_path_filestat_set_times( #[no_mangle] pub unsafe extern "C" fn __wasi_path_link( &mut lucet_ctx, - old_fd: wasm32::__wasi_fd_t, - old_flags: wasm32::__wasi_lookupflags_t, - old_path_ptr: wasm32::uintptr_t, - old_path_len: wasm32::size_t, - new_fd: wasm32::__wasi_fd_t, - new_path_ptr: wasm32::uintptr_t, - new_path_len: wasm32::size_t, -) -> wasm32::__wasi_errno_t { + old_fd: wasi::__wasi_fd_t, + old_flags: wasi::__wasi_lookupflags_t, + old_path_ptr: wasi32::uintptr_t, + old_path_len: wasi32::size_t, + new_fd: wasi::__wasi_fd_t, + new_path_ptr: wasi32::uintptr_t, + new_path_len: wasi32::size_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); let heap = &mut lucet_ctx.heap_mut(); path_link( @@ -475,13 +475,13 @@ pub unsafe extern "C" fn __wasi_path_link( #[no_mangle] pub unsafe extern "C" fn __wasi_path_readlink( &mut lucet_ctx, - dirfd: wasm32::__wasi_fd_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, - buf_ptr: wasm32::uintptr_t, - buf_len: wasm32::size_t, - bufused: wasm32::uintptr_t, -) -> wasm32::__wasi_errno_t { + dirfd: wasi::__wasi_fd_t, + path_ptr: wasi32::uintptr_t, + path_len: wasi32::size_t, + buf_ptr: wasi32::uintptr_t, + buf_len: wasi32::size_t, + bufused: wasi32::uintptr_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); let heap = &mut lucet_ctx.heap_mut(); path_readlink( @@ -492,10 +492,10 @@ pub unsafe extern "C" fn __wasi_path_readlink( #[no_mangle] pub unsafe extern "C" fn __wasi_path_remove_directory( &mut lucet_ctx, - dirfd: wasm32::__wasi_fd_t, - path_ptr: wasm32::uintptr_t, - path_len: wasm32::size_t, -) -> wasm32::__wasi_errno_t { + dirfd: wasi::__wasi_fd_t, + path_ptr: wasi32::uintptr_t, + path_len: wasi32::size_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); let heap = &mut lucet_ctx.heap_mut(); path_remove_directory(wasi_ctx, heap, dirfd, path_ptr, path_len) @@ -504,13 +504,13 @@ pub unsafe extern "C" fn __wasi_path_remove_directory( #[no_mangle] pub unsafe extern "C" fn __wasi_path_rename( &mut lucet_ctx, - old_dirfd: wasm32::__wasi_fd_t, - old_path_ptr: wasm32::uintptr_t, - old_path_len: wasm32::size_t, - new_dirfd: wasm32::__wasi_fd_t, - new_path_ptr: wasm32::uintptr_t, - new_path_len: wasm32::size_t, -) -> wasm32::__wasi_errno_t { + old_dirfd: wasi::__wasi_fd_t, + old_path_ptr: wasi32::uintptr_t, + old_path_len: wasi32::size_t, + new_dirfd: wasi::__wasi_fd_t, + new_path_ptr: wasi32::uintptr_t, + new_path_len: wasi32::size_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); let heap = &mut lucet_ctx.heap_mut(); path_rename( @@ -528,12 +528,12 @@ pub unsafe extern "C" fn __wasi_path_rename( #[no_mangle] pub unsafe extern "C" fn __wasi_path_symlink( &mut lucet_ctx, - old_path_ptr: wasm32::uintptr_t, - old_path_len: wasm32::size_t, - dir_fd: wasm32::__wasi_fd_t, - new_path_ptr: wasm32::uintptr_t, - new_path_len: wasm32::size_t, -) -> wasm32::__wasi_errno_t { + old_path_ptr: wasi32::uintptr_t, + old_path_len: wasi32::size_t, + dir_fd: wasi::__wasi_fd_t, + new_path_ptr: wasi32::uintptr_t, + new_path_len: wasi32::size_t, +) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); let heap = &mut lucet_ctx.heap_mut(); path_symlink( From 38cb83f0de7f90389aff7ce6348fabfd8d76ef8f Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 5 Nov 2019 10:19:41 -0800 Subject: [PATCH 471/512] pin wasi-common to f4ac1299b2001b575cfc99f5544a4a96355a6bff in cargo.toml --- Cargo.lock | 18 +++++++++--------- lucet-wasi/Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e34fe8b0f..71f48b8af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -973,7 +973,7 @@ dependencies = [ "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi-common 0.4.0 (git+https://github.com/cranestation/wasi-common)", + "wasi-common 0.4.0 (git+https://github.com/cranestation/wasi-common?rev=f4ac1299b2001b575cfc99f5544a4a96355a6bff)", ] [[package]] @@ -2001,7 +2001,7 @@ dependencies = [ [[package]] name = "wasi-common" version = "0.4.0" -source = "git+https://github.com/cranestation/wasi-common#74757fdd65ef6f8950e94bd2e7a8a7ed46530e46" +source = "git+https://github.com/cranestation/wasi-common?rev=f4ac1299b2001b575cfc99f5544a4a96355a6bff#f4ac1299b2001b575cfc99f5544a4a96355a6bff" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "cpu-time 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2013,15 +2013,15 @@ dependencies = [ "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi-common-cbindgen 0.4.0 (git+https://github.com/cranestation/wasi-common)", + "wasi-common-cbindgen 0.4.0 (git+https://github.com/cranestation/wasi-common?rev=f4ac1299b2001b575cfc99f5544a4a96355a6bff)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winx 0.4.0 (git+https://github.com/cranestation/wasi-common)", + "winx 0.4.0 (git+https://github.com/cranestation/wasi-common?rev=f4ac1299b2001b575cfc99f5544a4a96355a6bff)", ] [[package]] name = "wasi-common-cbindgen" version = "0.4.0" -source = "git+https://github.com/cranestation/wasi-common#74757fdd65ef6f8950e94bd2e7a8a7ed46530e46" +source = "git+https://github.com/cranestation/wasi-common?rev=f4ac1299b2001b575cfc99f5544a4a96355a6bff#f4ac1299b2001b575cfc99f5544a4a96355a6bff" dependencies = [ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2117,7 +2117,7 @@ dependencies = [ [[package]] name = "winx" version = "0.4.0" -source = "git+https://github.com/cranestation/wasi-common#74757fdd65ef6f8950e94bd2e7a8a7ed46530e46" +source = "git+https://github.com/cranestation/wasi-common?rev=f4ac1299b2001b575cfc99f5544a4a96355a6bff#f4ac1299b2001b575cfc99f5544a4a96355a6bff" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "cvt 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2331,8 +2331,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af5d153dc96aad7dc13ab90835b892c69867948112d95299e522d370c4e13a08" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" -"checksum wasi-common 0.4.0 (git+https://github.com/cranestation/wasi-common)" = "" -"checksum wasi-common-cbindgen 0.4.0 (git+https://github.com/cranestation/wasi-common)" = "" +"checksum wasi-common 0.4.0 (git+https://github.com/cranestation/wasi-common?rev=f4ac1299b2001b575cfc99f5544a4a96355a6bff)" = "" +"checksum wasi-common-cbindgen 0.4.0 (git+https://github.com/cranestation/wasi-common?rev=f4ac1299b2001b575cfc99f5544a4a96355a6bff)" = "" "checksum wasmonkey 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "af7c4bc80224427965ba21d87982cfc07d12e859824f303272056fb19f571ef9" "checksum wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5083b449454f7de0b15f131eee17de54b5a71dcb9adcf11df2b2f78fad0cd82" "checksum which 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5475d47078209a02e60614f7ba5e645ef3ed60f771920ac1906d7c1cc65024c8" @@ -2344,5 +2344,5 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" "checksum winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef84b96d10db72dd980056666d7f1e7663ce93d82fa33b63e71c966f4cf5032" -"checksum winx 0.4.0 (git+https://github.com/cranestation/wasi-common)" = "" +"checksum winx 0.4.0 (git+https://github.com/cranestation/wasi-common?rev=f4ac1299b2001b575cfc99f5544a4a96355a6bff)" = "" "checksum xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da90eac47bf1d7871b75004b9b631d107df15f37669383b23f0b5297bc7516b6" diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index 9126695d7..74e6f5a9f 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -34,7 +34,7 @@ lucet-module = { path = "../lucet-module", version = "0.4.1" } libc = "0.2.65" nix = "0.15" rand = "0.6" -wasi-common = { git = "https://github.com/cranestation/wasi-common", branch = "master" } +wasi-common = { git = "https://github.com/cranestation/wasi-common", rev = "f4ac1299b2001b575cfc99f5544a4a96355a6bff" } [dev-dependencies] lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.1" } From 66bb91f4b4c57d56b8760e70c5aa3f34154736e8 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 5 Nov 2019 10:25:34 -0800 Subject: [PATCH 472/512] Apply suggestions from code review Thank you Adam for a helpful and thorough code review! Co-Authored-By: Adam C. Foltzer --- lucet-wasi-fuzz/src/main.rs | 4 ++-- lucet-wasi/src/c_api.rs | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lucet-wasi-fuzz/src/main.rs b/lucet-wasi-fuzz/src/main.rs index b4023001f..aa0c511a4 100644 --- a/lucet-wasi-fuzz/src/main.rs +++ b/lucet-wasi-fuzz/src/main.rs @@ -369,9 +369,9 @@ fn run_with_stdout>( path: P, ) -> Result<(__wasi_exitcode_t, Vec), Error> { let ctx = WasiCtxBuilder::new() - .map_err(|_| format_err!("WasiCtxBuilder"))? + .map_err(|e| format_err!("WasiCtxBuilder: {}", e))? .args(["gen"].iter()) - .map_err(|_| format_err!("args"))?; + .map_err(|e| format_err!("WasiCtxBuilder args: {}", e))?; let (pipe_out, pipe_in) = nix::unistd::pipe()?; diff --git a/lucet-wasi/src/c_api.rs b/lucet-wasi/src/c_api.rs index 2b7d7f6ea..199b3e050 100644 --- a/lucet-wasi/src/c_api.rs +++ b/lucet-wasi/src/c_api.rs @@ -1,6 +1,5 @@ use crate::WasiCtxBuilder; -use libc; use lucet_runtime::{DlModule, Module, Region}; use lucet_runtime_internals::c_api::{lucet_dl_module, lucet_error, lucet_instance, lucet_region}; use lucet_runtime_internals::instance::instance_handle_to_raw; @@ -34,11 +33,11 @@ pub unsafe extern "C" fn lucet_wasi_ctx_args( .collect(); let args = match args { Ok(args) => args, - Err(_) => return lucet_error::Unsupported, + Err(_) => return lucet_error::InvalidArgument, }; *b = match b.args(args.iter()) { Ok(b) => b, - Err(_) => return lucet_error::Unsupported, + Err(_) => return lucet_error::InvalidArgument, }; Box::into_raw(b); lucet_error::Ok @@ -50,7 +49,7 @@ pub unsafe extern "C" fn lucet_wasi_ctx_inherit_env(wasi_ctx: *mut lucet_wasi_ct let mut b = Box::from_raw(wasi_ctx as *mut WasiCtxBuilder); *b = match b.inherit_env() { Ok(b) => b, - Err(_) => return lucet_error::Unsupported, + Err(_) => return lucet_error::InvalidArgument, }; Box::into_raw(b); lucet_error::Ok @@ -64,7 +63,7 @@ pub unsafe extern "C" fn lucet_wasi_ctx_inherit_stdio( let mut b = Box::from_raw(wasi_ctx as *mut WasiCtxBuilder); *b = match b.inherit_stdio() { Ok(b) => b, - Err(_) => return lucet_error::Unsupported, + Err(_) => return lucet_error::Internal, }; Box::into_raw(b); lucet_error::Ok From 2629f3c90529ca3cad2f523815cfa57e2fa38f72 Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Fri, 8 Nov 2019 19:48:40 +0100 Subject: [PATCH 473/512] heap_u32_mut: require a mutable heap (#359) --- lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs b/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs index 165cd0cdb..68276a9da 100644 --- a/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/alloc/mod.rs @@ -242,7 +242,7 @@ impl Alloc { } /// Return the heap as a mutable slice of 32-bit words. - pub unsafe fn heap_u32_mut(&self) -> &mut [u32] { + pub unsafe fn heap_u32_mut(&mut self) -> &mut [u32] { assert!(self.slot().heap as usize % 4 == 0, "heap is 4-byte aligned"); assert!( self.heap_accessible_size % 4 == 0, From b718d095b23d6a25b2dfa314ce3b7ba5be8215be Mon Sep 17 00:00:00 2001 From: Andy Wortman Date: Mon, 11 Nov 2019 12:34:23 -0800 Subject: [PATCH 474/512] replace lucet_runtime ensure_linked in lucet-wasi fixes https://github.com/fastly/lucet/issues/360 where the runtime's C API was being discarded by the linker. --- lucet-wasi/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/lucet-wasi/src/main.rs b/lucet-wasi/src/main.rs index df2dba522..4f0ed83ce 100644 --- a/lucet-wasi/src/main.rs +++ b/lucet-wasi/src/main.rs @@ -39,6 +39,7 @@ fn parse_humansized(desc: &str) -> Result { fn main() { // No-ops, but makes sure the linker doesn't throw away parts // of the runtime: + lucet_runtime::lucet_internal_ensure_linked(); lucet_wasi::export_wasi_funcs(); let matches = app_from_crate!() From f46d7a8f474de57c5091a05b5d98a63b695e81c1 Mon Sep 17 00:00:00 2001 From: Till Schneidereit Date: Tue, 12 Nov 2019 16:51:58 +0100 Subject: [PATCH 475/512] Make it a Bytecode Alliance project --- CODE_OF_CONDUCT.md | 58 +++++------------ ORG_CODE_OF_CONDUCT.md | 139 +++++++++++++++++++++++++++++++++++++++++ README.md | 3 + 3 files changed, 157 insertions(+), 43 deletions(-) create mode 100644 ORG_CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 59777fc6e..5c5ebdd25 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,18 +1,14 @@ # Contributor Covenant Code of Conduct +*Note*: this Code of Conduct pertains to individuals' behavior. Please also see the [Organizational Code of Conduct][OCoC]. + ## Our Pledge -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards -Examples of behavior that contributes to creating a positive environment -include: +Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences @@ -22,56 +18,32 @@ include: Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery and unwelcome sexual attention or - advances +* The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at labs@fastly.com, or tyler@fastly.com -if the message is sensitive. All complaints will be reviewed and investigated -and will result in a response that is deemed necessary and appropriate to the -circumstances. The project team is obligated to maintain confidentiality with -regard to the reporter of an incident. Further details of specific enforcement -policies may be posted separately. +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the Bytecode Alliance CoC team at [report@bytecodealliance.org](mailto:report@bytecodealliance.org). The CoC team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The CoC team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the Bytecode Alliance's leadership. ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] +[OCoC]: ORG_CODE_OF_CONDUCT.md [homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see -https://www.contributor-covenant.org/faq +[version]: https://www.contributor-covenant.org/version/1/4/ diff --git a/ORG_CODE_OF_CONDUCT.md b/ORG_CODE_OF_CONDUCT.md new file mode 100644 index 000000000..e05e40c3c --- /dev/null +++ b/ORG_CODE_OF_CONDUCT.md @@ -0,0 +1,139 @@ +# Bytecode Alliance Organizational Code of Conduct (OCoC) + +*Note*: this Code of Conduct pertains to organizations' behavior. Please also see the [Individual Code of Conduct](CODE_OF_CONDUCT.md). + +## Preamble + +The Bytecode Alliance (BA) welcomes involvement from organizations, +including commercial organizations. This document is an +*organizational* code of conduct, intended particularly to provide +guidance to commercial organizations. It is distinct from the +[Individual Code of Conduct (ICoC)](CODE_OF_CONDUCT.md), and does not +replace the ICoC. This OCoC applies to any group of people acting in +concert as a BA member or as a participant in BA activities, whether +or not that group is formally incorporated in some jurisdiction. + +The code of conduct described below is not a set of rigid rules, and +we did not write it to encompass every conceivable scenario that might +arise. For example, it is theoretically possible there would be times +when asserting patents is in the best interest of the BA community as +a whole. In such instances, consult with the BA, strive for +consensus, and interpret these rules with an intent that is generous +to the community the BA serves. + +While we may revise these guidelines from time to time based on +real-world experience, overall they are based on a simple principle: + +*Bytecode Alliance members should observe the distinction between + public community functions and private functions — especially + commercial ones — and should ensure that the latter support, or at + least do not harm, the former.* + +## Guidelines + + * **Do not cause confusion about Wasm standards or interoperability.** + + Having an interoperable WebAssembly core is a high priority for + the BA, and members should strive to preserve that core. It is fine + to develop additional non-standard features or APIs, but they + should always be clearly distinguished from the core interoperable + Wasm. + + Treat the WebAssembly name and any BA-associated names with + respect, and follow BA trademark and branding guidelines. If you + distribute a customized version of software originally produced by + the BA, or if you build a product or service using BA-derived + software, use names that clearly distinguish your work from the + original. (You should still provide proper attribution to the + original, of course, wherever such attribution would normally be + given.) + + Further, do not use the WebAssembly name or BA-associated names in + other public namespaces in ways that could cause confusion, e.g., + in company names, names of commercial service offerings, domain + names, publicly-visible social media accounts or online service + accounts, etc. It may sometimes be reasonable, however, to + register such a name in a new namespace and then immediately donate + control of that account to the BA, because that would help the project + maintain its identity. + + * **Do not restrict contributors.** If your company requires + employees or contractors to sign non-compete agreements, those + agreements must not prevent people from participating in the BA or + contributing to related projects. + + This does not mean that all non-compete agreements are incompatible + with this code of conduct. For example, a company may restrict an + employee's ability to solicit the company's customers. However, an + agreement must not block any form of technical or social + participation in BA activities, including but not limited to the + implementation of particular features. + + The accumulation of experience and expertise in individual persons, + who are ultimately free to direct their energy and attention as + they decide, is one of the most important drivers of progress in + open source projects. A company that limits this freedom may hinder + the success of the BA's efforts. + + * **Do not use patents as offensive weapons.** If any BA participant + prevents the adoption or development of BA technologies by + asserting its patents, that undermines the purpose of the + coalition. The collaboration fostered by the BA cannot include + members who act to undermine its work. + + * **Practice responsible disclosure** for security vulnerabilities. + Use designated, non-public reporting channels to disclose technical + vulnerabilities, and give the project a reasonable period to + respond, remediate, and patch. + + Vulnerability reporters may patch their company's own offerings, as + long as that patching does not significantly delay the reporting of + the vulnerability. Vulnerability information should never be used + for unilateral commercial advantage. Vendors may legitimately + compete on the speed and reliability with which they deploy + security fixes, but withholding vulnerability information damages + everyone in the long run by risking harm to the BA project's + reputation and to the security of all users. + + * **Respect the letter and spirit of open source practice.** While + there is not space to list here all possible aspects of standard + open source practice, some examples will help show what we mean: + + * Abide by all applicable open source license terms. Do not engage + in copyright violation or misattribution of any kind. + + * Do not claim others' ideas or designs as your own. + + * When others engage in publicly visible work (e.g., an upcoming + demo that is coordinated in a public issue tracker), do not + unilaterally announce early releases or early demonstrations of + that work ahead of their schedule in order to secure private + advantage (such as marketplace advantage) for yourself. + + The BA reserves the right to determine what constitutes good open + source practices and to take action as it deems appropriate to + encourage, and if necessary enforce, such practices. + +## Enforcement + +Instances of organizational behavior in violation of the OCoC may +be reported by contacting the Bytecode Alliance CoC team at +[report@bytecodealliance.org](mailto:report@bytecodealliance.org). The +CoC team will review and investigate all complaints, and will respond +in a way that it deems appropriate to the circumstances. The CoC team +is obligated to maintain confidentiality with regard to the reporter of +an incident. Further details of specific enforcement policies may be +posted separately. + +When the BA deems an organization in violation of this OCoC, the BA +will, at its sole discretion, determine what action to take. The BA +will decide what type, degree, and duration of corrective action is +needed, if any, before a violating organization can be considered for +membership (if it was not already a member) or can have its membership +reinstated (if it was a member and the BA canceled its membership due +to the violation). + +In practice, the BA's first approach will be to start a conversation, +with punitive enforcement used only as a last resort. Violations +often turn out to be unintentional and swiftly correctable with all +parties acting in good faith. diff --git a/README.md b/README.md index db9fa0fda..d4c2813c3 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # Lucet   [![Build Status]][travis] +**A [Bytecode Alliance][BA] project** + +[BA]: https://bytecodealliance.org/ [Build Status]: https://travis-ci.org/fastly/lucet.svg?branch=master [travis]: https://travis-ci.org/fastly/lucet From 5684d117f16f0fdf8c32f2d4474e07013b9e1950 Mon Sep 17 00:00:00 2001 From: Katelyn Martin Date: Wed, 20 Nov 2019 13:28:35 -0500 Subject: [PATCH 476/512] read function names from custom name section --- lucetc/src/decls.rs | 39 +++++--- lucetc/src/module.rs | 13 +++ lucetc/tests/wasm.rs | 141 +++++++++++++++++++++++------ lucetc/tests/wasm/names_export.wat | 4 + lucetc/tests/wasm/names_local.wat | 4 + 5 files changed, 157 insertions(+), 44 deletions(-) create mode 100644 lucetc/tests/wasm/names_export.wat create mode 100644 lucetc/tests/wasm/names_local.wat diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index 3a6c4b2fa..337851075 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -117,18 +117,31 @@ impl<'a> ModuleDecls<'a> { for ix in 0..decls.info.functions.len() { let func_index = UniqueFuncIndex::new(ix); + // Get the name for this function from the module names section, if it exists. + // Because names have to be unique, we append the index value (ix) to the name. + fn custom_name_for<'a>( + ix: usize, + func_index: UniqueFuncIndex, + decls: &mut ModuleDecls<'a>, + ) -> Option { + decls + .info + .function_names + .get(&func_index) + .cloned() + .map(|s| format!("{}_{}", s, ix)) + } + fn export_name_for<'a>( func_ix: UniqueFuncIndex, decls: &mut ModuleDecls<'a>, ) -> Option { let export = decls.info.functions.get(func_ix).unwrap(); - if !export.export_names.is_empty() { decls.exports.push(ExportFunction { fn_idx: LucetFunctionIndex::from_u32(decls.function_names.len() as u32), names: export.export_names.clone(), }); - Some(format!("guest_func_{}", export.export_names[0])) } else { None @@ -155,32 +168,33 @@ impl<'a> ModuleDecls<'a> { } }; + let custom_info = custom_name_for(ix, func_index, decls); let import_info = import_name_for(func_index, decls, bindings)?; let export_info = export_name_for(func_index, decls); + // We don't match on `custom_info` because export and import info are needed to + // determine the linkage type, and because we use different values as a fallback for + // exported functions and local functions. match (import_info, export_info) { (Some(import_sym), _) => { // if a function is only an import, declare the corresponding artifact import. // if a function is an export and import, it will not have a real function body // in this program, and we must not declare it with Linkage::Export (there will // never be a define to satisfy the symbol!) - decls.declare_function(clif_module, import_sym, Linkage::Import, func_index)?; } (None, Some(export_sym)) => { // This is a function that is only exported, so there will be a body in this // artifact. We can declare the export. + let export_sym = custom_info.unwrap_or(export_sym); decls.declare_function(clif_module, export_sym, Linkage::Export, func_index)?; } (None, None) => { - // No import or export for this function. It's local, and we have to make up a - // name. - decls.declare_function( - clif_module, - format!("guest_func_{}", ix), - Linkage::Local, - func_index, - )?; + // No import or export for this function, which means that it is local. We can + // look for a name provided in the custom names section, otherwise we have to + // make up a placeholder name for it using its index. + let local_sym = custom_info.unwrap_or_else(|| format!("guest_func_{}", ix)); + decls.declare_function(clif_module, local_sym, Linkage::Local, func_index)?; } } } @@ -524,9 +538,6 @@ impl<'a> ModuleDecls<'a> { functions.push(FunctionMetadata { signature: decl.signature_index, - // TODO: this is a best-effort attempt to figure out a useful name. - // in the future, we should use names from the module names section - // and maybe use export names as a fallback. name: Some(name.symbol()), }); } diff --git a/lucetc/src/module.rs b/lucetc/src/module.rs index 982c53290..93da10248 100644 --- a/lucetc/src/module.rs +++ b/lucetc/src/module.rs @@ -72,6 +72,8 @@ pub struct ModuleInfo<'a> { pub function_mapping: PrimaryMap, /// Function signatures: imported and local pub functions: PrimaryMap>, + /// Function names. + pub function_names: HashMap, /// Provided by `declare_table` pub tables: PrimaryMap>, /// Provided by `declare_memory` @@ -103,6 +105,7 @@ impl<'a> ModuleInfo<'a> { imported_memories: PrimaryMap::new(), function_mapping: PrimaryMap::new(), functions: PrimaryMap::new(), + function_names: HashMap::new(), tables: PrimaryMap::new(), memories: PrimaryMap::new(), globals: PrimaryMap::new(), @@ -401,4 +404,14 @@ impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { } Ok(()) } + + fn declare_func_name(&mut self, func_index: FuncIndex, name: &'a str) -> WasmResult<()> { + let unique_func_index = *self + .function_mapping + .get(func_index) + .expect("function indices are valid"); + self.function_names + .insert(unique_func_index, name.to_owned()); + Ok(()) + } } diff --git a/lucetc/tests/wasm.rs b/lucetc/tests/wasm.rs index 08579b265..b6a54d1bb 100644 --- a/lucetc/tests/wasm.rs +++ b/lucetc/tests/wasm.rs @@ -2,15 +2,35 @@ use lucet_module::bindings::Bindings; use std::collections::HashMap; use std::path::PathBuf; -pub fn load_wat_module(name: &str) -> Vec { +struct LoadOptions { + write_debug_names: bool, +} + +impl Default for LoadOptions { + fn default() -> Self { + LoadOptions { + write_debug_names: false, + } + } +} + +fn load_wat_module(name: &str, options: LoadOptions) -> Vec { use std::fs::File; use std::io::Read; - use wabt::wat2wasm; + use wabt::Wat2Wasm; let watfile = PathBuf::from(&format!("tests/wasm/{}.wat", name)); let mut contents = Vec::new(); let mut file = File::open(&watfile).expect("open module file"); file.read_to_end(&mut contents).expect("read module file"); - wat2wasm(contents).expect("convert module to wasm binary format") + let mut wat2wasm = Wat2Wasm::new(); + if options.write_debug_names { + wat2wasm.write_debug_names(true); + } + wat2wasm + .convert(contents) + .expect("convert module to wasm binary format") + .as_ref() + .to_owned() } pub fn test_bindings() -> Bindings { @@ -32,14 +52,14 @@ pub fn test_bindings() -> Bindings { mod module_data { /// Tests of the `ModuleData` generated by the lucetc Compiler - use super::load_wat_module; + use super::{load_wat_module, LoadOptions}; use lucet_module::bindings::Bindings; use lucetc::{Compiler, CpuFeatures, HeapSettings, LucetcErrorKind, OptLevel}; use std::path::PathBuf; #[test] fn exported_import() { - let m = load_wat_module("exported_import"); + let m = load_wat_module("exported_import", LoadOptions::default()); let b = super::test_bindings(); let h = HeapSettings::default(); let c = Compiler::new( @@ -67,7 +87,7 @@ mod module_data { #[test] fn multiple_import() { - let m = load_wat_module("multiple_import"); + let m = load_wat_module("multiple_import", LoadOptions::default()); let b = super::test_bindings(); let h = HeapSettings::default(); let c = Compiler::new( @@ -91,7 +111,7 @@ mod module_data { #[test] fn globals_export() { - let m = load_wat_module("globals_export"); + let m = load_wat_module("globals_export", LoadOptions::default()); let b = super::test_bindings(); let h = HeapSettings::default(); let c = Compiler::new( @@ -116,7 +136,7 @@ mod module_data { #[test] fn fibonacci() { - let m = load_wat_module("fibonacci"); + let m = load_wat_module("fibonacci", LoadOptions::default()); let b = super::test_bindings(); let h = HeapSettings::default(); let c = Compiler::new( @@ -139,7 +159,7 @@ mod module_data { #[test] fn arith() { - let m = load_wat_module("arith"); + let m = load_wat_module("arith", LoadOptions::default()); let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new( @@ -162,7 +182,7 @@ mod module_data { #[test] fn duplicate_imports() { - let m = load_wat_module("duplicate_imports"); + let m = load_wat_module("duplicate_imports", LoadOptions::default()); let b = Bindings::from_file(&PathBuf::from( "tests/bindings/duplicate_imports_bindings.json", )) @@ -197,7 +217,7 @@ mod module_data { #[test] fn icall_import() { - let m = load_wat_module("icall_import"); + let m = load_wat_module("icall_import", LoadOptions::default()); let b = Bindings::from_file(&PathBuf::from( "tests/bindings/icall_import_test_bindings.json", )) @@ -245,7 +265,7 @@ mod module_data { #[test] fn icall() { - let m = load_wat_module("icall"); + let m = load_wat_module("icall", LoadOptions::default()); let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new( @@ -279,7 +299,7 @@ mod module_data { #[test] fn icall_sparse() { - let m = load_wat_module("icall_sparse"); + let m = load_wat_module("icall_sparse", LoadOptions::default()); let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new( @@ -326,7 +346,7 @@ mod module_data { #[test] fn globals_import() { use lucet_module::Global as GlobalVariant; - let m = load_wat_module("globals_import"); + let m = load_wat_module("globals_import", LoadOptions::default()); let b = Bindings::empty(); let h = HeapSettings::default(); @@ -357,7 +377,7 @@ mod module_data { #[test] fn heap_spec_import() { use lucet_module::HeapSpec; - let m = load_wat_module("heap_spec_import"); + let m = load_wat_module("heap_spec_import", LoadOptions::default()); let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new( @@ -388,7 +408,7 @@ mod module_data { #[test] fn heap_spec_definition() { use lucet_module::HeapSpec; - let m = load_wat_module("heap_spec_definition"); + let m = load_wat_module("heap_spec_definition", LoadOptions::default()); let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new( @@ -418,7 +438,7 @@ mod module_data { #[test] fn heap_spec_none() { - let m = load_wat_module("heap_spec_none"); + let m = load_wat_module("heap_spec_none", LoadOptions::default()); let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new( @@ -436,7 +456,7 @@ mod module_data { #[test] fn oversize_data_segment() { - let m = load_wat_module("oversize_data_segment"); + let m = load_wat_module("oversize_data_segment", LoadOptions::default()); let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new( @@ -488,7 +508,7 @@ mod module_data { #[test] fn start_section() { - let m = load_wat_module("start_section"); + let m = load_wat_module("start_section", LoadOptions::default()); let b = Bindings::empty(); let h = HeapSettings::default(); let _c = Compiler::new( @@ -508,14 +528,76 @@ mod module_data { ); */ } + + #[test] + fn names_local() { + let m = load_wat_module( + "names_local", + LoadOptions { + write_debug_names: true, + }, + ); + let b = super::test_bindings(); + let h = HeapSettings::default(); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &None, + ) + .expect("compile local_names"); + let mdata = c.module_data().unwrap(); + + assert_eq!(mdata.import_functions().len(), 0); + assert_eq!(mdata.export_functions().len(), 0); + assert_eq!(mdata.function_info().len(), 3); + assert_eq!( + mdata.function_info().get(0).unwrap().name, + Some("func_name_0") + ) + } + + #[test] + fn names_export() { + let m = load_wat_module( + "names_export", + LoadOptions { + write_debug_names: true, + }, + ); + let b = super::test_bindings(); + let h = HeapSettings::default(); + let c = Compiler::new( + &m, + OptLevel::default(), + CpuFeatures::default(), + &b, + h, + false, + &None, + ) + .expect("compile local_names"); + let mdata = c.module_data().unwrap(); + + assert_eq!(mdata.import_functions().len(), 0); + assert_eq!(mdata.export_functions().len(), 1); + assert_eq!(mdata.function_info().len(), 3); + assert_eq!( + mdata.function_info().get(0).unwrap().name, + Some("func_name_0") + ) + } } mod compile { // Tests for compilation completion - use super::load_wat_module; + use super::{load_wat_module, LoadOptions}; use lucetc::{Compiler, CpuFeatures, HeapSettings, OptLevel}; fn run_compile_test(file: &str) { - let m = load_wat_module(file); + let m = load_wat_module(file, LoadOptions::default()); let b = super::test_bindings(); let h = HeapSettings::default(); let c = Compiler::new( @@ -561,14 +643,13 @@ mod compile { } mod validate { - - use super::load_wat_module; + use super::{load_wat_module, LoadOptions}; use lucet_validate::Validator; use lucetc::{Compiler, CpuFeatures, HeapSettings, OptLevel}; #[test] fn validate_arith() { - let m = load_wat_module("arith"); + let m = load_wat_module("arith", LoadOptions::default()); let b = super::test_bindings(); let h = HeapSettings::default(); @@ -592,7 +673,7 @@ mod validate { #[test] fn validate_import() { - let m = load_wat_module("import"); + let m = load_wat_module("import", LoadOptions::default()); let b = super::test_bindings(); let h = HeapSettings::default(); @@ -619,7 +700,7 @@ mod validate { #[test] fn validate_icall_import() { - let m = load_wat_module("icall_import"); + let m = load_wat_module("icall_import", LoadOptions::default()); let b = super::test_bindings(); let h = HeapSettings::default(); @@ -648,7 +729,7 @@ mod validate { #[test] fn validate_exported_import() { - let m = load_wat_module("exported_import"); + let m = load_wat_module("exported_import", LoadOptions::default()); let b = super::test_bindings(); let h = HeapSettings::default(); @@ -675,7 +756,7 @@ mod validate { #[test] fn validate_multiple_import() { - let m = load_wat_module("multiple_import"); + let m = load_wat_module("multiple_import", LoadOptions::default()); let b = super::test_bindings(); let h = HeapSettings::default(); @@ -702,7 +783,7 @@ mod validate { #[test] fn validate_import_many() { - let m = load_wat_module("import_many"); + let m = load_wat_module("import_many", LoadOptions::default()); let b = super::test_bindings(); let h = HeapSettings::default(); @@ -731,7 +812,7 @@ mod validate { #[test] fn validate_wasi_exe() { - let m = load_wat_module("wasi_exe"); + let m = load_wat_module("wasi_exe", LoadOptions::default()); let b = super::test_bindings(); let h = HeapSettings::default(); diff --git a/lucetc/tests/wasm/names_export.wat b/lucetc/tests/wasm/names_export.wat new file mode 100644 index 000000000..6e6e8d0ab --- /dev/null +++ b/lucetc/tests/wasm/names_export.wat @@ -0,0 +1,4 @@ +(module + (func $func_name (export "export_name") + ) +) diff --git a/lucetc/tests/wasm/names_local.wat b/lucetc/tests/wasm/names_local.wat new file mode 100644 index 000000000..69cdddddb --- /dev/null +++ b/lucetc/tests/wasm/names_local.wat @@ -0,0 +1,4 @@ +(module + (func $func_name + ) +) From fa5974115f935695b8685512d0820bbc1436cf99 Mon Sep 17 00:00:00 2001 From: Katelyn Martin Date: Mon, 25 Nov 2019 13:11:11 -0500 Subject: [PATCH 477/512] minor grammar fix in runtime docs --- lucet-runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lucet-runtime/src/lib.rs b/lucet-runtime/src/lib.rs index df5bbc450..49c740c01 100644 --- a/lucet-runtime/src/lib.rs +++ b/lucet-runtime/src/lib.rs @@ -325,7 +325,7 @@ //! //! ## Interaction With Host Signal Handlers //! -//! Great care must be taken if host application installs or otherwise modifies signal handlers +//! Great care must be taken if a host application installs or otherwise modifies signal handlers //! anywhere in the process. Lucet installs handlers for `SIGBUS`, `SIGFPE`, `SIGILL`, and `SIGSEGV` //! when the first Lucet instance begins running, and restores the preëxisting handlers when the //! last Lucet instance terminates. During this time, other threads in the host process *must not* From 5b1b33bbe03e4f0405e6803b86f34309ee0afbe7 Mon Sep 17 00:00:00 2001 From: Katelyn Martin Date: Mon, 25 Nov 2019 16:50:24 -0500 Subject: [PATCH 478/512] specify signature size for module data --- Cargo.lock | 23 +++++++++++++++++++++++ lucet-module/Cargo.toml | 2 ++ lucet-module/src/module_data.rs | 17 +++++++++++++---- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 71f48b8af..25cf58ebb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -503,6 +503,16 @@ dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "derivative" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "digest" version = "0.8.1" @@ -849,6 +859,7 @@ dependencies = [ "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.46.1", + "derivative 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -856,6 +867,7 @@ dependencies = [ "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "object 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde-big-array 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1704,6 +1716,15 @@ dependencies = [ "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde-big-array" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "serde_derive" version = "1.0.102" @@ -2185,6 +2206,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d" "checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" "checksum cvt 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34ac344c7efccb80cd25bc61b2170aec26f2f693fd40e765a539a1243db48c71" +"checksum derivative 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "942ca430eef7a3806595a6737bc388bf51adb888d3fc0dd1b50f1c170167ee3a" "checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" "checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" @@ -2296,6 +2318,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4b39bd9b0b087684013a792c59e3e07a46a01d2322518d8a1104641a0b1be0" +"checksum serde-big-array 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "883eee5198ea51720eab8be52a36cf6c0164ac90eea0ed95b649d5e35382404e" "checksum serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "ca13fc1a832f793322228923fbb3aba9f3f44444898f835d31ad1b74fa0a2bf8" "checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" diff --git a/lucet-module/Cargo.toml b/lucet-module/Cargo.toml index e82095b7b..6b21fd430 100644 --- a/lucet-module/Cargo.toml +++ b/lucet-module/Cargo.toml @@ -21,3 +21,5 @@ minisign = "0.5.11" object = "0.14.0" byteorder = "1.3" memoffset = "0.5.1" +serde-big-array = "0.2.0" +derivative = "1.0.3" diff --git a/lucet-module/src/module_data.rs b/lucet-module/src/module_data.rs index 44f77daab..fa1c3f157 100644 --- a/lucet-module/src/module_data.rs +++ b/lucet-module/src/module_data.rs @@ -7,11 +7,18 @@ use crate::{ types::Signature, Error, }; +use derivative::Derivative; use minisign::SignatureBones; use serde::{Deserialize, Serialize}; +use serde_big_array::big_array; pub const MODULE_DATA_SYM: &str = "lucet_module_data"; +big_array! { + BigArray; + SignatureBones::BYTES, +} + /// The metadata (and some data) for a Lucet module. /// /// The lifetime parameter exists to support zero-copy deserialization for the `&str` and `&[u8]` @@ -20,7 +27,8 @@ pub const MODULE_DATA_SYM: &str = "lucet_module_data"; /// /// The goal is for this structure to eventually include everything except the code for the guest /// functions themselves. -#[derive(Debug, Serialize, Deserialize)] +#[derive(Derivative, Serialize, Deserialize)] +#[derivative(Debug)] pub struct ModuleData<'a> { #[serde(borrow)] linear_memory: Option>, @@ -33,7 +41,9 @@ pub struct ModuleData<'a> { #[serde(borrow)] export_functions: Vec>, signatures: Vec, - module_signature: Vec, + #[serde(with = "BigArray")] + #[derivative(Debug = "ignore")] + module_signature: [u8; SignatureBones::BYTES], features: ModuleFeatures, } @@ -78,7 +88,6 @@ impl<'a> ModuleData<'a> { signatures: Vec, features: ModuleFeatures, ) -> Self { - let module_signature = vec![0u8; SignatureBones::BYTES]; Self { linear_memory, globals_spec, @@ -86,7 +95,7 @@ impl<'a> ModuleData<'a> { import_functions, export_functions, signatures, - module_signature, + module_signature: [0u8; SignatureBones::BYTES], features, } } From 380d0e4c6df58163cc90240f909c1d1e85a4bb24 Mon Sep 17 00:00:00 2001 From: Katelyn Martin Date: Mon, 25 Nov 2019 23:22:41 -0500 Subject: [PATCH 479/512] pr review: use exported names --- lucetc/src/decls.rs | 1 - lucetc/tests/wasm.rs | 113 ++++++++--------------------- lucetc/tests/wasm/names_export.wat | 4 - 3 files changed, 31 insertions(+), 87 deletions(-) delete mode 100644 lucetc/tests/wasm/names_export.wat diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index 337851075..9dfa53cc6 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -186,7 +186,6 @@ impl<'a> ModuleDecls<'a> { (None, Some(export_sym)) => { // This is a function that is only exported, so there will be a body in this // artifact. We can declare the export. - let export_sym = custom_info.unwrap_or(export_sym); decls.declare_function(clif_module, export_sym, Linkage::Export, func_index)?; } (None, None) => { diff --git a/lucetc/tests/wasm.rs b/lucetc/tests/wasm.rs index b6a54d1bb..0ff68bdfa 100644 --- a/lucetc/tests/wasm.rs +++ b/lucetc/tests/wasm.rs @@ -2,19 +2,7 @@ use lucet_module::bindings::Bindings; use std::collections::HashMap; use std::path::PathBuf; -struct LoadOptions { - write_debug_names: bool, -} - -impl Default for LoadOptions { - fn default() -> Self { - LoadOptions { - write_debug_names: false, - } - } -} - -fn load_wat_module(name: &str, options: LoadOptions) -> Vec { +fn load_wat_module(name: &str) -> Vec { use std::fs::File; use std::io::Read; use wabt::Wat2Wasm; @@ -22,11 +10,8 @@ fn load_wat_module(name: &str, options: LoadOptions) -> Vec { let mut contents = Vec::new(); let mut file = File::open(&watfile).expect("open module file"); file.read_to_end(&mut contents).expect("read module file"); - let mut wat2wasm = Wat2Wasm::new(); - if options.write_debug_names { - wat2wasm.write_debug_names(true); - } - wat2wasm + Wat2Wasm::new() + .write_debug_names(true) .convert(contents) .expect("convert module to wasm binary format") .as_ref() @@ -52,14 +37,14 @@ pub fn test_bindings() -> Bindings { mod module_data { /// Tests of the `ModuleData` generated by the lucetc Compiler - use super::{load_wat_module, LoadOptions}; + use super::load_wat_module; use lucet_module::bindings::Bindings; use lucetc::{Compiler, CpuFeatures, HeapSettings, LucetcErrorKind, OptLevel}; use std::path::PathBuf; #[test] fn exported_import() { - let m = load_wat_module("exported_import", LoadOptions::default()); + let m = load_wat_module("exported_import"); let b = super::test_bindings(); let h = HeapSettings::default(); let c = Compiler::new( @@ -87,7 +72,7 @@ mod module_data { #[test] fn multiple_import() { - let m = load_wat_module("multiple_import", LoadOptions::default()); + let m = load_wat_module("multiple_import"); let b = super::test_bindings(); let h = HeapSettings::default(); let c = Compiler::new( @@ -111,7 +96,7 @@ mod module_data { #[test] fn globals_export() { - let m = load_wat_module("globals_export", LoadOptions::default()); + let m = load_wat_module("globals_export"); let b = super::test_bindings(); let h = HeapSettings::default(); let c = Compiler::new( @@ -136,7 +121,7 @@ mod module_data { #[test] fn fibonacci() { - let m = load_wat_module("fibonacci", LoadOptions::default()); + let m = load_wat_module("fibonacci"); let b = super::test_bindings(); let h = HeapSettings::default(); let c = Compiler::new( @@ -159,7 +144,7 @@ mod module_data { #[test] fn arith() { - let m = load_wat_module("arith", LoadOptions::default()); + let m = load_wat_module("arith"); let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new( @@ -182,7 +167,7 @@ mod module_data { #[test] fn duplicate_imports() { - let m = load_wat_module("duplicate_imports", LoadOptions::default()); + let m = load_wat_module("duplicate_imports"); let b = Bindings::from_file(&PathBuf::from( "tests/bindings/duplicate_imports_bindings.json", )) @@ -217,7 +202,7 @@ mod module_data { #[test] fn icall_import() { - let m = load_wat_module("icall_import", LoadOptions::default()); + let m = load_wat_module("icall_import"); let b = Bindings::from_file(&PathBuf::from( "tests/bindings/icall_import_test_bindings.json", )) @@ -265,7 +250,7 @@ mod module_data { #[test] fn icall() { - let m = load_wat_module("icall", LoadOptions::default()); + let m = load_wat_module("icall"); let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new( @@ -299,7 +284,7 @@ mod module_data { #[test] fn icall_sparse() { - let m = load_wat_module("icall_sparse", LoadOptions::default()); + let m = load_wat_module("icall_sparse"); let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new( @@ -346,7 +331,7 @@ mod module_data { #[test] fn globals_import() { use lucet_module::Global as GlobalVariant; - let m = load_wat_module("globals_import", LoadOptions::default()); + let m = load_wat_module("globals_import"); let b = Bindings::empty(); let h = HeapSettings::default(); @@ -377,7 +362,7 @@ mod module_data { #[test] fn heap_spec_import() { use lucet_module::HeapSpec; - let m = load_wat_module("heap_spec_import", LoadOptions::default()); + let m = load_wat_module("heap_spec_import"); let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new( @@ -408,7 +393,7 @@ mod module_data { #[test] fn heap_spec_definition() { use lucet_module::HeapSpec; - let m = load_wat_module("heap_spec_definition", LoadOptions::default()); + let m = load_wat_module("heap_spec_definition"); let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new( @@ -438,7 +423,7 @@ mod module_data { #[test] fn heap_spec_none() { - let m = load_wat_module("heap_spec_none", LoadOptions::default()); + let m = load_wat_module("heap_spec_none"); let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new( @@ -456,7 +441,7 @@ mod module_data { #[test] fn oversize_data_segment() { - let m = load_wat_module("oversize_data_segment", LoadOptions::default()); + let m = load_wat_module("oversize_data_segment"); let b = Bindings::empty(); let h = HeapSettings::default(); let c = Compiler::new( @@ -508,7 +493,7 @@ mod module_data { #[test] fn start_section() { - let m = load_wat_module("start_section", LoadOptions::default()); + let m = load_wat_module("start_section"); let b = Bindings::empty(); let h = HeapSettings::default(); let _c = Compiler::new( @@ -531,12 +516,7 @@ mod module_data { #[test] fn names_local() { - let m = load_wat_module( - "names_local", - LoadOptions { - write_debug_names: true, - }, - ); + let m = load_wat_module("names_local"); let b = super::test_bindings(); let h = HeapSettings::default(); let c = Compiler::new( @@ -548,7 +528,7 @@ mod module_data { false, &None, ) - .expect("compile local_names"); + .expect("compile names_local"); let mdata = c.module_data().unwrap(); assert_eq!(mdata.import_functions().len(), 0); @@ -559,45 +539,14 @@ mod module_data { Some("func_name_0") ) } - - #[test] - fn names_export() { - let m = load_wat_module( - "names_export", - LoadOptions { - write_debug_names: true, - }, - ); - let b = super::test_bindings(); - let h = HeapSettings::default(); - let c = Compiler::new( - &m, - OptLevel::default(), - CpuFeatures::default(), - &b, - h, - false, - &None, - ) - .expect("compile local_names"); - let mdata = c.module_data().unwrap(); - - assert_eq!(mdata.import_functions().len(), 0); - assert_eq!(mdata.export_functions().len(), 1); - assert_eq!(mdata.function_info().len(), 3); - assert_eq!( - mdata.function_info().get(0).unwrap().name, - Some("func_name_0") - ) - } } mod compile { // Tests for compilation completion - use super::{load_wat_module, LoadOptions}; + use super::load_wat_module; use lucetc::{Compiler, CpuFeatures, HeapSettings, OptLevel}; fn run_compile_test(file: &str) { - let m = load_wat_module(file, LoadOptions::default()); + let m = load_wat_module(file); let b = super::test_bindings(); let h = HeapSettings::default(); let c = Compiler::new( @@ -643,13 +592,13 @@ mod compile { } mod validate { - use super::{load_wat_module, LoadOptions}; + use super::load_wat_module; use lucet_validate::Validator; use lucetc::{Compiler, CpuFeatures, HeapSettings, OptLevel}; #[test] fn validate_arith() { - let m = load_wat_module("arith", LoadOptions::default()); + let m = load_wat_module("arith"); let b = super::test_bindings(); let h = HeapSettings::default(); @@ -673,7 +622,7 @@ mod validate { #[test] fn validate_import() { - let m = load_wat_module("import", LoadOptions::default()); + let m = load_wat_module("import"); let b = super::test_bindings(); let h = HeapSettings::default(); @@ -700,7 +649,7 @@ mod validate { #[test] fn validate_icall_import() { - let m = load_wat_module("icall_import", LoadOptions::default()); + let m = load_wat_module("icall_import"); let b = super::test_bindings(); let h = HeapSettings::default(); @@ -729,7 +678,7 @@ mod validate { #[test] fn validate_exported_import() { - let m = load_wat_module("exported_import", LoadOptions::default()); + let m = load_wat_module("exported_import"); let b = super::test_bindings(); let h = HeapSettings::default(); @@ -756,7 +705,7 @@ mod validate { #[test] fn validate_multiple_import() { - let m = load_wat_module("multiple_import", LoadOptions::default()); + let m = load_wat_module("multiple_import"); let b = super::test_bindings(); let h = HeapSettings::default(); @@ -783,7 +732,7 @@ mod validate { #[test] fn validate_import_many() { - let m = load_wat_module("import_many", LoadOptions::default()); + let m = load_wat_module("import_many"); let b = super::test_bindings(); let h = HeapSettings::default(); @@ -812,7 +761,7 @@ mod validate { #[test] fn validate_wasi_exe() { - let m = load_wat_module("wasi_exe", LoadOptions::default()); + let m = load_wat_module("wasi_exe"); let b = super::test_bindings(); let h = HeapSettings::default(); diff --git a/lucetc/tests/wasm/names_export.wat b/lucetc/tests/wasm/names_export.wat deleted file mode 100644 index 6e6e8d0ab..000000000 --- a/lucetc/tests/wasm/names_export.wat +++ /dev/null @@ -1,4 +0,0 @@ -(module - (func $func_name (export "export_name") - ) -) From 5298634ca8316b005fbe639e75a420055308a56e Mon Sep 17 00:00:00 2001 From: Katelyn Martin Date: Mon, 25 Nov 2019 23:46:34 -0500 Subject: [PATCH 480/512] pr review: use SecondaryMap for names --- lucetc/src/decls.rs | 10 +++------- lucetc/src/module.rs | 9 ++++----- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index 9dfa53cc6..d2256aebc 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -127,8 +127,7 @@ impl<'a> ModuleDecls<'a> { decls .info .function_names - .get(&func_index) - .cloned() + .get(func_index) .map(|s| format!("{}_{}", s, ix)) } @@ -168,13 +167,9 @@ impl<'a> ModuleDecls<'a> { } }; - let custom_info = custom_name_for(ix, func_index, decls); let import_info = import_name_for(func_index, decls, bindings)?; let export_info = export_name_for(func_index, decls); - // We don't match on `custom_info` because export and import info are needed to - // determine the linkage type, and because we use different values as a fallback for - // exported functions and local functions. match (import_info, export_info) { (Some(import_sym), _) => { // if a function is only an import, declare the corresponding artifact import. @@ -192,7 +187,8 @@ impl<'a> ModuleDecls<'a> { // No import or export for this function, which means that it is local. We can // look for a name provided in the custom names section, otherwise we have to // make up a placeholder name for it using its index. - let local_sym = custom_info.unwrap_or_else(|| format!("guest_func_{}", ix)); + let local_sym = custom_name_for(ix, func_index, decls) + .unwrap_or_else(|| format!("guest_func_{}", ix)); decls.declare_function(clif_module, local_sym, Linkage::Local, func_index)?; } } diff --git a/lucetc/src/module.rs b/lucetc/src/module.rs index 93da10248..0fb1bd30f 100644 --- a/lucetc/src/module.rs +++ b/lucetc/src/module.rs @@ -1,7 +1,7 @@ //! Implements ModuleEnvironment for cranelift-wasm. Code derived from cranelift-wasm/environ/dummy.rs use crate::error::{LucetcError, LucetcErrorKind}; use crate::pointer::NATIVE_POINTER; -use cranelift_codegen::entity::{entity_impl, EntityRef, PrimaryMap}; +use cranelift_codegen::entity::{entity_impl, EntityRef, PrimaryMap, SecondaryMap}; use cranelift_codegen::ir; use cranelift_codegen::isa::TargetFrontendConfig; use cranelift_wasm::{ @@ -73,7 +73,7 @@ pub struct ModuleInfo<'a> { /// Function signatures: imported and local pub functions: PrimaryMap>, /// Function names. - pub function_names: HashMap, + pub function_names: SecondaryMap, /// Provided by `declare_table` pub tables: PrimaryMap>, /// Provided by `declare_memory` @@ -105,7 +105,7 @@ impl<'a> ModuleInfo<'a> { imported_memories: PrimaryMap::new(), function_mapping: PrimaryMap::new(), functions: PrimaryMap::new(), - function_names: HashMap::new(), + function_names: SecondaryMap::new(), tables: PrimaryMap::new(), memories: PrimaryMap::new(), globals: PrimaryMap::new(), @@ -410,8 +410,7 @@ impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> { .function_mapping .get(func_index) .expect("function indices are valid"); - self.function_names - .insert(unique_func_index, name.to_owned()); + self.function_names[unique_func_index] = name; Ok(()) } } From 1c149f3016ad6ac96e0eeecac5d2606981eecab8 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 26 Nov 2019 09:49:36 -0800 Subject: [PATCH 481/512] delete lucet-idl. superceded by witx --- Cargo.lock | 108 -- Cargo.toml | 3 - Makefile | 2 - lucet-idl/.gitignore | 1 - lucet-idl/Cargo.lock | 257 ---- lucet-idl/Cargo.toml | 29 - lucet-idl/LICENSE | 220 --- lucet-idl/TODO.md | 13 - lucet-idl/lucet-idl-test/.gitignore | 1 - lucet-idl/lucet-idl-test/Cargo.toml | 27 - .../resources/rust_host/.gitignore | 1 - .../resources/rust_host/Cargo.toml | 17 - .../resources/rust_host/src/harness.rs | 6 - .../resources/rust_host/src/idl.rs | 3 - .../resources/rust_host/src/main.rs | 22 - .../resources/rust_host/src/run.rs | 43 - lucet-idl/lucet-idl-test/src/c_guest.rs | 66 - lucet-idl/lucet-idl-test/src/host.rs | 114 -- lucet-idl/lucet-idl-test/src/lib.rs | 60 - lucet-idl/lucet-idl-test/src/main.rs | 191 --- lucet-idl/lucet-idl-test/src/rust_guest.rs | 80 -- lucet-idl/lucet-idl-test/src/syntax.rs | 419 ------ lucet-idl/lucet-idl-test/src/test_plan.rs | 210 --- lucet-idl/lucet-idl-test/src/values.rs | 391 ------ lucet-idl/lucet-idl-test/src/workspace.rs | 24 - lucet-idl/src/atoms.rs | 151 --- lucet-idl/src/c.rs | 335 ----- lucet-idl/src/config.rs | 47 - lucet-idl/src/cursor.rs | 628 --------- lucet-idl/src/error.rs | 76 -- lucet-idl/src/lexer.rs | 342 ----- lucet-idl/src/lib.rs | 95 -- lucet-idl/src/main.rs | 79 -- lucet-idl/src/parser.rs | 1201 ----------------- lucet-idl/src/prelude.rs | 122 -- lucet-idl/src/pretty_writer.rs | 104 -- lucet-idl/src/repr.rs | 173 --- lucet-idl/src/rust.rs | 491 ------- lucet-idl/src/rust/cursor.rs | 463 ------- lucet-idl/src/validate/datatypes.rs | 420 ------ lucet-idl/src/validate/function.rs | 417 ------ lucet-idl/src/validate/mod.rs | 7 - lucet-idl/src/validate/module.rs | 655 --------- lucet-idl/src/validate/names.rs | 112 -- lucet-idl/src/validate/package.rs | 152 --- lucet-idl/tests/example.idl | 55 - lucet-idl/tests/example.rs | 87 -- lucet-idl/tests/example_driver.c | 34 - 48 files changed, 8554 deletions(-) delete mode 100644 lucet-idl/.gitignore delete mode 100644 lucet-idl/Cargo.lock delete mode 100644 lucet-idl/Cargo.toml delete mode 100644 lucet-idl/LICENSE delete mode 100644 lucet-idl/TODO.md delete mode 100644 lucet-idl/lucet-idl-test/.gitignore delete mode 100644 lucet-idl/lucet-idl-test/Cargo.toml delete mode 100644 lucet-idl/lucet-idl-test/resources/rust_host/.gitignore delete mode 100644 lucet-idl/lucet-idl-test/resources/rust_host/Cargo.toml delete mode 100644 lucet-idl/lucet-idl-test/resources/rust_host/src/harness.rs delete mode 100644 lucet-idl/lucet-idl-test/resources/rust_host/src/idl.rs delete mode 100644 lucet-idl/lucet-idl-test/resources/rust_host/src/main.rs delete mode 100644 lucet-idl/lucet-idl-test/resources/rust_host/src/run.rs delete mode 100644 lucet-idl/lucet-idl-test/src/c_guest.rs delete mode 100644 lucet-idl/lucet-idl-test/src/host.rs delete mode 100644 lucet-idl/lucet-idl-test/src/lib.rs delete mode 100644 lucet-idl/lucet-idl-test/src/main.rs delete mode 100644 lucet-idl/lucet-idl-test/src/rust_guest.rs delete mode 100644 lucet-idl/lucet-idl-test/src/syntax.rs delete mode 100644 lucet-idl/lucet-idl-test/src/test_plan.rs delete mode 100644 lucet-idl/lucet-idl-test/src/values.rs delete mode 100644 lucet-idl/lucet-idl-test/src/workspace.rs delete mode 100644 lucet-idl/src/atoms.rs delete mode 100644 lucet-idl/src/c.rs delete mode 100644 lucet-idl/src/config.rs delete mode 100644 lucet-idl/src/cursor.rs delete mode 100644 lucet-idl/src/error.rs delete mode 100644 lucet-idl/src/lexer.rs delete mode 100644 lucet-idl/src/lib.rs delete mode 100644 lucet-idl/src/main.rs delete mode 100644 lucet-idl/src/parser.rs delete mode 100644 lucet-idl/src/prelude.rs delete mode 100644 lucet-idl/src/pretty_writer.rs delete mode 100644 lucet-idl/src/repr.rs delete mode 100644 lucet-idl/src/rust.rs delete mode 100644 lucet-idl/src/rust/cursor.rs delete mode 100644 lucet-idl/src/validate/datatypes.rs delete mode 100644 lucet-idl/src/validate/function.rs delete mode 100644 lucet-idl/src/validate/mod.rs delete mode 100644 lucet-idl/src/validate/module.rs delete mode 100644 lucet-idl/src/validate/names.rs delete mode 100644 lucet-idl/src/validate/package.rs delete mode 100644 lucet-idl/tests/example.idl delete mode 100644 lucet-idl/tests/example.rs delete mode 100644 lucet-idl/tests/example_driver.c diff --git a/Cargo.lock b/Cargo.lock index 25cf58ebb..a44f0724f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -121,19 +121,6 @@ dependencies = [ "which 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "bit-set" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bit-vec" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "bitflags" version = "0.7.0" @@ -618,20 +605,6 @@ dependencies = [ "miniz_oxide 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "fnv" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fs2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -807,51 +780,6 @@ dependencies = [ "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "lucet-idl" -version = "0.2.0" -dependencies = [ - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-entity 0.46.1", - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.1", - "lucetc 0.4.1", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lucet-idl-test" -version = "0.1.0" -dependencies = [ - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-idl 0.2.0", - "lucet-runtime 0.4.1", - "lucet-wasi 0.4.1", - "lucet-wasi-sdk 0.4.1", - "lucetc 0.4.1", - "proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lucet-idl-test-rust-host" -version = "0.1.0" -dependencies = [ - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-idl 0.2.0", - "lucet-runtime 0.4.1", - "lucet-wasi 0.4.1", -] - [[package]] name = "lucet-module" version = "0.4.1" @@ -1320,25 +1248,6 @@ dependencies = [ "terminal_size 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "proptest" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "rusty-fork 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "quick-error" version = "1.2.2" @@ -1635,17 +1544,6 @@ dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rusty-fork" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "ryu" version = "1.0.2" @@ -2173,8 +2071,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "505e45beaf0a1462f5548fe885edf2d83e62022b2ce8b10fef0f7686b48c9266" "checksum bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ab639324e3ee8774d296864fbc0dbbb256cf1a41c490b94cba90c082915f92" "checksum bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebd71393f1ec0509b553aa012b9b58e81dadbdff7130bd3b8cba576e69b32f75" -"checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80" -"checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" @@ -2218,8 +2114,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd7380b54ced79dda72ecc35cc4fbbd1da6bba54afaa37e96fd1c2a308cd469" "checksum flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ad3c5233c9a940c8719031b423d7e6c16af66e031cb0420b0896f5245bf181d3" -"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" -"checksum fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" @@ -2273,7 +2167,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" "checksum progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b820305721858696053a7fd0215cfeeee16ecaaf96b7a209945428e02f1c44" -"checksum proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf147e022eacf0c8a054ab864914a7602618adba841d800a9a9868a5237a529f" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" @@ -2308,7 +2201,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum rusty-fork 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd93264e10c577503e926bd1430193eeb5d21b059148910082245309b424fae" "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" "checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" diff --git a/Cargo.toml b/Cargo.toml index 7d5b8860c..9ae83d2c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,9 +3,6 @@ [workspace] members = [ "benchmarks/lucet-benchmarks", - "lucet-idl", - "lucet-idl/lucet-idl-test", - "lucet-idl/lucet-idl-test/resources/rust_host", "lucet-module", "lucet-objdump", "lucet-runtime", diff --git a/Makefile b/Makefile index 2ed2a6172..96d3ba657 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,6 @@ test-except-fuzz: -p lucet-runtime \ -p lucet-module \ -p lucetc \ - -p lucet-idl \ -p lucet-wasi-sdk \ -p lucet-wasi \ -p lucet-wasi-fuzz \ @@ -80,7 +79,6 @@ watch: -p lucet-runtime \ -p lucet-module \ -p lucetc \ - -p lucet-idl \ -p lucet-wasi-sdk \ -p lucet-wasi \ -p lucet-benchmarks \ diff --git a/lucet-idl/.gitignore b/lucet-idl/.gitignore deleted file mode 100644 index eb5a316cb..000000000 --- a/lucet-idl/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target diff --git a/lucet-idl/Cargo.lock b/lucet-idl/Cargo.lock deleted file mode 100644 index 309a2bce5..000000000 --- a/lucet-idl/Cargo.lock +++ /dev/null @@ -1,257 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "ansi_term" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "atty" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "autocfg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "backtrace" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "backtrace-sys" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bitflags" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cc" -version = "1.0.31" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cfg-if" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "clap" -version = "2.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "failure" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "failure_derive" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libc" -version = "0.2.50" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "lucet-idl" -version = "0.1.0" -dependencies = [ - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro2" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "quote" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "redox_syscall" -version = "0.1.51" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "redox_termios" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "strsim" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "syn" -version = "0.15.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "synstructure" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "termion" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "textwrap" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-width" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "vec_map" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "xfailure" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" -"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" -"checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4" -"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" -"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" -"checksum cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ce8bb087aacff865633f0bd5aeaed910fe2fe55b55f4739527f2e023a2e53d" -"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" -"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" -"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" -"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" -"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1" -"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" -"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" -"checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" -"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" -"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" -"checksum syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1825685f977249735d510a242a6727b46efe914bb67e38d30c071b1b72b1d5c2" -"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" -"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" -"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" -"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da90eac47bf1d7871b75004b9b631d107df15f37669383b23f0b5297bc7516b6" diff --git a/lucet-idl/Cargo.toml b/lucet-idl/Cargo.toml deleted file mode 100644 index 01359c88f..000000000 --- a/lucet-idl/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "lucet-idl" -version = "0.2.0" -description = "Describe interfaces between WebAssembly guest programs and lucet-runtime hosts" -homepage = "https://github.com/fastly/lucet" -repository = "https://github.com/fastly/lucet" -license = "Apache-2.0 WITH LLVM-exception" -categories = ["wasm"] -authors = ["Lucet team "] -edition = "2018" - -[lib] -crate-type=["rlib"] - -[[bin]] -name = "lucet-idl" -path = "src/main.rs" - -[dependencies] -clap = "2" -failure = "0.1" -xfailure = "0.1" -heck = "0.3" -lucetc = { path = "../lucetc" } -lucet-module = { path = "../lucet-module" } -cranelift-entity = { path = "../cranelift/cranelift-entity" } - -[dev-dependencies] -tempfile = "3.0" diff --git a/lucet-idl/LICENSE b/lucet-idl/LICENSE deleted file mode 100644 index f9d81955f..000000000 --- a/lucet-idl/LICENSE +++ /dev/null @@ -1,220 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - ---- LLVM Exceptions to the Apache 2.0 License ---- - -As an exception, if, as a result of your compiling your source code, portions -of this Software are embedded into an Object form of such source code, you -may redistribute such embedded portions in such Object form without complying -with the conditions of Sections 4(a), 4(b) and 4(d) of the License. - -In addition, if you combine or link compiled forms of this Software with -software that is licensed under the GPLv2 ("Combined Software") and if a -court of competent jurisdiction determines that the patent provision (Section -3), the indemnity provision (Section 9) or other Section of the License -conflicts with the conditions of the GPLv2, you may retroactively and -prospectively choose to deem waived or otherwise exclude such Section(s) of -the License, but only in their entirety and only with respect to the Combined -Software. - diff --git a/lucet-idl/TODO.md b/lucet-idl/TODO.md deleted file mode 100644 index 9334a8c1d..000000000 --- a/lucet-idl/TODO.md +++ /dev/null @@ -1,13 +0,0 @@ -* idl-test generates arbitrary values for a given type - * generate rust literals - * generate C literals -* describe ABI of functions: - * annotations to arguments saying whether they are in, out, or inout - * non-atomic arguments need to be passed by reference, cannot be return values -* idl package generates funcs that take a byte array (linear memory) and offset - and validate whether it is a valid repr of a type - * pointer, length validation - * enum variants - * bools -* add byte slices to language. - * hold off on other types of slices for now diff --git a/lucet-idl/lucet-idl-test/.gitignore b/lucet-idl/lucet-idl-test/.gitignore deleted file mode 100644 index 402fd5d87..000000000 --- a/lucet-idl/lucet-idl-test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -proptest-regressions diff --git a/lucet-idl/lucet-idl-test/Cargo.toml b/lucet-idl/lucet-idl-test/Cargo.toml deleted file mode 100644 index 8df1ce874..000000000 --- a/lucet-idl/lucet-idl-test/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "lucet-idl-test" -version = "0.1.0" -authors = ["Pat Hickey "] -edition = "2018" - -[lib] -crate-type=["rlib"] - -[[bin]] -name = "lucet-idl-test" -path = "src/main.rs" - -[dependencies] -lucet-idl = { path = "../" } -lucetc = { path = "../../lucetc" } -lucet-runtime = { path = "../../lucet-runtime" } -lucet-wasi = { path = "../../lucet-wasi" } -lucet-wasi-sdk = { path = "../../lucet-wasi-sdk" } -proptest = "0.9.4" -tempfile = "3.0" -failure = "0.1" -log = "0.4" -env_logger = "0.6" -fs2 = "0.4" -clap = "2" -heck= "0.3" diff --git a/lucet-idl/lucet-idl-test/resources/rust_host/.gitignore b/lucet-idl/lucet-idl-test/resources/rust_host/.gitignore deleted file mode 100644 index 0da6c9a3e..000000000 --- a/lucet-idl/lucet-idl-test/resources/rust_host/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.*.lock diff --git a/lucet-idl/lucet-idl-test/resources/rust_host/Cargo.toml b/lucet-idl/lucet-idl-test/resources/rust_host/Cargo.toml deleted file mode 100644 index 5203602d5..000000000 --- a/lucet-idl/lucet-idl-test/resources/rust_host/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "lucet-idl-test-rust-host" -version = "0.1.0" -authors = ["Pat Hickey "] -edition = "2018" - -[[bin]] -name = "lucet-idl-test-rust-host" -path = "src/main.rs" - -[dependencies] -lucet-idl = { path = "../../../" } -lucet-runtime = { path = "../../../../lucet-runtime" } -lucet-wasi = { path = "../../../../lucet-wasi" } -failure = "0.1" -log = "0.4" -env_logger = "0.6" diff --git a/lucet-idl/lucet-idl-test/resources/rust_host/src/harness.rs b/lucet-idl/lucet-idl-test/resources/rust_host/src/harness.rs deleted file mode 100644 index f2d1ce9f7..000000000 --- a/lucet-idl/lucet-idl-test/resources/rust_host/src/harness.rs +++ /dev/null @@ -1,6 +0,0 @@ -// PLACEHOLDER FILE -// this file is overwritten, and restored, by lucet-idl-test -pub struct Ctx; -pub fn ctx() -> Box { - Box::new(Ctx) -} diff --git a/lucet-idl/lucet-idl-test/resources/rust_host/src/idl.rs b/lucet-idl/lucet-idl-test/resources/rust_host/src/idl.rs deleted file mode 100644 index 94f7133ac..000000000 --- a/lucet-idl/lucet-idl-test/resources/rust_host/src/idl.rs +++ /dev/null @@ -1,3 +0,0 @@ -// PLACEHOLDER FILE -// this file is overwritten, and restored, by lucet-idl-test -pub fn ensure_linked() {} diff --git a/lucet-idl/lucet-idl-test/resources/rust_host/src/main.rs b/lucet-idl/lucet-idl-test/resources/rust_host/src/main.rs deleted file mode 100644 index 1bf200fb1..000000000 --- a/lucet-idl/lucet-idl-test/resources/rust_host/src/main.rs +++ /dev/null @@ -1,22 +0,0 @@ -use std::env; -use std::path::PathBuf; - -mod harness; -mod idl; -mod run; - -fn main() { - let args: Vec = env::args().collect(); - if args.len() != 2 { - eprintln!("usage: lucet-idl-test-rust-host "); - std::process::exit(1); - } - let module_path = PathBuf::from(&args[1]); - match run::run(module_path) { - Ok(()) => {} - Err(e) => { - eprintln!("{:?}", e); - std::process::exit(1); - } - } -} diff --git a/lucet-idl/lucet-idl-test/resources/rust_host/src/run.rs b/lucet-idl/lucet-idl-test/resources/rust_host/src/run.rs deleted file mode 100644 index 569a0f161..000000000 --- a/lucet-idl/lucet-idl-test/resources/rust_host/src/run.rs +++ /dev/null @@ -1,43 +0,0 @@ -use crate::{harness, idl}; -use failure::Error; -use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region}; -use lucet_wasi::{self, WasiCtxBuilder}; -use std::path::PathBuf; -use std::sync::Arc; - -pub fn run(module_path: PathBuf) -> Result<(), Error> { - lucet_wasi::export_wasi_funcs(); - idl::ensure_linked(); - - let module = DlModule::load(&module_path)?; - - let region = MmapRegion::create( - 1, - &Limits { - heap_memory_size: 4 * 1024 * 1024 * 1024, - heap_address_space_size: 8 * 1024 * 1024 * 1024, - globals_size: 4 * 1024 * 1024, - stack_size: 4 * 1024 * 1024, - }, - )?; - - let ctx = WasiCtxBuilder::new() - .expect("create new wasi context") - .inherit_stdio() - .expect("inherit stdio") - .build() - .expect("create empty wasi ctx"); - - let harness_ctx = harness::ctx(); - - let mut inst = region - .new_instance_builder(module as Arc) - .with_embed_ctx(ctx) - .with_embed_ctx(harness_ctx) - .build() - .expect("construct instance"); - - inst.run("_start", &[])?; - - Ok(()) -} diff --git a/lucet-idl/lucet-idl-test/src/c_guest.rs b/lucet-idl/lucet-idl-test/src/c_guest.rs deleted file mode 100644 index d35d747c5..000000000 --- a/lucet-idl/lucet-idl-test/src/c_guest.rs +++ /dev/null @@ -1,66 +0,0 @@ -use crate::workspace::Workspace; -use failure::Error; -use lucet_idl::{self, Backend, Config, Package}; -use lucet_wasi; -use lucet_wasi_sdk::{CompileOpts, Link}; -use lucetc::{Lucetc, LucetcOpts}; -use std::fs::File; -use std::io::Write; -use std::path::PathBuf; - -pub struct CGuestApp { - work: Workspace, -} - -impl CGuestApp { - pub fn new() -> Result { - Ok(Self { - work: Workspace::new()?, - }) - } - - fn generate_idl_h(&mut self, package: &Package) -> Result<(), Error> { - lucet_idl::codegen( - package, - &Config { - backend: Backend::CGuest, - }, - Box::new(File::create(self.work.source_path("idl.h"))?), - )?; - Ok(()) - } - - fn generate_main_c(&mut self) -> Result<(), Error> { - let mut main_file = File::create(self.work.source_path("main.c"))?; - main_file.write_all( - b" -#include -#include \"idl.h\" - -int main(int argc, char* argv[]) { - printf(\"hello, world from c guest\"); -}", - )?; - Ok(()) - } - - pub fn build(&mut self, package: &Package) -> Result { - self.generate_idl_h(package)?; - self.generate_main_c()?; - - Link::new(&[self.work.source_path("main.c")]) - .with_include(self.work.source_path("")) - .link(&self.work.output_path("out.wasm"))?; - - let mut bindings = lucet_wasi::bindings(); - bindings.extend(&package.bindings())?; - let lucetc = Lucetc::new(self.work.output_path("out.wasm")).with_bindings(bindings); - let so_file = self.work.output_path("out.so"); - lucetc.shared_object_file(&so_file)?; - Ok(so_file) - } - - pub fn into_workspace(self) -> Workspace { - self.work - } -} diff --git a/lucet-idl/lucet-idl-test/src/host.rs b/lucet-idl/lucet-idl-test/src/host.rs deleted file mode 100644 index e4e633284..000000000 --- a/lucet-idl/lucet-idl-test/src/host.rs +++ /dev/null @@ -1,114 +0,0 @@ -use crate::ModuleTestPlan; -use failure::{format_err, Error}; -use fs2::FileExt; -use lucet_idl::{self, pretty_writer::PrettyWriter, Backend, Config, Package}; -use std::fs::{self, File}; -use std::path::{Path, PathBuf}; -use std::process::Command; -use tempfile::TempDir; - -pub struct HostApp { - root: PathBuf, - tempdir: TempDir, - backups: Vec<(PathBuf, PathBuf)>, - // lockfile is never used in methods, it just needs to have the same lifetime as the app, it - // gets unlocked when HostApp drops - _lockfile: File, -} - -impl HostApp { - pub fn new(package: &Package, test_plan: &ModuleTestPlan) -> Result { - let modules = package.modules().collect::>(); - if modules.len() != 1 { - Err(format_err!( - "only one module per package supported at this time" - ))? - } - - // Need a system-wide lock on the source directory, because we will modify its contents and - // call `cargo run` on it. - // This way we can use the cache of compiled crates in the project cargo workspace. - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("resources") - .join("rust_host"); - let lockfile_path = root.join(".rust_host.lock"); - if !lockfile_path.exists() { - File::create(&lockfile_path)?; - } - - let lockfile = File::open(lockfile_path)?; - lockfile.lock_exclusive()?; - - let mut hostapp = HostApp { - root, - _lockfile: lockfile, - tempdir: TempDir::new()?, - backups: Vec::new(), - }; - - let idl_file = hostapp.source_file("idl.rs")?; - lucet_idl::codegen( - package, - &Config { - backend: Backend::RustHost, - }, - Box::new(idl_file), - )?; - - let mut harness_writer = PrettyWriter::new(Box::new(hostapp.source_file("harness.rs")?)); - test_plan.render_host(&mut harness_writer); - - Ok(hostapp) - } - - fn source_file(&mut self, name: &str) -> Result { - let filepath = self.root.join("src").join(name); - if filepath.exists() { - let backup = self.tempdir.path().join(name); - if backup.exists() { - Err(format_err!( - "cannot overwrite source file '{}': already overwritten", - name - ))? - } - self.backups.push((backup.clone(), filepath.clone())); - fs::rename(&filepath, backup)?; - } - let f = File::create(filepath)?; - Ok(f) - } - - pub fn build(&mut self) -> Result<(), Error> { - let run_cargo = Command::new("cargo") - .arg("build") - .current_dir(&self.root) - .status()?; - if !run_cargo.success() { - Err(format_err!("cargo died building host project"))? - } - Ok(()) - } - - pub fn run>(&mut self, guest_path: P) -> Result<(), Error> { - let run_cargo = Command::new("cargo") - .arg("run") - .arg("--bin") - .arg("lucet-idl-test-rust-host") - .arg("--") - .arg(guest_path.as_ref()) - .current_dir(&self.root) - .status()?; - if !run_cargo.success() { - Err(format_err!("cargo died building host project"))? - } - Ok(()) - } -} - -impl Drop for HostApp { - fn drop(&mut self) { - for (backup, orig) in self.backups.iter() { - fs::rename(backup, orig).expect("restore backup") - } - } -} diff --git a/lucet-idl/lucet-idl-test/src/lib.rs b/lucet-idl/lucet-idl-test/src/lib.rs deleted file mode 100644 index 3f4afea3d..000000000 --- a/lucet-idl/lucet-idl-test/src/lib.rs +++ /dev/null @@ -1,60 +0,0 @@ -mod c_guest; -mod host; -mod rust_guest; -pub mod syntax; -mod test_plan; -mod values; -mod workspace; - -pub use c_guest::CGuestApp; -pub use host::HostApp; -pub use rust_guest::RustGuestApp; -pub use syntax::Spec; -pub use test_plan::{FuncCallPredicate, ModuleTestPlan}; -pub use values::DatatypeExt; -pub use workspace::Workspace; - -#[cfg(test)] -mod tests { - use crate::{CGuestApp, HostApp, ModuleTestPlan, RustGuestApp, Spec}; - use lucet_idl::parse_package; - use proptest::prelude::*; - - proptest! { - #[test] - fn generate_idl(spec in Spec::strat(4)) { - let rendered = spec.render_idl(); - println!("{}", rendered); - let _ = parse_package(&rendered).unwrap(); - } - - #[test] - fn generate_rust_guest(spec in Spec::strat(20)) { - let rendered = spec.render_idl(); - let pkg = parse_package(&rendered).unwrap(); - let modules = pkg.modules().collect::>(); - let test_plan = ModuleTestPlan::trivial(&modules.get(0).expect("just one module")); - let mut rust_guest_app = RustGuestApp::new().expect("create rust guest app"); - let _rust_guest_so = rust_guest_app.build(&pkg, &test_plan).expect("compile rust guest app"); - } - - #[test] - fn generate_c_guest(spec in Spec::strat(20)) { - let rendered = spec.render_idl(); - let pkg = parse_package(&rendered).unwrap(); - let mut c_guest_app = CGuestApp::new().expect("create c guest app"); - let _c_guest_so = c_guest_app.build(&pkg).expect("compile c guest app"); - } - - #[test] - fn generate_host(spec in Spec::strat(20)) { - let rendered = spec.render_idl(); - let pkg = parse_package(&rendered).unwrap(); - let modules = pkg.modules().collect::>(); - let test_plan = ModuleTestPlan::trivial(&modules.get(0).expect("just one module")); - let mut host_app = HostApp::new(&pkg, &test_plan).expect("create host app"); - let _host_app = host_app.build().expect("compile host app"); - } - - } -} diff --git a/lucet-idl/lucet-idl-test/src/main.rs b/lucet-idl/lucet-idl-test/src/main.rs deleted file mode 100644 index e1d907f58..000000000 --- a/lucet-idl/lucet-idl-test/src/main.rs +++ /dev/null @@ -1,191 +0,0 @@ -#[macro_use] -extern crate clap; - -use clap::Arg; -use env_logger; -use log::{debug, info}; -use lucet_idl::{parse_package, Module, Package}; -use lucet_idl_test::{CGuestApp, HostApp, ModuleTestPlan, RustGuestApp, Spec, Workspace}; -use proptest::prelude::*; -use proptest::strategy::ValueTree; -use proptest::test_runner::TestRunner; -use std::fs::read_to_string; -use std::path::PathBuf; -use std::process; - -fn main() { - env_logger::init(); - let exe_config = ExeConfig::parse(); - - let mut runner = TestRunner::default(); - - let input_idl = match exe_config.input { - Some(path) => read_to_string(path).expect("read contents of input file"), - None => { - let spec = Spec::strat(10).new_tree(&mut runner).unwrap().current(); - let rendered = spec.render_idl(); - info!("generated spec:\n{}", rendered); - rendered - } - }; - - let pkg = parse_package(&input_idl).expect("parse generated package"); - - debug!("parsed package: {:?}", pkg); - if exe_config.generate_values { - generate_values(&pkg); - process::exit(0); - } - - if exe_config.generate_calls { - generate_calls(&pkg); - process::exit(0); - } - - let module = pkg - .modules() - .collect::>() - .pop() - .expect("get generated module"); - let test_plan = ModuleTestPlan::strat(&module) - .new_tree(&mut runner) - .unwrap() - .current(); - - // Workspace deleted when dropped - need to keep it alive for app to be run - let mut guest_apps: Vec<(PathBuf, Workspace)> = Vec::new(); - - if exe_config.build_rust_guest { - let mut rust_guest_app = RustGuestApp::new().expect("create rust guest app"); - let rust_guest_so = rust_guest_app - .build(&pkg, &test_plan) - .expect("compile rust guest app"); - guest_apps.push((rust_guest_so, rust_guest_app.into_workspace())); - } - - if exe_config.build_c_guest { - let mut c_guest_app = CGuestApp::new().expect("create c guest app"); - let c_guest_so = c_guest_app.build(&pkg).expect("compile c guest app"); - guest_apps.push((c_guest_so, c_guest_app.into_workspace())); - } - - if exe_config.build_host { - let mut host_app = HostApp::new(&pkg, &test_plan).expect("create host app"); - if exe_config.run_guests { - for (guest_app_path, _ws) in guest_apps.iter() { - host_app.run(guest_app_path).expect("run guest app"); - } - } - } -} - -#[derive(Clone, Debug)] -struct ExeConfig { - pub input: Option, - pub build_host: bool, - pub build_rust_guest: bool, - pub build_c_guest: bool, - pub run_guests: bool, - pub generate_values: bool, - pub generate_calls: bool, -} - -impl ExeConfig { - pub fn parse() -> Self { - let _ = include_str!("../Cargo.toml"); - let matches = app_from_crate!() - .arg( - Arg::with_name("input") - .required(false) - .help("Path to the input idl file. If not provided, input will be generated"), - ) - .arg( - Arg::with_name("no_host") - .required(false) - .takes_value(false) - .long("no-host") - .help(""), - ) - .arg( - Arg::with_name("no_c_guest") - .required(false) - .takes_value(false) - .long("no-c-guest") - .help(""), - ) - .arg( - Arg::with_name("no_rust_guest") - .required(false) - .takes_value(false) - .long("no-rust-guest") - .help(""), - ) - .arg( - Arg::with_name("no_run") - .required(false) - .takes_value(false) - .long("no-run") - .help(""), - ) - .arg( - Arg::with_name("generate_values") - .required(false) - .takes_value(false) - .long("generate-values") - .help(""), - ) - .arg( - Arg::with_name("generate_calls") - .required(false) - .takes_value(false) - .long("generate-calls") - .help(""), - ) - .get_matches(); - - ExeConfig { - input: matches.value_of("input").map(PathBuf::from), - build_host: !matches.is_present("no_host"), - build_c_guest: !matches.is_present("no_c_guest"), - build_rust_guest: !matches.is_present("no_rust_guest"), - run_guests: !matches.is_present("no_run") || !matches.is_present("no_host"), - generate_values: matches.is_present("generate_values"), - generate_calls: matches.is_present("generate_calls"), - } - } -} - -fn generate_values(package: &Package) { - use lucet_idl_test::DatatypeExt; - - for m in package.modules() { - for dt in m.datatypes() { - let dt_generator = dt.strat(); - let mut runner = TestRunner::default(); - let value = dt_generator - .new_tree(&mut runner) - .expect("create valuetree") - .current(); - println!("type: {:?}\nvalue: {:?}", dt, value); - } - } -} - -fn generate_calls(package: &Package) { - use lucet_idl_test::FuncCallPredicate; - - for m in package.modules() { - for func in m.functions() { - let func_pred_gen = FuncCallPredicate::strat(&func); - let mut runner = TestRunner::default(); - let value = func_pred_gen - .new_tree(&mut runner) - .expect("create valuetree") - .current(); - println!( - "==========\n{}\n=========", - value.render_caller().join("\n") - ); - } - } -} diff --git a/lucet-idl/lucet-idl-test/src/rust_guest.rs b/lucet-idl/lucet-idl-test/src/rust_guest.rs deleted file mode 100644 index c8b2fd244..000000000 --- a/lucet-idl/lucet-idl-test/src/rust_guest.rs +++ /dev/null @@ -1,80 +0,0 @@ -use crate::workspace::Workspace; -use crate::ModuleTestPlan; -use failure::{format_err, Error}; -use lucet_idl::{self, pretty_writer::PrettyWriter, Backend, Config, Package}; -use lucet_wasi; -use lucetc::{Lucetc, LucetcOpts}; -use std::fs::File; -use std::path::PathBuf; -use std::process::Command; - -pub struct RustGuestApp { - work: Workspace, -} - -impl RustGuestApp { - pub fn new() -> Result { - Ok(Self { - work: Workspace::new()?, - }) - } - - fn generate_idl_rs(&mut self, package: &Package) -> Result<(), Error> { - lucet_idl::codegen( - package, - &Config { - backend: Backend::RustGuest, - }, - Box::new(File::create(self.work.source_path("idl.rs"))?), - )?; - Ok(()) - } - - fn generate_main_rs(&mut self, test_plan: &ModuleTestPlan) -> Result<(), Error> { - let mut w = PrettyWriter::new(Box::new(File::create(self.work.source_path("main.rs"))?)); - w.writeln("#[allow(unused)]"); - w.writeln("mod idl;"); - w.writeln(format!("use idl::{}::*;", test_plan.module_name)); - - w.writeln("fn main() {").indent(); - w.writeln("println!(\"hello, world from rust guest\");"); - test_plan.render_guest(&mut w); - w.writeln("println!(\"test complete!\");"); - w.eob().writeln("}"); - Ok(()) - } - - fn rustc(&mut self) -> Result<(), Error> { - let cmd_rustc = Command::new("rustc") - .arg("+nightly") - .arg(self.work.source_path("main.rs")) - .arg("--target=wasm32-wasi") - .arg("-o") - .arg(self.work.output_path("out.wasm")) - .status()?; - if !cmd_rustc.success() { - Err(format_err!("rustc error building guest"))? - } - Ok(()) - } - - pub fn build( - &mut self, - package: &Package, - test_plan: &ModuleTestPlan, - ) -> Result { - self.generate_idl_rs(package)?; - self.generate_main_rs(test_plan)?; - self.rustc()?; - let mut bindings = lucet_wasi::bindings(); - bindings.extend(&package.bindings())?; - let lucetc = Lucetc::new(self.work.output_path("out.wasm")).with_bindings(bindings); - let so_file = self.work.output_path("out.so"); - lucetc.shared_object_file(&so_file)?; - Ok(so_file) - } - - pub fn into_workspace(self) -> Workspace { - self.work - } -} diff --git a/lucet-idl/lucet-idl-test/src/syntax.rs b/lucet-idl/lucet-idl-test/src/syntax.rs deleted file mode 100644 index 14542824d..000000000 --- a/lucet-idl/lucet-idl-test/src/syntax.rs +++ /dev/null @@ -1,419 +0,0 @@ -use lucet_idl::{AbiType, AtomType}; -use proptest::prelude::*; - -pub trait ArbTypeExt -where - Self: Sized, -{ - fn strat() -> BoxedStrategy; - fn render_idl(&self) -> String; -} - -impl ArbTypeExt for AtomType { - fn strat() -> BoxedStrategy { - prop_oneof![ - Just(AtomType::Bool), - Just(AtomType::U8), - Just(AtomType::U16), - Just(AtomType::U32), - Just(AtomType::U64), - Just(AtomType::I8), - Just(AtomType::I16), - Just(AtomType::I32), - Just(AtomType::I64), - Just(AtomType::F32), - Just(AtomType::F64), - ] - .boxed() - } - fn render_idl(&self) -> String { - use AtomType::*; - match self { - Bool => "bool", - U8 => "u8", - U16 => "u16", - U32 => "u32", - U64 => "u64", - I8 => "i8", - I16 => "i16", - I32 => "i32", - I64 => "i64", - F32 => "f32", - F64 => "f64", - } - .to_owned() - } -} - -impl ArbTypeExt for AbiType { - fn strat() -> BoxedStrategy { - prop_oneof![ - Just(AbiType::I32), - Just(AbiType::I64), - Just(AbiType::F32), - Just(AbiType::F64), - ] - .boxed() - } - fn render_idl(&self) -> String { - use AbiType::*; - match self { - I32 => "i32", - I64 => "i64", - F32 => "f32", - F64 => "f64", - } - .to_owned() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct DatatypeRef(usize); - -impl DatatypeRef { - pub fn strat() -> impl Strategy { - any::().prop_map(DatatypeRef) - } - - pub fn normalize(self, highest_definition: usize) -> Self { - assert!(highest_definition != 0); - DatatypeRef(self.0 % highest_definition) - } - - pub fn render_idl(&self) -> String { - format!("dt_{}", self.0) - } -} - -#[derive(Debug, Clone)] -pub enum DatatypeName { - Atom(AtomType), - Defined(DatatypeRef), -} - -impl DatatypeName { - pub fn normalize(self, highest_definition: usize) -> Self { - match self { - DatatypeName::Defined(def) => { - if highest_definition == 0 { - // No defined type to normalize to - instead use an atom type. - DatatypeName::Atom(AtomType::I64) - } else { - DatatypeName::Defined(def.normalize(highest_definition)) - } - } - DatatypeName::Atom(a) => DatatypeName::Atom(a.clone()), - } - } - - pub fn strat() -> impl Strategy { - prop_oneof![ - DatatypeRef::strat().prop_map(DatatypeName::Defined), - AtomType::strat().prop_map(DatatypeName::Atom) - ] - } - - pub fn render_idl(&self) -> String { - match self { - DatatypeName::Atom(a) => a.render_idl(), - DatatypeName::Defined(d) => d.render_idl(), - } - } -} - -#[derive(Debug, Clone)] -pub struct EnumSyntax { - pub variants: usize, -} - -impl EnumSyntax { - pub fn strat() -> impl Strategy { - // up to 20 variants for now. probably want to allow more in the future? - (1..20usize).prop_map(|variants| EnumSyntax { variants }) - } - - pub fn render_idl(&self, name: usize) -> String { - let mut s = String::new(); - for v in 0..self.variants { - s += &format!("v_{}, ", v); - } - format!("enum dt_{} {{ {} }} ", name, s) - } -} - -#[derive(Debug, Clone)] -pub struct StructSyntax { - pub members: Vec, -} - -impl StructSyntax { - pub fn strat() -> impl Strategy { - prop::collection::vec(DatatypeName::strat(), 1..10) - .prop_map(|members| StructSyntax { members }) - } - - pub fn normalize(self, highest_definition: usize) -> Self { - let members = self - .members - .into_iter() - .map(|m| m.normalize(highest_definition)) - .collect(); - Self { members } - } - - pub fn render_idl(&self, name: usize) -> String { - let mut s = String::new(); - for (ix, m) in self.members.iter().enumerate() { - s += &format!("m_{}: {}, ", ix, m.render_idl()); - } - format!("struct dt_{} {{ {} }} ", name, s) - } -} - -#[derive(Debug, Clone)] -pub struct AliasSyntax { - pub target: DatatypeName, -} - -impl AliasSyntax { - pub fn strat() -> impl Strategy { - DatatypeName::strat().prop_map(|target| AliasSyntax { target }) - } - pub fn normalize(self, highest_definition: usize) -> Self { - Self { - target: self.target.normalize(highest_definition), - } - } - pub fn render_idl(&self, name: usize) -> String { - format!("type dt_{} = {};", name, self.target.render_idl()) - } -} - -#[derive(Debug, Clone)] -pub enum DatatypeSyntax { - Enum(EnumSyntax), - Struct(StructSyntax), - Alias(AliasSyntax), -} - -impl DatatypeSyntax { - pub fn strat() -> impl Strategy { - prop_oneof![ - EnumSyntax::strat().prop_map(DatatypeSyntax::Enum), - StructSyntax::strat().prop_map(DatatypeSyntax::Struct), - AliasSyntax::strat().prop_map(DatatypeSyntax::Alias), - ] - } - - pub fn normalize(self, highest_definition: usize) -> Self { - match self { - DatatypeSyntax::Enum(e) => DatatypeSyntax::Enum(e.clone()), - DatatypeSyntax::Struct(s) => DatatypeSyntax::Struct(s.normalize(highest_definition)), - DatatypeSyntax::Alias(a) => DatatypeSyntax::Alias(a.normalize(highest_definition)), - } - } - - pub fn render_idl(&self, name: usize) -> String { - match self { - DatatypeSyntax::Enum(e) => e.render_idl(name), - DatatypeSyntax::Struct(s) => s.render_idl(name), - DatatypeSyntax::Alias(a) => a.render_idl(name), - } - } -} - -#[derive(Debug, Clone)] -pub enum FuncArgBindingSyntax { - InValue(AtomType), - InPtr(DatatypeRef), - OutPtr(DatatypeRef), - InOutPtr(DatatypeRef), - InSlice(DatatypeRef), - InOutSlice(DatatypeRef), -} - -impl FuncArgBindingSyntax { - pub fn strat() -> BoxedStrategy { - use FuncArgBindingSyntax::*; - prop_oneof![ - AtomType::strat().prop_map(InValue), - DatatypeRef::strat().prop_map(InPtr), - DatatypeRef::strat().prop_map(OutPtr), - DatatypeRef::strat().prop_map(InOutPtr), - DatatypeRef::strat().prop_map(InSlice), - DatatypeRef::strat().prop_map(InOutSlice), - ] - .boxed() - } - - pub fn normalize(self, highest_definition: usize) -> Self { - use FuncArgBindingSyntax::*; - match self { - InValue(atomtype) => InValue(atomtype), - InPtr(dt) => InPtr(dt.normalize(highest_definition)), - OutPtr(dt) => OutPtr(dt.normalize(highest_definition)), - InOutPtr(dt) => InOutPtr(dt.normalize(highest_definition)), - InSlice(dt) => InSlice(dt.normalize(highest_definition)), - InOutSlice(dt) => InOutSlice(dt.normalize(highest_definition)), - } - } -} - -#[derive(Debug, Clone)] -pub struct FunctionSyntax { - arg_bindings: Vec, - ret_binding: Option, -} - -impl FunctionSyntax { - pub fn strat(max_args: usize) -> impl Strategy { - ( - prop::collection::vec(FuncArgBindingSyntax::strat(), 0..max_args), - prop::option::of(AtomType::strat()), - ) - .prop_map(|(arg_bindings, ret_binding)| FunctionSyntax { - arg_bindings, - ret_binding, - }) - } - - pub fn normalize(self, highest_definition: usize) -> Self { - let arg_bindings = self - .arg_bindings - .into_iter() - .map(|a| a.normalize(highest_definition)) - .collect(); - Self { - arg_bindings, - ret_binding: self.ret_binding, - } - } - - pub fn render_idl(&self, name: usize) -> String { - let mut arg_syntax: Vec = Vec::new(); - let mut binding_syntax: Vec = Vec::new(); - - for (ix, a) in self.arg_bindings.iter().enumerate() { - use FuncArgBindingSyntax::*; - match a { - InValue(atomtype) => { - arg_syntax.push(format!( - "a_{}: {}", - ix, - AbiType::smallest_representation(atomtype).render_idl() - )); - binding_syntax.push(format!( - "b_{}: in {} <- a_{}", - ix, - atomtype.render_idl(), - ix - )); - } - InPtr(dt) => { - arg_syntax.push(format!("a_{}: i32", ix)); - binding_syntax.push(format!("b_{}: in {} <- *a_{}", ix, dt.render_idl(), ix)); - } - OutPtr(dt) => { - arg_syntax.push(format!("a_{}: i32", ix)); - binding_syntax.push(format!("b_{}: out {} <- *a_{}", ix, dt.render_idl(), ix)); - } - InOutPtr(dt) => { - arg_syntax.push(format!("a_{}: i32", ix)); - binding_syntax.push(format!( - "b_{}: inout {} <- *a_{}", - ix, - dt.render_idl(), - ix - )); - } - InSlice(dt) => { - arg_syntax.push(format!("a_{}_ptr: i32", ix)); - arg_syntax.push(format!("a_{}_len: i32", ix)); - binding_syntax.push(format!( - "b_{}: in {} <- [a_{}_ptr, a_{}_len]", - ix, - dt.render_idl(), - ix, - ix - )); - } - InOutSlice(dt) => { - arg_syntax.push(format!("a_{}_ptr: i32", ix)); - arg_syntax.push(format!("a_{}_len: i32", ix)); - binding_syntax.push(format!( - "b_{}: inout {} <- [a_{}_ptr, a_{}_len]", - ix, - dt.render_idl(), - ix, - ix - )); - } - } - } - - let mut ret_syntax = None; - if let Some(b) = self.ret_binding { - ret_syntax = Some(format!( - "r: {}", - AbiType::smallest_representation(&b).render_idl() - )); - let ix = self.arg_bindings.len(); - binding_syntax.push(format!("b_{}: out {} <- r", ix, b.render_idl(),)); - } - - format!( - "fn f_{}({}){}\nwhere {};", - name, - arg_syntax.join(", "), - ret_syntax.map(|r| format!("-> {}", r)).unwrap_or_default(), - binding_syntax.join(",\n"), - ) - } -} - -#[derive(Debug, Clone)] -pub struct Spec { - pub datatype_decls: Vec, - pub function_decls: Vec, -} - -impl Spec { - pub fn strat(max_size: usize) -> impl Strategy { - ( - prop::collection::vec(DatatypeSyntax::strat(), 1..max_size), - prop::collection::vec(FunctionSyntax::strat(max_size), 1..max_size), - ) - .prop_map(|(ds, fs)| Self::from_decls(ds, fs)) - } - - pub fn from_decls( - datatype_decls: Vec, - function_decls: Vec, - ) -> Self { - let datatype_decls: Vec = datatype_decls - .into_iter() - .enumerate() - .map(|(ix, decl)| decl.normalize(ix)) - .collect(); - let num_datatypes = datatype_decls.len(); - let function_decls = function_decls - .into_iter() - .map(|decl| decl.normalize(num_datatypes)) - .collect(); - Spec { - datatype_decls, - function_decls, - } - } - - pub fn render_idl(&self) -> String { - let mut s = String::new(); - for (ix, d) in self.datatype_decls.iter().enumerate() { - s += &format!(" {}\n", d.render_idl(ix)); - } - for (ix, d) in self.function_decls.iter().enumerate() { - s += &format!(" {}\n", d.render_idl(ix)); - } - format!("mod spec {{\n{}\n}}", s) - } -} diff --git a/lucet-idl/lucet-idl-test/src/test_plan.rs b/lucet-idl/lucet-idl-test/src/test_plan.rs deleted file mode 100644 index e81a7fb18..000000000 --- a/lucet-idl/lucet-idl-test/src/test_plan.rs +++ /dev/null @@ -1,210 +0,0 @@ -use crate::values::*; -use heck::SnakeCase; -use lucet_idl::{ - pretty_writer::PrettyWriter, BindingDirection, Function, Module, RustFunc, RustName, - RustTypeName, -}; -use proptest::prelude::*; - -#[derive(Debug, Clone)] -pub struct FuncCallPredicate { - func_name: String, - func_call_args: Vec, - func_call_rets: Vec, - func_sig_args: Vec, - func_sig_rets: Vec, - pre: Vec, - post: Vec, -} - -impl FuncCallPredicate { - pub fn strat(func: &Function) -> BoxedStrategy { - let args = func.rust_idiom_args(); - let rets = func.rust_idiom_rets(); - - // Precondition on all arguments - let pre_strat: Vec> = - args.iter().map(|a| BindingVal::arg_strat(a)).collect(); - - // Postcondition on all inout arguments, and all return values - let post_strat: Vec> = args - .iter() - .filter(|a| a.direction() == BindingDirection::InOut) - .map(|a| BindingVal::arg_strat(a)) - .chain(rets.iter().map(|r| BindingVal::ret_strat(r))) - .collect(); - - let func_call_args = args.iter().map(|a| a.arg_value()).collect::>(); - let func_sig_args = args.iter().map(|a| a.arg_declaration()).collect::>(); - - let func_call_rets = rets.iter().map(|r| r.name()).collect::>(); - let func_sig_rets = rets.iter().map(|a| a.ret_declaration()).collect::>(); - - let func_name = func.rust_name(); - (pre_strat, post_strat) - .prop_map(move |(pre, post)| FuncCallPredicate { - func_name: func_name.clone(), - func_call_args: func_call_args.clone(), - func_call_rets: func_call_rets.clone(), - func_sig_args: func_sig_args.clone(), - func_sig_rets: func_sig_rets.clone(), - pre, - post, - }) - .boxed() - } - - pub fn trivial(func: &Function) -> FuncCallPredicate { - let args = func.rust_idiom_args(); - let rets = func.rust_idiom_rets(); - - let pre = args.iter().map(|a| BindingVal::arg_trivial(a)).collect(); - let post = args - .iter() - .filter(|a| a.direction() == BindingDirection::InOut) - .map(|a| BindingVal::arg_trivial(a)) - .chain(rets.iter().map(|r| BindingVal::ret_trivial(r))) - .collect(); - - let func_call_args = args.iter().map(|a| a.arg_value()).collect::>(); - let func_sig_args = args.iter().map(|a| a.arg_declaration()).collect::>(); - - let func_call_rets = rets.iter().map(|r| r.name()).collect::>(); - let func_sig_rets = rets.iter().map(|a| a.ret_declaration()).collect::>(); - - FuncCallPredicate { - func_name: func.rust_name(), - func_call_args, - func_sig_args, - func_call_rets, - func_sig_rets, - pre, - post, - } - } - - pub fn render_caller(&self) -> Vec { - let mut lines: Vec = self - .pre - .iter() - .map(|val| val.render_rust_binding()) - .collect(); - - lines.push(format!( - "let {} = {}({}).unwrap();", - render_tuple(&self.func_call_rets, "_"), - self.func_name, - self.func_call_args.join(",") - )); - lines.append( - &mut self - .post - .iter() - .map(|val| { - format!( - "assert_eq!({}, {});", - val.name, - val.render_rust_constructor() - ) - }) - .collect(), - ); - lines - } - - pub fn render_callee(&self, w: &mut PrettyWriter) { - w.writeln(format!( - "fn {}(&mut self, {}) -> Result<{}, ()> {{", - self.func_name, - self.func_sig_args.join(", "), - render_tuple(&self.func_sig_rets, "()") - )) - .indent(); - // Assert preconditions hold - w.writelns( - &self - .pre - .iter() - .map(|val| format!("assert_eq!({}, {});", val.name, val.render_rust_ref())) - .collect::>(), - ); - // Make postconditions hold - let mut ret_vals = Vec::new(); - for post in self.post.iter() { - match post.variant { - BindingValVariant::Value(ref val) => { - ret_vals.push(val.render_rustval()); - } - BindingValVariant::Ptr(ref val) => { - w.writeln(format!("*{} = {};", post.name, val.render_rustval())); - } - BindingValVariant::Array(ref vals) => { - for (ix, val) in vals.iter().enumerate() { - w.writeln(format!("{}[{}] = {};", post.name, ix, val.render_rustval())); - } - } - } - } - w.writeln(format!("Ok({})", render_tuple(&ret_vals, "()"))); - w.eob().writeln("}"); - } -} - -#[derive(Debug, Clone)] -pub struct ModuleTestPlan { - pub module_name: String, - module_type_name: String, - func_predicates: Vec, -} - -impl ModuleTestPlan { - pub fn trivial(module: &Module) -> Self { - let module_name = module.name().to_snake_case(); - let module_type_name = module.rust_type_name(); - let func_predicates = module - .functions() - .map(|f| FuncCallPredicate::trivial(&f)) - .collect(); - ModuleTestPlan { - module_name, - module_type_name, - func_predicates, - } - } - - pub fn strat(module: &Module) -> BoxedStrategy { - let module_name = module.name().to_snake_case(); - let module_type_name = module.rust_type_name(); - module - .functions() - .map(|f| FuncCallPredicate::strat(&f)) - .collect::>() - .prop_map(move |func_predicates| ModuleTestPlan { - module_name: module_name.clone(), - module_type_name: module_type_name.clone(), - func_predicates, - }) - .boxed() - } - - pub fn render_guest(&self, w: &mut PrettyWriter) { - for func in self.func_predicates.iter() { - w.writelns(&func.render_caller()); - } - } - - pub fn render_host(&self, mut w: &mut PrettyWriter) { - w.writeln(format!("use crate::idl::{}::*;", self.module_name)); - w.writeln("pub struct TestHarness;"); - w.writeln(format!("impl {} for TestHarness {{", self.module_type_name,)) - .indent(); - for func in self.func_predicates.iter() { - func.render_callee(&mut w) - } - w.eob().writeln("}"); - w.writeln(format!( - "pub fn ctx() -> Box {{ Box::new(TestHarness) }}", - self.module_type_name - )); - } -} diff --git a/lucet-idl/lucet-idl-test/src/values.rs b/lucet-idl/lucet-idl-test/src/values.rs deleted file mode 100644 index 27ce780f4..000000000 --- a/lucet-idl/lucet-idl-test/src/values.rs +++ /dev/null @@ -1,391 +0,0 @@ -use heck::CamelCase; -use lucet_idl::{ - AliasDatatype, AtomType, BindingDirection, BindingParam, Datatype, DatatypeVariant, - EnumDatatype, RustIdiomArg, RustIdiomRet, StructDatatype, StructMember, -}; -use proptest::prelude::*; - -#[derive(Debug, Clone, PartialEq)] -pub enum AtomVal { - Bool(bool), - U8(u8), - U16(u16), - U32(u32), - U64(u64), - I8(i8), - I16(i16), - I32(i32), - I64(i64), - F32(f32), - F64(f64), -} - -impl AtomVal { - pub fn strat(atom_type: &AtomType) -> BoxedStrategy { - match atom_type { - AtomType::Bool => any::().prop_map(AtomVal::Bool).boxed(), - AtomType::U8 => any::().prop_map(AtomVal::U8).boxed(), - AtomType::U16 => any::().prop_map(AtomVal::U16).boxed(), - AtomType::U32 => any::().prop_map(AtomVal::U32).boxed(), - AtomType::U64 => any::().prop_map(AtomVal::U64).boxed(), - AtomType::I8 => any::().prop_map(AtomVal::I8).boxed(), - AtomType::I16 => any::().prop_map(AtomVal::I16).boxed(), - AtomType::I32 => any::().prop_map(AtomVal::I32).boxed(), - AtomType::I64 => any::().prop_map(AtomVal::I64).boxed(), - AtomType::F32 => any::().prop_map(AtomVal::F32).boxed(), - AtomType::F64 => any::().prop_map(AtomVal::F64).boxed(), - } - } - pub fn trivial(atom_type: &AtomType) -> Self { - match atom_type { - AtomType::Bool => AtomVal::Bool(false), - AtomType::U8 => AtomVal::U8(0), - AtomType::U16 => AtomVal::U16(0), - AtomType::U32 => AtomVal::U32(0), - AtomType::U64 => AtomVal::U64(0), - AtomType::I8 => AtomVal::I8(0), - AtomType::I16 => AtomVal::I16(0), - AtomType::I32 => AtomVal::I32(0), - AtomType::I64 => AtomVal::I64(0), - AtomType::F32 => AtomVal::F32(0.0), - AtomType::F64 => AtomVal::F64(0.0), - } - } - pub fn render_rustval(&self) -> String { - match self { - AtomVal::Bool(v) => format!("{}", v), - AtomVal::U8(v) => format!("{}", v), - AtomVal::U16(v) => format!("{}", v), - AtomVal::U32(v) => format!("{}", v), - AtomVal::U64(v) => format!("{}", v), - AtomVal::I8(v) => format!("{}", v), - AtomVal::I16(v) => format!("{}", v), - AtomVal::I32(v) => format!("{}", v), - AtomVal::I64(v) => format!("{}", v), - AtomVal::F32(v) => format!("{}f32", v), - AtomVal::F64(v) => format!("{}f64", v), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct EnumVal { - pub enum_name: String, - pub member_name: String, -} - -impl EnumVal { - pub fn strat(enum_datatype: &EnumDatatype) -> impl Strategy { - let name = enum_datatype.datatype().name().to_owned(); - prop::sample::select( - enum_datatype - .variants() - .map(|v| v.name().to_owned()) - .collect::>(), - ) - .prop_map(move |mem_name| EnumVal { - enum_name: name.clone(), - member_name: mem_name.clone(), - }) - } - pub fn trivial(enum_datatype: &EnumDatatype) -> Self { - let enum_name = enum_datatype.datatype().name().to_owned(); - let member_name = enum_datatype - .variants() - .collect::>() - .get(0) - .expect("at least one variant") - .name() - .to_owned(); - EnumVal { - enum_name, - member_name, - } - } - pub fn render_rustval(&self) -> String { - format!( - "{}::{}", - self.enum_name.to_camel_case(), - self.member_name.to_camel_case() - ) - } -} - -#[derive(Debug, Clone, PartialEq)] -pub struct StructVal { - pub struct_name: String, - pub members: Vec, -} - -impl StructVal { - pub fn strat(struct_dt: &StructDatatype) -> BoxedStrategy { - let name = struct_dt.datatype().name().to_owned(); - let member_strats: Vec> = struct_dt - .members() - .map(|m| StructMemberVal::strat(&m)) - .collect(); - member_strats - .prop_map(move |members| StructVal { - struct_name: name.clone(), - members, - }) - .boxed() - } - pub fn trivial(struct_dt: &StructDatatype) -> Self { - let struct_name = struct_dt.datatype().name().to_owned(); - let members = struct_dt - .members() - .map(|m| StructMemberVal::trivial(&m)) - .collect(); - StructVal { - struct_name, - members, - } - } - pub fn render_rustval(&self) -> String { - let members = self - .members - .iter() - .map(|v| format!("{}: {}", v.name, v.value.render_rustval())) - .collect::>(); - format!( - "{} {{ {} }}", - self.struct_name.to_camel_case(), - members.join(", ") - ) - } -} - -#[derive(Debug, Clone, PartialEq)] -pub struct StructMemberVal { - pub name: String, - pub value: Box, -} - -impl StructMemberVal { - pub fn strat(struct_member: &StructMember) -> BoxedStrategy { - let name = struct_member.name().to_owned(); - struct_member - .type_() - .strat() - .prop_map(move |value| StructMemberVal { - name: name.clone(), - value: Box::new(value), - }) - .boxed() - } - pub fn trivial(struct_member: &StructMember) -> Self { - let name = struct_member.name().to_owned(); - let value = Box::new(struct_member.type_().trivial_val()); - StructMemberVal { name, value } - } -} - -#[derive(Debug, Clone, PartialEq)] -pub struct AliasVal { - pub name: String, - pub value: Box, -} - -impl AliasVal { - pub fn strat(alias_dt: &AliasDatatype) -> BoxedStrategy { - let name = alias_dt.datatype().name().to_owned(); - alias_dt - .to() - .strat() - .prop_map(move |value| AliasVal { - name: name.clone(), - value: Box::new(value), - }) - .boxed() - } - pub fn trivial(alias_dt: &AliasDatatype) -> Self { - let name = alias_dt.datatype().name().to_owned(); - let value = Box::new(alias_dt.to().trivial_val()); - AliasVal { name, value } - } - pub fn render_rustval(&self) -> String { - self.value.render_rustval() - } -} - -#[derive(Debug, Clone, PartialEq)] -pub enum DatatypeVal { - Enum(EnumVal), - Struct(StructVal), - Alias(AliasVal), - Atom(AtomVal), -} - -impl DatatypeVal { - pub fn render_rustval(&self) -> String { - match self { - DatatypeVal::Enum(a) => a.render_rustval(), - DatatypeVal::Struct(a) => a.render_rustval(), - DatatypeVal::Alias(a) => a.render_rustval(), - DatatypeVal::Atom(a) => a.render_rustval(), - } - } -} - -pub trait DatatypeExt { - fn strat(&self) -> BoxedStrategy; - fn trivial_val(&self) -> DatatypeVal; -} - -impl<'a> DatatypeExt for Datatype<'a> { - fn strat(&self) -> BoxedStrategy { - match self.variant() { - DatatypeVariant::Struct(struct_dt) => StructVal::strat(&struct_dt) - .prop_map(DatatypeVal::Struct) - .boxed(), - DatatypeVariant::Enum(enum_dt) => { - EnumVal::strat(&enum_dt).prop_map(DatatypeVal::Enum).boxed() - } - DatatypeVariant::Alias(alias_dt) => AliasVal::strat(&alias_dt) - .prop_map(DatatypeVal::Alias) - .boxed(), - DatatypeVariant::Atom(a) => AtomVal::strat(&a).prop_map(DatatypeVal::Atom).boxed(), - } - } - fn trivial_val(&self) -> DatatypeVal { - match self.variant() { - DatatypeVariant::Struct(struct_dt) => { - DatatypeVal::Struct(StructVal::trivial(&struct_dt)) - } - DatatypeVariant::Enum(enum_dt) => DatatypeVal::Enum(EnumVal::trivial(&enum_dt)), - DatatypeVariant::Alias(alias_dt) => DatatypeVal::Alias(AliasVal::trivial(&alias_dt)), - DatatypeVariant::Atom(atom_dt) => DatatypeVal::Atom(AtomVal::trivial(&atom_dt)), - } - } -} - -#[derive(Debug, Clone, PartialEq)] -pub struct BindingVal { - pub name: String, - pub mutable: bool, - pub variant: BindingValVariant, -} - -#[derive(Debug, Clone, PartialEq)] -pub enum BindingValVariant { - Value(DatatypeVal), - Ptr(DatatypeVal), - Array(Vec), -} - -impl BindingVal { - pub fn arg_strat(arg: &RustIdiomArg) -> BoxedStrategy { - let mutable = arg.direction() == BindingDirection::InOut; - let name = arg.name(); - match arg.param() { - BindingParam::Value(_) => arg - .type_() - .strat() - .prop_map(move |v| BindingVal { - name: name.clone(), - mutable, - variant: BindingValVariant::Value(v), - }) - .boxed(), - BindingParam::Ptr(_) => arg - .type_() - .strat() - .prop_map(move |v| BindingVal { - name: name.clone(), - mutable, - variant: BindingValVariant::Ptr(v), - }) - .boxed(), - BindingParam::Slice(_, _) => prop::collection::vec(arg.type_().strat(), 100) - .prop_map(move |v| BindingVal { - name: name.clone(), - mutable, - variant: BindingValVariant::Array(v), - }) - .boxed(), - } - } - - pub fn arg_trivial(arg: &RustIdiomArg) -> Self { - let name = arg.name(); - let mutable = arg.direction() == BindingDirection::InOut; - let trivial_val = arg.type_().trivial_val(); - BindingVal { - name, - mutable, - variant: match arg.param() { - BindingParam::Value(_) => BindingValVariant::Value(trivial_val), - BindingParam::Ptr(_) => BindingValVariant::Ptr(trivial_val), - BindingParam::Slice(_, _) => BindingValVariant::Array(vec![trivial_val]), - }, - } - } - pub fn ret_strat(ret: &RustIdiomRet) -> BoxedStrategy { - let name = ret.name(); - // There can only be param or value bindings on returns, - // and both are idiomatically values. - ret.type_() - .strat() - .prop_map(move |v| BindingVal { - name: name.clone(), - mutable: false, - variant: BindingValVariant::Value(v), - }) - .boxed() - } - pub fn ret_trivial(ret: &RustIdiomRet) -> Self { - let name = ret.name(); - let trivial_val = ret.type_().trivial_val(); - BindingVal { - name, - mutable: false, - variant: BindingValVariant::Value(trivial_val), - } - } - - pub fn render_rust_binding(&self) -> String { - format!( - "let {}{} = {};", - if self.mutable { "mut " } else { "" }, - self.name, - self.render_rust_constructor(), - ) - } - - pub fn render_rust_constructor(&self) -> String { - match &self.variant { - BindingValVariant::Value(v) => v.render_rustval(), - BindingValVariant::Ptr(v) => v.render_rustval(), - BindingValVariant::Array(vs) => format!( - "vec![{}]", - vs.iter() - .map(|v| v.render_rustval()) - .collect::>() - .join(", ") - ), - } - } - - pub fn render_rust_ref(&self) -> String { - match &self.variant { - BindingValVariant::Value(v) => v.render_rustval(), - BindingValVariant::Ptr(v) => format!("&{}", v.render_rustval()), - BindingValVariant::Array(vs) => format!( - "vec![{}].as_slice()", - vs.iter() - .map(|v| v.render_rustval()) - .collect::>() - .join(", ") - ), - } - } -} - -pub fn render_tuple(vs: &[String], base_case: &str) -> String { - match vs.len() { - 0 => base_case.to_owned(), - 1 => vs[0].clone(), - _ => format!("({})", vs.join(", ")), - } -} diff --git a/lucet-idl/lucet-idl-test/src/workspace.rs b/lucet-idl/lucet-idl-test/src/workspace.rs deleted file mode 100644 index bc64ac184..000000000 --- a/lucet-idl/lucet-idl-test/src/workspace.rs +++ /dev/null @@ -1,24 +0,0 @@ -use failure::Error; -use std::fs; -use std::path::PathBuf; -use tempfile::TempDir; -pub struct Workspace { - tempdir: TempDir, -} - -impl Workspace { - pub fn new() -> Result { - let tempdir = TempDir::new()?; - fs::create_dir(tempdir.path().join("src"))?; - fs::create_dir(tempdir.path().join("out"))?; - Ok(Self { tempdir }) - } - - pub fn source_path(&self, name: &str) -> PathBuf { - self.tempdir.path().join("src").join(name) - } - - pub fn output_path(&self, name: &str) -> PathBuf { - self.tempdir.path().join("out").join(name) - } -} diff --git a/lucet-idl/src/atoms.rs b/lucet-idl/src/atoms.rs deleted file mode 100644 index 25ea32e74..000000000 --- a/lucet-idl/src/atoms.rs +++ /dev/null @@ -1,151 +0,0 @@ -use crate::MemArea; - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum AtomType { - Bool, - U8, - U16, - U32, - U64, - I8, - I16, - I32, - I64, - F32, - F64, -} - -impl MemArea for AtomType { - fn mem_size(&self) -> usize { - match self { - AtomType::Bool => 1, - AtomType::U8 | AtomType::I8 => 1, - AtomType::U16 | AtomType::I16 => 2, - AtomType::U32 | AtomType::I32 | AtomType::F32 => 4, - AtomType::U64 | AtomType::I64 | AtomType::F64 => 8, - } - } - fn mem_align(&self) -> usize { - self.mem_size() - } -} - -const ATOM_TYPE_NAMES: &'static [(AtomType, &'static str)] = &[ - (AtomType::Bool, "bool"), - (AtomType::U8, "u8"), - (AtomType::U16, "u16"), - (AtomType::U32, "u32"), - (AtomType::U64, "u64"), - (AtomType::I8, "i8"), - (AtomType::I16, "i16"), - (AtomType::I32, "i32"), - (AtomType::I64, "i64"), - (AtomType::F32, "f32"), - (AtomType::F64, "f64"), -]; - -#[cfg(test)] -#[test] -fn atom_type_names_are_indexed_correctly() { - for (ix, (atom, _name)) in ATOM_TYPE_NAMES.iter().enumerate() { - assert_eq!(ix, *atom as usize); - } -} - -impl ::std::convert::TryFrom<&str> for AtomType { - type Error = (); - fn try_from(name: &str) -> Result { - ATOM_TYPE_NAMES - .iter() - .find(|(_a, n)| *n == name) - .map(|(a, _n)| a.clone()) - .ok_or(()) - } -} - -impl ::std::fmt::Display for AtomType { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { - let (_a, n) = ATOM_TYPE_NAMES[*self as usize]; - write!(f, "{}", n) - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum AbiType { - I32, - I64, - F32, - F64, -} - -impl AbiType { - pub fn smallest_representation(a: &AtomType) -> Self { - match a { - AtomType::Bool - | AtomType::U8 - | AtomType::I8 - | AtomType::U16 - | AtomType::I16 - | AtomType::U32 - | AtomType::I32 => AbiType::I32, - AtomType::I64 | AtomType::U64 => AbiType::I64, - AtomType::F32 => AbiType::F32, - AtomType::F64 => AbiType::F64, - } - } - - pub fn can_represent(&self, a: &Self) -> bool { - match self { - AbiType::I64 => *a == AbiType::I32 || *a == AbiType::I64, - _ => a == self, - } - } - - pub fn from_atom(a: AtomType) -> Option { - match a { - AtomType::I32 => Some(AbiType::I32), - AtomType::I64 => Some(AbiType::I64), - AtomType::F32 => Some(AbiType::F32), - AtomType::F64 => Some(AbiType::F64), - _ => None, - } - } -} - -impl From for AtomType { - fn from(abi: AbiType) -> AtomType { - match abi { - AbiType::I32 => AtomType::I32, - AbiType::I64 => AtomType::I64, - AbiType::F32 => AtomType::F32, - AbiType::F64 => AtomType::F64, - } - } -} - -impl MemArea for AbiType { - fn mem_size(&self) -> usize { - match self { - AbiType::I32 | AbiType::F32 => 4, - AbiType::I64 | AbiType::F64 => 8, - } - } - - fn mem_align(&self) -> usize { - self.mem_size() - } -} - -impl ::std::convert::TryFrom<&str> for AbiType { - type Error = (); - fn try_from(name: &str) -> Result { - let atom = AtomType::try_from(name)?; - Self::from_atom(atom).ok_or(()) - } -} - -impl ::std::fmt::Display for AbiType { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { - write!(f, "{}", AtomType::from(self.clone())) - } -} diff --git a/lucet-idl/src/c.rs b/lucet-idl/src/c.rs deleted file mode 100644 index fd0a1abcd..000000000 --- a/lucet-idl/src/c.rs +++ /dev/null @@ -1,335 +0,0 @@ -use crate::pretty_writer::PrettyWriter; -use crate::{ - AbiType, AliasDatatype, AtomType, BindingDirection, BindingParam, Datatype, DatatypeVariant, - EnumDatatype, FuncBinding, Function, IDLError, MemArea, Package, StructDatatype, -}; -use std::io::Write; - -/// Generator for the C backend -pub struct CGenerator { - pub w: PrettyWriter, -} - -impl CGenerator { - pub fn new(w: Box) -> Self { - let mut w = PrettyWriter::new(w); - let prelude = r" -#include -#include -#include -#include "; - for line in prelude.lines() { - w.write_line(line.as_ref()); - } - w.eob(); - Self { w } - } - - pub fn generate_guest(&mut self, package: &Package) -> Result<(), IDLError> { - for module in package.modules() { - for dt in module.datatypes() { - self.gen_type_header(&dt)?; - match dt.variant() { - DatatypeVariant::Struct(s) => self.gen_struct(&s)?, - DatatypeVariant::Alias(a) => self.gen_alias(&a)?, - DatatypeVariant::Enum(e) => self.gen_enum(&e)?, - DatatypeVariant::Atom(_) => { - unreachable!("atoms should not be defined in package modules") - } - } - } - for func in module.functions() { - self.gen_abi_function(&func)?; - self.gen_idiomatic_function(&func)?; - } - } - Ok(()) - } - - fn gen_type_header(&mut self, dt: &Datatype) -> Result<(), IDLError> { - self.w - .eob() - .writeln(format!("// ---------- {} ----------", dt.name())) - .eob(); - Ok(()) - } - - // The most important thing in alias generation is to cache the size - // and alignment rules of what it ultimately points to - fn gen_alias(&mut self, alias: &AliasDatatype) -> Result<(), IDLError> { - let own_type_name = alias.datatype().c_type_name(); - self.w - .writeln(format!( - "typedef {} {};", - alias.to().c_type_name(), - own_type_name, - )) - .eob(); - - // Add an assertion to check that resolved size is the one we computed - self.w - .writeln(format!( - "_Static_assert(sizeof({}) == {}, \"unexpected alias size\");", - own_type_name, - alias.datatype().mem_size(), - )) - .eob(); - - Ok(()) - } - - fn gen_struct(&mut self, struct_: &StructDatatype) -> Result<(), IDLError> { - let own_type_name = struct_.datatype().c_type_name(); - self.w.writeln(format!("{} {{", own_type_name)); - let mut w_block = self.w.new_block(); - for member in struct_.members() { - w_block.writeln(format!( - "{} {};", - member.type_().c_type_name(), - member.name(), - )); - } - self.w.writeln("};").eob(); - - // Skip the first member, as it will always be at the beginning of the structure - for member in struct_.members().skip(1) { - self.w.writeln(format!( - "_Static_assert(offsetof({}, {}) == {}, \"unexpected offset\");", - own_type_name, - member.name(), - member.offset() - )); - } - - self.w - .writeln(format!( - "_Static_assert(sizeof({}) == {}, \"unexpected structure size\");", - own_type_name, - struct_.datatype().mem_size(), - )) - .eob(); - Ok(()) - } - - // Enums generate both a specific typedef, and a traditional C-style enum - // The typedef is required to use a native type which is consistent across all architectures - fn gen_enum(&mut self, enum_: &EnumDatatype) -> Result<(), IDLError> { - let own_type_name = enum_.datatype().c_type_name(); - self.w.writeln(format!("{} {{", own_type_name)); - let mut w = self.w.new_block(); - for variant in enum_.variants() { - w.writeln(format!( - "{}, // {}", - macro_for(enum_.datatype().name(), variant.name()), - variant.index(), - )); - } - self.w.writeln("};").eob(); - self.w - .writeln(format!( - "_Static_assert(sizeof({}) == {}, \"unexpected enumeration size\");", - own_type_name, - enum_.datatype().mem_size(), - )) - .eob(); - Ok(()) - } - - fn gen_abi_function(&mut self, func: &Function) -> Result<(), IDLError> { - let rets = func.rets().collect::>(); - let return_decl = match rets.len() { - 0 => "void".to_owned(), - 1 => rets[0].type_().c_type_name(), - _ => unreachable!("functions limited to 0 or 1 return arguments"), - }; - - let arg_list = func - .args() - .map(|a| format!("{} {}", a.type_().c_type_name(), a.name())) - .collect::>() - .join(", "); - - self.w.writeln(format!( - "extern {} {}({}) {};", - return_decl, - func.c_abi_func_name(), - arg_list, - func.c_abi_func_attributes(), - )); - - Ok(()) - } - - fn gen_idiomatic_function(&mut self, func: &Function) -> Result<(), IDLError> { - let mut ret_bindings = func.c_ret_bindings().collect::>(); - let ret_bindings = match ret_bindings.len() { - 0 => None, - 1 => Some(ret_bindings.pop().expect("only member")), - _ => unreachable!("functions limited to 0 or 1 return arguments"), - }; - - let own_return_decl = ret_bindings - .clone() - .map(|b| b.type_().c_type_name()) - .unwrap_or("void".to_owned()); - - let own_arg_list = func - .c_arg_bindings() - .map(|b| match b.param() { - BindingParam::Ptr(_p) => format!( - "{}{}* {}", - b.c_constness(), - b.type_().c_type_name(), - b.name() - ), - BindingParam::Slice(_ptr, _len) => format!( - "{}{}* {}_ptr, size_t {}_len", - b.c_constness(), - b.type_().c_type_name(), - b.name(), - b.name(), - ), - BindingParam::Value(_v) => format!("{} {}", b.type_().c_type_name(), b.name(),), - }) - .collect::>() - .join(", "); - - self.w.writeln(format!( - "{} {}({}) {{", - own_return_decl, - func.c_idiomatic_func_name(), - own_arg_list, - )); - { - let arg_bindings = func - .c_arg_bindings() - .map(|b| match b.param() { - BindingParam::Ptr(p) => format!("({}) {}", p.type_().c_type_name(), b.name()), - BindingParam::Slice(p, l) => format!( - "({}) {}_ptr, ({}) {}_len", - p.type_().c_type_name(), - b.name(), - l.type_().c_type_name(), - b.name() - ), - BindingParam::Value(v) => format!("({}) {}", v.type_().c_type_name(), b.name()), - }) - .collect::>() - .join(", "); - - let (ret_capture, ret_statement) = ret_bindings - .map(|b| match b.param() { - BindingParam::Ptr(p) => ( - format!("{} {} = ", p.type_().c_type_name(), p.name()), - format!("return (*{}) {};", b.type_().c_type_name(), p.name()), - ), - BindingParam::Value(v) => ( - format!("{} {} = ", v.type_().c_type_name(), v.name()), - format!("return ({}) {};", b.type_().c_type_name(), v.name()), - ), - BindingParam::Slice { .. } => unreachable!("return slices are not supported"), - }) - .unwrap_or((format!(""), format!("return;"))); - - let mut w = self.w.new_block(); - w.writeln(format!( - "{}{}({});", - ret_capture, - func.c_abi_func_name(), - arg_bindings, - )); - w.writeln(ret_statement); - } - self.w.eob().writeln("}"); - - Ok(()) - } -} - -pub trait CTypeName { - fn c_type_name(&self) -> String; -} - -impl CTypeName for AtomType { - fn c_type_name(&self) -> String { - match self { - AtomType::Bool => "bool", - AtomType::U8 => "uint8_t", - AtomType::U16 => "uint16_t", - AtomType::U32 => "uint32_t", - AtomType::U64 => "uint64_t", - AtomType::I8 => "int8_t", - AtomType::I16 => "int16_t", - AtomType::I32 => "int32_t", - AtomType::I64 => "int64_t", - AtomType::F32 => "float", - AtomType::F64 => "double", - } - .to_owned() - } -} - -impl CTypeName for AbiType { - fn c_type_name(&self) -> String { - AtomType::from(self.clone()).c_type_name() - } -} - -impl CTypeName for Datatype<'_> { - fn c_type_name(&self) -> String { - match self.variant() { - DatatypeVariant::Struct(_) => format!("struct {}", self.name()), - DatatypeVariant::Enum(_) => format!("enum {}", self.name()), - DatatypeVariant::Alias(_) => self.name().to_owned(), - DatatypeVariant::Atom(a) => a.c_type_name(), - } - } -} - -fn macro_for(prefix: &str, name: &str) -> String { - use heck::ShoutySnakeCase; - let mut macro_name = String::new(); - macro_name.push_str(&prefix.to_uppercase()); - macro_name.push('_'); - macro_name.push_str(&name.to_shouty_snake_case()); - macro_name -} - -impl Function<'_> { - fn c_abi_func_name(&self) -> String { - format!("_{}_{}", self.module().name(), self.name()) - } - fn c_abi_func_attributes(&self) -> String { - format!( - "__attribute__((import_module(\"{}\"),import_name(\"{}\")))", - self.module().name(), - self.name() - ) - } - fn c_idiomatic_func_name(&self) -> String { - format!("{}_{}", self.module().name(), self.name()) - } - - fn c_arg_bindings<'a>(&'a self) -> impl Iterator> { - self.bindings().filter(|b| !binding_is_ret(b)) - } - fn c_ret_bindings<'a>(&'a self) -> impl Iterator> { - self.bindings().filter(|b| binding_is_ret(b)) - } -} - -fn binding_is_ret(b: &FuncBinding) -> bool { - b.direction() == BindingDirection::Out && b.param().value().is_some() -} - -impl FuncBinding<'_> { - fn c_constness(&self) -> &'static str { - if self.direction() == BindingDirection::In - && (self.param().ptr().is_some() || self.param().slice().is_some()) - { - "const " - } else { - "" - } - } -} diff --git a/lucet-idl/src/config.rs b/lucet-idl/src/config.rs deleted file mode 100644 index d42a05803..000000000 --- a/lucet-idl/src/config.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::error::IDLError; - -#[derive(Clone, Debug)] -pub struct Config { - pub backend: Backend, -} - -impl Config { - pub fn parse(backend_opt: &str) -> Result { - let backend = Backend::from_str(backend_opt).ok_or_else(|| { - IDLError::UsageError(format!( - "Invalid backend: {}\nValid options are: {:?}", - backend_opt, - Backend::options() - )) - })?; - Ok(Self { backend }) - } -} - -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub enum Backend { - CGuest, - RustGuest, - RustHost, - Bindings, -} - -impl Backend { - pub fn from_str>(s: T) -> Option { - match s.as_ref() { - "c_guest" => Some(Backend::CGuest), - "rust_guest" => Some(Backend::RustGuest), - "rust_host" => Some(Backend::RustHost), - "bindings" => Some(Backend::Bindings), - _ => None, - } - } - pub fn options() -> Vec { - vec![ - "c_guest".to_owned(), - "rust_guest".to_owned(), - "rust_host".to_owned(), - "bindings".to_owned(), - ] - } -} diff --git a/lucet-idl/src/cursor.rs b/lucet-idl/src/cursor.rs deleted file mode 100644 index 64d114291..000000000 --- a/lucet-idl/src/cursor.rs +++ /dev/null @@ -1,628 +0,0 @@ -pub use crate::atoms::{AbiType, AtomType}; -use crate::repr::{ - AliasDatatypeRepr, BindingFromRepr, BindingIx, BindingRepr, DatatypeIdent, DatatypeIx, - DatatypeRepr, DatatypeVariantRepr, EnumDatatypeRepr, FuncIdent, FuncIx, FuncRepr, ModuleIx, - ModuleRepr, ParamIx, ParamRepr, StructDatatypeRepr, StructMemberRepr, -}; -pub use crate::repr::{BindingDirection, Package}; -use crate::MemArea; -use std::convert::TryFrom; - -impl Package { - pub fn module<'a>(&'a self, name: &str) -> Option> { - self.names - .iter() - .find(|(_, n)| *n == name) - .and_then(|(ix, _)| self.module_by_ix(ix)) - } - - fn all_modules<'a>(&'a self) -> impl Iterator> + 'a { - self.names.keys().map(move |ix| Module { pkg: &self, ix }) - } - - pub fn modules<'a>(&'a self) -> impl Iterator> + 'a { - self.all_modules().filter(|m| m.name() != "std") - } - - pub fn module_by_ix<'a>(&'a self, ix: ModuleIx) -> Option> { - if self.modules.is_valid(ix) { - Some(Module { pkg: &self, ix }) - } else { - None - } - } - - pub fn datatype_by_id<'a>(&'a self, id: DatatypeIdent) -> Option> { - self.module_by_ix(id.module) - .and_then(|m| m.datatype_by_ix(id.datatype)) - } -} - -#[derive(Debug, Clone)] -pub struct Module<'a> { - pkg: &'a Package, - ix: ModuleIx, -} - -impl<'a> Module<'a> { - fn repr(&self) -> &'a ModuleRepr { - self.pkg.modules.get(self.ix).expect("i exist") - } - - pub fn package(&self) -> &'a Package { - self.pkg - } - - pub fn name(&self) -> &str { - self.pkg.names.get(self.ix).expect("i exist") - } - - pub fn datatype(&self, name: &str) -> Option> { - if let Ok(atom) = AtomType::try_from(name) { - Some( - self.pkg - .datatype_by_id(atom.datatype_id()) - .expect("atom from id"), - ) - } else { - self.repr() - .datatypes - .names - .iter() - .find(|(_, n)| *n == name) - .and_then(|(ix, _)| self.datatype_by_ix(ix)) - } - } - - pub fn datatype_by_ix(&self, ix: DatatypeIx) -> Option> { - if self.repr().datatypes.datatypes.is_valid(ix) { - Some(Datatype { - pkg: self.pkg, - id: DatatypeIdent::new(self.ix, ix), - }) - } else { - None - } - } - - pub fn datatypes(&self) -> impl Iterator> { - let pkg = self.pkg; - let mix = self.ix; - self.repr() - .datatypes - .datatypes - .keys() - .map(move |ix| Datatype { - pkg, - id: DatatypeIdent::new(mix, ix), - }) - } - - pub fn function(&self, name: &str) -> Option> { - self.repr() - .funcs - .names - .iter() - .find(|(_, n)| *n == name) - .and_then(|(ix, _)| self.function_by_ix(ix)) - } - - pub fn function_by_ix(&self, ix: FuncIx) -> Option> { - if self.repr().funcs.funcs.is_valid(ix) { - Some(Function { - pkg: self.pkg, - id: FuncIdent::new(self.ix, ix), - }) - } else { - None - } - } - - pub fn functions(&self) -> impl Iterator> { - let pkg = self.pkg; - let mix = self.ix; - self.repr().funcs.funcs.keys().map(move |ix| Function { - pkg, - id: FuncIdent::new(mix, ix), - }) - } -} - -#[derive(Debug, Clone, Copy)] -pub struct Datatype<'a> { - pkg: &'a Package, - id: DatatypeIdent, -} - -impl<'a> Datatype<'a> { - fn repr(&self) -> &'a DatatypeRepr { - self.pkg - .modules - .get(self.id.module) - .expect("my mod exists") - .datatypes - .datatypes - .get(self.id.datatype) - .expect("i exist") - } - - pub fn id(&self) -> DatatypeIdent { - self.id - } - - pub fn name(&self) -> &'a str { - self.pkg - .modules - .get(self.id.module) - .expect("my mod exists") - .datatypes - .names - .get(self.id.datatype) - .expect("i exist") - } - - pub fn variant(&'a self) -> DatatypeVariant<'a> { - match self.repr().variant { - DatatypeVariantRepr::Atom(a) => DatatypeVariant::Atom(a), - DatatypeVariantRepr::Struct(ref repr) => DatatypeVariant::Struct(StructDatatype { - datatype: *self, - repr: &repr, - }), - DatatypeVariantRepr::Enum(ref repr) => DatatypeVariant::Enum(EnumDatatype { - datatype: *self, - repr: &repr, - }), - DatatypeVariantRepr::Alias(ref repr) => DatatypeVariant::Alias(AliasDatatype { - datatype: *self, - repr: &repr, - }), - } - } - - pub fn abi_type(&self) -> Option { - self.variant().abi_type() - } - - pub fn canonicalize(&self) -> Datatype<'a> { - match self.repr().variant { - DatatypeVariantRepr::Alias(ref repr) => AliasDatatype { - datatype: *self, - repr: &repr, - } - .canonicalize(), - _ => *self, - } - } - - pub fn contains_floats(&self) -> bool { - match self.variant() { - DatatypeVariant::Struct(s) => { - s.members().find(|m| m.type_().contains_floats()).is_some() - } - DatatypeVariant::Alias(a) => a.to().contains_floats(), - DatatypeVariant::Enum { .. } => false, - DatatypeVariant::Atom(AtomType::F32) | DatatypeVariant::Atom(AtomType::F64) => true, - DatatypeVariant::Atom(_) => false, - } - } - pub fn contains_enums(&self) -> bool { - match self.variant() { - DatatypeVariant::Struct(s) => { - s.members().find(|m| m.type_().contains_enums()).is_some() - } - DatatypeVariant::Alias(a) => a.to().contains_enums(), - DatatypeVariant::Enum { .. } => true, - DatatypeVariant::Atom { .. } => false, - } - } -} - -impl<'a> MemArea for Datatype<'a> { - fn mem_size(&self) -> usize { - self.repr().mem_size - } - fn mem_align(&self) -> usize { - self.repr().mem_align - } -} - -#[derive(Debug, Clone)] -pub enum DatatypeVariant<'a> { - Atom(AtomType), - Struct(StructDatatype<'a>), - Enum(EnumDatatype<'a>), - Alias(AliasDatatype<'a>), -} - -impl<'a> DatatypeVariant<'a> { - pub fn abi_type(&self) -> Option { - match self { - DatatypeVariant::Atom(a) => Some(AbiType::smallest_representation(a)), - DatatypeVariant::Struct(_) => None, - DatatypeVariant::Enum(_) => Some(AbiType::I32), - DatatypeVariant::Alias(a) => a.to().abi_type(), - } - } - - pub fn atom(self) -> Option { - match self { - DatatypeVariant::Atom(a) => Some(a), - _ => None, - } - } - pub fn struct_(self) -> Option> { - match self { - DatatypeVariant::Struct(s) => Some(s), - _ => None, - } - } - pub fn enum_(self) -> Option> { - match self { - DatatypeVariant::Enum(e) => Some(e), - _ => None, - } - } - pub fn alias(self) -> Option> { - match self { - DatatypeVariant::Alias(a) => Some(a), - _ => None, - } - } -} - -#[derive(Debug, Clone, Copy)] -pub struct StructDatatype<'a> { - datatype: Datatype<'a>, - repr: &'a StructDatatypeRepr, -} - -impl<'a> StructDatatype<'a> { - pub fn member(&self, name: &str) -> Option> { - self.members().find(|m| m.name() == name) - } - - pub fn members(&self) -> impl Iterator> { - let struct_ = *self; - self.repr - .members - .iter() - .map(move |repr| StructMember { struct_, repr }) - } - - pub fn datatype(&self) -> Datatype<'a> { - self.datatype - } -} - -impl<'a> From> for Datatype<'a> { - fn from(s: StructDatatype<'a>) -> Datatype<'a> { - s.datatype - } -} - -#[derive(Debug, Clone, Copy)] -pub struct StructMember<'a> { - struct_: StructDatatype<'a>, - repr: &'a StructMemberRepr, -} - -impl<'a> StructMember<'a> { - pub fn name(&self) -> &str { - &self.repr.name - } - pub fn offset(&self) -> usize { - self.repr.offset - } - pub fn type_(&self) -> Datatype<'a> { - Datatype { - pkg: self.struct_.datatype.pkg, - id: self.repr.type_, - } - } - pub fn struct_(&self) -> StructDatatype<'a> { - self.struct_ - } -} - -#[derive(Debug, Clone, Copy)] -pub struct EnumDatatype<'a> { - datatype: Datatype<'a>, - repr: &'a EnumDatatypeRepr, -} - -impl<'a> EnumDatatype<'a> { - pub fn variants(&self) -> impl Iterator> { - let enum_ = *self; - (0..self.repr.members.len()) - .into_iter() - .map(move |ix| EnumVariant { enum_, index: ix }) - } - - pub fn variant(&self, name: &str) -> Option> { - self.variants().find(|v| v.name() == name) - } - - pub fn datatype(&self) -> Datatype<'a> { - self.datatype - } -} - -impl<'a> From> for Datatype<'a> { - fn from(e: EnumDatatype<'a>) -> Datatype<'a> { - e.datatype - } -} - -#[derive(Debug, Clone, Copy)] -pub struct EnumVariant<'a> { - enum_: EnumDatatype<'a>, - index: usize, -} - -impl<'a> EnumVariant<'a> { - pub fn enum_(&self) -> EnumDatatype<'a> { - self.enum_ - } - pub fn name(&self) -> &str { - &self.enum_.repr.members[self.index].name - } - pub fn index(&self) -> usize { - self.index - } -} - -#[derive(Debug, Clone)] -pub struct AliasDatatype<'a> { - datatype: Datatype<'a>, - repr: &'a AliasDatatypeRepr, -} - -impl<'a> AliasDatatype<'a> { - pub fn to(&self) -> Datatype<'a> { - Datatype { - pkg: self.datatype.pkg, - id: self.repr.to, - } - } - - /// Find the non-alias datatype that this alias transitively refers to. - pub fn canonicalize(&self) -> Datatype<'a> { - // We can't just call this recursively because - // of the borrow checker, so we have to recurse in a loop :/ - let mut referent = Datatype { - pkg: self.datatype.pkg, - id: self.repr.to, - }; - while let DatatypeVariant::Alias(a) = referent.variant() { - referent.id = a.datatype.id; - } - Datatype { - pkg: self.datatype.pkg, - id: referent.id, - } - } - - pub fn datatype(&self) -> Datatype<'a> { - self.datatype - } -} - -impl<'a> From> for Datatype<'a> { - fn from(a: AliasDatatype<'a>) -> Datatype<'a> { - a.datatype - } -} - -#[derive(Debug, Clone, Copy)] -pub struct Function<'a> { - pkg: &'a Package, - id: FuncIdent, -} - -impl<'a> Function<'a> { - fn repr(&self) -> &'a FuncRepr { - &self.pkg.modules[self.id.module].funcs.funcs[self.id.func] - } - - pub fn name(&self) -> &str { - &self.pkg.modules[self.id.module].funcs.names[self.id.func] - } - - pub fn arg(&self, name: &str) -> Option> { - let func = *self; - self.repr() - .args - .iter() - .find(|(_, param)| param.name == name) - .map(move |(ix, _)| FuncParam { - func, - ix: ParamIx::Arg(ix), - }) - } - - pub fn args(&self) -> impl Iterator> { - let func = *self; - self.repr().args.iter().map(move |(ix, _)| FuncParam { - func, - ix: ParamIx::Arg(ix), - }) - } - - pub fn ret(&self, name: &str) -> Option> { - let func = *self; - self.repr() - .rets - .iter() - .find(|(_, param)| param.name == name) - .map(move |(ix, _)| FuncParam { - func, - ix: ParamIx::Ret(ix), - }) - } - - pub fn rets(&self) -> impl Iterator> { - let func = *self; - self.repr().rets.iter().map(move |(ix, _)| FuncParam { - func, - ix: ParamIx::Ret(ix), - }) - } - - pub fn param(&self, name: &str) -> Option> { - self.arg(name).or_else(|| self.ret(name)) - } - - pub fn params(&self) -> impl Iterator> { - self.args().chain(self.rets()) - } - - pub fn binding(&self, name: &str) -> Option> { - let func = *self; - self.repr() - .bindings - .iter() - .find(|(_, bind)| bind.name == name) - .map(move |(ix, _)| FuncBinding { func, ix }) - } - - pub fn bindings(&self) -> impl Iterator> { - let func = *self; - self.repr() - .bindings - .iter() - .map(move |(ix, _)| FuncBinding { func, ix }) - } - - pub fn module(&self) -> Module<'a> { - Module { - pkg: self.pkg, - ix: self.id.module, - } - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum ParamPosition { - Arg(usize), - Ret(usize), -} - -#[derive(Debug, Clone, Copy)] -pub struct FuncParam<'a> { - func: Function<'a>, - ix: ParamIx, -} - -impl<'a> FuncParam<'a> { - fn repr(&self) -> &'a ParamRepr { - match self.ix { - ParamIx::Arg(ix) => &self.func.repr().args[ix], - ParamIx::Ret(ix) => &self.func.repr().rets[ix], - } - } - pub fn name(&self) -> &str { - &self.repr().name - } - pub fn abi_type(&self) -> AbiType { - self.repr().type_ - } - pub fn type_(&self) -> Datatype<'a> { - self.func - .pkg - .datatype_by_id(AtomType::from(self.repr().type_).datatype_id()) - .expect("valid type") - } - pub fn param_position(&self) -> ParamPosition { - match self.ix { - ParamIx::Arg(ix) => ParamPosition::Arg(ix.as_u32() as usize), - ParamIx::Ret(ix) => ParamPosition::Ret(ix.as_u32() as usize), - } - } - pub fn binding(&self) -> FuncBinding<'a> { - let func = self.func; - self.func - .repr() - .bindings - .iter() - .find(|(_ix, b)| match b.from { - BindingFromRepr::Ptr(ix) | BindingFromRepr::Value(ix) => ix == self.ix, - BindingFromRepr::Slice(ptr_ix, len_ix) => ptr_ix == self.ix || len_ix == self.ix, - }) - .map(|(ix, _)| FuncBinding { func, ix }) - .expect("must be a binding for param") - } -} - -#[derive(Debug, Clone)] -pub struct FuncBinding<'a> { - func: Function<'a>, - ix: BindingIx, -} - -impl<'a> FuncBinding<'a> { - fn repr(&self) -> &'a BindingRepr { - &self.func.repr().bindings[self.ix] - } - pub fn name(&self) -> &str { - &self.repr().name - } - pub fn type_(&self) -> Datatype<'a> { - self.func - .pkg - .datatype_by_id(self.repr().type_) - .expect("valid type") - } - pub fn direction(&self) -> BindingDirection { - self.repr().direction - } - pub fn param(&self) -> BindingParam<'a> { - match self.repr().from { - BindingFromRepr::Ptr(ix) => BindingParam::Ptr(FuncParam { - func: self.func, - ix, - }), - BindingFromRepr::Slice(ptr_ix, len_ix) => BindingParam::Slice( - FuncParam { - func: self.func, - ix: ptr_ix, - }, - FuncParam { - func: self.func, - ix: len_ix, - }, - ), - BindingFromRepr::Value(ix) => BindingParam::Value(FuncParam { - func: self.func, - ix, - }), - } - } -} - -#[derive(Debug, Clone, Copy)] -pub enum BindingParam<'a> { - Ptr(FuncParam<'a>), - Slice(FuncParam<'a>, FuncParam<'a>), - Value(FuncParam<'a>), -} - -impl<'a> BindingParam<'a> { - pub fn ptr(self) -> Option> { - match self { - BindingParam::Ptr(p) => Some(p), - _ => None, - } - } - pub fn slice(self) -> Option<(FuncParam<'a>, FuncParam<'a>)> { - match self { - BindingParam::Slice(p, l) => Some((p, l)), - _ => None, - } - } - pub fn value(self) -> Option> { - match self { - BindingParam::Value(v) => Some(v), - _ => None, - } - } -} diff --git a/lucet-idl/src/error.rs b/lucet-idl/src/error.rs deleted file mode 100644 index d6ddbcb21..000000000 --- a/lucet-idl/src/error.rs +++ /dev/null @@ -1,76 +0,0 @@ -use crate::parser; -use crate::Location; -use std::io; - -#[derive(Debug, Fail)] -pub enum IDLError { - #[fail(display = "Internal error: {}", _0)] - InternalError(&'static str), - #[fail(display = "Incorrect usage: {}", _0)] - UsageError(String), - #[fail(display = "{}", _0)] - ParseError(#[cause] parser::ParseError), - #[fail(display = "{}", _0)] - ValidationError(#[cause] ValidationError), - #[fail(display = "{}", _0)] - Io(#[cause] io::Error), -} - -impl From for IDLError { - fn from(e: io::Error) -> Self { - IDLError::Io(e) - } -} - -impl From for IDLError { - fn from(e: parser::ParseError) -> Self { - IDLError::ParseError(e) - } -} - -impl From for IDLError { - fn from(e: ValidationError) -> Self { - IDLError::ValidationError(e) - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Fail)] -pub enum ValidationError { - #[fail(display = "Redefinition of name `{}`", name)] - NameAlreadyExists { - name: String, - at_location: Location, - previous_location: Location, - }, - #[fail(display = "Use of unknown name `{}`", name)] - NameNotFound { - name: String, - use_location: Location, - }, - #[fail(display = "Empty definition for `{}`", name)] - Empty { name: String, location: Location }, - #[fail(display = "Infinite definition for `{}`", name)] - Infinite { name: String, location: Location }, - #[fail(display = "Syntax error: expected {}", expected)] - Syntax { - expected: &'static str, - location: Location, - }, - #[fail(display = "Name `{}` bound to another sort", name)] - NameSortError { - name: String, - use_location: Location, - bound_location: Location, - }, - #[fail(display = "Name `{}` already bound", name)] - BindingNameAlreadyBound { - name: String, - at_location: Location, - bound_location: Location, - }, - #[fail(display = "Binding type error: expected {}", expected)] - BindingTypeError { - expected: &'static str, - location: Location, - }, -} diff --git a/lucet-idl/src/lexer.rs b/lucet-idl/src/lexer.rs deleted file mode 100644 index 59b86e60a..000000000 --- a/lucet-idl/src/lexer.rs +++ /dev/null @@ -1,342 +0,0 @@ -use crate::Location; -use std::str::CharIndices; - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum Token<'a> { - LPar, // ( - RPar, // ) - LBrace, // { - RBrace, // } - LBracket, // [ - RBracket, // ] - Star, // * - Colon, // : - Semi, // ; - Comma, // , - Hash, // # - Equals, // = - LArrow, // <- - RArrow, // -> - Word(&'a str), - Quote(&'a str), // Found between balanced "". No escaping. -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub struct LocatedToken<'a> { - pub token: Token<'a>, - pub location: Location, -} - -fn token(token: Token<'_>, location: Location) -> Result, LocatedError> { - Ok(LocatedToken { token, location }) -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum LexError { - InvalidChar(char), - UnterminatedComment, - UnterminatedQuote, -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub struct LocatedError { - pub error: LexError, - pub location: Location, -} - -fn error<'a>(error: LexError, location: Location) -> Result, LocatedError> { - Err(LocatedError { error, location }) -} - -pub struct Lexer<'a> { - source: &'a str, - chars: CharIndices<'a>, - lookahead: Option, - pos: usize, - line_number: usize, - column_start: usize, - tab_compensation: usize, -} - -impl<'a> Lexer<'a> { - pub fn new(s: &'a str) -> Lexer<'_> { - let mut lex = Lexer { - source: s, - chars: s.char_indices(), - lookahead: None, - pos: 0, - line_number: 1, - column_start: 0, - tab_compensation: 0, - }; - lex.next_ch(); - lex - } - - fn next_ch(&mut self) -> Option { - if self.lookahead == Some('\n') { - self.line_number += 1; - self.column_start = self.pos + 1; // Next column starts a fresh line - self.tab_compensation = 0; - } else if self.lookahead == Some('\t') { - self.tab_compensation += 7; // One column for the position of the char itself, add 7 more for a tabwidth of 8 - } - match self.chars.next() { - Some((idx, ch)) => { - self.pos = idx; - self.lookahead = Some(ch); - } - None => { - self.pos = self.source.len(); - self.lookahead = None; - } - } - self.lookahead - } - - fn loc(&self) -> Location { - Location { - line: self.line_number, - column: self.pos - self.column_start + self.tab_compensation, - } - } - - fn looking_at(&self, prefix: &str) -> bool { - self.source[self.pos..].starts_with(prefix) - } - - fn scan_char(&mut self, tok: Token<'a>) -> Result, LocatedError> { - assert!(self.lookahead.is_some()); - let loc = self.loc(); - self.next_ch(); - token(tok, loc) - } - - pub fn rest_of_line(&mut self) -> &'a str { - let begin = self.pos; - loop { - match self.next_ch() { - None | Some('\n') => return &self.source[begin..self.pos], - _ => {} - } - } - } - - fn scan_word(&mut self) -> Result, LocatedError> { - let begin = self.pos; - let loc = self.loc(); - assert!(self.lookahead == Some('_') || self.lookahead.unwrap().is_alphabetic()); - loop { - match self.next_ch() { - Some('_') => {} - Some(ch) if ch.is_alphanumeric() => {} - _ => break, - } - } - let text = &self.source[begin..self.pos]; - token(Token::Word(text), loc) - } - - fn scan_comment(&mut self) -> Result<(), LocatedError> { - assert!(self.lookahead == Some('/')); - let loc = self.loc(); - loop { - match self.next_ch() { - None => Err(LocatedError { - error: LexError::UnterminatedComment, - location: loc, - })?, - Some('*') => { - if self.looking_at("*/") { - self.next_ch(); // Consume the slash - self.next_ch(); // Move to next token for outer loop - break; - } - } - Some(_) => {} - } - } - Ok(()) - } - - fn scan_quote(&mut self) -> Result, LocatedError> { - let begin = self.pos; - let loc = self.loc(); - assert!(self.lookahead == Some('"')); - loop { - match self.next_ch() { - None => Err(LocatedError { - error: LexError::UnterminatedQuote, - location: loc, - })?, - Some('"') => { - self.next_ch(); - break; - } - _ => {} - } - } - let text = &self.source[(begin + 1)..(self.pos - 1)]; - token(Token::Quote(text), loc) - } - - #[allow(clippy::should_implement_trait)] - pub fn next(&mut self) -> Option, LocatedError>> { - loop { - let loc = self.loc(); - return match self.lookahead { - None => None, - Some(c) => Some(match c { - '(' => self.scan_char(Token::LPar), - ')' => self.scan_char(Token::RPar), - '{' => self.scan_char(Token::LBrace), - '}' => self.scan_char(Token::RBrace), - '[' => self.scan_char(Token::LBracket), - ']' => self.scan_char(Token::RBracket), - '*' => self.scan_char(Token::Star), - ':' => self.scan_char(Token::Colon), - ';' => self.scan_char(Token::Semi), - ',' => self.scan_char(Token::Comma), - '#' => self.scan_char(Token::Hash), - '=' => self.scan_char(Token::Equals), - '-' => { - if self.looking_at("->") { - self.next_ch(); // Consume - - self.next_ch(); // Consume > - token(Token::RArrow, loc) - } else { - self.next_ch(); - error(LexError::InvalidChar('-'), loc) - } - } - '<' => { - if self.looking_at("<-") { - self.next_ch(); // Consume < - self.next_ch(); // Consume - - token(Token::LArrow, loc) - } else { - self.next_ch(); - error(LexError::InvalidChar('<'), loc) - } - } - '/' => { - if self.looking_at("//") { - self.rest_of_line(); - continue; - } else if self.looking_at("/*") { - match self.scan_comment() { - Ok(()) => continue, - Err(e) => return Some(Err(e)), - } - } else { - self.next_ch(); - error(LexError::InvalidChar('/'), loc) - } - } - '"' => self.scan_quote(), - ch if ch.is_alphabetic() => self.scan_word(), - ch if ch.is_whitespace() => { - self.next_ch(); - continue; - } - _ => { - self.next_ch(); - error(LexError::InvalidChar(c), loc) - } - }), - }; - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn token( - token: Token<'_>, - line: usize, - column: usize, - ) -> Option, LocatedError>> { - Some(super::token(token, Location { line, column })) - } - - fn error<'a>( - err: LexError, - line: usize, - column: usize, - ) -> Option, LocatedError>> { - Some(super::error(err, Location { line, column })) - } - - #[test] - fn comments() { - let mut lex = Lexer::new("the quick // brown fox\njumped\n//over the three\nlazy//dogs"); - assert_eq!(lex.next(), token(Token::Word("the"), 1, 0)); - assert_eq!(lex.next(), token(Token::Word("quick"), 1, 4)); - assert_eq!(lex.next(), token(Token::Word("jumped"), 2, 0)); - assert_eq!(lex.next(), token(Token::Word("lazy"), 4, 0)); - assert_eq!(lex.next(), None); - - let mut lex = Lexer::new("line1 //\nsym_2/#\n\t\tl3///333"); - assert_eq!(lex.next(), token(Token::Word("line1"), 1, 0)); - assert_eq!(lex.next(), token(Token::Word("sym_2"), 2, 0)); - assert_eq!(lex.next(), error(LexError::InvalidChar('/'), 2, 5)); - assert_eq!(lex.next(), token(Token::Hash, 2, 6)); - assert_eq!(lex.next(), token(Token::Word("l3"), 3, 16)); // Two tabs = 16 columns - assert_eq!(lex.next(), None); - - let mut lex = Lexer::new("a /* b */ c"); - assert_eq!(lex.next(), token(Token::Word("a"), 1, 0)); - assert_eq!(lex.next(), token(Token::Word("c"), 1, 10)); - - let mut lex = Lexer::new("a /* b \n*/ c\n/*"); - assert_eq!(lex.next(), token(Token::Word("a"), 1, 0)); - assert_eq!(lex.next(), token(Token::Word("c"), 2, 3)); - assert_eq!(lex.next(), error(LexError::UnterminatedComment, 3, 0)); - } - - #[test] - fn quotes() { - let mut lex = Lexer::new("a \"bc\" d"); - assert_eq!(lex.next(), token(Token::Word("a"), 1, 0)); - assert_eq!(lex.next(), token(Token::Quote("bc"), 1, 2)); - assert_eq!(lex.next(), token(Token::Word("d"), 1, 7)); - - let mut lex = Lexer::new("a \"b\nc\" d"); - assert_eq!(lex.next(), token(Token::Word("a"), 1, 0)); - assert_eq!(lex.next(), token(Token::Quote("b\nc"), 1, 2)); - assert_eq!(lex.next(), token(Token::Word("d"), 2, 3)); - - let mut lex = Lexer::new("a \"b"); - assert_eq!(lex.next(), token(Token::Word("a"), 1, 0)); - assert_eq!(lex.next(), error(LexError::UnterminatedQuote, 1, 2)); - } - #[test] - fn punctuation() { - let mut lex = Lexer::new("{} () [] *#=:,;"); - assert_eq!(lex.next(), token(Token::LBrace, 1, 0)); - assert_eq!(lex.next(), token(Token::RBrace, 1, 1)); - assert_eq!(lex.next(), token(Token::LPar, 1, 3)); - assert_eq!(lex.next(), token(Token::RPar, 1, 4)); - assert_eq!(lex.next(), token(Token::LBracket, 1, 6)); - assert_eq!(lex.next(), token(Token::RBracket, 1, 7)); - assert_eq!(lex.next(), token(Token::Star, 1, 9)); - assert_eq!(lex.next(), token(Token::Hash, 1, 10)); - assert_eq!(lex.next(), token(Token::Equals, 1, 11)); - assert_eq!(lex.next(), token(Token::Colon, 1, 12)); - assert_eq!(lex.next(), token(Token::Comma, 1, 13)); - assert_eq!(lex.next(), token(Token::Semi, 1, 14)); - assert_eq!(lex.next(), None); - } - - #[test] - fn arrows() { - let mut lex = Lexer::new("<-->\n<- ->"); - assert_eq!(lex.next(), token(Token::LArrow, 1, 0)); - assert_eq!(lex.next(), token(Token::RArrow, 1, 2)); - assert_eq!(lex.next(), token(Token::LArrow, 2, 0)); - assert_eq!(lex.next(), token(Token::RArrow, 2, 3)); - assert_eq!(lex.next(), None); - } -} diff --git a/lucet-idl/src/lib.rs b/lucet-idl/src/lib.rs deleted file mode 100644 index d2ffbfe6a..000000000 --- a/lucet-idl/src/lib.rs +++ /dev/null @@ -1,95 +0,0 @@ -#![deny(bare_trait_objects)] - -#[macro_use] -extern crate failure; - -mod atoms; -mod c; -mod config; -mod cursor; -mod error; -mod lexer; -mod parser; -mod prelude; -pub mod pretty_writer; -mod repr; -mod rust; -mod validate; - -pub use crate::atoms::{AbiType, AtomType}; -pub use crate::config::{Backend, Config}; -pub use crate::cursor::{ - AliasDatatype, BindingDirection, BindingParam, Datatype, DatatypeVariant, EnumDatatype, - EnumVariant, FuncBinding, FuncParam, Function, Module, Package, ParamPosition, StructDatatype, - StructMember, -}; -pub use crate::error::{IDLError, ValidationError}; -pub use crate::rust::{ - RustFunc, RustIdiomArg, RustIdiomRet, RustName, RustTupleSyntax, RustTypeName, -}; - -use crate::c::CGenerator; -use crate::parser::Parser; -use crate::rust::RustGenerator; -use crate::validate::package_from_declarations; -use lucet_module::bindings::Bindings; -use std::collections::HashMap; -use std::fs; -use std::io::Write; -use std::path::Path; - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] -pub struct Location { - pub line: usize, - pub column: usize, -} - -pub trait MemArea { - fn mem_size(&self) -> usize; - fn mem_align(&self) -> usize; -} - -pub fn parse_package(input: &str) -> Result { - let mut parser = Parser::new(&input); - let decls = parser.match_package_decls()?; - let pkg = package_from_declarations(&decls)?; - Ok(pkg) -} - -pub fn codegen(package: &Package, config: &Config, output: Box) -> Result<(), IDLError> { - match config.backend { - Backend::CGuest => CGenerator::new(output).generate_guest(package)?, - Backend::RustGuest => RustGenerator::new(output).generate_guest(package)?, - Backend::RustHost => RustGenerator::new(output).generate_host(package)?, - Backend::Bindings => generate_bindings(&package.bindings(), output)?, - } - Ok(()) -} - -pub fn run(config: &Config, input_path: &Path, output: Box) -> Result<(), IDLError> { - let input = fs::read_to_string(input_path)?; - let pkg = parse_package(&input)?; - codegen(&pkg, config, output) -} - -impl Package { - pub fn bindings(&self) -> Bindings { - let mut bs = HashMap::new(); - for m in self.modules() { - let mut mod_bs = HashMap::new(); - for f in m.functions() { - mod_bs.insert(f.name().to_owned(), f.host_func_name()); - } - bs.insert(m.name().to_owned(), mod_bs); - } - Bindings::new(bs) - } -} - -fn generate_bindings(bindings: &Bindings, mut output: Box) -> Result<(), IDLError> { - let bindings_json = bindings - .to_string() - .map_err(|_| IDLError::InternalError("bindings generation"))?; - output.write_all(bindings_json.as_bytes())?; - Ok(()) -} diff --git a/lucet-idl/src/main.rs b/lucet-idl/src/main.rs deleted file mode 100644 index 6e30ac8d2..000000000 --- a/lucet-idl/src/main.rs +++ /dev/null @@ -1,79 +0,0 @@ -#[macro_use] -extern crate clap; - -use clap::Arg; -use lucet_idl::{run, Config, IDLError}; -use std::fs::File; -use std::io; -use std::io::prelude::*; -use std::path::PathBuf; -use std::process; - -#[derive(Clone, Debug)] -pub struct ExeConfig { - pub input_path: PathBuf, - pub output_path: Option, - pub config: Config, -} - -impl ExeConfig { - pub fn parse() -> Result { - let _ = include_str!("../Cargo.toml"); - let matches = app_from_crate!() - .arg( - Arg::with_name("input") - .required(true) - .help("Path to the input file"), - ) - .arg( - Arg::with_name("backend") - .short("b") - .long("backend") - .default_value("c_guest") - .takes_value(true) - .required(false) - .help("Backend, one of: c_guest, rust_guest, rust_host"), - ) - .arg( - Arg::with_name("output") - .short("o") - .takes_value(true) - .required(false) - .help("output path"), - ) - .get_matches(); - let input_path = PathBuf::from( - matches - .value_of("input") - .ok_or(IDLError::UsageError("Input file required".to_owned()))?, - ); - let output_path = matches.value_of("output").map(PathBuf::from); - let config = Config::parse(matches.value_of("backend").unwrap())?; - Ok(ExeConfig { - input_path, - output_path, - config, - }) - } -} -fn doit() -> Result<(), IDLError> { - let exe_config = ExeConfig::parse()?; - let mut source = String::new(); - File::open(&exe_config.input_path)?.read_to_string(&mut source)?; - - let output: Box = match exe_config.output_path { - Some(ref p) => Box::new(File::create(p)?), - None => Box::new(io::stdout()), - }; - - run(&exe_config.config, &exe_config.input_path, output)?; - - Ok(()) -} - -fn main() { - if let Err(e) = doit() { - eprintln!("{}", e); - process::exit(1); - } -} diff --git a/lucet-idl/src/parser.rs b/lucet-idl/src/parser.rs deleted file mode 100644 index e076e5230..000000000 --- a/lucet-idl/src/parser.rs +++ /dev/null @@ -1,1201 +0,0 @@ -use super::lexer::{LexError, Lexer, LocatedError, LocatedToken, Token}; -use super::Location; -use std::error::Error; -use std::fmt; - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum PackageDecl<'a> { - Module { - name: &'a str, - decls: Vec>, - location: Location, - }, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum ModuleDecl<'a> { - Struct { - name: &'a str, - members: Vec>, - location: Location, - }, - Enum { - name: &'a str, - variants: Vec>, - location: Location, - }, - Alias { - name: &'a str, - what: SyntaxIdent<'a>, - location: Location, - }, - Function { - name: &'a str, - args: Vec>, - rets: Vec>, - bindings: Vec>, - location: Location, - }, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct SyntaxIdent<'a> { - pub name: &'a str, - pub location: Location, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct StructMember<'a> { - pub name: &'a str, - pub type_: SyntaxIdent<'a>, - pub location: Location, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct EnumVariant<'a> { - pub name: &'a str, - pub location: Location, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct FuncArgSyntax<'a> { - pub name: &'a str, - pub type_: SyntaxIdent<'a>, - pub location: Location, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct ParseError { - pub location: Location, - pub message: String, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum BindingDirSyntax { - In, - Out, - InOut, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct BindingSyntax<'a> { - pub name: &'a str, - pub type_: SyntaxIdent<'a>, - pub direction: BindingDirSyntax, - pub from: BindingRefSyntax<'a>, - pub location: Location, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum BindingRefSyntax<'a> { - Ptr(Box>), - Slice(Box>, Box>), - Name(&'a str), -} - -impl fmt::Display for ParseError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "Parse error at line {} column {}: {}", - self.location.line, self.location.column, self.message - ) - } -} - -impl Error for ParseError { - fn description(&self) -> &str { - "Parse error" - } -} - -macro_rules! parse_err { - ($loc:expr, $msg: expr ) => { - Err(ParseError { - location: $loc.clone(), - message: $msg.to_string(), - }) - }; - - ($loc:expr, $fmt:expr, $( $arg:expr),+ ) => { - Err(ParseError { - location: $loc.clone(), - message: format!( $fmt, $( $arg ),+ ), - }) - }; -} -macro_rules! err_ctx { - ($ctx:expr, $res:expr) => { - match $res { - Ok(a) => Ok(a), - Err(ParseError { location, message }) => Err(ParseError { - location, - message: format!("in {}:\n{}", $ctx, message), - }), - } - }; -} - -pub struct Parser<'a> { - lex: Lexer<'a>, - lookahead: Option>, - pub lex_error: Option, - location: Location, -} - -impl<'a> Parser<'a> { - pub fn new(text: &'a str) -> Parser<'_> { - Parser { - lex: Lexer::new(text), - lookahead: None, - lex_error: None, - location: Location { line: 0, column: 0 }, - } - } - fn consume(&mut self) -> Token<'a> { - self.lookahead.take().expect("no token to consume") - } - fn token(&mut self) -> Option> { - while self.lookahead == None { - match self.lex.next() { - Some(Ok(LocatedToken { token, location })) => { - self.location = location; - self.lookahead = Some(token) - } - Some(Err(LocatedError { error, location })) => { - self.location = location; - self.lex_error = Some(error); - break; - } - None => break, - } - } - self.lookahead - } - - fn match_token(&mut self, want: Token<'a>, err_msg: &str) -> Result, ParseError> { - if self.token() == Some(want) { - Ok(self.consume()) - } else { - parse_err!(self.location, err_msg) - } - } - - fn match_a_word(&mut self, err_msg: &str) -> Result<&'a str, ParseError> { - match self.token() { - Some(Token::Word(text)) => { - self.consume(); - Ok(text) - } - t => parse_err!(self.location, "{}, got {:?}", err_msg, t), - } - } - - fn match_ident(&mut self, err_msg: &str) -> Result, ParseError> { - match self.token() { - Some(Token::Word(name)) => { - let location = self.location; - self.consume(); - Ok(SyntaxIdent { name, location }) - } - _ => err_ctx!(err_msg, parse_err!(self.location, "expected identifier")), - } - } - - fn match_struct_body(&mut self) -> Result>, ParseError> { - let mut members = Vec::new(); - loop { - match self.token() { - Some(Token::RBrace) => { - self.consume(); - break; - } - Some(Token::Word(member_name)) => { - let location = self.location; - self.consume(); - self.match_token(Token::Colon, "expected :")?; - let member_ref = self.match_ident("expected member type")?; - members.push(StructMember { - name: member_name, - type_: member_ref, - location, - }); - match self.token() { - Some(Token::Comma) => { - self.consume(); - continue; - } - Some(Token::RBrace) => { - self.consume(); - break; - } - _ => parse_err!(self.location, "in struct body:\nexpected , or '}'")?, - } - } - _ => parse_err!( - self.location, - "in struct body:\nexpected member name or '}'" - )?, - } - } - Ok(members) - } - - fn match_enum_body(&mut self) -> Result>, ParseError> { - let mut names = Vec::new(); - loop { - match self.token() { - Some(Token::RBrace) => { - self.consume(); - break; - } - Some(Token::Word(name)) => { - let location = self.location; - self.consume(); - names.push(EnumVariant { - name: name, - location, - }); - match self.token() { - Some(Token::Comma) => { - self.consume(); - continue; - } - Some(Token::RBrace) => { - self.consume(); - break; - } - _ => parse_err!(self.location, "expected , or }}")?, - } - } - _ => parse_err!(self.location, "expected variant")?, - } - } - Ok(names) - } - - fn match_func_args(&mut self) -> Result>, ParseError> { - let mut args = Vec::new(); - loop { - match self.token() { - Some(Token::RPar) => { - self.consume(); - break; - } - Some(Token::Word(name)) => { - let location = self.location; - self.consume(); - self.match_token(Token::Colon, "expected :")?; - let type_ = self.match_ident("type name")?; - - args.push(FuncArgSyntax { - name, - type_, - location, - }); - match self.token() { - Some(Token::Comma) => { - self.consume(); - continue; - } - Some(Token::RPar) => { - self.consume(); - break; - } - _ => parse_err!(self.location, "expected , or )")?, - } - } - _ => parse_err!(self.location, "expected argument, or )")?, - } - } - Ok(args) - } - - fn match_func_rets(&mut self) -> Result>, ParseError> { - let mut args = Vec::new(); - loop { - match self.token() { - Some(Token::Semi) | Some(Token::Word("where")) => { - break; - } - Some(Token::Word(name)) => { - let location = self.location; - self.consume(); - self.match_token(Token::Colon, "expected :")?; - let type_ = self.match_ident("type name")?; - args.push(FuncArgSyntax { - type_, - name, - location, - }); - match self.token() { - Some(Token::Comma) => { - self.consume(); - continue; - } - Some(Token::Semi) | Some(Token::Word("where")) => { - break; - } - x => parse_err!(self.location, "expected ',', where, or ;, got {:?}", x)?, - } - } - x => parse_err!(self.location, "expected func return value, got {:?}", x)?, - } - } - Ok(args) - } - - fn match_binding_exprs(&mut self) -> Result>, ParseError> { - let mut bindings = Vec::new(); - loop { - match self.token() { - Some(Token::Semi) => { - self.consume(); - break; - } - Some(Token::Word(name)) => { - let location = self.location; - self.consume(); - self.match_token(Token::Colon, "expected :")?; - let direction = self.match_bind_direction()?; - let type_ = self.match_ident("type name")?; - self.match_token(Token::LArrow, "expected <-")?; - let from = self.match_binding_ref()?; - bindings.push(BindingSyntax { - name, - type_, - direction, - from, - location, - }); - match self.token() { - Some(Token::Semi) => { - self.consume(); - break; - } - Some(Token::Comma) => { - self.consume(); - continue; - } - _ => parse_err!(self.location, "expected , or ;")?, - } - } - _ => parse_err!(self.location, "expected binding expression")?, - } - } - Ok(bindings) - } - - fn match_bind_direction(&mut self) -> Result { - match self.token() { - Some(Token::Word("in")) => { - self.consume(); - Ok(BindingDirSyntax::In) - } - Some(Token::Word("inout")) => { - self.consume(); - Ok(BindingDirSyntax::InOut) - } - Some(Token::Word("out")) => { - self.consume(); - Ok(BindingDirSyntax::Out) - } - _ => parse_err!(self.location, "expected binding direction (in, out, inout)"), - } - } - - fn match_binding_ref(&mut self) -> Result, ParseError> { - match self.token() { - Some(Token::Star) => { - self.consume(); - Ok(BindingRefSyntax::Ptr(Box::new(self.match_binding_ref()?))) - } - Some(Token::Word(name)) => { - self.consume(); - Ok(BindingRefSyntax::Name(name)) - } - Some(Token::LBracket) => { - self.consume(); - let ptr_arg = self.match_binding_ref()?; - let _ = self.match_token(Token::Comma, ", in binding ref slice"); - let len_arg = self.match_binding_ref()?; - let _ = self.match_token(Token::RBracket, "] at end of binding ref slice"); - Ok(BindingRefSyntax::Slice( - Box::new(ptr_arg), - Box::new(len_arg), - )) - } - x => parse_err!(self.location, "expected binding ref, got {:?}", x), - } - } - - pub fn match_module_decl(&mut self) -> Result, ParseError> { - match self.token() { - Some(Token::Word("struct")) => { - let location = self.location; - self.consume(); - let name = self.match_a_word("expected struct name")?; - self.match_token(Token::LBrace, "expected {")?; - let members = self.match_struct_body()?; - Ok(ModuleDecl::Struct { - name, - members, - location, - }) - } - Some(Token::Word("enum")) => { - let location = self.location; - self.consume(); - let name = self.match_a_word("expected enum name")?; - self.match_token(Token::LBrace, "expected {")?; - let variants = self.match_enum_body()?; - Ok(ModuleDecl::Enum { - name, - variants, - location, - }) - } - Some(Token::Word("type")) => { - let location = self.location; - self.consume(); - let name = self.match_a_word("expected type name")?; - self.match_token(Token::Equals, "expected =")?; - let what = self.match_ident("type value")?; - self.match_token(Token::Semi, "expected ;")?; - Ok(ModuleDecl::Alias { - name, - what, - location, - }) - } - Some(Token::Word("fn")) => { - let location = self.location; - self.consume(); - let name = self.match_a_word("expected function name")?; - - self.match_token(Token::LPar, "expected (")?; - let args = self.match_func_args()?; - let rets = if let Some(Token::RArrow) = self.token() { - self.consume(); - self.match_func_rets()? - } else { - Vec::new() - }; - - let bindings = match self.token() { - Some(Token::Semi) => { - self.consume(); - Vec::new() - } - Some(Token::Word("where")) => { - self.consume(); - self.match_binding_exprs()? - } - t => parse_err!(self.location, "expected where, -> or ;, got {:?}", t)?, - }; - - Ok(ModuleDecl::Function { - name, - args, - rets, - bindings, - location, - }) - } - Some(_) | None => parse_err!(self.location, "expected module declaration"), - } - } - - #[cfg(test)] - pub fn match_module_decls(&mut self) -> Result>, ParseError> { - let mut decls = Vec::new(); - while self.token().is_some() { - decls.push(self.match_module_decl()?); - } - Ok(decls) - } - - pub fn match_package_decl(&mut self) -> Result, ParseError> { - match self.token() { - Some(Token::Word("mod")) => { - let location = self.location; - self.consume(); - let name = self.match_a_word("expected module name")?; - self.match_token(Token::LBrace, "expected {")?; - - let mut decls = Vec::new(); - loop { - match self.token() { - Some(Token::RBrace) => { - self.consume(); - break; - } - Some(_) => { - let decl = self.match_module_decl()?; - decls.push(decl); - } - None => parse_err!(self.location, "expected module decl or }")?, - } - } - - Ok(PackageDecl::Module { - name, - decls, - location, - }) - } - Some(_) | None => parse_err!(self.location, "expected package declaration"), - } - } - - pub fn match_package_decls(&mut self) -> Result>, ParseError> { - let mut decls = Vec::new(); - loop { - match self.token() { - Some(_) => { - let decl = self.match_package_decl()?; - decls.push(decl); - } - None => break, - } - } - Ok(decls) - } -} - -#[cfg(test)] -mod tests { - use super::*; - #[test] - fn struct_empty() { - let mut parser = Parser::new("struct foo {}"); - assert_eq!( - parser.match_module_decl().expect("valid parse"), - ModuleDecl::Struct { - name: "foo", - members: Vec::new(), - location: Location { line: 1, column: 0 }, - } - ); - } - #[test] - fn struct_one_int_member() { - let mut parser = Parser::new("struct foo {a: i32 }"); - // column ruler: 0 7 12 15 - assert_eq!( - parser.match_module_decl().expect("valid parse"), - ModuleDecl::Struct { - name: "foo", - members: vec![StructMember { - name: "a", - type_: SyntaxIdent { - name: "i32", - location: Location { - line: 1, - column: 15, - }, - }, - location: Location { - line: 1, - column: 12, - }, - }], - location: Location { line: 1, column: 0 }, - } - ); - } - #[test] - fn struct_one_int_member_trailing_comma() { - let mut parser = Parser::new("struct foo {b: i32, }"); - // 0 7 12 15 - assert_eq!( - parser.match_module_decl().expect("valid parse"), - ModuleDecl::Struct { - name: "foo", - members: vec![StructMember { - name: "b", - type_: SyntaxIdent { - name: "i32", - location: Location { - line: 1, - column: 15, - }, - }, - location: Location { - line: 1, - column: 12, - }, - }], - location: Location { line: 1, column: 0 }, - } - ); - } - #[test] - fn struct_two_int_members() { - let mut parser = Parser::new("struct c { d: f64, e: u8 }"); - // 0 7 11 14 19 22 - assert_eq!( - parser.match_module_decl().expect("valid parse"), - ModuleDecl::Struct { - name: "c", - members: vec![ - StructMember { - name: "d", - type_: SyntaxIdent { - name: "f64", - location: Location { - line: 1, - column: 14, - }, - }, - location: Location { - line: 1, - column: 11, - }, - }, - StructMember { - name: "e", - type_: SyntaxIdent { - name: "u8", - location: Location { - line: 1, - column: 22, - }, - }, - location: Location { - line: 1, - column: 19, - }, - }, - ], - location: Location { line: 1, column: 0 }, - } - ); - } - - #[test] - fn struct_reserved_members() { - let mut parser = Parser::new("struct foo {a: mod, struct: enum }"); - // column ruler: 0 7 12 15 21 30 - assert_eq!( - parser.match_module_decl().expect("valid parse"), - ModuleDecl::Struct { - name: "foo", - members: vec![ - StructMember { - name: "a", - type_: SyntaxIdent { - name: "mod", - location: Location { - line: 1, - column: 15, - }, - }, - location: Location { - line: 1, - column: 12, - }, - }, - StructMember { - name: "struct", - type_: SyntaxIdent { - name: "enum", - location: Location { - line: 1, - column: 28, - }, - }, - location: Location { - line: 1, - column: 20, - }, - } - ], - location: Location { line: 1, column: 0 }, - } - ); - } - #[test] - fn enum_empty() { - let mut parser = Parser::new("enum foo {}"); - // 0 5 - assert_eq!( - parser.match_module_decl().expect("valid parse"), - ModuleDecl::Enum { - name: "foo", - variants: Vec::new(), - location: Location { line: 1, column: 0 }, - }, - ); - } - #[test] - fn enum_one_entry_trailing_comma() { - let mut parser = Parser::new("enum foo {first,}"); - // 0 5 10 - assert_eq!( - parser.match_module_decl().expect("valid parse"), - ModuleDecl::Enum { - name: "foo", - variants: vec![EnumVariant { - name: "first", - location: Location { - line: 1, - column: 10, - }, - }], - location: Location { line: 1, column: 0 }, - }, - ); - } - #[test] - fn enum_one_entry() { - let mut parser = Parser::new("enum bar {first}"); - // 0 5 10 - assert_eq!( - parser.match_module_decl().expect("valid parse"), - ModuleDecl::Enum { - name: "bar", - variants: vec![EnumVariant { - name: "first", - location: Location { - line: 1, - column: 10, - }, - }], - location: Location { line: 1, column: 0 }, - }, - ); - } - - #[test] - fn enum_four_entry() { - let mut parser = Parser::new("enum baz { one, two, three\n, four, }"); - // 0 5 11 16 21 0 2 - assert_eq!( - parser.match_module_decl().expect("valid parse"), - ModuleDecl::Enum { - name: "baz", - variants: vec![ - EnumVariant { - name: "one", - location: Location { - line: 1, - column: 11, - }, - }, - EnumVariant { - name: "two", - location: Location { - line: 1, - column: 16, - }, - }, - EnumVariant { - name: "three", - location: Location { - line: 1, - column: 21, - }, - }, - EnumVariant { - name: "four", - location: Location { line: 2, column: 2 }, - }, - ], - location: Location { line: 1, column: 0 }, - }, - ); - } - - #[test] - fn mod_empty() { - let mut parser = Parser::new("mod empty {}"); - // 0 5 10 - assert_eq!( - parser.match_package_decl().expect("valid parse"), - PackageDecl::Module { - name: "empty", - decls: Vec::new(), - location: Location { line: 1, column: 0 }, - } - ); - } - - #[test] - fn mod_types() { - let mut parser = Parser::new("mod one { enum foo {} struct bar {} }"); - // 0 5 10 15 20 - assert_eq!( - parser.match_package_decl().expect("valid parse"), - PackageDecl::Module { - name: "one", - decls: vec![ - ModuleDecl::Enum { - name: "foo", - variants: Vec::new(), - location: Location { - line: 1, - column: 10 - }, - }, - ModuleDecl::Struct { - name: "bar", - members: Vec::new(), - location: Location { - line: 1, - column: 22 - }, - } - ], - location: Location { line: 1, column: 0 }, - } - ); - } - - #[test] - fn fn_trivial() { - let canonical = ModuleDecl::Function { - name: "trivial", - args: Vec::new(), - rets: Vec::new(), - bindings: Vec::new(), - location: Location { line: 1, column: 0 }, - }; - assert_eq!( - Parser::new("fn trivial();") - // 0 5 10 - .match_module_decl() - .expect("valid parse"), - canonical, - ); - assert_eq!( - Parser::new("fn trivial ( ) ;") - // 0 5 10 - .match_module_decl() - .expect("valid parse"), - canonical, - ); - assert_eq!( - Parser::new("fn trivial()->;") - // 0 5 10 - .match_module_decl() - .expect("valid parse"), - canonical, - ); - } - - #[test] - fn fn_return_i32() { - fn canonical(column: usize) -> ModuleDecl<'static> { - ModuleDecl::Function { - name: "getch", - args: Vec::new(), - rets: vec![FuncArgSyntax { - type_: SyntaxIdent { - name: "i32", - location: Location { - line: 1, - column: column, - }, - }, - name: "r", - location: Location { - line: 1, - column: 14, - }, - }], - bindings: Vec::new(), - location: Location { line: 1, column: 0 }, - } - } - assert_eq!( - Parser::new("fn getch() -> r:i32;") - // 0 5 10 15 - .match_module_decl() - .expect("valid decls"), - canonical(16) - ); - assert_eq!( - Parser::new("fn getch() -> r: i32,;") - // 0 5 10 - .match_module_decl() - .expect("valid decls"), - canonical(17) - ); - assert_eq!( - Parser::new("fn getch() -> r :i32 , ;") - // 0 5 10 - .match_module_decl() - .expect("valid decls"), - canonical(17) - ); - } - - #[test] - fn fn_one_arg() { - let canonical = ModuleDecl::Function { - name: "foo", - args: vec![FuncArgSyntax { - type_: SyntaxIdent { - name: "i32", - location: Location { - line: 1, - column: 10, - }, - }, - name: "a", - location: Location { line: 1, column: 7 }, - }], - rets: Vec::new(), - bindings: Vec::new(), - location: Location { line: 1, column: 0 }, - }; - assert_eq!( - Parser::new("fn foo(a: i32);") - // 0 5 10 15 20 25 - .match_module_decl() - .expect("valid parse"), - canonical - ); - assert_eq!( - Parser::new("fn foo(a: i32,);") - // 0 5 10 15 20 25 - .match_module_decl() - .expect("valid parse"), - canonical - ); - } - - #[test] - fn fn_multi_arg() { - let canonical = ModuleDecl::Function { - name: "foo", - args: vec![ - FuncArgSyntax { - type_: SyntaxIdent { - name: "i32", - location: Location { - line: 1, - column: 10, - }, - }, - name: "a", - location: Location { line: 1, column: 7 }, - }, - FuncArgSyntax { - type_: SyntaxIdent { - name: "f64", - location: Location { - line: 1, - column: 18, - }, - }, - name: "b", - location: Location { - line: 1, - column: 15, - }, - }, - ], - rets: Vec::new(), - bindings: Vec::new(), - location: Location { line: 1, column: 0 }, - }; - assert_eq!( - Parser::new("fn foo(a: i32, b: f64);") - // 0 5 10 15 20 25 - .match_module_decl() - .expect("valid parse"), - canonical - ); - assert_eq!( - Parser::new("fn foo(a: i32, b: f64, );") - // 0 5 10 15 20 25 - .match_module_decl() - .expect("valid parse"), - canonical - ); - } - - #[test] - fn fn_many_returns() { - assert_eq!( - Parser::new("fn getch() -> r1: i32, r2: i64, r3: f32;") - // 0 5 10 15 20 25 30 - .match_module_decl() - .expect("valid parse"), - ModuleDecl::Function { - name: "getch", - args: Vec::new(), - rets: vec![ - FuncArgSyntax { - type_: SyntaxIdent { - name: "i32", - location: Location { - line: 1, - column: 18, - } - }, - name: "r1", - location: Location { - line: 1, - column: 14, - }, - }, - FuncArgSyntax { - type_: SyntaxIdent { - name: "i64", - location: Location { - line: 1, - column: 27 - } - }, - name: "r2", - location: Location { - line: 1, - column: 23, - }, - }, - FuncArgSyntax { - type_: SyntaxIdent { - name: "f32", - location: Location { - line: 1, - column: 36 - } - }, - name: "r3", - location: Location { - line: 1, - column: 32, - }, - }, - ], - bindings: Vec::new(), - location: Location { line: 1, column: 0 }, - } - ); - } - - #[test] - fn fn_with_bindings() { - assert_eq!( - Parser::new( - "fn fgetch(fptr: i32) -> r: i32 where \n\ - file: in file_t <- *fptr,\n\ - r: out u8 <- r,\n\ - some_slice: out something <- [a, b];" - ) - // 0 5 10 15 20 25 30 - .match_module_decl() - .expect("valid parse"), - ModuleDecl::Function { - name: "fgetch", - args: vec![FuncArgSyntax { - type_: SyntaxIdent { - name: "i32", - location: Location { - line: 1, - column: 16 - } - }, - name: "fptr", - location: Location { - line: 1, - column: 10, - }, - },], - rets: vec![FuncArgSyntax { - type_: SyntaxIdent { - name: "i32", - location: Location { - line: 1, - column: 27 - } - }, - name: "r", - location: Location { - line: 1, - column: 24, - }, - }], - bindings: vec![ - BindingSyntax { - name: "file", - type_: SyntaxIdent { - name: "file_t", - location: Location { line: 2, column: 9 }, - }, - direction: BindingDirSyntax::In, - from: BindingRefSyntax::Ptr(Box::new(BindingRefSyntax::Name("fptr"))), - location: Location { line: 2, column: 0 }, - }, - BindingSyntax { - name: "r", - type_: SyntaxIdent { - name: "u8", - location: Location { line: 3, column: 7 }, - }, - direction: BindingDirSyntax::Out, - from: BindingRefSyntax::Name("r"), - location: Location { line: 3, column: 0 }, - }, - BindingSyntax { - name: "some_slice", - type_: SyntaxIdent { - name: "something", - location: Location { - line: 4, - column: 16 - }, - }, - direction: BindingDirSyntax::Out, - from: BindingRefSyntax::Slice( - Box::new(BindingRefSyntax::Name("a")), - Box::new(BindingRefSyntax::Name("b")) - ), - location: Location { line: 4, column: 0 }, - } - ], - location: Location { line: 1, column: 0 }, - } - ); - } - - #[test] - fn no_mod_in_mod() { - let err = Parser::new("mod foo { mod bar { }}").match_package_decl(); - assert_eq!( - err, - Err(ParseError { - message: "expected module declaration".to_owned(), - location: Location { - line: 1, - column: 10 - } - }) - ); - Parser::new("mod foo { enum whatever {} mod bar { }}") - .match_package_decls() - .err() - .expect("error package"); - } - - #[test] - fn no_top_level_types() { - let err = Parser::new("mod foo { } enum bar {}") - .match_package_decls() - .err() - .expect("error package"); - assert_eq!( - err, - ParseError { - message: "expected package declaration".to_owned(), - location: Location { - line: 1, - column: 12 - } - } - ); - } -} diff --git a/lucet-idl/src/prelude.rs b/lucet-idl/src/prelude.rs deleted file mode 100644 index 831b4e8d5..000000000 --- a/lucet-idl/src/prelude.rs +++ /dev/null @@ -1,122 +0,0 @@ -use crate::atoms::AtomType; -use crate::repr::{ - DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, ModuleDatatypesRepr, - ModuleFuncsRepr, ModuleIx, ModuleRepr, -}; -use crate::MemArea; -use cranelift_entity::{EntityRef, PrimaryMap}; - -pub fn std_module() -> ModuleRepr { - ModuleRepr { - datatypes: std_datatypes(), - funcs: ModuleFuncsRepr { - names: PrimaryMap::new(), - funcs: PrimaryMap::new(), - }, - } -} - -fn std_datatypes() -> ModuleDatatypesRepr { - fn create_atom(repr: &mut ModuleDatatypesRepr, atom: AtomType) { - // Display instance takes care of name: - let ix = repr.names.push(format!("{}", atom)); - let mem_size = atom.mem_size(); - let mem_align = atom.mem_align(); - let dix = repr.datatypes.push(DatatypeRepr { - variant: DatatypeVariantRepr::Atom(atom), - mem_size, - mem_align, - }); - assert_eq!(ix, dix, "names and datatypes out of sync"); - repr.topological_order.push(ix); - } - - let mut repr = ModuleDatatypesRepr { - names: PrimaryMap::new(), - datatypes: PrimaryMap::new(), - topological_order: Vec::new(), - }; - create_atom(&mut repr, AtomType::Bool); - create_atom(&mut repr, AtomType::U8); - create_atom(&mut repr, AtomType::U16); - create_atom(&mut repr, AtomType::U32); - create_atom(&mut repr, AtomType::U64); - create_atom(&mut repr, AtomType::I8); - create_atom(&mut repr, AtomType::I16); - create_atom(&mut repr, AtomType::I32); - create_atom(&mut repr, AtomType::I64); - create_atom(&mut repr, AtomType::F32); - create_atom(&mut repr, AtomType::F64); - - repr -} - -impl AtomType { - pub fn datatype_id(&self) -> DatatypeIdent { - use AtomType::*; - match self { - Bool => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(0)), - U8 => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(1)), - U16 => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(2)), - U32 => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(3)), - U64 => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(4)), - I8 => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(5)), - I16 => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(6)), - I32 => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(7)), - I64 => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(8)), - F32 => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(9)), - F64 => DatatypeIdent::new(ModuleIx::new(0), DatatypeIx::new(10)), - } - } -} - -#[cfg(test)] -mod test { - use crate::atoms::AtomType; - use crate::repr::{DatatypeIdent, Package}; - use crate::validate::PackageBuilder; - #[test] - fn atom_idents() { - use AtomType::*; - let builder = PackageBuilder::new(); // Uses `super::std_module` - let prelude = builder.repr(); - - fn lookup_atom_by_id(package: &Package, ident: DatatypeIdent) -> AtomType { - let dt = package.datatype_by_id(ident).expect("get by id"); - dt.variant().atom().expect("datatype is atom") - } - - assert_eq!(Bool, lookup_atom_by_id(prelude, Bool.datatype_id())); - assert_eq!(U8, lookup_atom_by_id(prelude, U8.datatype_id())); - assert_eq!(U16, lookup_atom_by_id(prelude, U16.datatype_id())); - assert_eq!(U32, lookup_atom_by_id(prelude, U32.datatype_id())); - assert_eq!(U64, lookup_atom_by_id(prelude, U64.datatype_id())); - assert_eq!(I8, lookup_atom_by_id(prelude, I8.datatype_id())); - assert_eq!(I16, lookup_atom_by_id(prelude, I16.datatype_id())); - assert_eq!(I32, lookup_atom_by_id(prelude, I32.datatype_id())); - assert_eq!(I64, lookup_atom_by_id(prelude, I64.datatype_id())); - assert_eq!(F32, lookup_atom_by_id(prelude, F32.datatype_id())); - assert_eq!(F64, lookup_atom_by_id(prelude, F64.datatype_id())); - - fn lookup_atom_by_name(package: &Package, name: &str) -> AtomType { - let dt = package - .module("std") - .expect("std module exists") - .datatype(name) - .expect("get by name"); - dt.variant().atom().expect("datatype is atom") - } - - assert_eq!(Bool, lookup_atom_by_name(prelude, "bool")); - assert_eq!(U8, lookup_atom_by_name(prelude, "u8")); - assert_eq!(U16, lookup_atom_by_name(prelude, "u16")); - assert_eq!(U32, lookup_atom_by_name(prelude, "u32")); - assert_eq!(U64, lookup_atom_by_name(prelude, "u64")); - assert_eq!(I8, lookup_atom_by_name(prelude, "i8")); - assert_eq!(I16, lookup_atom_by_name(prelude, "i16")); - assert_eq!(I32, lookup_atom_by_name(prelude, "i32")); - assert_eq!(I64, lookup_atom_by_name(prelude, "i64")); - assert_eq!(F32, lookup_atom_by_name(prelude, "f32")); - assert_eq!(F64, lookup_atom_by_name(prelude, "f64")); - } -} diff --git a/lucet-idl/src/pretty_writer.rs b/lucet-idl/src/pretty_writer.rs deleted file mode 100644 index f061b72eb..000000000 --- a/lucet-idl/src/pretty_writer.rs +++ /dev/null @@ -1,104 +0,0 @@ -#![allow(unused)] -use std::cell::RefCell; -use std::io::prelude::*; -use std::rc::Rc; - -/// Write indented code -/// #[derive(Clone)] -pub struct PrettyWriter { - writer: Rc>>, - indent: u32, - indent_bytes: Vec, -} - -impl PrettyWriter { - /// Create a new `PrettyWriter` with `indent` initial units of indentation - pub fn new_with_indent(writer: Box, indent: u32) -> Self { - PrettyWriter { - writer: Rc::new(RefCell::new(writer)), - indent, - indent_bytes: b" ".to_vec(), - } - } - - /// Create a new `PrettyWriter` with no initial indentation - pub fn new(writer: Box) -> Self { - PrettyWriter::new_with_indent(writer, 0) - } - - /// Create an indented block within the current `PrettyWriter` - pub fn new_block(&mut self) -> Self { - PrettyWriter { - writer: self.writer.clone(), - indent: self.indent + 1, - indent_bytes: self.indent_bytes.clone(), - } - } - - pub fn indent(&mut self) -> &mut Self { - self.indent += 1; - self - } - - fn _write_all(&mut self, buf: &[u8]) { - self.writer - .borrow_mut() - .write_all(buf) - .expect("pretty_writer write_all") - } - - /// Return the current indentation level - #[allow(dead_code)] - pub fn indent_level(&self) -> u32 { - self.indent - } - - /// Output an indentation string - fn write_indent(&mut self) -> &mut Self { - let indent_bytes = &self.indent_bytes.clone(); - { - for _ in 0..self.indent { - self._write_all(indent_bytes) - } - } - self - } - - /// Output an end of line - pub fn eol(&mut self) -> &mut Self { - self._write_all(b"\n"); - self - } - - /// Output a block separator - pub fn eob(&mut self) -> &mut Self { - if self.indent > 0 { - self.indent -= 1; - } - self.eol() - } - - /// Write raw data - pub fn write(&mut self, buf: &[u8]) -> &mut Self { - self._write_all(buf); - self - } - - /// Indent, write raw data and terminate with an end of line - pub fn write_line(&mut self, buf: &[u8]) -> &mut Self { - self.write_indent().write(buf).eol() - } - - /// Indent, write raw data and terminate with an end of line - pub fn writeln>(&mut self, buf: S) -> &mut Self { - self.write_line(buf.as_ref().as_bytes()) - } - - /// Indent, write raw data and terminate with an end of line - pub fn writelns>(&mut self, lines: &[S]) -> &mut Self { - for line in lines.iter() { - self.write_line(line.as_ref().as_bytes()); - } - self - } -} diff --git a/lucet-idl/src/repr.rs b/lucet-idl/src/repr.rs deleted file mode 100644 index d935400cb..000000000 --- a/lucet-idl/src/repr.rs +++ /dev/null @@ -1,173 +0,0 @@ -use crate::atoms::{AbiType, AtomType}; -use cranelift_entity::{entity_impl, PrimaryMap}; - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct ModuleIx(u32); -entity_impl!(ModuleIx); - -#[derive(Debug, Clone)] -pub struct Package { - pub(crate) names: PrimaryMap, - pub(crate) modules: PrimaryMap, -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct DatatypeIx(u32); -entity_impl!(DatatypeIx); - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct DatatypeIdent { - pub module: ModuleIx, - pub datatype: DatatypeIx, -} - -impl DatatypeIdent { - pub fn new(module: ModuleIx, datatype: DatatypeIx) -> Self { - DatatypeIdent { module, datatype } - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct FuncIx(u32); -entity_impl!(FuncIx); - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct FuncIdent { - pub module: ModuleIx, - pub func: FuncIx, -} - -impl FuncIdent { - pub fn new(module: ModuleIx, func: FuncIx) -> Self { - FuncIdent { module, func } - } -} - -#[derive(Debug, Clone)] -pub struct ModuleRepr { - pub datatypes: ModuleDatatypesRepr, - pub funcs: ModuleFuncsRepr, -} - -impl ModuleRepr { - pub fn new(datatypes: ModuleDatatypesRepr, funcs: ModuleFuncsRepr) -> Self { - Self { datatypes, funcs } - } - pub fn from_datatypes(datatypes: ModuleDatatypesRepr) -> Self { - Self::new( - datatypes, - ModuleFuncsRepr { - names: PrimaryMap::new(), - funcs: PrimaryMap::new(), - }, - ) - } -} - -#[derive(Debug, Clone)] -pub struct ModuleDatatypesRepr { - pub names: PrimaryMap, - pub datatypes: PrimaryMap, - pub topological_order: Vec, -} - -#[derive(Debug, Clone)] -pub struct ModuleFuncsRepr { - pub names: PrimaryMap, - pub funcs: PrimaryMap, -} - -#[derive(Debug, Clone)] -pub struct DatatypeRepr { - pub variant: DatatypeVariantRepr, - pub mem_size: usize, - pub mem_align: usize, -} - -#[derive(Debug, Clone)] -pub enum DatatypeVariantRepr { - Atom(AtomType), - Struct(StructDatatypeRepr), - Enum(EnumDatatypeRepr), - Alias(AliasDatatypeRepr), -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct StructMemberRepr { - pub type_: DatatypeIdent, - pub name: String, - pub offset: usize, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct StructDatatypeRepr { - pub members: Vec, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct EnumMemberRepr { - pub name: String, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct EnumDatatypeRepr { - pub members: Vec, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct AliasDatatypeRepr { - pub to: DatatypeIdent, -} - -#[derive(Debug, Clone)] -pub struct FuncRepr { - pub args: PrimaryMap, - pub rets: PrimaryMap, - pub bindings: PrimaryMap, -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct ArgIx(u32); -entity_impl!(ArgIx); - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct RetIx(u32); -entity_impl!(RetIx); - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum ParamIx { - Arg(ArgIx), - Ret(RetIx), -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct BindingIx(u32); -entity_impl!(BindingIx); - -#[derive(Debug, Clone)] -pub struct ParamRepr { - pub name: String, - pub type_: AbiType, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct BindingRepr { - pub name: String, - pub type_: DatatypeIdent, - pub direction: BindingDirection, - pub from: BindingFromRepr, -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum BindingDirection { - In, - InOut, - Out, -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum BindingFromRepr { - Ptr(ParamIx), - Slice(ParamIx, ParamIx), - Value(ParamIx), -} diff --git a/lucet-idl/src/rust.rs b/lucet-idl/src/rust.rs deleted file mode 100644 index fecdea303..000000000 --- a/lucet-idl/src/rust.rs +++ /dev/null @@ -1,491 +0,0 @@ -mod cursor; - -use crate::error::IDLError; -use crate::pretty_writer::PrettyWriter; -use crate::{ - AliasDatatype, DatatypeVariant, EnumDatatype, Function, MemArea, Module, Package, - StructDatatype, -}; -pub use cursor::{ - render_tuple, RustFunc, RustIdiomArg, RustIdiomRet, RustName, RustTupleSyntax, RustTypeName, -}; -use heck::SnakeCase; -use std::io::Write; - -/// Generator for the Rust backend -pub struct RustGenerator { - pub w: PrettyWriter, -} - -impl RustGenerator { - pub fn new(w: Box) -> Self { - Self { - w: PrettyWriter::new(w), - } - } - - pub fn generate_guest(&mut self, package: &Package) -> Result<(), IDLError> { - for module in package.modules() { - self.w - .writeln(format!("pub mod {} {{", module.rust_name())) - .indent(); - self.generate_datatypes(&module)?; - - self.w - .writeln("mod abi {") - .indent() - .writeln(format!("#[link(wasm_import_module=\"{}\")]", module.name())) - .writeln("extern \"C\" {") - .indent(); - for f in module.functions() { - self.guest_abi_import(&f)?; - } - self.w.eob().writeln("}").eob().writeln("}"); - - for f in module.functions() { - self.guest_idiomatic_def(&f)?; - } - - self.w.eob().writeln("}"); - } - Ok(()) - } - - pub fn generate_host(&mut self, package: &Package) -> Result<(), IDLError> { - for module in package.modules() { - self.w - .writeln(format!("pub mod {} {{", module.rust_name())) - .indent(); - self.generate_datatypes(&module)?; - - self.host_trait_definition(&module)?; - - self.w - .writeln("use lucet_runtime::{lucet_hostcalls, lucet_hostcall_terminate};"); - self.w.writeln("lucet_hostcalls! {").indent(); - for func in module.functions() { - self.host_abi_definition(&func)?; - } - self.w.eob().writeln("}"); - - self.host_module_ensure_linked(&module); - - self.w - .eob() - .writeln(format!("}} // end module {}", module.rust_name())); - } - self.host_package_ensure_linked(&package); - - Ok(()) - } - - fn generate_datatypes(&mut self, module: &Module) -> Result<(), IDLError> { - for dt in module.datatypes() { - match dt.variant() { - DatatypeVariant::Struct(s) => self.gen_struct(&s)?, - DatatypeVariant::Alias(a) => self.gen_alias(&a)?, - DatatypeVariant::Enum(e) => self.gen_enum(&e)?, - DatatypeVariant::Atom { .. } => {} - } - } - Ok(()) - } - - fn gen_alias(&mut self, alias: &AliasDatatype) -> Result<(), IDLError> { - self.w.writeln(format!( - "pub type {} = {};", - alias.datatype().rust_type_name(), - alias.to().rust_type_name() - )); - - gen_testcase( - &mut self.w, - &alias.datatype().name().to_snake_case(), - move |w| { - w.writeln(format!( - "assert_eq!({}, ::std::mem::size_of::());", - alias.datatype().mem_size(), - alias.datatype().rust_type_name() - )); - Ok(()) - }, - )?; - Ok(()) - } - - fn gen_struct(&mut self, struct_: &StructDatatype) -> Result<(), IDLError> { - let mut derivations = vec!["Debug", "Copy", "Clone", "PartialEq", "PartialOrd"]; - if !struct_.datatype().contains_floats() { - derivations.push("Eq"); - derivations.push("Ord"); - derivations.push("Hash"); - } - if !struct_.datatype().contains_enums() { - derivations.push("Default"); - } - self.w - .writeln("#[repr(C)]") - .writeln(format!("#[derive({})]", derivations.join(", "))) - .writeln(format!( - "pub struct {} {{", - struct_.datatype().rust_type_name() - )); - - let mut w = self.w.new_block(); - for m in struct_.members() { - w.writeln(format!( - "pub {}: {},", - m.rust_name(), - m.type_().rust_type_name(), - )); - } - - self.w.writeln("}"); - - self.w - .writeln(format!("impl {} {{", struct_.datatype().rust_type_name())); - let mut w = self.w.new_block(); - - w.writeln("pub fn validate_bytes(repr: &[u8]) -> bool {"); - let mut ww = w.new_block(); - for m in struct_.members() { - match m.type_().canonicalize().variant() { - DatatypeVariant::Struct(_) | DatatypeVariant::Enum(_) => { - ww.writeln(format!( - "{}::validate_bytes(&repr[{}..{}]) &&", - m.type_().rust_type_name(), - m.offset(), - m.offset() + m.type_().mem_size(), - )); - } - DatatypeVariant::Atom(_) => { - ww.writeln(format!("// not validating {}", m.type_().rust_type_name())); - } - DatatypeVariant::Alias(_) => unreachable!("anti-aliased datatype"), - } - } - ww.writeln("true"); // to catch the trailing && - w.writeln("}"); - - self.w.writeln("}"); // end impl - - gen_testcase( - &mut self.w, - &struct_.datatype().name().to_snake_case(), - |w| { - w.writeln(format!( - "assert_eq!({}, ::std::mem::size_of::());", - struct_.datatype().mem_size(), - struct_.datatype().rust_type_name(), - )); - - for m in struct_.members() { - w.writeln("{"); - let mut ww = w.new_block(); - // This is essentially an inlining of the macros in the memoffset crate. - ww.writeln(format!( - "let base_uninit = ::std::mem::MaybeUninit::::uninit();", - struct_.datatype().rust_type_name(), - )) - .writeln("let base_ptr = base_uninit.as_ptr();") - .writeln(format!( - "let field_ptr = unsafe {{ &(*base_ptr).{} as *const _ }};", - m.rust_name(), - )) - .writeln("let offset = (field_ptr as usize) - (base_ptr as usize);") - .writeln(format!("assert_eq!({}, offset);", m.offset())); - w.writeln("}"); - } - Ok(()) - }, - )?; - Ok(()) - } - - // Enums generate both a specific typedef, and a traditional C-style enum - // The typedef is required to use a native type which is consistent across all architectures - fn gen_enum(&mut self, enum_: &EnumDatatype) -> Result<(), IDLError> { - self.w - .writeln("#[repr(u32)]") - .writeln("#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]") - .writeln(format!("pub enum {} {{", enum_.datatype().rust_type_name())); - - let mut w = self.w.new_block(); - for v in enum_.variants() { - w.writeln(format!("{},", v.rust_name())); - } - - self.w.writeln("}"); - - self.w - .writeln(format!("impl {} {{", enum_.datatype().rust_type_name())); - let mut w = self.w.new_block(); - w.writeln("pub fn from_u32(e: u32) -> Option {"); - let mut ww = w.new_block(); - ww.writeln("match e {"); - let mut www = ww.new_block(); - for v in enum_.variants() { - www.writeln(format!( - "{} => Some({}::{}),", - v.index(), - enum_.datatype().rust_type_name(), - v.rust_name() - )); - } - www.writeln("_ => None,"); - ww.writeln("}"); - w.writeln("}"); - - w.writeln("pub fn validate_bytes(repr: &[u8]) -> bool {"); - let mut ww = w.new_block(); - ww.writeln(format!( - "((repr[0] as u32) + ((repr[1] as u32) << 8) + \ - ((repr[2] as u32) << 16) + ((repr[3] as u32) << 24)) < {}", - enum_.variants().collect::>().len() - )); - w.writeln("}"); - self.w.writeln("}"); // end impl - - gen_testcase(&mut self.w, &enum_.datatype().name().to_snake_case(), |w| { - w.writeln(format!( - "assert_eq!({}, ::std::mem::size_of::());", - enum_.datatype().mem_size(), - enum_.datatype().rust_type_name(), - )); - Ok(()) - })?; - Ok(()) - } - fn guest_abi_import(&mut self, func: &Function) -> Result<(), IDLError> { - let mut arg_syntax = Vec::new(); - for a in func.args() { - arg_syntax.push(format!("{}: {}", a.rust_name(), a.type_().rust_type_name())); - } - - let ret_syntax = func - .rets() - .map(|r| r.type_().rust_type_name()) - .rust_tuple_syntax("()"); - - self.w.writeln("#[no_mangle]").writeln(format!( - "pub fn {}({}) -> {};", - func.rust_name(), - arg_syntax.join(", "), - ret_syntax - )); - - Ok(()) - } - - fn guest_idiomatic_def(&mut self, func: &Function) -> Result<(), IDLError> { - let name = func.rust_name(); - let idiom_args = func.rust_idiom_args(); - let idiom_rets = func.rust_idiom_rets(); - - let idiom_arg_syntax = idiom_args - .iter() - .map(|a| a.arg_declaration()) - .collect::>() - .join(", "); - let idiom_ret_syntax = format!( - "Result<{},()>", - idiom_rets - .iter() - .map(|r| r.ret_declaration()) - .rust_tuple_syntax("()") - ); - - self.w - .writeln(format!( - "pub fn {}({}) -> {} {{", - name, idiom_arg_syntax, idiom_ret_syntax - )) - .indent(); - for a in idiom_args.iter() { - self.w.writelns(&a.guest_abi_args()); - } - for r in idiom_rets.iter() { - self.w.writelns(&r.guest_abi_args()); - } - - self.w.writeln(format!( - "let {} = unsafe {{ abi::{}({}) }};", - func.rets().map(|r| r.rust_name()).rust_tuple_syntax("_"), - name, - func.args() - .map(|a| a.rust_name()) - .collect::>() - .join(", ") - )); - - for r in idiom_rets.iter() { - self.w.writeln(r.guest_from_abi_call()); - } - - self.w.writeln(format!( - "Ok({})", - idiom_rets.iter().map(|r| r.name()).rust_tuple_syntax("()") - )); - self.w.eob().writeln("}"); - Ok(()) - } - - fn host_abi_definition(&mut self, func: &Function) -> Result<(), IDLError> { - let mut args = vec![format!("&mut vmctx")]; - for a in func.args() { - args.push(format!( - "{}: {}", - a.rust_name().to_snake_case(), - a.type_().rust_type_name(), - )); - } - - let abi_rettype = func - .rets() - .map(|r| r.type_().rust_type_name()) - .rust_tuple_syntax("()"); - - self.w - .writeln("#[no_mangle]") - .writeln(format!( - "// Wasm func {}::{}", - func.module().name(), - func.rust_name() - )) - .writeln(format!( - "pub unsafe extern \"C\" fn {}({},) -> {} {{", - func.host_func_name(), - args.join(", "), - abi_rettype - )); - - self.w.indent(); - - let trait_type_name = func.module().rust_type_name(); - - self.w.writeln(format!( - "fn inner(heap: &mut [u8], obj: &mut dyn {}, {}) -> Result<{},()> {{", - trait_type_name, - func.args() - .map(|a| format!("{}: {}", a.rust_name(), a.type_().rust_type_name(),)) - .collect::>() - .join(", "), - abi_rettype, - )); - self.w.indent(); - { - let idiom_args = func.rust_idiom_args(); - let idiom_rets = func.rust_idiom_rets(); - - for a in idiom_args.iter() { - self.w.writelns(&a.host_unpack_to_abi()); - } - for r in idiom_rets.iter() { - self.w.writelns(&r.host_unpack_to_abi()); - } - self.w.writeln(format!( - "let {} = obj.{}({})?;", - idiom_rets.iter().map(|r| r.name()).rust_tuple_syntax("_"), - func.rust_name(), - idiom_args - .iter() - .map(|a| a.name()) - .collect::>() - .join(", "), - )); - for r in idiom_rets.iter() { - self.w.writeln(r.host_unpack_from_abi()); - } - self.w.writeln(format!( - "Ok({})", - func.rets() - .map(|r| r.name().to_string()) - .rust_tuple_syntax("()") - )); - } - self.w.eob().writeln("}"); - - self.w.writeln(format!( - "let mut ctx: ::std::cell::RefMut> = vmctx.get_embed_ctx_mut::>();", - typename =trait_type_name - )); - self.w.writeln("let mut heap = vmctx.heap_mut();"); - self.w.writeln(format!( - "match inner(&mut *heap, &mut **ctx, {}) {{ Ok(v) => v, Err(e) => lucet_hostcall_terminate!(\"FIXME\"), }}", - func.args() - .map(|a| a.name().to_owned()) - .collect::>() - .join(", "), - )); - self.w.eob().writeln("}"); - - Ok(()) - } - - fn host_trait_definition(&mut self, module: &Module) -> Result<(), IDLError> { - self.w - .writeln(format!("pub trait {} {{", module.rust_type_name())) - .indent(); - for func in module.functions() { - let mut args = func - .rust_idiom_args() - .iter() - .map(|a| a.arg_declaration()) - .collect::>(); - args.insert(0, "&mut self".to_owned()); - let rets = func - .rust_idiom_rets() - .iter() - .map(|a| a.ret_declaration()) - .rust_tuple_syntax("()"); - - self.w.writeln(format!( - "fn {}({}) -> {};", - func.rust_name(), - args.join(", "), - format!("Result<{},()>", rets), - )); - } - - self.w.eob().writeln("}"); - - Ok(()) - } - - fn host_module_ensure_linked(&mut self, module: &Module) { - self.w.writeln("pub fn ensure_linked() {").indent(); - self.w.writeln("unsafe {").indent(); - for func in module.functions() { - self.w.writeln(format!( - "::std::ptr::read_volatile({} as *const extern \"C\" fn());", - func.host_func_name(), - )); - } - self.w.eob().writeln("}"); - self.w.eob().writeln("}"); - } - - fn host_package_ensure_linked(&mut self, package: &Package) { - self.w.writeln("pub fn ensure_linked() {").indent(); - for module in package.modules() { - self.w - .writeln(format!("{}::ensure_linked()", module.rust_name())); - } - self.w.eob().writeln("}"); - } -} - -fn gen_testcase(w: &mut PrettyWriter, name: &str, f: F) -> Result<(), IDLError> -where - F: FnOnce(&mut PrettyWriter) -> Result<(), IDLError>, -{ - w.writeln("#[cfg(test)]") - .writeln(format!("mod {} {{", name)); - let mut ww = w.new_block(); - ww.writeln("#[test]").writeln("fn test() {"); - let mut www = ww.new_block(); - f(&mut www)?; - ww.writeln("}"); - w.writeln("}"); - Ok(()) -} diff --git a/lucet-idl/src/rust/cursor.rs b/lucet-idl/src/rust/cursor.rs deleted file mode 100644 index bcfd5779d..000000000 --- a/lucet-idl/src/rust/cursor.rs +++ /dev/null @@ -1,463 +0,0 @@ -use crate::{ - AbiType, AtomType, BindingDirection, BindingParam, Datatype, DatatypeVariant, EnumVariant, - FuncBinding, FuncParam, Function, MemArea, Module, StructMember, -}; -use heck::{CamelCase, SnakeCase}; - -pub trait RustTupleSyntax { - fn rust_tuple_syntax(&mut self, base_case: &str) -> String; -} - -impl RustTupleSyntax for I -where - I: Iterator, -{ - fn rust_tuple_syntax(&mut self, base_case: &str) -> String { - let rets = self.collect::>(); - render_tuple(&rets, base_case) - } -} - -pub trait RustTypeName { - fn rust_type_name(&self) -> String; -} - -impl RustTypeName for Module<'_> { - fn rust_type_name(&self) -> String { - self.name().to_camel_case() - } -} - -impl RustTypeName for AtomType { - fn rust_type_name(&self) -> String { - format!("{}", self) - } -} - -impl RustTypeName for AbiType { - fn rust_type_name(&self) -> String { - format!("{}", self) - } -} - -impl RustTypeName for Datatype<'_> { - fn rust_type_name(&self) -> String { - match self.variant() { - DatatypeVariant::Struct(_) | DatatypeVariant::Enum(_) | DatatypeVariant::Alias(_) => { - self.name().to_camel_case() - } - DatatypeVariant::Atom(a) => a.rust_type_name(), - } - } -} - -pub trait RustName { - fn rust_name(&self) -> String; -} - -impl RustName for Function<'_> { - fn rust_name(&self) -> String { - self.name().to_snake_case() - } -} - -impl RustName for Module<'_> { - fn rust_name(&self) -> String { - self.name().to_snake_case() - } -} - -impl RustName for EnumVariant<'_> { - fn rust_name(&self) -> String { - self.name().to_camel_case() - } -} - -impl RustName for StructMember<'_> { - fn rust_name(&self) -> String { - self.name().to_snake_case() - } -} - -impl RustName for FuncParam<'_> { - fn rust_name(&self) -> String { - self.name().to_snake_case() - } -} - -impl RustName for FuncBinding<'_> { - fn rust_name(&self) -> String { - self.name().to_snake_case() - } -} - -pub fn render_tuple(members: &[String], base_case: &str) -> String { - match members.len() { - 0 => base_case.to_owned(), - 1 => members[0].clone(), - _ => format!("({})", members.join(", ")), - } -} - -pub trait RustFunc<'a> { - fn rust_idiom_args(&self) -> Vec>; - fn rust_idiom_rets(&self) -> Vec>; - fn host_func_name(&self) -> String; -} - -impl<'a> RustFunc<'a> for Function<'a> { - fn rust_idiom_args(&self) -> Vec> { - self.bindings() - .filter(|b| b.direction() == BindingDirection::In) - .chain( - self.bindings() - .filter(|b| b.direction() == BindingDirection::InOut), - ) - .map(|b| RustIdiomArg { binding: b }) - .collect() - } - - fn rust_idiom_rets(&self) -> Vec> { - self.bindings() - .filter(|b| b.direction() == BindingDirection::Out) - .map(|binding| RustIdiomRet { binding }) - .collect() - } - - fn host_func_name(&self) -> String { - format!( - "__{}_{}", - self.module().name().to_snake_case(), - self.name().to_snake_case() - ) - } -} - -pub struct RustIdiomArg<'a> { - binding: FuncBinding<'a>, -} - -impl<'a> RustIdiomArg<'a> { - pub fn name(&self) -> String { - self.binding.rust_name() - } - pub fn direction(&self) -> BindingDirection { - self.binding.direction() - } - pub fn type_(&self) -> Datatype<'a> { - self.binding.type_() - } - pub fn type_name(&self) -> String { - self.type_().rust_type_name() - } - pub fn param(&self) -> BindingParam<'a> { - self.binding.param() - } - - fn mutable(&self) -> &'static str { - if self.binding.direction() == BindingDirection::InOut { - "mut " - } else { - "" - } - } - - pub fn arg_declaration(&self) -> String { - match self.binding.param() { - BindingParam::Ptr { .. } => { - format!("{}: &{}{}", self.name(), self.mutable(), self.type_name()) - } - BindingParam::Slice { .. } => { - format!("{}: &{}[{}]", self.name(), self.mutable(), self.type_name()) - } - BindingParam::Value { .. } => { - assert_eq!(self.binding.direction(), BindingDirection::In); - format!("{}: {}", self.name(), self.type_name()) - } - } - } - - pub fn arg_value(&self) -> String { - match self.binding.param() { - BindingParam::Ptr { .. } | BindingParam::Slice { .. } => { - format!("&{}{}", self.mutable(), self.name(),) - } - BindingParam::Value { .. } => { - assert_eq!(self.binding.direction(), BindingDirection::In); - self.name() - } - } - } - - pub fn guest_abi_args(&self) -> Vec { - match self.binding.param() { - BindingParam::Ptr(ptr) => vec![format!( - "let {} = {} as *const _ as i32;", - ptr.rust_name(), - self.name(), - )], - BindingParam::Slice(ptr, len) => vec![ - format!("let {} = {}.as_ptr() as i32;", ptr.rust_name(), self.name()), - format!("let {} = {}.len() as i32;", len.rust_name(), self.name()), - ], - BindingParam::Value(val) => match val.type_().variant() { - DatatypeVariant::Atom(AtomType::Bool) => { - vec![format!("let {} = {} != 0;", val.rust_name(), self.name(),)] - } - _ => vec![format!( - "let {} = {} as {};", - val.rust_name(), - self.name(), - val.type_().rust_type_name() - )], - }, - } - } - - pub fn host_unpack_to_abi(&self) -> Vec { - if self.binding.direction() == BindingDirection::In { - match self.binding.param() { - BindingParam::Ptr(ptr) => vec![ - format!("let {ptr} = {ptr} as usize;", - ptr = ptr.rust_name() - ), - format!("if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", - ptr = ptr.rust_name(), - align = self.binding.type_().mem_align(), - ), - format!("#[allow(non_snake_case)] let {name}___MEM: &[u8] = heap.get({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", - name = self.name(), - ptr = ptr.rust_name(), - len = self.binding.type_().mem_size(), - ), - format!("let {name}: &{typename} = unsafe {{ ({name}___MEM.as_ptr() as *const {typename}).as_ref().expect(\"determined to be valid ref\") }}; // convert pointer in linear memory to ref", - name = self.name(), - typename = self.type_name(), - ), - ], - BindingParam::Slice(ptr, len) => vec![ - format!("let {ptr} = {ptr} as usize;", - ptr = ptr.rust_name() - ), - format!("let {len} = {len} as usize;", - len = len.rust_name() - ), - format!("if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", - ptr = ptr.rust_name(), - align = self.binding.type_().mem_align(), - ), - format!("#[allow(non_snake_case)] let {name}___MEM: &[u8] = heap.get({ptr}..({ptr}+({len}*{elem_len}))).ok_or_else(|| () /* FIXME: bounds check failed */)?;", - name = self.name(), - ptr = ptr.rust_name(), - len = len.rust_name(), - elem_len =self.binding.type_().mem_size(), - ), - format!("let {name}: &[{typename}] = unsafe {{ ::std::slice::from_raw_parts({name}___MEM.as_ptr() as *const {typename}, {len}) }};", - name = self.name(), - typename = self.type_name(), - len = len.rust_name(), - ) - ], - BindingParam::Value(_val) => vec![cast_value_to_binding(&self.binding)], - } - } else { - assert_eq!(self.binding.direction(), BindingDirection::InOut); - match self.binding.param() { - BindingParam::Ptr(ptr) => vec![ - format!("let {ptr} = {ptr} as usize;", - ptr = ptr.rust_name() - ), - format!("if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", - ptr = ptr.rust_name(), - align = self.binding.type_().mem_align(), - ), - format!("#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", - name = self.name(), - ptr = ptr.rust_name(), - len = self.binding.type_().mem_size(), - ), - format!("let mut {name}: &mut {typename} = unsafe {{ ({name}___MEM.as_mut_ptr() as *mut {typename}).as_mut().expect(\"determined to be valid ref\") }}; // convert pointer in linear memory to ref", - name = self.name(), - typename = self.type_name(), - ), - ], - BindingParam::Slice(ptr, len) => vec![ - format!("let {ptr} = {ptr} as usize;", - ptr = ptr.rust_name() - ), - format!("let {len} = {len} as usize;", - len = len.rust_name() - ), - format!("if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", - ptr = ptr.rust_name(), - align = self.binding.type_().mem_align(), - ), - format!("#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+({len}*{elem_len}))).ok_or_else(|| () /* FIXME: bounds check failed */)?;", - name = self.name(), - ptr = ptr.rust_name(), - len = len.rust_name(), - elem_len = self.binding.type_().mem_size(), - ), - - format!("let mut {name}: &mut [{typename}] = unsafe {{ ::std::slice::from_raw_parts_mut({name}___MEM.as_mut_ptr() as *mut {typename}, {len}) }};", - name = self.name(), - typename = self.type_name(), - len = len.rust_name(), - ), - ], - BindingParam::Value {..} => unreachable!(), - } - } - } -} - -pub struct RustIdiomRet<'a> { - binding: FuncBinding<'a>, -} - -impl<'a> RustIdiomRet<'a> { - pub fn name(&self) -> String { - self.binding.rust_name() - } - pub fn direction(&self) -> BindingDirection { - self.binding.direction() - } - pub fn type_(&self) -> Datatype<'a> { - self.binding.type_() - } - pub fn type_name(&self) -> String { - self.type_().rust_type_name() - } - pub fn param(&self) -> BindingParam<'a> { - self.binding.param() - } - - pub fn ret_declaration(&self) -> String { - match self.binding.param() { - BindingParam::Ptr { .. } | BindingParam::Value { .. } => self.type_name(), - BindingParam::Slice { .. } => unreachable!(), - } - } - - pub fn guest_abi_args(&self) -> Vec { - match self.binding.param() { - BindingParam::Ptr(ptr) => vec![ - format!( - "#[allow(non_snake_case)] let mut {}___MEM = ::std::mem::MaybeUninit::<{}>::uninit();", - ptr.rust_name(), - self.type_name(), - ), - format!( - "let {} = {}___MEM.as_mut_ptr() as i32;", - ptr.rust_name(), - ptr.rust_name() - ), - ], - BindingParam::Value { .. } => vec![], - BindingParam::Slice { .. } => unreachable!(), - } - } - - pub fn guest_from_abi_call(&self) -> String { - match self.binding.param() { - BindingParam::Ptr(ptr) => format!( - "let {} = unsafe {{ {}___MEM.assume_init() }};", - self.name(), - ptr.rust_name() - ), - BindingParam::Value(_val) => cast_value_to_binding(&self.binding), - BindingParam::Slice { .. } => unreachable!(), - } - } - - pub fn host_unpack_to_abi(&self) -> Vec { - match self.binding.param() { - BindingParam::Ptr(ptr) => { - let mut lines = vec![ - format!( - "let {ptr} = {ptr} as usize;", - ptr = ptr.rust_name() - ), - format!( - "if {ptr} % {align} != 0 {{ Err(())?; /* FIXME: align failed */ }}", - ptr = ptr.name(), - align = self.binding.type_().mem_align(), - ), - format!( - "#[allow(non_snake_case)] let mut {name}___MEM: &mut [u8] = heap.get_mut({ptr}..({ptr}+{len})).ok_or_else(|| () /* FIXME: bounds check failed */)?;", - name = self.name(), - ptr = ptr.rust_name(), - len =self.binding.type_().mem_size(), - )]; - match self.binding.type_().canonicalize().variant() { - DatatypeVariant::Enum(_) | DatatypeVariant::Struct(_) => { - lines.push(format!("if !{}::validate_bytes(&{}___MEM) {{ Err(())?; /* FIXME invalid representation */ }}", - self.type_name(), self.name())) - } - DatatypeVariant::Atom(_) => {} // No representation validation required - DatatypeVariant::Alias(_) => unreachable!("anti-aliased"), - } - lines.push(format!( - "let mut {ptr}: &mut {typename} = unsafe {{ ({name}___MEM.as_mut_ptr() as *mut {typename}).as_mut().expect(\"determined to be valid ref\") }}; // convert pointer in linear memory to ref", - name = self.name(), - typename = self.type_name(), - ptr = ptr.rust_name(), - )); - lines - } - BindingParam::Value(_val) => vec![], - BindingParam::Slice { .. } => unreachable!(), - } - } - - pub fn host_unpack_from_abi(&self) -> String { - match self.binding.param() { - BindingParam::Ptr(ptr) => format!( - "*{} = {}; // Copy into out-pointer reference", - ptr.rust_name(), - self.name(), - ), - BindingParam::Value(val) => match val.type_().variant() { - DatatypeVariant::Atom(AtomType::Bool) => format!( - "let {value}: {typename} = {arg} != 0;", - value = val.rust_name(), - typename = val.type_().rust_type_name(), - arg = self.name(), - ), - - _ => format!( - "let {value}: {typename} = {arg} as {typename};", - value = val.rust_name(), - typename = val.type_().rust_type_name(), - arg = self.name(), - ), - }, - BindingParam::Slice { .. } => unreachable!(), - } - } -} - -fn cast_value_to_binding(b: &FuncBinding) -> String { - match b.param() { - BindingParam::Value(val) => match b.type_().canonicalize().variant() { - DatatypeVariant::Enum(_) => format!( - "let {} = {}::from_u32({} as u32).ok_or(())?; // FIXME throw the right error", - b.rust_name(), - b.type_().rust_type_name(), - val.rust_name(), - ), - DatatypeVariant::Atom(AtomType::Bool) => { - format!("let {} = {} != 0;", b.rust_name(), val.rust_name(),) - } - DatatypeVariant::Atom(_) => format!( - "let {} = {} as {};", - b.rust_name(), - val.rust_name(), - b.type_().rust_type_name(), - ), - DatatypeVariant::Alias(_) => unreachable!("anti-aliased"), - DatatypeVariant::Struct(_) => unreachable!("can't represent struct as binding value"), - }, - _ => panic!("can only cast BindingParam::Value to binding type"), - } -} diff --git a/lucet-idl/src/validate/datatypes.rs b/lucet-idl/src/validate/datatypes.rs deleted file mode 100644 index 550dc8550..000000000 --- a/lucet-idl/src/validate/datatypes.rs +++ /dev/null @@ -1,420 +0,0 @@ -use super::names::ModNamesBuilder; -use crate::parser::{ - EnumVariant as EnumVariantSyntax, StructMember as StructMemberSyntax, SyntaxIdent, -}; -use crate::repr::{ - AliasDatatypeRepr, DatatypeIdent, DatatypeIx, DatatypeRepr, DatatypeVariantRepr, - EnumDatatypeRepr, EnumMemberRepr, ModuleDatatypesRepr, Package, StructDatatypeRepr, - StructMemberRepr, -}; -use crate::{AtomType, Location, MemArea, ValidationError}; -use cranelift_entity::{PrimaryMap, SecondaryMap}; -use std::collections::HashMap; - -#[derive(Debug, PartialEq, Eq, Clone)] -struct DatatypeIR { - variant: VariantIR, - location: Location, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -struct StructMemberIR { - type_: DatatypeIdent, - name: String, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -struct StructIR { - members: Vec, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -struct EnumIR { - members: Vec, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -struct AliasIR { - to: DatatypeIdent, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -enum VariantIR { - Struct(StructIR), - Enum(EnumIR), - Alias(AliasIR), -} - -#[derive(Clone)] -pub struct DatatypeModuleBuilder<'a> { - env: &'a Package, - names: &'a ModNamesBuilder, - types: PrimaryMap, -} - -impl<'a> DatatypeModuleBuilder<'a> { - pub fn new(env: &'a Package, names: &'a ModNamesBuilder) -> Self { - Self { - env, - names, - types: PrimaryMap::new(), - } - } - - pub fn introduce_struct( - &mut self, - name: &str, - members_syntax: &[StructMemberSyntax], - location: Location, - ) -> Result<(), ValidationError> { - let ix = self - .names - .datatype_from_name(name) - .expect("name is introduced"); - if members_syntax.is_empty() { - Err(ValidationError::Empty { - name: name.to_owned(), - location, - })? - } - - let mut uniq_membs = HashMap::new(); - let mut members = Vec::new(); - for mem in members_syntax { - // Ensure that each member name is unique: - if let Some(existing) = uniq_membs.insert(mem.name.to_owned(), mem) { - Err(ValidationError::NameAlreadyExists { - name: mem.name.to_owned(), - at_location: mem.location, - previous_location: existing.location, - })? - } - // Get the DatatypeIdent for the member, which ensures that it refers only to - // defined types: - let type_ = self.names.datatype_id_from_syntax(&mem.type_)?; - // build the struct with this as the member: - members.push(StructMemberIR { - type_, - name: mem.name.to_owned(), - }); - } - self.define_datatype( - ix, - DatatypeIR { - variant: VariantIR::Struct(StructIR { members }), - location, - }, - ); - Ok(()) - } - - pub fn introduce_enum( - &mut self, - name: &str, - variants: &[EnumVariantSyntax], - location: Location, - ) -> Result<(), ValidationError> { - let ix = self - .names - .datatype_from_name(name) - .expect("name is introduced"); - if variants.is_empty() { - Err(ValidationError::Empty { - name: name.to_owned(), - location, - })? - } - - let mut uniq_vars = HashMap::new(); - let mut members = Vec::new(); - for var in variants { - // Ensure that each member name is unique: - if let Some(existing) = uniq_vars.insert(var.name.clone(), var) { - Err(ValidationError::NameAlreadyExists { - name: var.name.to_owned(), - at_location: var.location, - previous_location: existing.location, - })? - } - // build the enum with this as the member: - members.push(EnumMemberRepr { - name: var.name.to_owned(), - }) - } - self.define_datatype( - ix, - DatatypeIR { - variant: VariantIR::Enum(EnumIR { members }), - location, - }, - ); - Ok(()) - } - - pub fn introduce_alias( - &mut self, - name: &str, - dest: &SyntaxIdent, - location: Location, - ) -> Result<(), ValidationError> { - let ix = self - .names - .datatype_from_name(name) - .expect("name is introduced"); - let to = self.names.datatype_id_from_syntax(dest)?; - self.define_datatype( - ix, - DatatypeIR { - variant: VariantIR::Alias(AliasIR { to }), - location, - }, - ); - Ok(()) - } - - fn define_datatype(&mut self, ix: DatatypeIx, ir: DatatypeIR) { - let type_ix = self.types.push(ir); - assert_eq!( - ix, type_ix, - "datatypes must be introduced in the same order as their names" - ); - } - - pub fn build(self) -> Result { - let mut finalized = FinalizedTypes::new(self.names.types.len()); - - let mut ordered = Vec::new(); - for (ix, name) in self.names.types.iter() { - let decl = self - .types - .get(ix) - .expect("all datatypes declared were defined"); - - // Depth first search through datatypes will return an error if they - // are infinite, by marking all visited datatypes in this map: - let mut visited = SecondaryMap::new(); - visited.resize(self.names.types.len()); - - self.dfs_walk(ix, &mut visited, &mut ordered, &mut finalized) - .map_err(|_| ValidationError::Infinite { - name: name.clone(), - location: decl.location, - })?; - } - - let datatypes = finalized.build(); - - assert_eq!( - self.names.types.len(), - datatypes.len(), - "each datatype defined" - ); - assert_eq!( - datatypes.len(), - ordered.len(), - "is each datatype present in topological sort? lengths dont match" - ); - - Ok(ModuleDatatypesRepr { - names: self.names.types.clone(), - datatypes, - topological_order: ordered, - }) - } - - fn dfs_walk( - &self, - ix: DatatypeIx, - visited: &mut SecondaryMap, - ordered: &mut Vec, - finalized_types: &mut FinalizedTypes, - ) -> Result<(), ()> { - // Ensure that dfs terminates: - if visited[ix] { - Err(())? - } - visited[ix] = true; - - let dt = self.types.get(ix).expect("data type IR is defined"); - - match &dt.variant { - VariantIR::Struct(ref s) => { - // First, iterate down the member to ensure this is finite, and fill in type - // info for leaves first. - // IMPORTANT: assumes any type defined outside this module is an atom! - for mem in s.members.iter() { - if mem.type_.module == self.names.module { - self.dfs_walk(mem.type_.datatype, visited, ordered, finalized_types)?; - } - } - // If finalized type information has not yet been computed, we can now compute it: - if !finalized_types.is_defined(ix) { - let mut offset = 0; - let mut struct_align = 1; - let mut members: Vec = Vec::new(); - for mem in s.members.iter() { - let (mem_size, align) = - self.datatype_size_align(mem.type_, finalized_types); - - offset = align_to(offset, align); - struct_align = ::std::cmp::max(struct_align, align); - - members.push(StructMemberRepr { - type_: mem.type_.clone(), - name: mem.name.clone(), - offset, - }); - offset += mem_size; - } - - let mem_size = align_to(offset, struct_align); - - finalized_types.define( - ix, - DatatypeRepr { - variant: DatatypeVariantRepr::Struct(StructDatatypeRepr { members }), - mem_size, - mem_align: struct_align, - }, - ); - } - } - VariantIR::Alias(ref a) => { - // Iterate down the pointer to ensure this is finite, and fill in type - // info for pointee first. - // IMPORTANT: assumes any type defined outside this module is an atom! - if a.to.module == self.names.module { - self.dfs_walk(a.to.datatype, visited, ordered, finalized_types)?; - } - - // If finalized type information has not yet been computed, we can now compute it: - if !finalized_types.is_defined(ix) { - let (mem_size, mem_align) = self.datatype_size_align(a.to, finalized_types); - finalized_types.define( - ix, - DatatypeRepr { - variant: DatatypeVariantRepr::Alias(AliasDatatypeRepr { - to: a.to.clone(), - }), - mem_size, - mem_align, - }, - ); - } - } - VariantIR::Enum(ref e) => { - // No recursion to do on the dfs. - if !finalized_types.is_defined(ix) { - // x86_64 ABI says enum is 32 bits wide - let mem_size = AtomType::U32.mem_size(); - let mem_align = mem_size; - finalized_types.define( - ix, - DatatypeRepr { - variant: DatatypeVariantRepr::Enum(EnumDatatypeRepr { - members: e.members.clone(), - }), - mem_size, - mem_align, - }, - ); - } - } - } - if !ordered.contains(&ix) { - ordered.push(ix) - } - - // dfs: allowed to visit here again - visited[ix] = false; - Ok(()) - } - - fn datatype_size_align( - &self, - id: DatatypeIdent, - finalized_types: &FinalizedTypes, - ) -> (usize, usize) { - let (size, align) = if id.module == self.names.module { - finalized_types - .size_align(id.datatype) - .expect("looking up type defined in this module") - } else { - let dt = self - .env - .datatype_by_id(id) - .expect("looking up identifier external to this module"); - (dt.mem_size(), dt.mem_align()) - }; - assert!(size > 0); - assert!(align > 0); - (size, align) - } -} - -struct FinalizedTypes { - types: SecondaryMap>, -} - -impl FinalizedTypes { - fn new(map_size: usize) -> Self { - let mut types = SecondaryMap::new(); - types.resize(map_size); - Self { types } - } - - fn is_defined(&self, ix: DatatypeIx) -> bool { - self.types.get(ix).expect("index exists in types").is_some() - } - - fn size_align(&self, ix: DatatypeIx) -> Option<(usize, usize)> { - if let Some(d) = self.types.get(ix).expect("index exists in types") { - Some((d.mem_size, d.mem_align)) - } else { - None - } - } - - fn define(&mut self, ix: DatatypeIx, repr: DatatypeRepr) { - self.types[ix] = Some(repr) - } - - fn build(self) -> PrimaryMap { - let mut datatypes = PrimaryMap::new(); - for dt in self.types.values() { - datatypes.push(dt.clone().expect("all datatypes finalized")); - } - datatypes - } -} - -fn align_to(offs: usize, alignment: usize) -> usize { - offs + alignment - 1 - ((offs + alignment - 1) % alignment) -} - -#[cfg(test)] -mod align_test { - use super::align_to; - #[test] - fn align_test() { - assert_eq!(0, align_to(0, 1)); - assert_eq!(0, align_to(0, 2)); - assert_eq!(0, align_to(0, 4)); - assert_eq!(0, align_to(0, 8)); - - assert_eq!(1, align_to(1, 1)); - assert_eq!(2, align_to(1, 2)); - assert_eq!(4, align_to(1, 4)); - assert_eq!(8, align_to(1, 8)); - - assert_eq!(2, align_to(2, 1)); - assert_eq!(2, align_to(2, 2)); - assert_eq!(4, align_to(2, 4)); - assert_eq!(8, align_to(2, 8)); - - assert_eq!(5, align_to(5, 1)); - assert_eq!(6, align_to(5, 2)); - assert_eq!(8, align_to(5, 4)); - assert_eq!(8, align_to(5, 8)); - } -} diff --git a/lucet-idl/src/validate/function.rs b/lucet-idl/src/validate/function.rs deleted file mode 100644 index 74d200f82..000000000 --- a/lucet-idl/src/validate/function.rs +++ /dev/null @@ -1,417 +0,0 @@ -use super::names::ModNamesBuilder; -use crate::parser::{BindingDirSyntax, BindingRefSyntax, BindingSyntax, FuncArgSyntax}; -use crate::repr::{ - ArgIx, BindingDirection, BindingFromRepr, BindingIx, BindingRepr, FuncIx, FuncRepr, - ModuleFuncsRepr, ParamIx, ParamRepr, RetIx, -}; -use crate::{AbiType, AtomType, Datatype, Location, Module, ValidationError}; -use cranelift_entity::{EntityRef, PrimaryMap}; -use std::collections::HashMap; -use std::convert::TryFrom; -use std::ops::Deref; - -pub struct FunctionModuleBuilder<'a> { - env: Module<'a>, - names: &'a ModNamesBuilder, - funcs: PrimaryMap, -} - -impl<'a> FunctionModuleBuilder<'a> { - pub fn new(env: Module<'a>, names: &'a ModNamesBuilder) -> Self { - Self { - env, - names, - funcs: PrimaryMap::new(), - } - } - - pub fn introduce_func( - &mut self, - name: &str, - args: &[FuncArgSyntax], - rets: &[FuncArgSyntax], - bindings: &[BindingSyntax], - location: Location, - ) -> Result<(), ValidationError> { - let mut validator = FuncValidator::new(location, &self.env); - validator.introduce_args(args)?; - validator.introduce_rets(rets)?; - validator.introduce_bindings(bindings)?; - - let defined_ix = self.funcs.push(FuncRepr { - args: validator.args, - rets: validator.rets, - bindings: validator.bindings, - }); - let declared_ix = self.names.func_from_name(name).expect("declared func"); - assert_eq!( - defined_ix, declared_ix, - "funcs defined in different order than declared" - ); - Ok(()) - } - - pub fn build(self) -> ModuleFuncsRepr { - assert_eq!( - self.names.funcs.len(), - self.funcs.len(), - "each func declared has been defined" - ); - ModuleFuncsRepr { - names: self.names.funcs.clone(), - funcs: self.funcs, - } - } -} - -struct FuncValidator<'a> { - // arg/return name to declaration location and argument position - param_names: HashMap, - // Arg positions index into this vector: - args: PrimaryMap, - // Ret positions index into this vector: - rets: PrimaryMap, - // binding name to declaration location and binding position - binding_names: HashMap<&'a str, (Location, BindingIx)>, - // param position to binding syntax - bindings: PrimaryMap, - param_binding_sites: HashMap, - location: Location, - module: &'a Module<'a>, -} - -impl<'a> FuncValidator<'a> { - fn new(location: Location, module: &'a Module<'a>) -> Self { - Self { - param_names: HashMap::new(), - args: PrimaryMap::new(), - rets: PrimaryMap::new(), - binding_names: HashMap::new(), - bindings: PrimaryMap::new(), - param_binding_sites: HashMap::new(), - location, - module, - } - } - fn introduce_param_name( - &mut self, - arg_syntax: &FuncArgSyntax, - position: ParamIx, - ) -> Result { - if let Some((previous_location, _)) = self.param_names.get(arg_syntax.name) { - Err(ValidationError::NameAlreadyExists { - name: arg_syntax.name.to_owned(), - at_location: arg_syntax.location, - previous_location: *previous_location, - })?; - } else { - self.param_names - .insert(arg_syntax.name.to_owned(), (arg_syntax.location, position)); - } - let type_ = - AbiType::try_from(arg_syntax.type_.name).map_err(|_| ValidationError::Syntax { - expected: "abi type", - location: arg_syntax.type_.location, - })?; - Ok(ParamRepr { - name: arg_syntax.name.to_owned(), - type_, - }) - } - - fn introduce_args(&mut self, args: &[FuncArgSyntax]) -> Result<(), ValidationError> { - for (ix, arg) in args.iter().enumerate() { - let arg_ix = ArgIx::new(ix); - let a = self.introduce_param_name(arg, ParamIx::Arg(arg_ix))?; - let pushed_arg_ix = self.args.push(a); - assert_eq!(arg_ix, pushed_arg_ix); - } - Ok(()) - } - fn introduce_rets(&mut self, rets: &[FuncArgSyntax]) -> Result<(), ValidationError> { - if rets.len() > 1 { - Err(ValidationError::Syntax { - expected: "at most one return value", - location: self.location, - })? - } - for (ix, r) in rets.iter().enumerate() { - let ret_ix = RetIx::new(ix); - let r = self.introduce_param_name(r, ParamIx::Ret(ret_ix))?; - let pushed_ret_ix = self.rets.push(r); - assert_eq!(ret_ix, pushed_ret_ix); - } - Ok(()) - } - - fn introduce_bindings( - &mut self, - bindings: &[BindingSyntax<'a>], - ) -> Result<(), ValidationError> { - for (ix, binding) in bindings.iter().enumerate() { - let ix = BindingIx::new(ix); - let b = self.introduce_binding(binding, ix)?; - let pushed_ix = self.bindings.push(b); - assert_eq!(ix, pushed_ix); - } - for (ix, arg) in self.args.iter() { - let position = ParamIx::Arg(ix); - if !self.param_binding_sites.contains_key(&position) { - self.bindings - .push(self.implicit_value_binding(&arg, position)?); - } - } - for (ix, ret) in self.rets.iter() { - let position = ParamIx::Ret(ix); - if !self.param_binding_sites.contains_key(&position) { - self.bindings - .push(self.implicit_value_binding(&ret, position)?); - } - } - Ok(()) - } - - fn introduce_binding( - &mut self, - binding: &BindingSyntax<'a>, - ix: BindingIx, - ) -> Result { - // 1. make sure binding name is unique - if let Some((previous_location, _)) = self.binding_names.get(&binding.name) { - Err(ValidationError::NameAlreadyExists { - name: binding.name.to_owned(), - at_location: binding.location, - previous_location: *previous_location, - })?; - } else { - self.binding_names - .insert(binding.name, (binding.location, ix)); - } - - // 2. resolve type_ SyntaxIdent to a Datatype - let type_ = self.module.datatype(&binding.type_.name).ok_or_else(|| { - ValidationError::NameNotFound { - name: binding.type_.name.to_owned(), - use_location: binding.location, - } - })?; - - // 3. typecheck the binding: - let from = self.validate_binding_ref(&binding, &type_)?; - - // 4. direction from syntax: - let direction = match binding.direction { - BindingDirSyntax::In => BindingDirection::In, - BindingDirSyntax::InOut => BindingDirection::InOut, - BindingDirSyntax::Out => BindingDirection::Out, - }; - - Ok(BindingRepr { - name: binding.name.to_owned(), - type_: type_.id(), - direction, - from, - }) - } - - fn implicit_value_binding( - &self, - arg: &ParamRepr, - position: ParamIx, - ) -> Result { - // 1. make sure binding name is unique. We're re-using the arg name - // for the binding. If another binding overlapped with the arg name, - // it is now at fault. (complicated, huh... :/) - if let Some((previous_location, _)) = self.binding_names.get(arg.name.as_str()) { - let (arg_location, _) = self.param_names.get(&arg.name).expect("arg introduced"); - Err(ValidationError::BindingNameAlreadyBound { - name: arg.name.clone(), - at_location: *previous_location, - bound_location: *arg_location, - })?; - } - - // 2. resolve type - let type_ = AtomType::from(arg.type_).datatype_id(); - - // 3. construct the binding from-value for this position - let from = BindingFromRepr::Value(position); - - // 4. direction depends on whether param is an arg or ret - let direction = match position { - ParamIx::Arg(_) => BindingDirection::In, - ParamIx::Ret(_) => BindingDirection::Out, - }; - - Ok(BindingRepr { - name: arg.name.clone(), - type_, - direction, - from, - }) - } - - fn get_arg(&self, arg_name: &str) -> Option<(ParamIx, ParamRepr)> { - let (_, position) = self.param_names.get(arg_name)?; - match position { - ParamIx::Arg(ix) => Some(( - *position, - self.args.get(*ix).expect("in-bounds arg index").clone(), - )), - ParamIx::Ret(ix) => Some(( - *position, - self.rets.get(*ix).expect("in-bounds ret index").clone(), - )), - } - } - - fn validate_binding_arg_mapping( - &mut self, - name: &str, - location: Location, - ) -> Result<(ParamIx, ParamRepr), ValidationError> { - // Check that it refers to a valid arg: - let (position, arg) = self.get_arg(name).ok_or_else(|| ValidationError::Syntax { - expected: "name of an argument or return value", - location, - })?; - // Check that the arg has only been used once: - if let Some(use_location) = self.param_binding_sites.get(&position) { - Err(ValidationError::BindingNameAlreadyBound { - name: name.to_owned(), - at_location: location, - bound_location: *use_location, - })?; - } else { - self.param_binding_sites.insert(position.clone(), location); - } - Ok((position, arg)) - } - - fn validate_binding_ref( - &mut self, - binding: &BindingSyntax, - target_type: &Datatype<'a>, - ) -> Result { - match &binding.from { - // A pointer to a name is accepted: - BindingRefSyntax::Ptr(bref) => match **bref { - BindingRefSyntax::Name(ref name) => { - let (position, funcarg) = - self.validate_binding_arg_mapping(name, binding.location)?; - if funcarg.type_ != AbiType::I32 { - Err(ValidationError::BindingTypeError { - expected: "pointer bindings to be represented as an i32", - location: binding.location, - })?; - } - match position { - ParamIx::Arg(_) => { - // all good! Arg pointers are valid for in, inout, or out binding. - } - ParamIx::Ret(_) => { - Err(ValidationError::BindingTypeError { - expected: "return value cannot be bound to pointer", - location: binding.location, - })?; - } - } - Ok(BindingFromRepr::Ptr(position)) - } - _ => Err(ValidationError::Syntax { - expected: "pointer binding must be of form *arg", - location: binding.location, - }), - }, - // A slice of two names is accepted: - BindingRefSyntax::Slice(ref ptr_ref, ref len_ref) => { - match (ptr_ref.deref(), len_ref.deref()) { - ( - BindingRefSyntax::Name(ref ptr_name), - BindingRefSyntax::Name(ref len_name), - ) => { - let (ptr_position, ptr_arg) = - self.validate_binding_arg_mapping(ptr_name, binding.location)?; - if ptr_arg.type_ != AbiType::I32 { - Err(ValidationError::BindingTypeError { - expected: "slice pointer must be i32", - location: binding.location, - })?; - } - let (len_position, len_arg) = - self.validate_binding_arg_mapping(len_name, binding.location)?; - if len_arg.type_ != AbiType::I32 { - Err(ValidationError::BindingTypeError { - expected: "slice len must be i32", - location: binding.location, - })?; - } - match (&ptr_position, &len_position) { - (ParamIx::Arg(_), ParamIx::Arg(_)) => {} - _ => { - Err(ValidationError::BindingTypeError { - expected: "slice bindings must be inputs", - location: binding.location, - })?; - } - } - if binding.direction == BindingDirSyntax::Out { - Err(ValidationError::BindingTypeError { - expected: "slice bindings must be in or inout", - location: binding.location, - })?; - } - Ok(BindingFromRepr::Slice(ptr_position, len_position)) - } - _ => Err(ValidationError::Syntax { - expected: "slice binding must be of form [ptr, len]", - location: binding.location, - }), - } - } - // A bare name is accepted: - BindingRefSyntax::Name(ref name) => { - let (position, funcarg) = - self.validate_binding_arg_mapping(name, binding.location)?; - - // make sure funcarg.type_ is a valid representation of target type - match target_type.abi_type() { - Some(target_repr) => { - if !funcarg.type_.can_represent(&target_repr) { - Err(ValidationError::BindingTypeError { - expected: "binding type which can represent argument type", - location: binding.location, - })?; - } - } - None => { - Err(ValidationError::BindingTypeError { - expected: "binding type to be representable as value (try passing by reference instead)", - location: binding.location, - })?; - } - } - // Arg values must be in-only bindings, Ret values must be out-only bindings - match position { - ParamIx::Arg(_) => { - if binding.direction != BindingDirSyntax::In { - Err(ValidationError::BindingTypeError { - expected: "argument value must be input-only binding", - location: binding.location, - })?; - } - } - ParamIx::Ret(_) => { - if binding.direction != BindingDirSyntax::Out { - Err(ValidationError::BindingTypeError { - expected: "return value must be output-only binding", - location: binding.location, - })?; - } - } - } - Ok(BindingFromRepr::Value(position)) - } - } - } -} diff --git a/lucet-idl/src/validate/mod.rs b/lucet-idl/src/validate/mod.rs deleted file mode 100644 index d71f26dd6..000000000 --- a/lucet-idl/src/validate/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod datatypes; -mod function; -mod module; -mod names; -mod package; - -pub use package::{package_from_declarations, PackageBuilder}; diff --git a/lucet-idl/src/validate/module.rs b/lucet-idl/src/validate/module.rs deleted file mode 100644 index 9b6d58028..000000000 --- a/lucet-idl/src/validate/module.rs +++ /dev/null @@ -1,655 +0,0 @@ -use super::datatypes::DatatypeModuleBuilder; -use super::function::FunctionModuleBuilder; -use super::names::ModNamesBuilder; -use crate::parser::ModuleDecl; -use crate::repr::{ModuleIx, ModuleRepr}; -use crate::{Package, ValidationError}; - -pub fn module_from_declarations( - env: &Package, - ix: ModuleIx, - decls: &[ModuleDecl], -) -> Result { - // First, we need to declare names of all the declarations - let mut names = ModNamesBuilder::new(ix); - for decl in decls.iter() { - match decl { - ModuleDecl::Struct { name, location, .. } - | ModuleDecl::Enum { name, location, .. } - | ModuleDecl::Alias { name, location, .. } => { - names.introduce_datatype(name, location)?; - } - ModuleDecl::Function { name, location, .. } => { - names.introduce_function(name, location)?; - } - } - } - - // Datatypes are defined in terms of the parent environment: - let mut datatypes_builder = DatatypeModuleBuilder::new(env, &names); - - // Then, we can define each datatype - for decl in decls.iter() { - match decl { - ModuleDecl::Struct { - name, - location, - members, - } => { - datatypes_builder.introduce_struct(name, members, *location)?; - } - ModuleDecl::Enum { - name, - location, - variants, - } => { - datatypes_builder.introduce_enum(name, variants, *location)?; - } - ModuleDecl::Alias { - name, - location, - what, - } => { - datatypes_builder.introduce_alias(name, what, *location)?; - } - _ => {} - } - } - - // Finalize the datatypes - ensure finite, calculate layout information: - let datatypes_module = datatypes_builder.build()?; - - // Cons these datatypes onto the packagerepr, then create a Module cursor - let mut funcs_env_repr = env.clone(); - funcs_env_repr - .modules - .push(ModuleRepr::from_datatypes(datatypes_module.clone())); - let funcs_env = funcs_env_repr.module_by_ix(ix).unwrap(); - - // Now we can define each function: - let mut funcs_builder = FunctionModuleBuilder::new(funcs_env, &names); - - for decl in decls { - if let ModuleDecl::Function { - name, - args, - rets, - bindings, - location, - } = decl - { - funcs_builder.introduce_func(name, args, rets, bindings, *location)?; - } - } - - let funcs_module = funcs_builder.build(); - - Ok(ModuleRepr { - datatypes: datatypes_module, - funcs: funcs_module, - }) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::parser::Parser; - use crate::validate::package::PackageBuilder; - use crate::{BindingDirection, DatatypeVariant, Location, MemArea, ParamPosition}; - fn mod_syntax(syntax: &str) -> Result { - let mut parser = Parser::new(syntax); - let decls = parser.match_module_decls().expect("parses"); - - let mut pkg_builder = PackageBuilder::new(); - let mod_ix = pkg_builder - .introduce_name("mod", Location { line: 0, column: 0 }) - .expect("declare name ok"); - let module_repr = module_from_declarations(pkg_builder.repr(), mod_ix, &decls)?; - pkg_builder.define_module(mod_ix, module_repr); - Ok(pkg_builder.build()) - } - - #[test] - fn structs_basic() { - assert!(mod_syntax("struct foo { a: i32}").is_ok()); - assert!(mod_syntax("struct foo { a: i32, b: f32 }").is_ok()); - } - - #[test] - fn struct_two_atoms() { - let pkg_r = mod_syntax("struct foo { a: i32, b: f32 }").expect("valid"); - let module = pkg_r.module("mod").unwrap(); - let foo = module.datatype("foo").expect("foo datatype defined"); - assert_eq!(foo.mem_size(), 8); - assert_eq!(foo.mem_align(), 4); - match foo.variant() { - DatatypeVariant::Struct(s) => { - assert_eq!(s.members().collect::>().len(), 2); - let a = s.member("a").expect("get member a"); - assert_eq!(a.name(), "a"); - assert_eq!(a.type_().name(), "i32"); - assert_eq!(a.offset(), 0); - - let b = s.member("b").expect("get member b"); - assert_eq!(b.name(), "b"); - assert_eq!(b.type_().name(), "f32"); - assert_eq!(b.offset(), 4); - } - _ => panic!("foo is a struct!"), - } - } - - #[test] - fn struct_prev_definition() { - // Refer to a struct defined previously: - assert!(mod_syntax("struct foo { a: i32, b: f64 } struct bar { a: foo }").is_ok()); - } - - #[test] - fn struct_next_definition() { - // Refer to a struct defined afterwards: - assert!(mod_syntax("struct foo { a: i32, b: bar} struct bar { a: i32 }").is_ok()); - } - - #[test] - fn struct_self_referential() { - // Refer to itself - let e = mod_syntax("struct list { next: list, thing: i32 }"); - assert!(e.is_err()); - assert_eq!( - e.err().unwrap(), - ValidationError::Infinite { - name: "list".to_owned(), - location: Location { line: 1, column: 0 }, - } - ); - } - - #[test] - fn struct_empty() { - // No members - assert_eq!( - mod_syntax("struct foo {}").err().unwrap(), - ValidationError::Empty { - name: "foo".to_owned(), - location: Location { line: 1, column: 0 }, - } - ); - } - - #[test] - fn struct_duplicate_member() { - // Duplicate member in struct - assert_eq!( - mod_syntax("struct foo { \na: i32, \na: f64}") - .err() - .unwrap(), - ValidationError::NameAlreadyExists { - name: "a".to_owned(), - at_location: Location { line: 3, column: 0 }, - previous_location: Location { line: 2, column: 0 }, - } - ); - } - - #[test] - fn struct_duplicate_definition() { - // Duplicate definition of struct - assert_eq!( - mod_syntax("struct foo { a: i32 }\nstruct foo { a: i32 } ") - .err() - .unwrap(), - ValidationError::NameAlreadyExists { - name: "foo".to_owned(), - at_location: Location { line: 2, column: 0 }, - previous_location: Location { line: 1, column: 0 }, - } - ); - } - - #[test] - fn struct_undeclared_member() { - // Refer to type that is not declared - assert_eq!( - mod_syntax("struct foo { \nb: bar }").err().unwrap(), - ValidationError::NameNotFound { - name: "bar".to_owned(), - use_location: Location { line: 2, column: 3 }, - } - ); - } - - #[test] - fn enums() { - assert!(mod_syntax("enum foo { a }").is_ok()); - assert!(mod_syntax("enum foo { a, b }").is_ok()); - - { - let pkg = mod_syntax("enum foo { a, b }").expect("valid syntax"); - let m = pkg.module("mod").expect("get module"); - let foo = m.datatype("foo").expect("get foo"); - match foo.variant() { - DatatypeVariant::Enum(e) => { - assert_eq!(e.variants().collect::>().len(), 2); - let a = e.variant("a").expect("variant a exists"); - assert_eq!(a.name(), "a"); - assert_eq!(a.index(), 0); - let b = e.variant("b").expect("variant b exists"); - assert_eq!(b.name(), "b"); - assert_eq!(b.index(), 1); - } - _ => panic!("foo is an enum!"), - } - } - - // No members - assert_eq!( - mod_syntax("enum foo {}").err().unwrap(), - ValidationError::Empty { - name: "foo".to_owned(), - location: Location { line: 1, column: 0 }, - } - ); - - // Duplicate member in enum - assert_eq!( - mod_syntax("enum foo { \na,\na }").err().unwrap(), - ValidationError::NameAlreadyExists { - name: "a".to_owned(), - at_location: Location { line: 3, column: 0 }, - previous_location: Location { line: 2, column: 0 }, - } - ); - - // Duplicate definition of enum - assert_eq!( - mod_syntax("enum foo { a }\nenum foo { a } ").err().unwrap(), - ValidationError::NameAlreadyExists { - name: "foo".to_owned(), - at_location: Location { line: 2, column: 0 }, - previous_location: Location { line: 1, column: 0 }, - } - ); - } - - #[test] - fn aliases() { - assert!(mod_syntax("type foo = i32;").is_ok()); - assert!(mod_syntax("type foo = f64;").is_ok()); - assert!(mod_syntax("type foo = u8;").is_ok()); - assert!(mod_syntax("type link = u32;\nstruct list { next: link, thing: i32 }").is_ok()); - - let pkg = mod_syntax("type foo = bar;\nenum bar { a }").expect("valid"); - let m = pkg.module("mod").expect("get module"); - let foo = m.datatype("foo").expect("get foo"); - - match foo.variant() { - DatatypeVariant::Alias(a) => { - assert_eq!(a.datatype().name(), "foo"); - assert_eq!(a.to().name(), "bar"); - } - _ => panic!("foo is an alias"), - } - } - - #[test] - fn infinite() { - assert_eq!( - mod_syntax("type foo = bar;\ntype bar = foo;") - .err() - .unwrap(), - ValidationError::Infinite { - name: "foo".to_owned(), - location: Location { line: 1, column: 0 }, - } - ); - - assert_eq!( - mod_syntax("type foo = bar;\nstruct bar { a: foo }") - .err() - .unwrap(), - ValidationError::Infinite { - name: "foo".to_owned(), - location: Location { line: 1, column: 0 }, - } - ); - - assert_eq!( - mod_syntax("type foo = bar;\nstruct bar { a: baz }\nstruct baz { c: i32, e: foo }") - .err() - .unwrap(), - ValidationError::Infinite { - name: "foo".to_owned(), - location: Location { line: 1, column: 0 }, - } - ); - } - - #[test] - fn func_trivial() { - let pkg = mod_syntax("fn foo();").expect("valid module"); - let m = pkg.module("mod").expect("get module"); - let foo = m.function("foo").expect("get foo"); - assert_eq!(foo.name(), "foo"); - assert_eq!(foo.params().collect::>().len(), 0); - assert_eq!(foo.bindings().collect::>().len(), 0); - } - - #[test] - fn func_one_arg() { - let pkg = mod_syntax("fn foo(a: i64);").expect("valid module"); - let m = pkg.module("mod").expect("get module"); - let foo = m.function("foo").expect("get foo"); - - assert_eq!(foo.args().collect::>().len(), 1); - let a = foo.arg("a").expect("arg a exists"); - assert_eq!(a.name(), "a"); - assert_eq!(a.type_().name(), "i64"); - assert_eq!(a.binding().name(), "a"); - - assert_eq!(foo.rets().collect::>().len(), 0); - assert_eq!(foo.bindings().collect::>().len(), 1); - - let a_bind = foo.binding("a").expect("binding a exists"); - assert_eq!(a_bind.name(), "a"); - assert_eq!(a_bind.type_().name(), "i64"); - assert_eq!(a_bind.direction(), BindingDirection::In); - let a_val = a_bind.param().value().expect("binding is a value"); - assert_eq!(a_val.name(), "a"); - assert_eq!(a_val.param_position(), ParamPosition::Arg(0)); - } - - #[test] - fn func_one_ret() { - let pkg = mod_syntax("fn foo() -> r: i64;").expect("valid module"); - let m = pkg.module("mod").expect("get module"); - let foo = m.function("foo").expect("get foo"); - - assert_eq!(foo.rets().collect::>().len(), 1); - let r = foo.ret("r").expect("ret r exists"); - assert_eq!(r.name(), "r"); - assert_eq!(r.type_().name(), "i64"); - assert_eq!(r.binding().name(), "r"); - - assert_eq!(foo.args().collect::>().len(), 0); - assert_eq!(foo.bindings().collect::>().len(), 1); - - let r_bind = foo.binding("r").expect("binding r exists"); - assert_eq!(r_bind.name(), "r"); - assert_eq!(r_bind.type_().name(), "i64"); - assert_eq!(r_bind.direction(), BindingDirection::Out); - let r_val = r_bind.param().value().expect("binding is a value"); - assert_eq!(r_val.name(), "r"); - assert_eq!(r_val.param_position(), ParamPosition::Ret(0)); - } - - #[test] - fn func_multiple_returns() { - assert_eq!( - mod_syntax("fn trivial(a: i32) -> r1: i32, r2: i32;") - .err() - .unwrap(), - ValidationError::Syntax { - expected: "at most one return value", - location: Location { line: 1, column: 0 }, - } - ); - } - - #[test] - fn func_duplicate_arg() { - assert_eq!( - mod_syntax("fn trivial(a: i32, a: i32);").err().unwrap(), - ValidationError::NameAlreadyExists { - name: "a".to_owned(), - at_location: Location { - line: 1, - column: 19 - }, - previous_location: Location { - line: 1, - column: 11 - }, - } - ); - } - - #[test] - fn func_one_arg_value_binding() { - let pkg = mod_syntax("fn foo(a: i32) where\na_binding: in i8 <- a;").expect("valid"); - let m = pkg.module("mod").expect("get module"); - let foo = m.function("foo").expect("get foo"); - - assert_eq!(foo.args().collect::>().len(), 1); - assert_eq!(foo.bindings().collect::>().len(), 1); - - let a = foo.arg("a").expect("arg a exists"); - assert_eq!(a.name(), "a"); - assert_eq!(a.type_().name(), "i32"); - assert_eq!(a.binding().direction(), BindingDirection::In); - assert_eq!(a.binding().name(), "a_binding"); - a.binding() - .param() - .value() - .expect("binding param used as value"); - assert_eq!(a.binding().type_().name(), "i8"); - } - - #[test] - fn func_one_arg_ptr_binding() { - let pkg = mod_syntax("fn foo(a: i32) where\na_binding: inout i8 <- *a;").expect("valid"); - let m = pkg.module("mod").expect("get module"); - let foo = m.function("foo").expect("get foo"); - - assert_eq!(foo.args().collect::>().len(), 1); - assert_eq!(foo.bindings().collect::>().len(), 1); - - let a = foo.arg("a").expect("arg a exists"); - assert_eq!(a.name(), "a"); - assert_eq!(a.type_().name(), "i32"); - assert_eq!(a.binding().direction(), BindingDirection::InOut); - assert_eq!(a.binding().name(), "a_binding"); - a.binding() - .param() - .ptr() - .expect("binding param used as ptr"); - assert_eq!(a.binding().type_().name(), "i8"); - } - - #[test] - fn func_one_arg_binding_wrong_direction() { - assert_eq!( - mod_syntax("fn foo(a: i32) where\na_binding: out i8 <- a;") - .err() - .unwrap(), - ValidationError::BindingTypeError { - expected: "argument value must be input-only binding", - location: Location { line: 2, column: 0 } - }, - ); - } - - #[test] - fn func_one_arg_binding_wrong_type() { - // Cant convert int to float - assert_eq!( - mod_syntax("fn trivial(a: i32) where\na_binding: in f32 <- a;") - .err() - .unwrap(), - ValidationError::BindingTypeError { - expected: "binding type which can represent argument type", - location: Location { line: 2, column: 0 } - }, - ); - // Cant convert float to int - assert_eq!( - mod_syntax("fn trivial(a: f32) where\na_binding: in i32 <- a;") - .err() - .unwrap(), - ValidationError::BindingTypeError { - expected: "binding type which can represent argument type", - location: Location { line: 2, column: 0 } - }, - ); - // Cant represent i64 with i32 - assert_eq!( - mod_syntax("fn trivial(a: i32) where\na_binding: in i64 <- a;") - .err() - .unwrap(), - ValidationError::BindingTypeError { - expected: "binding type which can represent argument type", - location: Location { line: 2, column: 0 } - }, - ); - - // but, can represent i32 with i64 - mod_syntax("fn trivial(a: i64) where\na_binding: in i32 <- a;").unwrap(); - - // Cant represent f64 with f32 - assert_eq!( - mod_syntax("fn trivial(a: f32) where\na_binding: in f64 <- a;") - .err() - .unwrap(), - ValidationError::BindingTypeError { - expected: "binding type which can represent argument type", - location: Location { line: 2, column: 0 } - }, - ); - - // Cant represent ptr with f32 - assert_eq!( - mod_syntax("fn trivial(a: f32) where\na_binding: in i8 <- *a;") - .err() - .unwrap(), - ValidationError::BindingTypeError { - expected: "pointer bindings to be represented as an i32", - location: Location { line: 2, column: 0 } - }, - ); - // Cant represent ptr with i64 - assert_eq!( - mod_syntax("fn trivial(a: i64) where\na_binding: out i8 <- *a;") - .err() - .unwrap(), - ValidationError::BindingTypeError { - expected: "pointer bindings to be represented as an i32", - location: Location { line: 2, column: 0 } - }, - ); - } - - #[test] - fn func_one_ret_value_binding() { - let pkg = mod_syntax("fn foo() -> a: i32 where\na_binding: out i8 <- a;").expect("valid"); - - let m = pkg.module("mod").expect("get module"); - let foo = m.function("foo").expect("get foo"); - - assert_eq!(foo.rets().collect::>().len(), 1); - assert_eq!(foo.bindings().collect::>().len(), 1); - - let a = foo.ret("a").expect("ret a exists"); - assert_eq!(a.name(), "a"); - assert_eq!(a.type_().name(), "i32"); - assert_eq!(a.binding().direction(), BindingDirection::Out); - assert_eq!(a.binding().name(), "a_binding"); - a.binding() - .param() - .value() - .expect("binding param used as value"); - assert_eq!(a.binding().type_().name(), "i8"); - } - - #[test] - fn func_one_ret_pointer_binding() { - assert_eq!( - mod_syntax("fn trivial() -> a: i32 where\na_binding: out i8 <- *a;") - .err() - .unwrap(), - ValidationError::BindingTypeError { - expected: "return value cannot be bound to pointer", - location: Location { line: 2, column: 0 }, - } - ); - } - - #[test] - fn func_one_ret_wrong_direction() { - assert_eq!( - mod_syntax("fn trivial() -> a: i32 where\na_binding: in i8 <- a;") - .err() - .unwrap(), - ValidationError::BindingTypeError { - expected: "return value must be output-only binding", - location: Location { line: 2, column: 0 } - }, - ); - } - - #[test] - fn func_two_arg_slice_binding() { - let pkg = mod_syntax( - "fn foo(a_ptr: i32, a_len: i32) where\na_binding: inout i8 <- [a_ptr, a_len];", - ) - .expect("valid"); - let m = pkg.module("mod").expect("get module"); - let foo = m.function("foo").expect("get foo"); - - assert_eq!(foo.args().collect::>().len(), 2); - assert_eq!(foo.bindings().collect::>().len(), 1); - - let a_ptr = foo.arg("a_ptr").expect("arg a_ptr exists"); - let a_len = foo.arg("a_len").expect("arg a_len exists"); - assert_eq!(a_ptr.type_().name(), "i32"); - assert_eq!(a_len.type_().name(), "i32"); - - assert_eq!(a_ptr.binding().name(), "a_binding"); - assert_eq!(a_len.binding().name(), "a_binding"); - assert_eq!(a_ptr.binding().type_().name(), "i8"); - let (a_ptr_2, a_len_2) = a_ptr - .binding() - .param() - .slice() - .expect("binding param used as slice"); - assert_eq!(a_ptr_2.name(), "a_ptr"); - assert_eq!(a_len_2.name(), "a_len"); - } - - #[test] - fn func_buncha_bindings() { - let pkg = mod_syntax( - "fn nontrivial(a: i32, b: i32, c: f32) -> d: i32 where\n\ - a_binding: out u8 <- *a,\n\ - b_binding: inout u16 <- *b,\n\ - c_binding: in f32 <- c,\n\ - d_binding: out i8 <- d;\n\ - ", - ) - .expect("valid"); - - let m = pkg.module("mod").expect("get module"); - let nontrivial = m.function("nontrivial").expect("get nontrivial"); - - assert_eq!(nontrivial.args().collect::>().len(), 3); - assert_eq!(nontrivial.rets().collect::>().len(), 1); - assert_eq!(nontrivial.bindings().collect::>().len(), 4); - - let a = nontrivial.arg("a").expect("arg a exists"); - assert_eq!(a.type_().name(), "i32"); - let b = nontrivial.arg("b").expect("arg b exists"); - assert_eq!(b.type_().name(), "i32"); - let c = nontrivial.arg("c").expect("arg c exists"); - assert_eq!(c.type_().name(), "f32"); - let d = nontrivial.ret("d").expect("ret d exists"); - assert_eq!(d.type_().name(), "i32"); - - let a_binding = nontrivial.binding("a_binding").expect("a_binding exists"); - assert_eq!(a_binding.direction(), BindingDirection::Out); - let b_binding = nontrivial.binding("b_binding").expect("b_binding exists"); - assert_eq!(b_binding.direction(), BindingDirection::InOut); - let c_binding = nontrivial.binding("c_binding").expect("c_binding exists"); - assert_eq!(c_binding.direction(), BindingDirection::In); - let d_binding = nontrivial.binding("d_binding").expect("d_binding exists"); - assert_eq!(d_binding.direction(), BindingDirection::Out); - } -} diff --git a/lucet-idl/src/validate/names.rs b/lucet-idl/src/validate/names.rs deleted file mode 100644 index 627c1ab31..000000000 --- a/lucet-idl/src/validate/names.rs +++ /dev/null @@ -1,112 +0,0 @@ -use crate::parser::SyntaxIdent; -use crate::repr::{DatatypeIdent, DatatypeIx, FuncIx, ModuleIx}; -use crate::{AtomType, Location, ValidationError}; -use cranelift_entity::PrimaryMap; -use std::collections::HashMap; -use std::convert::TryFrom; - -pub struct ModNamesBuilder { - pub module: ModuleIx, - pub funcs: PrimaryMap, - pub types: PrimaryMap, - names: HashMap, -} - -impl ModNamesBuilder { - pub fn new(module: ModuleIx) -> Self { - Self { - module, - names: HashMap::new(), - funcs: PrimaryMap::new(), - types: PrimaryMap::new(), - } - } - - pub fn introduce_datatype( - &mut self, - name: &str, - location: &Location, - ) -> Result<(), ValidationError> { - if let Some((_, prev_loc)) = self.names.get(name) { - Err(ValidationError::NameAlreadyExists { - name: name.to_owned(), - at_location: *location, - previous_location: *prev_loc, - })?; - } - let ix = self.types.push(name.to_owned()); - self.names - .insert(name.to_owned(), (ModContentIx::Datatype(ix), *location)); - Ok(()) - } - - pub fn introduce_function( - &mut self, - name: &str, - location: &Location, - ) -> Result<(), ValidationError> { - if let Some((_, prev_loc)) = self.names.get(name) { - Err(ValidationError::NameAlreadyExists { - name: name.to_owned(), - at_location: *location, - previous_location: *prev_loc, - })?; - } - let ix = self.funcs.push(name.to_owned()); - self.names - .insert(name.to_owned(), (ModContentIx::Func(ix), *location)); - Ok(()) - } - - pub fn datatype_id_from_syntax( - &self, - syntax: &SyntaxIdent, - ) -> Result { - if let Ok(atom) = AtomType::try_from(syntax.name) { - Ok(atom.datatype_id()) - } else { - match self.names.get(syntax.name) { - Some((ModContentIx::Datatype(ix), _loc)) => { - Ok(DatatypeIdent::new(self.module, *ix)) - } - Some((_, bound_loc)) => Err(ValidationError::NameSortError { - name: syntax.name.to_owned(), - use_location: syntax.location, - bound_location: *bound_loc, - }), - None => Err(ValidationError::NameNotFound { - name: syntax.name.to_owned(), - use_location: syntax.location, - }), - } - } - } - - pub fn datatype_from_name(&self, name: &str) -> Option { - self.names.get(name).and_then(|(ix, _)| ix.datatype()) - } - - pub fn func_from_name(&self, name: &str) -> Option { - self.names.get(name).and_then(|(ix, _)| ix.func()) - } -} - -enum ModContentIx { - Datatype(DatatypeIx), - Func(FuncIx), -} - -impl ModContentIx { - fn datatype(&self) -> Option { - match self { - ModContentIx::Datatype(d) => Some(*d), - _ => None, - } - } - fn func(&self) -> Option { - match self { - ModContentIx::Func(f) => Some(*f), - _ => None, - } - } -} diff --git a/lucet-idl/src/validate/package.rs b/lucet-idl/src/validate/package.rs deleted file mode 100644 index bed4dc872..000000000 --- a/lucet-idl/src/validate/package.rs +++ /dev/null @@ -1,152 +0,0 @@ -use super::module::module_from_declarations; -use crate::error::ValidationError; -use crate::parser::PackageDecl; -use crate::prelude::std_module; -use crate::repr::{ModuleIx, ModuleRepr, Package}; -use crate::Location; -use cranelift_entity::PrimaryMap; -use std::collections::HashMap; - -pub fn package_from_declarations( - package_decls: &[PackageDecl], -) -> Result { - let mut pkg = PackageBuilder::new(); - for decl in package_decls { - match decl { - PackageDecl::Module { - name, - location, - decls, - } => { - let module_ix = pkg.introduce_name(name, *location)?; - let module_repr = module_from_declarations(pkg.repr(), module_ix, &decls)?; - pkg.define_module(module_ix, module_repr); - } - } - } - Ok(pkg.build()) -} - -pub struct PackageBuilder { - name_decls: HashMap)>, - repr: Package, -} - -impl PackageBuilder { - pub fn new() -> Self { - let mut repr = Package { - names: PrimaryMap::new(), - modules: PrimaryMap::new(), - }; - let mut name_decls = HashMap::new(); - repr.names.push("std".to_owned()); - let base_ix = repr.modules.push(std_module()); - name_decls.insert("std".to_owned(), (base_ix, None)); - - Self { name_decls, repr } - } - - pub fn introduce_name( - &mut self, - name: &str, - location: Location, - ) -> Result { - if let Some((_, prev_loc)) = self.name_decls.get(name) { - match prev_loc { - Some(prev_loc) => { - Err(ValidationError::NameAlreadyExists { - name: name.to_owned(), - at_location: location, - previous_location: *prev_loc, - })?; - } - None => { - Err(ValidationError::Syntax { - expected: "non-reserved module name", - location: location, - })?; - } - } - } - let ix = self.repr.names.push(name.to_owned()); - self.name_decls - .insert(name.to_owned(), (ix, Some(location))); - Ok(ix) - } - - pub fn repr(&self) -> &Package { - &self.repr - } - - pub fn define_module(&mut self, ix: ModuleIx, mod_repr: ModuleRepr) { - assert!(self.repr.names.is_valid(ix)); - let pushed_ix = self.repr.modules.push(mod_repr); - assert_eq!(ix, pushed_ix); - } - - pub fn build(self) -> Package { - self.repr - } -} - -#[cfg(test)] -mod test { - use super::*; - use crate::parser::Parser; - use crate::Package; - - fn pkg_(syntax: &str) -> Result { - let mut parser = Parser::new(syntax); - let decls = parser.match_package_decls().expect("parses"); - package_from_declarations(&decls) - } - - #[test] - fn one_empty_mod() { - let pkg = pkg_("mod empty {}").expect("valid package"); - let empty = pkg.module("empty").expect("mod empty exists"); - assert_eq!(empty.name(), "empty"); - assert_eq!(empty.datatypes().collect::>().len(), 0); - assert_eq!(empty.functions().collect::>().len(), 0); - } - - #[test] - fn multiple_empty_mod() { - let pkg = pkg_("mod empty1 {} mod empty2{}mod\nempty3{//\n}").expect("valid package"); - let _ = pkg.module("empty1").expect("mod empty1 exists"); - let _ = pkg.module("empty2").expect("mod empty2 exists"); - let _ = pkg.module("empty3").expect("mod empty3 exists"); - } - - #[test] - fn mod_with_a_type() { - let pkg = pkg_("mod foo { type bar = u8; }").expect("valid package"); - let foo = pkg.module("foo").expect("mod foo exists"); - let _bar = foo.datatype("bar").expect("foo::bar exists"); - } - - #[test] - fn no_mod_std_name() { - let err = pkg_("mod std {}").err().expect("error package"); - assert_eq!( - err, - ValidationError::Syntax { - expected: "non-reserved module name", - location: Location { line: 1, column: 0 }, - } - ); - } - - #[test] - fn no_mod_duplicate_name() { - let err = pkg_("mod foo {}\nmod foo {}").err().expect("error package"); - assert_eq!( - err, - ValidationError::NameAlreadyExists { - name: "foo".to_owned(), - at_location: Location { line: 2, column: 0 }, - previous_location: Location { line: 1, column: 0 }, - } - ); - } -} diff --git a/lucet-idl/tests/example.idl b/lucet-idl/tests/example.idl deleted file mode 100644 index e44f72f29..000000000 --- a/lucet-idl/tests/example.idl +++ /dev/null @@ -1,55 +0,0 @@ -mod example { - // Primitive types: - // `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`, `f32`, `f64`. - - // Enumerations - - enum color { - red, - blue, - green, - } - - // Aliases - - type colour = color; - type col = colour; - - // Structures - - struct st { - a: i8, - b: i32, - c: color, - } - - // functions - - // implicit bindings: in value, out value. - fn set_counter(to: i32) -> r: i32; - - // explicit bindings: in value, out value. - fn set_color(to_int: i32) -> r: i32 - where to: in color <- to_int, prev: out color <- r; - - // binding: in pointer - fn set_struct(struct_pointer: i32) - where st: in st <- *struct_pointer; - - // binding: out pointer - fn get_color_to_ptr(color_ptr: i32) - where color: out color <- *color_ptr; - - // binding: inout pointer - fn swap_color_by_ptr(color_ptr: i32) - where color: inout color <- *color_ptr; - - // binding: in slice - fn debug_str(ptr: i32, len: i32) -> r: i32 - where str: in u8 <- [ptr, len]; - - // binding: inout slice - fn inout_str(ptr: i32, len: i32) -> r: i32 - where str: inout u8 <- [ptr, len]; - -} diff --git a/lucet-idl/tests/example.rs b/lucet-idl/tests/example.rs deleted file mode 100644 index cc6167244..000000000 --- a/lucet-idl/tests/example.rs +++ /dev/null @@ -1,87 +0,0 @@ -use lucet_idl; -use std::env; -use std::fs::File; -use std::path::{Path, PathBuf}; -use std::process::Command; -use tempfile::TempDir; - -/// Get the base path of the installed WASI SDK. -/// -/// This logic is adapted from `lucet-wasi-sdk` so that we do not incur its additional dependencies. -fn wasi_sdk_clang() -> PathBuf { - PathBuf::from(&env::var("WASI_SDK").unwrap_or("/opt/wasi-sdk".to_owned())) - .join("bin") - .join("clang") -} - -#[test] -fn compile_c_guest() { - let config = lucet_idl::Config { - backend: lucet_idl::Backend::CGuest, - }; - - let tempdir = TempDir::new().expect("create tempdir"); - - lucet_idl::run( - &config, - Path::new("tests/example.idl"), - Box::new(File::create(tempdir.path().join("example.h")).expect("create file")), - ) - .expect("run lucet_idl"); - - let cmd_cc = Command::new(wasi_sdk_clang()) - .arg("--target=wasm32-wasi") - .arg("--std=c99") - .arg("-Wl,--allow-undefined") - .arg("-I") - .arg(tempdir.path()) - .arg("tests/example_driver.c") - .arg("-o") - .arg(tempdir.path().join("example")) - .status() - .expect("run cc"); - assert!(cmd_cc.success(), "failure to compile generated code"); -} - -#[test] -fn compile_and_test_rust_guest() { - compile_and_test_rust(lucet_idl::Backend::RustGuest) -} - -/* DISABLED: host needs the lucet_hostcalls! macro from lucet_runtime, - * and we dont want to manage the dep here, lucet-idl-test can handle it -#[test] -fn compile_and_test_rust_host() { - compile_and_test_rust(lucet_idl::Backend::RustHost) -} -*/ - -fn compile_and_test_rust(backend: lucet_idl::Backend) { - let config = lucet_idl::Config { backend }; - - let tempdir = TempDir::new().expect("create tempdir"); - - let gen_file = tempdir.path().join("out.rs"); - - lucet_idl::run( - &config, - Path::new("tests/example.idl"), - Box::new(File::create(gen_file.clone()).expect("create file")), - ) - .expect("run lucet_idl"); - - let cmd_rustc = Command::new("rustc") - .arg(gen_file.clone()) - .arg("--test") - .arg("--allow=dead_code") - .arg("-o") - .arg(tempdir.path().join("example")) - .status() - .expect("run rustcc"); - assert!(cmd_rustc.success(), "failure to compile generated code"); - - let cmd_run = Command::new(tempdir.path().join("example")) - .status() - .expect("run generated code"); - assert!(cmd_run.success(), "failure to run generated code"); -} diff --git a/lucet-idl/tests/example_driver.c b/lucet-idl/tests/example_driver.c deleted file mode 100644 index 590ccfac5..000000000 --- a/lucet-idl/tests/example_driver.c +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include -#include "example.h" - -int main (int argc, char *argv[]) { - - enum color c1 = COLOR_RED; - colour c2 = COLOR_BLUE; - col c3 = COLOR_GREEN; - - struct st s = { - .a = 0, - .b = 123, - .c = COLOR_RED, - }; - - int32_t ctr_res = example_set_counter(666); - - enum color c4 = example_set_color(c1); - - example_set_struct(&s); - - example_get_color_to_ptr(&c1); - - example_swap_color_by_ptr(&c2); - - const uint8_t debug_str[] = "hello, world!"; - example_debug_str(debug_str, sizeof(debug_str)); - - uint8_t inout_str[] = "hello again, I guess"; - example_inout_str(inout_str, sizeof(inout_str)); - - return 0; -} From ebf21f156c5f19ed764c76b12fb3bc58510bc519 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 26 Nov 2019 10:23:58 -0800 Subject: [PATCH 482/512] remove lucet-idl from bump-global-version --- helpers/bump-global-version.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers/bump-global-version.sh b/helpers/bump-global-version.sh index e2ad9acc5..a55d07149 100755 --- a/helpers/bump-global-version.sh +++ b/helpers/bump-global-version.sh @@ -6,7 +6,7 @@ VERSION=$(grep '#*Lucet version ' Cargo.toml | sed 's/^ *# Lucet version *//') dry_run() { echo "Checking if the package can be published (dry run)..." echo - find lucetc lucet-* benchmarks/lucet-* lucet-runtime/lucet-* lucet-idl/lucet-* -type f -maxdepth 1 -name 'Cargo.toml' -print | while read -r file; do + find lucetc lucet-* benchmarks/lucet-* lucet-runtime/lucet-* -type f -maxdepth 1 -name 'Cargo.toml' -print | while read -r file; do dir="$(dirname $file)" echo "* Checking [$dir]" (cd "$dir" && cargo publish --allow-dirty --dry-run >/dev/null) || exit 1 From d4f3e3b4e84c42148c19a325739761853f680201 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 25 Nov 2019 12:39:11 -0800 Subject: [PATCH 483/512] add `#[lucet_hostcall]` attr macro; deprecate `lucet_hostcalls!` The attribute macro is much more flexible syntactically, and in particular allows hostcall implementations to be properly `rustfmt`ed rather than being stuck in the invocation of a macro. --- Cargo.lock | 9 + Cargo.toml | 1 + benchmarks/lucet-benchmarks/src/modules.rs | 55 +++-- .../lucet-runtime-internals/Cargo.toml | 1 + .../src/hostcall_macros.rs | 3 + .../lucet-runtime-internals/src/lib.rs | 1 + .../lucet-runtime-internals/src/vmctx.rs | 44 ++-- lucet-runtime/lucet-runtime-macros/Cargo.toml | 17 ++ lucet-runtime/lucet-runtime-macros/src/lib.rs | 122 ++++++++++ .../lucet-runtime-tests/src/entrypoint.rs | 63 +++-- .../lucet-runtime-tests/src/guest_fault.rs | 22 +- lucet-runtime/lucet-runtime-tests/src/host.rs | 214 ++++++++--------- .../lucet-runtime-tests/src/strcmp.rs | 15 +- .../lucet-runtime-tests/src/timeout.rs | 28 +-- lucet-runtime/src/c_api.rs | 164 +++++++------ lucet-runtime/src/lib.rs | 75 +++--- lucet-spectest/src/bindings.rs | 31 ++- lucet-wasi/src/wasi.rs | 216 ++++++++++-------- 18 files changed, 609 insertions(+), 472 deletions(-) create mode 100644 lucet-runtime/lucet-runtime-macros/Cargo.toml create mode 100644 lucet-runtime/lucet-runtime-macros/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index a44f0724f..939bbae4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -844,6 +844,7 @@ dependencies = [ "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.4.1", + "lucet-runtime-macros 0.4.1", "memoffset 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -852,6 +853,14 @@ dependencies = [ "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lucet-runtime-macros" +version = "0.4.1" +dependencies = [ + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "lucet-runtime-tests" version = "0.4.1" diff --git a/Cargo.toml b/Cargo.toml index 9ae83d2c7..4d6dea704 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "lucet-objdump", "lucet-runtime", "lucet-runtime/lucet-runtime-internals", + "lucet-runtime/lucet-runtime-macros", "lucet-runtime/lucet-runtime-tests", "lucet-spectest", "lucet-validate", diff --git a/benchmarks/lucet-benchmarks/src/modules.rs b/benchmarks/lucet-benchmarks/src/modules.rs index c57d4edb2..1c789e96c 100644 --- a/benchmarks/lucet-benchmarks/src/modules.rs +++ b/benchmarks/lucet-benchmarks/src/modules.rs @@ -1,5 +1,5 @@ use lucet_module::lucet_signature; -use lucet_runtime::lucet_hostcalls; +use lucet_runtime::lucet_hostcall; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime_internals::module::{ FunctionPointer, HeapSpec, MockExportBuilder, MockModuleBuilder, Module, @@ -215,33 +215,32 @@ pub fn many_args_mock() -> Arc { } pub fn hostcalls_mock() -> Arc { - lucet_hostcalls! { - #[inline(never)] - #[no_mangle] - pub unsafe extern "C" fn hostcall_wrapped( - &mut vmctx, - x1: u64, - x2: u64, - x3: u64, - x4: u64, - x5: u64, - x6: u64, - x7: u64, - x8: u64, - x9: u64, - x10: u64, - x11: u64, - x12: u64, - x13: u64, - x14: u64, - x15: u64, - x16: u64, - ) -> () { - vmctx.heap_mut()[0] = - (x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16) - as u8; - assert_eq!(vmctx.heap()[0], 136); - } + #[lucet_hostcall] + #[inline(never)] + #[no_mangle] + pub unsafe extern "C" fn hostcall_wrapped( + vmctx: &mut Vmctx, + x1: u64, + x2: u64, + x3: u64, + x4: u64, + x5: u64, + x6: u64, + x7: u64, + x8: u64, + x9: u64, + x10: u64, + x11: u64, + x12: u64, + x13: u64, + x14: u64, + x15: u64, + x16: u64, + ) -> () { + vmctx.heap_mut()[0] = + (x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16) + as u8; + assert_eq!(vmctx.heap()[0], 136); } #[inline(never)] diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index 14db48848..6501a2879 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -11,6 +11,7 @@ edition = "2018" [dependencies] lucet-module = { path = "../../lucet-module", version = "0.4.1" } +lucet-runtime-macros = { path = "../lucet-runtime-macros", version = "0.4.1" } bitflags = "1.0" bincode = "1.1.4" diff --git a/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs b/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs index 64690fbb3..2a1bebde2 100644 --- a/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs +++ b/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs @@ -1,5 +1,7 @@ /// The macro that surrounds definitions of Lucet hostcalls in Rust. /// +/// **Note:** this macro has been deprecated and replaced by the `#[lucet_hostcall]` attribute. +/// /// It is important to use this macro for hostcalls, rather than exporting them directly, as it /// installs unwind protection that prevents panics from unwinding into the guest stack. /// @@ -20,6 +22,7 @@ /// } /// ``` #[macro_export] +#[deprecated(since = "0.4.2", note = "Use the #[lucet_hostcall] attribute instead")] macro_rules! lucet_hostcalls { { $( diff --git a/lucet-runtime/lucet-runtime-internals/src/lib.rs b/lucet-runtime/lucet-runtime-internals/src/lib.rs index fb7103d4e..168f91cb1 100644 --- a/lucet-runtime/lucet-runtime-internals/src/lib.rs +++ b/lucet-runtime/lucet-runtime-internals/src/lib.rs @@ -8,6 +8,7 @@ pub mod error; #[macro_use] pub mod hostcall_macros; +pub use lucet_runtime_macros::lucet_hostcall; #[macro_use] #[cfg(test)] diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index 3949ad3a9..2d38c3e2b 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -114,8 +114,9 @@ impl VmctxInternal for Vmctx { impl Vmctx { /// Create a `Vmctx` from the compiler-inserted `vmctx` argument in a guest function. /// - /// This is almost certainly not what you want to use to get a `Vmctx`; instead use the `&mut - /// Vmctx` argument to a `lucet_hostcalls!`-wrapped function. + /// This is almost certainly not what you want to use to get a `Vmctx`; instead use the first + /// argument of a function with the `#[lucet_hostcall]` attribute, which must have the type + /// `&mut Vmctx`. pub unsafe fn from_raw(vmctx: *mut lucet_vmctx) -> Vmctx { let inst = instance_from_vmctx(vmctx); assert!(inst.valid_magic()); @@ -277,29 +278,30 @@ impl Vmctx { /// from its own context. /// /// ```no_run - /// use lucet_runtime_internals::{lucet_hostcalls, lucet_hostcall_terminate}; + /// use lucet_runtime_macros::lucet_hostcall; + /// use lucet_runtime_internals::lucet_hostcall_terminate; /// use lucet_runtime_internals::vmctx::{lucet_vmctx, Vmctx}; /// - /// lucet_hostcalls! { - /// #[no_mangle] - /// pub unsafe extern "C" fn hostcall_call_binop( - /// &mut vmctx, - /// binop_table_idx: u32, - /// binop_func_idx: u32, - /// operand1: u32, - /// operand2: u32, - /// ) -> u32 { - /// if let Ok(binop) = vmctx.get_func_from_idx(binop_table_idx, binop_func_idx) { - /// let typed_binop = std::mem::transmute::< - /// usize, - /// extern "C" fn(*mut lucet_vmctx, u32, u32) -> u32 - /// >(binop.ptr.as_usize()); - /// unsafe { (typed_binop)(vmctx.as_raw(), operand1, operand2) } - /// } else { - /// lucet_hostcall_terminate!("invalid function index") - /// } + /// #[lucet_hostcall] + /// #[no_mangle] + /// pub unsafe extern "C" fn hostcall_call_binop( + /// vmctx: &mut Vmctx, + /// binop_table_idx: u32, + /// binop_func_idx: u32, + /// operand1: u32, + /// operand2: u32, + /// ) -> u32 { + /// if let Ok(binop) = vmctx.get_func_from_idx(binop_table_idx, binop_func_idx) { + /// let typed_binop = std::mem::transmute::< + /// usize, + /// extern "C" fn(*mut lucet_vmctx, u32, u32) -> u32, + /// >(binop.ptr.as_usize()); + /// unsafe { (typed_binop)(vmctx.as_raw(), operand1, operand2) } + /// } else { + /// lucet_hostcall_terminate!("invalid function index") /// } /// } + /// ``` pub fn get_func_from_idx( &self, table_idx: u32, diff --git a/lucet-runtime/lucet-runtime-macros/Cargo.toml b/lucet-runtime/lucet-runtime-macros/Cargo.toml new file mode 100644 index 000000000..7980fc789 --- /dev/null +++ b/lucet-runtime/lucet-runtime-macros/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "lucet-runtime-macros" +version = "0.4.1" +description = "Macros for the Lucet WebAssembly runtime" +homepage = "https://github.com/bytecodealliance/lucet" +repository = "https://github.com/bytecodealliance/lucet" +license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +authors = ["Lucet team "] +edition = "2018" + +[lib] +proc-macro = true + +[dependencies] +syn = { version = "1.0", features = ["full"] } +quote = "1.0" diff --git a/lucet-runtime/lucet-runtime-macros/src/lib.rs b/lucet-runtime/lucet-runtime-macros/src/lib.rs new file mode 100644 index 000000000..e8551dcb1 --- /dev/null +++ b/lucet-runtime/lucet-runtime-macros/src/lib.rs @@ -0,0 +1,122 @@ +extern crate proc_macro; +use proc_macro::TokenStream; +use quote::quote; +use syn::spanned::Spanned; + +/// This attribute generates a Lucet hostcall from a standalone Rust function that takes a `&mut +/// Vmctx` as its first argument. +/// +/// It is important to use this attribute for hostcalls, rather than exporting them +/// directly. Otherwise the behavior of instance termination and timeouts are +/// undefined. Additionally, the attribute makes the resulting function `unsafe extern "C"` +/// regardless of how the function is defined, as this ABI is required for all hostcalls. +/// +/// In most cases, you will want to also provide the `#[no_mangle]` attribute and `pub` visibility +/// in order for the hostcall to be exported from the final executable. +/// +/// ```ignore +/// #[lucet_hostcall] +/// #[no_mangle] +/// pub fn yield_5(vmctx: &mut Vmctx) { +/// vmctx.yield_val(5); +/// } +/// ``` +/// +/// Note that `lucet-runtime` must be a dependency of any crate where this attribute is used, and it +/// may not be renamed (this restriction may be lifted once [this +/// issue](https://github.com/rust-lang/rust/issues/54363) is resolved). +#[proc_macro_attribute] +pub fn lucet_hostcall(_attr: TokenStream, item: TokenStream) -> TokenStream { + // determine whether we need to import from `lucet_runtime_internals`; this is useful if we want + // to define a hostcall for a target (or tests, more concretely) that doesn't depend on + // `lucet-runtime` + let in_internals = std::env::var("CARGO_PKG_NAME").unwrap() == "lucet-runtime-internals"; + + let mut hostcall = syn::parse_macro_input!(item as syn::ItemFn); + let hostcall_ident = hostcall.sig.ident.clone(); + + // use the same attributes and visibility as the impl hostcall + let attrs = hostcall.attrs.clone(); + let vis = hostcall.vis.clone(); + + // remove #[no_mangle] from the attributes of the impl hostcall if it's there + hostcall.attrs = attrs + .iter() + .filter(|attr| !attr.path.is_ident("no_mangle")) + .cloned() + .collect(); + // make the impl hostcall private + hostcall.vis = syn::Visibility::Inherited; + + // modify the type signature of the exported raw hostcall based on the original signature + let mut raw_sig = hostcall.sig.clone(); + + // hostcalls are always unsafe + raw_sig.unsafety = Some(syn::Token![unsafe](raw_sig.span())); + + // hostcalls are always extern "C" + raw_sig.abi = Some(syn::parse_quote!(extern "C")); + + let vmctx_mod = if in_internals { + quote! { lucet_runtime_internals::vmctx } + } else { + quote! { lucet_runtime::vmctx } + }; + + // replace the first argument to the raw hostcall with the vmctx pointer + if let Some(arg0) = raw_sig.inputs.iter_mut().nth(0) { + let lucet_vmctx: syn::FnArg = syn::parse_quote!(vmctx_raw: *mut #vmctx_mod::lucet_vmctx); + *arg0 = lucet_vmctx; + } + + // the args after the first to provide to the hostcall impl + let impl_args = hostcall + .sig + .inputs + .iter() + .skip(1) + .map(|arg| match arg { + syn::FnArg::Receiver(_) => { + // this case is an error, but humor the token stream so it will produce a nicer + // error later + let s = syn::Token![self](arg.span()); + quote!(#s) + } + syn::FnArg::Typed(syn::PatType { pat, .. }) => quote!(#pat), + }) + .collect::>(); + + let termination_details = if in_internals { + quote! { lucet_runtime_internals::instance::TerminationDetails } + } else { + quote! { lucet_runtime::TerminationDetails } + }; + + let raw_hostcall = quote! { + #(#attrs)* + #vis + #raw_sig { + #[inline(always)] + #hostcall + + let mut vmctx = #vmctx_mod::Vmctx::from_raw(vmctx_raw); + #vmctx_mod::VmctxInternal::instance_mut(&mut vmctx).uninterruptable(|| { + let res = std::panic::catch_unwind(move || { + #hostcall_ident(&mut #vmctx_mod::Vmctx::from_raw(vmctx_raw), #(#impl_args),*) + }); + match res { + Ok(res) => res, + Err(e) => { + match e.downcast::<#termination_details>() { + Ok(details) => { + #vmctx_mod::Vmctx::from_raw(vmctx_raw).terminate_no_unwind(*details) + }, + Err(e) => std::panic::resume_unwind(e), + } + } + } + }) + } + }; + raw_hostcall.into() +} diff --git a/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs b/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs index db1bb3048..6334500d7 100644 --- a/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs +++ b/lucet-runtime/lucet-runtime-tests/src/entrypoint.rs @@ -194,19 +194,15 @@ macro_rules! entrypoint_tests { use libc::c_void; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime::{ - lucet_hostcalls, DlModule, Error, Limits, Module, Region, Val, WASM_PAGE_SIZE, + lucet_hostcall, DlModule, Error, Limits, Module, Region, Val, WASM_PAGE_SIZE, }; use std::sync::Arc; use $TestRegion as TestRegion; use $crate::entrypoint::{mock_calculator_module, wat_calculator_module}; - lucet_hostcalls! { - #[no_mangle] - pub unsafe extern "C" fn black_box( - &mut _vmctx, - _val: *mut c_void, - ) -> () {} - } + #[lucet_hostcall] + #[no_mangle] + pub fn black_box(_vmctx: &mut Vmctx, _val: *mut c_void) {} #[test] fn mock_calc_add_2() { @@ -886,35 +882,28 @@ macro_rules! entrypoint_tests { .expect("instance runs"); } - lucet_hostcalls! { - #[no_mangle] - pub unsafe extern "C" fn callback_hostcall( - &mut vmctx, - cb_idx: u32, - x: u64, - ) -> u64 { - let func = vmctx - .get_func_from_idx(0, cb_idx) - .expect("can get function by index"); - let func = std::mem::transmute::< - usize, - extern "C" fn(*mut lucet_vmctx, u64) -> u64 - >(func.ptr.as_usize()); - (func)(vmctx.as_raw(), x) + 1 - } - } - - lucet_hostcalls! { - #[no_mangle] - pub unsafe extern "C" fn add_4_hostcall( - &mut vmctx, - x: u64, - y: u64, - z: u64, - w: u64, - ) -> u64 { - x + y + z + w - } + #[lucet_hostcall] + #[no_mangle] + pub unsafe extern "C" fn callback_hostcall(vmctx: &mut Vmctx, cb_idx: u32, x: u64) -> u64 { + let func = vmctx + .get_func_from_idx(0, cb_idx) + .expect("can get function by index"); + let func = std::mem::transmute:: u64>( + func.ptr.as_usize(), + ); + (func)(vmctx.as_raw(), x) + 1 + } + + #[lucet_hostcall] + #[no_mangle] + pub unsafe extern "C" fn add_4_hostcall( + vmctx: &mut Vmctx, + x: u64, + y: u64, + z: u64, + w: u64, + ) -> u64 { + x + y + z + w } #[test] diff --git a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs index 3615f04eb..6d443fdb9 100644 --- a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs +++ b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs @@ -127,7 +127,7 @@ macro_rules! guest_fault_tests { use libc::{c_void, pthread_kill, pthread_self, siginfo_t, SIGALRM, SIGSEGV}; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime::{ - lucet_hostcall_terminate, lucet_hostcalls, DlModule, Error, FaultDetails, Instance, + lucet_hostcall, lucet_hostcall_terminate, DlModule, Error, FaultDetails, Instance, Limits, Region, SignalBehavior, TerminationDetails, TrapCode, }; use nix::sys::mman::{mmap, MapFlags, ProtFlags}; @@ -185,13 +185,10 @@ macro_rules! guest_fault_tests { static HOSTCALL_TEST_ERROR: &'static str = "hostcall_test threw an error!"; - lucet_hostcalls! { - #[no_mangle] - pub unsafe extern "C" fn hostcall_test( - &mut _vmctx, - ) -> () { - lucet_hostcall_terminate!(HOSTCALL_TEST_ERROR); - } + #[lucet_hostcall] + #[no_mangle] + pub fn hostcall_test(_vmctx: &mut Vmctx) { + lucet_hostcall_terminate!(HOSTCALL_TEST_ERROR); } fn run_onetwothree(inst: &mut Instance) { @@ -472,12 +469,9 @@ macro_rules! guest_fault_tests { *HOST_SIGSEGV_TRIGGERED.lock().unwrap() = true; } - lucet_hostcalls! { - pub unsafe extern "C" fn sleepy_guest( - &mut _vmctx, - ) -> () { - std::thread::sleep(std::time::Duration::from_millis(20)); - } + #[lucet_hostcall] + pub fn sleepy_guest(_vmctx: &mut Vmctx) { + std::thread::sleep(std::time::Duration::from_millis(20)); } test_ex(|| { diff --git a/lucet-runtime/lucet-runtime-tests/src/host.rs b/lucet-runtime/lucet-runtime-tests/src/host.rs index dd8ad21b8..bcc03baa2 100644 --- a/lucet-runtime/lucet-runtime-tests/src/host.rs +++ b/lucet-runtime/lucet-runtime-tests/src/host.rs @@ -5,7 +5,7 @@ macro_rules! host_tests { use libc::c_void; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime::{ - lucet_hostcall_terminate, lucet_hostcalls, DlModule, Error, Limits, Region, + lucet_hostcall, lucet_hostcall_terminate, DlModule, Error, Limits, Region, TerminationDetails, TrapCode, }; use std::sync::{Arc, Mutex}; @@ -29,115 +29,97 @@ macro_rules! host_tests { static ref HOSTCALL_MUTEX: Mutex<()> = Mutex::new(()); } - lucet_hostcalls! { - #[no_mangle] - pub unsafe extern "C" fn hostcall_test_func_hello( - &mut vmctx, - hello_ptr: u32, - hello_len: u32, - ) -> () { - let heap = vmctx.heap(); - let hello = heap.as_ptr() as usize + hello_ptr as usize; - if !vmctx.check_heap(hello as *const c_void, hello_len as usize) { - lucet_hostcall_terminate!("heap access"); - } - let hello = std::slice::from_raw_parts(hello as *const u8, hello_len as usize); - if hello.starts_with(b"hello") { - *vmctx.get_embed_ctx_mut::() = true; - } + #[lucet_hostcall] + #[no_mangle] + pub fn hostcall_test_func_hostcall_error(_vmctx: &mut Vmctx) { + lucet_hostcall_terminate!(ERROR_MESSAGE); + } + + #[lucet_hostcall] + #[no_mangle] + pub fn hostcall_test_func_hello(vmctx: &mut Vmctx, hello_ptr: u32, hello_len: u32) { + let heap = vmctx.heap(); + let hello = heap.as_ptr() as usize + hello_ptr as usize; + if !vmctx.check_heap(hello as *const c_void, hello_len as usize) { + lucet_hostcall_terminate!("heap access"); } + let hello = + unsafe { std::slice::from_raw_parts(hello as *const u8, hello_len as usize) }; + if hello.starts_with(b"hello") { + *vmctx.get_embed_ctx_mut::() = true; + } + } - #[no_mangle] - pub unsafe extern "C" fn hostcall_test_func_hostcall_error( - &mut _vmctx, - ) -> () { + #[lucet_hostcall] + #[allow(unreachable_code)] + #[no_mangle] + pub fn hostcall_test_func_hostcall_error_unwind(vmctx: &mut Vmctx) { + let lock = HOSTCALL_MUTEX.lock().unwrap(); + unsafe { lucet_hostcall_terminate!(ERROR_MESSAGE); } + drop(lock); + } - #[allow(unreachable_code)] - #[no_mangle] - pub unsafe extern "C" fn hostcall_test_func_hostcall_error_unwind( - &mut vmctx, - ) -> () { - let lock = HOSTCALL_MUTEX.lock().unwrap(); - unsafe { - lucet_hostcall_terminate!(ERROR_MESSAGE); - } - drop(lock); - } + #[lucet_hostcall] + #[no_mangle] + pub fn hostcall_bad_borrow(vmctx: &mut Vmctx) -> bool { + let heap = vmctx.heap(); + let mut other_heap = vmctx.heap_mut(); + heap[0] == other_heap[0] + } - #[no_mangle] - pub unsafe extern "C" fn hostcall_bad_borrow( - &mut vmctx, - ) -> bool { - let heap = vmctx.heap(); - let mut other_heap = vmctx.heap_mut(); - heap[0] == other_heap[0] + #[lucet_hostcall] + #[no_mangle] + pub fn hostcall_missing_embed_ctx(vmctx: &mut Vmctx) -> bool { + struct S { + x: bool, } + let ctx = vmctx.get_embed_ctx::(); + ctx.x + } - #[no_mangle] - pub unsafe extern "C" fn hostcall_missing_embed_ctx( - &mut vmctx, - ) -> bool { - struct S { - x: bool - } - let ctx = vmctx.get_embed_ctx::(); - ctx.x - } - - #[no_mangle] - pub unsafe extern "C" fn hostcall_multiple_vmctx( - &mut vmctx, - ) -> bool { - let mut vmctx1 = Vmctx::from_raw(vmctx.as_raw()); - vmctx1.heap_mut()[0] = 0xAF; - drop(vmctx1); - - let mut vmctx2 = Vmctx::from_raw(vmctx.as_raw()); - let res = vmctx2.heap()[0] == 0xAF; - drop(vmctx2); - - res - } - - #[no_mangle] - pub unsafe extern "C" fn hostcall_yields( - &mut vmctx, - ) -> () { - vmctx.yield_(); - } - - #[no_mangle] - pub unsafe extern "C" fn hostcall_yield_expects_5( - &mut vmctx, - ) -> u64 { - vmctx.yield_expecting_val() - } - - #[no_mangle] - pub unsafe extern "C" fn hostcall_yields_5( - &mut vmctx, - ) -> () { - vmctx.yield_val(5u64); - } - - #[no_mangle] - pub unsafe extern "C" fn hostcall_yield_facts( - &mut vmctx, - n: u64, - ) -> u64 { - fn fact(vmctx: &mut Vmctx, n: u64) -> u64 { - let result = if n <= 1 { - 1 - } else { - n * fact(vmctx, n - 1) - }; - vmctx.yield_val(result); - result - } - fact(vmctx, n) + #[lucet_hostcall] + #[no_mangle] + pub fn hostcall_multiple_vmctx(vmctx: &mut Vmctx) -> bool { + let mut vmctx1 = unsafe { Vmctx::from_raw(vmctx.as_raw()) }; + vmctx1.heap_mut()[0] = 0xAF; + drop(vmctx1); + + let mut vmctx2 = unsafe { Vmctx::from_raw(vmctx.as_raw()) }; + let res = vmctx2.heap()[0] == 0xAF; + drop(vmctx2); + + res + } + + #[lucet_hostcall] + #[no_mangle] + pub fn hostcall_yields(vmctx: &mut Vmctx) { + vmctx.yield_(); + } + + #[lucet_hostcall] + #[no_mangle] + pub fn hostcall_yield_expects_5(vmctx: &mut Vmctx) -> u64 { + vmctx.yield_expecting_val() + } + + #[lucet_hostcall] + #[no_mangle] + pub fn hostcall_yields_5(vmctx: &mut Vmctx) { + vmctx.yield_val(5u64); + } + + #[lucet_hostcall] + #[no_mangle] + pub fn hostcall_yield_facts(vmctx: &mut Vmctx, n: u64) -> u64 { + fn fact(vmctx: &mut Vmctx, n: u64) -> u64 { + let result = if n <= 1 { 1 } else { n * fact(vmctx, n - 1) }; + vmctx.yield_val(result); + result } + fact(vmctx, n) } pub enum CoopFactsK { @@ -145,24 +127,20 @@ macro_rules! host_tests { Result(u64), } - lucet_hostcalls! { - #[no_mangle] - pub unsafe extern "C" fn hostcall_coop_facts( - &mut vmctx, - n: u64, - ) -> u64 { - fn fact(vmctx: &mut Vmctx, n: u64) -> u64 { - let result = if n <= 1 { - 1 - } else { - let n_rec = fact(vmctx, n - 1); - vmctx.yield_val_expecting_val(CoopFactsK::Mult(n, n_rec)) - }; - vmctx.yield_val(CoopFactsK::Result(result)); - result - } - fact(vmctx, n) + #[lucet_hostcall] + #[no_mangle] + pub fn hostcall_coop_facts(vmctx: &mut Vmctx, n: u64) -> u64 { + fn fact(vmctx: &mut Vmctx, n: u64) -> u64 { + let result = if n <= 1 { + 1 + } else { + let n_rec = fact(vmctx, n - 1); + vmctx.yield_val_expecting_val(CoopFactsK::Mult(n, n_rec)) + }; + vmctx.yield_val(CoopFactsK::Result(result)); + result } + fact(vmctx, n) } #[test] diff --git a/lucet-runtime/lucet-runtime-tests/src/strcmp.rs b/lucet-runtime/lucet-runtime-tests/src/strcmp.rs index 9dc4032cb..d4d27a713 100644 --- a/lucet-runtime/lucet-runtime-tests/src/strcmp.rs +++ b/lucet-runtime/lucet-runtime-tests/src/strcmp.rs @@ -2,19 +2,18 @@ macro_rules! strcmp_tests { ( $TestRegion:path ) => { use libc::{c_char, c_int, c_void, strcmp}; - use lucet_runtime::vmctx::lucet_vmctx; - use lucet_runtime::{lucet_hostcalls, Error, Limits, Region, Val, WASM_PAGE_SIZE}; + use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; + use lucet_runtime::{lucet_hostcall, Error, Limits, Region, Val, WASM_PAGE_SIZE}; use std::ffi::CString; use std::sync::Arc; use $TestRegion as TestRegion; use $crate::build::test_module_c; - lucet_hostcalls! { - #[no_mangle] - pub unsafe extern "C" fn hostcall_host_fault( - &mut _vmctx, - ) -> () { - let oob = (-1isize) as *mut c_char; + #[lucet_hostcall] + #[no_mangle] + pub fn hostcall_host_fault(_vmctx: &mut Vmctx) { + let oob = (-1isize) as *mut c_char; + unsafe { *oob = 'x' as c_char; } } diff --git a/lucet-runtime/lucet-runtime-tests/src/timeout.rs b/lucet-runtime/lucet-runtime-tests/src/timeout.rs index 88fa04cce..8fb3e67b7 100644 --- a/lucet-runtime/lucet-runtime-tests/src/timeout.rs +++ b/lucet-runtime/lucet-runtime-tests/src/timeout.rs @@ -58,7 +58,7 @@ macro_rules! timeout_tests { ( $TestRegion:path ) => { use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime::{ - lucet_hostcall_terminate, lucet_hostcalls, DlModule, Error, FaultDetails, Instance, + lucet_hostcall, lucet_hostcall_terminate, DlModule, Error, FaultDetails, Instance, KillError, KillSuccess, Limits, Region, RunResult, SignalBehavior, TerminationDetails, TrapCode, YieldedVal, }; @@ -75,22 +75,18 @@ macro_rules! timeout_tests { use $crate::helpers::{FunctionPointer, MockExportBuilder, MockModuleBuilder}; use $crate::timeout::mock_timeout_module; - lucet_hostcalls! { - #[no_mangle] - pub unsafe extern "C" fn slow_hostcall( - &mut vmctx, - ) -> bool { - // make a window of time so we can timeout in a hostcall - thread::sleep(Duration::from_millis(200)); - true - } + #[lucet_hostcall] + #[no_mangle] + pub fn slow_hostcall(vmctx: &mut Vmctx) -> bool { + // make a window of time so we can timeout in a hostcall + thread::sleep(Duration::from_millis(200)); + true + } - #[no_mangle] - pub unsafe extern "C" fn yielding_hostcall( - &mut vmctx, - ) -> () { - vmctx.yield_(); - } + #[lucet_hostcall] + #[no_mangle] + pub fn yielding_hostcall(vmctx: &mut Vmctx) { + vmctx.yield_(); } fn run_onetwothree(inst: &mut Instance) { diff --git a/lucet-runtime/src/c_api.rs b/lucet-runtime/src/c_api.rs index c1886c223..4d69ab9c3 100644 --- a/lucet-runtime/src/c_api.rs +++ b/lucet-runtime/src/c_api.rs @@ -5,9 +5,10 @@ use lucet_runtime_internals::c_api::*; use lucet_runtime_internals::instance::{ instance_handle_from_raw, instance_handle_to_raw, InstanceInternal, }; +use lucet_runtime_internals::vmctx::{Vmctx, VmctxInternal}; use lucet_runtime_internals::WASM_PAGE_SIZE; use lucet_runtime_internals::{ - assert_nonnull, lucet_hostcall_terminate, lucet_hostcalls, with_ffi_arcs, + assert_nonnull, lucet_hostcall, lucet_hostcall_terminate, with_ffi_arcs, }; use num_traits::FromPrimitive; use std::ffi::CStr; @@ -371,98 +372,93 @@ pub fn ensure_linked() { }); } -lucet_hostcalls! { - #[no_mangle] - pub unsafe extern "C" fn lucet_vmctx_get_heap( - &mut vmctx, - ) -> *mut u8 { - vmctx.instance().alloc().slot().heap as *mut u8 - } +#[lucet_hostcall] +#[no_mangle] +pub unsafe extern "C" fn lucet_vmctx_get_heap(vmctx: &mut Vmctx) -> *mut u8 { + vmctx.instance().alloc().slot().heap as *mut u8 +} - #[no_mangle] - pub unsafe extern "C" fn lucet_vmctx_get_globals( - &mut vmctx, - ) -> *mut i64 { - vmctx.instance().alloc().slot().globals as *mut i64 - } +#[lucet_hostcall] +#[no_mangle] +pub unsafe extern "C" fn lucet_vmctx_get_globals(vmctx: &mut Vmctx) -> *mut i64 { + vmctx.instance().alloc().slot().globals as *mut i64 +} - #[no_mangle] - /// Get the number of WebAssembly pages currently in the heap. - pub unsafe extern "C" fn lucet_vmctx_current_memory( - &mut vmctx, - ) -> u32 { - vmctx.instance().alloc().heap_len() as u32 / WASM_PAGE_SIZE - } +#[lucet_hostcall] +#[no_mangle] +/// Get the number of WebAssembly pages currently in the heap. +pub unsafe extern "C" fn lucet_vmctx_current_memory(vmctx: &mut Vmctx) -> u32 { + vmctx.instance().alloc().heap_len() as u32 / WASM_PAGE_SIZE +} - #[no_mangle] - /// Grows the guest heap by the given number of WebAssembly pages. - /// - /// On success, returns the number of pages that existed before the call. On failure, returns `-1`. - pub unsafe extern "C" fn lucet_vmctx_grow_memory( - &mut vmctx, - additional_pages: u32, - ) -> i32 { - if let Ok(old_pages) = vmctx.instance_mut().grow_memory(additional_pages) { - old_pages as i32 - } else { - -1 - } +#[lucet_hostcall] +#[no_mangle] +/// Grows the guest heap by the given number of WebAssembly pages. +/// +/// On success, returns the number of pages that existed before the call. On failure, returns `-1`. +pub unsafe extern "C" fn lucet_vmctx_grow_memory(vmctx: &mut Vmctx, additional_pages: u32) -> i32 { + if let Ok(old_pages) = vmctx.instance_mut().grow_memory(additional_pages) { + old_pages as i32 + } else { + -1 } +} - #[no_mangle] - /// Check if a memory region is inside the instance heap. - pub unsafe extern "C" fn lucet_vmctx_check_heap( - &mut vmctx, - ptr: *mut c_void, - len: libc::size_t, - ) -> bool { - vmctx.instance().check_heap(ptr, len) - } +#[lucet_hostcall] +#[no_mangle] +/// Check if a memory region is inside the instance heap. +pub unsafe extern "C" fn lucet_vmctx_check_heap( + vmctx: &mut Vmctx, + ptr: *mut c_void, + len: libc::size_t, +) -> bool { + vmctx.instance().check_heap(ptr, len) +} - #[no_mangle] - pub unsafe extern "C" fn lucet_vmctx_get_func_from_idx( - &mut vmctx, - table_idx: u32, - func_idx: u32, - ) -> *const c_void { - vmctx.instance() - .module() - .get_func_from_idx(table_idx, func_idx) - .map(|fptr| fptr.ptr.as_usize() as *const c_void) - .unwrap_or(std::ptr::null()) - } +#[lucet_hostcall] +#[no_mangle] +pub unsafe extern "C" fn lucet_vmctx_get_func_from_idx( + vmctx: &mut Vmctx, + table_idx: u32, + func_idx: u32, +) -> *const c_void { + vmctx + .instance() + .module() + .get_func_from_idx(table_idx, func_idx) + .map(|fptr| fptr.ptr.as_usize() as *const c_void) + .unwrap_or(std::ptr::null()) +} - #[no_mangle] - pub unsafe extern "C" fn lucet_vmctx_terminate( - &mut _vmctx, - details: *mut c_void, - ) -> () { - lucet_hostcall_terminate!(CTerminationDetails { details }); - } +#[lucet_hostcall] +#[no_mangle] +pub unsafe extern "C" fn lucet_vmctx_terminate(_vmctx: &mut Vmctx, details: *mut c_void) -> () { + lucet_hostcall_terminate!(CTerminationDetails { details }); +} - #[no_mangle] - /// Get the delegate object for the current instance. - /// - /// TODO: rename - pub unsafe extern "C" fn lucet_vmctx_get_delegate( - &mut vmctx, - ) -> *mut c_void { - vmctx.instance() - .get_embed_ctx::<*mut c_void>() - .map(|r| r.map(|p| *p).unwrap_or(ptr::null_mut())) - .unwrap_or(std::ptr::null_mut()) - } +#[lucet_hostcall] +#[no_mangle] +/// Get the delegate object for the current instance. +/// +/// TODO: rename +/// +/// TODO: C implementations of hostcalls are highly questionable +pub unsafe extern "C" fn lucet_vmctx_get_delegate(vmctx: &mut Vmctx) -> *mut c_void { + vmctx + .instance() + .get_embed_ctx::<*mut c_void>() + .map(|r| r.map(|p| *p).unwrap_or(ptr::null_mut())) + .unwrap_or(std::ptr::null_mut()) +} - #[no_mangle] - pub unsafe extern "C" fn lucet_vmctx_yield( - &mut vmctx, - val: *mut c_void, - ) -> *mut c_void { - vmctx - .yield_val_try_val(CYieldedVal { val }) - .map(|CYieldedVal { val }| val) - .unwrap_or(std::ptr::null_mut()) - } +/// TODO: C implementations of hostcalls are highly questionable +#[lucet_hostcall] +#[no_mangle] +pub unsafe extern "C" fn lucet_vmctx_yield(vmctx: &mut Vmctx, val: *mut c_void) -> *mut c_void { + vmctx + .yield_val_try_val(CYieldedVal { val }) + .map(|CYieldedVal { val }| val) + .unwrap_or(std::ptr::null_mut()) } #[cfg(test)] diff --git a/lucet-runtime/src/lib.rs b/lucet-runtime/src/lib.rs index 49c740c01..41fe41f2e 100644 --- a/lucet-runtime/src/lib.rs +++ b/lucet-runtime/src/lib.rs @@ -73,26 +73,23 @@ //! demo](https://wasm.fastly-labs.com/), hostcalls are provided for manipulating HTTP requests, //! accessing a key/value store, etc. //! -//! Some simple hostcalls can be implemented by wrapping an externed C function with the -//! [`lucet_hostcalls!`](macro.lucet_hostcalls.html] macro. The function must take a special `&mut -//! vmctx` argument for the guest context, similar to `&mut self` on methods. Hostcalls that require -//! access to some underlying state, such as the key/value store in Terrarium, can access a custom -//! embedder context through `vmctx`. For example, to make a `u32` available to hostcalls: +//! Some simple hostcalls can be implemented by using the +//! [`#[lucet_hostcall]`](attr.lucet_hostcall.html] attribute on a function that takes `&mut Vmctx` +//! as its first argument. Hostcalls that require access to some embedder-specific state, such as +//! Terrarium's key-value store, can access a custom embedder context through `vmctx`. For example, +//! to make a `u32` available to hostcalls: //! //! ```no_run -//! use lucet_runtime::{DlModule, Limits, MmapRegion, Region, lucet_hostcalls}; +//! use lucet_runtime::{DlModule, Limits, MmapRegion, Region, lucet_hostcall}; //! use lucet_runtime::vmctx::{Vmctx, lucet_vmctx}; //! //! struct MyContext { x: u32 } //! -//! lucet_hostcalls! { -//! #[no_mangle] -//! pub unsafe extern "C" fn foo( -//! &mut vmctx, -//! ) -> () { -//! let mut hostcall_context = vmctx.get_embed_ctx_mut::(); -//! hostcall_context.x = 42; -//! } +//! #[lucet_hostcall] +//! #[no_mangle] +//! pub fn foo(vmctx: &mut Vmctx) { +//! let mut hostcall_context = vmctx.get_embed_ctx_mut::(); +//! hostcall_context.x = 42; //! } //! //! let module = DlModule::load("/my/lucet/module.so").unwrap(); @@ -198,7 +195,7 @@ //! and yield it when appropriate. //! //! ```no_run -//! use lucet_runtime::lucet_hostcalls; +//! use lucet_runtime::lucet_hostcall; //! use lucet_runtime::vmctx::Vmctx; //! //! pub enum FactorialsK { @@ -206,27 +203,23 @@ //! Result(u64), //! } //! -//! lucet_hostcalls! { -//! #[no_mangle] -//! pub unsafe extern "C" fn hostcall_factorials( -//! &mut vmctx, -//! n: u64, -//! ) -> u64 { -//! fn fact(vmctx: &mut Vmctx, n: u64) -> u64 { -//! let result = if n <= 1 { -//! 1 -//! } else { -//! let n_rec = fact(vmctx, n - 1); -//! // yield a request for the host to perform multiplication -//! vmctx.yield_val_expecting_val(FactorialsK::Mult(n, n_rec)) -//! // once resumed, that yield evaluates to the multiplication result -//! }; -//! // yield a result -//! vmctx.yield_val(FactorialsK::Result(result)); -//! result -//! } -//! fact(vmctx, n) +//! #[lucet_hostcall] +//! #[no_mangle] +//! pub fn hostcall_factorials(vmctx: &mut Vmctx, n: u64) -> u64 { +//! fn fact(vmctx: &mut Vmctx, n: u64) -> u64 { +//! let result = if n <= 1 { +//! 1 +//! } else { +//! let n_rec = fact(vmctx, n - 1); +//! // yield a request for the host to perform multiplication +//! vmctx.yield_val_expecting_val(FactorialsK::Mult(n, n_rec)) +//! // once resumed, that yield evaluates to the multiplication result +//! }; +//! // yield a result +//! vmctx.yield_val(FactorialsK::Result(result)); +//! result //! } +//! fact(vmctx, n) //! } //! ``` //! @@ -340,6 +333,10 @@ #![deny(bare_trait_objects)] +// This makes `lucet_runtime` in the expansion of `#[lucet_hostcall]` resolve to something +// meaningful when used in this crate. +extern crate self as lucet_runtime; + pub mod c_api; pub use lucet_module::{PublicKey, TrapCode}; @@ -349,11 +346,13 @@ pub use lucet_runtime_internals::instance::{ FaultDetails, Instance, InstanceHandle, KillError, KillSuccess, RunResult, SignalBehavior, TerminationDetails, YieldedVal, }; +#[allow(deprecated)] +pub use lucet_runtime_internals::lucet_hostcalls; pub use lucet_runtime_internals::module::{DlModule, Module}; pub use lucet_runtime_internals::region::mmap::MmapRegion; pub use lucet_runtime_internals::region::{InstanceBuilder, Region, RegionCreate}; pub use lucet_runtime_internals::val::{UntypedRetVal, Val}; -pub use lucet_runtime_internals::{lucet_hostcall_terminate, lucet_hostcalls, WASM_PAGE_SIZE}; +pub use lucet_runtime_internals::{lucet_hostcall, lucet_hostcall_terminate, WASM_PAGE_SIZE}; pub mod vmctx { //! Functions for manipulating instances from hostcalls. @@ -369,6 +368,10 @@ pub mod vmctx { //! associated with a running instance. This should never occur if run in guest code on the //! pointer argument inserted by the compiler. pub use lucet_runtime_internals::vmctx::{lucet_vmctx, Vmctx}; + + // must be exported for `lucet_hostcall`, but we don't want to advertise it + #[doc(hidden)] + pub use lucet_runtime_internals::vmctx::VmctxInternal; } /// Call this if you're having trouble with `lucet_*` symbols not being exported. diff --git a/lucet-spectest/src/bindings.rs b/lucet-spectest/src/bindings.rs index 3e3bd32c2..79f443563 100644 --- a/lucet-spectest/src/bindings.rs +++ b/lucet-spectest/src/bindings.rs @@ -1,27 +1,24 @@ use lucet_module::bindings::Bindings; +use lucet_runtime::lucet_hostcall; +use lucet_runtime::vmctx::Vmctx; use serde_json::json; -use lucet_runtime::lucet_hostcalls; - -lucet_hostcalls! { - #[no_mangle] - pub unsafe extern "C" fn print(&mut _vmctx,) -> () { - println!("hello, world!"); - } +#[lucet_hostcall] +#[no_mangle] +pub fn print(_vmctx: &mut Vmctx) { + println!("hello, world!"); } -lucet_hostcalls! { - #[no_mangle] - pub unsafe extern "C" fn print_i32(&mut _vmctx, x: i32,) -> () { - println!("{}", x); - } +#[lucet_hostcall] +#[no_mangle] +pub fn print_i32(_vmctx: &mut Vmctx, x: i32) { + println!("{}", x); } -lucet_hostcalls! { - #[no_mangle] - pub unsafe extern "C" fn print_f32(&mut _vmctx, x: i32,) -> () { - println!("{}", x); - } +#[lucet_hostcall] +#[no_mangle] +pub fn print_f32(_vmctx: &mut Vmctx, x: i32) { + println!("{}", x); } pub fn spec_test_bindings() -> Bindings { diff --git a/lucet-wasi/src/wasi.rs b/lucet-wasi/src/wasi.rs index 1469ab898..c0b9b7d8a 100644 --- a/lucet-wasi/src/wasi.rs +++ b/lucet-wasi/src/wasi.rs @@ -1,27 +1,23 @@ #![allow(clippy::too_many_arguments)] -pub use lucet_runtime::{self, vmctx::lucet_vmctx}; -pub use wasi_common::{wasi, wasi32, WasiCtx}; - -use lucet_runtime::lucet_hostcall_terminate; +use lucet_runtime::vmctx::Vmctx; +use lucet_runtime::{lucet_hostcall, lucet_hostcall_terminate}; use std::mem; use std::rc::Rc; use wasi_common::hostcalls::*; +use wasi_common::{wasi, wasi32, WasiCtx}; -lucet_runtime::lucet_hostcalls! { - +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_proc_exit( - &mut _lucet_vmctx, - rval: wasi::__wasi_exitcode_t, -) -> ! { +pub unsafe fn __wasi_proc_exit(_lucet_ctx: &mut Vmctx, rval: wasi::__wasi_exitcode_t) -> ! { export_wasi_funcs(); lucet_hostcall_terminate!(rval); } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_args_get( - &mut lucet_ctx, +pub unsafe fn __wasi_args_get( + lucet_ctx: &mut Vmctx, argv_ptr: wasi32::uintptr_t, argv_buf: wasi32::uintptr_t, ) -> wasi::__wasi_errno_t { @@ -30,9 +26,10 @@ pub unsafe extern "C" fn __wasi_args_get( args_get(wasi_ctx, heap, argv_ptr, argv_buf) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_args_sizes_get( - &mut lucet_ctx, +pub unsafe fn __wasi_args_sizes_get( + lucet_ctx: &mut Vmctx, argc_ptr: wasi32::uintptr_t, argv_buf_size_ptr: wasi32::uintptr_t, ) -> wasi::__wasi_errno_t { @@ -41,14 +38,16 @@ pub unsafe extern "C" fn __wasi_args_sizes_get( args_sizes_get(wasi_ctx, heap, argc_ptr, argv_buf_size_ptr) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_sched_yield(&mut _lucet_ctx,) -> wasi::__wasi_errno_t { +pub unsafe fn __wasi_sched_yield(_lucet_ctx: &mut Vmctx) -> wasi::__wasi_errno_t { sched_yield() } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_clock_res_get( - &mut lucet_ctx, +pub unsafe fn __wasi_clock_res_get( + lucet_ctx: &mut Vmctx, clock_id: wasi::__wasi_clockid_t, resolution_ptr: wasi32::uintptr_t, ) -> wasi::__wasi_errno_t { @@ -56,9 +55,10 @@ pub unsafe extern "C" fn __wasi_clock_res_get( clock_res_get(heap, clock_id, resolution_ptr) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_clock_time_get( - &mut lucet_ctx, +pub unsafe fn __wasi_clock_time_get( + lucet_ctx: &mut Vmctx, clock_id: wasi::__wasi_clockid_t, precision: wasi::__wasi_timestamp_t, time_ptr: wasi32::uintptr_t, @@ -67,9 +67,10 @@ pub unsafe extern "C" fn __wasi_clock_time_get( clock_time_get(heap, clock_id, precision, time_ptr) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_environ_get( - &mut lucet_ctx, +pub unsafe fn __wasi_environ_get( + lucet_ctx: &mut Vmctx, environ_ptr: wasi32::uintptr_t, environ_buf: wasi32::uintptr_t, ) -> wasi::__wasi_errno_t { @@ -78,9 +79,10 @@ pub unsafe extern "C" fn __wasi_environ_get( environ_get(wasi_ctx, heap, environ_ptr, environ_buf) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_environ_sizes_get( - &mut lucet_ctx, +pub unsafe fn __wasi_environ_sizes_get( + lucet_ctx: &mut Vmctx, environ_count_ptr: wasi32::uintptr_t, environ_size_ptr: wasi32::uintptr_t, ) -> wasi::__wasi_errno_t { @@ -89,18 +91,20 @@ pub unsafe extern "C" fn __wasi_environ_sizes_get( environ_sizes_get(wasi_ctx, heap, environ_count_ptr, environ_size_ptr) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_fd_close( - &mut lucet_ctx, +pub unsafe fn __wasi_fd_close( + lucet_ctx: &mut Vmctx, fd: wasi::__wasi_fd_t, ) -> wasi::__wasi_errno_t { let wasi_ctx = &mut lucet_ctx.get_embed_ctx_mut::(); fd_close(wasi_ctx, fd) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_fd_fdstat_get( - &mut lucet_ctx, +pub unsafe fn __wasi_fd_fdstat_get( + lucet_ctx: &mut Vmctx, fd: wasi::__wasi_fd_t, fdstat_ptr: wasi32::uintptr_t, ) -> wasi::__wasi_errno_t { @@ -109,9 +113,10 @@ pub unsafe extern "C" fn __wasi_fd_fdstat_get( fd_fdstat_get(wasi_ctx, heap, fd, fdstat_ptr) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_fd_fdstat_set_flags( - &mut lucet_ctx, +pub unsafe fn __wasi_fd_fdstat_set_flags( + lucet_ctx: &mut Vmctx, fd: wasi::__wasi_fd_t, fdflags: wasi::__wasi_fdflags_t, ) -> wasi::__wasi_errno_t { @@ -119,9 +124,10 @@ pub unsafe extern "C" fn __wasi_fd_fdstat_set_flags( fd_fdstat_set_flags(wasi_ctx, fd, fdflags) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_fd_tell( - &mut lucet_ctx, +pub unsafe fn __wasi_fd_tell( + lucet_ctx: &mut Vmctx, fd: wasi::__wasi_fd_t, offset: wasi32::uintptr_t, ) -> wasi::__wasi_errno_t { @@ -130,9 +136,10 @@ pub unsafe extern "C" fn __wasi_fd_tell( fd_tell(wasi_ctx, heap, fd, offset) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_fd_seek( - &mut lucet_ctx, +pub unsafe fn __wasi_fd_seek( + lucet_ctx: &mut Vmctx, fd: wasi::__wasi_fd_t, offset: wasi::__wasi_filedelta_t, whence: wasi::__wasi_whence_t, @@ -143,9 +150,10 @@ pub unsafe extern "C" fn __wasi_fd_seek( fd_seek(wasi_ctx, heap, fd, offset, whence, newoffset) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_fd_prestat_get( - &mut lucet_ctx, +pub unsafe fn __wasi_fd_prestat_get( + lucet_ctx: &mut Vmctx, fd: wasi::__wasi_fd_t, prestat_ptr: wasi32::uintptr_t, ) -> wasi::__wasi_errno_t { @@ -154,9 +162,10 @@ pub unsafe extern "C" fn __wasi_fd_prestat_get( fd_prestat_get(wasi_ctx, heap, fd, prestat_ptr) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_fd_prestat_dir_name( - &mut lucet_ctx, +pub unsafe fn __wasi_fd_prestat_dir_name( + lucet_ctx: &mut Vmctx, fd: wasi::__wasi_fd_t, path_ptr: wasi32::uintptr_t, path_len: wasi32::size_t, @@ -166,9 +175,10 @@ pub unsafe extern "C" fn __wasi_fd_prestat_dir_name( fd_prestat_dir_name(wasi_ctx, heap, fd, path_ptr, path_len) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_fd_read( - &mut lucet_ctx, +pub unsafe fn __wasi_fd_read( + lucet_ctx: &mut Vmctx, fd: wasi::__wasi_fd_t, iovs_ptr: wasi32::uintptr_t, iovs_len: wasi32::size_t, @@ -179,9 +189,10 @@ pub unsafe extern "C" fn __wasi_fd_read( fd_read(wasi_ctx, heap, fd, iovs_ptr, iovs_len, nread) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_fd_write( - &mut lucet_ctx, +pub unsafe fn __wasi_fd_write( + lucet_ctx: &mut Vmctx, fd: wasi::__wasi_fd_t, iovs_ptr: wasi32::uintptr_t, iovs_len: wasi32::size_t, @@ -192,9 +203,10 @@ pub unsafe extern "C" fn __wasi_fd_write( fd_write(wasi_ctx, heap, fd, iovs_ptr, iovs_len, nwritten) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_path_open( - &mut lucet_ctx, +pub unsafe fn __wasi_path_open( + lucet_ctx: &mut Vmctx, dirfd: wasi::__wasi_fd_t, dirflags: wasi::__wasi_lookupflags_t, path_ptr: wasi32::uintptr_t, @@ -222,9 +234,10 @@ pub unsafe extern "C" fn __wasi_path_open( ) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_random_get( - &mut lucet_ctx, +pub unsafe fn __wasi_random_get( + lucet_ctx: &mut Vmctx, buf_ptr: wasi32::uintptr_t, buf_len: wasi32::size_t, ) -> wasi::__wasi_errno_t { @@ -232,9 +245,10 @@ pub unsafe extern "C" fn __wasi_random_get( random_get(heap, buf_ptr, buf_len) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_poll_oneoff( - &mut lucet_ctx, +pub unsafe fn __wasi_poll_oneoff( + lucet_ctx: &mut Vmctx, input: wasi32::uintptr_t, output: wasi32::uintptr_t, nsubscriptions: wasi32::size_t, @@ -245,9 +259,10 @@ pub unsafe extern "C" fn __wasi_poll_oneoff( poll_oneoff(wasi_ctx, heap, input, output, nsubscriptions, nevents) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_fd_filestat_get( - &mut lucet_ctx, +pub unsafe fn __wasi_fd_filestat_get( + lucet_ctx: &mut Vmctx, fd: wasi::__wasi_fd_t, filestat_ptr: wasi32::uintptr_t, ) -> wasi::__wasi_errno_t { @@ -256,9 +271,10 @@ pub unsafe extern "C" fn __wasi_fd_filestat_get( fd_filestat_get(wasi_ctx, heap, fd, filestat_ptr) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_path_filestat_get( - &mut lucet_ctx, +pub unsafe fn __wasi_path_filestat_get( + lucet_ctx: &mut Vmctx, dirfd: wasi::__wasi_fd_t, dirflags: wasi::__wasi_lookupflags_t, path_ptr: wasi32::uintptr_t, @@ -278,9 +294,10 @@ pub unsafe extern "C" fn __wasi_path_filestat_get( ) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_path_create_directory( - &mut lucet_ctx, +pub unsafe fn __wasi_path_create_directory( + lucet_ctx: &mut Vmctx, dirfd: wasi::__wasi_fd_t, path_ptr: wasi32::uintptr_t, path_len: wasi32::size_t, @@ -290,9 +307,10 @@ pub unsafe extern "C" fn __wasi_path_create_directory( path_create_directory(wasi_ctx, heap, dirfd, path_ptr, path_len) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_path_unlink_file( - &mut lucet_ctx, +pub unsafe fn __wasi_path_unlink_file( + lucet_ctx: &mut Vmctx, dirfd: wasi::__wasi_fd_t, path_ptr: wasi32::uintptr_t, path_len: wasi32::size_t, @@ -302,9 +320,10 @@ pub unsafe extern "C" fn __wasi_path_unlink_file( path_unlink_file(wasi_ctx, heap, dirfd, path_ptr, path_len) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_fd_allocate( - &mut lucet_ctx, +pub unsafe fn __wasi_fd_allocate( + lucet_ctx: &mut Vmctx, fd: wasi::__wasi_fd_t, offset: wasi::__wasi_filesize_t, len: wasi::__wasi_filesize_t, @@ -313,9 +332,10 @@ pub unsafe extern "C" fn __wasi_fd_allocate( fd_allocate(wasi_ctx, fd, offset, len) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_fd_advise( - &mut lucet_ctx, +pub unsafe fn __wasi_fd_advise( + lucet_ctx: &mut Vmctx, fd: wasi::__wasi_fd_t, offset: wasi::__wasi_filesize_t, len: wasi::__wasi_filesize_t, @@ -325,27 +345,27 @@ pub unsafe extern "C" fn __wasi_fd_advise( fd_advise(wasi_ctx, fd, offset, len, advice) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_fd_datasync( - &mut lucet_ctx, +pub unsafe fn __wasi_fd_datasync( + lucet_ctx: &mut Vmctx, fd: wasi::__wasi_fd_t, ) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); fd_datasync(wasi_ctx, fd) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_fd_sync( - &mut lucet_ctx, - fd: wasi::__wasi_fd_t, -) -> wasi::__wasi_errno_t { +pub unsafe fn __wasi_fd_sync(lucet_ctx: &mut Vmctx, fd: wasi::__wasi_fd_t) -> wasi::__wasi_errno_t { let wasi_ctx = &lucet_ctx.get_embed_ctx::(); fd_sync(wasi_ctx, fd) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_fd_fdstat_set_rights( - &mut lucet_ctx, +pub unsafe fn __wasi_fd_fdstat_set_rights( + lucet_ctx: &mut Vmctx, fd: wasi::__wasi_fd_t, fs_rights_base: wasi::__wasi_rights_t, fs_rights_inheriting: wasi::__wasi_rights_t, @@ -354,9 +374,10 @@ pub unsafe extern "C" fn __wasi_fd_fdstat_set_rights( fd_fdstat_set_rights(wasi_ctx, fd, fs_rights_base, fs_rights_inheriting) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_fd_filestat_set_size( - &mut lucet_ctx, +pub unsafe fn __wasi_fd_filestat_set_size( + lucet_ctx: &mut Vmctx, fd: wasi::__wasi_fd_t, st_size: wasi::__wasi_filesize_t, ) -> wasi::__wasi_errno_t { @@ -364,9 +385,10 @@ pub unsafe extern "C" fn __wasi_fd_filestat_set_size( fd_filestat_set_size(wasi_ctx, fd, st_size) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_fd_filestat_set_times( - &mut lucet_ctx, +pub unsafe fn __wasi_fd_filestat_set_times( + lucet_ctx: &mut Vmctx, fd: wasi::__wasi_fd_t, st_atim: wasi::__wasi_timestamp_t, st_mtim: wasi::__wasi_timestamp_t, @@ -376,9 +398,10 @@ pub unsafe extern "C" fn __wasi_fd_filestat_set_times( fd_filestat_set_times(wasi_ctx, fd, st_atim, st_mtim, fst_flags) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_fd_pread( - &mut lucet_ctx, +pub unsafe fn __wasi_fd_pread( + lucet_ctx: &mut Vmctx, fd: wasi::__wasi_fd_t, iovs_ptr: wasi32::uintptr_t, iovs_len: wasi32::size_t, @@ -390,9 +413,10 @@ pub unsafe extern "C" fn __wasi_fd_pread( fd_pread(wasi_ctx, heap, fd, iovs_ptr, iovs_len, offset, nread) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_fd_pwrite( - &mut lucet_ctx, +pub unsafe fn __wasi_fd_pwrite( + lucet_ctx: &mut Vmctx, fd: wasi::__wasi_fd_t, iovs_ptr: wasi32::uintptr_t, iovs_len: wasi32::size_t, @@ -404,9 +428,10 @@ pub unsafe extern "C" fn __wasi_fd_pwrite( fd_pwrite(wasi_ctx, heap, fd, iovs_ptr, iovs_len, offset, nwritten) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_fd_readdir( - &mut lucet_ctx, +pub unsafe fn __wasi_fd_readdir( + lucet_ctx: &mut Vmctx, fd: wasi::__wasi_fd_t, buf: wasi32::uintptr_t, buf_len: wasi32::size_t, @@ -418,9 +443,10 @@ pub unsafe extern "C" fn __wasi_fd_readdir( fd_readdir(wasi_ctx, heap, fd, buf, buf_len, cookie, bufused) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_fd_renumber( - &mut lucet_ctx, +pub unsafe fn __wasi_fd_renumber( + lucet_ctx: &mut Vmctx, from: wasi::__wasi_fd_t, to: wasi::__wasi_fd_t, ) -> wasi::__wasi_errno_t { @@ -428,9 +454,10 @@ pub unsafe extern "C" fn __wasi_fd_renumber( fd_renumber(wasi_ctx, from, to) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_path_filestat_set_times( - &mut lucet_ctx, +pub unsafe fn __wasi_path_filestat_set_times( + lucet_ctx: &mut Vmctx, dirfd: wasi::__wasi_fd_t, dirflags: wasi::__wasi_lookupflags_t, path_ptr: wasi32::uintptr_t, @@ -446,9 +473,10 @@ pub unsafe extern "C" fn __wasi_path_filestat_set_times( ) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_path_link( - &mut lucet_ctx, +pub unsafe fn __wasi_path_link( + lucet_ctx: &mut Vmctx, old_fd: wasi::__wasi_fd_t, old_flags: wasi::__wasi_lookupflags_t, old_path_ptr: wasi32::uintptr_t, @@ -472,9 +500,10 @@ pub unsafe extern "C" fn __wasi_path_link( ) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_path_readlink( - &mut lucet_ctx, +pub unsafe fn __wasi_path_readlink( + lucet_ctx: &mut Vmctx, dirfd: wasi::__wasi_fd_t, path_ptr: wasi32::uintptr_t, path_len: wasi32::size_t, @@ -489,9 +518,10 @@ pub unsafe extern "C" fn __wasi_path_readlink( ) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_path_remove_directory( - &mut lucet_ctx, +pub unsafe fn __wasi_path_remove_directory( + lucet_ctx: &mut Vmctx, dirfd: wasi::__wasi_fd_t, path_ptr: wasi32::uintptr_t, path_len: wasi32::size_t, @@ -501,9 +531,10 @@ pub unsafe extern "C" fn __wasi_path_remove_directory( path_remove_directory(wasi_ctx, heap, dirfd, path_ptr, path_len) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_path_rename( - &mut lucet_ctx, +pub unsafe fn __wasi_path_rename( + lucet_ctx: &mut Vmctx, old_dirfd: wasi::__wasi_fd_t, old_path_ptr: wasi32::uintptr_t, old_path_len: wasi32::size_t, @@ -525,9 +556,10 @@ pub unsafe extern "C" fn __wasi_path_rename( ) } +#[lucet_hostcall] #[no_mangle] -pub unsafe extern "C" fn __wasi_path_symlink( - &mut lucet_ctx, +pub unsafe fn __wasi_path_symlink( + lucet_ctx: &mut Vmctx, old_path_ptr: wasi32::uintptr_t, old_path_len: wasi32::size_t, dir_fd: wasi::__wasi_fd_t, @@ -547,8 +579,6 @@ pub unsafe extern "C" fn __wasi_path_symlink( ) } -} - pub fn export_wasi_funcs() { let funcs: &[*const extern "C" fn()] = &[ __wasi_args_get as _, From 195151307514b4925a10a7eac7b4e5173663850b Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 25 Nov 2019 12:47:06 -0800 Subject: [PATCH 484/512] bump to 0.4.2 Deprecating an existing API and adding a new one are both minor semver changes --- Cargo.lock | 98 +++++++++---------- lucet-module/Cargo.toml | 2 +- lucet-objdump/Cargo.toml | 4 +- lucet-runtime/Cargo.toml | 12 +-- .../lucet-runtime-internals/Cargo.toml | 6 +- lucet-runtime/lucet-runtime-macros/Cargo.toml | 2 +- lucet-runtime/lucet-runtime-tests/Cargo.toml | 10 +- lucet-spectest/Cargo.toml | 8 +- lucet-validate/Cargo.toml | 4 +- lucet-wasi-fuzz/Cargo.toml | 2 +- lucet-wasi-sdk/Cargo.toml | 8 +- lucet-wasi/Cargo.toml | 12 +-- lucetc/Cargo.toml | 6 +- 13 files changed, 87 insertions(+), 87 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 939bbae4c..6b1b72fb9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -768,12 +768,12 @@ name = "lucet-benchmarks" version = "0.4.1" dependencies = [ "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.1", - "lucet-runtime 0.4.1", - "lucet-runtime-internals 0.4.1", - "lucet-wasi 0.4.1", - "lucet-wasi-sdk 0.4.1", - "lucetc 0.4.1", + "lucet-module 0.4.2", + "lucet-runtime 0.4.2", + "lucet-runtime-internals 0.4.2", + "lucet-wasi 0.4.2", + "lucet-wasi-sdk 0.4.2", + "lucetc 0.4.2", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -782,7 +782,7 @@ dependencies = [ [[package]] name = "lucet-module" -version = "0.4.1" +version = "0.4.2" dependencies = [ "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -801,28 +801,28 @@ dependencies = [ [[package]] name = "lucet-objdump" -version = "0.4.1" +version = "0.4.2" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.1", + "lucet-module 0.4.2", ] [[package]] name = "lucet-runtime" -version = "0.4.1" +version = "0.4.2" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.1", - "lucet-runtime-internals 0.4.1", - "lucet-runtime-tests 0.4.1", - "lucet-wasi-sdk 0.4.1", - "lucetc 0.4.1", + "lucet-module 0.4.2", + "lucet-runtime-internals 0.4.2", + "lucet-runtime-tests 0.4.2", + "lucet-wasi-sdk 0.4.2", + "lucetc 0.4.2", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -832,7 +832,7 @@ dependencies = [ [[package]] name = "lucet-runtime-internals" -version = "0.4.1" +version = "0.4.2" dependencies = [ "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -843,8 +843,8 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.1", - "lucet-runtime-macros 0.4.1", + "lucet-module 0.4.2", + "lucet-runtime-macros 0.4.2", "memoffset 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -855,7 +855,7 @@ dependencies = [ [[package]] name = "lucet-runtime-macros" -version = "0.4.1" +version = "0.4.2" dependencies = [ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -863,27 +863,27 @@ dependencies = [ [[package]] name = "lucet-runtime-tests" -version = "0.4.1" +version = "0.4.2" dependencies = [ "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.1", - "lucet-runtime-internals 0.4.1", - "lucet-wasi-sdk 0.4.1", - "lucetc 0.4.1", + "lucet-module 0.4.2", + "lucet-runtime-internals 0.4.2", + "lucet-wasi-sdk 0.4.2", + "lucetc 0.4.2", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucet-spectest" -version = "0.4.1" +version = "0.4.2" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.1", - "lucet-runtime 0.4.1", - "lucetc 0.4.1", + "lucet-module 0.4.2", + "lucet-runtime 0.4.2", + "lucetc 0.4.2", "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -892,12 +892,12 @@ dependencies = [ [[package]] name = "lucet-validate" -version = "0.4.1" +version = "0.4.2" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.46.1", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-wasi-sdk 0.4.1", + "lucet-wasi-sdk 0.4.2", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -906,7 +906,7 @@ dependencies = [ [[package]] name = "lucet-wasi" -version = "0.4.1" +version = "0.4.2" dependencies = [ "bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)", "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -914,11 +914,11 @@ dependencies = [ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.1", - "lucet-runtime 0.4.1", - "lucet-runtime-internals 0.4.1", - "lucet-wasi-sdk 0.4.1", - "lucetc 0.4.1", + "lucet-module 0.4.2", + "lucet-runtime 0.4.2", + "lucet-runtime-internals 0.4.2", + "lucet-wasi-sdk 0.4.2", + "lucetc 0.4.2", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -927,16 +927,16 @@ dependencies = [ [[package]] name = "lucet-wasi-fuzz" -version = "0.4.1" +version = "0.4.2" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.1", - "lucet-runtime 0.4.1", - "lucet-wasi 0.4.1", - "lucet-wasi-sdk 0.4.1", - "lucetc 0.4.1", + "lucet-module 0.4.2", + "lucet-runtime 0.4.2", + "lucet-wasi 0.4.2", + "lucet-wasi-sdk 0.4.2", + "lucetc 0.4.2", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -950,18 +950,18 @@ dependencies = [ [[package]] name = "lucet-wasi-sdk" -version = "0.4.1" +version = "0.4.2" dependencies = [ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.1", - "lucet-validate 0.4.1", - "lucetc 0.4.1", + "lucet-module 0.4.2", + "lucet-validate 0.4.2", + "lucetc 0.4.2", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucetc" -version = "0.4.1" +version = "0.4.2" dependencies = [ "bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -980,8 +980,8 @@ dependencies = [ "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.1", - "lucet-validate 0.4.1", + "lucet-module 0.4.2", + "lucet-validate 0.4.2", "memoffset 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/lucet-module/Cargo.toml b/lucet-module/Cargo.toml index 6b21fd430..b8bc8f2b0 100644 --- a/lucet-module/Cargo.toml +++ b/lucet-module/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-module" -version = "0.4.1" +version = "0.4.2" description = "A structured interface for Lucet modules" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" diff --git a/lucet-objdump/Cargo.toml b/lucet-objdump/Cargo.toml index d5dab36aa..f457bfc4c 100644 --- a/lucet-objdump/Cargo.toml +++ b/lucet-objdump/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-objdump" -version = "0.4.1" +version = "0.4.2" description = "Analyze object files emitted by the Lucet compiler" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -13,7 +13,7 @@ edition = "2018" goblin="0.0.24" byteorder="1.2.1" colored="1.8.0" -lucet-module = { path = "../lucet-module", version = "0.4.1" } +lucet-module = { path = "../lucet-module", version = "0.4.2" } [package.metadata.deb] name = "fst-lucet-objdump" diff --git a/lucet-runtime/Cargo.toml b/lucet-runtime/Cargo.toml index f60fcdbd9..9f12ae296 100644 --- a/lucet-runtime/Cargo.toml +++ b/lucet-runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime" -version = "0.4.1" +version = "0.4.2" description = "Pure Rust runtime for Lucet WebAssembly toolchain" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -11,8 +11,8 @@ edition = "2018" [dependencies] libc = "0.2.65" -lucet-runtime-internals = { path = "lucet-runtime-internals", version = "0.4.1" } -lucet-module = { path = "../lucet-module", version = "0.4.1" } +lucet-runtime-internals = { path = "lucet-runtime-internals", version = "0.4.2" } +lucet-module = { path = "../lucet-module", version = "0.4.2" } num-traits = "0.2" num-derive = "0.3.0" @@ -20,9 +20,9 @@ num-derive = "0.3.0" byteorder = "1.2" failure = "0.1" lazy_static = "1.1" -lucetc = { path = "../lucetc", version = "0.4.1" } -lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.4.1" } -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.1" } +lucetc = { path = "../lucetc", version = "0.4.2" } +lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.4.2" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.2" } nix = "0.15" rayon = "1.0" tempfile = "3.0" diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index 6501a2879..437f4b923 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime-internals" -version = "0.4.1" +version = "0.4.2" description = "Pure Rust runtime for Lucet WebAssembly toolchain (internals)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -10,8 +10,8 @@ authors = ["Lucet team "] edition = "2018" [dependencies] -lucet-module = { path = "../../lucet-module", version = "0.4.1" } -lucet-runtime-macros = { path = "../lucet-runtime-macros", version = "0.4.1" } +lucet-module = { path = "../../lucet-module", version = "0.4.2" } +lucet-runtime-macros = { path = "../lucet-runtime-macros", version = "0.4.2" } bitflags = "1.0" bincode = "1.1.4" diff --git a/lucet-runtime/lucet-runtime-macros/Cargo.toml b/lucet-runtime/lucet-runtime-macros/Cargo.toml index 7980fc789..f86cd8c2b 100644 --- a/lucet-runtime/lucet-runtime-macros/Cargo.toml +++ b/lucet-runtime/lucet-runtime-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime-macros" -version = "0.4.1" +version = "0.4.2" description = "Macros for the Lucet WebAssembly runtime" homepage = "https://github.com/bytecodealliance/lucet" repository = "https://github.com/bytecodealliance/lucet" diff --git a/lucet-runtime/lucet-runtime-tests/Cargo.toml b/lucet-runtime/lucet-runtime-tests/Cargo.toml index c0236096c..771bc8bc5 100644 --- a/lucet-runtime/lucet-runtime-tests/Cargo.toml +++ b/lucet-runtime/lucet-runtime-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime-tests" -version = "0.4.1" +version = "0.4.2" description = "Pure Rust runtime for Lucet WebAssembly toolchain (tests)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -18,10 +18,10 @@ test = false failure = "0.1" lazy_static = "1.1" tempfile = "3.0" -lucet-module = { path = "../../lucet-module", version = "0.4.1" } -lucet-runtime-internals = { path = "../lucet-runtime-internals", version = "0.4.1" } -lucet-wasi-sdk = { path = "../../lucet-wasi-sdk", version = "0.4.1" } -lucetc = { path = "../../lucetc", version = "0.4.1" } +lucet-module = { path = "../../lucet-module", version = "0.4.2" } +lucet-runtime-internals = { path = "../lucet-runtime-internals", version = "0.4.2" } +lucet-wasi-sdk = { path = "../../lucet-wasi-sdk", version = "0.4.2" } +lucetc = { path = "../../lucetc", version = "0.4.2" } [build-dependencies] cc = "1.0" diff --git a/lucet-spectest/Cargo.toml b/lucet-spectest/Cargo.toml index 7f8df4160..6876020fe 100644 --- a/lucet-spectest/Cargo.toml +++ b/lucet-spectest/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-spectest" -version = "0.4.1" +version = "0.4.2" description = "Test harness to run WebAssembly spec tests (.wast) against the Lucet toolchain" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -17,9 +17,9 @@ name = "spec-test" path = "src/main.rs" [dependencies] -lucetc = { path = "../lucetc", version = "0.4.1" } -lucet-module = { path = "../lucet-module", version = "0.4.1" } -lucet-runtime = { path = "../lucet-runtime", version = "0.4.1" } +lucetc = { path = "../lucetc", version = "0.4.2" } +lucet-module = { path = "../lucet-module", version = "0.4.2" } +lucet-runtime = { path = "../lucet-runtime", version = "0.4.2" } wabt = "0.9.2" serde = "1.0" serde_json = "1.0" diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index 430378d83..ee61fce70 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-validate" -version = "0.4.1" +version = "0.4.2" description = "Parse and validate webassembly files against witx interface" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -24,7 +24,7 @@ cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.46.1" wasmparser = "0.39.1" [dev-dependencies] -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.1" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.2" } tempfile = "3.0" wabt = "0.9.2" diff --git a/lucet-wasi-fuzz/Cargo.toml b/lucet-wasi-fuzz/Cargo.toml index 5fb368ad0..41ecc614c 100644 --- a/lucet-wasi-fuzz/Cargo.toml +++ b/lucet-wasi-fuzz/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi-fuzz" -version = "0.4.1" +version = "0.4.2" description = "Test the Lucet toolchain against native code execution using Csmith" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" diff --git a/lucet-wasi-sdk/Cargo.toml b/lucet-wasi-sdk/Cargo.toml index f73d9895e..0b0421312 100644 --- a/lucet-wasi-sdk/Cargo.toml +++ b/lucet-wasi-sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi-sdk" -version = "0.4.1" +version = "0.4.2" description = "A Rust interface to the wasi-sdk compiler and linker" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -11,9 +11,9 @@ edition = "2018" [dependencies] failure = "0.1" -lucetc = { path = "../lucetc", version = "0.4.1" } -lucet-module = { path = "../lucet-module", version = "0.4.1" } +lucetc = { path = "../lucetc", version = "0.4.2" } +lucet-module = { path = "../lucet-module", version = "0.4.2" } tempfile = "3.0" [dev-dependencies] -lucet-validate = { path = "../lucet-validate", version = "0.4.1" } +lucet-validate = { path = "../lucet-validate", version = "0.4.2" } diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index 74e6f5a9f..393f43c3c 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi" -version = "0.4.1" +version = "0.4.2" description = "Fastly's runtime for the WebAssembly System Interface (WASI)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -28,17 +28,17 @@ cast = "0.2" clap = "2.23" failure = "0.1" human-size = "0.4" -lucet-runtime = { path = "../lucet-runtime", version = "0.4.1" } -lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.4.1" } -lucet-module = { path = "../lucet-module", version = "0.4.1" } +lucet-runtime = { path = "../lucet-runtime", version = "0.4.2" } +lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.4.2" } +lucet-module = { path = "../lucet-module", version = "0.4.2" } libc = "0.2.65" nix = "0.15" rand = "0.6" wasi-common = { git = "https://github.com/cranestation/wasi-common", rev = "f4ac1299b2001b575cfc99f5544a4a96355a6bff" } [dev-dependencies] -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.1" } -lucetc = { path = "../lucetc", version = "0.4.1" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.2" } +lucetc = { path = "../lucetc", version = "0.4.2" } tempfile = "3.0" [build-dependencies] diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index f152eccc5..70f8da71e 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucetc" -version = "0.4.1" +version = "0.4.2" description = "Fastly's WebAssembly to native code compiler" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -23,8 +23,8 @@ cranelift-module = { path = "../cranelift/cranelift-module", version = "0.46.1" cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.46.1" } cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.46.1" } target-lexicon = "0.8.0" -lucet-module = { path = "../lucet-module", version = "0.4.1" } -lucet-validate = { path = "../lucet-validate", version = "0.4.1" } +lucet-module = { path = "../lucet-module", version = "0.4.2" } +lucet-validate = { path = "../lucet-validate", version = "0.4.2" } wasmparser = "0.39.1" clap="2.32" log = "0.4" From 62d6841bcab2165e08a159efd99188c50547e4cc Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 25 Nov 2019 14:13:31 -0800 Subject: [PATCH 485/512] redefine `lucet_hostcalls!` in terms of `#[lucet_hostcall]` Prompted by @jedisct1's comment, this will hopefully stave off bitrot as we deprecate `lucet_hostcalls!`. Also tweaks a comment in response to @data-pup's review. Thank you both! --- .../src/hostcall_macros.rs | 35 +++---------------- lucet-runtime/lucet-runtime-macros/src/lib.rs | 4 +-- lucet-runtime/lucet-runtime-tests/src/host.rs | 6 ++-- 3 files changed, 10 insertions(+), 35 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs b/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs index 2a1bebde2..177f1782e 100644 --- a/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs +++ b/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs @@ -36,40 +36,15 @@ macro_rules! lucet_hostcalls { )* } => { $( + #[allow(unused_mut)] + #[allow(unused_unsafe)] + #[$crate::lucet_hostcall] $(#[$attr])* pub unsafe extern "C" fn $name( - vmctx_raw: *mut $crate::vmctx::lucet_vmctx, + $vmctx: &mut $crate::vmctx::Vmctx, $( $arg: $arg_ty ),* ) -> $ret_ty { - #[inline(always)] - unsafe fn hostcall_impl( - $vmctx: &mut $crate::vmctx::Vmctx, - $( $arg : $arg_ty ),* - ) -> $ret_ty { - $($body)* - } - // don't warn if this macro happens to expand in a context where `VmctxInternal` - // was already imported - #[allow(unused_imports)] - use $crate::vmctx::VmctxInternal; - - $crate::vmctx::Vmctx::from_raw(vmctx_raw).instance_mut().uninterruptable(|| { - let res = std::panic::catch_unwind(move || { - hostcall_impl(&mut $crate::vmctx::Vmctx::from_raw(vmctx_raw), $( $arg ),*) - }); - match res { - Ok(res) => res, - Err(e) => { - match e.downcast::<$crate::instance::TerminationDetails>() { - Ok(details) => { - let mut vmctx = $crate::vmctx::Vmctx::from_raw(vmctx_raw); - vmctx.terminate_no_unwind(*details) - }, - Err(e) => std::panic::resume_unwind(e), - } - } - } - }) + $($body)* } )* } diff --git a/lucet-runtime/lucet-runtime-macros/src/lib.rs b/lucet-runtime/lucet-runtime-macros/src/lib.rs index e8551dcb1..d9161f52a 100644 --- a/lucet-runtime/lucet-runtime-macros/src/lib.rs +++ b/lucet-runtime/lucet-runtime-macros/src/lib.rs @@ -77,8 +77,8 @@ pub fn lucet_hostcall(_attr: TokenStream, item: TokenStream) -> TokenStream { .skip(1) .map(|arg| match arg { syn::FnArg::Receiver(_) => { - // this case is an error, but humor the token stream so it will produce a nicer - // error later + // this case is an error, but we produce some valid rust code anyway so that the + // compiler can produce a more meaningful error message at a later point let s = syn::Token![self](arg.span()); quote!(#s) } diff --git a/lucet-runtime/lucet-runtime-tests/src/host.rs b/lucet-runtime/lucet-runtime-tests/src/host.rs index bcc03baa2..dfb109307 100644 --- a/lucet-runtime/lucet-runtime-tests/src/host.rs +++ b/lucet-runtime/lucet-runtime-tests/src/host.rs @@ -53,12 +53,12 @@ macro_rules! host_tests { #[lucet_hostcall] #[allow(unreachable_code)] #[no_mangle] - pub fn hostcall_test_func_hostcall_error_unwind(vmctx: &mut Vmctx) { - let lock = HOSTCALL_MUTEX.lock().unwrap(); + pub fn hostcall_test_func_hostcall_error_unwind(_vmctx: &mut Vmctx) { + let _lock = HOSTCALL_MUTEX.lock().unwrap(); unsafe { lucet_hostcall_terminate!(ERROR_MESSAGE); } - drop(lock); + drop(_lock); } #[lucet_hostcall] From a6db2c04d56a5e97e00e69337c3ce674a8753235 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 25 Nov 2019 14:27:03 -0800 Subject: [PATCH 486/512] remove some unnecessary cloning in `#[lucet_hostcall]` --- lucet-runtime/lucet-runtime-macros/src/lib.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lucet-runtime/lucet-runtime-macros/src/lib.rs b/lucet-runtime/lucet-runtime-macros/src/lib.rs index d9161f52a..58134710d 100644 --- a/lucet-runtime/lucet-runtime-macros/src/lib.rs +++ b/lucet-runtime/lucet-runtime-macros/src/lib.rs @@ -40,11 +40,9 @@ pub fn lucet_hostcall(_attr: TokenStream, item: TokenStream) -> TokenStream { let vis = hostcall.vis.clone(); // remove #[no_mangle] from the attributes of the impl hostcall if it's there - hostcall.attrs = attrs - .iter() - .filter(|attr| !attr.path.is_ident("no_mangle")) - .cloned() - .collect(); + hostcall + .attrs + .retain(|attr| !attr.path.is_ident("no_mangle")); // make the impl hostcall private hostcall.vis = syn::Visibility::Inherited; From f076955c8dc18d5463877ac6de8b5d04c7608d3f Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 25 Nov 2019 15:03:49 -0800 Subject: [PATCH 487/512] use `lucet_runtime` rather than `$crate` in `lucet_hostcalls!` --- lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs b/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs index 177f1782e..5e6bb4f20 100644 --- a/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs +++ b/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs @@ -5,7 +5,7 @@ /// It is important to use this macro for hostcalls, rather than exporting them directly, as it /// installs unwind protection that prevents panics from unwinding into the guest stack. /// -/// Since this is not yet a proc macro, the syntax is unfortunately fairly brittle. The functions it +/// Since this is not a proc macro, the syntax is unfortunately fairly brittle. The functions it /// encloses must be of the form: /// /// ```ignore @@ -41,7 +41,7 @@ macro_rules! lucet_hostcalls { #[$crate::lucet_hostcall] $(#[$attr])* pub unsafe extern "C" fn $name( - $vmctx: &mut $crate::vmctx::Vmctx, + $vmctx: &mut lucet_runtime::vmctx::Vmctx, $( $arg: $arg_ty ),* ) -> $ret_ty { $($body)* From 5f2742c3863d45dfe59fb3608c02416dab12e755 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 26 Nov 2019 13:18:45 -0800 Subject: [PATCH 488/512] upgrade cranelift, wasi-common, witx deps, and friends * pull in latest Cranelift release 0.51 * upgrade to wasi-common 0.7, which fixes a lot of the WasiCtxBuilder stuff that required many extra unwraps * pull in latest WASI repo. This moves the preview0 stuff to another directory. Biggest change here is that the lucetc deb, which includes the wasi witx files, has a slightly different file layout now. * transitive upgrades to target-lexicon, faerie --- Cargo.lock | 316 +++++++++++++++++++------ benchmarks/lucet-benchmarks/src/seq.rs | 4 +- cranelift | 2 +- lucet-module/Cargo.toml | 2 +- lucet-validate/Cargo.toml | 6 +- lucet-validate/src/lib.rs | 10 +- lucet-validate/tests/wasitests.rs | 4 +- lucet-wasi-fuzz/src/main.rs | 7 +- lucet-wasi-sdk/tests/lucetc.rs | 2 +- lucet-wasi/Cargo.toml | 2 +- lucet-wasi/src/c_api.rs | 17 +- lucet-wasi/src/main.rs | 6 +- lucet-wasi/tests/test_helpers/mod.rs | 10 +- lucet-wasi/tests/tests.rs | 51 +--- lucetc/Cargo.toml | 30 ++- wasi | 2 +- 16 files changed, 290 insertions(+), 181 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a44f0724f..84750e3a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,6 +21,11 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "anyhow" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "approx" version = "0.1.1" @@ -283,93 +288,96 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.46.1" +version = "0.51.0" dependencies = [ - "cranelift-entity 0.46.1", + "cranelift-entity 0.51.0", ] [[package]] name = "cranelift-codegen" -version = "0.46.1" +version = "0.51.0" dependencies = [ - "cranelift-bforest 0.46.1", - "cranelift-codegen-meta 0.46.1", - "cranelift-codegen-shared 0.46.1", - "cranelift-entity 0.46.1", - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-bforest 0.51.0", + "cranelift-codegen-meta 0.51.0", + "cranelift-codegen-shared 0.51.0", + "cranelift-entity 0.51.0", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-codegen-meta" -version = "0.46.1" +version = "0.51.0" dependencies = [ - "cranelift-codegen-shared 0.46.1", - "cranelift-entity 0.46.1", + "cranelift-codegen-shared 0.51.0", + "cranelift-entity 0.51.0", ] [[package]] name = "cranelift-codegen-shared" -version = "0.46.1" +version = "0.51.0" +dependencies = [ + "packed_struct 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "packed_struct_codegen 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "cranelift-entity" -version = "0.46.1" +version = "0.51.0" [[package]] name = "cranelift-faerie" -version = "0.46.1" +version = "0.51.0" dependencies = [ - "cranelift-codegen 0.46.1", - "cranelift-module 0.46.1", - "faerie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen 0.51.0", + "cranelift-module 0.51.0", + "faerie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-frontend" -version = "0.46.1" +version = "0.51.0" dependencies = [ - "cranelift-codegen 0.46.1", + "cranelift-codegen 0.51.0", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-module" -version = "0.46.1" +version = "0.51.0" dependencies = [ - "cranelift-codegen 0.46.1", - "cranelift-entity 0.46.1", - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen 0.51.0", + "cranelift-entity 0.51.0", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-native" -version = "0.46.1" +version = "0.51.0" dependencies = [ - "cranelift-codegen 0.46.1", - "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen 0.51.0", + "raw-cpuid 7.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-wasm" -version = "0.46.1" +version = "0.51.0" dependencies = [ - "cranelift-codegen 0.46.1", - "cranelift-entity 0.46.1", - "cranelift-frontend 0.46.1", - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen 0.51.0", + "cranelift-entity 0.51.0", + "cranelift-frontend 0.51.0", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -546,16 +554,16 @@ dependencies = [ [[package]] name = "faerie" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "scroll 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "string-interner 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -654,6 +662,16 @@ dependencies = [ "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "goblin" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "scroll 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "heck" version = "0.3.1" @@ -741,6 +759,11 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "leb128" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "libc" version = "0.2.65" @@ -786,7 +809,7 @@ version = "0.4.1" dependencies = [ "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-entity 0.46.1", + "cranelift-entity 0.51.0", "derivative 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -886,13 +909,13 @@ name = "lucet-validate" version = "0.4.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-entity 0.46.1", + "cranelift-entity 0.51.0", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-wasi-sdk 0.4.1", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", - "witx 0.3.0", + "witx 0.6.0", ] [[package]] @@ -913,7 +936,7 @@ dependencies = [ "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi-common 0.4.0 (git+https://github.com/cranestation/wasi-common?rev=f4ac1299b2001b575cfc99f5544a4a96355a6bff)", + "wasi-common 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -958,15 +981,15 @@ dependencies = [ "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.46.1", - "cranelift-entity 0.46.1", - "cranelift-faerie 0.46.1", - "cranelift-frontend 0.46.1", - "cranelift-module 0.46.1", - "cranelift-native 0.46.1", - "cranelift-wasm 0.46.1", + "cranelift-codegen 0.51.0", + "cranelift-entity 0.51.0", + "cranelift-faerie 0.51.0", + "cranelift-frontend 0.51.0", + "cranelift-module 0.51.0", + "cranelift-native 0.51.0", + "cranelift-wasm 0.51.0", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "faerie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "faerie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -979,7 +1002,7 @@ dependencies = [ "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasmonkey 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1160,6 +1183,25 @@ name = "opaque-debug" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "packed_struct" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "packed_struct_codegen" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "packed_struct 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "parity-wasm" version = "0.40.3" @@ -1253,6 +1295,11 @@ name = "quick-error" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "quote" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "quote" version = "0.6.13" @@ -1441,6 +1488,16 @@ dependencies = [ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "raw-cpuid" +version = "7.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rayon" version = "1.2.0" @@ -1571,6 +1628,14 @@ dependencies = [ "scroll_derive 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "scroll" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "scroll_derive 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "scroll_derive" version = "0.9.5" @@ -1581,6 +1646,16 @@ dependencies = [ "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "scroll_derive" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "scrypt" version = "0.2.0" @@ -1687,7 +1762,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallvec" -version = "0.6.12" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1729,6 +1804,16 @@ name = "subtle" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "syn" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "syn" version = "0.15.44" @@ -1749,6 +1834,14 @@ dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "synom" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "synstructure" version = "0.12.1" @@ -1770,6 +1863,11 @@ dependencies = [ "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "target-lexicon" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "tempfile" version = "3.1.0" @@ -1808,6 +1906,24 @@ dependencies = [ "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "thiserror" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "thiserror-impl 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "thread_local" version = "0.3.6" @@ -1848,6 +1964,11 @@ name = "unicode-width" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-xid" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-xid" version = "0.1.0" @@ -1919,12 +2040,12 @@ dependencies = [ [[package]] name = "wasi-common" -version = "0.4.0" -source = "git+https://github.com/cranestation/wasi-common?rev=f4ac1299b2001b575cfc99f5544a4a96355a6bff#f4ac1299b2001b575cfc99f5544a4a96355a6bff" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "anyhow 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "cpu-time 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1932,15 +2053,17 @@ dependencies = [ "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi-common-cbindgen 0.4.0 (git+https://github.com/cranestation/wasi-common?rev=f4ac1299b2001b575cfc99f5544a4a96355a6bff)", + "thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi-common-cbindgen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wig 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winx 0.4.0 (git+https://github.com/cranestation/wasi-common?rev=f4ac1299b2001b575cfc99f5544a4a96355a6bff)", + "winx 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasi-common-cbindgen" -version = "0.4.0" -source = "git+https://github.com/cranestation/wasi-common?rev=f4ac1299b2001b575cfc99f5544a4a96355a6bff#f4ac1299b2001b575cfc99f5544a4a96355a6bff" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1968,6 +2091,14 @@ name = "wasmparser" version = "0.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "wast" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "leb128 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "which" version = "3.1.0" @@ -1976,6 +2107,16 @@ dependencies = [ "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "wig" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "witx 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi" version = "0.2.8" @@ -2035,8 +2176,8 @@ dependencies = [ [[package]] name = "winx" -version = "0.4.0" -source = "git+https://github.com/cranestation/wasi-common?rev=f4ac1299b2001b575cfc99f5544a4a96355a6bff#f4ac1299b2001b575cfc99f5544a4a96355a6bff" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "cvt 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2045,10 +2186,21 @@ dependencies = [ [[package]] name = "witx" -version = "0.3.0" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "wast 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "witx" +version = "0.6.0" +dependencies = [ + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "wast 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2060,6 +2212,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +"checksum anyhow 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)" = "6f1072d8f55592084072d2d3cb23a4b680a8543c00f10d446118e85ad3718142" "checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94" "checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" @@ -2108,7 +2261,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" "checksum errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2a071601ed01b988f896ab14b95e67335d1eeb50190932a1320f7fe3cadc84e" "checksum errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067" -"checksum faerie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "875d78b92b2a4d9e1e2c7eeccfa30a327d2ee6434db3beb8fd6fd92f41898bc4" +"checksum faerie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "01fed63609767c70e34203201032c249d60a24578a67ef0ce7cc13ff010e9cf2" "checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" "checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" @@ -2121,6 +2274,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" "checksum goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "e3fa261d919c1ae9d1e4533c4a2f99e10938603c4208d56c05bec7a872b661b0" +"checksum goblin 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6040506480da04a63de51a478e8021892d65d8411f29b2a422c2648bdd8bcb" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120" "checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" @@ -2132,6 +2286,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum leb128 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" "checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" "checksum libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" @@ -2154,6 +2309,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "155394f924cdddf08149da25bfb932d226b4a593ca7468b08191ff6335941af5" "checksum object 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a411a7fd46b7ebc9849c80513c84280f41cbc3159f489cd77fb30ecefdd1218a" "checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +"checksum packed_struct 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "90caf80e74380d94f2aabc83edb900b49123b3132442fb147f9155c87a756281" +"checksum packed_struct_codegen 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f6fda15ebe37b7b28889bd4aa75bb134652eaec9eb99d1bf02f806fca4357fc" "checksum parity-wasm 0.40.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1e39faaa292a687ea15120b1ac31899b13586446521df6c149e46f1584671e0f" "checksum parity-wasm 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc878dac00da22f8f61e7af3157988424567ab01d9920b962ef7dcbd7cd865" "checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" @@ -2168,6 +2325,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" "checksum progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b820305721858696053a7fd0215cfeeee16ecaaf96b7a209945428e02f1c44" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" +"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" @@ -2188,6 +2346,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e18c91676f670f6f0312764c759405f13afb98d5d73819840cf72a518487bff" "checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d" +"checksum raw-cpuid 7.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4a349ca83373cfa5d6dbb66fd76e58b2cca08da71a5f6400de0a0a6a9bceeaf" "checksum rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83a27732a533a1be0a0035a111fe76db89ad312f6f0347004c220c57f209a123" "checksum rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" @@ -2204,7 +2363,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" "checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" +"checksum scroll 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "abb2332cb595d33f7edd5700f4cbf94892e680c7f0ae56adab58a35190b66cb1" "checksum scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f84d114ef17fd144153d608fba7c446b0145d038985e7a8cc5d08bb0ce20383" +"checksum scroll_derive 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8584eea9b9ff42825b46faf46a8c24d2cff13ec152fa2a50df788b87c07ee28" "checksum scroll_derive 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1aa96c45e7f5a91cb7fabe7b279f02fea7126239fc40b732316e8b6a2d0fcb" "checksum scrypt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "656c79d0e90d0ab28ac86bf3c3d10bfbbac91450d3f190113b4e76d9fec3cfdd" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" @@ -2216,26 +2377,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" "checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" "checksum siphasher 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "83da420ee8d1a89e640d0948c646c1c088758d3a3c538f943bfa97bdac17929d" -"checksum smallvec 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "533e29e15d0748f28afbaf4ff7cab44d73e483a8e50b38c40bd13b7f3d48f542" +"checksum smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecf3b85f68e8abaa7555aa5abdb1153079387e60b718283d732f03897fcfc86" "checksum string-interner 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd710eadff449a1531351b0e43eb81ea404336fa2f56c777427ab0e32a4cf183" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum structopt 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4f66a4c0ddf7aee4677995697366de0749b0139057342eccbb609b12d0affc" "checksum structopt-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8fe0c13e476b4e21ff7f5c4ace3818b6d7bdc16897c31c73862471bc1663acae" "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" +"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" "checksum syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7bedb3320d0f3035594b0b723c8a28d7d336a3eda3881db79e61d676fb644c" +"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203" "checksum target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7975cb2c6f37d77b190bc5004a2bb015971464756fde9514651a525ada2a741a" +"checksum target-lexicon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6f4c118a7a38378f305a9e111fcb2f7f838c0be324bfb31a77ea04f7f6e684b4" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" "checksum terminal_size 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "023345d35850b69849741bd9a5432aa35290e3d8eb76af8717026f270d1cf133" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +"checksum thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "cc6b305ec0e323c7b6cfff6098a22516e0063d0bb7c3d88660a890217dca099a" +"checksum thiserror-impl 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45ba8d810d9c48fc456b7ad54574e8bfb7c7918a57ad7a6e6a0985d7959e8597" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4574b75faccaacddb9b284faecdf0b544b80b6b294f3d062d325c5726a209c20" "checksum toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01d1404644c8b12b16bfcffa4322403a91a451584daaaa7c28d3152e6cbc98cf" "checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" "checksum unicode-segmentation 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49f5526225fd8b77342d5986ab5f6055552e9c0776193b5b63fd53b46debfad7" "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" +"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" @@ -2246,11 +2413,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af5d153dc96aad7dc13ab90835b892c69867948112d95299e522d370c4e13a08" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" -"checksum wasi-common 0.4.0 (git+https://github.com/cranestation/wasi-common?rev=f4ac1299b2001b575cfc99f5544a4a96355a6bff)" = "" -"checksum wasi-common-cbindgen 0.4.0 (git+https://github.com/cranestation/wasi-common?rev=f4ac1299b2001b575cfc99f5544a4a96355a6bff)" = "" +"checksum wasi-common 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2a703d47961a9c2bf1dbeec7612446692dd8b380839c3d05f7211f72919c96df" +"checksum wasi-common-cbindgen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ecab99a12e72a7442e5a9ecfc819f42520e1e0122cf06c0ba64c6a0b6b5263ce" "checksum wasmonkey 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "af7c4bc80224427965ba21d87982cfc07d12e859824f303272056fb19f571ef9" "checksum wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5083b449454f7de0b15f131eee17de54b5a71dcb9adcf11df2b2f78fad0cd82" +"checksum wast 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "233648f540f07fce9b972436f2fbcae8a750c1121b6d32d949e1a44b4d9fc7b1" "checksum which 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5475d47078209a02e60614f7ba5e645ef3ed60f771920ac1906d7c1cc65024c8" +"checksum wig 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3856dfac1bfc00633ac5b3b9b65c9c56cb5014b27ca6dfdae17bb8177a8c19" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" @@ -2259,5 +2428,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" "checksum winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef84b96d10db72dd980056666d7f1e7663ce93d82fa33b63e71c966f4cf5032" -"checksum winx 0.4.0 (git+https://github.com/cranestation/wasi-common?rev=f4ac1299b2001b575cfc99f5544a4a96355a6bff)" = "" +"checksum winx 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c95125d6dc28a246c02340956929f4e67ac4c06c589b87de076d0dc0ad421b91" +"checksum witx 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f88e293d72e3bd74cc452f9c3e934958f075252324ea24bf40cc16f1f068a3d" "checksum xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da90eac47bf1d7871b75004b9b631d107df15f37669383b23f0b5297bc7516b6" diff --git a/benchmarks/lucet-benchmarks/src/seq.rs b/benchmarks/lucet-benchmarks/src/seq.rs index 85d28262b..6529f6c4c 100644 --- a/benchmarks/lucet-benchmarks/src/seq.rs +++ b/benchmarks/lucet-benchmarks/src/seq.rs @@ -260,11 +260,9 @@ fn run_hello(c: &mut Criterion) { b.iter_batched_ref( || { let ctx = WasiCtxBuilder::new() - .expect("create a new WASI context") .args(["hello"].iter()) - .expect("WASI arguments") .build() - .unwrap(); + .expect("build WasiCtx"); region .new_instance_builder(module.clone()) .with_embed_ctx(ctx) diff --git a/cranelift b/cranelift index 3217e4e32..da996fe5e 160000 --- a/cranelift +++ b/cranelift @@ -1 +1 @@ -Subproject commit 3217e4e3253bd15a93f1a191345c5e3a0dab31de +Subproject commit da996fe5ee4ea32a57156ba93f6813b052964183 diff --git a/lucet-module/Cargo.toml b/lucet-module/Cargo.toml index 6b21fd430..492a53dd1 100644 --- a/lucet-module/Cargo.toml +++ b/lucet-module/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Lucet team "] edition = "2018" [dependencies] -cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.46.1" } +cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.51.0" } failure = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index 430378d83..61bed1fb2 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -19,8 +19,8 @@ path = "src/main.rs" [dependencies] clap = "2" failure = "0.1" -witx = { path = "../wasi/tools/witx", version = "0.3.0" } -cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.46.1" } +witx = { path = "../wasi/tools/witx", version = "0.6.0" } +cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.51.0" } wasmparser = "0.39.1" [dev-dependencies] @@ -39,6 +39,6 @@ assets = [ ["LICENSE", "/opt/fst-lucet-validate/share/doc/lucet-validate/", "644"], ["../wasi/phases/unstable/witx/typenames.witx", "/opt/fst-lucet-validate/share/wasi/unstable/typenames.witx", "644"], - ["../wasi/phases/unstable/witx/wasi_unstable_preview0.witx", + ["../wasi/phases/unstable/witx/wasi_unstable.witx", "/opt/fst-lucet-validate/share/wasi/unstable/wasi_unstable_preview0.witx", "644"], ] diff --git a/lucet-validate/src/lib.rs b/lucet-validate/src/lib.rs index e1471f35f..e32b7fcbe 100644 --- a/lucet-validate/src/lib.rs +++ b/lucet-validate/src/lib.rs @@ -69,7 +69,7 @@ impl Validator { } pub fn load>(source_path: P) -> Result { - let witx = witx::load(source_path.as_ref())?; + let witx = witx::load(&[source_path.as_ref()])?; Ok(Self { witx, wasi_exe: false, @@ -117,11 +117,9 @@ impl Validator { } fn witx_module(&self, module: &str) -> Result, Error> { - match module { - "wasi_unstable" => self.witx.module(&Id::new("wasi_unstable_preview0")), - _ => self.witx.module(&Id::new(module)), - } - .ok_or_else(|| Error::ModuleNotFound(module.to_string())) + self.witx + .module(&Id::new(module)) + .ok_or_else(|| Error::ModuleNotFound(module.to_string())) } fn check_wasi_start_func(&self, moduletype: &ModuleType) -> Result<(), Error> { diff --git a/lucet-validate/tests/wasitests.rs b/lucet-validate/tests/wasitests.rs index 95ac9c0ac..82d1991b9 100644 --- a/lucet-validate/tests/wasitests.rs +++ b/lucet-validate/tests/wasitests.rs @@ -1,5 +1,5 @@ #[cfg(test)] -mod lucet_wasi_tests { +mod lucet_validate_tests { use lucet_validate::Validator; use std::fs; use std::path::Path; @@ -37,7 +37,7 @@ mod lucet_wasi_tests { #[test] fn validate_lucet_wasi_test_guests() { - let validator = Validator::load("../wasi/phases/unstable/witx/wasi_unstable_preview0.witx") + let validator = Validator::load("../wasi/phases/old/snapshot_0/witx/wasi_unstable.witx") .expect("load wasi_unstable_preview0"); for entry in diff --git a/lucet-wasi-fuzz/src/main.rs b/lucet-wasi-fuzz/src/main.rs index aa0c511a4..0b2fdfaee 100644 --- a/lucet-wasi-fuzz/src/main.rs +++ b/lucet-wasi-fuzz/src/main.rs @@ -368,14 +368,11 @@ fn run_with_stdout>( tmpdir: &TempDir, path: P, ) -> Result<(__wasi_exitcode_t, Vec), Error> { - let ctx = WasiCtxBuilder::new() - .map_err(|e| format_err!("WasiCtxBuilder: {}", e))? - .args(["gen"].iter()) - .map_err(|e| format_err!("WasiCtxBuilder args: {}", e))?; + let ctx = WasiCtxBuilder::new().args(&["gen"]); let (pipe_out, pipe_in) = nix::unistd::pipe()?; - let ctx = ctx.stdout(unsafe { File::from_raw_fd(pipe_in) })?.build()?; + let ctx = ctx.stdout(unsafe { File::from_raw_fd(pipe_in) }).build()?; let exitcode = run(tmpdir, path, ctx)?; diff --git a/lucet-wasi-sdk/tests/lucetc.rs b/lucet-wasi-sdk/tests/lucetc.rs index 0260e9528..83d5d2593 100644 --- a/lucet-wasi-sdk/tests/lucetc.rs +++ b/lucet-wasi-sdk/tests/lucetc.rs @@ -190,7 +190,7 @@ mod lucetc_tests { let b = Bindings::from_file("../lucet-wasi/bindings.json").expect("load lucet-wasi bindings"); let h = HeapSettings::default(); - let v = Validator::load("../wasi/phases/unstable/witx/wasi_unstable_preview0.witx") + let v = Validator::load("../wasi/phases/old/snapshot_0/witx/wasi_unstable.witx") .expect("wasi spec validation") .with_wasi_exe(true); // Compiler will only unwrap if the Validator defined above accepts the module diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index 74e6f5a9f..82e6c5cfe 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -34,7 +34,7 @@ lucet-module = { path = "../lucet-module", version = "0.4.1" } libc = "0.2.65" nix = "0.15" rand = "0.6" -wasi-common = { git = "https://github.com/cranestation/wasi-common", rev = "f4ac1299b2001b575cfc99f5544a4a96355a6bff" } +wasi-common = "0.7" [dev-dependencies] lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.1" } diff --git a/lucet-wasi/src/c_api.rs b/lucet-wasi/src/c_api.rs index 199b3e050..dde8447e2 100644 --- a/lucet-wasi/src/c_api.rs +++ b/lucet-wasi/src/c_api.rs @@ -27,7 +27,7 @@ pub unsafe extern "C" fn lucet_wasi_ctx_args( assert_nonnull!(wasi_ctx); let mut b = Box::from_raw(wasi_ctx as *mut WasiCtxBuilder); let args_raw = std::slice::from_raw_parts(argv, argc); - let args: Result, _> = args_raw + let args: Result, _> = args_raw .into_iter() .map(|arg| CStr::from_ptr(*arg).to_str()) .collect(); @@ -35,10 +35,7 @@ pub unsafe extern "C" fn lucet_wasi_ctx_args( Ok(args) => args, Err(_) => return lucet_error::InvalidArgument, }; - *b = match b.args(args.iter()) { - Ok(b) => b, - Err(_) => return lucet_error::InvalidArgument, - }; + *b = b.args(args.iter()); Box::into_raw(b); lucet_error::Ok } @@ -47,10 +44,7 @@ pub unsafe extern "C" fn lucet_wasi_ctx_args( pub unsafe extern "C" fn lucet_wasi_ctx_inherit_env(wasi_ctx: *mut lucet_wasi_ctx) -> lucet_error { assert_nonnull!(wasi_ctx); let mut b = Box::from_raw(wasi_ctx as *mut WasiCtxBuilder); - *b = match b.inherit_env() { - Ok(b) => b, - Err(_) => return lucet_error::InvalidArgument, - }; + *b = b.inherit_env(); Box::into_raw(b); lucet_error::Ok } @@ -61,10 +55,7 @@ pub unsafe extern "C" fn lucet_wasi_ctx_inherit_stdio( ) -> lucet_error { assert_nonnull!(wasi_ctx); let mut b = Box::from_raw(wasi_ctx as *mut WasiCtxBuilder); - *b = match b.inherit_stdio() { - Ok(b) => b, - Err(_) => return lucet_error::Internal, - }; + *b = b.inherit_stdio(); Box::into_raw(b); lucet_error::Ok } diff --git a/lucet-wasi/src/main.rs b/lucet-wasi/src/main.rs index 4f0ed83ce..175b62ade 100644 --- a/lucet-wasi/src/main.rs +++ b/lucet-wasi/src/main.rs @@ -235,13 +235,9 @@ fn run(config: Config<'_>) { .chain(config.guest_args.into_iter()) .collect::>(); let mut ctx = WasiCtxBuilder::new() - .expect("wasi context can be built") .args(args.iter()) - .expect("arguments can be stored") .inherit_stdio() - .expect("stdio can be inherited") - .inherit_env() - .expect("environment can be inherited"); + .inherit_env(); for (dir, guest_path) in config.preopen_dirs { ctx = ctx.preopened_dir(dir, guest_path); } diff --git a/lucet-wasi/tests/test_helpers/mod.rs b/lucet-wasi/tests/test_helpers/mod.rs index c6ac5df97..f209ab4b2 100644 --- a/lucet-wasi/tests/test_helpers/mod.rs +++ b/lucet-wasi/tests/test_helpers/mod.rs @@ -103,10 +103,7 @@ pub fn run_with_stdout>( ) -> Result<(__wasi_exitcode_t, String), Error> { let (pipe_out, pipe_in) = nix::unistd::pipe()?; - let ctx = ctx - .stdout(unsafe { File::from_raw_fd(pipe_in) }) - .unwrap() - .build()?; + let ctx = ctx.stdout(unsafe { File::from_raw_fd(pipe_in) }).build()?; let exitcode = run(path, ctx)?; @@ -124,10 +121,7 @@ pub fn run_with_null_stdin>( ) -> Result<__wasi_exitcode_t, Error> { let (pipe_out, pipe_in) = nix::unistd::pipe()?; - let ctx = ctx - .stdin(unsafe { File::from_raw_fd(pipe_out) }) - .unwrap() - .build()?; + let ctx = ctx.stdin(unsafe { File::from_raw_fd(pipe_out) }).build()?; let exitcode = run(path, ctx)?; diff --git a/lucet-wasi/tests/tests.rs b/lucet-wasi/tests/tests.rs index 41ba67926..372700377 100644 --- a/lucet-wasi/tests/tests.rs +++ b/lucet-wasi/tests/tests.rs @@ -8,7 +8,7 @@ use tempfile::TempDir; #[test] fn double_import() { - let ctx = WasiCtxBuilder::new().unwrap(); + let ctx = WasiCtxBuilder::new(); let (exitcode, stdout) = run_with_stdout("duplicate_import.wat", ctx).unwrap(); @@ -18,10 +18,7 @@ fn double_import() { #[test] fn hello() { - let ctx = WasiCtxBuilder::new() - .unwrap() - .args(["hello"].into_iter()) - .unwrap(); + let ctx = WasiCtxBuilder::new().args(["hello"].into_iter()); let (exitcode, stdout) = run_with_stdout( Path::new(LUCET_WASI_ROOT).join("examples").join("hello.c"), @@ -35,10 +32,7 @@ fn hello() { #[test] fn hello_args() { - let ctx = WasiCtxBuilder::new() - .unwrap() - .args(["hello", "test suite"].into_iter()) - .unwrap(); + let ctx = WasiCtxBuilder::new().args(["hello", "test suite"].into_iter()); let (exitcode, stdout) = run_with_stdout( Path::new(LUCET_WASI_ROOT).join("examples").join("hello.c"), @@ -53,11 +47,8 @@ fn hello_args() { #[test] fn hello_env() { let ctx = WasiCtxBuilder::new() - .unwrap() .args(["hello", "test suite"].into_iter()) - .unwrap() - .env("GREETING", "goodbye") - .unwrap(); + .env("GREETING", "goodbye"); let (exitcode, stdout) = run_with_stdout( Path::new(LUCET_WASI_ROOT).join("examples").join("hello.c"), @@ -126,11 +117,8 @@ fn stdin() { drop(stdin_file); let ctx = WasiCtxBuilder::new() - .unwrap() .args(["stdin"].into_iter()) - .unwrap() - .stdin(unsafe { File::from_raw_fd(pipe_out) }) - .unwrap(); + .stdin(unsafe { File::from_raw_fd(pipe_out) }); let (exitcode, stdout) = run_with_stdout("stdin.c", ctx).unwrap(); @@ -146,9 +134,7 @@ fn preopen_populates() { let preopen_dir = File::open(preopen_host_path).unwrap(); let ctx = WasiCtxBuilder::new() - .unwrap() .args(["preopen_populates"].into_iter()) - .unwrap() .preopened_dir(preopen_dir, "/preopen") .build() .expect("can build WasiCtx"); @@ -168,9 +154,7 @@ fn write_file() { let preopen_dir = File::open(&preopen_host_path).unwrap(); let ctx = WasiCtxBuilder::new() - .unwrap() .args(["write_file"].into_iter()) - .unwrap() .preopened_dir(preopen_dir, "/sandbox") .build() .expect("can build WasiCtx"); @@ -197,9 +181,7 @@ fn read_file() { let preopen_dir = File::open(&preopen_host_path).unwrap(); let ctx = WasiCtxBuilder::new() - .unwrap() .args(["read_file"].into_iter()) - .unwrap() .preopened_dir(preopen_dir, "/sandbox"); let (exitcode, stdout) = run_with_stdout("read_file.c", ctx).unwrap(); @@ -222,9 +204,7 @@ fn read_file_twice() { let preopen_dir = File::open(&preopen_host_path).unwrap(); let ctx = WasiCtxBuilder::new() - .unwrap() .args(["read_file_twice"].into_iter()) - .unwrap() .preopened_dir(preopen_dir, "/sandbox"); let (exitcode, stdout) = run_with_stdout("read_file_twice.c", ctx).unwrap(); @@ -252,9 +232,7 @@ fn cant_dotdot() { let preopen_dir = File::open(&preopen_host_path).unwrap(); let ctx = WasiCtxBuilder::new() - .unwrap() .args(["cant_dotdot"].into_iter()) - .unwrap() .preopened_dir(preopen_dir, "/sandbox") .build() .unwrap(); @@ -278,9 +256,7 @@ fn notdir() { let preopen_dir = File::open(&preopen_host_path).unwrap(); let ctx = WasiCtxBuilder::new() - .unwrap() .args(["notdir"].into_iter()) - .unwrap() .preopened_dir(preopen_dir, "/sandbox") .build() .unwrap(); @@ -309,9 +285,7 @@ fn follow_symlink() { let preopen_dir = File::open(&preopen_host_path).unwrap(); let ctx = WasiCtxBuilder::new() - .unwrap() .args(["follow_symlink"].into_iter()) - .unwrap() .preopened_dir(preopen_dir, "/sandbox"); let (exitcode, stdout) = run_with_stdout("follow_symlink.c", ctx).unwrap(); @@ -336,9 +310,7 @@ fn symlink_loop() { let preopen_dir = File::open(&preopen_host_path).unwrap(); let ctx = WasiCtxBuilder::new() - .unwrap() .args(["symlink_loop"].into_iter()) - .unwrap() .preopened_dir(preopen_dir, "/sandbox") .build() .unwrap(); @@ -368,9 +340,7 @@ fn symlink_escape() { let preopen_dir = File::open(&preopen_host_path).unwrap(); let ctx = WasiCtxBuilder::new() - .unwrap() .args(["symlink_escape"].into_iter()) - .unwrap() .preopened_dir(preopen_dir, "/sandbox") .build() .unwrap(); @@ -387,9 +357,7 @@ fn pseudoquine() { let pseudoquine_c = examples_dir.join("pseudoquine.c"); let ctx = WasiCtxBuilder::new() - .unwrap() .args(["pseudoquine"].into_iter()) - .unwrap() .preopened_dir(File::open(examples_dir).unwrap(), "/examples"); let (exitcode, stdout) = run_with_stdout(&pseudoquine_c, ctx).unwrap(); @@ -406,10 +374,7 @@ fn pseudoquine() { #[ignore] #[test] fn poll() { - let ctx = WasiCtxBuilder::new() - .unwrap() - .args(["poll"].into_iter()) - .unwrap(); + let ctx = WasiCtxBuilder::new().args(["poll"].into_iter()); let exitcode = run_with_null_stdin("poll.c", ctx).unwrap(); assert_eq!(exitcode, 0); } @@ -421,9 +386,7 @@ fn stat() { std::fs::create_dir(&preopen_host_path).unwrap(); let preopen_dir = File::open(&preopen_host_path).unwrap(); let ctx = WasiCtxBuilder::new() - .unwrap() .args(["stat"].into_iter()) - .unwrap() .preopened_dir(preopen_dir, "/sandbox") .build() .expect("can build WasiCtx"); @@ -438,9 +401,7 @@ fn fs() { std::fs::create_dir(&preopen_host_path).unwrap(); let preopen_dir = File::open(&preopen_host_path).unwrap(); let ctx = WasiCtxBuilder::new() - .unwrap() .args(["stat"].into_iter()) - .unwrap() .preopened_dir(preopen_dir, "/sandbox") .build() .expect("can build WasiCtx"); diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index f152eccc5..bf5d16281 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -15,21 +15,21 @@ path = "lucetc/main.rs" [dependencies] bincode = "1.1.4" -cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.46.1" } -cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.46.1" } -cranelift-native = { path = "../cranelift/cranelift-native", version = "0.46.1" } -cranelift-frontend = { path = "../cranelift/cranelift-frontend", version = "0.46.1" } -cranelift-module = { path = "../cranelift/cranelift-module", version = "0.46.1" } -cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.46.1" } -cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.46.1" } -target-lexicon = "0.8.0" +cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.51.0" } +cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.51.0" } +cranelift-native = { path = "../cranelift/cranelift-native", version = "0.51.0" } +cranelift-frontend = { path = "../cranelift/cranelift-frontend", version = "0.51.0" } +cranelift-module = { path = "../cranelift/cranelift-module", version = "0.51.0" } +cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.51.0" } +cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.51.0" } +target-lexicon = "0.9" lucet-module = { path = "../lucet-module", version = "0.4.1" } lucet-validate = { path = "../lucet-validate", version = "0.4.1" } wasmparser = "0.39.1" clap="2.32" log = "0.4" env_logger = "0.6" -faerie = "0.11.0" +faerie = "0.12.0" goblin = "0.0.24" failure = "0.1" byteorder = "1.2" @@ -56,8 +56,12 @@ assets = [ ["target/release/lucetc", "/opt/fst-lucetc/bin/lucetc", "755"], ["target/release/liblucetc.rlib", "/opt/fst-lucetc/lib/", "644"], ["LICENSE", "/opt/fst-lucetc/share/doc/lucetc/", "644"], - ["../wasi/phases/unstable/witx/typenames.witx", - "/opt/fst-lucetc/share/wasi/unstable/typenames.witx", "644"], - ["../wasi/phases/unstable/witx/wasi_unstable_preview0.witx", - "/opt/fst-lucetc/share/wasi/unstable/wasi_unstable_preview0.witx", "644"], + ["../wasi/phases/old/snapshot_0/witx/typenames.witx", + "/opt/fst-lucetc/share/wasi/snapshot_0/typenames.witx", "644"], + ["../wasi/phases/old/snapshot_0/witx/wasi_unstable.witx", + "/opt/fst-lucetc/share/wasi/snapshot_0/wasi_unstable.witx", "644"], + ["../wasi/phases/snapshot/witx/typenames.witx", + "/opt/fst-lucetc/share/wasi/snapshot_1/typenames.witx", "644"], + ["../wasi/phases/snapshot/witx/wasi_snapshot_preview1.witx", + "/opt/fst-lucetc/share/wasi/snapshot_1/wasi_snapshot_preview1.witx", "644"], ] diff --git a/wasi b/wasi index a50853b96..db7391469 160000 --- a/wasi +++ b/wasi @@ -1 +1 @@ -Subproject commit a50853b962ce7e1386b29e79a6f8884978f16834 +Subproject commit db7391469c136447af511c5d3000e0d55f09109e From 97c0097c10b1465c3eb5c2f5625cbca06589d52c Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 26 Nov 2019 14:58:50 -0800 Subject: [PATCH 489/512] lucet-validate: correct deb paths --- lucet-validate/Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index 1446b116f..11f9c0c58 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -37,8 +37,8 @@ assets = [ ["target/release/lucet-validate", "/opt/fst-lucet-validate/bin/lucet-validate", "755"], ["target/release/liblucet_validate.rlib", "/opt/fst-lucet-validate/lib/", "644"], ["LICENSE", "/opt/fst-lucet-validate/share/doc/lucet-validate/", "644"], - ["../wasi/phases/unstable/witx/typenames.witx", - "/opt/fst-lucet-validate/share/wasi/unstable/typenames.witx", "644"], - ["../wasi/phases/unstable/witx/wasi_unstable.witx", - "/opt/fst-lucet-validate/share/wasi/unstable/wasi_unstable_preview0.witx", "644"], + ["../wasi/phases/old/snapshot_0/witx/typenames.witx", + "/opt/fst-lucet-validate/share/wasi/snapshot_0/typenames.witx", "644"], + ["../wasi/phases/old/snapshot_0/witx/wasi_unstable.witx", + "/opt/fst-lucet-validate/share/wasi/snapshot_0/wasi_unstable.witx", "644"], ] From 28acfe568df058a8b0e6191982adbd834b290af9 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 26 Nov 2019 14:59:00 -0800 Subject: [PATCH 490/512] CI testing: add cargo-deb packaging --- Dockerfile | 2 +- Makefile | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5af3166f1..73b182584 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,7 +35,7 @@ ENV PATH=/root/.cargo/bin:$PATH RUN rustup component add rustfmt --toolchain nightly-2019-09-25-x86_64-unknown-linux-gnu RUN rustup target add wasm32-wasi -RUN cargo install --debug cargo-audit cargo-watch rsign2 +RUN cargo install --debug cargo-audit cargo-watch rsign2 cargo-deb RUN curl -sS -L -O https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-7/wasi-sdk_7.0_amd64.deb \ && dpkg -i wasi-sdk_7.0_amd64.deb && rm -f wasi-sdk_7.0_amd64.deb diff --git a/Makefile b/Makefile index 96d3ba657..5278866d7 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ install-dev: build-dev @helpers/install.sh --unoptimized .PHONY: test -test: indent-check test-except-fuzz test-fuzz +test: indent-check test-except-fuzz test-fuzz package .PHONY: test-except-fuzz test-except-fuzz: @@ -72,6 +72,11 @@ indent: indent-check: helpers/indent.sh check +.PHONY: package +package: + cargo deb -p lucet-validate + cargo deb -p lucetc + .PHONY: watch watch: cargo watch --exec "test \ From 40577b433d1088ed995f7100e025f9b0635cfa00 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 26 Nov 2019 15:58:17 -0800 Subject: [PATCH 491/512] CI: run `make package` on a parallel runner, so CI doesnt get longer --- .github/actions/test/action.yml | 6 +++++- .github/workflows/main.yml | 20 ++++++++++++++++++++ Makefile | 2 +- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/.github/actions/test/action.yml b/.github/actions/test/action.yml index bd111c486..550fce474 100644 --- a/.github/actions/test/action.yml +++ b/.github/actions/test/action.yml @@ -1,5 +1,9 @@ name: 'Test Lucet' description: 'run tests using standardized lucet development environment' +inputs: + target: + description: "Makefile target to execute" + required: true runs: using: 'docker' image: '../../../Dockerfile' @@ -11,4 +15,4 @@ runs: # rustup expects $HOME to be set to /root during `docker run` because thats what # it was set to during container creation. Actions clears $HOME so we set it here. # The test target of the Makefile is our standard CI. - - 'export HOME=/root; make test' + - 'export HOME=/root; make ${{ inputs.target }}' diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2b4c03fc8..b405f7a0e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,10 +13,30 @@ jobs: # Testing uses the development environment Docker container. # This action builds the container and executes the test suite inside it. - uses: ./.github/actions/test + with: + target: test + + - name: Ensure testing did not change sources + run: git diff --exit-code + + package: + name: Package + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + with: + submodules: true + + # Testing uses the development environment Docker container. + # This action builds the container and executes the test suite inside it. + - uses: ./.github/actions/test + with: + target: package - name: Ensure testing did not change sources run: git diff --exit-code + rustfmt: name: Rustfmt runs-on: ubuntu-16.04 diff --git a/Makefile b/Makefile index 5278866d7..922d99840 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ install-dev: build-dev @helpers/install.sh --unoptimized .PHONY: test -test: indent-check test-except-fuzz test-fuzz package +test: indent-check test-except-fuzz test-fuzz .PHONY: test-except-fuzz test-except-fuzz: From 6a7fbf9ca4497804be61959f809df57d91e1d666 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 3 Dec 2019 18:19:30 +0100 Subject: [PATCH 492/512] Use actions/checkout@v1 to support submodules checkout This commit fixes the CI by setting `actions/checkout` at version `v1`. The current master of `actions/checkout` now obsoleted the `with: submodules: true` input. See [actions/checkout/releases/tag/v2-beta] for more info. [actions/checkout/releases/tag/v2-beta]: https://github.com/actions/checkout/releases/tag/v2-beta --- .github/workflows/fuzz.yml | 2 +- .github/workflows/main.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index da8e4a664..6eaa49be4 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-16.04 steps: - - uses: actions/checkout@master + - uses: actions/checkout@v1 with: submodules: true diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b405f7a0e..4069b1e53 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,7 +6,7 @@ jobs: name: Test runs-on: ubuntu-latest steps: - - uses: actions/checkout@master + - uses: actions/checkout@v1 with: submodules: true @@ -23,7 +23,7 @@ jobs: name: Package runs-on: ubuntu-latest steps: - - uses: actions/checkout@master + - uses: actions/checkout@v1 with: submodules: true @@ -41,7 +41,7 @@ jobs: name: Rustfmt runs-on: ubuntu-16.04 steps: - - uses: actions/checkout@master + - uses: actions/checkout@v1 with: submodules: true - name: Install Rust (rustup) From 680e61ee4badb3b633cb2f455ee9017e4d423b7e Mon Sep 17 00:00:00 2001 From: Katelyn Martin Date: Fri, 13 Dec 2019 03:49:28 -0500 Subject: [PATCH 493/512] show unsupported global import in error message --- lucet-runtime/lucet-runtime-internals/src/instance.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index b2d8dd473..a38f0750a 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -546,7 +546,7 @@ impl Instance { Global::Import { .. } => { return Err(Error::Unsupported(format!( "global imports are unsupported; found: {:?}", - i + v ))); } Global::Def(def) => def.init_val(), From 22fd235176b5afb2051de3edd24c385a4164523d Mon Sep 17 00:00:00 2001 From: Katelyn Martin Date: Fri, 13 Dec 2019 03:59:27 -0500 Subject: [PATCH 494/512] misc. instance lints --- .../lucet-runtime-internals/src/instance.rs | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance.rs b/lucet-runtime/lucet-runtime-internals/src/instance.rs index b2d8dd473..1ed8945fb 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance.rs @@ -26,7 +26,7 @@ use std::ops::{Deref, DerefMut}; use std::ptr::{self, NonNull}; use std::sync::Arc; -pub const LUCET_INSTANCE_MAGIC: u64 = 746932922; +pub const LUCET_INSTANCE_MAGIC: u64 = 746_932_922; thread_local! { /// The host context. @@ -79,7 +79,7 @@ pub fn new_instance_handle( embed_ctx: CtxMap, ) -> Result { let inst = NonNull::new(instance) - .ok_or(lucet_format_err!("instance pointer is null; this is a bug"))?; + .ok_or_else(|| lucet_format_err!("instance pointer is null; this is a bug"))?; lucet_ensure!( unsafe { inst.as_ref().magic } != LUCET_INSTANCE_MAGIC, @@ -564,12 +564,9 @@ impl Instance { /// /// On success, returns the number of pages that existed before the call. pub fn grow_memory(&mut self, additional_pages: u32) -> Result { - let additional_bytes = - additional_pages - .checked_mul(WASM_PAGE_SIZE) - .ok_or(lucet_format_err!( - "additional pages larger than wasm address space", - ))?; + let additional_bytes = additional_pages + .checked_mul(WASM_PAGE_SIZE) + .ok_or_else(|| lucet_format_err!("additional pages larger than wasm address space",))?; let orig_len = self .alloc .expand_heap(additional_bytes, self.module.as_ref())?; @@ -750,7 +747,7 @@ impl Instance { let mut inst = Instance { magic: LUCET_INSTANCE_MAGIC, - embed_ctx: embed_ctx, + embed_ctx, module, ctx: Context::new(), state: State::Ready, @@ -976,8 +973,9 @@ impl Instance { // handler. // Run the C-style fatal handler, if it exists. - self.c_fatal_handler - .map(|h| unsafe { h(self as *mut Instance) }); + if let Some(h) = self.c_fatal_handler { + unsafe { h(self as *mut Instance) } + } // If there is no C-style fatal handler, or if it (erroneously) returns, // call the Rust handler that we know will not return From 657cbd5c932e308ccfda057c697c08488d792c86 Mon Sep 17 00:00:00 2001 From: Katelyn Martin Date: Fri, 13 Dec 2019 15:03:10 -0500 Subject: [PATCH 495/512] replace empty constructor w/ default impl --- .../lucet-runtime-internals/src/embed_ctx.rs | 14 ++++++++------ .../lucet-runtime-internals/src/region/mod.rs | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs b/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs index 55147dea2..20b693d48 100644 --- a/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs @@ -10,6 +10,14 @@ pub struct CtxMap { map: HashMap>>, } +impl Default for CtxMap { + fn default() -> Self { + CtxMap { + map: HashMap::default(), + } + } +} + impl CtxMap { pub fn clear(&mut self) { self.map.clear(); @@ -51,12 +59,6 @@ impl CtxMap { }) } - pub fn new() -> Self { - CtxMap { - map: HashMap::new(), - } - } - pub fn remove(&mut self) -> Option { self.map.remove(&TypeId::of::()).map(|x| { *(x.into_inner()) diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mod.rs b/lucet-runtime/lucet-runtime-internals/src/region/mod.rs index 7099ed639..3b0bc82a8 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mod.rs @@ -80,7 +80,7 @@ impl<'a> InstanceBuilder<'a> { InstanceBuilder { region, module, - embed_ctx: CtxMap::new(), + embed_ctx: CtxMap::default(), } } From 3df7ccf094edd808c9ca403a4ac6392f50914974 Mon Sep 17 00:00:00 2001 From: Katelyn Martin Date: Fri, 13 Dec 2019 16:02:36 -0500 Subject: [PATCH 496/512] we can derive default --- lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs b/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs index 20b693d48..71e0a1b45 100644 --- a/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs @@ -6,18 +6,11 @@ use std::collections::HashMap; /// /// This is similar to the type provided by the `anymap` crate, but we can get away with simpler /// types on the methods due to our more specialized use case. +#[derive(Default)] pub struct CtxMap { map: HashMap>>, } -impl Default for CtxMap { - fn default() -> Self { - CtxMap { - map: HashMap::default(), - } - } -} - impl CtxMap { pub fn clear(&mut self) { self.map.clear(); From 5a923882073800b6b74659fd776d600fa9a0c401 Mon Sep 17 00:00:00 2001 From: Katelyn Martin Date: Fri, 13 Dec 2019 16:34:08 -0500 Subject: [PATCH 497/512] keep `new()` but defined in terms of default --- lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs b/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs index 71e0a1b45..0e12f0902 100644 --- a/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/embed_ctx.rs @@ -59,4 +59,8 @@ impl CtxMap { .expect("value stored with TypeId::of:: is always type T") }) } + + pub fn new() -> Self { + Self::default() + } } From 86b00eae6d9234750c8609147f6960508850af12 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 16 Dec 2019 10:44:48 -0800 Subject: [PATCH 498/512] Make yield methods take `&mut Vmctx`; update semver This prevents resources like embedder contexts or heap views from living across yield points, which is important for safety since the host can modify the data underlying those resources while the instance is suspended. Since this is a semver breaking change, this patch also updates the package versions. --- Cargo.lock | 98 +++++++++---------- lucet-module/Cargo.toml | 2 +- lucet-objdump/Cargo.toml | 4 +- lucet-runtime/Cargo.toml | 12 +-- .../lucet-runtime-internals/Cargo.toml | 6 +- .../src/hostcall_macros.rs | 2 +- .../lucet-runtime-internals/src/vmctx.rs | 14 +-- lucet-runtime/lucet-runtime-macros/Cargo.toml | 2 +- lucet-runtime/lucet-runtime-tests/Cargo.toml | 10 +- lucet-spectest/Cargo.toml | 8 +- lucet-validate/Cargo.toml | 4 +- lucet-wasi-fuzz/Cargo.toml | 2 +- lucet-wasi-sdk/Cargo.toml | 8 +- lucet-wasi/Cargo.toml | 12 +-- lucetc/Cargo.toml | 6 +- 15 files changed, 95 insertions(+), 95 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d4474217f..a4e8b15bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -791,12 +791,12 @@ name = "lucet-benchmarks" version = "0.4.1" dependencies = [ "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.2", - "lucet-runtime 0.4.2", - "lucet-runtime-internals 0.4.2", - "lucet-wasi 0.4.2", - "lucet-wasi-sdk 0.4.2", - "lucetc 0.4.2", + "lucet-module 0.5.0", + "lucet-runtime 0.5.0", + "lucet-runtime-internals 0.5.0", + "lucet-wasi 0.5.0", + "lucet-wasi-sdk 0.5.0", + "lucetc 0.5.0", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -805,7 +805,7 @@ dependencies = [ [[package]] name = "lucet-module" -version = "0.4.2" +version = "0.5.0" dependencies = [ "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -824,28 +824,28 @@ dependencies = [ [[package]] name = "lucet-objdump" -version = "0.4.2" +version = "0.5.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.2", + "lucet-module 0.5.0", ] [[package]] name = "lucet-runtime" -version = "0.4.2" +version = "0.5.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.2", - "lucet-runtime-internals 0.4.2", - "lucet-runtime-tests 0.4.2", - "lucet-wasi-sdk 0.4.2", - "lucetc 0.4.2", + "lucet-module 0.5.0", + "lucet-runtime-internals 0.5.0", + "lucet-runtime-tests 0.5.0", + "lucet-wasi-sdk 0.5.0", + "lucetc 0.5.0", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -855,7 +855,7 @@ dependencies = [ [[package]] name = "lucet-runtime-internals" -version = "0.4.2" +version = "0.5.0" dependencies = [ "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -866,8 +866,8 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.2", - "lucet-runtime-macros 0.4.2", + "lucet-module 0.5.0", + "lucet-runtime-macros 0.5.0", "memoffset 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -878,7 +878,7 @@ dependencies = [ [[package]] name = "lucet-runtime-macros" -version = "0.4.2" +version = "0.5.0" dependencies = [ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -886,27 +886,27 @@ dependencies = [ [[package]] name = "lucet-runtime-tests" -version = "0.4.2" +version = "0.5.0" dependencies = [ "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.2", - "lucet-runtime-internals 0.4.2", - "lucet-wasi-sdk 0.4.2", - "lucetc 0.4.2", + "lucet-module 0.5.0", + "lucet-runtime-internals 0.5.0", + "lucet-wasi-sdk 0.5.0", + "lucetc 0.5.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucet-spectest" -version = "0.4.2" +version = "0.5.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.2", - "lucet-runtime 0.4.2", - "lucetc 0.4.2", + "lucet-module 0.5.0", + "lucet-runtime 0.5.0", + "lucetc 0.5.0", "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -915,12 +915,12 @@ dependencies = [ [[package]] name = "lucet-validate" -version = "0.4.2" +version = "0.5.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.51.0", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-wasi-sdk 0.4.2", + "lucet-wasi-sdk 0.5.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -929,7 +929,7 @@ dependencies = [ [[package]] name = "lucet-wasi" -version = "0.4.2" +version = "0.5.0" dependencies = [ "bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)", "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -937,11 +937,11 @@ dependencies = [ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.2", - "lucet-runtime 0.4.2", - "lucet-runtime-internals 0.4.2", - "lucet-wasi-sdk 0.4.2", - "lucetc 0.4.2", + "lucet-module 0.5.0", + "lucet-runtime 0.5.0", + "lucet-runtime-internals 0.5.0", + "lucet-wasi-sdk 0.5.0", + "lucetc 0.5.0", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -950,16 +950,16 @@ dependencies = [ [[package]] name = "lucet-wasi-fuzz" -version = "0.4.2" +version = "0.5.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.2", - "lucet-runtime 0.4.2", - "lucet-wasi 0.4.2", - "lucet-wasi-sdk 0.4.2", - "lucetc 0.4.2", + "lucet-module 0.5.0", + "lucet-runtime 0.5.0", + "lucet-wasi 0.5.0", + "lucet-wasi-sdk 0.5.0", + "lucetc 0.5.0", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -973,18 +973,18 @@ dependencies = [ [[package]] name = "lucet-wasi-sdk" -version = "0.4.2" +version = "0.5.0" dependencies = [ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.2", - "lucet-validate 0.4.2", - "lucetc 0.4.2", + "lucet-module 0.5.0", + "lucet-validate 0.5.0", + "lucetc 0.5.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucetc" -version = "0.4.2" +version = "0.5.0" dependencies = [ "bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1003,8 +1003,8 @@ dependencies = [ "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lucet-module 0.4.2", - "lucet-validate 0.4.2", + "lucet-module 0.5.0", + "lucet-validate 0.5.0", "memoffset 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/lucet-module/Cargo.toml b/lucet-module/Cargo.toml index e6b7d75b1..8ab4d8c7d 100644 --- a/lucet-module/Cargo.toml +++ b/lucet-module/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-module" -version = "0.4.2" +version = "0.5.0" description = "A structured interface for Lucet modules" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" diff --git a/lucet-objdump/Cargo.toml b/lucet-objdump/Cargo.toml index f457bfc4c..1a2cd19fa 100644 --- a/lucet-objdump/Cargo.toml +++ b/lucet-objdump/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-objdump" -version = "0.4.2" +version = "0.5.0" description = "Analyze object files emitted by the Lucet compiler" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -13,7 +13,7 @@ edition = "2018" goblin="0.0.24" byteorder="1.2.1" colored="1.8.0" -lucet-module = { path = "../lucet-module", version = "0.4.2" } +lucet-module = { path = "../lucet-module", version = "0.5.0" } [package.metadata.deb] name = "fst-lucet-objdump" diff --git a/lucet-runtime/Cargo.toml b/lucet-runtime/Cargo.toml index 9f12ae296..b965b22fd 100644 --- a/lucet-runtime/Cargo.toml +++ b/lucet-runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime" -version = "0.4.2" +version = "0.5.0" description = "Pure Rust runtime for Lucet WebAssembly toolchain" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -11,8 +11,8 @@ edition = "2018" [dependencies] libc = "0.2.65" -lucet-runtime-internals = { path = "lucet-runtime-internals", version = "0.4.2" } -lucet-module = { path = "../lucet-module", version = "0.4.2" } +lucet-runtime-internals = { path = "lucet-runtime-internals", version = "0.5.0" } +lucet-module = { path = "../lucet-module", version = "0.5.0" } num-traits = "0.2" num-derive = "0.3.0" @@ -20,9 +20,9 @@ num-derive = "0.3.0" byteorder = "1.2" failure = "0.1" lazy_static = "1.1" -lucetc = { path = "../lucetc", version = "0.4.2" } -lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.4.2" } -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.2" } +lucetc = { path = "../lucetc", version = "0.5.0" } +lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.5.0" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.5.0" } nix = "0.15" rayon = "1.0" tempfile = "3.0" diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index 437f4b923..a39ac4460 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime-internals" -version = "0.4.2" +version = "0.5.0" description = "Pure Rust runtime for Lucet WebAssembly toolchain (internals)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -10,8 +10,8 @@ authors = ["Lucet team "] edition = "2018" [dependencies] -lucet-module = { path = "../../lucet-module", version = "0.4.2" } -lucet-runtime-macros = { path = "../lucet-runtime-macros", version = "0.4.2" } +lucet-module = { path = "../../lucet-module", version = "0.5.0" } +lucet-runtime-macros = { path = "../lucet-runtime-macros", version = "0.5.0" } bitflags = "1.0" bincode = "1.1.4" diff --git a/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs b/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs index 5e6bb4f20..9c9271ce8 100644 --- a/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs +++ b/lucet-runtime/lucet-runtime-internals/src/hostcall_macros.rs @@ -22,7 +22,7 @@ /// } /// ``` #[macro_export] -#[deprecated(since = "0.4.2", note = "Use the #[lucet_hostcall] attribute instead")] +#[deprecated(since = "0.5.0", note = "Use the #[lucet_hostcall] attribute instead")] macro_rules! lucet_hostcalls { { $( diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index 2d38c3e2b..a7ccdb6c8 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -78,7 +78,7 @@ pub trait VmctxInternal { /// /// The dynamic type checks used by the other yield methods should make this explicit option /// type redundant, however this interface is used to avoid exposing a panic to the C API. - fn yield_val_try_val(&self, val: A) -> Option; + fn yield_val_try_val(&mut self, val: A) -> Option; } impl VmctxInternal for Vmctx { @@ -105,7 +105,7 @@ impl VmctxInternal for Vmctx { } } - fn yield_val_try_val(&self, val: A) -> Option { + fn yield_val_try_val(&mut self, val: A) -> Option { self.yield_impl::(val); self.try_take_resumed_val() } @@ -321,7 +321,7 @@ impl Vmctx { /// /// (The reason for the trailing underscore in the name is that Rust reserves `yield` as a /// keyword for future use.) - pub fn yield_(&self) { + pub fn yield_(&mut self) { self.yield_val_expecting_val::(EmptyYieldVal); } @@ -332,7 +332,7 @@ impl Vmctx { /// After suspending, the instance may be resumed by calling /// [`Instance::resume_with_val()`](../struct.Instance.html#method.resume_with_val) from the /// host with a value of type `R`. - pub fn yield_expecting_val(&self) -> R { + pub fn yield_expecting_val(&mut self) -> R { self.yield_val_expecting_val::(EmptyYieldVal) } @@ -342,7 +342,7 @@ impl Vmctx { /// /// After suspending, the instance may be resumed by the host using /// [`Instance::resume()`](../struct.Instance.html#method.resume). - pub fn yield_val(&self, val: A) { + pub fn yield_val(&mut self, val: A) { self.yield_val_expecting_val::(val); } @@ -353,12 +353,12 @@ impl Vmctx { /// After suspending, the instance may be resumed by calling /// [`Instance::resume_with_val()`](../struct.Instance.html#method.resume_with_val) from the /// host with a value of type `R`. - pub fn yield_val_expecting_val(&self, val: A) -> R { + pub fn yield_val_expecting_val(&mut self, val: A) -> R { self.yield_impl::(val); self.take_resumed_val() } - fn yield_impl(&self, val: A) { + fn yield_impl(&mut self, val: A) { let inst = unsafe { self.instance_mut() }; let expecting: Box> = Box::new(PhantomData); inst.state = State::Yielding { diff --git a/lucet-runtime/lucet-runtime-macros/Cargo.toml b/lucet-runtime/lucet-runtime-macros/Cargo.toml index f86cd8c2b..3d2d73fdc 100644 --- a/lucet-runtime/lucet-runtime-macros/Cargo.toml +++ b/lucet-runtime/lucet-runtime-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime-macros" -version = "0.4.2" +version = "0.5.0" description = "Macros for the Lucet WebAssembly runtime" homepage = "https://github.com/bytecodealliance/lucet" repository = "https://github.com/bytecodealliance/lucet" diff --git a/lucet-runtime/lucet-runtime-tests/Cargo.toml b/lucet-runtime/lucet-runtime-tests/Cargo.toml index 771bc8bc5..5525e74be 100644 --- a/lucet-runtime/lucet-runtime-tests/Cargo.toml +++ b/lucet-runtime/lucet-runtime-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-runtime-tests" -version = "0.4.2" +version = "0.5.0" description = "Pure Rust runtime for Lucet WebAssembly toolchain (tests)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -18,10 +18,10 @@ test = false failure = "0.1" lazy_static = "1.1" tempfile = "3.0" -lucet-module = { path = "../../lucet-module", version = "0.4.2" } -lucet-runtime-internals = { path = "../lucet-runtime-internals", version = "0.4.2" } -lucet-wasi-sdk = { path = "../../lucet-wasi-sdk", version = "0.4.2" } -lucetc = { path = "../../lucetc", version = "0.4.2" } +lucet-module = { path = "../../lucet-module", version = "0.5.0" } +lucet-runtime-internals = { path = "../lucet-runtime-internals", version = "0.5.0" } +lucet-wasi-sdk = { path = "../../lucet-wasi-sdk", version = "0.5.0" } +lucetc = { path = "../../lucetc", version = "0.5.0" } [build-dependencies] cc = "1.0" diff --git a/lucet-spectest/Cargo.toml b/lucet-spectest/Cargo.toml index 6876020fe..bf66aabf4 100644 --- a/lucet-spectest/Cargo.toml +++ b/lucet-spectest/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-spectest" -version = "0.4.2" +version = "0.5.0" description = "Test harness to run WebAssembly spec tests (.wast) against the Lucet toolchain" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -17,9 +17,9 @@ name = "spec-test" path = "src/main.rs" [dependencies] -lucetc = { path = "../lucetc", version = "0.4.2" } -lucet-module = { path = "../lucet-module", version = "0.4.2" } -lucet-runtime = { path = "../lucet-runtime", version = "0.4.2" } +lucetc = { path = "../lucetc", version = "0.5.0" } +lucet-module = { path = "../lucet-module", version = "0.5.0" } +lucet-runtime = { path = "../lucet-runtime", version = "0.5.0" } wabt = "0.9.2" serde = "1.0" serde_json = "1.0" diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index 11f9c0c58..dfc98bd4f 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-validate" -version = "0.4.2" +version = "0.5.0" description = "Parse and validate webassembly files against witx interface" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -24,7 +24,7 @@ cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.51.0" wasmparser = "0.39.1" [dev-dependencies] -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.2" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.5.0" } tempfile = "3.0" wabt = "0.9.2" diff --git a/lucet-wasi-fuzz/Cargo.toml b/lucet-wasi-fuzz/Cargo.toml index 41ecc614c..cd7aeb35a 100644 --- a/lucet-wasi-fuzz/Cargo.toml +++ b/lucet-wasi-fuzz/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi-fuzz" -version = "0.4.2" +version = "0.5.0" description = "Test the Lucet toolchain against native code execution using Csmith" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" diff --git a/lucet-wasi-sdk/Cargo.toml b/lucet-wasi-sdk/Cargo.toml index 0b0421312..6b60329a8 100644 --- a/lucet-wasi-sdk/Cargo.toml +++ b/lucet-wasi-sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi-sdk" -version = "0.4.2" +version = "0.5.0" description = "A Rust interface to the wasi-sdk compiler and linker" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -11,9 +11,9 @@ edition = "2018" [dependencies] failure = "0.1" -lucetc = { path = "../lucetc", version = "0.4.2" } -lucet-module = { path = "../lucet-module", version = "0.4.2" } +lucetc = { path = "../lucetc", version = "0.5.0" } +lucet-module = { path = "../lucet-module", version = "0.5.0" } tempfile = "3.0" [dev-dependencies] -lucet-validate = { path = "../lucet-validate", version = "0.4.2" } +lucet-validate = { path = "../lucet-validate", version = "0.5.0" } diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index b57d14f41..07bcbb385 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucet-wasi" -version = "0.4.2" +version = "0.5.0" description = "Fastly's runtime for the WebAssembly System Interface (WASI)" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -28,17 +28,17 @@ cast = "0.2" clap = "2.23" failure = "0.1" human-size = "0.4" -lucet-runtime = { path = "../lucet-runtime", version = "0.4.2" } -lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.4.2" } -lucet-module = { path = "../lucet-module", version = "0.4.2" } +lucet-runtime = { path = "../lucet-runtime", version = "0.5.0" } +lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.5.0" } +lucet-module = { path = "../lucet-module", version = "0.5.0" } libc = "0.2.65" nix = "0.15" rand = "0.6" wasi-common = "0.7" [dev-dependencies] -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.4.2" } -lucetc = { path = "../lucetc", version = "0.4.2" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.5.0" } +lucetc = { path = "../lucetc", version = "0.5.0" } tempfile = "3.0" [build-dependencies] diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index 16fc54801..3f680a1e9 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lucetc" -version = "0.4.2" +version = "0.5.0" description = "Fastly's WebAssembly to native code compiler" homepage = "https://github.com/fastly/lucet" repository = "https://github.com/fastly/lucet" @@ -23,8 +23,8 @@ cranelift-module = { path = "../cranelift/cranelift-module", version = "0.51.0" cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.51.0" } cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.51.0" } target-lexicon = "0.9" -lucet-module = { path = "../lucet-module", version = "0.4.2" } -lucet-validate = { path = "../lucet-validate", version = "0.4.2" } +lucet-module = { path = "../lucet-module", version = "0.5.0" } +lucet-validate = { path = "../lucet-validate", version = "0.5.0" } wasmparser = "0.39.1" clap="2.32" log = "0.4" From 85c50b594cf8d5fb7af25c06fe4634df1bc5814a Mon Sep 17 00:00:00 2001 From: "shravanrn@gmail.com" Date: Thu, 5 Sep 2019 18:29:48 -0700 Subject: [PATCH 499/512] Fixes #276 - Allow use of aligned heaps --- .../src/region/mmap.rs | 204 +++++++++++++++++- 1 file changed, 195 insertions(+), 9 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs index d1579eed9..8d22ced4e 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs @@ -56,6 +56,7 @@ pub struct MmapRegion { capacity: usize, freelist: Mutex>, limits: Limits, + min_heap_alignment: usize, } impl Region for MmapRegion {} @@ -281,6 +282,48 @@ impl MmapRegion { capacity: instance_capacity, freelist: Mutex::new(Vec::with_capacity(instance_capacity)), limits: limits.clone(), + min_heap_alignment: 0, // No constaints on heap alignment by default + }); + { + let mut freelist = region.freelist.lock().unwrap(); + for _ in 0..instance_capacity { + freelist.push(MmapRegion::create_slot(®ion)?); + } + } + + Ok(region) + } + + /// Create a new `MmapRegion` that can support a given number instances, each subject to the + /// same runtime limits. Additionally, ensure that the heap is aligned at least to the + /// specified amount. heap_alignment must be a power of 2. + /// + /// The region is returned in an `Arc`, because any instances created from it carry a reference + /// back to the region. + pub fn create_aligned( + instance_capacity: usize, + limits: &Limits, + heap_alignment: usize, + ) -> Result, Error> { + assert!( + SIGSTKSZ % host_page_size() == 0, + "signal stack size is a multiple of host page size" + ); + limits.validate()?; + + let is_power_of_2 = (heap_alignment & (heap_alignment - 1)) == 0; + + if !is_power_of_2 { + return Err(Error::InvalidArgument( + "heap_alignment must be a power of 2", + )); + } + + let region = Arc::new(MmapRegion { + capacity: instance_capacity, + freelist: Mutex::new(Vec::with_capacity(instance_capacity)), + limits: limits.clone(), + min_heap_alignment: heap_alignment, }); { let mut freelist = region.freelist.lock().unwrap(); @@ -294,15 +337,27 @@ impl MmapRegion { fn create_slot(region: &Arc) -> Result { // get the chunk of virtual memory that the `Slot` will manage - let mem = unsafe { - mmap( - ptr::null_mut(), - region.limits.total_memory_size(), - ProtFlags::PROT_NONE, - MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, - 0, - 0, - )? + let mem = if region.min_heap_alignment == 0 { + unsafe { + mmap( + ptr::null_mut(), + region.limits.total_memory_size(), + ProtFlags::PROT_NONE, + MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, + 0, + 0, + )? + } + } else { + unsafe { + mmap_aligned( + region.limits.total_memory_size(), + ProtFlags::PROT_NONE, + MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, + region.min_heap_alignment, // requested alignment + instance_heap_offset(), // offset that must be aligned + )? + } }; // set the first part of the memory to read/write so that the `Instance` can be stored there @@ -343,7 +398,138 @@ impl MmapRegion { } } +// Note alignment must be a power of 2 +// Offset must be a multiple of 4Kb (page size) +unsafe fn mmap_aligned( + requested_length: usize, + prot: ProtFlags, + flags: MapFlags, + alignment: usize, + alignment_offset: usize, +) -> Result<*mut c_void, Error> { + let addr = ptr::null_mut(); + let fd = 0; + let offset = 0; + + let padded_length = requested_length + alignment + alignment_offset; + let unaligned = mmap(addr, padded_length, prot, flags, fd, offset)? as usize; + + // Round up the next address that has addr % alignment = 0 + let aligned_nonoffset = (unaligned + (alignment - 1)) & !(alignment - 1); + + // Currently offset 0 is aligned according to alignment + // Alignment needs to be enforced at the given offset + let aligned = if aligned_nonoffset - alignment_offset >= unaligned { + aligned_nonoffset - alignment_offset + } else { + aligned_nonoffset - alignment_offset + alignment + }; + + //Sanity check + if aligned < unaligned + || (aligned + (requested_length - 1)) > (unaligned + (padded_length - 1)) + || (aligned + alignment_offset) % alignment != 0 + { + // explicitly ignore failures now, as this is just a best-effort clean up after the last fail + let _ = munmap(unaligned as *mut c_void, padded_length); + return Err(Error::Unsupported("Could not align memory".to_string())); + } + + { + let unused_front = aligned - unaligned; + if unused_front != 0 { + if munmap(unaligned as *mut c_void, unused_front).is_err() { + // explicitly ignore failures now, as this is just a best-effort clean up after the last fail + let _ = munmap(unaligned as *mut c_void, padded_length); + return Err(Error::Unsupported("Could not align memory".to_string())); + } + } + } + + { + let unused_back = (unaligned + (padded_length - 1)) - (aligned + (requested_length - 1)); + if unused_back != 0 { + if munmap((aligned + requested_length) as *mut c_void, unused_back).is_err() { + // explicitly ignore failures now, as this is just a best-effort clean up after the last fail + let _ = munmap(unaligned as *mut c_void, padded_length); + return Err(Error::Unsupported("Could not align memory".to_string())); + } + } + } + + return Ok(aligned as *mut c_void); +} + // TODO: remove this once `nix` PR https://github.com/nix-rust/nix/pull/991 is merged unsafe fn mprotect(addr: *mut c_void, length: libc::size_t, prot: ProtFlags) -> nix::Result<()> { nix::errno::Errno::result(libc::mprotect(addr, length, prot.bits())).map(drop) } + +#[cfg(test)] +mod tests2 { + use super::*; + use nix::sys::mman::{munmap, MapFlags, ProtFlags}; + + #[test] + fn test_aligned_mem() { + let kb: usize = 1024; + let mb: usize = 1024 * kb; + + struct TestProps { + pub mem_size: usize, + pub mem_align: usize, + pub offset: usize, + }; + + let tests = vec![ + TestProps { + mem_size: 1 * mb, + mem_align: 1 * mb, + offset: 0, + }, + TestProps { + mem_size: 1 * mb, + mem_align: 2 * mb, + offset: 0, + }, + TestProps { + mem_size: 32 * mb, + mem_align: 32 * mb, + offset: 0, + }, + TestProps { + mem_size: 32 * mb, + mem_align: 32 * mb, + offset: 4 * kb, + }, + ]; + + for test in tests { + let mem = unsafe { + mmap_aligned( + test.mem_size, + ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, + MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, + test.mem_align, + test.offset, + ) + .unwrap() + }; + + // Check alignment + let actual_align = ((mem as usize) + test.offset) % test.mem_align; + assert_eq!(actual_align, 0); + + // Make sure the memory is accessible + let mem_slice = + unsafe { std::slice::from_raw_parts_mut(mem as *mut u8, test.mem_size) }; + for loc in mem_slice { + *loc = 1; + } + + unsafe { + munmap(mem, test.mem_size).unwrap(); + } + } + } +} From 7616982ba792270f112f47b8565ddaf2cca46760 Mon Sep 17 00:00:00 2001 From: Katelyn Martin Date: Wed, 18 Dec 2019 12:41:28 -0500 Subject: [PATCH 500/512] add blank rustfmt config file --- .rustfmt.toml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .rustfmt.toml diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 000000000..8148fc634 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1 @@ +# This file tells tools we use rustfmt. We use the default settings. From d3a137701a9588b770d9e881bce5f3e70b12fa64 Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Fri, 20 Dec 2019 16:34:49 +0100 Subject: [PATCH 501/512] into_iter() -> iter() for arrays (#382) This was previously accepted by the compiler but is being phased out; it will become a hard error in a future rustc release. See https://github.com/rust-lang/rust/issues/66145 > --- lucet-runtime/lucet-runtime-internals/src/region/mmap.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs index 8d22ced4e..76d9d6ce1 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs @@ -89,7 +89,7 @@ impl RegionInternal for MmapRegion { // make the sigstack read/writable (slot.sigstack, SIGSTKSZ), ] - .into_iter() + .iter() { // eprintln!("setting r/w {:p}[{:x}]", *ptr, len); unsafe { mprotect(*ptr, *len, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE)? }; @@ -138,7 +138,7 @@ impl RegionInternal for MmapRegion { (slot.globals, slot.limits.globals_size), (slot.sigstack, SIGSTKSZ), ] - .into_iter() + .iter() { // eprintln!("setting none {:p}[{:x}]", *ptr, len); unsafe { From 9239c9707ae2dcbcb51bab10f1d4a84640ea9e20 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 6 Jan 2020 12:01:18 -0800 Subject: [PATCH 502/512] switch rustc version back to stable; add note about callback safety --- helpers/indent.sh | 2 +- lucet-runtime/lucet-runtime-internals/src/vmctx.rs | 8 ++++++++ rust-toolchain | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/helpers/indent.sh b/helpers/indent.sh index 2c0d8dc80..be4faea7d 100755 --- a/helpers/indent.sh +++ b/helpers/indent.sh @@ -10,7 +10,7 @@ cleanup() { } trap cleanup 1 2 3 6 15 -RUSTFMT_VERSION=1.4.8-nightly +RUSTFMT_VERSION=1.4.9-stable if ! rustfmt --version | grep -q "rustfmt $RUSTFMT_VERSION"; then echo "indent requires rustfmt $RUSTFMT_VERSION" diff --git a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs index a7ccdb6c8..b666f3574 100644 --- a/lucet-runtime/lucet-runtime-internals/src/vmctx.rs +++ b/lucet-runtime/lucet-runtime-internals/src/vmctx.rs @@ -272,11 +272,19 @@ impl Vmctx { /// This is useful when a hostcall takes a function pointer as its argument, as WebAssembly uses /// table indices as its runtime representation of function pointers. /// + /// # Safety + /// /// We do not currently reflect function type information into the Rust type system, so callers /// of the returned function must take care to cast it to the correct type before calling. The /// correct type will include the `vmctx` argument, which the caller is responsible for passing /// from its own context. /// + /// There is currently no guarantee that guest functions will return before faulting, or + /// terminating the instance in a subsequent hostcall. This means that any Rust resources that + /// are held open when the guest function is called might be leaked if the guest function, for + /// example, divides by zero. Work to make this safer is + /// [ongoing](https://github.com/bytecodealliance/lucet/pull/254). + /// /// ```no_run /// use lucet_runtime_macros::lucet_hostcall; /// use lucet_runtime_internals::lucet_hostcall_terminate; diff --git a/rust-toolchain b/rust-toolchain index 9e495a9f7..32b7211cb 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2019-09-25 +1.40.0 From 809ba7a66fb0ef9c8f87923d4703f93a2c438a49 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Mon, 6 Jan 2020 12:01:50 -0800 Subject: [PATCH 503/512] add `make test-full` target; make `test` more focused The benchmark and fuzz targets in particular take quite a long time to run, and are usually not the focus of development. They're still worth running in CI, though, to catch bitrot. --- .github/workflows/main.yml | 2 +- Makefile | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4069b1e53..7d2d79392 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,7 +14,7 @@ jobs: # This action builds the container and executes the test suite inside it. - uses: ./.github/actions/test with: - target: test + target: test-full - name: Ensure testing did not change sources run: git diff --exit-code diff --git a/Makefile b/Makefile index 922d99840..dead1ebe1 100644 --- a/Makefile +++ b/Makefile @@ -21,11 +21,10 @@ install-dev: build-dev @helpers/install.sh --unoptimized .PHONY: test -test: indent-check test-except-fuzz test-fuzz +test: indent-check test-packages -.PHONY: test-except-fuzz -test-except-fuzz: - cargo build -p lucet-spectest # build but *not* run spectests to mitigate bitrot while spectests don't pass +.PHONY: test-packages +test-packages: cargo test --no-fail-fast \ -p lucet-runtime-internals \ -p lucet-runtime \ @@ -35,6 +34,13 @@ test-except-fuzz: -p lucet-wasi \ -p lucet-wasi-fuzz \ -p lucet-validate + +.PHONY: test-full +test-full: indent-check test-except-fuzz test-fuzz + +.PHONY: test-except-fuzz +test-except-fuzz: test-packages + cargo build -p lucet-spectest # build but *not* run spectests to mitigate bitrot while spectests don't pass cargo test --benches -p lucet-benchmarks -- --test # run the benchmarks in debug mode helpers/lucet-toolchain-tests/signature.sh From 800d02e094af6d9637a290505fb849a3b962ed36 Mon Sep 17 00:00:00 2001 From: Katelyn Martin Date: Thu, 9 Jan 2020 12:14:55 -0500 Subject: [PATCH 504/512] clean up symbol data code --- lucet-module/src/signature.rs | 40 +++++++++++++++-------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/lucet-module/src/signature.rs b/lucet-module/src/signature.rs index 134bd7256..cb1af504f 100644 --- a/lucet-module/src/signature.rs +++ b/lucet-module/src/signature.rs @@ -150,22 +150,18 @@ impl RawModuleAndData { let obj = object::ElfFile::parse(obj_bin) .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?; let symbol_map = obj.symbol_map(); - for symbol in symbol_map.symbols() { - let kind = symbol.kind(); - if kind != SymbolKind::Data { - continue; + for symbol in symbol_map + .symbols() + .iter() + .filter(|sym| sym.kind() == SymbolKind::Data) + .filter(|sym| sym.name() == Some(symbol_name)) + { + if let Some(section_index) = symbol.section_index() { + let section = &obj.elf().section_headers[section_index.0]; + let offset = (symbol.address() - section.sh_addr + section.sh_offset) as usize; + let len = symbol.size() as usize; + return Ok(Some(SymbolData { offset, len })); } - if symbol.name() != Some(symbol_name) { - continue; - } - let section_index = match symbol.section_index() { - Some(section_index) => section_index, - None => continue, - }; - let section = &obj.elf().section_headers[section_index.0]; - let offset = (symbol.address() - section.sh_addr + section.sh_offset) as usize; - let len = symbol.size() as usize; - return Ok(Some(SymbolData { offset, len })); } Ok(None) } @@ -186,14 +182,12 @@ impl RawModuleAndData { } else { symbol_name }; - for symbol in symbol_map.symbols() { - let kind = symbol.kind(); - if kind != SymbolKind::Data && kind != SymbolKind::Unknown { - continue; - } - if symbol.name() != Some(symbol_name) { - continue; - } + if let Some(symbol) = symbol_map + .symbols() + .iter() + .filter(|sym| sym.kind() == SymbolKind::Data || sym.kind() == SymbolKind::Unknown) + .find(|sym| sym.name() == Some(symbol_name)) + { let offset = symbol.address() as usize; let len = symbol.size() as usize; return Ok(Some(SymbolData { offset, len })); From 4c7d5db192970ee0945ef26312d00ff92253a9da Mon Sep 17 00:00:00 2001 From: Katelyn Martin Date: Thu, 9 Jan 2020 13:16:02 -0500 Subject: [PATCH 505/512] move bindings tests into file in tests/ --- lucet-module/src/bindings.rs | 60 ---------------------------------- lucet-module/tests/bindings.rs | 56 +++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 60 deletions(-) create mode 100644 lucet-module/tests/bindings.rs diff --git a/lucet-module/src/bindings.rs b/lucet-module/src/bindings.rs index 3c1dab385..b9bd99800 100644 --- a/lucet-module/src/bindings.rs +++ b/lucet-module/src/bindings.rs @@ -141,63 +141,3 @@ impl Bindings { m } } - -#[cfg(test)] -mod tests { - fn test_file(f: &str) -> PathBuf { - PathBuf::from(format!("tests/bindings/{}", f)) - } - - use super::Bindings; - use std::collections::HashMap; - use std::path::PathBuf; - - #[test] - fn explicit() { - let mut explicit_map = HashMap::new(); - explicit_map.insert(String::from("hello"), String::from("goodbye")); - let map = Bindings::env(explicit_map); - - let result = map.translate("env", "hello").unwrap(); - assert!(result == "goodbye"); - - let result = map.translate("env", "nonexistent"); - if let Ok(_) = result { - assert!( - false, - "explicit import map returned value for non-existent symbol" - ) - } - } - - #[test] - fn explicit_from_nonexistent_file() { - let fail_map = Bindings::from_file(&test_file("nonexistent_bindings.json")); - assert!( - fail_map.is_err(), - "ImportMap::explicit_from_file did not fail on a non-existent file" - ); - } - - #[test] - fn explicit_from_garbage_file() { - let fail_map = Bindings::from_file(&test_file("garbage.json")); - assert!( - fail_map.is_err(), - "ImportMap::explicit_from_file did not fail on a garbage file" - ); - } - - #[test] - fn explicit_from_file() { - let map = Bindings::from_file(&test_file("bindings_test.json")) - .expect("load valid bindings from file"); - let result = map.translate("env", "hello").expect("hello has a binding"); - assert!(result == "json is cool"); - - assert!( - map.translate("env", "nonexistent").is_err(), - "bindings from file returned value for non-existent symbol" - ); - } -} diff --git a/lucet-module/tests/bindings.rs b/lucet-module/tests/bindings.rs new file mode 100644 index 000000000..74b3ebed4 --- /dev/null +++ b/lucet-module/tests/bindings.rs @@ -0,0 +1,56 @@ +use lucet_module::bindings::Bindings; +use std::collections::HashMap; +use std::path::PathBuf; + +fn test_file(f: &str) -> PathBuf { + PathBuf::from(format!("tests/bindings/{}", f)) +} + +#[test] +fn explicit() { + let mut explicit_map = HashMap::new(); + explicit_map.insert(String::from("hello"), String::from("goodbye")); + let map = Bindings::env(explicit_map); + + let result = map.translate("env", "hello").unwrap(); + assert!(result == "goodbye"); + + let result = map.translate("env", "nonexistent"); + if let Ok(_) = result { + assert!( + false, + "explicit import map returned value for non-existent symbol" + ) + } +} + +#[test] +fn explicit_from_nonexistent_file() { + let fail_map = Bindings::from_file(&test_file("nonexistent_bindings.json")); + assert!( + fail_map.is_err(), + "ImportMap::explicit_from_file did not fail on a non-existent file" + ); +} + +#[test] +fn explicit_from_garbage_file() { + let fail_map = Bindings::from_file(&test_file("garbage.json")); + assert!( + fail_map.is_err(), + "ImportMap::explicit_from_file did not fail on a garbage file" + ); +} + +#[test] +fn explicit_from_file() { + let map = Bindings::from_file(&test_file("bindings_test.json")) + .expect("load valid bindings from file"); + let result = map.translate("env", "hello").expect("hello has a binding"); + assert!(result == "json is cool"); + + assert!( + map.translate("env", "nonexistent").is_err(), + "bindings from file returned value for non-existent symbol" + ); +} From 6ee788b8572e0de6a538a699e6a3bffc62471c5e Mon Sep 17 00:00:00 2001 From: Katelyn Martin Date: Thu, 9 Jan 2020 13:32:02 -0500 Subject: [PATCH 506/512] fix test assertion --- lucet-module/tests/bindings.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lucet-module/tests/bindings.rs b/lucet-module/tests/bindings.rs index 74b3ebed4..58ea6da61 100644 --- a/lucet-module/tests/bindings.rs +++ b/lucet-module/tests/bindings.rs @@ -16,12 +16,10 @@ fn explicit() { assert!(result == "goodbye"); let result = map.translate("env", "nonexistent"); - if let Ok(_) = result { - assert!( - false, - "explicit import map returned value for non-existent symbol" - ) - } + assert!( + result.is_err(), + "explicit import map returned value for non-existent symbol" + ); } #[test] From 4e89abec7bf73921aba3a2b59858a56f0e943865 Mon Sep 17 00:00:00 2001 From: data-pup Date: Wed, 15 Jan 2020 15:25:01 -0500 Subject: [PATCH 507/512] ModuleDecls cleanup (#391) * Addresses two lint warnings about redundant field names, using the shorthand notation instead. * Moves `*_name_for` helper functions nested inside of `declare_funcs` out of a loop body. This is just a small readability fix for our loop. --- lucetc/src/decls.rs | 102 ++++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index d2256aebc..7e3744a58 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -114,58 +114,58 @@ impl<'a> ModuleDecls<'a> { clif_module: &mut ClifModule, bindings: &'a Bindings, ) -> Result<(), LucetcError> { - for ix in 0..decls.info.functions.len() { - let func_index = UniqueFuncIndex::new(ix); + // Get the name for this function from the module names section, if it exists. + // Because names have to be unique, we append the index value (ix) to the name. + fn custom_name_for<'a>( + ix: usize, + func_index: UniqueFuncIndex, + decls: &mut ModuleDecls<'a>, + ) -> Option { + decls + .info + .function_names + .get(func_index) + .map(|s| format!("{}_{}", s, ix)) + } - // Get the name for this function from the module names section, if it exists. - // Because names have to be unique, we append the index value (ix) to the name. - fn custom_name_for<'a>( - ix: usize, - func_index: UniqueFuncIndex, - decls: &mut ModuleDecls<'a>, - ) -> Option { - decls - .info - .function_names - .get(func_index) - .map(|s| format!("{}_{}", s, ix)) + fn export_name_for<'a>( + func_ix: UniqueFuncIndex, + decls: &mut ModuleDecls<'a>, + ) -> Option { + let export = decls.info.functions.get(func_ix).unwrap(); + if !export.export_names.is_empty() { + decls.exports.push(ExportFunction { + fn_idx: LucetFunctionIndex::from_u32(decls.function_names.len() as u32), + names: export.export_names.clone(), + }); + Some(format!("guest_func_{}", export.export_names[0])) + } else { + None } + } - fn export_name_for<'a>( - func_ix: UniqueFuncIndex, - decls: &mut ModuleDecls<'a>, - ) -> Option { - let export = decls.info.functions.get(func_ix).unwrap(); - if !export.export_names.is_empty() { - decls.exports.push(ExportFunction { - fn_idx: LucetFunctionIndex::from_u32(decls.function_names.len() as u32), - names: export.export_names.clone(), - }); - Some(format!("guest_func_{}", export.export_names[0])) - } else { - None - } - }; - - fn import_name_for<'a>( - func_ix: UniqueFuncIndex, - decls: &mut ModuleDecls<'a>, - bindings: &'a Bindings, - ) -> Result, failure::Context> { - if let Some((import_mod, import_field)) = decls.info.imported_funcs.get(func_ix) { - let import_symbol = bindings - .translate(import_mod, import_field) - .context(LucetcErrorKind::TranslatingModule)?; - decls.imports.push(ImportFunction { - fn_idx: LucetFunctionIndex::from_u32(decls.function_names.len() as u32), - module: import_mod, - name: import_field, - }); - Ok(Some(import_symbol.to_string())) - } else { - Ok(None) - } - }; + fn import_name_for<'a>( + func_ix: UniqueFuncIndex, + decls: &mut ModuleDecls<'a>, + bindings: &'a Bindings, + ) -> Result, failure::Context> { + if let Some((import_mod, import_field)) = decls.info.imported_funcs.get(func_ix) { + let import_symbol = bindings + .translate(import_mod, import_field) + .context(LucetcErrorKind::TranslatingModule)?; + decls.imports.push(ImportFunction { + fn_idx: LucetFunctionIndex::from_u32(decls.function_names.len() as u32), + module: import_mod, + name: import_field, + }); + Ok(Some(import_symbol.to_string())) + } else { + Ok(None) + } + } + + for ix in 0..decls.info.functions.len() { + let func_index = UniqueFuncIndex::new(ix); let import_info = import_name_for(func_index, decls, bindings)?; let export_info = export_name_for(func_index, decls); @@ -394,8 +394,8 @@ impl<'a> ModuleDecls<'a> { Ok(Some(HeapSpec { reserved_size, guard_size: heap_settings.guard_size, - initial_size: initial_size, - max_size: max_size, + initial_size, + max_size, })) } _ => Err(format_err!("lucetc only supports memory 0")) From b60dc3c3d3b2a6daaf9f4fa6377dd4ec90af03b0 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Tue, 14 Jan 2020 13:10:58 -0500 Subject: [PATCH 508/512] add `--target` option to lucetc Currently, `lucetc` assumes that the machine that it's compiling for (the "target") is the same as the machine on which `lucetc` is running ("the host"). While this is a reasonable assumption to make, many future uses of `lucetc` may require these machines to be distinct. Towards that end, let's introduce a `--target` option for specifying the machine `lucetc` is supposed to be generating code for, and thread that information through to all the places that require it. --- Cargo.lock | 2 ++ lucet-spectest/Cargo.toml | 1 + lucet-spectest/src/script.rs | 2 ++ lucet-wasi-sdk/Cargo.toml | 1 + lucet-wasi-sdk/tests/lucetc.rs | 6 ++++ lucetc/lucetc/main.rs | 3 +- lucetc/lucetc/options.rs | 24 ++++++++++++++ lucetc/src/compiler.rs | 11 +++++-- lucetc/src/compiler/cpu_features.rs | 5 ++- lucetc/src/lib.rs | 49 +++++++++++++++++++++++------ lucetc/tests/wasm.rs | 28 +++++++++++++++++ 11 files changed, 116 insertions(+), 16 deletions(-) mode change 100644 => 100755 lucetc/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index a4e8b15bf..b62e21560 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -909,6 +909,7 @@ dependencies = [ "lucetc 0.5.0", "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -979,6 +980,7 @@ dependencies = [ "lucet-module 0.5.0", "lucet-validate 0.5.0", "lucetc 0.5.0", + "target-lexicon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/lucet-spectest/Cargo.toml b/lucet-spectest/Cargo.toml index bf66aabf4..cced16189 100644 --- a/lucet-spectest/Cargo.toml +++ b/lucet-spectest/Cargo.toml @@ -26,3 +26,4 @@ serde_json = "1.0" failure = "0.1" clap="2.32" tempfile = "3.0" +target-lexicon = "0.9" diff --git a/lucet-spectest/src/script.rs b/lucet-spectest/src/script.rs index 41880b9dd..de4493f97 100644 --- a/lucet-spectest/src/script.rs +++ b/lucet-spectest/src/script.rs @@ -5,6 +5,7 @@ use lucetc::{Compiler, CpuFeatures, HeapSettings, LucetcError, LucetcErrorKind, use std::io; use std::process::Command; use std::sync::Arc; +use target_lexicon::Triple; #[derive(Fail, Debug)] pub enum ScriptError { @@ -69,6 +70,7 @@ impl ScriptEnv { let bindings = bindings::spec_test_bindings(); let compiler = Compiler::new( module, + Triple::host(), OptLevel::default(), CpuFeatures::baseline(), &bindings, diff --git a/lucet-wasi-sdk/Cargo.toml b/lucet-wasi-sdk/Cargo.toml index 6b60329a8..b056bb041 100644 --- a/lucet-wasi-sdk/Cargo.toml +++ b/lucet-wasi-sdk/Cargo.toml @@ -13,6 +13,7 @@ edition = "2018" failure = "0.1" lucetc = { path = "../lucetc", version = "0.5.0" } lucet-module = { path = "../lucet-module", version = "0.5.0" } +target-lexicon = "0.9" tempfile = "3.0" [dev-dependencies] diff --git a/lucet-wasi-sdk/tests/lucetc.rs b/lucet-wasi-sdk/tests/lucetc.rs index 83d5d2593..5106d7e73 100644 --- a/lucet-wasi-sdk/tests/lucetc.rs +++ b/lucet-wasi-sdk/tests/lucetc.rs @@ -9,6 +9,7 @@ mod lucetc_tests { use std::fs::File; use std::io::Read; use std::path::PathBuf; + use target_lexicon::Triple; /// Compile C -> WebAssembly using wasi-sdk's clang. Does not use the wasi-sdk /// libc, and does not produce a wasi executable, just a wasm module with the given set of @@ -46,6 +47,7 @@ mod lucetc_tests { let v = Validator::parse("").expect("empty validation environment"); let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -90,6 +92,7 @@ mod lucetc_tests { let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -120,6 +123,7 @@ mod lucetc_tests { .expect("empty validation environment"); let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -146,6 +150,7 @@ mod lucetc_tests { let v = Validator::parse("").expect("empty validation environment"); let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -196,6 +201,7 @@ mod lucetc_tests { // Compiler will only unwrap if the Validator defined above accepts the module let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, diff --git a/lucetc/lucetc/main.rs b/lucetc/lucetc/main.rs index 55ddbb67d..e1a0df525 100644 --- a/lucetc/lucetc/main.rs +++ b/lucetc/lucetc/main.rs @@ -83,7 +83,8 @@ pub fn run(opts: &Options) -> Result<(), Error> { let mut c = Lucetc::new(PathBuf::from(input)) .with_bindings(bindings) .with_opt_level(opts.opt_level) - .with_cpu_features(opts.cpu_features.clone()); + .with_cpu_features(opts.cpu_features.clone()) + .with_target(opts.target.clone()); match opts.witx_specs.len() { 0 => {} diff --git a/lucetc/lucetc/options.rs b/lucetc/lucetc/options.rs index 332dbbb36..8ba375a88 100644 --- a/lucetc/lucetc/options.rs +++ b/lucetc/lucetc/options.rs @@ -2,6 +2,8 @@ use clap::{Arg, ArgMatches, Values}; use failure::Error; use lucetc::{CpuFeatures, HeapSettings, OptLevel, SpecificFeature, TargetCpu}; use std::path::PathBuf; +use std::str::FromStr; +use target_lexicon::{Architecture, Triple}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CodegenOutput { @@ -119,6 +121,7 @@ pub struct Options { pub sk_path: Option, pub count_instructions: bool, pub error_style: ErrorStyle, + pub target: Triple, } impl Options { @@ -185,11 +188,24 @@ impl Options { Some("2") | Some("speed_and_size") => OptLevel::SpeedAndSize, Some(_) => panic!("unknown value for opt-level"), }; + + let target = match m.value_of("target") { + None => Triple::host(), + Some(t) => match Triple::from_str(&t) { + Ok(triple) => triple, + Err(_) => panic!("specified target is invalid"), + }, + }; + let cpu_features = cpu_features_from_args( m.value_of("target-cpu"), m.values_of("target-feature").unwrap_or_default(), )?; + if target.architecture != Architecture::X86_64 { + panic!("architectures other than x86-64 are unsupported"); + } + let keygen = m.is_present("keygen"); let sign = m.is_present("sign"); let verify = m.is_present("verify"); @@ -225,6 +241,7 @@ impl Options { pk_path, count_instructions, error_style, + target, }) } pub fn get() -> Result { @@ -251,6 +268,13 @@ impl Options { .multiple(false) .help("output destination, defaults to a.out if unspecified"), ) + .arg( + Arg::with_name("target") + .long("target") + .takes_value(true) + .multiple(false) + .help(format!("target to compile for, defaults to {} if unspecified", Triple::host()).as_str()), + ) .arg( Arg::with_name("target-cpu") .long("--target-cpu") diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index b5f80c4ce..500e4ee56 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -23,6 +23,7 @@ use failure::{format_err, Fail, ResultExt}; use lucet_module::bindings::Bindings; use lucet_module::{FunctionSpec, ModuleData, ModuleFeatures, MODULE_DATA_SYM}; use lucet_validate::Validator; +use target_lexicon::Triple; #[derive(Debug, Clone, Copy)] pub enum OptLevel { @@ -50,6 +51,7 @@ impl OptLevel { pub struct Compiler<'a> { decls: ModuleDecls<'a>, clif_module: ClifModule, + target: Triple, opt_level: OptLevel, cpu_features: CpuFeatures, count_instructions: bool, @@ -59,6 +61,7 @@ pub struct Compiler<'a> { impl<'a> Compiler<'a> { pub fn new( wasm_binary: &'a [u8], + target: Triple, opt_level: OptLevel, cpu_features: CpuFeatures, bindings: &'a Bindings, @@ -66,7 +69,7 @@ impl<'a> Compiler<'a> { count_instructions: bool, validator: &Option, ) -> Result { - let isa = Self::target_isa(opt_level, &cpu_features)?; + let isa = Self::target_isa(target.clone(), opt_level, &cpu_features)?; let frontend_config = isa.frontend_config(); let mut module_info = ModuleInfo::new(frontend_config.clone()); @@ -130,6 +133,7 @@ impl<'a> Compiler<'a> { cpu_features, count_instructions, module_translation_state, + target, }) } @@ -233,16 +237,17 @@ impl<'a> Compiler<'a> { } Ok(CraneliftFuncs::new( funcs, - Self::target_isa(self.opt_level, &self.cpu_features)?, + Self::target_isa(self.target, self.opt_level, &self.cpu_features)?, )) } fn target_isa( + target: Triple, opt_level: OptLevel, cpu_features: &CpuFeatures, ) -> Result, LucetcError> { let mut flags_builder = settings::builder(); - let isa_builder = cpu_features.isa_builder()?; + let isa_builder = cpu_features.isa_builder(target)?; flags_builder.enable("enable_verifier").unwrap(); flags_builder.enable("is_pic").unwrap(); flags_builder.set("opt_level", opt_level.to_flag()).unwrap(); diff --git a/lucetc/src/compiler/cpu_features.rs b/lucetc/src/compiler/cpu_features.rs index e6104c113..589e50348 100644 --- a/lucetc/src/compiler/cpu_features.rs +++ b/lucetc/src/compiler/cpu_features.rs @@ -184,7 +184,7 @@ impl CpuFeatures { } /// Return a `cranelift_codegen::isa::Builder` configured with these CPU features. - pub fn isa_builder(&self) -> Result { + pub fn isa_builder(&self, target: Triple) -> Result { use SpecificFeature::*; use TargetCpu::*; @@ -192,8 +192,7 @@ impl CpuFeatures { cranelift_native::builder() .map_err(|_| format_err!("host machine is not a supported target")) } else { - isa::lookup(Triple::host()) - .map_err(|_| format_err!("host machine is not a supported target")) + isa::lookup(target).map_err(|_| format_err!("not a supported target")) } .context(LucetcErrorKind::Unsupported)?; diff --git a/lucetc/src/lib.rs b/lucetc/src/lib.rs old mode 100644 new mode 100755 index a37cf8c9c..968555ca2 --- a/lucetc/src/lib.rs +++ b/lucetc/src/lib.rs @@ -34,6 +34,7 @@ pub use lucet_validate::Validator; use signature::{PublicKey, SecretKey}; use std::env; use std::path::{Path, PathBuf}; +use target_lexicon::Triple; use tempfile; enum LucetcInput { @@ -44,6 +45,7 @@ enum LucetcInput { pub struct Lucetc { input: LucetcInput, bindings: Vec, + target: Triple, opt_level: OptLevel, cpu_features: CpuFeatures, heap: HeapSettings, @@ -70,6 +72,9 @@ pub trait LucetcOpts { fn bindings(&mut self, bindings: Bindings); fn with_bindings(self, bindings: Bindings) -> Self; + fn target(&mut self, target: Triple); + fn with_target(self, target: Triple) -> Self; + fn opt_level(&mut self, opt_level: OptLevel); fn with_opt_level(self, opt_level: OptLevel) -> Self; @@ -122,6 +127,15 @@ impl LucetcOpts for T { self } + fn target(&mut self, target: Triple) { + self.as_lucetc().target = target; + } + + fn with_target(mut self, target: Triple) -> Self { + self.target(target); + self + } + fn opt_level(&mut self, opt_level: OptLevel) { self.as_lucetc().opt_level = opt_level; } @@ -249,6 +263,7 @@ impl Lucetc { Self { input: LucetcInput::Path(input.to_owned()), bindings: vec![], + target: Triple::host(), opt_level: OptLevel::default(), cpu_features: CpuFeatures::default(), heap: HeapSettings::default(), @@ -267,6 +282,7 @@ impl Lucetc { Ok(Self { input: LucetcInput::Bytes(input), bindings: vec![], + target: Triple::host(), opt_level: OptLevel::default(), cpu_features: CpuFeatures::default(), heap: HeapSettings::default(), @@ -313,6 +329,7 @@ impl Lucetc { let compiler = Compiler::new( &module_contents, + self.target.clone(), self.opt_level, self.cpu_features.clone(), &bindings, @@ -331,6 +348,7 @@ impl Lucetc { let compiler = Compiler::new( &module_contents, + self.target.clone(), self.opt_level, self.cpu_features.clone(), &bindings, @@ -351,7 +369,7 @@ impl Lucetc { let dir = tempfile::Builder::new().prefix("lucetc").tempdir()?; let objpath = dir.path().join("tmp.o"); self.object_file(objpath.clone())?; - link_so(objpath, &output)?; + link_so(objpath, &self.target, &output)?; if self.sign { let sk = self.sk.as_ref().ok_or( format_err!("signing requires a secret key").context(LucetcErrorKind::Signature), @@ -364,13 +382,7 @@ impl Lucetc { const LD_DEFAULT: &str = "ld"; -#[cfg(not(target_os = "macos"))] -const LDFLAGS_DEFAULT: &str = "-shared"; - -#[cfg(target_os = "macos")] -const LDFLAGS_DEFAULT: &str = "-dylib -dead_strip -export_dynamic -undefined dynamic_lookup"; - -fn link_so(objpath: P, sopath: Q) -> Result<(), Error> +fn link_so(objpath: P, target: &Triple, sopath: Q) -> Result<(), Error> where P: AsRef, Q: AsRef, @@ -378,7 +390,7 @@ where use std::process::Command; let mut cmd_ld = Command::new(env::var("LD").unwrap_or(LD_DEFAULT.into())); cmd_ld.arg(objpath.as_ref()); - let env_ldflags = env::var("LDFLAGS").unwrap_or(LDFLAGS_DEFAULT.into()); + let env_ldflags = env::var("LDFLAGS").unwrap_or_else(|_| ldflags_default(target)); for flag in env_ldflags.split_whitespace() { cmd_ld.arg(flag); } @@ -398,3 +410,22 @@ where } Ok(()) } + +fn ldflags_default(target: &Triple) -> String { + use target_lexicon::OperatingSystem; + + match target.operating_system { + OperatingSystem::Linux => "-shared", + OperatingSystem::MacOSX { .. } => { + "-dylib -dead_strip -export_dynamic -undefined dynamic_lookup" + } + _ => panic!( + "Cannot determine default flags for {}. + +Please define the LDFLAGS environment variable with the necessary command-line +flags for generating shared libraries.", + Triple::host() + ), + } + .into() +} diff --git a/lucetc/tests/wasm.rs b/lucetc/tests/wasm.rs index 0ff68bdfa..39a592f31 100644 --- a/lucetc/tests/wasm.rs +++ b/lucetc/tests/wasm.rs @@ -41,6 +41,7 @@ mod module_data { use lucet_module::bindings::Bindings; use lucetc::{Compiler, CpuFeatures, HeapSettings, LucetcErrorKind, OptLevel}; use std::path::PathBuf; + use target_lexicon::Triple; #[test] fn exported_import() { @@ -49,6 +50,7 @@ mod module_data { let h = HeapSettings::default(); let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -77,6 +79,7 @@ mod module_data { let h = HeapSettings::default(); let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -101,6 +104,7 @@ mod module_data { let h = HeapSettings::default(); let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -126,6 +130,7 @@ mod module_data { let h = HeapSettings::default(); let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -149,6 +154,7 @@ mod module_data { let h = HeapSettings::default(); let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -175,6 +181,7 @@ mod module_data { let h = HeapSettings::default(); let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -210,6 +217,7 @@ mod module_data { let h = HeapSettings::default(); let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -255,6 +263,7 @@ mod module_data { let h = HeapSettings::default(); let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -289,6 +298,7 @@ mod module_data { let h = HeapSettings::default(); let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -337,6 +347,7 @@ mod module_data { let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -367,6 +378,7 @@ mod module_data { let h = HeapSettings::default(); let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -398,6 +410,7 @@ mod module_data { let h = HeapSettings::default(); let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -428,6 +441,7 @@ mod module_data { let h = HeapSettings::default(); let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -446,6 +460,7 @@ mod module_data { let h = HeapSettings::default(); let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -477,6 +492,7 @@ mod module_data { let h = HeapSettings::default(); let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -498,6 +514,7 @@ mod module_data { let h = HeapSettings::default(); let _c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -521,6 +538,7 @@ mod module_data { let h = HeapSettings::default(); let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -545,12 +563,14 @@ mod compile { // Tests for compilation completion use super::load_wat_module; use lucetc::{Compiler, CpuFeatures, HeapSettings, OptLevel}; + use target_lexicon::Triple; fn run_compile_test(file: &str) { let m = load_wat_module(file); let b = super::test_bindings(); let h = HeapSettings::default(); let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -595,6 +615,7 @@ mod validate { use super::load_wat_module; use lucet_validate::Validator; use lucetc::{Compiler, CpuFeatures, HeapSettings, OptLevel}; + use target_lexicon::Triple; #[test] fn validate_arith() { @@ -609,6 +630,7 @@ mod validate { let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -636,6 +658,7 @@ mod validate { let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -665,6 +688,7 @@ mod validate { let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -692,6 +716,7 @@ mod validate { let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -719,6 +744,7 @@ mod validate { let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -748,6 +774,7 @@ mod validate { let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, @@ -772,6 +799,7 @@ mod validate { let c = Compiler::new( &m, + Triple::host(), OptLevel::default(), CpuFeatures::default(), &b, From 0bd116dbaeb713b5b1ce54f3af5484d7eeb935ed Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Fri, 17 Jan 2020 14:34:55 -0800 Subject: [PATCH 509/512] [lucet-runtime] export the `KillSwitch` type from the public API It was already possible to use via the `Instance::kill_switch()` method, but couldn't be named in a type signature or a type declaration. --- .../lucet-runtime-internals/src/instance/execution.rs | 2 +- lucet-runtime/src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/execution.rs b/lucet-runtime/lucet-runtime-internals/src/instance/execution.rs index 26ee4310c..50891eafe 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/execution.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/execution.rs @@ -225,6 +225,7 @@ pub enum Domain { Terminated, } +/// An object that can be used to terminate an instance's execution from a separate thread. pub struct KillSwitch { state: Weak, } @@ -242,7 +243,6 @@ pub enum KillError { type KillResult = Result; -/// An object that can be used to terminate an instance's execution from a separate thread. impl KillSwitch { pub(crate) fn new(state: Weak) -> Self { KillSwitch { state } diff --git a/lucet-runtime/src/lib.rs b/lucet-runtime/src/lib.rs index 41fe41f2e..d10ce4e08 100644 --- a/lucet-runtime/src/lib.rs +++ b/lucet-runtime/src/lib.rs @@ -343,8 +343,8 @@ pub use lucet_module::{PublicKey, TrapCode}; pub use lucet_runtime_internals::alloc::Limits; pub use lucet_runtime_internals::error::Error; pub use lucet_runtime_internals::instance::{ - FaultDetails, Instance, InstanceHandle, KillError, KillSuccess, RunResult, SignalBehavior, - TerminationDetails, YieldedVal, + FaultDetails, Instance, InstanceHandle, KillError, KillSuccess, KillSwitch, RunResult, + SignalBehavior, TerminationDetails, YieldedVal, }; #[allow(deprecated)] pub use lucet_runtime_internals::lucet_hostcalls; From 628edf6669b19c0c946316212306c2410f01ebe8 Mon Sep 17 00:00:00 2001 From: "Tanya L. Crenshaw" <56939192+fst-crenshaw@users.noreply.github.com> Date: Tue, 21 Jan 2020 20:44:29 -0800 Subject: [PATCH 510/512] Fixes #357: Migrate from using the failure to thiserror + anyhow. (#374) Co-authored-by: Pat Hickey --- Cargo.lock | 855 +++++++++--------- lucet-module/Cargo.toml | 3 +- lucet-module/src/bindings.rs | 43 +- lucet-module/src/error.rs | 40 +- lucet-module/src/lib.rs | 2 +- lucet-runtime/Cargo.toml | 2 +- .../lucet-runtime-internals/Cargo.toml | 4 +- .../src/context/mod.rs | 9 +- .../lucet-runtime-internals/src/error.rs | 54 +- lucet-runtime/lucet-runtime-tests/Cargo.toml | 2 +- .../lucet-runtime-tests/src/build.rs | 2 +- .../lucet-runtime-tests/src/stack.rs | 2 +- lucet-runtime/tests/instruction_counting.rs | 3 +- lucet-spectest/Cargo.toml | 3 +- lucet-spectest/src/error.rs | 69 +- lucet-spectest/src/lib.rs | 96 +- lucet-spectest/src/main.rs | 5 +- lucet-spectest/src/result.rs | 14 +- lucet-spectest/src/script.rs | 64 +- lucet-validate/Cargo.toml | 2 +- lucet-validate/src/lib.rs | 24 +- lucet-validate/src/main.rs | 28 +- lucet-wasi-fuzz/Cargo.toml | 2 +- lucet-wasi-fuzz/src/main.rs | 2 +- lucet-wasi-sdk/Cargo.toml | 3 +- lucet-wasi-sdk/src/lib.rs | 30 +- lucet-wasi-sdk/tests/lucetc.rs | 2 +- lucet-wasi/Cargo.toml | 2 +- lucet-wasi/src/main.rs | 2 +- lucet-wasi/tests/test_helpers/mod.rs | 2 +- lucetc/Cargo.toml | 2 + lucetc/lucetc/main.rs | 33 +- lucetc/lucetc/options.rs | 2 +- lucetc/src/compiler.rs | 105 +-- lucetc/src/compiler/cpu_features.rs | 16 +- lucetc/src/decls.rs | 133 ++- lucetc/src/error.rs | 150 +-- lucetc/src/function_manifest.rs | 12 +- lucetc/src/lib.rs | 25 +- lucetc/src/load.rs | 10 +- lucetc/src/module.rs | 11 +- lucetc/src/output.rs | 44 +- lucetc/src/patch.rs | 8 +- lucetc/src/signature.rs | 49 +- lucetc/src/sparsedata.rs | 19 +- lucetc/src/stack_probe.rs | 15 +- lucetc/src/table.rs | 70 +- lucetc/src/traps.rs | 14 +- lucetc/src/types.rs | 10 +- lucetc/tests/wasm.rs | 16 +- 50 files changed, 1041 insertions(+), 1074 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b62e21560..37eeedd40 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,7 +10,7 @@ name = "aho-corasick" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -23,28 +23,16 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.23" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "approx" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "arrayvec" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "atty" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -53,14 +41,19 @@ name = "autocfg" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "autocfg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "backtrace" -version = "0.3.40" +version = "0.3.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -69,17 +62,14 @@ name = "backtrace-sys" version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "base64" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "bencher" @@ -96,12 +86,11 @@ dependencies = [ [[package]] name = "bincode" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -110,7 +99,7 @@ version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cexpr 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "clang-sys 0.28.1 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -118,9 +107,9 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "which 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -141,7 +130,7 @@ name = "block-buffer" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -149,7 +138,7 @@ dependencies = [ [[package]] name = "block-padding" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -157,13 +146,13 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -186,17 +175,20 @@ dependencies = [ [[package]] name = "cast" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "cc" -version = "1.0.46" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cexpr" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -207,23 +199,13 @@ name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "cgmath" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "clang-sys" version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -233,11 +215,11 @@ version = "2.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -254,26 +236,27 @@ name = "cmake" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "colored" -version = "1.8.0" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "core_affinity" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -282,7 +265,7 @@ name = "cpu-time" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -303,9 +286,9 @@ dependencies = [ "cranelift-codegen-shared 0.51.0", "cranelift-entity 0.51.0", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -336,7 +319,7 @@ dependencies = [ "cranelift-module 0.51.0", "faerie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "goblin 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -346,7 +329,7 @@ version = "0.51.0" dependencies = [ "cranelift-codegen 0.51.0", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -357,7 +340,7 @@ dependencies = [ "cranelift-codegen 0.51.0", "cranelift-entity 0.51.0", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -377,8 +360,8 @@ dependencies = [ "cranelift-entity 0.51.0", "cranelift-frontend 0.51.0", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.39.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -394,23 +377,23 @@ name = "criterion" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", - "tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", + "tinytemplate 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -418,45 +401,47 @@ name = "criterion-plot" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-deque" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-epoch" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-queue" -version = "0.1.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-utils" -version = "0.6.6" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -472,14 +457,14 @@ dependencies = [ [[package]] name = "csv" -version = "1.1.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "bstr 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -487,7 +472,7 @@ name = "csv-core" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -526,11 +511,11 @@ name = "env_logger" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -539,7 +524,7 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -549,7 +534,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -558,8 +543,8 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "goblin 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "scroll 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "string-interner 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -571,7 +556,7 @@ name = "failure" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.42 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -580,10 +565,10 @@ name = "failure_derive" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -593,23 +578,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "filetime" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "flate2" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "miniz_oxide 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -638,7 +623,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -664,7 +649,7 @@ dependencies = [ [[package]] name = "goblin" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -677,15 +662,15 @@ name = "heck" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-segmentation 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hermit-abi" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -707,7 +692,7 @@ name = "humantime" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -718,7 +703,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -726,15 +711,15 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "itertools" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -766,7 +751,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.65" +version = "0.2.66" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -774,7 +759,7 @@ name = "libloading" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -798,8 +783,8 @@ dependencies = [ "lucet-wasi-sdk 0.5.0", "lucetc 0.5.0", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -807,19 +792,20 @@ dependencies = [ name = "lucet-module" version = "0.5.0" dependencies = [ - "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.51.0", "derivative 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "minisign 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "object 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde-big-array 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -827,7 +813,7 @@ name = "lucet-objdump" version = "0.5.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "colored 1.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.5.0", ] @@ -836,11 +822,11 @@ dependencies = [ name = "lucet-runtime" version = "0.5.0" dependencies = [ + "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.5.0", "lucet-runtime-internals 0.5.0", "lucet-runtime-tests 0.5.0", @@ -848,8 +834,8 @@ dependencies = [ "lucetc 0.5.0", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -857,23 +843,23 @@ dependencies = [ name = "lucet-runtime-internals" version = "0.5.0" dependencies = [ - "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.5.0", "lucet-runtime-macros 0.5.0", - "memoffset 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -881,15 +867,15 @@ name = "lucet-runtime-macros" version = "0.5.0" dependencies = [ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucet-runtime-tests" version = "0.5.0" dependencies = [ - "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.5.0", "lucet-runtime-internals 0.5.0", @@ -902,15 +888,16 @@ dependencies = [ name = "lucet-spectest" version = "0.5.0" dependencies = [ + "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.5.0", "lucet-runtime 0.5.0", "lucetc 0.5.0", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -920,11 +907,11 @@ version = "0.5.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.51.0", - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-wasi-sdk 0.5.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.39.3 (registry+https://github.com/rust-lang/crates.io-index)", "witx 0.6.0", ] @@ -932,12 +919,12 @@ dependencies = [ name = "lucet-wasi" version = "0.5.0" dependencies = [ + "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", "bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.5.0", "lucet-runtime 0.5.0", "lucet-runtime-internals 0.5.0", @@ -953,21 +940,21 @@ dependencies = [ name = "lucet-wasi-fuzz" version = "0.5.0" dependencies = [ + "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.5.0", "lucet-runtime 0.5.0", "lucet-wasi 0.5.0", "lucet-wasi-sdk 0.5.0", "lucetc 0.5.0", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -976,20 +963,22 @@ dependencies = [ name = "lucet-wasi-sdk" version = "0.5.0" dependencies = [ - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.5.0", "lucet-validate 0.5.0", "lucetc 0.5.0", "target-lexicon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lucetc" version = "0.5.0" dependencies = [ + "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", "bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-codegen 0.51.0", @@ -1007,30 +996,31 @@ dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "lucet-module 0.5.0", "lucet-validate 0.5.0", - "memoffset 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "minisign 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasmonkey 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.39.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "memchr" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "memoffset" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1038,12 +1028,12 @@ dependencies = [ [[package]] name = "minisign" -version = "0.5.11" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rpassword 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rpassword 4.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "scrypt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1061,23 +1051,18 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "nom" version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1086,30 +1071,30 @@ name = "num" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-complex 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-rational 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-complex" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1117,63 +1102,55 @@ name = "num-derive" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-integer" -version = "0.1.41" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-iter" -version = "0.1.39" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-rational" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-traits" -version = "0.1.43" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num_cpus" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1181,7 +1158,7 @@ name = "object" version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.40.3 (registry+https://github.com/rust-lang/crates.io-index)", "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1199,8 +1176,8 @@ name = "packed_struct" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1257,8 +1234,8 @@ name = "precision" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1269,12 +1246,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro-error" -version = "0.2.6" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-error-attr 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustversion 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro-error-attr" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "rustversion 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "syn-mid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1287,7 +1278,7 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1298,12 +1289,12 @@ name = "progress" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "terminal_size 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "terminal_size 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quick-error" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1324,19 +1315,7 @@ name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1345,7 +1324,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1359,11 +1338,11 @@ dependencies = [ [[package]] name = "rand" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1437,7 +1416,7 @@ name = "rand_jitter" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1449,7 +1428,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1495,7 +1474,7 @@ version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1505,30 +1484,30 @@ version = "7.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon-core" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1546,13 +1525,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "regex" -version = "1.3.1" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1565,7 +1544,7 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.12" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1576,19 +1555,13 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rgb" -version = "0.8.14" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "rpassword" -version = "3.0.2" +version = "4.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1612,6 +1585,16 @@ dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustversion" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ryu" version = "1.0.2" @@ -1619,10 +1602,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "same-file" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1662,9 +1645,9 @@ name = "scroll_derive" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1676,7 +1659,7 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1694,10 +1677,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.102" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1705,33 +1688,33 @@ name = "serde-big-array" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.102" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.41" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "sha2" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1751,18 +1734,18 @@ version = "0.1.0" dependencies = [ "bencher 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "core_affinity 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", + "core_affinity 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "hwloc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "precision 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "printtable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1773,7 +1756,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallvec" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1781,7 +1764,7 @@ name = "string-interner" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1791,23 +1774,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "structopt" -version = "0.3.3" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "structopt-derive" -version = "0.3.3" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-error 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1837,14 +1821,24 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.7" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "syn-mid" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "synom" version = "0.11.3" @@ -1855,12 +1849,12 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1871,7 +1865,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1885,8 +1879,8 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1894,18 +1888,18 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.0.5" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "terminal_size" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1914,30 +1908,30 @@ name = "textwrap" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "thiserror" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "thiserror-impl 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror-impl 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "thiserror-impl" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "thread_local" -version = "0.3.6" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1945,19 +1939,19 @@ dependencies = [ [[package]] name = "tinytemplate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "toml" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1967,12 +1961,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-segmentation" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-width" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2015,9 +2009,9 @@ name = "wabt" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", "wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2026,7 +2020,7 @@ name = "wabt-sys" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2036,17 +2030,17 @@ name = "wait-timeout" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "walkdir" -version = "2.2.9" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2054,17 +2048,17 @@ name = "wasi-common" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "anyhow 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", + "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "cpu-time 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "wasi-common-cbindgen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "wig 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2077,7 +2071,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2090,16 +2084,16 @@ dependencies = [ "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", "siphasher 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmparser" -version = "0.39.2" +version = "0.39.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2115,7 +2109,7 @@ name = "which" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2123,7 +2117,7 @@ name = "wig" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "witx 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2154,7 +2148,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi-util" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2165,26 +2159,6 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "wincolor" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winconsole" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "winx" version = "0.7.0" @@ -2210,7 +2184,7 @@ name = "witx" version = "0.6.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "wast 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2223,47 +2197,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -"checksum anyhow 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)" = "6f1072d8f55592084072d2d3cb23a4b680a8543c00f10d446118e85ad3718142" -"checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94" -"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" -"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" +"checksum anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c" +"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" -"checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea" +"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +"checksum backtrace 0.3.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b4b1549d804b6c73f4817df2ba073709e96e426f12987127c48e6745568c350b" "checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" -"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" +"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" "checksum bencher 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdb4953a096c551ce9ace855a604d702e6e62d77fac690575ae347571717f5" "checksum bimap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "505e45beaf0a1462f5548fe885edf2d83e62022b2ce8b10fef0f7686b48c9266" -"checksum bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ab639324e3ee8774d296864fbc0dbbb256cf1a41c490b94cba90c082915f92" +"checksum bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf" "checksum bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebd71393f1ec0509b553aa012b9b58e81dadbdff7130bd3b8cba576e69b32f75" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -"checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" -"checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245" +"checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +"checksum bstr 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3ede750122d9d1f87919570cb2cccee38c84fbc8c5599b25c289af40625b7030" "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" -"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" -"checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c" -"checksum cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7fa24eb00d5ffab90eaeaf1092ac85c04c64aaf358ea6f84505b8116d24c6af" +"checksum cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0" +"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" +"checksum cexpr 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fce5b5fb86b0c57c20c834c1b412fd09c77c8a59b9473f86272709e78874cd1d" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c" "checksum clang-sys 0.28.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81de550971c976f176130da4b2978d3b524eaa0fd9ac31f3ceb5ae1231fb4853" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62" -"checksum colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cdb90b60f2927f8d76139c72dbde7e10c3a2bc47c8594c9c7a66529f2687c03" -"checksum core_affinity 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6d162c6e463c31dbf78fefa99d042156c1c74d404e299cfe3df2923cb857595b" +"checksum colored 1.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8815e2ab78f3a59928fc32e141fbeece88320a240e43f47b2fd64ea3a88a5b3d" +"checksum core_affinity 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "7f8a03115cc34fb0d7c321dd154a3914b3ca082ccc5c11d91bf7117dbbe7171f" "checksum cpu-time 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e9e393a7668fe1fad3075085b86c781883000b4ede868f43627b34a87c8b7ded" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "938703e165481c8d612ea3479ac8342e5615185db37765162e762ec3523e2fc6" "checksum criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eccdc6ce8bbe352ca89025bee672aa6d24f4eb8c53e3a8b5d1bc58011da072a2" -"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" -"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" -"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" -"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" +"checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca" +"checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac" +"checksum crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db" +"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" "checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" -"checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d" +"checksum csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "00affe7f6ab566df61b4be3ce8cf16bc2576bca0963ceb0955e45d514bf9a279" "checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" "checksum cvt 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34ac344c7efccb80cd25bc61b2170aec26f2f693fd40e765a539a1243db48c71" "checksum derivative 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "942ca430eef7a3806595a6737bc388bf51adb888d3fc0dd1b50f1c170167ee3a" @@ -2276,8 +2248,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" "checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" -"checksum filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd7380b54ced79dda72ecc35cc4fbbd1da6bba54afaa37e96fd1c2a308cd469" -"checksum flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ad3c5233c9a940c8719031b423d7e6c16af66e031cb0420b0896f5245bf181d3" +"checksum filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1ff6d4dab0aa0c8e6346d46052e93b13a16cf847b54ed357087c35011048cc7d" +"checksum flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd6d6f4752952feb71363cffc9ebac9411b75b87c6ab6058c40c8900cf43c0f" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" @@ -2285,39 +2257,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" "checksum goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "e3fa261d919c1ae9d1e4533c4a2f99e10938603c4208d56c05bec7a872b661b0" -"checksum goblin 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6040506480da04a63de51a478e8021892d65d8411f29b2a422c2648bdd8bcb" +"checksum goblin 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3081214398d39e4bd7f2c1975f0488ed04614ffdd976c6fc7a0708278552c0da" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" -"checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120" +"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" "checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" "checksum human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bec6e801ef7367625bd94ad7e2965e6027189f3e9deef422388d993af2814a0" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" "checksum hwloc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2934f84993b8b4bcae9b6a4e5f0aca638462dda9c7b4f26a570241494f21e0f4" -"checksum indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d7b3ea5827fcb9d4fda14bf4da5f136f0db2ae9c8f4bd4e2d1c6fde4e6db2" -"checksum itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "87fa75c9dea7b07be3138c49abbb83fd4bea199b5cdc76f9804458edc5da0d6e" +"checksum indexmap 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b54058f0a6ff80b6803da8faf8997cde53872b38f4023728f6830b06cd3c0dc" +"checksum itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum leb128 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" -"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" +"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" "checksum libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" -"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" -"checksum memoffset 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a85c1a8c329f11437034d7313dca647c79096523533a1c79e86f1d0f657c7cc" -"checksum minisign 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "185d3531e38475163c1652a0915ac612be3f2655756af43f10789d6145f527c2" +"checksum memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223" +"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" +"checksum minisign 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)" = "55d7baea44770d41993f63733f07df59ae36a02cb1968292f3f625b1d1dcb780" "checksum miniz_oxide 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6f3f74f726ae935c3f514300cc6773a0c9492abc5e972d42ba0c0ebb88757625" "checksum nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229" -"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" "checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" -"checksum num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf4825417e1e1406b3782a8ce92f4d53f26ec055e3622e1881ca8e9f5f9e08db" -"checksum num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fcb0cf31fb3ff77e6d2a6ebd6800df7fdcd106f2ad89113c9130bcd07f93dffc" +"checksum num 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" +"checksum num-complex 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" "checksum num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c8b15b261814f992e33760b1fca9fe8b693d8a65299f20c9901688636cfb746" -"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" -"checksum num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e" -"checksum num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2885278d5fe2adc2f75ced642d52d879bffaceb5a2e0b1d4309ffdfb239b454" -"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" -"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" -"checksum num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "155394f924cdddf08149da25bfb932d226b4a593ca7468b08191ff6335941af5" +"checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" +"checksum num-iter 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "dfb0800a0291891dd9f4fe7bd9c19384f98f7fbe0cd0f39a2c6b88b9868bbc00" +"checksum num-rational 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "da4dc79f9e6c81bef96148c8f6b8e72ad4541caa4a24373e900a36da07de03a3" +"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" +"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" "checksum object 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a411a7fd46b7ebc9849c80513c84280f41cbc3159f489cd77fb30ecefdd1218a" "checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" "checksum packed_struct 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "90caf80e74380d94f2aabc83edb900b49123b3132442fb147f9155c87a756281" @@ -2331,17 +2301,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" "checksum precision 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "83f0b3de90e9edd6382604f4f28509ce25272deb065b94045fc47abcde567d55" "checksum printtable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "69967dae4cac71681361899d9905d3d2985fc989d7afb32a8dff3aed5461ecdf" -"checksum proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aeccfe4d5d8ea175d5f0e4a2ad0637e0f4121d63bd99d356fb1f39ab2e7c6097" +"checksum proc-macro-error 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1b79a464461615532fcc8a6ed8296fa66cc12350c18460ab3f4594a6cee0fcb6" +"checksum proc-macro-error-attr 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "23832e5eae6bac56bbac190500eef1aaede63776b5cd131eaa4ee7fe120cd892" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" +"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" "checksum progress 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b820305721858696053a7fd0215cfeeee16ecaaf96b7a209945428e02f1c44" -"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" +"checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" +"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" @@ -2358,21 +2328,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e18c91676f670f6f0312764c759405f13afb98d5d73819840cf72a518487bff" "checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d" "checksum raw-cpuid 7.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4a349ca83373cfa5d6dbb66fd76e58b2cca08da71a5f6400de0a0a6a9bceeaf" -"checksum rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83a27732a533a1be0a0035a111fe76db89ad312f6f0347004c220c57f209a123" -"checksum rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b" +"checksum rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098" +"checksum rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" -"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" +"checksum regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b5508c1941e4e7cb19965abef075d35a9a8b5cdf0846f30b4050e9b55dc55e87" "checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9" -"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" +"checksum regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e734e891f5b408a29efbf8309e656876276f49ab6a6ac208600b4419bd893d90" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" -"checksum rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2089e4031214d129e201f8c3c8c2fe97cd7322478a0d1cdf78e7029b0042efdb" -"checksum rpassword 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34fa7bcae7fca3c8471e8417088bbc3ad9af8066b0ecf4f3c0d98a0d772716e" +"checksum rpassword 4.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "99371657d3c8e4d816fb6221db98fa408242b0b53bac08f8676a41f8554fe99f" "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum rustversion 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a0538bd897e17257b0128d2fd95c2ed6df939374073a36166051a79e2eb7986" "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" -"checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" +"checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" "checksum scroll 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "abb2332cb595d33f7edd5700f4cbf94892e680c7f0ae56adab58a35190b66cb1" "checksum scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f84d114ef17fd144153d608fba7c446b0145d038985e7a8cc5d08bb0ce20383" @@ -2381,38 +2351,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum scrypt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "656c79d0e90d0ab28ac86bf3c3d10bfbbac91450d3f190113b4e76d9fec3cfdd" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4b39bd9b0b087684013a792c59e3e07a46a01d2322518d8a1104641a0b1be0" +"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" "checksum serde-big-array 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "883eee5198ea51720eab8be52a36cf6c0164ac90eea0ed95b649d5e35382404e" -"checksum serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "ca13fc1a832f793322228923fbb3aba9f3f44444898f835d31ad1b74fa0a2bf8" -"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2" -"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" +"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" +"checksum serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)" = "48c575e0cc52bdd09b47f330f646cf59afc586e9c4e3ccd6fc1f625b8ea1dad7" +"checksum sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "27044adfd2e1f077f649f59deb9490d3941d674002f7d062870a60ebe9bd47a0" "checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" "checksum siphasher 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "83da420ee8d1a89e640d0948c646c1c088758d3a3c538f943bfa97bdac17929d" -"checksum smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecf3b85f68e8abaa7555aa5abdb1153079387e60b718283d732f03897fcfc86" +"checksum smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44e59e0c9fa00817912ae6e4e6e3c4fe04455e75699d06eedc7d85917ed8e8f4" "checksum string-interner 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd710eadff449a1531351b0e43eb81ea404336fa2f56c777427ab0e32a4cf183" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum structopt 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4f66a4c0ddf7aee4677995697366de0749b0139057342eccbb609b12d0affc" -"checksum structopt-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8fe0c13e476b4e21ff7f5c4ace3818b6d7bdc16897c31c73862471bc1663acae" +"checksum structopt 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "df136b42d76b1fbea72e2ab3057343977b04b4a2e00836c3c7c0673829572713" +"checksum structopt-derive 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd50a87d2f7b8958055f3e73a963d78feaccca3836767a9069844e34b5b03c0a" "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -"checksum syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7bedb3320d0f3035594b0b723c8a28d7d336a3eda3881db79e61d676fb644c" +"checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5" +"checksum syn-mid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd3937748a7eccff61ba5b90af1a20dbf610858923a9192ea0ecb0cb77db1d0" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" -"checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203" +"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" "checksum target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7975cb2c6f37d77b190bc5004a2bb015971464756fde9514651a525ada2a741a" "checksum target-lexicon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6f4c118a7a38378f305a9e111fcb2f7f838c0be324bfb31a77ea04f7f6e684b4" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" -"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" -"checksum terminal_size 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "023345d35850b69849741bd9a5432aa35290e3d8eb76af8717026f270d1cf133" +"checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" +"checksum terminal_size 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "e25a60e3024df9029a414be05f46318a77c22538861a22170077d0388c0e926e" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -"checksum thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "cc6b305ec0e323c7b6cfff6098a22516e0063d0bb7c3d88660a890217dca099a" -"checksum thiserror-impl 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45ba8d810d9c48fc456b7ad54574e8bfb7c7918a57ad7a6e6a0985d7959e8597" -"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" -"checksum tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4574b75faccaacddb9b284faecdf0b544b80b6b294f3d062d325c5726a209c20" -"checksum toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01d1404644c8b12b16bfcffa4322403a91a451584daaaa7c28d3152e6cbc98cf" +"checksum thiserror 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6f357d1814b33bc2dc221243f8424104bfe72dbe911d5b71b3816a2dff1c977e" +"checksum thiserror-impl 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2e25d25307eb8436894f727aba8f65d07adf02e5b35a13cebed48bd282bfef" +"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +"checksum tinytemplate 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "57a3c6667d3e65eb1bc3aed6fd14011c6cbc3a0665218ab7f5daf040b9ec371a" +"checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" "checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" -"checksum unicode-segmentation 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49f5526225fd8b77342d5986ab5f6055552e9c0776193b5b63fd53b46debfad7" -"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" +"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" +"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" @@ -2423,11 +2394,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3c5c5c1286c6e578416982609f47594265f9d489f9b836157d403ad605a46693" "checksum wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af5d153dc96aad7dc13ab90835b892c69867948112d95299e522d370c4e13a08" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" -"checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" +"checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" "checksum wasi-common 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2a703d47961a9c2bf1dbeec7612446692dd8b380839c3d05f7211f72919c96df" "checksum wasi-common-cbindgen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ecab99a12e72a7442e5a9ecfc819f42520e1e0122cf06c0ba64c6a0b6b5263ce" "checksum wasmonkey 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "af7c4bc80224427965ba21d87982cfc07d12e859824f303272056fb19f571ef9" -"checksum wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5083b449454f7de0b15f131eee17de54b5a71dcb9adcf11df2b2f78fad0cd82" +"checksum wasmparser 0.39.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c702914acda5feeeffbc29e4d953e5b9ce79d8b98da4dbf18a77086e116c5470" "checksum wast 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "233648f540f07fce9b972436f2fbcae8a750c1121b6d32d949e1a44b4d9fc7b1" "checksum which 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5475d47078209a02e60614f7ba5e645ef3ed60f771920ac1906d7c1cc65024c8" "checksum wig 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3856dfac1bfc00633ac5b3b9b65c9c56cb5014b27ca6dfdae17bb8177a8c19" @@ -2435,10 +2406,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" +"checksum winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" -"checksum winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef84b96d10db72dd980056666d7f1e7663ce93d82fa33b63e71c966f4cf5032" "checksum winx 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c95125d6dc28a246c02340956929f4e67ac4c06c589b87de076d0dc0ad421b91" "checksum witx 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f88e293d72e3bd74cc452f9c3e934958f075252324ea24bf40cc16f1f068a3d" "checksum xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da90eac47bf1d7871b75004b9b631d107df15f37669383b23f0b5297bc7516b6" diff --git a/lucet-module/Cargo.toml b/lucet-module/Cargo.toml index 8ab4d8c7d..41736ec14 100644 --- a/lucet-module/Cargo.toml +++ b/lucet-module/Cargo.toml @@ -10,8 +10,8 @@ authors = ["Lucet team "] edition = "2018" [dependencies] +anyhow = "1.0" cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.51.0" } -failure = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" bincode = "1.1.4" @@ -21,5 +21,6 @@ minisign = "0.5.11" object = "0.14.0" byteorder = "1.3" memoffset = "0.5.1" +thiserror = "1.0.4" serde-big-array = "0.2.0" derivative = "1.0.3" diff --git a/lucet-module/src/bindings.rs b/lucet-module/src/bindings.rs index b9bd99800..aa5106b6d 100644 --- a/lucet-module/src/bindings.rs +++ b/lucet-module/src/bindings.rs @@ -1,4 +1,4 @@ -use failure::{format_err, Error}; +use crate::Error; use serde_json::{self, Map, Value}; use std::collections::{hash_map::Entry, HashMap}; use std::fs; @@ -27,7 +27,7 @@ impl Bindings { pub fn from_json(v: &Value) -> Result { match v.as_object() { Some(modules) => Self::parse_modules_json_obj(modules), - None => Err(format_err!("top level json expected to be object"))?, + None => Err(Error::ParseJsonObjError)?, } } @@ -53,12 +53,11 @@ impl Bindings { } Entry::Occupied(e) => { if binding != e.get() { - Err(format_err!( - "cannot re-bind {} from {} to {}", - e.key(), - binding, - e.get() - ))?; + Err(Error::RebindError { + key: e.key().to_owned(), + binding: binding.to_owned(), + attempt: e.get().to_owned(), + })?; } } } @@ -76,13 +75,15 @@ impl Bindings { match self.bindings.get(module) { Some(m) => match m.get(symbol) { Some(s) => Ok(s), - None => Err(format_err!("Unknown symbol `{}::{}`", module, symbol)), + None => Err(Error::UnknownSymbol { + module: module.to_owned(), + symbol: symbol.to_owned(), + }), }, - None => Err(format_err!( - "Unknown module for symbol `{}::{}`", - module, - symbol - )), + None => Err(Error::UnknownModule { + module: module.to_owned(), + symbol: symbol.to_owned(), + }), } } @@ -94,7 +95,12 @@ impl Bindings { let methodmap = Self::parse_methods_json_obj(methods)?; res.insert(modulename.to_owned(), methodmap); } - None => Err(format_err!(""))?, + None => { + Err(Error::ParseError { + key: modulename.to_owned(), + value: values.to_string(), + })?; + } } } Ok(Self::new(res)) @@ -107,7 +113,12 @@ impl Bindings { Some(importbinding) => { res.insert(method.to_owned(), importbinding.to_owned()); } - None => Err(format_err!(""))?, + None => { + Err(Error::ParseError { + key: method.to_owned(), + value: i.to_string(), + })?; + } } } Ok(res) diff --git a/lucet-module/src/error.rs b/lucet-module/src/error.rs index 311459392..e9e062bbf 100644 --- a/lucet-module/src/error.rs +++ b/lucet-module/src/error.rs @@ -1,16 +1,34 @@ -use failure::Fail; +use thiserror::Error; /// Module data (de)serialization errors. -#[derive(Debug, Fail)] +#[derive(Debug, Error)] pub enum Error { - #[fail(display = "Sparse data contained a page with length other than 4096")] + #[error("Deserialization error")] + DeserializationError(#[source] bincode::Error), + #[error("I/O error")] + IOError(#[source] std::io::Error), + #[error("Sparse data contained a page with length other than 4096")] IncorrectPageSize, - #[fail(display = "Deserialization error: {}", _0)] - DeserializationError(#[cause] bincode::Error), - #[fail(display = "Serialization error: {}", _0)] - SerializationError(#[cause] bincode::Error), - #[fail(display = "Module signature error: {}", _0)] - ModuleSignatureError(#[cause] minisign::PError), - #[fail(display = "I/O error: {}", _0)] - IOError(#[cause] std::io::Error), + #[error("Module signature error")] + ModuleSignatureError(#[source] minisign::PError), + #[error("Parse error at {key}::{value:?}")] + ParseError { key: String, value: String }, + #[error("Parse json error")] + ParseJsonError(#[from] serde_json::error::Error), + #[error("Top-level json must be an object")] + ParseJsonObjError, + #[error("Parse string error")] + ParseStringError(#[from] std::io::Error), + #[error("Cannot re-bind {key} from {binding} to {attempt}")] + RebindError { + key: String, + binding: String, + attempt: String, + }, + #[error("Serialization error")] + SerializationError(#[source] bincode::Error), + #[error("Unknown module for symbol `{module}::{symbol}")] + UnknownModule { module: String, symbol: String }, + #[error("Unknown symbol `{module}::{symbol}`")] + UnknownSymbol { module: String, symbol: String }, } diff --git a/lucet-module/src/lib.rs b/lucet-module/src/lib.rs index f53344bc2..83a6e988d 100644 --- a/lucet-module/src/lib.rs +++ b/lucet-module/src/lib.rs @@ -6,7 +6,7 @@ #![deny(bare_trait_objects)] pub mod bindings; -mod error; +pub mod error; mod functions; mod globals; mod linear_memory; diff --git a/lucet-runtime/Cargo.toml b/lucet-runtime/Cargo.toml index b965b22fd..c6aad54f7 100644 --- a/lucet-runtime/Cargo.toml +++ b/lucet-runtime/Cargo.toml @@ -18,7 +18,6 @@ num-derive = "0.3.0" [dev-dependencies] byteorder = "1.2" -failure = "0.1" lazy_static = "1.1" lucetc = { path = "../lucetc", version = "0.5.0" } lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.5.0" } @@ -26,6 +25,7 @@ lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.5.0" } nix = "0.15" rayon = "1.0" tempfile = "3.0" +anyhow = "1" [build-dependencies] # only used for tests diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index a39ac4460..83b1e86f2 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -13,10 +13,10 @@ edition = "2018" lucet-module = { path = "../../lucet-module", version = "0.5.0" } lucet-runtime-macros = { path = "../lucet-runtime-macros", version = "0.5.0" } +anyhow = "1.0" bitflags = "1.0" bincode = "1.1.4" byteorder = "1.3" -failure = "0.1" lazy_static = "1.1" libc = "0.2.65" libloading = "0.5" @@ -24,8 +24,8 @@ memoffset = "0.5.1" nix = "0.15" num-derive = "0.3.0" num-traits = "0.2" -xfailure = "0.1" raw-cpuid = "6.0.0" +thiserror = "1.0.4" # This is only a dependency to ensure that other crates don't pick a newer version as a transitive # dependency. `0.1.3 < getrandom <= 0.1.6` cause `lazy_static` to pull in spinlock implementations diff --git a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs index b89b945c3..d76c94ea0 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs @@ -5,13 +5,12 @@ mod tests; use crate::instance::Instance; use crate::val::{val_to_reg, val_to_stack, RegVal, UntypedRetVal, Val}; -use failure::Fail; use nix; use nix::sys::signal; use std::arch::x86_64::{__m128, _mm_setzero_ps}; use std::ptr::NonNull; use std::{mem, ptr}; -use xfailure::xbail; +use thiserror::Error; /// Callee-saved general-purpose registers in the AMD64 ABI. /// @@ -394,7 +393,7 @@ impl Context { args: &[Val], ) -> Result<(), Error> { if !stack_is_aligned(stack) { - xbail!(Error::UnalignedStack); + return Err(Error::UnalignedStack); } if backstop_callback != Context::default_backstop_callback { @@ -687,10 +686,10 @@ impl Context { } /// Errors that may arise when working with contexts. -#[derive(Debug, Fail)] +#[derive(Debug, Error)] pub enum Error { /// Raised when the bottom of the stack provided to `Context::init` is not 16-byte aligned - #[fail(display = "context initialized with unaligned stack")] + #[error("context initialized with unaligned stack")] UnalignedStack, } diff --git a/lucet-runtime/lucet-runtime-internals/src/error.rs b/lucet-runtime/lucet-runtime-internals/src/error.rs index 9bd927a0f..0e9e44afb 100644 --- a/lucet-runtime/lucet-runtime-internals/src/error.rs +++ b/lucet-runtime/lucet-runtime-internals/src/error.rs @@ -1,40 +1,40 @@ use crate::instance::{FaultDetails, TerminationDetails}; -use failure::Fail; +use thiserror::Error; /// Lucet runtime errors. -#[derive(Debug, Fail)] +#[derive(Debug, Error)] pub enum Error { - #[fail(display = "Invalid argument: {}", _0)] + #[error("Invalid argument: {0}")] InvalidArgument(&'static str), /// A [`Region`](trait.Region.html) cannot currently accommodate additional instances. - #[fail(display = "Region capacity reached: {} instances", _0)] + #[error("Region capacity reached: {0} instances")] RegionFull(usize), /// A module error occurred. - #[fail(display = "Module error: {}", _0)] + #[error("Module error: {0}")] ModuleError(ModuleError), /// A method call or module specification would exceed an instance's /// [`Limit`s](struct.Limits.html). - #[fail(display = "Instance limits exceeded: {}", _0)] + #[error("Instance limits exceeded: {0}")] LimitsExceeded(String), /// A method call attempted to modify linear memory for an instance that /// does not have linear memory - #[fail(display = "No linear memory available: {}", _0)] + #[error("No linear memory available: {0}")] NoLinearMemory(String), /// An attempt to look up a WebAssembly function by its symbol name failed. - #[fail(display = "Symbol not found: {}", _0)] + #[error("Symbol not found: {0}")] SymbolNotFound(String), /// An attempt to look up a WebAssembly function by its table index failed. - #[fail(display = "Function not found: (table {}, func {})", _0, _1)] + #[error("Function not found: (table {0}, func {1}")] FuncNotFound(u32, u32), /// An instance aborted due to a runtime fault. - #[fail(display = "Runtime fault: {:?}", _0)] + #[error("Runtime fault: {0:?}")] RuntimeFault(FaultDetails), /// An instance terminated, potentially with extra information about the termination. @@ -42,40 +42,34 @@ pub enum Error { /// This condition can arise from a hostcall explicitly calling /// [`Vmctx::terminate()`](vmctx/struct.Vmctx.html#method.terminate), or via a custom signal handler /// that returns [`SignalBehavior::Terminate`](enum.SignalBehavior.html#variant.Terminate). - #[fail(display = "Runtime terminated")] + #[error("Runtime terminated")] RuntimeTerminated(TerminationDetails), /// IO errors arising during dynamic loading with [`DlModule`](struct.DlModule.html). - #[fail(display = "Dynamic loading error: {}", _0)] - DlError(#[cause] std::io::Error), + #[error("Dynamic loading error: {0}")] + DlError(#[from] std::io::Error), - #[fail(display = "Instance not returned")] + #[error("Instance not returned")] InstanceNotReturned, - #[fail(display = "Instance not yielded")] + #[error("Instance not yielded")] InstanceNotYielded, - #[fail(display = "Start function yielded")] + #[error("Start function yielded")] StartYielded, /// A catch-all for internal errors that are likely unrecoverable by the runtime user. /// /// As the API matures, these will likely become rarer, replaced by new variants of this enum, /// or by panics for truly unrecoverable situations. - #[fail(display = "Internal error: {}", _0)] - InternalError(#[cause] failure::Error), + #[error("Internal error")] + InternalError(#[source] anyhow::Error), /// An unsupported feature was used. - #[fail(display = "Unsupported feature: {}", _0)] + #[error("Unsupported feature: {0}")] Unsupported(String), } -impl From for Error { - fn from(e: failure::Error) -> Error { - Error::InternalError(e) - } -} - impl From for Error { fn from(e: crate::context::Error) -> Error { Error::InternalError(e.into()) @@ -101,15 +95,15 @@ impl From for Error { } /// Lucet module errors. -#[derive(Debug, Fail)] +#[derive(Debug, Error)] pub enum ModuleError { /// An error was found in the definition of a Lucet module. - #[fail(display = "Incorrect module definition: {}", _0)] + #[error("Incorrect module definition: {0}")] IncorrectModule(String), /// An error occurred with the module data section, likely during deserialization. - #[fail(display = "Module data error: {}", _0)] - ModuleDataError(#[cause] lucet_module::Error), + #[error("Module data error: {0}")] + ModuleDataError(#[from] lucet_module::Error), } #[macro_export] @@ -138,7 +132,7 @@ macro_rules! lucet_ensure { #[macro_export] macro_rules! lucet_format_err { - ($($arg:tt)*) => { $crate::error::Error::InternalError(failure::format_err!($($arg)*)) } + ($($arg:tt)*) => { $crate::error::Error::InternalError(anyhow::format_err!($($arg)*)) } } #[macro_export] diff --git a/lucet-runtime/lucet-runtime-tests/Cargo.toml b/lucet-runtime/lucet-runtime-tests/Cargo.toml index 5525e74be..70293f38a 100644 --- a/lucet-runtime/lucet-runtime-tests/Cargo.toml +++ b/lucet-runtime/lucet-runtime-tests/Cargo.toml @@ -15,7 +15,7 @@ edition = "2018" test = false [dependencies] -failure = "0.1" +anyhow = "1" lazy_static = "1.1" tempfile = "3.0" lucet-module = { path = "../../lucet-module", version = "0.5.0" } diff --git a/lucet-runtime/lucet-runtime-tests/src/build.rs b/lucet-runtime/lucet-runtime-tests/src/build.rs index ad00f2c68..6a22fc21d 100644 --- a/lucet-runtime/lucet-runtime-tests/src/build.rs +++ b/lucet-runtime/lucet-runtime-tests/src/build.rs @@ -1,4 +1,4 @@ -use failure::Error; +use anyhow::Error; use lucet_module::bindings::Bindings; use lucet_runtime_internals::module::DlModule; use lucet_wasi_sdk::{CompileOpts, Link, LinkOpt, LinkOpts}; diff --git a/lucet-runtime/lucet-runtime-tests/src/stack.rs b/lucet-runtime/lucet-runtime-tests/src/stack.rs index 976866ab6..b9062476d 100644 --- a/lucet-runtime/lucet-runtime-tests/src/stack.rs +++ b/lucet-runtime/lucet-runtime-tests/src/stack.rs @@ -1,4 +1,4 @@ -use failure::Error; +use anyhow::Error; use lucet_runtime_internals::module::DlModule; use lucetc::Lucetc; use std::sync::Arc; diff --git a/lucet-runtime/tests/instruction_counting.rs b/lucet-runtime/tests/instruction_counting.rs index fd1bf8862..9230e4618 100644 --- a/lucet-runtime/tests/instruction_counting.rs +++ b/lucet-runtime/tests/instruction_counting.rs @@ -1,4 +1,5 @@ -use lucet_runtime::{DlModule, Error, Limits, MmapRegion, Region, RunResult}; +use anyhow::Error; +use lucet_runtime::{DlModule, Limits, MmapRegion, Region, RunResult}; use lucetc::{Lucetc, LucetcOpts}; use rayon::prelude::*; use std::fs::DirEntry; diff --git a/lucet-spectest/Cargo.toml b/lucet-spectest/Cargo.toml index cced16189..8403d2776 100644 --- a/lucet-spectest/Cargo.toml +++ b/lucet-spectest/Cargo.toml @@ -17,13 +17,14 @@ name = "spec-test" path = "src/main.rs" [dependencies] +anyhow = "1" lucetc = { path = "../lucetc", version = "0.5.0" } lucet-module = { path = "../lucet-module", version = "0.5.0" } lucet-runtime = { path = "../lucet-runtime", version = "0.5.0" } wabt = "0.9.2" serde = "1.0" serde_json = "1.0" -failure = "0.1" clap="2.32" tempfile = "3.0" target-lexicon = "0.9" +thiserror = "1.0.4" diff --git a/lucet-spectest/src/error.rs b/lucet-spectest/src/error.rs index e9ced68c5..f0da58470 100644 --- a/lucet-spectest/src/error.rs +++ b/lucet-spectest/src/error.rs @@ -1,56 +1,21 @@ -use failure::{Backtrace, Context, Fail}; -use std::fmt::{self, Display}; +use thiserror::Error; -#[derive(Debug)] -pub struct SpecTestError { - inner: Context, -} - -impl From> for SpecTestError { - fn from(inner: Context) -> SpecTestError { - SpecTestError { inner } - } -} - -impl From for SpecTestError { - fn from(kind: SpecTestErrorKind) -> SpecTestError { - SpecTestError { - inner: Context::new(kind), - } - } -} - -impl SpecTestError { - pub fn get_context(&self) -> &SpecTestErrorKind { - self.inner.get_context() - } -} - -impl Fail for SpecTestError { - fn cause(&self) -> Option<&dyn Fail> { - self.inner.cause() - } - fn backtrace(&self) -> Option<&Backtrace> { - self.inner.backtrace() - } -} - -impl Display for SpecTestError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Display::fmt(&self.inner, f) - } -} - -#[derive(Fail, Debug, PartialEq, Eq)] -pub enum SpecTestErrorKind { - #[fail(display = "Unsupported command")] - UnsupportedCommand, - #[fail(display = "Unexpected success")] +#[derive(Debug, Error)] +pub enum Error { + #[error("Parse error")] + ParseError(#[from] wabt::script::Error), + #[error("Read error")] + ReadError(#[from] std::io::Error), + #[error("Run failed with {0} failures")] + RunError(usize), + #[error("Unsupported command: {0}")] + UnsupportedCommand(String), + #[error("Unexpected success")] UnexpectedSuccess, - #[fail(display = "Unexpected failure")] - UnexpectedFailure, - #[fail(display = "Incorrect result")] - IncorrectResult, - #[fail(display = "Unsupported by lucetc")] + #[error("Unexpected failure: {0}")] + UnexpectedFailure(String), + #[error("Incorrect result: {0}")] + IncorrectResult(String), + #[error("Unsupported by lucetc")] UnsupportedLucetc, } diff --git a/lucet-spectest/src/lib.rs b/lucet-spectest/src/lib.rs index c32d74983..362b393ed 100644 --- a/lucet-spectest/src/lib.rs +++ b/lucet-spectest/src/lib.rs @@ -3,14 +3,13 @@ pub mod error; pub mod script; -pub use crate::error::{SpecTestError, SpecTestErrorKind}; +pub use crate::error::Error; pub use crate::result::{command_description, SpecScriptResult}; mod bindings; mod result; use crate::script::{ScriptEnv, ScriptError}; -use failure::{format_err, Error, ResultExt}; use lucet_runtime::{Error as RuntimeError, TrapCode, UntypedRetVal, Val}; use std::fs; use std::path::PathBuf; @@ -26,8 +25,8 @@ pub fn run_spec_test(spec_path: &PathBuf) -> Result { while let Some(ref cmd) = parser.next()? { match step(&mut script, &cmd.kind) { Ok(()) => res.pass(cmd), - Err(e) => match e.get_context() { - SpecTestErrorKind::UnsupportedCommand | SpecTestErrorKind::UnsupportedLucetc => { + Err(e) => match e { + Error::UnsupportedCommand(_) | Error::UnsupportedLucetc => { println!("skipped unsupported command"); res.skip(cmd, e) } @@ -42,19 +41,15 @@ pub fn run_spec_test(spec_path: &PathBuf) -> Result { Ok(res) } -fn unexpected_failure(e: ScriptError) -> SpecTestError { +fn unexpected_failure(e: ScriptError) -> Error { if e.unsupported() { - Error::from(e) - .context(SpecTestErrorKind::UnsupportedLucetc) - .into() + Error::UnsupportedLucetc } else { - Error::from(e) - .context(SpecTestErrorKind::UnexpectedFailure) - .into() + Error::UnexpectedFailure(e.to_string()) } } -fn step(script: &mut ScriptEnv, cmd: &CommandKind) -> Result<(), SpecTestError> { +fn step(script: &mut ScriptEnv, cmd: &CommandKind) -> Result<(), Error> { match cmd { CommandKind::Module { ref module, @@ -75,7 +70,7 @@ fn step(script: &mut ScriptEnv, cmd: &CommandKind) -> Result<(), SpecTestError> Err(ScriptError::ValidationError(_)) => Ok(()), Ok(_) => { script.delete_last(); - Err(SpecTestErrorKind::UnexpectedSuccess)? + Err(Error::UnexpectedSuccess)? } Err(e) => Err(unexpected_failure(e))?, } @@ -86,7 +81,7 @@ fn step(script: &mut ScriptEnv, cmd: &CommandKind) -> Result<(), SpecTestError> let module = module.clone().into_vec(); match script.instantiate(&module, &None) { Err(ScriptError::ValidationError(_)) => Ok(()), - Ok(_) => Err(SpecTestErrorKind::UnexpectedSuccess)?, + Ok(_) => Err(Error::UnexpectedSuccess)?, Err(e) => Err(unexpected_failure(e))?, } } @@ -96,7 +91,7 @@ fn step(script: &mut ScriptEnv, cmd: &CommandKind) -> Result<(), SpecTestError> let module = module.clone().into_vec(); match script.instantiate(&module, &None) { Err(ScriptError::InstantiateError(_)) => Ok(()), - Ok(_) => Err(SpecTestErrorKind::UnexpectedSuccess)?, + Ok(_) => Err(Error::UnexpectedSuccess)?, Err(e) => Err(unexpected_failure(e))?, } } @@ -106,7 +101,7 @@ fn step(script: &mut ScriptEnv, cmd: &CommandKind) -> Result<(), SpecTestError> let module = module.clone().into_vec(); match script.instantiate(&module, &None) { Err(ScriptError::ValidationError(_)) => Ok(()), - Ok(_) => Err(SpecTestErrorKind::UnexpectedSuccess)?, + Ok(_) => Err(Error::UnexpectedSuccess)?, Err(e) => Err(unexpected_failure(e))?, } } @@ -133,7 +128,10 @@ fn step(script: &mut ScriptEnv, cmd: &CommandKind) -> Result<(), SpecTestError> .map_err(unexpected_failure)?; Ok(()) } - _ => Err(SpecTestErrorKind::UnsupportedCommand)?, + _ => { + let message = format!("invoke {:?}", action); + Err(Error::UnsupportedCommand(message))? + } }, // TODO: verify the exhaustion message is what we expected @@ -150,23 +148,26 @@ fn step(script: &mut ScriptEnv, cmd: &CommandKind) -> Result<(), SpecTestError> let args = translate_args(args); let res = script.run(module, field, args); match res { - Ok(_) => Err(SpecTestErrorKind::UnexpectedSuccess)?, + Ok(_) => Err(Error::UnexpectedSuccess)?, Err(ScriptError::RuntimeError(RuntimeError::RuntimeFault(details))) => { match details.trapcode { Some(TrapCode::StackOverflow) => Ok(()), - e => Err(format_err!( - "AssertExhaustion expects stack overflow, got {:?}", - e - ) - .context(SpecTestErrorKind::UnexpectedFailure))?, + e => { + let message = + format!("AssertExhaustion expects stack overflow, got {:?}", e); + Err(Error::UnexpectedFailure(message))? + } } } Err(e) => Err(unexpected_failure(e))?, } } - _ => Err(SpecTestErrorKind::UnsupportedCommand)?, + _ => { + let message = format!("invoke {:?}", action); + Err(Error::UnsupportedCommand(message))? + } }, CommandKind::AssertReturn { @@ -189,8 +190,7 @@ fn step(script: &mut ScriptEnv, cmd: &CommandKind) -> Result<(), SpecTestError> check_retval(expected, res)?; Ok(()) } - _ => Err(format_err!("non-invoke action")) - .context(SpecTestErrorKind::UnsupportedCommand)?, + _ => Err(Error::UnsupportedCommand("non-invoke action".to_owned()))?, }, CommandKind::AssertReturnCanonicalNan { action } | CommandKind::AssertReturnArithmeticNan { action } => match action { @@ -207,12 +207,11 @@ fn step(script: &mut ScriptEnv, cmd: &CommandKind) -> Result<(), SpecTestError> if res.as_f32().is_nan() || res.as_f64().is_nan() { Ok(()) } else { - Err(format_err!("expected NaN, got {}", res)) - .context(SpecTestErrorKind::IncorrectResult)? + let message = format!("expected NaN, got {}", res); + Err(Error::IncorrectResult(message))? } } - _ => Err(format_err!("non-invoke action")) - .context(SpecTestErrorKind::UnsupportedCommand)?, + _ => Err(Error::UnsupportedCommand("non-invoke action".to_owned()))?, }, CommandKind::AssertTrap { ref action, .. } => match action { Action::Invoke { @@ -226,49 +225,54 @@ fn step(script: &mut ScriptEnv, cmd: &CommandKind) -> Result<(), SpecTestError> match res { Err(ScriptError::RuntimeError(_luceterror)) => Ok(()), Err(e) => Err(unexpected_failure(e)), - Ok(_) => Err(SpecTestErrorKind::UnexpectedSuccess)?, + Ok(_) => Err(Error::UnexpectedSuccess)?, } } - _ => Err(SpecTestErrorKind::UnsupportedCommand)?, + _ => { + let message = format!("invoke {:?}", action); + Err(Error::UnsupportedCommand(message))? + } }, } } -fn check_retval(expected: &[Value], got: UntypedRetVal) -> Result<(), SpecTestError> { +fn check_retval(expected: &[Value], got: UntypedRetVal) -> Result<(), Error> { match expected.len() { 0 => {} 1 => match expected[0] { Value::I32(expected) => { if expected != got.as_i32() { - Err(format_err!("expected {}, got {}", expected, got.as_i32())) - .context(SpecTestErrorKind::IncorrectResult)? + let message = format!("expected {}, got {}", expected, got.as_i32()); + Err(Error::IncorrectResult(message))? } } Value::I64(expected) => { if expected != got.as_i64() { - Err(format_err!("expected {}, got {}", expected, got.as_i64())) - .context(SpecTestErrorKind::IncorrectResult)? + let message = format!("expected {}, got {}", expected, got.as_i64()); + Err(Error::IncorrectResult(message))? } } Value::F32(expected) => { if expected != got.as_f32() && !expected.is_nan() && !got.as_f32().is_nan() { - Err(format_err!("expected {}, got {}", expected, got.as_f32())) - .context(SpecTestErrorKind::IncorrectResult)? + let message = format!("expected {}, got {}", expected, got.as_f32()); + Err(Error::IncorrectResult(message))? } } Value::F64(expected) => { if expected != got.as_f64() && !expected.is_nan() && !got.as_f64().is_nan() { - Err(format_err!("expected {}, got {}", expected, got.as_f64())) - .context(SpecTestErrorKind::IncorrectResult)? + let message = format!("expected {}, got {}", expected, got.as_f64()); + Err(Error::IncorrectResult(message))? } } - Value::V128(_) => { - Err(format_err!("got unsupported SIMD V128 value")) - .context(SpecTestErrorKind::UnsupportedCommand)?; + Value::V128(v) => { + let message = format!("got unsupported SIMD V128 value: {}", v); + Err(Error::UnsupportedCommand(message))?; } }, - n => Err(format_err!("{} expected return values not supported", n)) - .context(SpecTestErrorKind::UnsupportedCommand)?, + n => { + let message = format!("{} expected return values not supported", n); + Err(Error::UnsupportedCommand(message))? + } } Ok(()) } diff --git a/lucet-spectest/src/main.rs b/lucet-spectest/src/main.rs index 3dffa542f..aaa99bff3 100644 --- a/lucet-spectest/src/main.rs +++ b/lucet-spectest/src/main.rs @@ -2,8 +2,7 @@ extern crate clap; use clap::Arg; -use failure::{format_err, Error}; -use lucet_spectest; +use lucet_spectest::Error; use std::path::PathBuf; fn main() -> Result<(), Error> { @@ -22,7 +21,7 @@ fn main() -> Result<(), Error> { run.report(); if run.failed().len() > 0 { - Err(format_err!("{} failures", run.failed().len())) + Err(Error::RunError(run.failed().len())) } else { Ok(()) } diff --git a/lucet-spectest/src/result.rs b/lucet-spectest/src/result.rs index 9cf418c4a..f35d2470c 100644 --- a/lucet-spectest/src/result.rs +++ b/lucet-spectest/src/result.rs @@ -1,10 +1,10 @@ -use crate::error::SpecTestError; +use crate::error::Error; use wabt::script::{Command, CommandKind}; pub struct SpecScriptResult { pass: Vec, - skip: Vec<(Command, SpecTestError)>, - fail: Vec<(Command, SpecTestError)>, + skip: Vec<(Command, Error)>, + fail: Vec<(Command, Error)>, } impl SpecScriptResult { @@ -20,11 +20,11 @@ impl SpecScriptResult { self.pass.push(command.clone()) } - pub fn skip(&mut self, command: &Command, reason: SpecTestError) { + pub fn skip(&mut self, command: &Command, reason: Error) { self.skip.push((command.clone(), reason)) } - pub fn fail(&mut self, command: &Command, reason: SpecTestError) { + pub fn fail(&mut self, command: &Command, reason: Error) { self.fail.push((command.clone(), reason)) } @@ -32,11 +32,11 @@ impl SpecScriptResult { &self.pass } - pub fn skipped(&self) -> &[(Command, SpecTestError)] { + pub fn skipped(&self) -> &[(Command, Error)] { &self.skip } - pub fn failed(&self) -> &[(Command, SpecTestError)] { + pub fn failed(&self) -> &[(Command, Error)] { &self.fail } diff --git a/lucet-spectest/src/script.rs b/lucet-spectest/src/script.rs index de4493f97..a7b783de3 100644 --- a/lucet-spectest/src/script.rs +++ b/lucet-spectest/src/script.rs @@ -1,32 +1,34 @@ use crate::bindings; -use failure::{format_err, Error, Fail}; use lucet_runtime::{self, MmapRegion, Module as LucetModule, Region, UntypedRetVal, Val}; -use lucetc::{Compiler, CpuFeatures, HeapSettings, LucetcError, LucetcErrorKind, OptLevel}; +use lucetc::{Compiler, CpuFeatures, Error as LucetcError, HeapSettings, OptLevel}; use std::io; use std::process::Command; use std::sync::Arc; use target_lexicon::Triple; +use thiserror::Error; -#[derive(Fail, Debug)] +#[derive(Debug, Error)] pub enum ScriptError { - #[fail(display = "Validation error: {}", _0)] - ValidationError(LucetcError), - #[fail(display = "Program creation error: {}", _0)] - ProgramError(LucetcError), - #[fail(display = "Compilation error: {}", _0)] - CompileError(LucetcError), - #[fail(display = "Codegen error: {}", _0)] - CodegenError(Error), - #[fail(display = "Load error: {}", _0)] - LoadError(lucet_runtime::Error), - #[fail(display = "Instaitiation error: {}", _0)] - InstantiateError(lucet_runtime::Error), - #[fail(display = "Runtime error: {}", _0)] - RuntimeError(lucet_runtime::Error), - #[fail(display = "Malformed script: {}", _0)] + #[error("Validation error")] + ValidationError(#[source] LucetcError), + #[error("Program error")] + ProgramError(#[source] LucetcError), + #[error("Compilation error")] + CompileError(#[source] LucetcError), + #[error("Codegen error")] + CodegenError(#[source] LucetcError), + #[error("Load error")] + LoadError(#[source] lucet_runtime::Error), + #[error("Instantiation error")] + InstantiateError(#[source] lucet_runtime::Error), + #[error("Runtime error")] + RuntimeError(#[source] lucet_runtime::Error), + #[error("Malformed script: {0}")] MalformedScript(String), - #[fail(display = "IO error: {}", _0)] - IoError(io::Error), + #[error("IO error")] + IoError(#[from] io::Error), + #[error("run_ld error: {0}")] + LdError(String), } impl ScriptError { @@ -34,8 +36,8 @@ impl ScriptError { match self { ScriptError::ProgramError(ref lucetc_err) | ScriptError::ValidationError(ref lucetc_err) - | ScriptError::CompileError(ref lucetc_err) => match lucetc_err.get_context() { - &LucetcErrorKind::Unsupported => true, + | ScriptError::CompileError(ref lucetc_err) => match lucetc_err { + &LucetcError::Unsupported(_) => true, _ => false, }, _ => false, @@ -43,19 +45,13 @@ impl ScriptError { } } -impl From for ScriptError { - fn from(e: io::Error) -> ScriptError { - ScriptError::IoError(e) - } -} - pub struct ScriptEnv { instances: Vec<(Option, lucet_runtime::InstanceHandle)>, } fn program_error(e: LucetcError) -> ScriptError { - match e.get_context() { - LucetcErrorKind::Validation => ScriptError::ValidationError(e), + match e { + LucetcError::WasmValidation(_) => ScriptError::ValidationError(e), _ => ScriptError::ProgramError(e), } } @@ -97,11 +93,13 @@ impl ScriptEnv { cmd_ld.arg(sofile_path.clone()); let run_ld = cmd_ld.output()?; if !run_ld.status.success() { - Err(ScriptError::CodegenError(format_err!( + let message = format!( "ld {:?}: {}", objfile_path, String::from_utf8_lossy(&run_ld.stderr) - )))?; + ); + + Err(ScriptError::LdError(message))?; } let lucet_module: Arc = @@ -171,7 +169,7 @@ impl ScriptEnv { let (_, ref mut inst) = self.instance_named_mut(name)?; inst.run(field, &args) .and_then(|rr| rr.returned()) - .map_err(|e| ScriptError::RuntimeError(e)) + .map_err(ScriptError::RuntimeError) } pub fn register(&mut self, name: &Option, as_name: &str) -> Result<(), ScriptError> { diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index dfc98bd4f..83d69903e 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -18,9 +18,9 @@ path = "src/main.rs" [dependencies] clap = "2" -failure = "0.1" witx = { path = "../wasi/tools/witx", version = "0.6.0" } cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.51.0" } +thiserror = "1.0.4" wasmparser = "0.39.1" [dev-dependencies] diff --git a/lucet-validate/src/lib.rs b/lucet-validate/src/lib.rs index e32b7fcbe..03412fc69 100644 --- a/lucet-validate/src/lib.rs +++ b/lucet-validate/src/lib.rs @@ -1,9 +1,9 @@ mod moduletype; mod types; -use failure::Fail; use std::path::Path; use std::rc::Rc; +use thiserror::Error; use wasmparser; use witx::{self, Id, Module}; @@ -11,32 +11,26 @@ pub use self::moduletype::ModuleType; pub use self::types::{FuncSignature, ImportFunc}; pub use witx::{AtomType, Document, WitxError}; -#[derive(Debug, Fail)] +#[derive(Debug, Error)] pub enum Error { - #[fail(display = "WebAssembly validation error at offset {}: {}", _1, 0)] + #[error("WebAssembly validation error at offset {1}: {0}")] WasmValidation(&'static str, usize), - #[fail(display = "Unsupported: {}", _0)] + #[error("Unsupported: {0}")] Unsupported(String), - #[fail(display = "Module not found: {}", _0)] + #[error("Module not found: {0}")] ModuleNotFound(String), - #[fail(display = "Import not found: {}::{}", module, field)] + #[error("Import not found: {module}::{field}")] ImportNotFound { module: String, field: String }, - #[fail(display = "Export not found: {}", field)] + #[error("Export not found: {field}")] ExportNotFound { field: String }, - #[fail( - display = "Import type error: for {}::{}, expected {:?}, got {:?}", - module, field, expected, got - )] + #[error("Import type error: for {module}::{field}, expected {expected:?}, got {got:?}")] ImportTypeError { module: String, field: String, expected: FuncSignature, got: FuncSignature, }, - #[fail( - display = "Export type error: for {}, expected {:?}, got {:?}", - field, expected, got - )] + #[error("Export type error: for {field}, expected {expected:?}, got {got:?}")] ExportTypeError { field: String, expected: FuncSignature, diff --git a/lucet-validate/src/main.rs b/lucet-validate/src/main.rs index 9f14a05c1..634e573df 100644 --- a/lucet-validate/src/main.rs +++ b/lucet-validate/src/main.rs @@ -1,12 +1,12 @@ #[macro_use] extern crate clap; use clap::Arg; -use failure::Fail; use lucet_validate::{self, Validator}; use std::fs::File; use std::io::{self, Read}; use std::path::{Path, PathBuf}; use std::process; +use thiserror::Error; use witx; pub fn main() { @@ -87,24 +87,12 @@ fn run(module_path: &Path, witx_path: &Path, wasi_exe: bool) -> Result<(), Error Ok(()) } -#[derive(Debug, Fail)] +#[derive(Debug, Error)] enum Error { - #[fail(display = "{}", _0)] - Witx(#[cause] witx::WitxError), - #[fail(display = "With file {:?}: {}", _0, _1)] - Io(PathBuf, #[cause] io::Error), - #[fail(display = "{}", _0)] - Validate(#[cause] lucet_validate::Error), -} - -impl From for Error { - fn from(e: witx::WitxError) -> Error { - Error::Witx(e) - } -} - -impl From for Error { - fn from(e: lucet_validate::Error) -> Error { - Error::Validate(e) - } + #[error("Witx error")] + Witx(#[from] witx::WitxError), + #[error("With file {0:?}: {1}")] + Io(PathBuf, #[source] io::Error), + #[error("Validate error")] + Validate(#[from] lucet_validate::Error), } diff --git a/lucet-wasi-fuzz/Cargo.toml b/lucet-wasi-fuzz/Cargo.toml index cd7aeb35a..1156ff7eb 100644 --- a/lucet-wasi-fuzz/Cargo.toml +++ b/lucet-wasi-fuzz/Cargo.toml @@ -10,8 +10,8 @@ authors = ["Lucet team "] edition = "2018" [dependencies] +anyhow = "1" clap = "2.32" -failure = "0.1" libc = "0.2.65" lucetc = { path = "../lucetc" } lucet-runtime = { path = "../lucet-runtime" } diff --git a/lucet-wasi-fuzz/src/main.rs b/lucet-wasi-fuzz/src/main.rs index 0b2fdfaee..1613e37df 100644 --- a/lucet-wasi-fuzz/src/main.rs +++ b/lucet-wasi-fuzz/src/main.rs @@ -1,6 +1,6 @@ #![deny(bare_trait_objects)] -use failure::{bail, format_err, Error}; +use anyhow::{bail, format_err, Error}; use libc::c_ulong; use lucet_module::bindings::Bindings; use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region}; diff --git a/lucet-wasi-sdk/Cargo.toml b/lucet-wasi-sdk/Cargo.toml index b056bb041..db0a26ace 100644 --- a/lucet-wasi-sdk/Cargo.toml +++ b/lucet-wasi-sdk/Cargo.toml @@ -10,11 +10,12 @@ authors = ["Lucet team "] edition = "2018" [dependencies] -failure = "0.1" +anyhow = "1" lucetc = { path = "../lucetc", version = "0.5.0" } lucet-module = { path = "../lucet-module", version = "0.5.0" } target-lexicon = "0.9" tempfile = "3.0" +thiserror = "1.0.4" [dev-dependencies] lucet-validate = { path = "../lucet-validate", version = "0.5.0" } diff --git a/lucet-wasi-sdk/src/lib.rs b/lucet-wasi-sdk/src/lib.rs index 612e43bd7..685580f29 100644 --- a/lucet-wasi-sdk/src/lib.rs +++ b/lucet-wasi-sdk/src/lib.rs @@ -1,36 +1,24 @@ #![deny(bare_trait_objects)] -use failure::{Error, Fail}; use std::env; use std::io::Write; use std::path::{Path, PathBuf}; use std::process::{Command, Output}; use tempfile::TempDir; +use thiserror::Error; const WASI_TARGET: &str = "wasm32-unknown-wasi"; -#[derive(Debug, Fail)] +#[derive(Debug, Error)] pub enum CompileError { - #[fail(display = "File not found: {}", _0)] + #[error("File not found: {0}")] FileNotFound(String), - #[fail(display = "Clang reported error: {}", _0)] + #[error("Clang reported error: {stdout}")] Execution { stdout: String, stderr: String }, - #[fail(display = "Lucetc error: {}", _0)] - Lucetc { - #[cause] - e: Error, - }, - #[fail(display = "IO error: {}", _0)] - IO { - #[cause] - e: std::io::Error, - }, -} - -impl From for CompileError { - fn from(e: std::io::Error) -> CompileError { - CompileError::IO { e } - } + #[error("Lucetc error")] + Lucetc(#[from] lucetc::Error), + #[error("IO error")] + IO(#[from] std::io::Error), } impl CompileError { @@ -358,7 +346,7 @@ impl Lucetc { self.link.link(&self.wasm_file)?; self.lucetc .shared_object_file(output.as_ref()) - .map_err(|e| CompileError::Lucetc { e })?; + .map_err(CompileError::Lucetc)?; Ok(self.tmpdir.close()?) } } diff --git a/lucet-wasi-sdk/tests/lucetc.rs b/lucet-wasi-sdk/tests/lucetc.rs index 5106d7e73..e880ad0d4 100644 --- a/lucet-wasi-sdk/tests/lucetc.rs +++ b/lucet-wasi-sdk/tests/lucetc.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod lucetc_tests { - use failure::Error; + use anyhow::Error; use lucet_module::bindings::Bindings; use lucet_validate::Validator; use lucet_wasi_sdk::*; diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index 07bcbb385..1284b8a1b 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -24,9 +24,9 @@ edition = "2018" update-bindings = ["bindgen"] [dependencies] +anyhow = "1" cast = "0.2" clap = "2.23" -failure = "0.1" human-size = "0.4" lucet-runtime = { path = "../lucet-runtime", version = "0.5.0" } lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.5.0" } diff --git a/lucet-wasi/src/main.rs b/lucet-wasi/src/main.rs index 175b62ade..953aa53ec 100644 --- a/lucet-wasi/src/main.rs +++ b/lucet-wasi/src/main.rs @@ -3,8 +3,8 @@ #[macro_use] extern crate clap; +use anyhow::{format_err, Error}; use clap::Arg; -use failure::{format_err, Error}; use lucet_runtime::{self, DlModule, Limits, MmapRegion, Module, PublicKey, Region, RunResult}; use lucet_wasi::{self, WasiCtxBuilder, __wasi_exitcode_t}; use std::fs::File; diff --git a/lucet-wasi/tests/test_helpers/mod.rs b/lucet-wasi/tests/test_helpers/mod.rs index f209ab4b2..8ff4dc0e4 100644 --- a/lucet-wasi/tests/test_helpers/mod.rs +++ b/lucet-wasi/tests/test_helpers/mod.rs @@ -1,4 +1,4 @@ -use failure::{bail, Error}; +use anyhow::{bail, Error}; use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region}; use lucet_wasi::{self, WasiCtx, WasiCtxBuilder, __wasi_exitcode_t}; use lucet_wasi_sdk::{CompileOpts, Link}; diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index 3f680a1e9..68327ca46 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -14,6 +14,7 @@ name = "lucetc" path = "lucetc/main.rs" [dependencies] +anyhow = "1" bincode = "1.1.4" cranelift-codegen = { path = "../cranelift/cranelift-codegen", version = "0.51.0" } cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.51.0" } @@ -45,6 +46,7 @@ minisign = "0.5.11" memoffset = "0.5.1" serde = "1.0" serde_json = "1.0" +thiserror = "1.0.4" raw-cpuid = "6.0.0" [package.metadata.deb] diff --git a/lucetc/lucetc/main.rs b/lucetc/lucetc/main.rs index e1a0df525..1dee241b7 100644 --- a/lucetc/lucetc/main.rs +++ b/lucetc/lucetc/main.rs @@ -4,7 +4,7 @@ mod options; extern crate clap; use crate::options::{CodegenOutput, ErrorStyle, Options}; -use failure::{format_err, Error, ResultExt}; +use anyhow::{format_err, Error}; use log::info; use lucet_module::bindings::Bindings; use lucet_validate::Validator; @@ -25,15 +25,19 @@ pub struct SerializedLucetcError { impl From for SerializedLucetcError { fn from(e: Error) -> Self { SerializedLucetcError { - error: if let Some(cause) = e.as_fail().cause() { - format!("{}: {}", e, cause) - } else { - format!("{}", e) - }, + error: format!("{}", e), } } } +#[derive(Debug, thiserror::Error)] +enum BindingError { + #[error("adding bindings from {1}")] + ExtendError(#[source] lucet_module::error::Error, String), + #[error("bindings file {1}")] + FileError(#[source] lucet_module::error::Error, String), +} + fn main() { env_logger::init(); @@ -43,9 +47,6 @@ fn main() { match opts.error_style { ErrorStyle::Human => { eprintln!("Error: {}\n", err); - if let Some(cause) = err.as_fail().cause() { - eprintln!("{}", cause); - } } ErrorStyle::Json => { let errs: Vec = vec![err.into()]; @@ -73,11 +74,15 @@ pub fn run(opts: &Options) -> Result<(), Error> { let mut bindings = Bindings::empty(); for file in opts.binding_files.iter() { - let file_bindings = - Bindings::from_file(file).context(format!("bindings file {:?}", file))?; - bindings - .extend(&file_bindings) - .context(format!("adding bindings from {:?}", file))?; + let file_bindings = Bindings::from_file(file).map_err(|source| { + let file = format!("{:?}", file); + BindingError::FileError(source, file) + })?; + + bindings.extend(&file_bindings).map_err(|source| { + let file = format!("{:?}", file); + BindingError::ExtendError(source, file) + })?; } let mut c = Lucetc::new(PathBuf::from(input)) diff --git a/lucetc/lucetc/options.rs b/lucetc/lucetc/options.rs index 8ba375a88..eb1bc2c4e 100644 --- a/lucetc/lucetc/options.rs +++ b/lucetc/lucetc/options.rs @@ -1,5 +1,5 @@ +use anyhow::Error; use clap::{Arg, ArgMatches, Values}; -use failure::Error; use lucetc::{CpuFeatures, HeapSettings, OptLevel, SpecificFeature, TargetCpu}; use std::path::PathBuf; use std::str::FromStr; diff --git a/lucetc/src/compiler.rs b/lucetc/src/compiler.rs index 500e4ee56..43b374df7 100644 --- a/lucetc/src/compiler.rs +++ b/lucetc/src/compiler.rs @@ -2,7 +2,7 @@ mod cpu_features; pub use self::cpu_features::{CpuFeatures, SpecificFeature, TargetCpu}; use crate::decls::ModuleDecls; -use crate::error::{LucetcError, LucetcErrorKind}; +use crate::error::Error; use crate::function::FuncInfo; use crate::heap::HeapSettings; use crate::module::ModuleInfo; @@ -19,7 +19,6 @@ use cranelift_codegen::{ use cranelift_faerie::{FaerieBackend, FaerieBuilder, FaerieTrapCollection}; use cranelift_module::{Backend as ClifBackend, Module as ClifModule}; use cranelift_wasm::{translate_module, FuncTranslator, ModuleTranslationState, WasmError}; -use failure::{format_err, Fail, ResultExt}; use lucet_module::bindings::Bindings; use lucet_module::{FunctionSpec, ModuleData, ModuleFeatures, MODULE_DATA_SYM}; use lucet_validate::Validator; @@ -68,38 +67,32 @@ impl<'a> Compiler<'a> { heap_settings: HeapSettings, count_instructions: bool, validator: &Option, - ) -> Result { + ) -> Result { let isa = Self::target_isa(target.clone(), opt_level, &cpu_features)?; let frontend_config = isa.frontend_config(); let mut module_info = ModuleInfo::new(frontend_config.clone()); if let Some(v) = validator { - v.validate(wasm_binary) - .context(LucetcErrorKind::Validation)?; + v.validate(wasm_binary).map_err(Error::LucetValidation)?; } else { // As of cranelift-wasm 0.43 which uses wasmparser 0.39.1, the parser used inside // cranelift-wasm does not validate. We need to run the validating parser on the binary // first. The InvalidWebAssembly error below will never trigger. - wasmparser::validate(wasm_binary, None) - .map_err(|e| { - format_err!( - "invalid WebAssembly module, at offset {}: {}", - e.offset, - e.message - ) - }) - .context(LucetcErrorKind::Validation)?; + wasmparser::validate(wasm_binary, None).map_err(Error::WasmValidation)?; } let module_translation_state = translate_module(wasm_binary, &mut module_info).map_err(|e| match e { - WasmError::User(_) => e.context(LucetcErrorKind::Input), - WasmError::InvalidWebAssembly { .. } => e.context(LucetcErrorKind::Validation), // This will trigger once cranelift-wasm upgrades to a validating wasm parser. - WasmError::Unsupported { .. } => e.context(LucetcErrorKind::Unsupported), - WasmError::ImplLimitExceeded { .. } => { - e.context(LucetcErrorKind::TranslatingModule) + WasmError::User(u) => Error::Input(u.to_string()), + WasmError::InvalidWebAssembly { .. } => { + // Since wasmparser was already used to validate, + // reaching this case means there's a significant + // bug in either wasmparser or cranelift-wasm. + unreachable!(); } + WasmError::Unsupported(s) => Error::Unsupported(s.to_owned()), + WasmError::ImplLimitExceeded { .. } => Error::ClifWasmError(e), })?; let libcalls = Box::new(move |libcall| match libcall { @@ -107,15 +100,12 @@ impl<'a> Compiler<'a> { _ => (cranelift_module::default_libcall_names())(libcall), }); - let mut clif_module: ClifModule = ClifModule::new( - FaerieBuilder::new( - isa, - "lucet_guest".to_owned(), - FaerieTrapCollection::Enabled, - libcalls, - ) - .context(LucetcErrorKind::Validation)?, - ); + let mut clif_module: ClifModule = ClifModule::new(FaerieBuilder::new( + isa, + "lucet_guest".to_owned(), + FaerieTrapCollection::Enabled, + libcalls, + )?); let runtime = Runtime::lucet(frontend_config); let decls = ModuleDecls::new( @@ -142,11 +132,11 @@ impl<'a> Compiler<'a> { (&self.cpu_features).into() } - pub fn module_data(&self) -> Result, LucetcError> { + pub fn module_data(&self) -> Result, Error> { self.decls.get_module_data(self.module_features()) } - pub fn object_file(mut self) -> Result { + pub fn object_file(mut self) -> Result { let mut func_translator = FuncTranslator::new(); for (ref func, (code, code_offset)) in self.decls.function_bodies() { @@ -163,21 +153,22 @@ impl<'a> Compiler<'a> { &mut clif_context.func, &mut func_info, ) - .map_err(|e| format_err!("in {}: {:?}", func.name.symbol(), e)) - .context(LucetcErrorKind::FunctionTranslation)?; - + .map_err(|source| Error::FunctionTranslation { + symbol: func.name.symbol().to_string(), + source, + })?; self.clif_module .define_function(func.name.as_funcid().unwrap(), &mut clif_context) - .map_err(|e| format_err!("in {}: {:?}", func.name.symbol(), e)) - .context(LucetcErrorKind::FunctionDefinition)?; + .map_err(|source| Error::FunctionDefinition { + symbol: func.name.symbol().to_string(), + source, + })?; } stack_probe::declare_metadata(&mut self.decls, &mut self.clif_module).unwrap(); - let module_data_bytes = self - .module_data()? - .serialize() - .context(LucetcErrorKind::ModuleData)?; + let module_data_bytes = self.module_data()?.serialize()?; + let module_data_len = module_data_bytes.len(); write_module_data(&mut self.clif_module, module_data_bytes)?; @@ -205,12 +196,12 @@ impl<'a> Compiler<'a> { module_data_len, function_manifest, table_names, - ) - .context(LucetcErrorKind::Output)?; + )?; + Ok(obj) } - pub fn cranelift_funcs(self) -> Result { + pub fn cranelift_funcs(self) -> Result { use std::collections::HashMap; let mut funcs = HashMap::new(); @@ -230,8 +221,10 @@ impl<'a> Compiler<'a> { &mut clif_context.func, &mut func_info, ) - .map_err(|e| format_err!("in {}: {:?}", func.name.symbol(), e)) - .context(LucetcErrorKind::FunctionTranslation)?; + .map_err(|source| Error::FunctionTranslation { + symbol: func.name.symbol().to_string(), + source, + })?; funcs.insert(func.name.clone(), clif_context.func); } @@ -245,7 +238,7 @@ impl<'a> Compiler<'a> { target: Triple, opt_level: OptLevel, cpu_features: &CpuFeatures, - ) -> Result, LucetcError> { + ) -> Result, Error> { let mut flags_builder = settings::builder(); let isa_builder = cpu_features.isa_builder(target)?; flags_builder.enable("enable_verifier").unwrap(); @@ -258,7 +251,7 @@ impl<'a> Compiler<'a> { fn write_module_data( clif_module: &mut ClifModule, module_data_bytes: Vec, -) -> Result<(), LucetcError> { +) -> Result<(), Error> { use cranelift_module::{DataContext, Linkage}; let mut module_data_ctx = DataContext::new(); @@ -266,10 +259,10 @@ fn write_module_data( let module_data_decl = clif_module .declare_data(MODULE_DATA_SYM, Linkage::Local, true, None) - .context(LucetcErrorKind::ModuleData)?; + .map_err(Error::ClifModuleError)?; clif_module .define_data(module_data_decl, &module_data_ctx) - .context(LucetcErrorKind::ModuleData)?; + .map_err(Error::ClifModuleError)?; Ok(()) } @@ -277,29 +270,25 @@ fn write_module_data( fn write_startfunc_data( clif_module: &mut ClifModule, decls: &ModuleDecls<'_>, -) -> Result<(), LucetcError> { +) -> Result<(), Error> { use cranelift_module::{DataContext, Linkage}; - let error_kind = LucetcErrorKind::MetadataSerializer; - if let Some(func_ix) = decls.get_start_func() { let name = clif_module .declare_data("guest_start", Linkage::Export, false, None) - .context(error_kind.clone())?; + .map_err(Error::MetadataSerializer)?; let mut ctx = DataContext::new(); ctx.define_zeroinit(8); let start_func = decls .get_func(func_ix) .expect("start func is valid func id"); - let fid = start_func - .name - .as_funcid() - .ok_or(format_err!("start index pointed to a non-function")) - .context(error_kind.clone())?; + let fid = start_func.name.as_funcid().expect("start func is a func"); let fref = clif_module.declare_func_in_data(fid, &mut ctx); ctx.write_function_addr(0, fref); - clif_module.define_data(name, &ctx).context(error_kind)?; + clif_module + .define_data(name, &ctx) + .map_err(Error::MetadataSerializer)?; } Ok(()) } diff --git a/lucetc/src/compiler/cpu_features.rs b/lucetc/src/compiler/cpu_features.rs index 589e50348..4e7b8fcb1 100644 --- a/lucetc/src/compiler/cpu_features.rs +++ b/lucetc/src/compiler/cpu_features.rs @@ -1,6 +1,5 @@ -use crate::error::{LucetcError, LucetcErrorKind}; +use crate::error::Error; use cranelift_codegen::{isa, settings::Configurable}; -use failure::{format_err, ResultExt}; use lucet_module::ModuleFeatures; use std::collections::{HashMap, HashSet}; use target_lexicon::Triple; @@ -184,17 +183,18 @@ impl CpuFeatures { } /// Return a `cranelift_codegen::isa::Builder` configured with these CPU features. - pub fn isa_builder(&self, target: Triple) -> Result { + + pub fn isa_builder(&self, target: Triple) -> Result { use SpecificFeature::*; use TargetCpu::*; let mut isa_builder = if let Native = self.cpu { - cranelift_native::builder() - .map_err(|_| format_err!("host machine is not a supported target")) + cranelift_native::builder().map_err(|_| { + Error::Unsupported("host machine is not a supported target".to_string()) + }) } else { - isa::lookup(target).map_err(|_| format_err!("not a supported target")) - } - .context(LucetcErrorKind::Unsupported)?; + isa::lookup(Triple::host()).map_err(Error::UnsupportedIsa) + }?; let mut specific_features = self.specific_features.clone(); diff --git a/lucetc/src/decls.rs b/lucetc/src/decls.rs index 7e3744a58..b2c6525fc 100644 --- a/lucetc/src/decls.rs +++ b/lucetc/src/decls.rs @@ -1,4 +1,4 @@ -use crate::error::{LucetcError, LucetcErrorKind}; +use crate::error::Error; use crate::heap::HeapSettings; pub use crate::module::{Exportable, TableElems}; use crate::module::{ModuleInfo, UniqueFuncIndex}; @@ -14,7 +14,6 @@ use cranelift_wasm::{ Global, GlobalIndex, GlobalInit, MemoryIndex, ModuleEnvironment, SignatureIndex, Table, TableIndex, }; -use failure::{format_err, Error, ResultExt}; use lucet_module::bindings::Bindings; use lucet_module::ModuleFeatures; use lucet_module::{ @@ -84,7 +83,7 @@ impl<'a> ModuleDecls<'a> { bindings: &'a Bindings, runtime: Runtime, heap_settings: HeapSettings, - ) -> Result { + ) -> Result { let imports: Vec> = Vec::with_capacity(info.imported_funcs.len()); let (tables_list_name, table_names) = Self::declare_tables(&info, clif_module)?; let globals_spec = Self::build_globals_spec(&info)?; @@ -113,7 +112,7 @@ impl<'a> ModuleDecls<'a> { decls: &mut ModuleDecls<'a>, clif_module: &mut ClifModule, bindings: &'a Bindings, - ) -> Result<(), LucetcError> { + ) -> Result<(), Error> { // Get the name for this function from the module names section, if it exists. // Because names have to be unique, we append the index value (ix) to the name. fn custom_name_for<'a>( @@ -148,11 +147,9 @@ impl<'a> ModuleDecls<'a> { func_ix: UniqueFuncIndex, decls: &mut ModuleDecls<'a>, bindings: &'a Bindings, - ) -> Result, failure::Context> { + ) -> Result, Error> { if let Some((import_mod, import_field)) = decls.info.imported_funcs.get(func_ix) { - let import_symbol = bindings - .translate(import_mod, import_field) - .context(LucetcErrorKind::TranslatingModule)?; + let import_symbol = bindings.translate(import_mod, import_field)?; decls.imports.push(ImportFunction { fn_idx: LucetFunctionIndex::from_u32(decls.function_names.len() as u32), module: import_mod, @@ -166,7 +163,6 @@ impl<'a> ModuleDecls<'a> { for ix in 0..decls.info.functions.len() { let func_index = UniqueFuncIndex::new(ix); - let import_info = import_name_for(func_index, decls, bindings)?; let export_info = export_name_for(func_index, decls); @@ -206,7 +202,7 @@ impl<'a> ModuleDecls<'a> { decl_sym: String, decl_linkage: Linkage, signature: ir::Signature, - ) -> Result { + ) -> Result { let (new_funcidx, _) = self.info.declare_func_with_sig(signature)?; self.declare_function(clif_module, decl_sym, decl_linkage, new_funcidx)?; @@ -222,7 +218,7 @@ impl<'a> ModuleDecls<'a> { decl_sym: String, decl_linkage: Linkage, func_ix: UniqueFuncIndex, - ) -> Result { + ) -> Result { // This function declaration may be a subsequent additional declaration for a function // we've already been told about. In that case, func_ix will already be a valid index for a // function name, and we should not try to declare it again. @@ -230,13 +226,11 @@ impl<'a> ModuleDecls<'a> { // Regardless of the function being known internally, we must forward the additional // declaration to `clif_module` so functions with multiple forms of linkage (import + // export, exported twice, ...) are correctly declared in the resultant artifact. - let funcid = clif_module - .declare_function( - &decl_sym, - decl_linkage, - self.info.signature_for_function(func_ix), - ) - .context(LucetcErrorKind::TranslatingModule)?; + let funcid = clif_module.declare_function( + &decl_sym, + decl_linkage, + self.info.signature_for_function(func_ix), + )?; if func_ix.as_u32() as usize >= self.function_names.len() { // `func_ix` is new, so we need to add the name. If func_ix is new, it should be @@ -255,21 +249,18 @@ impl<'a> ModuleDecls<'a> { fn declare_tables( info: &ModuleInfo<'a>, clif_module: &mut ClifModule, - ) -> Result<(Name, PrimaryMap), LucetcError> { + ) -> Result<(Name, PrimaryMap), Error> { let mut table_names = PrimaryMap::new(); for ix in 0..info.tables.len() { let def_symbol = format!("guest_table_{}", ix); - let def_data_id = clif_module - .declare_data(&def_symbol, Linkage::Export, false, None) - .context(LucetcErrorKind::TranslatingModule)?; + let def_data_id = + clif_module.declare_data(&def_symbol, Linkage::Export, false, None)?; let def_name = Name::new_data(def_symbol, def_data_id); table_names.push(def_name); } - let tables_list_id = clif_module - .declare_data(TABLE_SYM, Linkage::Export, false, None) - .context(LucetcErrorKind::Table)?; + let tables_list_id = clif_module.declare_data(TABLE_SYM, Linkage::Export, false, None)?; let tables_list = Name::new_data(TABLE_SYM.to_string(), tables_list_id); Ok((tables_list, table_names)) @@ -279,7 +270,7 @@ impl<'a> ModuleDecls<'a> { decls: &mut ModuleDecls<'a>, clif_module: &mut ClifModule, runtime: Runtime, - ) -> Result<(), LucetcError> { + ) -> Result<(), Error> { for (func, (symbol, signature)) in runtime.functions.iter() { let func_id = decls.declare_new_function( clif_module, @@ -296,7 +287,7 @@ impl<'a> ModuleDecls<'a> { fn build_linear_memory_spec( info: &ModuleInfo<'a>, heap_settings: HeapSettings, - ) -> Result, LucetcError> { + ) -> Result, Error> { use crate::sparsedata::owned_sparse_data_from_initializers; if let Some(heap_spec) = Self::build_heap_spec(info, heap_settings)? { let data_initializers = info @@ -314,7 +305,7 @@ impl<'a> ModuleDecls<'a> { } } - fn build_globals_spec(info: &ModuleInfo<'a>) -> Result>, LucetcError> { + fn build_globals_spec(info: &ModuleInfo<'a>) -> Result>, Error> { let mut globals = Vec::new(); for ix in 0..info.globals.len() { let ix = GlobalIndex::new(ix); @@ -335,28 +326,21 @@ impl<'a> ModuleDecls<'a> { if let Some((module, field)) = info.imported_globals.get(ref_ix) { Ok(GlobalVariant::Import { module, field }) } else { - Err(format_err!("inconsistent state: global {} is declared as an import but has no entry in imported_globals", ref_ix.as_u32())) - .context(LucetcErrorKind::TranslatingModule) + Err(Error::GlobalDeclarationError(ref_ix.as_u32())) } } else { // This WASM restriction may be loosened in the future: - Err(format_err!("invalid global declarations: global {} is initialized by referencing another global value, but the referenced global is not an import", ix.as_u32())) - .context(LucetcErrorKind::TranslatingModule) + Err(Error::GlobalInitError(ix.as_u32())) } } GlobalInit::Import => { if let Some((module, field)) = info.imported_globals.get(ix) { Ok(GlobalVariant::Import { module, field }) } else { - Err(format_err!("inconsistent state: global {} is declared as an import but has no entry in imported_globals", ix.as_u32())) - .context(LucetcErrorKind::TranslatingModule) + Err(Error::GlobalDeclarationError(ix.as_u32())) } } - GlobalInit::V128Const(_) => Err(format_err!( - "invalid declaration of global {}: v128const type", - ix.as_u32() - )) - .context(LucetcErrorKind::Unsupported), + GlobalInit::V128Const(_) => Err(Error::GlobalUnsupported(ix.as_u32())), }?; globals.push(GlobalSpec::new(global, g_decl.export_names.clone())); @@ -367,7 +351,7 @@ impl<'a> ModuleDecls<'a> { fn build_heap_spec( info: &ModuleInfo<'a>, heap_settings: HeapSettings, - ) -> Result, LucetcError> { + ) -> Result, Error> { match info.memories.len() { 0 => Ok(None), 1 => { @@ -382,12 +366,11 @@ impl<'a> ModuleDecls<'a> { let reserved_size = std::cmp::max(initial_size, heap_settings.min_reserved_size); if reserved_size > heap_settings.max_reserved_size { - Err(format_err!( + let message = format!( "module reserved size ({}) exceeds max reserved size ({})", - reserved_size, - heap_settings.max_reserved_size - )) - .context(LucetcErrorKind::MemorySpecs)?; + reserved_size, heap_settings.max_reserved_size + ); + Err(Error::MemorySpecs(message))?; } // Find the max size permitted by the heap and the memory spec let max_size = memory.maximum.map(|pages| pages as u64 * wasm_page); @@ -398,8 +381,9 @@ impl<'a> ModuleDecls<'a> { max_size, })) } - _ => Err(format_err!("lucetc only supports memory 0")) - .context(LucetcErrorKind::Unsupported)?, + _ => Err(Error::Unsupported( + "lucetc only supports memory 0".to_string(), + ))?, } } // ********************* Public Interface ************************** @@ -417,16 +401,13 @@ impl<'a> ModuleDecls<'a> { ) } - pub fn get_func(&self, func_index: UniqueFuncIndex) -> Result, Error> { - let name = self - .function_names - .get(func_index) - .ok_or_else(|| format_err!("func index out of bounds: {:?}", func_index))?; + pub fn get_func(&self, func_index: UniqueFuncIndex) -> Option> { + let name = self.function_names.get(func_index).unwrap(); let exportable_sigix = self.info.functions.get(func_index).unwrap(); let signature_index = self.get_signature_uid(exportable_sigix.entity).unwrap(); let signature = self.info.signatures.get(signature_index).unwrap(); let import_name = self.info.imported_funcs.get(func_index); - Ok(FunctionDecl { + Some(FunctionDecl { signature, signature_index, export_names: exportable_sigix.export_names.clone(), @@ -453,10 +434,10 @@ impl<'a> ModuleDecls<'a> { } pub fn get_table(&self, table_index: TableIndex) -> Result, Error> { - let contents_name = self - .table_names - .get(table_index) - .ok_or_else(|| format_err!("table index out of bounds: {:?}", table_index))?; + let contents_name = self.table_names.get(table_index).ok_or_else(|| { + let message = format!("{:?}", table_index); + Error::TableIndexError(message) + })?; let exportable_tbl = self.info.tables.get(table_index).unwrap(); let import_name = self.info.imported_tables.get(table_index); let elems = self @@ -464,8 +445,8 @@ impl<'a> ModuleDecls<'a> { .table_elems .get(&table_index) .ok_or_else(|| { - format_err!("table is not local: {:?}", table_index) - .context(LucetcErrorKind::Unsupported) + let message = format!("table is not local: {:?}", table_index); + Error::Unsupported(message) })? .as_slice(); Ok(TableDecl { @@ -479,10 +460,10 @@ impl<'a> ModuleDecls<'a> { pub fn get_signature(&self, signature_index: SignatureIndex) -> Result<&ir::Signature, Error> { self.get_signature_uid(signature_index).and_then(|uid| { - self.info - .signatures - .get(uid) - .ok_or_else(|| format_err!("signature out of bounds: {:?}", uid)) + self.info.signatures.get(uid).ok_or_else(|| { + let message = format!("signature out of bounds: {:?}", uid); + Error::Signature(message) + }) }) } @@ -494,14 +475,17 @@ impl<'a> ModuleDecls<'a> { .signature_mapping .get(signature_index) .map(|x| *x) - .ok_or_else(|| format_err!("signature out of bounds: {:?}", signature_index)) + .ok_or_else(|| { + let message = format!("signature out of bounds: {:?}", signature_index); + Error::Signature(message) + }) } pub fn get_global(&self, global_index: GlobalIndex) -> Result<&Exportable<'_, Global>, Error> { - self.info - .globals - .get(global_index) - .ok_or_else(|| format_err!("global out of bounds: {:?}", global_index)) + self.info.globals.get(global_index).ok_or_else(|| { + let message = format!("global out of bounds: {:?}", global_index); + Error::GlobalIndexError(message) + }) } pub fn get_heap(&self) -> Option<&HeapSpec> { @@ -512,7 +496,7 @@ impl<'a> ModuleDecls<'a> { } } - pub fn get_module_data(&self, features: ModuleFeatures) -> Result, LucetcError> { + pub fn get_module_data(&self, features: ModuleFeatures) -> Result, Error> { let linear_memory = if let Some(ref spec) = self.linear_memory_spec { Some(spec.to_ref()) } else { @@ -528,8 +512,7 @@ impl<'a> ModuleDecls<'a> { let name = self .function_names .get(fn_index) - .ok_or_else(|| format_err!("func index out of bounds: {:?}", fn_index)) - .unwrap(); + .expect("fn_index is key into function_names"); functions.push(FunctionMetadata { signature: decl.signature_index, @@ -541,12 +524,8 @@ impl<'a> ModuleDecls<'a> { .info .signatures .values() - .map(|sig| { - to_lucet_signature(sig) - .map_err(|e| format_err!("error converting cranelift sig to wasm sig: {:?}", e)) - .context(LucetcErrorKind::TranslatingModule) - }) - .collect::, failure::Context>>()?; + .map(|sig| to_lucet_signature(sig).map_err(Error::SignatureConversion)) + .collect::, Error>>()?; Ok(ModuleData::new( linear_memory, diff --git a/lucetc/src/error.rs b/lucetc/src/error.rs index 7ac842842..5c9cde522 100644 --- a/lucetc/src/error.rs +++ b/lucetc/src/error.rs @@ -1,70 +1,84 @@ -use failure::{Backtrace, Context, Fail}; -use std::fmt::{self, Display}; +use crate::types::SignatureError; +use cranelift_module::ModuleError as ClifModuleError; +use cranelift_wasm::WasmError as ClifWasmError; +use faerie::ArtifactError; +use lucet_module::error::Error as LucetModuleError; +use thiserror::Error; -#[derive(Debug)] -pub struct LucetcError { - inner: Context, -} - -impl From> for LucetcError { - fn from(inner: Context) -> LucetcError { - LucetcError { inner } - } -} - -impl From for LucetcError { - fn from(kind: LucetcErrorKind) -> LucetcError { - LucetcError { - inner: Context::new(kind), - } - } -} - -impl LucetcError { - pub fn get_context(&self) -> &LucetcErrorKind { - self.inner.get_context() - } -} - -impl Fail for LucetcError { - fn cause(&self) -> Option<&dyn Fail> { - self.inner.cause() - } - fn backtrace(&self) -> Option<&Backtrace> { - self.inner.backtrace() - } -} - -impl Display for LucetcError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Display::fmt(&self.inner, f) - } -} - -#[derive(Debug, Fail, PartialEq, Eq, Clone)] -pub enum LucetcErrorKind { - #[fail(display = "Input")] - Input, - #[fail(display = "Validation")] - Validation, - #[fail(display = "Translating module")] - TranslatingModule, - #[fail(display = "Module data")] - ModuleData, - #[fail(display = "Metadata Serializer")] // specifically non-ModuleData; this will go away soon - MetadataSerializer, - #[fail(display = "Function Translation")] - FunctionTranslation, - #[fail(display = "Function Definition")] - FunctionDefinition, - #[fail(display = "Table")] - Table, - #[fail(display = "Memory Specs")] - MemorySpecs, - #[fail(display = "Output")] - Output, - #[fail(display = "Signature")] - Signature, - #[fail(display = "Unsupported")] - Unsupported, +#[derive(Debug, Error)] +pub enum Error { + // + // General #[from] implementations. + #[error("Builtins error")] + Builtins(#[from] parity_wasm::elements::Error), + #[error("Clif module error")] + ClifModuleError(#[from] ClifModuleError), + #[error("Translating error")] + ClifWasmError(#[from] ClifWasmError), + #[error("Lucet Module error")] + LucetModule(#[from] LucetModuleError), + #[error("Lucet validation error")] + LucetValidation(#[from] lucet_validate::Error), + #[error("I/O error")] + IOError(#[from] std::io::Error), + #[error("Error converting cranelift signature to wasm signature")] + SignatureConversion(#[from] SignatureError), + #[error("Wasm validating parser error")] + WasmValidation(#[from] wasmparser::BinaryReaderError), + #[error("Wat input")] + WatInput(#[from] wabt::Error), + // + // Cannot apply #[from] or #[source] to these error types due to missing traits. + #[error("Artifact error: {1}. {0:?}")] + ArtifactError(ArtifactError, String), + #[error("Failure: {1}. {0:?}")] + Failure(failure::Error, String), + #[error("Patcher error: {0:?}")] + Patcher(wasmonkey::WError), + // + // And all the rest + #[error("Function definition error in {symbol}")] + FunctionDefinition { + symbol: String, + #[source] + source: ClifModuleError, + }, + #[error("Function index out of bounds: {0}")] + FunctionIndexError(String), + #[error("Function translation error in {symbol}")] + FunctionTranslation { + symbol: String, + #[source] + source: ClifWasmError, + }, + #[error("Inconsistent state when translating module: global {0} is declared as an import but has no entry in imported_globals")] + GlobalDeclarationError(u32), + #[error("global out of bounds: {0}")] + GlobalIndexError(String), + #[error("global {0} is initialized by referencing another global value, but the referenced global is not an import")] + GlobalInitError(u32), + #[error("v128const type is not supported: {0}")] + GlobalUnsupported(u32), + #[error("Cannot initialize data beyond linear memory's initial size")] + InitData, + #[error("Input error: {0}")] + Input(String), + #[error("Ld error: {0}")] + LdError(String), + #[error("Memory specs: {0}")] + MemorySpecs(String), + #[error("Metadata serializer; start index point to a non-function")] + MetadataSerializer(#[source] ClifModuleError), + #[error("Output function: error writing function {1}")] + OutputFunction(#[source] std::fmt::Error, String), + #[error("Signature error: {0}")] + Signature(String), + #[error("Table index is out of bounds: {0}")] + TableIndexError(String), + #[error("Trap records are present for function {0} but the function does not exist.")] + TrapRecord(String), + #[error("Unsupported: {0}")] + Unsupported(String), + #[error("host machine is not a supported target")] + UnsupportedIsa(#[from] cranelift_codegen::isa::LookupError), } diff --git a/lucetc/src/function_manifest.rs b/lucetc/src/function_manifest.rs index eff20a7c8..460f3ff13 100644 --- a/lucetc/src/function_manifest.rs +++ b/lucetc/src/function_manifest.rs @@ -1,7 +1,7 @@ +use crate::error::Error; use crate::output::write_relocated_slice; use crate::traps::trap_sym_for_func; use faerie::{Artifact, Decl}; -use failure::{Error, ResultExt}; use lucet_module::FunctionSpec; use std::io::Cursor; use std::mem::size_of; @@ -16,7 +16,10 @@ pub fn write_function_manifest( obj: &mut Artifact, ) -> Result<(), Error> { obj.declare(FUNCTION_MANIFEST_SYM, Decl::data()) - .context(format!("declaring {}", FUNCTION_MANIFEST_SYM))?; + .map_err(|source| { + let message = format!("Manifest error declaring {}", FUNCTION_MANIFEST_SYM); + Error::ArtifactError(source, message) + })?; let mut manifest_buf: Cursor> = Cursor::new(Vec::with_capacity( functions.len() * size_of::(), @@ -57,7 +60,10 @@ pub fn write_function_manifest( } obj.define(FUNCTION_MANIFEST_SYM, manifest_buf.into_inner()) - .context(format!("defining {}", FUNCTION_MANIFEST_SYM))?; + .map_err(|source| { + let message = format!("Manifest error declaring {}", FUNCTION_MANIFEST_SYM); + Error::ArtifactError(source, message) + })?; Ok(()) } diff --git a/lucetc/src/lib.rs b/lucetc/src/lib.rs index 968555ca2..3a1adbcb0 100755 --- a/lucetc/src/lib.rs +++ b/lucetc/src/lib.rs @@ -23,12 +23,11 @@ mod types; use crate::load::read_bytes; pub use crate::{ compiler::{Compiler, CpuFeatures, OptLevel, SpecificFeature, TargetCpu}, - error::{LucetcError, LucetcErrorKind}, + error::Error, heap::HeapSettings, load::read_module, patch::patch_module, }; -use failure::{format_err, Error, ResultExt}; pub use lucet_module::bindings::Bindings; pub use lucet_validate::Validator; use signature::{PublicKey, SecretKey}; @@ -338,8 +337,8 @@ impl Lucetc { &self.validator, )?; let obj = compiler.object_file()?; + obj.write(output.as_ref())?; - obj.write(output.as_ref()).context("writing object file")?; Ok(()) } @@ -357,10 +356,7 @@ impl Lucetc { &self.validator, )?; - compiler - .cranelift_funcs()? - .write(&output) - .context("writing clif file")?; + compiler.cranelift_funcs()?.write(&output)?; Ok(()) } @@ -371,9 +367,9 @@ impl Lucetc { self.object_file(objpath.clone())?; link_so(objpath, &self.target, &output)?; if self.sign { - let sk = self.sk.as_ref().ok_or( - format_err!("signing requires a secret key").context(LucetcErrorKind::Signature), - )?; + let sk = self.sk.as_ref().ok_or(Error::Signature( + "signing requires a secret key".to_string(), + ))?; signature::sign_module(&output, sk)?; } Ok(()) @@ -397,16 +393,15 @@ where cmd_ld.arg("-o"); cmd_ld.arg(sopath.as_ref()); - let run_ld = cmd_ld - .output() - .context(format_err!("running ld on {:?}", objpath.as_ref()))?; + let run_ld = cmd_ld.output()?; if !run_ld.status.success() { - Err(format_err!( + let message = format!( "ld of {} failed: {}", objpath.as_ref().to_str().unwrap(), String::from_utf8_lossy(&run_ld.stderr) - ))?; + ); + Err(Error::LdError(message))?; } Ok(()) } diff --git a/lucetc/src/load.rs b/lucetc/src/load.rs index d756e28e2..e86f58bea 100644 --- a/lucetc/src/load.rs +++ b/lucetc/src/load.rs @@ -1,6 +1,5 @@ -use crate::error::LucetcErrorKind; +use crate::error::Error; use crate::signature::{self, PublicKey}; -use failure::*; use std::fs::File; use std::io::Read; use std::path::Path; @@ -22,7 +21,7 @@ pub fn read_module>( &contents, &signature_box, pk.as_ref() - .ok_or(format_err!("public key is missing").context(LucetcErrorKind::Signature))?, + .ok_or(Error::Signature("public key is missing".to_string()))?, )?; } read_bytes(contents) @@ -34,7 +33,8 @@ pub fn read_bytes(bytes: Vec) -> Result, Error> { } else { wat2wasm(bytes).map_err(|err| { use std::error::Error; - let mut result = err.description().to_string(); + let mut result = String::from("wat2wasm error: "); + result.push_str(err.description()); match unsafe { std::mem::transmute::(err) } { ErrorKind::Parse(msg) | // this shouldn't be reachable - we're going the other way @@ -47,7 +47,7 @@ pub fn read_bytes(bytes: Vec) -> Result, Error> { }, _ => { } }; - format_err!("{}", result).context(LucetcErrorKind::Input) + crate::error::Error::Input(result) })? }; Ok(converted) diff --git a/lucetc/src/module.rs b/lucetc/src/module.rs index 0fb1bd30f..59a3101e3 100644 --- a/lucetc/src/module.rs +++ b/lucetc/src/module.rs @@ -1,5 +1,5 @@ //! Implements ModuleEnvironment for cranelift-wasm. Code derived from cranelift-wasm/environ/dummy.rs -use crate::error::{LucetcError, LucetcErrorKind}; +use crate::error::Error; use crate::pointer::NATIVE_POINTER; use cranelift_codegen::entity::{entity_impl, EntityRef, PrimaryMap, SecondaryMap}; use cranelift_codegen::ir; @@ -8,7 +8,6 @@ use cranelift_wasm::{ FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, ModuleEnvironment, ModuleTranslationState, SignatureIndex, Table, TableElementType, TableIndex, WasmResult, }; -use failure::ResultExt; use lucet_module::UniqueSignatureIndex; use std::collections::{hash_map::Entry, HashMap}; @@ -133,13 +132,11 @@ impl<'a> ModuleInfo<'a> { pub fn declare_func_with_sig( &mut self, sig: ir::Signature, - ) -> Result<(UniqueFuncIndex, SignatureIndex), LucetcError> { + ) -> Result<(UniqueFuncIndex, SignatureIndex), Error> { let new_sigidx = SignatureIndex::from_u32(self.signature_mapping.len() as u32); - self.declare_signature(sig) - .context(LucetcErrorKind::TranslatingModule)?; + self.declare_signature(sig)?; let new_funcidx = UniqueFuncIndex::from_u32(self.functions.len() as u32); - self.declare_func_type(new_sigidx) - .context(LucetcErrorKind::TranslatingModule)?; + self.declare_func_type(new_sigidx)?; Ok((new_funcidx, new_sigidx)) } } diff --git a/lucetc/src/output.rs b/lucetc/src/output.rs index 66b706171..27ef1aecd 100644 --- a/lucetc/src/output.rs +++ b/lucetc/src/output.rs @@ -1,4 +1,4 @@ -use crate::error::LucetcErrorKind; +use crate::error::Error; use crate::function_manifest::{write_function_manifest, FUNCTION_MANIFEST_SYM}; use crate::name::Name; use crate::stack_probe; @@ -8,7 +8,6 @@ use byteorder::{LittleEndian, WriteBytesExt}; use cranelift_codegen::{ir, isa}; use cranelift_faerie::FaerieProduct; use faerie::{Artifact, Decl, Link}; -use failure::{format_err, Error, ResultExt}; use lucet_module::{ FunctionSpec, SerializedModule, VersionInfo, LUCET_MODULE_SYM, MODULE_DATA_SYM, }; @@ -33,8 +32,10 @@ impl CraneliftFuncs { let mut buffer = String::new(); for (n, func) in self.funcs.iter() { buffer.push_str(&format!("; {}\n", n.symbol())); - write_function(&mut buffer, func, &Some(self.isa.as_ref()).into()) - .context(format_err!("writing func {:?}", n))? + write_function(&mut buffer, func, &Some(self.isa.as_ref()).into()).map_err(|e| { + let message = format!("{:?}", n); + Error::OutputFunction(e, message) + })? } let mut file = File::create(path)?; file.write_all(buffer.as_bytes())?; @@ -98,8 +99,7 @@ impl ObjectFile { FunctionSpec::new(0, fn_spec.code_len(), 0, sink.sites.len() as u64), ); } else { - Err(format_err!("Inconsistent state: trap records present for function {} but the function does not exist?", sink.name)) - .context(LucetcErrorKind::TranslatingModule)?; + return Err(Error::TrapRecord(sink.name.to_owned())); } } @@ -121,12 +121,14 @@ impl ObjectFile { } pub fn write>(&self, path: P) -> Result<(), Error> { - let _ = path.as_ref().file_name().ok_or(format_err!( - "path {:?} needs to have filename", - path.as_ref() - )); + let _ = path.as_ref().file_name().ok_or(|| { + let message = format!("Path must be filename {:?}", path.as_ref()); + Error::Input(message); + }); let file = File::create(path)?; - self.artifact.write(file)?; + self.artifact + .write(file) + .map_err(|source| Error::Failure(source, "Write error".to_owned()))?; Ok(()) } } @@ -139,7 +141,10 @@ fn write_module( ) -> Result<(), Error> { let mut native_data = Cursor::new(Vec::with_capacity(std::mem::size_of::())); obj.declare(LUCET_MODULE_SYM, Decl::data().global()) - .context(format!("declaring {}", LUCET_MODULE_SYM))?; + .map_err(|source| { + let message = format!("Manifest error declaring {}", FUNCTION_MANIFEST_SYM); + Error::ArtifactError(source, message) + })?; let version = VersionInfo::current(include_str!(concat!(env!("OUT_DIR"), "/commit_hash")).as_bytes()); @@ -169,7 +174,10 @@ fn write_module( )?; obj.define(LUCET_MODULE_SYM, native_data.into_inner()) - .context(format!("defining {}", LUCET_MODULE_SYM))?; + .map_err(|source| { + let message = format!("Manifest error defining {}", FUNCTION_MANIFEST_SYM); + Error::ArtifactError(source, message) + })?; Ok(()) } @@ -204,7 +212,10 @@ pub(crate) fn write_relocated_slice( }, absolute_reloc, ) - .context(format!("linking {} into function manifest", to))?; + .map_err(|source| { + let message = format!("Manifest error linking {}", to); + Error::Failure(source, message) + })?; } (Some(to), _len) => { // This is a local buffer of known size @@ -213,7 +224,10 @@ pub(crate) fn write_relocated_slice( to, // is a reference to `to` (eg. fn_name) at: buf.position(), }) - .context(format!("linking {} into function manifest", to))?; + .map_err(|source| { + let message = format!("Manifest error linking {}", to); + Error::Failure(source, message) + })?; } (None, len) => { // There's actually no relocation to add, because there's no slice to put here. diff --git a/lucetc/src/patch.rs b/lucetc/src/patch.rs index f59fcd1f9..7160ecca2 100644 --- a/lucetc/src/patch.rs +++ b/lucetc/src/patch.rs @@ -1,4 +1,4 @@ -use failure::Error; +use crate::error::Error; use parity_wasm::elements::Module; use std::collections::HashMap; use std::path::Path; @@ -11,8 +11,10 @@ pub fn patch_module>( let mut patcher_config = PatcherConfig::default(); patcher_config.builtins_map_original_names = false; patcher_config.builtins_path = Some(builtins_path.as_ref().into()); - let patcher = Patcher::new(patcher_config, module)?; - let patched_builtins_map = patcher.patched_builtins_map("env")?; + let patcher = Patcher::new(patcher_config, module).map_err(Error::Patcher)?; + let patched_builtins_map = patcher + .patched_builtins_map("env") + .map_err(Error::Patcher)?; let patched_module = patcher.patched_module(); Ok((patched_module, patched_builtins_map)) } diff --git a/lucetc/src/signature.rs b/lucetc/src/signature.rs index 17a64b3ad..97a2a2638 100644 --- a/lucetc/src/signature.rs +++ b/lucetc/src/signature.rs @@ -1,4 +1,4 @@ -use failure::*; +use crate::error::Error; use lucet_module::ModuleSignature; pub use minisign::{KeyPair, PublicKey, SecretKey, SignatureBones, SignatureBox}; use std::fs::File; @@ -19,29 +19,35 @@ fn raw_key_path>(path: P) -> Option { pub fn sk_from_file>(sk_path: P) -> Result { match raw_key_path(sk_path.as_ref()) { - None => SecretKey::from_file(sk_path, None) - .map_err(|e| format_err!("Unable to read the secret key: {}", e)), + None => SecretKey::from_file(sk_path, None).map_err(|e| { + let message = format!("Unable to read the secret key: {}", e); + Error::Signature(message) + }), Some(sk_path) => { let mut sk_bin: Vec = Vec::new(); File::open(sk_path)?.read_to_end(&mut sk_bin)?; - SecretKey::from_bytes(&sk_bin) - .map_err(|e| format_err!("Unable to read the secret key: {}", e)) + SecretKey::from_bytes(&sk_bin).map_err(|e| { + let message = format!("Unable to read the secret key: {}", e); + Error::Signature(message) + }) } } } fn signature_path>(path: P) -> Result { - let path = path - .as_ref() - .to_str() - .ok_or_else(|| format_err!("Invalid path"))?; + let path = path.as_ref().to_str().ok_or_else(|| { + let message = format!("Invalid signature path {:?}", path.as_ref()); + Error::Input(message) + })?; Ok(PathBuf::from(format!("{}.minisig", path))) } pub fn signature_box_for_module_path>(path: P) -> Result { let signature_path = signature_path(path)?; - SignatureBox::from_file(&signature_path) - .map_err(|e| format_err!("Unable to load the signature file: {}", e)) + SignatureBox::from_file(&signature_path).map_err(|e| { + let message = format!("Unable to load the signature file: {}", e); + Error::Signature(message) + }) } pub fn keygen, Q: AsRef>(pk_path: P, sk_path: Q) -> Result { @@ -49,16 +55,24 @@ pub fn keygen, Q: AsRef>(pk_path: P, sk_path: Q) -> Result< None => { let pk_writer = File::create(pk_path)?; let sk_writer = File::create(sk_path)?; - KeyPair::generate_and_write_encrypted_keypair(pk_writer, sk_writer, None, None) - .map_err(|e| format_err!("Unable to generate the key pair: {}", e)) + KeyPair::generate_and_write_encrypted_keypair(pk_writer, sk_writer, None, None).map_err( + |e| { + let message = format!("Unable to generate the key pair: {}", e); + Error::Signature(message) + }, + ) } Some(sk_path_raw) => { - let kp = KeyPair::generate_unencrypted_keypair() - .map_err(|e| format_err!("Unable to generate the key pair: {}", e))?; + let kp = KeyPair::generate_unencrypted_keypair().map_err(|e| { + let message = format!("Unable to generate the key pair: {}", e); + Error::Signature(message) + })?; let mut pk_writer = File::create(pk_path)?; let mut sk_writer = File::create(sk_path_raw)?; - pk_writer.write_all(&kp.pk.to_box()?.to_bytes())?; + + pk_writer.write_all(&kp.pk.to_box().unwrap().to_bytes())?; sk_writer.write_all(&kp.sk.to_bytes())?; + Ok(kp) } } @@ -70,7 +84,8 @@ pub fn verify_source_code( signature_box: &SignatureBox, pk: &PublicKey, ) -> Result<(), Error> { - minisign::verify(pk, signature_box, Cursor::new(buf), false, false).map_err(|e| e.into()) + minisign::verify(pk, signature_box, Cursor::new(buf), false, false) + .map_err(|e| Error::Signature(e.to_string())) } // Sign the compiled code diff --git a/lucetc/src/sparsedata.rs b/lucetc/src/sparsedata.rs index cdbffd881..f228d8112 100644 --- a/lucetc/src/sparsedata.rs +++ b/lucetc/src/sparsedata.rs @@ -1,6 +1,5 @@ -use crate::error::{LucetcError, LucetcErrorKind}; +use crate::error::Error; use crate::module::DataInitializer; -use failure::{format_err, ResultExt}; use lucet_module::owned::OwnedSparseData; use lucet_module::HeapSpec; use std::collections::hash_map::Entry; @@ -57,23 +56,19 @@ fn split<'a>(di: &DataInitializer<'a>) -> Vec<(usize, DataInitializer<'a>)> { pub fn owned_sparse_data_from_initializers<'a>( initializers: &[DataInitializer<'a>], heap: &HeapSpec, -) -> Result { +) -> Result { let mut pagemap: HashMap> = HashMap::new(); for initializer in initializers { if initializer.base.is_some() { - Err(format_err!( - "cannot create sparse data: data initializer uses global as base" - )) - .context(LucetcErrorKind::Unsupported)? + let message = + "cannot create sparse data: data initializer uses global as base".to_owned(); + Err(Error::Unsupported(message))?; } let chunks = split(initializer); for (pagenumber, chunk) in chunks { if pagenumber > heap.initial_size as usize / PAGE_SIZE { - Err(format_err!( - "cannot initialize data beyond linear memory's initial size" - )) - .context(LucetcErrorKind::Validation)?; + Err(Error::InitData)?; } let base = chunk.offset as usize; let page = match pagemap.entry(pagenumber) { @@ -98,6 +93,6 @@ pub fn owned_sparse_data_from_initializers<'a>( } } assert_eq!(out.len() * 4096, heap.initial_size as usize); - let o = OwnedSparseData::new(out).context(LucetcErrorKind::ModuleData)?; + let o = OwnedSparseData::new(out)?; Ok(o) } diff --git a/lucetc/src/stack_probe.rs b/lucetc/src/stack_probe.rs index da6c3f645..c062a3186 100644 --- a/lucetc/src/stack_probe.rs +++ b/lucetc/src/stack_probe.rs @@ -9,6 +9,7 @@ //! treated like any other guest trap. use crate::decls::ModuleDecls; +use crate::error::Error; use crate::module::UniqueFuncIndex; use cranelift_codegen::binemit::TrapSink; use cranelift_codegen::ir; @@ -18,7 +19,6 @@ use cranelift_faerie::traps::{FaerieTrapManifest, FaerieTrapSink}; use cranelift_faerie::FaerieProduct; use cranelift_module::{Backend as ClifBackend, Linkage, Module as ClifModule}; use faerie::Decl; -use failure::Error; /// Stack probe symbol name pub const STACK_PROBE_SYM: &'static str = "lucet_probestack"; @@ -59,11 +59,14 @@ pub fn declare_metadata<'a, B: ClifBackend>( } pub fn declare_and_define(product: &mut FaerieProduct) -> Result<(), Error> { - product.artifact.declare_with( - STACK_PROBE_SYM, - Decl::function(), - STACK_PROBE_BINARY.to_vec(), - )?; + product + .artifact + .declare_with( + STACK_PROBE_SYM, + Decl::function(), + STACK_PROBE_BINARY.to_vec(), + ) + .map_err(|source| Error::Failure(source, "Stack probe error".to_owned()))?; add_sink( product .trap_manifest diff --git a/lucetc/src/table.rs b/lucetc/src/table.rs index 967372c3a..79130e9c5 100644 --- a/lucetc/src/table.rs +++ b/lucetc/src/table.rs @@ -1,5 +1,5 @@ use crate::decls::{ModuleDecls, TableDecl}; -use crate::error::{LucetcError, LucetcErrorKind}; +use crate::error::Error; use crate::module::UniqueFuncIndex; use crate::name::Name; use crate::pointer::NATIVE_POINTER_SIZE; @@ -8,7 +8,6 @@ use cranelift_codegen::entity::EntityRef; use cranelift_module::{Backend as ClifBackend, DataContext, Module as ClifModule}; use cranelift_wasm::{TableElementType, TableIndex}; use faerie::{Artifact, Link}; -use failure::{format_err, Error, ResultExt}; use std::io::Cursor; /// This symbol will be used to reference the `tables` field in `Module` - a sequence of tables. @@ -24,22 +23,21 @@ enum Elem { Empty, } -fn table_elements(decl: &TableDecl<'_>) -> Result, LucetcError> { +fn table_elements(decl: &TableDecl<'_>) -> Result, Error> { match decl.table.ty { TableElementType::Func => Ok(()), - _ => Err(format_err!("table with non-function elements: {:?}", decl)) - .context(LucetcErrorKind::Unsupported), + _ => { + let message = format!("table with non-function elements: {:?}", decl); + Err(Error::Unsupported(message)) + } }?; let mut elems = Vec::new(); for initializer in decl.elems.iter() { if initializer.base.is_some() { - Err(format_err!( - "table elements with global index base: {:?}", - initializer - )) - .context(LucetcErrorKind::Unsupported)? + let message = format!("table elements with global index base: {:?}", initializer); + Err(Error::Unsupported(message))? } let final_len = initializer.offset + initializer.elements.len(); if final_len > elems.len() { @@ -60,7 +58,7 @@ pub fn link_tables(tables: &[Name], obj: &mut Artifact) -> Result<(), Error> { to: table.symbol(), at: (TABLE_REF_SIZE * idx) as u64, }) - .context(LucetcErrorKind::Table)?; + .map_err(|source| Error::Failure(source, "Table error".to_owned()))?; } Ok(()) } @@ -68,7 +66,7 @@ pub fn link_tables(tables: &[Name], obj: &mut Artifact) -> Result<(), Error> { pub fn write_table_data( clif_module: &mut ClifModule, decls: &ModuleDecls<'_>, -) -> Result, LucetcError> { +) -> Result, Error> { let mut tables_vec = Cursor::new(Vec::new()); let mut table_names: Vec = Vec::new(); @@ -95,19 +93,21 @@ pub fn write_table_data( Elem::Func(func_index) => { // Note: this is the only place we validate that the table entry points to a valid // function. If this is ever removed, make sure this check happens elsewhere. - let func = decls - .get_func(*func_index) - .context(LucetcErrorKind::Table)?; - // First element in row is the SignatureIndex for the function - putelem(&mut table_data, func.signature_index.as_u32() as u64); - - // Second element in row is the pointer to the function. The Reloc is doing the work - // here. We put a 0 in the table data itself to be overwritten at link time. - let funcref = table_ctx.import_function(func.name.into()); - let position = table_data.position(); - assert!(position < ::max_value() as u64); - table_ctx.write_function_addr(position as u32, funcref); - putelem(&mut table_data, 0); + if let Some(func) = decls.get_func(*func_index) { + // First element in row is the SignatureIndex for the function + putelem(&mut table_data, func.signature_index.as_u32() as u64); + + // Second element in row is the pointer to the function. The Reloc is doing the work + // here. We put a 0 in the table data itself to be overwritten at link time. + let funcref = table_ctx.import_function(func.name.into()); + let position = table_data.position(); + assert!(position < ::max_value() as u64); + table_ctx.write_function_addr(position as u32, funcref); + putelem(&mut table_data, 0); + } else { + let message = format!("{:?}", func_index); + return Err(Error::FunctionIndexError(message)); + } } // EMPTY: Elem::Empty => { @@ -125,9 +125,7 @@ pub fn write_table_data( .contents_name .as_dataid() .expect("tables are data"); - clif_module - .define_data(table_id, &table_ctx) - .context(LucetcErrorKind::Table)?; + clif_module.define_data(table_id, &table_ctx)?; // have to link TABLE_SYM, table_id, // add space for the TABLE_SYM pointer @@ -145,14 +143,12 @@ pub fn write_table_data( let mut table_data_ctx = DataContext::new(); table_data_ctx.define(inner.into_boxed_slice()); - clif_module - .define_data( - decls - .get_tables_list_name() - .as_dataid() - .expect("lucet_tables is declared as data"), - &table_data_ctx, - ) - .context(LucetcErrorKind::Table)?; + clif_module.define_data( + decls + .get_tables_list_name() + .as_dataid() + .expect("lucet_tables is declared as data"), + &table_data_ctx, + )?; Ok(table_names) } diff --git a/lucetc/src/traps.rs b/lucetc/src/traps.rs index 7aac74435..5cdd34e47 100644 --- a/lucetc/src/traps.rs +++ b/lucetc/src/traps.rs @@ -1,8 +1,9 @@ +use crate::error::Error; + use cranelift_codegen::ir; use cranelift_faerie::traps::FaerieTrapManifest; use faerie::{Artifact, Decl}; -use failure::{Error, ResultExt}; use lucet_module::TrapSite; pub fn write_trap_tables(manifest: &FaerieTrapManifest, obj: &mut Artifact) -> Result<(), Error> { @@ -10,8 +11,10 @@ pub fn write_trap_tables(manifest: &FaerieTrapManifest, obj: &mut Artifact) -> R let func_sym = &sink.name; let trap_sym = trap_sym_for_func(func_sym); - obj.declare(&trap_sym, Decl::data()) - .context(format!("declaring {}", &trap_sym))?; + obj.declare(&trap_sym, Decl::data()).map_err(|source| { + let message = format!("Trap table error declaring {}", trap_sym); + Error::ArtifactError(source, message) + })?; // write the actual function-level trap table let traps: Vec = sink @@ -32,7 +35,10 @@ pub fn write_trap_tables(manifest: &FaerieTrapManifest, obj: &mut Artifact) -> R // and write the function trap table into the object obj.define(&trap_sym, trap_site_bytes.to_vec()) - .context(format!("defining {}", &trap_sym))?; + .map_err(|source| { + let message = format!("Trap table error defining {}", trap_sym); + Error::ArtifactError(source, message) + })?; } Ok(()) diff --git a/lucetc/src/types.rs b/lucetc/src/types.rs index cb2023a0a..ee4957b3c 100644 --- a/lucetc/src/types.rs +++ b/lucetc/src/types.rs @@ -1,6 +1,8 @@ use cranelift_codegen::ir; use lucet_module::Signature; use lucet_module::ValueType; +use std::fmt::{self, Display}; +use thiserror::Error; #[derive(Debug)] pub enum ValueError { @@ -38,12 +40,18 @@ fn to_lucet_value(value: &ir::AbiParam) -> Result { } } -#[derive(Debug)] +#[derive(Debug, Error)] pub enum SignatureError { BadElement(ir::AbiParam, ValueError), BadSignature, } +impl Display for SignatureError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Display::fmt(&self, f) + } +} + pub fn to_lucet_signature(value: &ir::Signature) -> Result { let mut params: Vec = Vec::new(); diff --git a/lucetc/tests/wasm.rs b/lucetc/tests/wasm.rs index 39a592f31..02ad271cb 100644 --- a/lucetc/tests/wasm.rs +++ b/lucetc/tests/wasm.rs @@ -39,7 +39,7 @@ mod module_data { /// Tests of the `ModuleData` generated by the lucetc Compiler use super::load_wat_module; use lucet_module::bindings::Bindings; - use lucetc::{Compiler, CpuFeatures, HeapSettings, LucetcErrorKind, OptLevel}; + use lucetc::{Compiler, CpuFeatures, HeapSettings, OptLevel}; use std::path::PathBuf; use target_lexicon::Triple; @@ -455,6 +455,7 @@ mod module_data { #[test] fn oversize_data_segment() { + use lucetc::Error as LucetcError; let m = load_wat_module("oversize_data_segment"); let b = Bindings::empty(); let h = HeapSettings::default(); @@ -472,13 +473,18 @@ mod module_data { c.is_err(), "compilation error because data initializers are oversized" ); - assert_eq!(*c.err().unwrap().get_context(), LucetcErrorKind::Validation); + assert!(if let LucetcError::InitData = c.err().unwrap() { + true + } else { + false + }); } // XXX adding more negative tests like the one above is valuable - lets do it #[test] fn invalid_module() { + use lucetc::Error as LucetcError; use std::fs::File; use std::io::Read; // I used the `wast2json` tool to produce the file invalid.wasm from an assert_invalid part @@ -504,7 +510,11 @@ mod module_data { c.is_err(), "compilation error because wasm module is invalid" ); - assert_eq!(*c.err().unwrap().get_context(), LucetcErrorKind::Validation); + assert!(if let LucetcError::WasmValidation(_) = c.err().unwrap() { + true + } else { + false + }); } #[test] From efb6d5794702cab2f23b29404d50e1f1fa3412d0 Mon Sep 17 00:00:00 2001 From: "Adam C. Foltzer" Date: Wed, 22 Jan 2020 11:53:18 -0800 Subject: [PATCH 511/512] use exact dependencies for crates within the repo Most of our thinking about semver for this project is concerned with the more "public-facing" crates like `lucetc`, `lucet-runtime`, and `lucet-wasi`, as opposed to "implementation detail" crates like `lucet-module`, `lucet-runtime-internals`, etc. As the project matures, we are paying more attention to semver for all of the crates, but this change makes the released sets of packages more consistent. --- lucet-objdump/Cargo.toml | 2 +- lucet-runtime/Cargo.toml | 10 +++++----- lucet-runtime/lucet-runtime-internals/Cargo.toml | 4 ++-- lucet-runtime/lucet-runtime-tests/Cargo.toml | 8 ++++---- lucet-spectest/Cargo.toml | 6 +++--- lucet-validate/Cargo.toml | 4 ++-- lucet-wasi-sdk/Cargo.toml | 6 +++--- lucet-wasi/Cargo.toml | 10 +++++----- lucetc/Cargo.toml | 6 +++--- 9 files changed, 28 insertions(+), 28 deletions(-) diff --git a/lucet-objdump/Cargo.toml b/lucet-objdump/Cargo.toml index 1a2cd19fa..90a02d826 100644 --- a/lucet-objdump/Cargo.toml +++ b/lucet-objdump/Cargo.toml @@ -13,7 +13,7 @@ edition = "2018" goblin="0.0.24" byteorder="1.2.1" colored="1.8.0" -lucet-module = { path = "../lucet-module", version = "0.5.0" } +lucet-module = { path = "../lucet-module", version = "=0.5.0" } [package.metadata.deb] name = "fst-lucet-objdump" diff --git a/lucet-runtime/Cargo.toml b/lucet-runtime/Cargo.toml index c6aad54f7..87a0f0d64 100644 --- a/lucet-runtime/Cargo.toml +++ b/lucet-runtime/Cargo.toml @@ -11,17 +11,17 @@ edition = "2018" [dependencies] libc = "0.2.65" -lucet-runtime-internals = { path = "lucet-runtime-internals", version = "0.5.0" } -lucet-module = { path = "../lucet-module", version = "0.5.0" } +lucet-runtime-internals = { path = "lucet-runtime-internals", version = "=0.5.0" } +lucet-module = { path = "../lucet-module", version = "=0.5.0" } num-traits = "0.2" num-derive = "0.3.0" [dev-dependencies] byteorder = "1.2" lazy_static = "1.1" -lucetc = { path = "../lucetc", version = "0.5.0" } -lucet-runtime-tests = { path = "lucet-runtime-tests", version = "0.5.0" } -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.5.0" } +lucetc = { path = "../lucetc", version = "=0.5.0" } +lucet-runtime-tests = { path = "lucet-runtime-tests", version = "=0.5.0" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "=0.5.0" } nix = "0.15" rayon = "1.0" tempfile = "3.0" diff --git a/lucet-runtime/lucet-runtime-internals/Cargo.toml b/lucet-runtime/lucet-runtime-internals/Cargo.toml index 83b1e86f2..ee45da261 100644 --- a/lucet-runtime/lucet-runtime-internals/Cargo.toml +++ b/lucet-runtime/lucet-runtime-internals/Cargo.toml @@ -10,8 +10,8 @@ authors = ["Lucet team "] edition = "2018" [dependencies] -lucet-module = { path = "../../lucet-module", version = "0.5.0" } -lucet-runtime-macros = { path = "../lucet-runtime-macros", version = "0.5.0" } +lucet-module = { path = "../../lucet-module", version = "=0.5.0" } +lucet-runtime-macros = { path = "../lucet-runtime-macros", version = "=0.5.0" } anyhow = "1.0" bitflags = "1.0" diff --git a/lucet-runtime/lucet-runtime-tests/Cargo.toml b/lucet-runtime/lucet-runtime-tests/Cargo.toml index 70293f38a..af197e24f 100644 --- a/lucet-runtime/lucet-runtime-tests/Cargo.toml +++ b/lucet-runtime/lucet-runtime-tests/Cargo.toml @@ -18,10 +18,10 @@ test = false anyhow = "1" lazy_static = "1.1" tempfile = "3.0" -lucet-module = { path = "../../lucet-module", version = "0.5.0" } -lucet-runtime-internals = { path = "../lucet-runtime-internals", version = "0.5.0" } -lucet-wasi-sdk = { path = "../../lucet-wasi-sdk", version = "0.5.0" } -lucetc = { path = "../../lucetc", version = "0.5.0" } +lucet-module = { path = "../../lucet-module", version = "=0.5.0" } +lucet-runtime-internals = { path = "../lucet-runtime-internals", version = "=0.5.0" } +lucet-wasi-sdk = { path = "../../lucet-wasi-sdk", version = "=0.5.0" } +lucetc = { path = "../../lucetc", version = "=0.5.0" } [build-dependencies] cc = "1.0" diff --git a/lucet-spectest/Cargo.toml b/lucet-spectest/Cargo.toml index 8403d2776..7ee2f0b0c 100644 --- a/lucet-spectest/Cargo.toml +++ b/lucet-spectest/Cargo.toml @@ -18,9 +18,9 @@ path = "src/main.rs" [dependencies] anyhow = "1" -lucetc = { path = "../lucetc", version = "0.5.0" } -lucet-module = { path = "../lucet-module", version = "0.5.0" } -lucet-runtime = { path = "../lucet-runtime", version = "0.5.0" } +lucetc = { path = "../lucetc", version = "=0.5.0" } +lucet-module = { path = "../lucet-module", version = "=0.5.0" } +lucet-runtime = { path = "../lucet-runtime", version = "=0.5.0" } wabt = "0.9.2" serde = "1.0" serde_json = "1.0" diff --git a/lucet-validate/Cargo.toml b/lucet-validate/Cargo.toml index 83d69903e..35be8670d 100644 --- a/lucet-validate/Cargo.toml +++ b/lucet-validate/Cargo.toml @@ -20,11 +20,11 @@ path = "src/main.rs" clap = "2" witx = { path = "../wasi/tools/witx", version = "0.6.0" } cranelift-entity = { path = "../cranelift/cranelift-entity", version = "0.51.0" } -thiserror = "1.0.4" +thiserror = "1.0.4" wasmparser = "0.39.1" [dev-dependencies] -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.5.0" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "=0.5.0" } tempfile = "3.0" wabt = "0.9.2" diff --git a/lucet-wasi-sdk/Cargo.toml b/lucet-wasi-sdk/Cargo.toml index db0a26ace..b15cec639 100644 --- a/lucet-wasi-sdk/Cargo.toml +++ b/lucet-wasi-sdk/Cargo.toml @@ -11,11 +11,11 @@ edition = "2018" [dependencies] anyhow = "1" -lucetc = { path = "../lucetc", version = "0.5.0" } -lucet-module = { path = "../lucet-module", version = "0.5.0" } +lucetc = { path = "../lucetc", version = "=0.5.0" } +lucet-module = { path = "../lucet-module", version = "=0.5.0" } target-lexicon = "0.9" tempfile = "3.0" thiserror = "1.0.4" [dev-dependencies] -lucet-validate = { path = "../lucet-validate", version = "0.5.0" } +lucet-validate = { path = "../lucet-validate", version = "=0.5.0" } diff --git a/lucet-wasi/Cargo.toml b/lucet-wasi/Cargo.toml index 1284b8a1b..60f52ee01 100644 --- a/lucet-wasi/Cargo.toml +++ b/lucet-wasi/Cargo.toml @@ -28,17 +28,17 @@ anyhow = "1" cast = "0.2" clap = "2.23" human-size = "0.4" -lucet-runtime = { path = "../lucet-runtime", version = "0.5.0" } -lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.5.0" } -lucet-module = { path = "../lucet-module", version = "0.5.0" } +lucet-runtime = { path = "../lucet-runtime", version = "=0.5.0" } +lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "=0.5.0" } +lucet-module = { path = "../lucet-module", version = "=0.5.0" } libc = "0.2.65" nix = "0.15" rand = "0.6" wasi-common = "0.7" [dev-dependencies] -lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.5.0" } -lucetc = { path = "../lucetc", version = "0.5.0" } +lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "=0.5.0" } +lucetc = { path = "../lucetc", version = "=0.5.0" } tempfile = "3.0" [build-dependencies] diff --git a/lucetc/Cargo.toml b/lucetc/Cargo.toml index 68327ca46..ccd267aff 100644 --- a/lucetc/Cargo.toml +++ b/lucetc/Cargo.toml @@ -24,8 +24,8 @@ cranelift-module = { path = "../cranelift/cranelift-module", version = "0.51.0" cranelift-faerie = { path = "../cranelift/cranelift-faerie", version = "0.51.0" } cranelift-wasm = { path = "../cranelift/cranelift-wasm", version = "0.51.0" } target-lexicon = "0.9" -lucet-module = { path = "../lucet-module", version = "0.5.0" } -lucet-validate = { path = "../lucet-validate", version = "0.5.0" } +lucet-module = { path = "../lucet-module", version = "=0.5.0" } +lucet-validate = { path = "../lucet-validate", version = "=0.5.0" } wasmparser = "0.39.1" clap="2.32" log = "0.4" @@ -46,7 +46,7 @@ minisign = "0.5.11" memoffset = "0.5.1" serde = "1.0" serde_json = "1.0" -thiserror = "1.0.4" +thiserror = "1.0.4" raw-cpuid = "6.0.0" [package.metadata.deb] From 08a10ca21406560f9068c9f8d275fc799e7d27f0 Mon Sep 17 00:00:00 2001 From: "Tanya L. Crenshaw" <56939192+fst-crenshaw@users.noreply.github.com> Date: Wed, 22 Jan 2020 12:09:38 -0800 Subject: [PATCH 512/512] Fix bad merge in cpu_features.rs. ISA lookup must be invoked on target (#399) --- lucetc/src/compiler/cpu_features.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lucetc/src/compiler/cpu_features.rs b/lucetc/src/compiler/cpu_features.rs index 4e7b8fcb1..d08ebb3bc 100644 --- a/lucetc/src/compiler/cpu_features.rs +++ b/lucetc/src/compiler/cpu_features.rs @@ -193,7 +193,7 @@ impl CpuFeatures { Error::Unsupported("host machine is not a supported target".to_string()) }) } else { - isa::lookup(Triple::host()).map_err(Error::UnsupportedIsa) + isa::lookup(target).map_err(Error::UnsupportedIsa) }?; let mut specific_features = self.specific_features.clone();