mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-26 12:20:56 +00:00
merge mozilla-inbound to mozilla-central. r=merge a=merge
MozReview-Commit-ID: 74cERYrHFIG
This commit is contained in:
commit
9187795579
@ -55,7 +55,7 @@
|
||||
# Due to Apple Mac OS X packaging requirements files that are in the same
|
||||
# directory on other platforms must be located in different directories on
|
||||
# Mac OS X. The following defines allow specifying the Mac OS X bundle
|
||||
# location which also work on other platforms.
|
||||
# location which will also work on other platforms.
|
||||
#
|
||||
# @DIR_MACOS@
|
||||
# Equals Contents/MacOS/ on Mac OS X and is an empty string on other platforms.
|
||||
@ -64,53 +64,6 @@
|
||||
# Equals Contents/Resources/ on Mac OS X and is an empty string on other
|
||||
# platforms.
|
||||
|
||||
# Common File Removals
|
||||
# This is located under the "distribution/" directory and it was added before
|
||||
# Firefox 27
|
||||
@DIR_MACOS@distribution/extensions/testpilot@labs.mozilla.com.xpi
|
||||
|
||||
# Mac OS X v2 signing removals
|
||||
#ifdef XP_MACOSX
|
||||
@DIR_MACOS@active-update.xml
|
||||
@DIR_MACOS@update-settings.ini
|
||||
@DIR_MACOS@updates.xml
|
||||
@DIR_MACOS@defaults/*
|
||||
@DIR_MACOS@updates/*
|
||||
#endif
|
||||
|
||||
# Common Directory removals
|
||||
@DIR_MACOS@chrome/
|
||||
#ifdef XP_UNIX
|
||||
#ifndef XP_MACOSX
|
||||
chrome/icons/
|
||||
chrome/icons/default/
|
||||
#endif
|
||||
#endif
|
||||
@DIR_MACOS@chrome/overlayinfo/
|
||||
@DIR_MACOS@components/
|
||||
@DIR_MACOS@defaults/autoconfig/
|
||||
@DIR_MACOS@defaults/profile/
|
||||
@DIR_MACOS@defaults/profile/chrome/
|
||||
@DIR_MACOS@defaults/profile/US/*
|
||||
@DIR_MACOS@defaults/profile/extensions/
|
||||
@DIR_MACOS@defaults/profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/*
|
||||
@DIR_MACOS@distribution/
|
||||
@DIR_MACOS@distribution/extensions/
|
||||
@DIR_MACOS@extensions/
|
||||
@DIR_MACOS@extensions/inspector@mozilla.org/*
|
||||
@DIR_MACOS@extensions/reporter@mozilla.org/*
|
||||
@DIR_MACOS@extensions/talkback@mozilla.org/*
|
||||
@DIR_MACOS@extensions/testpilot@labs.mozilla.com/*
|
||||
@DIR_MACOS@extensions/{641d8d09-7dda-4850-8228-ac0ab65e2ac9}/*
|
||||
@DIR_MACOS@extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/*
|
||||
@DIR_MACOS@greprefs/
|
||||
@DIR_MACOS@jssubloader/
|
||||
@DIR_MACOS@modules/
|
||||
#ifdef XP_MACOSX
|
||||
@DIR_MACOS@plugins/Default Plugin.plugin/*
|
||||
@DIR_MACOS@plugins/JavaEmbeddingPlugin.bundle/*
|
||||
@DIR_MACOS@plugins/MRJPlugin.plugin/*
|
||||
Contents/Plug-Ins/PrintPDE.plugin/*
|
||||
#endif
|
||||
@DIR_MACOS@searchplugins/*
|
||||
@DIR_MACOS@webapprt/components/
|
||||
# An update watershed was required to update to Firefox 56 for LZMA and SHA384
|
||||
# support. This made it possible to delete all of the removal instructions in
|
||||
# this file.
|
||||
|
@ -279,37 +279,6 @@ WebGLContext::GetExtension(JSContext* cx,
|
||||
}
|
||||
}
|
||||
|
||||
if (ext == WebGLExtensionID::Unknown) {
|
||||
// We keep backward compatibility for these deprecated vendor-prefixed
|
||||
// alias. Do not add new ones anymore. Hide it behind the
|
||||
// webgl.enable-draft-extensions flag instead.
|
||||
|
||||
if (CompareWebGLExtensionName(name, "MOZ_WEBGL_lose_context")) {
|
||||
ext = WebGLExtensionID::WEBGL_lose_context;
|
||||
|
||||
} else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_compressed_texture_s3tc")) {
|
||||
ext = WebGLExtensionID::WEBGL_compressed_texture_s3tc;
|
||||
|
||||
} else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_compressed_texture_atc")) {
|
||||
ext = WebGLExtensionID::WEBGL_compressed_texture_atc;
|
||||
|
||||
} else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_compressed_texture_pvrtc")) {
|
||||
ext = WebGLExtensionID::WEBGL_compressed_texture_pvrtc;
|
||||
|
||||
} else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_depth_texture")) {
|
||||
ext = WebGLExtensionID::WEBGL_depth_texture;
|
||||
}
|
||||
|
||||
if (ext != WebGLExtensionID::Unknown) {
|
||||
GenerateWarning("getExtension('%s'): MOZ_ prefixed WebGL extension"
|
||||
" strings are deprecated. Support for them will be"
|
||||
" removed in the future. Use unprefixed extension"
|
||||
" strings. To get draft extensions, set the"
|
||||
" webgl.enable-draft-extensions preference.",
|
||||
name.get());
|
||||
}
|
||||
}
|
||||
|
||||
if (ext == WebGLExtensionID::Unknown)
|
||||
return;
|
||||
|
||||
@ -475,26 +444,6 @@ WebGLContext::GetSupportedExtensions(dom::Nullable< nsTArray<nsString> >& retval
|
||||
arr.AppendElement(NS_ConvertUTF8toUTF16(extStr));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We keep backward compatibility for these deprecated vendor-prefixed
|
||||
* alias. Do not add new ones anymore. Hide it behind the
|
||||
* webgl.enable-draft-extensions flag instead.
|
||||
*/
|
||||
if (IsExtensionSupported(callerType, WebGLExtensionID::WEBGL_lose_context))
|
||||
arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_lose_context"));
|
||||
if (IsExtensionSupported(callerType,
|
||||
WebGLExtensionID::WEBGL_compressed_texture_s3tc))
|
||||
arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_s3tc"));
|
||||
if (IsExtensionSupported(callerType,
|
||||
WebGLExtensionID::WEBGL_compressed_texture_atc))
|
||||
arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_atc"));
|
||||
if (IsExtensionSupported(callerType,
|
||||
WebGLExtensionID::WEBGL_compressed_texture_pvrtc))
|
||||
arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_pvrtc"));
|
||||
if (IsExtensionSupported(callerType,
|
||||
WebGLExtensionID::WEBGL_depth_texture))
|
||||
arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_depth_texture"));
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -9,7 +9,8 @@
|
||||
|
||||
#include "mozilla/Move.h"
|
||||
|
||||
#include "js/Utility.h"
|
||||
#include "jsutil.h"
|
||||
|
||||
#include "js/Vector.h"
|
||||
|
||||
namespace js {
|
||||
@ -46,19 +47,11 @@ class Fifo
|
||||
|
||||
private:
|
||||
// Maintain invariants after adding or removing entries.
|
||||
bool fixup() {
|
||||
if (!front_.empty())
|
||||
return true;
|
||||
|
||||
if (!front_.reserve(rear_.length()))
|
||||
return false;
|
||||
|
||||
while (!rear_.empty()) {
|
||||
front_.infallibleAppend(mozilla::Move(rear_.back()));
|
||||
rear_.popBack();
|
||||
void fixup() {
|
||||
if (front_.empty() && !rear_.empty()) {
|
||||
front_.swap(rear_);
|
||||
Reverse(front_.begin(), front_.end());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
@ -98,10 +91,7 @@ class Fifo
|
||||
MOZ_MUST_USE bool pushBack(U&& u) {
|
||||
if (!rear_.append(mozilla::Forward<U>(u)))
|
||||
return false;
|
||||
if (!fixup()) {
|
||||
rear_.popBack();
|
||||
return false;
|
||||
}
|
||||
fixup();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -110,10 +100,7 @@ class Fifo
|
||||
MOZ_MUST_USE bool emplaceBack(Args&&... args) {
|
||||
if (!rear_.emplaceBack(mozilla::Forward<Args>(args)...))
|
||||
return false;
|
||||
if (!fixup()) {
|
||||
rear_.popBack();
|
||||
return false;
|
||||
}
|
||||
fixup();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -128,20 +115,17 @@ class Fifo
|
||||
}
|
||||
|
||||
// Remove the front element from the queue.
|
||||
MOZ_MUST_USE bool popFront() {
|
||||
void popFront() {
|
||||
MOZ_ASSERT(!empty());
|
||||
T t(mozilla::Move(front()));
|
||||
front_.popBack();
|
||||
if (!fixup()) {
|
||||
// Attempt to remain in a valid state by reinserting the element
|
||||
// back at the front. If we can't remain in a valid state in the
|
||||
// face of OOMs, crash.
|
||||
AutoEnterOOMUnsafeRegion oomUnsafe;
|
||||
if (!front_.append(mozilla::Move(t)))
|
||||
oomUnsafe.crash("js::Fifo::popFront");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
fixup();
|
||||
}
|
||||
|
||||
// Convenience utility.
|
||||
T popCopyFront() {
|
||||
T ret = front();
|
||||
popFront();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Clear all elements from the queue.
|
||||
@ -149,6 +133,15 @@ class Fifo
|
||||
front_.clear();
|
||||
rear_.clear();
|
||||
}
|
||||
|
||||
// Clear all elements for which the given predicate returns 'true'. Return
|
||||
// the number of elements removed.
|
||||
template <class Pred>
|
||||
size_t eraseIf(Pred pred) {
|
||||
size_t erased = EraseIf(front_, pred);
|
||||
erased += EraseIf(rear_, pred);
|
||||
return erased;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
@ -79,7 +79,7 @@ class MutableWrappedPtrOperations<TraceableFifo<T, Capacity, AllocPolicy>, Wrapp
|
||||
return fifo().emplaceBack(mozilla::Forward<Args...>(args...));
|
||||
}
|
||||
|
||||
bool popFront() { return fifo().popFront(); }
|
||||
void popFront() { fifo().popFront(); }
|
||||
void clear() { fifo().clear(); }
|
||||
};
|
||||
|
||||
|
@ -323,7 +323,7 @@ BEGIN_TEST(testTraceableFifo)
|
||||
bool match;
|
||||
CHECK(JS_StringEqualsAscii(cx, JSID_TO_STRING(shapes.front()->propid()), buffer, &match));
|
||||
CHECK(match);
|
||||
CHECK(shapes.popFront());
|
||||
shapes.popFront();
|
||||
}
|
||||
|
||||
CHECK(shapes.empty());
|
||||
|
@ -2298,10 +2298,7 @@ Debugger::appendAllocationSite(JSContext* cx, HandleObject obj, HandleSavedFrame
|
||||
}
|
||||
|
||||
if (allocationsLog.length() > maxAllocationsLogLength) {
|
||||
if (!allocationsLog.popFront()) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
allocationsLog.popFront();
|
||||
MOZ_ASSERT(allocationsLog.length() == maxAllocationsLogLength);
|
||||
allocationsLogOverflowed = true;
|
||||
}
|
||||
|
@ -238,10 +238,7 @@ DebuggerMemory::drainAllocationsLog(JSContext* cx, unsigned argc, Value* vp)
|
||||
// Pop the front queue entry, and delete it immediately, so that the GC
|
||||
// sees the AllocationsLogEntry's HeapPtr barriers run atomically with
|
||||
// the change to the graph (the queue link).
|
||||
if (!dbg->allocationsLog.popFront()) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
dbg->allocationsLog.popFront();
|
||||
}
|
||||
|
||||
dbg->allocationsLogOverflowed = false;
|
||||
@ -278,12 +275,8 @@ DebuggerMemory::setMaxAllocationsLogLength(JSContext* cx, unsigned argc, Value*
|
||||
Debugger* dbg = memory->getDebugger();
|
||||
dbg->maxAllocationsLogLength = max;
|
||||
|
||||
while (dbg->allocationsLog.length() > dbg->maxAllocationsLogLength) {
|
||||
if (!dbg->allocationsLog.popFront()) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while (dbg->allocationsLog.length() > dbg->maxAllocationsLogLength)
|
||||
dbg->allocationsLog.popFront();
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
|
@ -106,7 +106,7 @@ js::StartOffThreadWasmCompile(wasm::CompileTask* task, wasm::CompileMode mode)
|
||||
{
|
||||
AutoLockHelperThreadState lock;
|
||||
|
||||
if (!HelperThreadState().wasmWorklist(lock, mode).append(task))
|
||||
if (!HelperThreadState().wasmWorklist(lock, mode).pushBack(task))
|
||||
return false;
|
||||
|
||||
HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER, lock);
|
||||
@ -1802,7 +1802,7 @@ HelperThread::handleWasmWorkload(AutoLockHelperThreadState& locked, wasm::Compil
|
||||
MOZ_ASSERT(HelperThreadState().canStartWasmCompile(locked, mode));
|
||||
MOZ_ASSERT(idle());
|
||||
|
||||
currentTask.emplace(HelperThreadState().wasmWorklist(locked, mode).popCopy());
|
||||
currentTask.emplace(HelperThreadState().wasmWorklist(locked, mode).popCopyFront());
|
||||
|
||||
wasm::CompileTask* task = wasmTask();
|
||||
{
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "jsapi.h"
|
||||
#include "jscntxt.h"
|
||||
|
||||
#include "ds/Fifo.h"
|
||||
#include "jit/Ion.h"
|
||||
#include "threading/ConditionVariable.h"
|
||||
#include "vm/MutexIDs.h"
|
||||
@ -57,7 +58,7 @@ enum class ParseTaskKind
|
||||
namespace wasm {
|
||||
|
||||
struct CompileTask;
|
||||
typedef Vector<CompileTask*, 0, SystemAllocPolicy> CompileTaskPtrVector;
|
||||
typedef Fifo<CompileTask*, 0, SystemAllocPolicy> CompileTaskPtrFifo;
|
||||
|
||||
struct Tier2GeneratorTask
|
||||
{
|
||||
@ -107,8 +108,8 @@ class GlobalHelperThreadState
|
||||
IonBuilderVector ionWorklist_, ionFinishedList_, ionFreeList_;
|
||||
|
||||
// wasm worklists.
|
||||
wasm::CompileTaskPtrVector wasmWorklist_tier1_;
|
||||
wasm::CompileTaskPtrVector wasmWorklist_tier2_;
|
||||
wasm::CompileTaskPtrFifo wasmWorklist_tier1_;
|
||||
wasm::CompileTaskPtrFifo wasmWorklist_tier2_;
|
||||
wasm::Tier2GeneratorTaskPtrVector wasmTier2GeneratorWorklist_;
|
||||
|
||||
// Count of finished Tier2Generator tasks.
|
||||
@ -200,7 +201,7 @@ class GlobalHelperThreadState
|
||||
return ionFreeList_;
|
||||
}
|
||||
|
||||
wasm::CompileTaskPtrVector& wasmWorklist(const AutoLockHelperThreadState&, wasm::CompileMode m) {
|
||||
wasm::CompileTaskPtrFifo& wasmWorklist(const AutoLockHelperThreadState&, wasm::CompileMode m) {
|
||||
switch (m) {
|
||||
case wasm::CompileMode::Once:
|
||||
case wasm::CompileMode::Tier1:
|
||||
|
@ -366,9 +366,9 @@ struct js::AsmJSMetadata : Metadata, AsmJSMetadataCacheablePod
|
||||
return scriptSource.get();
|
||||
}
|
||||
bool getFuncName(const Bytes* maybeBytecode, uint32_t funcIndex, UTF8Bytes* name) const override {
|
||||
// asm.js doesn't allow exporting imports or putting imports in tables
|
||||
MOZ_ASSERT(funcIndex >= AsmJSFirstDefFuncIndex);
|
||||
const char* p = asmJSFuncNames[funcIndex - AsmJSFirstDefFuncIndex].get();
|
||||
const char* p = asmJSFuncNames[funcIndex].get();
|
||||
if (!p)
|
||||
return true;
|
||||
return name->append(p, strlen(p));
|
||||
}
|
||||
|
||||
@ -1385,38 +1385,52 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
class Func
|
||||
{
|
||||
PropertyName* name_;
|
||||
uint32_t sigIndex_;
|
||||
uint32_t firstUse_;
|
||||
uint32_t index_;
|
||||
uint32_t srcBegin_;
|
||||
uint32_t srcEnd_;
|
||||
uint32_t funcDefIndex_;
|
||||
|
||||
bool defined_;
|
||||
|
||||
// Available when defined:
|
||||
uint32_t srcBegin_;
|
||||
uint32_t srcEnd_;
|
||||
uint32_t line_;
|
||||
Bytes bytes_;
|
||||
Uint32Vector callSiteLineNums_;
|
||||
|
||||
public:
|
||||
Func(PropertyName* name, uint32_t firstUse, uint32_t index)
|
||||
: name_(name), firstUse_(firstUse), index_(index),
|
||||
srcBegin_(0), srcEnd_(0), defined_(false)
|
||||
Func(PropertyName* name, uint32_t sigIndex, uint32_t firstUse, uint32_t funcDefIndex)
|
||||
: name_(name), sigIndex_(sigIndex), firstUse_(firstUse), funcDefIndex_(funcDefIndex),
|
||||
defined_(false), srcBegin_(0), srcEnd_(0), line_(0)
|
||||
{}
|
||||
|
||||
PropertyName* name() const { return name_; }
|
||||
uint32_t sigIndex() const { return sigIndex_; }
|
||||
uint32_t firstUse() const { return firstUse_; }
|
||||
bool defined() const { return defined_; }
|
||||
uint32_t index() const { return index_; }
|
||||
uint32_t funcDefIndex() const { return funcDefIndex_; }
|
||||
|
||||
void define(ParseNode* fn) {
|
||||
void define(ParseNode* fn, uint32_t line, Bytes&& bytes, Uint32Vector&& callSiteLineNums) {
|
||||
MOZ_ASSERT(!defined_);
|
||||
defined_ = true;
|
||||
srcBegin_ = fn->pn_pos.begin;
|
||||
srcEnd_ = fn->pn_pos.end;
|
||||
line_ = line;
|
||||
bytes_ = Move(bytes);
|
||||
callSiteLineNums_ = Move(callSiteLineNums);
|
||||
}
|
||||
|
||||
uint32_t srcBegin() const { MOZ_ASSERT(defined_); return srcBegin_; }
|
||||
uint32_t srcEnd() const { MOZ_ASSERT(defined_); return srcEnd_; }
|
||||
uint32_t line() const { MOZ_ASSERT(defined_); return line_; }
|
||||
const Bytes& bytes() const { MOZ_ASSERT(defined_); return bytes_; }
|
||||
Uint32Vector& callSiteLineNums() { MOZ_ASSERT(defined_); return callSiteLineNums_; }
|
||||
};
|
||||
|
||||
typedef Vector<const Func*> ConstFuncVector;
|
||||
typedef Vector<Func*> FuncVector;
|
||||
typedef Vector<Func> FuncVector;
|
||||
|
||||
class FuncPtrTable
|
||||
class Table
|
||||
{
|
||||
uint32_t sigIndex_;
|
||||
PropertyName* name_;
|
||||
@ -1424,10 +1438,10 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
uint32_t mask_;
|
||||
bool defined_;
|
||||
|
||||
FuncPtrTable(FuncPtrTable&& rhs) = delete;
|
||||
Table(Table&& rhs) = delete;
|
||||
|
||||
public:
|
||||
FuncPtrTable(uint32_t sigIndex, PropertyName* name, uint32_t firstUse, uint32_t mask)
|
||||
Table(uint32_t sigIndex, PropertyName* name, uint32_t firstUse, uint32_t mask)
|
||||
: sigIndex_(sigIndex), name_(name), firstUse_(firstUse), mask_(mask), defined_(false)
|
||||
{}
|
||||
|
||||
@ -1439,7 +1453,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
void define() { MOZ_ASSERT(!defined_); defined_ = true; }
|
||||
};
|
||||
|
||||
typedef Vector<FuncPtrTable*> FuncPtrTableVector;
|
||||
typedef Vector<Table*> TableVector;
|
||||
|
||||
class Global
|
||||
{
|
||||
@ -1449,7 +1463,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
ConstantLiteral,
|
||||
ConstantImport,
|
||||
Function,
|
||||
FuncPtrTable,
|
||||
Table,
|
||||
FFI,
|
||||
ArrayView,
|
||||
ArrayViewCtor,
|
||||
@ -1467,8 +1481,8 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
unsigned index_;
|
||||
NumLit literalValue_;
|
||||
} varOrConst;
|
||||
uint32_t funcIndex_;
|
||||
uint32_t funcPtrTableIndex_;
|
||||
uint32_t funcDefIndex_;
|
||||
uint32_t tableIndex_;
|
||||
uint32_t ffiIndex_;
|
||||
struct {
|
||||
Scalar::Type viewType_;
|
||||
@ -1506,13 +1520,13 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
MOZ_ASSERT(which_ == ConstantLiteral);
|
||||
return u.varOrConst.literalValue_;
|
||||
}
|
||||
uint32_t funcIndex() const {
|
||||
uint32_t funcDefIndex() const {
|
||||
MOZ_ASSERT(which_ == Function);
|
||||
return u.funcIndex_;
|
||||
return u.funcDefIndex_;
|
||||
}
|
||||
uint32_t funcPtrTableIndex() const {
|
||||
MOZ_ASSERT(which_ == FuncPtrTable);
|
||||
return u.funcPtrTableIndex_;
|
||||
uint32_t tableIndex() const {
|
||||
MOZ_ASSERT(which_ == Table);
|
||||
return u.tableIndex_;
|
||||
}
|
||||
unsigned ffiIndex() const {
|
||||
MOZ_ASSERT(which_ == FFI);
|
||||
@ -1589,21 +1603,43 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
};
|
||||
|
||||
private:
|
||||
class NamedSig
|
||||
class HashableSig
|
||||
{
|
||||
PropertyName* name_;
|
||||
const SigWithId* sig_;
|
||||
uint32_t sigIndex_;
|
||||
const SigWithIdVector& sigs_;
|
||||
|
||||
public:
|
||||
NamedSig(PropertyName* name, const SigWithId& sig)
|
||||
: name_(name), sig_(&sig)
|
||||
HashableSig(uint32_t sigIndex, const SigWithIdVector& sigs)
|
||||
: sigIndex_(sigIndex), sigs_(sigs)
|
||||
{}
|
||||
uint32_t sigIndex() const {
|
||||
return sigIndex_;
|
||||
}
|
||||
const Sig& sig() const {
|
||||
return sigs_[sigIndex_];
|
||||
}
|
||||
|
||||
// Implement HashPolicy:
|
||||
typedef const Sig& Lookup;
|
||||
static HashNumber hash(Lookup l) {
|
||||
return l.hash();
|
||||
}
|
||||
static bool match(HashableSig lhs, Lookup rhs) {
|
||||
return lhs.sig() == rhs;
|
||||
}
|
||||
};
|
||||
|
||||
class NamedSig : public HashableSig
|
||||
{
|
||||
PropertyName* name_;
|
||||
|
||||
public:
|
||||
NamedSig(PropertyName* name, uint32_t sigIndex, const SigWithIdVector& sigs)
|
||||
: HashableSig(sigIndex, sigs), name_(name)
|
||||
{}
|
||||
PropertyName* name() const {
|
||||
return name_;
|
||||
}
|
||||
const Sig& sig() const {
|
||||
return *sig_;
|
||||
}
|
||||
|
||||
// Implement HashPolicy:
|
||||
struct Lookup {
|
||||
@ -1615,11 +1651,12 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
return HashGeneric(l.name, l.sig.hash());
|
||||
}
|
||||
static bool match(NamedSig lhs, Lookup rhs) {
|
||||
return lhs.name_ == rhs.name && *lhs.sig_ == rhs.sig;
|
||||
return lhs.name() == rhs.name && lhs.sig() == rhs.sig;
|
||||
}
|
||||
};
|
||||
typedef HashMap<NamedSig, uint32_t, NamedSig> ImportMap;
|
||||
typedef HashMap<const SigWithId*, uint32_t, SigHashPolicy> SigMap;
|
||||
|
||||
typedef HashSet<HashableSig, HashableSig> SigSet;
|
||||
typedef HashMap<NamedSig, uint32_t, NamedSig> FuncImportMap;
|
||||
typedef HashMap<PropertyName*, Global*> GlobalMap;
|
||||
typedef HashMap<PropertyName*, MathBuiltin> MathNameMap;
|
||||
typedef HashMap<PropertyName*, AsmJSAtomicsBuiltinFunction> AtomicsNameMap;
|
||||
@ -1640,18 +1677,17 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
|
||||
// Validation-internal state:
|
||||
LifoAlloc validationLifo_;
|
||||
FuncVector functions_;
|
||||
FuncPtrTableVector funcPtrTables_;
|
||||
FuncVector funcDefs_;
|
||||
TableVector tables_;
|
||||
GlobalMap globalMap_;
|
||||
SigMap sigMap_;
|
||||
ImportMap importMap_;
|
||||
SigSet sigSet_;
|
||||
FuncImportMap funcImportMap_;
|
||||
ArrayViewVector arrayViews_;
|
||||
bool atomicsPresent_;
|
||||
bool simdPresent_;
|
||||
|
||||
// State used to build the AsmJSModule in finish():
|
||||
ModuleEnvironment env_;
|
||||
ModuleGenerator mg_;
|
||||
MutableAsmJSMetadata asmJSMetadata_;
|
||||
|
||||
// Error reporting:
|
||||
@ -1687,29 +1723,26 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
return standardLibrarySimdOpNames_.putNew(atom->asPropertyName(), op);
|
||||
}
|
||||
bool newSig(Sig&& sig, uint32_t* sigIndex) {
|
||||
*sigIndex = 0;
|
||||
if (mg_.numSigs() >= AsmJSMaxTypes)
|
||||
if (env_.sigs.length() >= MaxTypes)
|
||||
return failCurrentOffset("too many signatures");
|
||||
|
||||
*sigIndex = mg_.numSigs();
|
||||
mg_.initSig(*sigIndex, Move(sig));
|
||||
return true;
|
||||
*sigIndex = env_.sigs.length();
|
||||
return env_.sigs.append(Move(sig));
|
||||
}
|
||||
bool declareSig(Sig&& sig, uint32_t* sigIndex) {
|
||||
SigMap::AddPtr p = sigMap_.lookupForAdd(sig);
|
||||
SigSet::AddPtr p = sigSet_.lookupForAdd(sig);
|
||||
if (p) {
|
||||
*sigIndex = p->value();
|
||||
MOZ_ASSERT(mg_.sig(*sigIndex) == sig);
|
||||
*sigIndex = p->sigIndex();
|
||||
MOZ_ASSERT(env_.sigs[*sigIndex] == sig);
|
||||
return true;
|
||||
}
|
||||
|
||||
return newSig(Move(sig), sigIndex) &&
|
||||
sigMap_.add(p, &mg_.sig(*sigIndex), *sigIndex);
|
||||
sigSet_.add(p, HashableSig(*sigIndex, env_.sigs));
|
||||
}
|
||||
|
||||
public:
|
||||
ModuleValidator(JSContext* cx, const CompileArgs& args, AsmJSParser& parser,
|
||||
ParseNode* moduleFunctionNode)
|
||||
ModuleValidator(JSContext* cx, AsmJSParser& parser, ParseNode* moduleFunctionNode)
|
||||
: cx_(cx),
|
||||
parser_(parser),
|
||||
moduleFunctionNode_(moduleFunctionNode),
|
||||
@ -1722,20 +1755,21 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
standardLibrarySimdOpNames_(cx),
|
||||
dummyFunction_(cx),
|
||||
validationLifo_(VALIDATION_LIFO_DEFAULT_CHUNK_SIZE),
|
||||
functions_(cx),
|
||||
funcPtrTables_(cx),
|
||||
funcDefs_(cx),
|
||||
tables_(cx),
|
||||
globalMap_(cx),
|
||||
sigMap_(cx),
|
||||
importMap_(cx),
|
||||
sigSet_(cx),
|
||||
funcImportMap_(cx),
|
||||
arrayViews_(cx),
|
||||
atomicsPresent_(false),
|
||||
simdPresent_(false),
|
||||
env_(CompileMode::Once, Tier::Ion, DebugEnabled::False, ModuleKind::AsmJS),
|
||||
mg_(args, &env_, nullptr, nullptr),
|
||||
errorString_(nullptr),
|
||||
errorOffset_(UINT32_MAX),
|
||||
errorOverRecursed_(false)
|
||||
{}
|
||||
{
|
||||
env_.minMemoryLength = RoundUpToNextValidAsmJSHeapLength(0);
|
||||
}
|
||||
|
||||
~ModuleValidator() {
|
||||
if (errorString_) {
|
||||
@ -1790,7 +1824,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
!parser_.pc->sc()->hasExplicitUseStrict();
|
||||
asmJSMetadata_->scriptSource.reset(parser_.ss);
|
||||
|
||||
if (!globalMap_.init() || !sigMap_.init() || !importMap_.init())
|
||||
if (!globalMap_.init() || !sigSet_.init() || !funcImportMap_.init())
|
||||
return false;
|
||||
|
||||
if (!standardLibraryMathNames_.init() ||
|
||||
@ -1855,17 +1889,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
if (!dummyFunction_)
|
||||
return false;
|
||||
|
||||
env_.minMemoryLength = RoundUpToNextValidAsmJSHeapLength(0);
|
||||
if (!env_.sigs.resize(AsmJSMaxTypes) ||
|
||||
!env_.funcSigs.resize(AsmJSMaxFuncs) ||
|
||||
!env_.funcImportGlobalDataOffsets.resize(AsmJSMaxImports) ||
|
||||
!env_.tables.resize(AsmJSMaxTables) ||
|
||||
!env_.asmJSSigToTableIndex.resize(AsmJSMaxTypes))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return mg_.init(/* codeSectionSize (ignored) = */ 0, asmJSMetadata_.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
JSContext* cx() const { return cx_; }
|
||||
@ -1873,13 +1897,13 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
PropertyName* globalArgumentName() const { return globalArgumentName_; }
|
||||
PropertyName* importArgumentName() const { return importArgumentName_; }
|
||||
PropertyName* bufferArgumentName() const { return bufferArgumentName_; }
|
||||
ModuleGenerator& mg() { return mg_; }
|
||||
const ModuleEnvironment& env() { return env_; }
|
||||
AsmJSParser& parser() const { return parser_; }
|
||||
TokenStream& tokenStream() const { return parser_.tokenStream; }
|
||||
RootedFunction& dummyFunction() { return dummyFunction_; }
|
||||
bool supportsSimd() const { return cx_->jitSupportsSimd(); }
|
||||
bool atomicsPresent() const { return atomicsPresent_; }
|
||||
uint32_t minMemoryLength() const { return mg_.minMemoryLength(); }
|
||||
uint32_t minMemoryLength() const { return env_.minMemoryLength; }
|
||||
|
||||
void initModuleFunctionName(PropertyName* name) {
|
||||
MOZ_ASSERT(!moduleFunctionName_);
|
||||
@ -1919,8 +1943,8 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
MOZ_ASSERT(type.isGlobalVarType());
|
||||
MOZ_ASSERT(type == Type::canonicalize(Type::lit(lit)));
|
||||
|
||||
uint32_t index;
|
||||
if (!mg_.addGlobal(type.canonicalToValType(), isConst, &index))
|
||||
uint32_t index = env_.globals.length();
|
||||
if (!env_.globals.emplaceBack(type.canonicalToValType(), !isConst, index))
|
||||
return false;
|
||||
|
||||
Global::Which which = isConst ? Global::ConstantLiteral : Global::Variable;
|
||||
@ -1946,9 +1970,9 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
if (!fieldChars)
|
||||
return false;
|
||||
|
||||
uint32_t index;
|
||||
uint32_t index = env_.globals.length();
|
||||
ValType valType = type.canonicalToValType();
|
||||
if (!mg_.addGlobal(valType, isConst, &index))
|
||||
if (!env_.globals.emplaceBack(valType, !isConst, index))
|
||||
return false;
|
||||
|
||||
Global::Which which = isConst ? Global::ConstantImport : Global::Variable;
|
||||
@ -2150,75 +2174,101 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
|
||||
// Declare which function is exported which gives us an index into the
|
||||
// module ExportVector.
|
||||
if (!mg_.addExport(Move(fieldChars), func.index()))
|
||||
uint32_t funcIndex = funcImportMap_.count() + func.funcDefIndex();
|
||||
if (!env_.exports.emplaceBack(Move(fieldChars), funcIndex, DefinitionKind::Function))
|
||||
return false;
|
||||
|
||||
// The exported function might have already been exported in which case
|
||||
// the index will refer into the range of AsmJSExports.
|
||||
return asmJSMetadata_->asmJSExports.emplaceBack(func.index(),
|
||||
return asmJSMetadata_->asmJSExports.emplaceBack(funcIndex,
|
||||
func.srcBegin() - asmJSMetadata_->srcStart,
|
||||
func.srcEnd() - asmJSMetadata_->srcStart);
|
||||
}
|
||||
bool addFunction(PropertyName* name, uint32_t firstUse, Sig&& sig, Func** func) {
|
||||
bool addFuncDef(PropertyName* name, uint32_t firstUse, Sig&& sig, Func** func) {
|
||||
uint32_t sigIndex;
|
||||
if (!declareSig(Move(sig), &sigIndex))
|
||||
return false;
|
||||
uint32_t funcIndex = AsmJSFirstDefFuncIndex + numFunctions();
|
||||
if (funcIndex >= AsmJSMaxFuncs)
|
||||
|
||||
uint32_t funcDefIndex = funcDefs_.length();
|
||||
if (funcDefIndex >= MaxFuncs)
|
||||
return failCurrentOffset("too many functions");
|
||||
mg_.initFuncSig(funcIndex, sigIndex);
|
||||
|
||||
Global* global = validationLifo_.new_<Global>(Global::Function);
|
||||
if (!global)
|
||||
return false;
|
||||
global->u.funcIndex_ = funcIndex;
|
||||
global->u.funcDefIndex_ = funcDefIndex;
|
||||
if (!globalMap_.putNew(name, global))
|
||||
return false;
|
||||
*func = validationLifo_.new_<Func>(name, firstUse, funcIndex);
|
||||
return *func && functions_.append(*func);
|
||||
if (!funcDefs_.emplaceBack(name, sigIndex, firstUse, funcDefIndex))
|
||||
return false;
|
||||
*func = &funcDefs_.back();
|
||||
return true;
|
||||
}
|
||||
bool declareFuncPtrTable(Sig&& sig, PropertyName* name, uint32_t firstUse, uint32_t mask,
|
||||
uint32_t* index)
|
||||
uint32_t* tableIndex)
|
||||
{
|
||||
if (mask > MaxTableInitialLength)
|
||||
return failCurrentOffset("function pointer table too big");
|
||||
|
||||
MOZ_ASSERT(env_.tables.length() == tables_.length());
|
||||
*tableIndex = env_.tables.length();
|
||||
|
||||
uint32_t sigIndex;
|
||||
if (!newSig(Move(sig), &sigIndex))
|
||||
return false;
|
||||
if (!mg_.initSigTableLength(sigIndex, mask + 1))
|
||||
|
||||
MOZ_ASSERT(sigIndex >= env_.asmJSSigToTableIndex.length());
|
||||
if (!env_.asmJSSigToTableIndex.resize(sigIndex + 1))
|
||||
return false;
|
||||
Global* global = validationLifo_.new_<Global>(Global::FuncPtrTable);
|
||||
|
||||
env_.asmJSSigToTableIndex[sigIndex] = env_.tables.length();
|
||||
if (!env_.tables.emplaceBack(TableKind::TypedFunction, Limits(mask + 1)))
|
||||
return false;
|
||||
|
||||
Global* global = validationLifo_.new_<Global>(Global::Table);
|
||||
if (!global)
|
||||
return false;
|
||||
global->u.funcPtrTableIndex_ = *index = funcPtrTables_.length();
|
||||
|
||||
global->u.tableIndex_ = *tableIndex;
|
||||
if (!globalMap_.putNew(name, global))
|
||||
return false;
|
||||
FuncPtrTable* t = validationLifo_.new_<FuncPtrTable>(sigIndex, name, firstUse, mask);
|
||||
return t && funcPtrTables_.append(t);
|
||||
|
||||
Table* t = validationLifo_.new_<Table>(sigIndex, name, firstUse, mask);
|
||||
return t && tables_.append(t);
|
||||
}
|
||||
bool defineFuncPtrTable(uint32_t funcPtrTableIndex, Uint32Vector&& elems) {
|
||||
FuncPtrTable& table = *funcPtrTables_[funcPtrTableIndex];
|
||||
bool defineFuncPtrTable(uint32_t tableIndex, Uint32Vector&& elems) {
|
||||
Table& table = *tables_[tableIndex];
|
||||
if (table.defined())
|
||||
return false;
|
||||
|
||||
table.define();
|
||||
return mg_.initSigTableElems(table.sigIndex(), Move(elems));
|
||||
|
||||
for (uint32_t& index : elems)
|
||||
index += funcImportMap_.count();
|
||||
|
||||
return env_.elemSegments.emplaceBack(tableIndex, InitExpr(Val(uint32_t(0))), Move(elems));
|
||||
}
|
||||
bool declareImport(PropertyName* name, Sig&& sig, unsigned ffiIndex, uint32_t* funcIndex) {
|
||||
ImportMap::AddPtr p = importMap_.lookupForAdd(NamedSig::Lookup(name, sig));
|
||||
bool declareImport(PropertyName* name, Sig&& sig, unsigned ffiIndex, uint32_t* importIndex) {
|
||||
FuncImportMap::AddPtr p = funcImportMap_.lookupForAdd(NamedSig::Lookup(name, sig));
|
||||
if (p) {
|
||||
*funcIndex = p->value();
|
||||
*importIndex = p->value();
|
||||
return true;
|
||||
}
|
||||
*funcIndex = asmJSMetadata_->asmJSImports.length();
|
||||
if (*funcIndex > AsmJSMaxImports)
|
||||
|
||||
*importIndex = funcImportMap_.count();
|
||||
MOZ_ASSERT(*importIndex == asmJSMetadata_->asmJSImports.length());
|
||||
|
||||
if (*importIndex >= MaxImports)
|
||||
return failCurrentOffset("too many imports");
|
||||
|
||||
if (!asmJSMetadata_->asmJSImports.emplaceBack(ffiIndex))
|
||||
return false;
|
||||
|
||||
uint32_t sigIndex;
|
||||
if (!declareSig(Move(sig), &sigIndex))
|
||||
return false;
|
||||
if (!mg_.initImport(*funcIndex, sigIndex))
|
||||
return false;
|
||||
return importMap_.add(p, NamedSig(name, mg_.sig(sigIndex)), *funcIndex);
|
||||
|
||||
return funcImportMap_.add(p, NamedSig(name, sigIndex, env_.sigs), *importIndex);
|
||||
}
|
||||
|
||||
bool tryConstantAccess(uint64_t start, uint64_t width) {
|
||||
@ -2227,8 +2277,8 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
if (len > uint64_t(INT32_MAX) + 1)
|
||||
return false;
|
||||
len = RoundUpToNextValidAsmJSHeapLength(len);
|
||||
if (len > mg_.minMemoryLength())
|
||||
mg_.bumpMinMemoryLength(len);
|
||||
if (len > env_.minMemoryLength)
|
||||
env_.minMemoryLength = len;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2303,17 +2353,17 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
const ArrayView& arrayView(unsigned i) const {
|
||||
return arrayViews_[i];
|
||||
}
|
||||
unsigned numFunctions() const {
|
||||
return functions_.length();
|
||||
unsigned numFuncDefs() const {
|
||||
return funcDefs_.length();
|
||||
}
|
||||
Func& function(unsigned i) const {
|
||||
return *functions_[i];
|
||||
const Func& funcDef(unsigned i) const {
|
||||
return funcDefs_[i];
|
||||
}
|
||||
unsigned numFuncPtrTables() const {
|
||||
return funcPtrTables_.length();
|
||||
return tables_.length();
|
||||
}
|
||||
FuncPtrTable& funcPtrTable(unsigned i) const {
|
||||
return *funcPtrTables_[i];
|
||||
Table& table(unsigned i) const {
|
||||
return *tables_[i];
|
||||
}
|
||||
|
||||
const Global* lookupGlobal(PropertyName* name) const {
|
||||
@ -2322,13 +2372,11 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Func* lookupFunction(PropertyName* name) {
|
||||
Func* lookupFuncDef(PropertyName* name) {
|
||||
if (GlobalMap::Ptr p = globalMap_.lookup(name)) {
|
||||
Global* value = p->value();
|
||||
if (value->which() == Global::Function) {
|
||||
MOZ_ASSERT(value->funcIndex() >= AsmJSFirstDefFuncIndex);
|
||||
return functions_[value->funcIndex() - AsmJSFirstDefFuncIndex];
|
||||
}
|
||||
if (value->which() == Global::Function)
|
||||
return &funcDefs_[value->funcDefIndex()];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -2357,19 +2405,36 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
|
||||
bool startFunctionBodies() {
|
||||
if (!arrayViews_.empty())
|
||||
mg_.initMemoryUsage(atomicsPresent_ ? MemoryUsage::Shared : MemoryUsage::Unshared);
|
||||
|
||||
return mg_.startFuncDefs();
|
||||
}
|
||||
bool finishFunctionBodies() {
|
||||
return mg_.finishFuncDefs();
|
||||
env_.memoryUsage = atomicsPresent_ ? MemoryUsage::Shared : MemoryUsage::Unshared;
|
||||
else
|
||||
env_.memoryUsage = MemoryUsage::None;
|
||||
return true;
|
||||
}
|
||||
SharedModule finish() {
|
||||
MOZ_ASSERT(env_.funcSigs.empty());
|
||||
if (!env_.funcSigs.resize(funcImportMap_.count() + funcDefs_.length()))
|
||||
return nullptr;
|
||||
for (FuncImportMap::Range r = funcImportMap_.all(); !r.empty(); r.popFront()) {
|
||||
uint32_t funcIndex = r.front().value();
|
||||
MOZ_ASSERT(!env_.funcSigs[funcIndex]);
|
||||
env_.funcSigs[funcIndex] = &env_.sigs[r.front().key().sigIndex()];
|
||||
}
|
||||
for (const Func& func : funcDefs_) {
|
||||
uint32_t funcIndex = funcImportMap_.count() + func.funcDefIndex();
|
||||
MOZ_ASSERT(!env_.funcSigs[funcIndex]);
|
||||
env_.funcSigs[funcIndex] = &env_.sigs[func.sigIndex()];
|
||||
}
|
||||
|
||||
if (!env_.funcImportGlobalDataOffsets.resize(funcImportMap_.count()))
|
||||
return nullptr;
|
||||
|
||||
asmJSMetadata_->usesSimd = simdPresent_;
|
||||
|
||||
MOZ_ASSERT(asmJSMetadata_->asmJSFuncNames.empty());
|
||||
for (const Func* func : functions_) {
|
||||
CacheableChars funcName = StringToNewUTF8CharsZ(cx_, *func->name());
|
||||
if (!asmJSMetadata_->asmJSFuncNames.resize(funcImportMap_.count()))
|
||||
return nullptr;
|
||||
for (const Func& func : funcDefs_) {
|
||||
CacheableChars funcName = StringToNewUTF8CharsZ(cx_, *func.name());
|
||||
if (!funcName || !asmJSMetadata_->asmJSFuncNames.emplaceBack(Move(funcName)))
|
||||
return nullptr;
|
||||
}
|
||||
@ -2382,13 +2447,47 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
uint32_t endAfterCurly = pos.end;
|
||||
asmJSMetadata_->srcLengthWithRightBrace = endAfterCurly - asmJSMetadata_->srcStart;
|
||||
|
||||
ScriptedCaller scriptedCaller;
|
||||
if (parser_.ss->filename()) {
|
||||
scriptedCaller.line = scriptedCaller.column = 0; // unused
|
||||
scriptedCaller.filename = DuplicateString(parser_.ss->filename());
|
||||
if (!scriptedCaller.filename)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MutableCompileArgs args = cx_->new_<CompileArgs>();
|
||||
if (!args || !args->initFromContext(cx_, Move(scriptedCaller)))
|
||||
return nullptr;
|
||||
|
||||
uint32_t codeSectionSize = 0;
|
||||
for (const Func& func : funcDefs_)
|
||||
codeSectionSize += func.bytes().length();
|
||||
|
||||
// asm.js does not have any wasm bytecode to save; view-source is
|
||||
// provided through the ScriptSource.
|
||||
SharedBytes bytes = cx_->new_<ShareableBytes>();
|
||||
if (!bytes)
|
||||
return nullptr;
|
||||
|
||||
return mg_.finishModule(*bytes);
|
||||
ModuleGenerator mg(*args, &env_, nullptr, nullptr);
|
||||
if (!mg.init(codeSectionSize, asmJSMetadata_.get()))
|
||||
return nullptr;
|
||||
|
||||
if (!mg.startFuncDefs())
|
||||
return nullptr;
|
||||
|
||||
for (Func& func : funcDefs_) {
|
||||
if (!mg.compileFuncDef(funcImportMap_.count() + func.funcDefIndex(), func.line(),
|
||||
func.bytes().begin(), func.bytes().end(),
|
||||
Move(func.callSiteLineNums()))) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mg.finishFuncDefs())
|
||||
return nullptr;
|
||||
|
||||
return mg.finishModule(*bytes);
|
||||
}
|
||||
};
|
||||
|
||||
@ -2927,13 +3026,13 @@ class MOZ_STACK_CLASS FunctionValidator
|
||||
continueLabels_.init();
|
||||
}
|
||||
|
||||
bool finish(uint32_t funcIndex, unsigned line) {
|
||||
void define(ModuleValidator::Func* func, unsigned line) {
|
||||
MOZ_ASSERT(!blockDepth_);
|
||||
MOZ_ASSERT(breakableStack_.empty());
|
||||
MOZ_ASSERT(continuableStack_.empty());
|
||||
MOZ_ASSERT(breakLabels_.empty());
|
||||
MOZ_ASSERT(continueLabels_.empty());
|
||||
return m_.mg().compileFuncDef(funcIndex, line, Move(bytes_), Move(callSiteLineNums_));
|
||||
func->define(fn_, line, Move(bytes_), Move(callSiteLineNums_));
|
||||
}
|
||||
|
||||
bool fail(ParseNode* pn, const char* str) {
|
||||
@ -3980,7 +4079,7 @@ CheckVarRef(FunctionValidator& f, ParseNode* varRef, Type* type)
|
||||
case ModuleValidator::Global::FFI:
|
||||
case ModuleValidator::Global::MathBuiltinFunction:
|
||||
case ModuleValidator::Global::AtomicsBuiltinFunction:
|
||||
case ModuleValidator::Global::FuncPtrTable:
|
||||
case ModuleValidator::Global::Table:
|
||||
case ModuleValidator::Global::ArrayView:
|
||||
case ModuleValidator::Global::ArrayViewCtor:
|
||||
case ModuleValidator::Global::SimdCtor:
|
||||
@ -4732,14 +4831,16 @@ static bool
|
||||
CheckFunctionSignature(ModuleValidator& m, ParseNode* usepn, Sig&& sig, PropertyName* name,
|
||||
ModuleValidator::Func** func)
|
||||
{
|
||||
ModuleValidator::Func* existing = m.lookupFunction(name);
|
||||
ModuleValidator::Func* existing = m.lookupFuncDef(name);
|
||||
if (!existing) {
|
||||
if (!CheckModuleLevelName(m, usepn, name))
|
||||
return false;
|
||||
return m.addFunction(name, usepn->pn_pos.begin, Move(sig), func);
|
||||
return m.addFuncDef(name, usepn->pn_pos.begin, Move(sig), func);
|
||||
}
|
||||
|
||||
if (!CheckSignatureAgainstExisting(m, usepn, sig, m.mg().funcSig(existing->index())))
|
||||
const SigWithId& existingSig = m.env().sigs[existing->sigIndex()];
|
||||
|
||||
if (!CheckSignatureAgainstExisting(m, usepn, sig, existingSig))
|
||||
return false;
|
||||
|
||||
*func = existing;
|
||||
@ -4773,10 +4874,10 @@ CheckInternalCall(FunctionValidator& f, ParseNode* callNode, PropertyName* calle
|
||||
if (!CheckFunctionSignature(f.m(), callNode, Move(sig), calleeName, &callee))
|
||||
return false;
|
||||
|
||||
if (!f.writeCall(callNode, Op::Call))
|
||||
if (!f.writeCall(callNode, MozOp::OldCallDirect))
|
||||
return false;
|
||||
|
||||
if (!f.encoder().writeVarU32(callee->index()))
|
||||
if (!f.encoder().writeVarU32(callee->funcDefIndex()))
|
||||
return false;
|
||||
|
||||
*type = Type::ret(ret);
|
||||
@ -4785,27 +4886,27 @@ CheckInternalCall(FunctionValidator& f, ParseNode* callNode, PropertyName* calle
|
||||
|
||||
static bool
|
||||
CheckFuncPtrTableAgainstExisting(ModuleValidator& m, ParseNode* usepn, PropertyName* name,
|
||||
Sig&& sig, unsigned mask, uint32_t* funcPtrTableIndex)
|
||||
Sig&& sig, unsigned mask, uint32_t* tableIndex)
|
||||
{
|
||||
if (const ModuleValidator::Global* existing = m.lookupGlobal(name)) {
|
||||
if (existing->which() != ModuleValidator::Global::FuncPtrTable)
|
||||
if (existing->which() != ModuleValidator::Global::Table)
|
||||
return m.failName(usepn, "'%s' is not a function-pointer table", name);
|
||||
|
||||
ModuleValidator::FuncPtrTable& table = m.funcPtrTable(existing->funcPtrTableIndex());
|
||||
ModuleValidator::Table& table = m.table(existing->tableIndex());
|
||||
if (mask != table.mask())
|
||||
return m.failf(usepn, "mask does not match previous value (%u)", table.mask());
|
||||
|
||||
if (!CheckSignatureAgainstExisting(m, usepn, sig, m.mg().sig(table.sigIndex())))
|
||||
if (!CheckSignatureAgainstExisting(m, usepn, sig, m.env().sigs[table.sigIndex()]))
|
||||
return false;
|
||||
|
||||
*funcPtrTableIndex = existing->funcPtrTableIndex();
|
||||
*tableIndex = existing->tableIndex();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!CheckModuleLevelName(m, usepn, name))
|
||||
return false;
|
||||
|
||||
if (!m.declareFuncPtrTable(Move(sig), name, usepn->pn_pos.begin, mask, funcPtrTableIndex))
|
||||
if (!m.declareFuncPtrTable(Move(sig), name, usepn->pn_pos.begin, mask, tableIndex))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -4825,7 +4926,7 @@ CheckFuncPtrCall(FunctionValidator& f, ParseNode* callNode, Type ret, Type* type
|
||||
|
||||
PropertyName* name = tableNode->name();
|
||||
if (const ModuleValidator::Global* existing = f.lookupGlobal(name)) {
|
||||
if (existing->which() != ModuleValidator::Global::FuncPtrTable)
|
||||
if (existing->which() != ModuleValidator::Global::Table)
|
||||
return f.failName(tableNode, "'%s' is not the name of a function-pointer array", name);
|
||||
}
|
||||
|
||||
@ -4860,7 +4961,7 @@ CheckFuncPtrCall(FunctionValidator& f, ParseNode* callNode, Type ret, Type* type
|
||||
return false;
|
||||
|
||||
// Call signature
|
||||
if (!f.encoder().writeVarU32(f.m().funcPtrTable(tableIndex).sigIndex()))
|
||||
if (!f.encoder().writeVarU32(f.m().table(tableIndex).sigIndex()))
|
||||
return false;
|
||||
|
||||
*type = Type::ret(ret);
|
||||
@ -4893,14 +4994,14 @@ CheckFFICall(FunctionValidator& f, ParseNode* callNode, unsigned ffiIndex, Type
|
||||
|
||||
Sig sig(Move(args), ret.canonicalToExprType());
|
||||
|
||||
uint32_t funcIndex;
|
||||
if (!f.m().declareImport(calleeName, Move(sig), ffiIndex, &funcIndex))
|
||||
uint32_t importIndex;
|
||||
if (!f.m().declareImport(calleeName, Move(sig), ffiIndex, &importIndex))
|
||||
return false;
|
||||
|
||||
if (!f.writeCall(callNode, Op::Call))
|
||||
return false;
|
||||
|
||||
if (!f.encoder().writeVarU32(funcIndex))
|
||||
if (!f.encoder().writeVarU32(importIndex))
|
||||
return false;
|
||||
|
||||
*type = Type::ret(ret);
|
||||
@ -5827,7 +5928,7 @@ CheckCoercedCall(FunctionValidator& f, ParseNode* call, Type ret, Type* type)
|
||||
case ModuleValidator::Global::ConstantLiteral:
|
||||
case ModuleValidator::Global::ConstantImport:
|
||||
case ModuleValidator::Global::Variable:
|
||||
case ModuleValidator::Global::FuncPtrTable:
|
||||
case ModuleValidator::Global::Table:
|
||||
case ModuleValidator::Global::ArrayView:
|
||||
case ModuleValidator::Global::ArrayViewCtor:
|
||||
return f.failName(callee, "'%s' is not callable function", callee->name());
|
||||
@ -6437,14 +6538,10 @@ CheckLoopConditionOnEntry(FunctionValidator& f, ParseNode* cond)
|
||||
if (!condType.isInt())
|
||||
return f.failf(cond, "%s is not a subtype of int", condType.toChars());
|
||||
|
||||
// TODO change this to i32.eqz
|
||||
// i32.eq 0 $f
|
||||
if (!f.writeInt32Lit(0))
|
||||
return false;
|
||||
if (!f.encoder().writeOp(Op::I32Eq))
|
||||
if (!f.encoder().writeOp(Op::I32Eqz))
|
||||
return false;
|
||||
|
||||
// brIf (i32.eq 0 $f) $out
|
||||
// brIf (i32.eqz $f) $out
|
||||
if (!f.writeBreakIf())
|
||||
return false;
|
||||
|
||||
@ -7126,10 +7223,7 @@ CheckFunction(ModuleValidator& m)
|
||||
if (func->defined())
|
||||
return m.failName(fn, "function '%s' already defined", FunctionName(fn));
|
||||
|
||||
func->define(fn);
|
||||
|
||||
if (!f.finish(func->index(), line))
|
||||
return m.fail(fn, "internal compiler failure (probably out of memory)");
|
||||
f.define(func, line);
|
||||
|
||||
// Release the parser's lifo memory only after the last use of a parse node.
|
||||
m.parser().release(mark);
|
||||
@ -7139,8 +7233,8 @@ CheckFunction(ModuleValidator& m)
|
||||
static bool
|
||||
CheckAllFunctionsDefined(ModuleValidator& m)
|
||||
{
|
||||
for (unsigned i = 0; i < m.numFunctions(); i++) {
|
||||
ModuleValidator::Func& f = m.function(i);
|
||||
for (unsigned i = 0; i < m.numFuncDefs(); i++) {
|
||||
const ModuleValidator::Func& f = m.funcDef(i);
|
||||
if (!f.defined())
|
||||
return m.failNameOffset(f.firstUse(), "missing definition of function %s", f.name());
|
||||
}
|
||||
@ -7183,18 +7277,18 @@ CheckFuncPtrTable(ModuleValidator& m, ParseNode* var)
|
||||
|
||||
unsigned mask = length - 1;
|
||||
|
||||
Uint32Vector elemFuncIndices;
|
||||
Uint32Vector elemFuncDefIndices;
|
||||
const Sig* sig = nullptr;
|
||||
for (ParseNode* elem = ListHead(arrayLiteral); elem; elem = NextNode(elem)) {
|
||||
if (!elem->isKind(PNK_NAME))
|
||||
return m.fail(elem, "function-pointer table's elements must be names of functions");
|
||||
|
||||
PropertyName* funcName = elem->name();
|
||||
const ModuleValidator::Func* func = m.lookupFunction(funcName);
|
||||
const ModuleValidator::Func* func = m.lookupFuncDef(funcName);
|
||||
if (!func)
|
||||
return m.fail(elem, "function-pointer table's elements must be names of functions");
|
||||
|
||||
const Sig& funcSig = m.mg().funcSig(func->index());
|
||||
const Sig& funcSig = m.env().sigs[func->sigIndex()];
|
||||
if (sig) {
|
||||
if (*sig != funcSig)
|
||||
return m.fail(elem, "all functions in table must have same signature");
|
||||
@ -7202,7 +7296,7 @@ CheckFuncPtrTable(ModuleValidator& m, ParseNode* var)
|
||||
sig = &funcSig;
|
||||
}
|
||||
|
||||
if (!elemFuncIndices.append(func->index()))
|
||||
if (!elemFuncDefIndices.append(func->funcDefIndex()))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -7214,7 +7308,7 @@ CheckFuncPtrTable(ModuleValidator& m, ParseNode* var)
|
||||
if (!CheckFuncPtrTableAgainstExisting(m, var, var->name(), Move(copy), mask, &tableIndex))
|
||||
return false;
|
||||
|
||||
if (!m.defineFuncPtrTable(tableIndex, Move(elemFuncIndices)))
|
||||
if (!m.defineFuncPtrTable(tableIndex, Move(elemFuncDefIndices)))
|
||||
return m.fail(var, "duplicate function-pointer definition");
|
||||
|
||||
return true;
|
||||
@ -7236,11 +7330,11 @@ CheckFuncPtrTables(ModuleValidator& m)
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < m.numFuncPtrTables(); i++) {
|
||||
ModuleValidator::FuncPtrTable& funcPtrTable = m.funcPtrTable(i);
|
||||
if (!funcPtrTable.defined()) {
|
||||
return m.failNameOffset(funcPtrTable.firstUse(),
|
||||
ModuleValidator::Table& table = m.table(i);
|
||||
if (!table.defined()) {
|
||||
return m.failNameOffset(table.firstUse(),
|
||||
"function-pointer table %s wasn't defined",
|
||||
funcPtrTable.name());
|
||||
table.name());
|
||||
}
|
||||
}
|
||||
|
||||
@ -7254,7 +7348,7 @@ CheckModuleExportFunction(ModuleValidator& m, ParseNode* pn, PropertyName* maybe
|
||||
return m.fail(pn, "expected name of exported function");
|
||||
|
||||
PropertyName* funcName = pn->name();
|
||||
const ModuleValidator::Func* func = m.lookupFunction(funcName);
|
||||
const ModuleValidator::Func* func = m.lookupFuncDef(funcName);
|
||||
if (!func)
|
||||
return m.failName(pn, "function '%s' not found", funcName);
|
||||
|
||||
@ -7338,19 +7432,7 @@ CheckModule(JSContext* cx, AsmJSParser& parser, ParseNode* stmtList, unsigned* t
|
||||
ParseNode* moduleFunctionNode = parser.pc->functionBox()->functionNode;
|
||||
MOZ_ASSERT(moduleFunctionNode);
|
||||
|
||||
ScriptedCaller scriptedCaller;
|
||||
if (parser.ss->filename()) {
|
||||
scriptedCaller.line = scriptedCaller.column = 0; // unused
|
||||
scriptedCaller.filename = DuplicateString(parser.ss->filename());
|
||||
if (!scriptedCaller.filename)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MutableCompileArgs args = cx->new_<CompileArgs>();
|
||||
if (!args || !args->initFromContext(cx, Move(scriptedCaller)))
|
||||
return nullptr;
|
||||
|
||||
ModuleValidator m(cx, *args, parser, moduleFunctionNode);
|
||||
ModuleValidator m(cx, parser, moduleFunctionNode);
|
||||
if (!m.init())
|
||||
return nullptr;
|
||||
|
||||
@ -7375,9 +7457,6 @@ CheckModule(JSContext* cx, AsmJSParser& parser, ParseNode* stmtList, unsigned* t
|
||||
if (!CheckFunctions(m))
|
||||
return nullptr;
|
||||
|
||||
if (!m.finishFunctionBodies())
|
||||
return nullptr;
|
||||
|
||||
if (!CheckFuncPtrTables(m))
|
||||
return nullptr;
|
||||
|
||||
|
@ -322,7 +322,8 @@ enum class Op
|
||||
};
|
||||
|
||||
inline bool
|
||||
IsPrefixByte(uint8_t b) {
|
||||
IsPrefixByte(uint8_t b)
|
||||
{
|
||||
return b >= uint8_t(Op::AtomicPrefix);
|
||||
}
|
||||
|
||||
@ -364,6 +365,7 @@ enum class MozOp
|
||||
F64Atan2,
|
||||
|
||||
// asm.js-style call_indirect with the callee evaluated first.
|
||||
OldCallDirect,
|
||||
OldCallIndirect,
|
||||
|
||||
// Atomics
|
||||
@ -504,22 +506,6 @@ static const unsigned MaxMemoryMaximumPages = 65536;
|
||||
static const unsigned MaxModuleBytes = 1024 * 1024 * 1024;
|
||||
static const unsigned MaxFunctionBytes = 128 * 1024;
|
||||
|
||||
// To be able to assign function indices during compilation while the number of
|
||||
// imports is still unknown, asm.js sets a maximum number of imports so it can
|
||||
// immediately start handing out function indices starting at the maximum + 1.
|
||||
// this means that there is a "hole" between the last import and the first
|
||||
// definition, but that's fine.
|
||||
|
||||
static const unsigned AsmJSMaxTypes = 4 * 1024;
|
||||
static const unsigned AsmJSMaxFuncs = 512 * 1024;
|
||||
static const unsigned AsmJSMaxImports = 4 * 1024;
|
||||
static const unsigned AsmJSMaxTables = 4 * 1024;
|
||||
static const unsigned AsmJSFirstDefFuncIndex = AsmJSMaxImports + 1;
|
||||
|
||||
static_assert(AsmJSMaxTypes <= MaxTypes, "conservative");
|
||||
static_assert(AsmJSMaxImports <= MaxImports, "conservative");
|
||||
static_assert(AsmJSFirstDefFuncIndex < MaxFuncs, "conservative");
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace js
|
||||
|
||||
|
@ -390,6 +390,8 @@ wasm::Classify(OpBytes op)
|
||||
case MozOp::F32x4store2:
|
||||
case MozOp::F32x4store3:
|
||||
return OpKind::TeeStore;
|
||||
case MozOp::OldCallDirect:
|
||||
return OpKind::OldCallDirect;
|
||||
case MozOp::OldCallIndirect:
|
||||
return OpKind::OldCallIndirect;
|
||||
case MozOp::I32AtomicsLoad:
|
||||
|
@ -133,6 +133,7 @@ enum class OpKind {
|
||||
TeeGlobal,
|
||||
Call,
|
||||
CallIndirect,
|
||||
OldCallDirect,
|
||||
OldCallIndirect,
|
||||
Return,
|
||||
If,
|
||||
@ -529,6 +530,8 @@ class MOZ_STACK_CLASS OpIter : private Policy
|
||||
MOZ_MUST_USE bool readB32x4Const(I32x4* i32x4);
|
||||
MOZ_MUST_USE bool readCall(uint32_t* calleeIndex, ValueVector* argValues);
|
||||
MOZ_MUST_USE bool readCallIndirect(uint32_t* sigIndex, Value* callee, ValueVector* argValues);
|
||||
MOZ_MUST_USE bool readOldCallDirect(uint32_t numFuncImports, uint32_t* funcIndex,
|
||||
ValueVector* argValues);
|
||||
MOZ_MUST_USE bool readOldCallIndirect(uint32_t* sigIndex, Value* callee, ValueVector* argValues);
|
||||
MOZ_MUST_USE bool readAtomicLoad(LinearMemoryAddress<Value>* addr,
|
||||
Scalar::Type* viewType);
|
||||
@ -1622,6 +1625,33 @@ OpIter<Policy>::readCallIndirect(uint32_t* sigIndex, Value* callee, ValueVector*
|
||||
return push(sig.ret());
|
||||
}
|
||||
|
||||
template <typename Policy>
|
||||
inline bool
|
||||
OpIter<Policy>::readOldCallDirect(uint32_t numFuncImports, uint32_t* funcIndex,
|
||||
ValueVector* argValues)
|
||||
{
|
||||
MOZ_ASSERT(Classify(op_) == OpKind::OldCallDirect);
|
||||
|
||||
uint32_t funcDefIndex;
|
||||
if (!readVarU32(&funcDefIndex))
|
||||
return fail("unable to read call function index");
|
||||
|
||||
if (UINT32_MAX - funcDefIndex < numFuncImports)
|
||||
return fail("callee index out of range");
|
||||
|
||||
*funcIndex = numFuncImports + funcDefIndex;
|
||||
|
||||
if (*funcIndex >= env_.funcSigs.length())
|
||||
return fail("callee index out of range");
|
||||
|
||||
const Sig& sig = *env_.funcSigs[*funcIndex];
|
||||
|
||||
if (!popCallArgs(sig.args(), argValues))
|
||||
return false;
|
||||
|
||||
return push(sig.ret());
|
||||
}
|
||||
|
||||
template <typename Policy>
|
||||
inline bool
|
||||
OpIter<Policy>::readOldCallIndirect(uint32_t* sigIndex, Value* callee, ValueVector* argValues)
|
||||
|
@ -359,6 +359,7 @@ typedef UniquePtr<MetadataTier> UniqueMetadataTier;
|
||||
|
||||
class Metadata : public ShareableBase<Metadata>, public MetadataCacheablePod
|
||||
{
|
||||
protected:
|
||||
UniqueMetadataTier metadata1_;
|
||||
mutable UniqueMetadataTier metadata2_; // Access only when hasTier2() is true
|
||||
mutable Atomic<bool> hasTier2_;
|
||||
|
@ -72,9 +72,6 @@ ModuleGenerator::ModuleGenerator(const CompileArgs& args, ModuleEnvironment* env
|
||||
linkDataTier_(nullptr),
|
||||
metadataTier_(nullptr),
|
||||
taskState_(mutexid::WasmCompileTaskState),
|
||||
numFuncDefs_(0),
|
||||
numSigs_(0),
|
||||
numTables_(0),
|
||||
lifo_(GENERATOR_LIFO_DEFAULT_CHUNK_SIZE),
|
||||
masmAlloc_(&lifo_),
|
||||
masm_(MacroAssembler::WasmToken(), masmAlloc_),
|
||||
@ -103,9 +100,9 @@ ModuleGenerator::~ModuleGenerator()
|
||||
// Remove any pending compilation tasks from the worklist.
|
||||
{
|
||||
AutoLockHelperThreadState lock;
|
||||
CompileTaskPtrVector& worklist = HelperThreadState().wasmWorklist(lock, mode());
|
||||
CompileTaskPtrFifo& worklist = HelperThreadState().wasmWorklist(lock, mode());
|
||||
auto pred = [this](CompileTask* task) { return &task->state == &taskState_; };
|
||||
size_t removed = EraseIf(worklist, pred);
|
||||
size_t removed = worklist.eraseIf(pred);
|
||||
MOZ_ASSERT(outstanding_ >= removed);
|
||||
outstanding_ -= removed;
|
||||
}
|
||||
@ -139,72 +136,77 @@ ModuleGenerator::~ModuleGenerator()
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::initAsmJS(Metadata* asmJSMetadata)
|
||||
ModuleGenerator::allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOffset)
|
||||
{
|
||||
MOZ_ASSERT(env_->isAsmJS());
|
||||
MOZ_ASSERT(!startedFuncDefs_);
|
||||
|
||||
if (!linkData_.initTier1(Tier::Ion, *asmJSMetadata))
|
||||
CheckedInt<uint32_t> newGlobalDataLength(metadata_->globalDataLength);
|
||||
|
||||
newGlobalDataLength += ComputeByteAlignment(newGlobalDataLength.value(), align);
|
||||
if (!newGlobalDataLength.isValid())
|
||||
return false;
|
||||
linkDataTier_ = &linkData_.linkData(Tier::Ion);
|
||||
|
||||
metadataTier_ = &asmJSMetadata->metadata(Tier::Ion);
|
||||
metadata_ = asmJSMetadata;
|
||||
MOZ_ASSERT(isAsmJS());
|
||||
*globalDataOffset = newGlobalDataLength.value();
|
||||
newGlobalDataLength += bytes;
|
||||
|
||||
// For asm.js, the Vectors in ModuleEnvironment are max-sized reservations
|
||||
// and will be initialized in a linear order via init* functions as the
|
||||
// module is generated.
|
||||
|
||||
MOZ_ASSERT(env_->sigs.length() == AsmJSMaxTypes);
|
||||
MOZ_ASSERT(env_->tables.length() == AsmJSMaxTables);
|
||||
MOZ_ASSERT(env_->asmJSSigToTableIndex.length() == AsmJSMaxTypes);
|
||||
if (!newGlobalDataLength.isValid())
|
||||
return false;
|
||||
|
||||
metadata_->globalDataLength = newGlobalDataLength.value();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::initWasm(size_t codeSectionSize)
|
||||
ModuleGenerator::init(size_t codeSectionSize, Metadata* maybeAsmJSMetadata)
|
||||
{
|
||||
MOZ_ASSERT(!env_->isAsmJS());
|
||||
// Perform fallible metadata, linkdata, assumption allocations.
|
||||
|
||||
auto metadataTier = js::MakeUnique<MetadataTier>(tier());
|
||||
if (!metadataTier)
|
||||
return false;
|
||||
if (maybeAsmJSMetadata) {
|
||||
MOZ_ASSERT(isAsmJS());
|
||||
metadataTier_ = &maybeAsmJSMetadata->metadata(tier());
|
||||
metadata_ = maybeAsmJSMetadata;
|
||||
} else {
|
||||
MOZ_ASSERT(!isAsmJS());
|
||||
auto metadataTier = js::MakeUnique<MetadataTier>(tier());
|
||||
if (!metadataTier)
|
||||
return false;
|
||||
metadataTier_ = metadataTier.get();
|
||||
metadata_ = js_new<Metadata>(Move(metadataTier));
|
||||
if (!metadata_)
|
||||
return false;
|
||||
}
|
||||
|
||||
metadata_ = js_new<Metadata>(Move(metadataTier));
|
||||
if (!metadata_)
|
||||
return false;
|
||||
|
||||
metadataTier_ = &metadata_->metadata(tier());
|
||||
if (compileArgs_->scriptedCaller.filename) {
|
||||
metadata_->filename = DuplicateString(compileArgs_->scriptedCaller.filename.get());
|
||||
if (!metadata_->filename)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!linkData_.initTier1(tier(), *metadata_))
|
||||
return false;
|
||||
|
||||
linkDataTier_ = &linkData_.linkData(tier());
|
||||
|
||||
MOZ_ASSERT(!isAsmJS());
|
||||
if (!assumptions_.clone(compileArgs_->assumptions))
|
||||
return false;
|
||||
|
||||
// For wasm, the amount of code, functions, signatures, imports, exports,
|
||||
// etc are known a priori.
|
||||
// The funcToCodeRange_ maps function indices to code-range indices and all
|
||||
// elements will be initialized by the time module generation is finished.
|
||||
|
||||
numSigs_ = env_->sigs.length();
|
||||
numTables_ = env_->tables.length();
|
||||
if (!funcToCodeRange_.appendN(BAD_CODE_RANGE, env_->funcSigs.length()))
|
||||
return false;
|
||||
|
||||
// When estimating the MacroAssembler buffer size, be extra conservative
|
||||
// since the price is low and the cost of an extra resize is high.
|
||||
// Pre-reserve space for large Vectors to avoid the significant cost of the
|
||||
// final reallocs. In particular, the MacroAssembler can be enormous, so be
|
||||
// extra conservative. Note, podResizeToFit calls at the end will trim off
|
||||
// unneeded capacity.
|
||||
|
||||
if (!masm_.reserve(size_t(1.2 * EstimateCompiledCodeSize(tier(), codeSectionSize))))
|
||||
return false;
|
||||
|
||||
// Although we could compute it more precisely (only the number of far jumps
|
||||
// is unknown), 2x number of functions is a good conservative estimate and
|
||||
// podResizeToFit will remove waste at the end.
|
||||
|
||||
if (!metadataTier_->codeRanges.reserve(2 * env_->numFuncDefs()))
|
||||
return false;
|
||||
|
||||
// Code can vary a lot, so use a conservative estimate of 1 load/store/call/trap
|
||||
// per 10 bytes of bytecode and rely on podResizeToFit() to remove waste.
|
||||
|
||||
const size_t CallSitesPerByteCode = 10;
|
||||
if (!metadataTier_->callSites.reserve(codeSectionSize / CallSitesPerByteCode))
|
||||
return false;
|
||||
@ -215,10 +217,19 @@ ModuleGenerator::initWasm(size_t codeSectionSize)
|
||||
|
||||
// Allocate space in TlsData for declarations that need it.
|
||||
|
||||
MOZ_ASSERT(metadata_->globalDataLength == 0);
|
||||
|
||||
for (size_t i = 0; i < env_->funcImportGlobalDataOffsets.length(); i++) {
|
||||
env_->funcImportGlobalDataOffsets[i] = metadata_->globalDataLength;
|
||||
metadata_->globalDataLength += sizeof(FuncImportTls);
|
||||
if (!addFuncImport(*env_->funcSigs[i], env_->funcImportGlobalDataOffsets[i]))
|
||||
uint32_t globalDataOffset;
|
||||
if (!allocateGlobalBytes(sizeof(FuncImportTls), sizeof(void*), &globalDataOffset))
|
||||
return false;
|
||||
|
||||
env_->funcImportGlobalDataOffsets[i] = globalDataOffset;
|
||||
|
||||
Sig copy;
|
||||
if (!copy.clone(*env_->funcSigs[i]))
|
||||
return false;
|
||||
if (!metadataTier_->funcImports.emplaceBack(Move(copy), globalDataOffset))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -227,72 +238,77 @@ ModuleGenerator::initWasm(size_t codeSectionSize)
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < numSigs_; i++) {
|
||||
SigWithId& sig = env_->sigs[i];
|
||||
if (SigIdDesc::isGlobal(sig)) {
|
||||
uint32_t globalDataOffset;
|
||||
if (!allocateGlobalBytes(sizeof(void*), sizeof(void*), &globalDataOffset))
|
||||
return false;
|
||||
if (!isAsmJS()) {
|
||||
for (SigWithId& sig : env_->sigs) {
|
||||
if (SigIdDesc::isGlobal(sig)) {
|
||||
uint32_t globalDataOffset;
|
||||
if (!allocateGlobalBytes(sizeof(void*), sizeof(void*), &globalDataOffset))
|
||||
return false;
|
||||
|
||||
sig.id = SigIdDesc::global(sig, globalDataOffset);
|
||||
sig.id = SigIdDesc::global(sig, globalDataOffset);
|
||||
|
||||
Sig copy;
|
||||
if (!copy.clone(sig))
|
||||
return false;
|
||||
Sig copy;
|
||||
if (!copy.clone(sig))
|
||||
return false;
|
||||
|
||||
if (!metadata_->sigIds.emplaceBack(Move(copy), sig.id))
|
||||
return false;
|
||||
} else {
|
||||
sig.id = SigIdDesc::immediate(sig);
|
||||
if (!metadata_->sigIds.emplaceBack(Move(copy), sig.id))
|
||||
return false;
|
||||
} else {
|
||||
sig.id = SigIdDesc::immediate(sig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (GlobalDesc& global : env_->globals) {
|
||||
if (global.isConstant())
|
||||
continue;
|
||||
if (!allocateGlobal(&global))
|
||||
|
||||
uint32_t width = SizeOf(global.type());
|
||||
|
||||
uint32_t globalDataOffset;
|
||||
if (!allocateGlobalBytes(width, width, &globalDataOffset))
|
||||
return false;
|
||||
|
||||
global.setOffset(globalDataOffset);
|
||||
}
|
||||
|
||||
// Build a HashSet of all exported functions, whether by explicit export of
|
||||
// the function, or implicitly by being an element of an external (imported
|
||||
// or exported) table, or being the start function.
|
||||
// Accumulate all exported functions, whether by explicit export or
|
||||
// implicitly by being an element of an external (imported or exported)
|
||||
// table or by being the start function. The FuncExportVector stored in
|
||||
// Metadata needs to be sorted (to allow O(log(n)) lookup at runtime) and
|
||||
// deduplicated, so use an intermediate vector to sort and de-duplicate.
|
||||
|
||||
Uint32Vector exportedFuncs;
|
||||
|
||||
for (const Export& exp : env_->exports) {
|
||||
if (exp.kind() == DefinitionKind::Function) {
|
||||
if (!exportedFuncs_.put(exp.funcIndex()))
|
||||
if (!exportedFuncs.append(exp.funcIndex()))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (env_->startFuncIndex) {
|
||||
metadata_->startFuncIndex.emplace(*env_->startFuncIndex);
|
||||
if (!exportedFuncs_.put(*env_->startFuncIndex))
|
||||
return false;
|
||||
for (ElemSegment& elems : env_->elemSegments) {
|
||||
if (env_->tables[elems.tableIndex].external) {
|
||||
if (!exportedFuncs.appendAll(elems.elemFuncIndices))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::init(size_t codeSectionSize, Metadata* maybeAsmJSMetadata)
|
||||
{
|
||||
if (!funcToCodeRange_.appendN(BAD_CODE_RANGE, env_->funcSigs.length()))
|
||||
if (env_->startFuncIndex && !exportedFuncs.append(*env_->startFuncIndex))
|
||||
return false;
|
||||
|
||||
if (!assumptions_.clone(compileArgs_->assumptions))
|
||||
std::sort(exportedFuncs.begin(), exportedFuncs.end());
|
||||
auto* newEnd = std::unique(exportedFuncs.begin(), exportedFuncs.end());
|
||||
exportedFuncs.erase(newEnd, exportedFuncs.end());
|
||||
|
||||
if (!metadataTier_->funcExports.reserve(exportedFuncs.length()))
|
||||
return false;
|
||||
|
||||
if (!exportedFuncs_.init())
|
||||
return false;
|
||||
|
||||
if (env_->isAsmJS() ? !initAsmJS(maybeAsmJSMetadata) : !initWasm(codeSectionSize))
|
||||
return false;
|
||||
|
||||
if (compileArgs_->scriptedCaller.filename) {
|
||||
metadata_->filename = DuplicateString(compileArgs_->scriptedCaller.filename.get());
|
||||
if (!metadata_->filename)
|
||||
for (uint32_t funcIndex : exportedFuncs) {
|
||||
Sig sig;
|
||||
if (!sig.clone(*env_->funcSigs[funcIndex]))
|
||||
return false;
|
||||
metadataTier_->funcExports.infallibleEmplaceBack(Move(sig), funcIndex);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -558,231 +574,6 @@ ModuleGenerator::linkCompiledCode(const CompiledCode& code)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::finishTask(CompileTask* task)
|
||||
{
|
||||
masm_.haltingAlign(CodeAlignment);
|
||||
|
||||
// Before merging in the new function's code, if calls in a prior code range
|
||||
// might go out of range, insert far jumps to extend the range.
|
||||
if (!InRange(startOfUnpatchedCallsites_, masm_.size() + task->output.bytes.length())) {
|
||||
startOfUnpatchedCallsites_ = masm_.size();
|
||||
if (!linkCallSites())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!linkCompiledCode(task->output))
|
||||
return false;
|
||||
|
||||
task->output.clear();
|
||||
|
||||
MOZ_ASSERT(task->inputs.empty());
|
||||
MOZ_ASSERT(task->output.empty());
|
||||
MOZ_ASSERT(task->lifo.isEmpty());
|
||||
freeTasks_.infallibleAppend(task);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::finishFuncExports()
|
||||
{
|
||||
// In addition to all the functions that were explicitly exported, any
|
||||
// element of an exported table is also exported.
|
||||
|
||||
for (ElemSegment& elems : env_->elemSegments) {
|
||||
if (env_->tables[elems.tableIndex].external) {
|
||||
for (uint32_t funcIndex : elems.elemFuncIndices) {
|
||||
if (!exportedFuncs_.put(funcIndex))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ModuleGenerator::exportedFuncs_ is an unordered HashSet. The
|
||||
// FuncExportVector stored in Metadata needs to be stored sorted by
|
||||
// function index to allow O(log(n)) lookup at runtime.
|
||||
|
||||
Uint32Vector sorted;
|
||||
if (!sorted.reserve(exportedFuncs_.count()))
|
||||
return false;
|
||||
|
||||
for (Uint32Set::Range r = exportedFuncs_.all(); !r.empty(); r.popFront())
|
||||
sorted.infallibleAppend(r.front());
|
||||
|
||||
std::sort(sorted.begin(), sorted.end());
|
||||
|
||||
MOZ_ASSERT(metadataTier_->funcExports.empty());
|
||||
if (!metadataTier_->funcExports.reserve(sorted.length()))
|
||||
return false;
|
||||
|
||||
for (uint32_t funcIndex : sorted) {
|
||||
Sig sig;
|
||||
if (!sig.clone(funcSig(funcIndex)))
|
||||
return false;
|
||||
|
||||
metadataTier_->funcExports.infallibleEmplaceBack(Move(sig), funcIndex);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::addFuncImport(const Sig& sig, uint32_t globalDataOffset)
|
||||
{
|
||||
MOZ_ASSERT(!finishedFuncDefs_);
|
||||
|
||||
Sig copy;
|
||||
if (!copy.clone(sig))
|
||||
return false;
|
||||
|
||||
return metadataTier_->funcImports.emplaceBack(Move(copy), globalDataOffset);
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOffset)
|
||||
{
|
||||
CheckedInt<uint32_t> newGlobalDataLength(metadata_->globalDataLength);
|
||||
|
||||
newGlobalDataLength += ComputeByteAlignment(newGlobalDataLength.value(), align);
|
||||
if (!newGlobalDataLength.isValid())
|
||||
return false;
|
||||
|
||||
*globalDataOffset = newGlobalDataLength.value();
|
||||
newGlobalDataLength += bytes;
|
||||
|
||||
if (!newGlobalDataLength.isValid())
|
||||
return false;
|
||||
|
||||
metadata_->globalDataLength = newGlobalDataLength.value();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::allocateGlobal(GlobalDesc* global)
|
||||
{
|
||||
MOZ_ASSERT(!startedFuncDefs_);
|
||||
unsigned width = 0;
|
||||
switch (global->type()) {
|
||||
case ValType::I32:
|
||||
case ValType::F32:
|
||||
width = 4;
|
||||
break;
|
||||
case ValType::I64:
|
||||
case ValType::F64:
|
||||
width = 8;
|
||||
break;
|
||||
case ValType::I8x16:
|
||||
case ValType::I16x8:
|
||||
case ValType::I32x4:
|
||||
case ValType::F32x4:
|
||||
case ValType::B8x16:
|
||||
case ValType::B16x8:
|
||||
case ValType::B32x4:
|
||||
width = 16;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t offset;
|
||||
if (!allocateGlobalBytes(width, width, &offset))
|
||||
return false;
|
||||
|
||||
global->setOffset(offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::addGlobal(ValType type, bool isConst, uint32_t* index)
|
||||
{
|
||||
MOZ_ASSERT(isAsmJS());
|
||||
MOZ_ASSERT(!startedFuncDefs_);
|
||||
|
||||
*index = env_->globals.length();
|
||||
GlobalDesc global(type, !isConst, *index);
|
||||
if (!allocateGlobal(&global))
|
||||
return false;
|
||||
|
||||
return env_->globals.append(global);
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::addExport(CacheableChars&& fieldName, uint32_t funcIndex)
|
||||
{
|
||||
MOZ_ASSERT(isAsmJS());
|
||||
return env_->exports.emplaceBack(Move(fieldName), funcIndex, DefinitionKind::Function) &&
|
||||
exportedFuncs_.put(funcIndex);
|
||||
}
|
||||
|
||||
void
|
||||
ModuleGenerator::initSig(uint32_t sigIndex, Sig&& sig)
|
||||
{
|
||||
MOZ_ASSERT(isAsmJS());
|
||||
MOZ_ASSERT(sigIndex == numSigs_);
|
||||
numSigs_++;
|
||||
|
||||
MOZ_ASSERT(env_->sigs[sigIndex] == Sig());
|
||||
env_->sigs[sigIndex] = Move(sig);
|
||||
}
|
||||
|
||||
const SigWithId&
|
||||
ModuleGenerator::sig(uint32_t index) const
|
||||
{
|
||||
MOZ_ASSERT(index < numSigs_);
|
||||
return env_->sigs[index];
|
||||
}
|
||||
|
||||
void
|
||||
ModuleGenerator::initFuncSig(uint32_t funcIndex, uint32_t sigIndex)
|
||||
{
|
||||
MOZ_ASSERT(isAsmJS());
|
||||
MOZ_ASSERT(!env_->funcSigs[funcIndex]);
|
||||
|
||||
env_->funcSigs[funcIndex] = &env_->sigs[sigIndex];
|
||||
}
|
||||
|
||||
void
|
||||
ModuleGenerator::initMemoryUsage(MemoryUsage memoryUsage)
|
||||
{
|
||||
MOZ_ASSERT(isAsmJS());
|
||||
MOZ_ASSERT(env_->memoryUsage == MemoryUsage::None);
|
||||
|
||||
env_->memoryUsage = memoryUsage;
|
||||
}
|
||||
|
||||
void
|
||||
ModuleGenerator::bumpMinMemoryLength(uint32_t newMinMemoryLength)
|
||||
{
|
||||
MOZ_ASSERT(isAsmJS());
|
||||
MOZ_ASSERT(newMinMemoryLength >= env_->minMemoryLength);
|
||||
|
||||
env_->minMemoryLength = newMinMemoryLength;
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::initImport(uint32_t funcIndex, uint32_t sigIndex)
|
||||
{
|
||||
MOZ_ASSERT(isAsmJS());
|
||||
|
||||
MOZ_ASSERT(!env_->funcSigs[funcIndex]);
|
||||
env_->funcSigs[funcIndex] = &env_->sigs[sigIndex];
|
||||
|
||||
uint32_t globalDataOffset;
|
||||
if (!allocateGlobalBytes(sizeof(FuncImportTls), sizeof(void*), &globalDataOffset))
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(!env_->funcImportGlobalDataOffsets[funcIndex]);
|
||||
env_->funcImportGlobalDataOffsets[funcIndex] = globalDataOffset;
|
||||
|
||||
MOZ_ASSERT(funcIndex == metadataTier_->funcImports.length());
|
||||
return addFuncImport(sig(sigIndex), globalDataOffset);
|
||||
}
|
||||
|
||||
const SigWithId&
|
||||
ModuleGenerator::funcSig(uint32_t funcIndex) const
|
||||
{
|
||||
MOZ_ASSERT(env_->funcSigs[funcIndex]);
|
||||
return *env_->funcSigs[funcIndex];
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::startFuncDefs()
|
||||
{
|
||||
@ -810,6 +601,21 @@ ModuleGenerator::startFuncDefs()
|
||||
for (size_t i = 0; i < numTasks; i++)
|
||||
freeTasks_.infallibleAppend(&tasks_[i]);
|
||||
|
||||
// Fill in function stubs for each import so that imported functions can be
|
||||
// used in all the places that normal function definitions can (table
|
||||
// elements, export calls, etc).
|
||||
|
||||
CompiledCode& importCode = tasks_[0].output;
|
||||
MOZ_ASSERT(importCode.empty());
|
||||
|
||||
if (!GenerateImportFunctions(*env_, metadataTier_->funcImports, &importCode))
|
||||
return false;
|
||||
|
||||
if (!linkCompiledCode(importCode))
|
||||
return false;
|
||||
|
||||
importCode.clear();
|
||||
|
||||
startedFuncDefs_ = true;
|
||||
MOZ_ASSERT(!finishedFuncDefs_);
|
||||
return true;
|
||||
@ -858,6 +664,31 @@ wasm::ExecuteCompileTaskFromHelperThread(CompileTask* task)
|
||||
taskState->failedOrFinished.notify_one();
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::finishTask(CompileTask* task)
|
||||
{
|
||||
masm_.haltingAlign(CodeAlignment);
|
||||
|
||||
// Before merging in the new function's code, if calls in a prior code range
|
||||
// might go out of range, insert far jumps to extend the range.
|
||||
if (!InRange(startOfUnpatchedCallsites_, masm_.size() + task->output.bytes.length())) {
|
||||
startOfUnpatchedCallsites_ = masm_.size();
|
||||
if (!linkCallSites())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!linkCompiledCode(task->output))
|
||||
return false;
|
||||
|
||||
task->output.clear();
|
||||
|
||||
MOZ_ASSERT(task->inputs.empty());
|
||||
MOZ_ASSERT(task->output.empty());
|
||||
MOZ_ASSERT(task->lifo.isEmpty());
|
||||
freeTasks_.infallibleAppend(task);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::launchBatchCompile()
|
||||
{
|
||||
@ -912,15 +743,13 @@ ModuleGenerator::finishOutstandingTask()
|
||||
|
||||
bool
|
||||
ModuleGenerator::compileFuncDef(uint32_t funcIndex, uint32_t lineOrBytecode,
|
||||
Bytes&& bytes, const uint8_t* begin, const uint8_t* end,
|
||||
const uint8_t* begin, const uint8_t* end,
|
||||
Uint32Vector&& lineNums)
|
||||
{
|
||||
MOZ_ASSERT(startedFuncDefs_);
|
||||
MOZ_ASSERT(!finishedFuncDefs_);
|
||||
MOZ_ASSERT_IF(mode() == CompileMode::Tier1, funcIndex < env_->numFuncs());
|
||||
|
||||
numFuncDefs_++;
|
||||
|
||||
if (!currentTask_) {
|
||||
if (freeTasks_.empty() && !finishOutstandingTask())
|
||||
return false;
|
||||
@ -930,7 +759,7 @@ ModuleGenerator::compileFuncDef(uint32_t funcIndex, uint32_t lineOrBytecode,
|
||||
uint32_t funcBytecodeLength = end - begin;
|
||||
|
||||
FuncCompileInputVector& inputs = currentTask_->inputs;
|
||||
if (!inputs.emplaceBack(funcIndex, lineOrBytecode, Move(bytes), begin, end, Move(lineNums)))
|
||||
if (!inputs.emplaceBack(funcIndex, lineOrBytecode, begin, end, Move(lineNums)))
|
||||
return false;
|
||||
|
||||
uint32_t threshold;
|
||||
@ -945,20 +774,6 @@ ModuleGenerator::compileFuncDef(uint32_t funcIndex, uint32_t lineOrBytecode,
|
||||
return batchedBytecode_ <= threshold || launchBatchCompile();
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::compileFuncDef(uint32_t funcIndex, uint32_t lineOrBytecode,
|
||||
const uint8_t* begin, const uint8_t* end)
|
||||
{
|
||||
return compileFuncDef(funcIndex, lineOrBytecode, Bytes(), begin, end, Uint32Vector());
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::compileFuncDef(uint32_t funcIndex, uint32_t lineOrBytecode,
|
||||
Bytes&& bytes, Uint32Vector&& lineNums)
|
||||
{
|
||||
return compileFuncDef(funcIndex, lineOrBytecode, Move(bytes), bytes.begin(), bytes.end(), Move(lineNums));
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::finishFuncDefs()
|
||||
{
|
||||
@ -973,62 +788,22 @@ ModuleGenerator::finishFuncDefs()
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(!isAsmJS(), numFuncDefs_ == env_->numFuncDefs());
|
||||
finishedFuncDefs_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::initSigTableLength(uint32_t sigIndex, uint32_t length)
|
||||
{
|
||||
MOZ_ASSERT(isAsmJS());
|
||||
MOZ_ASSERT(length != 0);
|
||||
MOZ_ASSERT(length <= MaxTableInitialLength);
|
||||
|
||||
MOZ_ASSERT(env_->asmJSSigToTableIndex[sigIndex] == 0);
|
||||
env_->asmJSSigToTableIndex[sigIndex] = numTables_;
|
||||
|
||||
TableDesc& table = env_->tables[numTables_++];
|
||||
table.kind = TableKind::TypedFunction;
|
||||
table.limits.initial = length;
|
||||
table.limits.maximum = Some(length);
|
||||
return allocateGlobalBytes(sizeof(TableTls), sizeof(void*), &table.globalDataOffset);
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::initSigTableElems(uint32_t sigIndex, Uint32Vector&& elemFuncIndices)
|
||||
{
|
||||
MOZ_ASSERT(isAsmJS());
|
||||
MOZ_ASSERT(finishedFuncDefs_);
|
||||
|
||||
uint32_t tableIndex = env_->asmJSSigToTableIndex[sigIndex];
|
||||
MOZ_ASSERT(env_->tables[tableIndex].limits.initial == elemFuncIndices.length());
|
||||
|
||||
InitExpr offset(Val(uint32_t(0)));
|
||||
return env_->elemSegments.emplaceBack(tableIndex, offset, Move(elemFuncIndices));
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::finishLinking()
|
||||
{
|
||||
// All functions and traps CodeRanges should have been processed.
|
||||
|
||||
#ifdef DEBUG
|
||||
if (isAsmJS()) {
|
||||
for (uint32_t i = 0; i < AsmJSFirstDefFuncIndex; i++)
|
||||
MOZ_ASSERT(funcToCodeRange_[i] == BAD_CODE_RANGE);
|
||||
for (uint32_t i = AsmJSFirstDefFuncIndex; i < AsmJSFirstDefFuncIndex + numFuncDefs_; i++)
|
||||
MOZ_ASSERT(funcToCodeRange_[i] != BAD_CODE_RANGE);
|
||||
for (uint32_t i = AsmJSFirstDefFuncIndex + numFuncDefs_; i < funcToCodeRange_.length(); i++)
|
||||
MOZ_ASSERT(funcToCodeRange_[i] == BAD_CODE_RANGE);
|
||||
} else {
|
||||
for (uint32_t codeRangeIndex : funcToCodeRange_)
|
||||
MOZ_ASSERT(codeRangeIndex != BAD_CODE_RANGE);
|
||||
}
|
||||
for (uint32_t codeRangeIndex : funcToCodeRange_)
|
||||
MOZ_ASSERT(codeRangeIndex != BAD_CODE_RANGE);
|
||||
#endif
|
||||
|
||||
// Now that all functions and stubs are generated and their CodeRanges
|
||||
// known, patch all calls (which can emit far jumps) and far jumps.
|
||||
// known, patch all calls (which can emit far jumps) and far jumps.
|
||||
|
||||
if (!linkCallSites())
|
||||
return false;
|
||||
@ -1081,6 +856,7 @@ ModuleGenerator::finishMetadata(const ShareableBytes& bytecode)
|
||||
metadata_->memoryUsage = env_->memoryUsage;
|
||||
metadata_->minMemoryLength = env_->minMemoryLength;
|
||||
metadata_->maxMemoryLength = env_->maxMemoryLength;
|
||||
metadata_->startFuncIndex = env_->startFuncIndex;
|
||||
metadata_->tables = Move(env_->tables);
|
||||
metadata_->globals = Move(env_->globals);
|
||||
metadata_->funcNames = Move(env_->funcNames);
|
||||
@ -1100,12 +876,6 @@ ModuleGenerator::finishMetadata(const ShareableBytes& bytecode)
|
||||
metadataTier_->debugTrapFarJumpOffsets.podResizeToFit();
|
||||
metadataTier_->debugFuncToCodeRange.podResizeToFit();
|
||||
|
||||
// For asm.js, the tables vector is over-allocated (to avoid resize during
|
||||
// parallel copilation). Shrink it back down to fit.
|
||||
|
||||
if (isAsmJS() && !metadata_->tables.resize(numTables_))
|
||||
return false;
|
||||
|
||||
// Complete function exports and element segments with code range indices,
|
||||
// now that every function has a code range.
|
||||
|
||||
@ -1155,13 +925,6 @@ ModuleGenerator::finishCodeSegment(const ShareableBytes& bytecode)
|
||||
{
|
||||
MOZ_ASSERT(finishedFuncDefs_);
|
||||
|
||||
// Because of asm.js, we can only generate the FuncExportVector at the end
|
||||
// of module generation (after we've seen the end of the exports object at
|
||||
// the end of the asm.js module).
|
||||
|
||||
if (!finishFuncExports())
|
||||
return nullptr;
|
||||
|
||||
// Now that all imports/exports are known, we can generate a special
|
||||
// CompiledCode containing stubs.
|
||||
|
||||
|
@ -27,11 +27,13 @@
|
||||
namespace js {
|
||||
namespace wasm {
|
||||
|
||||
struct CompileTask;
|
||||
typedef Vector<CompileTask*, 0, SystemAllocPolicy> CompileTaskPtrVector;
|
||||
|
||||
// FuncCompileInput contains the input for compiling a single function.
|
||||
|
||||
struct FuncCompileInput
|
||||
{
|
||||
Bytes bytesToDelete;
|
||||
const uint8_t* begin;
|
||||
const uint8_t* end;
|
||||
uint32_t index;
|
||||
@ -40,12 +42,10 @@ struct FuncCompileInput
|
||||
|
||||
FuncCompileInput(uint32_t index,
|
||||
uint32_t lineOrBytecode,
|
||||
Bytes&& bytesToDelete,
|
||||
const uint8_t* begin,
|
||||
const uint8_t* end,
|
||||
Uint32Vector&& callSiteLineNums)
|
||||
: bytesToDelete(Move(bytesToDelete)),
|
||||
begin(begin),
|
||||
: begin(begin),
|
||||
end(end),
|
||||
index(index),
|
||||
lineOrBytecode(lineOrBytecode),
|
||||
@ -145,9 +145,7 @@ struct CompileTask
|
||||
|
||||
class MOZ_STACK_CLASS ModuleGenerator
|
||||
{
|
||||
typedef HashSet<uint32_t, DefaultHasher<uint32_t>, SystemAllocPolicy> Uint32Set;
|
||||
typedef Vector<CompileTask, 0, SystemAllocPolicy> CompileTaskVector;
|
||||
typedef Vector<CompileTask*, 0, SystemAllocPolicy> CompileTaskPtrVector;
|
||||
typedef EnumeratedArray<Trap, Trap::Limit, uint32_t> Uint32TrapArray;
|
||||
typedef Vector<jit::CodeOffset, 0, SystemAllocPolicy> CodeOffsetVector;
|
||||
|
||||
@ -167,9 +165,6 @@ class MOZ_STACK_CLASS ModuleGenerator
|
||||
|
||||
// Data scoped to the ModuleGenerator's lifetime
|
||||
ExclusiveCompileTaskState taskState_;
|
||||
uint32_t numFuncDefs_;
|
||||
uint32_t numSigs_;
|
||||
uint32_t numTables_;
|
||||
LifoAlloc lifo_;
|
||||
jit::JitContext jcx_;
|
||||
jit::TempAllocator masmAlloc_;
|
||||
@ -180,7 +175,6 @@ class MOZ_STACK_CLASS ModuleGenerator
|
||||
TrapFarJumpVector trapFarJumps_;
|
||||
CallFarJumpVector callFarJumps_;
|
||||
CallSiteTargetVector callSiteTargets_;
|
||||
Uint32Set exportedFuncs_;
|
||||
uint32_t lastPatchedCallSite_;
|
||||
uint32_t startOfUnpatchedCallsites_;
|
||||
CodeOffsetVector debugTrapFarJumps_;
|
||||
@ -197,6 +191,8 @@ class MOZ_STACK_CLASS ModuleGenerator
|
||||
DebugOnly<bool> startedFuncDefs_;
|
||||
DebugOnly<bool> finishedFuncDefs_;
|
||||
|
||||
bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOff);
|
||||
|
||||
bool funcIsCompiled(uint32_t funcIndex) const;
|
||||
const CodeRange& funcCodeRange(uint32_t funcIndex) const;
|
||||
|
||||
@ -204,23 +200,13 @@ class MOZ_STACK_CLASS ModuleGenerator
|
||||
void noteCodeRange(uint32_t codeRangeIndex, const CodeRange& codeRange);
|
||||
bool linkCompiledCode(const CompiledCode& code);
|
||||
bool finishTask(CompileTask* task);
|
||||
bool launchBatchCompile();
|
||||
bool finishOutstandingTask();
|
||||
bool finishFuncExports();
|
||||
|
||||
bool finishLinking();
|
||||
bool finishMetadata(const ShareableBytes& bytecode);
|
||||
UniqueConstCodeSegment finishCodeSegment(const ShareableBytes& bytecode);
|
||||
UniqueJumpTable createJumpTable(const CodeSegment& codeSegment);
|
||||
bool addFuncImport(const Sig& sig, uint32_t globalDataOffset);
|
||||
bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOff);
|
||||
bool allocateGlobal(GlobalDesc* global);
|
||||
|
||||
bool launchBatchCompile();
|
||||
bool compileFuncDef(uint32_t funcIndex, uint32_t lineOrBytecode,
|
||||
Bytes&& bytes, const uint8_t* begin, const uint8_t* end,
|
||||
Uint32Vector&& lineNums);
|
||||
|
||||
bool initAsmJS(Metadata* asmJSMetadata);
|
||||
bool initWasm(size_t codeLength);
|
||||
|
||||
bool isAsmJS() const { return env_->isAsmJS(); }
|
||||
Tier tier() const { return env_->tier(); }
|
||||
@ -231,39 +217,22 @@ class MOZ_STACK_CLASS ModuleGenerator
|
||||
ModuleGenerator(const CompileArgs& args, ModuleEnvironment* env,
|
||||
Atomic<bool>* cancelled, UniqueChars* error);
|
||||
~ModuleGenerator();
|
||||
|
||||
MOZ_MUST_USE bool init(size_t codeSectionSize, Metadata* maybeAsmJSMetadata = nullptr);
|
||||
|
||||
// Function definitions:
|
||||
// After initialization, startFuncDefs() shall be called before one call to
|
||||
// compileFuncDef() for each funcIndex in the range [0, env->numFuncDefs),
|
||||
// followed by finishFuncDefs().
|
||||
|
||||
MOZ_MUST_USE bool startFuncDefs();
|
||||
MOZ_MUST_USE bool compileFuncDef(uint32_t funcIndex, uint32_t lineOrBytecode,
|
||||
const uint8_t* begin, const uint8_t* end);
|
||||
MOZ_MUST_USE bool compileFuncDef(uint32_t funcIndex, uint32_t lineOrBytecode,
|
||||
Bytes&& bytes, Uint32Vector&& callSiteLineNums);
|
||||
const uint8_t* begin, const uint8_t* end,
|
||||
Uint32Vector&& callSiteLineNums = Uint32Vector());
|
||||
MOZ_MUST_USE bool finishFuncDefs();
|
||||
|
||||
// asm.js accessors:
|
||||
uint32_t minMemoryLength() const { return env_->minMemoryLength; }
|
||||
uint32_t numSigs() const { return numSigs_; }
|
||||
const SigWithId& sig(uint32_t sigIndex) const;
|
||||
const SigWithId& funcSig(uint32_t funcIndex) const;
|
||||
// After finishFuncDefs(), one of the following is called, depending on the
|
||||
// CompileMode: finishModule for Once or Tier1, finishTier2 for Tier2.
|
||||
|
||||
// asm.js lazy initialization:
|
||||
void initSig(uint32_t sigIndex, Sig&& sig);
|
||||
void initFuncSig(uint32_t funcIndex, uint32_t sigIndex);
|
||||
MOZ_MUST_USE bool initImport(uint32_t funcIndex, uint32_t sigIndex);
|
||||
MOZ_MUST_USE bool initSigTableLength(uint32_t sigIndex, uint32_t length);
|
||||
MOZ_MUST_USE bool initSigTableElems(uint32_t sigIndex, Uint32Vector&& elemFuncIndices);
|
||||
void initMemoryUsage(MemoryUsage memoryUsage);
|
||||
void bumpMinMemoryLength(uint32_t newMinMemoryLength);
|
||||
MOZ_MUST_USE bool addGlobal(ValType type, bool isConst, uint32_t* index);
|
||||
MOZ_MUST_USE bool addExport(CacheableChars&& fieldChars, uint32_t funcIndex);
|
||||
|
||||
// Finish compilation of the given bytecode.
|
||||
SharedModule finishModule(const ShareableBytes& bytecode);
|
||||
|
||||
// Finish compilation of the given bytecode, installing tier-variant parts
|
||||
// for Tier 2 into module.
|
||||
MOZ_MUST_USE bool finishTier2(Module& module);
|
||||
};
|
||||
|
||||
|
@ -2037,14 +2037,19 @@ EmitCallArgs(FunctionCompiler& f, const Sig& sig, const DefVector& args, CallCom
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitCall(FunctionCompiler& f)
|
||||
EmitCall(FunctionCompiler& f, bool asmJSFuncDef)
|
||||
{
|
||||
uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode();
|
||||
|
||||
uint32_t funcIndex;
|
||||
DefVector args;
|
||||
if (!f.iter().readCall(&funcIndex, &args))
|
||||
return false;
|
||||
if (asmJSFuncDef) {
|
||||
if (!f.iter().readOldCallDirect(f.env().numFuncImports(), &funcIndex, &args))
|
||||
return false;
|
||||
} else {
|
||||
if (!f.iter().readCall(&funcIndex, &args))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (f.inDeadCode())
|
||||
return true;
|
||||
@ -3327,7 +3332,7 @@ EmitBodyExprs(FunctionCompiler& f)
|
||||
|
||||
// Calls
|
||||
case uint16_t(Op::Call):
|
||||
CHECK(EmitCall(f));
|
||||
CHECK(EmitCall(f, /* asmJSFuncDef = */ false));
|
||||
case uint16_t(Op::CallIndirect):
|
||||
CHECK(EmitCallIndirect(f, /* oldStyle = */ false));
|
||||
|
||||
@ -3723,6 +3728,8 @@ EmitBodyExprs(FunctionCompiler& f)
|
||||
CHECK_ASMJS(EmitBinaryMathBuiltinCall(f, SymbolicAddress::PowD, ValType::F64));
|
||||
case uint16_t(MozOp::F64Atan2):
|
||||
CHECK_ASMJS(EmitBinaryMathBuiltinCall(f, SymbolicAddress::ATan2D, ValType::F64));
|
||||
case uint16_t(MozOp::OldCallDirect):
|
||||
CHECK_ASMJS(EmitCall(f, /* asmJSFuncDef = */ true));
|
||||
case uint16_t(MozOp::OldCallIndirect):
|
||||
CHECK_ASMJS(EmitCallIndirect(f, /* oldStyle = */ true));
|
||||
|
||||
|
@ -542,6 +542,33 @@ GenerateImportFunction(jit::MacroAssembler& masm, const FuncImport& fi, SigIdDes
|
||||
return FinishOffsets(masm, offsets);
|
||||
}
|
||||
|
||||
static const unsigned STUBS_LIFO_DEFAULT_CHUNK_SIZE = 4 * 1024;
|
||||
|
||||
bool
|
||||
wasm::GenerateImportFunctions(const ModuleEnvironment& env, const FuncImportVector& imports,
|
||||
CompiledCode* code)
|
||||
{
|
||||
LifoAlloc lifo(STUBS_LIFO_DEFAULT_CHUNK_SIZE);
|
||||
TempAllocator alloc(&lifo);
|
||||
MacroAssembler masm(MacroAssembler::WasmToken(), alloc);
|
||||
|
||||
for (uint32_t funcIndex = 0; funcIndex < imports.length(); funcIndex++) {
|
||||
const FuncImport& fi = imports[funcIndex];
|
||||
|
||||
FuncOffsets offsets;
|
||||
if (!GenerateImportFunction(masm, fi, env.funcSigs[funcIndex]->id, &offsets))
|
||||
return false;
|
||||
if (!code->codeRanges.emplaceBack(funcIndex, /* bytecodeOffset = */ 0, offsets))
|
||||
return false;
|
||||
}
|
||||
|
||||
masm.finish();
|
||||
if (masm.oom())
|
||||
return false;
|
||||
|
||||
return code->swap(masm);
|
||||
}
|
||||
|
||||
// Generate a stub that is called via the internal ABI derived from the
|
||||
// signature of the import and calls into an appropriate callImport C++
|
||||
// function, having boxed all the ABI arguments into a homogeneous Value array.
|
||||
@ -1313,8 +1340,6 @@ GenerateDebugTrapStub(MacroAssembler& masm, Label* throwLabel, CallableOffsets*
|
||||
return FinishOffsets(masm, offsets);
|
||||
}
|
||||
|
||||
static const unsigned STUBS_LIFO_DEFAULT_CHUNK_SIZE = 4 * 1024;
|
||||
|
||||
bool
|
||||
wasm::GenerateStubs(const ModuleEnvironment& env, const FuncImportVector& imports,
|
||||
const FuncExportVector& exports, CompiledCode* code)
|
||||
@ -1343,14 +1368,6 @@ wasm::GenerateStubs(const ModuleEnvironment& env, const FuncImportVector& import
|
||||
return false;
|
||||
if (!code->codeRanges.emplaceBack(CodeRange::ImportJitExit, funcIndex, offsets))
|
||||
return false;
|
||||
|
||||
if (!env.isAsmJS()) {
|
||||
FuncOffsets offsets;
|
||||
if (!GenerateImportFunction(masm, fi, env.funcSigs[funcIndex]->id, &offsets))
|
||||
return false;
|
||||
if (!code->codeRanges.emplaceBack(funcIndex, /* bytecodeOffset = */ 0, offsets))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const FuncExport& fe : exports) {
|
||||
|
@ -28,6 +28,10 @@ extern bool
|
||||
GenerateBuiltinThunk(jit::MacroAssembler& masm, jit::ABIFunctionType abiType, ExitReason exitReason,
|
||||
void* funcPtr, CallableOffsets* offsets);
|
||||
|
||||
extern bool
|
||||
GenerateImportFunctions(const ModuleEnvironment& env, const FuncImportVector& imports,
|
||||
CompiledCode* code);
|
||||
|
||||
extern bool
|
||||
GenerateStubs(const ModuleEnvironment& env, const FuncImportVector& imports,
|
||||
const FuncExportVector& exports, CompiledCode* code);
|
||||
|
@ -2804,8 +2804,7 @@ ParseLimits(WasmParseContext& c, Limits* limits)
|
||||
if (c.ts.getIf(WasmToken::Index, &token))
|
||||
maximum.emplace(token.index());
|
||||
|
||||
Limits r = { initial.index(), maximum };
|
||||
*limits = r;
|
||||
*limits = Limits(initial.index(), maximum);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2872,8 +2871,7 @@ ParseMemory(WasmParseContext& c, WasmToken token, AstModule* module)
|
||||
return false;
|
||||
}
|
||||
|
||||
Limits memory = { uint32_t(pages), Some(uint32_t(pages)) };
|
||||
if (!module->addMemory(name, memory))
|
||||
if (!module->addMemory(name, Limits(pages, Some(pages))))
|
||||
return false;
|
||||
|
||||
if (!c.ts.match(WasmToken::CloseParen, c.error))
|
||||
@ -3165,8 +3163,7 @@ ParseTable(WasmParseContext& c, WasmToken token, AstModule* module)
|
||||
if (numElements != elems.length())
|
||||
return false;
|
||||
|
||||
Limits r = { numElements, Some(numElements) };
|
||||
if (!module->addTable(name, r))
|
||||
if (!module->addTable(name, Limits(numElements, Some(numElements))))
|
||||
return false;
|
||||
|
||||
auto* zero = new(c.lifo) AstConst(Val(uint32_t(0)));
|
||||
|
@ -164,6 +164,29 @@ struct ShareableBase : AtomicRefCounted<T>
|
||||
|
||||
// ValType utilities
|
||||
|
||||
static inline unsigned
|
||||
SizeOf(ValType vt)
|
||||
{
|
||||
switch (vt) {
|
||||
case ValType::I32:
|
||||
case ValType::F32:
|
||||
return 4;
|
||||
case ValType::I64:
|
||||
case ValType::F64:
|
||||
return 8;
|
||||
case ValType::I8x16:
|
||||
case ValType::I16x8:
|
||||
case ValType::I32x4:
|
||||
case ValType::F32x4:
|
||||
case ValType::B8x16:
|
||||
case ValType::B16x8:
|
||||
case ValType::B32x4:
|
||||
return 16;
|
||||
default:
|
||||
MOZ_CRASH("Invalid ValType");
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsSimdType(ValType vt)
|
||||
{
|
||||
@ -855,7 +878,8 @@ struct SigWithId : Sig
|
||||
SigIdDesc id;
|
||||
|
||||
SigWithId() = default;
|
||||
explicit SigWithId(Sig&& sig, SigIdDesc id) : Sig(Move(sig)), id(id) {}
|
||||
explicit SigWithId(Sig&& sig) : Sig(Move(sig)), id() {}
|
||||
SigWithId(Sig&& sig, SigIdDesc id) : Sig(Move(sig)), id(id) {}
|
||||
void operator=(Sig&& rhs) { Sig::operator=(Move(rhs)); }
|
||||
|
||||
WASM_DECLARE_SERIALIZABLE(SigWithId)
|
||||
@ -1328,6 +1352,11 @@ struct Limits
|
||||
{
|
||||
uint32_t initial;
|
||||
Maybe<uint32_t> maximum;
|
||||
|
||||
Limits() = default;
|
||||
explicit Limits(uint32_t initial, const Maybe<uint32_t>& maximum = Nothing())
|
||||
: initial(initial), maximum(maximum)
|
||||
{}
|
||||
};
|
||||
|
||||
// TableDesc describes a table as well as the offset of the table's base pointer
|
||||
|
@ -44,9 +44,10 @@ struct ModuleEnvironment
|
||||
CompileMode mode_;
|
||||
Tier tier_;
|
||||
|
||||
// Module fields filled out incrementally during decoding:
|
||||
// Module fields decoded from the module environment (or initialized while
|
||||
// validating an asm.js module) and immutable during compilation:
|
||||
MemoryUsage memoryUsage;
|
||||
Atomic<uint32_t> minMemoryLength;
|
||||
uint32_t minMemoryLength;
|
||||
Maybe<uint32_t> maxMemoryLength;
|
||||
SigWithIdVector sigs;
|
||||
SigWithIdPtrVector funcSigs;
|
||||
@ -57,6 +58,8 @@ struct ModuleEnvironment
|
||||
ImportVector imports;
|
||||
ExportVector exports;
|
||||
Maybe<uint32_t> startFuncIndex;
|
||||
|
||||
// Fields decoded as part of the wasm module tail:
|
||||
ElemSegmentVector elemSegments;
|
||||
DataSegmentVector dataSegments;
|
||||
NameInBytecodeVector funcNames;
|
||||
@ -98,24 +101,14 @@ struct ModuleEnvironment
|
||||
return sigs.length();
|
||||
}
|
||||
size_t numFuncs() const {
|
||||
// asm.js pre-reserves a bunch of function index space which is
|
||||
// incrementally filled in during function-body validation. Thus, there
|
||||
// are a few possible interpretations of numFuncs() (total index space
|
||||
// size vs. exact number of imports/definitions encountered so far) and
|
||||
// to simplify things we simply only define this quantity for wasm.
|
||||
MOZ_ASSERT(!isAsmJS());
|
||||
return funcSigs.length();
|
||||
}
|
||||
size_t numFuncDefs() const {
|
||||
// asm.js overallocates the length of funcSigs and in general does not
|
||||
// know the number of function definitions until it's done compiling.
|
||||
MOZ_ASSERT(!isAsmJS());
|
||||
return funcSigs.length() - funcImportGlobalDataOffsets.length();
|
||||
}
|
||||
size_t numFuncImports() const {
|
||||
MOZ_ASSERT(!isAsmJS());
|
||||
return funcImportGlobalDataOffsets.length();
|
||||
}
|
||||
size_t numFuncDefs() const {
|
||||
return funcSigs.length() - funcImportGlobalDataOffsets.length();
|
||||
}
|
||||
bool usesMemory() const {
|
||||
return UsesMemory(memoryUsage);
|
||||
}
|
||||
|
@ -355,7 +355,7 @@ class FastBernoulliTrial {
|
||||
* double is 2^64, not 2^64-1, so this doesn't actually set skipCount to a
|
||||
* value that can be safely assigned to mSkipCount.
|
||||
*
|
||||
* Jakub Oleson cleverly suggested flipping the sense of the comparison: if
|
||||
* Jakob Olesen cleverly suggested flipping the sense of the comparison: if
|
||||
* we require that skipCount < SIZE_MAX, then because of the gaps (2048)
|
||||
* between doubles at that magnitude, the highest double less than 2^64 is
|
||||
* 2^64 - 2048, which is fine to store in a size_t.
|
||||
|
@ -86,8 +86,6 @@ const FILE_WRONG_CHANNEL_MAR = "wrong_product_channel.mar";
|
||||
|
||||
const PERFORMING_STAGED_UPDATE = "Performing a staged update";
|
||||
const CALL_QUIT = "calling QuitProgressUI";
|
||||
const REMOVE_OLD_DIST_DIR = "removing old distribution directory";
|
||||
const MOVE_OLD_DIST_DIR = "Moving old distribution directory to new location";
|
||||
const ERR_UPDATE_IN_PROGRESS = "Update already in progress! Exiting";
|
||||
const ERR_RENAME_FILE = "rename_file: failed to rename file";
|
||||
const ERR_ENSURE_COPY = "ensure_copy: failed to copy the file";
|
||||
@ -3010,12 +3008,6 @@ function checkUpdateLogContents(aCompareLogFile, aStaged = false,
|
||||
// Skip lines that log failed attempts to open the callback executable.
|
||||
updateLogContents = updateLogContents.replace(/NS_main: callback app file .*/g, "");
|
||||
|
||||
if (IS_MACOSX) {
|
||||
// Skip lines that log moving the distribution directory for Mac v2 signing.
|
||||
updateLogContents = updateLogContents.replace(/Moving old [^\n]*\nrename_file: .*/g, "");
|
||||
updateLogContents = updateLogContents.replace(/New distribution directory .*/g, "");
|
||||
}
|
||||
|
||||
if (IS_WIN) {
|
||||
// The FindFile results when enumerating the filesystem on Windows is not
|
||||
// determistic so the results matching the following need to be fixed.
|
||||
|
@ -16,7 +16,6 @@ function run_test() {
|
||||
gTestFiles[gTestFiles.length - 1].compareContents = "FromComplete\n";
|
||||
gTestFiles[gTestFiles.length - 1].comparePerms = 0o644;
|
||||
gTestDirs = gTestDirsCompleteSuccess;
|
||||
setupDistributionDir();
|
||||
setupSymLinks();
|
||||
setupUpdaterTest(FILE_COMPLETE_MAR, false);
|
||||
}
|
||||
@ -56,7 +55,6 @@ function checkPostUpdateAppLogFinished() {
|
||||
checkPostUpdateRunningFile(true);
|
||||
checkFilesAfterUpdateSuccess(getApplyDirFile, false, true);
|
||||
checkUpdateLogContents(LOG_REPLACE_SUCCESS, false, true);
|
||||
checkDistributionDir();
|
||||
do_execute_soon(waitForUpdateXMLFiles);
|
||||
}
|
||||
|
||||
@ -68,33 +66,6 @@ function waitForUpdateXMLFilesFinished() {
|
||||
checkCallbackLog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the state of the distribution directory for the test.
|
||||
*/
|
||||
function setupDistributionDir() {
|
||||
if (IS_MACOSX) {
|
||||
// Create files in the old distribution directory location to verify that
|
||||
// the directory and its contents are removed when there is a distribution
|
||||
// directory in the new location.
|
||||
let testFile = getApplyDirFile(DIR_MACOS + "distribution/testFile", true);
|
||||
writeFile(testFile, "test\n");
|
||||
testFile = getApplyDirFile(DIR_MACOS + "distribution/test1/testFile", true);
|
||||
writeFile(testFile, "test\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the state of the distribution directory for the test.
|
||||
*/
|
||||
function checkDistributionDir() {
|
||||
if (IS_MACOSX) {
|
||||
let distributionDir = getApplyDirFile(DIR_MACOS + "distribution", true);
|
||||
Assert.ok(!distributionDir.exists(),
|
||||
MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path));
|
||||
checkUpdateLogContains(REMOVE_OLD_DIST_DIR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup symlinks for the test.
|
||||
*/
|
||||
|
@ -17,7 +17,6 @@ function run_test() {
|
||||
gTestFiles[gTestFiles.length - 2].comparePerms = 0o644;
|
||||
gTestDirs = gTestDirsPartialSuccess;
|
||||
preventDistributionFiles();
|
||||
setupDistributionDir();
|
||||
setupUpdaterTest(FILE_PARTIAL_MAR, true);
|
||||
}
|
||||
|
||||
@ -55,7 +54,6 @@ function checkPostUpdateAppLogFinished() {
|
||||
checkPostUpdateRunningFile(true);
|
||||
checkFilesAfterUpdateSuccess(getApplyDirFile, false, true);
|
||||
checkUpdateLogContents(LOG_REPLACE_SUCCESS, false, true, true);
|
||||
checkDistributionDir();
|
||||
do_execute_soon(waitForUpdateXMLFiles);
|
||||
}
|
||||
|
||||
@ -66,47 +64,3 @@ function waitForUpdateXMLFilesFinished() {
|
||||
checkUpdateManager(STATE_NONE, false, STATE_SUCCEEDED, 0, 1);
|
||||
checkCallbackLog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the state of the distribution directory for the test.
|
||||
*/
|
||||
function setupDistributionDir() {
|
||||
if (IS_MACOSX) {
|
||||
// Create files in the old distribution directory location to verify that
|
||||
// the directory and its contents are moved to the new location on update.
|
||||
let testFile = getApplyDirFile(DIR_MACOS + "distribution/testFile", true);
|
||||
writeFile(testFile, "test\n");
|
||||
testFile = getApplyDirFile(DIR_MACOS + "distribution/test/testFile", true);
|
||||
writeFile(testFile, "test\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the state of the distribution directory.
|
||||
*/
|
||||
function checkDistributionDir() {
|
||||
let distributionDir = getApplyDirFile(DIR_RESOURCES + "distribution", true);
|
||||
if (IS_MACOSX) {
|
||||
Assert.ok(distributionDir.exists(),
|
||||
MSG_SHOULD_EXIST + getMsgPath(distributionDir.path));
|
||||
|
||||
let testFile = getApplyDirFile(DIR_RESOURCES + "distribution/testFile", true);
|
||||
Assert.ok(testFile.exists(),
|
||||
MSG_SHOULD_EXIST + getMsgPath(testFile.path));
|
||||
|
||||
testFile = getApplyDirFile(DIR_RESOURCES + "distribution/test/testFile", true);
|
||||
Assert.ok(testFile.exists(),
|
||||
MSG_SHOULD_EXIST + getMsgPath(testFile.path));
|
||||
|
||||
distributionDir = getApplyDirFile(DIR_MACOS + "distribution", true);
|
||||
Assert.ok(!distributionDir.exists(),
|
||||
MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path));
|
||||
|
||||
checkUpdateLogContains(MOVE_OLD_DIST_DIR);
|
||||
} else {
|
||||
debugDump("testing that files aren't added with an add-if instruction " +
|
||||
"when the file's destination directory doesn't exist");
|
||||
Assert.ok(!distributionDir.exists(),
|
||||
MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path));
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ function run_test() {
|
||||
gTestFiles = gTestFilesCompleteSuccess;
|
||||
gTestDirs = gTestDirsCompleteSuccess;
|
||||
preventDistributionFiles();
|
||||
setupDistributionDir();
|
||||
setupUpdaterTest(FILE_COMPLETE_MAR, true);
|
||||
}
|
||||
|
||||
@ -39,7 +38,6 @@ function checkPostUpdateAppLogFinished() {
|
||||
checkPostUpdateRunningFile(true);
|
||||
checkFilesAfterUpdateSuccess(getApplyDirFile);
|
||||
checkUpdateLogContents(LOG_COMPLETE_SUCCESS, false, false, true);
|
||||
checkDistributionDir();
|
||||
do_execute_soon(waitForUpdateXMLFiles);
|
||||
}
|
||||
|
||||
@ -50,47 +48,3 @@ function waitForUpdateXMLFilesFinished() {
|
||||
checkUpdateManager(STATE_NONE, false, STATE_SUCCEEDED, 0, 1);
|
||||
checkCallbackLog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the state of the distribution directory for the test.
|
||||
*/
|
||||
function setupDistributionDir() {
|
||||
if (IS_MACOSX) {
|
||||
// Create files in the old distribution directory location to verify that
|
||||
// the directory and its contents are moved to the new location on update.
|
||||
let testFile = getApplyDirFile(DIR_MACOS + "distribution/testFile", true);
|
||||
writeFile(testFile, "test\n");
|
||||
testFile = getApplyDirFile(DIR_MACOS + "distribution/test/testFile", true);
|
||||
writeFile(testFile, "test\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the state of the distribution directory.
|
||||
*/
|
||||
function checkDistributionDir() {
|
||||
let distributionDir = getApplyDirFile(DIR_RESOURCES + "distribution", true);
|
||||
if (IS_MACOSX) {
|
||||
Assert.ok(distributionDir.exists(),
|
||||
MSG_SHOULD_EXIST + getMsgPath(distributionDir.path));
|
||||
|
||||
let testFile = getApplyDirFile(DIR_RESOURCES + "distribution/testFile", true);
|
||||
Assert.ok(testFile.exists(),
|
||||
MSG_SHOULD_EXIST + getMsgPath(testFile.path));
|
||||
|
||||
testFile = getApplyDirFile(DIR_RESOURCES + "distribution/test/testFile", true);
|
||||
Assert.ok(testFile.exists(),
|
||||
MSG_SHOULD_EXIST + getMsgPath(testFile.path));
|
||||
|
||||
distributionDir = getApplyDirFile(DIR_MACOS + "distribution", true);
|
||||
Assert.ok(!distributionDir.exists(),
|
||||
MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path));
|
||||
|
||||
checkUpdateLogContains(MOVE_OLD_DIST_DIR);
|
||||
} else {
|
||||
debugDump("testing that files aren't added with an add-if instruction " +
|
||||
"when the file's destination directory doesn't exist");
|
||||
Assert.ok(!distributionDir.exists(),
|
||||
MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path));
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ function run_test() {
|
||||
gTestFiles[gTestFiles.length - 2].compareContents = "FromPartial\n";
|
||||
gTestFiles[gTestFiles.length - 2].comparePerms = 0o644;
|
||||
gTestDirs = gTestDirsPartialSuccess;
|
||||
setupDistributionDir();
|
||||
// The third parameter will test that a relative path that contains a
|
||||
// directory traversal to the post update binary doesn't execute.
|
||||
setupUpdaterTest(FILE_PARTIAL_MAR, false, "test/../");
|
||||
@ -39,7 +38,6 @@ function runUpdateFinished() {
|
||||
checkPostUpdateRunningFile(false);
|
||||
checkFilesAfterUpdateSuccess(getApplyDirFile);
|
||||
checkUpdateLogContents(LOG_PARTIAL_SUCCESS);
|
||||
checkDistributionDir();
|
||||
do_execute_soon(waitForUpdateXMLFiles);
|
||||
}
|
||||
|
||||
@ -50,30 +48,3 @@ function waitForUpdateXMLFilesFinished() {
|
||||
checkUpdateManager(STATE_NONE, false, STATE_SUCCEEDED, 0, 1);
|
||||
checkCallbackLog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the state of the distribution directory for the test.
|
||||
*/
|
||||
function setupDistributionDir() {
|
||||
if (IS_MACOSX) {
|
||||
// Create files in the old distribution directory location to verify that
|
||||
// the directory and its contents are removed when there is a distribution
|
||||
// directory in the new location.
|
||||
let testFile = getApplyDirFile(DIR_MACOS + "distribution/testFile", true);
|
||||
writeFile(testFile, "test\n");
|
||||
testFile = getApplyDirFile(DIR_MACOS + "distribution/test/testFile", true);
|
||||
writeFile(testFile, "test\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the state of the distribution directory.
|
||||
*/
|
||||
function checkDistributionDir() {
|
||||
if (IS_MACOSX) {
|
||||
let distributionDir = getApplyDirFile(DIR_MACOS + "distribution", true);
|
||||
Assert.ok(!distributionDir.exists(),
|
||||
MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path));
|
||||
checkUpdateLogContains(REMOVE_OLD_DIST_DIR);
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ function run_test() {
|
||||
gTestFiles[gTestFiles.length - 1].compareContents = "FromComplete\n";
|
||||
gTestFiles[gTestFiles.length - 1].comparePerms = 0o644;
|
||||
gTestDirs = gTestDirsCompleteSuccess;
|
||||
setupDistributionDir();
|
||||
setupSymLinks();
|
||||
setupUpdaterTest(FILE_COMPLETE_MAR, false);
|
||||
}
|
||||
@ -56,7 +55,6 @@ function checkPostUpdateAppLogFinished() {
|
||||
checkPostUpdateRunningFile(true);
|
||||
checkFilesAfterUpdateSuccess(getApplyDirFile, false, true);
|
||||
checkUpdateLogContents(LOG_REPLACE_SUCCESS, false, true);
|
||||
checkDistributionDir();
|
||||
do_execute_soon(waitForUpdateXMLFiles);
|
||||
}
|
||||
|
||||
@ -68,33 +66,6 @@ function waitForUpdateXMLFilesFinished() {
|
||||
checkCallbackLog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the state of the distribution directory for the test.
|
||||
*/
|
||||
function setupDistributionDir() {
|
||||
if (IS_MACOSX) {
|
||||
// Create files in the old distribution directory location to verify that
|
||||
// the directory and its contents are removed when there is a distribution
|
||||
// directory in the new location.
|
||||
let testFile = getApplyDirFile(DIR_MACOS + "distribution/testFile", true);
|
||||
writeFile(testFile, "test\n");
|
||||
testFile = getApplyDirFile(DIR_MACOS + "distribution/test1/testFile", true);
|
||||
writeFile(testFile, "test\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the state of the distribution directory for the test.
|
||||
*/
|
||||
function checkDistributionDir() {
|
||||
if (IS_MACOSX) {
|
||||
let distributionDir = getApplyDirFile(DIR_MACOS + "distribution", true);
|
||||
Assert.ok(!distributionDir.exists(),
|
||||
MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path));
|
||||
checkUpdateLogContains(REMOVE_OLD_DIST_DIR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup symlinks for the test.
|
||||
*/
|
||||
|
@ -17,7 +17,6 @@ function run_test() {
|
||||
gTestFiles[gTestFiles.length - 2].comparePerms = 0o644;
|
||||
gTestDirs = gTestDirsPartialSuccess;
|
||||
preventDistributionFiles();
|
||||
setupDistributionDir();
|
||||
setupUpdaterTest(FILE_PARTIAL_MAR, true);
|
||||
}
|
||||
|
||||
@ -55,7 +54,6 @@ function checkPostUpdateAppLogFinished() {
|
||||
checkPostUpdateRunningFile(true);
|
||||
checkFilesAfterUpdateSuccess(getApplyDirFile, false, true);
|
||||
checkUpdateLogContents(LOG_REPLACE_SUCCESS, false, true, true);
|
||||
checkDistributionDir();
|
||||
do_execute_soon(waitForUpdateXMLFiles);
|
||||
}
|
||||
|
||||
@ -66,47 +64,3 @@ function waitForUpdateXMLFilesFinished() {
|
||||
checkUpdateManager(STATE_NONE, false, STATE_SUCCEEDED, 0, 1);
|
||||
checkCallbackLog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the state of the distribution directory for the test.
|
||||
*/
|
||||
function setupDistributionDir() {
|
||||
if (IS_MACOSX) {
|
||||
// Create files in the old distribution directory location to verify that
|
||||
// the directory and its contents are moved to the new location on update.
|
||||
let testFile = getApplyDirFile(DIR_MACOS + "distribution/testFile", true);
|
||||
writeFile(testFile, "test\n");
|
||||
testFile = getApplyDirFile(DIR_MACOS + "distribution/test/testFile", true);
|
||||
writeFile(testFile, "test\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the state of the distribution directory.
|
||||
*/
|
||||
function checkDistributionDir() {
|
||||
let distributionDir = getApplyDirFile(DIR_RESOURCES + "distribution", true);
|
||||
if (IS_MACOSX) {
|
||||
Assert.ok(distributionDir.exists(),
|
||||
MSG_SHOULD_EXIST + getMsgPath(distributionDir.path));
|
||||
|
||||
let testFile = getApplyDirFile(DIR_RESOURCES + "distribution/testFile", true);
|
||||
Assert.ok(testFile.exists(),
|
||||
MSG_SHOULD_EXIST + getMsgPath(testFile.path));
|
||||
|
||||
testFile = getApplyDirFile(DIR_RESOURCES + "distribution/test/testFile", true);
|
||||
Assert.ok(testFile.exists(),
|
||||
MSG_SHOULD_EXIST + getMsgPath(testFile.path));
|
||||
|
||||
distributionDir = getApplyDirFile(DIR_MACOS + "distribution", true);
|
||||
Assert.ok(!distributionDir.exists(),
|
||||
MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path));
|
||||
|
||||
checkUpdateLogContains(MOVE_OLD_DIST_DIR);
|
||||
} else {
|
||||
debugDump("testing that files aren't added with an add-if instruction " +
|
||||
"when the file's destination directory doesn't exist");
|
||||
Assert.ok(!distributionDir.exists(),
|
||||
MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path));
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ function run_test() {
|
||||
gTestFiles = gTestFilesCompleteSuccess;
|
||||
gTestDirs = gTestDirsCompleteSuccess;
|
||||
preventDistributionFiles();
|
||||
setupDistributionDir();
|
||||
setupUpdaterTest(FILE_COMPLETE_MAR, true);
|
||||
}
|
||||
|
||||
@ -39,7 +38,6 @@ function checkPostUpdateAppLogFinished() {
|
||||
checkPostUpdateRunningFile(true);
|
||||
checkFilesAfterUpdateSuccess(getApplyDirFile);
|
||||
checkUpdateLogContents(LOG_COMPLETE_SUCCESS, false, false, true);
|
||||
checkDistributionDir();
|
||||
do_execute_soon(waitForUpdateXMLFiles);
|
||||
}
|
||||
|
||||
@ -50,47 +48,3 @@ function waitForUpdateXMLFilesFinished() {
|
||||
checkUpdateManager(STATE_NONE, false, STATE_SUCCEEDED, 0, 1);
|
||||
checkCallbackLog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the state of the distribution directory for the test.
|
||||
*/
|
||||
function setupDistributionDir() {
|
||||
if (IS_MACOSX) {
|
||||
// Create files in the old distribution directory location to verify that
|
||||
// the directory and its contents are moved to the new location on update.
|
||||
let testFile = getApplyDirFile(DIR_MACOS + "distribution/testFile", true);
|
||||
writeFile(testFile, "test\n");
|
||||
testFile = getApplyDirFile(DIR_MACOS + "distribution/test/testFile", true);
|
||||
writeFile(testFile, "test\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the state of the distribution directory.
|
||||
*/
|
||||
function checkDistributionDir() {
|
||||
let distributionDir = getApplyDirFile(DIR_RESOURCES + "distribution", true);
|
||||
if (IS_MACOSX) {
|
||||
Assert.ok(distributionDir.exists(),
|
||||
MSG_SHOULD_EXIST + getMsgPath(distributionDir.path));
|
||||
|
||||
let testFile = getApplyDirFile(DIR_RESOURCES + "distribution/testFile", true);
|
||||
Assert.ok(testFile.exists(),
|
||||
MSG_SHOULD_EXIST + getMsgPath(testFile.path));
|
||||
|
||||
testFile = getApplyDirFile(DIR_RESOURCES + "distribution/test/testFile", true);
|
||||
Assert.ok(testFile.exists(),
|
||||
MSG_SHOULD_EXIST + getMsgPath(testFile.path));
|
||||
|
||||
distributionDir = getApplyDirFile(DIR_MACOS + "distribution", true);
|
||||
Assert.ok(!distributionDir.exists(),
|
||||
MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path));
|
||||
|
||||
checkUpdateLogContains(MOVE_OLD_DIST_DIR);
|
||||
} else {
|
||||
debugDump("testing that files aren't added with an add-if instruction " +
|
||||
"when the file's destination directory doesn't exist");
|
||||
Assert.ok(!distributionDir.exists(),
|
||||
MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path));
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ function run_test() {
|
||||
gTestFiles[gTestFiles.length - 2].compareContents = "FromPartial\n";
|
||||
gTestFiles[gTestFiles.length - 2].comparePerms = 0o644;
|
||||
gTestDirs = gTestDirsPartialSuccess;
|
||||
setupDistributionDir();
|
||||
// The third parameter will test that a relative path that contains a
|
||||
// directory traversal to the post update binary doesn't execute.
|
||||
setupUpdaterTest(FILE_PARTIAL_MAR, false, "test/../");
|
||||
@ -39,7 +38,6 @@ function runUpdateFinished() {
|
||||
checkPostUpdateRunningFile(false);
|
||||
checkFilesAfterUpdateSuccess(getApplyDirFile);
|
||||
checkUpdateLogContents(LOG_PARTIAL_SUCCESS);
|
||||
checkDistributionDir();
|
||||
do_execute_soon(waitForUpdateXMLFiles);
|
||||
}
|
||||
|
||||
@ -50,30 +48,3 @@ function waitForUpdateXMLFilesFinished() {
|
||||
checkUpdateManager(STATE_NONE, false, STATE_SUCCEEDED, 0, 1);
|
||||
checkCallbackLog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the state of the distribution directory for the test.
|
||||
*/
|
||||
function setupDistributionDir() {
|
||||
if (IS_MACOSX) {
|
||||
// Create files in the old distribution directory location to verify that
|
||||
// the directory and its contents are removed when there is a distribution
|
||||
// directory in the new location.
|
||||
let testFile = getApplyDirFile(DIR_MACOS + "distribution/testFile", true);
|
||||
writeFile(testFile, "test\n");
|
||||
testFile = getApplyDirFile(DIR_MACOS + "distribution/test/testFile", true);
|
||||
writeFile(testFile, "test\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the state of the distribution directory.
|
||||
*/
|
||||
function checkDistributionDir() {
|
||||
if (IS_MACOSX) {
|
||||
let distributionDir = getApplyDirFile(DIR_MACOS + "distribution", true);
|
||||
Assert.ok(!distributionDir.exists(),
|
||||
MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path));
|
||||
checkUpdateLogContains(REMOVE_OLD_DIST_DIR);
|
||||
}
|
||||
}
|
||||
|
@ -13,15 +13,6 @@
|
||||
*
|
||||
* Available methods for the manifest file:
|
||||
*
|
||||
* updatev2.manifest
|
||||
* -----------------
|
||||
* method = "add" | "add-if" | "patch" | "patch-if" | "remove" |
|
||||
* "rmdir" | "rmrfdir" | type
|
||||
*
|
||||
* 'type' is the update type (e.g. complete or partial) and when present MUST
|
||||
* be the first entry in the update manifest. The type is used to support
|
||||
* downgrades by causing the actions defined in precomplete to be performed.
|
||||
*
|
||||
* updatev3.manifest
|
||||
* -----------------
|
||||
* method = "add" | "add-if" | "add-if-not" | "patch" | "patch-if" |
|
||||
@ -29,6 +20,11 @@
|
||||
*
|
||||
* 'add-if-not' adds a file if it doesn't exist.
|
||||
*
|
||||
* 'type' is the update type (e.g. complete or partial) and when present MUST
|
||||
* be the first entry in the update manifest. The type is used to support
|
||||
* removing files that no longer exist when when applying a complete update by
|
||||
* causing the actions defined in the precomplete file to be performed.
|
||||
*
|
||||
* precomplete
|
||||
* -----------
|
||||
* method = "remove" | "rmdir"
|
||||
@ -2491,42 +2487,7 @@ UpdateThreadFunc(void *param)
|
||||
|
||||
#ifdef MOZ_VERIFY_MAR_SIGNATURE
|
||||
if (rv == OK) {
|
||||
#ifdef XP_WIN
|
||||
HKEY baseKey = nullptr;
|
||||
wchar_t valueName[] = L"Image Path";
|
||||
wchar_t rasenh[] = L"rsaenh.dll";
|
||||
bool reset = false;
|
||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
||||
L"SOFTWARE\\Microsoft\\Cryptography\\Defaults\\Provider\\Microsoft Enhanced Cryptographic Provider v1.0",
|
||||
0, KEY_READ | KEY_WRITE,
|
||||
&baseKey) == ERROR_SUCCESS) {
|
||||
wchar_t path[MAX_PATH + 1];
|
||||
DWORD size = sizeof(path);
|
||||
DWORD type;
|
||||
if (RegQueryValueExW(baseKey, valueName, 0, &type,
|
||||
(LPBYTE)path, &size) == ERROR_SUCCESS) {
|
||||
if (type == REG_SZ && wcscmp(path, rasenh) == 0) {
|
||||
wchar_t rasenhFullPath[] = L"%SystemRoot%\\System32\\rsaenh.dll";
|
||||
if (RegSetValueExW(baseKey, valueName, 0, REG_SZ,
|
||||
(const BYTE*)rasenhFullPath,
|
||||
sizeof(rasenhFullPath)) == ERROR_SUCCESS) {
|
||||
reset = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
rv = gArchiveReader.VerifySignature();
|
||||
#ifdef XP_WIN
|
||||
if (baseKey) {
|
||||
if (reset) {
|
||||
RegSetValueExW(baseKey, valueName, 0, REG_SZ,
|
||||
(const BYTE*)rasenh,
|
||||
sizeof(rasenh));
|
||||
}
|
||||
RegCloseKey(baseKey);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (rv == OK) {
|
||||
@ -3638,44 +3599,6 @@ int NS_main(int argc, NS_tchar **argv)
|
||||
#endif /* XP_WIN */
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
// When the update is successful remove the precomplete file in the root of
|
||||
// the application bundle and move the distribution directory from
|
||||
// Contents/MacOS to Contents/Resources and if both exist delete the
|
||||
// directory under Contents/MacOS (see Bug 1068439).
|
||||
if (gSucceeded && !sStagedUpdate) {
|
||||
NS_tchar oldPrecomplete[MAXPATHLEN];
|
||||
NS_tsnprintf(oldPrecomplete, sizeof(oldPrecomplete)/sizeof(oldPrecomplete[0]),
|
||||
NS_T("%s/precomplete"), gInstallDirPath);
|
||||
NS_tremove(oldPrecomplete);
|
||||
|
||||
NS_tchar oldDistDir[MAXPATHLEN];
|
||||
NS_tsnprintf(oldDistDir, sizeof(oldDistDir)/sizeof(oldDistDir[0]),
|
||||
NS_T("%s/Contents/MacOS/distribution"), gInstallDirPath);
|
||||
int rv = NS_taccess(oldDistDir, F_OK);
|
||||
if (!rv) {
|
||||
NS_tchar newDistDir[MAXPATHLEN];
|
||||
NS_tsnprintf(newDistDir, sizeof(newDistDir)/sizeof(newDistDir[0]),
|
||||
NS_T("%s/Contents/Resources/distribution"), gInstallDirPath);
|
||||
rv = NS_taccess(newDistDir, F_OK);
|
||||
if (!rv) {
|
||||
LOG(("New distribution directory already exists... removing old " \
|
||||
"distribution directory: " LOG_S, oldDistDir));
|
||||
rv = ensure_remove_recursive(oldDistDir);
|
||||
if (rv) {
|
||||
LOG(("Removing old distribution directory failed - err: %d", rv));
|
||||
}
|
||||
} else {
|
||||
LOG(("Moving old distribution directory to new location. src: " LOG_S \
|
||||
", dst:" LOG_S, oldDistDir, newDistDir));
|
||||
rv = rename_file(oldDistDir, newDistDir, true);
|
||||
if (rv) {
|
||||
LOG(("Moving old distribution directory to new location failed - " \
|
||||
"err: %d", rv));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isElevated) {
|
||||
SetGroupOwnershipAndPermissions(gInstallDirPath);
|
||||
freeArguments(argc, argv);
|
||||
@ -4216,11 +4139,8 @@ int DoUpdate()
|
||||
// extract the manifest
|
||||
int rv = gArchiveReader.ExtractFile("updatev3.manifest", manifest);
|
||||
if (rv) {
|
||||
rv = gArchiveReader.ExtractFile("updatev2.manifest", manifest);
|
||||
if (rv) {
|
||||
LOG(("DoUpdate: error extracting manifest file"));
|
||||
return rv;
|
||||
}
|
||||
LOG(("DoUpdate: error extracting manifest file"));
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_tchar *rb = GetManifestContents(manifest);
|
||||
|
Loading…
x
Reference in New Issue
Block a user