Commit ad7e3a0c authored by Wes Kocher's avatar Wes Kocher
Browse files

Backed out changeset d3197ffef609 (bug 1338217) for failures in...

Backed out changeset d3197ffef609 (bug 1338217) for failures in test_webassembly_compile.html on at least Windows VM debug a=backout a=merge

MozReview-Commit-ID: 35G0IT8FJML

--HG--
extra : source : 0b6169107c9b0a396fbec47c5d78a45e81281dea
parent df3f95a5
Loading
Loading
Loading
Loading
+0 −4
Original line number Diff line number Diff line
@@ -272,7 +272,6 @@ struct StatsClosure
    SourceSet seenSources;
    wasm::Metadata::SeenSet wasmSeenMetadata;
    wasm::ShareableBytes::SeenSet wasmSeenBytes;
    wasm::Code::SeenSet wasmSeenCode;
    wasm::Table::SeenSet wasmSeenTables;
    bool anonymize;

@@ -286,7 +285,6 @@ struct StatsClosure
        return seenSources.init() &&
               wasmSeenMetadata.init() &&
               wasmSeenBytes.init() &&
               wasmSeenCode.init() &&
               wasmSeenTables.init();
    }
};
@@ -477,7 +475,6 @@ StatsCellCallback(JSRuntime* rt, void* data, void* thing, JS::TraceKind traceKin
            module.addSizeOfMisc(rtStats->mallocSizeOf_,
                                 &closure->wasmSeenMetadata,
                                 &closure->wasmSeenBytes,
                                 &closure->wasmSeenCode,
                                 &info.objectsNonHeapCodeWasm,
                                 &info.objectsMallocHeapMisc);
        } else if (obj->is<WasmInstanceObject>()) {
@@ -487,7 +484,6 @@ StatsCellCallback(JSRuntime* rt, void* data, void* thing, JS::TraceKind traceKin
            instance.addSizeOfMisc(rtStats->mallocSizeOf_,
                                   &closure->wasmSeenMetadata,
                                   &closure->wasmSeenBytes,
                                   &closure->wasmSeenCode,
                                   &closure->wasmSeenTables,
                                   &info.objectsNonHeapCodeWasm,
                                   &info.objectsMallocHeapMisc);
+57 −251
Original line number Diff line number Diff line
@@ -64,7 +64,7 @@ RoundupCodeLength(uint32_t codeLength)
}

static uint8_t*
AllocateCodeBytes(uint32_t codeLength)
AllocateCodeSegment(JSContext* cx, uint32_t codeLength)
{
    codeLength = RoundupCodeLength(codeLength);

@@ -83,22 +83,20 @@ AllocateCodeBytes(uint32_t codeLength)
        }
    }

    if (!p)
    if (!p) {
        ReportOutOfMemory(cx);
        return nullptr;
    }

    // We account for the bytes allocated in WasmModuleObject::create, where we
    // have the necessary JSContext.
    cx->zone()->updateJitCodeMallocBytes(codeLength);

    wasmCodeAllocations++;
    return (uint8_t*)p;
}

static void
FreeCodeBytes(uint8_t* bytes, uint32_t codeLength)
FreeCodeSegment(uint8_t* bytes, uint32_t codeLength)
{
    MOZ_ASSERT(wasmCodeAllocations > 0);
    wasmCodeAllocations--;

    codeLength = RoundupCodeLength(codeLength);
#ifdef MOZ_VTUNE
    vtune::UnmarkBytes(bytes, codeLength);
@@ -138,33 +136,6 @@ StaticallyLink(const CodeSegment& cs, const LinkData& linkData)
    return true;
}

static void
StaticallyUnlink(uint8_t* base, const LinkData& linkData)
{
    for (LinkData::InternalLink link : linkData.internalLinks) {
        uint8_t* patchAt = base + link.patchAtOffset;
        void* target = 0;
        if (link.isRawPointerPatch())
            *(void**)(patchAt) = target;
        else
            Assembler::PatchInstructionImmediate(patchAt, PatchedImmPtr(target));
    }

    for (auto imm : MakeEnumeratedRange(SymbolicAddress::Limit)) {
        const Uint32Vector& offsets = linkData.symbolicLinks[imm];
        if (offsets.empty())
            continue;

        void* target = SymbolicAddressTarget(imm);
        for (uint32_t offset : offsets) {
            uint8_t* patchAt = base + offset;
            Assembler::PatchDataWithValueCheck(CodeLocationLabel(patchAt),
                                               PatchedImmPtr((void*)-1),
                                               PatchedImmPtr(target));
        }
    }
}

