diff --git a/package.json b/package.json index 38f3f343f..14518de78 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,6 @@ "test-internal-react": "babel-node --stack_size=10000 --stack_trace_limit=200 --max_old_space_size=16384 scripts/test-internal-react.js", "test-error-handler": "babel-node scripts/test-error-handler.js", "test-error-handler-with-coverage": "./node_modules/.bin/istanbul cover ./lib/test-error-handler.js --dir coverage.error && ./node_modules/.bin/remap-istanbul -i coverage.error/coverage.json -o coverage-sourcemapped.error -t html", - "test-node-cli-mode": "bash < scripts/test-node-cli-mode.sh", "test-std-in": "bash < scripts/test-std-in.sh", "test-react": "jest", "test-react-fast": "SKIP_REACT_JSX_TESTS=true jest", @@ -52,7 +51,6 @@ "repl": "node lib/repl-cli.js", "precheck": "yarn prepack-cli --check", "prepack-cli": "node --stack_size=10000 --stack_trace_limit=200 --max_old_space_size=16384 lib/prepack-cli.js --accelerateUnsupportedRequires --compatibility jsc-600-1-4-17 --delayUnsupportedRequires --mathRandomSeed 0", - "prepack-prepack": "node --stack_size=10000 --max_old_space_size=8096 ./bin/prepack.js ./lib/prepack-cli.js --out ./lib/prepack-cli.prepacked.js --compatibility node-cli --mathRandomSeed rnd", "validate": "yarn install --frozen-lockfile && yarn build && yarn build-scripts && yarn lint && yarn depcheck && yarn flow && yarn test", "prepublishOnly": "yarn build", "depcheck": "babel-node scripts/detect_bad_deps.js", diff --git a/scripts/test-node-cli-mode.sh b/scripts/test-node-cli-mode.sh deleted file mode 100644 index 230f0a375..000000000 --- a/scripts/test-node-cli-mode.sh +++ /dev/null @@ -1,17 +0,0 @@ -# Prepack test input -node ./bin/prepack.js ./test/node-cli/Simple.js --out Simple-test.js --compatibility node-cli -# Run the resulting program and check it for expected output -node ./Simple-test.js | grep "Hey world" > /dev/null -if [[ $? -ne 0 ]]; then - exit 1 -fi -rm ./Simple-test.js - -# Prepack test input -node ./bin/prepack.js ./test/node-cli/FileSystem.js --out FileSystem-test.js --compatibility node-cli -# Run the resulting program and check it for expected output -node ./FileSystem-test.js | grep "Hey Hello world" > /dev/null -if [[ $? -ne 0 ]]; then - exit 1 -fi -rm ./FileSystem-test.js diff --git a/src/intrinsics/node/bootstrap.js b/src/intrinsics/node/bootstrap.js deleted file mode 100644 index a6627e3cf..000000000 --- a/src/intrinsics/node/bootstrap.js +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -/* @flow */ - -import { FatalError } from "../../errors.js"; -import type { Realm } from "../../realm.js"; -import { FunctionValue } from "../../values/index.js"; - -declare var process: any; - -export default function(realm: Realm): FunctionValue { - // Extract the bootstrap source code from the hosting Node version. - let nodeSourceCode = process.binding("natives"); - let bootstrapSource = nodeSourceCode["internal/bootstrap_node"]; - let bootstrapFilename = "bootstrap_node.js"; - if (!bootstrapSource) { - throw new FatalError("The node-cli mode is only compatible with Node 7."); - } - - // We evaluate bootstrap script to get the bootstrap function. - let bootstrapFn = realm.$GlobalEnv.execute(bootstrapSource, bootstrapFilename, ""); - - if (!(bootstrapFn instanceof FunctionValue) || !bootstrapFn.$Call) { - throw new FatalError("The node bootstrap script should always yield a function."); - } - - return bootstrapFn; -} diff --git a/src/intrinsics/node/buffer.js b/src/intrinsics/node/buffer.js deleted file mode 100644 index 08c55973c..000000000 --- a/src/intrinsics/node/buffer.js +++ /dev/null @@ -1,144 +0,0 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -/* @flow */ - -import invariant from "../../invariant.js"; -import { FatalError } from "../../errors.js"; -import { Realm } from "../../realm.js"; -import { NumberValue, NativeFunctionValue, ObjectValue, StringValue } from "../../values/index.js"; -import { getNodeBufferFromTypedArray } from "./utils.js"; -import { Properties, To } from "../../singletons.js"; - -declare var process: any; - -export default function(realm: Realm): ObjectValue { - let nativeBuffer = process.binding("buffer"); - let nativeBufferPrototype = (require("buffer"): any).Buffer.prototype; - - let intrinsicName = 'process.binding("buffer")'; - let obj = new ObjectValue(realm, realm.intrinsics.ObjectPrototype, intrinsicName); - - // Buffer - - let setupBufferJS = new NativeFunctionValue( - realm, - intrinsicName + ".setupBufferJS", - "setupBufferJS", - 0, - (setupContext, setupArgs) => { - invariant(setupArgs.length === 2); - invariant(setupArgs[0] instanceof ObjectValue); - invariant(setupArgs[1] instanceof ObjectValue); - // TODO: Mutate the second argument by setting one of the properties to - // Buffer prototype just like the native implementation does. - let [proto] = setupArgs; - - let simpleWrapperNames = [ - "asciiSlice", - "base64Slice", - "latin1Slice", - "hexSlice", - "ucs2Slice", - "asciiWrite", - "base64Write", - "latin1Write", - "hexWrite", - "ucs2Write", - "utf8Write", - ]; - - for (let name of simpleWrapperNames) { - let wrapper = new NativeFunctionValue(realm, "Buffer.prototype." + name, name, 0, (context, args) => { - throw new FatalError("TODO: " + name); - }); - Properties.Set(realm, proto, name, wrapper, true); - } - - // utf8Slice is used to read source code. - let utf8Slice = new NativeFunctionValue(realm, "Buffer.prototype.utf8Slice", "utf8Slice", 0, (context, args) => { - invariant(context instanceof ObjectValue); - let self = getNodeBufferFromTypedArray(realm, context); - let decodedArgs = args.map((arg, i) => To.ToInteger(realm, arg)); - let utf8String = nativeBufferPrototype.utf8Slice.apply(self, decodedArgs); - return new StringValue(realm, utf8String); - }); - Properties.Set(realm, proto, "utf8Slice", utf8Slice, true); - - // copy has recently moved from the prototype to the instance upstream. - let copy = new NativeFunctionValue(realm, "Buffer.prototype.copy", "copy", 0, (context, args) => { - invariant(context instanceof ObjectValue); - let self = getNodeBufferFromTypedArray(realm, context); - let decodedArgs = args.map((arg, i) => { - if (i === 0) { - invariant(arg instanceof ObjectValue); - return getNodeBufferFromTypedArray(realm, arg); - } else { - return To.ToInteger(realm, arg); - } - }); - let bytesCopied = nativeBufferPrototype.copy.apply(self, decodedArgs); - return new NumberValue(realm, bytesCopied); - }); - Properties.Set(realm, proto, "copy", copy, true); - - // TODO: Set up more methods on the prototype and bindingObject - return realm.intrinsics.undefined; - } - ); - Properties.Set(realm, obj, "setupBufferJS", setupBufferJS, true); - - let createFromString = new NativeFunctionValue( - realm, - intrinsicName + ".createFromString", - "createFromString", - 0, - (context, args) => { - throw new FatalError("TODO"); - } - ); - Properties.Set(realm, obj, "createFromString", createFromString, true); - - let simpleWrapperNames = [ - "byteLengthUtf8", - "copy", - "compare", - "compareOffset", - "fill", - "indexOfBuffer", - "indexOfNumber", - "indexOfString", - - "readDoubleBE", - "readDoubleLE", - "readFloatBE", - "readFloatLE", - - "writeDoubleBE", - "writeDoubleLE", - "writeFloatBE", - "writeFloatLE", - - "swap16", - "swap32", - "swap64", - ]; - - for (let name of simpleWrapperNames) { - let wrapper = new NativeFunctionValue(realm, intrinsicName + "." + name, name, 0, (context, args) => { - throw new FatalError("TODO"); - }); - Properties.Set(realm, obj, name, wrapper, true); - } - - Properties.Set(realm, obj, "kMaxLength", new NumberValue(realm, nativeBuffer.kMaxLength), true); - Properties.Set(realm, obj, "kStringMaxLength", new NumberValue(realm, nativeBuffer.kStringMaxLength), true); - - return obj; -} diff --git a/src/intrinsics/node/contextify.js b/src/intrinsics/node/contextify.js deleted file mode 100644 index 107a9144a..000000000 --- a/src/intrinsics/node/contextify.js +++ /dev/null @@ -1,418 +0,0 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -/* @flow */ - -import invariant from "../../invariant.js"; -import { Realm } from "../../realm.js"; -import { AbruptCompletion, ThrowCompletion } from "../../completions.js"; -import { - Value, - ConcreteValue, - BooleanValue, - EmptyValue, - NativeFunctionValue, - ObjectValue, - StringValue, - UndefinedValue, -} from "../../values/index.js"; -import { Get, GetFunctionRealm } from "../../methods/index.js"; -import { Properties, To } from "../../singletons.js"; -import parse from "../../utils/parse.js"; -import type { BabelNodeFile } from "@babel/types"; - -// TODO: This creates a strong dependency on babel and its transforms even -// outside of devDependencies which is unfortunate. Get rid of this once classes -// and destructuring is fully implemented. -import { transform as babelTransform } from "@babel/core"; - -// Hook for transpiling -function transform(code: string, filename: string): string { - let patchedCode = code.replace( - // Work around the fact that Babel classes can't extend natives. - /class FastBuffer extends Uint8Array {\s+constructor\(arg1, arg2, arg3\) {\s+super\(arg1, arg2, arg3\);\s+}\s+}/g, - "function FastBuffer(arg1, arg2, arg3) {\n" + - " var self = new Uint8Array(arg1, arg2, arg3);\n" + - " Object.setPrototypeOf(self, FastBuffer.prototype);\n" + - " return self;\n" + - "}; Object.setPrototypeOf(FastBuffer, Uint8Array); Object.setPrototypeOf(FastBuffer.prototype, Uint8Array.prototype);" - ); - let transformedCode = babelTransform(patchedCode, { - plugins: [ - // Prepack doesn't support classes or destructuring yet. - "transform-es2015-classes", - "transform-es2015-destructuring", - "transform-es2015-parameters", - ], - retainLines: true, - }); - return transformedCode.code; -} - -export default function(realm: Realm): ObjectValue { - let intrinsicName = 'process.binding("contextify")'; - let obj = new ObjectValue(realm, realm.intrinsics.ObjectPrototype, intrinsicName); - - // Contextify - - function runInDebugContextImpl(code) { - // TODO: Make this an abstract result. - throw realm.createErrorThrowCompletion( - realm.intrinsics.Error, - "The V8 debugger is not available from within Prepack." - ); - } - - function makeContextImpl() { - // TODO: Allow sub-realms to be created and restored. - throw realm.createErrorThrowCompletion(realm.intrinsics.Error, "makeContext is not yet implemented in Prepack."); - } - - function isContextImpl() { - // TODO: We don't have a way to create contexts so this is always false. - return realm.intrinsics.false; - } - - // ContextifyScript - - class ContextifyScriptInternal { - ast: BabelNodeFile; - constructor(ast: BabelNodeFile) { - this.ast = ast; - } - } - - function ContextifyScriptConstructor(context, args, argLength, newTarget) { - if (!newTarget) { - throw realm.createErrorThrowCompletion(realm.intrinsics.Error, "Must call vm.Script as a constructor."); - } - let proto = Get(realm, newTarget, "prototype"); - if (!(proto instanceof ObjectValue)) { - realm = GetFunctionRealm(realm, newTarget); - proto = ContextifyScriptPrototype; - } - - invariant(args[0] instanceof ConcreteValue); - let code = To.ToString(realm, args[0]); - - let options = args[1]; - let filename = getFilenameArg(options); - let lineOffset = getLineOffsetArg(options); - let columnOffset = getColumnOffsetArg(options); - let displayErrors = getDisplayErrorsArg(options); - let cachedDataBuf = getCachedData(options); - let produceCachedData = getProduceCachedData(options); - - let resolvedOptions = { - filename: filename, - lineOffset: lineOffset, - columnOffset: columnOffset, - displayErrors: displayErrors, - cachedDataBuf: undefined, // Not serializable. - produceCachedData: produceCachedData, - }; - - let intrinsicConstructor = `new (${intrinsicName}).ContextifyScript(${JSON.stringify(code)}, ${JSON.stringify( - resolvedOptions - )})`; - - let self = new ObjectValue(realm, proto, intrinsicConstructor); - - if (cachedDataBuf.length) { - Properties.Set(realm, obj, "cachedDataRejected", realm.intrinsics.true, true); - } - - if (produceCachedData) { - Properties.Set(realm, obj, "cachedDataProduced", realm.intrinsics.false, true); - } - - let ast; - try { - // TODO: Somehow pass columnOffset to Babylon. - ast = parse(realm, transform(code, filename), filename, "script", 1 + lineOffset); - } catch (e) { - if (displayErrors && e instanceof ThrowCompletion) { - decorateErrorStack(e); - } - throw e; - } - // TODO: Pick up source map files and automatically fix up source locations. - - (self: any).$InternalSlot = new ContextifyScriptInternal(ast); - - return self; - } - - let runInDebugContext = new NativeFunctionValue( - realm, - `${intrinsicName}.runInDebugContext`, - "runInDebugContext", - 0, - runInDebugContextImpl - ); - Properties.Set(realm, obj, "runInDebugContext", runInDebugContext, true); - - let makeContext = new NativeFunctionValue(realm, `${intrinsicName}.makeContext`, "makeContext", 0, makeContextImpl); - Properties.Set(realm, obj, "makeContext", makeContext, true); - - let isContext = new NativeFunctionValue(realm, `${intrinsicName}.isContext`, "isContext", 0, isContextImpl); - Properties.Set(realm, obj, "isContext", isContext, true); - - let ContextifyScript = new NativeFunctionValue( - realm, - `${intrinsicName}.ContextifyScript`, - "ContextifyScript", - 0, - ContextifyScriptConstructor, - true - ); - Properties.Set(realm, obj, "ContextifyScript", ContextifyScript, true); - - // ContextifyScript.prototype - - function runInThisContext(self, args) { - let timeout = getTimeoutArg(args[0]); - let displayErrors = getDisplayErrorsArg(args[0]); - let breakOnSigint = getBreakOnSigintArg(args[0]); - return evalMachine(self, timeout, displayErrors, breakOnSigint); - } - - function runInContext(self, [sandbox, options]) { - throw realm.createErrorThrowCompletion( - realm.intrinsics.Error, - "Cannot run in arbitrary contexts within Prepack yet." - ); - } - - function decorateErrorStack(completion: AbruptCompletion): void { - let error = completion.value; - if (!(error instanceof ObjectValue)) { - return; - } - - let errorData = error.$ErrorData; - if (!errorData) { - return; - } - let errorLocation = errorData.locationData; - if (!errorLocation || errorLocation.stackDecorated) { - return; - } - - let stack = Get(realm, error, "stack"); - if (!(stack instanceof StringValue)) { - return; - } - - let lines = errorLocation.sourceCode.split(/\r?\n/); - let line = lines[errorLocation.loc.line - 1] || ""; - let arrow = " ".repeat(errorLocation.loc.column) + "^"; - let decoratedStack = `${errorLocation.filename}:${errorLocation.loc.line}\n${line}\n${arrow}\n${stack.value}`; - Properties.Set(realm, error, "stack", new StringValue(realm, decoratedStack), false); - - errorLocation.stackDecorated = true; - } - - function getBreakOnSigintArg(options: Value): boolean { - if (options instanceof UndefinedValue || options instanceof StringValue) { - return false; - } - if (!(options instanceof ObjectValue)) { - throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "options must be an object"); - } - - let value = Get(realm, options, "breakOnSigint"); - invariant(value instanceof ConcreteValue); - return value instanceof BooleanValue && value.value; - } - - function getTimeoutArg(options: Value): number { - if (options instanceof UndefinedValue || options instanceof StringValue) { - return -1; - } - if (!(options instanceof ObjectValue)) { - throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "options must be an object"); - } - - let value = Get(realm, options, "timeout"); - invariant(value instanceof ConcreteValue); - if (value instanceof UndefinedValue) { - return -1; - } - let timeout = To.ToInteger(realm, value); - - if (timeout <= 0) { - throw realm.createErrorThrowCompletion(realm.intrinsics.RangeError, "timeout must be a positive number"); - } - - return timeout; - } - - function getDisplayErrorsArg(options: Value): boolean { - if (options instanceof UndefinedValue || options instanceof StringValue) { - return true; - } - if (!(options instanceof ObjectValue)) { - throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "options must be an object"); - } - - let value = Get(realm, options, "displayErrors"); - invariant(value instanceof ConcreteValue); - if (value instanceof UndefinedValue) { - return true; - } - return To.ToBoolean(realm, value); - } - - function getFilenameArg(options: Value): string { - const defaultFilename = "evalmachine."; - if (options instanceof UndefinedValue) { - return defaultFilename; - } - if (options instanceof StringValue) { - return options.value; - } - if (!(options instanceof ObjectValue)) { - throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "options must be an object"); - } - - let value = Get(realm, options, "filename"); - invariant(value instanceof ConcreteValue); - if (value instanceof UndefinedValue) { - return defaultFilename; - } - return To.ToString(realm, value); - } - - function getCachedData(options: Value): Uint8Array { - if (!(options instanceof ObjectValue)) { - return new Uint8Array(0); - } - - let value = Get(realm, options, "cachedData"); - invariant(value instanceof ConcreteValue); - if (value instanceof UndefinedValue) { - return new Uint8Array(0); - } - - if ( - !(value instanceof ObjectValue) || - !value.$ViewedArrayBuffer || - !(value.$ViewedArrayBuffer.$ArrayBufferData instanceof Uint8Array) - ) { - throw realm.createErrorThrowCompletion( - realm.intrinsics.TypeError, - "options.cachedData must be a Buffer instance" - ); - } - - return value.$ViewedArrayBuffer.$ArrayBufferData; - } - - function getProduceCachedData(options: Value): boolean { - if (!(options instanceof ObjectValue)) { - return false; - } - - let value = Get(realm, options, "produceCachedData"); - invariant(value instanceof ConcreteValue); - return value instanceof BooleanValue && value.value; - } - - function getLineOffsetArg(options: Value): number { - const defaultLineOffset = 0; - if (!(options instanceof ObjectValue)) { - return defaultLineOffset; - } - let value = Get(realm, options, "lineOffset"); - invariant(value instanceof ConcreteValue); - return value instanceof UndefinedValue ? defaultLineOffset : To.ToInteger(realm, value); - } - - function getColumnOffsetArg(options: Value): number { - const defaultColumnOffset = 0; - if (!(options instanceof ObjectValue)) { - return defaultColumnOffset; - } - let value = Get(realm, options, "columnOffset"); - invariant(value instanceof ConcreteValue); - return value instanceof UndefinedValue ? defaultColumnOffset : To.ToInteger(realm, value); - } - - function evalMachine(self: Value, timeout: number, displayErrors: boolean, breakOnSigint: boolean): Value { - if (!(self instanceof ObjectValue) || !((self: any).$InternalSlot instanceof ContextifyScriptInternal)) { - throw realm.createErrorThrowCompletion( - realm.intrinsics.Error, - "Script methods can only be called on script instances." - ); - } - let script = ((self: any).$InternalSlot: ContextifyScriptInternal); - - let environment = realm.$GlobalEnv; - - let previousContext = realm.getRunningContext(); - previousContext.suspend(); - - let context = realm.createExecutionContext(); - context.lexicalEnvironment = environment; - context.variableEnvironment = environment; - context.realm = realm; - - realm.pushContext(context); - - let result; - try { - result = environment.evaluateCompletion(script.ast, false); - } finally { - context.suspend(); - realm.popContext(context); - invariant(context.lexicalEnvironment === realm.$GlobalEnv); - realm.onDestroyScope(context.lexicalEnvironment); - } - invariant(realm.getRunningContext() === previousContext); - previousContext.resume(); - - if (result instanceof EmptyValue) { - return realm.intrinsics.undefined; - } else if (result instanceof Value) { - return result; - } else { - invariant(result instanceof AbruptCompletion); - if (displayErrors) { - decorateErrorStack(result); - } - throw result; - } - } - - let ContextifyScriptPrototype = new ObjectValue( - realm, - realm.intrinsics.ObjectPrototype, - `${intrinsicName}.ContextifyScript.prototype` - ); - - ContextifyScriptPrototype.defineNativeMethod("runInContext", 2, runInContext); - ContextifyScriptPrototype.defineNativeMethod("runInThisContext", 1, runInThisContext); - - Properties.DefinePropertyOrThrow(realm, ContextifyScript, "prototype", { - value: ContextifyScriptPrototype, - writable: true, - enumerable: false, - configurable: false, - }); - - Properties.DefinePropertyOrThrow(realm, ContextifyScriptPrototype, "constructor", { - value: ContextifyScript, - writable: true, - enumerable: false, - configurable: true, - }); - - return obj; -} diff --git a/src/intrinsics/node/fs.js b/src/intrinsics/node/fs.js deleted file mode 100644 index 7b499a9ab..000000000 --- a/src/intrinsics/node/fs.js +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -/* @flow */ - -import invariant from "../../invariant.js"; -import type { Realm } from "../../realm.js"; -import { AbstractValue, NumberValue, ObjectValue, StringValue } from "../../values/index.js"; -import { ValuesDomain } from "../../domains/index.js"; -import buildExpressionTemplate from "../../utils/builder.js"; -import { getNodeBufferFromTypedArray } from "./utils.js"; -import { Properties, To } from "../../singletons.js"; - -declare var process: any; - -export default function(realm: Realm): ObjectValue { - let intrinsicName = 'process.binding("fs")'; - let nativeFS = process.binding("fs"); - - // fs - let obj = new ObjectValue(realm, realm.intrinsics.ObjectPrototype, intrinsicName); - obj.defineNativeMethod("FSInitialize", 0, (context, args) => { - // TODO: Implement the native implementation. - return realm.intrinsics.undefined; - }); - obj.defineNativeMethod("internalModuleStat", 0, (context, args) => { - const fileName = To.ToString(realm, args[0]); - return new NumberValue(realm, nativeFS.internalModuleStat(fileName)); - }); - obj.defineNativeMethod("lstat", 0, (context, args) => { - const path = To.ToString(realm, args[0]); - invariant(args[1] instanceof ObjectValue); - const buffer = getNodeBufferFromTypedArray(realm, args[1]); - const float64buffer = new Float64Array(buffer.buffer); - nativeFS.lstat(path, float64buffer); - return args[1]; - }); - obj.defineNativeMethod("fstat", 0, (context, args) => { - const fd = To.ToNumber(realm, args[0]); - invariant(args[1] instanceof ObjectValue); - const buffer = getNodeBufferFromTypedArray(realm, args[1]); - const float64buffer = new Float64Array(buffer.buffer); - nativeFS.fstat(fd, float64buffer); - return args[1]; - }); - obj.defineNativeMethod("open", 0, (context, args) => { - const path = To.ToString(realm, args[0]); - const flags = To.ToNumber(realm, args[1]); - const mode = To.ToNumber(realm, args[2]); - const fd = nativeFS.open(path, flags, mode); - return new NumberValue(realm, fd); - }); - obj.defineNativeMethod("close", 0, (context, args) => { - const fd = To.ToNumber(realm, args[0]); - nativeFS.close(fd); - return realm.intrinsics.undefined; - }); - obj.defineNativeMethod("read", 0, (context, args) => { - const fd = To.ToNumber(realm, args[0]); - invariant(args[1] instanceof ObjectValue); - const buffer = getNodeBufferFromTypedArray(realm, args[1]); - const offset = To.ToNumber(realm, args[2]); - const length = To.ToNumber(realm, args[3]); - const position = args[4] === realm.intrinsics.undefined ? undefined : To.ToNumber(realm, args[4]); - const bytesRead = nativeFS.read(fd, buffer, offset, length, position); - return new NumberValue(realm, bytesRead); - }); - obj.defineNativeMethod("internalModuleReadFile", 0, (context, args) => { - const path = To.ToString(realm, args[0]); - const result = nativeFS.internalModuleReadFile(path); - if (result === undefined) { - return realm.intrinsics.undefined; - } - return new StringValue(realm, result); - }); - - let FSReqWrapTemplateSrc = `${intrinsicName}.FSReqWrap`; - let FSReqWrapTemplate = buildExpressionTemplate(FSReqWrapTemplateSrc); - let val = AbstractValue.createFromTemplate(realm, FSReqWrapTemplate, ObjectValue, [], FSReqWrapTemplateSrc); - val.values = new ValuesDomain(new Set([new ObjectValue(realm)])); - val.intrinsicName = FSReqWrapTemplateSrc; - Properties.DefinePropertyOrThrow(realm, obj, "FSReqWrap", { - value: val, - writable: true, - configurable: true, - enumerable: true, - }); - - // TODO: Implement more of the native methods here. Ideally all of them should - // just be automatically proxied. - - return obj; -} diff --git a/src/intrinsics/node/process.js b/src/intrinsics/node/process.js deleted file mode 100644 index 941e8d505..000000000 --- a/src/intrinsics/node/process.js +++ /dev/null @@ -1,649 +0,0 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -/* @flow */ - -import invariant from "../../invariant.js"; -import type { Realm } from "../../realm.js"; -import { - AbstractObjectValue, - AbstractValue, - ArrayValue, - BooleanValue, - ConcreteValue, - FunctionValue, - NativeFunctionValue, - NumberValue, - ObjectValue, - StringValue, -} from "../../values/index.js"; -import { Get } from "../../methods/index.js"; -import { ValuesDomain } from "../../domains/index.js"; -import { Properties, To } from "../../singletons.js"; -import buildExpressionTemplate from "../../utils/builder.js"; -import initializeBuffer from "./buffer.js"; -import initializeContextify from "./contextify.js"; -import initializeFS from "./fs.js"; -import { copyProperty, createDeepIntrinsic } from "./utils.js"; - -declare var process: any; - -function initializeTimerWrap(realm) { - let obj = new ObjectValue(realm, realm.intrinsics.ObjectPrototype, "process.binding('timer_wrap')"); - let constructor = new NativeFunctionValue( - realm, - "process.binding('timer_wrap').Timer", - "Timer", - 0, - (context, args) => { - return realm.intrinsics.undefined; - } - ); - Properties.OrdinaryDefineOwnProperty(realm, obj, "Timer", { - value: constructor, - writable: true, - enumerable: true, - configurable: true, - }); - // TODO: Implement the rest of this protocol as needed. - return obj; -} - -function initializeTTYWrap(realm) { - let nativeTTYWrap = process.binding("tty_wrap"); - // let nativeTTY = nativeTTYWrap.TTY; - let obj = new ObjectValue(realm, realm.intrinsics.ObjectPrototype, "process.binding('tty_wrap')"); - - let constructor = new NativeFunctionValue( - realm, - "process.binding('tty_wrap').TTY", - "TTY", - 0, - (context, args, argCount, NewTarget) => { - invariant(args[0] instanceof ConcreteValue); - let fd = To.ToInteger(realm, args[0]); - invariant(args[1] instanceof ConcreteValue); - let value = To.ToBoolean(realm, args[1]); - - invariant(NewTarget, "TTY must be called as a constructor."); - - let proto = Get(realm, NewTarget, new StringValue(realm, "prototype")); - if (!(proto instanceof ObjectValue)) { - proto = TTYPrototype; - } - - // TODO: Store nativeTTY in an internal slot so that it can be used if this - // object gets passed to another native call. - - return new ObjectValue(realm, proto, `new (process.binding('tty_wrap').TTY)(${fd}, ${value.toString()})`); - } - ); - Properties.OrdinaryDefineOwnProperty(realm, obj, "TTY", { - value: constructor, - writable: true, - enumerable: true, - configurable: true, - }); - - let TTYPrototype = new ObjectValue( - realm, - realm.intrinsics.ObjectPrototype, - "process.binding('tty_wrap').TTY.prototype" - ); - - TTYPrototype.defineNativeMethod("setBlocking", 0, (context, args) => { - return realm.intrinsics.undefined; - }); - TTYPrototype.defineNativeMethod("getWindowSize", 0, (context, args) => { - return realm.intrinsics.undefined; - }); - TTYPrototype.defineNativeMethod("writeUtf8String", 0, (context, args) => { - // TODO: Store this as a side-effect. When we do that, we need the first arg - // to be passed along to that side-effect. - // let req = args[0]; - let content = args[1]; - invariant(content instanceof StringValue); - return realm.intrinsics.undefined; - }); - - Properties.DefinePropertyOrThrow(realm, constructor, "prototype", { - value: TTYPrototype, - writable: true, - enumerable: false, - configurable: false, - }); - - obj.defineNativeMethod("guessHandleType", 0, (context, args) => { - let fd = To.ToInteger(realm, args[0]); - return new StringValue(realm, nativeTTYWrap.guessHandleType(fd)); - // TODO: Make this abstract so that changing the pipe at runtime is - // possible. Currently this causes an introspection error. - - // let types = new TypesDomain(StringValue); - // let values = new ValuesDomain(new Set([ - // new StringValue(realm, "TCP"), - // new StringValue(realm, "TTY"), - // new StringValue(realm, "UDP"), - // new StringValue(realm, "FILE"), - // new StringValue(realm, "PIPE"), - // new StringValue(realm, "UNKNOWN") - // ])); - // let buildNode = buildExpressionTemplate( - // `(process.binding('tty_wrap').guessHandleType(${fd}))` - // )(this.realm.preludeGenerator); - // return realm.createAbstract(types, values, [], buildNode, undefined, `(process.binding('tty_wrap').guessHandleType(${fd}))`); - }); - - obj.defineNativeMethod("isTTY", 0, (context, args) => { - let fd = To.ToInteger(realm, args[0]); - const isTTYtemplateSrc = `(process.binding('tty_wrap').isTTY(${fd}))`; - const isTTYtemplate = buildExpressionTemplate(isTTYtemplateSrc); - let val = AbstractValue.createFromTemplate(realm, isTTYtemplate, BooleanValue, [], isTTYtemplateSrc); - val.intrinsicName = isTTYtemplateSrc; - return val; - }); - // TODO: Implement the rest of this protocol. - return obj; -} - -function initializeSignalWrap(realm) { - // TODO: Implement more of this protocol. When doing so, we'll likely need to - // forward it to the native implementation. - // let nativeSignalWrap = process.binding("signal_wrap"); - let obj = new ObjectValue(realm, realm.intrinsics.ObjectPrototype, "process.binding('signal_wrap')"); - - let constructor = new NativeFunctionValue( - realm, - "process.binding('signal_wrap').Signal", - "Signal", - 0, - (context, args) => { - return realm.intrinsics.undefined; - } - ); - Properties.OrdinaryDefineOwnProperty(realm, obj, "Signal", { - value: constructor, - writable: true, - enumerable: true, - configurable: true, - }); - - let SignalPrototype = new ObjectValue( - realm, - realm.intrinsics.ObjectPrototype, - "process.binding('signal_wrap').Signal.prototype" - ); - SignalPrototype.defineNativeMethod("unref", 0, (context, args) => { - // TODO: Track the side-effect of this. - return realm.intrinsics.undefined; - }); - SignalPrototype.defineNativeMethod("start", 0, (context, args) => { - // TODO: Track the side-effect of this. - return realm.intrinsics.undefined; - }); - SignalPrototype.defineNativeMethod("close", 0, (context, args) => { - // TODO: Track the side-effect of this. - return realm.intrinsics.undefined; - }); - - Properties.DefinePropertyOrThrow(realm, constructor, "prototype", { - value: SignalPrototype, - writable: true, - enumerable: false, - configurable: false, - }); - - // TODO - return obj; -} - -function initializeStreamWrap(realm) { - // let nativeStreamWrap = process.binding("stream_wrap"); - let obj = new ObjectValue(realm, realm.intrinsics.ObjectPrototype, "process.binding('stream_wrap')"); - - let constructor = new NativeFunctionValue( - realm, - "process.binding('stream_wrap').WriteWrap", - "WriteWrap", - 0, - (context, args) => { - return realm.intrinsics.undefined; - } - ); - Properties.OrdinaryDefineOwnProperty(realm, obj, "WriteWrap", { - value: constructor, - writable: true, - enumerable: true, - configurable: true, - }); - - let WriteWrapPrototype = new ObjectValue( - realm, - realm.intrinsics.ObjectPrototype, - "process.binding('stream_wrap').WriteWrap.prototype" - ); - WriteWrapPrototype.defineNativeMethod("unref", 0, (context, args) => { - // TODO: Track the side-effect of this. - return realm.intrinsics.undefined; - }); - - Properties.DefinePropertyOrThrow(realm, constructor, "prototype", { - value: WriteWrapPrototype, - writable: true, - enumerable: false, - configurable: false, - }); - - let ShutdownWrap = createAbstractValue(realm, FunctionValue, "process.binding('stream_wrap').ShutdownWrap"); - Properties.DefinePropertyOrThrow(realm, obj, "ShutdownWrap", { - value: ShutdownWrap, - writable: true, - configurable: true, - enumerable: true, - }); - - // TODO - return obj; -} - -function initializeFSEvent(realm) { - let obj = new ObjectValue(realm, realm.intrinsics.ObjectPrototype, "process.binding('fs_event_wrap')"); - let FSEvent = createAbstractValue(realm, FunctionValue, "process.binding('fs_event_wrap').FSEvent"); - Properties.DefinePropertyOrThrow(realm, obj, "FSEvent", { - value: FSEvent, - writable: true, - configurable: true, - enumerable: true, - }); - - // TODO - return obj; -} - -function initializeURL(realm) { - let obj = new ObjectValue(realm, realm.intrinsics.ObjectPrototype); - // TODO - return obj; -} - -function initializeUtil(realm) { - let obj = new ObjectValue(realm, realm.intrinsics.ObjectPrototype, 'process.binding("util")'); - obj.defineNativeMethod("isUint8Array", 0, (context, args) => { - let arr = args[0]; - if (arr instanceof ObjectValue && arr.$TypedArrayName === "Uint8Array") { - return realm.intrinsics.true; - } - return realm.intrinsics.false; - }); - copyProperty( - realm, - process.binding("util"), - obj, - "pushValToArrayMax", - new NumberValue(realm, process.binding("util").pushValToArrayMax, 'process.binding("util").pushValToArrayMax') - ); - // TODO - return obj; -} - -function createAbstractValue(realm, type, intrinsicName): AbstractObjectValue { - let template = buildExpressionTemplate(intrinsicName); - let val = AbstractValue.createFromTemplate(realm, template, ObjectValue, [], intrinsicName); - val.values = new ValuesDomain(new Set([new ObjectValue(realm)])); - val.intrinsicName = intrinsicName; - return (val: any); -} - -function createIntrinsicArrayValue(realm, intrinsicName) { - // Like ArrayCreate but accepts an intrinsic name. - let obj = new ArrayValue(realm, intrinsicName); - obj.setExtensible(true); - Properties.OrdinaryDefineOwnProperty(realm, obj, "length", { - value: realm.intrinsics.zero, - writable: true, - enumerable: false, - configurable: false, - }); - return obj; -} - -function reverseConfigJSON(config) { - // Hack to restore the gyp config format - let json = JSON.stringify(process.config).replace(/"/g, "'"); - return "\n" + json; -} - -export default function(realm: Realm, processArgv: Array): ObjectValue { - if (!realm.useAbstractInterpretation) { - invariant(false, "Realm is not enabled for Abstract Interpretation"); - } - // TODO: This causes a dependency on the native `process` which doesn't - // exist in all environments such as the webpack version. - - // Constant bindings - // TODO: Implement icu module so that we can let hasIntl be true. - let configOverride = { ...process.binding("config"), hasIntl: false }; - // By the time we run the host has already deleted natives.config so we have - // to restore it. - let nativeOverride = { ...process.binding("natives"), config: reverseConfigJSON(process.config) }; - let config = createDeepIntrinsic(realm, configOverride, 'process.binding("config")'); - let constants = createDeepIntrinsic(realm, process.binding("constants"), 'process.binding("constants")'); - let natives = createDeepIntrinsic(realm, nativeOverride, 'process.binding("natives")'); - - // Built-in native bindings - let contextify = initializeContextify(realm); - let fs = initializeFS(realm); - let fsEvent = initializeFSEvent(realm); - let url = initializeURL(realm); - let timerWrap = initializeTimerWrap(realm); - let ttyWrap = initializeTTYWrap(realm); - let signalWrap = initializeSignalWrap(realm); - let streamWrap = initializeStreamWrap(realm); - let caresWrap = createAbstractValue(realm, ObjectValue, 'process.binding("cares_wrap")'); - let tcpWrap = createAbstractValue(realm, ObjectValue, 'process.binding("tcp_wrap")'); - tcpWrap.makeSimple(); - let pipeWrap = createAbstractValue(realm, ObjectValue, 'process.binding("pipe_wrap")'); - pipeWrap.makeSimple(); - let uv = createAbstractValue(realm, ObjectValue, 'process.binding("uv")'); - let buffer = initializeBuffer(realm); - let util = initializeUtil(realm); - let os = createAbstractValue(realm, ObjectValue, 'process.binding("os")'); - os.makeSimple(); - - // List of loaded native modules - let moduleLoadList = createIntrinsicArrayValue(realm, "process.moduleLoadList"); - - // The process object - let obj = new ObjectValue(realm, realm.intrinsics.ObjectPrototype, "process"); - obj.defineNativeMethod("binding", 1, (context, args) => { - let arg0 = args.length < 1 ? realm.intrinsics.undefined : args[0]; - let module = To.ToString(realm, arg0); - // TODO: Add the module to the moduleLoadList but don't track that - // as a side-effect. - switch (module) { - // Constants - case "config": - return config; - case "constants": - return constants; - case "natives": - return natives; - - // Built-in bindings - case "contextify": - return contextify; - case "fs": - return fs; - case "fs_event_wrap": - return fsEvent; - case "url": - return url; - case "uv": - return uv; - case "buffer": - return buffer; - case "util": - return util; - case "os": - return os; - case "timer_wrap": - return timerWrap; - case "tty_wrap": - return ttyWrap; - case "cares_wrap": - return caresWrap; - case "tcp_wrap": - return tcpWrap; - case "pipe_wrap": - return pipeWrap; - case "stream_wrap": - return streamWrap; - case "signal_wrap": - return signalWrap; - - default: - throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, `No such module: ${module}`); - } - }); - - copyProperty(realm, process, obj, "moduleLoadList", moduleLoadList); - - // Constants on the process - let constantNames = [ - "version", - "versions", - "_promiseRejectEvent", - "arch", - "platform", - "release", - "features", - "_needImmediateCallback", - ]; - for (let name of constantNames) { - let value = createDeepIntrinsic(realm, process[name], "process." + name); - copyProperty(realm, process, obj, name, value); - } - - // process._events is a mutable object with null prototype. - let _events = new ObjectValue(realm, realm.intrinsics.null, "process._events"); - copyProperty(realm, process, obj, "_events", _events); - - // TODO: When abstract numbers in string templates is implemented, turn this - // back into an abstract value. - // let pid = createAbstractValue(realm, NumberValue, "process.pid"); - let pid = new NumberValue(realm, 0, "process.pid"); - copyProperty(realm, process, obj, "pid", pid); - let debugPort = createAbstractValue(realm, NumberValue, "process.debugPort"); - copyProperty(realm, process, obj, "debugPort", debugPort); - let title = createAbstractValue(realm, StringValue, "process.title"); - copyProperty(realm, process, obj, "title", title); - - // process.execArgv should probably be passed as an argument to the compile - // step rather than letting arbitrary options be passed to the program. - // For now I'll just hard code it as empty array. - // TODO: Allow execArgv to be passed as a compiler option. - let execArgv = createIntrinsicArrayValue(realm, "process.execArgv"); - copyProperty(realm, process, obj, "execArgv", execArgv); - - let cwd = new NativeFunctionValue(realm, "process.cwd", "cwd", 0, (context, args) => { - return new StringValue(realm, process.cwd(), "process.cwd()"); - }); - copyProperty(realm, process, obj, "cwd", cwd); - - // These properties all depend on options being defined in "execArgv" but - // since we hard coded it, none of this will be added. - // "_eval" : string - // "_print_eval" : boolean - // "_syntax_check_only" : boolean - // "_forceRepl" : boolean - // "noDeprecation" : boolean - // "noProcessWarnings" : boolean - // "traceProcessWarnings" : boolean - // "throwDeprecation" : boolean - // "_noBrowserGlobals" : boolean - // "profProcess" : boolean - // "traceDeprecation" : boolean - // "_debugWaitConnect" : boolean - - // "_preload_modules" gets looped over so it needs to be known but typically - // we don't need to do this so we can just leave it not defined. - - // Side-effectful Methods - - let methodNames = [ - "_startProfilerIdleNotifier", - "_stopProfilerIdleNotifier", - "_getActiveRequests", - "_getActiveHandles", - "reallyExit", - "abort", - "chdir", - "umask", - - // Start Posix only - "getuid", - "geteuid", - "setuid", - "seteuid", - - "setgid", - "setegid", - "getgid", - "getegid", - - "getgroups", - "setgroups", - "initgroups", - // End Posix only - - "_kill", - - "_debugProcess", - "_debugPause", - "_debugEnd", - - "hrtime", - - "cpuUsage", - - "dlopen", - - "uptime", - "memoryUsage", - - "_linkedBinding", - - "_setupNextTick", - "_setupPromises", - "_setupDomainUse", - ]; - - for (let name of methodNames) { - let abstractMethod = createAbstractValue(realm, FunctionValue, "process." + name); - copyProperty(realm, process, obj, name, abstractMethod); - } - - let argv0 = new StringValue(realm, process.argv0, "process.argv0"); - Properties.DefinePropertyOrThrow(realm, obj, "argv0", { - value: argv0, - writable: false, - configurable: true, - enumerable: true, - }); - - let argv = createAbstractValue(realm, ObjectValue, "process.argv"); - - Properties.DefinePropertyOrThrow(realm, argv, "0", { - value: argv0, - writable: true, - configurable: true, - enumerable: true, - }); - - Properties.DefinePropertyOrThrow(realm, argv, "1", { - value: new StringValue(realm, processArgv[1]), - writable: true, - configurable: true, - enumerable: true, - }); - - Properties.DefinePropertyOrThrow(realm, argv, "indexOf", { - value: new NativeFunctionValue(realm, "process.argv.indexOf", "indexOf", 0, (context, args) => { - return realm.intrinsics.false; - }), - writable: true, - configurable: true, - enumerable: true, - }); - - argv.makeSimple(); - copyProperty(realm, process, obj, "argv", argv); - - let execPath = new StringValue(realm, process.execPath, "process.execPath"); - copyProperty(realm, process, obj, "execPath", execPath); - - let env = new ObjectValue(realm, realm.intrinsics.ObjectPrototype, "process.env"); - // TODO: This abstract value doesn't work with a conditional for some reason. - Properties.DefinePropertyOrThrow(realm, env, "NODE_NO_WARNINGS", { - value: new StringValue(realm, "0", "process.env.NODE_NO_WARNINGS"), - writable: true, - configurable: true, - enumerable: true, - }); - - // Uncomment this to debug the module resolution system. - // DefinePropertyOrThrow(realm, env, "NODE_DEBUG", { - // value: new StringValue( - // realm, "module", "process.env.NODE_DEBUG" - // ), - // writable: true, - // configurable: true, - // enumerable: true, - // }); - env.makeSimple(); - copyProperty(realm, process, obj, "env", env); - - // This method just gets passed a value from the initialization code and - // then deletes itself. - // TODO: The generated code needs to either always invoke this (make it - // abstract) or, if we assume it has been done, it doesn't need to delete it. - obj.defineNativeMethod("_setupProcessObject", 1, (self, [pushValueToArray]) => { - Properties.OrdinaryDelete(realm, obj, "_setupProcessObject"); - return realm.intrinsics.undefined; - }); - - // This method injects a generic global promise reject callback. In real - // environment we'd want to call this at rejections but we can safely skip it. - obj.defineNativeMethod("_setupPromises", 1, (self, [promiseRejectCallback]) => { - Properties.OrdinaryDelete(realm, obj, "_setupPromises"); - return realm.intrinsics.undefined; - }); - - // TODO: Support Promises. Set up a micro task runner and invoke the - // tickCallback as needed. - obj.defineNativeMethod("_setupNextTick", 1, (self, [tickCallback, runMicrotasks]) => { - Properties.OrdinaryDelete(realm, obj, "_setupNextTick"); - let runMicrotasksCallback = new NativeFunctionValue( - realm, - "(function() { throw new Error('TODO runMicrotasks not reachable') })", - "runMicrotasks", - 0, - (context, args) => { - // TODO: Implement Promises and micro tasks. - return realm.intrinsics.undefined; - } - ); - Properties.OrdinaryDefineOwnProperty(realm, runMicrotasks, "runMicrotasks", { - value: runMicrotasksCallback, - writable: true, - enumerable: true, - configurable: true, - }); - let tickInfo = new ObjectValue( - realm, - realm.intrinsics.ObjectPrototype, - "(function() { throw new Error('TODO tickInfo is not reachable in the host environment') })" - ); - Properties.OrdinaryDefineOwnProperty(realm, tickInfo, "0", { - value: realm.intrinsics.zero, - writable: true, - enumerable: true, - configurable: true, - }); - Properties.OrdinaryDefineOwnProperty(realm, tickInfo, "1", { - value: realm.intrinsics.zero, - writable: true, - enumerable: true, - configurable: true, - }); - return tickInfo; - }); - - return obj; -} diff --git a/src/intrinsics/node/utils.js b/src/intrinsics/node/utils.js deleted file mode 100644 index 468a2fa10..000000000 --- a/src/intrinsics/node/utils.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -/* @flow */ - -import invariant from "../../invariant.js"; -import { FatalError } from "../../errors.js"; -import type { Realm } from "../../realm.js"; -import { type Value, BooleanValue, ObjectValue, NumberValue, StringValue } from "../../values/index.js"; -import { Properties } from "../../singletons.js"; - -export function getNodeBufferFromTypedArray(realm: Realm, value: ObjectValue): Uint8Array { - let buffer = value.$ViewedArrayBuffer; - invariant(buffer instanceof ObjectValue && buffer.$ArrayBufferData); - return buffer.$ArrayBufferData; -} - -// Takes a value from the host realm and create it into a Prepack Realm. -// TODO: Move this to a bigger general purpose proxy between the environments. -// See issue #644 for more details. -export function createDeepIntrinsic(realm: Realm, value: mixed, intrinsicName: string): Value { - switch (typeof value) { - case "undefined": - return realm.intrinsics.undefined; - case "boolean": - return new BooleanValue(realm, value, intrinsicName); - case "number": - return new NumberValue(realm, value, intrinsicName); - case "string": - return new StringValue(realm, value, intrinsicName); - // $FlowFixMe flow doesn't understand symbols. - case "symbol": - throw new FatalError("Symbol cannot be safely cloned."); - case "function": - throw new FatalError("Functions could be supported but are not yet."); - case "object": { - if (value === null) { - return realm.intrinsics.null; - } - if (Array.isArray(value)) { - throw new FatalError("Arrays are not supported yet."); - } - let prototype = Object.getPrototypeOf(value); - if (prototype !== (Object: any).prototype) { - throw new FatalError( - "Only simple objects are supported for now. Got: " + - ((typeof (prototype: any).constructor === "function" && prototype.constructor.name) || - Object.prototype.toString.call(prototype)) - ); - } - let obj = new ObjectValue( - realm, - realm.intrinsics.ObjectPrototype, - intrinsicName // We use the intrinsic name for Objects to preserve their referential equality - ); - let names = Object.getOwnPropertyNames(value); - for (let name of names) { - // We intentionally invoke the getter on value[name] which resolves any - // lazy getters. - let newValue = createDeepIntrinsic(realm, value[name], intrinsicName + "." + name); - copyProperty(realm, value, obj, name, newValue); - } - return obj; - } - default: - invariant(false); - } -} - -// Define a value with the same descriptor settings as the original object. -export function copyProperty(realm: Realm, originalObject: {}, realmObject: ObjectValue, name: string, value: Value) { - let desc = Object.getOwnPropertyDescriptor(originalObject, name); - if (!desc) { - return; - } - if (desc.get || desc.set) { - throw new FatalError("Getter/setters are not supported because functions are not supported yet."); - } - let newDesc = { - value: value, - writable: !!desc.writable, - configurable: !!desc.configurable, - enumerable: !!desc.enumerable, - }; - Properties.DefinePropertyOrThrow(realm, realmObject, name, newDesc); -} diff --git a/src/options.js b/src/options.js index 39e18776c..fef529e1e 100644 --- a/src/options.js +++ b/src/options.js @@ -11,23 +11,8 @@ import type { ErrorHandler } from "./errors.js"; -export type Compatibility = - | "browser" - | "jsc-600-1-4-17" - | "mobile" - | "node-source-maps" - | "node-cli" - | "fb-www" - | "node-react"; -export const CompatibilityValues = [ - "browser", - "jsc-600-1-4-17", - "mobile", - "node-source-maps", - "node-cli", - "fb-www", - "node-react", -]; +export type Compatibility = "browser" | "jsc-600-1-4-17" | "mobile" | "node-source-maps" | "fb-www" | "node-react"; +export const CompatibilityValues = ["browser", "jsc-600-1-4-17", "mobile", "node-source-maps", "fb-www", "node-react"]; export type InvariantModeTypes = | "throw" diff --git a/src/prepack-node-environment.js b/src/prepack-node-environment.js deleted file mode 100644 index d2bfa1e28..000000000 --- a/src/prepack-node-environment.js +++ /dev/null @@ -1,117 +0,0 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -/* @flow */ - -/* API functions for running Prepack on code that expects to run on Node */ - -import invariant from "./invariant.js"; -import { ExecutionContext } from "./realm.js"; -import Serializer from "./serializer/index.js"; -import { SerializerStatistics } from "./serializer/statistics.js"; -import { Completion } from "./completions.js"; -import { Value } from "./values"; -import construct_realm from "./construct_realm.js"; -import initializeGlobals from "./globals.js"; -import { getRealmOptions, getSerializerOptions } from "./prepack-options"; -import { FatalError } from "./errors.js"; -import initializeBootstrap from "./intrinsics/node/bootstrap.js"; -import initializeProcess from "./intrinsics/node/process.js"; - -import type { PrepackOptions } from "./prepack-options"; -import { defaultOptions } from "./options"; -import type { SourceMap } from "./types.js"; - -declare var process: any; - -export function prepackNodeCLI( - filename: string, - options: PrepackOptions = defaultOptions, - callback: (any, ?{ code: string, map?: SourceMap }) => void -): void { - let serialized; - try { - serialized = prepackNodeCLISync(filename, options); - } catch (err) { - callback(err); - return; - } - callback(null, serialized); -} - -export function prepackNodeCLISync(filename: string, options: PrepackOptions = defaultOptions) { - if (process.version !== "v7.9.0") { - console.warn( - `Prepack's node-cli mode currently only works on Node v7.9.0.\n` + - `You are running version ${process.version} which will likely fail.` - ); - } - - let realm = construct_realm(getRealmOptions(options), undefined, new SerializerStatistics()); - initializeGlobals(realm); - - let processObj = initializeProcess(realm, ["node", filename]); - let bootstrapFn = initializeBootstrap(realm); - - let serializer = new Serializer(realm, getSerializerOptions(options)); - - let context = new ExecutionContext(); - context.lexicalEnvironment = realm.$GlobalEnv; - context.variableEnvironment = realm.$GlobalEnv; - context.realm = realm; - realm.pushContext(context); - let res; - try { - if (bootstrapFn.$Call) { - res = bootstrapFn.$Call(realm.intrinsics.null, [processObj]); - } - } catch (err) { - if (err instanceof Completion) { - res = err; - } else if (err instanceof Error) { - throw err; - } else { - throw new FatalError(err); - } - } finally { - realm.popContext(context); - } - if (res instanceof Completion) { - context = new ExecutionContext(); - realm.pushContext(context); - try { - serializer.logger.logCompletion(res); - } finally { - realm.popContext(context); - realm.onDestroyScope(realm.$GlobalEnv); - } - } - - // Hack: Turn these objects generated by the bootstrap script into - // intrinsics that exist in a preinitialized environment. This ensures - // that we don't end up with duplicates of these. This won't work in an - // uninitialized environment. - let nextTick = realm.$GlobalEnv.execute("process.nextTick", "", ""); - invariant(nextTick instanceof Value); - nextTick.intrinsicName = "process.nextTick"; - let tickCallback = realm.$GlobalEnv.execute("process._tickCallback", "", ""); - invariant(tickCallback instanceof Value); - tickCallback.intrinsicName = "process._tickCallback"; - let tickDomainCallback = realm.$GlobalEnv.execute("process._tickDomainCallback", "", ""); - invariant(tickDomainCallback instanceof Value); - tickDomainCallback.intrinsicName = "process._tickDomainCallback"; - - // Serialize - let sources = [{ filePath: "", fileContents: "" }]; - let serialized = serializer.init(sources, options.sourceMaps); - if (!serialized) { - throw new FatalError("serializer failed"); - } - return serialized; -} diff --git a/src/prepack-node.js b/src/prepack-node.js index c0ebfe99f..a353475f0 100644 --- a/src/prepack-node.js +++ b/src/prepack-node.js @@ -15,7 +15,6 @@ import { defaultOptions } from "./options"; import { FatalError } from "./errors.js"; import { type PrepackOptions } from "./prepack-options"; -import { prepackNodeCLI, prepackNodeCLISync } from "./prepack-node-environment.js"; import { prepackSources } from "./prepack-standalone.js"; import { type SourceMap } from "./types.js"; import { DebugChannel } from "./debugger/server/channel/DebugChannel.js"; @@ -25,7 +24,6 @@ import { SerializerStatistics } from "./serializer/statistics.js"; import fs from "fs"; -export * from "./prepack-node-environment"; export * from "./prepack-standalone"; function createStatistics(options: PrepackOptions) { @@ -87,10 +85,6 @@ export function prepackFile( callback: (any, ?{ code: string, map?: SourceMap }) => void, fileErrorHandler?: (err: ?Error) => void ): void { - if (options.compatibility === "node-cli") { - prepackNodeCLI(filename, options, callback); - return; - } let sourceMapFilename = options.inputSourceMapFilename !== undefined ? options.inputSourceMapFilename : filename + ".map"; fs.readFile(filename, "utf8", function(fileErr, code) { @@ -122,13 +116,6 @@ export function prepackFile( } export function prepackFileSync(filenames: Array, options: PrepackOptions = defaultOptions): SerializedResult { - if (options.compatibility === "node-cli") { - if (filenames.length !== 1) { - console.error(`Does not support multiple file prepack in node-cli mode.`); - process.exit(1); - } - return prepackNodeCLISync(filenames[0], options); - } const sourceFiles = filenames.map(filename => { let code = fs.readFileSync(filename, "utf8"); let sourceMap = ""; diff --git a/src/serializer/ResidualHeapSerializer.js b/src/serializer/ResidualHeapSerializer.js index 5459e2c6e..9db962609 100644 --- a/src/serializer/ResidualHeapSerializer.js +++ b/src/serializer/ResidualHeapSerializer.js @@ -2389,7 +2389,7 @@ export class ResidualHeapSerializer { } if (this._shouldBeWrapped(body)) { - let globalExpression = this.realm.isCompatibleWith("node-cli") ? t.identifier("global") : t.thisExpression(); + let globalExpression = t.thisExpression(); let functionExpression = t.functionExpression(null, [], t.blockStatement(body, globalDirectives)); let callExpression = this.preludeGenerator.usesThis diff --git a/test/node-cli/FileSystem.js b/test/node-cli/FileSystem.js deleted file mode 100644 index f80107782..000000000 --- a/test/node-cli/FileSystem.js +++ /dev/null @@ -1,24 +0,0 @@ -var fs = require("fs"); - -var greetingPath = require.resolve("./Greeting.txt"); - -var greetingJSON = require("./Greeting.json"); - -// The residual program after initialization. -__residual( - "boolean", - function(fs, greetingJSON, greetingPath, console, JSON) { - var greetingText = fs.readFileSync(greetingPath, "utf8"); - - console.log(`${greetingJSON.greeting} ${greetingText} world!`); - - // Currently, we're required to have a return value even though - // we're not going to use it. - return false; - }, - fs, - greetingJSON, - greetingPath, - console, - JSON -); diff --git a/test/node-cli/Greeting.js b/test/node-cli/Greeting.js deleted file mode 100644 index 9cee822ae..000000000 --- a/test/node-cli/Greeting.js +++ /dev/null @@ -1,7 +0,0 @@ -let greeting = "Hello"; -let now = Date.now(); -let future = +new Date(2000, 1, 1); -if (now > future) { - greeting = "Hey"; -} -module.exports = greeting; diff --git a/test/node-cli/Greeting.json b/test/node-cli/Greeting.json deleted file mode 100644 index 6b06c5dd4..000000000 --- a/test/node-cli/Greeting.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "greeting": "Hey" -} diff --git a/test/node-cli/Greeting.txt b/test/node-cli/Greeting.txt deleted file mode 100644 index 5ab2f8a43..000000000 --- a/test/node-cli/Greeting.txt +++ /dev/null @@ -1 +0,0 @@ -Hello \ No newline at end of file diff --git a/test/node-cli/Simple.js b/test/node-cli/Simple.js deleted file mode 100644 index d0808da0b..000000000 --- a/test/node-cli/Simple.js +++ /dev/null @@ -1,15 +0,0 @@ -var greeting = require("./Greeting"); - -// The residual program after initialization. -__residual( - "boolean", - function(greeting, console) { - console.log(greeting + " world!"); - - // Currently, we're required to have a return value even though - // we're not going to use it. - return false; - }, - greeting, - console -); diff --git a/website/js/repl.js b/website/js/repl.js index 02349ad16..9e43afbb2 100644 --- a/website/js/repl.js +++ b/website/js/repl.js @@ -40,7 +40,7 @@ var optionsConfig = [ { type: "choice", name: "compatibility", - choices: ["browser", "jsc-600-1-4-17", "node-source-maps", "node-cli", "node-react"], + choices: ["browser", "jsc-600-1-4-17", "node-source-maps", "node-react"], defaultVal: "node-react", description: "The target environment for Prepack" },