tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

testCompileScript.cpp (8082B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "mozilla/RefPtr.h"     // RefPtr
      6 #include "mozilla/ScopeExit.h"  // MakeScopeExit
      7 #include "mozilla/Utf8.h"       // mozilla::Utf8Unit
      8 
      9 #include "frontend/CompilationStencil.h"  // JS::Stencil, frontend::CompilationStencil
     10 #include "js/CompileOptions.h"  // JS::CompileOptions, JS::InstantiateOptions
     11 #include "js/experimental/CompileScript.h"  // JS::NewFrontendContext
     12 #include "js/SourceText.h"                  // JS::Source{Ownership,Text}
     13 #include "jsapi-tests/tests.h"
     14 #include "vm/ErrorReporting.h"
     15 #include "vm/JSONPrinter.h"  // js::JSONPrinter
     16 
     17 using namespace JS;
     18 
     19 template <typename T>
     20 static void dump(const T& data) {
     21  js::Fprinter printer(stderr);
     22  js::JSONPrinter json(printer, true);
     23 
     24  data->dump(json);
     25  printer.put("\n");
     26 }
     27 
     28 BEGIN_TEST(testCompileScript) {
     29  CHECK(testCompile());
     30  CHECK(testNonsyntacticCompile());
     31  CHECK(testCompileModule());
     32  CHECK(testPrepareForInstantiate());
     33 
     34  return true;
     35 }
     36 
     37 bool testCompile() {
     38  static constexpr std::string_view src = "42\n";
     39  static constexpr std::u16string_view src_16 = u"42\n";
     40 
     41  static_assert(src.length() == src_16.length(),
     42                "Source buffers must be same length");
     43 
     44  JS::CompileOptions options(cx);
     45 
     46  JS::FrontendContext* fc = JS::NewFrontendContext();
     47  CHECK(fc);
     48  auto destroyFc =
     49      mozilla::MakeScopeExit([fc] { JS::DestroyFrontendContext(fc); });
     50 
     51  {  // 16-bit characters
     52    JS::SourceText<char16_t> buf16;
     53    CHECK(buf16.init(cx, src_16.data(), src_16.length(),
     54                     JS::SourceOwnership::Borrowed));
     55 
     56    RefPtr<JS::Stencil> stencil =
     57        CompileGlobalScriptToStencil(fc, options, buf16);
     58    CHECK(stencil);
     59    RefPtr<const js::frontend::CompilationStencil> initial =
     60        stencil->getInitial();
     61    CHECK(initial->scriptExtra.size() == 1);
     62    CHECK(initial->scriptExtra[0].extent.sourceStart == 0);
     63    CHECK(initial->scriptExtra[0].extent.sourceEnd == 3);
     64    CHECK(initial->scriptData.size() == 1);
     65    CHECK(initial->scriptData[0].hasSharedData());  // has generated bytecode
     66    CHECK(initial->scriptData[0].gcThingsLength == 1);
     67  }
     68 
     69  {  // 8-bit characters
     70    JS::SourceText<mozilla::Utf8Unit> buf8;
     71    CHECK(
     72        buf8.init(cx, src.data(), src.length(), JS::SourceOwnership::Borrowed));
     73 
     74    RefPtr<JS::Stencil> stencil =
     75        CompileGlobalScriptToStencil(fc, options, buf8);
     76    CHECK(stencil);
     77    RefPtr<const js::frontend::CompilationStencil> initial =
     78        stencil->getInitial();
     79    CHECK(initial->scriptExtra.size() == 1);
     80    CHECK(initial->scriptExtra[0].extent.sourceStart == 0);
     81    CHECK(initial->scriptExtra[0].extent.sourceEnd == 3);
     82    CHECK(initial->scriptData.size() == 1);
     83    CHECK(initial->scriptData[0].hasSharedData());  // has generated bytecode
     84    CHECK(initial->scriptData[0].gcThingsLength == 1);
     85  }
     86 
     87  {  // propagates failures
     88    static constexpr std::string_view badSrc = "{ a: 1, b: 3\n";
     89    JS::SourceText<mozilla::Utf8Unit> srcBuf;
     90    CHECK(srcBuf.init(cx, badSrc.data(), badSrc.length(),
     91                      JS::SourceOwnership::Borrowed));
     92 
     93    RefPtr<JS::Stencil> stencil =
     94        CompileGlobalScriptToStencil(fc, options, srcBuf);
     95    CHECK(!stencil);
     96    CHECK(fc->maybeError().isSome());
     97    const js::CompileError& error = fc->maybeError().ref();
     98    CHECK(JSEXN_SYNTAXERR == error.exnType);
     99    CHECK(error.lineno == 1);
    100    CHECK(error.column.oneOriginValue() == 10);
    101  }
    102 
    103  return true;
    104 }
    105 
    106 bool testNonsyntacticCompile() {
    107  const char* chars =
    108      "function f() { return x; }"
    109      "f();";
    110 
    111  JS::SourceText<mozilla::Utf8Unit> srcBuf;
    112  CHECK(srcBuf.init(cx, chars, strlen(chars), JS::SourceOwnership::Borrowed));
    113 
    114  JS::CompileOptions options(cx);
    115  options.setNonSyntacticScope(true);
    116 
    117  JS::FrontendContext* fc = JS::NewFrontendContext();
    118  CHECK(fc);
    119  auto destroyFc =
    120      mozilla::MakeScopeExit([fc] { JS::DestroyFrontendContext(fc); });
    121 
    122  RefPtr<JS::Stencil> stencil =
    123      CompileGlobalScriptToStencil(fc, options, srcBuf);
    124  CHECK(stencil);
    125 
    126  JS::InstantiateOptions instantiateOptions(options);
    127  JS::RootedScript script(
    128      cx, JS::InstantiateGlobalStencil(cx, instantiateOptions, stencil));
    129  CHECK(script);
    130  CHECK(script->hasNonSyntacticScope());
    131 
    132  return true;
    133 }
    134 
    135 bool testCompileModule() {
    136  static constexpr std::string_view src = "import 'a'; 42\n";
    137  static constexpr std::u16string_view src_16 = u"import 'a'; 42\n";
    138 
    139  static_assert(src.length() == src_16.length(),
    140                "Source buffers must be same length");
    141 
    142  JS::CompileOptions options(cx);
    143 
    144  JS::FrontendContext* fc = JS::NewFrontendContext();
    145  CHECK(fc);
    146  auto destroyFc =
    147      mozilla::MakeScopeExit([fc] { JS::DestroyFrontendContext(fc); });
    148 
    149  {  // 16-bit characters
    150    JS::SourceText<char16_t> buf16;
    151    CHECK(buf16.init(cx, src_16.data(), src_16.length(),
    152                     JS::SourceOwnership::Borrowed));
    153 
    154    RefPtr<JS::Stencil> stencil =
    155        CompileModuleScriptToStencil(fc, options, buf16);
    156    CHECK(stencil);
    157    RefPtr<const js::frontend::CompilationStencil> initial =
    158        stencil->getInitial();
    159    CHECK(initial->isModule());
    160    CHECK(initial->scriptExtra.size() == 1);
    161    CHECK(initial->scriptExtra[0].extent.sourceStart == 0);
    162    CHECK(initial->scriptExtra[0].extent.sourceEnd == 15);
    163    CHECK(initial->scriptData.size() == 1);
    164    CHECK(initial->scriptData[0].hasSharedData());  // has generated bytecode
    165    CHECK(initial->scriptData[0].gcThingsLength == 1);
    166  }
    167 
    168  {  // 8-bit characters
    169    JS::SourceText<mozilla::Utf8Unit> buf8;
    170    CHECK(
    171        buf8.init(cx, src.data(), src.length(), JS::SourceOwnership::Borrowed));
    172 
    173    RefPtr<JS::Stencil> stencil =
    174        CompileModuleScriptToStencil(fc, options, buf8);
    175    CHECK(stencil);
    176    RefPtr<const js::frontend::CompilationStencil> initial =
    177        stencil->getInitial();
    178    CHECK(initial->scriptExtra.size() == 1);
    179    CHECK(initial->scriptExtra[0].extent.sourceStart == 0);
    180    CHECK(initial->scriptExtra[0].extent.sourceEnd == 15);
    181    CHECK(initial->scriptData.size() == 1);
    182    CHECK(initial->scriptData[0].hasSharedData());  // has generated bytecode
    183    CHECK(initial->scriptData[0].gcThingsLength == 1);
    184  }
    185 
    186  {  // propagates failures
    187    static constexpr std::string_view badSrc = "{ a: 1, b: 3\n";
    188    JS::SourceText<mozilla::Utf8Unit> srcBuf;
    189    CHECK(srcBuf.init(cx, badSrc.data(), badSrc.length(),
    190                      JS::SourceOwnership::Borrowed));
    191 
    192    RefPtr<JS::Stencil> stencil =
    193        CompileModuleScriptToStencil(fc, options, srcBuf);
    194    CHECK(!stencil);
    195    CHECK(fc->maybeError().isSome());
    196    const js::CompileError& error = fc->maybeError().ref();
    197    CHECK(JSEXN_SYNTAXERR == error.exnType);
    198    CHECK(error.lineno == 1);
    199    CHECK(error.column.oneOriginValue() == 10);
    200  }
    201 
    202  return true;
    203 }
    204 
    205 bool testPrepareForInstantiate() {
    206  static constexpr std::u16string_view src_16 =
    207      u"function f() { return {'field': 42};}; f()['field']\n";
    208 
    209  JS::CompileOptions options(cx);
    210 
    211  JS::SourceText<char16_t> buf16;
    212  CHECK(buf16.init(cx, src_16.data(), src_16.length(),
    213                   JS::SourceOwnership::Borrowed));
    214 
    215  JS::FrontendContext* fc = JS::NewFrontendContext();
    216  CHECK(fc);
    217  auto destroyFc =
    218      mozilla::MakeScopeExit([fc] { JS::DestroyFrontendContext(fc); });
    219 
    220  RefPtr<JS::Stencil> stencil =
    221      CompileGlobalScriptToStencil(fc, options, buf16);
    222  CHECK(stencil);
    223  RefPtr<const js::frontend::CompilationStencil> initial =
    224      stencil->getInitial();
    225  CHECK(initial->scriptData.size() == 2);
    226  CHECK(initial->scopeData.size() == 1);       // function f
    227  CHECK(initial->parserAtomData.size() == 1);  // 'field'
    228 
    229  JS::InstantiationStorage storage;
    230  CHECK(JS::PrepareForInstantiate(fc, *stencil, storage));
    231  CHECK(storage.isValid());
    232  // TODO storage.gcOutput_ is private, so there isn't a good way to check the
    233  // scriptData and scopeData capacities
    234 
    235  return true;
    236 }
    237 END_TEST(testCompileScript);