static void
SendCodeRangesToProfiler(const CodeSegment& cs, const Bytes& bytecode, const Metadata& metadata)
{
@@ -214,99 +185,53 @@ SendCodeRangesToProfiler(const CodeSegment& cs, const Bytes& bytecode, const Met
}

/* static */ UniqueConstCodeSegment
CodeSegment::create(jit::MacroAssembler& masm,
                    const ShareableBytes& bytecode,
CodeSegment::create(JSContext* cx,
                    const Bytes& codeBytes,
                    const SharedBytes& bytecode,
                    const LinkData& linkData,
                    const Metadata& metadata)
{
    // Round up the code size to page size since this is eventually required by
    // the executable-code allocator and for setting memory protection.
    uint32_t bytesNeeded = masm.bytesNeeded();
    uint32_t padding = ComputeByteAlignment(bytesNeeded, gc::SystemPageSize());
    uint32_t codeLength = bytesNeeded + padding;

    MOZ_ASSERT(linkData.functionCodeLength < codeLength);

    uint8_t* codeBase = AllocateCodeBytes(codeLength);
    if (!codeBase)
        return nullptr;

    // We'll flush the icache after static linking, in initialize().
    masm.executableCopy(codeBase, /* flushICache = */ false);

    // Zero the padding.
    memset(codeBase + bytesNeeded, 0, padding);

    return create(codeBase, codeLength, bytecode, linkData, metadata);
}

/* static */ UniqueConstCodeSegment
CodeSegment::create(const Bytes& unlinkedBytes, const ShareableBytes& bytecode,
                    const LinkData& linkData, const Metadata& metadata)
{
    uint32_t codeLength = unlinkedBytes.length();
    MOZ_ASSERT(codeLength % gc::SystemPageSize() == 0);

    uint8_t* codeBytes = AllocateCodeBytes(codeLength);
    if (!codeBytes)
        return nullptr;
    memcpy(codeBytes, unlinkedBytes.begin(), codeLength);
    MOZ_ASSERT(codeBytes.length() % gc::SystemPageSize() == 0);
    MOZ_ASSERT(linkData.functionCodeLength < codeBytes.length());

    return create(codeBytes, codeLength, bytecode, linkData, metadata);
}

/* static */ UniqueConstCodeSegment
CodeSegment::create(uint8_t* codeBase, uint32_t codeLength,
                    const ShareableBytes& bytecode,
                    const LinkData& linkData,
                    const Metadata& metadata)
{
    // These should always exist and should never be first in the code segment.
    MOZ_ASSERT(linkData.interruptOffset != 0);
    MOZ_ASSERT(linkData.outOfBoundsOffset != 0);
    MOZ_ASSERT(linkData.unalignedAccessOffset != 0);

    auto cs = js::MakeUnique<CodeSegment>();
    if (!cs) {
        FreeCodeBytes(codeBase, codeLength);
    uint8_t* codeBase = AllocateCodeSegment(cx, codeBytes.length());
    if (!codeBase)
        return nullptr;
    }

    if (!cs->initialize(codeBase, codeLength, bytecode, linkData, metadata))
    auto cs = cx->make_unique<const CodeSegment>(codeBase, linkData.functionCodeLength,
                                                 codeBytes.length(),
                                                 codeBase + linkData.interruptOffset,
                                                 codeBase + linkData.outOfBoundsOffset,
                                                 codeBase + linkData.unalignedAccessOffset);
    if (!cs) {
        FreeCodeSegment(codeBase, codeBytes.length());
        return nullptr;

    return UniqueConstCodeSegment(cs.release());
    }

bool
CodeSegment::initialize(uint8_t* codeBase, uint32_t codeLength,
                        const ShareableBytes& bytecode,
                        const LinkData& linkData,
                        const Metadata& metadata)
    {
    MOZ_ASSERT(bytes_ == nullptr);

    bytes_ = codeBase;
    // This CodeSegment instance now owns the code bytes, and the CodeSegment's
    // destructor will take care of freeing those bytes in the case of error.
    functionLength_ = linkData.functionCodeLength;
    length_ = codeLength;
    interruptCode_ = codeBase + linkData.interruptOffset;
    outOfBoundsCode_ = codeBase + linkData.outOfBoundsOffset;
    unalignedAccessCode_ = codeBase + linkData.unalignedAccessOffset;

    if (!StaticallyLink(*this, linkData))
        return false;
        JitContext jcx(CompileRuntime::get(cx->compartment()->runtimeFromAnyThread()));
        AutoFlushICache afc("CodeSegment::create");
        AutoFlushICache::setRange(uintptr_t(codeBase), cs->length());

    ExecutableAllocator::cacheFlush(codeBase, RoundupCodeLength(codeLength));
        memcpy(codeBase, codeBytes.begin(), codeBytes.length());
        if (!StaticallyLink(*cs, linkData))
            return nullptr;
    }

    // Reprotect the whole region to avoid having separate RW and RX mappings.
    if (!ExecutableAllocator::makeExecutable(codeBase, RoundupCodeLength(codeLength)))
        return false;
    if (!ExecutableAllocator::makeExecutable(codeBase, RoundupCodeLength(cs->length()))) {
        ReportOutOfMemory(cx);
        return nullptr;
    }

    SendCodeRangesToProfiler(*this, bytecode.bytes, metadata);
    SendCodeRangesToProfiler(*cs, bytecode->bytes, metadata);

    return true;
    return cs;
}

CodeSegment::~CodeSegment()
@@ -314,69 +239,12 @@ CodeSegment::~CodeSegment()
    if (!bytes_)
        return;

    MOZ_ASSERT(length() > 0);
    FreeCodeBytes(bytes_, length());
}

UniqueConstBytes
CodeSegment::unlinkedBytesForDebugging(const LinkData& linkData) const
{
    UniqueBytes unlinkedBytes = js::MakeUnique<Bytes>();
    if (!unlinkedBytes)
        return nullptr;
    if (!unlinkedBytes->append(base(), length()))
        return nullptr;
    StaticallyUnlink(unlinkedBytes->begin(), linkData);
    return UniqueConstBytes(unlinkedBytes.release());
}

size_t
CodeSegment::serializedSize() const
{
    return sizeof(uint32_t) + length_;
}

void
CodeSegment::addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf, size_t* code, size_t* data) const
{
    *data += mallocSizeOf(this);
    *code += RoundupCodeLength(length_);
}

