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

- Bug 1235923 - Part 1: Add C++ APIs for unbarriered pointer tracing; r=sfink (dc22d4c486)
- Bug 1235923 - Part 2: Use new Root tracing APIs in Gecko; r=smaug (f455edf9b2)
- Bug 1225650 - Use stable hashing for JSObject2WrappedJSMap; r=jonco (bdefc44e0e)
- Bug 1238786 - Part 1: Allow null pointers in public tracing APIs; r=sfink (0ad99d3854)
- Bug 1238786 - Part 2: We no longer need to null check before using trace APIs; r=smaug (c1caf8f003)
- Bug 1240264 - Annotate intentional switch fallthroughs in dom/media/. r=cpearce (85bf054d64)
- Bug 1230692. Fix WebAudioDecodeJob to properly suppress exceptions from its callbacks. r=ehsan (f7ae8b0502)
- Bug 1237557 - Suppress the exception if calling the callback fails when finishing a decodeAudioData operation, because there is not much we can do. r=ehsan (73775a3145)
- Bug 1238779 - Remove the unused and nonsensical JS_TraceRuntime; r=fitzgen (e2d98419f9)
- Bug 1234862 - Part 1: Rename GCMethods to BarrierMethods; r=sfink (1dab0dee58)
- Bug 1233117 - Fix handling of eval in modules r=jandem (be635033a6)
- Bug 1233109 - Alias fewer bindings at module toplevel r=shu (8d5fb08136)
- Bug 1000780 - Part 1: Bake in already-cloned intrinsic functions even if the callsite doesn't have type information. r=jandem (ee6a2134e5)
- Bug 1000780 - Part 2: Emit JSOP_FUNAPPLY when using std_Function_apply in self-hosted code. r=jandem (a71e470a12)
- Bug 1000780 - Part 3: Free up JSFunction flag. r=jwalden+bmo (73db74b60a)
- Bug 1000780 - Part 4: Remove Function#bind usage from async stack tests. r=fitzgen (707102b764)
- Bug 1216150 - Implement ECMA 402 DateTimeFormat formatToParts (8b1b2974e5)
- Bug 1234702 - Part 1: Allow opt-in calls to content invoking spread opts in self-hosted code. (r=till) (90e847bcad)
- Bug 1234702 - Part 2: Fix up class constructor scripts to allow cloning. (r=Waldo) (08fc55eccf)
- Bug 1234702 - Part 3: Self-host default derived class constructor. (r=till) (0702fe0790)
- Bug 1234702 - Part 4: Self-host default base class constructor. (r=till) (c499d25dd7)
- Bug 1235408: Lazily resolve SIMD types; r=jandem (59d116461c)
- Bug 1000780 - Part 5: Self-host Function.prototype.bind. r=jandem (ee118512ad)
- Bug 1000780 - Part 6: Fix nit in jsfun.h. r=jandem (61cb77f34c)
- Bug 1234845 part 1 - Remove fun() method from frames and remove some dead code. r=luke (6c474eb5b0)
- Bug 1234845 part 2 - Remove some dead code from InterpreterFrame. r=jonco (c4fe3cc77b)
- Bug 1234845 part 3 - Remove some fields and unions from InterpreterFrame. r=luke (7efd5a7348)
- Bug 1234845 part 4 - Eval frame refactoring, remove isFunctionFrame. r=luke (141df1a467)
- Bug 1234845 part 5 - Rename isNonEvalFunctionFrame to isFunctionFrame and use the script instead of flags. r=luke (c3fb98a60c)
- Bug 1234845 part 6 - Simplify isEvalFrame, make it use script->isForEval() instead of flags. r=luke (200d188811)
- Bug 1234845 part 7 - Simplify isGlobalFrame and isModuleFrame. r=jonco (dcf7ce2d63)
- Bug 1234845 part 8 - Remove JitProfilingFrameIterator special case for eval that's no longer needed. r=shu (57e416d498)
- Bug 1234845 part 9 - Remove callee slot from non-function interpreter frames. r=luke (dfbf5309a1)
- Bug 1234845 part 10 - Remove ExecuteType and InitialFrameFlags enums. r=luke (3c08ae26aa)
- Bug 1234845 part 11 - Remove HAS_SCOPECHAIN InterpreterFrame flag, repack flags. r=luke (74e66ac19c)
This commit is contained in:
2023-08-03 15:16:47 +08:00
parent df6f7b7065
commit c975928fff
112 changed files with 2154 additions and 1638 deletions
+1 -1
View File
@@ -258,7 +258,7 @@ protected:
void TraceWrapper(JSTracer* aTrc, const char* name)
{
if (mWrapper) {
JS_CallUnbarrieredObjectTracer(aTrc, &mWrapper, name);
js::UnsafeTraceManuallyBarrieredEdge(aTrc, &mWrapper, name);
}
}
+4 -4
View File
@@ -334,7 +334,7 @@ class ProtoAndIfaceCache
void Trace(JSTracer* aTracer) {
for (size_t i = 0; i < ArrayLength(*this); ++i) {
JS::TraceNullableEdge(aTracer, &(*this)[i], "protoAndIfaceCache[i]");
JS::TraceEdge(aTracer, &(*this)[i], "protoAndIfaceCache[i]");
}
}
@@ -393,7 +393,7 @@ class ProtoAndIfaceCache
Page* p = mPages[i];
if (p) {
for (size_t j = 0; j < ArrayLength(*p); ++j) {
JS::TraceNullableEdge(trc, &(*p)[j], "protoAndIfaceCache[i]");
JS::TraceEdge(trc, &(*p)[j], "protoAndIfaceCache[i]");
}
}
}
@@ -2118,7 +2118,7 @@ class SequenceTracer<JSObject*, false, false, false>
public:
static void TraceSequence(JSTracer* trc, JSObject** objp, JSObject** end) {
for (; objp != end; ++objp) {
JS_CallUnbarrieredObjectTracer(trc, objp, "sequence<object>");
JS::UnsafeTraceRoot(trc, objp, "sequence<object>");
}
}
};
@@ -2132,7 +2132,7 @@ class SequenceTracer<JS::Value, false, false, false>
public:
static void TraceSequence(JSTracer* trc, JS::Value* valp, JS::Value* end) {
for (; valp != end; ++valp) {
JS_CallUnbarrieredValueTracer(trc, valp, "sequence<any>");
JS::UnsafeTraceRoot(trc, valp, "sequence<any>");
}
}
};
+3 -3
View File
@@ -9620,7 +9620,7 @@ class CGUnionStruct(CGThing):
if t.isObject():
traceCases.append(
CGCase("e" + vars["name"],
CGGeneric('JS_CallUnbarrieredObjectTracer(trc, %s, "%s");\n' %
CGGeneric('JS::UnsafeTraceRoot(trc, %s, "%s");\n' %
("&mValue.m" + vars["name"] + ".Value()",
"mValue.m" + vars["name"]))))
elif t.isDictionary():
@@ -12620,12 +12620,12 @@ class CGDictionary(CGThing):
memberLoc)
if type.isObject():
trace = CGGeneric('JS_CallUnbarrieredObjectTracer(trc, %s, "%s");\n' %
trace = CGGeneric('JS::UnsafeTraceRoot(trc, %s, "%s");\n' %
("&"+memberData, memberName))
if type.nullable():
trace = CGIfWrapper(trace, memberData)
elif type.isAny():
trace = CGGeneric('JS_CallUnbarrieredValueTracer(trc, %s, "%s");\n' %
trace = CGGeneric('JS::UnsafeTraceRoot(trc, %s, "%s");\n' %
("&"+memberData, memberName))
elif (type.isSequence() or type.isDictionary() or
type.isSpiderMonkeyInterface() or type.isUnion()):
+2 -6
View File
@@ -44,12 +44,8 @@ protected:
public:
inline void TraceSelf(JSTracer* trc)
{
if (mTypedObj) {
JS_CallUnbarrieredObjectTracer(trc, &mTypedObj, "TypedArray.mTypedObj");
}
if (mWrappedObj) {
JS_CallUnbarrieredObjectTracer(trc, &mWrappedObj, "TypedArray.mWrappedObj");
}
JS::UnsafeTraceRoot(trc, &mTypedObj, "TypedArray.mTypedObj");
JS::UnsafeTraceRoot(trc, &mTypedObj, "TypedArray.mWrappedObj");
}
private:
+1 -2
View File
@@ -1855,8 +1855,7 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow,
nsPIDOMWindow *outer = aWindow->GetOuterWindow();
vc.mBrowserWindow.Construct(outer->WindowID());
}
// | Fall through
// V
MOZ_FALLTHROUGH;
case dom::MediaSourceEnum::Screen:
case dom::MediaSourceEnum::Application:
case dom::MediaSourceEnum::Window:
+1 -1
View File
@@ -252,7 +252,7 @@ already_AddRefed<SharedThreadPool> GetMediaThreadPool(MediaThreadType aType)
name = "MediaPDecoder";
break;
default:
MOZ_ASSERT(false);
MOZ_FALLTHROUGH_ASSERT("Unexpected MediaThreadType");
case MediaThreadType::PLAYBACK:
name = "MediaPlayback";
break;
+2 -2
View File
@@ -558,7 +558,7 @@ public:
aPrevious->mCurve, aPrevious->mCurveLength,
aPrevious->mDuration, aTime);
case AudioTimelineEvent::SetTarget:
MOZ_ASSERT(false, "unreached");
MOZ_FALLTHROUGH_ASSERT("AudioTimelineEvent::SetTarget");
case AudioTimelineEvent::SetValue:
case AudioTimelineEvent::Cancel:
case AudioTimelineEvent::Stream:
@@ -606,7 +606,7 @@ public:
aPrevious->mCurve, aPrevious->mCurveLength,
aPrevious->mDuration, aTime);
case AudioTimelineEvent::SetTarget:
MOZ_ASSERT(false, "unreached");
MOZ_FALLTHROUGH_ASSERT("AudioTimelineEvent::SetTarget");
case AudioTimelineEvent::SetValue:
case AudioTimelineEvent::Cancel:
case AudioTimelineEvent::Stream:
+7 -6
View File
@@ -549,15 +549,17 @@ WebAudioDecodeJob::OnSuccess(ErrorCode aErrorCode)
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aErrorCode == NoError);
// Ignore errors in calling the callback, since there is not much that we can
// do about it here.
ErrorResult rv;
if (mSuccessCallback) {
ErrorResult rv;
mSuccessCallback->Call(*mOutput, rv);
// Ignore errors in calling the callback, since there is not much that we can
// do about it here.
rv.SuppressException();
}
mPromise->MaybeResolve(mOutput);
mContext->RemoveFromDecodeQueue(this);
}
void
@@ -568,7 +570,7 @@ WebAudioDecodeJob::OnFailure(ErrorCode aErrorCode)
const char* errorMessage;
switch (aErrorCode) {
case NoError:
MOZ_ASSERT(false, "Who passed NoError to OnFailure?");
MOZ_FALLTHROUGH_ASSERT("Who passed NoError to OnFailure?");
// Fall through to get some sort of a sane error message if this actually
// happens at runtime.
case UnknownError:
@@ -599,8 +601,7 @@ WebAudioDecodeJob::OnFailure(ErrorCode aErrorCode)
// Ignore errors in calling the callback, since there is not much that we can
// do about it here.
if (mFailureCallback) {
ErrorResult rv;
mFailureCallback->Call(rv);
mFailureCallback->Call();
}
mPromise->MaybeReject(NS_ERROR_DOM_ENCODING_NOT_SUPPORTED_ERR);
+1 -1
View File
@@ -129,7 +129,7 @@ void WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
case EBML_ID:
mLastInitStartOffset = mCurrentOffset + (p - aBuffer) -
(mElement.mID.mLength + mElement.mSize.mLength);
/* FALLTHROUGH */
MOZ_FALLTHROUGH;
default:
mSkipBytes = mElement.mSize.mValue;
mState = SKIP_DATA;
+5 -5
View File
@@ -287,9 +287,9 @@ TraceJSObjWrappers(JSTracer *trc, void *data)
// any of them moved.
for (JSObjWrapperTable::Enum e(sJSObjWrappers); !e.empty(); e.popFront()) {
nsJSObjWrapperKey key = e.front().key();
JS_CallUnbarrieredObjectTracer(trc, &key.mJSObj, "sJSObjWrappers key object");
JS::UnsafeTraceRoot(trc, &key.mJSObj, "sJSObjWrappers key object");
nsJSObjWrapper *wrapper = e.front().value();
JS::TraceNullableEdge(trc, &wrapper->mJSObj, "sJSObjWrappers wrapper object");
JS::TraceEdge(trc, &wrapper->mJSObj, "sJSObjWrappers wrapper object");
if (key != e.front().key()) {
e.rekeyFront(key);
}
@@ -1102,7 +1102,7 @@ JSObjWrapperKeyMarkCallback(JSTracer* trc, JSObject* obj, void* data) {
if (!p)
return;
JS_CallUnbarrieredObjectTracer(trc, &obj, "sJSObjWrappers key object");
js::UnsafeTraceManuallyBarrieredEdge(trc, &obj, "sJSObjWrappers key object");
nsJSObjWrapperKey newKey(obj, npp);
sJSObjWrappers.rekeyIfMoved(oldKey, newKey);
}
@@ -2274,8 +2274,8 @@ NPObjectMember_Trace(JSTracer* trc, JSObject* obj)
// There's no strong reference from our private data to the
// NPObject, so make sure to mark the NPObject wrapper to keep the
// NPObject alive as long as this NPObjectMember is alive.
JS::TraceNullableEdge(trc, &memberPrivate->npobjWrapper,
"NPObject Member => npobjWrapper");
JS::TraceEdge(trc, &memberPrivate->npobjWrapper,
"NPObject Member => npobjWrapper");
}
static bool
+13 -9
View File
@@ -79,18 +79,22 @@ private:
JSObject* mCompiled;
};
friend struct js::GCMethods<nsXBLMaybeCompiled<UncompiledT>>;
friend struct js::BarrierMethods<nsXBLMaybeCompiled<UncompiledT>>;
};
/* Add support for JS::Heap<nsXBLMaybeCompiled>. */
namespace js {
template <class UncompiledT>
struct GCMethods<nsXBLMaybeCompiled<UncompiledT> >
struct GCPolicy<nsXBLMaybeCompiled<UncompiledT>>
{
typedef struct GCMethods<JSObject *> Base;
static nsXBLMaybeCompiled<UncompiledT> initial() { return nsXBLMaybeCompiled<UncompiledT>(); }
};
template <class UncompiledT>
struct BarrierMethods<nsXBLMaybeCompiled<UncompiledT>>
{
typedef struct BarrierMethods<JSObject *> Base;
static void postBarrier(nsXBLMaybeCompiled<UncompiledT>* functionp,
nsXBLMaybeCompiled<UncompiledT> prev,
@@ -109,14 +113,14 @@ struct GCMethods<nsXBLMaybeCompiled<UncompiledT> >
};
template <class UncompiledT>
class HeapBase<nsXBLMaybeCompiled<UncompiledT> >
class HeapBase<nsXBLMaybeCompiled<UncompiledT>>
{
const JS::Heap<nsXBLMaybeCompiled<UncompiledT> >& wrapper() const {
return *static_cast<const JS::Heap<nsXBLMaybeCompiled<UncompiledT> >*>(this);
const JS::Heap<nsXBLMaybeCompiled<UncompiledT>>& wrapper() const {
return *static_cast<const JS::Heap<nsXBLMaybeCompiled<UncompiledT>>*>(this);
}
JS::Heap<nsXBLMaybeCompiled<UncompiledT> >& wrapper() {
return *static_cast<JS::Heap<nsXBLMaybeCompiled<UncompiledT> >*>(this);
JS::Heap<nsXBLMaybeCompiled<UncompiledT>>& wrapper() {
return *static_cast<JS::Heap<nsXBLMaybeCompiled<UncompiledT>>*>(this);
}
const nsXBLMaybeCompiled<UncompiledT>* extract() const {
+1 -1
View File
@@ -249,7 +249,7 @@ public:
void TraceScriptObject(JSTracer* aTrc)
{
JS::TraceNullableEdge(aTrc, &mScriptObject, "active window XUL prototype script");
JS::TraceEdge(aTrc, &mScriptObject, "active window XUL prototype script");
}
void Trace(const TraceCallbacks& aCallbacks, void* aClosure)
+2 -2
View File
@@ -337,8 +337,8 @@ typedef JSString*
* (e.g., the DOM attributes for a given node reflected as obj) on demand.
*
* JS looks for a property in an object, and if not found, tries to resolve
* the given id. *resolvedp should be set to true iff the property was
* was defined on |obj|.
* the given id. *resolvedp should be set to true iff the property was defined
* on |obj|.
*/
typedef bool
(* JSResolveOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
+1 -1
View File
@@ -154,7 +154,7 @@ class Builder {
// A rooted reference to our value.
PersistentRooted<T> value;
BuiltThing(JSContext* cx, Builder& owner_, T value_ = js::GCMethods<T>::initial())
BuiltThing(JSContext* cx, Builder& owner_, T value_ = js::GCPolicy<T>::initial())
: owner(owner_), value(cx, value_)
{
owner.assertBuilt(value_);
+6 -1
View File
@@ -169,9 +169,14 @@ extern JS_PUBLIC_DATA(const JS::HandleId) JSID_EMPTYHANDLE;
namespace js {
template <>
struct GCMethods<jsid>
struct GCPolicy<jsid>
{
static jsid initial() { return JSID_VOID; }
};
template <>
struct BarrierMethods<jsid>
{
static void postBarrier(jsid* idp, jsid prev, jsid next) {}
};
+19 -15
View File
@@ -105,7 +105,11 @@
namespace js {
template <typename T>
struct GCMethods {
struct BarrierMethods {
};
template <typename T>
struct GCPolicy {
static T initial() { return T(); }
};
@@ -221,7 +225,7 @@ class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase<T>
Heap() {
static_assert(sizeof(T) == sizeof(Heap<T>),
"Heap<T> must be binary compatible with T.");
init(js::GCMethods<T>::initial());
init(js::GCPolicy<T>::initial());
}
explicit Heap(T p) { init(p); }
@@ -234,7 +238,7 @@ class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase<T>
explicit Heap(const Heap<T>& p) { init(p.ptr); }
~Heap() {
post(ptr, js::GCMethods<T>::initial());
post(ptr, js::GCPolicy<T>::initial());
}
DECLARE_POINTER_CONSTREF_OPS(T);
@@ -258,7 +262,7 @@ class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase<T>
private:
void init(T newPtr) {
ptr = newPtr;
post(js::GCMethods<T>::initial(), ptr);
post(js::GCPolicy<T>::initial(), ptr);
}
void set(T newPtr) {
@@ -268,7 +272,7 @@ class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase<T>
}
void post(const T& prev, const T& next) {
js::GCMethods<T>::postBarrier(&ptr, prev, next);
js::BarrierMethods<T>::postBarrier(&ptr, prev, next);
}
enum {
@@ -527,7 +531,7 @@ struct RootKind<T*>
};
template <typename T>
struct GCMethods<T*>
struct BarrierMethods<T*>
{
static T* initial() { return nullptr; }
static void postBarrier(T** vp, T* prev, T* next) {
@@ -538,7 +542,7 @@ struct GCMethods<T*>
};
template <>
struct GCMethods<JSObject*>
struct BarrierMethods<JSObject*>
{
static JSObject* initial() { return nullptr; }
static gc::Cell* asGCThingOrNull(JSObject* v) {
@@ -553,7 +557,7 @@ struct GCMethods<JSObject*>
};
template <>
struct GCMethods<JSFunction*>
struct BarrierMethods<JSFunction*>
{
static JSFunction* initial() { return nullptr; }
static void postBarrier(JSFunction** vp, JSFunction* prev, JSFunction* next) {
@@ -703,7 +707,7 @@ class MOZ_RAII Rooted : public js::RootedBase<T>
public:
template <typename RootingContext>
explicit Rooted(const RootingContext& cx)
: ptr(js::GCMethods<T>::initial())
: ptr(js::GCPolicy<T>::initial())
{
registerWithRootLists(js::RootListsForRootingContext(cx));
}
@@ -808,7 +812,7 @@ class MOZ_RAII FakeRooted : public RootedBase<T>
{
public:
template <typename CX>
explicit FakeRooted(CX* cx) : ptr(GCMethods<T>::initial()) {}
explicit FakeRooted(CX* cx) : ptr(GCPolicy<T>::initial()) {}
template <typename CX>
FakeRooted(CX* cx, T initial) : ptr(initial) {}
@@ -1025,11 +1029,11 @@ class PersistentRooted : public js::PersistentRootedBase<T>,
}
public:
PersistentRooted() : ptr(js::GCMethods<T>::initial()) {}
PersistentRooted() : ptr(js::GCPolicy<T>::initial()) {}
template <typename RootingContext>
explicit PersistentRooted(const RootingContext& cx)
: ptr(js::GCMethods<T>::initial())
: ptr(js::GCPolicy<T>::initial())
{
registerWithRootLists(js::RootListsForRootingContext(cx));
}
@@ -1062,7 +1066,7 @@ class PersistentRooted : public js::PersistentRootedBase<T>,
template <typename RootingContext>
void init(const RootingContext& cx) {
init(cx, js::GCMethods<T>::initial());
init(cx, js::GCPolicy<T>::initial());
}
template <typename RootingContext, typename U>
@@ -1073,7 +1077,7 @@ class PersistentRooted : public js::PersistentRootedBase<T>,
void reset() {
if (initialized()) {
set(js::GCMethods<T>::initial());
set(js::GCPolicy<T>::initial());
ListBase::remove();
}
}
@@ -1170,7 +1174,7 @@ CallTraceCallbackOnNonHeap(T* v, const TraceCallbacks& aCallbacks, const char* a
{
static_assert(sizeof(T) == sizeof(JS::Heap<T>), "T and Heap<T> must be compatible.");
MOZ_ASSERT(v);
mozilla::DebugOnly<Cell*> cell = GCMethods<T>::asGCThingOrNull(*v);
mozilla::DebugOnly<Cell*> cell = BarrierMethods<T>::asGCThingOrNull(*v);
MOZ_ASSERT(cell);
MOZ_ASSERT(!IsInsideNursery(cell));
JS::Heap<T>* asHeapT = reinterpret_cast<JS::Heap<T>*>(v);
+25 -36
View File
@@ -294,47 +294,26 @@ namespace JS {
// is dependent on the object's address. For example, if the object's address
// is used as a key in a hashtable, then the object must be removed and
// re-inserted with the correct hash.
//
// Note that while |edgep| must never be null, it is fine for |*edgep| to be
// nullptr.
template <typename T>
extern JS_PUBLIC_API(void)
TraceEdge(JSTracer* trc, JS::Heap<T>* edgep, const char* name);
// As with JS::TraceEdge, but checks if *edgep is a nullptr before proceeding.
// Note that edgep itself must always be non-null.
extern JS_PUBLIC_API(void)
TraceEdge(JSTracer* trc, JS::TenuredHeap<JSObject*>* edgep, const char* name);
// Edges that are always traced as part of root marking do not require
// incremental barriers. This function allows for marking non-barriered
// pointers, but asserts that this happens during root marking.
//
// Note that while |edgep| must never be null, it is fine for |*edgep| to be
// nullptr.
template <typename T>
extern JS_PUBLIC_API(void)
TraceNullableEdge(JSTracer* trc, JS::Heap<T>* edgep, const char* name);
UnsafeTraceRoot(JSTracer* trc, T* edgep, const char* name);
} // namespace JS
// The following JS_CallUnbarriered*Tracer functions should only be called where
// you know for sure that a heap post barrier is not required. Use with extreme
// caution!
extern JS_PUBLIC_API(void)
JS_CallUnbarrieredValueTracer(JSTracer* trc, JS::Value* valuep, const char* name);
extern JS_PUBLIC_API(void)
JS_CallUnbarrieredIdTracer(JSTracer* trc, jsid* idp, const char* name);
extern JS_PUBLIC_API(void)
JS_CallUnbarrieredObjectTracer(JSTracer* trc, JSObject** objp, const char* name);
extern JS_PUBLIC_API(void)
JS_CallUnbarrieredStringTracer(JSTracer* trc, JSString** strp, const char* name);
extern JS_PUBLIC_API(void)
JS_CallUnbarrieredScriptTracer(JSTracer* trc, JSScript** scriptp, const char* name);
/**
* Trace an object that is known to always be tenured. No post barriers are
* required in this case.
*/
extern JS_PUBLIC_API(void)
JS_CallTenuredObjectTracer(JSTracer* trc, JS::TenuredHeap<JSObject*>* objp, const char* name);
extern JS_PUBLIC_API(void)
JS_TraceRuntime(JSTracer* trc);
namespace JS {
extern JS_PUBLIC_API(void)
TraceChildren(JSTracer* trc, GCCellPtr thing);
@@ -353,6 +332,16 @@ JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc,
void* thing, JS::TraceKind kind, bool includeDetails);
namespace js {
// Trace an edge that is not a GC root and is not wrapped in a barriered
// wrapper for some reason.
//
// This method does not check if |*edgep| is non-null before tracing through
// it, so callers must check any nullable pointer before calling this method.
template <typename T>
extern JS_PUBLIC_API(void)
UnsafeTraceManuallyBarrieredEdge(JSTracer* trc, T* edgep, const char* name);
namespace gc {
template <typename T>
extern JS_PUBLIC_API(bool)
@@ -396,8 +385,8 @@ struct DefaultGCPolicy : public StructGCPolicy<T> {};
template <>
struct DefaultGCPolicy<jsid>
{
static void trace(JSTracer* trc, jsid* id, const char* name) {
JS_CallUnbarrieredIdTracer(trc, id, name);
static void trace(JSTracer* trc, jsid* idp, const char* name) {
js::UnsafeTraceManuallyBarrieredEdge(trc, idp, name);
}
};
+4 -3
View File
@@ -1699,14 +1699,15 @@ JS_PUBLIC_API(void) HeapValuePostBarrier(Value* valuep, const Value& prev, const
namespace js {
template <> struct GCMethods<const JS::Value>
template <>
struct GCPolicy<JS::Value>
{
static JS::Value initial() { return JS::UndefinedValue(); }
};
template <> struct GCMethods<JS::Value>
template <>
struct BarrierMethods<JS::Value>
{
static JS::Value initial() { return JS::UndefinedValue(); }
static gc::Cell* asGCThingOrNull(const JS::Value& v) {
return v.isMarkable() ? v.toGCThing() : nullptr;
}
+8 -8
View File
@@ -3227,15 +3227,15 @@ CheckNewArrayView(ModuleValidator& m, PropertyName* varName, ParseNode* newExpr)
static bool
IsSimdTypeName(ModuleValidator& m, PropertyName* name, AsmJSSimdType* type)
{
if (name == m.cx()->names().int32x4) {
if (name == m.cx()->names().Int32x4) {
*type = AsmJSSimdType_int32x4;
return true;
}
if (name == m.cx()->names().float32x4) {
if (name == m.cx()->names().Float32x4) {
*type = AsmJSSimdType_float32x4;
return true;
}
if (name == m.cx()->names().bool32x4) {
if (name == m.cx()->names().Bool32x4) {
*type = AsmJSSimdType_bool32x4;
return true;
}
@@ -6939,7 +6939,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line, unsigned* c
// This flows into FunctionBox, so must be tenured.
RootedFunction fun(m.cx(),
NewScriptedFunction(m.cx(), 0, JSFunction::INTERPRETED,
name, gc::AllocKind::FUNCTION,
name, /* proto = */ nullptr, gc::AllocKind::FUNCTION,
TenuredObject));
if (!fun)
return false;
@@ -7547,9 +7547,9 @@ static PropertyName*
SimdTypeToName(JSContext* cx, AsmJSSimdType type)
{
switch (type) {
case AsmJSSimdType_int32x4: return cx->names().int32x4;
case AsmJSSimdType_float32x4: return cx->names().float32x4;
case AsmJSSimdType_bool32x4: return cx->names().bool32x4;
case AsmJSSimdType_int32x4: return cx->names().Int32x4;
case AsmJSSimdType_float32x4: return cx->names().Float32x4;
case AsmJSSimdType_bool32x4: return cx->names().Bool32x4;
}
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected SIMD type");
}
@@ -7874,7 +7874,7 @@ HandleDynamicLinkFailure(JSContext* cx, const CallArgs& args, AsmJSModule& modul
return false;
RootedFunction fun(cx, NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL,
name, gc::AllocKind::FUNCTION,
name, /* proto = */ nullptr, gc::AllocKind::FUNCTION,
TenuredObject));
if (!fun)
return false;
+17
View File
@@ -0,0 +1,17 @@
// Give a builtin constructor that we can use as the default. When we give
// it to our newly made class, we will be sure to set it up with the correct name
// and .prototype, so that everything works properly.
var DefaultDerivedClassConstructor =
class extends null {
constructor(...args) {
super(...allowContentSpread(args));
}
};
MakeDefaultConstructor(DefaultDerivedClassConstructor);
var DefaultBaseClassConstructor =
class {
constructor() { }
};
MakeDefaultConstructor(DefaultBaseClassConstructor);
+3 -3
View File
@@ -101,7 +101,7 @@ function Date_toLocaleString() {
}
// Step 7.
return intl_FormatDateTime(dateTimeFormat, x);
return intl_FormatDateTime(dateTimeFormat, x, false);
}
@@ -134,7 +134,7 @@ function Date_toLocaleDateString() {
}
// Step 7.
return intl_FormatDateTime(dateTimeFormat, x);
return intl_FormatDateTime(dateTimeFormat, x, false);
}
@@ -167,5 +167,5 @@ function Date_toLocaleTimeString() {
}
// Step 7.
return intl_FormatDateTime(dateTimeFormat, x);
return intl_FormatDateTime(dateTimeFormat, x, false);
}
+6 -8
View File
@@ -212,8 +212,7 @@ TryEvalJSON(JSContext* cx, JSLinearString* str, MutableHandleValue rval)
: ParseEvalStringAsJSON(cx, linearChars.twoByteRange(), rval);
}
// Define subset of ExecuteType so that casting performs the injection.
enum EvalType { DIRECT_EVAL = EXECUTE_DIRECT_EVAL, INDIRECT_EVAL = EXECUTE_INDIRECT_EVAL };
enum EvalType { DIRECT_EVAL, INDIRECT_EVAL };
// Common code implementing direct and indirect eval.
//
@@ -268,7 +267,7 @@ EvalKernel(JSContext* cx, const CallArgs& args, EvalType evalType, AbstractFrame
EvalScriptGuard esg(cx);
if (evalType == DIRECT_EVAL && caller.isNonEvalFunctionFrame())
if (evalType == DIRECT_EVAL && caller.isFunctionFrame())
esg.lookupInEvalCache(linearStr, callerScript, pc);
if (!esg.foundScript()) {
@@ -328,7 +327,7 @@ EvalKernel(JSContext* cx, const CallArgs& args, EvalType evalType, AbstractFrame
// Look up the newTarget from the frame iterator.
Value newTargetVal = NullValue();
return ExecuteKernel(cx, esg.script(), *scopeobj, newTargetVal, ExecuteType(evalType),
return ExecuteKernel(cx, esg.script(), *scopeobj, newTargetVal,
NullFramePtr() /* evalInFrame */, args.rval().address());
}
@@ -409,7 +408,7 @@ js::DirectEvalStringFromIon(JSContext* cx,
}
return ExecuteKernel(cx, esg.script(), *scopeobj, newTargetValue,
ExecuteType(DIRECT_EVAL), NullFramePtr() /* evalInFrame */, vp.address());
NullFramePtr() /* evalInFrame */, vp.address());
}
bool
@@ -433,8 +432,7 @@ js::DirectEval(JSContext* cx, const CallArgs& args)
JSOp(*iter.pc()) == JSOP_STRICTEVAL ||
JSOp(*iter.pc()) == JSOP_SPREADEVAL ||
JSOp(*iter.pc()) == JSOP_STRICTSPREADEVAL);
MOZ_ASSERT_IF(caller.isFunctionFrame(),
caller.compartment() == caller.callee()->compartment());
MOZ_ASSERT(caller.compartment() == caller.script()->compartment());
RootedObject scopeChain(cx, caller.scopeChain());
return EvalKernel(cx, args, DIRECT_EVAL, caller, scopeChain, iter.pc());
@@ -482,7 +480,7 @@ js::ExecuteInGlobalAndReturnScope(JSContext* cx, HandleObject global, HandleScri
return false;
RootedValue rval(cx);
if (!ExecuteKernel(cx, script, *scope, UndefinedValue(), EXECUTE_GLOBAL,
if (!ExecuteKernel(cx, script, *scope, UndefinedValue(),
NullFramePtr() /* evalInFrame */, rval.address()))
{
return false;
+299
View File
@@ -0,0 +1,299 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// ES6 spec draft 29, 19.2.3.2
function FunctionBind(thisArg, ...boundArgs) {
// Step 1.
var target = this;
// Step 2.
if (!IsCallable(target))
ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, 'Function', 'bind', target);
// Step 3 (implicit).
// Steps 4-5.
var F;
var argCount = boundArgs.length;
switch (argCount) {
case 0:
F = bind_bindFunction0(target, thisArg, boundArgs);
break;
case 1:
F = bind_bindFunction1(target, thisArg, boundArgs);
break;
case 2:
F = bind_bindFunction2(target, thisArg, boundArgs);
break;
default:
F = bind_bindFunctionN(target, thisArg, boundArgs);
}
// Steps 6-7.
var targetHasLength = callFunction(std_Object_hasOwnProperty, target, "length");
// Step 8.
var L;
if (targetHasLength) {
// Steps 8.a-b.
var targetLen = target.length;
// Step 8.c.
if (typeof targetLen !== 'number') {
L = 0;
} else {
// Steps d.i-ii.
L = std_Math_max(0, ToInteger(targetLen) - argCount);
}
} else {
// Step 9.
L = 0;
}
// Steps 12-13.
var targetName = target.name;
// Step 14.
if (typeof targetName !== "string")
targetName = "";
// Steps 10-11, 15-16.
_FinishBoundFunctionInit(F, target, L, targetName);
// Ensure that the apply intrinsic has been cloned so it can be baked into
// JIT code.
var funApply = std_Function_apply;
// Step 17.
return F;
}
/**
* bind_bindFunction{0,1,2} are special cases of the generic bind_bindFunctionN
* below. They avoid the need to merge the lists of bound arguments and call
* arguments to the bound function into a new list which is then used in a
* destructuring call of the bound function.
*
* All three of these functions again have special-cases for call argument
* counts between 0 and 5. For calls with 6+ arguments, all - bound and call -
* arguments are copied into an array before invoking the generic call and
* construct helper functions. This avoids having to use rest parameters and
* destructuring in the fast path.
*
* All bind_bindFunction{X} functions have the same signature to enable simple
* reading out of closed-over state by debugging functions.
*/
function bind_bindFunction0(fun, thisArg, boundArgs) {
return function bound() {
var a = arguments;
var constructing = _IsConstructing();
if (constructing) {
switch (a.length) {
case 0:
return new fun();
case 1:
return new fun(a[0]);
case 2:
return new fun(a[0], a[1]);
case 3:
return new fun(a[0], a[1], a[2]);
case 4:
return new fun(a[0], a[1], a[2], a[3]);
case 5:
return new fun(a[0], a[1], a[2], a[3], a[4]);
}
} else {
switch (a.length) {
case 0:
return callContentFunction(fun, thisArg);
case 1:
return callContentFunction(fun, thisArg, a[0]);
case 2:
return callContentFunction(fun, thisArg, a[0], a[1]);
case 3:
return callContentFunction(fun, thisArg, a[0], a[1], a[2]);
case 4:
return callContentFunction(fun, thisArg, a[0], a[1], a[2], a[3]);
case 5:
return callContentFunction(fun, thisArg, a[0], a[1], a[2], a[3], a[4]);
}
}
var callArgs = FUN_APPLY(bind_mapArguments, null, arguments);
return bind_invokeFunctionN(fun, thisArg, constructing, boundArgs, callArgs);
};
}
function bind_bindFunction1(fun, thisArg, boundArgs) {
var bound1 = boundArgs[0];
return function bound() {
var a = arguments;
var constructing = _IsConstructing();
if (constructing) {
switch (a.length) {
case 0:
return new fun(bound1);
case 1:
return new fun(bound1, a[0]);
case 2:
return new fun(bound1, a[0], a[1]);
case 3:
return new fun(bound1, a[0], a[1], a[2]);
case 4:
return new fun(bound1, a[0], a[1], a[2], a[3]);
case 5:
return new fun(bound1, a[0], a[1], a[2], a[3], a[4]);
}
} else {
switch (a.length) {
case 0:
return callContentFunction(fun, thisArg, bound1);
case 1:
return callContentFunction(fun, thisArg, bound1, a[0]);
case 2:
return callContentFunction(fun, thisArg, bound1, a[0], a[1]);
case 3:
return callContentFunction(fun, thisArg, bound1, a[0], a[1], a[2]);
case 4:
return callContentFunction(fun, thisArg, bound1, a[0], a[1], a[2], a[3]);
case 5:
return callContentFunction(fun, thisArg, bound1, a[0], a[1], a[2], a[3], a[4]);
}
}
var callArgs = FUN_APPLY(bind_mapArguments, null, arguments);
return bind_invokeFunctionN(fun, thisArg, constructing, boundArgs, callArgs);
};
}
function bind_bindFunction2(fun, thisArg, boundArgs) {
var bound1 = boundArgs[0];
var bound2 = boundArgs[1];
return function bound() {
var a = arguments;
var constructing = _IsConstructing();
if (constructing) {
switch (a.length) {
case 0:
return new fun(bound1, bound2);
case 1:
return new fun(bound1, bound2, a[0]);
case 2:
return new fun(bound1, bound2, a[0], a[1]);
case 3:
return new fun(bound1, bound2, a[0], a[1], a[2]);
case 4:
return new fun(bound1, bound2, a[0], a[1], a[2], a[3]);
case 5:
return new fun(bound1, bound2, a[0], a[1], a[2], a[3], a[4]);
}
} else {
switch (a.length) {
case 0:
return callContentFunction(fun, thisArg, bound1, bound2);
case 1:
return callContentFunction(fun, thisArg, bound1, bound2, a[0]);
case 2:
return callContentFunction(fun, thisArg, bound1, bound2, a[0], a[1]);
case 3:
return callContentFunction(fun, thisArg, bound1, bound2, a[0], a[1], a[2]);
case 4:
return callContentFunction(fun, thisArg, bound1, bound2, a[0], a[1], a[2], a[3]);
case 5:
return callContentFunction(fun, thisArg, bound1, bound2, a[0], a[1], a[2], a[3], a[4]);
}
}
var callArgs = FUN_APPLY(bind_mapArguments, null, arguments);
return bind_invokeFunctionN(fun, thisArg, constructing, boundArgs, callArgs);
};
}
function bind_bindFunctionN(fun, thisArg, boundArgs) {
assert(boundArgs.length > 2, "Fast paths should be used for few-bound-args cases.");
return function bound() {
if (arguments.length === 0) {
if (_IsConstructing())
return bind_constructFunctionN(fun, boundArgs);
else
return bind_applyFunctionN(fun, thisArg, boundArgs);
}
var callArgs = FUN_APPLY(bind_mapArguments, null, arguments);
return bind_invokeFunctionN(fun, thisArg, _IsConstructing(), boundArgs, callArgs);
};
}
function bind_mapArguments() {
var len = arguments.length;
var args = std_Array(len);
for (var i = 0; i < len; i++)
_DefineDataProperty(args, i, arguments[i]);
return args;
}
function bind_invokeFunctionN(fun, thisArg, constructing, boundArgs, callArgs) {
var boundArgsCount = boundArgs.length;
var callArgsCount = callArgs.length;
var args = std_Array(boundArgsCount + callArgsCount);
for (var i = 0; i < boundArgsCount; i++)
_DefineDataProperty(args, i, boundArgs[i]);
for (var i = 0; i < callArgsCount; i++)
_DefineDataProperty(args, i + boundArgsCount, callArgs[i]);
if (constructing)
return bind_constructFunctionN(fun, args);
return bind_applyFunctionN(fun, thisArg, args);
}
function bind_applyFunctionN(fun, thisArg, a) {
switch (a.length) {
case 0:
return callContentFunction(fun, thisArg);
case 1:
return callContentFunction(fun, thisArg, a[0]);
case 2:
return callContentFunction(fun, thisArg, a[0], a[1]);
case 3:
return callContentFunction(fun, thisArg, a[0], a[1], a[2]);
case 4:
return callContentFunction(fun, thisArg, a[0], a[1], a[2], a[3]);
case 5:
return callContentFunction(fun, thisArg, a[0], a[1], a[2], a[3], a[4]);
case 6:
return callContentFunction(fun, thisArg, a[0], a[1], a[2], a[3], a[4], a[5]);
case 7:
return callContentFunction(fun, thisArg, a[0], a[1], a[2], a[3], a[4], a[5], a[6]);
case 8:
return callContentFunction(fun, thisArg, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
case 9:
return callContentFunction(fun, thisArg, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
default:
return FUN_APPLY(fun, thisArg, a);
}
}
function bind_constructFunctionN(fun, a) {
switch (a.length) {
case 1:
return new fun(a[0]);
case 2:
return new fun(a[0], a[1]);
case 3:
return new fun(a[0], a[1], a[2]);
case 4:
return new fun(a[0], a[1], a[2], a[3]);
case 5:
return new fun(a[0], a[1], a[2], a[3], a[4]);
case 6:
return new fun(a[0], a[1], a[2], a[3], a[4], a[5]);
case 7:
return new fun(a[0], a[1], a[2], a[3], a[4], a[5], a[6]);
case 8:
return new fun(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
case 9:
return new fun(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
case 10:
return new fun(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]);
case 11:
return new fun(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10]);
case 12:
return new fun(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11]);
default:
assert(a.length !== 0,
"bound function construction without args should be handled by caller");
return _ConstructFunction(fun, a);
}
}
+297 -7
View File
@@ -12,6 +12,7 @@
#include "builtin/Intl.h"
#include "mozilla/Range.h"
#include "mozilla/ScopeExit.h"
#include <string.h>
@@ -45,6 +46,7 @@ using namespace js;
using mozilla::IsFinite;
using mozilla::IsNegativeZero;
using mozilla::MakeScopeExit;
#if ENABLE_INTL_API
using icu::Locale;
@@ -176,6 +178,7 @@ ucol_getKeywordValuesForLocale(const char* key, const char* locale, UBool common
struct UParseError;
struct UFieldPosition;
struct UFieldPositionIterator;
typedef void* UNumberFormat;
enum UNumberFormatStyle {
@@ -339,6 +342,46 @@ udatpg_close(UDateTimePatternGenerator* dtpg)
typedef void* UCalendar;
typedef void* UDateFormat;
enum UDateFormatField {
UDAT_ERA_FIELD = 0,
UDAT_YEAR_FIELD = 1,
UDAT_MONTH_FIELD = 2,
UDAT_DATE_FIELD = 3,
UDAT_HOUR_OF_DAY1_FIELD = 4,
UDAT_HOUR_OF_DAY0_FIELD = 5,
UDAT_MINUTE_FIELD = 6,
UDAT_SECOND_FIELD = 7,
UDAT_FRACTIONAL_SECOND_FIELD = 8,
UDAT_DAY_OF_WEEK_FIELD = 9,
UDAT_DAY_OF_YEAR_FIELD = 10,
UDAT_DAY_OF_WEEK_IN_MONTH_FIELD = 11,
UDAT_WEEK_OF_YEAR_FIELD = 12,
UDAT_WEEK_OF_MONTH_FIELD = 13,
UDAT_AM_PM_FIELD = 14,
UDAT_HOUR1_FIELD = 15,
UDAT_HOUR0_FIELD = 16,
UDAT_TIMEZONE_FIELD = 17,
UDAT_YEAR_WOY_FIELD = 18,
UDAT_DOW_LOCAL_FIELD = 19,
UDAT_EXTENDED_YEAR_FIELD = 20,
UDAT_JULIAN_DAY_FIELD = 21,
UDAT_MILLISECONDS_IN_DAY_FIELD = 22,
UDAT_TIMEZONE_RFC_FIELD = 23,
UDAT_TIMEZONE_GENERIC_FIELD = 24,
UDAT_STANDALONE_DAY_FIELD = 25,
UDAT_STANDALONE_MONTH_FIELD = 26,
UDAT_QUARTER_FIELD = 27,
UDAT_STANDALONE_QUARTER_FIELD = 28,
UDAT_TIMEZONE_SPECIAL_FIELD = 29,
UDAT_YEAR_NAME_FIELD = 30,
UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD = 31,
UDAT_TIMEZONE_ISO_FIELD = 32,
UDAT_TIMEZONE_ISO_LOCAL_FIELD = 33,
UDAT_RELATED_YEAR_FIELD = 34,
UDAT_TIME_SEPARATOR_FIELD = 35,
UDAT_FIELD_COUNT = 36
};
enum UDateFormatStyle {
UDAT_PATTERN = -2,
UDAT_IGNORE = UDAT_PATTERN
@@ -383,6 +426,32 @@ udat_format(const UDateFormat* format, UDate dateToFormat, UChar* result,
MOZ_CRASH("udat_format: Intl API disabled");
}
static int32_t
udat_formatForFields(const UDateFormat* format, UDate dateToFormat,
UChar* result, int32_t resultLength, UFieldPositionIterator* fpositer,
UErrorCode* status)
{
MOZ_CRASH("udat_formatForFields: Intl API disabled");
}
static UFieldPositionIterator*
ufieldpositer_open(UErrorCode* status)
{
MOZ_CRASH("ufieldpositer_open: Intl API disabled");
}
static void
ufieldpositer_close(UFieldPositionIterator* fpositer)
{
MOZ_CRASH("ufieldpositer_close: Intl API disabled");
}
static int32_t
ufieldpositer_next(UFieldPositionIterator* fpositer, int32_t* beginIndex, int32_t* endIndex)
{
MOZ_CRASH("ufieldpositer_next: Intl API disabled");
}
static void
udat_close(UDateFormat* format)
{
@@ -1669,11 +1738,9 @@ InitDateTimeFormatClass(JSContext* cx, HandleObject Intl, Handle<GlobalObject*>
if (!JS_DefineFunctions(cx, proto, dateTimeFormat_methods))
return nullptr;
/*
* Install the getter for DateTimeFormat.prototype.format, which returns a
* bound formatting function for the specified DateTimeFormat object
* (suitable for passing to methods like Array.prototype.map).
*/
// Install a getter for DateTimeFormat.prototype.format that returns a
// formatting function bound to a specified DateTimeFormat object (suitable
// for passing to methods like Array.prototype.map).
RootedValue getter(cx);
if (!GlobalObject::getIntrinsicValue(cx, cx->global(), cx->names().DateTimeFormatFormatGet,
&getter))
@@ -1687,6 +1754,22 @@ InitDateTimeFormatClass(JSContext* cx, HandleObject Intl, Handle<GlobalObject*>
return nullptr;
}
// If the still-experimental DateTimeFormat.prototype.formatToParts method
// is enabled, also add its getter.
if (cx->compartment()->creationOptions().experimentalDateTimeFormatFormatToPartsEnabled()) {
if (!GlobalObject::getIntrinsicValue(cx, cx->global(),
cx->names().DateTimeFormatFormatToPartsGet, &getter))
{
return nullptr;
}
if (!DefineProperty(cx, proto, cx->names().formatToParts, UndefinedHandleValue,
JS_DATA_TO_FUNC_PTR(JSGetterOp, &getter.toObject()),
nullptr, JSPROP_GETTER | JSPROP_SHARED))
{
return nullptr;
}
}
RootedValue options(cx);
if (!CreateDefaultOptions(cx, &options))
return nullptr;
@@ -1986,6 +2069,210 @@ intl_FormatDateTime(JSContext* cx, UDateFormat* df, double x, MutableHandleValue
return false;
result.setString(str);
return true;
}
using FieldType = ImmutablePropertyNamePtr JSAtomState::*;
static FieldType
GetFieldTypeForFormatField(UDateFormatField fieldName)
{
// See intl/icu/source/i18n/unicode/udat.h for a detailed field list. This
// switch is deliberately exhaustive: cases might have to be added/removed
// if this code is compiled with a different ICU with more
// UDateFormatField enum initializers. Please guard such cases with
// appropriate ICU version-testing #ifdefs, should cross-version divergence
// occur.
switch (fieldName) {
case UDAT_ERA_FIELD:
return &JSAtomState::era;
case UDAT_YEAR_FIELD:
case UDAT_YEAR_WOY_FIELD:
case UDAT_EXTENDED_YEAR_FIELD:
case UDAT_YEAR_NAME_FIELD:
return &JSAtomState::year;
case UDAT_MONTH_FIELD:
case UDAT_STANDALONE_MONTH_FIELD:
return &JSAtomState::month;
case UDAT_DATE_FIELD:
case UDAT_JULIAN_DAY_FIELD:
return &JSAtomState::day;
case UDAT_HOUR_OF_DAY1_FIELD:
case UDAT_HOUR_OF_DAY0_FIELD:
case UDAT_HOUR1_FIELD:
case UDAT_HOUR0_FIELD:
return &JSAtomState::hour;
case UDAT_MINUTE_FIELD:
return &JSAtomState::minute;
case UDAT_SECOND_FIELD:
return &JSAtomState::second;
case UDAT_DAY_OF_WEEK_FIELD:
case UDAT_STANDALONE_DAY_FIELD:
case UDAT_DOW_LOCAL_FIELD:
case UDAT_DAY_OF_WEEK_IN_MONTH_FIELD:
return &JSAtomState::weekday;
case UDAT_AM_PM_FIELD:
return &JSAtomState::dayperiod;
case UDAT_TIMEZONE_FIELD:
return &JSAtomState::timeZoneName;
case UDAT_FRACTIONAL_SECOND_FIELD:
case UDAT_DAY_OF_YEAR_FIELD:
case UDAT_WEEK_OF_YEAR_FIELD:
case UDAT_WEEK_OF_MONTH_FIELD:
case UDAT_MILLISECONDS_IN_DAY_FIELD:
case UDAT_TIMEZONE_RFC_FIELD:
case UDAT_TIMEZONE_GENERIC_FIELD:
case UDAT_QUARTER_FIELD:
case UDAT_STANDALONE_QUARTER_FIELD:
case UDAT_TIMEZONE_SPECIAL_FIELD:
case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD:
case UDAT_TIMEZONE_ISO_FIELD:
case UDAT_TIMEZONE_ISO_LOCAL_FIELD:
#ifndef U_HIDE_INTERNAL_API
case UDAT_RELATED_YEAR_FIELD:
#endif
#ifndef U_HIDE_DRAFT_API
case UDAT_TIME_SEPARATOR_FIELD:
#endif
// These fields are all unsupported.
return nullptr;
case UDAT_FIELD_COUNT:
MOZ_ASSERT_UNREACHABLE("format field sentinel value returned by "
"iterator!");
}
MOZ_ASSERT_UNREACHABLE("unenumerated, undocumented format field returned "
"by iterator");
return nullptr;
}
static bool
intl_FormatToPartsDateTime(JSContext* cx, UDateFormat* df, double x, MutableHandleValue result)
{
if (!IsFinite(x)) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DATE_NOT_FINITE);
return false;
}
Vector<char16_t, INITIAL_CHAR_BUFFER_SIZE> chars(cx);
if (!chars.resize(INITIAL_CHAR_BUFFER_SIZE))
return false;
UErrorCode status = U_ZERO_ERROR;
UFieldPositionIterator* fpositer = ufieldpositer_open(&status);
if (U_FAILURE(status)) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
return false;
}
auto closeFieldPosIter = MakeScopeExit([&]() { ufieldpositer_close(fpositer); });
int resultSize =
udat_formatForFields(df, x, Char16ToUChar(chars.begin()), INITIAL_CHAR_BUFFER_SIZE,
fpositer, &status);
if (status == U_BUFFER_OVERFLOW_ERROR) {
if (!chars.resize(resultSize))
return false;
status = U_ZERO_ERROR;
udat_formatForFields(df, x, Char16ToUChar(chars.begin()), resultSize, fpositer, &status);
}
if (U_FAILURE(status)) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
return false;
}
RootedArrayObject partsArray(cx, NewDenseEmptyArray(cx));
if (!partsArray)
return false;
if (resultSize == 0) {
// An empty string contains no parts, so avoid extra work below.
result.setObject(*partsArray);
return true;
}
RootedString overallResult(cx, NewStringCopyN<CanGC>(cx, chars.begin(), resultSize));
if (!overallResult)
return false;
size_t lastEndIndex = 0;
uint32_t partIndex = 0;
RootedObject singlePart(cx);
RootedValue partType(cx);
RootedString partSubstr(cx);
RootedValue val(cx);
auto AppendPart = [&](FieldType type, size_t beginIndex, size_t endIndex) {
singlePart = NewBuiltinClassInstance<PlainObject>(cx);
if (!singlePart)
return false;
partType = StringValue(cx->names().*type);
if (!DefineProperty(cx, singlePart, cx->names().type, partType))
return false;
partSubstr = SubstringKernel(cx, overallResult, beginIndex, endIndex - beginIndex);
if (!partSubstr)
return false;
val = StringValue(partSubstr);
if (!DefineProperty(cx, singlePart, cx->names().value, val))
return false;
val = ObjectValue(*singlePart);
if (!DefineElement(cx, partsArray, partIndex, val))
return false;
lastEndIndex = endIndex;
partIndex++;
return true;
};
int32_t fieldInt, beginIndexInt, endIndexInt;
while ((fieldInt = ufieldpositer_next(fpositer, &beginIndexInt, &endIndexInt)) >= 0) {
MOZ_ASSERT(beginIndexInt >= 0);
MOZ_ASSERT(endIndexInt >= 0);
MOZ_ASSERT(beginIndexInt <= endIndexInt,
"field iterator returning invalid range");
size_t beginIndex(beginIndexInt);
size_t endIndex(endIndexInt);
// Technically this isn't guaranteed. But it appears true in pratice,
// and http://bugs.icu-project.org/trac/ticket/12024 is expected to
// correct the documentation lapse.
MOZ_ASSERT(lastEndIndex <= beginIndex,
"field iteration didn't return fields in order start to "
"finish as expected");
if (FieldType type = GetFieldTypeForFormatField(static_cast<UDateFormatField>(fieldInt))) {
if (lastEndIndex < beginIndex) {
if (!AppendPart(&JSAtomState::separator, lastEndIndex, beginIndex))
return false;
}
if (!AppendPart(type, beginIndex, endIndex))
return false;
}
}
// Append any final separator.
if (lastEndIndex < overallResult->length()) {
if (!AppendPart(&JSAtomState::separator, lastEndIndex, overallResult->length()))
return false;
}
result.setObject(*partsArray);
return true;
}
@@ -1993,9 +2280,10 @@ bool
js::intl_FormatDateTime(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2);
MOZ_ASSERT(args.length() == 3);
MOZ_ASSERT(args[0].isObject());
MOZ_ASSERT(args[1].isNumber());
MOZ_ASSERT(args[2].isBoolean());
RootedObject dateTimeFormat(cx, &args[0].toObject());
@@ -2024,7 +2312,9 @@ js::intl_FormatDateTime(JSContext* cx, unsigned argc, Value* vp)
// Use the UDateFormat to actually format the time stamp.
RootedValue result(cx);
bool success = intl_FormatDateTime(cx, df, args[1].toNumber(), &result);
bool success = args[2].toBoolean()
? intl_FormatToPartsDateTime(cx, df, args[1].toNumber(), &result)
: intl_FormatDateTime(cx, df, args[1].toNumber(), &result);
if (!isDateTimeFormatInstance)
udat_close(df);
+33 -5
View File
@@ -1596,7 +1596,7 @@ function Intl_Collator_compare_get() {
var F = collatorCompareToBind;
// Step 1.b-d.
var bc = callFunction(std_Function_bind, F, this);
var bc = callFunction(FunctionBind, F, this);
internals.boundCompare = bc;
}
@@ -2037,7 +2037,7 @@ function Intl_NumberFormat_format_get() {
var F = numberFormatFormatToBind;
// Step 1.b-d.
var bf = callFunction(std_Function_bind, F, this);
var bf = callFunction(FunctionBind, F, this);
internals.boundFormat = bf;
}
// Step 2.
@@ -2713,10 +2713,9 @@ function dateTimeFormatFormatToBind() {
var x = (date === undefined) ? std_Date_now() : ToNumber(date);
// Step 1.a.iii.
return intl_FormatDateTime(this, x);
return intl_FormatDateTime(this, x, false);
}
/**
* Returns a function bound to this DateTimeFormat that returns a String value
* representing the result of calling ToNumber(date) according to the
@@ -2734,7 +2733,7 @@ function Intl_DateTimeFormat_format_get() {
var F = dateTimeFormatFormatToBind;
// Step 1.b-d.
var bf = callFunction(std_Function_bind, F, this);
var bf = callFunction(FunctionBind, F, this);
internals.boundFormat = bf;
}
@@ -2743,6 +2742,35 @@ function Intl_DateTimeFormat_format_get() {
}
function dateTimeFormatFormatToPartsToBind() {
// Steps 1.a.i-ii
var date = arguments.length > 0 ? arguments[0] : undefined;
var x = (date === undefined) ? std_Date_now() : ToNumber(date);
// Step 1.a.iii.
return intl_FormatDateTime(this, x, true);
}
function Intl_DateTimeFormat_formatToParts_get() {
// Check "this DateTimeFormat object" per introduction of section 12.3.
var internals = getDateTimeFormatInternals(this, "formatToParts");
// Step 1.
if (internals.boundFormatToParts === undefined) {
// Step 1.a.
var F = dateTimeFormatFormatToPartsToBind;
// Step 1.b-d.
var bf = callFunction(FunctionBind, F, this);
internals.boundFormatToParts = bf;
}
// Step 2.
return internals.boundFormatToParts;
}
/**
* Returns the resolved options for a DateTimeFormat object.
*
+9 -16
View File
@@ -906,18 +906,18 @@ ModuleBuilder::ModuleBuilder(JSContext* cx, HandleModuleObject module)
{}
bool
ModuleBuilder::initModule()
ModuleBuilder::buildTables()
{
for (const auto& e : exportEntries_) {
RootedExportEntryObject exp(cx_, e);
if (!exp->moduleRequest()) {
RootedImportEntryObject importEntry(cx_, importEntryFor(exp->localName()));
if (!importEntry) {
if (!appendLocalExportEntry(exp))
if (!localExportEntries_.append(exp))
return false;
} else {
if (importEntry->importName() == cx_->names().star) {
if (!appendLocalExportEntry(exp))
if (!localExportEntries_.append(exp))
return false;
} else {
RootedAtom exportName(cx_, exp->exportName());
@@ -942,6 +942,12 @@ ModuleBuilder::initModule()
}
}
return true;
}
bool
ModuleBuilder::initModule()
{
RootedArrayObject requestedModules(cx_, createArray<JSAtom*>(requestedModules_));
if (!requestedModules)
return false;
@@ -972,19 +978,6 @@ ModuleBuilder::initModule()
return true;
}
bool
ModuleBuilder::appendLocalExportEntry(HandleExportEntryObject exp)
{
if (!module_->initialEnvironment().lookup(cx_, AtomToId(exp->localName()))) {
JSAutoByteString str;
str.encodeLatin1(cx_, exp->localName());
JS_ReportErrorNumber(cx_, GetErrorMessage, nullptr, JSMSG_MISSING_EXPORT, str.ptr());
return false;
}
return localExportEntries_.append(exp);
}
bool
ModuleBuilder::processImport(frontend::ParseNode* pn)
{
+7 -4
View File
@@ -282,6 +282,12 @@ class MOZ_STACK_CLASS ModuleBuilder
bool hasExportedName(JSAtom* name) const;
using ExportEntryVector = TraceableVector<ExportEntryObject*>;
const ExportEntryVector& localExportEntries() const {
return localExportEntries_;
}
bool buildTables();
bool initModule();
private:
@@ -289,8 +295,7 @@ class MOZ_STACK_CLASS ModuleBuilder
using RootedAtomVector = JS::Rooted<AtomVector>;
using ImportEntryVector = TraceableVector<ImportEntryObject*>;
using RootedImportEntryVector = JS::Rooted<ImportEntryVector>;
using ExportEntryVector = TraceableVector<ExportEntryObject*> ;
using RootedExportEntryVector = JS::Rooted<ExportEntryVector> ;
using RootedExportEntryVector = JS::Rooted<ExportEntryVector>;
JSContext* cx_;
RootedModuleObject module_;
@@ -310,8 +315,6 @@ class MOZ_STACK_CLASS ModuleBuilder
bool maybeAppendRequestedModule(HandleAtom module);
bool appendLocalExportEntry(HandleExportEntryObject exp);
template <typename T>
ArrayObject* createArray(const TraceableVector<T>& vector);
};
+7 -2
View File
@@ -1092,14 +1092,19 @@ FinishObjectClassInit(JSContext* cx, JS::HandleObject ctor, JS::HandleObject pro
return false;
/*
* Define self-hosted functions after setting the intrinsics holder
* (which is needed to define self-hosted functions)
* Define self-hosted functions on Object and Function after setting the
* intrinsics holder (which is needed to define self-hosted functions).
*/
if (!cx->runtime()->isSelfHostingGlobal(global)) {
if (!JS_DefineFunctions(cx, ctor, object_static_methods, OnlyDefineLateProperties))
return false;
if (!JS_DefineFunctions(cx, proto, object_methods, OnlyDefineLateProperties))
return false;
RootedObject funProto(cx, global->getOrCreateFunctionPrototype(cx));
if (!funProto)
return false;
if (!JS_DefineFunctions(cx, funProto, function_methods, OnlyDefineLateProperties))
return false;
}
/*
+147 -221
View File
@@ -61,15 +61,24 @@ js::IsVectorObject(HandleValue v)
return CheckVectorObject(v, V::type);
}
template bool js::IsVectorObject<Int8x16>(HandleValue v);
template bool js::IsVectorObject<Int16x8>(HandleValue v);
template bool js::IsVectorObject<Int32x4>(HandleValue v);
template bool js::IsVectorObject<Float32x4>(HandleValue v);
template bool js::IsVectorObject<Float64x2>(HandleValue v);
template bool js::IsVectorObject<Bool8x16>(HandleValue v);
template bool js::IsVectorObject<Bool16x8>(HandleValue v);
template bool js::IsVectorObject<Bool32x4>(HandleValue v);
template bool js::IsVectorObject<Bool64x2>(HandleValue v);
#define FOR_EACH_SIMD(macro) \
macro(Int8x16) \
macro(Int16x8) \
macro(Int32x4) \
macro(Uint8x16) \
macro(Uint16x8) \
macro(Uint32x4) \
macro(Float32x4) \
macro(Float64x2) \
macro(Bool8x16) \
macro(Bool16x8) \
macro(Bool32x4) \
macro(Bool64x2)
#define InstantiateIsVectorObject_(T) \
template bool js::IsVectorObject<T>(HandleValue v);
FOR_EACH_SIMD(InstantiateIsVectorObject_)
#undef InstantiateIsVectorObject_
static inline bool
ErrorBadArgs(JSContext* cx)
@@ -100,7 +109,8 @@ template<typename T>
static SimdTypeDescr*
GetTypeDescr(JSContext* cx)
{
return cx->global()->getOrCreateSimdTypeDescr<T>(cx);
RootedGlobalObject global(cx, cx->global());
return GlobalObject::getOrCreateSimdTypeDescr<T>(cx, global);
}
template<typename V>
@@ -147,67 +157,18 @@ const Class SimdTypeDescr::class_ = {
namespace {
// These classes just exist to group together various properties and so on.
class Int8x16Defn {
public:
static const SimdTypeDescr::Type type = SimdTypeDescr::Int8x16;
static const JSFunctionSpec Methods[];
};
class Int16x8Defn {
public:
static const SimdTypeDescr::Type type = SimdTypeDescr::Int16x8;
static const JSFunctionSpec Methods[];
};
class Int32x4Defn {
public:
static const SimdTypeDescr::Type type = SimdTypeDescr::Int32x4;
static const JSFunctionSpec Methods[];
};
class Uint8x16Defn {
public:
static const SimdTypeDescr::Type type = SimdTypeDescr::Uint8x16;
static const JSFunctionSpec Methods[];
};
class Uint16x8Defn {
public:
static const SimdTypeDescr::Type type = SimdTypeDescr::Uint16x8;
static const JSFunctionSpec Methods[];
};
class Uint32x4Defn {
public:
static const SimdTypeDescr::Type type = SimdTypeDescr::Uint32x4;
static const JSFunctionSpec Methods[];
};
class Float32x4Defn {
public:
static const SimdTypeDescr::Type type = SimdTypeDescr::Float32x4;
static const JSFunctionSpec Methods[];
};
class Float64x2Defn {
public:
static const SimdTypeDescr::Type type = SimdTypeDescr::Float64x2;
static const JSFunctionSpec Methods[];
};
class Bool8x16Defn {
public:
static const SimdTypeDescr::Type type = SimdTypeDescr::Bool8x16;
static const JSFunctionSpec Methods[];
};
class Bool16x8Defn {
public:
static const SimdTypeDescr::Type type = SimdTypeDescr::Bool16x8;
static const JSFunctionSpec Methods[];
};
class Bool32x4Defn {
public:
static const SimdTypeDescr::Type type = SimdTypeDescr::Bool32x4;
static const JSFunctionSpec Methods[];
};
class Bool64x2Defn {
public:
static const SimdTypeDescr::Type type = SimdTypeDescr::Bool64x2;
static const JSFunctionSpec Methods[];
// Define classes (Int8x16Defn, Int16x8Defn, etc.) to group together various
// properties and so on.
#define DEFINE_DEFN_(TypeName) \
class TypeName##Defn { \
public: \
static const SimdTypeDescr::Type type = SimdTypeDescr::TypeName; \
static const JSFunctionSpec Methods[]; \
};
FOR_EACH_SIMD(DEFINE_DEFN_)
#undef DEFINE_DEFN_
} // namespace
// Shared type descriptor methods for all SIMD types.
@@ -320,68 +281,6 @@ const JSFunctionSpec Bool64x2Defn::Methods[] = {
JS_FS_END
};
template<typename T>
static JSObject*
CreateAndBindSimdClass(JSContext* cx, Handle<GlobalObject*> global, HandleObject globalSimdObject,
HandlePropertyName stringRepr)
{
const SimdTypeDescr::Type type = T::type;
RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx));
if (!funcProto)
return nullptr;
// Create type constructor itself and initialize its reserved slots.
Rooted<SimdTypeDescr*> typeDescr(cx);
typeDescr = NewObjectWithGivenProto<SimdTypeDescr>(cx, funcProto, SingletonObject);
if (!typeDescr)
return nullptr;
typeDescr->initReservedSlot(JS_DESCR_SLOT_KIND, Int32Value(type::Simd));
typeDescr->initReservedSlot(JS_DESCR_SLOT_STRING_REPR, StringValue(stringRepr));
typeDescr->initReservedSlot(JS_DESCR_SLOT_ALIGNMENT, Int32Value(SimdTypeDescr::alignment(type)));
typeDescr->initReservedSlot(JS_DESCR_SLOT_SIZE, Int32Value(SimdTypeDescr::size(type)));
typeDescr->initReservedSlot(JS_DESCR_SLOT_OPAQUE, BooleanValue(false));
typeDescr->initReservedSlot(JS_DESCR_SLOT_TYPE, Int32Value(T::type));
if (!CreateUserSizeAndAlignmentProperties(cx, typeDescr))
return nullptr;
// Create prototype property, which inherits from Object.prototype.
RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
if (!objProto)
return nullptr;
Rooted<TypedProto*> proto(cx);
proto = NewObjectWithGivenProto<TypedProto>(cx, objProto, SingletonObject);
if (!proto)
return nullptr;
typeDescr->initReservedSlot(JS_DESCR_SLOT_TYPROTO, ObjectValue(*proto));
// Link constructor to prototype and install properties.
if (!JS_DefineFunctions(cx, typeDescr, TypeDescriptorMethods))
return nullptr;
if (!LinkConstructorAndPrototype(cx, typeDescr, proto) ||
!JS_DefineFunctions(cx, proto, SimdTypedObjectMethods))
{
return nullptr;
}
// Bind type descriptor to the global SIMD object
RootedValue typeValue(cx, ObjectValue(*typeDescr));
if (!JS_DefineFunctions(cx, typeDescr, T::Methods) ||
!DefineProperty(cx, globalSimdObject, stringRepr, typeValue, nullptr, nullptr,
JSPROP_READONLY | JSPROP_PERMANENT))
{
return nullptr;
}
uint32_t slot = uint32_t(typeDescr->type());
globalSimdObject->as<NativeObject>().setReservedSlot(slot, ObjectValue(*typeDescr));
return typeDescr;
}
template <typename T>
static bool
FillLanes(JSContext* cx, Handle<TypedObject*> result, const CallArgs& args)
@@ -410,21 +309,14 @@ SimdTypeDescr::call(JSContext* cx, unsigned argc, Value* vp)
if (!result)
return false;
#define CASE_CALL_(Type) \
case SimdTypeDescr::Type: return FillLanes< ::Type>(cx, result, args);
switch (descr->type()) {
case SimdTypeDescr::Int8x16: return FillLanes< ::Int8x16>(cx, result, args);
case SimdTypeDescr::Int16x8: return FillLanes< ::Int16x8>(cx, result, args);
case SimdTypeDescr::Int32x4: return FillLanes< ::Int32x4>(cx, result, args);
case SimdTypeDescr::Uint8x16: return FillLanes< ::Uint8x16>(cx, result, args);
case SimdTypeDescr::Uint16x8: return FillLanes< ::Uint16x8>(cx, result, args);
case SimdTypeDescr::Uint32x4: return FillLanes< ::Uint32x4>(cx, result, args);
case SimdTypeDescr::Float32x4: return FillLanes< ::Float32x4>(cx, result, args);
case SimdTypeDescr::Float64x2: return FillLanes< ::Float64x2>(cx, result, args);
case SimdTypeDescr::Bool8x16: return FillLanes< ::Bool8x16>(cx, result, args);
case SimdTypeDescr::Bool16x8: return FillLanes< ::Bool16x8>(cx, result, args);
case SimdTypeDescr::Bool32x4: return FillLanes< ::Bool32x4>(cx, result, args);
case SimdTypeDescr::Bool64x2: return FillLanes< ::Bool64x2>(cx, result, args);
FOR_EACH_SIMD(CASE_CALL_)
}
#undef CASE_CALL_
MOZ_CRASH("unexpected SIMD descriptor");
return false;
}
@@ -436,7 +328,13 @@ static const uint32_t SIMD_SLOTS_COUNT = SimdTypeDescr::LAST_TYPE + 1;
const Class SIMDObject::class_ = {
"SIMD",
JSCLASS_HAS_RESERVED_SLOTS(SIMD_SLOTS_COUNT)
JSCLASS_HAS_RESERVED_SLOTS(SIMD_SLOTS_COUNT),
nullptr, /* addProperty */
nullptr, /* delProperty */
nullptr, /* getProperty */
nullptr, /* setProperty */
nullptr, /* enumerate */
resolve /* resolve */
};
bool
@@ -470,77 +368,106 @@ GlobalObject::initSimdObject(JSContext* cx, Handle<GlobalObject*> global)
return true;
}
template<typename /* TypeDefn */ T>
static bool
CreateSimdType(JSContext* cx, Handle<GlobalObject*> global, HandlePropertyName stringRepr)
{
RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx));
if (!funcProto)
return false;
// Create type constructor itself and initialize its reserved slots.
Rooted<SimdTypeDescr*> typeDescr(cx);
typeDescr = NewObjectWithGivenProto<SimdTypeDescr>(cx, funcProto, SingletonObject);
if (!typeDescr)
return false;
const SimdTypeDescr::Type type = T::type;
typeDescr->initReservedSlot(JS_DESCR_SLOT_KIND, Int32Value(type::Simd));
typeDescr->initReservedSlot(JS_DESCR_SLOT_STRING_REPR, StringValue(stringRepr));
typeDescr->initReservedSlot(JS_DESCR_SLOT_ALIGNMENT, Int32Value(SimdTypeDescr::alignment(type)));
typeDescr->initReservedSlot(JS_DESCR_SLOT_SIZE, Int32Value(SimdTypeDescr::size(type)));
typeDescr->initReservedSlot(JS_DESCR_SLOT_OPAQUE, BooleanValue(false));
typeDescr->initReservedSlot(JS_DESCR_SLOT_TYPE, Int32Value(T::type));
if (!CreateUserSizeAndAlignmentProperties(cx, typeDescr))
return false;
// Create prototype property, which inherits from Object.prototype.
RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
if (!objProto)
return false;
Rooted<TypedProto*> proto(cx);
proto = NewObjectWithGivenProto<TypedProto>(cx, objProto, SingletonObject);
if (!proto)
return false;
typeDescr->initReservedSlot(JS_DESCR_SLOT_TYPROTO, ObjectValue(*proto));
// Link constructor to prototype and install properties.
if (!JS_DefineFunctions(cx, typeDescr, TypeDescriptorMethods))
return false;
if (!LinkConstructorAndPrototype(cx, typeDescr, proto) ||
!JS_DefineFunctions(cx, proto, SimdTypedObjectMethods))
{
return false;
}
// Bind type descriptor to the global SIMD object
RootedObject globalSimdObject(cx, global->getOrCreateSimdGlobalObject(cx));
MOZ_ASSERT(globalSimdObject);
RootedValue typeValue(cx, ObjectValue(*typeDescr));
if (!JS_DefineFunctions(cx, typeDescr, T::Methods) ||
!DefineProperty(cx, globalSimdObject, stringRepr, typeValue, nullptr, nullptr,
JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_RESOLVING))
{
return false;
}
uint32_t slot = uint32_t(typeDescr->type());
MOZ_ASSERT(globalSimdObject->as<NativeObject>().getReservedSlot(slot).isUndefined());
globalSimdObject->as<NativeObject>().setReservedSlot(slot, ObjectValue(*typeDescr));
return !!typeDescr;
}
bool
GlobalObject::initSimdType(JSContext* cx, Handle<GlobalObject*> global, uint32_t simdTypeDescrType)
{
#define CREATE_(Type) \
case SimdTypeDescr::Type: return CreateSimdType<Type##Defn>(cx, global, cx->names().Type);
switch (SimdTypeDescr::Type(simdTypeDescrType)) {
FOR_EACH_SIMD(CREATE_)
}
MOZ_CRASH("unexpected simd type");
#undef CREATE_
}
bool
SIMDObject::resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolved)
{
*resolved = false;
if (!JSID_IS_ATOM(id))
return true;
JSAtom* str = JSID_TO_ATOM(id);
Rooted<GlobalObject*> global(cx, cx->global());
#define TRY_RESOLVE_(Type) \
if (str == cx->names().Type) { \
*resolved = CreateSimdType<Type##Defn>(cx, global, cx->names().Type); \
return *resolved; \
}
FOR_EACH_SIMD(TRY_RESOLVE_)
#undef TRY_RESOLVE_
return true;
}
JSObject*
js::InitSIMDClass(JSContext* cx, HandleObject obj)
{
MOZ_ASSERT(obj->is<GlobalObject>());
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
RootedObject globalSimdObject(cx, global->getOrCreateSimdGlobalObject(cx));
if (!globalSimdObject)
return nullptr;
RootedObject i8x16(cx);
i8x16 = CreateAndBindSimdClass<Int8x16Defn>(cx, global, globalSimdObject, cx->names().int8x16);
if (!i8x16)
return nullptr;
RootedObject i16x8(cx);
i16x8 = CreateAndBindSimdClass<Int16x8Defn>(cx, global, globalSimdObject, cx->names().int16x8);
if (!i16x8)
return nullptr;
RootedObject i32x4(cx);
i32x4 = CreateAndBindSimdClass<Int32x4Defn>(cx, global, globalSimdObject, cx->names().int32x4);
if (!i32x4)
return nullptr;
RootedObject u8x16(cx);
u8x16 = CreateAndBindSimdClass<Uint8x16Defn>(cx, global, globalSimdObject, cx->names().uint8x16);
if (!u8x16)
return nullptr;
RootedObject u16x8(cx);
u16x8 = CreateAndBindSimdClass<Uint16x8Defn>(cx, global, globalSimdObject, cx->names().uint16x8);
if (!u16x8)
return nullptr;
RootedObject u32x4(cx);
u32x4 = CreateAndBindSimdClass<Uint32x4Defn>(cx, global, globalSimdObject, cx->names().uint32x4);
if (!u32x4)
return nullptr;
RootedObject f32x4(cx);
f32x4 = CreateAndBindSimdClass<Float32x4Defn>(cx, global, globalSimdObject, cx->names().float32x4);
if (!f32x4)
return nullptr;
RootedObject f64x2(cx);
f64x2 = CreateAndBindSimdClass<Float64x2Defn>(cx, global, globalSimdObject, cx->names().float64x2);
if (!f64x2)
return nullptr;
RootedObject b8x16(cx);
b8x16 = CreateAndBindSimdClass<Bool8x16Defn>(cx, global, globalSimdObject, cx->names().bool8x16);
if (!b8x16)
return nullptr;
RootedObject b16x8(cx);
b16x8 = CreateAndBindSimdClass<Bool16x8Defn>(cx, global, globalSimdObject, cx->names().bool16x8);
if (!b16x8)
return nullptr;
RootedObject b32x4(cx);
b32x4 = CreateAndBindSimdClass<Bool32x4Defn>(cx, global, globalSimdObject, cx->names().bool32x4);
if (!b32x4)
return nullptr;
RootedObject b64x2(cx);
b64x2 = CreateAndBindSimdClass<Bool64x2Defn>(cx, global, globalSimdObject, cx->names().bool64x2);
if (!b64x2)
return nullptr;
return globalSimdObject;
return global->getOrCreateSimdGlobalObject(cx);
}
template<typename V>
@@ -561,15 +488,14 @@ js::CreateSimd(JSContext* cx, const typename V::Elem* data)
return result;
}
template JSObject* js::CreateSimd<Int8x16>(JSContext* cx, const Int8x16::Elem* data);
template JSObject* js::CreateSimd<Int16x8>(JSContext* cx, const Int16x8::Elem* data);
template JSObject* js::CreateSimd<Int32x4>(JSContext* cx, const Int32x4::Elem* data);
template JSObject* js::CreateSimd<Float32x4>(JSContext* cx, const Float32x4::Elem* data);
template JSObject* js::CreateSimd<Float64x2>(JSContext* cx, const Float64x2::Elem* data);
template JSObject* js::CreateSimd<Bool8x16>(JSContext* cx, const Bool8x16::Elem* data);
template JSObject* js::CreateSimd<Bool16x8>(JSContext* cx, const Bool16x8::Elem* data);
template JSObject* js::CreateSimd<Bool32x4>(JSContext* cx, const Bool32x4::Elem* data);
template JSObject* js::CreateSimd<Bool64x2>(JSContext* cx, const Bool64x2::Elem* data);
#define InstantiateCreateSimd_(Type) \
template JSObject* js::CreateSimd<Type>(JSContext* cx, const Type::Elem* data);
FOR_EACH_SIMD(InstantiateCreateSimd_)
#undef InstantiateCreateSimd_
#undef FOR_EACH_SIMD
namespace js {
// Unary SIMD operators
+1
View File
@@ -784,6 +784,7 @@ class SIMDObject : public JSObject
public:
static const Class class_;
static bool toString(JSContext* cx, unsigned int argc, Value* vp);
static bool resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId, bool* resolved);
};
// These classes implement the concept containing the following constraints:
+8
View File
@@ -15,6 +15,10 @@
#define IS_UINT32(x) ((x) >>> 0 === (x))
#define MAX_NUMERIC_INDEX 0x1fffffffffffff // == Math.pow(2, 53) - 1
// Unforgeable version of Function.prototype.apply.
#define FUN_APPLY(FUN, RECEIVER, ARGS) \
callFunction(std_Function_apply, FUN, RECEIVER, ARGS)
// Unforgeable versions of ARRAY.push(ELEMENT) and ARRAY.slice.
#define ARRAY_PUSH(ARRAY, ELEMENT) \
callFunction(std_Array_push, ARRAY, ELEMENT);
@@ -39,6 +43,10 @@
// global. This slot is used only in debug build.
#define HAS_SELFHOSTED_CANONICAL_NAME_SLOT 0
// Stores the length for bound functions, so the .length property doesn't need
// to be resolved eagerly.
#define BOUND_FUN_LENGTH_SLOT 1
// Stores the private WeakMap slot used for WeakSets
#define WEAKSET_MAP_SLOT 0
+13 -13
View File
@@ -231,7 +231,7 @@ const Class js::ScalarTypeDescr::class_ = {
const JSFunctionSpec js::ScalarTypeDescr::typeObjectMethods[] = {
JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
{"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"},
{"array", {nullptr, nullptr}, 0, 0, "ArrayShorthand"},
{"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"},
JS_FS_END
};
@@ -2595,7 +2595,7 @@ js::GetFloat32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<GlobalObject*> global(cx, cx->global());
MOZ_ASSERT(global);
args.rval().setObject(*global->getOrCreateSimdTypeDescr<Float32x4>(cx));
args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Float32x4>(cx, global));
return true;
}
@@ -2605,7 +2605,7 @@ js::GetFloat64x2TypeDescr(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<GlobalObject*> global(cx, cx->global());
MOZ_ASSERT(global);
args.rval().setObject(*global->getOrCreateSimdTypeDescr<Float64x2>(cx));
args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Float64x2>(cx, global));
return true;
}
@@ -2615,7 +2615,7 @@ js::GetInt8x16TypeDescr(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<GlobalObject*> global(cx, cx->global());
MOZ_ASSERT(global);
args.rval().setObject(*global->getOrCreateSimdTypeDescr<Int8x16>(cx));
args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Int8x16>(cx, global));
return true;
}
@@ -2625,7 +2625,7 @@ js::GetInt16x8TypeDescr(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<GlobalObject*> global(cx, cx->global());
MOZ_ASSERT(global);
args.rval().setObject(*global->getOrCreateSimdTypeDescr<Int16x8>(cx));
args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Int16x8>(cx, global));
return true;
}
@@ -2635,7 +2635,7 @@ js::GetInt32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<GlobalObject*> global(cx, cx->global());
MOZ_ASSERT(global);
args.rval().setObject(*global->getOrCreateSimdTypeDescr<Int32x4>(cx));
args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Int32x4>(cx, global));
return true;
}
@@ -2645,7 +2645,7 @@ js::GetUint8x16TypeDescr(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<GlobalObject*> global(cx, cx->global());
MOZ_ASSERT(global);
args.rval().setObject(*global->getOrCreateSimdTypeDescr<Uint8x16>(cx));
args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Uint8x16>(cx, global));
return true;
}
@@ -2655,7 +2655,7 @@ js::GetUint16x8TypeDescr(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<GlobalObject*> global(cx, cx->global());
MOZ_ASSERT(global);
args.rval().setObject(*global->getOrCreateSimdTypeDescr<Uint16x8>(cx));
args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Uint16x8>(cx, global));
return true;
}
@@ -2665,7 +2665,7 @@ js::GetUint32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<GlobalObject*> global(cx, cx->global());
MOZ_ASSERT(global);
args.rval().setObject(*global->getOrCreateSimdTypeDescr<Uint32x4>(cx));
args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Uint32x4>(cx, global));
return true;
}
@@ -2675,7 +2675,7 @@ js::GetBool8x16TypeDescr(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<GlobalObject*> global(cx, cx->global());
MOZ_ASSERT(global);
args.rval().setObject(*global->getOrCreateSimdTypeDescr<Bool8x16>(cx));
args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Bool8x16>(cx, global));
return true;
}
@@ -2685,7 +2685,7 @@ js::GetBool16x8TypeDescr(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<GlobalObject*> global(cx, cx->global());
MOZ_ASSERT(global);
args.rval().setObject(*global->getOrCreateSimdTypeDescr<Bool16x8>(cx));
args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Bool16x8>(cx, global));
return true;
}
@@ -2695,7 +2695,7 @@ js::GetBool32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<GlobalObject*> global(cx, cx->global());
MOZ_ASSERT(global);
args.rval().setObject(*global->getOrCreateSimdTypeDescr<Bool32x4>(cx));
args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Bool32x4>(cx, global));
return true;
}
@@ -2705,7 +2705,7 @@ js::GetBool64x2TypeDescr(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<GlobalObject*> global(cx, cx->global());
MOZ_ASSERT(global);
args.rval().setObject(*global->getOrCreateSimdTypeDescr<Bool64x2>(cx));
args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Bool64x2>(cx, global));
return true;
}
+1 -1
View File
@@ -5549,7 +5549,7 @@ PostBarrierCallback(JSTracer* trc, JSString* key, void* data)
UnbarrieredFieldInfoHash* table = reinterpret_cast<UnbarrieredFieldInfoHash*>(data);
JSString* prior = key;
JS_CallUnbarrieredStringTracer(trc, &key, "CType fieldName");
js::UnsafeTraceManuallyBarrieredEdge(trc, &key, "CType fieldName");
table->rekeyIfMoved(JS_ASSERT_STRING_IS_FLAT(prior), JS_ASSERT_STRING_IS_FLAT(key));
}
+42 -11
View File
@@ -3973,9 +3973,9 @@ BytecodeEmitter::emitDestructuringLHS(ParseNode* target, VarEmitOption emitOptio
}
bool
BytecodeEmitter::emitIteratorNext(ParseNode* pn)
BytecodeEmitter::emitIteratorNext(ParseNode* pn, bool allowSelfHosted)
{
MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting,
MOZ_ASSERT(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting,
".next() iteration is prohibited in self-hosted code because it "
"can run user-modifiable iteration code");
@@ -5514,7 +5514,7 @@ BytecodeEmitter::emitForInOrOfVariables(ParseNode* pn)
}
bool
BytecodeEmitter::emitForOf(StmtType type, ParseNode* pn)
BytecodeEmitter::emitForOf(StmtType type, ParseNode* pn, bool allowSelfHosted)
{
MOZ_ASSERT(type == StmtType::FOR_OF_LOOP || type == StmtType::SPREAD);
#ifdef DEBUG
@@ -5623,7 +5623,7 @@ BytecodeEmitter::emitForOf(StmtType type, ParseNode* pn)
if (!emitDupAt(2)) // ITER ARR I ITER
return false;
}
if (!emitIteratorNext(forHead)) // ... RESULT
if (!emitIteratorNext(forHead, allowSelfHosted)) // ... RESULT
return false;
if (!emit1(JSOP_DUP)) // ... RESULT RESULT
return false;
@@ -7193,12 +7193,15 @@ BytecodeEmitter::emitSelfHostedCallFunction(ParseNode* pn)
return false;
}
if (pn->getOp() != JSOP_CALL) {
JSOp callOp = pn->getOp();
if (callOp != JSOP_CALL) {
reportError(pn, JSMSG_NOT_CONSTRUCTOR, errorName);
return false;
}
ParseNode* funNode = pn2->pn_next;
if (funNode->getKind() == PNK_NAME && funNode->name() == cx->names().std_Function_apply)
callOp = JSOP_FUNAPPLY;
if (!emitTree(funNode))
return false;
@@ -7222,10 +7225,10 @@ BytecodeEmitter::emitSelfHostedCallFunction(ParseNode* pn)
emittingForInit = oldEmittingForInit;
uint32_t argc = pn->pn_count - 3;
if (!emitCall(pn->getOp(), argc))
if (!emitCall(callOp, argc))
return false;
checkTypeSet(pn->getOp());
checkTypeSet(callOp);
return true;
}
@@ -7269,6 +7272,18 @@ BytecodeEmitter::emitSelfHostedForceInterpreter(ParseNode* pn)
return true;
}
bool
BytecodeEmitter::emitSelfHostedAllowContentSpread(ParseNode* pn)
{
if (pn->pn_count != 2) {
reportError(pn, JSMSG_MORE_ARGS_NEEDED, "allowContentSpread", "1", "");
return false;
}
// We're just here as a sentinel. Pass the value through directly.
return emitTree(pn->pn_head->pn_next);
}
bool
BytecodeEmitter::emitCallOrNew(ParseNode* pn)
{
@@ -7317,6 +7332,8 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
return emitSelfHostedResumeGenerator(pn);
if (pn2->name() == cx->names().forceInterpreter)
return emitSelfHostedForceInterpreter(pn);
if (pn2->name() == cx->names().allowContentSpread)
return emitSelfHostedAllowContentSpread(pn);
// Fall through.
}
if (!emitNameOp(pn2, callop))
@@ -7932,9 +7949,9 @@ BytecodeEmitter::emitArrayComp(ParseNode* pn)
}
bool
BytecodeEmitter::emitSpread()
BytecodeEmitter::emitSpread(bool allowSelfHosted)
{
return emitForOf(StmtType::SPREAD, nullptr);
return emitForOf(StmtType::SPREAD, nullptr, allowSelfHosted);
}
bool
@@ -8024,11 +8041,25 @@ BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count, JSOp op)
}
if (!updateSourceCoordNotes(pn2->pn_pos.begin))
return false;
bool allowSelfHostedSpread = false;
if (pn2->isKind(PNK_ELISION)) {
if (!emit1(JSOP_HOLE))
return false;
} else {
ParseNode* expr = pn2->isKind(PNK_SPREAD) ? pn2->pn_kid : pn2;
ParseNode* expr;
if (pn2->isKind(PNK_SPREAD)) {
expr = pn2->pn_kid;
if (emitterMode == BytecodeEmitter::SelfHosting &&
expr->isKind(PNK_CALL) &&
expr->pn_head->name() == cx->names().allowContentSpread)
{
allowSelfHostedSpread = true;
}
} else {
expr = pn2;
}
if (!emitTree(expr)) // ARRAY INDEX? VALUE
return false;
}
@@ -8039,7 +8070,7 @@ BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count, JSOp op)
return false;
if (!emit2(JSOP_PICK, 2)) // ITER ARRAY INDEX
return false;
if (!emitSpread()) // ARRAY INDEX
if (!emitSpread(allowSelfHostedSpread)) // ARRAY INDEX
return false;
} else if (afterSpread) {
if (!emit1(JSOP_INITELEM_INC))
+4 -3
View File
@@ -575,7 +575,7 @@ struct BytecodeEmitter
// Pops iterator from the top of the stack. Pushes the result of |.next()|
// onto the stack.
bool emitIteratorNext(ParseNode* pn);
bool emitIteratorNext(ParseNode* pn, bool allowSelfHosted = false);
// Check if the value on top of the stack is "undefined". If so, replace
// that value on the stack with the value defined by |defaultExpr|.
@@ -612,6 +612,7 @@ struct BytecodeEmitter
bool emitSelfHostedCallFunction(ParseNode* pn);
bool emitSelfHostedResumeGenerator(ParseNode* pn);
bool emitSelfHostedForceInterpreter(ParseNode* pn);
bool emitSelfHostedAllowContentSpread(ParseNode* pn);
bool emitComprehensionFor(ParseNode* compFor);
bool emitComprehensionForIn(ParseNode* pn);
@@ -641,7 +642,7 @@ struct BytecodeEmitter
// |.next()| and put the results into the I-th element of array with
// incrementing I, then push the result I (it will be original I +
// iteration count). The stack after iteration will look like |ARRAY INDEX|.
bool emitSpread();
bool emitSpread(bool allowSelfHosted = false);
// If type is StmtType::FOR_OF_LOOP, emit bytecode for a for-of loop.
// pn should be PNK_FOR, and pn->pn_left should be PNK_FOROF.
@@ -651,7 +652,7 @@ struct BytecodeEmitter
//
// Please refer the comment above emitSpread for additional information about
// stack convention.
bool emitForOf(StmtType type, ParseNode* pn);
bool emitForOf(StmtType type, ParseNode* pn, bool allowSelfHosted = false);
bool emitClass(ParseNode* pn);
bool emitSuperPropLHS(ParseNode* superBase, bool isCall = false);
+31 -9
View File
@@ -305,8 +305,6 @@ ParseContext<FullParseHandler>::define(TokenStream& ts,
if (!checkLocalsOverflow(ts))
return false;
}
if (atModuleScope())
dn->pn_dflags |= PND_CLOSED;
if (!decls_.addUnique(name, dn))
return false;
break;
@@ -316,8 +314,6 @@ ParseContext<FullParseHandler>::define(TokenStream& ts,
// See FullParseHandler::setLexicalDeclarationOp.
dn->setOp(dn->pn_scopecoord.isFree() ? JSOP_INITGLEXICAL : JSOP_INITLEXICAL);
dn->pn_dflags |= (PND_LEXICAL | PND_BOUND);
if (atModuleLevel())
dn->pn_dflags |= PND_CLOSED;
if (atBodyLevel()) {
if (!bodyLevelLexicals_.append(dn))
return false;
@@ -335,7 +331,7 @@ ParseContext<FullParseHandler>::define(TokenStream& ts,
break;
case Definition::IMPORT:
dn->pn_dflags |= PND_LEXICAL | PND_CLOSED;
dn->pn_dflags |= PND_LEXICAL;
MOZ_ASSERT(atBodyLevel());
if (!decls_.addShadow(name, dn))
return false;
@@ -948,9 +944,9 @@ Parser<ParseHandler>::checkStrictBinding(PropertyName* name, Node pn)
return true;
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::standaloneModule(HandleModuleObject module, ModuleBuilder& builder)
template <>
ParseNode*
Parser<FullParseHandler>::standaloneModule(HandleModuleObject module, ModuleBuilder& builder)
{
MOZ_ASSERT(checkOptionsCalled);
@@ -984,6 +980,28 @@ Parser<ParseHandler>::standaloneModule(HandleModuleObject module, ModuleBuilder&
return null();
}
if (!builder.buildTables())
return null();
// Check exported local bindings exist and mark them as closed over.
for (auto entry : modulebox->builder.localExportEntries()) {
JSAtom* name = entry->localName();
MOZ_ASSERT(name);
Definition* def = modulepc.decls().lookupFirst(name);
if (!def) {
JSAutoByteString str;
if (!str.encodeLatin1(context, name))
return null();
JS_ReportErrorNumber(context->asJSContext(), GetErrorMessage, nullptr,
JSMSG_MISSING_EXPORT, str.ptr());
return null();
}
def->pn_dflags |= PND_CLOSED;
}
if (!FoldConstants(context, &pn, this))
return null();
@@ -2825,6 +2843,10 @@ Parser<FullParseHandler>::functionArgsAndBody(InHandling inHandling, ParseNode*
{
ParseContext<FullParseHandler>* outerpc = pc;
// Close over top level function definitions in modules.
if (pc->sc->isModuleBox())
pn->pn_dflags |= PND_CLOSED;
// Create box for fun->object early to protect against last-ditch GC.
FunctionBox* funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind);
if (!funbox)
@@ -4898,7 +4920,7 @@ Parser<FullParseHandler>::namedImportsOrNamespaceImport(TokenKind tt, Node impor
// const variables which are initialized during the
// ModuleDeclarationInstantiation step. Thus we don't set the PND_IMPORT
// flag on the definition.
bindingName->pn_dflags |= PND_CONST;
bindingName->pn_dflags |= PND_CONST | PND_CLOSED;
BindData<FullParseHandler> data(context);
data.initLexical(HoistVars, JSOP_DEFLET, nullptr, JSMSG_TOO_MANY_LOCALS);
handler.setPosition(bindingName, pos());
-5
View File
@@ -331,11 +331,6 @@ struct MOZ_STACK_CLASS ParseContext : public GenericParseContext
return atBodyLevel() && sc->isModuleBox();
}
// True if the current lexical scope is the topmost level of a module.
bool atModuleScope() {
return sc->isModuleBox() && !innermostScopeStmt();
}
// True if this is the ParseContext for the body of a function created by
// the Function constructor.
bool isFunctionConstructorBody() const {
+4 -4
View File
@@ -90,7 +90,7 @@ template <typename T>
void
ReadBarrierFunctor<S>::operator()(T* t)
{
InternalGCMethods<T*>::readBarrier(t);
InternalBarrierMethods<T*>::readBarrier(t);
}
template void ReadBarrierFunctor<JS::Value>::operator()<JS::Symbol>(JS::Symbol*);
template void ReadBarrierFunctor<JS::Value>::operator()<JSObject>(JSObject*);
@@ -101,7 +101,7 @@ template <typename T>
void
PreBarrierFunctor<S>::operator()(T* t)
{
InternalGCMethods<T*>::preBarrier(t);
InternalBarrierMethods<T*>::preBarrier(t);
}
template void PreBarrierFunctor<JS::Value>::operator()<JS::Symbol>(JS::Symbol*);
template void PreBarrierFunctor<JS::Value>::operator()<JSObject>(JSObject*);
@@ -170,12 +170,12 @@ JS_PUBLIC_API(void)
JS::HeapObjectPostBarrier(JSObject** objp, JSObject* prev, JSObject* next)
{
MOZ_ASSERT(objp);
js::InternalGCMethods<JSObject*>::postBarrier(objp, prev, next);
js::InternalBarrierMethods<JSObject*>::postBarrier(objp, prev, next);
}
JS_PUBLIC_API(void)
JS::HeapValuePostBarrier(JS::Value* valuep, const Value& prev, const Value& next)
{
MOZ_ASSERT(valuep);
js::InternalGCMethods<JS::Value>::postBarrier(valuep, prev, next);
js::InternalBarrierMethods<JS::Value>::postBarrier(valuep, prev, next);
}
+33 -33
View File
@@ -156,23 +156,23 @@
* via:
*
* WriteBarrieredBase<T>::pre
* -> InternalGCMethods<T*>::preBarrier
* -> InternalBarrierMethods<T*>::preBarrier
* -> T::writeBarrierPre
* -> InternalGCMethods<Value>::preBarrier
* -> InternalGCMethods<jsid>::preBarrier
* -> InternalGCMethods<T*>::preBarrier
* -> InternalBarrierMethods<Value>::preBarrier
* -> InternalBarrierMethods<jsid>::preBarrier
* -> InternalBarrierMethods<T*>::preBarrier
* -> T::writeBarrierPre
*
* HeapPtr<T>::post and RelocatablePtr<T>::post
* -> InternalGCMethods<T*>::postBarrier
* -> InternalBarrierMethods<T*>::postBarrier
* -> T::writeBarrierPost
* -> InternalGCMethods<Value>::postBarrier
* -> InternalBarrierMethods<Value>::postBarrier
* -> StoreBuffer::put
*
* These classes are designed to be used by the internals of the JS engine.
* Barriers designed to be used externally are provided in js/RootingAPI.h.
* These external barriers call into the same post-barrier implementations at
* InternalGCMethods<T>::post via an indirect call to Heap(.+)Barrier.
* InternalBarrierMethods<T>::post via an indirect call to Heap(.+)Barrier.
*/
class JSAtom;
@@ -240,10 +240,10 @@ void MarkIdForBarrier(JSTracer* trc, jsid* idp, const char* name);
} // namespace gc
template <typename T>
struct InternalGCMethods {};
struct InternalBarrierMethods {};
template <typename T>
struct InternalGCMethods<T*>
struct InternalBarrierMethods<T*>
{
static bool isMarkable(T* v) { return v != nullptr; }
@@ -265,7 +265,7 @@ template <typename S> struct ReadBarrierFunctor : public VoidDefaultAdaptor<S> {
};
template <>
struct InternalGCMethods<Value>
struct InternalBarrierMethods<Value>
{
static bool isMarkable(Value v) { return v.isMarkable(); }
static bool isMarkableTaggedPointer(Value v) { return isMarkable(v); }
@@ -301,7 +301,7 @@ struct InternalGCMethods<Value>
};
template <>
struct InternalGCMethods<jsid>
struct InternalBarrierMethods<jsid>
{
static bool isMarkable(jsid id) { return JSID_IS_STRING(id) || JSID_IS_SYMBOL(id); }
static bool isMarkableTaggedPointer(jsid id) { return isMarkable(id); }
@@ -368,11 +368,11 @@ class WriteBarrieredBase : public BarrieredBase<T>
void unsafeSet(T v) { this->value = v; }
// For users who need to manually barrier the raw types.
static void writeBarrierPre(const T& v) { InternalGCMethods<T>::preBarrier(v); }
static void writeBarrierPre(const T& v) { InternalBarrierMethods<T>::preBarrier(v); }
protected:
void pre() { InternalGCMethods<T>::preBarrier(this->value); }
void post(T prev, T next) { InternalGCMethods<T>::postBarrier(&this->value, prev, next); }
void pre() { InternalBarrierMethods<T>::preBarrier(this->value); }
void post(T prev, T next) { InternalBarrierMethods<T>::postBarrier(&this->value, prev, next); }
};
/*
@@ -385,7 +385,7 @@ template <class T>
class PreBarriered : public WriteBarrieredBase<T>
{
public:
PreBarriered() : WriteBarrieredBase<T>(GCMethods<T>::initial()) {}
PreBarriered() : WriteBarrieredBase<T>(GCPolicy<T>::initial()) {}
/*
* Allow implicit construction for use in generic contexts, such as DebuggerWeakMap::markKeys.
*/
@@ -430,12 +430,12 @@ template <class T>
class HeapPtr : public WriteBarrieredBase<T>
{
public:
HeapPtr() : WriteBarrieredBase<T>(GCMethods<T>::initial()) {}
HeapPtr() : WriteBarrieredBase<T>(GCPolicy<T>::initial()) {}
explicit HeapPtr(T v) : WriteBarrieredBase<T>(v) {
this->post(GCMethods<T>::initial(), v);
this->post(GCPolicy<T>::initial(), v);
}
explicit HeapPtr(const HeapPtr<T>& v) : WriteBarrieredBase<T>(v) {
this->post(GCMethods<T>::initial(), v);
this->post(GCPolicy<T>::initial(), v);
}
#ifdef DEBUG
~HeapPtr() {
@@ -447,7 +447,7 @@ class HeapPtr : public WriteBarrieredBase<T>
void init(T v) {
this->value = v;
this->post(GCMethods<T>::initial(), v);
this->post(GCPolicy<T>::initial(), v);
}
DECLARE_POINTER_ASSIGN_OPS(HeapPtr, T);
@@ -482,11 +482,11 @@ template <class T>
class RelocatablePtr : public WriteBarrieredBase<T>
{
public:
RelocatablePtr() : WriteBarrieredBase<T>(GCMethods<T>::initial()) {}
RelocatablePtr() : WriteBarrieredBase<T>(GCPolicy<T>::initial()) {}
// Implicitly adding barriers is a reasonable default.
MOZ_IMPLICIT RelocatablePtr(const T& v) : WriteBarrieredBase<T>(v) {
this->post(GCMethods<T>::initial(), this->value);
this->post(GCPolicy<T>::initial(), this->value);
}
/*
@@ -496,17 +496,17 @@ class RelocatablePtr : public WriteBarrieredBase<T>
* simply omit the rvalue variant.
*/
MOZ_IMPLICIT RelocatablePtr(const RelocatablePtr<T>& v) : WriteBarrieredBase<T>(v) {
this->post(GCMethods<T>::initial(), this->value);
this->post(GCPolicy<T>::initial(), this->value);
}
~RelocatablePtr() {
this->pre();
this->post(this->value, GCMethods<T>::initial());
this->post(this->value, GCPolicy<T>::initial());
}
void init(T v) {
this->value = v;
this->post(GCMethods<T>::initial(), this->value);
this->post(GCPolicy<T>::initial(), this->value);
}
DECLARE_POINTER_ASSIGN_OPS(RelocatablePtr, T);
@@ -540,8 +540,8 @@ class ReadBarrieredBase : public BarrieredBase<T>
explicit ReadBarrieredBase(T v) : BarrieredBase<T>(v) {}
protected:
void read() const { InternalGCMethods<T>::readBarrier(this->value); }
void post(T prev, T next) { InternalGCMethods<T>::postBarrier(&this->value, prev, next); }
void read() const { InternalBarrierMethods<T>::readBarrier(this->value); }
void post(T prev, T next) { InternalBarrierMethods<T>::postBarrier(&this->value, prev, next); }
};
// Incremental GC requires that weak pointers have read barriers. This is mostly
@@ -561,16 +561,16 @@ template <typename T>
class ReadBarriered : public ReadBarrieredBase<T>
{
public:
ReadBarriered() : ReadBarrieredBase<T>(GCMethods<T>::initial()) {}
ReadBarriered() : ReadBarrieredBase<T>(GCPolicy<T>::initial()) {}
// It is okay to add barriers implicitly.
MOZ_IMPLICIT ReadBarriered(const T& v) : ReadBarrieredBase<T>(v) {
this->post(GCMethods<T>::initial(), v);
this->post(GCPolicy<T>::initial(), v);
}
// Copy is creating a new edge, so we must read barrier the source edge.
explicit ReadBarriered(const ReadBarriered& v) : ReadBarrieredBase<T>(v) {
this->post(GCMethods<T>::initial(), v.get());
this->post(GCPolicy<T>::initial(), v.get());
}
// Move retains the lifetime status of the source edge, so does not fire
@@ -578,11 +578,11 @@ class ReadBarriered : public ReadBarrieredBase<T>
ReadBarriered(ReadBarriered&& v)
: ReadBarrieredBase<T>(mozilla::Forward<ReadBarriered<T>>(v))
{
this->post(GCMethods<T>::initial(), v.value);
this->post(GCPolicy<T>::initial(), v.value);
}
~ReadBarriered() {
this->post(this->value, GCMethods<T>::initial());
this->post(this->value, GCPolicy<T>::initial());
}
ReadBarriered& operator=(const ReadBarriered& v) {
@@ -593,8 +593,8 @@ class ReadBarriered : public ReadBarrieredBase<T>
}
const T get() const {
if (!InternalGCMethods<T>::isMarkable(this->value))
return GCMethods<T>::initial();
if (!InternalBarrierMethods<T>::isMarkable(this->value))
return GCPolicy<T>::initial();
this->read();
return this->value;
}
+29 -10
View File
@@ -413,16 +413,19 @@ template <typename T>
JS_PUBLIC_API(void)
JS::TraceEdge(JSTracer* trc, JS::Heap<T>* thingp, const char* name)
{
DispatchToTracer(trc, ConvertToBase(thingp->unsafeGet()), name);
MOZ_ASSERT(thingp);
if (InternalBarrierMethods<T>::isMarkable(thingp->get()))
DispatchToTracer(trc, ConvertToBase(thingp->unsafeGet()), name);
}
template <typename T>
JS_PUBLIC_API(void)
JS::TraceNullableEdge(JSTracer* trc, JS::Heap<T>* thingp, const char* name)
JS::TraceEdge(JSTracer* trc, JS::TenuredHeap<JSObject*>* thingp, const char* name)
{
MOZ_ASSERT(thingp);
if (InternalGCMethods<T>::isMarkable(thingp->get()))
DispatchToTracer(trc, ConvertToBase(thingp->unsafeGet()), name);
if (JSObject* ptr = thingp->getPtr()) {
DispatchToTracer(trc, &ptr, name);
thingp->setPtr(ptr);
}
}
template <typename T>
@@ -432,6 +435,13 @@ js::TraceManuallyBarrieredEdge(JSTracer* trc, T* thingp, const char* name)
DispatchToTracer(trc, ConvertToBase(thingp), name);
}
template <typename T>
JS_PUBLIC_API(void)
js::UnsafeTraceManuallyBarrieredEdge(JSTracer* trc, T* thingp, const char* name)
{
DispatchToTracer(trc, ConvertToBase(thingp), name);
}
template <typename T>
void
js::TraceWeakEdge(JSTracer* trc, WeakRef<T>* thingp, const char* name)
@@ -464,7 +474,7 @@ void
js::TraceNullableRoot(JSTracer* trc, T* thingp, const char* name)
{
AssertRootMarkingPhase(trc);
if (InternalGCMethods<T>::isMarkableTaggedPointer(*thingp))
if (InternalBarrierMethods<T>::isMarkableTaggedPointer(*thingp))
DispatchToTracer(trc, ConvertToBase(thingp), name);
}
@@ -475,13 +485,21 @@ js::TraceNullableRoot(JSTracer* trc, ReadBarriered<T>* thingp, const char* name)
TraceNullableRoot(trc, thingp->unsafeGet(), name);
}
template <typename T>
JS_PUBLIC_API(void)
JS::UnsafeTraceRoot(JSTracer* trc, T* thingp, const char* name)
{
MOZ_ASSERT(thingp);
js::TraceNullableRoot(trc, thingp, name);
}
template <typename T>
void
js::TraceRange(JSTracer* trc, size_t len, WriteBarrieredBase<T>* vec, const char* name)
{
JS::AutoTracingIndex index(trc);
for (auto i : MakeRange(len)) {
if (InternalGCMethods<T>::isMarkable(vec[i].get()))
if (InternalBarrierMethods<T>::isMarkable(vec[i].get()))
DispatchToTracer(trc, ConvertToBase(vec[i].unsafeUnbarrieredForTracing()), name);
++index;
}
@@ -494,7 +512,7 @@ js::TraceRootRange(JSTracer* trc, size_t len, T* vec, const char* name)
AssertRootMarkingPhase(trc);
JS::AutoTracingIndex index(trc);
for (auto i : MakeRange(len)) {
if (InternalGCMethods<T>::isMarkable(vec[i]))
if (InternalBarrierMethods<T>::isMarkable(vec[i]))
DispatchToTracer(trc, ConvertToBase(&vec[i]), name);
++index;
}
@@ -516,8 +534,9 @@ FOR_EACH_GC_POINTER_TYPE(INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS)
#define INSTANTIATE_PUBLIC_TRACE_FUNCTIONS(type) \
template JS_PUBLIC_API(void) JS::TraceEdge<type>(JSTracer*, JS::Heap<type>*, const char*); \
template JS_PUBLIC_API(void) JS::TraceNullableEdge<type>(JSTracer*, JS::Heap<type>*, \
const char*);
template JS_PUBLIC_API(void) JS::UnsafeTraceRoot<type>(JSTracer*, type*, const char*); \
template JS_PUBLIC_API(void) js::UnsafeTraceManuallyBarrieredEdge<type>(JSTracer*, type*, \
const char*);
FOR_EACH_PUBLIC_GC_POINTER_TYPE(INSTANTIATE_PUBLIC_TRACE_FUNCTIONS)
#undef INSTANTIATE_PUBLIC_TRACE_FUNCTIONS
-42
View File
@@ -105,48 +105,6 @@ JS::CallbackTracer::getTracingEdgeName(char* buffer, size_t bufferSize)
/*** Public Tracing API **************************************************************************/
JS_PUBLIC_API(void)
JS_CallUnbarrieredValueTracer(JSTracer* trc, Value* valuep, const char* name)
{
TraceManuallyBarrieredEdge(trc, valuep, name);
}
JS_PUBLIC_API(void)
JS_CallUnbarrieredIdTracer(JSTracer* trc, jsid* idp, const char* name)
{
TraceManuallyBarrieredEdge(trc, idp, name);
}
JS_PUBLIC_API(void)
JS_CallUnbarrieredObjectTracer(JSTracer* trc, JSObject** objp, const char* name)
{
TraceManuallyBarrieredEdge(trc, objp, name);
}
JS_PUBLIC_API(void)
JS_CallUnbarrieredStringTracer(JSTracer* trc, JSString** strp, const char* name)
{
TraceManuallyBarrieredEdge(trc, strp, name);
}
JS_PUBLIC_API(void)
JS_CallUnbarrieredScriptTracer(JSTracer* trc, JSScript** scriptp, const char* name)
{
TraceManuallyBarrieredEdge(trc, scriptp, name);
}
JS_PUBLIC_API(void)
JS_CallTenuredObjectTracer(JSTracer* trc, JS::TenuredHeap<JSObject*>* objp, const char* name)
{
JSObject* obj = objp->getPtr();
if (!obj)
return;
TraceManuallyBarrieredEdge(trc, &obj, name);
objp->setPtr(obj);
}
JS_PUBLIC_API(void)
JS::TraceChildren(JSTracer* trc, GCCellPtr thing)
{
+5
View File
@@ -0,0 +1,5 @@
export default class {
triple(x) {
return x * 3;
}
}
@@ -0,0 +1,3 @@
export default function(x) {
return x * 2;
}
@@ -78,6 +78,6 @@ 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(function () {}.bind()), s(48, 80));
assertEq(tByteSize(() => 1), s(48, 80));
assertEq(tByteSize(Math.sin), s(32, 64));
@@ -0,0 +1,2 @@
// |jit-test| module
eval("1");
@@ -0,0 +1,10 @@
g = newGlobal();
g.parent = this;
g.eval("(" + function() {
Debugger(parent)
.onExceptionUnwind = function(frame)
frame.eval("")
} + ")()");
m = parseModule(` s1 `);
m.declarationInstantiation();
m.evaluation();
@@ -0,0 +1,37 @@
// Test debugger access to aliased and unaliased bindings work correctly.
load(libdir + "asserts.js");
var g = newGlobal();
var dbg = Debugger(g);
dbg.onDebuggerStatement = function (frame) {
let env = frame.environment.parent;
assertEq(env.getVariable('a'), 1);
assertEq(env.getVariable('b'), 2);
assertEq(env.getVariable('c'), 3);
assertEq(env.getVariable('d'), 4);
assertEq(env.getVariable('e'), 5);
};
g.eval(
`
let moduleRepo = {};
setModuleResolveHook(function(module, specifier) {
if (specifier in moduleRepo)
return moduleRepo[specifier];
throw "Module '" + specifier + "' not found";
});
let m = parseModule(
\`
var a = 1;
let b = 2;
export var c = 3;
export let d = 4;
let e = 5;
function f() { debugger; return e; }
\`);
m.declarationInstantiation();
m.evaluation();
`);
@@ -0,0 +1,38 @@
// Test debugger access to aliased and unaliased bindings work correctly.
load(libdir + "asserts.js");
var g = newGlobal();
var dbg = Debugger(g);
dbg.onDebuggerStatement = function (frame) {
let env = frame.environment;
assertEq(env.getVariable('a'), 1);
assertEq(env.getVariable('b'), 2);
assertEq(env.getVariable('c'), 3);
assertEq(env.getVariable('d'), 4);
assertEq(env.getVariable('e'), 5);
};
g.eval(
`
let moduleRepo = {};
setModuleResolveHook(function(module, specifier) {
if (specifier in moduleRepo)
return moduleRepo[specifier];
throw "Module '" + specifier + "' not found";
});
let m = parseModule(
\`
var a = 1;
let b = 2;
export var c = 3;
export let d = 4;
let e = 5;
function f() { return e; }
debugger;
\`);
m.declarationInstantiation();
m.evaluation();
`);
@@ -78,6 +78,12 @@ program([
]).assert(parseAsModule("export {}"));
program([
letDeclaration([
{
id: ident("a"),
init: lit(1)
}
]),
exportDeclaration(
null,
[
@@ -89,9 +95,15 @@ program([
null,
false
)
]).assert(parseAsModule("export { a }"));
]).assert(parseAsModule("let a = 1; export { a }"));
program([
letDeclaration([
{
id: ident("a"),
init: lit(1)
}
]),
exportDeclaration(
null,
[
@@ -103,9 +115,15 @@ program([
null,
false
)
]).assert(parseAsModule("export { a as b }"));
]).assert(parseAsModule("let a = 1; export { a as b }"));
program([
letDeclaration([
{
id: ident("as"),
init: lit(1)
}
]),
exportDeclaration(
null,
[
@@ -117,9 +135,15 @@ program([
null,
false
)
]).assert(parseAsModule("export { as as as }"));
]).assert(parseAsModule("let as = 1; export { as as as }"));
program([
letDeclaration([
{
id: ident("a"),
init: lit(1)
}
]),
exportDeclaration(
null,
[
@@ -131,9 +155,19 @@ program([
null,
false
)
]).assert(parseAsModule("export { a as true }"));
]).assert(parseAsModule("let a = 1; export { a as true }"));
program([
letDeclaration([
{
id: ident("a"),
init: lit(1)
},
{
id: ident("b"),
init: lit(2)
}
]),
exportDeclaration(
null,
[
@@ -149,9 +183,19 @@ program([
null,
false
)
]).assert(parseAsModule("export { a, b }"));
]).assert(parseAsModule("let a = 1, b = 2; export { a, b }"));
program([
letDeclaration([
{
id: ident("a"),
init: lit(1)
},
{
id: ident("c"),
init: lit(2)
}
]),
exportDeclaration(
null,
[
@@ -167,7 +211,7 @@ program([
null,
false
)
]).assert(parseAsModule("export { a as b, c as d }"));
]).assert(parseAsModule("let a = 1, c = 2; export { a as b, c as d }"));
program([
exportDeclaration(
@@ -0,0 +1,5 @@
// |jit-test| module
import c from "defaultClass.js";
let o = new c();
assertEq(o.triple(14), 42);
@@ -0,0 +1,4 @@
// |jit-test| module
import f from "defaultFunction.js";
assertEq(f(21), 42);
@@ -25,8 +25,17 @@ function testHasNames(names, expected) {
});
}
let a = moduleRepo['a'] = parseModule("export var a = 1; export var b = 2;");
let b = moduleRepo['b'] = parseModule("import * as ns from 'a'; var x = ns.a + ns.b;");
let a = moduleRepo['a'] = parseModule(
`export var a = 1;
export var b = 2;`
);
let b = moduleRepo['b'] = parseModule(
`import * as ns from 'a';
export { ns };
export var x = ns.a + ns.b;`
);
b.declarationInstantiation();
b.evaluation();
testHasNames(getModuleEnvironmentNames(b), ["ns", "x"]);
@@ -4,7 +4,7 @@ const defaultAsyncStackLimit = 60;
function recur(n, limit) {
if (n > 0) {
return callFunctionWithAsyncStack(recur.bind(undefined, n - 1, limit),
return callFunctionWithAsyncStack(function recur() {return recur(n - 1, limit)},
saveStack(limit), "Recurse");
}
return saveStack(limit);
@@ -141,13 +141,15 @@ function v() {
{ name: "u", asyncCause: "UtoV" },
]);
let xToCall = x.bind(undefined, saveStack(0, low));
let stack = saveStack(0, low);
function xToCall() { return x(stack);};
let stackX = callFunctionWithAsyncStack(xToCall, saveStack(), "VtoX");
print("high.checkVisibleStack(stackX)");
checkVisibleStack(stackX, [
{ name: "x", asyncCause: null },
{ name: "xToCall", asyncCause: null },
{ name: "v", asyncCause: "VtoX" },
{ name: "u", asyncCause: "UtoV" },
]);
@@ -187,6 +189,7 @@ function x(stackV) {
return saveStack(0, high);
}
function y() {
let stackY = saveStack();
+4 -1
View File
@@ -260,8 +260,11 @@ jit::ExceptionHandlerBailout(JSContext* cx, const InlineFrameIterator& frame,
bool
jit::EnsureHasScopeObjects(JSContext* cx, AbstractFramePtr fp)
{
// Ion does not compile eval scripts.
MOZ_ASSERT(!fp.isEvalFrame());
if (fp.isFunctionFrame() &&
fp.fun()->needsCallObject() &&
fp.callee()->needsCallObject() &&
!fp.hasCallObj())
{
return fp.initFunctionScopeObjects(cx);
+1 -1
View File
@@ -1721,7 +1721,7 @@ CopyFromRematerializedFrame(JSContext* cx, JitActivation* act, uint8_t* fp, size
frame->setScopeChain(rematFrame->scopeChain());
if (frame->isNonEvalFunctionFrame())
if (frame->isFunctionFrame())
frame->thisArgument() = rematFrame->thisArgument();
for (unsigned i = 0; i < frame->numActualArgs(); i++)
+1 -7
View File
@@ -356,13 +356,7 @@ BaselineCompiler::emitPrologue()
// is passed in R1, so we have to be careful not to clobber it.
// Initialize BaselineFrame::flags.
uint32_t flags = 0;
if (script->isForEval())
flags |= BaselineFrame::EVAL;
masm.store32(Imm32(flags), frame.addressOfFlags());
if (script->isForEval())
masm.storePtr(ImmGCPtr(script), frame.addressOfEvalScript());
masm.store32(Imm32(0), frame.addressOfFlags());
// Handle scope chain pre-initialization (in case GC gets run
// during stack check). For global and eval scripts, the scope
+1 -1
View File
@@ -89,7 +89,7 @@ inline CallObject&
BaselineFrame::callObj() const
{
MOZ_ASSERT(hasCallObj());
MOZ_ASSERT(fun()->needsCallObject());
MOZ_ASSERT(callee()->needsCallObject());
JSObject* obj = scopeChain();
while (!obj->is<CallObject>())
+5 -13
View File
@@ -33,7 +33,7 @@ BaselineFrame::trace(JSTracer* trc, JitFrameIterator& frameIterator)
replaceCalleeToken(MarkCalleeToken(trc, calleeToken()));
// Mark |this|, actual and formal args.
if (isNonEvalFunctionFrame()) {
if (isFunctionFrame()) {
TraceRoot(trc, &thisArgument(), "baseline-this");
unsigned numArgs = js::Max(numActualArgs(), numFormalArgs());
@@ -48,11 +48,8 @@ BaselineFrame::trace(JSTracer* trc, JitFrameIterator& frameIterator)
if (hasReturnValue())
TraceRoot(trc, returnValue().address(), "baseline-rval");
if (isEvalFrame()) {
TraceRoot(trc, &evalScript_, "baseline-evalscript");
if (isFunctionFrame())
TraceRoot(trc, evalNewTargetAddress(), "baseline-evalNewTarget");
}
if (isEvalFrame() && script()->isDirectEvalInFunction())
TraceRoot(trc, evalNewTargetAddress(), "baseline-evalNewTarget");
if (hasArgsObj())
TraceRoot(trc, &argsObj_, "baseline-args-obj");
@@ -126,8 +123,8 @@ BaselineFrame::initStrictEvalScopeObjects(JSContext* cx)
bool
BaselineFrame::initFunctionScopeObjects(JSContext* cx)
{
MOZ_ASSERT(isNonEvalFunctionFrame());
MOZ_ASSERT(fun()->needsCallObject());
MOZ_ASSERT(isFunctionFrame());
MOZ_ASSERT(callee()->needsCallObject());
CallObject* callobj = CallObject::createForFunction(cx, this);
if (!callobj)
@@ -148,11 +145,6 @@ BaselineFrame::initForOsr(InterpreterFrame* fp, uint32_t numStackValues)
if (fp->hasCallObjUnchecked())
flags_ |= BaselineFrame::HAS_CALL_OBJ;
if (fp->isEvalFrame()) {
flags_ |= BaselineFrame::EVAL;
evalScript_ = fp->script();
}
if (fp->script()->needsArgsObj() && fp->hasArgsObj()) {
flags_ |= BaselineFrame::HAS_ARGS_OBJ;
argsObj_ = &fp->argsObj();
+15 -43
View File
@@ -24,13 +24,6 @@ struct BaselineDebugModeOSRInfo;
// locals
// stack values
// Eval frames
//
// Like js::InterpreterFrame, every BaselineFrame is either a global frame
// or a function frame. Both global and function frames can optionally
// be "eval frames". The callee token for eval function frames is the
// enclosing function. BaselineFrame::evalScript_ stores the eval script
// itself.
class BaselineFrame
{
public:
@@ -53,8 +46,7 @@ class BaselineFrame
// invariants of debuggee compartments, scripts, and frames.
DEBUGGEE = 1 << 6,
// Eval frame, see the "eval frames" comment.
EVAL = 1 << 7,
// (1 << 7 and 1 << 8 are unused)
// Frame has over-recursed on an early check.
OVER_RECURSED = 1 << 9,
@@ -100,9 +92,7 @@ class BaselineFrame
uint32_t hiReturnValue_;
uint32_t frameSize_;
JSObject* scopeChain_; // Scope chain (always initialized).
JSScript* evalScript_; // If isEvalFrame(), the current eval script.
ArgumentsObject* argsObj_; // If HAS_ARGS_OBJ, the arguments object.
void* unused; // See static assertion re: sizeof, below.
uint32_t overrideOffset_; // If HAS_OVERRIDE_PC, the bytecode offset.
uint32_t flags_;
@@ -154,16 +144,8 @@ class BaselineFrame
return CalleeTokenIsConstructing(calleeToken());
}
JSScript* script() const {
if (isEvalFrame())
return evalScript();
return ScriptFromCalleeToken(calleeToken());
}
JSFunction* fun() const {
return CalleeTokenToFunction(calleeToken());
}
JSFunction* maybeFun() const {
return isFunctionFrame() ? fun() : nullptr;
}
JSFunction* callee() const {
return CalleeTokenToFunction(calleeToken());
}
@@ -212,7 +194,7 @@ class BaselineFrame
return script()->functionNonDelazifying()->nargs();
}
Value& thisArgument() const {
MOZ_ASSERT(isNonEvalFunctionFrame());
MOZ_ASSERT(isFunctionFrame());
return *(Value*)(reinterpret_cast<const uint8_t*>(this) +
BaselineFrame::Size() +
offsetOfThis());
@@ -226,7 +208,7 @@ class BaselineFrame
private:
Value* evalNewTargetAddress() const {
MOZ_ASSERT(isEvalFrame());
MOZ_ASSERT(isFunctionFrame());
MOZ_ASSERT(script()->isDirectEvalInFunction());
return (Value*)(reinterpret_cast<const uint8_t*>(this) +
BaselineFrame::Size() +
offsetOfEvalNewTarget());
@@ -234,15 +216,16 @@ class BaselineFrame
public:
Value newTarget() const {
MOZ_ASSERT(isFunctionFrame());
if (isEvalFrame())
return *evalNewTargetAddress();
if (fun()->isArrow())
return fun()->getExtendedSlot(FunctionExtended::ARROW_NEWTARGET_SLOT);
if (isConstructing())
MOZ_ASSERT(isFunctionFrame());
if (callee()->isArrow())
return callee()->getExtendedSlot(FunctionExtended::ARROW_NEWTARGET_SLOT);
if (isConstructing()) {
return *(Value*)(reinterpret_cast<const uint8_t*>(this) +
BaselineFrame::Size() +
offsetOfArg(Max(numFormalArgs(), numActualArgs())));
}
return UndefinedValue();
}
@@ -336,11 +319,6 @@ class BaselineFrame
flags_ |= HAS_CACHED_SAVED_FRAME;
}
JSScript* evalScript() const {
MOZ_ASSERT(isEvalFrame());
return evalScript_;
}
bool overRecursed() const {
return flags_ & OVER_RECURSED;
}
@@ -394,17 +372,14 @@ class BaselineFrame
void trace(JSTracer* trc, JitFrameIterator& frame);
bool isFunctionFrame() const {
return CalleeTokenIsFunction(calleeToken());
bool isGlobalFrame() const {
return script()->isGlobalCode();
}
bool isModuleFrame() const {
return CalleeTokenIsModuleScript(calleeToken());
return script()->module();
}
bool isGlobalFrame() const {
return !isFunctionFrame() && !isModuleFrame();
}
bool isEvalFrame() const {
return flags_ & EVAL;
bool isEvalFrame() const {
return script()->isForEval();
}
bool isStrictEvalFrame() const {
return isEvalFrame() && script()->strict();
@@ -416,8 +391,8 @@ class BaselineFrame
bool isNonStrictDirectEvalFrame() const {
return isNonStrictEvalFrame() && isNonGlobalEvalFrame();
}
bool isNonEvalFunctionFrame() const {
return isFunctionFrame() && !isEvalFrame();
bool isFunctionFrame() const {
return CalleeTokenIsFunction(calleeToken());
}
bool isDebuggerEvalFrame() const {
return false;
@@ -466,9 +441,6 @@ class BaselineFrame
static int reverseOffsetOfFlags() {
return -int(Size()) + offsetof(BaselineFrame, flags_);
}
static int reverseOffsetOfEvalScript() {
return -int(Size()) + offsetof(BaselineFrame, evalScript_);
}
static int reverseOffsetOfReturnValue() {
return -int(Size()) + offsetof(BaselineFrame, loReturnValue_);
}
-3
View File
@@ -280,9 +280,6 @@ class FrameInfo
Address addressOfFlags() const {
return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFlags());
}
Address addressOfEvalScript() const {
return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfEvalScript());
}
Address addressOfReturnValue() const {
return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfReturnValue());
}
+4 -3
View File
@@ -5701,6 +5701,7 @@ GetTemplateObjectForNative(JSContext* cx, Native native, const CallArgs& args,
}
if (JitSupportsSimd()) {
RootedGlobalObject global(cx, cx->global());
#define ADD_INT32X4_SIMD_OP_NAME_(OP) || native == js::simd_int32x4_##OP
#define ADD_BOOL32X4_SIMD_OP_NAME_(OP) || native == js::simd_bool32x4_##OP
#define ADD_FLOAT32X4_SIMD_OP_NAME_(OP) || native == js::simd_float32x4_##OP
@@ -5713,7 +5714,7 @@ GetTemplateObjectForNative(JSContext* cx, Native native, const CallArgs& args,
ADD_INT32X4_SIMD_OP_NAME_(fromFloat32x4)
ADD_INT32X4_SIMD_OP_NAME_(fromFloat32x4Bits))
{
Rooted<SimdTypeDescr*> descr(cx, cx->global()->getOrCreateSimdTypeDescr<Int32x4>(cx));
Rooted<SimdTypeDescr*> descr(cx, GlobalObject::getOrCreateSimdTypeDescr<Int32x4>(cx, global));
res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr));
return !!res;
}
@@ -5724,7 +5725,7 @@ GetTemplateObjectForNative(JSContext* cx, Native native, const CallArgs& args,
FOREACH_COMP_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_)
FOREACH_COMP_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_))
{
Rooted<SimdTypeDescr*> descr(cx, cx->global()->getOrCreateSimdTypeDescr<Bool32x4>(cx));
Rooted<SimdTypeDescr*> descr(cx, GlobalObject::getOrCreateSimdTypeDescr<Bool32x4>(cx, global));
res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr));
return !!res;
}
@@ -5736,7 +5737,7 @@ GetTemplateObjectForNative(JSContext* cx, Native native, const CallArgs& args,
ADD_FLOAT32X4_SIMD_OP_NAME_(fromInt32x4Bits)
ION_COMMONX4_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_))
{
Rooted<SimdTypeDescr*> descr(cx, cx->global()->getOrCreateSimdTypeDescr<Float32x4>(cx));
Rooted<SimdTypeDescr*> descr(cx, GlobalObject::getOrCreateSimdTypeDescr<Float32x4>(cx, global));
res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr));
return !!res;
}
+5 -11
View File
@@ -84,7 +84,7 @@ CheckFrame(InterpreterFrame* fp)
return false;
}
if (fp->isNonEvalFunctionFrame() && fp->numActualArgs() > BASELINE_MAX_ARGS_LENGTH) {
if (fp->isFunctionFrame() && fp->numActualArgs() > BASELINE_MAX_ARGS_LENGTH) {
// Fall back to the interpreter to avoid running out of stack space.
JitSpew(JitSpew_BaselineAbort, "Too many arguments (%u)", fp->numActualArgs());
return false;
@@ -201,7 +201,7 @@ jit::EnterBaselineAtBranch(JSContext* cx, InterpreterFrame* fp, jsbytecode* pc)
AutoValueVector vals(cx);
RootedValue thisv(cx);
if (fp->isNonEvalFunctionFrame()) {
if (fp->isFunctionFrame()) {
data.constructing = fp->isConstructing();
data.numActualArgs = fp->numActualArgs();
data.maxArgc = Max(fp->numActualArgs(), fp->numFormalArgs()) + 1; // +1 = include |this|
@@ -216,11 +216,7 @@ jit::EnterBaselineAtBranch(JSContext* cx, InterpreterFrame* fp, jsbytecode* pc)
data.maxArgv = thisv.address();
data.scopeChain = fp->scopeChain();
// For eval function frames, set the callee token to the enclosing function.
if (fp->isFunctionFrame())
data.calleeToken = CalleeToToken(&fp->callee(), /* constructing = */ false);
else
data.calleeToken = CalleeToToken(fp->script());
data.calleeToken = CalleeToToken(fp->script());
if (fp->isEvalFrame()) {
if (!vals.reserve(2))
@@ -228,7 +224,7 @@ jit::EnterBaselineAtBranch(JSContext* cx, InterpreterFrame* fp, jsbytecode* pc)
vals.infallibleAppend(thisv);
if (fp->isFunctionFrame())
if (fp->script()->isDirectEvalInFunction())
vals.infallibleAppend(fp->newTarget());
else
vals.infallibleAppend(NullValue());
@@ -371,9 +367,7 @@ jit::CanEnterBaselineMethod(JSContext* cx, RunState& state)
return Method_Error;
}
} else {
MOZ_ASSERT(state.isExecute());
ExecuteType type = state.asExecute()->type();
if (type == EXECUTE_DEBUG) {
if (state.asExecute()->isDebuggerEval()) {
JitSpew(JitSpew_BaselineAbort, "debugger frame");
return Method_CantCompile;
}
+1 -1
View File
@@ -1985,7 +1985,7 @@ CodeGenerator::visitLambda(LLambda* lir)
emitLambdaInit(output, scopeChain, info);
if (info.flags & JSFunction::EXTENDED) {
MOZ_ASSERT(info.fun->allowSuperProperty());
MOZ_ASSERT(info.fun->allowSuperProperty() || info.fun->isSelfHostedBuiltin());
static_assert(FunctionExtended::NUM_EXTENDED_SLOTS == 2, "All slots must be initialized");
masm.storeValue(UndefinedValue(), Address(output, FunctionExtended::offsetOfExtendedSlot(0)));
masm.storeValue(UndefinedValue(), Address(output, FunctionExtended::offsetOfExtendedSlot(1)));
-2
View File
@@ -78,8 +78,6 @@
\
_(ObjectCreate) \
\
_(CallBoundFunction) \
\
_(SimdInt32x4) \
_(SimdFloat32x4) \
_(SimdBool32x4) \
+10 -18
View File
@@ -2307,6 +2307,7 @@ CheckFrame(JSContext* cx, BaselineFrame* frame)
{
MOZ_ASSERT(!frame->script()->isGenerator());
MOZ_ASSERT(!frame->isDebuggerEvalFrame());
MOZ_ASSERT(!frame->isEvalFrame());
// This check is to not overrun the stack.
if (frame->isFunctionFrame()) {
@@ -2639,9 +2640,9 @@ MethodStatus
jit::CompileFunctionForBaseline(JSContext* cx, HandleScript script, BaselineFrame* frame)
{
MOZ_ASSERT(jit::IsIonEnabled(cx));
MOZ_ASSERT(frame->fun()->nonLazyScript()->canIonCompile());
MOZ_ASSERT(!frame->fun()->nonLazyScript()->isIonCompilingOffThread());
MOZ_ASSERT(!frame->fun()->nonLazyScript()->hasIonScript());
MOZ_ASSERT(frame->callee()->nonLazyScript()->canIonCompile());
MOZ_ASSERT(!frame->callee()->nonLazyScript()->isIonCompilingOffThread());
MOZ_ASSERT(!frame->callee()->nonLazyScript()->hasIonScript());
MOZ_ASSERT(frame->isFunctionFrame());
// Mark as forbidden if frame can't be handled.
@@ -2791,27 +2792,18 @@ jit::SetEnterJitData(JSContext* cx, EnterJitData& data, RunState& state, AutoVal
data.calleeToken = CalleeToToken(state.script());
if (state.script()->isForEval() &&
!(state.asExecute()->type() & InterpreterFrame::GLOBAL))
{
ScriptFrameIter iter(cx);
if (iter.isFunctionFrame())
data.calleeToken = CalleeToToken(iter.callee(cx), /* constructing = */ false);
if (state.script()->isForEval() && state.script()->isDirectEvalInFunction()) {
// Push newTarget onto the stack.
if (!vals.reserve(1))
return false;
ScriptFrameIter iter(cx);
data.maxArgc = 1;
data.maxArgv = vals.begin();
if (iter.isFunctionFrame()) {
if (state.asExecute()->newTarget().isNull())
vals.infallibleAppend(iter.newTarget());
else
vals.infallibleAppend(state.asExecute()->newTarget());
} else {
vals.infallibleAppend(NullValue());
}
if (state.asExecute()->newTarget().isNull())
vals.infallibleAppend(iter.newTarget());
else
vals.infallibleAppend(state.asExecute()->newTarget());
}
}
+12 -5
View File
@@ -75,7 +75,7 @@ jit::NewBaselineFrameInspector(TempAllocator* temp, BaselineFrame* frame, Compil
// during compilation could capture nursery pointers, so the values' types
// are recorded instead.
if (frame->isNonEvalFunctionFrame())
if (frame->isFunctionFrame())
inspector->thisType = TypeSet::GetMaybeUntrackedValueType(frame->thisArgument());
if (frame->scopeChain()->isSingleton())
@@ -6278,6 +6278,9 @@ IonBuilder::createThis(JSFunction* target, MDefinition* callee, MDefinition* new
return magic;
}
if (target->isBoundFunction())
return constant(MagicValue(JS_UNINITIALIZED_LEXICAL));
if (target->isDerivedClassConstructor()) {
MOZ_ASSERT(target->isClassConstructor());
return constant(MagicValue(JS_UNINITIALIZED_LEXICAL));
@@ -8381,9 +8384,11 @@ IonBuilder::jsop_intrinsic(PropertyName* name)
{
TemporaryTypeSet* types = bytecodeTypes(pc);
// If we haven't executed this opcode yet, we need to get the intrinsic
// value and monitor the result.
if (types->empty()) {
Value vp = script()->global().maybeExistingIntrinsicValue(name);
// If the intrinsic value doesn't yet exist, we haven't executed this
// opcode yet, so we need to get it and monitor the result.
if (vp.isUndefined()) {
MCallGetIntrinsicValue* ins = MCallGetIntrinsicValue::New(alloc(), name);
current->add(ins);
@@ -8395,10 +8400,12 @@ IonBuilder::jsop_intrinsic(PropertyName* name)
return pushTypeBarrier(ins, types, BarrierKind::TypeSet);
}
if (types->empty())
types->addType(TypeSet::GetValueType(vp), alloc().lifoAlloc());
// Bake in the intrinsic, guaranteed to exist because a non-empty typeset
// means the intrinsic was successfully gotten in the VM call above.
// Assert that TI agrees with us on the type.
Value vp = script()->global().existingIntrinsicValue(name);
MOZ_ASSERT(types->hasType(TypeSet::GetValueType(vp)));
pushConstant(vp);
+1 -9
View File
@@ -2966,15 +2966,7 @@ JitProfilingFrameIterator::JitProfilingFrameIterator(
return;
}
// In some rare cases (e.g. baseline eval frame), the callee script may
// not have a baselineScript. Treat this is an empty frame-sequence and
// move on.
if (!frameScript()->hasBaselineScript()) {
type_ = JitFrame_Entry;
fp_ = nullptr;
returnAddressToFp_ = nullptr;
return;
}
MOZ_ASSERT(frameScript()->hasBaselineScript());
// If nothing matches, for now just assume we are at the start of the last frame's
// baseline jit code.
-71
View File
@@ -199,10 +199,6 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target)
case InlinableNative::ObjectCreate:
return inlineObjectCreate(callInfo);
// Bound function.
case InlinableNative::CallBoundFunction:
return inlineBoundFunction(callInfo, target);
// SIMD natives.
case InlinableNative::SimdInt32x4:
return inlineSimdInt32x4(callInfo, target->native());
@@ -2667,73 +2663,6 @@ IonBuilder::inlineAssertRecoveredOnBailout(CallInfo& callInfo)
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineBoundFunction(CallInfo& nativeCallInfo, JSFunction* target)
{
trackOptimizationOutcome(TrackedOutcome::CantInlineBound);
if (!target->getBoundFunctionTarget()->is<JSFunction>())
return InliningStatus_NotInlined;
JSFunction* scriptedTarget = &(target->getBoundFunctionTarget()->as<JSFunction>());
// Don't optimize if we're constructing and the callee is not a
// constructor, so that CallKnown does not have to handle this case
// (it should always throw).
if (nativeCallInfo.constructing() && !scriptedTarget->isConstructor())
return InliningStatus_NotInlined;
if (nativeCallInfo.constructing() && nativeCallInfo.getNewTarget() != nativeCallInfo.fun())
return InliningStatus_NotInlined;
if (gc::IsInsideNursery(scriptedTarget))
return InliningStatus_NotInlined;
for (size_t i = 0; i < target->getBoundFunctionArgumentCount(); i++) {
const Value val = target->getBoundFunctionArgument(i);
if (val.isObject() && gc::IsInsideNursery(&val.toObject()))
return InliningStatus_NotInlined;
if (val.isString() && !val.toString()->isAtom())
return InliningStatus_NotInlined;
}
const Value thisVal = target->getBoundFunctionThis();
if (thisVal.isObject() && gc::IsInsideNursery(&thisVal.toObject()))
return InliningStatus_NotInlined;
if (thisVal.isString() && !thisVal.toString()->isAtom())
return InliningStatus_NotInlined;
size_t argc = target->getBoundFunctionArgumentCount() + nativeCallInfo.argc();
if (argc > ARGS_LENGTH_MAX)
return InliningStatus_NotInlined;
nativeCallInfo.thisArg()->setImplicitlyUsedUnchecked();
CallInfo callInfo(alloc(), nativeCallInfo.constructing());
callInfo.setFun(constant(ObjectValue(*scriptedTarget)));
callInfo.setThis(constant(thisVal));
if (!callInfo.argv().reserve(argc))
return InliningStatus_Error;
for (size_t i = 0; i < target->getBoundFunctionArgumentCount(); i++) {
MConstant* argConst = constant(target->getBoundFunctionArgument(i));
callInfo.argv().infallibleAppend(argConst);
}
for (size_t i = 0; i < nativeCallInfo.argc(); i++)
callInfo.argv().infallibleAppend(nativeCallInfo.getArg(i));
// We only inline when it was not a super-call, so just set the newTarget
// to be the target function, per spec.
if (nativeCallInfo.constructing())
callInfo.setNewTarget(callInfo.fun());
if (!makeCall(scriptedTarget, callInfo))
return InliningStatus_Error;
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineAtomicsCompareExchange(CallInfo& callInfo)
{
+2 -2
View File
@@ -142,8 +142,8 @@ RematerializedFrame::pushOnScopeChain(ScopeObject& scope)
bool
RematerializedFrame::initFunctionScopeObjects(JSContext* cx)
{
MOZ_ASSERT(isNonEvalFunctionFrame());
MOZ_ASSERT(fun()->needsCallObject());
MOZ_ASSERT(isFunctionFrame());
MOZ_ASSERT(callee()->needsCallObject());
CallObject* callobj = CallObject::createForFunction(cx, this);
if (!callobj)
return false;
+5 -16
View File
@@ -124,7 +124,7 @@ class RematerializedFrame
bool initFunctionScopeObjects(JSContext* cx);
bool hasCallObj() const {
MOZ_ASSERT(fun()->needsCallObject());
MOZ_ASSERT(callee()->needsCallObject());
return hasCallObj_;
}
CallObject& callObj() const;
@@ -141,27 +141,16 @@ class RematerializedFrame
bool isFunctionFrame() const {
return !!script_->functionNonDelazifying();
}
bool isModuleFrame() const {
return !!script_->module();
}
bool isGlobalFrame() const {
return !isFunctionFrame() && !isModuleFrame();
return script_->isGlobalCode();
}
bool isNonEvalFunctionFrame() const {
// Ion doesn't support eval frames.
return isFunctionFrame();
bool isModuleFrame() const {
return script_->module();
}
JSScript* script() const {
return script_;
}
JSFunction* fun() const {
MOZ_ASSERT(isFunctionFrame());
return script_->functionNonDelazifying();
}
JSFunction* maybeFun() const {
return isFunctionFrame() ? fun() : nullptr;
}
JSFunction* callee() const {
MOZ_ASSERT(isFunctionFrame());
return callee_;
@@ -186,7 +175,7 @@ class RematerializedFrame
}
unsigned numFormalArgs() const {
return maybeFun() ? fun()->nargs() : 0;
return isFunctionFrame() ? callee()->nargs() : 0;
}
unsigned numActualArgs() const {
return numActualArgs_;
+1 -1
View File
@@ -4739,7 +4739,7 @@ DoTypeMonitorFallback(JSContext* cx, BaselineFrame* frame, ICTypeMonitor_Fallbac
// In derived class constructors (including nested arrows/eval), the
// |this| argument or GETALIASEDVAR can return the magic TDZ value.
MOZ_ASSERT(value.isMagic(JS_UNINITIALIZED_LEXICAL));
MOZ_ASSERT(frame->isFunctionFrame());
MOZ_ASSERT(frame->isFunctionFrame() || frame->isEvalFrame());
MOZ_ASSERT(stub->monitorsThis() ||
*GetNextPc(pc) == JSOP_CHECKTHIS ||
*GetNextPc(pc) == JSOP_CHECKRETURN);
+3 -3
View File
@@ -569,12 +569,12 @@ CreateThis(JSContext* cx, HandleObject callee, HandleObject newTarget, MutableHa
rval.set(MagicValue(JS_IS_CONSTRUCTING));
if (callee->is<JSFunction>()) {
JSFunction* fun = &callee->as<JSFunction>();
RootedFunction fun(cx, &callee->as<JSFunction>());
if (fun->isInterpreted() && fun->isConstructor()) {
JSScript* script = fun->getOrCreateScript(cx);
if (!script || !script->ensureHasTypes(cx))
return false;
if (script->isDerivedClassConstructor()) {
if (fun->isBoundFunction() || script->isDerivedClassConstructor()) {
rval.set(MagicValue(JS_UNINITIALIZED_LEXICAL));
} else {
JSObject* thisObj = CreateThisForFunction(cx, callee, newTarget, GenericObject);
@@ -712,7 +712,7 @@ DebugEpilogue(JSContext* cx, BaselineFrame* frame, jsbytecode* pc, bool ok)
JSScript* script = frame->script();
frame->setOverridePc(script->lastPC());
if (frame->isNonEvalFunctionFrame()) {
if (frame->isFunctionFrame()) {
MOZ_ASSERT_IF(ok, frame->hasReturnValue());
DebugScopes::onPopCall(frame, cx);
} else if (frame->isStrictEvalFrame()) {
+1
View File
@@ -4253,6 +4253,7 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
}
fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL, funAtom,
/* proto = */ nullptr,
gc::AllocKind::FUNCTION, TenuredObject,
enclosingDynamicScope));
if (!fun)
+21 -1
View File
@@ -2187,7 +2187,8 @@ class JS_PUBLIC_API(CompartmentCreationOptions)
invisibleToDebugger_(false),
mergeable_(false),
preserveJitCode_(false),
cloneSingletons_(false)
cloneSingletons_(false),
experimentalDateTimeFormatFormatToPartsEnabled_(false)
{
zone_.spec = JS::FreshZone;
}
@@ -2250,6 +2251,24 @@ class JS_PUBLIC_API(CompartmentCreationOptions)
return *this;
}
// ECMA-402 is considering adding a "formatToParts" DateTimeFormat method,
// that exposes not just a formatted string but its ordered subcomponents.
// The method, its semantics, and its name are all well short of being
// finalized, so for now it's exposed *only* if requested.
//
// Until "formatToParts" is included in a final specification edition, it's
// subject to change or removal at any time. Do *not* rely on it in
// mission-critical code that can't be changed if ECMA-402 decides not to
// accept the method in its current form.
bool experimentalDateTimeFormatFormatToPartsEnabled() const {
return experimentalDateTimeFormatFormatToPartsEnabled_;
}
CompartmentCreationOptions& setExperimentalDateTimeFormatFormatToPartsEnabled(bool flag) {
experimentalDateTimeFormatFormatToPartsEnabled_ = flag;
return *this;
}
private:
JSAddonId* addonId_;
JSTraceOp traceGlobal_;
@@ -2261,6 +2280,7 @@ class JS_PUBLIC_API(CompartmentCreationOptions)
bool mergeable_;
bool preserveJitCode_;
bool cloneSingletons_;
bool experimentalDateTimeFormatFormatToPartsEnabled_;
};
/**
-1
View File
@@ -294,7 +294,6 @@ CallJSNativeConstructor(JSContext* cx, Native native, const CallArgs& args)
* - (new Object(Object)) returns the callee.
*/
MOZ_ASSERT_IF(native != js::proxy_Construct &&
native != js::CallOrConstructBoundFunction &&
native != js::IteratorConstructor &&
(!callee->is<JSFunction>() || callee->as<JSFunction>().native() != obj_construct),
args.rval().isObject() && callee != &args.rval().toObject());
+6 -1
View File
@@ -394,6 +394,11 @@ JS_FRIEND_API(JSFunction*)
js::GetOutermostEnclosingFunctionOfScriptedCaller(JSContext* cx)
{
ScriptFrameIter iter(cx);
// Skip eval frames.
while (!iter.done() && iter.isEvalFrame())
++iter;
if (iter.done())
return nullptr;
@@ -715,7 +720,7 @@ FormatFrame(JSContext* cx, const ScriptFrameIter& iter, char* buf, int num,
RootedValue thisVal(cx);
if (iter.hasUsableAbstractFramePtr() &&
iter.isNonEvalFunctionFrame() &&
iter.isFunctionFrame() &&
fun && !fun->isArrow() && !fun->isDerivedClassConstructor())
{
if (!GetFunctionThis(cx, iter.abstractFramePtr(), &thisVal))
+82 -247
View File
@@ -29,6 +29,7 @@
#include "builtin/Eval.h"
#include "builtin/Object.h"
#include "builtin/SelfHostingDefines.h"
#include "frontend/BytecodeCompiler.h"
#include "frontend/TokenStream.h"
#include "gc/Marking.h"
@@ -93,10 +94,9 @@ static bool
AdvanceToActiveCallLinear(JSContext* cx, NonBuiltinScriptFrameIter& iter, HandleFunction fun)
{
MOZ_ASSERT(!fun->isBuiltin());
MOZ_ASSERT(!fun->isBoundFunction(), "all bound functions are currently native (ergo builtin)");
for (; !iter.done(); ++iter) {
if (!iter.isFunctionFrame() || iter.isEvalFrame())
if (!iter.isFunctionFrame())
continue;
if (iter.matchCallee(cx, fun))
return true;
@@ -252,6 +252,9 @@ CallerGetterImpl(JSContext* cx, const CallArgs& args)
}
++iter;
while (!iter.done() && iter.isEvalFrame())
++iter;
if (iter.done() || !iter.isFunctionFrame()) {
args.rval().setNull();
return true;
@@ -318,6 +321,9 @@ CallerSetterImpl(JSContext* cx, const CallArgs& args)
return true;
++iter;
while (!iter.done() && iter.isEvalFrame())
++iter;
if (iter.done() || !iter.isFunctionFrame())
return true;
@@ -362,7 +368,6 @@ static bool
ResolveInterpretedFunctionPrototype(JSContext* cx, HandleFunction fun, HandleId id)
{
MOZ_ASSERT(fun->isInterpreted() || fun->isAsmJSNative());
MOZ_ASSERT(!fun->isFunctionPrototype());
MOZ_ASSERT(id == NameToId(cx->names().prototype));
// Assert that fun is not a compiler-created function object, which
@@ -478,11 +483,18 @@ fun_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
if (fun->hasResolvedLength())
return true;
uint16_t length;
if (!fun->getLength(cx, &length))
return false;
// Bound functions' length can have values up to MAX_SAFE_INTEGER,
// so they're handled differently from other functions.
if (fun->isBoundFunction()) {
MOZ_ASSERT(fun->getExtendedSlot(BOUND_FUN_LENGTH_SLOT).isNumber());
v.set(fun->getExtendedSlot(BOUND_FUN_LENGTH_SLOT));
} else {
uint16_t length;
if (!fun->getLength(cx, &length))
return false;
v.setInt32(length);
v.setInt32(length);
}
} else {
if (fun->hasResolvedName())
return true;
@@ -839,7 +851,6 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key)
return nullptr;
RootedFunction functionProto(cx, &functionProto_->as<JSFunction>());
functionProto->setIsFunctionPrototype();
const char* rawSource = "() {\n}";
size_t sourceLen = strlen(rawSource);
@@ -1169,7 +1180,8 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
} else {
MOZ_ASSERT(!fun->isExprBody());
if (fun->isNative() && fun->native() == js::DefaultDerivedClassConstructor) {
bool derived = fun->infallibleIsDefaultClassConstructor(cx);
if (derived && fun->isDerivedClassConstructor()) {
if (!out.append("(...args) {\n ") ||
!out.append("super(...args);\n}"))
{
@@ -1179,7 +1191,7 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
if (!out.append("() {\n "))
return nullptr;
if (!fun->isNative() || fun->native() != js::DefaultClassConstructor) {
if (!derived) {
if (!out.append("[native code]"))
return nullptr;
}
@@ -1369,74 +1381,83 @@ js::fun_apply(JSContext* cx, unsigned argc, Value* vp)
return true;
}
static const uint32_t JSSLOT_BOUND_FUNCTION_TARGET = 0;
static const uint32_t JSSLOT_BOUND_FUNCTION_THIS = 1;
static const uint32_t JSSLOT_BOUND_FUNCTION_ARGS_COUNT = 2;
static const uint32_t BOUND_FUNCTION_RESERVED_SLOTS = 3;
inline bool
JSFunction::initBoundFunction(JSContext* cx, HandleObject target, HandleValue thisArg,
const Value* args, unsigned argslen)
bool
JSFunction::infallibleIsDefaultClassConstructor(JSContext* cx) const
{
RootedFunction self(cx, this);
/*
* Convert to a dictionary to set the BOUND_FUNCTION flag and increase
* the slot span to cover the arguments and additional slots for the 'this'
* value and arguments count.
*/
if (!self->toDictionaryMode(cx))
if (!isSelfHostedBuiltin())
return false;
if (!self->JSObject::setFlags(cx, BaseShape::BOUND_FUNCTION))
bool isDefault = false;
if (isInterpretedLazy()) {
JSAtom* name = &getExtendedSlot(LAZY_FUNCTION_NAME_SLOT).toString()->asAtom();
isDefault = name == cx->names().DefaultDerivedClassConstructor ||
name == cx->names().DefaultBaseClassConstructor;
} else {
isDefault = nonLazyScript()->isDefaultClassConstructor();
}
MOZ_ASSERT_IF(isDefault, isConstructor());
MOZ_ASSERT_IF(isDefault, isClassConstructor());
return isDefault;
}
bool
JSFunction::getLength(JSContext* cx, uint16_t* length)
{
JS::RootedFunction self(cx, this);
MOZ_ASSERT(!self->isBoundFunction());
if (self->isInterpretedLazy() && !self->getOrCreateScript(cx))
return false;
if (!self->setSlotSpan(cx, BOUND_FUNCTION_RESERVED_SLOTS + argslen))
return false;
self->setSlot(JSSLOT_BOUND_FUNCTION_TARGET, ObjectValue(*target));
self->setSlot(JSSLOT_BOUND_FUNCTION_THIS, thisArg);
self->setSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT, PrivateUint32Value(argslen));
self->initSlotRange(BOUND_FUNCTION_RESERVED_SLOTS, args, argslen);
self->setJitInfo(&jit::JitInfo_CallBoundFunction);
*length = self->hasScript() ? self->nonLazyScript()->funLength()
: (self->nargs() - self->hasRest());
return true;
}
static const js::Value&
BoundFunctionEnvironmentSlotValue(const JSFunction* fun, uint32_t slotIndex)
{
MOZ_ASSERT(fun->isBoundFunction());
MOZ_ASSERT(fun->environment()->is<CallObject>());
CallObject* callObject = &fun->environment()->as<CallObject>();
return callObject->getSlot(slotIndex);
}
JSObject*
JSFunction::getBoundFunctionTarget() const
{
MOZ_ASSERT(isBoundFunction());
return &getSlot(JSSLOT_BOUND_FUNCTION_TARGET).toObject();
js::Value targetVal = BoundFunctionEnvironmentSlotValue(this, JSSLOT_BOUND_FUNCTION_TARGET);
MOZ_ASSERT(IsCallable(targetVal));
return &targetVal.toObject();
}
const js::Value&
JSFunction::getBoundFunctionThis() const
{
MOZ_ASSERT(isBoundFunction());
return BoundFunctionEnvironmentSlotValue(this, JSSLOT_BOUND_FUNCTION_THIS);
}
return getSlot(JSSLOT_BOUND_FUNCTION_THIS);
static ArrayObject*
GetBoundFunctionArguments(const JSFunction* boundFun)
{
js::Value argsVal = BoundFunctionEnvironmentSlotValue(boundFun, JSSLOT_BOUND_FUNCTION_ARGS);
return &argsVal.toObject().as<ArrayObject>();
}
const js::Value&
JSFunction::getBoundFunctionArgument(unsigned which) const
JSFunction::getBoundFunctionArgument(JSContext* cx, unsigned which) const
{
MOZ_ASSERT(isBoundFunction());
MOZ_ASSERT(which < getBoundFunctionArgumentCount());
return getSlot(BOUND_FUNCTION_RESERVED_SLOTS + which);
RootedArrayObject boundArgs(cx, GetBoundFunctionArguments(this));
RootedValue res(cx);
return boundArgs->getDenseElement(which);
}
size_t
JSFunction::getBoundFunctionArgumentCount() const
{
MOZ_ASSERT(isBoundFunction());
return getSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT).toPrivateUint32();
return GetBoundFunctionArguments(this)->length();
}
/* static */ bool
@@ -1593,9 +1614,14 @@ JSFunction::maybeRelazify(JSRuntime* rt)
return;
// To delazify self-hosted builtins we need the name of the function
// to clone. This name is stored in the first extended slot.
if (isSelfHostedBuiltin() && !isExtended())
// to clone. This name is stored in the first extended slot. Since
// that slot is sometimes also used for other purposes, make sure it
// contains a string.
if (isSelfHostedBuiltin() &&
(!isExtended() || !getExtendedSlot(LAZY_FUNCTION_NAME_SLOT).isString()))
{
return;
}
JSScript* script = nonLazyScript();
@@ -1612,73 +1638,6 @@ JSFunction::maybeRelazify(JSRuntime* rt)
}
}
/* ES5 15.3.4.5.1 and 15.3.4.5.2. */
bool
js::CallOrConstructBoundFunction(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedFunction fun(cx, &args.callee().as<JSFunction>());
MOZ_ASSERT(fun->isBoundFunction());
/* 15.3.4.5.1 step 1, 15.3.4.5.2 step 3. */
unsigned boundArgsLen = fun->getBoundFunctionArgumentCount();
uint32_t argsLen = args.length();
if (argsLen + boundArgsLen > ARGS_LENGTH_MAX) {
ReportAllocationOverflow(cx);
return false;
}
/* 15.3.4.5.1 step 3, 15.3.4.5.2 step 1. */
RootedObject target(cx, fun->getBoundFunctionTarget());
/* 15.3.4.5.1 step 2. */
const Value& boundThis = fun->getBoundFunctionThis();
if (args.isConstructing()) {
ConstructArgs cargs(cx);
if (!cargs.init(argsLen + boundArgsLen))
return false;
/* 15.3.4.5.1, 15.3.4.5.2 step 4. */
for (uint32_t i = 0; i < boundArgsLen; i++)
cargs[i].set(fun->getBoundFunctionArgument(i));
for (uint32_t i = 0; i < argsLen; i++)
cargs[boundArgsLen + i].set(args[i]);
RootedValue targetv(cx, ObjectValue(*target));
/* ES6 9.4.1.2 step 5 */
RootedValue newTarget(cx);
if (&args.newTarget().toObject() == fun)
newTarget.set(targetv);
else
newTarget.set(args.newTarget());
return Construct(cx, targetv, cargs, newTarget, args.rval());
}
InvokeArgs invokeArgs(cx);
if (!invokeArgs.init(argsLen + boundArgsLen))
return false;
/* 15.3.4.5.1, 15.3.4.5.2 step 4. */
for (uint32_t i = 0; i < boundArgsLen; i++)
invokeArgs[i].set(fun->getBoundFunctionArgument(i));
for (uint32_t i = 0; i < argsLen; i++)
invokeArgs[boundArgsLen + i].set(args[i]);
/* 15.3.4.5.1, 15.3.4.5.2 step 5. */
invokeArgs.setCallee(ObjectValue(*target));
invokeArgs.setThis(boundThis);
if (!Invoke(cx, invokeArgs))
return false;
args.rval().set(invokeArgs.rval());
return true;
}
static bool
fun_isGenerator(JSContext* cx, unsigned argc, Value* vp)
{
@@ -1693,132 +1652,6 @@ fun_isGenerator(JSContext* cx, unsigned argc, Value* vp)
return true;
}
static JSFunction*
NewNativeFunctionWithGivenProto(JSContext* cx, Native native, unsigned nargs,
HandleAtom atom, HandleObject proto)
{
return NewFunctionWithProto(cx, native, nargs, JSFunction::NATIVE_FUN, nullptr, atom, proto,
AllocKind::FUNCTION, GenericObject, NewFunctionGivenProto);
}
static JSFunction*
NewNativeConstructorWithGivenProto(JSContext* cx, Native native, unsigned nargs,
HandleAtom atom, HandleObject proto)
{
return NewFunctionWithProto(cx, native, nargs, JSFunction::NATIVE_CTOR, nullptr, atom, proto,
AllocKind::FUNCTION, GenericObject, NewFunctionGivenProto);
}
// ES6 draft rev32 19.2.3.2
bool
js::fun_bind(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
RootedValue thisv(cx, args.thisv());
// Step 2.
if (!IsCallable(thisv)) {
ReportIncompatibleMethod(cx, args, &JSFunction::class_);
return false;
}
// Step 3.
Value* boundArgs = nullptr;
unsigned argslen = 0;
if (args.length() > 1) {
boundArgs = args.array() + 1;
argslen = args.length() - 1;
}
RootedValue thisArg(cx, args.length() >= 1 ? args[0] : UndefinedValue());
RootedObject target(cx, &thisv.toObject());
// This is part of step 4, but we're delaying allocating the function object.
RootedObject proto(cx);
if (!GetPrototype(cx, target, &proto))
return false;
double length = 0.0;
// Try to avoid invoking the resolve hook.
if (target->is<JSFunction>() && !target->as<JSFunction>().hasResolvedLength()) {
uint16_t len;
if (!target->as<JSFunction>().getLength(cx, &len))
return false;
length = Max(0.0, double(len) - argslen);
} else {
// Steps 5-6.
RootedId id(cx, NameToId(cx->names().length));
bool hasLength;
if (!HasOwnProperty(cx, target, id, &hasLength))
return false;
// Step 7-8.
if (hasLength) {
// a-b.
RootedValue targetLen(cx);
if (!GetProperty(cx, target, target, id, &targetLen))
return false;
// d.
if (targetLen.isNumber())
length = Max(0.0, JS::ToInteger(targetLen.toNumber()) - argslen);
}
}
RootedString name(cx, cx->names().empty);
if (target->is<JSFunction>() && !target->as<JSFunction>().hasResolvedName()) {
if (target->as<JSFunction>().atom())
name = target->as<JSFunction>().atom();
} else {
// Steps 11-12.
RootedValue targetName(cx);
if (!GetProperty(cx, target, target, cx->names().name, &targetName))
return false;
// Step 13.
if (targetName.isString())
name = targetName.toString();
}
// Step 14. Relevant bits from SetFunctionName.
StringBuffer sb(cx);
// Disabled for B2G failures.
// if (!sb.append("bound ") || !sb.append(name))
// return false;
if (!sb.append(name))
return false;
RootedAtom nameAtom(cx, sb.finishAtom());
if (!nameAtom)
return false;
// Step 4.
RootedFunction fun(cx, target->isConstructor() ?
NewNativeConstructorWithGivenProto(cx, CallOrConstructBoundFunction, length, nameAtom, proto) :
NewNativeFunctionWithGivenProto(cx, CallOrConstructBoundFunction, length, nameAtom, proto));
if (!fun)
return false;
if (!fun->initBoundFunction(cx, target, thisArg, boundArgs, argslen))
return false;
// Steps 9-10. Set length again, because NewNativeFunction/NewNativeConstructor
// sometimes truncates.
if (length != fun->nargs()) {
RootedValue lengthVal(cx, NumberValue(length));
if (!DefineProperty(cx, fun, cx->names().length, lengthVal, nullptr, nullptr,
JSPROP_READONLY))
{
return false;
}
}
// Step 15.
args.rval().setObject(*fun);
return true;
}
/*
* Report "malformed formal parameter" iff no illegal char or similar scanner
* error was already reported.
@@ -1837,8 +1670,8 @@ const JSFunctionSpec js::function_methods[] = {
JS_FN(js_toString_str, fun_toString, 0,0),
JS_FN(js_apply_str, fun_apply, 2,0),
JS_FN(js_call_str, fun_call, 1,0),
JS_FN("bind", fun_bind, 1,0),
JS_FN("isGenerator", fun_isGenerator,0,0),
JS_SELF_HOSTED_FN("bind", "FunctionBind", 1,JSPROP_DEFINE_LATE),
JS_FS_END
};
@@ -2109,6 +1942,7 @@ js::NewNativeConstructor(ExclusiveContext* cx, Native native, unsigned nargs, Ha
JSFunction*
js::NewScriptedFunction(ExclusiveContext* cx, unsigned nargs,
JSFunction::Flags flags, HandleAtom atom,
HandleObject proto /* = nullptr */,
gc::AllocKind allocKind /* = AllocKind::FUNCTION */,
NewObjectKind newKind /* = GenericObject */,
HandleObject enclosingDynamicScopeArg /* = nullptr */)
@@ -2117,7 +1951,7 @@ js::NewScriptedFunction(ExclusiveContext* cx, unsigned nargs,
if (!enclosingDynamicScope)
enclosingDynamicScope = &cx->global()->lexicalScope();
return NewFunctionWithProto(cx, nullptr, nargs, flags, enclosingDynamicScope,
atom, nullptr, allocKind, newKind);
atom, proto, allocKind, newKind);
}
#ifdef DEBUG
@@ -2407,6 +2241,7 @@ js::DefineFunction(JSContext* cx, HandleObject obj, HandleId id, Native native,
if (!native)
fun = NewScriptedFunction(cx, nargs,
JSFunction::INTERPRETED_LAZY, atom,
/* proto = */ nullptr,
allocKind, GenericObject, obj);
else if (flags & JSFUN_CONSTRUCTOR)
fun = NewNativeConstructor(cx, native, nargs, atom, allocKind);
+27 -29
View File
@@ -28,6 +28,10 @@ typedef JSNative Native;
struct JSAtomState;
static const uint32_t JSSLOT_BOUND_FUNCTION_TARGET = 2;
static const uint32_t JSSLOT_BOUND_FUNCTION_THIS = 3;
static const uint32_t JSSLOT_BOUND_FUNCTION_ARGS = 4;
class JSFunction : public js::NativeObject
{
public:
@@ -48,7 +52,7 @@ class JSFunction : public js::NativeObject
INTERPRETED = 0x0001, /* function has a JSScript and environment. */
CONSTRUCTOR = 0x0002, /* function that can be called as a constructor */
EXTENDED = 0x0004, /* structure is FunctionExtended */
IS_FUN_PROTO = 0x0008, /* function is Function.prototype for some global object */
BOUND_FUN = 0x0008, /* function was created with Function.prototype.bind. */
EXPR_BODY = 0x0010, /* arrow function with expression body or
* expression closure: function(x) x*x */
HAS_GUESSED_ATOM = 0x0020, /* function had no explicit name, but a
@@ -93,8 +97,8 @@ class JSFunction : public js::NativeObject
INTERPRETED_GENERATOR = INTERPRETED,
NO_XDR_FLAGS = RESOLVED_LENGTH | RESOLVED_NAME,
STABLE_ACROSS_CLONES = IS_FUN_PROTO | CONSTRUCTOR | EXPR_BODY | HAS_GUESSED_ATOM |
LAMBDA | SELF_HOSTED | HAS_REST | FUNCTION_KIND_MASK
STABLE_ACROSS_CLONES = CONSTRUCTOR | EXPR_BODY | HAS_GUESSED_ATOM | LAMBDA |
SELF_HOSTED | HAS_REST | FUNCTION_KIND_MASK
};
static_assert((INTERPRETED | INTERPRETED_LAZY) == js::JS_FUNCTION_INTERPRETED_BITS,
@@ -183,15 +187,17 @@ class JSFunction : public js::NativeObject
bool isAsmJSNative() const { return kind() == AsmJS; }
/* Possible attributes of an interpreted function: */
bool isFunctionPrototype() const { return flags() & IS_FUN_PROTO; }
bool isExprBody() const { return flags() & EXPR_BODY; }
bool hasGuessedAtom() const { return flags() & HAS_GUESSED_ATOM; }
bool isLambda() const { return flags() & LAMBDA; }
bool isBoundFunction() const { return flags() & BOUND_FUN; }
bool hasRest() const { return flags() & HAS_REST; }
bool isInterpretedLazy() const { return flags() & INTERPRETED_LAZY; }
bool hasScript() const { return flags() & INTERPRETED; }
bool isBeingParsed() const { return flags() & BEING_PARSED; }
bool infallibleIsDefaultClassConstructor(JSContext* cx) const;
// Arrow functions store their lexical new.target in the first extended slot.
bool isArrow() const { return kind() == Arrow; }
// Every class-constructor is also a method.
@@ -255,6 +261,13 @@ class JSFunction : public js::NativeObject
flags_ |= CONSTRUCTOR;
}
void setIsClassConstructor() {
MOZ_ASSERT(!isClassConstructor());
MOZ_ASSERT(isConstructor());
setKind(ClassConstructor);
}
// Can be called multiple times by the parser.
void setArgCount(uint16_t nargs) {
this->nargs_ = nargs;
@@ -265,6 +278,11 @@ class JSFunction : public js::NativeObject
flags_ |= HAS_REST;
}
void setIsBoundFunction() {
MOZ_ASSERT(!isBoundFunction());
flags_ |= BOUND_FUN;
}
void setIsSelfHostedBuiltin() {
MOZ_ASSERT(isInterpreted());
MOZ_ASSERT(!isSelfHostedBuiltin());
@@ -278,11 +296,6 @@ class JSFunction : public js::NativeObject
flags_ |= SELF_HOSTED;
}
void setIsFunctionPrototype() {
MOZ_ASSERT(!isFunctionPrototype());
flags_ |= IS_FUN_PROTO;
}
// Can be called multiple times by the parser.
void setIsExprBody() {
flags_ |= EXPR_BODY;
@@ -453,15 +466,7 @@ class JSFunction : public js::NativeObject
return u.i.s.script_;
}
bool getLength(JSContext* cx, uint16_t* length) {
JS::RootedFunction self(cx, this);
if (self->isInterpretedLazy() && !self->getOrCreateScript(cx))
return false;
*length = self->hasScript() ? self->nonLazyScript()->funLength()
: (self->nargs() - self->hasRest());
return true;
}
bool getLength(JSContext* cx, uint16_t* length);
js::LazyScript* lazyScript() const {
MOZ_ASSERT(isInterpretedLazy() && u.i.s.lazy_);
@@ -571,12 +576,9 @@ class JSFunction : public js::NativeObject
/* Bound function accessors. */
inline bool initBoundFunction(JSContext* cx, js::HandleObject target, js::HandleValue thisArg,
const js::Value* args, unsigned argslen);
JSObject* getBoundFunctionTarget() const;
const js::Value& getBoundFunctionThis() const;
const js::Value& getBoundFunctionArgument(unsigned which) const;
const js::Value& getBoundFunctionArgument(JSContext* cx, unsigned which) const;
size_t getBoundFunctionArgumentCount() const;
private:
@@ -656,7 +658,8 @@ NewNativeConstructor(ExclusiveContext* cx, JSNative native, unsigned nargs, Hand
// the global.
extern JSFunction*
NewScriptedFunction(ExclusiveContext* cx, unsigned nargs, JSFunction::Flags flags,
HandleAtom atom, gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
HandleAtom atom, HandleObject proto = nullptr,
gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
NewObjectKind newKind = GenericObject,
HandleObject enclosingDynamicScope = nullptr);
@@ -692,9 +695,6 @@ FunctionHasResolveHook(const JSAtomState& atomState, jsid id);
extern bool
fun_toString(JSContext* cx, unsigned argc, Value* vp);
extern bool
fun_bind(JSContext* cx, unsigned argc, Value* vp);
struct WellKnownSymbols;
extern bool
@@ -839,10 +839,8 @@ ReportIncompatibleMethod(JSContext* cx, CallReceiver call, const Class* clasp);
extern void
ReportIncompatible(JSContext* cx, CallReceiver call);
bool
CallOrConstructBoundFunction(JSContext*, unsigned, js::Value*);
extern const JSFunctionSpec function_methods[];
extern const JSFunctionSpec function_selfhosted_methods[];
extern bool
fun_apply(JSContext* cx, unsigned argc, Value* vp);
+2 -2
View File
@@ -3606,7 +3606,7 @@ js::DumpInterpreterFrame(JSContext* cx, InterpreterFrame* start)
v.setObject(*fun);
dumpValue(v);
} else {
fprintf(stderr, "global frame, no callee");
fprintf(stderr, "global or eval frame, no callee");
}
fputc('\n', stderr);
@@ -3618,7 +3618,7 @@ js::DumpInterpreterFrame(JSContext* cx, InterpreterFrame* start)
fprintf(stderr, " current op: %s\n", CodeName[*pc]);
MaybeDumpObject("staticScope", i.script()->getStaticBlockScope(pc));
}
if (i.isNonEvalFunctionFrame())
if (i.isFunctionFrame())
MaybeDumpValue("this", i.thisArgument(cx));
if (!i.isJit()) {
fprintf(stderr, " rval: ");
+1 -1
View File
@@ -428,7 +428,7 @@ JSObject::nonProxyIsExtensible() const
inline bool
JSObject::isBoundFunction() const
{
return hasAllFlags(js::BaseShape::BOUND_FUNCTION);
return is<JSFunction>() && as<JSFunction>().isBoundFunction();
}
inline bool
+5 -13
View File
@@ -1020,14 +1020,12 @@ struct ExpressionDecompiler
{
JSContext* cx;
RootedScript script;
RootedFunction fun;
BytecodeParser parser;
Sprinter sprinter;
ExpressionDecompiler(JSContext* cx, JSScript* script, JSFunction* fun)
ExpressionDecompiler(JSContext* cx, JSScript* script)
: cx(cx),
script(cx, script),
fun(cx, fun),
parser(cx, script),
sprinter(cx)
{}
@@ -1259,7 +1257,7 @@ ExpressionDecompiler::loadAtom(jsbytecode* pc)
JSAtom*
ExpressionDecompiler::getArg(unsigned slot)
{
MOZ_ASSERT(fun);
MOZ_ASSERT(script->functionNonDelazifying());
MOZ_ASSERT(slot < script->bindings.numArgs());
for (BindingIter bi(script); bi; bi++) {
@@ -1405,9 +1403,6 @@ DecompileExpressionFromStack(JSContext* cx, int spindex, int skipStackHits, Hand
RootedScript script(cx, frameIter.script());
AutoCompartment ac(cx, &script->global());
jsbytecode* valuepc = frameIter.pc();
RootedFunction fun(cx, frameIter.isFunctionFrame()
? frameIter.calleeTemplate()
: nullptr);
MOZ_ASSERT(script->containsPC(valuepc));
@@ -1420,7 +1415,7 @@ DecompileExpressionFromStack(JSContext* cx, int spindex, int skipStackHits, Hand
if (!valuepc)
return true;
ExpressionDecompiler ed(cx, script, fun);
ExpressionDecompiler ed(cx, script);
if (!ed.init())
return false;
if (!ed.decompilePC(valuepc))
@@ -1487,9 +1482,6 @@ DecompileArgumentFromStack(JSContext* cx, int formalIndex, char** res)
RootedScript script(cx, frameIter.script());
AutoCompartment ac(cx, &script->global());
jsbytecode* current = frameIter.pc();
RootedFunction fun(cx, frameIter.isFunctionFrame()
? frameIter.calleeTemplate()
: nullptr);
MOZ_ASSERT(script->containsPC(current));
@@ -1509,7 +1501,7 @@ DecompileArgumentFromStack(JSContext* cx, int formalIndex, char** res)
if (uint32_t(formalStackIndex) >= parser.stackDepthAtPC(current))
return true;
ExpressionDecompiler ed(cx, script, fun);
ExpressionDecompiler ed(cx, script);
if (!ed.init())
return false;
if (!ed.decompilePCForStackOperand(current, formalStackIndex))
@@ -1833,7 +1825,7 @@ GetPCCountJSON(JSContext* cx, const ScriptAndCounts& sac, StringBuffer& buf)
}
{
ExpressionDecompiler ed(cx, script, script->functionDelazifying());
ExpressionDecompiler ed(cx, script);
if (!ed.init())
return false;
if (!ed.decompilePC(pc))
+19 -6
View File
@@ -176,7 +176,6 @@ Bindings::initWithTemporaryStorage(ExclusiveContext* cx, MutableHandle<Bindings>
uint32_t slot = CallObject::RESERVED_SLOTS;
for (BindingIter bi(self); bi; bi++) {
MOZ_ASSERT_IF(isModule, bi->aliased());
if (!bi->aliased())
continue;
@@ -627,6 +626,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
HasInnerFunctions,
NeedsHomeObject,
IsDerivedClassConstructor,
IsDefaultClassConstructor,
};
uint32_t length, lineno, column, nslots;
@@ -772,6 +772,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
scriptBits |= (1 << NeedsHomeObject);
if (script->isDerivedClassConstructor())
scriptBits |= (1 << IsDerivedClassConstructor);
if (script->isDefaultClassConstructor())
scriptBits |= (1 << IsDefaultClassConstructor);
}
if (!xdr->codeUint32(&prologueLength))
@@ -916,6 +918,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
script->needsHomeObject_ = true;
if (scriptBits & (1 << IsDerivedClassConstructor))
script->isDerivedClassConstructor_ = true;
if (scriptBits & (1 << IsDefaultClassConstructor))
script->isDefaultClassConstructor_ = true;
if (scriptBits & (1 << IsLegacyGenerator)) {
MOZ_ASSERT(!(scriptBits & (1 << IsStarGenerator)));
@@ -3392,8 +3396,17 @@ CloneInnerInterpretedFunction(JSContext* cx, HandleObject enclosingScope, Handle
}
gc::AllocKind allocKind = srcFun->getAllocKind();
RootedFunction clone(cx, NewFunctionWithProto(cx, nullptr, 0,
JSFunction::INTERPRETED, nullptr, nullptr,
uint16_t flags = srcFun->flags();
if (srcFun->isSelfHostedBuiltin()) {
// Functions in the self-hosting compartment are only extended in
// debug mode. For top-level functions, FUNCTION_EXTENDED gets used by
// the cloning algorithm. Do the same for inner functions here.
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
flags |= JSFunction::Flags::EXTENDED;
}
RootedAtom atom(cx, srcFun->displayAtom());
RootedFunction clone(cx, NewFunctionWithProto(cx, nullptr, srcFun->nargs(),
JSFunction::Flags(flags), nullptr, atom,
cloneProto, allocKind, TenuredObject));
if (!clone)
return nullptr;
@@ -3405,9 +3418,6 @@ CloneInnerInterpretedFunction(JSContext* cx, HandleObject enclosingScope, Handle
if (!cloneScript)
return nullptr;
clone->setArgCount(srcFun->nargs());
clone->setFlags(srcFun->flags());
clone->initAtom(srcFun->displayAtom());
if (!JSFunction::setTypeForScriptedFunction(cx, clone))
return nullptr;
@@ -3572,6 +3582,9 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri
dst->hasInnerFunctions_ = src->hasInnerFunctions();
dst->isGeneratorExp_ = src->isGeneratorExp();
dst->setGeneratorKind(src->generatorKind());
dst->isDerivedClassConstructor_ = src->isDerivedClassConstructor();
dst->needsHomeObject_ = src->needsHomeObject();
dst->isDefaultClassConstructor_ = src->isDefaultClassConstructor();
if (nconsts != 0) {
HeapValue* vector = Rebase<HeapValue>(dst, src, src->consts()->vector);
+23 -8
View File
@@ -1195,6 +1195,7 @@ class JSScript : public js::gc::TenuredCell
bool needsHomeObject_:1;
bool isDerivedClassConstructor_:1;
bool isDefaultClassConstructor_:1;
// Add padding so JSScript is gc::Cell aligned. Make padding protected
// instead of private to suppress -Wunused-private-field compiler warnings.
@@ -1287,23 +1288,23 @@ class JSScript : public js::gc::TenuredCell
void setColumn(size_t column) { column_ = column; }
// The fixed part of a stack frame is comprised of vars (in function code)
// and block-scoped locals (in all kinds of code).
// The fixed part of a stack frame is comprised of vars (in function and
// module code) and block-scoped locals (in all kinds of code).
size_t nfixed() const {
return function_ ? bindings.numFixedLocals() : bindings.numBlockScoped();
return isGlobalOrEvalCode() ? bindings.numBlockScoped() : bindings.numFixedLocals();
}
// Number of fixed slots reserved for vars. Only nonzero for function
// code.
// or module code.
size_t nfixedvars() const {
return function_ ? bindings.numUnaliasedVars() : 0;
return isGlobalOrEvalCode() ? 0 : bindings.numUnaliasedVars();
}
// Number of fixed slots reserved for body-level lexicals and vars. This
// value minus nfixedvars() is the number of body-level lexicals. Only
// nonzero for function code.
// nonzero for function or module code.
size_t nbodyfixed() const {
return function_ ? bindings.numUnaliasedBodyLevelLocals() : 0;
return isGlobalOrEvalCode() ? 0 : bindings.numUnaliasedBodyLevelLocals();
}
// Calculate the number of fixed slots that are live at a particular bytecode.
@@ -1426,6 +1427,9 @@ class JSScript : public js::gc::TenuredCell
bool failedLexicalCheck() const {
return failedLexicalCheck_;
}
bool isDefaultClassConstructor() const {
return isDefaultClassConstructor_;
}
void setFailedBoundsCheck() { failedBoundsCheck_ = true; }
void setFailedShapeGuard() { failedShapeGuard_ = true; }
@@ -1434,6 +1438,7 @@ class JSScript : public js::gc::TenuredCell
void setUninlineable() { uninlineable_ = true; }
void setInvalidatedIdempotentCache() { invalidatedIdempotentCache_ = true; }
void setFailedLexicalCheck() { failedLexicalCheck_ = true; }
void setIsDefaultClassConstructor() { isDefaultClassConstructor_ = true; }
bool hasScriptCounts() const { return hasScriptCounts_; }
@@ -1638,6 +1643,13 @@ class JSScript : public js::gc::TenuredCell
}
inline void setModule(js::ModuleObject* module);
bool isGlobalOrEvalCode() const {
return !function_ && !module_;
}
bool isGlobalCode() const {
return isGlobalOrEvalCode() && !isForEval();
}
JSFlatString* sourceData(JSContext* cx);
static bool loadSource(JSContext* cx, js::ScriptSource* ss, bool* worked);
@@ -1656,7 +1668,10 @@ class JSScript : public js::gc::TenuredCell
public:
/* Return whether this script was compiled for 'eval' */
bool isForEval() { return isCachedEval() || isActiveEval(); }
bool isForEval() const { return isCachedEval() || isActiveEval(); }
/* Return whether this is a 'direct eval' script in a function scope. */
bool isDirectEvalInFunction() const { return isForEval() && savedCallerFun(); }
/*
* Return whether this script is a top-level script.
+1 -1
View File
@@ -4244,7 +4244,7 @@ static const JSFunctionSpec string_static_methods[] = {
JS_INLINABLE_FN("fromCharCode", js::str_fromCharCode, 1, 0, StringFromCharCode),
JS_SELF_HOSTED_FN("fromCodePoint", "String_static_fromCodePoint", 1,0),
JS_SELF_HOSTED_FN("raw", "String_static_raw", 2,0),
JS_SELF_HOSTED_FN("raw", "String_static_raw", 1,0),
JS_SELF_HOSTED_FN("substring", "String_static_substring", 3,0),
JS_SELF_HOSTED_FN("substr", "String_static_substr", 3,0),
JS_SELF_HOSTED_FN("slice", "String_static_slice", 3,0),
+2
View File
@@ -700,8 +700,10 @@ selfhosted.inputs = [
'builtin/SelfHostingDefines.h',
'builtin/Utilities.js',
'builtin/Array.js',
'builtin/Classes.js',
'builtin/Date.js',
'builtin/Error.js',
'builtin/Function.js',
'builtin/Generator.js',
'builtin/Intl.js',
'builtin/IntlData.js',
+5 -2
View File
@@ -2170,8 +2170,6 @@ DisassembleScript(JSContext* cx, HandleScript script, HandleFunction fun,
Sprint(sp, " CONSTRUCTOR");
if (fun->isExprBody())
Sprint(sp, " EXPRESSION_CLOSURE");
if (fun->isFunctionPrototype())
Sprint(sp, " Function.prototype");
if (fun->isSelfHostedBuiltin())
Sprint(sp, " SELF_HOSTED");
if (fun->isArrow())
@@ -3975,6 +3973,11 @@ NewGlobal(JSContext* cx, unsigned argc, Value* vp)
if (v.isBoolean())
creationOptions.setCloneSingletons(v.toBoolean());
if (!JS_GetProperty(cx, opts, "experimentalDateTimeFormatFormatToPartsEnabled", &v))
return true;
if (v.isBoolean())
creationOptions.setExperimentalDateTimeFormatFormatToPartsEnabled(v.toBoolean());
if (!JS_GetProperty(cx, opts, "sameZoneAs", &v))
return false;
if (v.isObject())
@@ -0,0 +1,176 @@
// |reftest| skip-if(!this.hasOwnProperty("Intl")||!this.newGlobal||!newGlobal({experimentalDateTimeFormatFormatToPartsEnabled:true}).Intl.DateTimeFormat().formatToParts)
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
// Tests the format function with a diverse set of locales and options.
// Always use UTC to avoid dependencies on test environment.
/*
* Return true if A is equal to B, where equality on arrays and objects
* means that they have the same set of enumerable properties, the values
* of each property are deep_equal, and their 'length' properties are
* equal. Equality on other types is ==.
*/
function deepEqual(a, b) {
if (typeof a !== typeof b)
return false;
if (a === null)
return b === null;
if (typeof a === 'object') {
// For every property of a, does b have that property with an equal value?
var props = {};
for (var prop in a) {
if (!deepEqual(a[prop], b[prop]))
return false;
props[prop] = true;
}
// Are all of b's properties present on a?
for (var prop in b)
if (!props[prop])
return false;
// length isn't enumerable, but we want to check it, too.
return a.length === b.length;
}
return Object.is(a, b);
}
function composeDate(parts) {
return parts.map(({value}) => value)
.reduce((string, part) => string + part);
}
var format;
var date = Date.UTC(2012, 11, 17, 3, 0, 42);
// The experimental formatToParts method is only exposed if specifically
// requested. Perform all tests using DateTimeFormat instances from a global
// object with this method enabled.
var DateTimeFormat =
newGlobal({experimentalDateTimeFormatFormatToPartsEnabled:true}).Intl.DateTimeFormat;
// Locale en-US; default options.
format = new DateTimeFormat("en-us", {timeZone: "UTC"});
assertEq(deepEqual(format.formatToParts(date), [
{ type: 'month', value: '12' },
{ type: 'separator', value: '/' },
{ type: 'day', value: '17' },
{ type: 'separator', value: '/' },
{ type: 'year', value: '2012' }
]), true);
// Just date
format = new DateTimeFormat("en-us", {
year: 'numeric',
month: 'numeric',
day: 'numeric',
timeZone: "UTC"});
assertEq(deepEqual(format.formatToParts(date), [
{ type: 'month', value: '12' },
{ type: 'separator', value: '/' },
{ type: 'day', value: '17' },
{ type: 'separator', value: '/' },
{ type: 'year', value: '2012' }
]), true);
assertEq(composeDate(format.formatToParts(date)), format.format(date));
// Just time in hour24
format = new DateTimeFormat("en-us", {
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
hour12: false,
timeZone: "UTC"});
assertEq(deepEqual(format.formatToParts(date), [
{ type: 'hour', value: '03' },
{ type: 'separator', value: ':' },
{ type: 'minute', value: '00' },
{ type: 'separator', value: ':' },
{ type: 'second', value: '42' }
]), true);
assertEq(composeDate(format.formatToParts(date)), format.format(date));
// Just time in hour12
format = new DateTimeFormat("en-us", {
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
hour12: true,
timeZone: "UTC"});
assertEq(deepEqual(format.formatToParts(date), [
{ type: 'hour', value: '3' },
{ type: 'separator', value: ':' },
{ type: 'minute', value: '00' },
{ type: 'separator', value: ':' },
{ type: 'second', value: '42' },
{ type: 'separator', value: ' ' },
{ type: 'dayperiod', value: 'AM' }
]), true);
assertEq(composeDate(format.formatToParts(date)), format.format(date));
// Just month.
format = new DateTimeFormat("en-us", {
month: "narrow",
timeZone: "UTC"});
assertEq(deepEqual(format.formatToParts(date), [
{ type: 'month', value: 'D' }
]), true);
assertEq(composeDate(format.formatToParts(date)), format.format(date));
// Just weekday.
format = new DateTimeFormat("en-us", {
weekday: "narrow",
timeZone: "UTC"});
assertEq(deepEqual(format.formatToParts(date), [
{ type: 'weekday', value: 'M' }
]), true);
assertEq(composeDate(format.formatToParts(date)), format.format(date));
// Year and era.
format = new DateTimeFormat("en-us", {
year: "numeric",
era: "short",
timeZone: "UTC"});
assertEq(deepEqual(format.formatToParts(date), [
{ type: 'year', value: '2012' },
{ type: 'separator', value: ' ' },
{ type: 'era', value: 'AD' }
]), true);
assertEq(composeDate(format.formatToParts(date)), format.format(date));
// Time and date
format = new DateTimeFormat("en-us", {
weekday: 'long',
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
hour12: true,
timeZone: "UTC"});
assertEq(deepEqual(format.formatToParts(date), [
{ type: 'weekday', value: 'Monday' },
{ type: 'separator', value: ', ' },
{ type: 'month', value: '12' },
{ type: 'separator', value: '/' },
{ type: 'day', value: '17' },
{ type: 'separator', value: '/' },
{ type: 'year', value: '2012' },
{ type: 'separator', value: ', ' },
{ type: 'hour', value: '3' },
{ type: 'separator', value: ':' },
{ type: 'minute', value: '00' },
{ type: 'separator', value: ':' },
{ type: 'second', value: '42' },
{ type: 'separator', value: ' ' },
{ type: 'dayperiod', value: 'AM' }
]), true);
assertEq(composeDate(format.formatToParts(date)), format.format(date));
if (typeof reportCompare === "function")
reportCompare(0, 0, 'ok');
@@ -0,0 +1,19 @@
/* Make sure that the default derived class constructor has the required spread semantics.
*
* Test credit André Bargull
*/
Array.prototype[Symbol.iterator] = function*() { yield 1; yield 2; };
class Base {
constructor(a, b) {
assertEq(a, 1);
assertEq(b, 2);
}
};
class Derived extends Base {};
new Derived();
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");
@@ -43,16 +43,18 @@ if (typeof parseModule === "function")
if (typeof Reflect.parse === "function")
{
var twoStatementAST =
Reflect.parse(`export { x } /* ASI should trigger here */
Reflect.parse(`let x = 0;
export { x } /* ASI should trigger here */
fro\\u006D`,
{ target: "module" });
var statements = twoStatementAST.body;
assertEq(statements.length, 2,
assertEq(statements.length, 3,
"should have two items in the module, not one ExportDeclaration");
assertEq(statements[0].type, "ExportDeclaration");
assertEq(statements[1].type, "ExpressionStatement");
assertEq(statements[1].expression.name, "from");
assertEq(statements[0].type, "VariableDeclaration");
assertEq(statements[1].type, "ExportDeclaration");
assertEq(statements[2].type, "ExpressionStatement");
assertEq(statements[2].expression.name, "from");
var oneStatementAST =
Reflect.parse(`export { x } /* no ASI here */
+1 -1
View File
@@ -39,7 +39,7 @@ ArgumentsObject::MaybeForwardToCallObject(AbstractFramePtr frame, ArgumentsObjec
ArgumentsData* data)
{
JSScript* script = frame.script();
if (frame.fun()->needsCallObject() && script->argumentsAliasesFormals()) {
if (frame.callee()->needsCallObject() && script->argumentsAliasesFormals()) {
obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(frame.callObj()));
for (AliasedFormalIter fi(script); fi; fi++)
data->args[fi.frameIndex()] = MagicScopeSlotValue(fi.scopeSlot());
+30 -12
View File
@@ -13,6 +13,7 @@
#define FOR_EACH_COMMON_PROPERTYNAME(macro) \
macro(add, add, "add") \
macro(allowContentSpread, allowContentSpread, "allowContentSpread") \
macro(anonymous, anonymous, "anonymous") \
macro(Any, Any, "Any") \
macro(apply, apply, "apply") \
@@ -23,10 +24,10 @@
macro(ArrayValues, ArrayValues, "ArrayValues") \
macro(ArrayValuesAt, ArrayValuesAt, "ArrayValuesAt") \
macro(Async, Async, "Async") \
macro(bool8x16, bool8x16, "Bool8x16") \
macro(bool16x8, bool16x8, "Bool16x8") \
macro(bool32x4, bool32x4, "Bool32x4") \
macro(bool64x2, bool64x2, "Bool64x2") \
macro(Bool8x16, Bool8x16, "Bool8x16") \
macro(Bool16x8, Bool16x8, "Bool16x8") \
macro(Bool32x4, Bool32x4, "Bool32x4") \
macro(Bool64x2, Bool64x2, "Bool64x2") \
macro(breakdown, breakdown, "breakdown") \
macro(buffer, buffer, "buffer") \
macro(builder, builder, "builder") \
@@ -38,6 +39,7 @@
macro(BYTES_PER_ELEMENT, BYTES_PER_ELEMENT, "BYTES_PER_ELEMENT") \
macro(call, call, "call") \
macro(callContentFunction, callContentFunction, "callContentFunction") \
macro(std_Function_apply, std_Function_apply, "std_Function_apply") \
macro(callee, callee, "callee") \
macro(caller, caller, "caller") \
macro(callFunction, callFunction, "callFunction") \
@@ -60,9 +62,14 @@
macro(currencyDisplay, currencyDisplay, "currencyDisplay") \
macro(DateTimeFormat, DateTimeFormat, "DateTimeFormat") \
macro(DateTimeFormatFormatGet, DateTimeFormatFormatGet, "Intl_DateTimeFormat_format_get") \
macro(DateTimeFormatFormatToPartsGet, DateTimeFormatFormatToPartsGet, "Intl_DateTimeFormat_formatToParts_get") \
macro(day, day, "day") \
macro(dayperiod, dayperiod, "dayperiod") \
macro(decodeURI, decodeURI, "decodeURI") \
macro(decodeURIComponent, decodeURIComponent, "decodeURIComponent") \
macro(default_, default_, "default") \
macro(DefaultBaseClassConstructor, DefaultBaseClassConstructor, "DefaultBaseClassConstructor") \
macro(DefaultDerivedClassConstructor, DefaultDerivedClassConstructor, "DefaultDerivedClassConstructor") \
macro(defineProperty, defineProperty, "defineProperty") \
macro(defineGetter, defineGetter, "__defineGetter__") \
macro(defineSetter, defineSetter, "__defineSetter__") \
@@ -82,6 +89,7 @@
macro(entries, entries, "entries") \
macro(enumerable, enumerable, "enumerable") \
macro(enumerate, enumerate, "enumerate") \
macro(era, era, "era") \
macro(escape, escape, "escape") \
macro(eval, eval, "eval") \
macro(false, false_, "false") \
@@ -94,12 +102,13 @@
macro(fix, fix, "fix") \
macro(flags, flags, "flags") \
macro(float32, float32, "float32") \
macro(float32x4, float32x4, "Float32x4") \
macro(Float32x4, Float32x4, "Float32x4") \
macro(float64, float64, "float64") \
macro(float64x2, float64x2, "Float64x2") \
macro(Float64x2, Float64x2, "Float64x2") \
macro(forceInterpreter, forceInterpreter, "forceInterpreter") \
macro(forEach, forEach, "forEach") \
macro(format, format, "format") \
macro(formatToParts, formatToParts, "formatToParts") \
macro(frame, frame, "frame") \
macro(from, from, "from") \
macro(gcCycleNumber, gcCycleNumber, "gcCycleNumber") \
@@ -114,6 +123,7 @@
macro(has, has, "has") \
macro(hasOwn, hasOwn, "hasOwn") \
macro(hasOwnProperty, hasOwnProperty, "hasOwnProperty") \
macro(hour, hour, "hour") \
macro(ignoreCase, ignoreCase, "ignoreCase") \
macro(ignorePunctuation, ignorePunctuation, "ignorePunctuation") \
macro(includes, includes, "includes") \
@@ -124,9 +134,9 @@
macro(inNursery, inNursery, "inNursery") \
macro(innermost, innermost, "innermost") \
macro(input, input, "input") \
macro(int8x16, int8x16, "Int8x16") \
macro(int16x8, int16x8, "Int16x8") \
macro(int32x4, int32x4, "Int32x4") \
macro(Int8x16, Int8x16, "Int8x16") \
macro(Int16x8, Int16x8, "Int16x8") \
macro(Int32x4, Int32x4, "Int32x4") \
macro(isFinite, isFinite, "isFinite") \
macro(isNaN, isNaN, "isNaN") \
macro(isPrototypeOf, isPrototypeOf, "isPrototypeOf") \
@@ -158,8 +168,10 @@
macro(minimumFractionDigits, minimumFractionDigits, "minimumFractionDigits") \
macro(minimumIntegerDigits, minimumIntegerDigits, "minimumIntegerDigits") \
macro(minimumSignificantDigits, minimumSignificantDigits, "minimumSignificantDigits") \
macro(minute, minute, "minute") \
macro(missingArguments, missingArguments, "missingArguments") \
macro(module, module, "module") \
macro(month, month, "month") \
macro(multiline, multiline, "multiline") \
macro(name, name, "name") \
macro(NaN, NaN, "NaN") \
@@ -206,7 +218,9 @@
macro(revoke, revoke, "revoke") \
macro(script, script, "script") \
macro(scripts, scripts, "scripts") \
macro(second, second, "second") \
macro(sensitivity, sensitivity, "sensitivity") \
macro(separator, separator, "separator") \
macro(set, set, "set") \
macro(shape, shape, "shape") \
macro(size, size, "size") \
@@ -227,6 +241,7 @@
macro(throw, throw_, "throw") \
macro(timestamp, timestamp, "timestamp") \
macro(timeZone, timeZone, "timeZone") \
macro(timeZoneName, timeZoneName, "timeZoneName") \
macro(toGMTString, toGMTString, "toGMTString") \
macro(toISOString, toISOString, "toISOString") \
macro(toJSON, toJSON, "toJSON") \
@@ -235,6 +250,7 @@
macro(toString, toString, "toString") \
macro(toUTCString, toUTCString, "toUTCString") \
macro(true, true_, "true") \
macro(type, type, "type") \
macro(unescape, unescape, "unescape") \
macro(uneval, uneval, "uneval") \
macro(unicode, unicode, "unicode") \
@@ -243,9 +259,9 @@
macro(uint8Clamped, uint8Clamped, "uint8Clamped") \
macro(uint16, uint16, "uint16") \
macro(uint32, uint32, "uint32") \
macro(uint8x16, uint8x16, "Uint8x16") \
macro(uint16x8, uint16x8, "Uint16x8") \
macro(uint32x4, uint32x4, "Uint32x4") \
macro(Uint8x16, Uint8x16, "Uint8x16") \
macro(Uint16x8, Uint16x8, "Uint16x8") \
macro(Uint32x4, Uint32x4, "Uint32x4") \
macro(unsized, unsized, "unsized") \
macro(unwatch, unwatch, "unwatch") \
macro(url, url, "url") \
@@ -261,7 +277,9 @@
macro(void0, void0, "(void 0)") \
macro(watch, watch, "watch") \
macro(WeakSet_add, WeakSet_add, "WeakSet_add") \
macro(weekday, weekday, "weekday") \
macro(writable, writable, "writable") \
macro(year, year, "year") \
macro(yield, yield, "yield") \
macro(raw, raw, "raw") \
/* Type names must be contiguous and ordered; see js::TypeName. */ \
+4 -5
View File
@@ -6320,7 +6320,7 @@ static bool
DebuggerFrame_getCallee(JSContext* cx, unsigned argc, Value* vp)
{
THIS_FRAME(cx, argc, vp, "get callee", args, thisobj, frame);
RootedValue calleev(cx, frame.isNonEvalFunctionFrame() ? frame.calleev() : NullValue());
RootedValue calleev(cx, frame.isFunctionFrame() ? frame.calleev() : NullValue());
if (!Debugger::fromChildJSObject(thisobj)->wrapDebuggeeValue(cx, &calleev))
return false;
args.rval().set(calleev);
@@ -6509,7 +6509,7 @@ DebuggerFrame_getScript(JSContext* cx, unsigned argc, Value* vp)
Debugger* debug = Debugger::fromChildJSObject(thisobj);
RootedObject scriptObject(cx);
if (frame.isFunctionFrame() && !frame.isEvalFrame()) {
if (frame.isFunctionFrame()) {
RootedFunction callee(cx, frame.callee());
if (callee->isInterpreted()) {
RootedScript script(cx, callee->nonLazyScript());
@@ -6709,8 +6709,7 @@ EvaluateInEnv(JSContext* cx, Handle<Env*> env, AbstractFramePtr frame,
script->setActiveEval();
}
ExecuteType type = !frame ? EXECUTE_GLOBAL : EXECUTE_DEBUG;
return ExecuteKernel(cx, script, *env, NullValue(), type, frame, rval.address());
return ExecuteKernel(cx, script, *env, NullValue(), frame, rval.address());
}
enum EvalBindings { EvalHasExtraBindings = true, EvalWithDefaultBindings = false };
@@ -7244,7 +7243,7 @@ DebuggerObject_getBoundArguments(JSContext* cx, unsigned argc, Value* vp)
if (!boundArgs.resize(length))
return false;
for (size_t i = 0; i < length; i++) {
boundArgs[i].set(fun->getBoundFunctionArgument(i));
boundArgs[i].set(fun->getBoundFunctionArgument(cx, i));
if (!dbg->wrapDebuggeeValue(cx, boundArgs[i]))
return false;
}
+1 -1
View File
@@ -24,7 +24,7 @@ GeneratorObject::create(JSContext* cx, AbstractFramePtr frame)
RootedNativeObject obj(cx);
if (frame.script()->isStarGenerator()) {
RootedValue pval(cx);
RootedObject fun(cx, frame.fun());
RootedObject fun(cx, frame.callee());
// FIXME: This would be faster if we could avoid doing a lookup to get
// the prototype for the instance. Bug 906600.
if (!GetProperty(cx, fun, fun, cx->names().prototype, &pval))
+6 -2
View File
@@ -24,7 +24,7 @@
#include "builtin/ModuleObject.h"
#include "builtin/Object.h"
#include "builtin/RegExp.h"
#include "builtin/SIMD.h"
#include "builtin/SelfHostingDefines.h"
#include "builtin/SymbolObject.h"
#include "builtin/TypedObject.h"
#include "builtin/WeakMapObject.h"
@@ -690,8 +690,12 @@ GlobalObject::getSelfHostedFunction(JSContext* cx, Handle<GlobalObject*> global,
}
RootedFunction fun(cx);
if (!cx->runtime()->createLazySelfHostedFunctionClone(cx, selfHostedName, name, nargs, &fun))
if (!cx->runtime()->createLazySelfHostedFunctionClone(cx, selfHostedName, name, nargs,
/* proto = */ nullptr,
SingletonObject, &fun))
{
return false;
}
funVal.setObject(*fun);
return GlobalObject::addIntrinsicValue(cx, global, selfHostedName, funVal);
+25 -6
View File
@@ -443,11 +443,18 @@ class GlobalObject : public NativeObject
}
template<class /* SimdTypeDescriptor (cf SIMD.h) */ T>
SimdTypeDescr* getOrCreateSimdTypeDescr(JSContext* cx) {
RootedObject globalSimdObject(cx, cx->global()->getOrCreateSimdGlobalObject(cx));
static SimdTypeDescr*
getOrCreateSimdTypeDescr(JSContext* cx, Handle<GlobalObject*> global) {
RootedObject globalSimdObject(cx, global->getOrCreateSimdGlobalObject(cx));
if (!globalSimdObject)
return nullptr;
const Value& slot = globalSimdObject->as<NativeObject>().getReservedSlot(uint32_t(T::type));
uint32_t typeSlotIndex(T::type);
if (globalSimdObject->as<NativeObject>().getReservedSlot(typeSlotIndex).isUndefined() &&
!GlobalObject::initSimdType(cx, global, typeSlotIndex))
{
return nullptr;
}
const Value& slot = globalSimdObject->as<NativeObject>().getReservedSlot(typeSlotIndex);
MOZ_ASSERT(slot.isObject());
return &slot.toObject().as<SimdTypeDescr>();
}
@@ -573,18 +580,29 @@ class GlobalObject : public NativeObject
static NativeObject* getIntrinsicsHolder(JSContext* cx, Handle<GlobalObject*> global);
Value existingIntrinsicValue(PropertyName* name) {
Value maybeExistingIntrinsicValue(PropertyName* name) {
Value slot = getReservedSlot(INTRINSICS);
MOZ_ASSERT(slot.isObject(), "intrinsics holder must already exist");
// If we're in the self-hosting compartment itself, the
// intrinsics-holder isn't initialized at this point.
if (slot.isUndefined())
return UndefinedValue();
NativeObject* holder = &slot.toObject().as<NativeObject>();
Shape* shape = holder->lookupPure(name);
MOZ_ASSERT(shape, "intrinsic must already have been added to holder");
if (!shape)
return UndefinedValue();
return holder->getSlot(shape->slot());
}
Value existingIntrinsicValue(PropertyName* name) {
Value val = maybeExistingIntrinsicValue(name);
MOZ_ASSERT(!val.isUndefined(), "intrinsic must already have been added to holder");
return val;
}
static bool
maybeGetIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global, Handle<PropertyName*> name,
MutableHandleValue vp)
@@ -704,6 +722,7 @@ class GlobalObject : public NativeObject
// Implemented in builtim/SIMD.cpp
static bool initSimdObject(JSContext* cx, Handle<GlobalObject*> global);
static bool initSimdType(JSContext* cx, Handle<GlobalObject*> global, uint32_t simdTypeDescrType);
static bool initStandardClasses(JSContext* cx, Handle<GlobalObject*> global);
static bool initSelfHostingBuiltins(JSContext* cx, Handle<GlobalObject*> global,
+42 -74
View File
@@ -138,12 +138,12 @@ js::BoxNonStrictThis(JSContext* cx, const CallReceiver& call)
bool
js::GetFunctionThis(JSContext* cx, AbstractFramePtr frame, MutableHandleValue res)
{
MOZ_ASSERT(frame.isNonEvalFunctionFrame());
MOZ_ASSERT(!frame.fun()->isArrow());
MOZ_ASSERT(frame.isFunctionFrame());
MOZ_ASSERT(!frame.callee()->isArrow());
if (frame.thisArgument().isObject() ||
frame.fun()->strict() ||
frame.fun()->isSelfHostedBuiltin())
frame.callee()->strict() ||
frame.callee()->isSelfHostedBuiltin())
{
res.set(frame.thisArgument());
return true;
@@ -293,9 +293,26 @@ MakeDefaultConstructor(JSContext* cx, JSOp op, JSAtom* atom, HandleObject proto)
bool derived = op == JSOP_DERIVEDCONSTRUCTOR;
MOZ_ASSERT(derived == !!proto);
PropertyName* lookup = derived ? cx->names().DefaultDerivedClassConstructor
: cx->names().DefaultBaseClassConstructor;
RootedPropertyName selfHostedName(cx, lookup);
RootedAtom name(cx, atom == cx->names().empty ? nullptr : atom);
JSNative native = derived ? DefaultDerivedClassConstructor : DefaultClassConstructor;
return NewFunctionWithProto(cx, native, 0, JSFunction::NATIVE_CLASS_CTOR, nullptr, name, proto);
RootedFunction ctor(cx);
if (!cx->runtime()->createLazySelfHostedFunctionClone(cx, selfHostedName, name,
/* nargs = */ 0,
proto, TenuredObject, &ctor))
{
return nullptr;
}
ctor->setIsConstructor();
ctor->setIsClassConstructor();
MOZ_ASSERT(ctor->infallibleIsDefaultClassConstructor(cx));
return ctor;
}
bool
@@ -326,7 +343,9 @@ RunState::maybeCreateThisForConstructor(JSContext* cx)
InvokeState& invoke = *asInvoke();
if (invoke.constructing() && invoke.args().thisv().isPrimitive()) {
RootedObject callee(cx, &invoke.args().callee());
if (script()->isDerivedClassConstructor()) {
if (callee->isBoundFunction()) {
invoke.args().setThis(MagicValue(JS_UNINITIALIZED_LEXICAL));
} else if (script()->isDerivedClassConstructor()) {
MOZ_ASSERT(callee->as<JSFunction>().isClassConstructor());
invoke.args().setThis(MagicValue(JS_UNINITIALIZED_LEXICAL));
} else {
@@ -348,14 +367,14 @@ Interpret(JSContext* cx, RunState& state);
InterpreterFrame*
InvokeState::pushInterpreterFrame(JSContext* cx)
{
return cx->runtime()->interpreterStack().pushInvokeFrame(cx, args_, initial_);
return cx->runtime()->interpreterStack().pushInvokeFrame(cx, args_, construct_);
}
InterpreterFrame*
ExecuteState::pushInterpreterFrame(JSContext* cx)
{
return cx->runtime()->interpreterStack().pushExecuteFrame(cx, script_, newTargetValue_,
scopeChain_, type_, evalInFrame_);
scopeChain_, evalInFrame_);
}
// MSVC with PGO inlines a lot of functions in RunScript, resulting in large
// stack frames and stack overflow issues, see bug 1167883. Turn off PGO to
@@ -429,9 +448,6 @@ js::Invoke(JSContext* cx, const CallArgs& args, MaybeConstruct construct)
/* Perform GC if necessary on exit from the function. */
AutoGCIfRequested gcIfRequested(cx->runtime());
/* MaybeConstruct is a subset of InitialFrameFlags */
InitialFrameFlags initial = (InitialFrameFlags) construct;
unsigned skipForCallee = args.length() + 1 + (construct == CONSTRUCT);
if (args.calleev().isPrimitive())
return ReportIsNotFunction(cx, args.calleev(), skipForCallee, construct);
@@ -461,7 +477,7 @@ js::Invoke(JSContext* cx, const CallArgs& args, MaybeConstruct construct)
return false;
/* Run function until JSOP_RETRVAL, JSOP_RETURN or error. */
InvokeState state(cx, args, initial);
InvokeState state(cx, args, construct);
// Check to see if createSingleton flag should be set for this frame.
if (construct) {
@@ -629,12 +645,11 @@ js::InvokeSetter(JSContext* cx, const Value& thisv, Value fval, HandleValue v)
bool
js::ExecuteKernel(JSContext* cx, HandleScript script, JSObject& scopeChainArg,
const Value& newTargetValue, ExecuteType type, AbstractFramePtr evalInFrame,
const Value& newTargetValue, AbstractFramePtr evalInFrame,
Value* result)
{
MOZ_ASSERT_IF(evalInFrame, type == EXECUTE_DEBUG);
MOZ_ASSERT_IF(type == EXECUTE_GLOBAL, IsGlobalLexicalScope(&scopeChainArg) ||
!IsSyntacticScope(&scopeChainArg));
MOZ_ASSERT_IF(script->isGlobalCode(),
IsGlobalLexicalScope(&scopeChainArg) || !IsSyntacticScope(&scopeChainArg));
#ifdef DEBUG
RootedObject terminatingScope(cx, &scopeChainArg);
while (IsSyntacticScope(terminatingScope))
@@ -659,7 +674,7 @@ js::ExecuteKernel(JSContext* cx, HandleScript script, JSObject& scopeChainArg,
}
probes::StartExecution(script);
ExecuteState state(cx, script, newTargetValue, scopeChainArg, type, evalInFrame, result);
ExecuteState state(cx, script, newTargetValue, scopeChainArg, evalInFrame, result);
bool ok = RunScript(cx, state);
probes::StopExecution(script);
@@ -692,9 +707,7 @@ js::Execute(JSContext* cx, HandleScript script, JSObject& scopeChainArg, Value*
} while ((s = s->enclosingScope()));
#endif
ExecuteType type = script->module() ? EXECUTE_MODULE : EXECUTE_GLOBAL;
return ExecuteKernel(cx, script, *scopeChain, NullValue(), type,
return ExecuteKernel(cx, script, *scopeChain, NullValue(),
NullFramePtr() /* evalInFrame */, rval);
}
@@ -1505,11 +1518,11 @@ class ReservedRooted : public ReservedRootedBase<T>
}
explicit ReservedRooted(Rooted<T>* root) : savedRoot(root) {
*root = js::GCMethods<T>::initial();
*root = js::GCPolicy<T>::initial();
}
~ReservedRooted() {
*savedRoot = js::GCMethods<T>::initial();
*savedRoot = js::GCPolicy<T>::initial();
}
void set(const T& p) const { *savedRoot = p; }
@@ -2798,7 +2811,7 @@ CASE(JSOP_FUNCALL)
if (REGS.fp()->hasPushedSPSFrame())
cx->runtime()->spsProfiler.updatePC(script, REGS.pc);
bool construct = (*REGS.pc == JSOP_NEW || *REGS.pc == JSOP_SUPERCALL);
MaybeConstruct construct = MaybeConstruct(*REGS.pc == JSOP_NEW || *REGS.pc == JSOP_SUPERCALL);
unsigned argStackSlots = GET_ARGC(REGS.pc) + construct;
MOZ_ASSERT(REGS.stackDepth() >= 2u + GET_ARGC(REGS.pc));
@@ -2836,13 +2849,12 @@ CASE(JSOP_FUNCALL)
if (!funScript)
goto error;
InitialFrameFlags initial = construct ? INITIAL_CONSTRUCT : INITIAL_NONE;
bool createSingleton = ObjectGroup::useSingletonForNewObject(cx, script, REGS.pc);
TypeMonitorCall(cx, args, construct);
mozilla::Maybe<InvokeState> state;
state.emplace(cx, args, initial);
state.emplace(cx, args, construct);
if (createSingleton)
state->setCreateSingleton();
@@ -2876,7 +2888,7 @@ CASE(JSOP_FUNCALL)
state.reset();
funScript = fun->nonLazyScript();
if (!activation.pushInlineFrame(args, funScript, initial))
if (!activation.pushInlineFrame(args, funScript, construct))
goto error;
if (createSingleton)
@@ -3361,7 +3373,7 @@ CASE(JSOP_LAMBDA_ARROW)
END_CASE(JSOP_LAMBDA_ARROW)
CASE(JSOP_CALLEE)
MOZ_ASSERT(REGS.fp()->isNonEvalFunctionFrame());
MOZ_ASSERT(REGS.fp()->isFunctionFrame());
PUSH_COPY(REGS.fp()->calleev());
END_CASE(JSOP_CALLEE)
@@ -3713,7 +3725,7 @@ END_CASE(JSOP_GENERATOR)
CASE(JSOP_INITIALYIELD)
{
MOZ_ASSERT(!cx->isExceptionPending());
MOZ_ASSERT(REGS.fp()->isNonEvalFunctionFrame());
MOZ_ASSERT(REGS.fp()->isFunctionFrame());
ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-1].toObject());
POP_RETURN_VALUE();
MOZ_ASSERT(REGS.stackDepth() == 0);
@@ -3725,7 +3737,7 @@ CASE(JSOP_INITIALYIELD)
CASE(JSOP_YIELD)
{
MOZ_ASSERT(!cx->isExceptionPending());
MOZ_ASSERT(REGS.fp()->isNonEvalFunctionFrame());
MOZ_ASSERT(REGS.fp()->isFunctionFrame());
ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-1].toObject());
if (!GeneratorObject::normalSuspend(cx, obj, REGS.fp(), REGS.pc,
REGS.spForStackDepth(0), REGS.stackDepth() - 2))
@@ -4845,50 +4857,6 @@ js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber,
ReportRuntimeLexicalError(cx, errorNumber, name);
}
bool
js::DefaultClassConstructor(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (!args.isConstructing()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_CALL_CLASS_CONSTRUCTOR);
return false;
}
RootedObject newTarget(cx, &args.newTarget().toObject());
JSObject* obj = CreateThis(cx, &PlainObject::class_, newTarget);
if (!obj)
return false;
args.rval().set(ObjectValue(*obj));
return true;
}
bool
js::DefaultDerivedClassConstructor(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (!args.isConstructing()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_CALL_CLASS_CONSTRUCTOR);
return false;
}
RootedObject fun(cx, &args.callee());
RootedObject superFun(cx);
if (!GetPrototype(cx, fun, &superFun))
return false;
RootedValue fval(cx, ObjectOrNullValue(superFun));
if (!IsConstructor(fval)) {
ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, fval, nullptr);
return false;
}
ConstructArgs constArgs(cx);
if (!FillArgumentsFromArraylike(cx, constArgs, args))
return false;
return Construct(cx, fval, constArgs, args.newTarget(), args.rval());
}
void
js::ReportRuntimeRedeclaration(JSContext* cx, HandlePropertyName name,
frontend::Definition::Kind declKind)
+7 -17
View File
@@ -40,11 +40,6 @@ GetFunctionThis(JSContext* cx, AbstractFramePtr frame, MutableHandleValue res);
extern bool
GetNonSyntacticGlobalThis(JSContext* cx, HandleObject scopeChain, MutableHandleValue res);
enum MaybeConstruct {
NO_CONSTRUCT = INITIAL_NONE,
CONSTRUCT = INITIAL_CONSTRUCT
};
/*
* numToSkip is the number of stack values the expression decompiler should skip
* before it reaches |v|. If it's -1, the decompiler will search the stack.
@@ -113,8 +108,7 @@ InternalConstructWithProvidedThis(JSContext* cx, HandleValue fval, HandleValue t
*/
extern bool
ExecuteKernel(JSContext* cx, HandleScript script, JSObject& scopeChain,
const Value& newTargetVal, ExecuteType type, AbstractFramePtr evalInFrame,
Value* result);
const Value& newTargetVal, AbstractFramePtr evalInFrame, Value* result);
/* Execute a script with the given scopeChain as global code. */
extern bool
@@ -169,8 +163,6 @@ class RunState
// Eval or global script.
class ExecuteState : public RunState
{
ExecuteType type_;
RootedValue newTargetValue_;
RootedObject scopeChain_;
@@ -179,10 +171,8 @@ class ExecuteState : public RunState
public:
ExecuteState(JSContext* cx, JSScript* script, const Value& newTargetValue,
JSObject& scopeChain, ExecuteType type, AbstractFramePtr evalInFrame,
Value* result)
JSObject& scopeChain, AbstractFramePtr evalInFrame, Value* result)
: RunState(cx, Execute, script),
type_(type),
newTargetValue_(cx, newTargetValue),
scopeChain_(cx, &scopeChain),
evalInFrame_(evalInFrame),
@@ -191,7 +181,7 @@ class ExecuteState : public RunState
Value newTarget() { return newTargetValue_; }
JSObject* scopeChain() const { return scopeChain_; }
ExecuteType type() const { return type_; }
bool isDebuggerEval() const { return !!evalInFrame_; }
virtual InterpreterFrame* pushInterpreterFrame(JSContext* cx);
@@ -205,21 +195,21 @@ class ExecuteState : public RunState
class InvokeState : public RunState
{
const CallArgs& args_;
InitialFrameFlags initial_;
MaybeConstruct construct_;
bool createSingleton_;
public:
InvokeState(JSContext* cx, const CallArgs& args, InitialFrameFlags initial)
InvokeState(JSContext* cx, const CallArgs& args, MaybeConstruct construct)
: RunState(cx, Invoke, args.callee().as<JSFunction>().nonLazyScript()),
args_(args),
initial_(initial),
construct_(construct),
createSingleton_(false)
{ }
bool createSingleton() const { return createSingleton_; }
void setCreateSingleton() { createSingleton_ = true; }
bool constructing() const { return InitialFrameFlagsAreConstructing(initial_); }
bool constructing() const { return construct_; }
const CallArgs& args() const { return args_; }
virtual InterpreterFrame* pushInterpreterFrame(JSContext* cx);
+2
View File
@@ -984,6 +984,8 @@ struct JSRuntime : public JS::shadow::Runtime,
bool isSelfHostingZone(const JS::Zone* zone) const;
bool createLazySelfHostedFunctionClone(JSContext* cx, js::HandlePropertyName selfHostedName,
js::HandleAtom name, unsigned nargs,
js::HandleObject proto,
js::NewObjectKind newKind,
js::MutableHandleFunction fun);
bool cloneSelfHostedFunctionScript(JSContext* cx, js::Handle<js::PropertyName*> name,
js::Handle<JSFunction*> targetFun);
+1 -1
View File
@@ -1130,7 +1130,7 @@ SavedStacks::insertFrames(JSContext* cx, FrameIter& iter, MutableHandleSavedFram
if (maxFrameCount == 0)
parentIsInCache = iter.hasCachedSavedFrame();
auto displayAtom = iter.isNonEvalFunctionFrame() ? iter.functionDisplayAtom() : nullptr;
auto displayAtom = iter.isFunctionFrame() ? iter.functionDisplayAtom() : nullptr;
if (!stackChain->emplaceBack(location.source(),
location.line(),
location.column(),

Some files were not shown because too many files have changed in this diff Show More