Bug 1349917 - Introducing jsbinParse and jsbinSerialize to the js shell draft
authorDavid Teller <dteller@mozilla.com>
Fri, 21 Apr 2017 13:43:50 +0200
changeset 567761 6d506951a416bc051448abe6cf8b4fad9b938d49
parent 567760 0f8dc8c27dd305d3a5eb6d9ffee5c5b4da843b12
child 567762 d4db1ee1b5b3faf894417ba1d13a1ccb9a43f5e2
push id55689
push userdteller@mozilla.com
push dateTue, 25 Apr 2017 14:21:34 +0000
bugs1349917
milestone55.0a1
Bug 1349917 - Introducing jsbinParse and jsbinSerialize to the js shell MozReview-Commit-ID: 1YGWPJ6FtQ1
js/src/shell/js.cpp
--- 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"