uint8_t*
CodeSegment::serialize(uint8_t* cursor, const LinkData& linkData) const
{
    cursor = WriteScalar<uint32_t>(cursor, length_);
    uint8_t* base = cursor;
    cursor = WriteBytes(cursor, bytes_, length_);
    StaticallyUnlink(base, linkData);
    return cursor;
}

const uint8_t*
CodeSegment::deserialize(const uint8_t* cursor, const ShareableBytes& bytecode,
                         const LinkData& linkData, const Metadata& metadata)
{
    uint32_t length;
    cursor = ReadScalar<uint32_t>(cursor, &length);
    if (!cursor)
        return nullptr;

    MOZ_ASSERT(length_ % gc::SystemPageSize() == 0);
    uint8_t* bytes = AllocateCodeBytes(length);
    if (!bytes)
        return nullptr;

    cursor = ReadBytes(cursor, bytes, length);
    if (!cursor) {
        FreeCodeBytes(bytes, length);
        return nullptr;
    }
    MOZ_ASSERT(wasmCodeAllocations > 0);
    wasmCodeAllocations--;

    if (!initialize(bytes, length, bytecode, linkData, metadata))
        return nullptr;
    MOZ_ASSERT(length() > 0);

    return cursor;
    FreeCodeSegment(bytes_, length());
}

size_t
@@ -623,11 +491,6 @@ Code::Code(UniqueConstCodeSegment segment,
    MOZ_ASSERT_IF(metadata_->debugEnabled, maybeBytecode);
}

Code::Code()
  : profilingLabels_(mutexid::WasmCodeProfilingLabels, CacheableCharsVector())
{
}

