Backed out changeset 5e65de3569fe (bug 1506969) for causing spidermonkey bustages on testScriptSourceCompression.cpp CLOSED TREE
authorarthur.iakab <aiakab@mozilla.com>
Fri, 30 Nov 2018 08:42:51 +0200
changeset 448943 c9f1ca2ec3b354a82fb78adbbcfef9a12109476e
parent 448942 5e65de3569fe33856451396ab77f78ba9c03a8c8
child 448944 8e424cc8655849d3629bf1730b1f6f2a342eb1d1
push id35130
push usernerli@mozilla.com
push dateFri, 30 Nov 2018 09:35:34 +0000
treeherdermozilla-central@58a0412e1557 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1506969
milestone65.0a1
backs out5e65de3569fe33856451396ab77f78ba9c03a8c8
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
Backed out changeset 5e65de3569fe (bug 1506969) for causing spidermonkey bustages on testScriptSourceCompression.cpp CLOSED TREE
js/src/jsapi-tests/moz.build
js/src/jsapi-tests/testScriptSourceCompression.cpp
js/src/vm/JSScript.cpp
js/src/vm/JSScript.h
--- a/js/src/jsapi-tests/moz.build
+++ b/js/src/jsapi-tests/moz.build
@@ -89,17 +89,16 @@ UNIFIED_SOURCES += [
     'testReadableStream.cpp',
     'testRegExp.cpp',
     'testResolveRecursion.cpp',
     'tests.cpp',
     'testSameValue.cpp',
     'testSavedStacks.cpp',
     'testScriptInfo.cpp',
     'testScriptObject.cpp',
-    'testScriptSourceCompression.cpp',
     'testSetProperty.cpp',
     'testSetPropertyIgnoringNamedGetter.cpp',
     'testSharedImmutableStringsCache.cpp',
     'testSourcePolicy.cpp',
     'testStringBuffer.cpp',
     'testStringIsArrayIndex.cpp',
     'testStructuredClone.cpp',
     'testSymbol.cpp',
deleted file mode 100644
--- a/js/src/jsapi-tests/testScriptSourceCompression.cpp
+++ /dev/null
@@ -1,481 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "mozilla/ArrayUtils.h" // mozilla::ArrayLength
-#include "mozilla/Assertions.h" // MOZ_RELEASE_ASSERT
-
-#include <algorithm> // std::all_of, std::copy_n, std::equal, std::move
-#include <memory> // std::uninitialized_fill_n
-#include <stddef.h> // size_t
-#include <stdint.h> // uint32_t
-
-#include "jsapi.h" // JS_FlattenString, JS_GC, JS_Get{Latin1,TwoByte}FlatStringChars, JS_GetStringLength, JS_ValueToFunction
-
-#include "js/CompilationAndEvaluation.h" // JS::Evaluate
-#include "js/CompileOptions.h" // JS::CompileOptions
-#include "js/Conversions.h" // JS::ToString
-#include "js/GCAPI.h" // JS_GC
-#include "js/MemoryFunctions.h" // JS_malloc
-#include "js/RootingAPI.h" // JS::MutableHandle, JS::Rooted
-#include "js/SourceText.h" // JS::SourceOwnership, JS::SourceText
-#include "js/UniquePtr.h" // js::UniquePtr
-#include "js/Utility.h" // JS::FreePolicy
-#include "js/Value.h" // JS::NullValue, JS::ObjectValue, JS::Value
-#include "jsapi-tests/tests.h"
-#include "vm/Compression.h" // js::Compressor::CHUNK_SIZE
-#include "vm/JSFunction.h" // JSFunction::getOrCreateScript
-#include "vm/JSScript.h" // JSScript, js::ScriptSource::MinimumCompressibleLength
-
-using mozilla::ArrayLength;
-
-struct JSContext;
-class JSString;
-
-template<typename CharT>
-using Source = js::UniquePtr<CharT[], JS::FreePolicy>;
-
-constexpr size_t ChunkSize = js::Compressor::CHUNK_SIZE;
-constexpr size_t MinimumCompressibleLength = js::ScriptSource::MinimumCompressibleLength;
-
-// Don't use ' ' to spread stuff across lines.
-constexpr char FillerWhitespace = '\n';
-
-template<typename CharT>
-static Source<CharT>
-MakeSourceAllWhitespace(JSContext* cx, size_t len)
-{
-    static_assert(ChunkSize % sizeof(CharT) == 0,
-                  "chunk size presumed to be a multiple of char size");
-
-    Source<CharT> source(reinterpret_cast<CharT*>(JS_malloc(cx, len * sizeof(CharT))));
-    if (source) {
-        std::uninitialized_fill_n(source.get(), len, FillerWhitespace);
-    }
-    return source;
-}
-
-static bool
-Evaluate(JSContext* cx, const JS::CompileOptions& options, const char16_t* src, size_t srclen)
-{
-    JS::SourceText<char16_t> sourceText;
-    if (!sourceText.init(cx, src, srclen, JS::SourceOwnership::Borrowed)) {
-        return false;
-    }
-
-    JS::Rooted<JS::Value> dummy(cx);
-    return JS::Evaluate(cx, options, sourceText, &dummy);
-}
-
-template<typename CharT>
-static JSFunction*
-EvaluateChars(JSContext* cx, Source<CharT> chars, size_t len, char functionName, const char* func)
-{
-    JS::CompileOptions options(cx);
-    options.setFileAndLine(func, 1);
-
-    if (!Evaluate(cx, options, chars.get(), len)) {
-        return nullptr;
-    }
-
-    JS::Rooted<JS::Value> rval(cx);
-    const char16_t name[] = { char16_t(functionName) };
-    JS::SourceText<char16_t> srcbuf;
-    if (!srcbuf.init(cx, name, ArrayLength(name), JS::SourceOwnership::Borrowed)) {
-        return nullptr;
-    }
-    if (!JS::Evaluate(cx, options, srcbuf, &rval)) {
-        return nullptr;
-    }
-
-    MOZ_RELEASE_ASSERT(rval.isObject());
-    return JS_ValueToFunction(cx, rval);
-}
-
-static void
-CompressSourceSync(JS::Handle<JSFunction*> fun, JSContext* cx)
-{
-    JS::Rooted<JSScript*> script(cx, JSFunction::getOrCreateScript(cx, fun));
-    MOZ_RELEASE_ASSERT(script);
-    MOZ_RELEASE_ASSERT(script->scriptSource()->hasSourceText());
-
-    // Hoodoo voodoo that presently compresses |fun|'s source.
-    // XXX Be a mensch: replace this with targeted actions to do this!
-    JS_GC(cx);
-    JS_GC(cx);
-
-    MOZ_RELEASE_ASSERT(script->scriptSource()->hasCompressedSource());
-}
-
-static constexpr char FunctionStart[] = "function @() {";
-constexpr size_t FunctionStartLength = ArrayLength(FunctionStart) - 1;
-constexpr size_t FunctionNameOffset = 9;
-
-static_assert(FunctionStart[FunctionNameOffset] == '@',
-              "offset must correctly point at the function name location");
-
-static constexpr char FunctionEnd[] = "return 42; }";
-constexpr size_t FunctionEndLength = ArrayLength(FunctionEnd)  - 1;
-
-template<typename CharT>
-static void
-WriteFunctionOfSizeAtOffset(Source<CharT>& source, size_t usableSourceLen,
-                            char functionName, size_t functionLength, size_t offset)
-{
-    MOZ_RELEASE_ASSERT(functionLength >= MinimumCompressibleLength,
-                       "function must be a certain size to be compressed");
-    MOZ_RELEASE_ASSERT(offset <= usableSourceLen,
-                       "offset must not exceed usable source");
-    MOZ_RELEASE_ASSERT(functionLength <= usableSourceLen,
-                       "function must fit in usable source");
-    MOZ_RELEASE_ASSERT(offset <= usableSourceLen - functionLength,
-                       "function must not extend past usable source");
-
-    // Fill in the function start.
-    std::copy_n(FunctionStart, FunctionStartLength, &source[offset]);
-    source[offset + FunctionNameOffset] = functionName;
-
-    // Fill in the function end.
-    std::copy_n(FunctionEnd, FunctionEndLength,
-                &source[offset + functionLength - FunctionEndLength]);
-}
-
-static JSString*
-DecompressSource(JSContext* cx, JS::Handle<JSFunction*> fun)
-{
-    JS::Rooted<JS::Value> fval(cx, JS::ObjectValue(*JS_GetFunctionObject(fun)));
-    return JS::ToString(cx, fval);
-}
-
-static bool
-IsExpectedFunctionString(JS::Handle<JSString*> str, char functionName, JSContext* cx)
-{
-    JSFlatString* fstr = JS_FlattenString(cx, str);
-    MOZ_RELEASE_ASSERT(fstr);
-
-    size_t len = JS_GetStringLength(str);
-    if (len < FunctionStartLength || len < FunctionEndLength) {
-        return false;
-    }
-
-    JS::AutoAssertNoGC nogc(cx);
-
-    auto CheckContents = [functionName, len](const auto* chars) {
-        // Check the function in parts:
-        //
-        //   * "function "
-        //   * "A"
-        //   * "() {"
-        //   * "\n...\n"
-        //   * "return 42; }"
-        return std::equal(chars, chars + FunctionNameOffset, FunctionStart) &&
-               chars[FunctionNameOffset] == functionName &&
-               std::equal(chars + FunctionNameOffset + 1, chars + FunctionStartLength,
-                          FunctionStart + FunctionNameOffset + 1) &&
-               std::all_of(chars + FunctionStartLength, chars + len - FunctionEndLength,
-                          [](auto c) { return c == FillerWhitespace; }) &&
-               std::equal(chars + len - FunctionEndLength, chars + len,
-                          FunctionEnd);
-    };
-
-    bool hasExpectedContents;
-    if (JS_StringHasLatin1Chars(str)) {
-        const JS::Latin1Char* chars = JS_GetLatin1FlatStringChars(nogc, fstr);
-        hasExpectedContents = CheckContents(chars);
-    } else {
-        const char16_t* chars = JS_GetTwoByteFlatStringChars(nogc, fstr);
-        hasExpectedContents = CheckContents(chars);
-    }
-
-    return hasExpectedContents;
-}
-
-BEGIN_TEST(testScriptSourceCompression_inOneChunk)
-{
-    CHECK(run<char16_t>());
-    return true;
-}
-
-template<typename CharT>
-bool
-run()
-{
-    constexpr size_t len = MinimumCompressibleLength + 55;
-    auto source = MakeSourceAllWhitespace<CharT>(cx, len);
-    CHECK(source);
-
-    // Write out a 'b' or 'c' function that is long enough to be compressed,
-    // that starts after source start and ends before source end.
-    constexpr char FunctionName = 'a' + sizeof(CharT);
-    WriteFunctionOfSizeAtOffset(source, len, FunctionName, MinimumCompressibleLength,
-                                len - MinimumCompressibleLength);
-
-    JS::Rooted<JSFunction*> fun(cx);
-    fun = EvaluateChars(cx, std::move(source), len, FunctionName, __FUNCTION__);
-    CHECK(fun);
-
-    CompressSourceSync(fun, cx);
-
-    JS::Rooted<JSString*> str(cx, DecompressSource(cx, fun));
-    CHECK(str);
-    CHECK(IsExpectedFunctionString(str, FunctionName, cx));
-
-    return true;
-}
-END_TEST(testScriptSourceCompression_inOneChunk)
-
-BEGIN_TEST(testScriptSourceCompression_endsAtBoundaryInOneChunk)
-{
-    CHECK(run<char16_t>());
-    return true;
-}
-
-template<typename CharT>
-bool
-run()
-{
-    constexpr size_t len = ChunkSize / sizeof(CharT);
-    auto source = MakeSourceAllWhitespace<CharT>(cx, len);
-    CHECK(source);
-
-    // Write out a 'd' or 'e' function that is long enough to be compressed,
-    // that (for no particular reason) starts after source start and ends
-    // before usable source end.
-    constexpr char FunctionName = 'c' + sizeof(CharT);
-    WriteFunctionOfSizeAtOffset(source, len, FunctionName, MinimumCompressibleLength,
-                                         len - MinimumCompressibleLength);
-
-    JS::Rooted<JSFunction*> fun(cx);
-    fun = EvaluateChars(cx, std::move(source), len, FunctionName, __FUNCTION__);
-    CHECK(fun);
-
-    CompressSourceSync(fun, cx);
-
-    JS::Rooted<JSString*> str(cx, DecompressSource(cx, fun));
-    CHECK(str);
-    CHECK(IsExpectedFunctionString(str, FunctionName, cx));
-
-    return true;
-}
-END_TEST(testScriptSourceCompression_endsAtBoundaryInOneChunk)
-
-BEGIN_TEST(testScriptSourceCompression_isExactChunk)
-{
-    CHECK(run<char16_t>());
-    return true;
-}
-
-template<typename CharT>
-bool
-run()
-{
-    constexpr size_t len = ChunkSize / sizeof(CharT);
-    auto source = MakeSourceAllWhitespace<CharT>(cx, len);
-    CHECK(source);
-
-    // Write out a 'f' or 'g' function that occupies the entire source (and
-    // entire chunk, too).
-    constexpr char FunctionName = 'e' + sizeof(CharT);
-    WriteFunctionOfSizeAtOffset(source, len, FunctionName, len, 0);
-
-    JS::Rooted<JSFunction*> fun(cx);
-    fun = EvaluateChars(cx, std::move(source), len, FunctionName, __FUNCTION__);
-    CHECK(fun);
-
-    CompressSourceSync(fun, cx);
-
-    JS::Rooted<JSString*> str(cx, DecompressSource(cx, fun));
-    CHECK(str);
-    CHECK(IsExpectedFunctionString(str, FunctionName, cx));
-
-    return true;
-}
-END_TEST(testScriptSourceCompression_isExactChunk)
-
-BEGIN_TEST(testScriptSourceCompression_crossesChunkBoundary)
-{
-    CHECK(run<char16_t>());
-    return true;
-}
-
-template<typename CharT>
-bool
-run()
-{
-    constexpr size_t len = ChunkSize / sizeof(CharT) + 293;
-    auto source = MakeSourceAllWhitespace<CharT>(cx, len);
-    CHECK(source);
-
-    // This function crosses a chunk boundary but does not end at one.
-    constexpr size_t FunctionSize = 177 + ChunkSize / sizeof(CharT);
-
-    // Write out a 'h' or 'i' function.
-    constexpr char FunctionName = 'g' + sizeof(CharT);
-    WriteFunctionOfSizeAtOffset(source, len, FunctionName, FunctionSize, 37);
-
-    JS::Rooted<JSFunction*> fun(cx);
-    fun = EvaluateChars(cx, std::move(source), len, FunctionName, __FUNCTION__);
-    CHECK(fun);
-
-    CompressSourceSync(fun, cx);
-
-    JS::Rooted<JSString*> str(cx, DecompressSource(cx, fun));
-    CHECK(str);
-    CHECK(IsExpectedFunctionString(str, FunctionName, cx));
-
-    return true;
-}
-END_TEST(testScriptSourceCompression_crossesChunkBoundary)
-
-BEGIN_TEST(testScriptSourceCompression_crossesChunkBoundary_endsAtBoundary)
-{
-    CHECK(run<char16_t>());
-    return true;
-}
-
-template<typename CharT>
-bool
-run()
-{
-    // Exactly two chunks.
-    constexpr size_t len = (2 * ChunkSize) / sizeof(CharT);
-    auto source = MakeSourceAllWhitespace<CharT>(cx, len);
-    CHECK(source);
-
-    // This function crosses a chunk boundary, and it ends exactly at the end
-    // of both the second chunk and the full source.
-    constexpr size_t FunctionSize = 1 + ChunkSize / sizeof(CharT);
-
-    // Write out a 'j' or 'k' function.
-    constexpr char FunctionName = 'i' + sizeof(CharT);
-    WriteFunctionOfSizeAtOffset(source, len, FunctionName,
-                                FunctionSize, len - FunctionSize);
-
-    JS::Rooted<JSFunction*> fun(cx);
-    fun = EvaluateChars(cx, std::move(source), len, FunctionName, __FUNCTION__);
-    CHECK(fun);
-
-    CompressSourceSync(fun, cx);
-
-    JS::Rooted<JSString*> str(cx, DecompressSource(cx, fun));
-    CHECK(str);
-    CHECK(IsExpectedFunctionString(str, FunctionName, cx));
-
-    return true;
-}
-END_TEST(testScriptSourceCompression_crossesChunkBoundary_endsAtBoundary)
-
-BEGIN_TEST(testScriptSourceCompression_containsWholeChunk)
-{
-    CHECK(run<char16_t>());
-    return true;
-}
-
-template<typename CharT>
-bool
-run()
-{
-    constexpr size_t len = (2 * ChunkSize) / sizeof(CharT) + 17;
-    auto source = MakeSourceAllWhitespace<CharT>(cx, len);
-    CHECK(source);
-
-    // This function crosses two chunk boundaries and begins/ends in the middle
-    // of chunk boundaries.
-    constexpr size_t FunctionSize = 2 + ChunkSize / sizeof(CharT);
-
-    // Write out a 'l' or 'm' function.
-    constexpr char FunctionName = 'k' + sizeof(CharT);
-    WriteFunctionOfSizeAtOffset(source, len, FunctionName,
-                                FunctionSize, ChunkSize / sizeof(CharT) - 1);
-
-    JS::Rooted<JSFunction*> fun(cx);
-    fun = EvaluateChars(cx, std::move(source), len, FunctionName, __FUNCTION__);
-    CHECK(fun);
-
-    CompressSourceSync(fun, cx);
-
-    JS::Rooted<JSString*> str(cx, DecompressSource(cx, fun));
-    CHECK(str);
-    CHECK(IsExpectedFunctionString(str, FunctionName, cx));
-
-    return true;
-}
-END_TEST(testScriptSourceCompression_containsWholeChunk)
-
-BEGIN_TEST(testScriptSourceCompression_containsWholeChunk_endsAtBoundary)
-{
-    CHECK(run<char16_t>());
-    return true;
-}
-
-template<typename CharT>
-bool
-run()
-{
-    // Exactly three chunks.
-    constexpr size_t len = (3 * ChunkSize) / sizeof(CharT);
-    auto source = MakeSourceAllWhitespace<CharT>(cx, len);
-    CHECK(source);
-
-    // This function crosses two chunk boundaries and ends at a chunk boundary.
-    constexpr size_t FunctionSize = 1 + (2 * ChunkSize) / sizeof(CharT);
-
-    // Write out a 'n' or 'o' function.
-    constexpr char FunctionName = 'm' + sizeof(CharT);
-    WriteFunctionOfSizeAtOffset(source, len, FunctionName,
-                                FunctionSize, ChunkSize / sizeof(CharT) - 1);
-
-    JS::Rooted<JSFunction*> fun(cx);
-    fun = EvaluateChars(cx, std::move(source), len, FunctionName, __FUNCTION__);
-    CHECK(fun);
-
-    CompressSourceSync(fun, cx);
-
-    JS::Rooted<JSString*> str(cx, DecompressSource(cx, fun));
-    CHECK(str);
-    CHECK(IsExpectedFunctionString(str, FunctionName, cx));
-
-    return true;
-}
-END_TEST(testScriptSourceCompression_containsWholeChunk_endsAtBoundary)
-
-BEGIN_TEST(testScriptSourceCompression_spansMultipleMiddleChunks)
-{
-    CHECK(run<char16_t>());
-    return true;
-}
-
-template<typename CharT>
-bool
-run()
-{
-    // Four chunks.
-    constexpr size_t len = (4 * ChunkSize) / sizeof(CharT);
-    auto source = MakeSourceAllWhitespace<CharT>(cx, len);
-    CHECK(source);
-
-    // This function spans the two middle chunks and further extends one
-    // character to each side.
-    constexpr size_t FunctionSize = 2 + (2 * ChunkSize) / sizeof(CharT);
-
-    // Write out a 'p' or 'q' function.
-    constexpr char FunctionName = 'o' + sizeof(CharT);
-    WriteFunctionOfSizeAtOffset(source, len, FunctionName,
-                                FunctionSize, ChunkSize / sizeof(CharT) - 1);
-
-    JS::Rooted<JSFunction*> fun(cx);
-    fun = EvaluateChars(cx, std::move(source), len, FunctionName, __FUNCTION__);
-    CHECK(fun);
-
-    CompressSourceSync(fun, cx);
-
-    JS::Rooted<JSString*> str(cx, DecompressSource(cx, fun));
-    CHECK(str);
-    CHECK(IsExpectedFunctionString(str, FunctionName, cx));
-
-    return true;
-}
-END_TEST(testScriptSourceCompression_spansMultipleMiddleChunks)
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -1986,17 +1986,18 @@ ScriptSource::tryCompressOffThread(JSCon
     //
     // Otherwise, enqueue a compression task to be processed when a major
     // GC is requested.
 
     bool canCompressOffThread =
         HelperThreadState().cpuCount > 1 &&
         HelperThreadState().threadCount >= 2 &&
         CanUseExtraThreads();
-    if (length() < ScriptSource::MinimumCompressibleLength || !canCompressOffThread) {
+    const size_t TINY_SCRIPT = 256;
+    if (TINY_SCRIPT > length() || !canCompressOffThread) {
         return true;
     }
 
     // The SourceCompressionTask needs to record the major GC number for
     // scheduling. If we're parsing off thread, this number is not safe to
     // access.
     //
     // When parsing on the main thread, the attempts made to compress off
--- a/js/src/vm/JSScript.h
+++ b/js/src/vm/JSScript.h
@@ -676,22 +676,16 @@ class ScriptSource
         if (--refs == 0) {
             js_delete(this);
         }
     }
     MOZ_MUST_USE bool initFromOptions(JSContext* cx,
                                       const JS::ReadOnlyCompileOptions& options,
                                       const mozilla::Maybe<uint32_t>& parameterListEnd = mozilla::Nothing());
 
-    /**
-     * The minimum script length (in code units) necessary for a script to be
-     * eligible to be compressed.
-     */
-    static constexpr size_t MinimumCompressibleLength = 256;
-
     template<typename Unit>
     MOZ_MUST_USE bool setSourceCopy(JSContext* cx, JS::SourceText<Unit>& srcBuf);
 
     void setSourceRetrievable() { sourceRetrievable_ = true; }
     bool sourceRetrievable() const { return sourceRetrievable_; }
     bool hasSourceText() const { return hasUncompressedSource() || hasCompressedSource(); }
     bool hasBinASTSource() const { return data.is<BinAST>(); }