mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:30:27 +00:00
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:
@@ -258,7 +258,7 @@ protected:
|
||||
void TraceWrapper(JSTracer* aTrc, const char* name)
|
||||
{
|
||||
if (mWrapper) {
|
||||
JS_CallUnbarrieredObjectTracer(aTrc, &mWrapper, name);
|
||||
js::UnsafeTraceManuallyBarrieredEdge(aTrc, &mWrapper, name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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()):
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>())
|
||||
|
||||
@@ -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
@@ -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_);
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
|
||||
@@ -78,8 +78,6 @@
|
||||
\
|
||||
_(ObjectCreate) \
|
||||
\
|
||||
_(CallBoundFunction) \
|
||||
\
|
||||
_(SimdInt32x4) \
|
||||
_(SimdFloat32x4) \
|
||||
_(SimdBool32x4) \
|
||||
|
||||
+10
-18
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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
@@ -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_;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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: ");
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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),
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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. */ \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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, ®S.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, ®S.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
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user