struct CallSiteRetAddrOffset
{
    const CallSiteVector& callSites;
@@ -637,73 +500,25 @@ struct CallSiteRetAddrOffset
    }
};

size_t
Code::serializedSize() const
{
    return metadata().serializedSize() +
           segment().serializedSize();
}

uint8_t*
Code::serialize(uint8_t* cursor, const LinkData& linkData) const
{
    MOZ_RELEASE_ASSERT(!metadata().debugEnabled);

    cursor = metadata().serialize(cursor);
    cursor = segment().serialize(cursor, linkData);
    return cursor;
}

const uint8_t*
Code::deserialize(const uint8_t* cursor, const SharedBytes& bytecode, const LinkData& linkData,
                  Metadata* maybeMetadata)
{
    MutableMetadata metadata;
    if (maybeMetadata) {
        metadata = maybeMetadata;
    } else {
        metadata = js_new<Metadata>();
        if (!metadata)
            return nullptr;
    }
    cursor = metadata->deserialize(cursor);
    if (!cursor)
        return nullptr;

    UniqueCodeSegment codeSegment = js::MakeUnique<CodeSegment>();
    if (!codeSegment)
        return nullptr;

    cursor = codeSegment->deserialize(cursor, *bytecode, linkData, *metadata);
    if (!cursor)
        return nullptr;

    segment_ = UniqueConstCodeSegment(codeSegment.release());
    metadata_ = metadata;
    maybeBytecode_ = bytecode;

    return cursor;
}

const CallSite*
Code::lookupCallSite(void* returnAddress) const
{
    uint32_t target = ((uint8_t*)returnAddress) - segment_->base();
    size_t lowerBound = 0;
    size_t upperBound = metadata().callSites.length();
    size_t upperBound = metadata_->callSites.length();

    size_t match;
    if (!BinarySearch(CallSiteRetAddrOffset(metadata().callSites), lowerBound, upperBound, target, &match))
    if (!BinarySearch(CallSiteRetAddrOffset(metadata_->callSites), lowerBound, upperBound, target, &match))
        return nullptr;

    return &metadata().callSites[match];
    return &metadata_->callSites[match];
}

const CodeRange*
Code::lookupRange(void* pc) const
{
    CodeRange::OffsetInCode target((uint8_t*)pc - segment_->base());
    return LookupInSorted(metadata().codeRanges, target);
    return LookupInSorted(metadata_->codeRanges, target);
}

struct MemoryAccessOffset
@@ -722,20 +537,20 @@ Code::lookupMemoryAccess(void* pc) const

    uint32_t target = ((uint8_t*)pc) - segment_->base();
    size_t lowerBound = 0;
    size_t upperBound = metadata().memoryAccesses.length();
    size_t upperBound = metadata_->memoryAccesses.length();

    size_t match;
    if (!BinarySearch(MemoryAccessOffset(metadata().memoryAccesses), lowerBound, upperBound, target, &match))
    if (!BinarySearch(MemoryAccessOffset(metadata_->memoryAccesses), lowerBound, upperBound, target, &match))
        return nullptr;

    return &metadata().memoryAccesses[match];
    return &metadata_->memoryAccesses[match];
}

bool
Code::getFuncName(uint32_t funcIndex, UTF8Bytes* name) const
{
    const Bytes* maybeBytecode = maybeBytecode_ ? &maybeBytecode_.get()->bytes : nullptr;
    return metadata().getFuncName(maybeBytecode, funcIndex, name);
    return metadata_->getFuncName(maybeBytecode, funcIndex, name);
}

