Bug 1588861 - Part 4: Add test harness for xdr modules. r=iain
authorcaroline <cullen.caroline@gmail.com>
Tue, 10 Dec 2019 01:46:29 +0000
changeset 506286 b622095c76ab52fdd32c1fa41a1541f3c8b49d01
parent 506285 2a0aacbd11dee6907445c902aa088ab4b9492d6b
child 506287 815a452c73af2cd2f56e3b755b4f163108d23c4f
push id36901
push useraciure@mozilla.com
push dateTue, 10 Dec 2019 21:29:05 +0000
treeherdermozilla-central@1fb1ca98f23b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersiain
bugs1588861
milestone73.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1588861 - Part 4: Add test harness for xdr modules. r=iain Differential Revision: https://phabricator.services.mozilla.com/D55596
js/src/gc/GCEnum.h
js/src/shell/js.cpp
--- a/js/src/gc/GCEnum.h
+++ b/js/src/gc/GCEnum.h
@@ -137,17 +137,18 @@ enum class ZealMode {
   _(DebuggerOnStepHandler)                 \
   _(DebuggerOnPopHandler)                  \
   _(RealmInstrumentation)                  \
   _(ICUObject)                             \
   _(FinalizationGroupRecordVector)         \
   _(FinalizationGroupRegistrations)        \
   _(FinalizationRecordVector)              \
   _(ZoneAllocPolicy)                       \
-  _(SharedArrayRawBuffer)
+  _(SharedArrayRawBuffer)                  \
+  _(XDRBufferElements)
 
 #define JS_FOR_EACH_MEMORY_USE(_)  \
   JS_FOR_EACH_PUBLIC_MEMORY_USE(_) \
   JS_FOR_EACH_INTERNAL_MEMORY_USE(_)
 
 enum class MemoryUse : uint8_t {
 #define DEFINE_MEMORY_USE(Name) Name,
   JS_FOR_EACH_MEMORY_USE(DEFINE_MEMORY_USE)
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -4703,16 +4703,145 @@ static bool ParseModule(JSContext* cx, u
   if (!module) {
     return false;
   }
 
   args.rval().setObject(*module);
   return true;
 }
 
+// A JSObject that holds XDRBuffer.
+class XDRBufferObject : public NativeObject {
+  static const size_t VECTOR_SLOT = 0;
+  static const unsigned RESERVED_SLOTS = 1;
+
+ public:
+  static const JSClassOps classOps_;
+  static const JSClass class_;
+
+  inline static MOZ_MUST_USE XDRBufferObject* create(JSContext* cx,
+                                                     JS::TranscodeBuffer* buf);
+
+  JS::TranscodeBuffer* data() const {
+    Value value = getReservedSlot(VECTOR_SLOT);
+    auto buf = static_cast<JS::TranscodeBuffer*>(value.toPrivate());
+    MOZ_ASSERT(buf);
+    return buf;
+  }
+
+  bool hasData() const {
+    // Data may not be present if we hit OOM in initialization.
+    return !getReservedSlot(VECTOR_SLOT).isUndefined();
+  }
+
+  static void finalize(JSFreeOp* fop, JSObject* obj);
+};
+
+/*static */ const JSClassOps XDRBufferObject::classOps_ = {
+    nullptr, /* addProperty */
+    nullptr, /* delProperty */
+    nullptr, /* enumerate   */
+    nullptr, /* newEnumerate */
+    nullptr, /* resolve     */
+    nullptr, /* mayResolve  */
+    XDRBufferObject::finalize};
+
+/*static */ const JSClass XDRBufferObject::class_ = {
+    "XDRBufferObject",
+    JSCLASS_HAS_RESERVED_SLOTS(XDRBufferObject::RESERVED_SLOTS) |
+        JSCLASS_BACKGROUND_FINALIZE,
+    &XDRBufferObject::classOps_};
+
+XDRBufferObject* XDRBufferObject::create(JSContext* cx,
+                                         JS::TranscodeBuffer* buf) {
+  XDRBufferObject* bufObj = NewObjectWithNullTaggedProto<XDRBufferObject>(cx);
+  if (!bufObj) {
+    return nullptr;
+  }
+
+  auto heapBuf = cx->make_unique<JS::TranscodeBuffer>();
+  if (!heapBuf) {
+    return nullptr;
+  }
+
+  if (!heapBuf->appendAll(*buf)) {
+    return nullptr;
+  }
+
+  size_t len = heapBuf->length();
+  InitReservedSlot(bufObj, VECTOR_SLOT, heapBuf.release(), len,
+                   MemoryUse::XDRBufferElements);
+
+  return bufObj;
+}
+
+void XDRBufferObject::finalize(JSFreeOp* fop, JSObject* obj) {
+  XDRBufferObject* buf = &obj->as<XDRBufferObject>();
+  if (buf->hasData()) {
+    fop->free_(buf, buf->data(), buf->data()->length(),
+               MemoryUse::XDRBufferElements);
+  }
+}
+
+static bool CodeModule(JSContext* cx, unsigned argc, Value* vp) {
+  CallArgs args = CallArgsFromVp(argc, vp);
+  if (!args.requireAtLeast(cx, "codeModule", 1)) {
+    return false;
+  }
+
+  if (!args[0].isObject() || !args[0].toObject().is<ModuleObject>()) {
+    const char* typeName = InformalValueTypeName(args[0]);
+    JS_ReportErrorASCII(cx, "expected module object, got %s", typeName);
+    return false;
+  }
+
+  RootedModuleObject modObject(cx, &args[0].toObject().as<ModuleObject>());
+  JS::TranscodeBuffer buf;
+  XDREncoder xdrEncoder_(cx, buf);
+  XDRResult res = xdrEncoder_.codeModuleObject(&modObject);
+  if (res.isErr()) {
+    return false;
+  }
+
+  XDRBufferObject* xdrBuf = XDRBufferObject::create(cx, &buf);
+  if (!xdrBuf) {
+    return false;
+  }
+  args.rval().setObject(*xdrBuf);
+  return true;
+}
+
+static bool DecodeModule(JSContext* cx, unsigned argc, Value* vp) {
+  CallArgs args = CallArgsFromVp(argc, vp);
+  if (!args.requireAtLeast(cx, "decodeModule", 1)) {
+    return false;
+  }
+
+  if (!args[0].isObject() || !args[0].toObject().is<XDRBufferObject>()) {
+    const char* typeName = InformalValueTypeName(args[0]);
+    JS_ReportErrorASCII(cx, "expected XDRBufferObject to compile, got %s",
+                        typeName);
+    return false;
+  }
+
+  XDRDecoder xdrDecoder_(cx, *args[0].toObject().as<XDRBufferObject>().data());
+  RootedModuleObject modObject(cx, nullptr);
+  XDRResult res = xdrDecoder_.codeModuleObject(&modObject);
+  if (res.isErr()) {
+    return false;
+  }
+
+  if (!ModuleObject::Freeze(cx, modObject)) {
+    return false;
+  }
+
+  args.rval().setObject(*modObject);
+  return true;
+}
+
 static bool SetModuleLoadHook(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
   if (!args.requireAtLeast(cx, "setModuleLoadHook", 1)) {
     return false;
   }
 
   if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
     const char* typeName = InformalValueTypeName(args[0]);
@@ -8577,16 +8706,24 @@ static const JSFunctionSpecWithHelp shel
     JS_FN_HELP("compile", Compile, 1, 0,
 "compile(code)",
 "  Compiles a string to bytecode, potentially throwing."),
 
     JS_FN_HELP("parseModule", ParseModule, 1, 0,
 "parseModule(code)",
 "  Parses source text as a module and returns a Module object."),
 
+    JS_FN_HELP("codeModule", CodeModule, 1, 0,
+"codeModule(module)",
+"   Takes an uninstantiated ModuleObject and returns a XDR bytecode representation of that ModuleObject."),
+
+    JS_FN_HELP("decodeModule", DecodeModule, 1, 0,
+"decodeModule(code)",
+"   Takes a XDR bytecode representation of an uninstantiated ModuleObject and returns a ModuleObject."),
+
     JS_FN_HELP("setModuleLoadHook", SetModuleLoadHook, 1, 0,
 "setModuleLoadHook(function(path))",
 "  Set the shell specific module load hook to |function|.\n"
 "  This hook is used to load a module graph.  It should be implemented by the\n"
 "  module loader."),
 
     JS_FN_HELP("setModuleResolveHook", SetModuleResolveHook, 1, 0,
 "setModuleResolveHook(function(referrer, specifier))",