--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -28,16 +28,17 @@
#if defined(XP_WIN)
# include <io.h> /* for isatty() */
#endif
#include <locale.h>
#if defined(MALLOC_H)
# include MALLOC_H /* for malloc_usable_size, malloc_size, _msize */
#endif
#include <math.h>
+#include <sstream>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#ifdef XP_UNIX
# include <sys/mman.h>
@@ -60,16 +61,17 @@
#ifdef XP_WIN
# include "jswin.h"
#endif
#include "jswrapper.h"
#include "shellmoduleloader.out.h"
#include "builtin/ModuleObject.h"
#include "builtin/TestingFunctions.h"
+#include "frontend/BinaryAST.h"
#include "frontend/Parser.h"
#include "gc/GCInternals.h"
#include "jit/arm/Simulator-arm.h"
#include "jit/InlinableNatives.h"
#include "jit/Ion.h"
#include "jit/JitcodeMap.h"
#include "jit/OptimizationTracking.h"
#include "js/Debug.h"
@@ -4372,19 +4374,96 @@ GetModuleLoadPath(JSContext* cx, unsigne
args.rval().setString(str);
} else {
args.rval().setNull();
}
return true;
}
+struct ParseOptions {
+ bool binSerialize;
+ bool dumpParseTreeInDebugMode;
+ ParseOptions()
+ : binSerialize(false)
+ , dumpParseTreeInDebugMode(false)
+ { }
+};
+
+static bool
+ParseAux(JSContext* cx, unsigned argc, Value* vp, ParseOptions& instructions);
+
static bool
Parse(JSContext* cx, unsigned argc, Value* vp)
{
+ ParseOptions options;
+ options.dumpParseTreeInDebugMode = true;
+ return ParseAux(cx, argc, vp, options);
+}
+
+static bool
+CreateBinaryAST(JSContext* cx, unsigned argc, Value* vp)
+{
+ ParseOptions options;
+ options.binSerialize = true;
+ return ParseAux(cx, argc, vp, options);
+}
+
+static bool
+ReadBinaryAST(JSContext* cx, unsigned argc, Value* vp)
+{
+ using namespace js::frontend;
+
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ if (args.length() < 1) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
+ "parse", "0", "s");
+ return false;
+ }
+ if (!args[0].isObject()) {
+ const char* typeName = InformalValueTypeName(args[0]);
+ JS_ReportErrorASCII(cx, "expected object (typed array) to parse, got %s", typeName);
+ return false;
+ }
+
+ RootedObject obj(cx, &args[0].toObject());
+ if (!JS_IsArrayBufferObject(obj)) {
+ const char* typeName = InformalValueTypeName(args[0]);
+ JS_ReportErrorASCII(cx, "expected typed array to parse, got %s", typeName);
+ return false;
+ }
+
+ uint32_t buf_length = 0;
+ bool buf_isSharedMemory = false;
+ uint8_t* buf_data = nullptr;
+ GetArrayBufferLengthAndData(obj, &buf_length, &buf_isSharedMemory, &buf_data);
+
+ std::string buf_str((const char*)buf_data, buf_length);
+ std::istringstream in_stream(buf_str);
+ // FIXME: We need to explicitly use a std::string (even if this means that we copy) to ensure that \0 doesn't kill us
+ // In a real implementation, we'll probably want to replace istringstream with something better.
+ std::cerr << "ReadBinaryAST from " << buf_length << " bytes at " << (void*)buf_data << "\n";
+ std::cerr << "ReadBinaryAST string: " << buf_str.length() << "\n";
+
+ std::ostringstream _debug; // Ignored.
+// in_stream.exceptions(in_stream.exceptions() | std::istringstream::badbit | std::istringstream::failbit | std::istringstream::eofbit );
+
+ ParseNodeAllocator allocator(cx, cx->tempLifoAlloc());
+ if (!binParse(cx, allocator, in_stream, _debug)) {
+ return false;
+ }
+
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+ParseAux(JSContext* cx, unsigned argc, Value* vp, ParseOptions& instructions)
+{
using namespace js::frontend;
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() < 1) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
"parse", "0", "s");
return false;
@@ -4417,20 +4496,43 @@ Parse(JSContext* cx, unsigned argc, Valu
nullptr);
if (!parser.checkOptions())
return false;
ParseNode* pn = parser.parse();
if (!pn)
return false;
#ifdef DEBUG
- DumpParseTree(pn);
- fputc('\n', stderr);
+ if (instructions.dumpParseTreeInDebugMode) {
+ DumpParseTree(pn);
+ fputc('\n', stderr);
+ }
#endif
- args.rval().setUndefined();
+
+ if (!instructions.binSerialize) {
+ args.rval().setUndefined();
+ return true;
+ }
+
+ std::ostringstream out_stream;
+ std::ostringstream _debug; // Ignored.
+ if (!binSerialize(cx, pn, out_stream, _debug)) {
+ return false;
+ }
+ const auto out_string = out_stream.str();
+
+ RootedObject buf_obj(cx, JS_NewArrayBuffer(cx, out_string.length()));
+ uint32_t buf_length;
+ uint8_t* buf_data;
+ bool buf_isSharedMemory;
+ js::GetArrayBufferLengthAndData(buf_obj, &buf_length, &buf_isSharedMemory, &buf_data);
+ std::copy(out_string.begin(), out_string.end(), buf_data);
+ std::cerr << "Just wrote " << (out_string.end() - out_string.begin()) << " bytes at " << (void*)buf_data << "\n";
+
+ args.rval().set(JS::ObjectOrNullValue(buf_obj));
return true;
}
static bool
SyntaxParse(JSContext* cx, unsigned argc, Value* vp)
{
using namespace js::frontend;
@@ -6524,16 +6626,24 @@ static const JSFunctionSpecWithHelp shel
JS_FN_HELP("parse", Parse, 1, 0,
"parse(code)",
" Parses a string, potentially throwing."),
JS_FN_HELP("syntaxParse", SyntaxParse, 1, 0,
"syntaxParse(code)",
" Check the syntax of a string, returning success value"),
+ JS_FN_HELP("jsbinSerialize", CreateBinaryAST, 1, 0,
+"jsbinSerialize(source)",
+" Compile a source string into a binary AST."),
+
+JS_FN_HELP("jsbinParse", ReadBinaryAST, 1, 0,
+"jsbinParse(typedarray)",
+" Read an AST from a binary AST."),
+
JS_FN_HELP("offThreadCompileScript", OffThreadCompileScript, 1, 0,
"offThreadCompileScript(code[, options])",
" Compile |code| on a helper thread. To wait for the compilation to finish\n"
" and run the code, call |runOffThreadScript|. If present, |options| may\n"
" have properties saying how the code should be compiled:\n"
" noScriptRval: use the no-script-rval compiler option (default: false)\n"
" fileName: filename for error messages and debug info\n"
" lineNumber: starting line number for error messages and debug info\n"