JSAtom*
@@ -765,7 +580,7 @@ Code::ensureProfilingLabels(bool profilingEnabled) const
    if (!labels->empty())
        return;

    for (const CodeRange& codeRange : metadata().codeRanges) {
    for (const CodeRange& codeRange : metadata_->codeRanges) {
        if (!codeRange.isFunction())
            continue;

@@ -777,7 +592,7 @@ Code::ensureProfilingLabels(bool profilingEnabled) const
        if (!getFuncName(codeRange.funcIndex(), &name) || !name.append(" (", 2))
            return;

        if (const char* filename = metadata().filename.get()) {
        if (const char* filename = metadata_->filename.get()) {
            if (!name.append(filename, strlen(filename)))
                return;
        } else {
@@ -816,24 +631,15 @@ Code::profilingLabel(uint32_t funcIndex) const
}

void
Code::addSizeOfMiscIfNotSeen(MallocSizeOf mallocSizeOf,
Code::addSizeOfMisc(MallocSizeOf mallocSizeOf,
                    Metadata::SeenSet* seenMetadata,
                    ShareableBytes::SeenSet* seenBytes,
                             Code::SeenSet* seenCode,
                    size_t* code,
                    size_t* data) const
{
    auto p = seenCode->lookupForAdd(this);
    if (p)
        return;
    bool ok = seenCode->add(p, this);
    (void)ok;  // oh well

    *code += segment_->length();
    *data += mallocSizeOf(this) +
             metadata().sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenMetadata) +
             profilingLabels_.lock()->sizeOfExcludingThis(mallocSizeOf);

    segment_->addSizeOfMisc(mallocSizeOf, code, data);
             metadata_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenMetadata);

    if (maybeBytecode_)
        *data += maybeBytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes);
+31 −60
Original line number Diff line number Diff line
@@ -53,7 +53,6 @@ typedef RefPtr<const ShareableBytes> SharedBytes;
// A wasm CodeSegment owns the allocated executable code for a wasm module.

class CodeSegment;
typedef UniquePtr<CodeSegment> UniqueCodeSegment;
typedef UniquePtr<const CodeSegment> UniqueConstCodeSegment;

class CodeSegment
@@ -71,40 +70,32 @@ class CodeSegment
    uint8_t* outOfBoundsCode_;
    uint8_t* unalignedAccessCode_;

    // This assumes ownership of the codeBytes, and deletes them in the event of error.
    bool initialize(uint8_t* codeBase, uint32_t codeLength, const ShareableBytes& bytecode,
                    const LinkData& linkData, const Metadata& metadata);
    CodeSegment(uint8_t* bytes, uint32_t functionLength, uint32_t length, uint8_t* interruptCode,
                uint8_t* outOfBoundsCode, uint8_t* unalignedAccessCode)
      : bytes_(bytes),
        functionLength_(functionLength),
        length_(length),
        interruptCode_(interruptCode),
        outOfBoundsCode_(outOfBoundsCode),
        unalignedAccessCode_(unalignedAccessCode)
    {
    }

  protected:
    CodeSegment() { PodZero(this); }
    template <class> friend struct js::MallocProvider;

    // codeBytes must be executable memory.
    // This assumes ownership of the codeBytes, and deletes them in the event of error.
    static UniqueConstCodeSegment create(uint8_t* codeBytes,
                                         uint32_t codeLength,
                                         const ShareableBytes& bytecode,
                                         const LinkData& linkData,
                                         const Metadata& metadata);
  public:
    CodeSegment(const CodeSegment&) = delete;
    CodeSegment(CodeSegment&&) = delete;
    void operator=(const CodeSegment&) = delete;
    void operator=(CodeSegment&&) = delete;

    CodeSegment()
      : bytes_(nullptr),
        functionLength_(0),
        length_(0),
        interruptCode_(nullptr),
        outOfBoundsCode_(nullptr),
        unalignedAccessCode_(nullptr)
    {}

    static UniqueConstCodeSegment create(jit::MacroAssembler& masm,
                                         const ShareableBytes& bytecode,
                                         const LinkData& linkData,
                                         const Metadata& metadata);

    static UniqueConstCodeSegment create(const Bytes& codeBytes,
                                         const ShareableBytes& bytecode,
  public:
    static UniqueConstCodeSegment create(JSContext* cx,
                                         const Bytes& codeBytes,
                                         const SharedBytes& bytecode,
                                         const LinkData& linkData,
                                         const Metadata& metadata);

    ~CodeSegment();

    uint8_t* base() const { return bytes_; }
@@ -126,15 +117,6 @@ class CodeSegment
    bool containsCodePC(const void* pc) const {
        return pc >= base() && pc < (base() + length_);
    }

    UniqueConstBytes unlinkedBytesForDebugging(const LinkData& linkData) const;

    size_t serializedSize() const;
    uint8_t* serialize(uint8_t* cursor, const LinkData& linkData) const;
    const uint8_t* deserialize(const uint8_t* cursor, const ShareableBytes& bytecode,
                               const LinkData& linkData, const Metadata& metadata);

    void addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf, size_t* code, size_t* data) const;
};

// A FuncExport represents a single function definition inside a wasm Module
@@ -390,14 +372,12 @@ typedef RefPtr<const Metadata> SharedMetadata;

class Code : public ShareableBase<Code>
{
    UniqueConstCodeSegment              segment_;
    SharedMetadata                      metadata_;
    SharedBytes                         maybeBytecode_;
    ExclusiveData<CacheableCharsVector> profilingLabels_;
    const UniqueConstCodeSegment              segment_;
    const SharedMetadata                      metadata_;
    const SharedBytes                         maybeBytecode_;
    const ExclusiveData<CacheableCharsVector> profilingLabels_;

  public:
    Code();

    Code(UniqueConstCodeSegment segment,
         const Metadata& metadata,
         const ShareableBytes* maybeBytecode);
@@ -425,25 +405,16 @@ class Code : public ShareableBase<Code>

    // about:memory reporting:

    void addSizeOfMiscIfNotSeen(MallocSizeOf mallocSizeOf,
    void addSizeOfMisc(MallocSizeOf mallocSizeOf,
                       Metadata::SeenSet* seenMetadata,
                       ShareableBytes::SeenSet* seenBytes,
                                Code::SeenSet* seenCode,
                       size_t* code,
                       size_t* data) const;

    // A Code object is serialized as the length and bytes of the machine code
    // after statically unlinking it; the Code is then later recreated from the
    // machine code and other parts.

    size_t serializedSize() const;
    uint8_t* serialize(uint8_t* cursor, const LinkData& linkData) const;
    const uint8_t* deserialize(const uint8_t* cursor, const SharedBytes& bytecode,
                               const LinkData& linkData, Metadata* maybeMetadata);
    WASM_DECLARE_SERIALIZABLE(Code);
};

typedef RefPtr<const Code> SharedCode;
typedef RefPtr<Code> MutableCode;

} // namespace wasm
} // namespace js
+28 −49

