зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland. a=merge CLOSED TREE
This commit is contained in:
Коммит
3fc7bec4e3
|
@ -123,7 +123,7 @@ NS_IMPL_RELEASE_INHERITED(ModuleScript, LoadedScript)
|
|||
|
||||
ModuleScript::ModuleScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL)
|
||||
: LoadedScript(ScriptKind::eModule, aFetchOptions, aBaseURL),
|
||||
mSourceElementAssociated(false) {
|
||||
mDebuggerDataInitialized(false) {
|
||||
MOZ_ASSERT(!ModuleRecord());
|
||||
MOZ_ASSERT(!HasParseError());
|
||||
MOZ_ASSERT(!HasErrorToRethrow());
|
||||
|
@ -182,11 +182,11 @@ void ModuleScript::SetErrorToRethrow(const JS::Value& aError) {
|
|||
mErrorToRethrow = aError;
|
||||
}
|
||||
|
||||
void ModuleScript::SetSourceElementAssociated() {
|
||||
void ModuleScript::SetDebuggerDataInitialized() {
|
||||
MOZ_ASSERT(ModuleRecord());
|
||||
MOZ_ASSERT(!mSourceElementAssociated);
|
||||
MOZ_ASSERT(!mDebuggerDataInitialized);
|
||||
|
||||
mSourceElementAssociated = true;
|
||||
mDebuggerDataInitialized = true;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -64,7 +64,7 @@ class ModuleScript final : public LoadedScript {
|
|||
JS::Heap<JSObject*> mModuleRecord;
|
||||
JS::Heap<JS::Value> mParseError;
|
||||
JS::Heap<JS::Value> mErrorToRethrow;
|
||||
bool mSourceElementAssociated;
|
||||
bool mDebuggerDataInitialized;
|
||||
|
||||
~ModuleScript();
|
||||
|
||||
|
@ -78,7 +78,7 @@ class ModuleScript final : public LoadedScript {
|
|||
void SetModuleRecord(JS::Handle<JSObject*> aModuleRecord);
|
||||
void SetParseError(const JS::Value& aError);
|
||||
void SetErrorToRethrow(const JS::Value& aError);
|
||||
void SetSourceElementAssociated();
|
||||
void SetDebuggerDataInitialized();
|
||||
|
||||
JSObject* ModuleRecord() const { return mModuleRecord; }
|
||||
|
||||
|
@ -86,7 +86,7 @@ class ModuleScript final : public LoadedScript {
|
|||
JS::Value ErrorToRethrow() const { return mErrorToRethrow; }
|
||||
bool HasParseError() const { return !mParseError.isUndefined(); }
|
||||
bool HasErrorToRethrow() const { return !mErrorToRethrow.isUndefined(); }
|
||||
bool SourceElementAssociated() const { return mSourceElementAssociated; }
|
||||
bool DebuggerDataInitialized() const { return mDebuggerDataInitialized; }
|
||||
|
||||
void UnlinkModuleRecord();
|
||||
|
||||
|
|
|
@ -1108,21 +1108,22 @@ bool ScriptLoader::InstantiateModuleTree(ModuleLoadRequest* aRequest) {
|
|||
return true;
|
||||
}
|
||||
|
||||
nsresult ScriptLoader::AssociateSourceElementsForModuleTree(
|
||||
nsresult ScriptLoader::InitDebuggerDataForModuleTree(
|
||||
JSContext* aCx, ModuleLoadRequest* aRequest) {
|
||||
// Preloading can cause JS scripts to be compiled before DOM script element
|
||||
// nodes have been created. This method ensures compiled scripts are
|
||||
// associated with DOM element nodes before execution.
|
||||
// JS scripts can be associated with a DOM element for use by the debugger,
|
||||
// but preloading can cause scripts to be compiled before DOM script element
|
||||
// nodes have been created. This method ensures that this association takes
|
||||
// place before the first time a module script is run.
|
||||
|
||||
MOZ_ASSERT(aRequest);
|
||||
|
||||
ModuleScript* moduleScript = aRequest->mModuleScript;
|
||||
if (moduleScript->SourceElementAssociated()) {
|
||||
if (moduleScript->DebuggerDataInitialized()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
for (ModuleLoadRequest* childRequest : aRequest->mImports) {
|
||||
nsresult rv = AssociateSourceElementsForModuleTree(aCx, childRequest);
|
||||
nsresult rv = InitDebuggerDataForModuleTree(aCx, childRequest);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
|
@ -1133,13 +1134,13 @@ nsresult ScriptLoader::AssociateSourceElementsForModuleTree(
|
|||
if (element) {
|
||||
nsresult rv = nsJSUtils::InitModuleSourceElement(aCx, module, element);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
moduleScript->SetSourceElementAssociated();
|
||||
}
|
||||
|
||||
// The script is now ready to be exposed to the debugger.
|
||||
JS::Rooted<JSScript*> script(aCx, JS::GetModuleScript(module));
|
||||
JS::ExposeScriptToDebugger(aCx, script);
|
||||
|
||||
moduleScript->SetDebuggerDataInitialized();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -2576,10 +2577,8 @@ nsresult ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) {
|
|||
JS::Rooted<JSObject*> module(cx, moduleScript->ModuleRecord());
|
||||
MOZ_ASSERT(module);
|
||||
|
||||
if (!moduleScript->SourceElementAssociated()) {
|
||||
rv = AssociateSourceElementsForModuleTree(cx, request);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
rv = InitDebuggerDataForModuleTree(cx, request);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = nsJSUtils::ModuleEvaluate(cx, module);
|
||||
MOZ_ASSERT(NS_FAILED(rv) == aes.HasException());
|
||||
|
|
|
@ -524,8 +524,8 @@ class ScriptLoader final : public nsISupports {
|
|||
RefPtr<mozilla::GenericPromise> StartFetchingModuleAndDependencies(
|
||||
ModuleLoadRequest* aParent, nsIURI* aURI);
|
||||
|
||||
nsresult AssociateSourceElementsForModuleTree(JSContext* aCx,
|
||||
ModuleLoadRequest* aRequest);
|
||||
nsresult InitDebuggerDataForModuleTree(JSContext* aCx,
|
||||
ModuleLoadRequest* aRequest);
|
||||
|
||||
void RunScriptWhenSafe(ScriptLoadRequest* aRequest);
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ enum class GamepadCapabilityFlags : uint16_t;
|
|||
#endif // MOZILLA_INTERNAL_API
|
||||
namespace gfx {
|
||||
|
||||
static const int32_t kVRExternalVersion = 5;
|
||||
static const int32_t kVRExternalVersion = 6;
|
||||
|
||||
// We assign VR presentations to groups with a bitmask.
|
||||
// Currently, we will only display either content or chrome.
|
||||
|
@ -390,20 +390,25 @@ struct VRExternalShmem {
|
|||
int32_t size;
|
||||
#if defined(__ANDROID__)
|
||||
pthread_mutex_t systemMutex;
|
||||
pthread_mutex_t browserMutex;
|
||||
pthread_mutex_t geckoMutex;
|
||||
pthread_mutex_t servoMutex;
|
||||
pthread_cond_t systemCond;
|
||||
pthread_cond_t browserCond;
|
||||
pthread_cond_t geckoCond;
|
||||
pthread_cond_t servoCond;
|
||||
#else
|
||||
int64_t generationA;
|
||||
#endif // defined(__ANDROID__)
|
||||
VRSystemState state;
|
||||
#if !defined(__ANDROID__)
|
||||
int64_t generationB;
|
||||
int64_t browserGenerationA;
|
||||
int64_t geckoGenerationA;
|
||||
int64_t servoGenerationA;
|
||||
#endif // !defined(__ANDROID__)
|
||||
VRBrowserState browserState;
|
||||
VRBrowserState geckoState;
|
||||
VRBrowserState servoState;
|
||||
#if !defined(__ANDROID__)
|
||||
int64_t browserGenerationB;
|
||||
int64_t geckoGenerationB;
|
||||
int64_t servoGenerationB;
|
||||
#endif // !defined(__ANDROID__)
|
||||
};
|
||||
|
||||
|
|
|
@ -870,14 +870,14 @@ void VRSystemManagerExternal::PushState(VRBrowserState* aBrowserState,
|
|||
MOZ_ASSERT(mExternalShmem);
|
||||
if (mExternalShmem) {
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->browserMutex)) ==
|
||||
if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->geckoMutex)) ==
|
||||
0) {
|
||||
memcpy((void*)&(mExternalShmem->browserState), aBrowserState,
|
||||
memcpy((void*)&(mExternalShmem->geckoState), aBrowserState,
|
||||
sizeof(VRBrowserState));
|
||||
if (aNotifyCond) {
|
||||
pthread_cond_signal((pthread_cond_t*)&(mExternalShmem->browserCond));
|
||||
pthread_cond_signal((pthread_cond_t*)&(mExternalShmem->geckoCond));
|
||||
}
|
||||
pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->browserMutex));
|
||||
pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->geckoMutex));
|
||||
}
|
||||
#else
|
||||
bool status = true;
|
||||
|
@ -886,13 +886,13 @@ void VRSystemManagerExternal::PushState(VRBrowserState* aBrowserState,
|
|||
status = lock.GetStatus();
|
||||
#endif // defined(XP_WIN)
|
||||
if (status) {
|
||||
mExternalShmem->browserGenerationA++;
|
||||
memcpy((void*)&(mExternalShmem->browserState), (void*)aBrowserState,
|
||||
mExternalShmem->geckoGenerationA++;
|
||||
memcpy((void*)&(mExternalShmem->geckoState), (void*)aBrowserState,
|
||||
sizeof(VRBrowserState));
|
||||
mExternalShmem->browserGenerationB++; mExternalShmem->browserGenerationA++;
|
||||
memcpy((void*)&(mExternalShmem->browserState), (void*)aBrowserState,
|
||||
mExternalShmem->geckoGenerationB++; mExternalShmem->geckoGenerationA++;
|
||||
memcpy((void*)&(mExternalShmem->geckoState), (void*)aBrowserState,
|
||||
sizeof(VRBrowserState));
|
||||
mExternalShmem->browserGenerationB++;
|
||||
mExternalShmem->geckoGenerationB++;
|
||||
}
|
||||
#endif // defined(MOZ_WIDGET_ANDROID)
|
||||
}
|
||||
|
|
|
@ -478,15 +478,15 @@ void VRService::PullState(mozilla::gfx::VRBrowserState& aState) {
|
|||
// locked for the duration of the memcpy to and from shmem on
|
||||
// both sides.
|
||||
// On x86/x64 It is fallable -- If a dirty copy is detected by
|
||||
// a mismatch of browserGenerationA and browserGenerationB,
|
||||
// a mismatch of geckoGenerationA and geckoGenerationB,
|
||||
// the copy is discarded and will not replace the last known
|
||||
// browser state.
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->browserMutex)) ==
|
||||
if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->geckoMutex)) ==
|
||||
0) {
|
||||
memcpy(&aState, &tmp.browserState, sizeof(VRBrowserState));
|
||||
pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->browserMutex));
|
||||
memcpy(&aState, &tmp.geckoState, sizeof(VRBrowserState));
|
||||
pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->geckoMutex));
|
||||
}
|
||||
#else
|
||||
bool status = true;
|
||||
|
@ -496,12 +496,12 @@ void VRService::PullState(mozilla::gfx::VRBrowserState& aState) {
|
|||
#endif // defined(XP_WIN)
|
||||
if (status) {
|
||||
VRExternalShmem tmp;
|
||||
if (mAPIShmem->browserGenerationA != mBrowserGeneration) {
|
||||
if (mAPIShmem->geckoGenerationA != mBrowserGeneration) {
|
||||
memcpy(&tmp, mAPIShmem, sizeof(VRExternalShmem));
|
||||
if (tmp.browserGenerationA == tmp.browserGenerationB &&
|
||||
tmp.browserGenerationA != 0 && tmp.browserGenerationA != -1) {
|
||||
memcpy(&aState, &tmp.browserState, sizeof(VRBrowserState));
|
||||
mBrowserGeneration = tmp.browserGenerationA;
|
||||
if (tmp.geckoGenerationA == tmp.geckoGenerationB &&
|
||||
tmp.geckoGenerationA != 0 && tmp.geckoGenerationA != -1) {
|
||||
memcpy(&aState, &tmp.geckoState, sizeof(VRBrowserState));
|
||||
mBrowserGeneration = tmp.geckoGenerationA;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -801,8 +801,8 @@ static const uint32_t JSCLASS_RESERVED_SLOTS_MASK =
|
|||
#define JSCLASS_HIGH_FLAGS_SHIFT \
|
||||
(JSCLASS_RESERVED_SLOTS_SHIFT + JSCLASS_RESERVED_SLOTS_WIDTH)
|
||||
|
||||
static const uint32_t JSCLASS_IS_ANONYMOUS = 1
|
||||
<< (JSCLASS_HIGH_FLAGS_SHIFT + 0);
|
||||
static const uint32_t JSCLASS_INTERNAL_FLAG1 =
|
||||
1 << (JSCLASS_HIGH_FLAGS_SHIFT + 0);
|
||||
static const uint32_t JSCLASS_IS_GLOBAL = 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 1);
|
||||
static const uint32_t JSCLASS_INTERNAL_FLAG2 =
|
||||
1 << (JSCLASS_HIGH_FLAGS_SHIFT + 2);
|
||||
|
|
|
@ -79,8 +79,7 @@ static bool ModuleValueGetter(JSContext* cx, unsigned argc, Value* vp) {
|
|||
// ImportEntryObject
|
||||
|
||||
/* static */ const Class ImportEntryObject::class_ = {
|
||||
"ImportEntry", JSCLASS_HAS_RESERVED_SLOTS(ImportEntryObject::SlotCount) |
|
||||
JSCLASS_IS_ANONYMOUS};
|
||||
"ImportEntry", JSCLASS_HAS_RESERVED_SLOTS(ImportEntryObject::SlotCount)};
|
||||
|
||||
DEFINE_GETTER_FUNCTIONS(ImportEntryObject, moduleRequest, ModuleRequestSlot)
|
||||
DEFINE_GETTER_FUNCTIONS(ImportEntryObject, importName, ImportNameSlot)
|
||||
|
@ -149,8 +148,7 @@ DEFINE_UINT32_ACCESSOR_METHOD(ImportEntryObject, columnNumber)
|
|||
// ExportEntryObject
|
||||
|
||||
/* static */ const Class ExportEntryObject::class_ = {
|
||||
"ExportEntry", JSCLASS_HAS_RESERVED_SLOTS(ExportEntryObject::SlotCount) |
|
||||
JSCLASS_IS_ANONYMOUS};
|
||||
"ExportEntry", JSCLASS_HAS_RESERVED_SLOTS(ExportEntryObject::SlotCount)};
|
||||
|
||||
DEFINE_GETTER_FUNCTIONS(ExportEntryObject, exportName, ExportNameSlot)
|
||||
DEFINE_GETTER_FUNCTIONS(ExportEntryObject, moduleRequest, ModuleRequestSlot)
|
||||
|
@ -233,8 +231,7 @@ static Value StringOrNullValue(JSString* maybeString) {
|
|||
|
||||
/* static */ const Class RequestedModuleObject::class_ = {
|
||||
"RequestedModule",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(RequestedModuleObject::SlotCount) |
|
||||
JSCLASS_IS_ANONYMOUS};
|
||||
JSCLASS_HAS_RESERVED_SLOTS(RequestedModuleObject::SlotCount)};
|
||||
|
||||
DEFINE_GETTER_FUNCTIONS(RequestedModuleObject, moduleSpecifier,
|
||||
ModuleSpecifierSlot)
|
||||
|
@ -692,7 +689,7 @@ void FunctionDeclaration::trace(JSTracer* trc) {
|
|||
|
||||
/* static */ const Class ModuleObject::class_ = {
|
||||
"Module",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(ModuleObject::SlotCount) | JSCLASS_IS_ANONYMOUS |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(ModuleObject::SlotCount) |
|
||||
JSCLASS_BACKGROUND_FINALIZE,
|
||||
&ModuleObject::classOps_};
|
||||
|
||||
|
|
|
@ -2299,8 +2299,7 @@ static const JSClassOps FinalizeCounterClassOps = {nullptr, /* addProperty */
|
|||
finalize_counter_finalize};
|
||||
|
||||
static const JSClass FinalizeCounterClass = {
|
||||
"FinalizeCounter", JSCLASS_IS_ANONYMOUS | JSCLASS_FOREGROUND_FINALIZE,
|
||||
&FinalizeCounterClassOps};
|
||||
"FinalizeCounter", JSCLASS_FOREGROUND_FINALIZE, &FinalizeCounterClassOps};
|
||||
|
||||
static bool MakeFinalizeObserver(JSContext* cx, unsigned argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
|
|
@ -1506,6 +1506,26 @@ function TypedArrayStaticFrom(source, mapfn = undefined, thisArg = undefined) {
|
|||
if (!IsCallable(usingIterator))
|
||||
ThrowTypeError(JSMSG_NOT_ITERABLE, DecompileArg(0, source));
|
||||
|
||||
// Try to take a fast path when there's no mapper function and the
|
||||
// constructor is a built-in TypedArray constructor.
|
||||
if (!mapping && IsTypedArrayConstructor(C)) {
|
||||
// TODO: Add fast path for TypedArray inputs (bug 1491813).
|
||||
|
||||
// The source is a packed array using the default iterator.
|
||||
if (usingIterator === ArrayValues && IsPackedArray(source) &&
|
||||
ArrayIteratorPrototypeOptimizable())
|
||||
{
|
||||
// Steps 7.b-c.
|
||||
var targetObj = new C(source.length);
|
||||
|
||||
// Steps 7.a, 7.d-f.
|
||||
TypedArrayInitFromPackedArray(targetObj, source);
|
||||
|
||||
// Step 7.g.
|
||||
return targetObj;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 7.a.
|
||||
var values = IterableToList(source, usingIterator);
|
||||
|
||||
|
@ -1598,21 +1618,6 @@ function TypedArraySpecies() {
|
|||
}
|
||||
_SetCanonicalName(TypedArraySpecies, "get [Symbol.species]");
|
||||
|
||||
// ES 2017 draft June 2, 2016 22.2.3.32
|
||||
function TypedArrayToStringTag() {
|
||||
// Step 1.
|
||||
var O = this;
|
||||
|
||||
// Steps 2-3.
|
||||
if (!IsObject(O) || !IsPossiblyWrappedTypedArray(O))
|
||||
return undefined;
|
||||
|
||||
// Steps 4-6.
|
||||
// Modified to retrieve the [[TypedArrayName]] from the constructor.
|
||||
return _NameForTypedArray(O);
|
||||
}
|
||||
_SetCanonicalName(TypedArrayToStringTag, "get [Symbol.toStringTag]");
|
||||
|
||||
// ES2018 draft rev 0525bb33861c7f4e9850f8a222c89642947c4b9c
|
||||
// 22.2.2.1.1 Runtime Semantics: IterableToList( items, method )
|
||||
function IterableToList(items, method) {
|
||||
|
|
|
@ -72,7 +72,6 @@ enum class DeclarationKind : uint8_t {
|
|||
FormalParameter,
|
||||
CoverArrowParameter,
|
||||
Var,
|
||||
ForOfVar,
|
||||
Let,
|
||||
Const,
|
||||
Class, // Handled as same as `let` after parsing.
|
||||
|
@ -97,7 +96,6 @@ static inline BindingKind DeclarationKindToBindingKind(DeclarationKind kind) {
|
|||
case DeclarationKind::BodyLevelFunction:
|
||||
case DeclarationKind::ModuleBodyLevelFunction:
|
||||
case DeclarationKind::VarForAnnexBLexicalFunction:
|
||||
case DeclarationKind::ForOfVar:
|
||||
return BindingKind::Var;
|
||||
|
||||
case DeclarationKind::Let:
|
||||
|
|
|
@ -40,8 +40,6 @@ const char* DeclarationKindString(DeclarationKind kind) {
|
|||
return "function";
|
||||
case DeclarationKind::VarForAnnexBLexicalFunction:
|
||||
return "annex b var";
|
||||
case DeclarationKind::ForOfVar:
|
||||
return "var in for-of";
|
||||
case DeclarationKind::SimpleCatchParameter:
|
||||
case DeclarationKind::CatchParameter:
|
||||
return "catch parameter";
|
||||
|
@ -53,8 +51,7 @@ const char* DeclarationKindString(DeclarationKind kind) {
|
|||
bool DeclarationKindIsVar(DeclarationKind kind) {
|
||||
return kind == DeclarationKind::Var ||
|
||||
kind == DeclarationKind::BodyLevelFunction ||
|
||||
kind == DeclarationKind::VarForAnnexBLexicalFunction ||
|
||||
kind == DeclarationKind::ForOfVar;
|
||||
kind == DeclarationKind::VarForAnnexBLexicalFunction;
|
||||
}
|
||||
|
||||
bool DeclarationKindIsParameter(DeclarationKind kind) {
|
||||
|
@ -359,10 +356,8 @@ Maybe<DeclarationKind> ParseContext::isVarRedeclaredInEval(
|
|||
switch (bi.kind()) {
|
||||
case BindingKind::Let: {
|
||||
// Annex B.3.5 allows redeclaring simple (non-destructured)
|
||||
// catch parameters with var declarations, except when it
|
||||
// appears in a for-of.
|
||||
bool annexB35Allowance = si.kind() == ScopeKind::SimpleCatch &&
|
||||
kind != DeclarationKind::ForOfVar;
|
||||
// catch parameters with var declarations.
|
||||
bool annexB35Allowance = si.kind() == ScopeKind::SimpleCatch;
|
||||
if (!annexB35Allowance) {
|
||||
return Some(ScopeKindIsCatch(si.kind())
|
||||
? DeclarationKind::CatchParameter
|
||||
|
@ -434,13 +429,6 @@ bool ParseContext::tryDeclareVarHelper(HandlePropertyName name,
|
|||
// restrictive kind. These semantics are implemented in
|
||||
// CheckCanDeclareGlobalBinding.
|
||||
//
|
||||
// For a var previously declared as ForOfVar, this previous
|
||||
// DeclarationKind is used only to check for if the
|
||||
// 'arguments' binding should be declared. Since body-level
|
||||
// functions shadow 'arguments' [5], it is correct to alter
|
||||
// the kind to BodyLevelFunction. See
|
||||
// declareFunctionArgumentsObject.
|
||||
//
|
||||
// VarForAnnexBLexicalFunction declarations are declared when
|
||||
// the var scope exits. It is not possible for a var to be
|
||||
// previously declared as VarForAnnexBLexicalFunction and
|
||||
|
@ -450,7 +438,6 @@ bool ParseContext::tryDeclareVarHelper(HandlePropertyName name,
|
|||
// [2] ES 18.2.1.3
|
||||
// [3] ES 8.1.1.4.15
|
||||
// [4] ES 8.1.1.4.16
|
||||
// [5] ES 9.2.12
|
||||
if (dryRunOption == NotDryRun &&
|
||||
kind == DeclarationKind::BodyLevelFunction) {
|
||||
MOZ_ASSERT(declaredKind !=
|
||||
|
@ -459,11 +446,9 @@ bool ParseContext::tryDeclareVarHelper(HandlePropertyName name,
|
|||
}
|
||||
} else if (!DeclarationKindIsParameter(declaredKind)) {
|
||||
// Annex B.3.5 allows redeclaring simple (non-destructured)
|
||||
// catch parameters with var declarations, except when it
|
||||
// appears in a for-of.
|
||||
// catch parameters with var declarations.
|
||||
bool annexB35Allowance =
|
||||
declaredKind == DeclarationKind::SimpleCatchParameter &&
|
||||
kind != DeclarationKind::ForOfVar;
|
||||
declaredKind == DeclarationKind::SimpleCatchParameter;
|
||||
|
||||
// Annex B.3.3 allows redeclaring functions in the same block.
|
||||
bool annexB33Allowance =
|
||||
|
|
|
@ -608,8 +608,7 @@ bool GeneralParser<ParseHandler, Unit>::noteDeclaredName(
|
|||
|
||||
switch (kind) {
|
||||
case DeclarationKind::Var:
|
||||
case DeclarationKind::BodyLevelFunction:
|
||||
case DeclarationKind::ForOfVar: {
|
||||
case DeclarationKind::BodyLevelFunction: {
|
||||
Maybe<DeclarationKind> redeclaredKind;
|
||||
uint32_t prevPos;
|
||||
if (!pc->tryDeclareVar(name, kind, pos.begin, &redeclaredKind,
|
||||
|
@ -1882,8 +1881,7 @@ bool PerHandlerParser<ParseHandler>::declareFunctionArgumentsObject() {
|
|||
// declared 'var arguments', we still need to declare 'arguments' in the
|
||||
// function scope.
|
||||
DeclaredNamePtr p = varScope.lookupDeclaredName(argumentsName);
|
||||
if (p && (p->value()->kind() == DeclarationKind::Var ||
|
||||
p->value()->kind() == DeclarationKind::ForOfVar)) {
|
||||
if (p && p->value()->kind() == DeclarationKind::Var) {
|
||||
if (hasExtraBodyVarScope) {
|
||||
tryDeclareArguments = true;
|
||||
} else {
|
||||
|
@ -4154,11 +4152,6 @@ GeneralParser<ParseHandler, Unit>::declarationPattern(
|
|||
*forHeadKind = ParseNodeKind::ForIn;
|
||||
} else if (isForOf) {
|
||||
*forHeadKind = ParseNodeKind::ForOf;
|
||||
|
||||
// Annex B.3.5 has different early errors for vars in for-of loops.
|
||||
if (declKind == DeclarationKind::Var) {
|
||||
declKind = DeclarationKind::ForOfVar;
|
||||
}
|
||||
} else {
|
||||
*forHeadKind = ParseNodeKind::ForHead;
|
||||
}
|
||||
|
@ -4306,11 +4299,6 @@ GeneralParser<ParseHandler, Unit>::declarationName(DeclarationKind declKind,
|
|||
*forHeadKind = ParseNodeKind::ForIn;
|
||||
} else if (isForOf) {
|
||||
*forHeadKind = ParseNodeKind::ForOf;
|
||||
|
||||
// Annex B.3.5 has different early errors for vars in for-of loops.
|
||||
if (declKind == DeclarationKind::Var) {
|
||||
declKind = DeclarationKind::ForOfVar;
|
||||
}
|
||||
} else {
|
||||
*forHeadKind = ParseNodeKind::ForHead;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
// Test TypedArray constructor when called with iterables or typed arrays.
|
||||
|
||||
function testPackedArray() {
|
||||
function test() {
|
||||
var array = [
|
||||
1, 2, 3,
|
||||
4, 5, 6,
|
||||
7, 8, 9,
|
||||
];
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
var ta = new Int32Array(array);
|
||||
assertEq(ta.length, array.length);
|
||||
for (var j = 0; j < array.length; ++j) {
|
||||
assertEq(ta[j], array[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < 2; ++i) {
|
||||
test();
|
||||
}
|
||||
}
|
||||
testPackedArray();
|
||||
|
||||
function testHoleArray() {
|
||||
function test() {
|
||||
var array = [
|
||||
1, /* hole */, 3,
|
||||
4, /* hole */, 6,
|
||||
7, /* hole */, 9,
|
||||
];
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
var ta = new Int32Array(array);
|
||||
assertEq(ta.length, array.length);
|
||||
for (var j = 0; j < array.length; ++j) {
|
||||
assertEq(ta[j], array[j] || 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < 2; ++i) {
|
||||
test();
|
||||
}
|
||||
}
|
||||
testHoleArray();
|
||||
|
||||
function testTypedArraySameType() {
|
||||
function test() {
|
||||
var array = new Int32Array([
|
||||
1, 2, 3,
|
||||
4, 5, 6,
|
||||
7, 8, 9,
|
||||
]);
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
var ta = new Int32Array(array);
|
||||
assertEq(ta.length, array.length);
|
||||
for (var j = 0; j < array.length; ++j) {
|
||||
assertEq(ta[j], array[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < 2; ++i) {
|
||||
test();
|
||||
}
|
||||
}
|
||||
testTypedArraySameType();
|
||||
|
||||
function testTypedArrayDifferentType() {
|
||||
function test() {
|
||||
var array = new Float32Array([
|
||||
1, 2, 3,
|
||||
4, 5, 6,
|
||||
7, 8, 9,
|
||||
]);
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
var ta = new Int32Array(array);
|
||||
assertEq(ta.length, array.length);
|
||||
for (var j = 0; j < array.length; ++j) {
|
||||
assertEq(ta[j], array[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < 2; ++i) {
|
||||
test();
|
||||
}
|
||||
}
|
||||
testTypedArrayDifferentType();
|
||||
|
||||
function testIterable() {
|
||||
function test() {
|
||||
var array = [
|
||||
1, 2, 3,
|
||||
4, 5, 6,
|
||||
7, 8, 9,
|
||||
];
|
||||
array = Object.defineProperties({
|
||||
[Symbol.iterator]() {
|
||||
var index = 0;
|
||||
return {
|
||||
next() {
|
||||
var done = index >= array.length;
|
||||
var value = !done ? array[index++] : undefined;
|
||||
return {done, value};
|
||||
}
|
||||
};
|
||||
}
|
||||
}, Object.getOwnPropertyDescriptors(array));
|
||||
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
var ta = new Int32Array(array);
|
||||
assertEq(ta.length, array.length);
|
||||
for (var j = 0; j < array.length; ++j) {
|
||||
assertEq(ta[j], array[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < 2; ++i) {
|
||||
test();
|
||||
}
|
||||
}
|
||||
testIterable();
|
||||
|
||||
function testWrappedArray() {
|
||||
var g = newGlobal();
|
||||
|
||||
function test() {
|
||||
var array = new g.Array(
|
||||
1, 2, 3,
|
||||
4, 5, 6,
|
||||
7, 8, 9,
|
||||
);
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
var ta = new Int32Array(array);
|
||||
assertEq(ta.length, array.length);
|
||||
for (var j = 0; j < array.length; ++j) {
|
||||
assertEq(ta[j], array[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < 2; ++i) {
|
||||
test();
|
||||
}
|
||||
}
|
||||
testWrappedArray();
|
||||
|
||||
function testWrappedTypedArray() {
|
||||
var g = newGlobal();
|
||||
|
||||
function test() {
|
||||
var array = new g.Int32Array([
|
||||
1, 2, 3,
|
||||
4, 5, 6,
|
||||
7, 8, 9,
|
||||
]);
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
var ta = new Int32Array(array);
|
||||
assertEq(ta.length, array.length);
|
||||
for (var j = 0; j < array.length; ++j) {
|
||||
assertEq(ta[j], array[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < 2; ++i) {
|
||||
test();
|
||||
}
|
||||
}
|
||||
testWrappedTypedArray();
|
|
@ -0,0 +1,50 @@
|
|||
var invalidatedFunction = function() { return false; }
|
||||
|
||||
var counter = 0;
|
||||
|
||||
function maybeInvalidate(iplusk) {
|
||||
if (iplusk === 0) {
|
||||
// This should happen only once; it will invalidate the call frame of
|
||||
// the ion() function, which should rewind to just after the wasm call
|
||||
// (if it got its own resume point).
|
||||
// Before the patch, the wasm call doesn't get its resume point, so
|
||||
// it's repeated and the importedFunc() is called once too many.
|
||||
counter++;
|
||||
invalidatedFunction = function () { return true; };
|
||||
}
|
||||
}
|
||||
|
||||
function importedFunc(k) {
|
||||
for (let i = 100; i --> 0 ;) {
|
||||
maybeInvalidate(i + k);
|
||||
}
|
||||
}
|
||||
|
||||
let { exports } = new WebAssembly.Instance(
|
||||
new WebAssembly.Module(
|
||||
wasmTextToBinary(`
|
||||
(module
|
||||
(func $imp (import "env" "importedFunc") (param i32))
|
||||
(func (export "exp") (param i32)
|
||||
get_local 0
|
||||
call $imp
|
||||
)
|
||||
)
|
||||
`)
|
||||
), {
|
||||
env: {
|
||||
importedFunc
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
function ion(k) {
|
||||
exports.exp(k);
|
||||
invalidatedFunction();
|
||||
}
|
||||
|
||||
for (let k = 100; k --> 0 ;) {
|
||||
ion(k);
|
||||
}
|
||||
|
||||
assertEq(counter, 1);
|
|
@ -3301,86 +3301,94 @@ static bool TryAttachFunCallStub(JSContext* cx, ICCall_Fallback* stub,
|
|||
static bool GetTemplateObjectForNative(JSContext* cx, HandleFunction target,
|
||||
const CallArgs& args,
|
||||
MutableHandleObject res) {
|
||||
Native native = target->native();
|
||||
if (!target->hasJitInfo() ||
|
||||
target->jitInfo()->type() != JSJitInfo::InlinableNative) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for natives to which template objects can be attached. This is
|
||||
// done to provide templates to Ion for inlining these natives later on.
|
||||
switch (target->jitInfo()->inlinableNative) {
|
||||
case InlinableNative::Array: {
|
||||
// Note: the template array won't be used if its length is inaccurately
|
||||
// computed here. (We allocate here because compilation may occur on a
|
||||
// separate thread where allocation is impossible.)
|
||||
size_t count = 0;
|
||||
if (args.length() != 1) {
|
||||
count = args.length();
|
||||
} else if (args.length() == 1 && args[0].isInt32() &&
|
||||
args[0].toInt32() >= 0) {
|
||||
count = args[0].toInt32();
|
||||
}
|
||||
|
||||
if (native == ArrayConstructor || native == array_construct) {
|
||||
// Note: the template array won't be used if its length is inaccurately
|
||||
// computed here. (We allocate here because compilation may occur on a
|
||||
// separate thread where allocation is impossible.)
|
||||
size_t count = 0;
|
||||
if (args.length() != 1) {
|
||||
count = args.length();
|
||||
} else if (args.length() == 1 && args[0].isInt32() &&
|
||||
args[0].toInt32() >= 0) {
|
||||
count = args[0].toInt32();
|
||||
}
|
||||
if (count > ArrayObject::EagerAllocationMaxLength) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (count <= ArrayObject::EagerAllocationMaxLength) {
|
||||
// With this and other array templates, analyze the group so that
|
||||
// we don't end up with a template whose structure might change later.
|
||||
res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, count,
|
||||
TenuredObject));
|
||||
return !!res;
|
||||
}
|
||||
}
|
||||
|
||||
if (args.length() == 1) {
|
||||
size_t len = 0;
|
||||
|
||||
if (args[0].isInt32() && args[0].toInt32() >= 0) {
|
||||
len = args[0].toInt32();
|
||||
}
|
||||
|
||||
if (!TypedArrayObject::GetTemplateObjectForNative(cx, native, len, res)) {
|
||||
return false;
|
||||
}
|
||||
if (res) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (native == js::array_slice) {
|
||||
if (args.thisv().isObject()) {
|
||||
RootedObject obj(cx, &args.thisv().toObject());
|
||||
if (!obj->isSingleton()) {
|
||||
res.set(NewFullyAllocatedArrayTryReuseGroup(cx, obj, 0, TenuredObject));
|
||||
return !!res;
|
||||
case InlinableNative::ArraySlice: {
|
||||
if (!args.thisv().isObject()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
RootedObject obj(cx, &args.thisv().toObject());
|
||||
if (obj->isSingleton()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
res.set(NewFullyAllocatedArrayTryReuseGroup(cx, obj, 0, TenuredObject));
|
||||
return !!res;
|
||||
}
|
||||
}
|
||||
|
||||
if (native == StringConstructor) {
|
||||
RootedString emptyString(cx, cx->runtime()->emptyString);
|
||||
res.set(StringObject::create(cx, emptyString, /* proto = */ nullptr,
|
||||
TenuredObject));
|
||||
return !!res;
|
||||
}
|
||||
case InlinableNative::String: {
|
||||
RootedString emptyString(cx, cx->runtime()->emptyString);
|
||||
res.set(StringObject::create(cx, emptyString, /* proto = */ nullptr,
|
||||
TenuredObject));
|
||||
return !!res;
|
||||
}
|
||||
|
||||
if (native == obj_create && args.length() == 1 && args[0].isObjectOrNull()) {
|
||||
RootedObject proto(cx, args[0].toObjectOrNull());
|
||||
res.set(ObjectCreateImpl(cx, proto, TenuredObject));
|
||||
return !!res;
|
||||
}
|
||||
case InlinableNative::ObjectCreate: {
|
||||
if (args.length() != 1 || !args[0].isObjectOrNull()) {
|
||||
return true;
|
||||
}
|
||||
RootedObject proto(cx, args[0].toObjectOrNull());
|
||||
res.set(ObjectCreateImpl(cx, proto, TenuredObject));
|
||||
return !!res;
|
||||
}
|
||||
|
||||
if (native == js::intrinsic_NewArrayIterator) {
|
||||
res.set(NewArrayIteratorObject(cx, TenuredObject));
|
||||
return !!res;
|
||||
}
|
||||
case InlinableNative::IntrinsicNewArrayIterator: {
|
||||
res.set(NewArrayIteratorObject(cx, TenuredObject));
|
||||
return !!res;
|
||||
}
|
||||
|
||||
if (native == js::intrinsic_NewStringIterator) {
|
||||
res.set(NewStringIteratorObject(cx, TenuredObject));
|
||||
return !!res;
|
||||
}
|
||||
case InlinableNative::IntrinsicNewStringIterator: {
|
||||
res.set(NewStringIteratorObject(cx, TenuredObject));
|
||||
return !!res;
|
||||
}
|
||||
|
||||
if (native == js::intrinsic_NewRegExpStringIterator) {
|
||||
res.set(NewRegExpStringIteratorObject(cx, TenuredObject));
|
||||
return !!res;
|
||||
}
|
||||
case InlinableNative::IntrinsicNewRegExpStringIterator: {
|
||||
res.set(NewRegExpStringIteratorObject(cx, TenuredObject));
|
||||
return !!res;
|
||||
}
|
||||
|
||||
return true;
|
||||
case InlinableNative::TypedArrayConstructor: {
|
||||
if (args.length() != 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return TypedArrayObject::GetTemplateObjectForNative(cx, target->native(),
|
||||
args[0], res);
|
||||
}
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool GetTemplateObjectForClassHook(JSContext* cx, JSNative hook,
|
||||
|
|
|
@ -6318,6 +6318,19 @@ void CodeGenerator::visitNewTypedArrayDynamicLength(
|
|||
masm.bind(ool->rejoin());
|
||||
}
|
||||
|
||||
typedef TypedArrayObject* (*TypedArrayCreateWithTemplateFn)(JSContext*,
|
||||
HandleObject,
|
||||
HandleObject);
|
||||
static const VMFunction TypedArrayCreateWithTemplateInfo =
|
||||
FunctionInfo<TypedArrayCreateWithTemplateFn>(
|
||||
js::TypedArrayCreateWithTemplate, "TypedArrayCreateWithTemplate");
|
||||
|
||||
void CodeGenerator::visitNewTypedArrayFromArray(LNewTypedArrayFromArray* lir) {
|
||||
pushArg(ToRegister(lir->array()));
|
||||
pushArg(ImmGCPtr(lir->mir()->templateObject()));
|
||||
callVM(TypedArrayCreateWithTemplateInfo, lir);
|
||||
}
|
||||
|
||||
// Out-of-line object allocation for JSOP_NEWOBJECT.
|
||||
class OutOfLineNewObject : public OutOfLineCodeBase<CodeGenerator> {
|
||||
LNewObject* lir_;
|
||||
|
@ -12593,10 +12606,21 @@ void CodeGenerator::visitIsArrayV(LIsArrayV* lir) {
|
|||
EmitObjectIsArray(masm, ool, temp, output, ¬Array);
|
||||
}
|
||||
|
||||
typedef bool (*IsPossiblyWrappedTypedArrayFn)(JSContext*, JSObject*, bool*);
|
||||
static const VMFunction IsPossiblyWrappedTypedArrayInfo =
|
||||
FunctionInfo<IsPossiblyWrappedTypedArrayFn>(
|
||||
jit::IsPossiblyWrappedTypedArray, "IsPossiblyWrappedTypedArray");
|
||||
|
||||
void CodeGenerator::visitIsTypedArray(LIsTypedArray* lir) {
|
||||
Register object = ToRegister(lir->object());
|
||||
Register output = ToRegister(lir->output());
|
||||
|
||||
OutOfLineCode* ool = nullptr;
|
||||
if (lir->mir()->isPossiblyWrapped()) {
|
||||
ool = oolCallVM(IsPossiblyWrappedTypedArrayInfo, lir, ArgList(object),
|
||||
StoreRegisterTo(output));
|
||||
}
|
||||
|
||||
Label notTypedArray;
|
||||
Label done;
|
||||
|
||||
|
@ -12618,8 +12642,14 @@ void CodeGenerator::visitIsTypedArray(LIsTypedArray* lir) {
|
|||
masm.move32(Imm32(1), output);
|
||||
masm.jump(&done);
|
||||
masm.bind(¬TypedArray);
|
||||
if (ool) {
|
||||
masm.branchTestClassIsProxy(true, output, ool->entry());
|
||||
}
|
||||
masm.move32(Imm32(0), output);
|
||||
masm.bind(&done);
|
||||
if (ool) {
|
||||
masm.bind(ool->rejoin());
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::visitIsObject(LIsObject* ins) {
|
||||
|
|
|
@ -144,6 +144,7 @@
|
|||
_(IntrinsicGuardToSharedArrayBuffer) \
|
||||
\
|
||||
_(TypedArrayConstructor) \
|
||||
_(IntrinsicIsTypedArrayConstructor) \
|
||||
_(IntrinsicIsTypedArray) \
|
||||
_(IntrinsicIsPossiblyWrappedTypedArray) \
|
||||
_(IntrinsicTypedArrayLength) \
|
||||
|
|
|
@ -772,6 +772,7 @@ class IonBuilder : public MIRGenerator,
|
|||
// TypedArray intrinsics.
|
||||
enum WrappingBehavior { AllowWrappedTypedArrays, RejectWrappedTypedArrays };
|
||||
InliningResult inlineTypedArray(CallInfo& callInfo, Native native);
|
||||
InliningResult inlineIsTypedArrayConstructor(CallInfo& callInfo);
|
||||
InliningResult inlineIsTypedArrayHelper(CallInfo& callInfo,
|
||||
WrappingBehavior wrappingBehavior);
|
||||
InliningResult inlineIsTypedArray(CallInfo& callInfo);
|
||||
|
|
|
@ -21,11 +21,13 @@ using namespace js::jit;
|
|||
|
||||
void JSONSpewer::beginFunction(JSScript* script) {
|
||||
beginObject();
|
||||
if (script) {
|
||||
formatProperty("name", "%s:%u", script->filename(), script->lineno());
|
||||
} else {
|
||||
property("name", "wasm compilation");
|
||||
}
|
||||
formatProperty("name", "%s:%u", script->filename(), script->lineno());
|
||||
beginListProperty("passes");
|
||||
}
|
||||
|
||||
void JSONSpewer::beginWasmFunction(unsigned funcIndex) {
|
||||
beginObject();
|
||||
formatProperty("name", "wasm-func%u", funcIndex);
|
||||
beginListProperty("passes");
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ class JSONSpewer : JSONPrinter {
|
|||
explicit JSONSpewer(GenericPrinter& out) : JSONPrinter(out) {}
|
||||
|
||||
void beginFunction(JSScript* script);
|
||||
void beginWasmFunction(unsigned funcIndex);
|
||||
void beginPass(const char* pass);
|
||||
void spewMDef(MDefinition* def);
|
||||
void spewMResumePoint(MResumePoint* rp);
|
||||
|
|
|
@ -245,9 +245,15 @@ void GraphSpewer::beginFunction(JSScript* function) {
|
|||
if (!isSpewing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
jsonSpewer_.beginFunction(function);
|
||||
ionspewer.beginFunction();
|
||||
}
|
||||
|
||||
void GraphSpewer::beginWasmFunction(unsigned funcIndex) {
|
||||
if (!isSpewing()) {
|
||||
return;
|
||||
}
|
||||
jsonSpewer_.beginWasmFunction(funcIndex);
|
||||
ionspewer.beginFunction();
|
||||
}
|
||||
|
||||
|
@ -321,6 +327,12 @@ void jit::SpewBeginFunction(MIRGenerator* mir, JSScript* function) {
|
|||
mir->graphSpewer().beginFunction(function);
|
||||
}
|
||||
|
||||
void jit::SpewBeginWasmFunction(MIRGenerator* mir, unsigned funcIndex) {
|
||||
MIRGraph* graph = &mir->graph();
|
||||
mir->graphSpewer().init(graph, nullptr);
|
||||
mir->graphSpewer().beginWasmFunction(funcIndex);
|
||||
}
|
||||
|
||||
AutoSpewEndFunction::~AutoSpewEndFunction() {
|
||||
mir_->graphSpewer().endFunction();
|
||||
}
|
||||
|
@ -330,203 +342,181 @@ Fprinter& jit::JitSpewPrinter() {
|
|||
return out;
|
||||
}
|
||||
|
||||
static void PrintHelpAndExit(int status = 0) {
|
||||
fflush(nullptr);
|
||||
printf(
|
||||
"\n"
|
||||
"usage: IONFLAGS=option,option,option,... where options can be:\n"
|
||||
"\n"
|
||||
" aborts Compilation abort messages\n"
|
||||
" scripts Compiled scripts\n"
|
||||
" mir MIR information\n"
|
||||
" prune Prune unused branches\n"
|
||||
" escape Escape analysis\n"
|
||||
" alias Alias analysis\n"
|
||||
" alias-sum Alias analysis: shows summaries for every block\n"
|
||||
" gvn Global Value Numbering\n"
|
||||
" licm Loop invariant code motion\n"
|
||||
" flac Fold linear arithmetic constants\n"
|
||||
" eaa Effective address analysis\n"
|
||||
" sincos Replace sin/cos by sincos\n"
|
||||
" sink Sink transformation\n"
|
||||
" regalloc Register allocation\n"
|
||||
" inline Inlining\n"
|
||||
" snapshots Snapshot information\n"
|
||||
" codegen Native code generation\n"
|
||||
" bailouts Bailouts\n"
|
||||
" caches Inline caches\n"
|
||||
" osi Invalidation\n"
|
||||
" safepoints Safepoints\n"
|
||||
" pools Literal Pools (ARM only for now)\n"
|
||||
" cacheflush Instruction Cache flushes (ARM only for now)\n"
|
||||
" range Range Analysis\n"
|
||||
" logs JSON visualization logging\n"
|
||||
" logs-sync Same as logs, but flushes between each pass (sync. "
|
||||
"compiled functions only).\n"
|
||||
" profiling Profiling-related information\n"
|
||||
" trackopts Optimization tracking information gathered by the "
|
||||
"Gecko profiler. "
|
||||
"(Note: call enableGeckoProfiling() in your script to enable it).\n"
|
||||
" trackopts-ext Encoding information about optimization tracking\n"
|
||||
" dump-mir-expr Dump the MIR expressions\n"
|
||||
" cfg Control flow graph generation\n"
|
||||
" all Everything\n"
|
||||
"\n"
|
||||
" bl-aborts Baseline compiler abort messages\n"
|
||||
" bl-scripts Baseline script-compilation\n"
|
||||
" bl-op Baseline compiler detailed op-specific messages\n"
|
||||
" bl-ic Baseline inline-cache messages\n"
|
||||
" bl-ic-fb Baseline IC fallback stub messages\n"
|
||||
" bl-osr Baseline IC OSR messages\n"
|
||||
" bl-bails Baseline bailouts\n"
|
||||
" bl-dbg-osr Baseline debug mode on stack recompile messages\n"
|
||||
" bl-all All baseline spew\n"
|
||||
"\n"
|
||||
"See also SPEW=help for information on the Structured Spewer."
|
||||
"\n");
|
||||
exit(status);
|
||||
}
|
||||
|
||||
static bool IsFlag(const char* found, const char* flag) {
|
||||
return strlen(found) == strlen(flag) && strcmp(found, flag) == 0;
|
||||
}
|
||||
|
||||
void jit::CheckLogging() {
|
||||
if (LoggingChecked) {
|
||||
return;
|
||||
}
|
||||
|
||||
LoggingChecked = true;
|
||||
const char* env = getenv("IONFLAGS");
|
||||
|
||||
char* env = getenv("IONFLAGS");
|
||||
if (!env) {
|
||||
return;
|
||||
}
|
||||
if (strstr(env, "help")) {
|
||||
fflush(nullptr);
|
||||
printf(
|
||||
"\n"
|
||||
"usage: IONFLAGS=option,option,option,... where options can be:\n"
|
||||
"\n"
|
||||
" aborts Compilation abort messages\n"
|
||||
" scripts Compiled scripts\n"
|
||||
" mir MIR information\n"
|
||||
" prune Prune unused branches\n"
|
||||
" escape Escape analysis\n"
|
||||
" alias Alias analysis\n"
|
||||
" alias-sum Alias analysis: shows summaries for every block\n"
|
||||
" gvn Global Value Numbering\n"
|
||||
" licm Loop invariant code motion\n"
|
||||
" flac Fold linear arithmetic constants\n"
|
||||
" eaa Effective address analysis\n"
|
||||
" sincos Replace sin/cos by sincos\n"
|
||||
" sink Sink transformation\n"
|
||||
" regalloc Register allocation\n"
|
||||
" inline Inlining\n"
|
||||
" snapshots Snapshot information\n"
|
||||
" codegen Native code generation\n"
|
||||
" bailouts Bailouts\n"
|
||||
" caches Inline caches\n"
|
||||
" osi Invalidation\n"
|
||||
" safepoints Safepoints\n"
|
||||
" pools Literal Pools (ARM only for now)\n"
|
||||
" cacheflush Instruction Cache flushes (ARM only for now)\n"
|
||||
" range Range Analysis\n"
|
||||
" logs JSON visualization logging\n"
|
||||
" logs-sync Same as logs, but flushes between each pass (sync. "
|
||||
"compiled functions only).\n"
|
||||
" profiling Profiling-related information\n"
|
||||
" trackopts Optimization tracking information gathered by the "
|
||||
"Gecko profiler. "
|
||||
"(Note: call enableGeckoProfiling() in your script to enable it).\n"
|
||||
" trackopts-ext Encoding information about optimization tracking\n"
|
||||
" dump-mir-expr Dump the MIR expressions\n"
|
||||
" cfg Control flow graph generation\n"
|
||||
" all Everything\n"
|
||||
"\n"
|
||||
" bl-aborts Baseline compiler abort messages\n"
|
||||
" bl-scripts Baseline script-compilation\n"
|
||||
" bl-op Baseline compiler detailed op-specific messages\n"
|
||||
" bl-ic Baseline inline-cache messages\n"
|
||||
" bl-ic-fb Baseline IC fallback stub messages\n"
|
||||
" bl-osr Baseline IC OSR messages\n"
|
||||
" bl-bails Baseline bailouts\n"
|
||||
" bl-dbg-osr Baseline debug mode on stack recompile messages\n"
|
||||
" bl-all All baseline spew\n"
|
||||
"\n"
|
||||
"See also SPEW=help for information on the Structured Spewer."
|
||||
"\n");
|
||||
exit(0);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
if (ContainsFlag(env, "aborts")) {
|
||||
EnableChannel(JitSpew_IonAbort);
|
||||
}
|
||||
if (ContainsFlag(env, "prune")) {
|
||||
EnableChannel(JitSpew_Prune);
|
||||
}
|
||||
if (ContainsFlag(env, "escape")) {
|
||||
EnableChannel(JitSpew_Escape);
|
||||
}
|
||||
if (ContainsFlag(env, "alias")) {
|
||||
EnableChannel(JitSpew_Alias);
|
||||
}
|
||||
if (ContainsFlag(env, "alias-sum")) {
|
||||
EnableChannel(JitSpew_AliasSummaries);
|
||||
}
|
||||
if (ContainsFlag(env, "scripts")) {
|
||||
EnableChannel(JitSpew_IonScripts);
|
||||
}
|
||||
if (ContainsFlag(env, "mir")) {
|
||||
EnableChannel(JitSpew_IonMIR);
|
||||
}
|
||||
if (ContainsFlag(env, "gvn")) {
|
||||
EnableChannel(JitSpew_GVN);
|
||||
}
|
||||
if (ContainsFlag(env, "range")) {
|
||||
EnableChannel(JitSpew_Range);
|
||||
}
|
||||
if (ContainsFlag(env, "licm")) {
|
||||
EnableChannel(JitSpew_LICM);
|
||||
}
|
||||
if (ContainsFlag(env, "flac")) {
|
||||
EnableChannel(JitSpew_FLAC);
|
||||
}
|
||||
if (ContainsFlag(env, "eaa")) {
|
||||
EnableChannel(JitSpew_EAA);
|
||||
}
|
||||
if (ContainsFlag(env, "sincos")) {
|
||||
EnableChannel(JitSpew_Sincos);
|
||||
}
|
||||
if (ContainsFlag(env, "sink")) {
|
||||
EnableChannel(JitSpew_Sink);
|
||||
}
|
||||
if (ContainsFlag(env, "regalloc")) {
|
||||
EnableChannel(JitSpew_RegAlloc);
|
||||
}
|
||||
if (ContainsFlag(env, "inline")) {
|
||||
EnableChannel(JitSpew_Inlining);
|
||||
}
|
||||
if (ContainsFlag(env, "snapshots")) {
|
||||
EnableChannel(JitSpew_IonSnapshots);
|
||||
}
|
||||
if (ContainsFlag(env, "codegen")) {
|
||||
EnableChannel(JitSpew_Codegen);
|
||||
}
|
||||
if (ContainsFlag(env, "bailouts")) {
|
||||
EnableChannel(JitSpew_IonBailouts);
|
||||
}
|
||||
if (ContainsFlag(env, "osi")) {
|
||||
EnableChannel(JitSpew_IonInvalidate);
|
||||
}
|
||||
if (ContainsFlag(env, "caches")) {
|
||||
EnableChannel(JitSpew_IonIC);
|
||||
}
|
||||
if (ContainsFlag(env, "safepoints")) {
|
||||
EnableChannel(JitSpew_Safepoints);
|
||||
}
|
||||
if (ContainsFlag(env, "pools")) {
|
||||
EnableChannel(JitSpew_Pools);
|
||||
}
|
||||
if (ContainsFlag(env, "cacheflush")) {
|
||||
EnableChannel(JitSpew_CacheFlush);
|
||||
}
|
||||
if (ContainsFlag(env, "logs")) {
|
||||
EnableIonDebugAsyncLogging();
|
||||
}
|
||||
if (ContainsFlag(env, "logs-sync")) {
|
||||
EnableIonDebugSyncLogging();
|
||||
}
|
||||
if (ContainsFlag(env, "profiling")) {
|
||||
EnableChannel(JitSpew_Profiling);
|
||||
}
|
||||
if (ContainsFlag(env, "trackopts")) {
|
||||
JitOptions.disableOptimizationTracking = false;
|
||||
EnableChannel(JitSpew_OptimizationTracking);
|
||||
}
|
||||
if (ContainsFlag(env, "trackopts-ext")) {
|
||||
EnableChannel(JitSpew_OptimizationTrackingExtended);
|
||||
}
|
||||
if (ContainsFlag(env, "dump-mir-expr")) {
|
||||
EnableChannel(JitSpew_MIRExpressions);
|
||||
}
|
||||
if (ContainsFlag(env, "cfg")) {
|
||||
EnableChannel(JitSpew_CFG);
|
||||
}
|
||||
if (ContainsFlag(env, "all")) {
|
||||
LoggingBits = uint64_t(-1);
|
||||
}
|
||||
|
||||
if (ContainsFlag(env, "bl-aborts")) {
|
||||
EnableChannel(JitSpew_BaselineAbort);
|
||||
}
|
||||
if (ContainsFlag(env, "bl-scripts")) {
|
||||
EnableChannel(JitSpew_BaselineScripts);
|
||||
}
|
||||
if (ContainsFlag(env, "bl-op")) {
|
||||
EnableChannel(JitSpew_BaselineOp);
|
||||
}
|
||||
if (ContainsFlag(env, "bl-ic")) {
|
||||
EnableChannel(JitSpew_BaselineIC);
|
||||
}
|
||||
if (ContainsFlag(env, "bl-ic-fb")) {
|
||||
EnableChannel(JitSpew_BaselineICFallback);
|
||||
}
|
||||
if (ContainsFlag(env, "bl-osr")) {
|
||||
EnableChannel(JitSpew_BaselineOSR);
|
||||
}
|
||||
if (ContainsFlag(env, "bl-bails")) {
|
||||
EnableChannel(JitSpew_BaselineBailouts);
|
||||
}
|
||||
if (ContainsFlag(env, "bl-dbg-osr")) {
|
||||
EnableChannel(JitSpew_BaselineDebugModeOSR);
|
||||
}
|
||||
if (ContainsFlag(env, "bl-all")) {
|
||||
EnableChannel(JitSpew_BaselineAbort);
|
||||
EnableChannel(JitSpew_BaselineScripts);
|
||||
EnableChannel(JitSpew_BaselineOp);
|
||||
EnableChannel(JitSpew_BaselineIC);
|
||||
EnableChannel(JitSpew_BaselineICFallback);
|
||||
EnableChannel(JitSpew_BaselineOSR);
|
||||
EnableChannel(JitSpew_BaselineBailouts);
|
||||
EnableChannel(JitSpew_BaselineDebugModeOSR);
|
||||
const char* found = strtok(env, ",");
|
||||
while (found) {
|
||||
fprintf(stderr, "found tag: %s\n", found);
|
||||
// We're at the end of a flag; check if the previous substring was a
|
||||
// known flag (i-1 is the last character of the flag we just read).
|
||||
if (IsFlag(found, "help")) {
|
||||
PrintHelpAndExit();
|
||||
} else if (IsFlag(found, "aborts")) {
|
||||
EnableChannel(JitSpew_IonAbort);
|
||||
} else if (IsFlag(found, "prune")) {
|
||||
EnableChannel(JitSpew_Prune);
|
||||
} else if (IsFlag(found, "escape")) {
|
||||
EnableChannel(JitSpew_Escape);
|
||||
} else if (IsFlag(found, "alias")) {
|
||||
EnableChannel(JitSpew_Alias);
|
||||
} else if (IsFlag(found, "alias-sum")) {
|
||||
EnableChannel(JitSpew_AliasSummaries);
|
||||
} else if (IsFlag(found, "scripts")) {
|
||||
EnableChannel(JitSpew_IonScripts);
|
||||
} else if (IsFlag(found, "mir")) {
|
||||
EnableChannel(JitSpew_IonMIR);
|
||||
} else if (IsFlag(found, "gvn")) {
|
||||
EnableChannel(JitSpew_GVN);
|
||||
} else if (IsFlag(found, "range")) {
|
||||
EnableChannel(JitSpew_Range);
|
||||
} else if (IsFlag(found, "licm")) {
|
||||
EnableChannel(JitSpew_LICM);
|
||||
} else if (IsFlag(found, "flac")) {
|
||||
EnableChannel(JitSpew_FLAC);
|
||||
} else if (IsFlag(found, "eaa")) {
|
||||
EnableChannel(JitSpew_EAA);
|
||||
} else if (IsFlag(found, "sincos")) {
|
||||
EnableChannel(JitSpew_Sincos);
|
||||
} else if (IsFlag(found, "sink")) {
|
||||
EnableChannel(JitSpew_Sink);
|
||||
} else if (IsFlag(found, "regalloc")) {
|
||||
EnableChannel(JitSpew_RegAlloc);
|
||||
} else if (IsFlag(found, "inline")) {
|
||||
EnableChannel(JitSpew_Inlining);
|
||||
} else if (IsFlag(found, "snapshots")) {
|
||||
EnableChannel(JitSpew_IonSnapshots);
|
||||
} else if (IsFlag(found, "codegen")) {
|
||||
EnableChannel(JitSpew_Codegen);
|
||||
} else if (IsFlag(found, "bailouts")) {
|
||||
EnableChannel(JitSpew_IonBailouts);
|
||||
} else if (IsFlag(found, "osi")) {
|
||||
EnableChannel(JitSpew_IonInvalidate);
|
||||
} else if (IsFlag(found, "caches")) {
|
||||
EnableChannel(JitSpew_IonIC);
|
||||
} else if (IsFlag(found, "safepoints")) {
|
||||
EnableChannel(JitSpew_Safepoints);
|
||||
} else if (IsFlag(found, "pools")) {
|
||||
EnableChannel(JitSpew_Pools);
|
||||
} else if (IsFlag(found, "cacheflush")) {
|
||||
EnableChannel(JitSpew_CacheFlush);
|
||||
} else if (IsFlag(found, "logs")) {
|
||||
EnableIonDebugAsyncLogging();
|
||||
} else if (IsFlag(found, "logs-sync")) {
|
||||
EnableIonDebugSyncLogging();
|
||||
} else if (IsFlag(found, "profiling")) {
|
||||
EnableChannel(JitSpew_Profiling);
|
||||
} else if (IsFlag(found, "trackopts")) {
|
||||
JitOptions.disableOptimizationTracking = false;
|
||||
EnableChannel(JitSpew_OptimizationTracking);
|
||||
} else if (IsFlag(found, "trackopts-ext")) {
|
||||
EnableChannel(JitSpew_OptimizationTrackingExtended);
|
||||
} else if (IsFlag(found, "dump-mir-expr")) {
|
||||
EnableChannel(JitSpew_MIRExpressions);
|
||||
} else if (IsFlag(found, "cfg")) {
|
||||
EnableChannel(JitSpew_CFG);
|
||||
} else if (IsFlag(found, "all")) {
|
||||
LoggingBits = uint64_t(-1);
|
||||
} else if (IsFlag(found, "bl-aborts")) {
|
||||
EnableChannel(JitSpew_BaselineAbort);
|
||||
} else if (IsFlag(found, "bl-scripts")) {
|
||||
EnableChannel(JitSpew_BaselineScripts);
|
||||
} else if (IsFlag(found, "bl-op")) {
|
||||
EnableChannel(JitSpew_BaselineOp);
|
||||
} else if (IsFlag(found, "bl-ic")) {
|
||||
EnableChannel(JitSpew_BaselineIC);
|
||||
} else if (IsFlag(found, "bl-ic-fb")) {
|
||||
EnableChannel(JitSpew_BaselineICFallback);
|
||||
} else if (IsFlag(found, "bl-osr")) {
|
||||
EnableChannel(JitSpew_BaselineOSR);
|
||||
} else if (IsFlag(found, "bl-bails")) {
|
||||
EnableChannel(JitSpew_BaselineBailouts);
|
||||
} else if (IsFlag(found, "bl-dbg-osr")) {
|
||||
EnableChannel(JitSpew_BaselineDebugModeOSR);
|
||||
} else if (IsFlag(found, "bl-all")) {
|
||||
EnableChannel(JitSpew_BaselineAbort);
|
||||
EnableChannel(JitSpew_BaselineScripts);
|
||||
EnableChannel(JitSpew_BaselineOp);
|
||||
EnableChannel(JitSpew_BaselineIC);
|
||||
EnableChannel(JitSpew_BaselineICFallback);
|
||||
EnableChannel(JitSpew_BaselineOSR);
|
||||
EnableChannel(JitSpew_BaselineBailouts);
|
||||
EnableChannel(JitSpew_BaselineDebugModeOSR);
|
||||
} else {
|
||||
fprintf(stderr, "Unknown flag.\n");
|
||||
PrintHelpAndExit(64);
|
||||
}
|
||||
found = strtok(nullptr, ",");
|
||||
}
|
||||
|
||||
FILE* spewfh = stderr;
|
||||
|
|
|
@ -135,6 +135,7 @@ class GraphSpewer {
|
|||
bool isSpewing() const { return graph_; }
|
||||
void init(MIRGraph* graph, JSScript* function);
|
||||
void beginFunction(JSScript* function);
|
||||
void beginWasmFunction(unsigned funcIndex);
|
||||
void spewPass(const char* pass);
|
||||
void spewPass(const char* pass, BacktrackingAllocator* ra);
|
||||
void endFunction();
|
||||
|
@ -143,6 +144,8 @@ class GraphSpewer {
|
|||
};
|
||||
|
||||
void SpewBeginFunction(MIRGenerator* mir, JSScript* function);
|
||||
void SpewBeginWasmFunction(MIRGenerator* mir, unsigned funcIndex);
|
||||
|
||||
class AutoSpewEndFunction {
|
||||
private:
|
||||
MIRGenerator* mir_;
|
||||
|
@ -202,6 +205,7 @@ class GraphSpewer {
|
|||
};
|
||||
|
||||
static inline void SpewBeginFunction(MIRGenerator* mir, JSScript* function) {}
|
||||
static inline void SpewBeginWasmFunction(MIRGenerator* mir, unsigned funcIndex) {}
|
||||
|
||||
class AutoSpewEndFunction {
|
||||
public:
|
||||
|
|
|
@ -202,6 +202,15 @@ void LIRGenerator::visitNewTypedArrayDynamicLength(
|
|||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void LIRGenerator::visitNewTypedArrayFromArray(MNewTypedArrayFromArray* ins) {
|
||||
MDefinition* array = ins->array();
|
||||
MOZ_ASSERT(array->type() == MIRType::Object);
|
||||
|
||||
auto* lir = new (alloc()) LNewTypedArrayFromArray(useRegisterAtStart(array));
|
||||
defineReturn(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void LIRGenerator::visitNewObject(MNewObject* ins) {
|
||||
LNewObject* lir = new (alloc()) LNewObject(temp());
|
||||
define(lir, ins);
|
||||
|
@ -4132,6 +4141,10 @@ void LIRGenerator::visitIsTypedArray(MIsTypedArray* ins) {
|
|||
|
||||
auto* lir = new (alloc()) LIsTypedArray(useRegister(ins->value()));
|
||||
define(lir, ins);
|
||||
|
||||
if (ins->isPossiblyWrapped()) {
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
}
|
||||
|
||||
void LIRGenerator::visitIsCallable(MIsCallable* ins) {
|
||||
|
|
|
@ -361,6 +361,8 @@ IonBuilder::InliningResult IonBuilder::inlineNativeCall(CallInfo& callInfo,
|
|||
// TypedArray intrinsics.
|
||||
case InlinableNative::TypedArrayConstructor:
|
||||
return inlineTypedArray(callInfo, target->native());
|
||||
case InlinableNative::IntrinsicIsTypedArrayConstructor:
|
||||
return inlineIsTypedArrayConstructor(callInfo);
|
||||
case InlinableNative::IntrinsicIsTypedArray:
|
||||
return inlineIsTypedArray(callInfo);
|
||||
case InlinableNative::IntrinsicIsPossiblyWrappedTypedArray:
|
||||
|
@ -2929,19 +2931,11 @@ IonBuilder::InliningResult IonBuilder::inlineTypedArray(CallInfo& callInfo,
|
|||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
MDefinition* arg = callInfo.getArg(0);
|
||||
|
||||
if (arg->type() != MIRType::Int32) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
JSObject* templateObject = inspector->getTemplateObjectForNative(pc, native);
|
||||
|
||||
if (!templateObject) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeNoTemplateObj);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(templateObject->is<TypedArrayObject>());
|
||||
TypedArrayObject* obj = &templateObject->as<TypedArrayObject>();
|
||||
|
||||
|
@ -2951,41 +2945,96 @@ IonBuilder::InliningResult IonBuilder::inlineTypedArray(CallInfo& callInfo,
|
|||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
MInstruction* ins = nullptr;
|
||||
MDefinition* arg = callInfo.getArg(0);
|
||||
MInstruction* ins;
|
||||
if (arg->type() == MIRType::Int32) {
|
||||
if (!arg->isConstant()) {
|
||||
ins = MNewTypedArrayDynamicLength::New(
|
||||
alloc(), constraints(), templateObject,
|
||||
templateObject->group()->initialHeap(constraints()), arg);
|
||||
} else {
|
||||
// Negative lengths must throw a RangeError. (We don't track that this
|
||||
// might have previously thrown, when determining whether to inline, so we
|
||||
// have to deal with this error case when inlining.)
|
||||
int32_t providedLen = arg->maybeConstantValue()->toInt32();
|
||||
if (providedLen <= 0) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
if (!arg->isConstant()) {
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
ins = MNewTypedArrayDynamicLength::New(
|
||||
uint32_t len = AssertedCast<uint32_t>(providedLen);
|
||||
if (obj->length() != len) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
MConstant* templateConst =
|
||||
MConstant::NewConstraintlessObject(alloc(), obj);
|
||||
current->add(templateConst);
|
||||
ins = MNewTypedArray::New(alloc(), constraints(), templateConst,
|
||||
obj->group()->initialHeap(constraints()));
|
||||
}
|
||||
} else if (arg->type() == MIRType::Object) {
|
||||
TemporaryTypeSet* types = arg->resultTypeSet();
|
||||
if (!types) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
// Don't inline if the argument is a, possibly wrapped, ArrayBuffer or
|
||||
// SharedArrayBuffer object.
|
||||
auto IsPossiblyWrappedArrayBufferMaybeSharedClass = [](const Class* clasp) {
|
||||
return clasp->isProxy() || clasp == &ArrayBufferObject::class_ ||
|
||||
clasp == &SharedArrayBufferObject::class_;
|
||||
};
|
||||
auto result = types->forAllClasses(
|
||||
constraints(), IsPossiblyWrappedArrayBufferMaybeSharedClass);
|
||||
if (result != TemporaryTypeSet::ForAllResult::ALL_FALSE) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
ins = MNewTypedArrayFromArray::New(
|
||||
alloc(), constraints(), templateObject,
|
||||
templateObject->group()->initialHeap(constraints()), arg);
|
||||
} else {
|
||||
// Negative lengths must throw a RangeError. (We don't track that this
|
||||
// might have previously thrown, when determining whether to inline, so we
|
||||
// have to deal with this error case when inlining.)
|
||||
int32_t providedLen = arg->maybeConstantValue()->toInt32();
|
||||
if (providedLen <= 0) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
uint32_t len = AssertedCast<uint32_t>(providedLen);
|
||||
|
||||
if (obj->length() != len) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), obj);
|
||||
current->add(templateConst);
|
||||
ins = MNewTypedArray::New(alloc(), constraints(), templateConst,
|
||||
obj->group()->initialHeap(constraints()));
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
MOZ_TRY(resumeAfter(ins));
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningResult IonBuilder::inlineIsTypedArrayConstructor(
|
||||
CallInfo& callInfo) {
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 1);
|
||||
|
||||
if (getInlineReturnType() != MIRType::Boolean) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
if (callInfo.getArg(0)->type() != MIRType::Object) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
// Try inlining with a constant if the argument is definitely a TypedArray
|
||||
// constructor.
|
||||
TemporaryTypeSet* types = callInfo.getArg(0)->resultTypeSet();
|
||||
if (!types || types->unknownObject() || types->getObjectCount() == 0) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
for (unsigned i = 0; i < types->getObjectCount(); i++) {
|
||||
JSObject* singleton = types->getSingleton(i);
|
||||
if (!singleton || !IsTypedArrayConstructor(singleton)) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
}
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
|
||||
pushConstant(BooleanValue(true));
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningResult IonBuilder::inlineIsTypedArrayHelper(
|
||||
CallInfo& callInfo, WrappingBehavior wrappingBehavior) {
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
|
@ -3008,8 +3057,7 @@ IonBuilder::InliningResult IonBuilder::inlineIsTypedArrayHelper(
|
|||
|
||||
// Wrapped typed arrays won't appear to be typed arrays per a
|
||||
// |forAllClasses| query. If wrapped typed arrays are to be considered
|
||||
// typed arrays, a negative answer is not conclusive. Don't inline in
|
||||
// that case.
|
||||
// typed arrays, a negative answer is not conclusive.
|
||||
auto isPossiblyWrapped = [this, wrappingBehavior, types]() {
|
||||
if (wrappingBehavior != AllowWrappedTypedArrays) {
|
||||
return false;
|
||||
|
@ -3028,9 +3076,11 @@ IonBuilder::InliningResult IonBuilder::inlineIsTypedArrayHelper(
|
|||
|
||||
bool result = false;
|
||||
bool isConstant = true;
|
||||
bool possiblyWrapped = false;
|
||||
switch (types->forAllClasses(constraints(), IsTypedArrayClass)) {
|
||||
case TemporaryTypeSet::ForAllResult::ALL_FALSE:
|
||||
if (isPossiblyWrapped()) {
|
||||
// Don't inline if we never saw typed arrays, but always only proxies.
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
|
@ -3045,20 +3095,22 @@ IonBuilder::InliningResult IonBuilder::inlineIsTypedArrayHelper(
|
|||
break;
|
||||
|
||||
case TemporaryTypeSet::ForAllResult::MIXED:
|
||||
if (isPossiblyWrapped()) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
isConstant = false;
|
||||
possiblyWrapped = isPossiblyWrapped();
|
||||
break;
|
||||
}
|
||||
|
||||
if (isConstant) {
|
||||
pushConstant(BooleanValue(result));
|
||||
} else {
|
||||
auto* ins = MIsTypedArray::New(alloc(), callInfo.getArg(0));
|
||||
auto* ins =
|
||||
MIsTypedArray::New(alloc(), callInfo.getArg(0), possiblyWrapped);
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
|
||||
if (possiblyWrapped) {
|
||||
MOZ_TRY(resumeAfter(ins));
|
||||
}
|
||||
}
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
|
@ -4052,6 +4104,8 @@ IonBuilder::InliningResult IonBuilder::inlineWasmCall(CallInfo& callInfo,
|
|||
current->push(call);
|
||||
current->add(call);
|
||||
|
||||
MOZ_TRY(resumeAfter(call));
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
|
||||
return InliningStatus_Inlined;
|
||||
|
|
|
@ -2138,12 +2138,10 @@ class MNewTypedArrayDynamicLength : public MUnaryInstruction,
|
|||
: MUnaryInstruction(classOpcode, length),
|
||||
templateObject_(templateObject),
|
||||
initialHeap_(initialHeap) {
|
||||
MOZ_ASSERT(!templateObject->isSingleton());
|
||||
setGuard(); // Need to throw if length is negative.
|
||||
setResultType(MIRType::Object);
|
||||
if (!templateObject->isSingleton()) {
|
||||
setResultTypeSet(
|
||||
MakeSingletonTypeSet(alloc, constraints, templateObject));
|
||||
}
|
||||
setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, templateObject));
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -2161,6 +2159,40 @@ class MNewTypedArrayDynamicLength : public MUnaryInstruction,
|
|||
}
|
||||
};
|
||||
|
||||
// Create a new TypedArray from an Array (or Array-like object) or a TypedArray.
|
||||
class MNewTypedArrayFromArray : public MUnaryInstruction,
|
||||
public SingleObjectPolicy::Data {
|
||||
CompilerObject templateObject_;
|
||||
gc::InitialHeap initialHeap_;
|
||||
|
||||
MNewTypedArrayFromArray(TempAllocator& alloc,
|
||||
CompilerConstraintList* constraints,
|
||||
JSObject* templateObject, gc::InitialHeap initialHeap,
|
||||
MDefinition* array)
|
||||
: MUnaryInstruction(classOpcode, array),
|
||||
templateObject_(templateObject),
|
||||
initialHeap_(initialHeap) {
|
||||
MOZ_ASSERT(!templateObject->isSingleton());
|
||||
setGuard(); // Can throw during construction.
|
||||
setResultType(MIRType::Object);
|
||||
setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, templateObject));
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(NewTypedArrayFromArray)
|
||||
TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
|
||||
|
||||
MDefinition* array() const { return getOperand(0); }
|
||||
JSObject* templateObject() const { return templateObject_; }
|
||||
gc::InitialHeap initialHeap() const { return initialHeap_; }
|
||||
|
||||
bool appendRoots(MRootList& roots) const override {
|
||||
return roots.append(templateObject_);
|
||||
}
|
||||
|
||||
bool possiblyCalls() const override { return true; }
|
||||
};
|
||||
|
||||
class MNewObject : public MUnaryInstruction, public NoTypePolicy::Data {
|
||||
public:
|
||||
enum Mode { ObjectLiteral, ObjectCreate };
|
||||
|
@ -10727,10 +10759,19 @@ class MIsArray : public MUnaryInstruction,
|
|||
|
||||
class MIsTypedArray : public MUnaryInstruction,
|
||||
public SingleObjectPolicy::Data {
|
||||
explicit MIsTypedArray(MDefinition* value)
|
||||
: MUnaryInstruction(classOpcode, value) {
|
||||
bool possiblyWrapped_;
|
||||
|
||||
explicit MIsTypedArray(MDefinition* value, bool possiblyWrapped)
|
||||
: MUnaryInstruction(classOpcode, value),
|
||||
possiblyWrapped_(possiblyWrapped) {
|
||||
setResultType(MIRType::Boolean);
|
||||
setMovable();
|
||||
|
||||
if (possiblyWrapped) {
|
||||
// Proxy checks may throw, so we're neither removable nor movable.
|
||||
setGuard();
|
||||
} else {
|
||||
setMovable();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -10738,6 +10779,7 @@ class MIsTypedArray : public MUnaryInstruction,
|
|||
TRIVIAL_NEW_WRAPPERS
|
||||
NAMED_OPERANDS((0, value))
|
||||
|
||||
bool isPossiblyWrapped() const { return possiblyWrapped_; }
|
||||
AliasSet getAliasSet() const override { return AliasSet::None(); }
|
||||
};
|
||||
|
||||
|
|
|
@ -1797,6 +1797,17 @@ MOZ_MUST_USE bool TrySkipAwait(JSContext* cx, HandleValue val,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool IsPossiblyWrappedTypedArray(JSContext* cx, JSObject* obj, bool* result) {
|
||||
JSObject* unwrapped = CheckedUnwrap(obj);
|
||||
if (!unwrapped) {
|
||||
ReportAccessDenied(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
*result = unwrapped->is<TypedArrayObject>();
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*ProxyGetPropertyFn)(JSContext*, HandleObject, HandleId,
|
||||
MutableHandleValue);
|
||||
const VMFunction ProxyGetPropertyInfo =
|
||||
|
|
|
@ -1182,6 +1182,8 @@ bool DoConcatStringObject(JSContext* cx, HandleValue lhs, HandleValue rhs,
|
|||
MOZ_MUST_USE bool TrySkipAwait(JSContext* cx, HandleValue val,
|
||||
MutableHandleValue resolved);
|
||||
|
||||
bool IsPossiblyWrappedTypedArray(JSContext* cx, JSObject* obj, bool* result);
|
||||
|
||||
// VMFunctions shared by JITs
|
||||
extern const VMFunction SetArrayLengthInfo;
|
||||
extern const VMFunction SetObjectElementInfo;
|
||||
|
|
|
@ -48,7 +48,7 @@ class LBinaryMath : public LInstructionHelper<1, 2 + ExtraUses, Temps> {
|
|||
//
|
||||
// Note: LSafepoints are 1:1 with LOsiPoints, so it holds a reference to the
|
||||
// corresponding LSafepoint to inform it of the LOsiPoint's masm offset when it
|
||||
// gets CG'd.
|
||||
// gets GC'd.
|
||||
class LOsiPoint : public LInstructionHelper<0, 0, 0> {
|
||||
LSafepoint* safepoint_;
|
||||
|
||||
|
@ -386,6 +386,22 @@ class LNewTypedArrayDynamicLength : public LInstructionHelper<1, 1, 1> {
|
|||
}
|
||||
};
|
||||
|
||||
class LNewTypedArrayFromArray : public LCallInstructionHelper<1, 1, 0> {
|
||||
public:
|
||||
LIR_HEADER(NewTypedArrayFromArray)
|
||||
|
||||
explicit LNewTypedArrayFromArray(const LAllocation& array)
|
||||
: LCallInstructionHelper(classOpcode) {
|
||||
setOperand(0, array);
|
||||
}
|
||||
|
||||
const LAllocation* array() { return getOperand(0); }
|
||||
|
||||
MNewTypedArrayFromArray* mir() const {
|
||||
return mir_->toNewTypedArrayFromArray();
|
||||
}
|
||||
};
|
||||
|
||||
class LNewObject : public LInstructionHelper<1, 0, 1> {
|
||||
public:
|
||||
LIR_HEADER(NewObject)
|
||||
|
@ -6070,6 +6086,7 @@ class LIsTypedArray : public LInstructionHelper<1, 1, 0> {
|
|||
setOperand(0, object);
|
||||
}
|
||||
const LAllocation* object() { return getOperand(0); }
|
||||
MIsTypedArray* mir() const { return mir_->toIsTypedArray(); }
|
||||
};
|
||||
|
||||
class LIsObject : public LInstructionHelper<1, BOX_PIECES, 0> {
|
||||
|
|
|
@ -872,7 +872,7 @@ JS_PUBLIC_API bool JS_ResolveStandardClass(JSContext* cx, HandleObject obj,
|
|||
JSProtoKey key = stdnm ? stdnm->key : JSProto_Null;
|
||||
if (key != JSProto_Null) {
|
||||
const Class* clasp = ProtoKeyToClass(key);
|
||||
if (!clasp || !(clasp->flags & JSCLASS_IS_ANONYMOUS)) {
|
||||
if (!clasp || clasp->specShouldDefineConstructor()) {
|
||||
if (!GlobalObject::ensureConstructor(cx, global, key)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -947,9 +947,6 @@ static bool EnumerateStandardClassesInTable(JSContext* cx,
|
|||
}
|
||||
|
||||
if (const Class* clasp = ProtoKeyToClass(key)) {
|
||||
if (clasp->flags & JSCLASS_IS_ANONYMOUS) {
|
||||
continue;
|
||||
}
|
||||
if (!clasp->specShouldDefineConstructor()) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -1260,3 +1260,7 @@ skip script test262/harness/detachArrayBuffer.js
|
|||
# https://github.com/tc39/test262/pull/1965
|
||||
skip script test262/language/expressions/dynamic-import/indirect-resolution.js
|
||||
skip script test262/language/expressions/dynamic-import/namespace/default-property-not-set-own.js
|
||||
|
||||
# https://github.com/tc39/test262/pull/2023
|
||||
skip script test262/language/statements/try/early-catch-var.js
|
||||
skip script test262/language/eval-code/direct/var-env-lower-lex-catch-non-strict.js
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
// |reftest| skip-if(!xulRuntime.shell)
|
||||
|
||||
assertThrowsInstanceOf(() => evaluate(`
|
||||
evaluate(`
|
||||
try { throw null; } catch (e) { eval("for (var e of []) {}") }
|
||||
`), SyntaxError);
|
||||
`);
|
||||
|
||||
assertThrowsInstanceOf(new Function(`
|
||||
new Function(`
|
||||
try { throw null; } catch (e) { eval("for (var e of []) {}") }
|
||||
`), SyntaxError);
|
||||
`)();
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
|
|
@ -82,6 +82,14 @@ function h1() {
|
|||
}
|
||||
h1();
|
||||
|
||||
// Tests that var declaration is allowed in for-of head.
|
||||
function h2() {
|
||||
try {} catch (e) {
|
||||
for (var e of {});
|
||||
}
|
||||
}
|
||||
h2();
|
||||
|
||||
// Tests that redeclaring a var inside the catch is allowed.
|
||||
function h3() {
|
||||
var e;
|
||||
|
@ -91,16 +99,6 @@ function h3() {
|
|||
}
|
||||
h3();
|
||||
|
||||
// Tests that var declaration is not allowed in for-of head.
|
||||
assertThrowsInstanceOf(function () {
|
||||
eval(`
|
||||
function h2() {
|
||||
try {} catch (e) { for (var e of {}); }
|
||||
}
|
||||
log += 'unreached';
|
||||
`);
|
||||
}, SyntaxError);
|
||||
|
||||
if (typeof evaluate === "function") {
|
||||
assertThrowsInstanceOf(function () {
|
||||
evaluate(`
|
||||
|
|
|
@ -222,8 +222,7 @@ CallObject* CallObject::createHollowForDebug(JSContext* cx,
|
|||
}
|
||||
|
||||
const Class CallObject::class_ = {
|
||||
"Call", JSCLASS_IS_ANONYMOUS |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(CallObject::RESERVED_SLOTS)};
|
||||
"Call", JSCLASS_HAS_RESERVED_SLOTS(CallObject::RESERVED_SLOTS)};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
@ -318,8 +317,7 @@ const Class CallObject::class_ = {
|
|||
}
|
||||
|
||||
const Class VarEnvironmentObject::class_ = {
|
||||
"Var", JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_RESERVED_SLOTS(
|
||||
VarEnvironmentObject::RESERVED_SLOTS)};
|
||||
"Var", JSCLASS_HAS_RESERVED_SLOTS(VarEnvironmentObject::RESERVED_SLOTS)};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
@ -342,8 +340,7 @@ const ClassOps ModuleEnvironmentObject::classOps_ = {
|
|||
|
||||
const Class ModuleEnvironmentObject::class_ = {
|
||||
"ModuleEnvironmentObject",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(ModuleEnvironmentObject::RESERVED_SLOTS) |
|
||||
JSCLASS_IS_ANONYMOUS,
|
||||
JSCLASS_HAS_RESERVED_SLOTS(ModuleEnvironmentObject::RESERVED_SLOTS),
|
||||
&ModuleEnvironmentObject::classOps_,
|
||||
JS_NULL_CLASS_SPEC,
|
||||
JS_NULL_CLASS_EXT,
|
||||
|
@ -554,8 +551,7 @@ void ModuleEnvironmentObject::fixEnclosingEnvironmentAfterCompartmentMerge(
|
|||
|
||||
const Class WasmInstanceEnvironmentObject::class_ = {
|
||||
"WasmInstance",
|
||||
JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_RESERVED_SLOTS(
|
||||
WasmInstanceEnvironmentObject::RESERVED_SLOTS)};
|
||||
JSCLASS_HAS_RESERVED_SLOTS(WasmInstanceEnvironmentObject::RESERVED_SLOTS)};
|
||||
|
||||
/* static */ WasmInstanceEnvironmentObject*
|
||||
WasmInstanceEnvironmentObject::createHollowForDebug(
|
||||
|
@ -591,8 +587,7 @@ WasmInstanceEnvironmentObject::createHollowForDebug(
|
|||
|
||||
const Class WasmFunctionCallObject::class_ = {
|
||||
"WasmCall",
|
||||
JSCLASS_IS_ANONYMOUS |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(WasmFunctionCallObject::RESERVED_SLOTS)};
|
||||
JSCLASS_HAS_RESERVED_SLOTS(WasmFunctionCallObject::RESERVED_SLOTS)};
|
||||
|
||||
/* static */ WasmFunctionCallObject*
|
||||
WasmFunctionCallObject::createHollowForDebug(JSContext* cx,
|
||||
|
@ -791,8 +786,7 @@ static const ObjectOps WithEnvironmentObjectOps = {
|
|||
|
||||
const Class WithEnvironmentObject::class_ = {
|
||||
"With",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(WithEnvironmentObject::RESERVED_SLOTS) |
|
||||
JSCLASS_IS_ANONYMOUS,
|
||||
JSCLASS_HAS_RESERVED_SLOTS(WithEnvironmentObject::RESERVED_SLOTS),
|
||||
JS_NULL_CLASS_OPS,
|
||||
JS_NULL_CLASS_SPEC,
|
||||
JS_NULL_CLASS_EXT,
|
||||
|
@ -818,8 +812,7 @@ const Class WithEnvironmentObject::class_ = {
|
|||
|
||||
const Class NonSyntacticVariablesObject::class_ = {
|
||||
"NonSyntacticVariablesObject",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(NonSyntacticVariablesObject::RESERVED_SLOTS) |
|
||||
JSCLASS_IS_ANONYMOUS};
|
||||
JSCLASS_HAS_RESERVED_SLOTS(NonSyntacticVariablesObject::RESERVED_SLOTS)};
|
||||
|
||||
bool js::CreateNonSyntacticEnvironmentChain(JSContext* cx,
|
||||
AutoObjectVector& envChain,
|
||||
|
@ -1069,8 +1062,7 @@ void LexicalEnvironmentObject::setWindowProxyThisValue(JSObject* obj) {
|
|||
|
||||
const Class LexicalEnvironmentObject::class_ = {
|
||||
"LexicalEnvironment",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(LexicalEnvironmentObject::RESERVED_SLOTS) |
|
||||
JSCLASS_IS_ANONYMOUS,
|
||||
JSCLASS_HAS_RESERVED_SLOTS(LexicalEnvironmentObject::RESERVED_SLOTS),
|
||||
JS_NULL_CLASS_OPS,
|
||||
JS_NULL_CLASS_SPEC,
|
||||
JS_NULL_CLASS_EXT,
|
||||
|
@ -1211,8 +1203,7 @@ static const ObjectOps RuntimeLexicalErrorObjectObjectOps = {
|
|||
|
||||
const Class RuntimeLexicalErrorObject::class_ = {
|
||||
"RuntimeLexicalError",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(RuntimeLexicalErrorObject::RESERVED_SLOTS) |
|
||||
JSCLASS_IS_ANONYMOUS,
|
||||
JSCLASS_HAS_RESERVED_SLOTS(RuntimeLexicalErrorObject::RESERVED_SLOTS),
|
||||
JS_NULL_CLASS_OPS,
|
||||
JS_NULL_CLASS_SPEC,
|
||||
JS_NULL_CLASS_EXT,
|
||||
|
|
|
@ -348,8 +348,7 @@ TypedObjectModuleObject& js::GlobalObject::getTypedObjectModule() const {
|
|||
}
|
||||
|
||||
const Class GlobalObject::OffThreadPlaceholderObject::class_ = {
|
||||
"off-thread-prototype-placeholder",
|
||||
JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_RESERVED_SLOTS(1)};
|
||||
"off-thread-prototype-placeholder", JSCLASS_HAS_RESERVED_SLOTS(1)};
|
||||
|
||||
/* static */ GlobalObject::OffThreadPlaceholderObject*
|
||||
GlobalObject::OffThreadPlaceholderObject::New(JSContext* cx, unsigned slot) {
|
||||
|
|
|
@ -2011,15 +2011,8 @@ static NativeObject* DefineConstructorAndPrototype(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// Attributes used when installing the constructor on |obj|.
|
||||
uint32_t propertyAttrs = 0;
|
||||
|
||||
RootedNativeObject ctor(cx);
|
||||
if (!constructor) {
|
||||
if (clasp->flags & JSCLASS_IS_ANONYMOUS) {
|
||||
propertyAttrs = JSPROP_READONLY | JSPROP_PERMANENT;
|
||||
}
|
||||
|
||||
ctor = proto;
|
||||
} else {
|
||||
ctor = NewNativeConstructor(cx, constructor, nargs, atom);
|
||||
|
@ -2040,7 +2033,7 @@ static NativeObject* DefineConstructorAndPrototype(
|
|||
|
||||
RootedId id(cx, AtomToId(atom));
|
||||
RootedValue value(cx, ObjectValue(*ctor));
|
||||
if (!DefineDataProperty(cx, obj, id, value, propertyAttrs)) {
|
||||
if (!DefineDataProperty(cx, obj, id, value, 0)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -1346,8 +1346,7 @@ static const ClassOps ScriptSourceObjectClassOps = {
|
|||
|
||||
const Class ScriptSourceObject::class_ = {
|
||||
"ScriptSource",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | JSCLASS_IS_ANONYMOUS |
|
||||
JSCLASS_FOREGROUND_FINALIZE,
|
||||
JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | JSCLASS_FOREGROUND_FINALIZE,
|
||||
&ScriptSourceObjectClassOps};
|
||||
|
||||
ScriptSourceObject* ScriptSourceObject::createInternal(JSContext* cx,
|
||||
|
|
|
@ -159,6 +159,39 @@ bool js::ForOfPIC::Chain::tryOptimizeArray(JSContext* cx,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool js::ForOfPIC::Chain::tryOptimizeArrayIteratorNext(JSContext* cx,
|
||||
bool* optimized) {
|
||||
MOZ_ASSERT(optimized);
|
||||
|
||||
*optimized = false;
|
||||
|
||||
if (!initialized_) {
|
||||
// If PIC is not initialized, initialize it.
|
||||
if (!initialize(cx)) {
|
||||
return false;
|
||||
}
|
||||
} else if (!disabled_ && !isArrayNextStillSane()) {
|
||||
// Otherwise, if array iterator state is no longer sane, reinitialize.
|
||||
reset();
|
||||
|
||||
if (!initialize(cx)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(initialized_);
|
||||
|
||||
// If PIC is disabled, don't bother trying to optimize.
|
||||
if (disabled_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// By the time we get here, we should have a sane iterator state to work with.
|
||||
MOZ_ASSERT(isArrayNextStillSane());
|
||||
|
||||
*optimized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool js::ForOfPIC::Chain::hasMatchingStub(ArrayObject* obj) {
|
||||
// Ensure PIC is initialized and not disabled.
|
||||
MOZ_ASSERT(initialized_ && !disabled_);
|
||||
|
@ -291,8 +324,8 @@ const Class ForOfPIC::class_ = {
|
|||
/* static */ NativeObject* js::ForOfPIC::createForOfPICObject(
|
||||
JSContext* cx, Handle<GlobalObject*> global) {
|
||||
cx->check(global);
|
||||
NativeObject* obj =
|
||||
NewNativeObjectWithGivenProto(cx, &ForOfPIC::class_, nullptr);
|
||||
NativeObject* obj = NewNativeObjectWithGivenProto(cx, &ForOfPIC::class_,
|
||||
nullptr, TenuredObject);
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -203,6 +203,13 @@ struct ForOfPIC {
|
|||
bool tryOptimizeArray(JSContext* cx, HandleArrayObject array,
|
||||
bool* optimized);
|
||||
|
||||
// Check if %ArrayIteratorPrototype% still uses the default "next" method.
|
||||
bool tryOptimizeArrayIteratorNext(JSContext* cx, bool* optimized);
|
||||
|
||||
void trace(JSTracer* trc);
|
||||
void sweep(FreeOp* fop);
|
||||
|
||||
private:
|
||||
// Check if the global array-related objects have not been messed with
|
||||
// in a way that would disable this PIC.
|
||||
bool isArrayStateStillSane();
|
||||
|
@ -215,10 +222,6 @@ struct ForOfPIC {
|
|||
canonicalNextFunc_);
|
||||
}
|
||||
|
||||
void trace(JSTracer* trc);
|
||||
void sweep(FreeOp* fop);
|
||||
|
||||
private:
|
||||
// Check if a matching optimized stub for the given object exists.
|
||||
bool hasMatchingStub(ArrayObject* obj);
|
||||
|
||||
|
|
|
@ -352,7 +352,7 @@ const ClassSpec SavedFrame::classSpec_ = {
|
|||
/* static */ const Class SavedFrame::class_ = {
|
||||
"SavedFrame",
|
||||
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SavedFrame::JSSLOT_COUNT) |
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_SavedFrame) | JSCLASS_IS_ANONYMOUS |
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_SavedFrame) |
|
||||
JSCLASS_FOREGROUND_FINALIZE,
|
||||
&SavedFrameClassOps, &SavedFrame::classSpec_};
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "vm/JSContext.h"
|
||||
#include "vm/JSFunction.h"
|
||||
#include "vm/JSObject.h"
|
||||
#include "vm/PIC.h"
|
||||
#include "vm/Printer.h"
|
||||
#include "vm/Realm.h"
|
||||
#include "vm/RegExpObject.h"
|
||||
|
@ -67,6 +68,7 @@
|
|||
#include "vm/NativeObject-inl.h"
|
||||
#include "vm/NumberObject-inl.h"
|
||||
#include "vm/StringObject-inl.h"
|
||||
#include "vm/TypedArrayObject-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::selfhosted;
|
||||
|
@ -796,6 +798,25 @@ bool js::intrinsic_NewArrayIterator(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool intrinsic_ArrayIteratorPrototypeOptimizable(JSContext* cx,
|
||||
unsigned argc,
|
||||
Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 0);
|
||||
|
||||
ForOfPIC::Chain* stubChain = ForOfPIC::getOrCreate(cx);
|
||||
if (!stubChain) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool optimized;
|
||||
if (!stubChain->tryOptimizeArrayIteratorNext(cx, &optimized)) {
|
||||
return false;
|
||||
}
|
||||
args.rval().setBoolean(optimized);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool intrinsic_GetNextMapEntryForIterator(JSContext* cx, unsigned argc,
|
||||
Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
@ -1068,6 +1089,16 @@ static bool intrinsic_GetTypedArrayKind(JSContext* cx, unsigned argc,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool intrinsic_IsTypedArrayConstructor(JSContext* cx, unsigned argc,
|
||||
Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 1);
|
||||
MOZ_ASSERT(args[0].isObject());
|
||||
|
||||
args.rval().setBoolean(js::IsTypedArrayConstructor(&args[0].toObject()));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool intrinsic_TypedArrayBuffer(JSContext* cx, unsigned argc,
|
||||
Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
@ -1705,6 +1736,43 @@ static bool intrinsic_TypedArrayBitwiseSlice(JSContext* cx, unsigned argc,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool intrinsic_TypedArrayInitFromPackedArray(JSContext* cx,
|
||||
unsigned argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 2);
|
||||
MOZ_ASSERT(args[0].isObject());
|
||||
MOZ_ASSERT(args[1].isObject());
|
||||
|
||||
Rooted<TypedArrayObject*> target(cx,
|
||||
&args[0].toObject().as<TypedArrayObject>());
|
||||
MOZ_ASSERT(!target->hasDetachedBuffer());
|
||||
MOZ_ASSERT(!target->isSharedMemory());
|
||||
|
||||
RootedArrayObject source(cx, &args[1].toObject().as<ArrayObject>());
|
||||
MOZ_ASSERT(IsPackedArray(source));
|
||||
MOZ_ASSERT(source->length() == target->length());
|
||||
|
||||
switch (target->type()) {
|
||||
#define INIT_TYPED_ARRAY(T, N) \
|
||||
case Scalar::N: { \
|
||||
if (!ElementSpecific<T, UnsharedOps>::initFromIterablePackedArray( \
|
||||
cx, target, source)) { \
|
||||
return false; \
|
||||
} \
|
||||
break; \
|
||||
}
|
||||
JS_FOR_EACH_TYPED_ARRAY(INIT_TYPED_ARRAY)
|
||||
#undef INIT_TYPED_ARRAY
|
||||
|
||||
default:
|
||||
MOZ_CRASH(
|
||||
"TypedArrayInitFromPackedArray with a typed array with bogus type");
|
||||
}
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool intrinsic_RegExpCreate(JSContext* cx, unsigned argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
|
@ -2121,24 +2189,6 @@ static bool intrinsic_ConstructorForTypedArray(JSContext* cx, unsigned argc,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool intrinsic_NameForTypedArray(JSContext* cx, unsigned argc,
|
||||
Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 1);
|
||||
MOZ_ASSERT(args[0].isObject());
|
||||
|
||||
auto* object = UnwrapAndDowncastValue<TypedArrayObject>(cx, args[0]);
|
||||
if (!object) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JSProtoKey protoKey = StandardProtoKeyOrNull(object);
|
||||
MOZ_ASSERT(protoKey);
|
||||
|
||||
args.rval().setString(ClassName(protoKey, cx));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool intrinsic_HostResolveImportedModule(JSContext* cx, unsigned argc,
|
||||
Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
@ -2428,7 +2478,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
JS_FN("MakeDefaultConstructor", intrinsic_MakeDefaultConstructor, 2, 0),
|
||||
JS_FN("_ConstructorForTypedArray", intrinsic_ConstructorForTypedArray, 1,
|
||||
0),
|
||||
JS_FN("_NameForTypedArray", intrinsic_NameForTypedArray, 1, 0),
|
||||
JS_FN("DecompileArg", intrinsic_DecompileArg, 2, 0),
|
||||
JS_INLINABLE_FN("_FinishBoundFunctionInit",
|
||||
intrinsic_FinishBoundFunctionInit, 3, 0,
|
||||
|
@ -2469,6 +2518,8 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
|
||||
JS_INLINABLE_FN("NewArrayIterator", intrinsic_NewArrayIterator, 0, 0,
|
||||
IntrinsicNewArrayIterator),
|
||||
JS_FN("ArrayIteratorPrototypeOptimizable",
|
||||
intrinsic_ArrayIteratorPrototypeOptimizable, 0, 0),
|
||||
|
||||
JS_FN("CallArrayIteratorMethodIfWrapped",
|
||||
CallNonGenericSelfhostedMethod<Is<ArrayIteratorObject>>, 2, 0),
|
||||
|
@ -2566,6 +2617,9 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
"IsPossiblyWrappedTypedArray",
|
||||
intrinsic_IsPossiblyWrappedInstanceOfBuiltin<TypedArrayObject>, 1, 0,
|
||||
IntrinsicIsPossiblyWrappedTypedArray),
|
||||
JS_INLINABLE_FN("IsTypedArrayConstructor",
|
||||
intrinsic_IsTypedArrayConstructor, 1, 0,
|
||||
IntrinsicIsTypedArrayConstructor),
|
||||
|
||||
JS_FN("TypedArrayBuffer", intrinsic_TypedArrayBuffer, 1, 0),
|
||||
JS_FN("TypedArrayByteOffset", intrinsic_TypedArrayByteOffset, 1, 0),
|
||||
|
@ -2591,6 +2645,9 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
|
||||
JS_FN("TypedArrayBitwiseSlice", intrinsic_TypedArrayBitwiseSlice, 4, 0),
|
||||
|
||||
JS_FN("TypedArrayInitFromPackedArray",
|
||||
intrinsic_TypedArrayInitFromPackedArray, 2, 0),
|
||||
|
||||
JS_FN("CallArrayBufferMethodIfWrapped",
|
||||
CallNonGenericSelfhostedMethod<Is<ArrayBufferObject>>, 2, 0),
|
||||
JS_FN("CallSharedArrayBufferMethodIfWrapped",
|
||||
|
|
|
@ -382,11 +382,26 @@ class TypedArrayObjectTemplate : public TypedArrayObject {
|
|||
|
||||
static TypedArrayObject* makeTypedInstance(JSContext* cx,
|
||||
CreateSingleton createSingleton,
|
||||
HandleObjectGroup group,
|
||||
gc::AllocKind allocKind) {
|
||||
if (createSingleton == CreateSingleton::Yes) {
|
||||
MOZ_ASSERT(!group);
|
||||
return newBuiltinClassInstance(cx, allocKind, SingletonObject);
|
||||
}
|
||||
|
||||
if (group) {
|
||||
MOZ_ASSERT(group->clasp() == instanceClass());
|
||||
NewObjectKind newKind = GenericObject;
|
||||
{
|
||||
AutoSweepObjectGroup sweep(group);
|
||||
if (group->shouldPreTenure(sweep)) {
|
||||
newKind = TenuredObject;
|
||||
}
|
||||
}
|
||||
return NewObjectWithGroup<TypedArrayObject>(cx, group, allocKind,
|
||||
newKind);
|
||||
}
|
||||
|
||||
jsbytecode* pc;
|
||||
RootedScript script(cx, cx->currentScript(&pc));
|
||||
Rooted<TypedArrayObject*> obj(
|
||||
|
@ -406,7 +421,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject {
|
|||
static TypedArrayObject* makeInstance(
|
||||
JSContext* cx, Handle<ArrayBufferObjectMaybeShared*> buffer,
|
||||
CreateSingleton createSingleton, uint32_t byteOffset, uint32_t len,
|
||||
HandleObject proto) {
|
||||
HandleObject proto, HandleObjectGroup group = nullptr) {
|
||||
MOZ_ASSERT(len < INT32_MAX / BYTES_PER_ELEMENT);
|
||||
|
||||
gc::AllocKind allocKind =
|
||||
|
@ -427,9 +442,10 @@ class TypedArrayObjectTemplate : public TypedArrayObject {
|
|||
AutoSetNewObjectMetadata metadata(cx);
|
||||
Rooted<TypedArrayObject*> obj(cx);
|
||||
if (proto && proto != checkProto) {
|
||||
MOZ_ASSERT(!group);
|
||||
obj = makeProtoInstance(cx, proto, allocKind);
|
||||
} else {
|
||||
obj = makeTypedInstance(cx, createSingleton, allocKind);
|
||||
obj = makeTypedInstance(cx, createSingleton, group, allocKind);
|
||||
}
|
||||
if (!obj || !obj->init(cx, buffer, byteOffset, len, BYTES_PER_ELEMENT)) {
|
||||
return nullptr;
|
||||
|
@ -446,6 +462,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject {
|
|||
bool fitsInline = nbytes <= INLINE_BUFFER_LIMIT;
|
||||
gc::AllocKind allocKind = !fitsInline ? gc::GetGCObjectKind(instanceClass())
|
||||
: AllocKindForLazyBuffer(nbytes);
|
||||
MOZ_ASSERT(allocKind >= gc::GetGCObjectKind(instanceClass()));
|
||||
|
||||
AutoSetNewObjectMetadata metadata(cx);
|
||||
jsbytecode* pc;
|
||||
|
@ -552,6 +569,15 @@ class TypedArrayObjectTemplate : public TypedArrayObject {
|
|||
return obj;
|
||||
}
|
||||
|
||||
static TypedArrayObject* makeTypedArrayWithTemplate(
|
||||
JSContext* cx, TypedArrayObject* templateObj, HandleObject array) {
|
||||
MOZ_ASSERT(!IsWrapper(array));
|
||||
MOZ_ASSERT(!array->is<ArrayBufferObjectMaybeShared>());
|
||||
|
||||
RootedObjectGroup group(cx, templateObj->group());
|
||||
return fromArray(cx, array, nullptr, group);
|
||||
}
|
||||
|
||||
// ES2018 draft rev 8340bf9a8427ea81bb0d1459471afbcc91d18add
|
||||
// 22.2.4.1 TypedArray ( )
|
||||
// 22.2.4.2 TypedArray ( length )
|
||||
|
@ -881,14 +907,17 @@ class TypedArrayObjectTemplate : public TypedArrayObject {
|
|||
uint32_t count,
|
||||
MutableHandle<ArrayBufferObject*> buffer);
|
||||
|
||||
static JSObject* fromArray(JSContext* cx, HandleObject other,
|
||||
HandleObject proto = nullptr);
|
||||
static TypedArrayObject* fromArray(JSContext* cx, HandleObject other,
|
||||
HandleObject proto = nullptr,
|
||||
HandleObjectGroup group = nullptr);
|
||||
|
||||
static JSObject* fromTypedArray(JSContext* cx, HandleObject other,
|
||||
bool isWrapped, HandleObject proto);
|
||||
static TypedArrayObject* fromTypedArray(JSContext* cx, HandleObject other,
|
||||
bool isWrapped, HandleObject proto,
|
||||
HandleObjectGroup group);
|
||||
|
||||
static JSObject* fromObject(JSContext* cx, HandleObject other,
|
||||
HandleObject proto);
|
||||
static TypedArrayObject* fromObject(JSContext* cx, HandleObject other,
|
||||
HandleObject proto,
|
||||
HandleObjectGroup group);
|
||||
|
||||
static const NativeType getIndex(TypedArrayObject* tarray, uint32_t index) {
|
||||
MOZ_ASSERT(index < tarray->length());
|
||||
|
@ -931,6 +960,24 @@ TypedArrayObject* js::TypedArrayCreateWithTemplate(JSContext* cx,
|
|||
}
|
||||
}
|
||||
|
||||
TypedArrayObject* js::TypedArrayCreateWithTemplate(JSContext* cx,
|
||||
HandleObject templateObj,
|
||||
HandleObject array) {
|
||||
MOZ_ASSERT(templateObj->is<TypedArrayObject>());
|
||||
TypedArrayObject* tobj = &templateObj->as<TypedArrayObject>();
|
||||
|
||||
switch (tobj->type()) {
|
||||
#define CREATE_TYPED_ARRAY(T, N) \
|
||||
case Scalar::N: \
|
||||
return TypedArrayObjectTemplate<T>::makeTypedArrayWithTemplate(cx, tobj, \
|
||||
array);
|
||||
JS_FOR_EACH_TYPED_ARRAY(CREATE_TYPED_ARRAY)
|
||||
#undef CREATE_TYPED_ARRAY
|
||||
default:
|
||||
MOZ_CRASH("Unsupported TypedArray type");
|
||||
}
|
||||
}
|
||||
|
||||
// ES2018 draft rev 2aea8f3e617b49df06414eb062ab44fad87661d3
|
||||
// 24.1.1.1 AllocateArrayBuffer ( constructor, byteLength )
|
||||
// byteLength = count * BYTES_PER_ELEMENT
|
||||
|
@ -1025,27 +1072,29 @@ static JSObject* GetBufferSpeciesConstructor(
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
/* static */ JSObject* TypedArrayObjectTemplate<T>::fromArray(
|
||||
JSContext* cx, HandleObject other, HandleObject proto /* = nullptr */) {
|
||||
/* static */ TypedArrayObject* TypedArrayObjectTemplate<T>::fromArray(
|
||||
JSContext* cx, HandleObject other, HandleObject proto /* = nullptr */,
|
||||
HandleObjectGroup group /* = nullptr */) {
|
||||
// Allow nullptr proto for FriendAPI methods, which don't care about
|
||||
// subclassing.
|
||||
if (other->is<TypedArrayObject>()) {
|
||||
return fromTypedArray(cx, other, /* wrapped= */ false, proto);
|
||||
return fromTypedArray(cx, other, /* wrapped= */ false, proto, group);
|
||||
}
|
||||
|
||||
if (other->is<WrapperObject>() &&
|
||||
UncheckedUnwrap(other)->is<TypedArrayObject>()) {
|
||||
return fromTypedArray(cx, other, /* wrapped= */ true, proto);
|
||||
return fromTypedArray(cx, other, /* wrapped= */ true, proto, group);
|
||||
}
|
||||
|
||||
return fromObject(cx, other, proto);
|
||||
return fromObject(cx, other, proto, group);
|
||||
}
|
||||
|
||||
// ES2018 draft rev 272beb67bc5cd9fd18a220665198384108208ee1
|
||||
// 22.2.4.3 TypedArray ( typedArray )
|
||||
template <typename T>
|
||||
/* static */ JSObject* TypedArrayObjectTemplate<T>::fromTypedArray(
|
||||
JSContext* cx, HandleObject other, bool isWrapped, HandleObject proto) {
|
||||
/* static */ TypedArrayObject* TypedArrayObjectTemplate<T>::fromTypedArray(
|
||||
JSContext* cx, HandleObject other, bool isWrapped, HandleObject proto,
|
||||
HandleObjectGroup group) {
|
||||
// Step 1.
|
||||
MOZ_ASSERT_IF(!isWrapped, other->is<TypedArrayObject>());
|
||||
MOZ_ASSERT_IF(isWrapped, other->is<WrapperObject>() &&
|
||||
|
@ -1123,8 +1172,8 @@ template <typename T>
|
|||
|
||||
// Steps 3-4 (remaining part), 20-23.
|
||||
Rooted<TypedArrayObject*> obj(
|
||||
cx,
|
||||
makeInstance(cx, buffer, CreateSingleton::No, 0, elementLength, proto));
|
||||
cx, makeInstance(cx, buffer, CreateSingleton::No, 0, elementLength, proto,
|
||||
group));
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1165,8 +1214,9 @@ static MOZ_ALWAYS_INLINE bool IsOptimizableInit(JSContext* cx,
|
|||
// ES2017 draft rev 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e
|
||||
// 22.2.4.4 TypedArray ( object )
|
||||
template <typename T>
|
||||
/* static */ JSObject* TypedArrayObjectTemplate<T>::fromObject(
|
||||
JSContext* cx, HandleObject other, HandleObject proto) {
|
||||
/* static */ TypedArrayObject* TypedArrayObjectTemplate<T>::fromObject(
|
||||
JSContext* cx, HandleObject other, HandleObject proto,
|
||||
HandleObjectGroup group) {
|
||||
// Steps 1-2 (Already performed in caller).
|
||||
|
||||
// Steps 3-4 (Allocation deferred until later).
|
||||
|
@ -1191,7 +1241,8 @@ template <typename T>
|
|||
}
|
||||
|
||||
Rooted<TypedArrayObject*> obj(
|
||||
cx, makeInstance(cx, buffer, CreateSingleton::No, 0, len, proto));
|
||||
cx,
|
||||
makeInstance(cx, buffer, CreateSingleton::No, 0, len, proto, group));
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1266,7 +1317,7 @@ template <typename T>
|
|||
}
|
||||
|
||||
Rooted<TypedArrayObject*> obj(
|
||||
cx, makeInstance(cx, buffer, CreateSingleton::No, 0, len, proto));
|
||||
cx, makeInstance(cx, buffer, CreateSingleton::No, 0, len, proto, group));
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1290,17 +1341,46 @@ bool TypedArrayConstructor(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static bool GetTemplateObjectForNative(JSContext* cx, HandleValue arg,
|
||||
MutableHandleObject res) {
|
||||
if (arg.isInt32()) {
|
||||
uint32_t len = 0;
|
||||
if (arg.toInt32() >= 0) {
|
||||
len = arg.toInt32();
|
||||
}
|
||||
|
||||
size_t nbytes;
|
||||
if (!js::CalculateAllocSize<T>(len, &nbytes)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (nbytes >= TypedArrayObject::SINGLETON_BYTE_LENGTH) {
|
||||
return true;
|
||||
}
|
||||
|
||||
res.set(TypedArrayObjectTemplate<T>::makeTemplateObject(cx, len));
|
||||
return !!res;
|
||||
}
|
||||
|
||||
if (arg.isObject() && !IsWrapper(&arg.toObject()) &&
|
||||
!arg.toObject().is<ArrayBufferObjectMaybeShared>()) {
|
||||
// We don't use the template's length in the object case, so we can create
|
||||
// the template typed array with an initial length of zero.
|
||||
uint32_t len = 0;
|
||||
res.set(TypedArrayObjectTemplate<T>::makeTemplateObject(cx, len));
|
||||
return !!res;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ bool TypedArrayObject::GetTemplateObjectForNative(
|
||||
JSContext* cx, Native native, uint32_t len, MutableHandleObject res) {
|
||||
#define CHECK_TYPED_ARRAY_CONSTRUCTOR(T, N) \
|
||||
if (native == &TypedArrayObjectTemplate<T>::class_constructor) { \
|
||||
size_t nbytes; \
|
||||
if (!js::CalculateAllocSize<T>(len, &nbytes)) return true; \
|
||||
\
|
||||
if (nbytes < TypedArrayObject::SINGLETON_BYTE_LENGTH) { \
|
||||
res.set(TypedArrayObjectTemplate<T>::makeTemplateObject(cx, len)); \
|
||||
return !!res; \
|
||||
} \
|
||||
JSContext* cx, Native native, HandleValue arg, MutableHandleObject res) {
|
||||
MOZ_ASSERT(!res);
|
||||
#define CHECK_TYPED_ARRAY_CONSTRUCTOR(T, N) \
|
||||
if (native == &TypedArrayObjectTemplate<T>::class_constructor) { \
|
||||
return ::GetTemplateObjectForNative<T>(cx, arg, res); \
|
||||
}
|
||||
JS_FOR_EACH_TYPED_ARRAY(CHECK_TYPED_ARRAY_CONSTRUCTOR)
|
||||
#undef CHECK_TYPED_ARRAY_CONSTRUCTOR
|
||||
|
@ -1328,6 +1408,38 @@ bool BufferGetterImpl(JSContext* cx, const CallArgs& args) {
|
|||
return CallNonGenericMethod<TypedArrayObject::is, BufferGetterImpl>(cx, args);
|
||||
}
|
||||
|
||||
// ES2019 draft rev fc9ecdcd74294d0ca3146d4b274e2a8e79565dc3
|
||||
// 22.2.3.32 get %TypedArray%.prototype [ @@toStringTag ]
|
||||
static bool TypedArray_toStringTagGetter(JSContext* cx, unsigned argc,
|
||||
Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
// Steps 1-2.
|
||||
if (!args.thisv().isObject()) {
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject* obj = CheckedUnwrap(&args.thisv().toObject());
|
||||
if (!obj) {
|
||||
ReportAccessDenied(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 3.
|
||||
if (!obj->is<TypedArrayObject>()) {
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Steps 4-6.
|
||||
JSProtoKey protoKey = StandardProtoKeyOrNull(obj);
|
||||
MOZ_ASSERT(protoKey);
|
||||
|
||||
args.rval().setString(ClassName(protoKey, cx));
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ const JSPropertySpec TypedArrayObject::protoAccessors[] = {
|
||||
JS_PSG("length", TypedArray_lengthGetter, 0),
|
||||
JS_PSG("buffer", TypedArray_bufferGetter, 0),
|
||||
|
@ -1335,7 +1447,7 @@ bool BufferGetterImpl(JSContext* cx, const CallArgs& args) {
|
|||
TypedArrayObject::Getter<TypedArrayObject::byteLengthValue>, 0),
|
||||
JS_PSG("byteOffset",
|
||||
TypedArrayObject::Getter<TypedArrayObject::byteOffsetValue>, 0),
|
||||
JS_SELF_HOSTED_SYM_GET(toStringTag, "TypedArrayToStringTag", 0),
|
||||
JS_SYM_GET(toStringTag, TypedArray_toStringTagGetter, 0),
|
||||
JS_PS_END};
|
||||
|
||||
template <typename T>
|
||||
|
@ -1858,6 +1970,16 @@ const Class TypedArrayObject::protoClasses[Scalar::MaxTypedArrayViewType] = {
|
|||
return native == TypedArray_lengthGetter;
|
||||
}
|
||||
|
||||
bool js::IsTypedArrayConstructor(const JSObject* obj) {
|
||||
#define CHECK_TYPED_ARRAY_CONSTRUCTOR(T, N) \
|
||||
if (IsNativeFunction(obj, N##Array::class_constructor)) { \
|
||||
return true; \
|
||||
}
|
||||
JS_FOR_EACH_TYPED_ARRAY(CHECK_TYPED_ARRAY_CONSTRUCTOR)
|
||||
#undef CHECK_TYPED_ARRAY_CONSTRUCTOR
|
||||
return false;
|
||||
}
|
||||
|
||||
bool js::IsTypedArrayConstructor(HandleValue v, uint32_t type) {
|
||||
switch (type) {
|
||||
case Scalar::Int8:
|
||||
|
|
|
@ -136,7 +136,8 @@ class TypedArrayObject : public ArrayBufferViewObject {
|
|||
void getElements(Value* vp);
|
||||
|
||||
static bool GetTemplateObjectForNative(JSContext* cx, Native native,
|
||||
uint32_t len, MutableHandleObject res);
|
||||
HandleValue arg,
|
||||
MutableHandleObject res);
|
||||
|
||||
/*
|
||||
* Byte length above which created typed arrays will have singleton types
|
||||
|
@ -191,6 +192,10 @@ extern TypedArrayObject* TypedArrayCreateWithTemplate(JSContext* cx,
|
|||
HandleObject templateObj,
|
||||
int32_t len);
|
||||
|
||||
extern TypedArrayObject* TypedArrayCreateWithTemplate(JSContext* cx,
|
||||
HandleObject templateObj,
|
||||
HandleObject array);
|
||||
|
||||
inline bool IsTypedArrayClass(const Class* clasp) {
|
||||
return &TypedArrayObject::classes[0] <= clasp &&
|
||||
clasp < &TypedArrayObject::classes[Scalar::MaxTypedArrayViewType];
|
||||
|
@ -201,6 +206,8 @@ inline Scalar::Type GetTypedArrayClassType(const Class* clasp) {
|
|||
return static_cast<Scalar::Type>(clasp - &TypedArrayObject::classes[0]);
|
||||
}
|
||||
|
||||
bool IsTypedArrayConstructor(const JSObject* obj);
|
||||
|
||||
bool IsTypedArrayConstructor(HandleValue v, uint32_t type);
|
||||
|
||||
// In WebIDL terminology, a BufferSource is either an ArrayBuffer or a typed
|
||||
|
|
|
@ -177,7 +177,7 @@ void WasmFrameIter::popFrame() {
|
|||
// | WASM FRAME | (already unwound)
|
||||
// |---------------------|
|
||||
//
|
||||
// The next value of FP is just a regular jit frame used marked to
|
||||
// The next value of FP is just a regular jit frame used as a marker to
|
||||
// know that we should transition to a JSJit frame iterator.
|
||||
unwoundIonCallerFP_ = (uint8_t*)fp_;
|
||||
unwoundIonFrameType_ = FrameType::JSJitToWasm;
|
||||
|
|
|
@ -4070,7 +4070,7 @@ bool wasm::IonCompileFunctions(const ModuleEnvironment& env, LifoAlloc& lifo,
|
|||
|
||||
// Compile MIR graph
|
||||
{
|
||||
jit::SpewBeginFunction(&mir, nullptr);
|
||||
jit::SpewBeginWasmFunction(&mir, func.index);
|
||||
jit::AutoSpewEndFunction spewEndFunction(&mir);
|
||||
|
||||
if (!OptimizeMIR(&mir)) {
|
||||
|
|
|
@ -82,7 +82,7 @@ fuzzy(0-1,0-10000) == opacity-preserve3d-4.html opacity-preserve3d-4-ref.html
|
|||
== opacity-preserve3d-5.html opacity-preserve3d-5-ref.html
|
||||
== snap-perspective-1.html snap-perspective-1-ref.html
|
||||
== mask-layer-1.html mask-layer-ref.html
|
||||
fuzzy-if(webrender&>kWidget,8-8,100-100) == mask-layer-2.html mask-layer-ref.html
|
||||
fuzzy-if(webrender&>kWidget,8-8,100-100) fuzzy-if(webrender&&cocoaWidget,1-1,16-16) == mask-layer-2.html mask-layer-ref.html
|
||||
fuzzy-if(webrender,0-16,0-100) == mask-layer-3.html mask-layer-ref.html
|
||||
== split-intersect1.html split-intersect1-ref.html
|
||||
fuzzy(0-255,0-150) == split-intersect2.html split-intersect2-ref.html
|
||||
|
|
|
@ -411,50 +411,52 @@ class RemoteArgumentsParser(ReftestArgumentsParser):
|
|||
type=str,
|
||||
dest="adb_path",
|
||||
default=None,
|
||||
help="path to adb")
|
||||
help="Path to adb binary.")
|
||||
|
||||
self.add_argument("--deviceSerial",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="deviceSerial",
|
||||
help="adb serial number of remote device to test")
|
||||
help="adb serial number of remote device. This is required "
|
||||
"when more than one device is connected to the host. "
|
||||
"Use 'adb devices' to see connected devices.")
|
||||
|
||||
self.add_argument("--remote-webserver",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="remoteWebServer",
|
||||
help="IP Address of the webserver hosting the reftest content")
|
||||
help="IP address of the remote web server.")
|
||||
|
||||
self.add_argument("--http-port",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="httpPort",
|
||||
help="port of the web server for http traffic")
|
||||
help="http port of the remote web server.")
|
||||
|
||||
self.add_argument("--ssl-port",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="sslPort",
|
||||
help="Port for https traffic to the web server")
|
||||
help="ssl port of the remote web server.")
|
||||
|
||||
self.add_argument("--remoteTestRoot",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="remoteTestRoot",
|
||||
help="remote directory to use as test root "
|
||||
"(eg. /mnt/sdcard/tests or /data/local/tests)")
|
||||
help="Remote directory to use as test root "
|
||||
"(eg. /mnt/sdcard/tests or /data/local/tests).")
|
||||
|
||||
self.add_argument("--httpd-path",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="httpdPath",
|
||||
help="path to the httpd.js file")
|
||||
help="Path to the httpd.js file.")
|
||||
|
||||
self.add_argument("--no-device-info",
|
||||
action="store_false",
|
||||
dest="printDeviceInfo",
|
||||
default=True,
|
||||
help="do not display verbose diagnostics about the remote device")
|
||||
help="Do not display verbose diagnostics about the remote device.")
|
||||
|
||||
def validate_remote(self, options, automation):
|
||||
if options.remoteWebServer is None:
|
||||
|
|
|
@ -849,7 +849,9 @@ class AndroidArguments(ArgumentContainer):
|
|||
args = [
|
||||
[["--deviceSerial"],
|
||||
{"dest": "deviceSerial",
|
||||
"help": "ip address of remote device to test",
|
||||
"help": "adb serial number of remote device. This is required "
|
||||
"when more than one device is connected to the host. "
|
||||
"Use 'adb devices' to see connected devices.",
|
||||
"default": None,
|
||||
}],
|
||||
[["--adbpath"],
|
||||
|
@ -861,42 +863,42 @@ class AndroidArguments(ArgumentContainer):
|
|||
[["--remote-webserver"],
|
||||
{"dest": "remoteWebServer",
|
||||
"default": None,
|
||||
"help": "ip address where the remote web server is hosted at",
|
||||
"help": "IP address of the remote web server.",
|
||||
}],
|
||||
[["--http-port"],
|
||||
{"dest": "httpPort",
|
||||
"default": DEFAULT_PORTS['http'],
|
||||
"help": "http port of the remote web server",
|
||||
"help": "http port of the remote web server.",
|
||||
"suppress": True,
|
||||
}],
|
||||
[["--ssl-port"],
|
||||
{"dest": "sslPort",
|
||||
"default": DEFAULT_PORTS['https'],
|
||||
"help": "ssl port of the remote web server",
|
||||
"help": "ssl port of the remote web server.",
|
||||
"suppress": True,
|
||||
}],
|
||||
[["--robocop-apk"],
|
||||
{"dest": "robocopApk",
|
||||
"default": "",
|
||||
"help": "name of the Robocop APK to use for ADB test running",
|
||||
"help": "Name of the robocop APK to use.",
|
||||
}],
|
||||
[["--remoteTestRoot"],
|
||||
{"dest": "remoteTestRoot",
|
||||
"default": None,
|
||||
"help": "remote directory to use as test root \
|
||||
(eg. /mnt/sdcard/tests or /data/local/tests)",
|
||||
"help": "Remote directory to use as test root "
|
||||
"(eg. /mnt/sdcard/tests or /data/local/tests).",
|
||||
"suppress": True,
|
||||
}],
|
||||
[["--enable-coverage"],
|
||||
{"action": "store_true",
|
||||
"default": False,
|
||||
"help": "Enable collecting code coverage information when running"
|
||||
"help": "Enable collecting code coverage information when running "
|
||||
"robocop tests.",
|
||||
}],
|
||||
[["--coverage-output-dir"],
|
||||
{"action": "store",
|
||||
"default": None,
|
||||
"help": "When using --enable-java-coverage, save the code coverage report"
|
||||
"help": "When using --enable-java-coverage, save the code coverage report "
|
||||
"files to this directory.",
|
||||
}],
|
||||
]
|
||||
|
|
|
@ -333,12 +333,14 @@ class JunitArgumentParser(argparse.ArgumentParser):
|
|||
type=str,
|
||||
dest="adbPath",
|
||||
default=None,
|
||||
help="Path to adb executable.")
|
||||
help="Path to adb binary.")
|
||||
self.add_argument("--deviceSerial",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="deviceSerial",
|
||||
help="adb serial number of remote device.")
|
||||
help="adb serial number of remote device. This is required "
|
||||
"when more than one device is connected to the host. "
|
||||
"Use 'adb devices' to see connected devices. ")
|
||||
self.add_argument("--remoteTestRoot",
|
||||
action="store",
|
||||
type=str,
|
||||
|
@ -410,18 +412,18 @@ class JunitArgumentParser(argparse.ArgumentParser):
|
|||
type=str,
|
||||
dest="httpPort",
|
||||
default=DEFAULT_PORTS['http'],
|
||||
help="Port of the web server for http traffic.")
|
||||
help="http port of the remote web server.")
|
||||
self.add_argument("--remote-webserver",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="remoteWebServer",
|
||||
help="IP address of the webserver.")
|
||||
help="IP address of the remote web server.")
|
||||
self.add_argument("--ssl-port",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="sslPort",
|
||||
default=DEFAULT_PORTS['https'],
|
||||
help="Port of the web server for https traffic.")
|
||||
help="ssl port of the remote web server.")
|
||||
# Remaining arguments are test filters.
|
||||
self.add_argument("test_filters",
|
||||
nargs="*",
|
||||
|
|
|
@ -171,39 +171,43 @@ class RemoteCPPUnittestOptions(cppunittests.CPPUnittestOptions):
|
|||
|
||||
self.add_option("--deviceSerial", action="store",
|
||||
type="string", dest="device_serial",
|
||||
help="serial ID of device")
|
||||
help="adb serial number of remote device. This is required "
|
||||
"when more than one device is connected to the host. "
|
||||
"Use 'adb devices' to see connected devices.")
|
||||
defaults["device_serial"] = None
|
||||
|
||||
self.add_option("--adbPath", action="store",
|
||||
type="string", dest="adb_path",
|
||||
help="Path to adb")
|
||||
help="Path to adb binary.")
|
||||
defaults["adb_path"] = None
|
||||
|
||||
self.add_option("--noSetup", action="store_false",
|
||||
dest="setup",
|
||||
help="do not copy any files to device (to be used only if "
|
||||
"device is already setup)")
|
||||
help="Do not copy any files to device (to be used only if "
|
||||
"device is already setup).")
|
||||
defaults["setup"] = True
|
||||
|
||||
self.add_option("--localLib", action="store",
|
||||
type="string", dest="local_lib",
|
||||
help="location of libraries to push -- preferably stripped")
|
||||
help="Location of libraries to push -- preferably stripped.")
|
||||
defaults["local_lib"] = None
|
||||
|
||||
self.add_option("--apk", action="store",
|
||||
type="string", dest="local_apk",
|
||||
help="local path to Fennec APK")
|
||||
help="Local path to Firefox for Android APK.")
|
||||
defaults["local_apk"] = None
|
||||
|
||||
self.add_option("--localBinDir", action="store",
|
||||
type="string", dest="local_bin",
|
||||
help="local path to bin directory")
|
||||
help="Local path to bin directory.")
|
||||
defaults[
|
||||
"local_bin"] = build_obj.bindir if build_obj is not None else None
|
||||
|
||||
self.add_option("--remoteTestRoot", action="store",
|
||||
type="string", dest="remote_test_root",
|
||||
help="remote directory to use as test root (eg. /data/local/tests)")
|
||||
help="Remote directory to use as test root "
|
||||
"(eg. /mnt/sdcard/tests or /data/local/tests).")
|
||||
|
||||
# /data/local/tests is used because it is usually not possible to set +x permissions
|
||||
# on binaries on /mnt/sdcard
|
||||
defaults["remote_test_root"] = "/data/local/tests"
|
||||
|
|
|
@ -141,31 +141,33 @@ def add_common_arguments(parser):
|
|||
|
||||
def add_remote_arguments(parser):
|
||||
parser.add_argument("--objdir", action="store", type=str, dest="objdir",
|
||||
help="local objdir, containing xpcshell binaries")
|
||||
help="Local objdir, containing xpcshell binaries.")
|
||||
|
||||
parser.add_argument("--apk", action="store", type=str, dest="localAPK",
|
||||
help="local path to Fennec APK")
|
||||
help="Local path to Firefox for Android APK.")
|
||||
|
||||
parser.add_argument("--deviceSerial", action="store", type=str, dest="deviceSerial",
|
||||
help="serial ID of device")
|
||||
help="adb serial number of remote device. This is required "
|
||||
"when more than one device is connected to the host. "
|
||||
"Use 'adb devices' to see connected devices.")
|
||||
|
||||
parser.add_argument("--adbPath", action="store", type=str, dest="adbPath",
|
||||
default=None,
|
||||
help="Path to adb")
|
||||
help="Path to adb binary.")
|
||||
|
||||
parser.add_argument("--noSetup", action="store_false", dest="setup", default=True,
|
||||
help="do not copy any files to device (to be used only if "
|
||||
"device is already setup)")
|
||||
help="Do not copy any files to device (to be used only if "
|
||||
"device is already setup).")
|
||||
|
||||
parser.add_argument("--local-lib-dir", action="store", type=str, dest="localLib",
|
||||
help="local path to library directory")
|
||||
help="Local path to library directory.")
|
||||
|
||||
parser.add_argument("--local-bin-dir", action="store", type=str, dest="localBin",
|
||||
help="local path to bin directory")
|
||||
help="Local path to bin directory.")
|
||||
|
||||
parser.add_argument("--remoteTestRoot", action="store", type=str, dest="remoteTestRoot",
|
||||
help="remote directory to use as test root "
|
||||
"(eg. /mnt/sdcard/tests or /data/local/tests)")
|
||||
help="Remote directory to use as test root "
|
||||
"(eg. /mnt/sdcard/tests or /data/local/tests).")
|
||||
|
||||
|
||||
def parser_desktop():
|
||||
|
|
|
@ -48,32 +48,20 @@ add_task(async function test_all_downloads() {
|
|||
Assert.ok(!!download);
|
||||
list.add(download);
|
||||
|
||||
// Second download.
|
||||
download = await Downloads.createDownload({
|
||||
source: { url: url.spec, isPrivate: false },
|
||||
target: { path: FileTestUtils.getTempFile(TEST_TARGET_FILE_NAME).path },
|
||||
let view;
|
||||
let removePromise = new Promise(resolve => {
|
||||
view = {
|
||||
onDownloadAdded() {},
|
||||
onDownloadChanged() {},
|
||||
onDownloadRemoved() { resolve(); },
|
||||
};
|
||||
});
|
||||
await download.start();
|
||||
Assert.ok(!!download);
|
||||
list.add(download);
|
||||
|
||||
await list.addView(view);
|
||||
|
||||
let items = await list.getAll();
|
||||
Assert.equal(items.length, 2);
|
||||
|
||||
await new Promise(resolve => {
|
||||
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_DOWNLOADS, value => {
|
||||
Assert.equal(value, 0);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
items = await list.getAll();
|
||||
|
||||
// We don't remove the active downloads.
|
||||
Assert.equal(items.length, 1);
|
||||
|
||||
await download.cancel();
|
||||
|
||||
await new Promise(resolve => {
|
||||
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_DOWNLOADS, value => {
|
||||
Assert.equal(value, 0);
|
||||
|
@ -81,6 +69,8 @@ add_task(async function test_all_downloads() {
|
|||
});
|
||||
});
|
||||
|
||||
await removePromise;
|
||||
|
||||
items = await list.getAll();
|
||||
Assert.equal(items.length, 0);
|
||||
});
|
||||
|
@ -103,6 +93,17 @@ add_task(async function test_range_downloads() {
|
|||
let items = await list.getAll();
|
||||
Assert.equal(items.length, 1);
|
||||
|
||||
let view;
|
||||
let removePromise = new Promise(resolve => {
|
||||
view = {
|
||||
onDownloadAdded() {},
|
||||
onDownloadChanged() {},
|
||||
onDownloadRemoved() { resolve(); },
|
||||
};
|
||||
});
|
||||
|
||||
await list.addView(view);
|
||||
|
||||
await new Promise(resolve => {
|
||||
Services.clearData.deleteDataInTimeRange(download.startTime.getTime() * 1000,
|
||||
download.startTime.getTime() * 1000,
|
||||
|
@ -113,6 +114,8 @@ add_task(async function test_range_downloads() {
|
|||
});
|
||||
});
|
||||
|
||||
await removePromise;
|
||||
|
||||
items = await list.getAll();
|
||||
Assert.equal(items.length, 0);
|
||||
});
|
||||
|
@ -137,6 +140,17 @@ add_task(async function test_principal_downloads() {
|
|||
let items = await list.getAll();
|
||||
Assert.equal(items.length, 2);
|
||||
|
||||
let view;
|
||||
let removePromise = new Promise(resolve => {
|
||||
view = {
|
||||
onDownloadAdded() {},
|
||||
onDownloadChanged() {},
|
||||
onDownloadRemoved() { resolve(); },
|
||||
};
|
||||
});
|
||||
|
||||
await list.addView(view);
|
||||
|
||||
let uri = Services.io.newURI("http://example.com");
|
||||
let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
|
||||
|
||||
|
@ -149,9 +163,21 @@ add_task(async function test_principal_downloads() {
|
|||
});
|
||||
});
|
||||
|
||||
await removePromise;
|
||||
|
||||
items = await list.getAll();
|
||||
Assert.equal(items.length, 1);
|
||||
|
||||
removePromise = new Promise(resolve => {
|
||||
view = {
|
||||
onDownloadAdded() {},
|
||||
onDownloadChanged() {},
|
||||
onDownloadRemoved() { resolve(); },
|
||||
};
|
||||
});
|
||||
|
||||
await list.addView(view);
|
||||
|
||||
await new Promise(resolve => {
|
||||
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_DOWNLOADS, value => {
|
||||
Assert.equal(value, 0);
|
||||
|
@ -159,6 +185,8 @@ add_task(async function test_principal_downloads() {
|
|||
});
|
||||
});
|
||||
|
||||
await removePromise;
|
||||
|
||||
items = await list.getAll();
|
||||
Assert.equal(items.length, 0);
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче