import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1043863 - OpenedConnection.prototype.executeBeforeShutdown. r=mak (35dec49b1)
- Bug 1157946 - Early return if aResponse.sources is undefined;r=fitzgen (c730d5693)
- Bug 1157914 - Don't re-render the graphs until selection is done; r=jsantell (6af87a63b)
- Bug 1160332 - Correctly check that the mouse is active in graphs to clean up rerender jank, a rebase error from 1157914. r=vp (7d761d64a)
- Bug 1150011 - Fix GC hash table checks to work in release builds r=nbp (b7f1436a4)
- Bug 996982 - Fix Debugger script delazification logic to account for relazified clones. (r=bz) (df51ca106)
- Bug 1157963 - Don't delazify functions about to be finalized. (r=jimb) (a72665ff0)
- Bug 1155618 - Fix some places where OOM errors are not reported to th…e context r=terrence (37a0f3a0b)
- Bug 1069979 - Don't throw away timezone-strings with dots in Date() r=evilpie (9443f6175)
- Bug 1160356 - Make Date.UTC conform to ES3-6 in converting *all* arguments to number before computing the return value. r=evilpie (f5d7c9fba)
- Bug 1160356 - Reorganize the code for the Date function/constructor into three separate methods, to be more consistent with ES6's definition of it. Don't change the actual algorithm yet -- this is just code motion. r=evilpie (9f4ed070f)
- Bug 1160356 - Make new Date(arg1, arg2, ...) conform to ES3-6 in converting *all* arguments to number before computing the return value. r=evilpie (92da1cef7)
- pointer style (d43325489)
- Bug 1160535 part 1 - Give JSFunction its own AllocKind. r=terrence (952baab50)
- Bug 1160535 part 2 - Do function relazification as part of a new GC phase instead of during marking. r=terrence (3fa0357e6)
- Bug 1160535 part 3 - Make the LazyScript -> JSScript pointer weak. r=jonco,terrence (cf1276e6a)
- Bug 1160535 part 4 - Remove an assert in XDRInterpretedFunction that's now bogus. r=nbp (8220d24b0)
- Bug 1160535 part 5 - Remove the now bogus !maybeScript check in CreateLazyScriptsForCompartment. r=shu (f833671cd)
- Bug 1163091 - Handle unboxed arrays in jsarray.cpp fast paths, r=jandem. (daaa46019)
- reapply (better) to jsarray.cpp Bug 1389974 Fix False positive rooting (bf526deb2)
- Bug 1165904 - Don't call methods on null pointers to fix some -fsanitize=null errors. r=terrence (0d48886e6)
- Bug 1162622 - Check fewer traced things as it's too slow to check all edges; r=sfink (0cd9b9634)
- Bug 1162296 - Use generic value traversal when scanning unboxed memory; r=jonco (57904891a)
- Bug 1162590 - Change the name of the 2-arg traverse to traverseEdge; r=sfink (fd4d9fe3c)
- Bug 1150639 - Use a stricter off-thread check in triggerZoneGC; r=bhackett (fad3ddb51)
- Bug 1149752 - Cancel GC caused by user inactivity if the user becomes active again r=terrence r=smaug (43129e9ec)
- Bug 1154441 - imported patch budget, r=terrence (b3cbb9a23)
- pointer style (8cc66c5eb)
- pointer style (dc3509b86)
- Bug 1155455 - Relax assertion to take account of breakpoints added during incremental sweeping r=terrence (8a70639be)
- Bug 1150253 - Part 1: SpiderMonkey should call an embedder-provided callback (57af26988)
- Bug 1137536, part 3 - Move the top level DeferredFinalize functions into their own file. r=smaug (ff9931f27)
- Bug 1150253 - Part 2: Gecko should provide a callback for SpiderMonkey to enqueue the onGarbageCollection hook runnable; r=mccr8 (80006d63b)
- Bug 1150253 - Part 3: Migrate onGarbageCollection tests; r=sfink --HG-- rename : js/src/jit-test/tests/debug/Memory-onGarbageCollection-04.js => js/xpconnect/tests/unit/test_onGarbageCollection-04.js (4e55ef74e)
- Bug 1160567 - Assert that object derived types are not exposed in the API; r=jonco (f45b01740)
- Bug 1160163 - Refactor arena decommit so we don't have to pass dummy thing kind to allocateArena() r=terrence (11bf82efb)
- Bug 1157382 - Fix possible data race caused by accessing the mark bits of cells in another runtime r=terrence (ed6e851d0)
- Bug 1163059 - Add a more convenient wrapper for isAtomsZone; r=sfink (7f2c4352a)
- Bug 1163790 - Part 1: Share unboxed trace list traversal between tenuring and marking; r=bhackett (be44e89d3)
- pointer style (ab055fdfa)
- Bug 1163790 - Part 2: Share inlined Class tracing between marking and tenuring; r=bhackett (8af0179a9)
- poitner style and whitespace cleanup (7e2c17317)
- Bug 891107 - Part 1: Show information about value, type, function, and argument number in type conversion error messages in js-ctypes. r=jorendorff (2e461d5d3)
- Bug 1143281 - Check argument type in StructType.prototype.addressOfField. r=jorendorff (2d218c368)
- Bug 891107 - Part 2: Report argument length error as TypeError in js-ctypes. r=jorendorff (0e2fa7f9a)
- Bug 891107 - Part 3: Report argument type error as TypeError in js-ctypes. r=jorendorff (19d4604da)
- Bug 987514, part 1 - Move the contents of jsreflect.h into the sole file that includes it (jsreflect.cpp). No change in behavior. r=Waldo. (b5d7dd976)
- pointer style (949c6d6b9)
- Bug 1157415 - Tweak XPConnect stack size for 32bit Windows. (r=bholley) (59a75dcbf)
- Bug 1158223 - Tweak XPConnect stack size on 64bit Windows. (r=bholley) (e6ccaf2a9)
- No bug - Bump the Windows stack frame size. r=shu (3fcdcb6d1)
- Bug 1010556 - Bump ASAN kTrustedScriptBuffer constant, to account for the new frame size. r=bholley (3b9ae31f6)
- Bug 1067610 - Refactor backtracking allocator to handle grouped registers better, r=sunfish. (a4ea2aa7e)
- Bug 1167815 - Switch toMoveOperand to pass by value. r=bhackett (0156abb47)
- pointer style (0ebc66f85)
- Bug 1168807 - Move MacroAssemblerSpecific::framePushed_ fields to the generic MacroAssembler. r=jandem (28caaac48)
-  Bug 1168750 - SharedStubs: (part1) Rename BaselineRegisters.h and BaselineHelpers.h, r=jandem (ac876a39d)
- Bug 1155618 - Report allocation failure to context for baseline ICStubs r=jandem (04ef0592b)
- Bug 1157231 - Optimize calls to own property setters. r=efaust (734e9a9ff)
- Bug 1141865 - Part 1: Make two ICCall_Fallback, one for constructing invocations. (r=jandem) (707c2db57)
- pointer style (f73948d66)
- Bug 1157624: A few AsmJSValidate cleanups; r=luke (1f801ed0d)
- Bug 1157624: Remove asm.js ternary optimizations and activate the FoldTest optimization pass for asm.js; r=luke (3be4020ca)
- Bug 1157624: A few free asm.js tests; r=luke (63a07c8c8)
- Bug 1155211 - SIMD: rename lane mutators - load/store. r=bbouvier (e0ded7107)
- Bug 1147403 part 1 - Move Sprinter into its own header and add a FILE & LifoAlloc variants. r=h4writer (2d80c984b)
- pointer style (b2dffa01f)
- Bug 1159899: IonMonkey: Fix folding of ~~x, r=nbp (f77eae89d)
- Bug 1154971 - ValueNumbering: Skip finding the leader if the simplified instruction existed before the simplification. r=sunfish (59262ac7f)
- coding style and reshuffle (6b9ad2920)
- Bug 1147403 part 2 - IonMonkey: Use GenericPrinter& instead of FILE* for *::dump functions. r=h4writer (a7f0e88fb)
- pointer style (62208cb4e)
- Bug 979094 - Fix ending location of variable declaration. r=jimb (af438060c)
- Bug 748550 - Remove support for |for (... = ... in/of ...)| now that ES6 has removed it. r=jorendorff (23683a4c8)
- Bug 1155472 - Reorder the various statement items in Parser::statement to correspond to the ordering in the Statement grammar production. r=efaust (d828017c1)
- Bug 1151931 - Part 1: Avoid warning about unreachable code after return statement in some asm.js tests. r=Waldo (ab85fb859)
- Bug 1153656 - Test class only if available in semicolon-less-return.js. r=efaust (0b0e6bbc6)
- Bug 1151931 - Part 2: Warn about unreachable code after return statement. r=Waldo (a2ec0aa5f)
- Bug 1158547 - Removes the useless declaration in Parser.cpp. r=jorendorff (9ac67193b)
- pointer style (f72b5c598)
- Bug 1155472 - Add the ES6 grammar parametrization to all the Parser methods, so that the permissibility of |in|, |yield| as keyword, &c. is specified directly, not by inspecting instantaneous statefulness. Don't change the statefulness yet, tho -- stop relying on it (where appropriate) in a later patch. r=efaust (589e7d8c1)
This commit is contained in:
2020-09-12 12:54:45 +08:00
parent 7606140ee5
commit 500383702e
309 changed files with 11475 additions and 8138 deletions
+12
View File
@@ -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();
+2 -2
View File
@@ -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"
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
+4
View File
@@ -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());
}
+8 -1
View File
@@ -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) {}
};
+9 -1
View File
@@ -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();
+2
View File
@@ -22,6 +22,8 @@
#include "asmjs/AsmJSValidate.h"
#include "jit/MacroAssembler.h"
#include "jit/MacroAssembler-inl.h"
using namespace js;
using namespace js::jit;
+3 -3
View File
@@ -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;
+5 -4
View File
@@ -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
View File
@@ -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;
+1 -1
View File
@@ -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
+1
View File
@@ -17,6 +17,7 @@
#include "jsapi.h"
#include "jsfriendapi.h"
#include "jsprf.h"
#include "builtin/TypedObject.h"
#include "js/Value.h"
+26 -26
View File
@@ -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)
+1 -1
View File
@@ -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;
}
+21 -1
View File
@@ -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."),
+14 -14
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+28
View File
@@ -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
};
+4 -1
View File
@@ -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.
+26 -1
View File
@@ -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}")
+3 -2
View File
@@ -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());
+21
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+77 -58
View File
@@ -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);
+30 -5
View File
@@ -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) {}
-27
View File
@@ -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
-9
View File
@@ -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;
+4 -1
View File
@@ -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;
}
+1
View File
@@ -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;
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
-1
View File
@@ -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;
}
-1
View File
@@ -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
+12 -7
View File
@@ -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;
+9 -5
View File
@@ -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
View File
@@ -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;
}
}
}
}
+3
View File
@@ -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;
+32
View File
@@ -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);
};
}
+1
View File
@@ -0,0 +1 @@
load(libdir + "../../tests/ecma_6/Class/shell.js");
+48 -48
View File
@@ -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();
}
}
+30 -31
View File
@@ -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);
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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");
+1 -1
View File
@@ -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);
+244
View File
@@ -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.
[];
}
})();
@@ -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);
+17
View File
@@ -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));
+10
View File
@@ -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) {}
}
+5
View File
@@ -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