File changed.

Preview size limit exceeded, changes collapsed.

+3 −23
Original line number Diff line number Diff line
@@ -71,8 +71,6 @@ class GeneratedSourceMap
    void setTotalLines(uint32_t val) { totalLines_ = val; }

    bool searchLineByOffset(JSContext* cx, uint32_t offset, size_t* exprlocIndex);

    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
};

typedef UniquePtr<GeneratedSourceMap> UniqueGeneratedSourceMap;
@@ -82,6 +80,7 @@ typedef HashMap<uint32_t, WasmBreakpointSite*, DefaultHasher<uint32_t>, SystemAl
class DebugState
{
    const SharedCode         code_;
    const SharedMetadata     metadata_;
    const SharedBytes        maybeBytecode_;
    UniqueGeneratedSourceMap maybeSourceMap_;

@@ -98,6 +97,7 @@ class DebugState

  public:
    DebugState(SharedCode code,
               const Metadata& metadata,
               const ShareableBytes* maybeBytecode);

    // If the source bytecode was saved when this Code was constructed, this
@@ -140,26 +140,6 @@ class DebugState
    // Debug URL helpers.

    JSString* debugDisplayURL(JSContext* cx) const;

    // Accessors for commonly used elements of linked structures.

    const Metadata& metadata() const { return code_->metadata(); }
    bool debugEnabled() const { return metadata().debugEnabled; }
    const CodeRangeVector& codeRanges() const { return metadata().codeRanges; }
    const CallSiteVector& callSites() const { return metadata().callSites; }

    uint32_t debugFuncToCodeRange(uint32_t funcIndex) const {
        return metadata().debugFuncToCodeRange[funcIndex];
    }

    // about:memory reporting:

    void addSizeOfMisc(MallocSizeOf mallocSizeOf,
                       Metadata::SeenSet* seenMetadata,
                       ShareableBytes::SeenSet* seenBytes,
                       Code::SeenSet* seenCode,
                       size_t* code,
                       size_t* data) const;
};

typedef UniquePtr<DebugState> UniqueDebugState;
Loading