mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 05:37:11 +00:00
Merge branch 'master' into AppConstants
This commit is contained in:
@@ -220,7 +220,13 @@ static nsIScriptSecurityManager *sSecurityManager;
|
||||
// the appropriate pref is set.
|
||||
|
||||
static bool sGCOnMemoryPressure;
|
||||
|
||||
// nsJSEnvironmentObserver observes the user-interaction-inactive notifications
|
||||
// and triggers a shrinking a garbage collection if the user is still inactive
|
||||
// after NS_SHRINKING_GC_DELAY ms later, if the appropriate pref is set.
|
||||
|
||||
static bool sCompactOnUserInactive;
|
||||
static bool sIsCompactingOnUserInactive = false;
|
||||
|
||||
// In testing, we call RunNextCollectorTimer() to ensure that the collectors are run more
|
||||
// aggressively than they would be in regular browsing. sExpensiveCollectorPokes keeps
|
||||
@@ -300,6 +306,10 @@ nsJSEnvironmentObserver::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
}
|
||||
} else if (!nsCRT::strcmp(aTopic, "user-interaction-active")) {
|
||||
nsJSContext::KillShrinkingGCTimer();
|
||||
if (sIsCompactingOnUserInactive) {
|
||||
JS::AbortIncrementalGC(sRuntime);
|
||||
}
|
||||
MOZ_ASSERT(!sIsCompactingOnUserInactive);
|
||||
} else if (!nsCRT::strcmp(aTopic, "quit-application") ||
|
||||
!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
|
||||
sShuttingDown = true;
|
||||
@@ -1820,6 +1830,7 @@ void
|
||||
ShrinkingGCTimerFired(nsITimer* aTimer, void* aClosure)
|
||||
{
|
||||
nsJSContext::KillShrinkingGCTimer();
|
||||
sIsCompactingOnUserInactive = true;
|
||||
nsJSContext::GarbageCollectNow(JS::gcreason::USER_INACTIVE,
|
||||
nsJSContext::IncrementalGC,
|
||||
nsJSContext::ShrinkingGC);
|
||||
@@ -2237,6 +2248,7 @@ DOMGCSliceCallback(JSRuntime *aRt, JS::GCProgress aProgress, const JS::GCDescrip
|
||||
}
|
||||
|
||||
sCCLockedOut = false;
|
||||
sIsCompactingOnUserInactive = false;
|
||||
|
||||
// May need to kill the inter-slice GC timer
|
||||
nsJSContext::KillInterSliceGCTimer();
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include "mozilla/Alignment.h"
|
||||
#include "mozilla/Array.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/DeferredFinalize.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/CallbackObject.h"
|
||||
#include "mozilla/dom/DOMJSClass.h"
|
||||
@@ -26,8 +28,6 @@
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "nsCycleCollector.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsJSUtils.h"
|
||||
|
||||
@@ -50,12 +50,12 @@
|
||||
#include "prprf.h"
|
||||
#include "nsNodeUtils.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsCycleCollector.h"
|
||||
|
||||
// Nasty hack. Maybe we could move some of the classinfo utility methods
|
||||
// (e.g. WrapNative) over to nsContentUtils?
|
||||
#include "nsDOMClassInfo.h"
|
||||
|
||||
#include "mozilla/DeferredFinalize.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
|
||||
+23
-1
@@ -12,10 +12,11 @@
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#include "jspubtd.h"
|
||||
|
||||
#include "js/GCAPI.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
@@ -24,6 +25,9 @@ class Debugger;
|
||||
} // namespace js
|
||||
|
||||
namespace JS {
|
||||
|
||||
using mozilla::UniquePtr;
|
||||
|
||||
namespace dbg {
|
||||
|
||||
// Helping embedding code build objects for Debugger
|
||||
@@ -261,6 +265,24 @@ class BuilderOrigin : public Builder {
|
||||
void SetDebuggerMallocSizeOf(JSRuntime* runtime, mozilla::MallocSizeOf mallocSizeOf);
|
||||
|
||||
|
||||
|
||||
// Debugger and Garbage Collection Events
|
||||
// --------------------------------------
|
||||
//
|
||||
// The Debugger wants to report about its debuggees' GC cycles, however entering
|
||||
// JS after a GC is troublesome since SpiderMonkey will often do something like
|
||||
// force a GC and then rely on the nursery being empty. If we call into some
|
||||
// Debugger's hook after the GC, then JS runs and the nursery won't be
|
||||
// empty. Instead, we rely on embedders to call back into SpiderMonkey after a
|
||||
// GC and notify Debuggers to call their onGarbageCollection hook.
|
||||
|
||||
|
||||
// For each Debugger that observed a debuggee involved in the given GC event,
|
||||
// call its `onGarbageCollection` hook.
|
||||
JS_PUBLIC_API(bool)
|
||||
FireOnGarbageCollectionHook(JSContext* cx, GarbageCollectionEvent::Ptr&& data);
|
||||
|
||||
|
||||
|
||||
// Handlers for observing Promises
|
||||
// -------------------------------
|
||||
|
||||
+70
-1
@@ -7,12 +7,18 @@
|
||||
#ifndef js_GCAPI_h
|
||||
#define js_GCAPI_h
|
||||
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/Vector.h"
|
||||
|
||||
#include "js/HeapAPI.h"
|
||||
|
||||
namespace js {
|
||||
namespace gc {
|
||||
class GCRuntime;
|
||||
}
|
||||
namespace gcstats {
|
||||
struct Statistics;
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum JSGCMode {
|
||||
@@ -42,6 +48,8 @@ typedef enum JSGCInvocationKind {
|
||||
|
||||
namespace JS {
|
||||
|
||||
using mozilla::UniquePtr;
|
||||
|
||||
#define GCREASONS(D) \
|
||||
/* Reasons internal to the JS engine */ \
|
||||
D(API) \
|
||||
@@ -60,6 +68,7 @@ namespace JS {
|
||||
D(SHARED_MEMORY_LIMIT) \
|
||||
D(PERIODIC_FULL_GC) \
|
||||
D(INCREMENTAL_TOO_SLOW) \
|
||||
D(ABORT_GC) \
|
||||
\
|
||||
/* These are reserved for future use. */ \
|
||||
D(RESERVED0) \
|
||||
@@ -78,7 +87,6 @@ namespace JS {
|
||||
D(RESERVED13) \
|
||||
D(RESERVED14) \
|
||||
D(RESERVED15) \
|
||||
D(RESERVED16) \
|
||||
\
|
||||
/* Reasons from Firefox */ \
|
||||
D(DOM_WINDOW_UTILS) \
|
||||
@@ -237,6 +245,65 @@ IncrementalGCSlice(JSRuntime* rt, gcreason::Reason reason, int64_t millis = 0);
|
||||
extern JS_PUBLIC_API(void)
|
||||
FinishIncrementalGC(JSRuntime* rt, gcreason::Reason reason);
|
||||
|
||||
/*
|
||||
* If IsIncrementalGCInProgress(rt), this call aborts the ongoing collection and
|
||||
* performs whatever work needs to be done to return the collector to its idle
|
||||
* state. This may take an arbitrarily long time. When this function returns,
|
||||
* IsIncrementalGCInProgress(rt) will always be false.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
AbortIncrementalGC(JSRuntime* rt);
|
||||
|
||||
namespace dbg {
|
||||
|
||||
// The `JS::dbg::GarbageCollectionEvent` class is essentially a view of the
|
||||
// `js::gcstats::Statistics` data without the uber implementation-specific bits.
|
||||
// It should generally be palatable for web developers.
|
||||
class GarbageCollectionEvent
|
||||
{
|
||||
// The major GC number of the GC cycle this data pertains to.
|
||||
uint64_t majorGCNumber_;
|
||||
|
||||
// Reference to a non-owned, statically allocated C string. This is a very
|
||||
// short reason explaining why a GC was triggered.
|
||||
const char* reason;
|
||||
|
||||
// Reference to a nullable, non-owned, statically allocated C string. If the
|
||||
// collection was forced to be non-incremental, this is a short reason of
|
||||
// why the GC could not perform an incremental collection.
|
||||
const char* nonincrementalReason;
|
||||
|
||||
// Represents a single slice of a possibly multi-slice incremental garbage
|
||||
// collection.
|
||||
struct Collection {
|
||||
int64_t startTimestamp;
|
||||
int64_t endTimestamp;
|
||||
};
|
||||
|
||||
// The set of garbage collection slices that made up this GC cycle.
|
||||
mozilla::Vector<Collection> collections;
|
||||
|
||||
GarbageCollectionEvent(const GarbageCollectionEvent& rhs) = delete;
|
||||
GarbageCollectionEvent& operator=(const GarbageCollectionEvent& rhs) = delete;
|
||||
|
||||
public:
|
||||
explicit GarbageCollectionEvent(uint64_t majorGCNum)
|
||||
: majorGCNumber_(majorGCNum)
|
||||
, reason(nullptr)
|
||||
, nonincrementalReason(nullptr)
|
||||
, collections()
|
||||
{ }
|
||||
|
||||
using Ptr = UniquePtr<GarbageCollectionEvent, DeletePolicy<GarbageCollectionEvent>>;
|
||||
static Ptr Create(JSRuntime* rt, ::js::gcstats::Statistics& stats, uint64_t majorGCNumber);
|
||||
|
||||
JSObject* toJSObject(JSContext* cx) const;
|
||||
|
||||
uint64_t majorGCNumber() const { return majorGCNumber_; }
|
||||
};
|
||||
|
||||
} // namespace dbg
|
||||
|
||||
enum GCProgress {
|
||||
/*
|
||||
* During non-incremental GC, the GC is bracketed by JSGC_CYCLE_BEGIN/END
|
||||
@@ -263,6 +330,8 @@ struct JS_PUBLIC_API(GCDescription) {
|
||||
|
||||
char16_t* formatMessage(JSRuntime* rt) const;
|
||||
char16_t* formatJSON(JSRuntime* rt, uint64_t timestamp) const;
|
||||
|
||||
JS::dbg::GarbageCollectionEvent::Ptr toGCEvent(JSRuntime* rt) const;
|
||||
};
|
||||
|
||||
typedef void
|
||||
|
||||
@@ -222,6 +222,8 @@ class JS_FRIEND_API(GCCellPtr)
|
||||
return reinterpret_cast<uintptr_t>(asCell());
|
||||
}
|
||||
|
||||
bool mayBeOwnedByOtherRuntime() const;
|
||||
|
||||
private:
|
||||
uintptr_t checkedCast(void* p, JSGCTraceKind traceKind) {
|
||||
js::gc::Cell* cell = static_cast<js::gc::Cell*>(p);
|
||||
@@ -365,6 +367,8 @@ GCThingIsMarkedGray(GCCellPtr thing)
|
||||
{
|
||||
if (js::gc::IsInsideNursery(thing.asCell()))
|
||||
return false;
|
||||
if (thing.mayBeOwnedByOtherRuntime())
|
||||
return false;
|
||||
return js::gc::detail::CellIsMarkedGray(thing.asCell());
|
||||
}
|
||||
|
||||
|
||||
@@ -214,9 +214,13 @@ JS_FRIEND_API(void) HeapCellRelocate(js::gc::Cell** cellp);
|
||||
*/
|
||||
extern JS_FRIEND_API(void)
|
||||
AssertGCThingMustBeTenured(JSObject* obj);
|
||||
extern JS_FRIEND_API(void)
|
||||
AssertGCThingIsNotAnObjectSubclass(js::gc::Cell* cell);
|
||||
#else
|
||||
inline void
|
||||
AssertGCThingMustBeTenured(JSObject* obj) {}
|
||||
inline void
|
||||
AssertGCThingIsNotAnObjectSubclass(js::gc::Cell* cell) {}
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -639,7 +643,10 @@ struct GCMethods<T*>
|
||||
{
|
||||
static T* initial() { return nullptr; }
|
||||
static bool needsPostBarrier(T* v) { return false; }
|
||||
static void postBarrier(T** vp) {}
|
||||
static void postBarrier(T** vp) {
|
||||
if (vp)
|
||||
JS::AssertGCThingIsNotAnObjectSubclass(reinterpret_cast<js::gc::Cell*>(vp));
|
||||
}
|
||||
static void relocate(T** vp) {}
|
||||
};
|
||||
|
||||
|
||||
@@ -33,6 +33,12 @@ struct JS_PUBLIC_API(WorkBudget)
|
||||
*/
|
||||
struct JS_PUBLIC_API(SliceBudget)
|
||||
{
|
||||
// Memory of the originally requested budget. If isUnlimited, neither of
|
||||
// these are in use. If deadline==0, then workBudget is valid. Otherwise
|
||||
// timeBudget is valid.
|
||||
TimeBudget timeBudget;
|
||||
WorkBudget workBudget;
|
||||
|
||||
int64_t deadline; /* in microseconds */
|
||||
intptr_t counter;
|
||||
|
||||
@@ -64,10 +70,12 @@ struct JS_PUBLIC_API(SliceBudget)
|
||||
return checkOverBudget();
|
||||
}
|
||||
|
||||
bool isUnlimited() {
|
||||
bool isUnlimited() const {
|
||||
return deadline == unlimitedDeadline;
|
||||
}
|
||||
|
||||
int describe(char* buffer, size_t maxlen) const;
|
||||
|
||||
private:
|
||||
bool checkOverBudget();
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include "asmjs/AsmJSValidate.h"
|
||||
#include "jit/MacroAssembler.h"
|
||||
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
|
||||
@@ -801,7 +801,7 @@ NewExportedFunction(JSContext* cx, const AsmJSModule::ExportedFunction& func,
|
||||
unsigned numArgs = func.isChangeHeap() ? 1 : func.numArgs();
|
||||
JSFunction *fun =
|
||||
NewNativeConstructor(cx, CallAsmJS, numArgs, name,
|
||||
JSFunction::ExtendedFinalizeKind, GenericObject,
|
||||
gc::AllocKind::FUNCTION_EXTENDED, GenericObject,
|
||||
JSFunction::ASMJS_CTOR);
|
||||
if (!fun)
|
||||
return nullptr;
|
||||
@@ -824,7 +824,7 @@ HandleDynamicLinkFailure(JSContext* cx, const CallArgs& args, AsmJSModule& modul
|
||||
return false;
|
||||
|
||||
RootedFunction fun(cx, NewScriptedFunction(cx, 0, JSFunction::INTERPRETED,
|
||||
name, JSFunction::FinalizeKind,
|
||||
name, gc::AllocKind::FUNCTION,
|
||||
TenuredObject));
|
||||
if (!fun)
|
||||
return false;
|
||||
@@ -1095,7 +1095,7 @@ js::NewAsmJSModuleFunction(ExclusiveContext* cx, JSFunction* origFun, HandleObje
|
||||
: JSFunction::ASMJS_CTOR;
|
||||
JSFunction *moduleFun =
|
||||
NewNativeConstructor(cx, LinkAsmJS, origFun->nargs(), name,
|
||||
JSFunction::ExtendedFinalizeKind, TenuredObject,
|
||||
gc::AllocKind::FUNCTION_EXTENDED, TenuredObject,
|
||||
flags);
|
||||
if (!moduleFun)
|
||||
return nullptr;
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#include "frontend/ParseNode-inl.h"
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
#include "vm/ArrayBufferObject-inl.h"
|
||||
#include "vm/Stack-inl.h"
|
||||
|
||||
@@ -964,13 +965,13 @@ const Class AsmJSModuleObject::class_ = {
|
||||
AsmJSModuleObject_trace
|
||||
};
|
||||
|
||||
AsmJSModuleObject *
|
||||
AsmJSModuleObject::create(ExclusiveContext *cx, ScopedJSDeletePtr<AsmJSModule> *module)
|
||||
AsmJSModuleObject*
|
||||
AsmJSModuleObject::create(ExclusiveContext* cx, ScopedJSDeletePtr<AsmJSModule>* module)
|
||||
{
|
||||
JSObject *obj = NewObjectWithGivenProto(cx, &AsmJSModuleObject::class_, NullPtr());
|
||||
JSObject* obj = NewObjectWithGivenProto(cx, &AsmJSModuleObject::class_, NullPtr());
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
AsmJSModuleObject *nobj = &obj->as<AsmJSModuleObject>();
|
||||
AsmJSModuleObject* nobj = &obj->as<AsmJSModuleObject>();
|
||||
|
||||
nobj->setReservedSlot(MODULE_SLOT, PrivateValue(module->forget()));
|
||||
return nobj;
|
||||
|
||||
+27
-164
@@ -49,6 +49,7 @@
|
||||
|
||||
#include "frontend/ParseNode-inl.h"
|
||||
#include "frontend/Parser-inl.h"
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::frontend;
|
||||
@@ -498,7 +499,7 @@ ParseVarOrConstStatement(AsmJSParser& parser, ParseNode** var)
|
||||
return true;
|
||||
}
|
||||
|
||||
*var = parser.statement();
|
||||
*var = parser.statement(YieldIsName);
|
||||
if (!*var)
|
||||
return false;
|
||||
|
||||
@@ -538,9 +539,10 @@ class Type
|
||||
Type() : which_(Which(-1)) {}
|
||||
static Type Of(const AsmJSNumLit& lit) {
|
||||
MOZ_ASSERT(lit.hasType());
|
||||
MOZ_ASSERT(Type::Which(lit.which()) >= Fixnum && Type::Which(lit.which()) <= Float32x4);
|
||||
Which which = Type::Which(lit.which());
|
||||
MOZ_ASSERT(which >= Fixnum && which <= Float32x4);
|
||||
Type t;
|
||||
t.which_ = Type::Which(lit.which());
|
||||
t.which_ = which;
|
||||
return t;
|
||||
}
|
||||
MOZ_IMPLICIT Type(Which w) : which_(w) {}
|
||||
@@ -1120,7 +1122,7 @@ class MOZ_STACK_CLASS ModuleCompiler
|
||||
PropertyName* name() const { return name_; }
|
||||
bool defined() const { return defined_; }
|
||||
|
||||
void define(ModuleCompiler& m, ParseNode* fn) {
|
||||
void define(ParseNode* fn) {
|
||||
MOZ_ASSERT(!defined_);
|
||||
defined_ = true;
|
||||
srcBegin_ = fn->pn_pos.begin;
|
||||
@@ -2597,10 +2599,6 @@ class FunctionCompiler
|
||||
return m_.lookupGlobal(name);
|
||||
}
|
||||
|
||||
bool supportsSimd() const {
|
||||
return m_.supportsSimd();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void enterHeapExpression() {
|
||||
@@ -3369,11 +3367,11 @@ class FunctionCompiler
|
||||
{
|
||||
if (!loopStack_.append(pn) || !breakableStack_.append(pn))
|
||||
return false;
|
||||
MOZ_ASSERT_IF(curBlock_, curBlock_->loopDepth() == loopStack_.length() - 1);
|
||||
if (inDeadCode()) {
|
||||
*loopEntry = nullptr;
|
||||
return true;
|
||||
}
|
||||
MOZ_ASSERT(curBlock_->loopDepth() == loopStack_.length() - 1);
|
||||
*loopEntry = MBasicBlock::NewAsmJS(mirGraph(), info(), curBlock_,
|
||||
MBasicBlock::PENDING_LOOP_HEADER);
|
||||
if (!*loopEntry)
|
||||
@@ -5998,19 +5996,19 @@ CheckSimdOperationCall(FunctionCompiler& f, ParseNode* call, const ModuleCompile
|
||||
|
||||
case AsmJSSimdOperation_load:
|
||||
return CheckSimdLoad(f, call, opType, 4, def, type);
|
||||
case AsmJSSimdOperation_loadX:
|
||||
case AsmJSSimdOperation_load1:
|
||||
return CheckSimdLoad(f, call, opType, 1, def, type);
|
||||
case AsmJSSimdOperation_loadXY:
|
||||
case AsmJSSimdOperation_load2:
|
||||
return CheckSimdLoad(f, call, opType, 2, def, type);
|
||||
case AsmJSSimdOperation_loadXYZ:
|
||||
case AsmJSSimdOperation_load3:
|
||||
return CheckSimdLoad(f, call, opType, 3, def, type);
|
||||
case AsmJSSimdOperation_store:
|
||||
return CheckSimdStore(f, call, opType, 4, def, type);
|
||||
case AsmJSSimdOperation_storeX:
|
||||
case AsmJSSimdOperation_store1:
|
||||
return CheckSimdStore(f, call, opType, 1, def, type);
|
||||
case AsmJSSimdOperation_storeXY:
|
||||
case AsmJSSimdOperation_store2:
|
||||
return CheckSimdStore(f, call, opType, 2, def, type);
|
||||
case AsmJSSimdOperation_storeXYZ:
|
||||
case AsmJSSimdOperation_store3:
|
||||
return CheckSimdStore(f, call, opType, 3, def, type);
|
||||
|
||||
case AsmJSSimdOperation_bitselect:
|
||||
@@ -6935,150 +6933,6 @@ CheckLabel(FunctionCompiler& f, ParseNode* labeledStmt, LabelVector* maybeLabels
|
||||
return f.bindLabeledBreaks(&labels, labeledStmt);
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckLeafCondition(FunctionCompiler& f, ParseNode* cond, ParseNode* thenStmt, ParseNode* elseOrJoinStmt,
|
||||
MBasicBlock** thenBlock, MBasicBlock** elseOrJoinBlock)
|
||||
{
|
||||
MDefinition* condDef;
|
||||
Type condType;
|
||||
if (!CheckExpr(f, cond, &condDef, &condType))
|
||||
return false;
|
||||
if (!condType.isInt())
|
||||
return f.failf(cond, "%s is not a subtype of int", condType.toChars());
|
||||
|
||||
if (!f.branchAndStartThen(condDef, thenBlock, elseOrJoinBlock, thenStmt, elseOrJoinStmt))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckIfCondition(FunctionCompiler& f, ParseNode* cond, ParseNode* thenStmt, ParseNode* elseOrJoinStmt,
|
||||
MBasicBlock** thenBlock, MBasicBlock** elseOrJoinBlock);
|
||||
|
||||
static bool
|
||||
CheckIfConditional(FunctionCompiler& f, ParseNode* conditional, ParseNode* thenStmt, ParseNode* elseOrJoinStmt,
|
||||
MBasicBlock** thenBlock, MBasicBlock** elseOrJoinBlock)
|
||||
{
|
||||
MOZ_ASSERT(conditional->isKind(PNK_CONDITIONAL));
|
||||
|
||||
// a ? b : c <=> (a && b) || (!a && c)
|
||||
// b is always referred to the AND condition, as we need A and B to reach this test,
|
||||
// c is always referred as the OR condition, as we reach it if we don't have A.
|
||||
ParseNode* cond = TernaryKid1(conditional);
|
||||
ParseNode* lhs = TernaryKid2(conditional);
|
||||
ParseNode* rhs = TernaryKid3(conditional);
|
||||
|
||||
MBasicBlock* maybeAndTest = nullptr;
|
||||
MBasicBlock* maybeOrTest = nullptr;
|
||||
MBasicBlock** ifTrueBlock = &maybeAndTest;
|
||||
MBasicBlock** ifFalseBlock = &maybeOrTest;
|
||||
ParseNode* ifTrueBlockNode = lhs;
|
||||
ParseNode* ifFalseBlockNode = rhs;
|
||||
|
||||
// Try to spot opportunities for short-circuiting in the AND subpart
|
||||
uint32_t andTestLiteral = 0;
|
||||
bool skipAndTest = false;
|
||||
|
||||
if (IsLiteralInt(f.m(), lhs, &andTestLiteral)) {
|
||||
skipAndTest = true;
|
||||
if (andTestLiteral == 0) {
|
||||
// (a ? 0 : b) is equivalent to !a && b
|
||||
// If a is true, jump to the elseBlock directly
|
||||
ifTrueBlock = elseOrJoinBlock;
|
||||
ifTrueBlockNode = elseOrJoinStmt;
|
||||
} else {
|
||||
// (a ? 1 : b) is equivalent to a || b
|
||||
// If a is true, jump to the thenBlock directly
|
||||
ifTrueBlock = thenBlock;
|
||||
ifTrueBlockNode = thenStmt;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to spot opportunities for short-circuiting in the OR subpart
|
||||
uint32_t orTestLiteral = 0;
|
||||
bool skipOrTest = false;
|
||||
|
||||
if (IsLiteralInt(f.m(), rhs, &orTestLiteral)) {
|
||||
skipOrTest = true;
|
||||
if (orTestLiteral == 0) {
|
||||
// (a ? b : 0) is equivalent to a && b
|
||||
// If a is false, jump to the elseBlock directly
|
||||
ifFalseBlock = elseOrJoinBlock;
|
||||
ifFalseBlockNode = elseOrJoinStmt;
|
||||
} else {
|
||||
// (a ? b : 1) is equivalent to !a || b
|
||||
// If a is false, jump to the thenBlock directly
|
||||
ifFalseBlock = thenBlock;
|
||||
ifFalseBlockNode = thenStmt;
|
||||
}
|
||||
}
|
||||
|
||||
// Pathological cases: a ? 0 : 0 (i.e. false) or a ? 1 : 1 (i.e. true)
|
||||
// These cases can't be optimized properly at this point: one of the blocks might be
|
||||
// created and won't ever be executed. Furthermore, it introduces inconsistencies in the
|
||||
// MIR graph (even if we try to create a block by hand, it will have no predecessor, which
|
||||
// breaks graph assumptions). The only way we could optimize it is to do it directly in
|
||||
// CheckIf by removing the control flow entirely.
|
||||
if (skipOrTest && skipAndTest && (!!orTestLiteral == !!andTestLiteral))
|
||||
return CheckLeafCondition(f, conditional, thenStmt, elseOrJoinStmt, thenBlock, elseOrJoinBlock);
|
||||
|
||||
if (!CheckIfCondition(f, cond, ifTrueBlockNode, ifFalseBlockNode, ifTrueBlock, ifFalseBlock))
|
||||
return false;
|
||||
f.assertCurrentBlockIs(*ifTrueBlock);
|
||||
|
||||
// Add supplementary tests, if needed
|
||||
if (!skipAndTest) {
|
||||
if (!CheckIfCondition(f, lhs, thenStmt, elseOrJoinStmt, thenBlock, elseOrJoinBlock))
|
||||
return false;
|
||||
f.assertCurrentBlockIs(*thenBlock);
|
||||
}
|
||||
|
||||
if (!skipOrTest) {
|
||||
f.switchToElse(*ifFalseBlock);
|
||||
if (!CheckIfCondition(f, rhs, thenStmt, elseOrJoinStmt, thenBlock, elseOrJoinBlock))
|
||||
return false;
|
||||
f.assertCurrentBlockIs(*thenBlock);
|
||||
}
|
||||
|
||||
// We might not be on the thenBlock in one case
|
||||
if (ifTrueBlock == elseOrJoinBlock) {
|
||||
MOZ_ASSERT(skipAndTest && andTestLiteral == 0);
|
||||
f.switchToElse(*thenBlock);
|
||||
}
|
||||
|
||||
// Check post-conditions
|
||||
f.assertCurrentBlockIs(*thenBlock);
|
||||
MOZ_ASSERT_IF(!f.inDeadCode(), *thenBlock && *elseOrJoinBlock);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Recursive function that checks for a complex condition (formed with ternary
|
||||
// conditionals) and creates the associated short-circuiting control flow graph.
|
||||
//
|
||||
// After a call to CheckCondition, the followings are true:
|
||||
// - if *thenBlock and *elseOrJoinBlock were non-null on entry, their value is
|
||||
// not changed by this function.
|
||||
// - *thenBlock and *elseOrJoinBlock are non-null on exit.
|
||||
// - the current block on exit is the *thenBlock.
|
||||
static bool
|
||||
CheckIfCondition(FunctionCompiler& f, ParseNode* cond, ParseNode* thenStmt,
|
||||
ParseNode* elseOrJoinStmt, MBasicBlock** thenBlock, MBasicBlock** elseOrJoinBlock)
|
||||
{
|
||||
JS_CHECK_RECURSION_DONT_REPORT(f.cx(), return f.m().failOverRecursed());
|
||||
|
||||
if (cond->isKind(PNK_CONDITIONAL))
|
||||
return CheckIfConditional(f, cond, thenStmt, elseOrJoinStmt, thenBlock, elseOrJoinBlock);
|
||||
|
||||
// We've reached a leaf, i.e. an atomic condition
|
||||
if (!CheckLeafCondition(f, cond, thenStmt, elseOrJoinStmt, thenBlock, elseOrJoinBlock))
|
||||
return false;
|
||||
|
||||
// Check post-conditions
|
||||
f.assertCurrentBlockIs(*thenBlock);
|
||||
MOZ_ASSERT_IF(!f.inDeadCode(), *thenBlock && *elseOrJoinBlock);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckIf(FunctionCompiler& f, ParseNode* ifStmt)
|
||||
{
|
||||
@@ -7099,7 +6953,14 @@ CheckIf(FunctionCompiler& f, ParseNode* ifStmt)
|
||||
MBasicBlock* elseBlock = nullptr;
|
||||
ParseNode* elseOrJoinStmt = elseStmt ? elseStmt : nextStmt;
|
||||
|
||||
if (!CheckIfCondition(f, cond, thenStmt, elseOrJoinStmt, &thenBlock, &elseBlock))
|
||||
MDefinition* condDef;
|
||||
Type condType;
|
||||
if (!CheckExpr(f, cond, &condDef, &condType))
|
||||
return false;
|
||||
if (!condType.isInt())
|
||||
return f.failf(cond, "%s is not a subtype of int", condType.toChars());
|
||||
|
||||
if (!f.branchAndStartThen(condDef, &thenBlock, &elseBlock, thenStmt, elseOrJoinStmt))
|
||||
return false;
|
||||
|
||||
if (!CheckStatement(f, thenStmt))
|
||||
@@ -7599,7 +7460,7 @@ ParseFunction(ModuleCompiler& m, ParseNode** fnOut)
|
||||
// This flows into FunctionBox, so must be tenured.
|
||||
RootedFunction fun(m.cx(),
|
||||
NewScriptedFunction(m.cx(), 0, JSFunction::INTERPRETED,
|
||||
name, JSFunction::FinalizeKind,
|
||||
name, gc::AllocKind::FUNCTION,
|
||||
TenuredObject));
|
||||
if (!fun)
|
||||
return false;
|
||||
@@ -7618,7 +7479,9 @@ ParseFunction(ModuleCompiler& m, ParseNode** fnOut)
|
||||
if (!funpc.init(tokenStream))
|
||||
return false;
|
||||
|
||||
if (!m.parser().functionArgsAndBodyGeneric(fn, fun, Normal, Statement)) {
|
||||
if (!m.parser().functionArgsAndBodyGeneric(InAllowed, YieldIsName, fn, fun, Normal,
|
||||
Statement))
|
||||
{
|
||||
if (tokenStream.hadError() || directives == newDirectives)
|
||||
return false;
|
||||
|
||||
@@ -7699,7 +7562,7 @@ CheckFunction(ModuleCompiler& m, LifoAlloc& lifo, MIRGenerator** mir, ModuleComp
|
||||
if (func->defined())
|
||||
return m.failName(fn, "function '%s' already defined", FunctionName(fn));
|
||||
|
||||
func->define(m, fn);
|
||||
func->define(fn);
|
||||
func->accumulateCompileTime((PRMJ_Now() - before) / PRMJ_USEC_PER_MSEC);
|
||||
|
||||
m.parser().release(mark);
|
||||
@@ -8196,7 +8059,7 @@ CheckModuleReturn(ModuleCompiler& m)
|
||||
return m.fail(nullptr, "invalid asm.js statement");
|
||||
}
|
||||
|
||||
ParseNode* returnStmt = m.parser().statement();
|
||||
ParseNode* returnStmt = m.parser().statement(YieldIsName);
|
||||
if (!returnStmt)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -1089,7 +1089,7 @@ CreateObjectConstructor(JSContext* cx, JSProtoKey key)
|
||||
|
||||
/* Create the Object function now that we have a [[Prototype]] for it. */
|
||||
return NewNativeConstructor(cx, obj_construct, 1, HandlePropertyName(cx->names().Object),
|
||||
JSFunction::FinalizeKind, SingletonObject);
|
||||
gc::AllocKind::FUNCTION, SingletonObject);
|
||||
}
|
||||
|
||||
static JSObject*
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
|
||||
/* JS reflection package. */
|
||||
|
||||
#include "jsreflect.h"
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
|
||||
@@ -34,7 +32,80 @@ using JS::AutoValueArray;
|
||||
using mozilla::ArrayLength;
|
||||
using mozilla::DebugOnly;
|
||||
|
||||
char const * const js::aopNames[] = {
|
||||
enum ASTType {
|
||||
AST_ERROR = -1,
|
||||
#define ASTDEF(ast, str, method) ast,
|
||||
#include "jsast.tbl"
|
||||
#undef ASTDEF
|
||||
AST_LIMIT
|
||||
};
|
||||
|
||||
enum AssignmentOperator {
|
||||
AOP_ERR = -1,
|
||||
|
||||
/* assign */
|
||||
AOP_ASSIGN = 0,
|
||||
/* operator-assign */
|
||||
AOP_PLUS, AOP_MINUS, AOP_STAR, AOP_DIV, AOP_MOD, AOP_POW,
|
||||
/* shift-assign */
|
||||
AOP_LSH, AOP_RSH, AOP_URSH,
|
||||
/* binary */
|
||||
AOP_BITOR, AOP_BITXOR, AOP_BITAND,
|
||||
|
||||
AOP_LIMIT
|
||||
};
|
||||
|
||||
enum BinaryOperator {
|
||||
BINOP_ERR = -1,
|
||||
|
||||
/* eq */
|
||||
BINOP_EQ = 0, BINOP_NE, BINOP_STRICTEQ, BINOP_STRICTNE,
|
||||
/* rel */
|
||||
BINOP_LT, BINOP_LE, BINOP_GT, BINOP_GE,
|
||||
/* shift */
|
||||
BINOP_LSH, BINOP_RSH, BINOP_URSH,
|
||||
/* arithmetic */
|
||||
BINOP_ADD, BINOP_SUB, BINOP_STAR, BINOP_DIV, BINOP_MOD, BINOP_POW,
|
||||
/* binary */
|
||||
BINOP_BITOR, BINOP_BITXOR, BINOP_BITAND,
|
||||
/* misc */
|
||||
BINOP_IN, BINOP_INSTANCEOF,
|
||||
|
||||
BINOP_LIMIT
|
||||
};
|
||||
|
||||
enum UnaryOperator {
|
||||
UNOP_ERR = -1,
|
||||
|
||||
UNOP_DELETE = 0,
|
||||
UNOP_NEG,
|
||||
UNOP_POS,
|
||||
UNOP_NOT,
|
||||
UNOP_BITNOT,
|
||||
UNOP_TYPEOF,
|
||||
UNOP_VOID,
|
||||
|
||||
UNOP_LIMIT
|
||||
};
|
||||
|
||||
enum VarDeclKind {
|
||||
VARDECL_ERR = -1,
|
||||
VARDECL_VAR = 0,
|
||||
VARDECL_CONST,
|
||||
VARDECL_LET,
|
||||
VARDECL_LIMIT
|
||||
};
|
||||
|
||||
enum PropKind {
|
||||
PROP_ERR = -1,
|
||||
PROP_INIT = 0,
|
||||
PROP_GETTER,
|
||||
PROP_SETTER,
|
||||
PROP_MUTATEPROTO,
|
||||
PROP_LIMIT
|
||||
};
|
||||
|
||||
static const char* const aopNames[] = {
|
||||
"=", /* AOP_ASSIGN */
|
||||
"+=", /* AOP_PLUS */
|
||||
"-=", /* AOP_MINUS */
|
||||
@@ -50,7 +121,7 @@ char const * const js::aopNames[] = {
|
||||
"&=" /* AOP_BITAND */
|
||||
};
|
||||
|
||||
char const * const js::binopNames[] = {
|
||||
static const char* const binopNames[] = {
|
||||
"==", /* BINOP_EQ */
|
||||
"!=", /* BINOP_NE */
|
||||
"===", /* BINOP_STRICTEQ */
|
||||
@@ -75,7 +146,7 @@ char const * const js::binopNames[] = {
|
||||
"instanceof", /* BINOP_INSTANCEOF */
|
||||
};
|
||||
|
||||
char const * const js::unopNames[] = {
|
||||
static const char* const unopNames[] = {
|
||||
"delete", /* UNOP_DELETE */
|
||||
"-", /* UNOP_NEG */
|
||||
"+", /* UNOP_POS */
|
||||
@@ -85,14 +156,14 @@ char const * const js::unopNames[] = {
|
||||
"void" /* UNOP_VOID */
|
||||
};
|
||||
|
||||
char const * const js::nodeTypeNames[] = {
|
||||
static const char* const nodeTypeNames[] = {
|
||||
#define ASTDEF(ast, str, method) str,
|
||||
#include "jsast.tbl"
|
||||
#undef ASTDEF
|
||||
nullptr
|
||||
};
|
||||
|
||||
static char const * const callbackNames[] = {
|
||||
static const char* const callbackNames[] = {
|
||||
#define ASTDEF(ast, str, method) method,
|
||||
#include "jsast.tbl"
|
||||
#undef ASTDEF
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "jsprf.h"
|
||||
|
||||
#include "builtin/TypedObject.h"
|
||||
#include "js/Value.h"
|
||||
|
||||
+26
-26
@@ -43,10 +43,10 @@
|
||||
V(greaterThanOrEqual, (CompareFunc<Float32x4, GreaterThanOrEqual>), 2) \
|
||||
V(lessThan, (CompareFunc<Float32x4, LessThan>), 2) \
|
||||
V(lessThanOrEqual, (CompareFunc<Float32x4, LessThanOrEqual>), 2) \
|
||||
V(load, (Load<Float32x4, 4>), 2) \
|
||||
V(loadXYZ, (Load<Float32x4, 3>), 2) \
|
||||
V(loadXY, (Load<Float32x4, 2>), 2) \
|
||||
V(loadX, (Load<Float32x4, 1>), 2) \
|
||||
V(load, (Load<Float32x4, 4>), 2) \
|
||||
V(load3, (Load<Float32x4, 3>), 2) \
|
||||
V(load2, (Load<Float32x4, 2>), 2) \
|
||||
V(load1, (Load<Float32x4, 1>), 2) \
|
||||
V(max, (BinaryFunc<Float32x4, Maximum, Float32x4>), 2) \
|
||||
V(maxNum, (BinaryFunc<Float32x4, MaxNum, Float32x4>), 2) \
|
||||
V(min, (BinaryFunc<Float32x4, Minimum, Float32x4>), 2) \
|
||||
@@ -54,10 +54,10 @@
|
||||
V(mul, (BinaryFunc<Float32x4, Mul, Float32x4>), 2) \
|
||||
V(notEqual, (CompareFunc<Float32x4, NotEqual>), 2) \
|
||||
V(or, (CoercedBinaryFunc<Float32x4, Int32x4, Or, Float32x4>), 2) \
|
||||
V(store, (Store<Float32x4, 4>), 3) \
|
||||
V(storeXYZ, (Store<Float32x4, 3>), 3) \
|
||||
V(storeXY, (Store<Float32x4, 2>), 3) \
|
||||
V(storeX, (Store<Float32x4, 1>), 3) \
|
||||
V(store, (Store<Float32x4, 4>), 3) \
|
||||
V(store3, (Store<Float32x4, 3>), 3) \
|
||||
V(store2, (Store<Float32x4, 2>), 3) \
|
||||
V(store1, (Store<Float32x4, 1>), 3) \
|
||||
V(sub, (BinaryFunc<Float32x4, Sub, Float32x4>), 2) \
|
||||
V(withX, (FuncWith<Float32x4, WithX>), 2) \
|
||||
V(withY, (FuncWith<Float32x4, WithY>), 2) \
|
||||
@@ -101,16 +101,16 @@
|
||||
V(greaterThanOrEqual, (CompareFunc<Float64x2, GreaterThanOrEqual>), 2) \
|
||||
V(lessThan, (CompareFunc<Float64x2, LessThan>), 2) \
|
||||
V(lessThanOrEqual, (CompareFunc<Float64x2, LessThanOrEqual>), 2) \
|
||||
V(load, (Load<Float64x2, 2>), 2) \
|
||||
V(loadX, (Load<Float64x2, 1>), 2) \
|
||||
V(load, (Load<Float64x2, 2>), 2) \
|
||||
V(load1, (Load<Float64x2, 1>), 2) \
|
||||
V(max, (BinaryFunc<Float64x2, Maximum, Float64x2>), 2) \
|
||||
V(maxNum, (BinaryFunc<Float64x2, MaxNum, Float64x2>), 2) \
|
||||
V(min, (BinaryFunc<Float64x2, Minimum, Float64x2>), 2) \
|
||||
V(minNum, (BinaryFunc<Float64x2, MinNum, Float64x2>), 2) \
|
||||
V(mul, (BinaryFunc<Float64x2, Mul, Float64x2>), 2) \
|
||||
V(notEqual, (CompareFunc<Float64x2, NotEqual>), 2) \
|
||||
V(store, (Store<Float64x2, 2>), 3) \
|
||||
V(storeX, (Store<Float64x2, 1>), 3) \
|
||||
V(store, (Store<Float64x2, 2>), 3) \
|
||||
V(store1, (Store<Float64x2, 1>), 3) \
|
||||
V(sub, (BinaryFunc<Float64x2, Sub, Float64x2>), 2) \
|
||||
V(withX, (FuncWith<Float64x2, WithX>), 2) \
|
||||
V(withY, (FuncWith<Float64x2, WithY>), 2)
|
||||
@@ -148,10 +148,10 @@
|
||||
V(greaterThanOrEqual, (CompareFunc<Int32x4, GreaterThanOrEqual>), 2) \
|
||||
V(lessThan, (CompareFunc<Int32x4, LessThan>), 2) \
|
||||
V(lessThanOrEqual, (CompareFunc<Int32x4, LessThanOrEqual>), 2) \
|
||||
V(load, (Load<Int32x4, 4>), 2) \
|
||||
V(loadXYZ, (Load<Int32x4, 3>), 2) \
|
||||
V(loadXY, (Load<Int32x4, 2>), 2) \
|
||||
V(loadX, (Load<Int32x4, 1>), 2) \
|
||||
V(load, (Load<Int32x4, 4>), 2) \
|
||||
V(load3, (Load<Int32x4, 3>), 2) \
|
||||
V(load2, (Load<Int32x4, 2>), 2) \
|
||||
V(load1, (Load<Int32x4, 1>), 2) \
|
||||
V(mul, (BinaryFunc<Int32x4, Mul, Int32x4>), 2) \
|
||||
V(notEqual, (CompareFunc<Int32x4, NotEqual>), 2) \
|
||||
V(or, (BinaryFunc<Int32x4, Or, Int32x4>), 2) \
|
||||
@@ -159,10 +159,10 @@
|
||||
V(shiftLeftByScalar, (Int32x4BinaryScalar<ShiftLeft>), 2) \
|
||||
V(shiftRightArithmeticByScalar, (Int32x4BinaryScalar<ShiftRightArithmetic>), 2) \
|
||||
V(shiftRightLogicalByScalar, (Int32x4BinaryScalar<ShiftRightLogical>), 2) \
|
||||
V(store, (Store<Int32x4, 4>), 3) \
|
||||
V(storeXYZ, (Store<Int32x4, 3>), 3) \
|
||||
V(storeXY, (Store<Int32x4, 2>), 3) \
|
||||
V(storeX, (Store<Int32x4, 1>), 3) \
|
||||
V(store, (Store<Int32x4, 4>), 3) \
|
||||
V(store3, (Store<Int32x4, 3>), 3) \
|
||||
V(store2, (Store<Int32x4, 2>), 3) \
|
||||
V(store1, (Store<Int32x4, 1>), 3) \
|
||||
V(withX, (FuncWith<Int32x4, WithX>), 2) \
|
||||
V(withY, (FuncWith<Int32x4, WithY>), 2) \
|
||||
V(withZ, (FuncWith<Int32x4, WithZ>), 2) \
|
||||
@@ -244,13 +244,13 @@
|
||||
_(swizzle) \
|
||||
_(shuffle) \
|
||||
_(load) \
|
||||
_(loadX) \
|
||||
_(loadXY) \
|
||||
_(loadXYZ) \
|
||||
_(load1) \
|
||||
_(load2) \
|
||||
_(load3) \
|
||||
_(store) \
|
||||
_(storeX) \
|
||||
_(storeXY) \
|
||||
_(storeXYZ) \
|
||||
_(store1) \
|
||||
_(store2) \
|
||||
_(store3) \
|
||||
_(check)
|
||||
#define ION_ONLY_INT32X4_SIMD_OP(_) \
|
||||
_(bool)
|
||||
|
||||
@@ -161,7 +161,7 @@ SymbolObject::keyFor(JSContext* cx, unsigned argc, Value* vp)
|
||||
HandleValue arg = args.get(0);
|
||||
if (!arg.isSymbol()) {
|
||||
ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE, JSDVG_SEARCH_STACK,
|
||||
arg, js::NullPtr(), "not a symbol", nullptr);
|
||||
arg, js::NullPtr(), "not a symbol", nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -708,6 +708,22 @@ GCSlice(JSContext* cx, unsigned argc, Value* vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
AbortGC(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (args.length() != 0) {
|
||||
RootedObject callee(cx, &args.callee());
|
||||
ReportUsageError(cx, callee, "Wrong number of arguments");
|
||||
return false;
|
||||
}
|
||||
|
||||
cx->runtime()->gc.abortGC();
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ValidateGC(JSContext* cx, unsigned argc, jsval* vp)
|
||||
{
|
||||
@@ -1132,7 +1148,7 @@ MakeFinalizeObserver(JSContext* cx, unsigned argc, jsval* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
JSObject *obj = JS_NewObjectWithGivenProto(cx, &FinalizeCounterClass, JS::NullPtr());
|
||||
JSObject* obj = JS_NewObjectWithGivenProto(cx, &FinalizeCounterClass, JS::NullPtr());
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
@@ -2667,6 +2683,10 @@ gc::ZealModeHelpText),
|
||||
"gcslice([n])",
|
||||
" Start or continue an an incremental GC, running a slice that processes about n objects."),
|
||||
|
||||
JS_FN_HELP("abortgc", AbortGC, 1, 0,
|
||||
"abortgc()",
|
||||
" Abort the current incremental GC."),
|
||||
|
||||
JS_FN_HELP("validategc", ValidateGC, 1, 0,
|
||||
"validategc(true|false)",
|
||||
" If true, a separate validation step is performed after an incremental GC."),
|
||||
|
||||
@@ -439,7 +439,7 @@ class ArrayTypeDescr : public ComplexTypeDescr
|
||||
class StructMetaTypeDescr : public NativeObject
|
||||
{
|
||||
private:
|
||||
static JSObject *create(JSContext *cx, HandleObject structTypeGlobal,
|
||||
static JSObject* create(JSContext* cx, HandleObject structTypeGlobal,
|
||||
HandleObject fields);
|
||||
|
||||
public:
|
||||
@@ -455,7 +455,7 @@ class StructMetaTypeDescr : public NativeObject
|
||||
|
||||
// This is the function that gets called when the user
|
||||
// does `new StructType(...)`. It produces a struct type object.
|
||||
static bool construct(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool construct(JSContext* cx, unsigned argc, Value* vp);
|
||||
};
|
||||
|
||||
class StructTypeDescr : public ComplexTypeDescr
|
||||
@@ -570,8 +570,8 @@ class TypedObject : public JSObject
|
||||
|
||||
int32_t offset() const;
|
||||
int32_t length() const;
|
||||
uint8_t *typedMem() const;
|
||||
uint8_t *typedMemBase() const;
|
||||
uint8_t* typedMem() const;
|
||||
uint8_t* typedMemBase() const;
|
||||
bool isAttached() const;
|
||||
bool maybeForwardedIsAttached() const;
|
||||
|
||||
@@ -579,7 +579,7 @@ class TypedObject : public JSObject
|
||||
return typeDescr().size();
|
||||
}
|
||||
|
||||
uint8_t *typedMem(size_t offset) const {
|
||||
uint8_t* typedMem(size_t offset) const {
|
||||
// It seems a bit surprising that one might request an offset
|
||||
// == size(), but it can happen when taking the "address of" a
|
||||
// 0-sized value. (In other words, we maintain the invariant
|
||||
@@ -594,18 +594,18 @@ class TypedObject : public JSObject
|
||||
// Creates a new typed object whose memory is freshly allocated and
|
||||
// initialized with zeroes (or, in the case of references, an appropriate
|
||||
// default value).
|
||||
static TypedObject *createZeroed(JSContext *cx, HandleTypeDescr typeObj, int32_t length,
|
||||
static TypedObject* createZeroed(JSContext* cx, HandleTypeDescr typeObj, int32_t length,
|
||||
gc::InitialHeap heap = gc::DefaultHeap);
|
||||
|
||||
// User-accessible constructor (`new TypeDescriptor(...)`). Note that the
|
||||
// callee here is the type descriptor.
|
||||
static bool construct(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool construct(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
/* Accessors for self hosted code. */
|
||||
static bool GetBuffer(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool GetByteOffset(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool GetBuffer(JSContext* cx, unsigned argc, Value* vp);
|
||||
static bool GetByteOffset(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
Shape *shapeFromGC() { return shape_; }
|
||||
Shape** addressOfShapeFromGC() { return shape_.unsafeGet(); }
|
||||
};
|
||||
|
||||
typedef Handle<TypedObject*> HandleTypedObject;
|
||||
@@ -715,8 +715,8 @@ class InlineTypedObject : public TypedObject
|
||||
return gc::GetGCObjectKindForBytes(nbytes + sizeof(TypedObject));
|
||||
}
|
||||
|
||||
uint8_t *inlineTypedMem() const {
|
||||
return (uint8_t *) &data_;
|
||||
uint8_t* inlineTypedMem() const {
|
||||
return (uint8_t*) &data_;
|
||||
}
|
||||
|
||||
static void obj_trace(JSTracer* trace, JSObject* object);
|
||||
@@ -1021,8 +1021,8 @@ TypedObject::opaque() const
|
||||
return IsOpaqueTypedObjectClass(getClass());
|
||||
}
|
||||
|
||||
JSObject *
|
||||
InitTypedObjectModuleObject(JSContext *cx, JS::HandleObject obj);
|
||||
JSObject*
|
||||
InitTypedObjectModuleObject(JSContext* cx, JS::HandleObject obj);
|
||||
|
||||
} // namespace js
|
||||
|
||||
|
||||
+848
-225
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "ffi.h"
|
||||
#include "jsalloc.h"
|
||||
#include "jsprf.h"
|
||||
#include "prlink.h"
|
||||
|
||||
#include "ctypes/typedefs.h"
|
||||
@@ -53,6 +54,32 @@ AppendString(Vector<T, N, AP>& v, const char (&array)[ArrayLength])
|
||||
v[i + vlen] = array[i];
|
||||
}
|
||||
|
||||
template <class T, size_t N, class AP>
|
||||
void
|
||||
AppendChars(Vector<T, N, AP>& v, const char c, size_t count)
|
||||
{
|
||||
size_t vlen = v.length();
|
||||
if (!v.resize(vlen + count))
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
v[i + vlen] = c;
|
||||
}
|
||||
|
||||
template <class T, size_t N, class AP>
|
||||
void
|
||||
AppendUInt(Vector<T, N, AP>& v, unsigned n)
|
||||
{
|
||||
char array[16];
|
||||
size_t alen = JS_snprintf(array, 16, "%u", n);
|
||||
size_t vlen = v.length();
|
||||
if (!v.resize(vlen + alen))
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < alen; ++i)
|
||||
v[i + vlen] = array[i];
|
||||
}
|
||||
|
||||
template <class T, size_t N, size_t M, class AP>
|
||||
void
|
||||
AppendString(Vector<T, N, AP>& v, Vector<T, M, AP>& w)
|
||||
@@ -375,6 +402,7 @@ enum CDataSlot {
|
||||
SLOT_REFERENT = 1, // JSObject this object must keep alive, if any
|
||||
SLOT_DATA = 2, // pointer to a buffer containing the binary data
|
||||
SLOT_OWNS = 3, // JSVAL_TRUE if this CData owns its own buffer
|
||||
SLOT_FUNNAME = 4, // JSString representing the function name
|
||||
CDATA_SLOTS
|
||||
};
|
||||
|
||||
|
||||
@@ -321,7 +321,7 @@ Library::Declare(JSContext* cx, unsigned argc, jsval* vp)
|
||||
|
||||
void* data;
|
||||
PRFuncPtr fnptr;
|
||||
JSString* nameStr = args[0].toString();
|
||||
RootedString nameStr(cx, args[0].toString());
|
||||
AutoCString symbol;
|
||||
if (isFunction) {
|
||||
// Build the symbol, with mangling if necessary.
|
||||
@@ -352,6 +352,9 @@ Library::Declare(JSContext* cx, unsigned argc, jsval* vp)
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
if (isFunction)
|
||||
JS_SetReservedSlot(result, SLOT_FUNNAME, StringValue(nameStr));
|
||||
|
||||
args.rval().setObject(*result);
|
||||
|
||||
// Seal the CData object, to prevent modification of the function pointer.
|
||||
|
||||
@@ -10,5 +10,30 @@
|
||||
*/
|
||||
|
||||
MSG_DEF(CTYPESMSG_PLACEHOLDER_0, 0, JSEXN_NONE, NULL)
|
||||
MSG_DEF(CTYPESMSG_TYPE_ERROR, 2, JSEXN_TYPEERR, "expected type {0}, got {1}")
|
||||
|
||||
/* type conversion */
|
||||
MSG_DEF(CTYPESMSG_CONV_ERROR_ARG,3, JSEXN_TYPEERR, "can't pass {0} to argument {1} of {2}")
|
||||
MSG_DEF(CTYPESMSG_CONV_ERROR_ARRAY,3, JSEXN_TYPEERR, "can't convert {0} to element {1} of the type {2}")
|
||||
MSG_DEF(CTYPESMSG_CONV_ERROR_FIN,2, JSEXN_TYPEERR, "can't convert {0} to the type of argument 1 of {1}")
|
||||
MSG_DEF(CTYPESMSG_CONV_ERROR_RET,2, JSEXN_TYPEERR, "can't convert {0} to the return type of {1}")
|
||||
MSG_DEF(CTYPESMSG_CONV_ERROR_SET,2, JSEXN_TYPEERR, "can't convert {0} to the type {1}")
|
||||
MSG_DEF(CTYPESMSG_CONV_ERROR_STRUCT,5, JSEXN_TYPEERR, "can't convert {0} to the '{1}' field ({2}) of {3}{4}")
|
||||
MSG_DEF(CTYPESMSG_NON_PRIMITIVE, 1, JSEXN_TYPEERR, ".value only works on character and numeric types, not `{0}`")
|
||||
MSG_DEF(CTYPESMSG_TYPE_ERROR, 2, JSEXN_TYPEERR, "expected {0}, got {1}")
|
||||
|
||||
/* array */
|
||||
MSG_DEF(CTYPESMSG_ARRAY_MISMATCH,4, JSEXN_TYPEERR, "length of {0} does not match to the length of the type {1} (expected {2}, got {3})")
|
||||
MSG_DEF(CTYPESMSG_ARRAY_OVERFLOW,4, JSEXN_TYPEERR, "length of {0} does not fit to the length of the type {1} (expected {2} or lower, got {3})")
|
||||
|
||||
/* struct */
|
||||
MSG_DEF(CTYPESMSG_FIELD_MISMATCH,5, JSEXN_TYPEERR, "property count of {0} does not match to field count of the type {1} (expected {2}, got {3}){4}")
|
||||
MSG_DEF(CTYPESMSG_PROP_NONSTRING,3, JSEXN_TYPEERR, "property name {0} of {1} is not a string{2}")
|
||||
|
||||
/* data finalizer */
|
||||
MSG_DEF(CTYPESMSG_EMPTY_FIN, 1, JSEXN_TYPEERR, "attempting to convert an empty CDataFinalizer{0}")
|
||||
MSG_DEF(CTYPESMSG_FIN_SIZE_ERROR,2, JSEXN_TYPEERR, "expected an object with the same size as argument 1 of {0}, got {1}")
|
||||
|
||||
/* native function */
|
||||
MSG_DEF(CTYPESMSG_ARG_RANGE_MISMATCH,3, JSEXN_RANGEERR, "{0}argument of {1} must be {2}")
|
||||
MSG_DEF(CTYPESMSG_ARG_TYPE_MISMATCH,3, JSEXN_TYPEERR, "{0}argument of {1} must be {2}")
|
||||
MSG_DEF(CTYPESMSG_WRONG_ARG_LENGTH,3, JSEXN_TYPEERR, "{0} takes {1} argument{2}")
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
#include "frontend/Parser-inl.h"
|
||||
#include "vm/ScopeObject-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::frontend;
|
||||
@@ -328,7 +329,7 @@ frontend::CompileScript(ExclusiveContext* cx, LifoAlloc* alloc, HandleObject sco
|
||||
TokenStream::Position pos(parser.keepAtoms);
|
||||
parser.tokenStream.tell(&pos);
|
||||
|
||||
ParseNode* pn = parser.statement(canHaveDirectives);
|
||||
ParseNode* pn = parser.statement(YieldIsName, canHaveDirectives);
|
||||
if (!pn) {
|
||||
if (parser.hadAbortedSyntaxParse()) {
|
||||
// Parsing inner functions lazily may lead the parser into an
|
||||
@@ -352,7 +353,7 @@ frontend::CompileScript(ExclusiveContext* cx, LifoAlloc* alloc, HandleObject sco
|
||||
return nullptr;
|
||||
MOZ_ASSERT(parser.pc == pc.ptr());
|
||||
|
||||
pn = parser.statement();
|
||||
pn = parser.statement(YieldIsName);
|
||||
}
|
||||
if (!pn) {
|
||||
MOZ_ASSERT(!parser.hadAbortedSyntaxParse());
|
||||
|
||||
@@ -625,6 +625,15 @@ class FullParseHandler
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isReturnStatement(ParseNode* node) {
|
||||
return node->isKind(PNK_RETURN);
|
||||
}
|
||||
|
||||
bool isStatementPermittedAfterReturnStatement(ParseNode *node) {
|
||||
ParseNodeKind kind = node->getKind();
|
||||
return kind == PNK_FUNCTION || kind == PNK_VAR || kind == PNK_BREAK || kind == PNK_THROW;
|
||||
}
|
||||
|
||||
inline bool finishInitializerAssignment(ParseNode* pn, ParseNode* init, JSOp op);
|
||||
|
||||
void setBeginPosition(ParseNode* pn, ParseNode* oth) {
|
||||
@@ -651,11 +660,23 @@ class FullParseHandler
|
||||
}
|
||||
|
||||
ParseNode* newList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
|
||||
MOZ_ASSERT(kind != PNK_VAR);
|
||||
return new_<ListNode>(kind, op, pos());
|
||||
}
|
||||
ParseNode* newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
|
||||
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET ||
|
||||
kind == PNK_GLOBALCONST);
|
||||
return new_<ListNode>(kind, op, pos());
|
||||
}
|
||||
|
||||
/* New list with one initial child node. kid must be non-null. */
|
||||
ParseNode* newList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) {
|
||||
MOZ_ASSERT(kind != PNK_VAR);
|
||||
return new_<ListNode>(kind, op, kid);
|
||||
}
|
||||
ParseNode* newDeclarationList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) {
|
||||
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET ||
|
||||
kind == PNK_GLOBALCONST);
|
||||
return new_<ListNode>(kind, op, kid);
|
||||
}
|
||||
|
||||
|
||||
+457
-328
File diff suppressed because it is too large
Load Diff
+77
-58
@@ -330,6 +330,13 @@ enum VarContext { HoistVars, DontHoistVars };
|
||||
enum FunctionType { Getter, Setter, Normal };
|
||||
enum PropListType { ObjectLiteral, ClassBody };
|
||||
|
||||
// Specify a value for an ES6 grammar parametrization. We have no enum for
|
||||
// [Return] because its behavior is exactly equivalent to checking whether
|
||||
// we're in a function box -- easier and simpler than passing an extra
|
||||
// parameter everywhere.
|
||||
enum YieldHandling { YieldIsName, YieldIsKeyword };
|
||||
enum InHandling { InAllowed, InProhibited };
|
||||
|
||||
template <typename ParseHandler>
|
||||
class Parser : private JS::AutoGCRooter, public StrictModeGetter
|
||||
{
|
||||
@@ -459,10 +466,11 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
|
||||
|
||||
Node stringLiteral();
|
||||
Node noSubstitutionTemplate();
|
||||
Node templateLiteral();
|
||||
bool taggedTemplate(Node nodeList, TokenKind tt);
|
||||
Node templateLiteral(YieldHandling yieldHandling);
|
||||
bool taggedTemplate(YieldHandling yieldHandling, Node nodeList, TokenKind tt);
|
||||
bool appendToCallSiteObj(Node callSiteObj);
|
||||
bool addExprAndGetNextTemplStrToken(Node nodeList, TokenKind* ttp);
|
||||
bool addExprAndGetNextTemplStrToken(YieldHandling yieldHandling, Node nodeList,
|
||||
TokenKind* ttp);
|
||||
|
||||
inline Node newName(PropertyName* name);
|
||||
inline Node newYieldExpression(uint32_t begin, Node expr, bool isYieldStar = false);
|
||||
@@ -470,9 +478,9 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
|
||||
inline bool abortIfSyntaxParser();
|
||||
|
||||
public:
|
||||
|
||||
/* Public entry points for parsing. */
|
||||
Node statement(bool canHaveDirectives = false);
|
||||
Node statement(YieldHandling yieldHandling, bool canHaveDirectives = false);
|
||||
|
||||
bool maybeParseDirective(Node list, Node pn, bool* cont);
|
||||
|
||||
// Parse a function, given only its body. Used for the Function and
|
||||
@@ -491,9 +499,11 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
|
||||
* statements; pass ExpressionBody if the body is a single expression.
|
||||
*/
|
||||
enum FunctionBodyType { StatementListBody, ExpressionBody };
|
||||
Node functionBody(FunctionSyntaxKind kind, FunctionBodyType type);
|
||||
Node functionBody(InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind,
|
||||
FunctionBodyType type);
|
||||
|
||||
bool functionArgsAndBodyGeneric(Node pn, HandleFunction fun, FunctionType type,
|
||||
bool functionArgsAndBodyGeneric(InHandling inHandling, YieldHandling yieldHandling, Node pn,
|
||||
HandleFunction fun, FunctionType type,
|
||||
FunctionSyntaxKind kind);
|
||||
|
||||
// Determine whether |yield| is a valid name in the current context, or
|
||||
@@ -534,66 +544,73 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
|
||||
* Some parsers have two versions: an always-inlined version (with an 'i'
|
||||
* suffix) and a never-inlined version (with an 'n' suffix).
|
||||
*/
|
||||
Node functionStmt();
|
||||
Node functionStmt(YieldHandling yieldHandling);
|
||||
Node functionExpr(InvokedPrediction invoked = PredictUninvoked);
|
||||
Node statements();
|
||||
Node statements(YieldHandling yieldHandling);
|
||||
|
||||
Node blockStatement();
|
||||
Node ifStatement();
|
||||
Node doWhileStatement();
|
||||
Node whileStatement();
|
||||
Node forStatement();
|
||||
Node switchStatement();
|
||||
Node continueStatement();
|
||||
Node breakStatement();
|
||||
Node returnStatement();
|
||||
Node withStatement();
|
||||
Node labeledStatement();
|
||||
Node throwStatement();
|
||||
Node tryStatement();
|
||||
Node blockStatement(YieldHandling yieldHandling);
|
||||
Node ifStatement(YieldHandling yieldHandling);
|
||||
Node doWhileStatement(YieldHandling yieldHandling);
|
||||
Node whileStatement(YieldHandling yieldHandling);
|
||||
Node forStatement(YieldHandling yieldHandling);
|
||||
Node switchStatement(YieldHandling yieldHandling);
|
||||
Node continueStatement(YieldHandling yieldHandling);
|
||||
Node breakStatement(YieldHandling yieldHandling);
|
||||
Node returnStatement(YieldHandling yieldHandling);
|
||||
Node withStatement(YieldHandling yieldHandling);
|
||||
Node labeledStatement(YieldHandling yieldHandling);
|
||||
Node throwStatement(YieldHandling yieldHandling);
|
||||
Node tryStatement(YieldHandling yieldHandling);
|
||||
Node debuggerStatement();
|
||||
|
||||
Node lexicalDeclaration(bool isConst);
|
||||
Node lexicalDeclaration(YieldHandling yieldHandling, bool isConst);
|
||||
Node importDeclaration();
|
||||
Node exportDeclaration();
|
||||
Node expressionStatement(InvokedPrediction invoked = PredictUninvoked);
|
||||
Node variables(ParseNodeKind kind, bool* psimple = nullptr,
|
||||
StaticBlockObject* blockObj = nullptr,
|
||||
VarContext varContext = HoistVars);
|
||||
Node expr(InvokedPrediction invoked = PredictUninvoked);
|
||||
Node assignExpr(InvokedPrediction invoked = PredictUninvoked);
|
||||
Node assignExprWithoutYield(unsigned err);
|
||||
Node yieldExpression();
|
||||
Node condExpr1(InvokedPrediction invoked = PredictUninvoked);
|
||||
Node orExpr1(InvokedPrediction invoked = PredictUninvoked);
|
||||
Node unaryExpr(InvokedPrediction invoked = PredictUninvoked);
|
||||
Node memberExpr(TokenKind tt, bool allowCallSyntax,
|
||||
Node expressionStatement(YieldHandling yieldHandling,
|
||||
InvokedPrediction invoked = PredictUninvoked);
|
||||
Node variables(YieldHandling yieldHandling,
|
||||
ParseNodeKind kind, bool* psimple = nullptr,
|
||||
StaticBlockObject* blockObj = nullptr, VarContext varContext = HoistVars);
|
||||
Node expr(InHandling inHandling, YieldHandling yieldHandling,
|
||||
InvokedPrediction invoked = PredictUninvoked);
|
||||
Node assignExpr(InHandling inHandling, YieldHandling yieldHandling,
|
||||
InvokedPrediction invoked = PredictUninvoked);
|
||||
Node primaryExpr(TokenKind tt, InvokedPrediction invoked = PredictUninvoked);
|
||||
Node parenExprOrGeneratorComprehension();
|
||||
Node exprInParens();
|
||||
Node assignExprWithoutYield(YieldHandling yieldHandling, unsigned err);
|
||||
Node yieldExpression(InHandling inHandling);
|
||||
Node condExpr1(InHandling inHandling, YieldHandling yieldHandling,
|
||||
InvokedPrediction invoked = PredictUninvoked);
|
||||
Node orExpr1(InHandling inHandling, YieldHandling yieldHandling,
|
||||
InvokedPrediction invoked = PredictUninvoked);
|
||||
Node unaryExpr(YieldHandling yieldHandling, InvokedPrediction invoked = PredictUninvoked);
|
||||
Node memberExpr(YieldHandling yieldHandling, TokenKind tt, bool allowCallSyntax,
|
||||
InvokedPrediction invoked = PredictUninvoked);
|
||||
Node primaryExpr(YieldHandling yieldHandling, TokenKind tt,
|
||||
InvokedPrediction invoked = PredictUninvoked);
|
||||
Node parenExprOrGeneratorComprehension(YieldHandling yieldHandling);
|
||||
Node exprInParens(InHandling inHandling, YieldHandling yieldHandling);
|
||||
|
||||
bool checkAndMarkSuperScope();
|
||||
|
||||
bool methodDefinition(PropListType listType, Node propList, Node propname, FunctionType type,
|
||||
GeneratorKind generatorKind, bool isStatic, JSOp Op);
|
||||
bool methodDefinition(YieldHandling yieldHandling, PropListType listType, Node propList,
|
||||
Node propname, FunctionType type, GeneratorKind generatorKind,
|
||||
bool isStatic, JSOp Op);
|
||||
|
||||
/*
|
||||
* Additional JS parsers.
|
||||
*/
|
||||
bool functionArguments(FunctionSyntaxKind kind, FunctionType type, Node* list, Node funcpn,
|
||||
bool* hasRest);
|
||||
bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind, FunctionType type,
|
||||
Node* list, Node funcpn, bool* hasRest);
|
||||
|
||||
Node functionDef(HandlePropertyName name, FunctionType type, FunctionSyntaxKind kind,
|
||||
GeneratorKind generatorKind, InvokedPrediction invoked = PredictUninvoked);
|
||||
bool functionArgsAndBody(Node pn, HandleFunction fun,
|
||||
FunctionType type, FunctionSyntaxKind kind,
|
||||
GeneratorKind generatorKind,
|
||||
Node functionDef(InHandling inHandling, YieldHandling uieldHandling, HandlePropertyName name,
|
||||
FunctionType type, FunctionSyntaxKind kind, GeneratorKind generatorKind,
|
||||
InvokedPrediction invoked = PredictUninvoked);
|
||||
bool functionArgsAndBody(InHandling inHandling, Node pn, HandleFunction fun, FunctionType type,
|
||||
FunctionSyntaxKind kind, GeneratorKind generatorKind,
|
||||
Directives inheritedDirectives, Directives* newDirectives);
|
||||
|
||||
Node unaryOpExpr(ParseNodeKind kind, JSOp op, uint32_t begin);
|
||||
Node unaryOpExpr(YieldHandling yieldHandling, ParseNodeKind kind, JSOp op, uint32_t begin);
|
||||
|
||||
Node condition();
|
||||
Node condition(InHandling inHandling, YieldHandling yieldHandling);
|
||||
|
||||
Node generatorComprehensionLambda(GeneratorKind comprehensionKind, unsigned begin,
|
||||
Node innerStmt);
|
||||
@@ -611,16 +628,18 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
|
||||
Node arrayComprehension(uint32_t begin);
|
||||
Node generatorComprehension(uint32_t begin);
|
||||
|
||||
bool argumentList(Node listNode, bool* isSpread);
|
||||
Node destructuringExpr(BindData<ParseHandler>* data, TokenKind tt);
|
||||
Node destructuringExprWithoutYield(BindData<ParseHandler>* data, TokenKind tt, unsigned msg);
|
||||
bool argumentList(YieldHandling yieldHandling, Node listNode, bool* isSpread);
|
||||
Node destructuringExpr(YieldHandling yieldHandling, BindData<ParseHandler>* data,
|
||||
TokenKind tt);
|
||||
Node destructuringExprWithoutYield(YieldHandling yieldHandling, BindData<ParseHandler>* data,
|
||||
TokenKind tt, unsigned msg);
|
||||
|
||||
enum ClassContext { ClassStatement, ClassExpression };
|
||||
Node classDefinition(ClassContext classContext);
|
||||
Node classDefinition(YieldHandling yieldHandling, ClassContext classContext);
|
||||
|
||||
Node identifierName();
|
||||
Node identifierName(YieldHandling yieldHandling);
|
||||
|
||||
bool matchLabel(MutableHandle<PropertyName*> label);
|
||||
bool matchLabel(YieldHandling yieldHandling, MutableHandle<PropertyName*> label);
|
||||
|
||||
bool allowsForEachIn() {
|
||||
#if !JS_HAS_FOR_EACH_IN
|
||||
@@ -659,11 +678,11 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
|
||||
Node pushLexicalScope(Handle<StaticBlockObject*> blockObj, StmtInfoPC* stmt);
|
||||
Node pushLetScope(Handle<StaticBlockObject*> blockObj, StmtInfoPC* stmt);
|
||||
bool noteNameUse(HandlePropertyName name, Node pn);
|
||||
Node computedPropertyName(Node literal);
|
||||
Node arrayInitializer();
|
||||
Node computedPropertyName(YieldHandling yieldHandling, Node literal);
|
||||
Node arrayInitializer(YieldHandling yieldHandling);
|
||||
Node newRegExp();
|
||||
|
||||
Node propertyList(PropListType type);
|
||||
Node propertyList(YieldHandling yieldHandling, PropListType type);
|
||||
Node newPropertyListNode(PropListType type);
|
||||
|
||||
bool checkAndPrepareLexical(bool isConst, const TokenPos &errorPos);
|
||||
|
||||
@@ -43,6 +43,10 @@ class SyntaxParseHandler
|
||||
NodeGetProp,
|
||||
NodeStringExprStatement,
|
||||
NodeLValue,
|
||||
NodeReturn,
|
||||
NodeHoistableDeclaration,
|
||||
NodeBreak,
|
||||
NodeThrow,
|
||||
|
||||
// In rare cases a parenthesized |node| doesn't have the same semantics
|
||||
// as |node|. Each such node has a special Node value, and we use a
|
||||
@@ -214,14 +218,14 @@ class SyntaxParseHandler
|
||||
Node newSwitchStatement(uint32_t begin, Node discriminant, Node caseList) { return NodeGeneric; }
|
||||
Node newCaseOrDefault(uint32_t begin, Node expr, Node body) { return NodeGeneric; }
|
||||
Node newContinueStatement(PropertyName* label, const TokenPos& pos) { return NodeGeneric; }
|
||||
Node newBreakStatement(PropertyName* label, const TokenPos& pos) { return NodeGeneric; }
|
||||
Node newReturnStatement(Node expr, Node genrval, const TokenPos& pos) { return NodeGeneric; }
|
||||
Node newBreakStatement(PropertyName* label, const TokenPos& pos) { return NodeBreak; }
|
||||
Node newReturnStatement(Node expr, Node genrval, const TokenPos& pos) { return NodeReturn; }
|
||||
|
||||
Node newLabeledStatement(PropertyName* label, Node stmt, uint32_t begin) {
|
||||
return NodeGeneric;
|
||||
}
|
||||
|
||||
Node newThrowStatement(Node expr, const TokenPos& pos) { return NodeGeneric; }
|
||||
Node newThrowStatement(Node expr, const TokenPos& pos) { return NodeThrow; }
|
||||
Node newTryStatement(uint32_t begin, Node body, Node catchList, Node finallyBlock) {
|
||||
return NodeGeneric;
|
||||
}
|
||||
@@ -238,7 +242,7 @@ class SyntaxParseHandler
|
||||
Node catchName, Node catchGuard, Node catchBody) { return true; }
|
||||
|
||||
void setLastFunctionArgumentDefault(Node funcpn, Node pn) {}
|
||||
Node newFunctionDefinition() { return NodeGeneric; }
|
||||
Node newFunctionDefinition() { return NodeHoistableDeclaration; }
|
||||
void setFunctionBody(Node pn, Node kid) {}
|
||||
void setFunctionBox(Node pn, FunctionBox* funbox) {}
|
||||
void addFunctionArgument(Node pn, Node argpn) {}
|
||||
@@ -273,11 +277,23 @@ class SyntaxParseHandler
|
||||
}
|
||||
|
||||
Node newList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
|
||||
MOZ_ASSERT(kind != PNK_VAR);
|
||||
return NodeGeneric;
|
||||
}
|
||||
Node newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
|
||||
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET ||
|
||||
kind == PNK_GLOBALCONST);
|
||||
return kind == PNK_VAR ? NodeHoistableDeclaration : NodeGeneric;
|
||||
}
|
||||
Node newList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) {
|
||||
MOZ_ASSERT(kind != PNK_VAR);
|
||||
return NodeGeneric;
|
||||
}
|
||||
Node newDeclarationList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) {
|
||||
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET ||
|
||||
kind == PNK_GLOBALCONST);
|
||||
return kind == PNK_VAR ? NodeHoistableDeclaration : NodeGeneric;
|
||||
}
|
||||
|
||||
Node newCatchList() {
|
||||
return newList(PNK_CATCHLIST, JSOP_NOP);
|
||||
@@ -288,7 +304,8 @@ class SyntaxParseHandler
|
||||
}
|
||||
|
||||
void addList(Node list, Node kid) {
|
||||
MOZ_ASSERT(list == NodeGeneric || list == NodeUnparenthesizedCommaExpr);
|
||||
MOZ_ASSERT(list == NodeGeneric || list == NodeUnparenthesizedCommaExpr ||
|
||||
list == NodeHoistableDeclaration);
|
||||
}
|
||||
|
||||
Node newAssignment(ParseNodeKind kind, Node lhs, Node rhs,
|
||||
@@ -311,6 +328,14 @@ class SyntaxParseHandler
|
||||
return node == NodeUnparenthesizedAssignment;
|
||||
}
|
||||
|
||||
bool isReturnStatement(Node node) {
|
||||
return node == NodeReturn;
|
||||
}
|
||||
|
||||
bool isStatementPermittedAfterReturnStatement(Node pn) {
|
||||
return pn == NodeHoistableDeclaration || pn == NodeBreak || pn == NodeThrow;
|
||||
}
|
||||
|
||||
void setOp(Node pn, JSOp op) {}
|
||||
void setBlockId(Node pn, unsigned blockid) {}
|
||||
void setFlag(Node pn, unsigned flag) {}
|
||||
|
||||
@@ -322,33 +322,6 @@ TokenStream::TokenStream(ExclusiveContext* cx, const ReadOnlyCompileOptions& opt
|
||||
isExprEnding[TOK_RP] = 1;
|
||||
isExprEnding[TOK_RB] = 1;
|
||||
isExprEnding[TOK_RC] = 1;
|
||||
|
||||
memset(isExprStarting, 0, sizeof(isExprStarting));
|
||||
isExprStarting[TOK_INC] = 1;
|
||||
isExprStarting[TOK_DEC] = 1;
|
||||
isExprStarting[TOK_LB] = 1;
|
||||
isExprStarting[TOK_LC] = 1;
|
||||
isExprStarting[TOK_LP] = 1;
|
||||
isExprStarting[TOK_NAME] = 1;
|
||||
isExprStarting[TOK_NUMBER] = 1;
|
||||
isExprStarting[TOK_STRING] = 1;
|
||||
isExprStarting[TOK_TEMPLATE_HEAD] = 1;
|
||||
isExprStarting[TOK_NO_SUBS_TEMPLATE] = 1;
|
||||
isExprStarting[TOK_REGEXP] = 1;
|
||||
isExprStarting[TOK_TRUE] = 1;
|
||||
isExprStarting[TOK_FALSE] = 1;
|
||||
isExprStarting[TOK_NULL] = 1;
|
||||
isExprStarting[TOK_THIS] = 1;
|
||||
isExprStarting[TOK_NEW] = 1;
|
||||
isExprStarting[TOK_DELETE] = 1;
|
||||
isExprStarting[TOK_YIELD] = 1;
|
||||
isExprStarting[TOK_CLASS] = 1;
|
||||
isExprStarting[TOK_ADD] = 1;
|
||||
isExprStarting[TOK_SUB] = 1;
|
||||
isExprStarting[TOK_TYPEOF] = 1;
|
||||
isExprStarting[TOK_VOID] = 1;
|
||||
isExprStarting[TOK_NOT] = 1;
|
||||
isExprStarting[TOK_BITNOT] = 1;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
@@ -500,14 +500,6 @@ class MOZ_STACK_CLASS TokenStream
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nextTokenStartsExpr(bool* startsExpr, Modifier modifier = None) {
|
||||
TokenKind tt;
|
||||
if (!peekToken(&tt, modifier))
|
||||
return false;
|
||||
*startsExpr = isExprStarting[tt];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nextTokenEndsExpr(bool* endsExpr) {
|
||||
TokenKind tt;
|
||||
if (!peekToken(&tt))
|
||||
@@ -844,7 +836,6 @@ class MOZ_STACK_CLASS TokenStream
|
||||
mozilla::UniquePtr<char16_t[], JS::FreePolicy> displayURL_; // the user's requested source URL or null
|
||||
mozilla::UniquePtr<char16_t[], JS::FreePolicy> sourceMapURL_; // source map's filename or null
|
||||
CharBuffer tokenbuf; // current token string buffer
|
||||
uint8_t isExprStarting[TOK_LIMIT];// which tokens can start exprs?
|
||||
uint8_t isExprEnding[TOK_LIMIT];// which tokens definitely terminate exprs?
|
||||
ExclusiveContext* const cx;
|
||||
bool mutedErrors;
|
||||
|
||||
@@ -72,7 +72,10 @@ GCRuntime::checkAllocatorState(JSContext* cx, AllocKind kind)
|
||||
|
||||
// For testing out of memory conditions
|
||||
if (js::oom::ShouldFailWithOOM()) {
|
||||
ReportOutOfMemory(cx);
|
||||
// If we are doing a fallible allocation, percolate up the OOM
|
||||
// instead of reporting it.
|
||||
if (allowGC)
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -733,6 +733,7 @@ typedef ReadBarriered<DebugScopeObject*> ReadBarrieredDebugScopeObject;
|
||||
typedef ReadBarriered<GlobalObject*> ReadBarrieredGlobalObject;
|
||||
typedef ReadBarriered<JSFunction*> ReadBarrieredFunction;
|
||||
typedef ReadBarriered<JSObject*> ReadBarrieredObject;
|
||||
typedef ReadBarriered<JSScript*> ReadBarrieredScript;
|
||||
typedef ReadBarriered<ScriptSourceObject*> ReadBarrieredScriptSourceObject;
|
||||
typedef ReadBarriered<Shape*> ReadBarrieredShape;
|
||||
typedef ReadBarriered<UnownedBaseShape*> ReadBarrieredUnownedBaseShape;
|
||||
|
||||
@@ -619,6 +619,7 @@ class GCRuntime
|
||||
void startGC(JSGCInvocationKind gckind, JS::gcreason::Reason reason, int64_t millis = 0);
|
||||
void gcSlice(JS::gcreason::Reason reason, int64_t millis = 0);
|
||||
void finishGC(JS::gcreason::Reason reason);
|
||||
void abortGC();
|
||||
void startDebugGC(JSGCInvocationKind gckind, SliceBudget& budget);
|
||||
void debugGCSlice(SliceBudget& budget);
|
||||
|
||||
|
||||
+25
-13
@@ -77,7 +77,10 @@ enum InitialHeap {
|
||||
/* The GC allocation kinds. */
|
||||
enum class AllocKind : uint8_t {
|
||||
FIRST,
|
||||
OBJECT0 = FIRST,
|
||||
OBJECT_FIRST = FIRST,
|
||||
FUNCTION = FIRST,
|
||||
FUNCTION_EXTENDED,
|
||||
OBJECT0,
|
||||
OBJECT0_BACKGROUND,
|
||||
OBJECT2,
|
||||
OBJECT2_BACKGROUND,
|
||||
@@ -108,13 +111,13 @@ enum class AllocKind : uint8_t {
|
||||
|
||||
static_assert(int(AllocKind::FIRST) == 0, "Various places depend on AllocKind starting at 0, "
|
||||
"please audit them carefully!");
|
||||
static_assert(int(AllocKind::OBJECT0) == 0, "Various places depend on AllocKind::OBJECT0 being 0, "
|
||||
"please audit them carefully!");
|
||||
static_assert(int(AllocKind::OBJECT_FIRST) == 0, "Various places depend on AllocKind::OBJECT_FIRST "
|
||||
"being 0, please audit them carefully!");
|
||||
|
||||
inline bool
|
||||
IsObjectAllocKind(AllocKind kind)
|
||||
{
|
||||
return kind >= AllocKind::OBJECT0 && kind <= AllocKind::OBJECT_LAST;
|
||||
return kind >= AllocKind::OBJECT_FIRST && kind <= AllocKind::OBJECT_LAST;
|
||||
}
|
||||
|
||||
inline bool
|
||||
@@ -138,10 +141,10 @@ AllAllocKinds()
|
||||
|
||||
// Returns a sequence for use in a range-based for loop,
|
||||
// to iterate over all object alloc kinds.
|
||||
inline decltype(mozilla::MakeEnumeratedRange<int>(AllocKind::OBJECT0, AllocKind::OBJECT_LIMIT))
|
||||
inline decltype(mozilla::MakeEnumeratedRange<int>(AllocKind::OBJECT_FIRST, AllocKind::OBJECT_LIMIT))
|
||||
ObjectAllocKinds()
|
||||
{
|
||||
return mozilla::MakeEnumeratedRange<int>(AllocKind::OBJECT0, AllocKind::OBJECT_LIMIT);
|
||||
return mozilla::MakeEnumeratedRange<int>(AllocKind::OBJECT_FIRST, AllocKind::OBJECT_LIMIT);
|
||||
}
|
||||
|
||||
// Returns a sequence for use in a range-based for loop,
|
||||
@@ -168,6 +171,8 @@ static inline JSGCTraceKind
|
||||
MapAllocToTraceKind(AllocKind kind)
|
||||
{
|
||||
static const JSGCTraceKind map[] = {
|
||||
JSTRACE_OBJECT, /* AllocKind::FUNCTION */
|
||||
JSTRACE_OBJECT, /* AllocKind::FUNCTION_EXTENDED */
|
||||
JSTRACE_OBJECT, /* AllocKind::OBJECT0 */
|
||||
JSTRACE_OBJECT, /* AllocKind::OBJECT0_BACKGROUND */
|
||||
JSTRACE_OBJECT, /* AllocKind::OBJECT2 */
|
||||
@@ -1022,19 +1027,20 @@ struct Chunk
|
||||
ArenaHeader* allocateArena(JSRuntime* rt, JS::Zone* zone, AllocKind kind,
|
||||
const AutoLockGC& lock);
|
||||
|
||||
enum ArenaDecommitState { IsCommitted = false, IsDecommitted = true };
|
||||
void releaseArena(JSRuntime* rt, ArenaHeader* aheader, const AutoLockGC& lock,
|
||||
ArenaDecommitState state = IsCommitted);
|
||||
void releaseArena(JSRuntime* rt, ArenaHeader* aheader, const AutoLockGC& lock);
|
||||
void recycleArena(ArenaHeader* aheader, SortedArenaList& dest, AllocKind thingKind,
|
||||
size_t thingsPerArena);
|
||||
|
||||
static Chunk* allocate(JSRuntime* rt);
|
||||
bool decommitOneFreeArena(JSRuntime* rt, AutoLockGC& lock);
|
||||
void decommitAllArenasWithoutUnlocking(const AutoLockGC& lock);
|
||||
|
||||
void decommitAllArenas(JSRuntime* rt);
|
||||
static Chunk* allocate(JSRuntime* rt);
|
||||
|
||||
private:
|
||||
inline void init(JSRuntime* rt);
|
||||
|
||||
void decommitAllArenas(JSRuntime* rt);
|
||||
|
||||
/* Search for a decommitted arena to allocate. */
|
||||
unsigned findDecommittedArenaOffset();
|
||||
ArenaHeader* fetchNextDecommittedArena();
|
||||
@@ -1042,6 +1048,9 @@ struct Chunk
|
||||
void addArenaToFreeList(JSRuntime* rt, ArenaHeader* aheader);
|
||||
void addArenaToDecommittedList(JSRuntime* rt, const ArenaHeader* aheader);
|
||||
|
||||
void updateChunkListAfterAlloc(JSRuntime* rt, const AutoLockGC& lock);
|
||||
void updateChunkListAfterFree(JSRuntime* rt, const AutoLockGC& lock);
|
||||
|
||||
public:
|
||||
/* Unlink and return the freeArenasHead. */
|
||||
inline ArenaHeader* fetchNextFreeArena(JSRuntime* rt);
|
||||
@@ -1112,6 +1121,7 @@ inline uintptr_t
|
||||
ArenaHeader::address() const
|
||||
{
|
||||
uintptr_t addr = reinterpret_cast<uintptr_t>(this);
|
||||
MOZ_ASSERT(addr);
|
||||
MOZ_ASSERT(!(addr & ArenaMask));
|
||||
MOZ_ASSERT(Chunk::withinArenasRange(addr));
|
||||
return addr;
|
||||
@@ -1175,7 +1185,8 @@ ArenaHeader::setNextDelayedMarking(ArenaHeader* aheader)
|
||||
MOZ_ASSERT(!(uintptr_t(aheader) & ArenaMask));
|
||||
MOZ_ASSERT(!auxNextLink && !hasDelayedMarking);
|
||||
hasDelayedMarking = 1;
|
||||
auxNextLink = aheader->arenaAddress() >> ArenaShift;
|
||||
if (aheader)
|
||||
auxNextLink = aheader->arenaAddress() >> ArenaShift;
|
||||
}
|
||||
|
||||
inline void
|
||||
@@ -1198,7 +1209,8 @@ ArenaHeader::setNextAllocDuringSweep(ArenaHeader* aheader)
|
||||
{
|
||||
MOZ_ASSERT(!auxNextLink && !allocatedDuringIncremental);
|
||||
allocatedDuringIncremental = 1;
|
||||
auxNextLink = aheader->arenaAddress() >> ArenaShift;
|
||||
if (aheader)
|
||||
auxNextLink = aheader->arenaAddress() >> ArenaShift;
|
||||
}
|
||||
|
||||
inline void
|
||||
|
||||
+146
-155
@@ -39,6 +39,7 @@ using mozilla::DebugOnly;
|
||||
using mozilla::IsBaseOf;
|
||||
using mozilla::IsSame;
|
||||
using mozilla::MakeRange;
|
||||
using mozilla::PodCopy;
|
||||
|
||||
// Tracing Overview
|
||||
// ================
|
||||
@@ -218,10 +219,10 @@ js::CheckTracedThing(JSTracer* trc, T thing)
|
||||
if (isGcMarkingTracer) {
|
||||
GCMarker* gcMarker = static_cast<GCMarker*>(trc);
|
||||
MOZ_ASSERT_IF(gcMarker->shouldCheckCompartments(),
|
||||
zone->isCollecting() || rt->isAtomsZone(zone));
|
||||
zone->isCollecting() || zone->isAtomsZone());
|
||||
|
||||
MOZ_ASSERT_IF(gcMarker->markColor() == GRAY,
|
||||
!zone->isGCMarkingBlack() || rt->isAtomsZone(zone));
|
||||
!zone->isGCMarkingBlack() || zone->isAtomsZone());
|
||||
|
||||
MOZ_ASSERT(!(zone->isGCSweeping() || zone->isGCFinished() || zone->isGCCompacting()));
|
||||
}
|
||||
@@ -326,8 +327,7 @@ AssertZoneIsMarking(JSString* str)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
Zone* zone = TenuredCell::fromPointer(str)->zone();
|
||||
JSRuntime* rt = str->runtimeFromMainThread();
|
||||
MOZ_ASSERT(zone->isGCMarking() || rt->isAtomsZone(zone));
|
||||
MOZ_ASSERT(zone->isGCMarking() || zone->isAtomsZone());
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -336,8 +336,7 @@ AssertZoneIsMarking(JS::Symbol* sym)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
Zone* zone = TenuredCell::fromPointer(sym)->zone();
|
||||
JSRuntime* rt = sym->runtimeFromMainThread();
|
||||
MOZ_ASSERT(zone->isGCMarking() || rt->isAtomsZone(zone));
|
||||
MOZ_ASSERT(zone->isGCMarking() || zone->isAtomsZone());
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -671,6 +670,7 @@ DoMarking(GCMarker* gcmarker, T thing)
|
||||
if (MustSkipMarking(thing))
|
||||
return;
|
||||
|
||||
CheckTracedThing(gcmarker, thing);
|
||||
gcmarker->traverse(thing);
|
||||
|
||||
// Mark the compartment as live.
|
||||
@@ -761,10 +761,10 @@ GCMarker::traverse(AccessorShape* thing) {
|
||||
|
||||
template <typename S, typename T>
|
||||
void
|
||||
js::GCMarker::traverse(S source, T target)
|
||||
js::GCMarker::traverseEdge(S source, T target)
|
||||
{
|
||||
MOZ_ASSERT_IF(!ThingIsPermanentAtomOrWellKnownSymbol(target),
|
||||
runtime()->isAtomsZone(target->zone()) || target->zone() == source->zone());
|
||||
target->zone()->isAtomsZone() || target->zone() == source->zone());
|
||||
traverse(target);
|
||||
}
|
||||
|
||||
@@ -772,31 +772,37 @@ namespace js {
|
||||
// Special-case JSObject->JSObject edges to check the compartment too.
|
||||
template <>
|
||||
void
|
||||
GCMarker::traverse(JSObject* source, JSObject* target)
|
||||
GCMarker::traverseEdge(JSObject* source, JSObject* target)
|
||||
{
|
||||
MOZ_ASSERT(target->compartment() == source->compartment());
|
||||
traverse(target);
|
||||
}
|
||||
} // namespace js
|
||||
|
||||
template <typename V, typename S> struct TraverseFunctor : public VoidDefaultAdaptor<V> {
|
||||
template <typename V, typename S> struct TraverseEdgeFunctor : public VoidDefaultAdaptor<V> {
|
||||
template <typename T> void operator()(T t, GCMarker* gcmarker, S s) {
|
||||
return gcmarker->traverse(s, t);
|
||||
return gcmarker->traverseEdge(s, t);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename S>
|
||||
void
|
||||
js::GCMarker::traverse(S source, jsid id)
|
||||
js::GCMarker::traverseEdge(S source, jsid id)
|
||||
{
|
||||
DispatchIdTyped(TraverseFunctor<jsid, S>(), id, this, source);
|
||||
DispatchIdTyped(TraverseEdgeFunctor<jsid, S>(), id, this, source);
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
void
|
||||
js::GCMarker::traverseEdge(S source, Value v)
|
||||
{
|
||||
DispatchValueTyped(TraverseEdgeFunctor<Value, S>(), v, this, source);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
js::GCMarker::mark(T* thing)
|
||||
{
|
||||
CheckTracedThing(this, thing);
|
||||
AssertZoneIsMarking(thing);
|
||||
MOZ_ASSERT(!IsInsideNursery(gc::TenuredCell::fromPointer(thing)));
|
||||
return gc::ParticipatesInCC<T>::value
|
||||
@@ -823,9 +829,6 @@ LazyScript::traceChildren(JSTracer* trc)
|
||||
if (enclosingScope_)
|
||||
TraceEdge(trc, &enclosingScope_, "enclosingScope");
|
||||
|
||||
if (script_)
|
||||
TraceEdge(trc, &script_, "realScript");
|
||||
|
||||
// We rely on the fact that atoms are always tenured.
|
||||
FreeVariable* freeVariables = this->freeVariables();
|
||||
for (auto i : MakeRange(numFreeVariables())) {
|
||||
@@ -841,25 +844,22 @@ inline void
|
||||
js::GCMarker::eagerlyMarkChildren(LazyScript *thing)
|
||||
{
|
||||
if (thing->function_)
|
||||
traverse(thing, static_cast<JSObject*>(thing->function_));
|
||||
traverseEdge(thing, static_cast<JSObject*>(thing->function_));
|
||||
|
||||
if (thing->sourceObject_)
|
||||
traverse(thing, static_cast<JSObject*>(thing->sourceObject_));
|
||||
traverseEdge(thing, static_cast<JSObject*>(thing->sourceObject_));
|
||||
|
||||
if (thing->enclosingScope_)
|
||||
traverse(thing, static_cast<JSObject*>(thing->enclosingScope_));
|
||||
|
||||
if (thing->script_)
|
||||
traverse(thing, static_cast<JSScript*>(thing->script_));
|
||||
traverseEdge(thing, static_cast<JSObject*>(thing->enclosingScope_));
|
||||
|
||||
// We rely on the fact that atoms are always tenured.
|
||||
LazyScript::FreeVariable* freeVariables = thing->freeVariables();
|
||||
for (auto i : MakeRange(thing->numFreeVariables()))
|
||||
traverse(thing, static_cast<JSString*>(freeVariables[i].atom()));
|
||||
traverseEdge(thing, static_cast<JSString*>(freeVariables[i].atom()));
|
||||
|
||||
HeapPtrFunction* innerFunctions = thing->innerFunctions();
|
||||
for (auto i : MakeRange(thing->numInnerFunctions()))
|
||||
traverse(thing, static_cast<JSObject*>(innerFunctions[i]));
|
||||
traverseEdge(thing, static_cast<JSObject*>(innerFunctions[i]));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -880,16 +880,16 @@ js::GCMarker::eagerlyMarkChildren(Shape* shape)
|
||||
{
|
||||
MOZ_ASSERT(shape->isMarked(this->markColor()));
|
||||
do {
|
||||
traverse(shape, shape->base());
|
||||
traverse(shape, shape->propidRef().get());
|
||||
traverseEdge(shape, shape->base());
|
||||
traverseEdge(shape, shape->propidRef().get());
|
||||
|
||||
// When triggered between slices on belhalf of a barrier, these
|
||||
// objects may reside in the nursery, so require an extra check.
|
||||
// FIXME: Bug 1157967 - remove the isTenured checks.
|
||||
if (shape->hasGetterObject() && shape->getterObject()->isTenured())
|
||||
traverse(shape, shape->getterObject());
|
||||
traverseEdge(shape, shape->getterObject());
|
||||
if (shape->hasSetterObject() && shape->setterObject()->isTenured())
|
||||
traverse(shape, shape->setterObject());
|
||||
traverseEdge(shape, shape->setterObject());
|
||||
|
||||
shape = shape->previous();
|
||||
} while (shape && mark(shape));
|
||||
@@ -1040,16 +1040,16 @@ js::GCMarker::lazilyMarkChildren(ObjectGroup* group)
|
||||
unsigned count = group->getPropertyCount();
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
if (ObjectGroup::Property* prop = group->getProperty(i))
|
||||
traverse(group, prop->id.get());
|
||||
traverseEdge(group, prop->id.get());
|
||||
}
|
||||
|
||||
if (group->proto().isObject())
|
||||
traverse(group, group->proto().toObject());
|
||||
traverseEdge(group, group->proto().toObject());
|
||||
|
||||
group->compartment()->mark();
|
||||
|
||||
if (GlobalObject* global = group->compartment()->unsafeUnbarrieredMaybeGlobal())
|
||||
traverse(group, static_cast<JSObject*>(global));
|
||||
traverseEdge(group, static_cast<JSObject*>(global));
|
||||
|
||||
if (group->newScript())
|
||||
group->newScript()->trace(this);
|
||||
@@ -1061,13 +1061,101 @@ js::GCMarker::lazilyMarkChildren(ObjectGroup* group)
|
||||
group->unboxedLayout().trace(this);
|
||||
|
||||
if (ObjectGroup* unboxedGroup = group->maybeOriginalUnboxedGroup())
|
||||
traverse(group, unboxedGroup);
|
||||
traverseEdge(group, unboxedGroup);
|
||||
|
||||
if (TypeDescr* descr = group->maybeTypeDescr())
|
||||
traverse(group, static_cast<JSObject*>(descr));
|
||||
traverseEdge(group, static_cast<JSObject*>(descr));
|
||||
|
||||
if (JSFunction* fun = group->maybeInterpretedFunction())
|
||||
traverse(group, static_cast<JSObject*>(fun));
|
||||
traverseEdge(group, static_cast<JSObject*>(fun));
|
||||
}
|
||||
|
||||
struct TraverseObjectFunctor
|
||||
{
|
||||
template <typename T>
|
||||
void operator()(T* thing, GCMarker* gcmarker, JSObject* src) {
|
||||
gcmarker->traverseEdge(src, *thing);
|
||||
}
|
||||
};
|
||||
|
||||
// Call the trace hook set on the object, if present. If further tracing of
|
||||
// NativeObject fields is required, this will return the native object.
|
||||
enum class CheckGeneration { DoChecks, NoChecks};
|
||||
template <typename Functor, typename... Args>
|
||||
static inline NativeObject*
|
||||
CallTraceHook(Functor f, JSTracer* trc, JSObject* obj, CheckGeneration check, Args&&... args)
|
||||
{
|
||||
const Class* clasp = obj->getClass();
|
||||
MOZ_ASSERT(clasp);
|
||||
MOZ_ASSERT(obj->isNative() == clasp->isNative());
|
||||
|
||||
if (!clasp->trace)
|
||||
return &obj->as<NativeObject>();
|
||||
|
||||
// Global objects all have the same trace hook. That hook is safe without barriers
|
||||
// if the global has no custom trace hook of its own, or has been moved to a different
|
||||
// compartment, and so can't have one.
|
||||
MOZ_ASSERT_IF(!(clasp->trace == JS_GlobalObjectTraceHook &&
|
||||
(!obj->compartment()->options().getTrace() || !obj->isOwnGlobal())),
|
||||
clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS);
|
||||
|
||||
if (clasp->trace == InlineTypedObject::obj_trace) {
|
||||
Shape** pshape = obj->as<InlineTypedObject>().addressOfShapeFromGC();
|
||||
f(pshape, mozilla::Forward<Args>(args)...);
|
||||
|
||||
InlineTypedObject& tobj = obj->as<InlineTypedObject>();
|
||||
if (tobj.typeDescr().hasTraceList()) {
|
||||
VisitTraceList(f, tobj.typeDescr().traceList(), tobj.inlineTypedMem(),
|
||||
mozilla::Forward<Args>(args)...);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (clasp == &UnboxedPlainObject::class_) {
|
||||
JSObject** pexpando = obj->as<UnboxedPlainObject>().addressOfExpando();
|
||||
if (*pexpando)
|
||||
f(pexpando, mozilla::Forward<Args>(args)...);
|
||||
|
||||
UnboxedPlainObject& unboxed = obj->as<UnboxedPlainObject>();
|
||||
const UnboxedLayout& layout = check == CheckGeneration::DoChecks
|
||||
? unboxed.layout()
|
||||
: unboxed.layoutDontCheckGeneration();
|
||||
if (layout.traceList()) {
|
||||
VisitTraceList(f, layout.traceList(), unboxed.data(),
|
||||
mozilla::Forward<Args>(args)...);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
clasp->trace(trc, obj);
|
||||
|
||||
if (!clasp->isNative())
|
||||
return nullptr;
|
||||
return &obj->as<NativeObject>();
|
||||
}
|
||||
|
||||
template <typename F, typename... Args>
|
||||
static void
|
||||
VisitTraceList(F f, const int32_t* traceList, uint8_t* memory, Args&&... args)
|
||||
{
|
||||
while (*traceList != -1) {
|
||||
f(reinterpret_cast<JSString**>(memory + *traceList), mozilla::Forward<Args>(args)...);
|
||||
traceList++;
|
||||
}
|
||||
traceList++;
|
||||
while (*traceList != -1) {
|
||||
JSObject** objp = reinterpret_cast<JSObject**>(memory + *traceList);
|
||||
if (*objp)
|
||||
f(objp, mozilla::Forward<Args>(args)...);
|
||||
traceList++;
|
||||
}
|
||||
traceList++;
|
||||
while (*traceList != -1) {
|
||||
f(reinterpret_cast<Value*>(memory + *traceList), mozilla::Forward<Args>(args)...);
|
||||
traceList++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1128,9 +1216,6 @@ GCMarker::processMarkStackTop(SliceBudget& budget)
|
||||
HeapSlot* end;
|
||||
JSObject* obj;
|
||||
|
||||
const int32_t* unboxedTraceList;
|
||||
uint8_t* unboxedMemory;
|
||||
|
||||
// Decode
|
||||
uintptr_t addr = stack.pop();
|
||||
uintptr_t tag = addr & StackTagMask;
|
||||
@@ -1192,7 +1277,7 @@ GCMarker::processMarkStackTop(SliceBudget& budget)
|
||||
|
||||
const Value& v = *vp++;
|
||||
if (v.isString()) {
|
||||
traverse(obj, v.toString());
|
||||
traverseEdge(obj, v.toString());
|
||||
} else if (v.isObject()) {
|
||||
JSObject* obj2 = &v.toObject();
|
||||
MOZ_ASSERT(obj->compartment() == obj2->compartment());
|
||||
@@ -1203,41 +1288,11 @@ GCMarker::processMarkStackTop(SliceBudget& budget)
|
||||
goto scan_obj;
|
||||
}
|
||||
} else if (v.isSymbol()) {
|
||||
traverse(obj, v.toSymbol());
|
||||
traverseEdge(obj, v.toSymbol());
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
scan_unboxed:
|
||||
{
|
||||
while (*unboxedTraceList != -1) {
|
||||
JSString* str = *reinterpret_cast<JSString**>(unboxedMemory + *unboxedTraceList);
|
||||
traverse(obj, str);
|
||||
unboxedTraceList++;
|
||||
}
|
||||
unboxedTraceList++;
|
||||
while (*unboxedTraceList != -1) {
|
||||
JSObject* obj2 = *reinterpret_cast<JSObject**>(unboxedMemory + *unboxedTraceList);
|
||||
MOZ_ASSERT_IF(obj2, obj->compartment() == obj2->compartment());
|
||||
if (obj2)
|
||||
traverse(obj, obj2);
|
||||
unboxedTraceList++;
|
||||
}
|
||||
unboxedTraceList++;
|
||||
while (*unboxedTraceList != -1) {
|
||||
const Value& v = *reinterpret_cast<Value*>(unboxedMemory + *unboxedTraceList);
|
||||
if (v.isString()) {
|
||||
traverse(obj, v.toString());
|
||||
} else if (v.isObject()) {
|
||||
traverse(obj, &v.toObject());
|
||||
} else if (v.isSymbol()) {
|
||||
traverse(obj, v.toSymbol());
|
||||
}
|
||||
unboxedTraceList++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
scan_obj:
|
||||
{
|
||||
AssertZoneIsMarking(obj);
|
||||
@@ -1249,48 +1304,15 @@ GCMarker::processMarkStackTop(SliceBudget& budget)
|
||||
}
|
||||
|
||||
ObjectGroup* group = obj->groupFromGC();
|
||||
traverse(obj, group);
|
||||
traverseEdge(obj, group);
|
||||
|
||||
/* Call the trace hook if necessary. */
|
||||
const Class* clasp = group->clasp();
|
||||
if (clasp->trace) {
|
||||
// Global objects all have the same trace hook. That hook is safe without barriers
|
||||
// if the global has no custom trace hook of its own, or has been moved to a different
|
||||
// compartment, and so can't have one.
|
||||
MOZ_ASSERT_IF(!(clasp->trace == JS_GlobalObjectTraceHook &&
|
||||
(!obj->compartment()->options().getTrace() || !obj->isOwnGlobal())),
|
||||
clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS);
|
||||
if (clasp->trace == InlineTypedObject::obj_trace) {
|
||||
Shape* shape = obj->as<InlineTypedObject>().shapeFromGC();
|
||||
traverse(obj, shape);
|
||||
TypeDescr* descr = &obj->as<InlineTypedObject>().typeDescr();
|
||||
if (!descr->hasTraceList())
|
||||
return;
|
||||
unboxedTraceList = descr->traceList();
|
||||
unboxedMemory = obj->as<InlineTypedObject>().inlineTypedMem();
|
||||
goto scan_unboxed;
|
||||
}
|
||||
if (clasp == &UnboxedPlainObject::class_) {
|
||||
JSObject* expando = obj->as<UnboxedPlainObject>().maybeExpando();
|
||||
if (expando)
|
||||
traverse(obj, expando);
|
||||
const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layout();
|
||||
unboxedTraceList = layout.traceList();
|
||||
if (!unboxedTraceList)
|
||||
return;
|
||||
unboxedMemory = obj->as<UnboxedPlainObject>().data();
|
||||
goto scan_unboxed;
|
||||
}
|
||||
clasp->trace(this, obj);
|
||||
}
|
||||
|
||||
if (!clasp->isNative())
|
||||
NativeObject *nobj = CallTraceHook(TraverseObjectFunctor(), this, obj,
|
||||
CheckGeneration::DoChecks, this, obj);
|
||||
if (!nobj)
|
||||
return;
|
||||
|
||||
NativeObject* nobj = &obj->as<NativeObject>();
|
||||
|
||||
Shape* shape = nobj->lastProperty();
|
||||
traverse(obj, shape);
|
||||
traverseEdge(obj, shape);
|
||||
|
||||
unsigned nslots = nobj->slotSpan();
|
||||
|
||||
@@ -1301,7 +1323,7 @@ GCMarker::processMarkStackTop(SliceBudget& budget)
|
||||
if (nobj->denseElementsAreCopyOnWrite()) {
|
||||
JSObject* owner = nobj->getElementsHeader()->ownerObject();
|
||||
if (owner != nobj) {
|
||||
traverse(obj, owner);
|
||||
traverseEdge(obj, owner);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1922,34 +1944,22 @@ js::Nursery::collectToFixedPoint(TenuringTracer& mover, TenureCountCache& tenure
|
||||
}
|
||||
}
|
||||
|
||||
struct TenuringFunctor
|
||||
{
|
||||
template <typename T>
|
||||
void operator()(T* thing, TenuringTracer& mover) {
|
||||
mover.traverse(thing);
|
||||
}
|
||||
};
|
||||
|
||||
// Visit all object children of the object and trace them.
|
||||
void
|
||||
js::TenuringTracer::traceObject(JSObject* obj)
|
||||
{
|
||||
const Class* clasp = obj->getClass();
|
||||
if (clasp->trace) {
|
||||
if (clasp->trace == InlineTypedObject::obj_trace) {
|
||||
TypeDescr* descr = &obj->as<InlineTypedObject>().typeDescr();
|
||||
if (descr->hasTraceList())
|
||||
markTraceList(descr->traceList(), obj->as<InlineTypedObject>().inlineTypedMem());
|
||||
return;
|
||||
}
|
||||
if (clasp == &UnboxedPlainObject::class_) {
|
||||
JSObject** pexpando = obj->as<UnboxedPlainObject>().addressOfExpando();
|
||||
if (*pexpando)
|
||||
traverse(pexpando);
|
||||
const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layoutDontCheckGeneration();
|
||||
if (layout.traceList())
|
||||
markTraceList(layout.traceList(), obj->as<UnboxedPlainObject>().data());
|
||||
return;
|
||||
}
|
||||
clasp->trace(this, obj);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(obj->isNative() == clasp->isNative());
|
||||
if (!clasp->isNative())
|
||||
NativeObject *nobj = CallTraceHook(TenuringFunctor(), this, obj,
|
||||
CheckGeneration::NoChecks, *this);
|
||||
if (!nobj)
|
||||
return;
|
||||
NativeObject* nobj = &obj->as<NativeObject>();
|
||||
|
||||
// Note: the contents of copy on write elements pointers are filled in
|
||||
// during parsing and cannot contain nursery pointers.
|
||||
@@ -1969,8 +1979,10 @@ js::TenuringTracer::traceObjectSlots(NativeObject* nobj, uint32_t start, uint32_
|
||||
HeapSlot* dynStart;
|
||||
HeapSlot* dynEnd;
|
||||
nobj->getSlotRange(start, length, &fixedStart, &fixedEnd, &dynStart, &dynEnd);
|
||||
traceSlots(fixedStart->unsafeGet(), fixedEnd->unsafeGet());
|
||||
traceSlots(dynStart->unsafeGet(), dynEnd->unsafeGet());
|
||||
if (fixedStart)
|
||||
traceSlots(fixedStart->unsafeGet(), fixedEnd->unsafeGet());
|
||||
if (dynStart)
|
||||
traceSlots(dynStart->unsafeGet(), dynEnd->unsafeGet());
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1980,27 +1992,6 @@ js::TenuringTracer::traceSlots(Value* vp, Value* end)
|
||||
traverse(vp);
|
||||
}
|
||||
|
||||
void
|
||||
js::TenuringTracer::markTraceList(const int32_t* traceList, uint8_t* memory)
|
||||
{
|
||||
while (*traceList != -1) {
|
||||
// Strings are not in the nursery and do not need tracing.
|
||||
traceList++;
|
||||
}
|
||||
traceList++;
|
||||
while (*traceList != -1) {
|
||||
JSObject** pobj = reinterpret_cast<JSObject**>(memory + *traceList);
|
||||
traverse(pobj);
|
||||
traceList++;
|
||||
}
|
||||
traceList++;
|
||||
while (*traceList != -1) {
|
||||
Value* pslot = reinterpret_cast<Value*>(memory + *traceList);
|
||||
traverse(pslot);
|
||||
traceList++;
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
js::TenuringTracer::moveObjectToTenured(JSObject* dst, JSObject* src, AllocKind dstKind)
|
||||
{
|
||||
|
||||
+3
-3
@@ -149,10 +149,10 @@ class GCMarker : public JSTracer
|
||||
template <typename T> void traverse(T thing);
|
||||
|
||||
// Calls traverse on target after making additional assertions.
|
||||
template <typename S, typename T> void traverse(S source, T target);
|
||||
|
||||
template <typename S, typename T> void traverseEdge(S source, T target);
|
||||
// C++ requires explicit declarations of partial template instantiations.
|
||||
template <typename S> void traverse(S source, jsid target);
|
||||
template <typename S> void traverseEdge(S source, jsid target);
|
||||
template <typename S> void traverseEdge(S source, Value target);
|
||||
|
||||
/*
|
||||
* Care must be taken changing the mark color from gray to black. The cycle
|
||||
|
||||
@@ -25,7 +25,6 @@ js::Nursery::getForwardedPointer(JSObject** ref) const
|
||||
const gc::RelocationOverlay* overlay = reinterpret_cast<const gc::RelocationOverlay*>(*ref);
|
||||
if (!overlay->isForwarded())
|
||||
return false;
|
||||
/* This static cast from Cell* restricts T to valid (GC thing) types. */
|
||||
*ref = static_cast<JSObject*>(overlay->forwardingAddress());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -88,7 +88,6 @@ class TenuringTracer : public JSTracer
|
||||
size_t moveSlotsToTenured(NativeObject* dst, NativeObject* src, gc::AllocKind dstKind);
|
||||
|
||||
void traceSlots(JS::Value* vp, JS::Value* end);
|
||||
void markTraceList(const int32_t* traceList, uint8_t* memory);
|
||||
};
|
||||
|
||||
class Nursery
|
||||
|
||||
@@ -318,6 +318,7 @@ static const PhaseInfo phases[] = {
|
||||
{ PHASE_GC_BEGIN, "Begin Callback", PHASE_NO_PARENT },
|
||||
{ PHASE_WAIT_BACKGROUND_THREAD, "Wait Background Thread", PHASE_NO_PARENT },
|
||||
{ PHASE_MARK_DISCARD_CODE, "Mark Discard Code", PHASE_NO_PARENT },
|
||||
{ PHASE_RELAZIFY_FUNCTIONS, "Relazify Functions", PHASE_NO_PARENT },
|
||||
{ PHASE_PURGE, "Purge", PHASE_NO_PARENT },
|
||||
{ PHASE_MARK, "Mark", PHASE_NO_PARENT },
|
||||
{ PHASE_UNMARK, "Unmark", PHASE_MARK },
|
||||
@@ -522,6 +523,9 @@ Statistics::formatData(StatisticsSerializer& ss, uint64_t timestamp)
|
||||
continue;
|
||||
}
|
||||
|
||||
char budgetDescription[200];
|
||||
slices[i].budget.describe(budgetDescription, sizeof(budgetDescription) - 1);
|
||||
|
||||
ss.beginObject(nullptr);
|
||||
ss.extra(" ");
|
||||
ss.appendNumber("Slice", "%d", "", i);
|
||||
@@ -529,6 +533,7 @@ Statistics::formatData(StatisticsSerializer& ss, uint64_t timestamp)
|
||||
ss.extra(" (");
|
||||
ss.appendDecimal("When", "ms", t(slices[i].start - slices[0].start));
|
||||
ss.appendString("Reason", ExplainReason(slices[i].reason));
|
||||
ss.appendString("Budget", budgetDescription);
|
||||
if (ss.isJSON()) {
|
||||
ss.appendDecimal("Page Faults", "",
|
||||
double(slices[i].endFaults - slices[i].startFaults));
|
||||
@@ -622,13 +627,16 @@ Statistics::formatDescription()
|
||||
UniqueChars
|
||||
Statistics::formatSliceDescription(unsigned i, const SliceData& slice)
|
||||
{
|
||||
char budgetDescription[200];
|
||||
slice.budget.describe(budgetDescription, sizeof(budgetDescription) - 1);
|
||||
|
||||
const char* format =
|
||||
"\
|
||||
---- Slice %u ----\n\
|
||||
Reason: %s\n\
|
||||
Reset: %s%s\n\
|
||||
Page Faults: %ld\n\
|
||||
Pause: %.3fms (@ %.3fms)\n\
|
||||
Pause: %.3fms of %s budget (@ %.3fms)\n\
|
||||
";
|
||||
char buffer[1024];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
@@ -636,7 +644,7 @@ Statistics::formatSliceDescription(unsigned i, const SliceData& slice)
|
||||
ExplainReason(slice.reason),
|
||||
slice.resetReason ? "yes - " : "no", slice.resetReason ? slice.resetReason : "",
|
||||
uint64_t(slice.endFaults - slice.startFaults),
|
||||
t(slice.duration()), t(slice.start - slices[0].start));
|
||||
t(slice.duration()), budgetDescription, t(slice.start - slices[0].start));
|
||||
return make_string_copy(buffer);
|
||||
}
|
||||
|
||||
@@ -964,9 +972,6 @@ Statistics::endGC()
|
||||
if (fp)
|
||||
printStats();
|
||||
|
||||
if (!aborted)
|
||||
Debugger::onGarbageCollection(runtime, *this);
|
||||
|
||||
// Clear the timers at the end of a GC because we accumulate time in
|
||||
// between GCs for some (which come before PHASE_GC_BEGIN in the list.)
|
||||
PodZero(&phaseStartTimes[PHASE_GC_BEGIN], PHASE_LIMIT - PHASE_GC_BEGIN);
|
||||
@@ -978,7 +983,7 @@ Statistics::endGC()
|
||||
|
||||
void
|
||||
Statistics::beginSlice(const ZoneGCStats& zoneStats, JSGCInvocationKind gckind,
|
||||
JS::gcreason::Reason reason)
|
||||
SliceBudget budget, JS::gcreason::Reason reason)
|
||||
{
|
||||
this->zoneStats = zoneStats;
|
||||
|
||||
@@ -986,7 +991,7 @@ Statistics::beginSlice(const ZoneGCStats& zoneStats, JSGCInvocationKind gckind,
|
||||
if (first)
|
||||
beginGC(gckind);
|
||||
|
||||
SliceData data(reason, PRMJ_Now(), GetPageFaultCount());
|
||||
SliceData data(budget, reason, PRMJ_Now(), GetPageFaultCount());
|
||||
if (!slices.append(data)) {
|
||||
// OOM testing fails if we CrashAtUnhandlableOOM here.
|
||||
aborted = true;
|
||||
|
||||
@@ -29,6 +29,7 @@ enum Phase {
|
||||
PHASE_GC_BEGIN,
|
||||
PHASE_WAIT_BACKGROUND_THREAD,
|
||||
PHASE_MARK_DISCARD_CODE,
|
||||
PHASE_RELAZIFY_FUNCTIONS,
|
||||
PHASE_PURGE,
|
||||
PHASE_MARK,
|
||||
PHASE_UNMARK,
|
||||
@@ -162,7 +163,7 @@ struct Statistics
|
||||
void endParallelPhase(Phase phase, const GCParallelTask* task);
|
||||
|
||||
void beginSlice(const ZoneGCStats& zoneStats, JSGCInvocationKind gckind,
|
||||
JS::gcreason::Reason reason);
|
||||
SliceBudget budget, JS::gcreason::Reason reason);
|
||||
void endSlice();
|
||||
|
||||
void startTimingMutator();
|
||||
@@ -206,13 +207,16 @@ struct Statistics
|
||||
static const size_t MAX_NESTING = 20;
|
||||
|
||||
struct SliceData {
|
||||
SliceData(JS::gcreason::Reason reason, int64_t start, size_t startFaults)
|
||||
: reason(reason), resetReason(nullptr), start(start), startFaults(startFaults)
|
||||
SliceData(SliceBudget budget, JS::gcreason::Reason reason, int64_t start, size_t startFaults)
|
||||
: budget(budget), reason(reason),
|
||||
resetReason(nullptr),
|
||||
start(start), startFaults(startFaults)
|
||||
{
|
||||
for (size_t i = 0; i < MAX_MULTIPARENT_PHASES + 1; i++)
|
||||
mozilla::PodArrayZero(phaseTimes[i]);
|
||||
}
|
||||
|
||||
SliceBudget budget;
|
||||
JS::gcreason::Reason reason;
|
||||
const char* resetReason;
|
||||
int64_t start, end;
|
||||
@@ -318,12 +322,12 @@ struct Statistics
|
||||
struct AutoGCSlice
|
||||
{
|
||||
AutoGCSlice(Statistics& stats, const ZoneGCStats& zoneStats, JSGCInvocationKind gckind,
|
||||
JS::gcreason::Reason reason
|
||||
SliceBudget budget, JS::gcreason::Reason reason
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: stats(stats)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
stats.beginSlice(zoneStats, gckind, reason);
|
||||
stats.beginSlice(zoneStats, gckind, budget, reason);
|
||||
}
|
||||
~AutoGCSlice() { stats.endSlice(); }
|
||||
|
||||
|
||||
+29
-14
@@ -14,6 +14,7 @@
|
||||
#include "vm/Debugger.h"
|
||||
#include "vm/Runtime.h"
|
||||
|
||||
#include "jscompartmentinlines.h"
|
||||
#include "jsgcinlines.h"
|
||||
|
||||
using namespace js;
|
||||
@@ -73,9 +74,7 @@ Zone::setNeedsIncrementalBarrier(bool needs, ShouldUpdateJit updateJit)
|
||||
jitUsingBarriers_ = needs;
|
||||
}
|
||||
|
||||
if (needs && runtimeFromMainThread()->isAtomsZone(this))
|
||||
MOZ_ASSERT(!runtimeFromMainThread()->exclusiveThreadsPresent());
|
||||
|
||||
MOZ_ASSERT_IF(needs && isAtomsZone(), !runtimeFromMainThread()->exclusiveThreadsPresent());
|
||||
MOZ_ASSERT_IF(needs, canCollect());
|
||||
needsIncrementalBarrier_ = needs;
|
||||
}
|
||||
@@ -132,24 +131,31 @@ Zone::sweepBreakpoints(FreeOp *fop)
|
||||
|
||||
MOZ_ASSERT(isGCSweepingOrCompacting());
|
||||
for (ZoneCellIterUnderGC i(this, AllocKind::SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
MOZ_ASSERT_IF(isGCSweeping(), script->zone()->isGCSweeping());
|
||||
JSScript* script = i.get<JSScript>();
|
||||
if (!script->hasAnyBreakpointsOrStepMode())
|
||||
continue;
|
||||
|
||||
bool scriptGone = IsAboutToBeFinalizedUnbarriered(&script);
|
||||
MOZ_ASSERT(script == i.get<JSScript>());
|
||||
for (unsigned i = 0; i < script->length(); i++) {
|
||||
BreakpointSite *site = script->getBreakpointSite(script->offsetToPC(i));
|
||||
BreakpointSite* site = script->getBreakpointSite(script->offsetToPC(i));
|
||||
if (!site)
|
||||
continue;
|
||||
|
||||
Breakpoint *nextbp;
|
||||
for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) {
|
||||
Breakpoint* nextbp;
|
||||
for (Breakpoint* bp = site->firstBreakpoint(); bp; bp = nextbp) {
|
||||
nextbp = bp->nextInSite();
|
||||
HeapPtrNativeObject& dbgobj = bp->debugger->toJSObjectRef();
|
||||
|
||||
// If we are sweeping, then we expect the script and the
|
||||
// debugger object to be swept in the same zone group, except if
|
||||
// the breakpoint was added after we computed the zone
|
||||
// groups. In this case both script and debugger object must be
|
||||
// live.
|
||||
MOZ_ASSERT_IF(isGCSweeping() && dbgobj->zone()->isCollecting(),
|
||||
dbgobj->zone()->isGCSweeping());
|
||||
dbgobj->zone()->isGCSweeping() ||
|
||||
(!scriptGone && dbgobj->asTenured().isMarked()));
|
||||
|
||||
bool dying = scriptGone || IsAboutToBeFinalized(&dbgobj);
|
||||
MOZ_ASSERT_IF(!dying, !IsAboutToBeFinalized(&bp->getHandlerRef()));
|
||||
if (dying)
|
||||
@@ -160,7 +166,7 @@ Zone::sweepBreakpoints(FreeOp *fop)
|
||||
}
|
||||
|
||||
void
|
||||
Zone::discardJitCode(FreeOp *fop)
|
||||
Zone::discardJitCode(FreeOp* fop)
|
||||
{
|
||||
if (!jitZone())
|
||||
return;
|
||||
@@ -242,7 +248,7 @@ Zone::canCollect()
|
||||
if (usedByExclusiveThread)
|
||||
return false;
|
||||
JSRuntime* rt = runtimeFromAnyThread();
|
||||
if (rt->isAtomsZone(this) && rt->exclusiveThreadsPresent())
|
||||
if (isAtomsZone() && rt->exclusiveThreadsPresent())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@@ -251,7 +257,8 @@ void
|
||||
Zone::notifyObservingDebuggers()
|
||||
{
|
||||
for (CompartmentsInZoneIter comps(this); !comps.done(); comps.next()) {
|
||||
RootedGlobalObject global(runtimeFromAnyThread(), comps->maybeGlobal());
|
||||
JSRuntime* rt = runtimeFromAnyThread();
|
||||
RootedGlobalObject global(rt, comps->maybeGlobal());
|
||||
if (!global)
|
||||
continue;
|
||||
|
||||
@@ -259,8 +266,16 @@ Zone::notifyObservingDebuggers()
|
||||
if (!dbgs)
|
||||
continue;
|
||||
|
||||
for (GlobalObject::DebuggerVector::Range r = dbgs->all(); !r.empty(); r.popFront())
|
||||
r.front()->debuggeeIsBeingCollected();
|
||||
for (GlobalObject::DebuggerVector::Range r = dbgs->all(); !r.empty(); r.popFront()) {
|
||||
if (!r.front()->debuggeeIsBeingCollected(rt->gc.majorGCCount())) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,
|
||||
"OOM while notifying observing Debuggers of a GC: The onGarbageCollection\n"
|
||||
"hook will not be fired for this GC for some Debuggers!\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -222,6 +222,9 @@ struct Zone : public JS::shadow::Zone,
|
||||
js::jit::JitZone* getJitZone(JSContext* cx) { return jitZone_ ? jitZone_ : createJitZone(cx); }
|
||||
js::jit::JitZone* jitZone() { return jitZone_; }
|
||||
|
||||
bool isAtomsZone() const { return runtimeFromAnyThread()->isAtomsZone(this); }
|
||||
bool isSelfHostingZone() const { return runtimeFromAnyThread()->isSelfHostingZone(this); }
|
||||
|
||||
#ifdef DEBUG
|
||||
// For testing purposes, return the index of the zone group which this zone
|
||||
// was swept in in the last GC.
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
#endif
|
||||
#include "vm/MatchPairs.h"
|
||||
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::irregexp;
|
||||
using namespace js::jit;
|
||||
|
||||
@@ -65,3 +65,35 @@ if (typeof assertNoWarning === 'undefined') {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof assertErrorMessage === 'undefined') {
|
||||
var assertErrorMessage = function assertErrorMessage(f, ctor, test) {
|
||||
try {
|
||||
f();
|
||||
} catch (e) {
|
||||
if (!(e instanceof ctor))
|
||||
throw new Error("Assertion failed: expected exception " + ctor.name + ", got " + e);
|
||||
if (typeof test == "string") {
|
||||
if (test != e.message)
|
||||
throw new Error("Assertion failed: expeceted " + test + ", got " + e.message);
|
||||
} else {
|
||||
if (!test.test(e.message))
|
||||
throw new Error("Assertion failed: expeceted " + test.toString() + ", got " + e.message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
throw new Error("Assertion failed: expected exception " + ctor.name + ", no exception thrown");
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof assertTypeErrorMessage === 'undefined') {
|
||||
var assertTypeErrorMessage = function assertTypeErrorMessage(f, test) {
|
||||
assertErrorMessage(f, TypeError, test);
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof assertRangeErrorMessage === 'undefined') {
|
||||
var assertRangeErrorMessage = function assertRangeErrorMessage(f, test) {
|
||||
assertErrorMessage(f, RangeError, test);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
load(libdir + "../../tests/ecma_6/Class/shell.js");
|
||||
@@ -34,65 +34,65 @@ function f() {
|
||||
|
||||
|
||||
|
||||
function testLoadX() {
|
||||
assertEqX4(SIMD.float32x4.loadX(f64, 0), [1,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadX(f32, 1), [2,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadX(i32, 2), [3,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadX(i16, 3 << 1), [4,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadX(u16, 4 << 1), [5,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadX(i8 , 5 << 2), [6,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadX(u8 , 6 << 2), [7,0,0,0]);
|
||||
function testLoad1() {
|
||||
assertEqX4(SIMD.float32x4.load1(f64, 0), [1,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load1(f32, 1), [2,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load1(i32, 2), [3,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load1(i16, 3 << 1), [4,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load1(u16, 4 << 1), [5,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load1(i8 , 5 << 2), [6,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load1(u8 , 6 << 2), [7,0,0,0]);
|
||||
|
||||
assertEqX4(SIMD.float32x4.loadX(f64, (16 >> 1) - (4 >> 1)), [13,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadX(f32, 16 - 4), [13,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadX(i32, 16 - 4), [13,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadX(i16, (16 << 1) - (4 << 1)), [13,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadX(u16, (16 << 1) - (4 << 1)), [13,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadX(i8, (16 << 2) - (4 << 2)), [13,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadX(u8, (16 << 2) - (4 << 2)), [13,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load1(f64, (16 >> 1) - (4 >> 1)), [13,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load1(f32, 16 - 4), [13,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load1(i32, 16 - 4), [13,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load1(i16, (16 << 1) - (4 << 1)), [13,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load1(u16, (16 << 1) - (4 << 1)), [13,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load1(i8, (16 << 2) - (4 << 2)), [13,0,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load1(u8, (16 << 2) - (4 << 2)), [13,0,0,0]);
|
||||
}
|
||||
|
||||
function testLoadXY() {
|
||||
assertEqX4(SIMD.float32x4.loadXY(f64, 0), [1,2,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXY(f32, 1), [2,3,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXY(i32, 2), [3,4,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXY(i16, 3 << 1), [4,5,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXY(u16, 4 << 1), [5,6,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXY(i8 , 5 << 2), [6,7,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXY(u8 , 6 << 2), [7,8,0,0]);
|
||||
function testLoad2() {
|
||||
assertEqX4(SIMD.float32x4.load2(f64, 0), [1,2,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load2(f32, 1), [2,3,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load2(i32, 2), [3,4,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load2(i16, 3 << 1), [4,5,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load2(u16, 4 << 1), [5,6,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load2(i8 , 5 << 2), [6,7,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load2(u8 , 6 << 2), [7,8,0,0]);
|
||||
|
||||
assertEqX4(SIMD.float32x4.loadXY(f64, (16 >> 1) - (4 >> 1)), [13,14,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXY(f32, 16 - 4), [13,14,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXY(i32, 16 - 4), [13,14,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXY(i16, (16 << 1) - (4 << 1)), [13,14,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXY(u16, (16 << 1) - (4 << 1)), [13,14,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXY(i8, (16 << 2) - (4 << 2)), [13,14,0,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXY(u8, (16 << 2) - (4 << 2)), [13,14,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load2(f64, (16 >> 1) - (4 >> 1)), [13,14,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load2(f32, 16 - 4), [13,14,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load2(i32, 16 - 4), [13,14,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load2(i16, (16 << 1) - (4 << 1)), [13,14,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load2(u16, (16 << 1) - (4 << 1)), [13,14,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load2(i8, (16 << 2) - (4 << 2)), [13,14,0,0]);
|
||||
assertEqX4(SIMD.float32x4.load2(u8, (16 << 2) - (4 << 2)), [13,14,0,0]);
|
||||
}
|
||||
|
||||
function testLoadXYZ() {
|
||||
assertEqX4(SIMD.float32x4.loadXYZ(f64, 0), [1,2,3,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXYZ(f32, 1), [2,3,4,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXYZ(i32, 2), [3,4,5,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXYZ(i16, 3 << 1), [4,5,6,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXYZ(u16, 4 << 1), [5,6,7,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXYZ(i8 , 5 << 2), [6,7,8,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXYZ(u8 , 6 << 2), [7,8,9,0]);
|
||||
function testLoad3() {
|
||||
assertEqX4(SIMD.float32x4.load3(f64, 0), [1,2,3,0]);
|
||||
assertEqX4(SIMD.float32x4.load3(f32, 1), [2,3,4,0]);
|
||||
assertEqX4(SIMD.float32x4.load3(i32, 2), [3,4,5,0]);
|
||||
assertEqX4(SIMD.float32x4.load3(i16, 3 << 1), [4,5,6,0]);
|
||||
assertEqX4(SIMD.float32x4.load3(u16, 4 << 1), [5,6,7,0]);
|
||||
assertEqX4(SIMD.float32x4.load3(i8 , 5 << 2), [6,7,8,0]);
|
||||
assertEqX4(SIMD.float32x4.load3(u8 , 6 << 2), [7,8,9,0]);
|
||||
|
||||
assertEqX4(SIMD.float32x4.loadXYZ(f64, (16 >> 1) - (4 >> 1)), [13,14,15,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXYZ(f32, 16 - 4), [13,14,15,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXYZ(i32, 16 - 4), [13,14,15,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXYZ(i16, (16 << 1) - (4 << 1)), [13,14,15,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXYZ(u16, (16 << 1) - (4 << 1)), [13,14,15,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXYZ(i8, (16 << 2) - (4 << 2)), [13,14,15,0]);
|
||||
assertEqX4(SIMD.float32x4.loadXYZ(u8, (16 << 2) - (4 << 2)), [13,14,15,0]);
|
||||
assertEqX4(SIMD.float32x4.load3(f64, (16 >> 1) - (4 >> 1)), [13,14,15,0]);
|
||||
assertEqX4(SIMD.float32x4.load3(f32, 16 - 4), [13,14,15,0]);
|
||||
assertEqX4(SIMD.float32x4.load3(i32, 16 - 4), [13,14,15,0]);
|
||||
assertEqX4(SIMD.float32x4.load3(i16, (16 << 1) - (4 << 1)), [13,14,15,0]);
|
||||
assertEqX4(SIMD.float32x4.load3(u16, (16 << 1) - (4 << 1)), [13,14,15,0]);
|
||||
assertEqX4(SIMD.float32x4.load3(i8, (16 << 2) - (4 << 2)), [13,14,15,0]);
|
||||
assertEqX4(SIMD.float32x4.load3(u8, (16 << 2) - (4 << 2)), [13,14,15,0]);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 150; i++) {
|
||||
testLoad();
|
||||
testLoadX();
|
||||
testLoadXY();
|
||||
testLoadXYZ();
|
||||
testLoad1();
|
||||
testLoad2();
|
||||
testLoad3();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,68 +48,68 @@ function f() {
|
||||
check(4);
|
||||
}
|
||||
|
||||
function testStoreX() {
|
||||
SIMD.float32x4.storeX(f64, 0, f4);
|
||||
function testStore1() {
|
||||
SIMD.float32x4.store1(f64, 0, f4);
|
||||
check(1);
|
||||
SIMD.float32x4.storeX(f32, 0, f4);
|
||||
SIMD.float32x4.store1(f32, 0, f4);
|
||||
check(1);
|
||||
SIMD.float32x4.storeX(i32, 0, f4);
|
||||
SIMD.float32x4.store1(i32, 0, f4);
|
||||
check(1);
|
||||
SIMD.float32x4.storeX(u32, 0, f4);
|
||||
SIMD.float32x4.store1(u32, 0, f4);
|
||||
check(1);
|
||||
SIMD.float32x4.storeX(i16, 0, f4);
|
||||
SIMD.float32x4.store1(i16, 0, f4);
|
||||
check(1);
|
||||
SIMD.float32x4.storeX(u16, 0, f4);
|
||||
SIMD.float32x4.store1(u16, 0, f4);
|
||||
check(1);
|
||||
SIMD.float32x4.storeX(i8, 0, f4);
|
||||
SIMD.float32x4.store1(i8, 0, f4);
|
||||
check(1);
|
||||
SIMD.float32x4.storeX(u8, 0, f4);
|
||||
SIMD.float32x4.store1(u8, 0, f4);
|
||||
check(1);
|
||||
}
|
||||
|
||||
function testStoreXY() {
|
||||
SIMD.float32x4.storeXY(f64, 0, f4);
|
||||
function testStore2() {
|
||||
SIMD.float32x4.store2(f64, 0, f4);
|
||||
check(2);
|
||||
SIMD.float32x4.storeXY(f32, 0, f4);
|
||||
SIMD.float32x4.store2(f32, 0, f4);
|
||||
check(2);
|
||||
SIMD.float32x4.storeXY(i32, 0, f4);
|
||||
SIMD.float32x4.store2(i32, 0, f4);
|
||||
check(2);
|
||||
SIMD.float32x4.storeXY(u32, 0, f4);
|
||||
SIMD.float32x4.store2(u32, 0, f4);
|
||||
check(2);
|
||||
SIMD.float32x4.storeXY(i16, 0, f4);
|
||||
SIMD.float32x4.store2(i16, 0, f4);
|
||||
check(2);
|
||||
SIMD.float32x4.storeXY(u16, 0, f4);
|
||||
SIMD.float32x4.store2(u16, 0, f4);
|
||||
check(2);
|
||||
SIMD.float32x4.storeXY(i8, 0, f4);
|
||||
SIMD.float32x4.store2(i8, 0, f4);
|
||||
check(2);
|
||||
SIMD.float32x4.storeXY(u8, 0, f4);
|
||||
SIMD.float32x4.store2(u8, 0, f4);
|
||||
check(2);
|
||||
}
|
||||
|
||||
function testStoreXYZ() {
|
||||
SIMD.float32x4.storeXYZ(f64, 0, f4);
|
||||
function testStore3() {
|
||||
SIMD.float32x4.store3(f64, 0, f4);
|
||||
check(3);
|
||||
SIMD.float32x4.storeXYZ(f32, 0, f4);
|
||||
SIMD.float32x4.store3(f32, 0, f4);
|
||||
check(3);
|
||||
SIMD.float32x4.storeXYZ(i32, 0, f4);
|
||||
SIMD.float32x4.store3(i32, 0, f4);
|
||||
check(3);
|
||||
SIMD.float32x4.storeXYZ(u32, 0, f4);
|
||||
SIMD.float32x4.store3(u32, 0, f4);
|
||||
check(3);
|
||||
SIMD.float32x4.storeXYZ(i16, 0, f4);
|
||||
SIMD.float32x4.store3(i16, 0, f4);
|
||||
check(3);
|
||||
SIMD.float32x4.storeXYZ(u16, 0, f4);
|
||||
SIMD.float32x4.store3(u16, 0, f4);
|
||||
check(3);
|
||||
SIMD.float32x4.storeXYZ(i8, 0, f4);
|
||||
SIMD.float32x4.store3(i8, 0, f4);
|
||||
check(3);
|
||||
SIMD.float32x4.storeXYZ(u8, 0, f4);
|
||||
SIMD.float32x4.store3(u8, 0, f4);
|
||||
check(3);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 150; i++) {
|
||||
testStore();
|
||||
testStoreX();
|
||||
testStoreXY();
|
||||
testStoreXYZ();
|
||||
testStore1();
|
||||
testStore2();
|
||||
testStore3();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,4 +141,3 @@ print('Testing range checks...');
|
||||
testBailout(-1);
|
||||
testBailout(-15);
|
||||
testBailout(12 * 4 + 1);
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ assertEq(asmLink(asmCompile(USE_ASM + 'function f(){;} return f'))(), undefined)
|
||||
assertAsmTypeFail(USE_ASM + 'function f(i,j){;} return f');
|
||||
assertEq(asmLink(asmCompile('"use asm";; function f(){};;; return f;;'))(), undefined);
|
||||
assertAsmTypeFail(USE_ASM + 'function f(x){} return f');
|
||||
assertAsmTypeFail(USE_ASM + 'function f(){return; return 1} return f');
|
||||
assertAsmTypeFail(USE_ASM + 'function f(){if (0) return; return 1} return f');
|
||||
assertEq(asmLink(asmCompile(USE_ASM + 'function f(x){x=x|0} return f'))(42), undefined);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + 'function f(x){x=x|0; return x|0} return f'))(42), 42);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + 'function f(x){x=x|0; return x|0;;;} return f'))(42), 42);
|
||||
|
||||
@@ -12,7 +12,7 @@ assertEq(asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; if ((i|0) == 0) i
|
||||
assertAsmTypeFail(USE_ASM + "function f(i) { i=i|0; if (i) return 0; } return f");
|
||||
assertAsmTypeFail(USE_ASM + "function f(i) { i=i|0; if (i) return 0; else return 1 } return f");
|
||||
assertAsmTypeFail(USE_ASM + "function f(i) { i=i|0; if (i) return 0; return 1.0 } return f");
|
||||
assertAsmTypeFail(USE_ASM + "function f() { return 0; 1 } return f");
|
||||
assertAsmTypeFail(USE_ASM + "function f() { if (0) return 0; 1 } return f");
|
||||
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f() { while (0) {} return 0} return f"))(), 0);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f() { for (;0;) {} return 0} return f"))(), 0);
|
||||
@@ -178,11 +178,15 @@ assertEq(f(2), 13);
|
||||
assertEq(f(3), 12);
|
||||
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f() { var i=8,sum=0; a:for(; (i|0)<20; i=(i+1)|0) { switch(i&3) { case 0:case 1:sum=(sum+i)|0;break;case 2:sum=(sum+100)|0;continue;default:break a} sum=(sum+10)|0; } sum=(sum+1000)|0; return sum|0 } return f"))(), 1137);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f() { a: do{break a;}while(0); a: do{break a;}while(0); return 42 } return f"))(), 42);
|
||||
assertEq(asmLink(asmCompile('g', USE_ASM + "function f() { g:{ return 42 } return 13 } return f"), null)(), 42);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f(x) {x=x|0;switch (x|0) {case 31:return 13;case 9: {x = 3;if ((x|0) <= 0) {return -1;}}}return 1;} return f"))(31), 13);
|
||||
|
||||
var imp = { ffi:function() { throw "Wrong" } };
|
||||
assertEq(asmLink(asmCompile('glob','imp', USE_ASM + "var ffi=imp.ffi; function f() { var i=0; return (i+1)|0; return ffi(i|0)|0 } return f"), null, imp)(), 1);
|
||||
|
||||
assertEq(asmLink(asmCompile(USE_ASM + 'function f() {var k = 1;if (1) {for(k = 1; k|0; k=k-1|0) {}} return 1}; return f'))(), 1);
|
||||
|
||||
// Ternaries conditionals
|
||||
//
|
||||
// Basic ternaries
|
||||
@@ -211,6 +215,14 @@ assertEq(f(1), 0);
|
||||
assertEq(f(0), 0);
|
||||
assertEq(guard.called(), false);
|
||||
|
||||
var f = asmLink(asmCompile('glob', 'ffi', USE_ASM + "var func=ffi.func; function f(x,y) { x=x|0;y=y|0; var a=2;if(x?func()|0:y)a=1;else a=0; return a|0 } return f"), this, {func: guard.call});
|
||||
assertEq(f(0,1), 1);
|
||||
assertEq(guard.called(), false);
|
||||
|
||||
var f = asmLink(asmCompile('glob', 'ffi', USE_ASM + "var func=ffi.func; function f(x,y) { x=x|0;y=y|0; var a=2;if(x?y:func()|0)a=1;else a=0; return a|0 } return f"), this, {func: guard.call});
|
||||
assertEq(f(1,0), 0);
|
||||
assertEq(guard.called(), false);
|
||||
|
||||
var f = asmLink(asmCompile(USE_ASM + "function f(x,y) { x=x|0;y=y|0; var a=2;if(x?0:y)a=1;else a=0; return a|0 } return f"));
|
||||
assertEq(f(1,1), 0);
|
||||
assertEq(f(1,0), 0);
|
||||
|
||||
@@ -115,12 +115,35 @@ assertEq(f(0, INT32_MIN), 1);
|
||||
assertEq(f(UINT32_MAX, 0), 0);
|
||||
assertEq(f(0, UINT32_MAX), 1);
|
||||
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)==(j|0); return k|0 } return f"))(1,2), 0);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)!=(j|0); return k|0 } return f"))(1,2), 1);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)<(j|0); return k|0 } return f"))(1,2), 1);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)>(j|0); return k|0 } return f"))(1,2), 0);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)<=(j|0); return k|0 } return f"))(1,2), 1);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)>=(j|0); return k|0 } return f"))(1,2), 0);
|
||||
var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)==(j|0); return k|0 } return f"));
|
||||
assertEq(f(1,2), 0);
|
||||
assertEq(f(1,1), 1);
|
||||
assertEq(f(2,1), 0);
|
||||
|
||||
var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)!=(j|0); return k|0 } return f"));
|
||||
assertEq(f(1,2), 1);
|
||||
assertEq(f(1,1), 0);
|
||||
assertEq(f(2,1), 1);
|
||||
|
||||
var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)<(j|0); return k|0 } return f"));
|
||||
assertEq(f(1,2), 1);
|
||||
assertEq(f(1,1), 0);
|
||||
assertEq(f(1,0), 0);
|
||||
|
||||
var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)>(j|0); return k|0 } return f"));
|
||||
assertEq(f(1,2), 0);
|
||||
assertEq(f(1,1), 0);
|
||||
assertEq(f(1,0), 1);
|
||||
|
||||
var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)<=(j|0); return k|0 } return f"));
|
||||
assertEq(f(1,2), 1);
|
||||
assertEq(f(1,1), 1);
|
||||
assertEq(f(1,0), 0);
|
||||
|
||||
var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)>=(j|0); return k|0 } return f"));
|
||||
assertEq(f(1,2), 0);
|
||||
assertEq(f(1,1), 1);
|
||||
assertEq(f(1,0), 1);
|
||||
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "const I=2; function f(i) { i=i|0; var k=0; k=(i|0)<I; return k|0 } return f"))(1), 1);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "const I=2; function f(i) { i=i|0; var k=0; k=(i>>>0)<I; return k|0 } return f"))(1), 1);
|
||||
|
||||
@@ -30,7 +30,7 @@ assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { retu
|
||||
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { return +(inc() + 1.1) } return f');
|
||||
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { return (+inc() + 1)|0 } return f');
|
||||
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { var i = 0; inc(i>>>0) } return f');
|
||||
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { return inc(); return } return f');
|
||||
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { if (0) return inc(); return } return f');
|
||||
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { inc(inc()) } return f');
|
||||
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { g(inc()) } function g() {} return f');
|
||||
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { inc()|inc() } return f');
|
||||
|
||||
@@ -63,6 +63,8 @@ assertEq(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + TO_FLOAT32 + HEAP32
|
||||
assertEq(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + TO_FLOAT32 + HEAP32 + HEAP64 + "function f() { f64[0] = 1.5; return toF(f64[0]); } return f"), this, null, heap)(), 1.5);
|
||||
assertEq(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + TO_FLOAT32 + HEAP32 + HEAP64 + "function f() { f32[0] = toF(42); f64[0] = f32[0]; return +f64[0]; } return f"), this, null, heap)(), 42);
|
||||
|
||||
assertEq(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + TO_FLOAT32 + HEAP32 + "function f() { f32[0] = toF(-1.4013e-45) / toF(42.); } return f"), this, null, heap)(), undefined);
|
||||
|
||||
// Coercions
|
||||
// -> from Float32
|
||||
assertAsmTypeFail('glob', USE_ASM + TO_FLOAT32 + "function f() { var n = 0; n = toF(4.5) | 0; } return f");
|
||||
|
||||
@@ -137,7 +137,7 @@ assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if
|
||||
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return } function f() { return 42 } return f');
|
||||
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return 1 } function f() { return 42 } return f');
|
||||
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return false } function f() { return 42 } return f');
|
||||
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true; 1 } function f() { return 42 } return f');
|
||||
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; if (0) return true; 1 } function f() { return 42 } return f');
|
||||
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
|
||||
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); b=b2; return true } function f() { return 42 } return f');
|
||||
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
|
||||
|
||||
@@ -280,45 +280,45 @@ function MakeCodeFor(typeName) {
|
||||
var type = glob.SIMD.${typeName};
|
||||
var c = type.check;
|
||||
|
||||
var lx = type.loadX;
|
||||
var lxy = type.loadXY;
|
||||
var lxyz = type.loadXYZ;
|
||||
var l1 = type.load1;
|
||||
var l2 = type.load2;
|
||||
var l3 = type.load3;
|
||||
|
||||
var sx = type.storeX;
|
||||
var sxy = type.storeXY;
|
||||
var sxyz = type.storeXYZ;
|
||||
var s1 = type.store1;
|
||||
var s2 = type.store2;
|
||||
var s3 = type.store3;
|
||||
|
||||
var u8 = new glob.Uint8Array(heap);
|
||||
|
||||
function loadX(i) { i=i|0; return lx(u8, i); }
|
||||
function loadXY(i) { i=i|0; return lxy(u8, i); }
|
||||
function loadXYZ(i) { i=i|0; return lxyz(u8, i); }
|
||||
function load1(i) { i=i|0; return l1(u8, i); }
|
||||
function load2(i) { i=i|0; return l2(u8, i); }
|
||||
function load3(i) { i=i|0; return l3(u8, i); }
|
||||
|
||||
function loadCstX() { return lx(u8, 41 << 2); }
|
||||
function loadCstXY() { return lxy(u8, 41 << 2); }
|
||||
function loadCstXYZ() { return lxyz(u8, 41 << 2); }
|
||||
function loadCst1() { return l1(u8, 41 << 2); }
|
||||
function loadCst2() { return l2(u8, 41 << 2); }
|
||||
function loadCst3() { return l3(u8, 41 << 2); }
|
||||
|
||||
function storeX(i, x) { i=i|0; x=c(x); return sx(u8, i, x); }
|
||||
function storeXY(i, x) { i=i|0; x=c(x); return sxy(u8, i, x); }
|
||||
function storeXYZ(i, x) { i=i|0; x=c(x); return sxyz(u8, i, x); }
|
||||
function store1(i, x) { i=i|0; x=c(x); return s1(u8, i, x); }
|
||||
function store2(i, x) { i=i|0; x=c(x); return s2(u8, i, x); }
|
||||
function store3(i, x) { i=i|0; x=c(x); return s3(u8, i, x); }
|
||||
|
||||
function storeCstX(x) { x=c(x); return sx(u8, 41 << 2, x); }
|
||||
function storeCstXY(x) { x=c(x); return sxy(u8, 41 << 2, x); }
|
||||
function storeCstXYZ(x) { x=c(x); return sxyz(u8, 41 << 2, x); }
|
||||
function storeCst1(x) { x=c(x); return s1(u8, 41 << 2, x); }
|
||||
function storeCst2(x) { x=c(x); return s2(u8, 41 << 2, x); }
|
||||
function storeCst3(x) { x=c(x); return s3(u8, 41 << 2, x); }
|
||||
|
||||
return {
|
||||
loadX: loadX,
|
||||
loadXY: loadXY,
|
||||
loadXYZ: loadXYZ,
|
||||
loadCstX: loadCstX,
|
||||
loadCstXY: loadCstXY,
|
||||
loadCstXYZ: loadCstXYZ,
|
||||
storeX: storeX,
|
||||
storeXY: storeXY,
|
||||
storeXYZ: storeXYZ,
|
||||
storeCstX: storeCstX,
|
||||
storeCstXY: storeCstXY,
|
||||
storeCstXYZ: storeCstXYZ,
|
||||
load1: load1,
|
||||
load2: load2,
|
||||
load3: load3,
|
||||
loadCst1: loadCst1,
|
||||
loadCst2: loadCst2,
|
||||
loadCst3: loadCst3,
|
||||
store1: store1,
|
||||
store2: store2,
|
||||
store3: store3,
|
||||
storeCst1: storeCst1,
|
||||
storeCst2: storeCst2,
|
||||
storeCst3: storeCst3,
|
||||
}
|
||||
`;
|
||||
}
|
||||
@@ -336,45 +336,45 @@ function TestPartialLoads(m, typedArray, x, y, z, w) {
|
||||
|
||||
// Test correct loads
|
||||
var i = 0, j = 0; // i in elems, j in bytes
|
||||
assertEqX4(m.loadX(j), [x(i), 0, 0, 0]);
|
||||
assertEqX4(m.loadXY(j), [x(i), y(i), 0, 0]);
|
||||
assertEqX4(m.loadXYZ(j), [x(i), y(i), z(i), 0]);
|
||||
assertEqX4(m.load1(j), [x(i), 0, 0, 0]);
|
||||
assertEqX4(m.load2(j), [x(i), y(i), 0, 0]);
|
||||
assertEqX4(m.load3(j), [x(i), y(i), z(i), 0]);
|
||||
|
||||
j += 4;
|
||||
assertEqX4(m.loadX(j), [y(i), 0, 0, 0]);
|
||||
assertEqX4(m.loadXY(j), [y(i), z(i), 0, 0]);
|
||||
assertEqX4(m.loadXYZ(j), [y(i), z(i), w(i), 0]);
|
||||
assertEqX4(m.load1(j), [y(i), 0, 0, 0]);
|
||||
assertEqX4(m.load2(j), [y(i), z(i), 0, 0]);
|
||||
assertEqX4(m.load3(j), [y(i), z(i), w(i), 0]);
|
||||
|
||||
j += 4;
|
||||
assertEqX4(m.loadX(j), [z(i), 0, 0, 0]);
|
||||
assertEqX4(m.loadXY(j), [z(i), w(i), 0, 0]);
|
||||
assertEqX4(m.loadXYZ(j), [z(i), w(i), x(i+4), 0]);
|
||||
assertEqX4(m.load1(j), [z(i), 0, 0, 0]);
|
||||
assertEqX4(m.load2(j), [z(i), w(i), 0, 0]);
|
||||
assertEqX4(m.load3(j), [z(i), w(i), x(i+4), 0]);
|
||||
|
||||
j += 4;
|
||||
assertEqX4(m.loadX(j), [w(i), 0, 0, 0]);
|
||||
assertEqX4(m.loadXY(j), [w(i), x(i+4), 0, 0]);
|
||||
assertEqX4(m.loadXYZ(j), [w(i), x(i+4), y(i+4), 0]);
|
||||
assertEqX4(m.load1(j), [w(i), 0, 0, 0]);
|
||||
assertEqX4(m.load2(j), [w(i), x(i+4), 0, 0]);
|
||||
assertEqX4(m.load3(j), [w(i), x(i+4), y(i+4), 0]);
|
||||
|
||||
j += 4;
|
||||
i += 4;
|
||||
assertEqX4(m.loadX(j), [x(i), 0, 0, 0]);
|
||||
assertEqX4(m.loadXY(j), [x(i), y(i), 0, 0]);
|
||||
assertEqX4(m.loadXYZ(j), [x(i), y(i), z(i), 0]);
|
||||
assertEqX4(m.load1(j), [x(i), 0, 0, 0]);
|
||||
assertEqX4(m.load2(j), [x(i), y(i), 0, 0]);
|
||||
assertEqX4(m.load3(j), [x(i), y(i), z(i), 0]);
|
||||
|
||||
// Test loads with constant indexes (41)
|
||||
assertEqX4(m.loadCstX(), [y(40), 0, 0, 0]);
|
||||
assertEqX4(m.loadCstXY(), [y(40), z(40), 0, 0]);
|
||||
assertEqX4(m.loadCstXYZ(), [y(40), z(40), w(40), 0]);
|
||||
assertEqX4(m.loadCst1(), [y(40), 0, 0, 0]);
|
||||
assertEqX4(m.loadCst2(), [y(40), z(40), 0, 0]);
|
||||
assertEqX4(m.loadCst3(), [y(40), z(40), w(40), 0]);
|
||||
|
||||
// Test limit and OOB accesses
|
||||
assertEqX4(m.loadX((SIZE - 1) << 2), [w(SIZE - 4), 0, 0, 0]);
|
||||
assertThrowsInstanceOf(() => m.loadX(((SIZE - 1) << 2) + 1), RangeError);
|
||||
assertEqX4(m.load1((SIZE - 1) << 2), [w(SIZE - 4), 0, 0, 0]);
|
||||
assertThrowsInstanceOf(() => m.load1(((SIZE - 1) << 2) + 1), RangeError);
|
||||
|
||||
assertEqX4(m.loadXY((SIZE - 2) << 2), [z(SIZE - 4), w(SIZE - 4), 0, 0]);
|
||||
assertThrowsInstanceOf(() => m.loadXY(((SIZE - 2) << 2) + 1), RangeError);
|
||||
assertEqX4(m.load2((SIZE - 2) << 2), [z(SIZE - 4), w(SIZE - 4), 0, 0]);
|
||||
assertThrowsInstanceOf(() => m.load2(((SIZE - 2) << 2) + 1), RangeError);
|
||||
|
||||
assertEqX4(m.loadXYZ((SIZE - 3) << 2), [y(SIZE - 4), z(SIZE - 4), w(SIZE - 4), 0]);
|
||||
assertThrowsInstanceOf(() => m.loadXYZ(((SIZE - 3) << 2) + 1), RangeError);
|
||||
assertEqX4(m.load3((SIZE - 3) << 2), [y(SIZE - 4), z(SIZE - 4), w(SIZE - 4), 0]);
|
||||
assertThrowsInstanceOf(() => m.load3(((SIZE - 3) << 2) + 1), RangeError);
|
||||
}
|
||||
|
||||
// Partial stores
|
||||
@@ -390,16 +390,16 @@ function TestPartialStores(m, typedArray, typeName, x, y, z, w) {
|
||||
assertEq(typedArray[i], i + 1);
|
||||
}
|
||||
|
||||
function TestStoreX(i) {
|
||||
m.storeX(i, val);
|
||||
function TestStore1(i) {
|
||||
m.store1(i, val);
|
||||
CheckNotModified(0, i >> 2);
|
||||
assertEq(typedArray[i >> 2], x);
|
||||
CheckNotModified((i >> 2) + 1, SIZE);
|
||||
typedArray[i >> 2] = (i >> 2) + 1;
|
||||
}
|
||||
|
||||
function TestStoreXY(i) {
|
||||
m.storeXY(i, val);
|
||||
function TestStore2(i) {
|
||||
m.store2(i, val);
|
||||
CheckNotModified(0, i >> 2);
|
||||
assertEq(typedArray[i >> 2], x);
|
||||
assertEq(typedArray[(i >> 2) + 1], y);
|
||||
@@ -408,8 +408,8 @@ function TestPartialStores(m, typedArray, typeName, x, y, z, w) {
|
||||
typedArray[(i >> 2) + 1] = (i >> 2) + 2;
|
||||
}
|
||||
|
||||
function TestStoreXYZ(i) {
|
||||
m.storeXYZ(i, val);
|
||||
function TestStore3(i) {
|
||||
m.store3(i, val);
|
||||
CheckNotModified(0, i >> 2);
|
||||
assertEq(typedArray[i >> 2], x);
|
||||
assertEq(typedArray[(i >> 2) + 1], y);
|
||||
@@ -427,48 +427,48 @@ function TestPartialStores(m, typedArray, typeName, x, y, z, w) {
|
||||
|
||||
Reset();
|
||||
|
||||
TestStoreX(0);
|
||||
TestStoreX(1 << 2);
|
||||
TestStoreX(2 << 2);
|
||||
TestStoreX(3 << 2);
|
||||
TestStoreX(1337 << 2);
|
||||
TestStore1(0);
|
||||
TestStore1(1 << 2);
|
||||
TestStore1(2 << 2);
|
||||
TestStore1(3 << 2);
|
||||
TestStore1(1337 << 2);
|
||||
|
||||
var i = (SIZE - 1) << 2;
|
||||
TestStoreX(i);
|
||||
TestOOBStore(() => m.storeX(i + 1, val));
|
||||
TestOOBStore(() => m.storeX(-1, val));
|
||||
TestStore1(i);
|
||||
TestOOBStore(() => m.store1(i + 1, val));
|
||||
TestOOBStore(() => m.store1(-1, val));
|
||||
|
||||
TestStoreXY(0);
|
||||
TestStoreXY(1 << 2);
|
||||
TestStoreXY(2 << 2);
|
||||
TestStoreXY(3 << 2);
|
||||
TestStoreXY(1337 << 2);
|
||||
TestStore2(0);
|
||||
TestStore2(1 << 2);
|
||||
TestStore2(2 << 2);
|
||||
TestStore2(3 << 2);
|
||||
TestStore2(1337 << 2);
|
||||
|
||||
var i = (SIZE - 2) << 2;
|
||||
TestStoreXY(i);
|
||||
TestOOBStore(() => m.storeXY(i + 1, val));
|
||||
TestOOBStore(() => m.storeXY(-1, val));
|
||||
TestStore2(i);
|
||||
TestOOBStore(() => m.store2(i + 1, val));
|
||||
TestOOBStore(() => m.store2(-1, val));
|
||||
|
||||
TestStoreXYZ(0);
|
||||
TestStoreXYZ(1 << 2);
|
||||
TestStoreXYZ(2 << 2);
|
||||
TestStoreXYZ(3 << 2);
|
||||
TestStoreXYZ(1337 << 2);
|
||||
TestStore3(0);
|
||||
TestStore3(1 << 2);
|
||||
TestStore3(2 << 2);
|
||||
TestStore3(3 << 2);
|
||||
TestStore3(1337 << 2);
|
||||
|
||||
var i = (SIZE - 3) << 2;
|
||||
TestStoreXYZ(i);
|
||||
TestOOBStore(() => m.storeXYZ(i + 1, val));
|
||||
TestOOBStore(() => m.storeXYZ(-1, val));
|
||||
TestOOBStore(() => m.storeXYZ(-9, val));
|
||||
TestStore3(i);
|
||||
TestOOBStore(() => m.store3(i + 1, val));
|
||||
TestOOBStore(() => m.store3(-1, val));
|
||||
TestOOBStore(() => m.store3(-9, val));
|
||||
|
||||
// Constant indexes (41)
|
||||
m.storeCstX(val);
|
||||
m.storeCst1(val);
|
||||
CheckNotModified(0, 41);
|
||||
assertEq(typedArray[41], x);
|
||||
CheckNotModified(42, SIZE);
|
||||
typedArray[41] = 42;
|
||||
|
||||
m.storeCstXY(val);
|
||||
m.storeCst2(val);
|
||||
CheckNotModified(0, 41);
|
||||
assertEq(typedArray[41], x);
|
||||
assertEq(typedArray[42], y);
|
||||
@@ -476,7 +476,7 @@ function TestPartialStores(m, typedArray, typeName, x, y, z, w) {
|
||||
typedArray[41] = 42;
|
||||
typedArray[42] = 43;
|
||||
|
||||
m.storeCstXYZ(val);
|
||||
m.storeCst3(val);
|
||||
CheckNotModified(0, 41);
|
||||
assertEq(typedArray[41], x);
|
||||
assertEq(typedArray[42], y);
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
// |jit-test| test-also-noasmjs
|
||||
load(libdir + "asm.js");
|
||||
load(libdir + "asserts.js");
|
||||
|
||||
setIonCheckGraphCoherency(false);
|
||||
setCachingEnabled(false);
|
||||
|
||||
var ab = new ArrayBuffer(BUF_MIN);
|
||||
|
||||
// Compute a set of interesting indices.
|
||||
indices = [0]
|
||||
for (var i of [4,1024,BUF_MIN,Math.pow(2,30),Math.pow(2,31),Math.pow(2,32),Math.pow(2,33)]) {
|
||||
for (var j of [-2,-1,0,1,2]) {
|
||||
for (var k of [1,-1])
|
||||
indices.push((i+j)*k);
|
||||
}
|
||||
}
|
||||
|
||||
function testInt(ctor, shift, scale, disp) {
|
||||
var arr = new ctor(ab);
|
||||
|
||||
var c = asmCompile('glob', 'imp', 'b',
|
||||
USE_ASM +
|
||||
'var arr=new glob.' + ctor.name + '(b); ' +
|
||||
'function load(i) {i=i|0; return arr[((i<<' + scale + ')+' + disp + ')>>' + shift + ']|0 } ' +
|
||||
'function store(i,j) {i=i|0;j=j|0; arr[((i<<' + scale + ')+' + disp + ')>>' + shift + '] = j } ' +
|
||||
'function storeZero(i) {i=i|0; arr[((i<<' + scale + ')+' + disp + ')>>' + shift + '] = 0 } ' +
|
||||
'function storeNegOne(i) {i=i|0; arr[((i<<' + scale + ')+' + disp + ')>>' + shift + '] = -1 } ' +
|
||||
'return { load: load, store: store, storeZero: storeZero, storeNegOne: storeNegOne }');
|
||||
var f = asmLink(c, this, null, ab);
|
||||
|
||||
var v = arr[0];
|
||||
arr[0] = -1;
|
||||
var negOne = arr[0]|0;
|
||||
arr[0] = v;
|
||||
|
||||
for (var i of indices) {
|
||||
var index = ((i<<scale)+disp)>>shift;
|
||||
v = arr[index]|0;
|
||||
|
||||
// Loads
|
||||
assertEq(f.load(i), v);
|
||||
|
||||
// Stores of immediates
|
||||
arr[index] = 1;
|
||||
f.storeZero(i);
|
||||
assertEq(arr[index]|0, 0);
|
||||
f.storeNegOne(i);
|
||||
assertEq(arr[index]|0, index>>>0 < arr.length ? negOne : 0);
|
||||
|
||||
// Stores
|
||||
arr[index] = ~v;
|
||||
f.store(i, v);
|
||||
assertEq(arr[index]|0, v);
|
||||
}
|
||||
}
|
||||
|
||||
function testFloat(ctor, shift, scale, disp, coercion) {
|
||||
var arr = new ctor(ab);
|
||||
|
||||
var c = asmCompile('glob', 'imp', 'b',
|
||||
USE_ASM +
|
||||
'var arr=new glob.' + ctor.name + '(b); ' +
|
||||
'var toF = glob.Math.fround; ' +
|
||||
'function load(i) {i=i|0; return ' + coercion + '(arr[((i<<' + scale + ')+' + disp + ')>>' + shift + ']) } ' +
|
||||
'function store(i,j) {i=i|0;j=+j; arr[((i<<' + scale + ')+' + disp + ')>>' + shift + '] = j } ' +
|
||||
'return { load: load, store: store }');
|
||||
var f = asmLink(c, this, null, ab);
|
||||
|
||||
for (var i of indices) {
|
||||
var index = ((i<<scale)+disp)>>shift;
|
||||
var v = +arr[index];
|
||||
|
||||
// Loads
|
||||
assertEq(f.load(i), v);
|
||||
|
||||
// Stores
|
||||
arr[index] = ~v;
|
||||
f.store(i, v);
|
||||
assertEq(+arr[index], v);
|
||||
}
|
||||
}
|
||||
|
||||
function testFloat32(ctor, shift, scale, disp) {
|
||||
testFloat(ctor, shift, scale, disp, "toF");
|
||||
}
|
||||
function testFloat64(ctor, shift, scale, disp) {
|
||||
testFloat(ctor, shift, scale, disp, "+");
|
||||
}
|
||||
|
||||
function assertEqX4(observed, expected) {
|
||||
assertEq(observed.x, expected.x);
|
||||
assertEq(observed.y, expected.y);
|
||||
assertEq(observed.z, expected.z);
|
||||
assertEq(observed.w, expected.w);
|
||||
}
|
||||
|
||||
function testSimdX4(ctor, shift, scale, disp, simdName, simdCtor) {
|
||||
var arr = new ctor(ab);
|
||||
|
||||
var c = asmCompile('glob', 'imp', 'b',
|
||||
USE_ASM +
|
||||
'var arr=new glob.' + ctor.name + '(b); ' +
|
||||
'var SIMD_' + simdName + ' = glob.SIMD.' + simdName + '; ' +
|
||||
'var SIMD_' + simdName + '_check = SIMD_' + simdName + '.check; ' +
|
||||
'var SIMD_' + simdName + '_load = SIMD_' + simdName + '.load; ' +
|
||||
'var SIMD_' + simdName + '_load3 = SIMD_' + simdName + '.load3; ' +
|
||||
'var SIMD_' + simdName + '_load2 = SIMD_' + simdName + '.load2; ' +
|
||||
'var SIMD_' + simdName + '_load1 = SIMD_' + simdName + '.load1; ' +
|
||||
'var SIMD_' + simdName + '_store = SIMD_' + simdName + '.store; ' +
|
||||
'var SIMD_' + simdName + '_store3 = SIMD_' + simdName + '.store3; ' +
|
||||
'var SIMD_' + simdName + '_store2 = SIMD_' + simdName + '.store2; ' +
|
||||
'var SIMD_' + simdName + '_store1 = SIMD_' + simdName + '.store1; ' +
|
||||
'function load(i) {i=i|0; return SIMD_' + simdName + '_check(SIMD_' + simdName + '_load(arr, ((i<<' + scale + ')+' + disp + ')>>' + shift + ')) } ' +
|
||||
'function load3(i) {i=i|0; return SIMD_' + simdName + '_check(SIMD_' + simdName + '_load3(arr, ((i<<' + scale + ')+' + disp + ')>>' + shift + ')) } ' +
|
||||
'function load2(i) {i=i|0; return SIMD_' + simdName + '_check(SIMD_' + simdName + '_load2(arr, ((i<<' + scale + ')+' + disp + ')>>' + shift + ')) } ' +
|
||||
'function load1(i) {i=i|0; return SIMD_' + simdName + '_check(SIMD_' + simdName + '_load1(arr, ((i<<' + scale + ')+' + disp + ')>>' + shift + ')) } ' +
|
||||
'function store(i,j) {i=i|0;j=SIMD_' + simdName + '_check(j); SIMD_' + simdName + '_store(arr, ((i<<' + scale + ')+' + disp + ')>>' + shift + ', j) } ' +
|
||||
'function store3(i,j) {i=i|0;j=SIMD_' + simdName + '_check(j); SIMD_' + simdName + '_store3(arr, ((i<<' + scale + ')+' + disp + ')>>' + shift + ', j) } ' +
|
||||
'function store2(i,j) {i=i|0;j=SIMD_' + simdName + '_check(j); SIMD_' + simdName + '_store2(arr, ((i<<' + scale + ')+' + disp + ')>>' + shift + ', j) } ' +
|
||||
'function store1(i,j) {i=i|0;j=SIMD_' + simdName + '_check(j); SIMD_' + simdName + '_store1(arr, ((i<<' + scale + ')+' + disp + ')>>' + shift + ', j) } ' +
|
||||
'return { load: load, load3: load3, load2: load2, load1: load1, store: store, store3: store3, store2 : store2, store1 : store1 }');
|
||||
var f = asmLink(c, this, null, ab);
|
||||
|
||||
for (var i of indices) {
|
||||
var index = ((i<<scale)+disp)>>shift;
|
||||
|
||||
var v, v3, v2, v1;
|
||||
var t = false, t3 = false, t2 = false, t1 = false;
|
||||
try { v = simdCtor.load(arr, index); }
|
||||
catch (e) {
|
||||
assertEq(e instanceof RangeError, true);
|
||||
t = true;
|
||||
}
|
||||
try { v3 = simdCtor.load3(arr, index); }
|
||||
catch (e) {
|
||||
assertEq(e instanceof RangeError, true);
|
||||
t3 = true;
|
||||
}
|
||||
try { v2 = simdCtor.load2(arr, index); }
|
||||
catch (e) {
|
||||
assertEq(e instanceof RangeError, true);
|
||||
t2 = true;
|
||||
}
|
||||
try { v1 = simdCtor.load1(arr, index); }
|
||||
catch (e) {
|
||||
assertEq(e instanceof RangeError, true);
|
||||
t1 = true;
|
||||
}
|
||||
|
||||
// Loads
|
||||
var l, l3, l2, l1;
|
||||
var r = false, r3 = false, r2 = false, r1 = false;
|
||||
try { l = f.load(i); }
|
||||
catch (e) {
|
||||
assertEq(e instanceof RangeError, true);
|
||||
r = true;
|
||||
}
|
||||
try { l3 = f.load3(i); }
|
||||
catch (e) {
|
||||
assertEq(e instanceof RangeError, true);
|
||||
r3 = true;
|
||||
}
|
||||
try { l2 = f.load2(i); }
|
||||
catch (e) {
|
||||
assertEq(e instanceof RangeError, true);
|
||||
r2 = true;
|
||||
}
|
||||
try { l1 = f.load1(i); }
|
||||
catch (e) {
|
||||
assertEq(e instanceof RangeError, true);
|
||||
r1 = true;
|
||||
}
|
||||
assertEq(t, r);
|
||||
assertEq(t3, r3);
|
||||
assertEq(t2, r2);
|
||||
assertEq(t1, r1);
|
||||
if (!t) assertEqX4(v, l);
|
||||
if (!t3) assertEqX4(v3, l3);
|
||||
if (!t2) assertEqX4(v2, l2);
|
||||
if (!t1) assertEqX4(v1, l1);
|
||||
|
||||
// Stores
|
||||
if (!t) {
|
||||
simdCtor.store(arr, index, simdCtor.not(v));
|
||||
f.store(i, v);
|
||||
assertEqX4(simdCtor.load(arr, index), v);
|
||||
} else
|
||||
assertThrowsInstanceOf(() => f.store(i, simdCtor()), RangeError);
|
||||
if (!t3) {
|
||||
simdCtor.store3(arr, index, simdCtor.not(v3));
|
||||
f.store3(i, v3);
|
||||
assertEqX4(simdCtor.load3(arr, index), v3);
|
||||
} else
|
||||
assertThrowsInstanceOf(() => f.store3(i, simdCtor()), RangeError);
|
||||
if (!t2) {
|
||||
simdCtor.store2(arr, index, simdCtor.not(v2));
|
||||
f.store2(i, v2);
|
||||
assertEqX4(simdCtor.load2(arr, index), v2);
|
||||
} else
|
||||
assertThrowsInstanceOf(() => f.store2(i, simdCtor()), RangeError);
|
||||
if (!t1) {
|
||||
simdCtor.store1(arr, index, simdCtor.not(v1));
|
||||
f.store1(i, v1);
|
||||
assertEqX4(simdCtor.load1(arr, index), v1);
|
||||
} else
|
||||
assertThrowsInstanceOf(() => f.store1(i, simdCtor()), RangeError);
|
||||
}
|
||||
}
|
||||
|
||||
function testFloat32x4(ctor, shift, scale, disp) {
|
||||
testSimdX4(ctor, shift, scale, disp, 'float32x4', SIMD.float32x4);
|
||||
}
|
||||
function testInt32x4(ctor, shift, scale, disp) {
|
||||
testSimdX4(ctor, shift, scale, disp, 'int32x4', SIMD.int32x4);
|
||||
}
|
||||
|
||||
function test(tester, ctor, shift) {
|
||||
var arr = new ctor(ab);
|
||||
for (var i = 0; i < arr.length; i++)
|
||||
arr[i] = Math.imul(i, Math.imul((i & 1), 2) - 1);
|
||||
for (scale of [0,1,2,3]) {
|
||||
for (disp of [0,1,2,8,Math.pow(2,31)-1,Math.pow(2,31),Math.pow(2,32)-1])
|
||||
tester(ctor, shift, scale, disp);
|
||||
}
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
var v = arr[i];
|
||||
arr[i] = Math.imul(i, Math.imul((i & 1), 2) - 1);
|
||||
assertEq(arr[i], v);
|
||||
}
|
||||
}
|
||||
|
||||
test(testInt, Int8Array, 0);
|
||||
test(testInt, Uint8Array, 0);
|
||||
test(testInt, Int16Array, 1);
|
||||
test(testInt, Uint16Array, 1);
|
||||
test(testInt, Int32Array, 2);
|
||||
test(testInt, Uint32Array, 2);
|
||||
test(testFloat32, Float32Array, 2);
|
||||
test(testFloat64, Float64Array, 3);
|
||||
if (typeof SIMD !== 'undefined' && isSimdAvailable()) {
|
||||
test(testInt32x4, Uint8Array, 0);
|
||||
test(testFloat32x4, Uint8Array, 0);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Binary: cache/js-dbg-32-f561f17e6c27-linux
|
||||
// Flags:
|
||||
//
|
||||
Reflect.parse("for (var x = 3 in []) { }")
|
||||
Reflect.parse("for (var x in []) { }")
|
||||
|
||||
@@ -3,4 +3,10 @@
|
||||
//
|
||||
load(libdir + 'asserts.js');
|
||||
// value is not iterable
|
||||
assertThrowsInstanceOf(function(){for(var[x]=x>>x in[[]<[]]){[]}}, TypeError);
|
||||
(function() {
|
||||
for (var [x] in [[] < []])
|
||||
{
|
||||
// Just a useless expression.
|
||||
[];
|
||||
}
|
||||
})();
|
||||
|
||||
+107
-97
@@ -1,5 +1,6 @@
|
||||
// Warning should be shown for expression-like statement after semicolon-less
|
||||
// return (bug 1005110).
|
||||
// Warning should be shown for unreachable statement after return (bug 1151931).
|
||||
|
||||
load(libdir + "class.js");
|
||||
|
||||
if (options().indexOf("werror") == -1)
|
||||
options("werror");
|
||||
@@ -10,7 +11,7 @@ function testWarn(code, lineNumber, columnNumber) {
|
||||
eval(code);
|
||||
} catch (e) {
|
||||
caught = true;
|
||||
assertEq(e.message, "unreachable expression after semicolon-less return statement", code);
|
||||
assertEq(e.constructor, SyntaxError);
|
||||
assertEq(e.lineNumber, lineNumber);
|
||||
assertEq(e.columnNumber, columnNumber);
|
||||
}
|
||||
@@ -21,7 +22,7 @@ function testWarn(code, lineNumber, columnNumber) {
|
||||
Reflect.parse(code);
|
||||
} catch (e) {
|
||||
caught = true;
|
||||
assertEq(e.message, "unreachable expression after semicolon-less return statement", code);
|
||||
assertEq(e.constructor, SyntaxError);
|
||||
}
|
||||
assertEq(caught, true, "warning should be caught for " + code);
|
||||
}
|
||||
@@ -44,8 +45,6 @@ function testPass(code) {
|
||||
assertEq(caught, false, "warning should not be caught for " + code);
|
||||
}
|
||||
|
||||
// not EOL
|
||||
|
||||
testPass(`
|
||||
function f() {
|
||||
return (
|
||||
@@ -53,16 +52,8 @@ function f() {
|
||||
);
|
||||
}
|
||||
`);
|
||||
testPass(`
|
||||
function f() {
|
||||
return;
|
||||
1 + 2;
|
||||
}
|
||||
`);
|
||||
|
||||
// starts expression
|
||||
|
||||
// TOK_INC
|
||||
// unary expression
|
||||
testWarn(`
|
||||
function f() {
|
||||
var i = 0;
|
||||
@@ -70,8 +61,6 @@ function f() {
|
||||
++i;
|
||||
}
|
||||
`, 5, 4);
|
||||
|
||||
// TOK_DEC
|
||||
testWarn(`
|
||||
function f() {
|
||||
var i = 0;
|
||||
@@ -80,7 +69,7 @@ function f() {
|
||||
}
|
||||
`, 5, 4);
|
||||
|
||||
// TOK_LB
|
||||
// array
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
@@ -88,7 +77,7 @@ function f() {
|
||||
}
|
||||
`, 4, 4);
|
||||
|
||||
// TOK_LC
|
||||
// block (object)
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
@@ -107,7 +96,7 @@ function f() {
|
||||
}
|
||||
`, 4, 2);
|
||||
|
||||
// TOK_LP
|
||||
// expression in paren
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
@@ -115,7 +104,7 @@ function f() {
|
||||
}
|
||||
`, 4, 4);
|
||||
|
||||
// TOK_NAME
|
||||
// name
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
@@ -123,7 +112,7 @@ function f() {
|
||||
}
|
||||
`, 4, 4);
|
||||
|
||||
// TOK_NUMBER
|
||||
// binary expression
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
@@ -137,7 +126,7 @@ function f() {
|
||||
}
|
||||
`, 4, 4);
|
||||
|
||||
// TOK_STRING
|
||||
// string
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
@@ -157,15 +146,13 @@ function f() {
|
||||
}
|
||||
`, 4, 4);
|
||||
|
||||
// TOK_TEMPLATE_HEAD
|
||||
// template string
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
\`foo\${1 + 2}\`;
|
||||
}
|
||||
`, 4, 4);
|
||||
|
||||
// TOK_NO_SUBS_TEMPLATE
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
@@ -173,7 +160,7 @@ function f() {
|
||||
}
|
||||
`, 4, 4);
|
||||
|
||||
// TOK_REGEXP
|
||||
// RegExp
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
@@ -181,15 +168,13 @@ function f() {
|
||||
}
|
||||
`, 4, 4);
|
||||
|
||||
// TOK_TRUE
|
||||
// boolean
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
true;
|
||||
}
|
||||
`, 4, 4);
|
||||
|
||||
// TOK_FALSE
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
@@ -197,7 +182,7 @@ function f() {
|
||||
}
|
||||
`, 4, 4);
|
||||
|
||||
// TOK_NULL
|
||||
// null
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
@@ -205,7 +190,7 @@ function f() {
|
||||
}
|
||||
`, 4, 4);
|
||||
|
||||
// TOK_THIS
|
||||
// this
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
@@ -213,7 +198,7 @@ function f() {
|
||||
}
|
||||
`, 4, 4);
|
||||
|
||||
// TOK_NEW
|
||||
// new
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
@@ -221,7 +206,7 @@ function f() {
|
||||
}
|
||||
`, 4, 4);
|
||||
|
||||
// TOK_DELETE
|
||||
// delete
|
||||
testWarn(`
|
||||
function f() {
|
||||
var a = {x: 10};
|
||||
@@ -230,7 +215,7 @@ function f() {
|
||||
}
|
||||
`, 5, 4);
|
||||
|
||||
// TOK_YIELD
|
||||
// yield
|
||||
testWarn(`
|
||||
function* f() {
|
||||
return
|
||||
@@ -238,39 +223,35 @@ function* f() {
|
||||
}
|
||||
`, 4, 4);
|
||||
|
||||
// TOK_CLASS
|
||||
testWarn(`
|
||||
// class
|
||||
if (classesEnabled()) {
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
class A { constructor() {} };
|
||||
}
|
||||
`, 4, 4);
|
||||
}
|
||||
|
||||
// TOK_ADD
|
||||
// unary expression
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
+1;
|
||||
}
|
||||
`, 4, 4);
|
||||
|
||||
// TOK_SUB
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
-1;
|
||||
}
|
||||
`, 4, 4);
|
||||
|
||||
// TOK_NOT
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
!1;
|
||||
}
|
||||
`, 4, 4);
|
||||
|
||||
// TOK_BITNOT
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
@@ -278,14 +259,12 @@ function f() {
|
||||
}
|
||||
`, 4, 4);
|
||||
|
||||
// don't start expression
|
||||
|
||||
// TOK_EOF
|
||||
// eof
|
||||
testPass(`
|
||||
var f = new Function("return\\n");
|
||||
`);
|
||||
|
||||
// TOK_SEMI
|
||||
// empty statement
|
||||
testPass(`
|
||||
function f() {
|
||||
return
|
||||
@@ -293,7 +272,7 @@ function f() {
|
||||
}
|
||||
`);
|
||||
|
||||
// TOK_RC
|
||||
// end of block
|
||||
testPass(`
|
||||
function f() {
|
||||
{
|
||||
@@ -302,7 +281,7 @@ function f() {
|
||||
}
|
||||
`);
|
||||
|
||||
// TOK_FUNCTION
|
||||
// function (hosted)
|
||||
testPass(`
|
||||
function f() {
|
||||
g();
|
||||
@@ -311,16 +290,16 @@ function f() {
|
||||
}
|
||||
`);
|
||||
|
||||
// TOK_IF
|
||||
testPass(`
|
||||
// if
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
if (true)
|
||||
1 + 2;
|
||||
}
|
||||
`);
|
||||
`, 4, 2);
|
||||
|
||||
// TOK_ELSE
|
||||
// else
|
||||
testPass(`
|
||||
function f() {
|
||||
if (true)
|
||||
@@ -330,8 +309,8 @@ function f() {
|
||||
}
|
||||
`);
|
||||
|
||||
// TOK_SWITCH
|
||||
testPass(`
|
||||
// switch
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
switch (1) {
|
||||
@@ -339,9 +318,32 @@ function f() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
`, 4, 2);
|
||||
|
||||
// return in switch
|
||||
testWarn(`
|
||||
function f() {
|
||||
switch (1) {
|
||||
case 1:
|
||||
return;
|
||||
1 + 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
`, 6, 6);
|
||||
|
||||
// break in switch
|
||||
testPass(`
|
||||
function f() {
|
||||
switch (1) {
|
||||
case 1:
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
// TOK_CASE
|
||||
// case
|
||||
testPass(`
|
||||
function f() {
|
||||
switch (1) {
|
||||
@@ -353,7 +355,7 @@ function f() {
|
||||
}
|
||||
`);
|
||||
|
||||
// TOK_DEFAULT
|
||||
// default
|
||||
testPass(`
|
||||
function f() {
|
||||
switch (1) {
|
||||
@@ -365,14 +367,14 @@ function f() {
|
||||
}
|
||||
`);
|
||||
|
||||
// TOK_WHILE
|
||||
testPass(`
|
||||
// while
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
while (false)
|
||||
1 + 2;
|
||||
}
|
||||
`);
|
||||
`, 4, 2);
|
||||
testPass(`
|
||||
function f() {
|
||||
do
|
||||
@@ -381,27 +383,27 @@ function f() {
|
||||
}
|
||||
`);
|
||||
|
||||
// TOK_DO
|
||||
testPass(`
|
||||
// do
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
do {
|
||||
1 + 2;
|
||||
} while (false);
|
||||
}
|
||||
`);
|
||||
`, 4, 2);
|
||||
|
||||
// TOK_FOR
|
||||
testPass(`
|
||||
// for
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
for (;;) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
`);
|
||||
`, 4, 2);
|
||||
|
||||
// TOK_BREAK
|
||||
// break in for
|
||||
testPass(`
|
||||
function f() {
|
||||
for (;;) {
|
||||
@@ -409,19 +411,19 @@ function f() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
`);
|
||||
`, 5, 4);
|
||||
|
||||
// TOK_CONTINUE
|
||||
testPass(`
|
||||
// continue
|
||||
testWarn(`
|
||||
function f() {
|
||||
for (;;) {
|
||||
return
|
||||
continue;
|
||||
}
|
||||
}
|
||||
`);
|
||||
`, 5, 4);
|
||||
|
||||
// TOK_VAR
|
||||
// var (hosted)
|
||||
testPass(`
|
||||
function f() {
|
||||
return
|
||||
@@ -429,43 +431,43 @@ function f() {
|
||||
}
|
||||
`);
|
||||
|
||||
// TOK_CONST
|
||||
testPass(`
|
||||
// const
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
const a = 1;
|
||||
}
|
||||
`);
|
||||
`, 4, 2);
|
||||
|
||||
// TOK_WITH
|
||||
testPass(`
|
||||
// with
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
with ({}) {
|
||||
1;
|
||||
}
|
||||
}
|
||||
`);
|
||||
`, 4, 2);
|
||||
|
||||
// TOK_RETURN
|
||||
testPass(`
|
||||
// return
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
return;
|
||||
}
|
||||
`);
|
||||
`, 4, 2);
|
||||
|
||||
// TOK_TRY
|
||||
testPass(`
|
||||
// try
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
try {
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
`);
|
||||
`, 4, 2);
|
||||
|
||||
// TOK_THROW
|
||||
// throw
|
||||
testPass(`
|
||||
function f() {
|
||||
return
|
||||
@@ -473,29 +475,37 @@ function f() {
|
||||
}
|
||||
`);
|
||||
|
||||
// TOK_DEBUGGER
|
||||
testPass(`
|
||||
// debugger
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
debugger;
|
||||
}
|
||||
`);
|
||||
`, 4, 2);
|
||||
|
||||
// TOK_LET
|
||||
testPass(`
|
||||
// let
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
let a = 1;
|
||||
}
|
||||
`);
|
||||
`, 4, 2);
|
||||
|
||||
// exceptional case
|
||||
// skip hoisted
|
||||
|
||||
// It's not possible to distinguish between a label statement and an expression
|
||||
// starts with identifier, by checking a token next to return.
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
a: 1;
|
||||
var a = 0;
|
||||
(1 + 2);
|
||||
}
|
||||
`, 4, 2);
|
||||
`, 5, 2);
|
||||
|
||||
testWarn(`
|
||||
function f() {
|
||||
return
|
||||
function f() {}
|
||||
var a = 0;
|
||||
(1 + 2);
|
||||
}
|
||||
`, 6, 2);
|
||||
@@ -1,17 +0,0 @@
|
||||
// |jit-test| error: TypeError
|
||||
|
||||
(eval("\
|
||||
(function () {\
|
||||
for (var[x] = function(){} in \
|
||||
(function m(a) {\
|
||||
if (a < 1) {\
|
||||
x;\
|
||||
return\
|
||||
}\
|
||||
return m(a - 1) + m(a - 2)\
|
||||
})(7)\
|
||||
(eval(\"\"))\
|
||||
)\
|
||||
([])\
|
||||
})\
|
||||
"))()
|
||||
@@ -1,3 +0,0 @@
|
||||
(function() {
|
||||
for (var [e] = [] in (eval("for (b = 0; b < 6; ++b) gc()"))) {}
|
||||
})()
|
||||
@@ -0,0 +1,12 @@
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
let strcut = ctypes.StructType("a", [ { "x": ctypes.int32_t, } ])();
|
||||
for (let arg of [1, undefined, null, false, {}, [], Symbol("foo")]) {
|
||||
assertThrowsInstanceOf(() => { struct.addressOfField(arg); },
|
||||
Error);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,9 @@
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
assertTypeErrorMessage(() => { ctypes.default_abi.toSource(1); },
|
||||
"ABI.prototype.toSource takes no arguments");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,15 @@
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
assertTypeErrorMessage(() => { ctypes.ArrayType(); },
|
||||
"ArrayType takes one or two arguments");
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t.array(10)(1, 2); },
|
||||
"size defined ArrayType constructor takes at most one argument");
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t.array()(1, 2); },
|
||||
"size undefined ArrayType constructor takes one argument");
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t.array(10)().addressOfElement(); },
|
||||
"ArrayType.prototype.addressOfElement takes one argument");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,15 @@
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t(0).address(1); },
|
||||
"CData.prototype.address takes no arguments");
|
||||
assertTypeErrorMessage(() => { ctypes.char.array(10)().readString(1); },
|
||||
"CData.prototype.readString takes no arguments");
|
||||
assertTypeErrorMessage(() => { ctypes.char.array(10)().readStringReplaceMalformed(1); },
|
||||
"CData.prototype.readStringReplaceMalformed takes no arguments");
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t(0).toSource(1); },
|
||||
"CData.prototype.toSource takes no arguments");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,11 @@
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
assertTypeErrorMessage(() => { ctypes.cast(); },
|
||||
"ctypes.cast takes two arguments");
|
||||
assertTypeErrorMessage(() => { ctypes.getRuntime(); },
|
||||
"ctypes.getRuntime takes one argument");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,16 @@
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
assertTypeErrorMessage(() => { ctypes.CDataFinalizer(1); },
|
||||
"CDataFinalizer constructor takes two arguments");
|
||||
|
||||
let fin = ctypes.CDataFinalizer(ctypes.int32_t(0), ctypes.FunctionType(ctypes.default_abi, ctypes.int32_t, [ctypes.int32_t]).ptr(x => x));
|
||||
assertTypeErrorMessage(() => { fin.forget(1); },
|
||||
"CDataFinalizer.prototype.forget takes no arguments");
|
||||
assertTypeErrorMessage(() => { fin.dispose(1); },
|
||||
"CDataFinalizer.prototype.dispose takes no arguments");
|
||||
fin.forget();
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,11 @@
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
assertTypeErrorMessage(() => { ctypes.FunctionType(); },
|
||||
"FunctionType takes two or three arguments");
|
||||
assertTypeErrorMessage(() => { ctypes.FunctionType(ctypes.default_abi, ctypes.void_t, []).ptr({}, 1); },
|
||||
"FunctionType constructor takes one argument");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,36 @@
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
assertTypeErrorMessage(() => { ctypes.Int64(1).toString(1, 2); },
|
||||
"Int64.prototype.toString takes at most one argument");
|
||||
assertTypeErrorMessage(() => { ctypes.Int64(1).toSource(1); },
|
||||
"Int64.prototype.toSource takes no arguments");
|
||||
assertTypeErrorMessage(() => { ctypes.Int64(); },
|
||||
"Int64 constructor takes one argument");
|
||||
assertTypeErrorMessage(() => { ctypes.Int64.compare(); },
|
||||
"Int64.compare takes two arguments");
|
||||
assertTypeErrorMessage(() => { ctypes.Int64.lo(); },
|
||||
"Int64.lo takes one argument");
|
||||
assertTypeErrorMessage(() => { ctypes.Int64.hi(); },
|
||||
"Int64.hi takes one argument");
|
||||
assertTypeErrorMessage(() => { ctypes.Int64.join(); },
|
||||
"Int64.join takes two arguments");
|
||||
|
||||
assertTypeErrorMessage(() => { ctypes.UInt64(1).toString(1, 2); },
|
||||
"UInt64.prototype.toString takes at most one argument");
|
||||
assertTypeErrorMessage(() => { ctypes.UInt64(1).toSource(1); },
|
||||
"UInt64.prototype.toSource takes no arguments");
|
||||
assertTypeErrorMessage(() => { ctypes.UInt64(); },
|
||||
"UInt64 constructor takes one argument");
|
||||
assertTypeErrorMessage(() => { ctypes.UInt64.compare(); },
|
||||
"UInt64.compare takes two arguments");
|
||||
assertTypeErrorMessage(() => { ctypes.UInt64.lo(); },
|
||||
"UInt64.lo takes one argument");
|
||||
assertTypeErrorMessage(() => { ctypes.UInt64.hi(); },
|
||||
"UInt64.hi takes one argument");
|
||||
assertTypeErrorMessage(() => { ctypes.UInt64.join(); },
|
||||
"UInt64.join takes two arguments");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,11 @@
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
assertTypeErrorMessage(() => { ctypes.PointerType(); },
|
||||
"PointerType takes one argument");
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t.ptr(1, 2, 3, 4); },
|
||||
"PointerType constructor takes 0, 1, 2, or 3 arguments");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,11 @@
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t(1, 2, 3); },
|
||||
"CType constructor takes at most one argument");
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t.array(1, 2); },
|
||||
"CType.prototype.array takes at most one argument");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,17 @@
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
assertTypeErrorMessage(() => { ctypes.StructType(); },
|
||||
"StructType takes one or two arguments");
|
||||
assertTypeErrorMessage(() => { ctypes.StructType("a").define(); },
|
||||
"StructType.prototype.define takes one argument");
|
||||
assertTypeErrorMessage(() => { ctypes.StructType("a", [])(1, 2, 3); },
|
||||
"StructType constructor takes at most one argument");
|
||||
assertTypeErrorMessage(() => { ctypes.StructType("a", [ {"x": ctypes.int32_t }, {"y": ctypes.int32_t }, {"z": ctypes.int32_t }])(1, 2); },
|
||||
"StructType constructor takes 0, 1, or 3 arguments");
|
||||
assertTypeErrorMessage(() => { ctypes.StructType("a", [ {"x": ctypes.int32_t } ])().addressOfField(); },
|
||||
"StructType.prototype.addressOfField takes one argument");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,17 @@
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t.array({}); },
|
||||
"argument of CType.prototype.array must be a nonnegative integer");
|
||||
assertTypeErrorMessage(() => { ctypes.ArrayType(1); },
|
||||
"first argument of ArrayType must be a CType");
|
||||
assertTypeErrorMessage(() => { ctypes.ArrayType(ctypes.int32_t, {}); },
|
||||
"second argument of ArrayType must be a nonnegative integer");
|
||||
assertTypeErrorMessage(() => { ctypes.char.array()({}); },
|
||||
"argument of size undefined ArrayType constructor must be an array object or integer");
|
||||
assertTypeErrorMessage(() => { ctypes.char.array()(false); },
|
||||
"argument of size undefined ArrayType constructor must be an array object or integer");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,13 @@
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
assertTypeErrorMessage(() => { ctypes.cast(1, 2); },
|
||||
"first argument of ctypes.cast must be a CData");
|
||||
assertTypeErrorMessage(() => { ctypes.cast(ctypes.int32_t(0), 2); },
|
||||
"second argument of ctypes.cast must be a CType");
|
||||
assertTypeErrorMessage(() => { ctypes.getRuntime(1); },
|
||||
"argument of ctypes.getRuntime must be a CType");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,9 @@
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
assertTypeErrorMessage(() => { ctypes.FunctionType(ctypes.default_abi, ctypes.int32_t, 1); },
|
||||
"third argument of FunctionType must be an array");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,28 @@
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
assertRangeErrorMessage(() => { ctypes.Int64(0).toString("a"); },
|
||||
"argument of Int64.prototype.toString must be an integer at least 2 and no greater than 36");
|
||||
assertTypeErrorMessage(() => { ctypes.Int64.compare(1, 2); },
|
||||
"first argument of Int64.compare must be a Int64");
|
||||
assertTypeErrorMessage(() => { ctypes.Int64.compare(ctypes.Int64(0), 2); },
|
||||
"second argument of Int64.compare must be a Int64");
|
||||
assertTypeErrorMessage(() => { ctypes.Int64.lo(1); },
|
||||
"argument of Int64.lo must be a Int64");
|
||||
assertTypeErrorMessage(() => { ctypes.Int64.hi(1); },
|
||||
"argument of Int64.hi must be a Int64");
|
||||
|
||||
assertRangeErrorMessage(() => { ctypes.UInt64(0).toString("a"); },
|
||||
"argument of UInt64.prototype.toString must be an integer at least 2 and no greater than 36");
|
||||
assertTypeErrorMessage(() => { ctypes.UInt64.compare(1, 2); },
|
||||
"first argument of UInt64.compare must be a UInt64");
|
||||
assertTypeErrorMessage(() => { ctypes.UInt64.compare(ctypes.UInt64(0), 2); },
|
||||
"second argument of UInt64.compare must be a UInt64");
|
||||
assertTypeErrorMessage(() => { ctypes.UInt64.lo(1); },
|
||||
"argument of UInt64.lo must be a UInt64");
|
||||
assertTypeErrorMessage(() => { ctypes.UInt64.hi(1); },
|
||||
"argument of UInt64.hi must be a UInt64");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,9 @@
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
assertTypeErrorMessage(() => { ctypes.PointerType({}); },
|
||||
"argument of PointerType must be a CType");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,17 @@
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
assertTypeErrorMessage(() => { ctypes.StructType(1); },
|
||||
"first argument of StructType must be a string");
|
||||
assertTypeErrorMessage(() => { ctypes.StructType("a", 1); },
|
||||
"second argument of StructType must be an array");
|
||||
assertTypeErrorMessage(() => { ctypes.StructType("a").define(1); },
|
||||
"argument of StructType.prototype.define must be an array");
|
||||
assertTypeErrorMessage(() => { ctypes.StructType("a").define({}); },
|
||||
"argument of StructType.prototype.define must be an array");
|
||||
assertTypeErrorMessage(() => { ctypes.StructType("a", [{x:ctypes.int32_t}])().addressOfField(1); },
|
||||
"argument of StructType.prototype.addressOfField must be a string");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,36 @@
|
||||
// Type conversion error should report its type.
|
||||
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
// constructor
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t.array()("foo"); },
|
||||
"can't convert the string \"foo\" to the type ctypes.int32_t.array()");
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t.array(10)("foo"); },
|
||||
"can't convert the string \"foo\" to the type ctypes.int32_t.array(10)");
|
||||
assertTypeErrorMessage(() => { ctypes.char.array(2)("foo"); },
|
||||
"length of the string \"foo\" does not fit to the length of the type ctypes.char.array(2) (expected 2 or lower, got 3)");
|
||||
assertTypeErrorMessage(() => { ctypes.char16_t.array(2)("foo"); },
|
||||
"length of the string \"foo\" does not fit to the length of the type ctypes.char16_t.array(2) (expected 2 or lower, got 3)");
|
||||
assertTypeErrorMessage(() => { ctypes.int8_t.array(2)(new ArrayBuffer(8)); },
|
||||
"length of the array buffer ({}) does not match to the length of the type ctypes.int8_t.array(2) (expected 2, got 8)");
|
||||
assertTypeErrorMessage(() => { ctypes.int8_t.array(2)(new Int8Array(8)); },
|
||||
"length of the typed array ({0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0}) does not match to the length of the type ctypes.int8_t.array(2) (expected 2, got 8)");
|
||||
|
||||
// elem setter
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t.array(10)()[0] = "foo"; },
|
||||
"can't convert the string \"foo\" to element 0 of the type ctypes.int32_t.array(10)");
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t.array(10)()[1] = "foo"; },
|
||||
"can't convert the string \"foo\" to element 1 of the type ctypes.int32_t.array(10)");
|
||||
|
||||
// value setter
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t.array(1)().value = ["foo"]; },
|
||||
"can't convert the string \"foo\" to element 0 of the type ctypes.int32_t.array(1)");
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t.array(1)().value = [2, "foo"]; },
|
||||
"length of the array [2, \"foo\"] does not match to the length of the type ctypes.int32_t.array(1) (expected 1, got 2)");
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t.array(2)().value = [2, "foo"]; },
|
||||
"can't convert the string \"foo\" to element 1 of the type ctypes.int32_t.array(2)");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,14 @@
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
let obj = {
|
||||
toSource() {
|
||||
throw 1;
|
||||
}
|
||||
};
|
||||
assertTypeErrorMessage(() => { ctypes.double().value = obj; },
|
||||
"can't convert <<error converting value to string>> to the type double");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,61 @@
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
// non object
|
||||
assertTypeErrorMessage(() => { ctypes.CDataFinalizer(0, "foo"); },
|
||||
"expected _a CData object_ of a function pointer type, got the string \"foo\"");
|
||||
// non CData object
|
||||
assertTypeErrorMessage(() => { ctypes.CDataFinalizer(0, ["foo"]); },
|
||||
"expected a _CData_ object of a function pointer type, got the array [\"foo\"]");
|
||||
|
||||
// a CData which is not a pointer
|
||||
assertTypeErrorMessage(() => { ctypes.CDataFinalizer(0, ctypes.int32_t(0)); },
|
||||
"expected a CData object of a function _pointer_ type, got ctypes.int32_t(0)");
|
||||
// a pointer CData which is not a function
|
||||
assertTypeErrorMessage(() => { ctypes.CDataFinalizer(0, ctypes.int32_t.ptr(0)); },
|
||||
"expected a CData object of a _function_ pointer type, got ctypes.int32_t.ptr(ctypes.UInt64(\"0x0\"))");
|
||||
|
||||
// null function
|
||||
let func_type = ctypes.FunctionType(ctypes.default_abi, ctypes.voidptr_t,
|
||||
[ctypes.int32_t, ctypes.int32_t]).ptr;
|
||||
let f0 = func_type(0);
|
||||
assertTypeErrorMessage(() => { ctypes.CDataFinalizer(0, f0); },
|
||||
"expected a CData object of a _non-NULL_ function pointer type, got ctypes.FunctionType(ctypes.default_abi, ctypes.voidptr_t, [ctypes.int32_t, ctypes.int32_t]).ptr(ctypes.UInt64(\"0x0\"))");
|
||||
|
||||
// a function with 2 arguments
|
||||
let f1 = func_type(x => x);
|
||||
assertTypeErrorMessage(() => { ctypes.CDataFinalizer(0, f1); },
|
||||
"expected a function accepting exactly one argument, got ctypes.FunctionType(ctypes.default_abi, ctypes.voidptr_t, [ctypes.int32_t, ctypes.int32_t])");
|
||||
|
||||
// non CData in argument 1
|
||||
let func_type2 = ctypes.FunctionType(ctypes.default_abi, ctypes.voidptr_t,
|
||||
[ctypes.int32_t.ptr]).ptr;
|
||||
let f2 = func_type2(x => x);
|
||||
assertTypeErrorMessage(() => { ctypes.CDataFinalizer(0, f2); },
|
||||
"can't convert the number 0 to the type of argument 1 of ctypes.FunctionType(ctypes.default_abi, ctypes.voidptr_t, [ctypes.int32_t.ptr]).ptr");
|
||||
|
||||
// wrong struct in argument 1
|
||||
let test_struct = ctypes.StructType("test_struct", [{ "x": ctypes.int32_t }]);
|
||||
let func_type3 = ctypes.FunctionType(ctypes.default_abi, ctypes.voidptr_t,
|
||||
[test_struct]).ptr;
|
||||
let f3 = func_type3(x => x);
|
||||
assertTypeErrorMessage(() => { ctypes.CDataFinalizer({ "x": "foo" }, f3); },
|
||||
"can't convert the string \"foo\" to the 'x' field (int32_t) of test_struct at argument 1 of ctypes.FunctionType(ctypes.default_abi, ctypes.voidptr_t, [test_struct]).ptr");
|
||||
|
||||
// different size in argument 1
|
||||
let func_type4 = ctypes.FunctionType(ctypes.default_abi, ctypes.int32_t,
|
||||
[ctypes.int32_t]).ptr;
|
||||
let f4 = func_type4(x => x);
|
||||
assertTypeErrorMessage(() => { ctypes.CDataFinalizer(ctypes.int16_t(0), f4); },
|
||||
"expected an object with the same size as argument 1 of ctypes.FunctionType(ctypes.default_abi, ctypes.int32_t, [ctypes.int32_t]).ptr, got ctypes.int16_t(0)");
|
||||
|
||||
let fin = ctypes.CDataFinalizer(ctypes.int32_t(0), f4);
|
||||
fin.dispose();
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t(0).value = fin; },
|
||||
"attempting to convert an empty CDataFinalizer");
|
||||
assertTypeErrorMessage(() => { f4(fin); },
|
||||
/attempting to convert an empty CDataFinalizer at argument 1 of ctypes\.FunctionType\(ctypes\.default_abi, ctypes\.int32_t, \[ctypes\.int32_t\]\)\.ptr\(ctypes\.UInt64\(\"[x0-9A-Fa-f]+\"\)\)/);
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,33 @@
|
||||
// Type conversion error should report its type.
|
||||
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
// Note: js shell cannot handle the exception in return value.
|
||||
|
||||
// primitive
|
||||
let func_type = ctypes.FunctionType(ctypes.default_abi, ctypes.voidptr_t,
|
||||
[ctypes.int32_t]).ptr;
|
||||
let f1 = func_type(function() {});
|
||||
assertTypeErrorMessage(() => { f1("foo"); },
|
||||
/can't pass the string "foo" to argument 1 of ctypes\.FunctionType\(ctypes\.default_abi, ctypes\.voidptr_t, \[ctypes\.int32_t\]\)\.ptr\(ctypes\.UInt64\("[x0-9A-Fa-f]+"\)\)/);
|
||||
|
||||
// struct
|
||||
let test_struct = ctypes.StructType("test_struct", [{ "x": ctypes.int32_t }]);
|
||||
let func_type2 = ctypes.FunctionType(ctypes.default_abi, ctypes.int32_t,
|
||||
[test_struct]).ptr;
|
||||
let f2 = func_type2(function() {});
|
||||
assertTypeErrorMessage(() => { f2({ "x": "foo" }); },
|
||||
/can't convert the string \"foo\" to the 'x' field \(int32_t\) of test_struct at argument 1 of ctypes\.FunctionType\(ctypes\.default_abi, ctypes.int32_t, \[test_struct\]\)\.ptr\(ctypes\.UInt64\(\"[x0-9A-Fa-f]+\"\)\)/);
|
||||
assertTypeErrorMessage(() => { f2({ "x": "foo", "y": "bar" }); },
|
||||
/property count of the object \(\{x:\"foo\", y:\"bar\"\}\) does not match to field count of the type test_struct \(expected 1, got 2\) at argument 1 of ctypes\.FunctionType\(ctypes\.default_abi, ctypes\.int32_t, \[test_struct\]\)\.ptr\(ctypes\.UInt64\(\"[x0-9A-Fa-f]+\"\)\)/);
|
||||
assertTypeErrorMessage(() => { f2({ 0: "foo" }); },
|
||||
/property name the number 0 of the object \(\{0:\"foo\"\}\) is not a string at argument 1 of ctypes\.FunctionType\(ctypes\.default_abi, ctypes\.int32_t, \[test_struct\]\)\.ptr\(ctypes\.UInt64\(\"[x0-9A-Fa-f]+\"\)\)/);
|
||||
|
||||
// error sentinel
|
||||
assertTypeErrorMessage(() => { func_type(function() {}, null, "foo"); },
|
||||
"can't convert the string \"foo\" to the return type of ctypes.FunctionType(ctypes.default_abi, ctypes.voidptr_t, [ctypes.int32_t])");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,20 @@
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
assertTypeErrorMessage(() => { ctypes.Int64("0xfffffffffffffffffffffff"); },
|
||||
"can't pass the string \"0xfffffffffffffffffffffff\" to argument 1 of Int64");
|
||||
assertTypeErrorMessage(() => { ctypes.Int64.join("foo", 0); },
|
||||
"can't pass the string \"foo\" to argument 1 of Int64.join");
|
||||
assertTypeErrorMessage(() => { ctypes.Int64.join(0, "foo"); },
|
||||
"can't pass the string \"foo\" to argument 2 of Int64.join");
|
||||
|
||||
assertTypeErrorMessage(() => { ctypes.UInt64("0xfffffffffffffffffffffff"); },
|
||||
"can't pass the string \"0xfffffffffffffffffffffff\" to argument 1 of UInt64");
|
||||
assertTypeErrorMessage(() => { ctypes.UInt64.join("foo", 0); },
|
||||
"can't pass the string \"foo\" to argument 1 of UInt64.join");
|
||||
assertTypeErrorMessage(() => { ctypes.UInt64.join(0, "foo"); },
|
||||
"can't pass the string \"foo\" to argument 2 of UInt64.join");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,37 @@
|
||||
// Type conversion error for native function should report its name and type
|
||||
// in C style.
|
||||
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
let lib;
|
||||
try {
|
||||
lib = ctypes.open(ctypes.libraryName("c"));
|
||||
} catch (e) {
|
||||
}
|
||||
if (!lib)
|
||||
return;
|
||||
|
||||
let func = lib.declare("hypot",
|
||||
ctypes.default_abi,
|
||||
ctypes.double,
|
||||
ctypes.double, ctypes.double);
|
||||
assertTypeErrorMessage(() => { func(1, "xyzzy"); },
|
||||
"can't pass the string \"xyzzy\" to argument 2 of double hypot(double, double)");
|
||||
|
||||
// test C style source for various types
|
||||
let test_struct = ctypes.StructType("test_struct", [{ "x": ctypes.int32_t }]);
|
||||
let test_func = ctypes.FunctionType(ctypes.default_abi, ctypes.voidptr_t,
|
||||
[ctypes.int32_t]).ptr;
|
||||
func = lib.declare("hypot",
|
||||
ctypes.default_abi,
|
||||
ctypes.double,
|
||||
ctypes.double, ctypes.int32_t.ptr.ptr.ptr.array(),
|
||||
test_struct, test_struct.ptr.ptr,
|
||||
test_func, test_func.ptr.ptr.ptr, "...");
|
||||
assertTypeErrorMessage(() => { func("xyzzy", 1, 2, 3, 4, 5); },
|
||||
"can't pass the string \"xyzzy\" to argument 1 of double hypot(double, int32_t****, struct test_struct, struct test_struct**, void* (*)(int32_t), void* (****)(int32_t), ...)");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,29 @@
|
||||
// Type conversion error should report its type.
|
||||
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
let test_struct = ctypes.StructType("test_struct", [{ "x": ctypes.int32_t }]);
|
||||
let struct_val = test_struct();
|
||||
|
||||
// constructor
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t.ptr("foo"); },
|
||||
"can't convert the string \"foo\" to the type ctypes.int32_t.ptr");
|
||||
|
||||
// value setter
|
||||
assertTypeErrorMessage(() => { test_struct.ptr().value = "foo"; },
|
||||
"can't convert the string \"foo\" to the type test_struct.ptr");
|
||||
assertTypeErrorMessage(() => { test_struct.ptr().value = {}; },
|
||||
"can't convert the object ({}) to the type test_struct.ptr");
|
||||
assertTypeErrorMessage(() => { test_struct.ptr().value = [1, 2]; },
|
||||
"can't convert the array [1, 2] to the type test_struct.ptr");
|
||||
assertTypeErrorMessage(() => { test_struct.ptr().value = Int8Array([1, 2]); },
|
||||
"can't convert the typed array ({0:1, 1:2}) to the type test_struct.ptr");
|
||||
|
||||
// contents setter
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t().address().contents = {}; },
|
||||
"can't convert the object ({}) to the type int32_t");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,44 @@
|
||||
// Type conversion error should report its type.
|
||||
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
// constructor
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t("foo"); },
|
||||
"can't convert the string \"foo\" to the type int32_t");
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t(null); },
|
||||
"can't convert null to the type int32_t");
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t(undefined); },
|
||||
"can't convert undefined to the type int32_t");
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t({}); },
|
||||
"can't convert the object ({}) to the type int32_t");
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t([]); },
|
||||
"can't convert the array [] to the type int32_t");
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t(new Int8Array([])); },
|
||||
"can't convert the typed array ({}) to the type int32_t");
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t(ctypes.int32_t); },
|
||||
"can't convert ctypes.int32_t to the type int32_t");
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t("0xfffffffffffffffffffffff"); },
|
||||
"can't convert the string \"0xfffffffffffffffffffffff\" to the type int32_t");
|
||||
if (typeof Symbol === "function") {
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t(Symbol.iterator); },
|
||||
"can't convert Symbol.iterator to the type int32_t");
|
||||
assertTypeErrorMessage(() => { ctypes.int32_t(Symbol("foo")); },
|
||||
"can't convert Symbol(\"foo\") to the type int32_t");
|
||||
}
|
||||
|
||||
// value setter
|
||||
let test_struct = ctypes.StructType("test_struct", [{ "x": ctypes.int32_t }]);
|
||||
let struct_val = test_struct();
|
||||
assertTypeErrorMessage(() => { ctypes.bool().value = struct_val; },
|
||||
"can't convert test_struct(0) to the type boolean");
|
||||
assertTypeErrorMessage(() => { ctypes.char16_t().value = struct_val; },
|
||||
"can't convert test_struct(0) to the type char16_t");
|
||||
assertTypeErrorMessage(() => { ctypes.int8_t().value = struct_val; },
|
||||
"can't convert test_struct(0) to the type int8_t");
|
||||
assertTypeErrorMessage(() => { ctypes.double().value = struct_val; },
|
||||
"can't convert test_struct(0) to the type double");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,36 @@
|
||||
// Type conversion error should report its type.
|
||||
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
let test_struct = ctypes.StructType("test_struct", [{ "x": ctypes.int32_t },
|
||||
{ "bar": ctypes.int32_t }]);
|
||||
|
||||
// constructor
|
||||
assertTypeErrorMessage(() => { new test_struct("foo"); },
|
||||
"can't convert the string \"foo\" to the type test_struct");
|
||||
assertTypeErrorMessage(() => { new test_struct("foo", "x"); },
|
||||
"can't convert the string \"foo\" to the 'x' field (int32_t) of test_struct");
|
||||
assertTypeErrorMessage(() => { new test_struct({ "x": "foo", "bar": 1 }); },
|
||||
"can't convert the string \"foo\" to the 'x' field (int32_t) of test_struct");
|
||||
assertTypeErrorMessage(() => { new test_struct({ 0: 1, "bar": 1 }); },
|
||||
"property name the number 0 of the object ({0:1, bar:1}) is not a string");
|
||||
|
||||
// field setter
|
||||
let struct_val = test_struct();
|
||||
assertTypeErrorMessage(() => { struct_val.x = "foo"; },
|
||||
"can't convert the string \"foo\" to the 'x' field (int32_t) of test_struct");
|
||||
assertTypeErrorMessage(() => { struct_val.bar = "foo"; },
|
||||
"can't convert the string \"foo\" to the 'bar' field (int32_t) of test_struct");
|
||||
|
||||
// value setter
|
||||
assertTypeErrorMessage(() => { struct_val.value = { "x": "foo" }; },
|
||||
"property count of the object ({x:\"foo\"}) does not match to field count of the type test_struct (expected 2, got 1)");
|
||||
assertTypeErrorMessage(() => { struct_val.value = { "x": "foo", "bar": 1 }; },
|
||||
"can't convert the string \"foo\" to the 'x' field (int32_t) of test_struct");
|
||||
assertTypeErrorMessage(() => { struct_val.value = "foo"; },
|
||||
"can't convert the string \"foo\" to the type test_struct");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -0,0 +1,20 @@
|
||||
// Accessing `value` property of non primitive type should report its type.
|
||||
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function test() {
|
||||
let test_struct = ctypes.StructType("test_struct", [{ "x": ctypes.voidptr_t }]);
|
||||
assertTypeErrorMessage(() => test_struct().value,
|
||||
".value only works on character and numeric types, not `test_struct`");
|
||||
|
||||
let test_array = ctypes.ArrayType(test_struct);
|
||||
assertTypeErrorMessage(() => test_array(10).value,
|
||||
".value only works on character and numeric types, not `test_struct.array(10)`");
|
||||
|
||||
let test_pointer = ctypes.PointerType(test_struct);
|
||||
assertTypeErrorMessage(() => test_pointer(10).value,
|
||||
".value only works on character and numeric types, not `test_struct.ptr`");
|
||||
}
|
||||
|
||||
if (typeof ctypes === "object")
|
||||
test();
|
||||
@@ -1,57 +0,0 @@
|
||||
// Test basic usage of onGarbageCollection
|
||||
|
||||
const root = newGlobal();
|
||||
const dbg = new Debugger();
|
||||
const wrappedRoot = dbg.addDebuggee(root)
|
||||
|
||||
const NUM_SLICES = root.NUM_SLICES = 10;
|
||||
|
||||
let fired = false;
|
||||
let slicesFound = 0;
|
||||
|
||||
dbg.memory.onGarbageCollection = data => {
|
||||
fired = true;
|
||||
|
||||
print("Got onGarbageCollection: " + JSON.stringify(data, null, 2));
|
||||
|
||||
assertEq(typeof data.reason, "string");
|
||||
assertEq(typeof data.nonincrementalReason == "string" || data.nonincrementalReason === null,
|
||||
true);
|
||||
|
||||
let lastStartTimestamp = 0;
|
||||
for (let i = 0; i < data.collections.length; i++) {
|
||||
let slice = data.collections[i];
|
||||
|
||||
assertEq(slice.startTimestamp >= lastStartTimestamp, true);
|
||||
assertEq(slice.startTimestamp <= slice.endTimestamp, true);
|
||||
|
||||
lastStartTimestamp = slice.startTimestamp;
|
||||
}
|
||||
|
||||
assertEq(data.collections.length >= 1, true);
|
||||
slicesFound += data.collections.length;
|
||||
}
|
||||
|
||||
root.eval(
|
||||
`
|
||||
this.allocs = [];
|
||||
|
||||
// GC slices
|
||||
for (var i = 0; i < NUM_SLICES; i++) {
|
||||
this.allocs.push({});
|
||||
gcslice();
|
||||
}
|
||||
|
||||
// Full GC
|
||||
this.allocs.push({});
|
||||
gc();
|
||||
`
|
||||
);
|
||||
|
||||
// The hook should have been fired at least once.
|
||||
assertEq(fired, true);
|
||||
|
||||
// NUM_SLICES + 1 full gc + however many were triggered naturally (due to
|
||||
// whatever zealousness setting).
|
||||
print("Found " + slicesFound + " slices");
|
||||
assertEq(slicesFound >= NUM_SLICES + 1, true);
|
||||
@@ -1,69 +0,0 @@
|
||||
// Test multiple debuggers, GCs, and zones interacting with each other.
|
||||
|
||||
gczeal(0);
|
||||
|
||||
const root1 = newGlobal();
|
||||
const dbg1 = new Debugger();
|
||||
dbg1.addDebuggee(root1)
|
||||
|
||||
const root2 = newGlobal();
|
||||
const dbg2 = new Debugger();
|
||||
dbg2.addDebuggee(root2)
|
||||
|
||||
let fired1 = false;
|
||||
let fired2 = false;
|
||||
dbg1.memory.onGarbageCollection = _ => fired1 = true;
|
||||
dbg2.memory.onGarbageCollection = _ => fired2 = true;
|
||||
|
||||
function reset() {
|
||||
fired1 = false;
|
||||
fired2 = false;
|
||||
}
|
||||
|
||||
// GC 1 only
|
||||
root1.eval(`gc(this)`);
|
||||
assertEq(fired1, true);
|
||||
assertEq(fired2, false);
|
||||
|
||||
// GC 2 only
|
||||
reset();
|
||||
root2.eval(`gc(this)`);
|
||||
assertEq(fired1, false);
|
||||
assertEq(fired2, true);
|
||||
|
||||
// Full GC
|
||||
reset();
|
||||
gc();
|
||||
assertEq(fired1, true);
|
||||
assertEq(fired2, true);
|
||||
|
||||
// Full GC with no debuggees
|
||||
reset();
|
||||
dbg1.removeAllDebuggees();
|
||||
dbg2.removeAllDebuggees();
|
||||
gc();
|
||||
assertEq(fired1, false);
|
||||
assertEq(fired2, false);
|
||||
|
||||
// One debugger with multiple debuggees in different zones.
|
||||
|
||||
dbg1.addDebuggee(root1);
|
||||
dbg1.addDebuggee(root2);
|
||||
|
||||
// Just debuggee 1
|
||||
reset();
|
||||
root1.eval(`gc(this)`);
|
||||
assertEq(fired1, true);
|
||||
assertEq(fired2, false);
|
||||
|
||||
// Just debuggee 2
|
||||
reset();
|
||||
root2.eval(`gc(this)`);
|
||||
assertEq(fired1, true);
|
||||
assertEq(fired2, false);
|
||||
|
||||
// All debuggees
|
||||
reset();
|
||||
gc();
|
||||
assertEq(fired1, true);
|
||||
assertEq(fired2, false);
|
||||
@@ -1,18 +0,0 @@
|
||||
// Test that the onGarbageCollection hook is not reentrant.
|
||||
|
||||
gczeal(0);
|
||||
|
||||
const root = newGlobal();
|
||||
const dbg = new Debugger();
|
||||
const wrappedRoot = dbg.addDebuggee(root)
|
||||
|
||||
let timesFired = 0;
|
||||
|
||||
dbg.memory.onGarbageCollection = _ => {
|
||||
timesFired++;
|
||||
root.eval(`gc()`);
|
||||
}
|
||||
|
||||
root.eval(`gc()`);
|
||||
|
||||
assertEq(timesFired, 1);
|
||||
@@ -18,4 +18,4 @@ global.eval("function f(n){var w0,x1=3,y2=4,z3=9} debugger;");
|
||||
global.f(3);
|
||||
|
||||
// Should have hit each variable declared.
|
||||
assertEq(global.log, "18 21 26 31 33 ");
|
||||
assertEq(global.log, "18 21 26 31 35 ");
|
||||
|
||||
@@ -17,4 +17,4 @@ global.log = '';
|
||||
global.eval("function f(n){var o={a:1,b:2,c:3}} debugger;");
|
||||
global.f(3);
|
||||
// Should hit each property in the object.
|
||||
assertEq(global.log, "18 21 25 29 19 ");
|
||||
assertEq(global.log, "18 21 25 29 33 ");
|
||||
|
||||
@@ -17,4 +17,4 @@ global.log = '';
|
||||
global.eval("function f(n){var a=[1,2,n]} debugger;");
|
||||
global.f(3);
|
||||
// Should hit each item in the array.
|
||||
assertEq(global.log, "18 21 23 25 19 ");
|
||||
assertEq(global.log, "18 21 23 25 27 ");
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// Test Script.lineCount.
|
||||
|
||||
var g = newGlobal();
|
||||
var dbg = Debugger(g);
|
||||
|
||||
function test(scriptText, expectedLineCount) {
|
||||
let found = false;
|
||||
|
||||
dbg.onNewScript = function(script, global) {
|
||||
assertEq(script.lineCount, expectedLineCount);
|
||||
found = true;
|
||||
};
|
||||
|
||||
g.evaluate(scriptText);
|
||||
assertEq(found, true);
|
||||
}
|
||||
|
||||
src = 'var a = (function(){\n' + // 0
|
||||
'var b = 9;\n' + // 1
|
||||
'console.log("x", b);\n'+ // 2
|
||||
'return b;\n' + // 3
|
||||
'})();\n'; // 4
|
||||
test(src, 5);
|
||||
@@ -0,0 +1,17 @@
|
||||
// |jit-test| error: TypeError
|
||||
if (!("gczeal" in this))
|
||||
quit();
|
||||
var g = newGlobal();
|
||||
gczeal(10, 2)
|
||||
var dbg = Debugger(g);
|
||||
dbg.onDebuggerStatement = function (frame1) {
|
||||
function hit(frame2)
|
||||
hit[0] = "mutated";
|
||||
var s = frame1.script;
|
||||
var offs = s.getLineOffsets(g.line0 + 2);
|
||||
for (var i = 0; i < offs.length; i++)
|
||||
s.setBreakpoint(offs[i], {hit: hit});
|
||||
return;
|
||||
};
|
||||
var lfGlobal = newGlobal();
|
||||
g.eval("var line0 = Error().lineNumber;\n debugger;\nx = 1;\n");
|
||||
@@ -0,0 +1,49 @@
|
||||
// Test aborting an incremental GC in all possible states
|
||||
|
||||
if (!("gcstate" in this && "gczeal" in this && "abortgc" in this))
|
||||
quit();
|
||||
|
||||
function testAbort(zoneCount, objectCount, sliceCount, abortState)
|
||||
{
|
||||
// Allocate objectCount objects in zoneCount zones and run a incremental
|
||||
// shrinking GC.
|
||||
|
||||
var zones = [];
|
||||
for (var i = 0; i < zoneCount; i++) {
|
||||
var zone = newGlobal();
|
||||
evaluate("var objects; " +
|
||||
"function makeObjectGraph(objectCount) { " +
|
||||
" objects = []; " +
|
||||
" for (var i = 0; i < objectCount; i++) " +
|
||||
" objects.push({i: i}); " +
|
||||
"}",
|
||||
{ global: zone });
|
||||
zone.makeObjectGraph(objectCount);
|
||||
zones.push(zone);
|
||||
}
|
||||
|
||||
var didAbort = false;
|
||||
startgc(sliceCount, "shrinking");
|
||||
while (gcstate() !== "none") {
|
||||
var state = gcstate();
|
||||
if (state == abortState) {
|
||||
abortgc();
|
||||
didAbort = true;
|
||||
break;
|
||||
}
|
||||
|
||||
gcslice(sliceCount);
|
||||
}
|
||||
|
||||
assertEq(gcstate(), "none");
|
||||
if (abortState)
|
||||
assertEq(didAbort, true);
|
||||
|
||||
return zones;
|
||||
}
|
||||
|
||||
gczeal(0);
|
||||
testAbort(10, 10000, 10000);
|
||||
testAbort(10, 10000, 10000, "mark");
|
||||
testAbort(10, 10000, 10000, "sweep");
|
||||
testAbort(10, 10000, 10000, "compact");
|
||||
@@ -79,5 +79,5 @@ assertEq(tByteSize([1, 2, 3, 4, 5, 6, 7, 8]), s(112, 128));
|
||||
// Various forms of functions.
|
||||
assertEq(tByteSize(function () {}), s(32, 64));
|
||||
assertEq(tByteSize(function () {}.bind()), s(96, 128));
|
||||
assertEq(tByteSize(() => 1), s(48, 96));
|
||||
assertEq(tByteSize(() => 1), s(48, 80));
|
||||
assertEq(tByteSize(Math.sin), s(32, 64));
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
|
||||
function f(x, y) {
|
||||
return Math.imul(0, Math.imul(y | 0, x >> 0))
|
||||
}
|
||||
for (var i = 0; i < 2; i++) {
|
||||
try {
|
||||
(f(1 ? 0 : undefined))()
|
||||
} catch (e) {}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
function f(x) {
|
||||
return ~~(x >>> 0) / (x >>> 0) | 0
|
||||
}
|
||||
f(1)
|
||||
assertEq(f(-1), 0);
|
||||
@@ -3,7 +3,7 @@ function test() {
|
||||
function f()
|
||||
k.apply(this, arguments);
|
||||
if (undefined >> undefined !== 0) {}
|
||||
for (var [ v , c ] = 0 in this.tracemonkey) { }
|
||||
for (var [ v , c ] in this.tracemonkey) { }
|
||||
}
|
||||
try { test(); } catch(exc1) {}
|
||||
try { test(); } catch(exc1) {}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user