merge mozilla-central to autoland. r=merge a=merge

This commit is contained in:
Sebastian Hengst 2017-09-28 12:16:20 +02:00
commit 127937baec
33 changed files with 595 additions and 1220 deletions

View File

@ -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.

View 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

View File

@ -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

View File

@ -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(); }
};

View File

@ -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());

View File

@ -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;
}

View File

@ -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;

View File

@ -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();
{

View File

@ -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:

View File

@ -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;

View File

@ -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

View File

@ -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:

View File

@ -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)

View File

@ -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_;

View File

@ -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.

View File

@ -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);
};

View File

@ -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));

View File

@ -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) {

View File

@ -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);

View File

@ -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)));

View File

@ -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

View File

@ -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);
}

View File

@ -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.

View File

@ -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.

View File

@ -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.
*/

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -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);
}
}

View File

@ -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.
*/

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -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);
}
}

View File

@ -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);